Docker và bảo mật mật khẩu


162

Gần đây tôi đã thử nghiệm với Docker về việc xây dựng một số dịch vụ để chơi và một điều khiến tôi khó chịu là đã đặt mật khẩu vào Dockerfile. Tôi là một nhà phát triển nên việc lưu trữ mật khẩu trong nguồn cảm thấy như một cú đấm vào mặt. Điều này thậm chí có nên là một mối quan tâm? Có bất kỳ quy ước tốt nào về cách xử lý mật khẩu trong Dockerfiles không?


7
Có một vấn đề mở trên Github yêu cầu thực hành tốt nhất về Docker và bí mật, vấn đề nằm ở đây: github.com/docker/docker/issues/13490
Luís Bianchin

Câu trả lời:


92

Chắc chắn đó là một mối quan tâm. Dockerfiles thường được kiểm tra trong kho và chia sẻ với người khác. Một cách khác là cung cấp bất kỳ thông tin đăng nhập (tên người dùng, mật khẩu, mã thông báo, bất cứ điều gì nhạy cảm) dưới dạng các biến môi trường khi chạy . Điều này có thể thông qua -eđối số (đối với các vars riêng lẻ trên CLI) hoặc --env-fileđối số (đối với nhiều biến trong một tệp) tới docker run. Đọc này để sử dụng môi trường với docker-compose.

Sử dụng --env-filechắc chắn là một lựa chọn an toàn hơn vì điều này bảo vệ chống lại các bí mật hiển thị trong pshoặc trong nhật ký nếu một người sử dụng set -x.

Tuy nhiên, env vars cũng không đặc biệt an toàn. Chúng được hiển thị thông qua docker inspectvà do đó chúng có sẵn cho bất kỳ người dùng nào có thể chạy dockercác lệnh. (Tất nhiên, bất kỳ người dùng nào có quyền truy cập dockervào máy chủ cũng có quyền root .)

Mẫu ưa thích của tôi là sử dụng tập lệnh bao bọc như là ENTRYPOINThoặc CMD. Kịch bản trình bao bọc trước tiên có thể nhập các bí mật từ một vị trí bên ngoài vào vùng chứa trong thời gian chạy, sau đó thực thi ứng dụng, cung cấp các bí mật. Các cơ chế chính xác của điều này thay đổi dựa trên môi trường thời gian chạy của bạn. Trong AWS, bạn có thể sử dụng kết hợp các vai trò IAM, Dịch vụ quản lý khóa và S3 để lưu trữ các bí mật được mã hóa trong nhóm S3. Một cái gì đó như HashiCorp Vault hoặc uy tín là một lựa chọn khác.

AFAIK không có mẫu tối ưu để sử dụng dữ liệu nhạy cảm như là một phần của quá trình xây dựng. Trong thực tế, tôi có một câu hỏi SO về chủ đề này. Bạn có thể sử dụng docker-squash để loại bỏ các lớp khỏi hình ảnh. Nhưng không có chức năng riêng trong Docker cho mục đích này.

Bạn có thể thấy các bình luận shykes về cấu hình trong các thùng chứa hữu ích.


Như đã lưu ý trong các bình luận khác, sẽ có 2 lớp (sau ADD và sau RUN đầu tiên) có chứa .configtệp.
Petr Gladkikh

1
Các biến env dường như là cách tốt nhất để đi. Tôi đã xem xét điều này trong bối cảnh phát triển Dockerfile TDDing.
gnoll110

5
Tôi lo ngại rằng nếu mật khẩu của bạn là biến env, nó sẽ xuất hiện docker inspect.
mỏng

Một cài đặt mặc định của docker (trên linux) yêu cầu các đặc quyền sudoer để chạy docker inspect. Nếu kẻ tấn công đã có thể sudo, việc lấy mật khẩu của bạn ra khỏi docker kiểm tra có lẽ là khá thấp trong danh sách những điều mà bây giờ có thể sai. Chi tiết đặc biệt này có vẻ như rủi ro chấp nhận được với tôi.
GrandOpener

7
@GrandOpener Điều đó chỉ áp dụng cho trường hợp có kẻ tấn công sử dụng hệ thống của bạn. Nếu tôi đẩy một hình ảnh docker vào một kho lưu trữ và nó bị kéo bởi một người khác, tôi không quan tâm nếu họ có sudo trên hệ thống của riêng họ nhưng tôi chắc chắn quan tâm nếu họ thấy những bí mật trong env không còn tồn tại ở đó nữa.
vee_ess

74

Nhóm của chúng tôi tránh đưa thông tin đăng nhập vào kho, vì vậy điều đó có nghĩa là chúng không được phép vào Dockerfile. Thực tiễn tốt nhất của chúng tôi trong các ứng dụng là sử dụng tín dụng từ các biến môi trường.

Chúng tôi giải quyết cho việc này bằng cách sử dụng docker-compose.

Trong docker-compose.yml, bạn có thể chỉ định một tệp chứa các biến môi trường cho vùng chứa:

 env_file:
- .env

Đảm bảo thêm .envvào .gitignore, sau đó đặt thông tin đăng nhập trong .envtệp như:

SOME_USERNAME=myUser
SOME_PWD_VAR=myPwd

Lưu trữ .envtệp cục bộ hoặc ở một vị trí an toàn nơi các thành viên còn lại có thể lấy nó.

Xem: https://docs.docker.com/compose/envir-variabled/#/the-env-file


15
Bạn cũng có thể làm điều này mà không cần tệp .env, nếu bạn muốn. Chỉ cần sử dụng thuộc tính môi trường trong tệp docker-compose.yml của bạn. "Các biến môi trường chỉ có một khóa được giải quyết theo các giá trị của chúng trên máy Compose đang chạy, điều này có thể hữu ích cho các giá trị bí mật hoặc dành riêng cho máy chủ."
D. Visser

1
cho người đàn ông này một cái bánh quy! :) vâng đây là thực hành thực sự tốt Tôi chỉ muốn nói thêm rằng docs.docker.com/compose/env-file này nên làm việc tự động nhưng trong Docker soạn phiên bản 2 có vẻ như bạn cần phải khai báo nó như mô tả trong câu trả lời này.
tương

5
Việc sử dụng các biến môi trường không được khuyến khích bởi chính nhóm Docker, vì env var có thể được nhìn thấy qua / Proc / <pid> / môi trường và docker kiểm tra. Nó chỉ làm xáo trộn cách lấy thông tin đăng nhập cho kẻ tấn công đã giành được quyền truy cập root. Tất nhiên thông tin không bao giờ nên được theo dõi bởi CVS. Tôi đoán cách duy nhất để ngăn người dùng root nhận được tín dụng là đọc thông tin đăng nhập từ trong ứng dụng web (hy vọng rằng nó không cập nhật tệp môi trường Proc) từ tệp được mã hóa, quá trình giải mã yêu cầu mật khẩu một cách an toàn. Tôi nghĩ rằng tôi sẽ thử với một ngôi mộ: github.com/dyne/Tomb
pawamoy

.gitignoređể .envtệp có thông tin nhạy cảm không được đăng ký vào GitHub. Tôi khá chắc chắn rằng nó sẽ không hoạt động nếu bạn thêm nó.dockerignore
TheStherSide 22/2/19

xin chào @theUtherSide, cảm ơn câu trả lời của bạn, tôi có một câu hỏi, khi tôi không kiểm tra .envtệp và tôi triển khai đến một máy chủ trên cơ sở, bạn có đề nghị tạo lại .envtệp trên máy chủ không?
nhà phát triển mã nguồn mở

37

Docker ngay bây giờ (phiên bản 1.13 hoặc 17.06 trở lên) có hỗ trợ quản lý thông tin bí mật. Dưới đây là tổng quantài liệu chi tiết hơn

Tính năng tương tự tồn tại trong kubernetesDCOS


Một số lệnh hữu ích từ các liên kết trên docker secret create:: tạo bí mật docker secret inspect: hiển thị thông tin chi tiết về bí mật docker secret ls: xem tất cả bí mật docker secret rm: xóa --secretcờ bí mật cụ thể để docker service create: tạo bí mật trong khi tạo dịch vụ --secret-addvà gắn --secret-rmcờ cho docker service update: cập nhật giá trị của bí mật hoặc xóa bí mật Trong nhiệm vụ cập nhật dịch vụ. Các bí mật Docker được bảo vệ tại phần còn lại trên các nút của người quản lý và được cung cấp cho các nút worker khi trong quá trình khởi động container.
PJ

7
Có, bạn cần thiết lập một bầy để sử dụng bí mật Docker
Heather QC

11
Đây là một khởi đầu tốt cho một câu trả lời, nhưng cần nhiều thông tin hơn từ những gì được liên kết để xuất hiện trong chính câu trả lời.
Jeff Lambert

7
Không chắc đây có thể là câu trả lời được chấp nhận nếu nó chỉ hoạt động với bầy đàn. Nhiều người không sử dụng bầy đàn, nhưng vẫn cần truyền bí mật.
John Y

9

