Шифруйте контейнеры или Как обойти ограничения на частные репозитории в публичных реестрах контейнеров

от автора

Если вы не хотите платить за дополнительные частные репозитории или чтобы в ваших контейнерах копались все подряд, читайте дальше…

В Docker Hub и других реестрах контейнеров существуют ограничения на частные репозитории. Чтобы сохранить образы контейнеров недоступными для публичного скачивания, нужно заплатить, и чем больше частных репозиториев вам нужно, тем выше стоимость. Однако есть способ обойти это ограничение, давайте узнаем как.

TL;DR: Используйте зашифрованные образы.

В Podman есть функция, позволяющая шифровать образы контейнеров, делая их доступными только с определенным ключом. Это делает образы конфиденциальными, даже если они хранятся в общедоступном хранилище. Кроме того, для дополнительной безопасности можно зашифровать сам ключ с помощью пароля. Давайте посмотрим, как это сделать!

Для начала вам нужно установить Podman. Это альтернатива Docker и, на мой взгляд, более функциональная, так что ее стоит иметь в своей системе. Впрочем, не волнуйтесь — вы сможете запускать все с помощью того же Docker. Podman необходим для загрузки и скачивания образов, которые затем будут импортированы в Docker и запущены как обычно. Мы будем использовать как командную строку, так и Ansible для лучшей автоматизации.

Для использования всех возможностей Ansible нам понадобится коллекция Ansible Podman, которая предоставляет широчайшие возможности для автоматизации любых контейнеров и гибкие способы работы со всеми технологиями, связанными с контейнерами — собственно контейнерами, контейнерными сетями, томами, подами, образами, секретами, реестрами и многим другим. Она входит в официальный дистрибутив Ansible, поэтому вы можете использовать ее оттуда, но функции, которые нам нужны, являются новейшими, и скорее всего нам нужно будет установить ее из Ansible Galaxy:

ansible-galaxy collection install containers.podman

или, если вы хотите получить все самое лучшее и свежее, возьмите из мастера:

git clone https://github.com/containers/ansible-podman-collections cd ansible-podman-collections ansible-galaxy collection install --force .

Теперь мы готовы!

Генерация ключей шифрования

Сначала давайте изучим функциональность ключей шифрования. Нам нужно сгенерировать открытый и закрытый ключи для шифрования и дешифрования, они также могут быть защищены паролем. Для этого можно использовать образ или бинарник OpenSSL:

mkdir -p keys openssl genrsa -out ./keys/container_private.pem 2048 && \ openssl rsa -in ./keys/container_private.pem -pubout -out ./keys/container_public.pem

Если у вас не установлен openssl, вы можете использовать контейнер nginx, который мы в любом случае будем использовать для постройки образов контейнера для тестов:

docker run -it -v $PWD/keys:/data:z docker.io/library/nginx sh -c "\ openssl genrsa -out /data/container_private.pem 2048 && \ openssl rsa -in /data/container_private.pem -pubout -out /data/container_public.pem"

Эта же команда работает с podman вместо docker:

podman run -it -v $PWD/keys:/data:z docker.io/library/nginx sh -c "\ openssl genrsa -out /data/container_private.pem 2048 && \ openssl rsa -in /data/container_private.pem -pubout -out /data/container_public.pem"

В Ansible вы можете сгенерировать ключи следующим образом:

- name: Generate SSL keys   containers.podman.podman_container:     name: temporary     state: started     image: docker.io/library/nginx     rm: true     volumes:       - /tmp/keys:/data:z     command:       - bash       - -c       - >-         openssl genrsa -out /data/container_private.pem 2048 &&         openssl rsa -in /data/container_private.pem -pubout -out /data/container_public.pem 

Ключи будут находиться в каталоге /tmp/keys, или вы можете указать свой собственный путь.

Сборка и шифрование контейнера

Далее давайте соберем и зашифруем контейнер.
Создайте Dockerfile:

cat <<EOF> Dockerfile FROM docker.io/library/nginx COPY index.html /usr/share/nginx/html/index.html EOF  echo "test passed" > index.html podman build . -t docker.io/sshnaidm/something:open

Мы используем Podman для сборки, потому что загрузка зашифрованного образа в реестр может быть выполнено только с помощью инструмента Podman. Однако конвертирование образов между podman и docker очень простое:

docker save docker.io/sshnaidm/something:open | podman load # или так podman image push docker.io/sshnaidm/something:close docker-daemon:docker.io/sshnaidm/something:closed

В Ansible создайте, постройте и выложите образ в репозиторий:

- name: Create Dockerfile   copy:     content: |       FROM docker.io/library/nginx       COPY index.html /usr/share/nginx/html/index.html     dest: "{{ playbook_dir }}/Dockerfile"  - name: Create index.html   copy:     content: "<h1>test passed!</h1>"     dest: "{{ playbook_dir }}/index.html"  - name: Build and push the image   containers.podman.podman_image:     name: docker.io/sshnaidm/something     tag: closed     path: "{{ playbook_dir }}"     state: build     build:       file: "{{ playbook_dir }}/Dockerfile"     push: true     push_args:       dest: docker.io/sshnaidm/something:closed       extra_args: --encryption-key jwe:/absolute/path/to/keys/container_public.pem 

Теггирование и выгрузка с шифрованием

