Docker dan mengamankan kata sandi

162

Saya telah bereksperimen dengan Docker baru-baru ini untuk membangun beberapa layanan untuk bermain-main dengan dan satu hal yang terus mengganggu saya telah memasukkan kata sandi di Dockerfile. Saya seorang pengembang sehingga menyimpan kata sandi di sumber terasa seperti pukulan di wajah. Haruskah ini menjadi perhatian? Apakah ada konvensi yang baik tentang bagaimana menangani kata sandi di Dockerfiles?

anthonator
sumber
7
Ada masalah terbuka pada Github yang meminta praktik terbaik terkait Docker dan rahasia, masalahnya ada di sini: github.com/docker/docker/issues/13490
Luís Bianchin

Jawaban:

93

Jelas itu adalah masalah. Dockerfiles biasanya masuk ke repositori dan dibagikan dengan orang lain. Alternatifnya adalah memberikan kredensial (nama pengguna, kata sandi, token, apa pun yang sensitif) sebagai variabel lingkungan saat runtime . Ini dimungkinkan melalui -eargumen (untuk masing-masing vars pada CLI) atau --env-fileargumen (untuk beberapa variabel dalam file) ke docker run. Baca ini untuk menggunakan lingkungan dengan komposisi buruh pelabuhan.

Menggunakan --env-filejelas merupakan pilihan yang lebih aman karena ini melindungi terhadap rahasia yang muncul di psatau dalam log jika digunakan set -x.

Namun, env vars juga tidak terlalu aman. Mereka terlihat melalui docker inspect, dan karenanya mereka tersedia untuk setiap pengguna yang dapat menjalankan dockerperintah. (Tentu saja, setiap pengguna yang memiliki akses ke dockerhost juga memiliki root .)

Pola pilihan saya adalah menggunakan skrip pembungkus sebagai ENTRYPOINTatau CMD. Skrip pembungkus dapat pertama-tama mengimpor rahasia dari lokasi luar ke dalam wadah pada saat run time, kemudian menjalankan aplikasi, memberikan rahasia. Mekanik yang tepat untuk ini berbeda-beda berdasarkan lingkungan waktu kerja Anda. Di AWS, Anda dapat menggunakan kombinasi peran IAM, Layanan Manajemen Kunci , dan S3 untuk menyimpan rahasia terenkripsi dalam keranjang S3. Sesuatu seperti HashiCorp Vault atau credstash adalah pilihan lain.

AFAIK tidak ada pola optimal untuk menggunakan data sensitif sebagai bagian dari proses pembangunan. Bahkan, saya punya pertanyaan SO tentang topik ini. Anda dapat menggunakan docker-squash untuk menghapus lapisan dari suatu gambar. Tetapi tidak ada fungsi asli di Docker untuk tujuan ini.

Anda mungkin menemukan komentar shykes tentang konfigurasi dalam wadah berguna.

Ben Whaley
sumber
Sebagaimana dicatat dalam komentar lain akan ada 2 lapisan (setelah ADD dan setelah RUN pertama) yang berisi .configfile.
Petr Gladkikh
1
Ya, variabel env tampaknya cara terbaik untuk pergi. Saya telah melihat ini dalam konteks pengembangan Dockerfile TDDing.
gnoll110
5
Saya khawatir jika kata sandi Anda adalah variabel env, kata sandi itu muncul di docker inspect.
langsing
Instalasi default docker (di linux) membutuhkan hak sudoer untuk dijalankan docker inspect. Jika penyerang sudah bisa sudo, mengambil kata sandi Anda dari pemeriksaan buruh pelabuhan mungkin cukup rendah pada daftar hal-hal yang sekarang bisa salah. Detail khusus ini sepertinya risiko yang dapat diterima bagi saya.
GrandOpener
7
@GrandOpener Itu hanya berlaku untuk situasi di mana ada penyerang menggunakan sistem Anda. Jika saya mendorong gambar buruh pelabuhan ke repositori, dan itu ditarik oleh orang lain, saya tidak peduli jika mereka memiliki sudo di sistem mereka sendiri, tetapi saya pasti peduli jika mereka melihat rahasia di env yang tidak lagi seharusnya ada di sana.
vee_ess
75

Tim kami menghindari memasukkan kredensial ke dalam repositori, sehingga itu berarti mereka tidak diizinkan masuk Dockerfile. Praktik terbaik kami dalam aplikasi adalah menggunakan kredit dari variabel lingkungan.

Kami memecahkan ini menggunakan docker-compose.

Di dalam docker-compose.yml, Anda dapat menentukan file yang berisi variabel lingkungan untuk wadah:

 env_file:
- .env

Pastikan untuk menambahkan .envke .gitignore, kemudian mengatur kredensial dalam .envfile seperti:

SOME_USERNAME=myUser
SOME_PWD_VAR=myPwd

Simpan .envfile secara lokal atau di lokasi yang aman tempat anggota tim lainnya dapat mengambilnya.

Lihat: https://docs.docker.com/compose/environment-variables/#/the-env-file

sisi lain
sumber
15
Anda juga dapat melakukan ini tanpa file .env, jika diinginkan. Cukup gunakan properti environment di file docker-compose.yml Anda. "Variabel lingkungan dengan hanya kunci diselesaikan untuk nilai-nilai mereka pada mesin Compose sedang berjalan, yang dapat membantu untuk nilai-nilai rahasia atau spesifik host."
D. Visser
1
berikan dia kue! :) ya ini benar-benar praktik yang baik Saya hanya ingin menambahkan bahwa docs.docker.com/compose/env-file ini seharusnya bekerja secara otomatis tetapi dalam docker menulis versi 2 sepertinya Anda perlu mendeklarasikannya seperti dijelaskan dalam jawaban ini.
Setara8
5
Menggunakan variabel lingkungan tidak disarankan oleh tim Docker sendiri, karena env var dapat dilihat melalui / proc / <pid> / environment dan docker inspect. Itu hanya mengaburkan cara untuk mendapatkan kredensial bagi penyerang yang telah mendapatkan akses root. Tentu saja kredensial tidak boleh dilacak oleh CVS. Saya kira satu-satunya cara untuk mencegah pengguna root untuk mendapatkan kredit adalah dengan membaca kredensial dari dalam aplikasi web (berharap bahwa itu tidak memperbarui file lingkungan proc-nya) dari file yang dienkripsi, proses dekripsi secara aman meminta kata sandi. Saya pikir saya akan mencoba dengan sebuah makam: github.com/dyne/Tomb
pawamoy
.gitignoresehingga .envfile dengan informasi sensitif tidak bisa masuk ke GitHub. Saya cukup yakin ini tidak akan berhasil jika Anda menambahkannya.dockerignore
theUtherSide
hai @theUtherSide, terima kasih atas jawaban Anda, saya punya pertanyaan, ketika saya tidak checkin .envfile dan saya melakukan penyebaran ke server di tempat, apakah Anda menyarankan untuk membuat .envfile lagi di server secara manual?
opensource-developer
37

Docker sekarang (versi 1.13 atau 17.06 dan lebih tinggi) memiliki dukungan untuk mengelola informasi rahasia. Berikut ini ikhtisar dan dokumentasi yang lebih rinci

Fitur serupa ada di kubernet dan DCOS

Heather QC
sumber
Beberapa perintah yang berguna dari tautan di atas docker secret create:: buat rahasia docker secret inspect: tampilkan informasi terperinci tentang rahasia docker secret ls: lihat semua rahasia docker secret rm: hapus --secretbendera rahasia khusus untuk docker service create: buat rahasia selama pembuatan layanan --secret-adddan --secret-rmtanda untuk docker service update: perbarui nilai rahasia atau hapus rahasia selama tugas pembaruan layanan. Rahasia buruh pelabuhan dilindungi saat istirahat di node manajer dan disediakan untuk node pekerja saat selama wadah startup.
PJ
7
Ya, Anda perlu menyiapkan segerombolan untuk menggunakan rahasia Docker
Heather QC
11
Ini adalah permulaan yang bagus untuk sebuah jawaban, tetapi membutuhkan lebih banyak informasi dari yang terkait untuk muncul dalam jawaban itu sendiri.
Jeff Lambert
7
Tidak yakin ini bisa menjadi jawaban yang diterima jika hanya berfungsi dengan kawanan. Banyak orang tidak menggunakan gerombolan, tetapi masih perlu menyampaikan rahasia.
John Y
9

