Rahasia aman saat membangun di Docker Compose

Terjemahan artikel disiapkan sebelum dimulainya kursus Pengembang Web Python .




Ketika Anda membangun gambar Docker, Anda mungkin perlu rahasia, seperti kata sandi untuk repositori paket pribadi. Anda tidak ingin rahasia ini berakhir di gambar, karena siapa pun yang mendapatkan akses ke gambar akan mendapatkan akses ke repositori pribadi Anda.
Catatan : Jika Anda berpikir "Mengapa tidak hanya menggunakan variabel lingkungan?" Yang digunakan untuk rahasia dalam runtime saat membuat gambar. Artikel ini berfokus pada membangun rahasia yang digunakan saat membuat gambar menggunakan file Docker.
Docker versi terbaru menyimpan rahasia menggunakan layanan BuildKit eksperimental , dan di Docker Compose 1.25 dan yang lebih baru, Anda sudah dapat membuat gambar menggunakan BuildKit. Sayangnya, pada Maret 2020, kemampuan untuk bekerja dengan aman dengan rahasia dari Compose masih dalam pengembangan .

Jadi apa yang harus dilakukan sekarang?

Dalam artikel hari ini, saya akan menunjukkan bagaimana Anda dapat menggunakan Dockerfile yang sama untuk secara aman membuat gambar rahasia tanpa kehilangan manfaat pengembangan cepat menggunakan Docker Compose.

Dua opsi untuk menggunakan dockerfile Anda


Sangat nyaman untuk menggunakan Dockerfile yang sama untuk produksi dan untuk pengembangan lokal dengan Docker Compose. Biasanya Anda menggunakan Dockerfile bersama dengan fungsi build dari Compose:

version: "3.7"
services:
  yourapp:
    build:
      context: "."	

Maka Anda dapat melakukan:

$ docker-compose up

Dengan perintah ini, Anda dapat (kembali) mengumpulkan gambar dan kemudian menjalankannya.
Untuk digunakan pada produksi, Anda mengumpulkan gambar dan mengirimkannya dengan dorongan :

$ docker build -t myimage .
$ docker push myimage

Dan sementara semuanya berjalan dengan baik. Tetapi bagaimana jika Anda membutuhkan bangunan rahasia?

Percobaan pertama (tidak aman)


Misalkan Anda memiliki skrip yang memerlukan bangunan rahasia, misalnya, untuk mengunduh paket Python dari repositori DevPI pribadi . Untuk kesederhanaan, kami hanya akan mendapatkan rahasia dengan bantuan use-secret.shuntuk menunjukkan bahwa kami memilikinya.

#!/bin/bash
set -euo pipefail

echo "Secret is: $THEPASSWORD"

Anda bisa meneruskan rahasia menggunakan argumen build Docker, karena mereka didukung di mana-mana, termasuk di Docker Compose.
Catatan : Melampaui ruang lingkup diskusi kami, saya ingin mengatakan bahwa penggunaan file Docker dalam artikel ini bukan praktik terbaik, namun kompleksitas yang berlebihan dapat mengganggu penyampaian makna utama artikel.
Oleh karena itu, jika Anda ingin menjalankan aplikasi Python di produksi dengan Docker, berikut adalah dua cara yang baik untuk melakukan ini:


FROM python:3.8-slim-buster
# Using ARG for build secrets is INSECURE!
ARG THEPASSWORD
COPY use_secret.sh .
RUN ./use_secret.sh

Kita dapat menulis docker-compose.yml, yang akan dikirimkan secara rahasia:

version: "3.7"
services:
  yourapp:
    build:
      context: "."
      args:
        THEPASSWORD: "s3kr!t"

Untuk pekerjaan lokal, Anda dapat menjalankan atau membuat gambar menggunakan Tulis:

$ docker-compose build | grep Secret
Secret is: s3kr!t

Dan semuanya baik-baik saja.

Dan kita juga dapat merakit gambar menggunakan Docker, dalam persiapan untuk memindahkannya ke registri gambar:

$ docker build -t myimage --build-arg THEPASSWORD=s3krit . | grep Secret
Secret is: s3krit

Melakukan hal itu tidak aman: jangan pernah melakukannya . Jika kita memutuskan untuk melihat lapisan gambar, kita akan melihat rahasianya terbaring di dalamnya!

$ docker history myimage
IMAGE               CREATED              CREATED BY                                      SIZE
c224231ec30b        47 seconds ago       |1 THEPASSWORD=s3krit /bin/sh -c ./use_secre…   0B
6aef62acf0db        48 seconds ago       /bin/sh -c #(nop) COPY file:7aa28bbe6595e0d5…   62B
f88b19ca8e65        About a minute ago   /bin/sh -c #(nop)  ARG THEPASSWORD              0B
...