Тегировать и выгрузить образ с помощью podman с шифрованием JWE:

cd keys/ podman tag docker.io/sshnaidm/something:open docker.io/sshnaidm/something:closed podman push --encryption-key jwe:container_public.pem docker.io/sshnaidm/something:closed

Мы загрузили наш зашифрованный образ в Docker Hub. Теперь попробуйте скачать его с помощью docker или podman:

$ podman pull docker.io/sshnaidm/something:closed Trying to pull docker.io/sshnaidm/something:closed... Getting image source signatures Copying blob 37745a742023 [--------------------------------------] 0.0b / 1.4KiB | 0.0 b/s Copying blob 37745a742023 done   |  [skipped...] Error: writing blob: adding layer with blob "sha256:69458e593f618c768281ca90b8ed5eb78df30df39902d948f894fd8c7e80906f": processing tar file(archive/tar: invalid tar header): exit status 1 

Не-а, не получается 🙂

С помощью docker:

$ docker pull docker.io/sshnaidm/something:closed closed: Pulling from sshnaidm/something 69458e593f61: Extracting [==================================================>]  32.74MB/32.74MB 1a1e276c1a3b: Download complete  [skipped...] failed to register layer: archive/tar: invalid tar header 

Не-а, не получается 🙂

Невозможно скачать и использовать образ без ключа. Только имея ключ можно загрузить его, что фактически делает его приватным образом контейнера в публичном репозитории!

Скачивание и запуск зашифрованного образа

Скачать и использовать зашифрованный образ:

cd keys/ podman pull --decryption-key container_private.pem docker.io/sshnaidm/something:closed # Load it to Docker if you can't use Podman: podman save docker.io/sshnaidm/something:closed | docker load docker run -d --name webserver -p 8888:80 docker.io/sshnaidm/something:closed curl localhost:8888 $ test passed 

С помощью Ansible вы можете скачать и запустить его в одной таске:

- name: Run container   containers.podman.podman_container:     name: webserver     image: docker.io/sshnaidm/something:closed     state: started     decryption_key: /full/path/to/keys/container_private.pem     publish:       - 8888:80 

И наконец:

curl localhost:8888 $ test passed 

Полезные Bash-скрипты и Ansible Playbook

Для удобства здесь приведены bash скрипты для клиента и сервера, а также плейбук Ansible для сборки и распространения образа из публичного реестра, как если бы он был приватным:

На клиенте создайте образ, сгенерируйте ключи и отправьте его в зашифрованном виде:

# On client, build image, generate keys, and push encrypted openssl genrsa -out container_private.pem 2048 openssl rsa -in container_private.pem -pubout -out ./keys/container_public.pem  cat <<EOF> Dockerfile FROM docker.io/library/nginx COPY index.html /usr/share/nginx/html/index.html EOF  echo "test passed" > index.html  podman build . -t docker.io/sshnaidm/something:production podman push --encryption-key jwe:container_public.pem docker.io/sshnaidm/something:production 

Скопируйте файл container_private.pem на сервер и выполните там:

podman pull --decryption-key container_private.pem docker.io/sshnaidm/something:production # In case of Docker: podman save docker.io/sshnaidm/something:production | docker load docker run -d --name webserver -p 8888:80 docker.io/sshnaidm/something:production # In case of Podman: podman run -d --name webserver -p 8888:80 docker.io/sshnaidm/something:production 

Или все это вместе выполните одним Ansible плейбуком:

- hosts: client   tasks:      - name: Generate SSL keys       containers.podman.podman_container:         name: temporary         state: started         image: docker.io/library/nginx         rm: true         volumes:           - /tmp/keys:/data:z         command:           - bash           - -c           - >-             openssl genrsa -out   /data/container_private.pem 2048 &&             openssl rsa -in /data/container_private.pem -pubout -out /data/container_public.pem      - name: Create Dockerfile       copy:         content: |           FROM docker.io/library/nginx           COPY index.html /usr/share/nginx/html/index.html         dest: "{{ playbook_dir }}/Dockerfile"      - name: Create index.html       copy:         content: "<h1>test passed!</h1>"         dest: "{{ playbook_dir }}/index.html"      - name: Build and push image       containers.podman.podman_image:         name: docker.io/sshnaidm/something         tag: production         path: "{{ playbook_dir }}"         state: build         build:           file: "{{ playbook_dir }}/Dockerfile"         push: true         push_args:           dest: docker.io/sshnaidm/something:production           extra_args: --encryption-key jwe:/absolute/path/to/keys/container_public.pem  - hosts: server   tasks:      - name: Distribute keys       copy:         src: /full/path/to/keys/container_private.pem         dest: /full/path/to/keys/container_private.pem      - name: Run container with Podman       containers.podman.podman_container:         name: webserver         image: docker.io/sshnaidm/something:production         state: started         decryption_key: /full/path/to/keys/container_private.pem         publish:           - 8888:80 

Сэкономьте на публичных репозиториях и сделайте свои образы контейнеров более защищенными!

П.С. Когда это писалось докерхаб был ещё доступен, поэтому основной фокус теперь все таки на шифровании, особенно если пользоваться различными непонятными реестрами и ненадежными сервисами.


ссылка на оригинал статьи https://habr.com/ru/articles/819511/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *