# Redis ACL
## USER
### Add user
Step1: Add new user
``` SH
# 但是這個時候還沒有密碼
> ACL SETUSER JC
OK
```
Step2: Set user status
``` SH
# USER status 預設為 OFF
# ON 為打開 OFF 為關閉, 關閉後不能 AUTH
> ACL SETUSER JC ON
OK
```
Step3: Set new user password
``` SH
# 設定密碼
# 一個 username 可以多組密碼
# 設定多組密碼都可以做為認證
> ACL SETUSER JC >Temp4321
OK
> ACL SETUSER JC >Temp1234
OK
```
Ster4: 認證使用者
``` SH
> AUTH JC Temp4321
OK
> AUTH JC Temp1234
OK
```
Ster5: 將使用者暫時關閉
``` SH
# 先關閉
> ACL SETUSER JC OFF
OK
# 再做認證, 就會失敗
# 程式碼上面會馬上失敗嗎
> AUTH JC Temp1234
(error) WRONGPASS invalid username-password pair
```
Step6: Remove user
``` SH
# 直接刪除使用者
> ACL DELUSER JC
(integer) 1
> AUTH JC Temp1234
(error) WRONGPASS invalid username-password pair
```
### 多筆 user 權限如何控管
* 可以使用 File load `ACL LOAD` 去一次設定多個 users 以及權限, 然後將 file git 化
* 確認有哪些 users
``` sh
> ACL USERS
1) "JC"
2) "default"
```
* 確認 user 有哪些權限
``` sh
> ACL GETUSER JC
1) "flags"
2) 1) "on"
3) "passwords"
4) 1) "639b2d69fe3052812ab45b5f1e18d0f66155803a08e458d57c967981b9037e64"
2) "2452801270ab2eca597e6663e6cefb3a77d5e089aff3120a32819088818994aa"
5) "commands"
6) "-@all"
7) "keys"
8) (empty array)
```
### COMMAND
指令 `+<command>`
使用 `KEYS` 和 `GET` command 都會失敗, 因為都沒有定義
``` SH
# 認證 JC
> AUTH JC Temp4321
OK
# 使用 KEYS command
> KEYS *
(error) NOPERM this user has no permissions to run the 'keys' command or its subcommand
# 使用 GET command
> GET Taipei
(error) NOPERM this user has no permissions to run the 'get' command or its subcommand
```
加入 ACL rules
``` sh
# 認證
> AUTH 1qaz@WSX
OK
# 把 KEYS 指令加入 JC 可以使用的 command
> ACL SETUSER JC +KEYS
OK
# 把 GET 指令加入 JC 可以使用的 command
> ACL SETUSER JC +GET
OK
```
使用 `KEYS` command 會成功
但是 `GET` command 還是會失敗, 因為沒有指定能使用的 keys
``` SH
# 認證 JC
> AUTH JC Temp4321
OK
# 使用 KEYS command
> KEYS *
1) "Sicily"
2) "Taipei"
# 使用 GET command
> GET Taipei
(error) NOPERM this user has no permissions to access one of the keys used as arguments
```
### KEY
指令 `~<pattern>`
same as `KEYS` cmmand pattern, support:
> h?llo matches hello, hallo and hxllo
h*llo matches hllo and heeeello
h[ae]llo matches hello and hallo, but not hillo
h[^e]llo matches hallo, hbllo, ... but not hello
h[a-b]llo matches hallo and hbllo
加入 ACL rules
``` sh
# 認證
> AUTH 1qaz@WSX
OK
# 把 * 加入 KEY 的 pattern
> ACL SETUSER JC ~*
OK
```
使用 `GET` command 成功
``` SH
# 認證 JC
> AUTH JC Temp4321
OK
# 使用 GET command
> GET Taipei
"Tenlong"
```
移除 Key
``` SH
# 認證
> AUTH 1qaz@WSX
OK
# 把 * 從 JC 的 KEYS 移除
> ACL SETUSER JC ~* resetkeys
OK
# 認證 JC
> AUTH JC Temp4321
OK
> GET Taipei
(error) NOPERM this user has no permissions to access one of the keys used as arguments
```
### CATEGORY
使用 `+@<category>`
依據分類來給予權限, Redis 的分類可以參考
CATEGORY 是比 COMMAND 大的 scope, 如果用 `ACL read` 可以看到屬於 read CATEGORY 的 COMMAND
``` SH
# 顯示大分類
> ACL CAT
1) "keyspace"
2) "read"
3) "write"
4) "set"
5) "sortedset"
6) "list"
7) "hash"
8) "string"
9) "bitmap"
10) "hyperloglog"
11) "geo"
12) "stream"
13) "pubsub"
14) "admin"
15) "fast"
16) "slow"
17) "blocking"
18) "dangerous"
19) "connection"
20) "transaction"
21) "scripting"
# 顯示 read CATEGORY 的 COMMAND
> ACL CAT read
1) "zrevrange"
2) "zlexcount"
3) "getrange"
4) "zrangebyscore"
5) "zrevrangebylex"
6) "zscore"
7) "zrevrangebyscore"
8) "hget"
9) "sunion"
10) "exists"
11) "zrangebylex"
12) "hmget"
13) "hvals"
14) "lrange"
15) "zrange"
16) "hkeys"
17) "get"
...
```
## 使用時機
### 官方說明
* You want to improve security by restricting the access to commands and keys, so that untrusted clients have no access and trusted clients have just the minimum access level to the database in order to perform the work needed. For instance certain clients may just be able to execute read only commands.
* You want to improve operational safety, so that processes or humans accessing Redis are not allowed, because of software errors or manual mistakes, to damage the data or the configuration. For instance there is no reason for a worker that fetches delayed jobs from Redis to be able to call the FLUSHALL command.
其實都是在防止 redis client, 所以 ACL 的設定應該是 service scope 的設定, 如:
* CAS server 可以有 `SET` 以及 `GET` 的 command 權限, 並且可以 access key prefix `~cas:*`
* CAS client 只能有 `GET` 的 command 權限, 並且可以 access key prefix `~cas:{clientName}`
## 注意
* Redis 版本必須是 6 以上
* 確認 Redis 相關 package 有支援 username (noderedis 需要 3.1.0 版本以上才有)
* Redis cluster mode slaver 都只能使用 read categroy 的 command
* npm redis client 需要開以下權限:
> INFO
> EVAL (走 LUA script)
* 當 User 被 grant EVAL 的 command, 即使其他 command (例如: get, set...) 沒有被 grant, 在 EVAL 內都可以被執行(可以確認).
* Grant 權限的方式盡量以 command 以及 keys pattern 為主, 使用到 category level grant, 因為 category 底下的 command 可能會隨著版本而有增加, 一旦 category 的 command 增加, 被 grant 的 user 就會自動新增新的 command 的權限
## 參考
> [ACL doc](https://redis.io/topics/acl)
> [Set ACL user](https://redis.io/commands/acl-setuser)
> [ACL category](https://redis.io/commands/acl-cat)
> [ACL log](https://redis.io/commands/acl-log)
> [KEYS pattern](https://redis.io/commands/KEYS)