Redis ACL Access Control List

Redis Server Course Redis Technical Support Redis Enterprise Server

Redis ACL (Access Control List/접근 제어)

개요 槪要 Outline

ACL(Access Control List/접근 제어)은 사용자 관리 명령입니다. 사용자를 만들고 암호(password)를 지정하고 실행 가능한 명령을 지정할 수 있습니다.

사용자 등록 SETUSER

  • ACL SETUSER user on >password allkeys allcommands
  • 127.0.0.1:6379> ACL SETUSER user on >password allkeys allcommands
    OK
    127.0.0.1:6379> ACL LIST
    1) "user default on nopass ~* +@all"
    2) "user user on #5e88489... ~* +@all"
  • user: user-id를 설정한다.
  • on/off: 사용 여부를 정한다. On이면 사용 가능하고, off이면 사용할 수 없다.
    Off는 사용자는 등록하지만 일단 사용하지 못하게 할 경우 또는 기존 사용자를 사용하지 못하게 할 경우 사용한다. 이 경우 새로 로그인(auth)은 할 수 없지만, 이미 로그인한 사용자의 사용을 막지는 못한다.
  • >password: 패스워드(password) 설정은 '>' 구분자 다음에 지정한다.
    패스워드는 자릿수, 숫자, 특수문자 포함 같은 제한이 없으므로 자유롭게 지정할 수 있다.
    패스워드 없이 사용하려면 nopass를 지정한다.
    패스워드를 지정했을 경우 로그인: auth user password
    패스워드를 지정하지 않았을 경우 로그인: auth user anyword <- 어떤 문자열이든 입력해도 된다.
  • allkeys: 모든 키에 대해서 사용하게 할 경우 allkeys 또는 ~*를 지정한다.
    특정 패턴(pattern)을 지정할 수 있다. 예) ~user*, ~key* 이렇게 지정하면 user 또는 key로 시작하는 키에 대해서만 사용할 수 있다.
    ~* 상태에서 특정 패턴을 지정하려면 우선 resetkeys 한 다음 지정할 수 있다.
    예) ACL SETUSER user resetkeys ~user*
    Resetkeys를 지정하면 어떠한 키도 사용할 수 없다.
    지정한 패턴은 해당 사용자(로그인한 사용자 포함)에게 즉시 적용된다.
    키 패턴을 지정하면 매 명령마다 비교하므로 성능이 떨어질 수 있다. 성능이 우선일 경우 사용에 주의하기 바랍니다.
  • allcommands: 모든 명령에 대해서 사용하게 할 경우 allcommands 또는 +@all을 지정한다.
    명령은 그룹 또는 명령으로 추가 또는 뺄 수 있다. 명령 그룹은 +@group으로 지정 가능하고 명령은 +command로 지정한다. 빼기는 -@group 또는 -command로 한다.
    지정한 명령은 해당 사용자(로그인한 사용자 포함)에게 즉시 적용된다.
    명령 그룹은 ACL CAT으로 확인하고, 그룹에 속한 명령은 ACL CAT group로 확인할 수 있다.
    Nocommands는 어떤 명령도 사용할 수 없다. -@all과 같다.
  • ACL SETUSER 명령은 페스워드가 있기 때문에 로그를 남기지 않는다.

사용자 조회 GETUSER

  • ACL GETUSER user
  • 127.0.0.1:6379> ACL GETUSER user
    1) "flags"
    2) 1) "on"
        2) "allkeys"
        3) "allcommands"
    3) "passwords"
    4) 1) "5e884898da28047151d0e56f8dc6292773603d0d6aabbdd62a11ef721d1542d8"
    5) "commands"
    6) "+@all"
    7) "keys"
    8) 1) "*"
  • flags: on|off/allkeys/allcommands/nopass
    on|off: on 또는 off 표시
    allkeys: 모든 키를 사용할 수 있는 경우 표시
    allcommands: 모든 명령을 사용할 수 있는 경우 표시
    nopass: 패스워드가 필요 없는 경우 표시
    Allkeys 또는 allcommands이면 flag만으로 사용 여부를 확인할 수 있으므로 성능면에서 유리하다.
  • passwords: 패스워드가 있으면 위와 같이 표시되고 없으면 "(empty array)"가 표시된다.
  • commands: 모든 명령을 사용 가능할 경우 "+@all"가 표시되고 일부만 사용 가능할 경우 해당 그룹 또는 명령 표시된다.
  • keys: 모든 키를 사용 가능할 경우 "*"가 표시되고 일부만 사용 가능할 경우 지정한 패턴이 표시된다.

사용자 삭제 DELUSER

  • ACL DELUSER user
  • 127.0.0.1:6379> ACL DELUSER user
    (integer) 1
  • 사용자를 삭제합니다. 현재 로그인한 사용자에게는 적용되지 않습니다.
  • Default user는 삭제할 수 없습니다.

