Redis Connection IP Control   클라이언트 접속 IP 통제

<< Info Hits, Misses Login >>

클라이언트 접속 IP 통제 기능 설명

시작

이 기능은 IP 기반의 접근 제어 목록(Access Control List, ACL) 기능을 구현하고 싶은데 조언을 구하는 요청에 의해서 만들어졌습니다.   요청해 주신 분께 감사드립니다.

접속 IP 통제 기능은 레디스 서버에 원래 있는 기능이 아니고, 레디스게이트에서 개발한 것이다.

클라이언트가 레디스 서버에 접속할 때 접속 IP를 확인해서 접속 허용 IP 목록에 있는 클라이언트는 접속을 허용하고, 목록에 없는 IP는 접속을 불허해서 명령을 실행할 수 없게 했다.

이 프로그램 소스와 문서는 버전 3.2.0을 기준으로 만들었다.

설명 동영상


처리 과정

  1. IP 리스트를 파일에 등록한다.   파일명은 iplist.txt이다.   이 파일은 작업 디렉터리(working directory)에 놓는다.
  2. 레디스 서버가 시작할 때 서버는 작업 디렉토리에서 IP 리스트 파일을 읽어서 메모리에 저장한다.   소스 보기
  3. 접속 통제 기능: 클라이언트가 접속하면 서버는 접속 IP와 서버에 있는 IP를 비교해서 있으면 접속을 허용하고, 없으면 허용하지 않는다.   소스 보기
  4. 서버 실행중에 IP 리스트가 변경되어도, 서버 재 시작 없어 debug reload-iplist 명령으로 IP 리스트를 변경할 수 있다.   소스 보기
  5. 명령 실행 통제 기능: 명령 실행 시마다 IP를 확인하는 기능이 있다.   이미 접속한 클라이언트도 서버에서 접속 허용 IP 리스트를 재 로드하면, 명령 실행 시 IP를 확인해서 IP 리스트에 없으면 명령을 실행할 수 없게 한다.   소스 보기
  6. 서버 메모리에 등록된 IP 리스트를 debug iplist 명령으로 조회해 볼 수 있다.   소스 보기
  7. redis.conf 파일에 파라미터 2개를 등록해서 접속 허용, 명령 실행 허용을 설정할 수 있다.   소스 보기
    perm-iplist-connect-enabled : 접속 허용 여부 설정 yes/no
    perm-iplist-command-enabled : 명령 실행 허용 여부 설정 yes/no
  8. 이 파라미터 2개는 config get/set 명령으로 조회할 수 있고, 설정할 수 있다.   소스 보기
  9. config rewrite 명령으로 위에 두 파라미터도 정상적으로 rewrite 된다.   소스 보기
  10. Data Structure : Dictionary(Hash Table)과 List로 구현했다.   소스 보기
  11. 나머지 소스       소스 시작 부분으로 가기

성능

클라이언트가 처음 접속 시 IP를 확인하는 부분(접속 IP 통제)이나, 명령 실행 시마다 IP를 확인하는 부분(명령 실행 통제) 모두 IP를 확인하는데 테스트 서버에서 1마이크로 초(microsecond) 정도 시간에 처리됩니다.   접속 IP 통제 기능은 당연히 사용할 것이지만, 명령 실행 통제 기능은 매 명령마다 IP를 확인하므로 성능을 고려해서 사용하시기 바랍니다.

  • 테스트 서버 Spec
  • OS : CentOS 7
    H/W Model: HP DL320e Gen8 v2
    Processor : Intel Xeon E3-1231V3.3 3.4GHz
    Main Memory: DDR3 8GB RAM

적용

레디스 센티널 적용: 마스터, 슬레이브, 센티널 서버의 IP를 iplist.txt에 등록한다.
레디스 클러스터 적용: 클러스터를 구성하는 모든 마스터, 슬레이브 서버를 iplist.txt에 등록한다.


1. 접속 허용 IP 리스트       목차로 가기

파일명은 iplist.txt이어야 하고, redis.conf 파일에서 설정한 작업 디렉터리(working directory)에 있어야 한다.

  • 아래는 접속 허용 IP 리스트 파일 예제이다.
  • # 이것은 허용 IP list 파일입니다.
    # 여기에 있는 IP들 만이 redis server에 접속할 수 있습니다.
    # 이 파일명은 iplist.txt로 고정되어 있고, 레디스 working directory에 있어야 합니다.
    # '#'으로 시작하면 주석(comment)입니다.
    # IP는 IP 그대로 입력할 수 있고, glob-style로 입력할 수 있습니다.
    #
    # IP 그대로 입력한 경우
    # 127.10.10.123
    # 127.10.10.124
    #
    # Glob-style로 입력한 경우
    # 127.20.30.* : 127.20.30.으로 시작하는 IP를 허용합니다.
    # 127.20.40.? : 127.20.40.0 ~ 127.20.40.9까지의 IP를 허용합니다.
    # 127.20.50.1* : 127.20.50.1로 시작하는 IP를 허용합니다.
    # 127.20.60.1? : 127.20.60.10 ~ 127.20.60.19까지의 IP를 허용합니다.
    # 127.20.70.11[1-5] : 127.20.70.111 ~ 128.20.70.115까지의 IP를 허용합니다.
    # 127.20.70.2[1-5]8 : 127.20.70.218, 228, 238, 248, 258 IP를 허용합니다.
    # 127.30.*.* : 세 번째, 네 번째 단위를 허용하는 경우.
    # 127.30.* : dot가 2개 이어서 적정한 IP 형태가 아니라고 판단해서
    # 에러를 내보내고 서버가 중지합니다.
    #
    # Glob-style 주의사항
    # 127.30.*.111로 입력한 경우 127.30.으로 시작하는 모든 IP를 허용합니다.
    # 마지막 111은 무시됩니다.
    # 127.30.* : 세 번째, 네 번째 단위를 허용하는 경우 이렇게 입력하면 에러 납니다.
    # 위에서처럼 127.30.*.*으로 입력하세요.
    #
    # '^'는 허용하지 않습니다. Glob-style에서는 허용하지만, IP check에서는 허용하지 않습니다.
    # '\'으로 시작하는 특수문자도 허용하지 않습니다.
    #
    # 주의 사항
    # 1) 적정한 IP 형태가 아니면 Redis Server가 에러는 내보내고 시작하지 않습니다.
    # 2) 주석은 첫 칼럼이 '#'로 시작해야 합니다. 앞에 space를 포함하면 안됩니다.
    # 3) 주석을 포함해서 한 라인에 길이는 1024바이트까지입니다.
    # 4) 공백 라인을 허용합니다.
    # 5) IP는 앞, 뒤에 space를 포함할 수 있습니다.

    127.0.0.1

    127.10.10.1
    127.10.10.2
    127.10.10.3
    127.10.10.4
    127.10.10.5
    127.10.10.6

    127.20.30.*
    127.20.40.?
    127.20.50.1*
    127.20.60.1?
    127.20.70.11[1-5]
    127.20.70.2[1-5]8
    127.30.*.*

2. 레디스 서버 시작 시 IP 리스트 로드       목차로 가기

  • 다음은 서버 시작 시 서버 로그(redis.log)에 출력되는 내용이다.   네 번째 줄이 IP 리스트를 성공적으로 로드했다는 내용이다.
  • # Server started, Redis version 3.2.0
    * DB loaded from append only file: 0.000 seconds
    * The server is now ready to accept connections on port 6000
    * IPs loaded from iplist.txt
  • 만약 IP 리스트에 있는 IP가 형식에 맞지 않으면 다음과 같은 에러를 서버 로그에 남기고 서버는 시작되지 않는다.
  • Invalid IP in iplist.txt. Exiting

3. 접속 통제 기능       목차로 가기

  • IP 리스트에 없는 IP로 클라이언트가 접속했을 때 접속을 시도한 IP를 포함한 내용이 서버 로그(redis.log)에 기록된다.
  • 02 Jul 08:41:36.208 * IP 127.0.0.1: 불법 IP의 접속 시도가 있었습니다.
  • 해당 클라이언트에서 명령을 실행하면 다음과 같은 응답을 받는다.
  • (error) ERR 당신의 IP로는 더 이상 명령을 실행할 수 없습니다.

