본문 바로가기

기타

[mongodb] docker container로 구성된 mongo cluster에 authentication 적용하기

728x90

안녕하세요 반갑습니다. 오랜만에 글을 씁니다.

 

오늘은 지난번에 구축했던 container로 구성한 mongo cluster에 authentication을 적용해보겠습니다.

 

mongo는 기본적으로 authentication을 적용시켜두지 않으면 no auth상태로 ip와 port만 알고있으면 어디에서든지 접근이 가능합니다. 보안이 매우 취약한 생태인데 저는 이 사실도 모르고 단순히 admin계정과 db사용자 계정만 만들어두면 자동으로 적용되는줄 알았습니다.

 

최근에서야 문제가 있음을 깨닫고 급하게 알아보기 시작했습니다.

 

cluster로 구성하지 않은 일반적인 mongo의 경우 mongod --auth 명령어로 단순히 적용이 가능하지만 (config를 수정해야 한다거나 그런건 말하지 않겠음) cluster로 구성되어있을경우 그렇게 단순한 문제가 아닙니다. 

 

일단 적용시켜야할 부분이 mongos(router), config server, shard server 총 세 가지 종류가 있고 심지어 우리는 이 모든 것을 docker-compose를 통한 컨테이너로 만들었기 때문에 여간 귀찮은게 아닙니다.

 

결론적으로 cluster의 경우 사용자 authentication을 적용할 경우 keyfile이 필요합니다. 단순히 --auth만 설정해두는게 아닌 클러스터로 구성된 노드들 간의 통신에도 authentication이 적용되야하기 때문에 별도의 keyfile을 만들어서 해당 keyfile을 모든 노드가 가지고있어야합니다.

 

신경써야할게 여러가지지만 순서를 정해서 진행하겠습니다.

 

1. no auth 상태(기본 상태)에서 admin 계정과 사용자 계정 만들기

2. keyfile을 만들기

3. 만든 keyfile을 mongo 클러스터를 구성하고 있는 모든 node에 넣기

4. docker-compose 파일을 수정하여 명령어 적용하기 

5. 적용 확인 

 

이 순서대로 진행해보겠습니다.

 

 

1. 

 

일단 지난번에 만든 mongo cluster를 봅시다.

root@server1:/home# docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                      NAMES
ab5f2e5a0cba        mongo               "docker-entrypoint.s…"   17 hours ago        Up 17 hours         0.0.0.0:37017->27017/tcp   mongos
16b99036b86c        mongo               "docker-entrypoint.s…"   19 hours ago        Up 19 hours         0.0.0.0:50001->27017/tcp   shard1svr1
5bbdbd766ac4        mongo               "docker-entrypoint.s…"   19 hours ago        Up 19 hours         0.0.0.0:40001->27017/tcp   cfgsvr1

 

mongos에 접속하여 admin계정과 다른 db의 사용자 계정을 하나씩 만들어 줍시다. 

docker exec로 내부에 들어가서 mongo 명령어로 들어가셔도되고 저번에 mongo client를 설치해뒀으니 그냥 로컬상에서 mongo 명령어로 접속하셔도됩니다. 여기서 중요한건 mongos로 접속하셔야합니다.

 

mongo mongodb://<IP>:<port>

admin 계정을 만들기 위해서 다음과 같이 입력합니다.

 

> use admin

> db.createUser({
+    user: "계정이름",
+    pwd: "비밀번호",
+    roles:["dbAdminAnyDatabase"]
+})

use admin은 admin 데이터베이스를 사용하겠다는 말이고  db.createUser는 데이터베이스에서 user를 만들겠다는 말입니다.

roles의 경우 공식 docs 잘 정리된게 있으니 찾아보시기바랍니다.

 

docs.mongodb.com/manual/reference/built-in-roles/index.html

 

Built-In Roles — MongoDB Manual

Built-In Roles MongoDB grants access to data and commands through role-based authorization and provides built-in roles that provide the different levels of access commonly needed in a database system. You can additionally create user-defined roles. A role

docs.mongodb.com

 

 

admin 계정을 만들고 이번엔 test db와 test user를 만들어보겠습니다.

 

> use test

> db.createUser({
+    user: "계정이름",
+    pwd: "비밀번호",
+    roles:["readWrite"]
+})

이렇게만 만들면 show dbs했을때 test db가 안보일겁니다. 왜 why? 안에 내용이 없기때문입니다. 따라서 collection이나 document를 아무거나 하나 채워줍시다.

 

> db.createCollection("test")

 

 

2. 

 

이번엔 로컬로 나와서 keyfile을 생성합시다. keyfile을 통해 인증을 하는 이유는 클러스터내의 노드 끼리 서로를 인증하기 위함이라고 합니다.

 

 

로컬 컴퓨터에서 다음처럼 keyfile을 생성합니다.

$ openssl rand -base64 756 > mongodb.key 
$ chmod 400 mongodb.key

 

 

 

3. 

 

만든 keyfile을 mongo 컨테이너에 넣어줍시다. 우선 현재 사용되고 있는 docker image가 mongo 이미지입니다.

해당 이미지를 실행시킨 컨테이너에 요 keyfile을 이동시켜줍시다. (현재 실행되고있는 mongo 컨테이너면됨)

$ docker cp mongodb.key <컨테이너이름>:<컨테이너내부경로>/mongodb.key

docker cp명령어를 사용하여 파일을 복사해줍니다. 

docker cp 명령어를 이용하면 이처럼 로컬파일을 컨테이너 안으로 옮길 수 있고 반대로 컨테이너안의 파일을 로컬로 옮길 수 있습니다.

 

해당 파일을 옮겼다면 이 컨테이너를 이미지화 해줍니다.

$ docker commit <컨테이너명> <저장할이미지명>

이런식으로 저장해서 keyfile이 저장된 mongo 이미지를 만들어줍니다.

 

 

4. 

 

자 이제 docker-compose.yaml 파일을 수정해봅시다.

 

이전에 작성해둔 거를 편집해줍시다.

 

해당 파일은 config 서버에 대한 docker-compose 파일입니다.

version: '3'

services:

  cfgsvr1:
    container_name: cfgsvr1
    image: <아까만든 docker이미지>
#    command: mongod --configsvr --replSet cfgrs --port 27017 --dbpath /data/db
    command: mongod --configsvr --replSet cfgrs --port 27017 --dbpath /data/db --keyFile <key파일경로>/mongodb.key --auth
    ports:
      - 40001:27017
    volumes:
      - cfgsvr1:/data/db
      
      
volumes:
  cfgsvr1: {}

 

중요한 부분만 보면 

--keyFile <컨테이너내부경로>/mongodb.key --auth

command 부분에 요부분을 주목합시다. 컨테이너 내부 경로는 아까 keyfile이 저장된 경로입니다. --auth 옵션을 통해 auth를 활성화하겠다라는 의미입니다.

 

docker-compose up -d

해줍시다.

 

 

다음은 shard 서버입니다.

version: '3'

services:

  shard1svr1:
    container_name: shard1svr1
    image: <아까만든이미지>
#    command: mongod --shardsvr --replSet shard1rs --port 27017 --dbpath /data/db
    command: mongod --shardsvr --replSet shard1rs --port 27017 --dbpath /data/db --keyFile <키파일경로>/mongodb.key --auth
    ports:
      - 50001:27017
    volumes:
      - shard1svr1:/data/db


마찬가지로 docker-compose up -d 해줍시다.

 

마지막으로 mongos입니다.

 

version: '3'

services:

  mongos:
    container_name: mongos
    image: <아까만든이미지>
#    command: mongos --configdb cfgrs/192.168.0.3:40001 --bind_ip 0.0.0.0 --port 27017
    command: mongos --configdb cfgrs/192.168.0.3:40001 --bind_ip 0.0.0.0 --port 27017 --keyFile <key경로>/mongodb.key
    ports:
      - 37017:27017

 

똑같이 해줍시다.

 

근데 이 때 keyfile에 대한 오류가 뜰 수 가 있습니다. docker logs 같은 걸로 확인해보면 key파일이 막 이상하다 라고 되있는 경우가 있는데 이때는 컨테이너 안으로 들어가서 keyfile을 한번확인해줍시다.

 

# ll
total 12
drwxr-xr-x 2 root    root    4096 Dec 29 08:18 ./
drwxr-xr-x 3 mongodb mongodb 4096 Dec 29 06:43 ../
-r-------- 1 mongodb root    1024 Dec 29 05:57 mongodb.key

ll 명령어로 봤을 때 mongodb.key가 위처럼 표시되어야합니다. 

저같은 경우 사용자가 root로 되어있어서 되지않았었는데 어쨌든 위처럼 똑같이 mongodb.key파일을 맞춰줍시다. 

chmod든 chown 등을 사용해서

 

5.

마지막으로 확인입니다.

 

이제 외부에서 계정과 패스워드 없이 접근했을 때 db에 관한 접근이 이루어지면 안됩니다.

 

이전처럼 접근했을때 show dbs를 치면 놀랍게도 아무것도 보이지 않습니다.

 

하지만 

 

mongo mongodb://<IP>:<Port>/"db명" -u "userid" -p "pwd"

이렇게 접근할 경우 설정된 권한에 맞게 표시되는것을 확인할 수 있습니다.

 

 

 

반응형