[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
: 해시 관련 커맨드hyperloglog
fast
: 빠른 O(1) 커맨드. argument에 따라 반복이 될 순 있지만 key의 개수에 영향을 받지 않음keyspace
: key, database를 읽고 쓰거나 메타데이터에 연관된 커맨드.DEL
,RESTORE
,DUMP
,RENAME
,EXISTS
,DBSIZE
,KEYS
,EXPIRE
,TTL
등의 커맨드가 해당된다list
: 리스트 자료구조 관련 커맨드pubsub
read
: 키 값 또는 메타데이터를 읽는 커맨드scripting
set
: 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 파일 경로는 위와 같은 형식으로 쓰면 된다