4. 서버 실행 중 IP 리스트 재 로드: debug reload-iplist       목차로 가기

레디스 서버 실행 중에 접속 허용 IP가 변경되어도 레디스 서버를 재 시작할 필요가 없다.   iplist.txt 파일을 수정 후 debug reload-iplist 명령으로 재 로드할 수 있다.

  • 아래는 클라이언트에서 debug reload-iplist 명령을 실행한 것이다.
  • 127.0.0.1:6000> debug reload-iplist
    OK
  • 서버 로그에는 아래 내용이 기록된다.
  • * IPs loaded by DEBUG IPLIST-RELOAD

5. 명령 실행 통제 기능       목차로 가기

  • 클라이언트가 처음 접속할 때는 IP 리스트에 있었지만, IP 리스트 재 로드 후 불법 IP가 되었다면, 명령 실행 시 IP를 확인해서 명령을 실행할 수 없게 한다.   IP 재 로드 후 처음 명령은 아래와 같은 에러 메시지를 받게 되며, 두 번째 명령을 입력하면 아무런 응답을 받지 못한다.   이것은 첫 번째 명령이후 레디스 서버에서 클라이언트와의 연결을 끊기 때문이다.
  • 127.0.0.1:6000> info
    (error) ERR 당신의 IP로는 더 이상 명령을 실행할 수 없습니다.
    127.0.0.1:6000>
    127.0.0.1:6000> set key
    ^C
  • 이 기능은 perm-iplist-comamnd-enabled 파라미터로 redis.conf 파일에 설정할 수 있고, config get 명령으로 조회하고 config set 명령으로 변경 할 수 있다.

6. IP 리스트 조회       목차로 가기

  • 레디스 서버 메모리에 저장된 IP 리스트를 조회할 수 있다.   사용 명령은 debug iplist이다.  
  • 127.0.0.1:6000> debug iplist
    1) "129.10.10.1"
    2) "129.10.10.6"
    3) "129.10.10.5"
    4) "129.10.10.3"
    5) "129.10.10.4"
    6) "127.0.0.1"
    7) "129.10.10.2"
    8) "128.10.10.*"
  • 조회되는 IP들은 파일에 입력된 순서와 다르다. 이것은 IP를 dict(hash table)에 저장하는데, hash table은 저장된 순서와 상관없이 조회되기 때문이다. Glob-style IP는 마지막에 나온다.
  • 소트된 IP을 조회하려면 debug iplist-sort 명령을 사용한다.
  • 127.0.0.1:6000> debug iplist-sort
    1) "127.0.0.1"
    2) "128.10.10.*"
    3) "129.10.10.1"
    4) "129.10.10.2"
    5) "129.10.10.3"
    6) "129.10.10.4"
    7) "129.10.10.5"
    8) "129.10.10.6"

7. 관련 파라미터 2개       목차로 가기

  • 접속 허용 여부 설정 : perm-iplist-connect-enabled     yes/no
  • 명령 실행 허용 여부 설정 : perm-iplist-command-enabled     yes/no
    '명령 실행 허용 여부' 기능은 명령이 실행될 때마다 IP를 확인하므로 처리 속도가 떨어질 수 있다.

8. 서버 실행 중 파라미터 조회와 설정       목차로 가기

  • config get perm-iplist* 명령을 사용하면 아래와 같이 조회된다.
  • 127.0.0.1:6000> config get perm-iplist*
    1) "perm-iplist-connect-enabled"
    2) "no"
    3) "perm-iplist-command-enabled"
    4) "no"
  • config set 명령으로 설정을 변경할 수 있다.
  • 127.0.0.1:6000> config set perm-iplist-connect-enabled yes
    OK

9. Config rewrite로 변경된 파라미터 저장       목차로 가기

  • 초기 redis.conf 파일 중 iplist 관련 파라미터 2개
  • perm-iplist-connect-enabled     no
    perm-iplist-command-enabled     no
  • config get 명령으로 조회하고, config set 명령으로 설정
  • 127.0.0.1:6000> config get perm-iplist*
    1) "perm-iplist-connect-enabled"
    2) "no"
    3) "perm-iplist-command-enabled"
    4) "no"
    127.0.0.1:6000> config set perm-iplist-connect-enabled yes
    OK
  • config rewrite 후 redis.conf 파일 내용
  • perm-iplist-connect-enabled     yes
    perm-iplist-command-enabled     no

