[Redis] ACL
Redis ACL(Access Control List, 액세스 컨트롤 리스트)을 사용해 커넥션이 실행할 수 있는 명령과 액세스할 수 있는 키를 제한할 수 있다.
예를 들어 FLUSHALL같은 위험한 명령어는 실수로라도 입력될 수 없도록 막을 수도 있으며, 여러 부서나 모듈이 공유하는 Redis에서 차이니즈월을 만드는 것도 ACL로 할 수 있다.
ACL은 Redis 6 이상부터 사용할 수 있다
$ docker run --name test-redis -d -p 6379:6379 redis
$ redis-cli
참고로 로컬에 도커로 redis를 띄우고, 접속은 redis-cli를 받아서(맥이라면 brew install redis) 하면 테스트하기 편하다
ACL 구성
127.0.0.1:6379> ACL LIST
1) "user default on nopass ~* &* +@all"
ACL LIST를 이용해 현재 등록된 ACL을 확인할 수 있다. 기본 설정은 위와 같다.
ACL은 DSL(domain specific language)을 사용해 정의되며, 첫번째부터 마지막 / 왼쪽에서 오른쪽 순서로 읽는다.
기본으로 등록된 ACL의 구성을 알아보면 아래와 같다.
user default: 맨 처음 두 단어는user {유저명}을 나타낸다.on: 유저를 사용한다nopass: 패스워드가 없어도 된다~*: 모든 키에 접근 가능&*: 모든 Pub/Sub 채널에 접근 가능+@all: 모든 커맨드 사용 가능
각 항목별로 더 자세히 알아보자
User
on: 유저를 사용한다.off: 유저를 허용하지 않는다 (AUTH가 되지 않는다)- 이미 인증이 끝난 커넥션엔 영향을 주지 못한다
Commands
+<command>: 유저가 사용할 수 있는 커맨드로 추가한다. 파이프(|)를 이용해 서브커맨드를 명시할 수 있다. (ex.+config|get)-<command>: 유저가 사용할 수 있는 커맨드에서 제외한다. 파이프를 이용해 서브커맨드를 명시할 수 있다.+@<category>: 특정 카테고리의 커맨드를 사용 가능한 커맨드로 전부 추가한다. (ex.@admin,@set,@sortedset등) 전체 카테고리 목록은ACL CAT으로 확인할 수 있다.@all은 모든 커맨드에 해당된다-@<category>: 특정 카테고리의 커맨드를 사용할 수 있는 커맨드에서 제외한다+<command>|first-arg(deprecated): 커맨드와 특정 매개변수 조합만 허용한다. sub command가 없는 커맨드에만 사용할 수 있다. negative 형태는 사용할 수 없다.allcommands:+@all과 동일nocommands:-@all과 동일
Key
~<pattern>: 특정 패턴의 키를 커맨드에서 사용할 수 있도록 한다. 패턴은 glob이다. 예를 들어~*는 모든 키에 해당된다.%R~<pattern>: (Redis 7.0 이상) 특정 패턴에 해당되는 키를 읽을 수 있는 권한을 추가한다%W~<pattern>: (Redis 7.0 이상) 특정 패턴에 해당되는 키를 쓸 수 있는 권한을 추가한다%RW~<pattern>: (Redis 7.0 이상)~<pattern>과 동일allkeys:~*와 동일resetkeys: 허용된 키 패턴 목록을 초기화한다. 예를 들어~foo:* ~bar:* resetkeys ~objects:*형식의 ACL은 맨 오른쪽에 있는~objects:*만 허용한다.
키의 Read/Write permission에 관한 더 자세한 내용은 https://redis.io/docs/management/security/acl/#key-permissions 링크를 참고하자.
Pub/Sub channels
&<pattern>: 액세스할 수 있는 Pub/Sub 채널을 glob 스타일 패턴으로 추가한다.allchannels:&*와 동일resetchannels: 허용된 채널 목록을 초기화한다.
Password
><password>: 유저가 사용 가능한 패스워드로<password>를 추가한다. 예를 들어>mypass는 유저 패스워드로 mypass를 추가한다. 한 유저가 여러 패스워드를 사용할 수 있다.<<password>: 유저가 사용 가능한 패스워드에서<password>를 제거한다.#<hash>: SHA-256 해시를 유저가 사용 가능한 패스워드로 추가한다.!<hash>: 유저가 사용 가능한 패스워드에서 SHA-256 해시를 제거한다.nopass: 유저 패스워드를 모두 제거하고, 패스워드 없이 로그인할 수 있도록 한다.resetpass: 등록된 모든 사용 가능한 패스워드를 제거하고nopass상태도 제거한다.resetpass이후에 패스워드를 등록하거나nopass를 등록해야 로그인할 수 있다.
Configure selector
Redis 7.0부터 ACL 룰을 Selector(셀렉터)라고 하는 여러 룰의 집합으로 그룹화할 수 있다.
(<rule list>): (Redis 7.0 이상) 룰에 해당되는 Selector를 만든다. Selector는 유저 권한 다음으로 계산되며, 정의된 순서에 따라 계산된다. 커맨드는 사용자 권한 또는 아무 Selector에 매칭되는 경우 실행된다.clearselectors: (Redis 7.0 이상) 유저에게 등록된 모든 selector를 제거한다
Reset user
reset: 유저를 생성 직후 상태와 동일하도록 초기화한다. resetpass, resetkeys, resetchannels, allchannels, off, clearselectors, -@all 을 실행한 것과 동일하다.
Command Categories
레디스 커맨드들은 여러 카테고리에 속해 있다. 카테고리 단위 ACL을 부여하는 것이 가능하다. 예를 들면 @slow 카테고리에 해당되는 커맨드를 사용할 수 없도록 할 수 있다.
커맨드 카테고리들은 아래와 같다
admin: 관리용 커맨드이며, 일반적인 어플리케이션은 사용할 일이 없는 커맨드다.REPLICAOF,CONFIG,DEBUG,SAVE,MONITOR,ACL,SHUTDOWN등의 커맨드가 해당된다bitmap: 비트맵 자료구조 관련 커맨드blocking: 다른 커맨드가 불리기 전까지 커넥션을 블락킹할 수 있는 커맨드.BLPOP등의 명령어가 해당된다connection: 현재 커넥션 또는 다른 커넥션에 영향을 줄 수 있는 커맨드dangerous: 잠재적으로 매우 위험한 커맨드.FLUSHALL,MIGRATE,RESTORE,KEYS등의 커맨드가 해당된다geo: 지리적 자료구조 관련 커맨드hash: 해시 관련 커맨드hyperloglogfast: 빠른 O(1) 커맨드. argument에 따라 반복이 될 순 있지만 key의 개수에 영향을 받지 않음keyspace: key, database를 읽고 쓰거나 메타데이터에 연관된 커맨드.DEL,RESTORE,DUMP,RENAME,EXISTS,DBSIZE,KEYS,EXPIRE,TTL등의 커맨드가 해당된다list: 리스트 자료구조 관련 커맨드pubsubread: 키 값 또는 메타데이터를 읽는 커맨드scriptingset: set 자료구조 관련 커맨드sortedset: 정렬된 set 자료구조(=zset) 관련 커맨드slow:fast가 아닌 모든 커맨드stream: 스트림 관련 커맨드string: 문자열 관련 커맨드transaction:WATCH/MULTI/EXEC관련 커맨드write: 키 값 또는 메타데이터를 쓰는 커맨드
한 커맨드가 여러 카테고리에 해당될 수 있다. (ex. SADD: @write, @set, @fast)
긴 설명이 끝났다. 이제 직접 ACL을 추가해보자
유저는 두가지 방법으로 등록이 가능하다
- ACL SETUSER 커맨드로 추가하기
- 파일에서 읽기 (ACL LOAD)
1) ACL SETUSER
> ACL SETUSER alice
OK
ACL SETUSER 커맨드는 유저명과 적용될 ACL 룰을 입력받는다. 유저명만 입력하면 기본값이 적용되고, 이미 유저가 존재하는 경우 아무 작업도 수행하지 않는다.
> ACL LIST
1) "user alice off resetchannels -@all"
2) "user default on nopass ~* &* +@all"
유저를 만들면 기본적인 ACL은 위와 같다.
- off 상태이다 - AUTH 커맨드를 사용할 수 없다
- 비밀번호가 설정되어 있지 않다
- 어떤 커맨드도 사용할 수 없다
- 접근 가능한 키 패턴이 없다
- 접근 가능한 Pub/Sub 채널이 없다
즉 기본적으로는 권한이 막힌 상태로 생성된다.
이제 권한을 부여해보자. "cached:" 문자열로 시작되는 키에 GET 커맨드만 사용할 수 있도록 해보겠다.
> ACL SETUSER alice on >mypass ~cached:* +get
OK
위처럼 추가할 수 있다.
> AUTH alice mypass
OK
> GET foo
(error) NOPERM this user has no permissions to access one of the keys used as arguments
> GET cached:1234
(nil)
> SET cached:1234 zap
(error) NOPERM this user has no permissions to run the 'set' command
의도대로 권한이 없는 키나 동작은 NOPERM 에러가 나오는 것을 확인할 수 있다.
> ACL GETUSER alice
1) "flags"
2) 1) "on"
3) "passwords"
4) 1) "ea71c25a7a602246b4c39824b855678894a96f43bb9b71319c39700a1e045222"
5) "commands"
6) "-@all +get"
7) "keys"
8) "~cached:*"
9) "channels"
10) ""
11) "selectors"
12) (empty array)
ACL GETUSER로 유저 권한을 좀 더 읽기 편하게 볼 수 있다.
> ACL GETUSER alice
1# "flags" => 1~ "on"
2# "passwords" => 1) "2d9c75273d72b32df726fb545c8a4edc719f0a95a6fd993950b10c474ad9c927"
3# "commands" => "-@all +get"
4# "keys" => "~cached:*"
5# "channels" => ""
6# "selectors" => (empty array)
RESP3으로 보면 이렇게 나온다. (https://redis.io/commands/hello/ 참고)
> ACL SETUSER alice ~objects:* ~items:* ~public:*
OK
한번에 여러 키 패턴을 추가하는 것도 가능하다
> ACL SETUSER myuser +set
OK
> ACL SETUSER myuser +get
OK
> ACL LIST
1) "user default on nopass ~* &* +@all"
2) "user myuser off resetchannels -@all +get +set"
ACL SETUSER 명령어는 ACL을 유저에게 적용하는 것이기 때문에, 호출할 때마다 리셋되는 것이 아니라는 것에 유의해야 한다.
2) ACL LOAD
ACL을 설정으로 관리하는 방법은 두가지 방법이 있다
- redis.conf 안에 직접 넣기
- redis.conf에 "aclfile"로 path 넣기
두 방법중 하나를 골라야한다
ACL을 정의하는 방법은 똑같고, 위치만 다르다고 보면 된다.
user <username> ... acl rules ...
위 형식으로 쓰면 되고, 예를 들면
user worker +@list +@connection ~jobs:* on >ffa9203c493aa99
worker라는 유저에 list, connection 카테고리 커맨드를 허용하고, jobs:로 시작하는 키의 접근권한을 주며 SHA-256 해시가 ffa9203c493aa99 인 비밀번호를 등록하는 ACL은 위와 같다.
aclfile /etc/redis/users.acl
ACL 파일 경로는 위와 같은 형식으로 쓰면 된다
