** 구성 환경
Docker Desktop for Windows (WSL 2 기반, Ubuntu 22.04.4 LTS 환경)
. 단일 MongoDB 인스턴스
. OpenSSL 3.0.13 (자체 서명된 CA 및 TLS 적용)
. MongoDB Compass 1.46.2, mongosh 2.5.0
TLS를 구성하려면 우선 인증서(Certificate)와 개인 키(Private Key)가 필요합니다. 일반적으로 상용 CA(인증 기관)에서 발급받거나, 테스트 및 개발 환경에서는 OpenSSL 등을 이용해 자체 서명된 인증서(Self-Signed Certificate)를 생성할 수 있습니다.
** 운영환경 : 반드시 상용 CA에서 발급받은 인증서를 사용하고, 신뢰할 수 없는 자체 서명 인증서는 보안 경고를 유발하므로 실제 서비스에서는 절대 사용해서는 안됩니다.
** 개발환경 : OpenSSL로 자체 서명 인증서를 만들어서 사용하고 이 방식으로 구성해보겠습니다.
자체 서명 인증서 생성(openssl req -x509)으로 SAN을 넣는 데 문제가 있을 수 있으므로, 인증서 서명 요청(CSR)을 생성하고, 그 CSR을 별도로 자체 CA로 서명하는 방식을 사용하는데 이 방법은 일반적인 CA 구성에서 많이 사용되며, SAN 포함에 더 안정적이므로 CA용 개인키 생성부터 시작하는 방법으로 진행합니다.
MongoDB 서버 인증서를 "공식적으로 보증"해 줄 "인증기관(CA)"을 먼저 정해야 하고, 이 CA가 있어야 나중에 MongoDB 서버의 인증서에 "이 인증서는 믿을 수 있다"는 도장을 찍어줄 수 있습니다. CA를 먼저 만들고, 그 CA의 서명을 통해 서버 인증서를 발급받는 이 과정은 일반적인 기업 환경에서 인증서가 발급되고 사용되는 방식과 매우 유사하며, 특히 SAN과 같은 확장 정보를 안정적으로 포함하는 데 가장 효과적인 방법입니다.
# mkdir -p /drives/c/mongodata/certs
# cd /drives/c/mongodata/certs
# openssl genrsa -out ca.key 2048
# openssl req -new -x509 -key ca.key -out ca.pem -days 3650 -subj "/CN=MyRootCA"
# openssl genrsa -out mongodb.key 2048
# cd /drives/c/mongodata/certs
# vi san.cnf
[req]
default_bits = 2048
prompt = no
default_md = sha256
distinguished_name = dn
req_extensions = v3_req
[dn]
C = KR
ST = Seoul
L = Seoul
O = MyCompany
OU = MyDept
CN = mongodb_single # 접속하려는 호스트 이름 지정
[v3_req]
subjectAltName = @alt_names
[alt_names]
DNS.1 = mongodb_single # Docker Compose 서비스 이름
DNS.2 = localhost # localhost로도 접속할 수 있도록 추가
IP.1 = 127.0.0.1 # 로컬 IP로도 접속할 수 있도록 추가
# openssl req -new -key mongodb.key -out mongodb.csr -config san.cnf
# openssl req -in mongodb.csr -text -noout | grep -A 5 "Subject Alternative Name"
X509v3 Subject Alternative Name:
DNS:mongodb_single, DNS:localhost, IP Address:127.0.0.1
Signature Algorithm: sha256WithRSAEncryption
Signature Value:
27:3a:5f:ea:ba:b7:51:1d:13:43:77:a8:42:72:dd:9b:96:39:
3e:89:02:d0:9a:9c:bb:56:77:e8:9a:37:cb:52:83:c0:0e:47:
※ Subject Alternative Name 필드 아래에 DNS:mongodb_single, DNS:localhost, IP Address:127.0.0.1이 보여야 함
# openssl x509 -req -in mongodb.csr -CA ca.pem -CAkey ca.key -CAcreateserial -out mongodb.crt -days 365 -sha256 -extensions v3_req -extfile san.cnf
※ ca.srl도 동시에 발급됨
# openssl x509 -in mongodb.crt -text -noout | grep -A 5 "Subject Alternative Name:"
X509v3 Subject Alternative Name:
DNS:mongodb_single, DNS:localhost, IP Address:127.0.0.1
X509v3 Subject Key Identifier:
C5:64:0F:2E:AD:3F:3E:56:24:27:94:B5:F1:02:22:2E:58:0E:A8:4E
X509v3 Authority Key Identifier:
DirName:/CN=MyRootCA
# cat mongodb.key mongodb.crt > mongodb.pem
# cd /drives/c/mongodata
# docker-compose -f docker-compose_single.yml down -v
# docker-compose -f docker-compose_single.yml up -d
## down -v: 컨테이너뿐만 아니라 관련된 모든 Docker 볼륨까지 제거합니다. 혹시 모를 캐시된 설정이나 남아있는 데이터를 완전히 지우고 새롭게 시작하기 위해 사용하는데, 이전에 생성된 데이터나 로그도 함께 제거될 수 있으니 주의가 필요함
$ mongosh "mongodb://localhost:27027/?tls=true&tlsCAFile=/etc/ssl/mongodb/ca.pem"
% use admin
% db.createUser(
{
user: "admin",
pwd: "1234",
roles: [
{ role: "userAdminAnyDatabase", db: "admin" }, // 사용자 관리 권한
{ role: "dbAdminAnyDatabase", db: "admin" }, // 모든 DB 관리 권한
{ role: "readWriteAnyDatabase", db: "admin" } // 모든 DB 읽기/쓰기 권한
]
}
);
## Compass 접속
. Connection URI : mongodb://admin:****@mongodb_single:27031/?tls=true&tlsCAFile=C%3A%5Cmongodata%5Ccerts%5Cca.pem&authSource=admin
. Edit Connection > Advanced Connection Options
. Authentication
. Authentication Method : Username/Password
. Username : admin
. Password : ****
. Authentication Database : admin
. TLS/SSL
. SSL/TLS Connection : On
. Certificate Authority (.pem) : C:\mongodata\certs\ca.pem 선택
## Mongosh 접속
$ mongosh "mongodb://admin:****@mongodb_single:27027/?tls=true&tlsCAFile=/etc/ssl/mongodb/ca.pem&authSource=admin"
## docker-compose_single.yml
#version: "3.8"
services:
mongodb_single:
image: mongo:latest
hostname: mongodb_single
container_name: mongodb_single
restart: always
ports:
- "27031:27027"
volumes:
- ./data/mongodb_single:/data/db
- ./mongod_single.conf:/etc/mongod.conf
- ./logs/mongodb_single:/var/log/mongodb
- ./certs:/etc/ssl/mongodb
command: ["mongod", "--config", "/etc/mongod.conf"]
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
## mongod_single.conf
storage:
dbPath: /data/db
systemLog:
destination: file
path: /var/log/mongodb/mongod.log
logAppend: true
net:
port: 27027
bindIp: 0.0.0.0
tls:
mode: requireTLS
certificateKeyFile: /etc/ssl/mongodb/mongodb.pem
CAFile: /etc/ssl/mongodb/ca.pem
allowConnectionsWithoutCertificates: true
## 서버가 클라이언트로부터 인증서를 받지 않고도 연결을 허용하도록 함(서버만 인증서로 자신을 인증하고 클라이언트 인증서는 요구하지 않는 경우가 일반적)
security:
authorization: enabled