Docker 데몬 소켓 보호하기
Docker 데몬 소켓 보호하기
Docker는 기본적으로 네트워크에 연결되지 않은 UNIX 소켓을 통해 실행돼요. 필요에 따라 SSH나 TLS(HTTPS) 소켓을 사용해서 통신하도록 설정할 수도 있는데, 이 문서에서는 그 두 가지 방법을 자세히 살펴볼게요. 원격지에서 Docker 데몬을 안전하게 제어해야 하는 상황이라면 이 내용이 큰 도움이 될 거예요.
출처: 공식문서
본문
SSH로 Docker 데몬 소켓 보호하기
참고
여기서 사용하는
USERNAME은 원격 머신에서 Docker 소켓에 접근할 권한이 있어야 해요. 비루트 사용자에게 Docker 소켓 접근 권한을 부여하는 방법은 Docker를 비루트 사용자로 관리하기 문서를 참고하세요.
아래 예시는 SSH를 이용해 host1.example.com에 있는 원격 dockerd 데몬에 docker-user 사용자로 연결하는 Docker 컨텍스트를 생성하는 방법을 보여줘요.
$ docker context create \
--docker host=ssh://[email protected] \
--description="Remote engine" \
my-remote-engine
my-remote-engine
Successfully created context "my-remote-engine"
컨텍스트를 만들었다면 docker context use 명령으로 docker CLI가 해당 컨텍스트를 사용하도록 전환하고, 원격 엔진에 연결할 수 있어요.
$ docker context use my-remote-engine
my-remote-engine
Current context is now "my-remote-engine"
$ docker info
<prints output of the remote engine>
기본(로컬) 데몬으로 돌아가려면 default 컨텍스트를 사용하면 돼요.
$ docker context use default
default
Current context is now "default"
또는 DOCKER_HOST 환경 변수를 사용하면 컨텍스트를 만들지 않고도 임시로 docker CLI가 SSH를 통해 원격 호스트에 연결하도록 전환할 수 있어요. 다른 엔진에 임시 연결이 필요할 때 유용해요.
$ export DOCKER_HOST=ssh://[email protected]
$ docker info
<prints output of the remote engine>
SSH 팁
SSH를 더 편리하게 사용하려면 ~/.ssh/config에 아래 설정을 추가해 두세요. 그러면 docker CLI를 여러 번 호출해도 SSH 연결을 재사용할 수 있어요.
ControlMaster auto
ControlPath ~/.ssh/control-%C
ControlPersist yes
TLS(HTTPS)로 Docker 데몬 소켓 보호하기
HTTP를 통해 Docker에 안전하게 접근해야 한다면 tlsverify 플래그를 지정하고 tlscacert 플래그로 신뢰할 수 있는 CA 인증서를 지정해서 TLS(HTTPS)를 활성화할 수 있어요.
데몬 모드에서는 해당 CA가 서명한 인증서로 인증된 클라이언트의 연결만 허용해요. 클라이언트 모드에서는 반대로 해당 CA가 서명한 인증서를 가진 서버에만 연결해요.
중요
TLS를 사용하고 CA를 관리하는 건 고급 주제예요. 프로덕션 환경에서 사용하기 전에 OpenSSL, x509, TLS에 대해 충분히 숙지해 두세요.
OpenSSL로 CA, 서버, 클라이언트 키 생성하기
참고
아래 예시에서
$HOST는 모두 Docker 데몬 호스트의 DNS 이름으로 바꿔주세요.
먼저 Docker 데몬 호스트 머신에서 CA 개인 키와 공개 키를 생성할게요.
$ openssl genrsa -aes256 -out ca-key.pem 4096
Generating RSA private key, 4096 bit long modulus
..............................................................................++
........++
e is 65537 (0x10001)
Enter pass phrase for ca-key.pem:
Verifying - Enter pass phrase for ca-key.pem:
$ openssl req -new -x509 -days 365 -key ca-key.pem -sha256 -out ca.pem
Enter pass phrase for ca-key.pem:
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [AU]:
State or Province Name (full name) [Some-State]:Queensland
Locality Name (eg, city) []:Brisbane
Organization Name (eg, company) [Internet Widgits Pty Ltd]:Docker Inc
Organizational Unit Name (eg, section) []:Sales
Common Name (e.g. server FQDN or YOUR name) []:$HOST
Email Address []:[email protected]
이제 CA가 준비됐으니 서버 키와 인증서 서명 요청(CSR)을 만들 차례예요. "Common Name"이 Docker에 연결할 때 사용하는 호스트 이름과 일치하는지 확인해 주세요.
참고
아래 예시에서
$HOST는 모두 Docker 데몬 호스트의 DNS 이름으로 바꿔주세요.
$ openssl genrsa -out server-key.pem 4096
Generating RSA private key, 4096 bit long modulus
.....................................................................++
.................................................................................................++
e is 65537 (0x10001)
$ openssl req -subj "/CN=$HOST" -sha256 -new -key server-key.pem -out server.csr
다음으로, 이 공개 키를 CA로 서명할게요.
TLS 연결은 DNS 이름뿐 아니라 IP 주소로도 이루어질 수 있으므로 인증서를 만들 때 IP 주소를 지정해야 해요. 예를 들어 10.10.10.20과 127.0.0.1로의 연결을 허용하려면 다음과 같이 설정해요.
$ echo subjectAltName = DNS:$HOST,IP:10.10.10.20,IP:127.0.0.1 >> extfile.cnf
Docker 데몬 키의 확장 사용 속성을 서버 인증 전용으로 설정할게요.
$ echo extendedKeyUsage = serverAuth >> extfile.cnf
이제 서명된 인증서를 생성할게요.
$ openssl x509 -req -days 365 -sha256 -in server.csr -CA ca.pem -CAkey ca-key.pem \
-CAcreateserial -out server-cert.pem -extfile extfile.cnf
Signature ok
subject=/CN=your.host.com
Getting CA Private Key
Enter pass phrase for ca-key.pem:
인증 플러그인은 상호 TLS 인증을 보완하는 더 세밀한 제어를 제공해요. 위에서 설명한 다른 정보에 더해, Docker 데몬에서 실행되는 인증 플러그인은 연결하는 Docker 클라이언트의 인증서 정보도 받아요.
클라이언트 인증을 위해 클라이언트 키와 인증서 서명 요청을 생성할게요.
참고
다음 몇 단계를 간단히 하기 위해 Docker 데몬 호스트 머신에서 이 단계를 수행해도 돼요.
$ openssl genrsa -out key.pem 4096
Generating RSA private key, 4096 bit long modulus
.........................................................++
................++
e is 65537 (0x10001)
$ openssl req -subj '/CN=client' -new -key key.pem -out client.csr
키를 클라이언트 인증에 적합하게 만들기 위해 새로운 확장 설정 파일을 생성할게요.
$ echo extendedKeyUsage = clientAuth > extfile-client.cnf
이제 서명된 인증서를 생성할게요.
$ openssl x509 -req -days 365 -sha256 -in client.csr -CA ca.pem -CAkey ca-key.pem \
-CAcreateserial -out cert.pem -extfile extfile-client.cnf
Signature ok
subject=/CN=client
Getting CA Private Key
Enter pass phrase for ca-key.pem:
cert.pem과 server-cert.pem을 생성한 후에는 두 인증서 서명 요청과 확장 설정 파일을 안전하게 제거해도 돼요.
$ rm -v client.csr server.csr extfile.cnf extfile-client.cnf
기본 umask가 022인 경우, 비밀 키는 그룹과 다른 사용자에게도 읽힐 수 있고, 본인과 그룹은 쓰기도 가능해요.
키를 우발적인 손상으로부터 보호하려면 쓰기 권한을 제거하세요. 본인만 읽을 수 있게 하려면 파일 모드를 다음과 같이 변경해요.
$ chmod -v 0400 ca-key.pem key.pem server-key.pem
인증서는 공개적으로 읽혀도 괜찮지만, 우발적인 손상을 막기 위해 쓰기 권한은 제거하는 게 좋아요.
$ chmod -v 0444 ca.pem server-cert.pem cert.pem
이제 Docker 데몬이 CA가 신뢰하는 인증서를 제공하는 클라이언트의 연결만 수락하도록 설정할 수 있어요.
$ dockerd \
--tlsverify \
--tlscacert=ca.pem \
--tlscert=server-cert.pem \
--tlskey=server-key.pem \
-H=0.0.0.0:2376
Docker에 연결하고 인증서를 검증하려면 클라이언트 키, 인증서, 신뢰하는 CA를 제공하세요.
팁
이 단계는 Docker 클라이언트 머신에서 실행해야 해요. 따라서 CA 인증서, 서버 인증서, 클라이언트 인증서를 해당 머신으로 복사해야 해요.
참고
아래 예시에서
$HOST는 모두 Docker 데몬 호스트의 DNS 이름으로 바꿔주세요.
$ docker --tlsverify \
--tlscacert=ca.pem \
--tlscert=cert.pem \
--tlskey=key.pem \
-H=$HOST:2376 version
참고
TLS를 사용하는 Docker는 TCP 포트 2376에서 실행해야 해요.
경고
위 예시에서 볼 수 있듯이 인증서 인증을 사용할 때는
docker클라이언트를sudo나docker그룹으로 실행할 필요가 없어요. 즉, 키를 가진 사람은 누구나 Docker 데몬에 어떤 명령이든 내릴 수 있고, 이는 데몬이 실행 중인 머신에 대한 루트 접근 권한을 갖는 것과 같아요. 키는 루트 비밀번호처럼 안전하게 보관하세요!
기본값으로 보안 설정
Docker 클라이언트 연결을 기본적으로 보안 설정하려면 파일을 홈 디렉터리의 .docker 디렉터리로 옮기고, 매번 -H=tcp://$HOST:2376과 --tlsverify를 전달하는 대신 DOCKER_HOST와 DOCKER_TLS_VERIFY 변수를 설정하면 돼요.
$ mkdir -pv ~/.docker
$ cp -v {ca,cert,key}.pem ~/.docker
$ export DOCKER_HOST=tcp://$HOST:2376 DOCKER_TLS_VERIFY=1
이제 Docker는 기본적으로 안전하게 연결해요.
$ docker ps
기타 모드
완전한 양방향 인증이 필요 없다면 플래그를 조합해 다양한 다른 모드로 Docker를 실행할 수 있어요.
데몬 모드
tlsverify,tlscacert,tlscert,tlskey설정: 클라이언트 인증tls,tlscert,tlskey: 클라이언트 인증 안 함
클라이언트 모드
tls: 공개/기본 CA 풀을 기반으로 서버 인증tlsverify,tlscacert: 지정된 CA를 기반으로 서버 인증tls,tlscert,tlskey: 클라이언트 인증서로 인증하되, 지정된 CA로 서버를 인증하지 않음tlsverify,tlscacert,tlscert,tlskey: 클라이언트 인증서로 인증하고 지정된 CA로 서버도 인증
클라이언트는 인증서가 발견되면 자동으로 클라이언트 인증서를 보내므로, 키를 ~/.docker/{ca,cert,key}.pem에 넣어두기만 하면 돼요. 다른 위치에 키를 보관하고 싶다면 DOCKER_CERT_PATH 환경 변수로 위치를 지정할 수 있어요.
$ export DOCKER_CERT_PATH=~/.docker/zone1/
$ docker --tlsverify ps
curl로 보안 Docker 포트에 연결하기
curl로 테스트 API 요청을 보내려면 세 가지 추가 명령줄 플래그가 필요해요.
$ curl https://$HOST:2376/images/json \
--cert ~/.docker/cert.pem \
--key ~/.docker/key.pem \
--cacert ~/.docker/ca.pem