Siapa pun yang mendapatkan akses ke gambar ini akan mengenali kata sandi Anda. Lalu apa yang bisa dilakukan?

Rahasia BuildKit (Solusi Sebagian)


BuildKit adalah solusi baru (dan masih eksperimental) untuk membuat gambar Docker, yang, antara lain, menambahkan dukungan untuk penggunaan rahasia yang aman selama perakitan . Docker Compose memiliki dukungan BuildKit sejak v1.25.

Tetapi ada satu masalah: Menulis Docker masih tidak mendukung fungsionalitas rahasia BuildKit. Sekarang sedang dilakukan pekerjaan ini, tetapi pada Maret 2020, tidak ada solusi siap pakai, belum lagi rilis stabil.

Karena itu, kami akan menggabungkan dua pendekatan ini:

  • Docker Compose akan terus menggunakan argumen build untuk memberikan rahasia;
  • Untuk gambar produksi yang dibangun menggunakan buruh pelabuhan, kami menggunakan BuildKit untuk memberikan rahasia.

Dengan cara ini kita dapat menggunakan Dockerfile yang sama untuk bekerja secara lokal dan pada produksi.
BuildKit bekerja dengan rahasia sebagai berikut: file dengan rahasia dipasang di direktori sementara sementara perintah RUN dijalankan, misalnya, dalam /var/secrets/thepassword. Karena sudah terpasang selama pelaksanaan perintah RUN, itu tidak akan ditambahkan ke gambar akhir.

Kami akan memodifikasi file use_secret.shuntuk memeriksa apakah ada file sementara. Jika ada, ia menggunakan pengaturan variabel lingkungannya $THEPASSWORD. Jika file tidak ada, maka kita akan kembali ke variabel environment. Artinya, $THEPASSWORDdapat diinstal menggunakan BuildKit atau membangun argumen:

#!/bin/bash
set -euo pipefail
if [ -f /run/secrets/thepassword ]; then
   export THEPASSWORD=$(cat /run/secrets/thepassword)
fi

echo "Secret is: $THEPASSWORD"

Kemudian kita akan memodifikasi Dockerfile untuk menambahkan BuildKit dan me-mount rahasianya:

# syntax = docker/dockerfile:1.0-experimental
FROM python:3.8-slim-buster
# Only use the build arg for local development:
ARG THEPASSWORD
COPY use_secret.sh .
# Mount the secret to /run/secrets:
RUN --mount=type=secret,id=thepassword ./use_secret.sh

docker-compose.ymlKami tidak mengubah file :

version: "3.7"
services:
  yourapp:
    build:
      context: "."
      args:
        THEPASSWORD: "s3kr!t"

Sekarang Anda perlu mendefinisikan dua variabel lingkungan, salah satunya akan memberi tahu Docker bahwa Anda perlu menggunakan BuildKit, yang kedua yang Compose perlu gunakan versi CLI dari Docker dan, karenanya, BuildKit. Kami juga akan menulis rahasia ke file:

$ export DOCKER_BUILDKIT=1
$ export COMPOSE_DOCKER_CLI_BUILD=1
$ echo 's3krit' > /tmp/mypassword

Dengan Compose, kami menggunakan argumen build:

$ docker-compose build --progress=plain \
    --no-cache 2>&1 | grep Secret
#12 0.347 Secret is: s3kr!t

Harap perhatikan bahwa --no-cacheperlu dipahami bahwa gambar akan benar-benar dibangun kembali jika Anda sendiri menjalankan semua hal di atas. Dalam kehidupan nyata, parameter ini dapat dihilangkan. 2>&1redirect stderrke stdoutuntuk operasi yang benar grep.

Ketika kami siap membangun berdasarkan produksi, kami menggunakan buruh pelabuhan dengan fungsionalitas rahasia dari BuildKit:

$ docker build --no-cache -t myimage \
    --secret id=thepassword,src=/tmp/mypassword \
    --progress=plain . 2>&1 | grep Secret
#12 0.359 Secret is: s3krit

Apakah ini aman?


Mari kita pastikan rahasianya tidak terlihat:

$ docker history myimage
IMAGE               CREATED             CREATED BY                                      SIZE
a77f3c32b723        25 seconds ago      RUN |1 THEPASSWORD= /bin/sh -c ./use_secret.…   0B
<missing>           25 seconds ago      COPY use_secret.sh . # buildkit                 160B
...

Hore! Kami melewati rahasia ke Dockerfile yang sama menggunakan Compose dan docker build, dan dalam kasus terakhir tidak mengungkapkan rahasia dari majelis.



Pelajari lebih lanjut tentang kursus.



All Articles