본인 확인 WHOAMI

  • ACL WHOAMI
  • 127.0.0.1:6379> ACL WHOAMI
    user
  • 로그인한 사용자 본인의 user-id를 보여줍니다.

사용자 리스트 조회 USERS

  • ACL USERS
  • 127.0.0.1:6379> ACL USERS
    1) default
    2) user
  • 사용자 user-id 리스트를 보여줍니다.

사용자 정보 리스트 조회 LIST

  • ACL LIST
  • 127.0.0.1:6379> ACL LIST
    1) "user default on nopass ~* +@all"
    2) "user user on #5e884898da28047151d0e56f8dc6292773603d0d6aabbdd62a11ef721d1542d8 ~* +@all"
  • 조회된 정보는 ACL GETUSER와 비슷하다.

사용자 정보 저장 SAVE

  • ACL SAVE
  • 127.0.0.1:6379> ACL SAVE
    OK
  • 사용자 정보를 aclfile에 저장한다. Aclfile은 redis.conf 파일에 지정한다.
  • Aclfile은 config get 명령으로 조회할 수 있으나 config set 명령으로 지정할 수는 없다. 그러므로 redis.conf 파일에 지정해야 한다. 지정한 파일이 없으면 레디스 서버가 시작할 수 없으므로 처음에는 빈 파일이라도 놓아야 한다.
  • 저장하는 사용자 정보는 ACL LIST와 같다.

사용자 정보 로드 LOAD

  • ACL LOAD
  • 127.0.0.1:6379> ACL LOAD
    OK
  • Aclfile에서 사용자 정보를 로드한다. 물론 레디스 서버가 시작할 때 로드한다. Aclfile을 수기로 작성했을 경우 또는 다른 서버에서 생성한 파일을 이용할 경우 사용한다.

명령 그룹 조회 CAT

  • ACL CAT
  • 127.0.0.1:6379> 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"
  • keyspace: del, expire, flushdb, keys, ttl, scan 등
  • read: get, lrange, smembers, zrange, hget, xrange 등
  • write: set, lpush, sadd, zadd, hset, xadd 등
  • set: sadd, scard, srem, spop 등
  • sortedset: zadd, zcard, srem, zpopmin 등
  • list: lpush, llen, lrem, lpop 등
  • hash: hset, hlen, ldel, hget 등
  • string: set, get, incr 등
  • bitmap: setbit, bitop, getbit 등
  • hyperloglog: pfadd, pfmerge, pfcount, pfselftest
  • geo: geoadd, geodist, georadius 등
  • stream: xadd, xlen, xrange, xdel 등
  • pubsub: publish, subscribe, pubsub 등
  • admin: bgsave, config, debug, shutdown 등
    Admin 명령은 dangerous 그룹에 포함된다.
  • fast: get, lpush, hget 등
  • slow: lrem, mset, save 등
  • blocking: blpop, brpop, brpoplpush, bzpopmin, bzpopmax, xread, xreadgroup
  • dangerous: flushdb, keys, shutdown, info, client 등
  • connection: hello, client, auth, echo, ping, command
  • transaction: watch, multi, unwatch, discard, exec
  • scripting: evalsha, eval, script

각 명령이 어느 그룹에 속하는지는 "command info 명령"을 사용해서 확인할 수 있다. 예를 들면, SET 명령은 write, string, slow이고, GET 명령은 read, string, fast이다.

패스워드 생성 GENPASS

  • ACL GENPASS [<bits>]
  • 127.0.0.1:6379> ACL GENPASS
    "49ca9a888aef783f1f61fba6576e40f3a86f01fed022f2d4a37d274b58574ac1" <- 64
    127.0.0.1:6379> ACL GENPASS 128
    "de01ed9faeeb36445de6dadccf68dd74" <- 32
    127.0.0.1:6379> ACL GENPASS 64
    "e2dc8c4c119e61b7" <- 16
  • 디폴트로 64바이트 문자열로 패스워드를 생성한다. 옵션(비트수)을 지정해서 생성되는 패스워드 문자수를 조절할 수 있다.

암호화 알고리즘 SHA-256

암호화 알고리즘으로 SHA-256을 사용한다. 이 알고리즘은 동일한 패스워드는 항상 동일한 해시값을 만들어낸다. 다른 알고리즘인 blowfish의 경우 동일한 패스워드에도 다른 해시값을 만들어내므로 해킹이 더 어렵다.