10. Data Structure: Dictionary(Hash Table)와 List를 사용했다.       목차로 가기

  • 일반 IP 저장: Dictionary(줄여서 dict)을 사용했다.   Dict은 레디스 서버에서 키 관리, Sets, Hashes의 메인 자료 구조로 사용된다.   장점은 hash function을 사용하기 때문에 데이터 건수가 많아도 거의 조회시간이 거의 일정하다.
  • Dict의 자세한 자료구조는 Sets, Hashes, Common Keys 의 Data Structure : Hash Table 메뉴를 참고하세요.
  • Glob-style IP 저장: List을 사용했다.
  • 클라이언트가 접속하면 먼저 dict에서 hash function으로 찾고, 있으면 접속 허용하고, 없으면 List에서 glob-style IP를 찾는다.


라이센스와 법적 책임

  • 본 소스는 BSD 라이선스에 기반을 둡니다
  • 레디스게이트에서는 본 기능을 여러 번 테스트를 했으나 문제 발생 가능성은 있습니다.
    문제 발생에 대한 책임이 레디스게이트에 없음을 알려드립니다.

소스 파일 리스트

  • 수정 파일 목록: server.h, server.c, networking.c, config.c, debug.c, Makefile
  • 새로 작성한 파일 목록: iplist.h, iplist.c

받기(download)

위 리스트에 있는 수정 파일, 새로 작성한 파일을 zip으로 묶었습니다.   클릭해서 다운 받으세요.
본 소스는 레디스 버전 3.2.0으로 만들었습니다.
기존 3.2.0 소스에 이 파일들을 복사한 다음 make로 컴파일하세요.


소스 코드

여기에서 중요한 부분을 설명합니다. 변경되거나 추가된 소스 모두를 설명하지는 않습니다.
소스 코드 변경 시 위 받기 파일에 먼저 반영될 수 있습니다.   소스 코드 사용 시 위 zip 파일을 다운 받아 사용하세요.

1. IP 리스트 파일 등록       목차로 가기

IP 리스트 파일 등록에 대한 별도 소스는 없습니다.


2. IP 리스트 로드       목차로 가기

파일명: iplist.c
레디스 서버 시작할 때와 debug reload-iplist 명령 실행 시 IP 리스트를 iplist.txt 파일에서 읽어서 dict 구조체에 넣는 부분이다.

파일명: server.c
main()에 추가한다.
서버 main()에서 레디스 서버 시작할 때 IP 리스트를 iplist.txt 파일에서 읽어서 dict/list 구조체에 넣는 loadIplist()를 호출하는 부분이다.


3. 클라이언트 접속 시 IP 확인       목차로 가기

파일명: networking.c
클라이언트 접속 시 IP를 확인해서 접속 여부를 정한다.
acceptTcpHandler() function에 아래 소스를 추가한다.


4. debug reload-iplist      목차로 가기

파일명: debug.c
debugCommand()에 추가한다.


5. 명령 실행 통제 기능       목차로 가기

파일명: server.c
processCommand()에 추가한다.


6. debug iplist 와 debug iplist-sort       목차로 가기

파일명: debug.c
debugCommand()에 추가한다.


7. Load redis.conf file       목차로 가기

파일명: config.c
loadServerConfigFromString()에 추가한다.


8. config get/set       목차로 가기

파일명: config.c
configGetCommand()에 추가한다.

configSetCommand()에 추가한다.


9. config rewrite       목차로 가기

파일명: config.c
rewriteConfig()에 추가한다.


10. Data Structure: Dictionary(Hash table)       목차로 가기

파일명: server.c


11. 나머지 소스       목차로 가기

파일명: server.h

파일명: server.c

파일명: iplist.h


본 접속 IP 통제 기능에 대한 건의 사항이나 잘못된 점(버그) 등이 있으면 댓글을 남겨주세요.



<< Info Hits, Misses Connection IP Control Login >>

질문하거나 댓글을 보려면 클릭하세요.  댓글수 :    조회수 :

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