[Redis] ACL

[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

ACL
Redis Access Control List

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을 추가해보자

유저는 두가지 방법으로 등록이 가능하다

  1. ACL SETUSER 커맨드로 추가하기
  2. 파일에서 읽기 (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을 설정으로 관리하는 방법은 두가지 방법이 있다

  1. redis.conf 안에 직접 넣기
  2. 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 파일 경로는 위와 같은 형식으로 쓰면 된다

Reference

ACL
Redis Access Control List