나는 최근에 Docker를 사용하여 놀 수있는 서비스를 구축하는 것을 실험 해 왔으며 계속 잔소리하는 것이 Dockerfile에 암호를 넣고 있습니다. 나는 개발자이므로 소스에 암호를 저장하면 얼굴이 펀치처럼 느껴집니다. 이것이 문제가되어야합니까? Dockerfile에서 비밀번호를 처리하는 방법에 대한 좋은 규칙이 있습니까?
나는 최근에 Docker를 사용하여 놀 수있는 서비스를 구축하는 것을 실험 해 왔으며 계속 잔소리하는 것이 Dockerfile에 암호를 넣고 있습니다. 나는 개발자이므로 소스에 암호를 저장하면 얼굴이 펀치처럼 느껴집니다. 이것이 문제가되어야합니까? Dockerfile에서 비밀번호를 처리하는 방법에 대한 좋은 규칙이 있습니까?
답변:
확실히 걱정입니다. Dockerfile은 일반적으로 리포지토리에 체크인되어 다른 사람들과 공유됩니다. 대안은 런타임시 환경 변수로 모든 신임 정보 (사용자 이름, 비밀번호, 토큰, 민감한 것)를 제공하는 것 입니다. 이것은 -e
인수 (CLI의 개별 변수의 경우) 또는 --env-file
인수 (파일의 여러 변수의 경우)를 통해 가능 docker run
합니다. docker-compose와 함께 환경을 사용하려면 이것을 읽으십시오 .
사용 --env-file
하는 ps
경우 로그 또는 로그 에 표시되는 비밀로부터 보호하기 때문에 사용하는 것이 더 안전한 옵션 set -x
입니다.
그러나 환경 변수는 특히 안전하지 않습니다. 이들은를 통해 볼 수 docker inspect
있으므로 docker
명령 을 실행할 수있는 모든 사용자가 사용할 수 있습니다 . (물론 docker
호스트에서 액세스 할 수있는 모든 사용자 는 어쨌든 루트 를 가지고 있습니다.)
내가 선호하는 패턴은 래퍼 스크립트를 ENTRYPOINT
또는 로 사용하는 것 CMD
입니다. 랩퍼 스크립트는 먼저 런타임시 외부 위치에서 컨테이너로 비밀을 가져온 다음 애플리케이션을 실행하여 비밀을 제공 할 수 있습니다. 이것의 정확한 메커니즘은 런타임 환경에 따라 다릅니다. AWS에서는 IAM 역할, 키 관리 서비스 및 S3 의 조합을 사용하여 암호화 된 비밀을 S3 버킷에 저장할 수 있습니다. HashiCorp Vault 또는 credstash 와 같은 것이 또 다른 옵션입니다.
AFAIK는 빌드 프로세스의 일부로 중요한 데이터를 사용하기위한 최적의 패턴이 없습니다. 사실, 나는 이 주제에 대한 SO 질문 이 있습니다. docker-squash 를 사용 하여 이미지에서 레이어를 제거 할 수 있습니다 . 그러나이 목적을 위해 Docker에는 기본 기능이 없습니다.
.config
파일 을 포함하는 2 개의 레이어 (ADD 후 및 첫 RUN 후)가 있습니다 .
docker inspect
.
docker inspect
. 침입자가 이미 sudo를 할 수 있다면, docker inspect에서 암호를 빼내는 것은 아마도 잘못 될 수있는 것들의 목록에서 아마도 낮을 것입니다. 이 특정 세부 사항은 나에게 허용되는 위험처럼 보입니다.
Google 팀은 리포지토리에 자격 증명을 넣지 않기 때문에에 허용되지 않습니다 Dockerfile
. 응용 프로그램 내에서 우리의 모범 사례는 환경 변수의 cred를 사용하는 것입니다.
우리는 이것을 사용하여 해결합니다 docker-compose
.
내 docker-compose.yml
에서 컨테이너의 환경 변수가 포함 된 파일을 지정할 수 있습니다.
env_file:
- .env
반드시 추가 할 수 있도록 .env
하기 위해 .gitignore
, 다음 내 자격 증명 설정 .env
등의 파일을 :
SOME_USERNAME=myUser
SOME_PWD_VAR=myPwd
.env
파일을 로컬 또는 팀의 다른 팀이 확보 할 수있는 안전한 위치에 저장하십시오 .
참조 : https://docs.docker.com/compose/environment-variables/#/the-env-file
.gitignore
그래서 것을 .env
중요한 정보와 파일을 체크 인되지 않습니다 GitHub의에. 추가하면 작동하지 않을 것입니다..dockerignore
.env
파일을 체크인 하지 않고 전제로 서버에 배포 할 때 질문 이 있습니다 .env
. 서버에서 수동으로 파일을 다시 작성하는 것이 좋습니다 ?
Docker now (버전 1.13 또는 17.06 이상)는 비밀 정보 관리를 지원합니다. 여기의 개요 및 자세한 설명서
비슷한 기능의 존재 는 Kubernetes 및 DCOS
docker secret create
: 비밀 생성 : 비밀에 docker secret inspect
대한 자세한 정보 표시 docker secret ls
: 모든 비밀보기 docker secret rm
: 특정 비밀 --secret
플래그 제거 docker service create
: 서비스 생성시 비밀 생성 --secret-add
및 --secret-rm
플래그 docker service update
: 비밀 값 업데이트 또는 비밀 제거 서비스 업데이트 작업 중 Docker 비밀은 관리자 노드에서 유휴 상태로 보호되고 컨테이너 시작 중에 작업자 노드에 프로비저닝됩니다.
이미지를 다운로드 할 수있는 사람에게 자격 증명을 브로드 캐스트하지 않는 한 컨테이너에 자격 증명을 추가해서는 안됩니다. 특히 creds 파일이 중간 파일 시스템 계층의 최종 이미지에 남아 있기 때문에 ADD creds
and 이후의 작업 RUN rm creds
은 안전하지 않습니다. 이미지에 액세스 할 수있는 사람이라면 누구나 쉽게 추출 할 수 있습니다.
종속성을 체크 아웃하기 위해 cred가 필요할 때 본 전형적인 솔루션은 컨테이너를 사용하여 다른 컨테이너를 만드는 것입니다. 즉, 일반적으로 기본 컨테이너에 빌드 환경이 있으며 앱 컨테이너를 빌드하려면 해당 환경을 호출해야합니다. 따라서 간단한 해결책은 앱 소스를 추가 한 다음 RUN
빌드 명령 을 추가하는 것 입니다. 만약 당신이 그 안에 신념이 필요하다면 이것은 안전하지 않습니다 RUN
. 대신 로컬 소스에 소스를 넣고 docker run
컨테이너 에서 (와 같이 ) 로컬 소스 디렉토리를 볼륨으로 마운트하고 creds를 다른 볼륨으로 주입하거나 마운트하여 빌드 단계를 수행하십시오. 빌드 단계가 완료되면 ADD
이제 빌드 된 아티팩트가 포함 된 로컬 소스 디렉토리를 간단히 보내 최종 컨테이너를 빌드하십시오 .
Docker 가이 모든 것을 단순화하기 위해 몇 가지 기능을 추가하기를 희망합니다!
업데이트 : 앞으로 메소드가 중첩 된 빌드를 갖는 것처럼 보입니다. 간단히 말해서, dockerfile은 런타임 환경을 구축하는 데 사용되는 첫 번째 컨테이너와 모든 컨테이너를 최종 컨테이너에 조립할 수있는 두 번째 중첩 컨테이너 빌드를 설명합니다. 이렇게하면 빌드 타임이 두 번째 컨테이너에 없습니다. 앱을 빌드하는 데 JDK가 필요하지만 실행을 위해 JRE 만 필요한 Java 앱입니다. https://github.com/docker/docker/issues/7115 에서 시작 하여 대체 제안에 대한 링크 중 일부를 따르는 것이 가장 좋습니다 .
환경 변수를 많이 사용하는 경우 혼란 스러울 수있는 환경 변수를 사용하는 대신 볼륨을 사용하여 호스트의 디렉토리를 컨테이너에서 액세스 할 수 있습니다.
모든 자격 증명을 해당 폴더에 파일로 저장하면 컨테이너가 파일을 읽고 원하는대로 사용할 수 있습니다.
예를 들면 다음과 같습니다.
$ echo "secret" > /root/configs/password.txt
$ docker run -v /root/configs:/cfg ...
In the Docker container:
# echo Password is `cat /cfg/password.txt`
Password is secret
많은 프로그램이 별도의 파일에서 자격 증명을 읽을 수 있으므로이 방법으로 프로그램을 파일 중 하나를 가리킬 수 있습니다.
런타임 전용 솔루션
docker-compose는 비-스웜 모드 솔루션을 제공합니다 (v1.11부터 : bind mounts를 사용하는 비밀 ).
비밀은 /run/secrets/
docker-compose에 의해 아래 파일로 마운트됩니다 . 이렇게하면 빌드 타임에 /run/secrets/
마운트되지 않으므로 런타임 (컨테이너 실행)에서는 문제가 해결되지만 빌드 타임 (이미지 빌드)에서는 문제 가 해결되지 않습니다. 또한이 동작은 docker-compose로 컨테이너를 실행하는 데 달려 있습니다.
예:
도커 파일
FROM alpine
RUN cat /run/secrets/password
CMD sleep inifinity
docker-compose.yml
version: '3.1'
services:
app:
build: .
secrets:
- password
secrets:
password:
file: password.txt
빌드하려면 다음을 실행하십시오.
docker-compose up -d
더 읽을 거리 :
으로 도커 v1.9 개발자 당신은 사용할 수 ARG 명령 에 이미지에 명령 라인으로 전달 된 인수 가져 빌드 작업을 . 간단히 --build-arg 플래그를 사용하십시오 . 따라서 Dockerfile에 명시 적 암호 (또는 다른 합리적인 정보)를 유지하지 않고 즉시 전달할 수 있습니다.
출처 : https://docs.docker.com/engine/reference/commandline/build/ http://docs.docker.com/engine/reference/builder/#arg
예:
도커 파일
FROM busybox
ARG user
RUN echo "user is $user"
이미지 빌드 명령
docker build --build-arg user=capuccino -t test_arguments -f path/to/dockerfile .
빌드하는 동안 인쇄
$ docker build --build-arg user=capuccino -t test_arguments -f ./test_args.Dockerfile .
Sending build context to Docker daemon 2.048 kB
Step 1 : FROM busybox
---> c51f86c28340
Step 2 : ARG user
---> Running in 43a4aa0e421d
---> f0359070fc8f
Removing intermediate container 43a4aa0e421d
Step 3 : RUN echo "user is $user"
---> Running in 4360fb10d46a
**user is capuccino**
---> 1408147c1cb9
Removing intermediate container 4360fb10d46a
Successfully built 1408147c1cb9
그것이 도움이되기를 바랍니다! 안녕.
--build-arg var=secret
가 SSH 개인 키를 이미지에 전달하는 데 사용하지 않는 이유를 궁금해하는 이유 는 문서화되지 않았습니다. 누구나 설명 할 수 있습니까?
docker history
는 build-arg
/ ARG
변수 가 노출 되어 있기 때문 입니다. 이미지를 가져 와서 검사하고 빌드 중에 전달 된 비밀을 build-arg
/ ARG
매개 변수로 볼 수 있습니다.
내 접근 방식은 효과가있는 것 같지만 아마도 순진합니다. 왜 그런지 말해줘.
docker build 동안 설정된 ARG는 history 하위 명령에 의해 노출되므로 아무 것도 수행하지 않습니다. 그러나 컨테이너를 실행할 때 run 명령에 제공된 환경 변수는 컨테이너에서 사용할 수 있지만 이미지의 일부는 아닙니다.
따라서 Dockerfile에서 비밀 데이터가 포함되지 않은 설정을 수행하십시오. 과 같은 CMD를 설정하십시오 /root/finish.sh
. run 명령에서 환경 변수를 사용하여 비밀 데이터를 컨테이너로 보냅니다. finish.sh
본질적으로 변수를 사용하여 빌드 작업을 완료합니다.
비밀 데이터를보다 쉽게 관리하려면 --env-file
스위치를 사용하여 docker run에 의해로드 된 파일에 비밀 데이터를 저장하십시오 . 물론 파일을 비밀로 유지하십시오. .gitignore
등.
나를 위해, finish.sh
파이썬 프로그램을 실행합니다. 이전에 실행되지 않았는지 확인한 다음 설정을 완료합니다 (예 : 데이터베이스 이름을 Django 's에 복사 settings.py
).
12 팩터 응용 프로그램의 방법론은 모든 구성이 환경 변수에 보관해야합니다 것을 알 수 있습니다.
Docker compose는 구성에서 변수 대체 를 수행 할 수 있으므로 호스트에서 docker로 비밀번호를 전달하는 데 사용할 수 있습니다.
전적으로 동의하지만 간단한 해결책은 없습니다. 단일 실패 지점이 계속 존재합니다. 도커 파일 등입니다. Apcera에는 이중 인증과 같은 계획이 있습니다. 즉, Apcera 구성 규칙이 없으면 두 컨테이너가 통신 할 수 없습니다. 데모에서 uid / pwd는 명확했으며 관리자가 연결을 구성 할 때까지 재사용 할 수 없었습니다. 그러나 이것이 작동하기 위해서는 Docker 또는 적어도 네트워크 플러그인을 패치해야합니다 (이러한 것이있는 경우).