ACL(Auth) 로그

  • ACL LOG [<count> | RESET]
  • 실패한 로그인(auth) 정보를 조회한다.
    127.0.0.1:6379> AUTH user1 a
    (error) WRONGPASS invalid username-password pair
    127.0.0.1:6379> ACL LOG
    1) 1) "count"
    2) (integer) 1
    3) "reason"
    4) "auth"
    5) "context"
    6) "toplevel"
    7) "object"
    8) "auth"
    9) "username"
    10) "user1"
    11) "age-seconds"
    12) "2.2170000000000001"
    13) "client-info"
    14) "id=4 addr=127.0.0.1:45542 fd=8 name= age=3213 idle=0 flags=N db=0 sub=0 psub=0 multi=-1 qbuf=32 qbuf-free=32736 obl=0 oll=0 omem=0 events=r cmd=auth user=user1"

ACL 활용

로그인(AUTH)

  • AUTH user password: client list로 조회하면 마지막 항목에 user가 나온다.
  • AUTH password: 이 경우 user는 default이다. Client list -> user=default

ACL 사용

  • Aclfile을 만들고 redis.conf 파일에 aclfile을 지정한다.
  • Requirepass: aclfile 없이 requirepass를 지정하면 default user의 패스워드가 된다.
    Aclfile이 있으면 requirepass는 무시되고 aclfile이 적용된다.
  • 관리자 user 설정: ACL SETUSER admin on >password allkeys allcommands
  • 조회 user 설정: ACL SETUSER reader on >password allkeys +@read
  • Read/Write 가능한 일반 사용자 설정: ACL SETUSER writer on >password allkeys allcommands -@dangerous
  • 127.0.0.1:6379> acl list
    1) "user admin on #5e8848... ~* +@all"
    2) "user default on #d74ff0... ~* +@all"
    3) "user reader on #5e8848... ~* -@all +@read +@hash +@geo -hmset -hsetnx -hdel -georadius -hincrbyfloat -hset -georadiusbymember -hincrby -geoadd"
    4) "user writer on #5e8848... ~* +@all -@admin -@dangerous"

복제(replica)와 ACL

  • 마스터와 복제 노드의 redis.conf에 masteruser와 masterauth를 설정한다. Masteruser와 masterauth는 aclfile에 지정한 권한 있는 사용자를 사용한다.
    예) masteruser admin, masterauth password
  • 마스터와 복제 노드에 동일한 aclfile을 사용한다.

센티널(sentinel)과 ACL

  • sentinel.conf 파일에 sentinel auth-user <master-name> <username>를 지정한다. 이것은 sentinel auth-pass 파라미터와 짝을 이루어 레디스 서버를 모니터하고 장애조치(failover)하는데 사용된다.
    레디스 서버에 같은 user와 password가 적용되어 있어야 한다.

레디스 클러스터(cluster)와 ACL

  • 클러스터는 아직 ACL을 지원하지 않는다. 클러스터를 구성할 수는 있으나 마스터 다운 시 failover가 진행되지 않는다.

ACL 사용하지 않기

  • Aclfile을 지정하지 않는다.

서브명령(subcommand)에 권한 부여하기

  • Client 명령은 getname, setname, list, kill 등 여러 가지 서브명령이 있는데, 이중 getname과 setname의 실행 권한을 줄 경우, 왜냐하면 kill 권한을 주면 다른 client를 죽일 수 있기 때문이다.
    ACL SETUSER reader +client|getname
    ACL SETUSER reader +client|setname
  • 서브명령 2개를 같이 지정할 수는 없다.
    ACL SETUSER reader +client|getname|setname <- 이렇게 안된다.
  • 빼기는 할 수 없다.
    ACL SETUSER reader -client|getname <- 이렇게 안된다.
  • 서브명령이 유효한지 검사하지 않는다.
    ACL SETUSER reader +client|aaa
  • Client setname 권한만 필요하다면 hello 명령 권한을 주는 것이 더 간단하다.
  • ver 6.0-rc1 기준으로 서브명령 사용은 완전히 구현되어 있지 않다.
    CLIENT, CONFIG, SCRIPT 같이 키를 사용하지 않는 몇 개 명령만 사용할 수 있다.

    사용 여부 비교가 argv[1]을 비교하는데, 이것은 client list 같은 경우는 적용되지만 set key value nx 같은 (대부분의 명령이 이렇다) 경우는 서브명령이 argv[3]에 있으므로 사용할 수 없다고 나온다.
    ACLCheckCommandPerm() acl.c
    if (!strcasecmp(c->argv[1]->ptr, u->allowed_subcommands[id][subid]))