Bạn không bao giờ nên thêm thông tin đăng nhập vào vùng chứa trừ khi bạn phát thông tin tín dụng cho bất kỳ ai có thể tải xuống hình ảnh. Cụ thể, làm và ADD credssau RUN rm credsnày không an toàn vì tệp tín dụng vẫn còn trong hình ảnh cuối cùng trong lớp hệ thống tệp trung gian. Bất cứ ai có quyền truy cập vào hình ảnh đều dễ dàng trích xuất nó.

Giải pháp điển hình mà tôi đã thấy khi bạn cần tín dụng để kiểm tra các phụ thuộc và đó là sử dụng một container để xây dựng một container khác. Tức là, thông thường bạn có một số môi trường xây dựng trong bộ chứa cơ sở của bạn và bạn cần phải gọi nó để xây dựng bộ chứa ứng dụng của mình. Vì vậy, giải pháp đơn giản là thêm nguồn ứng dụng của bạn và sau đó RUNlà các lệnh xây dựng. Điều này là không an toàn nếu bạn cần tín dụng trong đó RUN. Thay vào đó, những gì bạn làm là đưa nguồn của bạn vào một thư mục cục bộ, chạy (như trong docker run) thùng chứa để thực hiện bước xây dựng với thư mục nguồn cục bộ được gắn dưới dạng âm lượng và tín dụng được chèn hoặc gắn vào một ổ đĩa khác. Khi bước xây dựng hoàn tất, bạn xây dựng vùng chứa cuối cùng của mình bằng cách nhập ADDthư mục nguồn cục bộ hiện chứa các tạo phẩm được xây dựng.

Tôi hy vọng Docker bổ sung một số tính năng để đơn giản hóa tất cả điều này!

Cập nhật: có vẻ như phương pháp sắp tới sẽ có các bản dựng lồng nhau. Nói tóm lại, dockerfile sẽ mô tả một container đầu tiên được sử dụng để xây dựng môi trường thời gian chạy và sau đó là một container chứa thứ hai lồng nhau có thể lắp ráp tất cả các mảnh vào container cuối cùng. Bằng cách này, công cụ thời gian xây dựng không có trong thùng chứa thứ hai. Đây là một ứng dụng Java nơi bạn cần JDK để xây dựng ứng dụng nhưng chỉ có JRE để chạy nó. Có một số đề xuất đang được thảo luận, tốt nhất để bắt đầu từ https://github.com/docker/docker/issues/7115 và theo một số liên kết cho các đề xuất thay thế.


7

Một cách khác để sử dụng các biến môi trường, có thể trở nên lộn xộn nếu bạn có nhiều biến số, là sử dụng các ổ đĩa để làm cho một thư mục trên máy chủ có thể truy cập được trong container.

Nếu bạn đặt tất cả thông tin đăng nhập của bạn dưới dạng tệp trong thư mục đó, thì vùng chứa có thể đọc các tệp và sử dụng chúng khi nó vừa ý.

Ví dụ:

$ 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

Nhiều chương trình có thể đọc thông tin đăng nhập của họ từ một tệp riêng biệt, vì vậy bằng cách này, bạn có thể chỉ chương trình tới một trong các tệp.


5

giải pháp chỉ chạy trong thời gian

docker-compose cũng cung cấp giải pháp chế độ không swarm (kể từ v1.11: Bí mật sử dụng gắn kết liên kết ).

Các bí mật được gắn kết như các tập tin dưới đây /run/secrets/bởi docker-compose. Điều này giải quyết vấn đề tại thời gian chạy (chạy container), nhưng không giải quyết tại thời gian xây dựng (xây dựng hình ảnh), vì /run/secrets/không được gắn vào thời gian xây dựng. Hơn nữa, hành vi này phụ thuộc vào việc chạy container với docker-compose.


Thí dụ:

Dockerfile

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

Để xây dựng, thực thi:

docker-compose up -d

Đọc thêm:


2

Với Docker v1.9, bạn có thể sử dụng lệnh ARG để tìm nạp các đối số được truyền bởi dòng lệnh vào hình ảnh trên hành động xây dựng . Đơn giản chỉ cần sử dụng cờ --build-arg . Vì vậy, bạn có thể tránh để giữ mật khẩu rõ ràng (hoặc thông tin hợp lý khác) trên Dockerfile và chuyển chúng nhanh chóng.

nguồn: https://docs.docker.com/engine/reference/commandline/build/ http://docs.docker.com/engine/reference/builder/#arg

Thí dụ:

Dockerfile

FROM busybox
ARG user
RUN echo "user is $user"

xây dựng lệnh hình ảnh

docker build --build-arg user=capuccino -t test_arguments -f path/to/dockerfile .

trong quá trình xây dựng nó in

$ 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

Hy vọng nó giúp! Tạm biệt.