Anda tidak boleh menambahkan kredensial ke wadah kecuali Anda menyiarkan kredibilitas kepada siapa pun yang dapat mengunduh gambar. Secara khusus, melakukan dan ADD credsdan kemudian RUN rm credstidak aman karena file kredit tetap pada gambar akhir di lapisan sistem file menengah. Mudah bagi siapa saja yang memiliki akses ke gambar untuk mengekstraknya.

Solusi khas yang saya lihat ketika Anda membutuhkan kredit untuk checkout dependensi dan sejenisnya adalah dengan menggunakan satu wadah untuk membangun yang lain. Yaitu, biasanya Anda memiliki beberapa lingkungan build di wadah dasar Anda dan Anda harus memohonnya untuk membangun wadah aplikasi Anda. Jadi solusi sederhana adalah menambahkan sumber aplikasi Anda dan kemudian RUNmembangun perintah. Ini tidak aman jika Anda membutuhkan kredit dalam hal itu RUN. Alih-alih apa yang Anda lakukan adalah memasukkan sumber Anda ke direktori lokal, jalankan (seperti dalam docker run) wadah untuk melakukan langkah pembangunan dengan direktori sumber lokal dipasang sebagai volume dan kredibilitasnya disuntikkan atau dipasang sebagai volume lain. Setelah langkah pembangunan selesai, Anda membangun wadah akhir Anda hanya ADDdengan memasukkan direktori sumber lokal yang sekarang berisi artefak bawaan.

Saya berharap Docker menambahkan beberapa fitur untuk menyederhanakan semua ini!

Pembaruan: sepertinya metode yang akan datang adalah untuk membangun bersarang. Singkatnya, buruh pelabuhan akan menjelaskan wadah pertama yang digunakan untuk membangun lingkungan run-time dan kemudian membangun wadah bersarang kedua yang dapat merakit semua potongan ke dalam wadah akhir. Dengan demikian, barang bawaan tidak ada dalam wadah kedua. Ini aplikasi Java di mana Anda memerlukan JDK untuk membangun aplikasi tetapi hanya JRE untuk menjalankannya. Ada sejumlah proposal yang sedang dibahas, sebaiknya dimulai dari https://github.com/docker/docker/issues/7115 dan ikuti beberapa tautan untuk proposal alternatif.

TVE
sumber
7

Alternatif untuk menggunakan variabel lingkungan, yang bisa berantakan jika Anda memiliki banyak variabel, adalah dengan menggunakan volume untuk membuat direktori pada host yang dapat diakses dalam wadah.

Jika Anda meletakkan semua kredensial Anda sebagai file di folder itu, maka wadah itu dapat membaca file dan menggunakannya sesuai keinginan.

Sebagai contoh:

$ 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

Banyak program dapat membaca kredensial mereka dari file terpisah, jadi dengan cara ini Anda bisa mengarahkan program ke salah satu file.

Malvine
sumber
5

solusi run-time saja

docker-compose juga menyediakan solusi mode non-swarm (sejak v1.11: Rahasia menggunakan bind mounts ).

Rahasia dipasang sebagai file di bawah ini /run/secrets/oleh susunan buruh pelabuhan. Ini menyelesaikan masalah saat run-time (menjalankan wadah), tetapi tidak pada build-time (membangun gambar), karena /run/secrets/tidak dipasang pada build-time. Selanjutnya perilaku ini tergantung pada menjalankan wadah dengan menyusun buruh pelabuhan.


Contoh:

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

Untuk membangun, jalankan:

docker-compose up -d

Bacaan lebih lanjut:

Murmel
sumber
2

Dengan Docker v1.9 Anda dapat menggunakan instruksi ARG untuk mengambil argumen yang dilewatkan oleh baris perintah ke gambar saat dibuat . Cukup gunakan flag --build-arg . Jadi Anda dapat menghindari untuk menyimpan kata sandi eksplisit (atau informasi masuk akal lainnya) di Dockerfile dan meneruskannya dengan cepat.

sumber: https://docs.docker.com/engine/reference/commandline/build/ http://docs.docker.com/engine/reference/builder/#arg

Contoh:

Dockerfile

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

membangun perintah gambar

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

selama build it print

$ 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

Semoga ini bisa membantu! Sampai jumpa.

