Sebagian besar aplikasi membutuhkan data yang bersifat rahasia untuk bekerja, dan data semacam itu perlu penanganan yang berbeda dari konfigurasi biasa. Topik ini membahas apa itu secret, data sensitif yang membuka akses pada sistem lain, kemudian membedah tiga tempat yang paling sering membocorkannya, yaitu layer image, repositori git, dan variabel lingkungan runtime. Bagian akhirnya memperkenalkan praktik yang lebih aman untuk kebutuhan build maupun runtime. Topik ini sekaligus menyediakan mekanisme pengganti untuk larangan menampung rahasia pada ARG dan ENV yang sudah ditegaskan pada modul Image dan Dockerfile.
Apa itu secret#
Secret adalah nilai yang membuka akses pada sistem lain, dan kebocorannya langsung memberi pihak luar hak yang sama dengan aplikasi. Contohnya tiga macam nilai berikut.
- Kata sandi basis data, misalnya
rahasia-db-catatanuntuk basis data aplikasi catatan. - token API, kode pengganti kredensial yang diberikan layanan lain dan dapat dicabut terpisah.
- Kunci tanda tangan, nilai yang dipakai aplikasi menandai data sehingga keasliannya dapat diverifikasi.
Ciri yang membedakan secret dari konfigurasi biasa adalah akibat kebocorannya. Port aplikasi yang terbaca orang lain hampir tidak berdampak, sedangkan kata sandi basis data yang terbaca berarti basis data bisa dibuka dari mana saja. Karena itu penanganan secret ditetapkan sebagai aturan keras, bukan sekadar rekomendasi, dan aturannya sederhana, yaitu secret hanya boleh diketahui oleh proses yang benar-benar memakainya pada saat memakainya. Sekali sebuah nilai dianggap bocor, nilai itu wajib diganti, dan penggantiannya inilah yang disebut rotasi.
Tiga tempat yang sering bocor#
Tempat bocor yang pertama adalah layer image. Nilai yang diisi lewat --build-arg tercatat pada instruksi Dockerfile dan terbaca kembali lewat docker history, sedangkan nilai ENV tersimpan pada konfigurasi image dan terbaca lewat docker inspect. Keduanya tampil apa adanya tanpa alat tambahan, sehingga secret yang lolos ke ARG maupun ENV sebenarnya sudah diterbitkan kepada semua orang yang dapat menarik image tersebut.
Tempat bocor yang kedua adalah repositori git. Berkas .env yang berisi secret sering dibuat di direktori proyek untuk kenyamanan pengembangan, lalu ikut terkomit (commit, rekaman perubahan yang tersimpan pada riwayat git) bersama kode. Berkas semacam ini semestinya masuk daftar .gitignore sejak hari pertama proyek. Masalah yang paling sering terjadi adalah berkas itu sudah terlanjur terkomit sebelum aturan itu dipasang.
KATA_SANDI_DB=rahasia-db-catatan
TOKEN_API=token-contoh-aplikasi-catatanTempat bocor yang ketiga adalah variabel lingkungan runtime. Secret yang disuntikkan dengan -e atau berkas .env memang tidak masuk image. Namun, docker inspect pada container yang berjalan menampilkan seluruh variabel lingkungannya. Proses lain di dalam container yang sama, misalnya shell yang dibuka dengan docker exec, dapat membacanya pula. Pesan error dan log aplikasi pun kadang ikut mencetak isi variabel lingkungan tanpa sengaja.
Demonstrasi: nilai ENV terbaca kembali#
Perangkat lunak Docker tidak tersedia di sandbox, tetapi mekanisme kebocoran pada layer image dapat diperagakan dengan berkas teks biasa. Blok berikut menulis Dockerfile kecil yang memuat nilai ENV ke direktori sementara, lalu membaca nilai itu kembali dari berkasnya, persis seperti cara docker history membaca instruksi pada layer.
# simulasi: menunjukkan bahwa nilai ENV pada Dockerfile terbaca kembali
(
# membuat direktori sementara agar berkas proyek tidak tersentuh
DIR=$(mktemp -d)
cd "$DIR"
# menulis Dockerfile kecil yang memuat nilai ENV
cat > Dockerfile <<'EOF'
FROM python:3.12-slim
ENV KUNCI_DB=rahasia-db-catatan
COPY app.py .
EOF
# membaca kembali nilai tersebut, meniru cara docker history membaca layer
grep KUNCI_DB Dockerfile
)ENV KUNCI_DB=rahasia-db-catatanNilai rahasia-db-catatan tampil kembali utuh dari berkas yang ditulis di atas. Seluruh simulasi berjalan dalam subshell pada direktori sementara, sehingga berkas proyek tidak tersentuh. Pada image sungguhan, pembacaan seperti itu dilakukan dengan docker history aplikasi-catatan, yang menampilkan setiap instruksi build beserta nilai yang dipakainya, dan dengan docker inspect, yang menampilkan konfigurasi ENV image. Simulasi ini memperlihatkan intinya, yaitu Dockerfile dan layer image hanyalah berkas teks yang dapat dibaca siapa pun, sehingga nilai apa pun yang ditulis di dalamnya dianggap sudah terbit. Cara pemeriksaan seperti ini berguna pula untuk menelaah Dockerfile milik orang lain, karena isi berkasnya terbaca tanpa harus membangun apa pun.
Praktik yang lebih aman#
Praktik yang lebih aman dipilih sesuai kebutuhan, yaitu apakah secret dibutuhkan saat build, saat container berjalan, atau pada skala produksi. Tabel berikut merangkum ketiganya.
| Kebutuhan | Praktik | Cara kerja |
|---|---|---|
| Secret saat build | Secret BuildKit | BuildKit memasang secret sebagai berkas sementara selama RUN, tanpa menulisnya pada layer |
| Secret saat runtime dengan Compose | Secret Compose | berkas secret dipasang di /run/secrets/ dan dibaca aplikasi saat menyala |
| Produksi dengan banyak layanan | Manajer secret eksternal | secret disimpan terpusat dan disuntikkan ke aplikasi saat runtime |
Secret BuildKit ditulis sebagai opsi --mount pada instruksi RUN di Dockerfile, lalu diisi lewat flag --secret pada docker build. Contoh berikut memasang token index paket privat, sedangkan alamat index yang tidak sensitif tetap lewat ARG.
FROM python:3.12-slim
WORKDIR /aplikasi
COPY requirements.txt .
# Alamat index tidak sensitif, sehingga boleh diterima lewat ARG
ARG INDEX_PAKET
# Token dipasang BuildKit sebagai berkas sementara selama RUN ini
RUN --mount=type=secret,id=token_paket \
pip install --no-cache-dir \
--index-url "https://aplikasi:$(cat /run/secrets/token_paket)@${INDEX_PAKET}/simple" \
-r requirements.txt# tidak-dijalankan: daemon Docker tidak tersedia di sandbox
# mengisi secret BuildKit dari berkas lokal saat build
docker build --build-arg INDEX_PAKET=pypi-internal.contoh \
--secret id=token_paket,src=./token_paket.txt -t aplikasi-catatan .Dengan pola ini, token tidak pernah ditulis pada Dockerfile, tidak lewat --build-arg, dan tidak tersimpan pada layer, sehingga docker history hanya menampilkan baris RUN-nya tanpa isi secret. Secret hanya ada sebagai berkas sementara selama instruksi RUN berjalan, lalu hilang bersamaan dengan selesainya instruksi tersebut.
Untuk runtime, Compose menyediakan mekanisme serupa. Deklarasi secrets menghubungkan satu nama secret dengan berkas sumbernya, lalu Compose memasang berkas itu di dalam container pada /run/secrets/.
services:
aplikasi:
image: aplikasi-catatan
secrets:
- kunci_db
secrets:
kunci_db:
file: ./kunci_db.txtAplikasi membaca /run/secrets/kunci_db saat menyala, dan nilai tersebut tidak tampak pada docker inspect sebagai variabel lingkungan karena bentuknya berkas, bukan variabel lingkungan. Untuk produksi dengan banyak layanan, secret dikelola pada sistem manajemen secret terpusat, yaitu layanan khusus yang menyimpan secret, mencatat siapa yang memakainya, dan mendistribusikannya saat runtime. Rotasi secret menjadi pekerjaan yang terpusat pula, sehingga satu secret yang bocor cukup diganti di satu tempat.
Kesalahan umum#
Tiga kesalahan berikut masih sering terjadi meskipun larangannya sudah ditegaskan.
- Menaruh secret pada ARG karena dianggap hilang setelah build. Nilai
--build-argterbaca kembali padadocker history, sehingga secret itu ikut terbit bersama image. Perbaikannya, pakai secret BuildKit denganRUN --mount=type=secret. - Menghapus
.envdari repositori tanpa mengganti secretnya. Riwayat git masih menyimpan nilai lama, sehingga kebocorannya tetap terbuka. Perbaikannya, ganti dan cabut secret tersebut, baru bersihkan berkasnya. - Menyimpan secret pada ENV demi kenyamanan.
docker inspectdan proses lain di container menampilkannya dengan mudah. Perbaikannya, sampaikan secret sebagai berkas di/run/secrets/atau lewat manajer secret terpusat. - Menganggap secrets pada CI menggantikan seluruh perlindungan. Nilai dari
secrets.DOCKERHUB_TOKENtetap bisa bocor bila skrip buatan sendiri mencetaknya pada log. Perbaikannya, pastikan skrip tidak menampilkan kredensial dan rotasi token dijalankan secara berkala.
Ringkasan#
- Secret adalah data sensitif seperti kata sandi basis data, token API, dan kunci tanda tangan yang kebocorannya langsung membuka akses.
- Tiga tempat bocor yang lazim adalah layer image melalui ARG dan ENV, repositori git melalui
.envyang terkomit, dan variabel lingkungan runtime yang terbaca viadocker inspect. - Praktik yang lebih aman adalah secret BuildKit saat build, secret Compose atau berkas
/run/secrets/saat runtime, dan manajer secret terpusat untuk produksi. - Secret hanya tersedia pada saat dibutuhkan dan tidak pernah tertanam pada image maupun konfigurasi yang tersimpan.
Referensi#
- Build secrets — Docker Docs
— Cara memakai secret BuildKit dengan
RUN --mount=type=secretdan flag--secret. - Use Compose secrets — Docker Docs
— Menyediakan secret pada Compose melalui berkas yang dipasang di
/run/secrets/. - Dockerfile reference — Docker Docs
— Sintaks instruksi RUN beserta flag
--mountyang dipakai secret BuildKit.