26
Theo tài liệu ARG của Docker : "Không nên sử dụng các biến thời gian xây dựng để truyền các bí mật như khóa github, thông tin người dùng, v.v."
Lie Ryan

3
Chỉ cần tự hỏi tại sao Docker không khuyến khích sử dụng --build-arg var=secretđể chuyển khóa riêng SSH vào hình ảnh, không có tài liệu hợp lý nào được ghi lại. Bất cứ ai có thể giải thích nó?
Henk Wiersema

2
@HenkWiersema Quá trình thông tin, nhật ký và lịch sử lệnh không an toàn. Thông tin quy trình có sẵn công khai và bao gồm tất cả các tham số dòng lệnh. Thường thì những cuộc gọi này kết thúc trong nhật ký cũng có thể được công khai. Không có gì lạ khi kẻ tấn công kiểm tra thông tin về các quy trình đang chạy và truy tìm các logfile công khai để tìm bí mật. Ngay cả khi nó không công khai, nó có thể được lưu trữ trong lịch sử lệnh của bạn, điều này giúp người khác dễ dàng lấy bí mật thông qua tài khoản phi hành chính.
tu-Tái lập Monica-dor duh

2
Cách được đề xuất để cung cấp thông tin đăng nhập cần thiết trong thời gian xây dựng là gì? Ví dụ: một hình ảnh cần truy cập aws s3 để tìm nạp một tập dữ liệu lớn sẽ nằm trong ảnh?
ely

3
Tôi tưởng tượng lý do nó không được khuyến khích là vì docker historyphơi bày build-arg/ ARGbiến. Người ta có thể kéo bất kỳ hình ảnh nào, kiểm tra nó và xem bất kỳ bí mật nào được truyền trong quá trình xây dựng dưới dạng build-arg/ ARGtham số.
vee_ess

2

Cách tiếp cận của tôi có vẻ hiệu quả, nhưng có lẽ là ngây thơ. Hãy cho tôi biết tại sao nó sai.

Các ARG được thiết lập trong quá trình xây dựng docker được tiết lộ bởi tiểu ban lịch sử, do đó không đi đến đó. Tuy nhiên, khi chạy một container, các biến môi trường được đưa ra trong lệnh run có sẵn cho container, nhưng không phải là một phần của hình ảnh.

Vì vậy, trong Dockerfile, hãy thiết lập không liên quan đến dữ liệu bí mật. Đặt một CMD của một cái gì đó như /root/finish.sh. Trong lệnh chạy, sử dụng các biến môi trường để gửi dữ liệu bí mật vào vùng chứa. finish.shsử dụng các biến cơ bản để hoàn thành các nhiệm vụ xây dựng.

Để làm cho việc quản lý dữ liệu bí mật dễ dàng hơn, hãy đặt nó vào một tệp được tải bởi docker chạy bằng công --env-filetắc. Tất nhiên, giữ bí mật tập tin..gitignorevà như vậy.

Đối với tôi, finish.shchạy một chương trình Python. Nó kiểm tra để đảm bảo rằng nó không chạy trước đó, sau đó kết thúc thiết lập (ví dụ: sao chép tên cơ sở dữ liệu vào Django settings.py).


2

Có một lệnh docker mới để quản lý "bí mật". Nhưng điều đó chỉ làm việc cho các cụm swarm.

docker service create
--name my-iis
--publish target=8000,port=8000
--secret src=homepage,target="\inetpub\wwwroot\index.html"
microsoft/iis:nanoserver 

1

Các phương pháp ứng dụng 12-Factor nói, rằng bất kỳ cấu hình nên được lưu trữ trong các biến môi trường.

Docker compose có thể thay thế biến trong cấu hình, do đó có thể được sử dụng để truyền mật khẩu từ máy chủ đến docker.


Tôi đánh giá cao các tài liệu tham khảo cho kinh thánh.
JakeCowton

-2

Trong khi tôi hoàn toàn đồng ý không có giải pháp đơn giản. Tiếp tục có một điểm thất bại duy nhất. Hoặc là dockerfile, vân vân, vân vân. Apcera có một kế hoạch trông giống như sidekick - xác thực kép. Nói cách khác, hai container không thể nói chuyện trừ khi có quy tắc cấu hình Apcera. Trong bản demo của họ, uid / pwd đã rõ ràng và không thể được sử dụng lại cho đến khi quản trị viên cấu hình liên kết. Tuy nhiên, để nó hoạt động, có lẽ nó có nghĩa là vá Docker hoặc ít nhất là plugin mạng (nếu có một thứ như vậy).


2
Có một câu trả lời ở đâu đó cho câu hỏi được hỏi?
Abhijit Sarkar
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.