NickGnd
sumber
26
Menurut dokumen ARG Docker : "Tidak disarankan untuk menggunakan variabel build-time untuk meneruskan rahasia seperti kunci github, kredensial pengguna, dll."
Lie Ryan
3
Hanya bertanya-tanya mengapa Docker tidak merekomendasikan untuk digunakan --build-arg var=secretuntuk melewatkan kunci pribadi SSH ke gambar, tidak ada alasan yang didokumentasikan. Adakah yang bisa menjelaskannya?
Henk Wiersema
2
@HenkWiersema Informasi proses, log, dan riwayat perintah tidak aman. Informasi proses tersedia untuk umum dan itu mencakup semua parameter baris perintah. Seringkali panggilan ini berakhir di log yang dapat juga publik. Ini tidak biasa bagi penyerang untuk memeriksa informasi tentang proses yang sedang berjalan dan menjaring logfile publik untuk mencari rahasia. Bahkan ketika itu bukan publik, itu dapat disimpan dalam sejarah perintah Anda yang akan memudahkan seseorang untuk mendapatkan rahasia melalui akun non-administratif.
tu-Reinstate Monica-dor duh
2
Apa cara yang disarankan untuk memasok kredensial yang diperlukan saat membangun? Misalnya, gambar yang membutuhkan akses s3 aws untuk mengambil kumpulan data besar yang akan berada di dalam gambar?
Ely
3
Saya membayangkan alasan mengapa tidak direkomendasikan adalah karena docker historymengekspos build-arg/ ARGvariabel. Satu dapat menarik gambar apapun, memeriksanya dan melihat rahasia berlalu selama membangun sebagai build-arg/ ARGparameter.
vee_ess
2

Pendekatan saya tampaknya berhasil, tetapi mungkin naif. Katakan padaku mengapa itu salah.

ARG yang ditetapkan selama pembuatan buruh pelabuhan terpapar oleh perintah sejarah, jadi jangan pergi ke sana. Namun, saat menjalankan wadah, variabel lingkungan yang diberikan dalam perintah jalankan tersedia untuk wadah, tetapi bukan bagian dari gambar.

Jadi, di Dockerfile, lakukan pengaturan yang tidak melibatkan data rahasia. Tetapkan CMD dari sesuatu seperti /root/finish.sh. Dalam menjalankan perintah, gunakan variabel lingkungan untuk mengirim data rahasia ke dalam wadah. finish.shmenggunakan variabel dasarnya untuk menyelesaikan membangun tugas.

Untuk mempermudah mengelola data rahasia, masukkan ke dalam file yang dimuat oleh buruh pelabuhan dengan --env-filesakelar. Tentu saja, jaga kerahasiaannya. .gitignoredan seperti.

Bagi saya, finish.shjalankan program Python. Itu memeriksa untuk memastikan itu belum berjalan sebelumnya, kemudian menyelesaikan pengaturan (misalnya, menyalin nama database ke Django settings.py).

Kieran Mathieson
sumber
2

Ada perintah buruh pelabuhan baru untuk manajemen "rahasia". Tapi itu hanya berfungsi untuk kelompok swarm.

docker service create
--name my-iis
--publish target=8000,port=8000
--secret src=homepage,target="\inetpub\wwwroot\index.html"
microsoft/iis:nanoserver 
José Ibañez
sumber
1

The 12-Factor metodologi aplikasi mengatakan, bahwa konfigurasi harus disimpan dalam variabel lingkungan.

Penulisan Docker dapat melakukan substitusi variabel dalam konfigurasi, sehingga dapat digunakan untuk meneruskan kata sandi dari host ke docker.

Bunyk
sumber
Saya menghargai referensi ke Alkitab.
JakeCowton
-2

Sementara saya setuju sepenuhnya, tidak ada solusi sederhana. Terus ada satu titik kegagalan. Entah dockerfile, etcd, dan sebagainya. Apcera memiliki rencana yang mirip dengan sidekick - otentikasi ganda. Dengan kata lain dua wadah tidak dapat berbicara kecuali ada aturan konfigurasi Apcera. Dalam demo mereka, uid / pwd jelas dan tidak dapat digunakan kembali sampai admin mengkonfigurasi tautannya. Agar ini berfungsi, mungkin berarti menambal Docker atau setidaknya plugin jaringan (jika ada hal seperti itu).

Richard
sumber
2
Apakah ada jawaban di suatu tempat untuk pertanyaan yang diajukan?
Abhijit Sarkar