Найпоширеніший спосіб передати пароль бази чи ключ API в контейнер - змінна оточення. Але змінні оточення легко витікають:
docker inspectпоказує всі змінні контейнера відкритим текстом - будь-хто з доступом до Docker на хості їх бачить;/proc/<pid>/environ- процеси з достатніми правами читають оточення інших процесів;- дочірні процеси успадковують оточення: сторонній бінарний файл, запущений застосунком, отримує всі секрети;
- логи й звіти про помилки: сторінки налагодження,
phpinfo(), дампи оточення в системах моніторингу; ENVу Dockerfile зберігається в образі - будь-хто з доступом до образу (реєстр) прочитаєdocker history/docker inspectобразу.
Секрети Compose монтують значення файлом у /run/secrets/<назва>:
services:
app:
image: myapp
secrets:
- db_password
environment:
DB_PASSWORD_FILE: /run/secrets/db_password
secrets:
db_password:
file: ./secrets/db_password.txt # або environment: DB_PASSWORD з оточення хоста
- значення не видно в
docker inspectконтейнера; - доступ лише для сервісів, яким секрет явно надано;
- багато офіційних образів підтримують змінні з суфіксом
_FILE(POSTGRES_PASSWORD_FILE,MYSQL_ROOT_PASSWORD_FILE) - читають секрет з файлу.
Застосунок має вміти читати секрет з файлу. Для Laravel - невеликий код у конфігурації чи завантаження змінних з файлу на старті контейнера (скрипт-обгортка, що читає /run/secrets/* і експортує їх лише для процесу PHP).
Що варто пам'ятати:
- секрети Compose без Swarm - це по суті bind mount файлу: захищають від
inspectі випадкового витоку, але не від root на хості; - у продакшені - менеджери секретів (Vault, AWS Secrets Manager, Doppler) чи механізми оркестратора (Kubernetes Secrets з шифруванням);
- на етапі збирання образу секрети передаються через
RUN --mount=type=secret, а неARGчиENV; - файл
.envз секретами - у.dockerignoreі.gitignore.