패스워드에 관한 추가 정보

  • 한 사용자(user)에게 패스워드를 여러 개 지정할 수 있다.
    ACL SETUSER reader >password1
    ACL SETUSER reader >password2
  • 지정한 패스워드를 지울 때
    ACL SETUSER reader <password2
  • 패스워드를 모두 지울때
    ACL SETUSER reader resetpass
    해당 사용자에게 지정한 모든 패스워드를 삭제한다. 이렇게 하면 패스워드가 없기 때문에 로그인 할 수 없다.
    ACL LIST로 보면 password 항목에 아무것도 표시되지 않는다.
  • 패스워드 없이 사용하고자 할 때
    ACL SETUSER reader nopass
    이렇게 하면 로그인(auth)할 때 어떤 문자(열)을 넣어도 된다. 예) auth reader any
    ACL LIST로 보면 password 항목에 nopass로 표시된다.
  • 해시값으로 패스워드 추가할 때
    ACL SETUSER reader #5e884898da28047151d0e56f8dc6292773603d0d6aabbdd62a11ef721d1542d8 이렇게 하면 평문(plaintext) 패스워드를 감출 수 있다.
  • 해시값으로 패스워드 지울 때
    ACL SETUSER reader !5e884898da28047151d0e56f8dc6292773603d0d6aabbdd62a11ef721d1542d8

RESET

  • ACL SETUSER RESET: off, resetpass, resetkeys, nocommands가 적용된다. 즉, 사용자의 모든 권한을 제거할 때 사용한다.
    Reset 후 사용자 정보: user user1 off -@all
    Off는 이미 로그인(auth)한 사용자에게는 적용되지 않지만 resetkeys와 nocommands는 즉시 적용된다.

ACL 내부 구조

사용자별 명령(command) 사용 여부 설정과 확인

사용자마다 사용 가능 명령 리스트를 만들고, 명령이 실행될 때마다 문자열 비교를 한다면 성능에 문제가 생길 수도 있을 것이다. 레디스에서는 어떻게 처리했는지 알아보자.

  • 레디스 서버가 시작(initServerConfig)할 때 각 명령(command)에 0번 부터 id를 부여한다. 이때 rax(radix tree 기수 트리) 구조체에 명령어(command name)을 넣으면서(insert) id를 부여한다. Rax에 명령어를 key로 넣으므로 실수로 같은 명령을 두번 넣어도 하나의 id만 부여된다.
    예) ver 6.0 기준: 202개 명령 Command id 부여 ACLGetCommandID() acl.c
    module -> 0
    get -> 1
    set -> 2
    ...
    acl -> 201
  • 사용자별로 특정 명령을 추가하면(acl setuser user +get) allowed_commands 배열에 해당 비트를 1로 설정한다.
  • 명령을 실행하면 ACLCheckCommandPerm()을 수행해서 command->id와 user->allowed_commands[word]의 bit를 비교 사용여부를 정한다.

사용자 설정: struct user

  • sds name: user name
  • uint64_t flags: flag 참조
  • 4 bit 3 bit 2 bit 1 bit 0 bit
    no pass all commands all keys off on
    USER_FLAG_ENABLED (1<<0)
    USER_FLAG_DISABLED (1<<1)
    USER_FLAG_ALLKEYS (1<<2)
    USER_FLAG_ALLCOMMANDS (1<<3)
    USER_FLAG_NOPASS (1<<4)
    if (user->flags & USER_FLAG_ENABLED) then
  • uint64_t allowed_commands[16]: 사용자별로 사용 가능한 명령을 비트(bit) 단위로 설정한다. 6.0 기준 202개다. 배열 하나가 8바이트(64비트)이므로 64*16=1024개 명령을 저장할 수 있다.
  • allowed_commands[0] 0~63
    63 bit 62 bit * bit 1 bit 0 bit
    zrangebylex zrevrangebyscore ... get module
    allowed_commands[1] 64~127
    63 bit 62 bit * bit 1 bit 0 bit
    flushall flushdb ... zcount zrevrangebylex
    allowed_commands[2] 128~191
    63 bit 62 bit * bit 1 bit 0 bit
    xack xsetid ... info sort
    allowed_commands[3] 192~201
    9 bit 8 bit * bit 1 bit 0 bit
    acl lolwut ... xclaim xpending
  • sds **allowed_subcommands: command 배열 -> subcommand 배열
  • allowed_subcommands
    cmd->id 0: module
    ...
    cmd->id 158: client
    ...
    1023



    ------->


    SET subcommands
    0: getname
    1: setname
    2: list
    if (!strcasecmp(c->argv[1]->ptr, u->allowed_subcommands[id][subid]))
  • list *passwords: 패스워드 리스트, 한 사용자가 여러개의 패스워드를 가질 수 있다.
  • list *patterns: 키 패턴 리스트, stringmatchlen()로 비교한다.

동영상 강의


명령문 Command

ACL [SETUSER|GETUSER|DELUSER|WHOAMI|USERS|LIST|SAVE|LOAD|CAT|GENPASS|LOG]

  • 이 명령은 버전 6.0.0부터 사용할 수 있다.
  • 이 문서는 버전 6.0.1을 기준으로 만들었다.

<< Server Cmds Intro ACL PROTECTED-MODE >>

조회수 :

Email 답글이 올라오면 이메일로 알려드리겠습니다.