Под секретами подразумеваются: логины, пароли, сертификаты, api ключи, ssh ключи и другие секретные данные. В основном конечно это данные необходимые для подключения к тому или иному сервису.

Конечно на данный момент уже существует куча сервисов сторонних компаний для хранения секретов, например, Hashicorp Vault. Но минус таких сервисов в том, что их еще нужно развернуть и настроить.

С версии Docker 1.13.0 база, которую использует Swarm лежит на диске в зашифрованном виде по умолчанию, которая находится на менеджерах кластера. По умолчанию именно тут хранится вся информация необходимая для коммуникации узлов кластера между собой. Например, tls сертификаты для узлов.

В самом начале необходимо конечно же поместить секреты в саму базу и уже потом передать эти секреты сервисам и соответственно их контейнерам/задачам. Только контейнеры в сервисе могут получить доступ к этим секретам, т.е. контейнеры вне сервиса не смогут получить доступ к ним. Все эти секреты помещаются в оперативную память и доступны внутри контейнера по пути /run/secrets/<имя>. Хранится всё в виде ключ: значение.

В этом конфиг-файле для стека swarm я поместил все пароли в открытом виде. И понятное дело, что это может привести к утечке и последующему взлому, поэтому использовать такой вариант в боевой среде не рекомендуется.

Также если передавать пароли через переменные при создании сервиса или контейнера, то при выполнении команды docker container inspect эти пароли будут выведены.

swarm-secrets-concept.svg

Создание секрета

Для того, чтобы добавить новый секрет в кластер Swarm используется команда docker secreat create.

Вариант 1️⃣

Для начала создаётся файл, в который помещается секрет. После используется команда docker secreat create для создания секрета со значением из файла.

vim psql_user.txt
app
docker secret create psql_user psql_user.txt
y5jqu91e43jivxje614br60op

После добавления секрета необходимо удалить файл.

rm psql_user.txt

Вариант 2️⃣

Этот вариант не рекомендуется использовать потому что при использовании мониторинга с записью всех команд пользователя в консоли пароль может быть записан в систему мониторинга.

set +o history
echo "secret" | docker secreat create psql_pwd
set -o history

swarm-secret-creation.svg

Просмотр секретов

Для того чтобы просмотреть какие секреты есть в базе используется команда docker secret ls.

docker secret ls
ID                          NAME        DRIVER    CREATED          UPDATED
y5jqu91e43jivxje614br60op   psql_user             29 seconds ago   29 seconds ago

После того как секрет был создан я сам уже не смогу получить его содержимое, только сервис (контейнер) может получить к нему доступ.

Передача секретов контейнерам

Для примера я создам сервис с образа postgresql и передам ему секрет psql_user и psql_pwd.

docker service create \
  --name db-key \
  --secret psql_user \
  --secret psql_pwd \
  -e POSTGRES_DB=app \
  -e POSTGRES_PASSWORD_FILE=/run/secrets/psql_pwd \
  -e POSTGRES_USER_FILE=/run/secrets/psql_user \
  postgres:16

Проверю что контейнер сервиса запущен и работает:

docker service ps db-key
ID             NAME       IMAGE         NODE             DESIRED STATE   CURRENT STATE            ERROR     PORTS
sxe1t1rbeew0   db-key.1   postgres:16   c-stream-9-vm4   Running         Running 18 seconds ago

В конфиг файле сервиса это передаётся как:

version: "3.8"

services:
  db:
    image: postgres:16
    environment:
      POSTGRES_DB: app
      POSTGRES_USER_FILE: /run/secrets/psql_user 
      POSTGRES_PASSWORD_FILE: /run/secrets/psql_pwd 
    secrets:
      - psql_pwd 
      - psql_user 
    volumes:
      - db_data:/var/lib/postgresql/data
    networks:
      - backend

secrets:
  psql_pwd:
    external: true   # secret уже создан командой `docker secret create`
  psql_user:
    external: true   # secret уже создан командой `docker secret create`

networks:
  backend:
    driver: overlay

volumes:
  db_data:

Обратите внимание если секреты уже созданы еще до создания самого сервиса необходимо указать параметр external: true, если же секреты еще не созданы, то передаём путь к файлу со значением.

secrets:
  psql_pwd:
    file : ./psql_pwd.txt
	psql_user: 
    file : ./psql_user.txt

Проверка что секреты проброшены

Для проверки я переходу в псевдотерминал контейнера сервиса db и проверяю там файлы в директории /run/secrets.

docker exec -it db-key.1.sxe1t1rbeew0v3yml18zkgfzr bash
ls /run/secrets/
psql_pwd  psql_user
cat /run/secrets/psql_pwd  
secret

Теперь если я выполню команду docker container inspect в выводе я не увижу само имя пользователя или пароль в открытом виде.

docker container inspect db-key.1.sxe1t1rbeew0v3yml18zkgfzr
			"Env": [
                "POSTGRES_DB=app",
                "POSTGRES_PASSWORD_FILE=/run/secrets/psql_pwd",
                "POSTGRES_USER_FILE=/run/secrets/psql_user",
                "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/lib/postgresql/16/bin",
                "GOSU_VERSION=1.19",
                "LANG=en_US.utf8",
                "PG_MAJOR=16",
                "PG_VERSION=16.11-1.pgdg13+1",
                "PGDATA=/var/lib/postgresql/data"
            ],