Развертывание postgresql docker с ssl-сертификатом и ключом с томами

#postgresql #docker #ssl #permissions

#postgresql #docker #ssl #разрешения

Вопрос:

Я пытаюсь развернуть контейнер postgresql. Я пытаюсь поместить ssl-сертификат и ключ в контейнер, используя тома, но я не могу получить правильные разрешения. Файлы должны быть доступны для чтения postgres пользователю контейнера, но также иметь ограниченные разрешения ( 600 ).

Возможно ли это с использованием томов, или мне придется переопределить Dockerfile для этого?

Спасибо.

Ответ №1:

Можно смонтировать ключ и сертификат в контейнер postgres, и postgres сможет использовать их оттуда. Но вам придется столкнуться с проблемой с владельцем и разрешениями server.key .

Из документации PostgreSQL по этому вопросу:

В системах Unix разрешения для server.key должны запрещать любой доступ к миру или группе; добейтесь этого с помощью команды chmod 0600 server.key. В качестве альтернативы файл может принадлежать root и иметь групповой доступ на чтение (то есть разрешения 0640).

Это означает, что вы должны:

  1. Задайте владельцу server.key файла значение root или postgres .
  2. В зависимости от владельца файла server.key вам придется установить для него соответствующие 600 или 640 разрешения. (Обновление: здесь подразумевается, что владельцем группы файла является группа, которая содержит postgres пользователя, как группа по умолчанию postgres )

Если вы работаете с хоста Windows, вам будет нелегко с этим справиться. Потому что разрешения для любого файла в томе, который вы сопоставляете в контейнер, будут -rwxr-xr-x ( 755 ), а владельцем будет root . И вы не сможете изменить это, пока файл монтируется с ваших томов Windows. Если вы попытаетесь использовать chmod для файла, он просто завершится с ошибкой.

С другой стороны, если вы находитесь на хосте Linux, это можно сделать с минимальными усилиями. Разрешения от хост-системы будут сохранены в образе. И право собственности тоже будет, в буквальном смысле. Под этим я подразумеваю, что числовой владелец и владелец группы server.key будут сохранены, когда они будут сопоставлены с томом в контейнере. Между хостом и контейнером они совместно используют ACL Linux, поэтому они просто соблюдают одни и те же свойства файлов. (Владелец, владелец группы, разрешения). Итак, если у вашего локального пользователя Linux на хост-компьютере есть UID:GID 1000:1000 , и вы создаете server.key файл, то для UID:GID файла также будет установлено значение 1000:1000 . Если вы затем сопоставите файл с контейнером и понаблюдаете за ним изнутри — он также просто увидит 1000:1000 . Это означает, что мы можем управлять UID:GID как изнутри, так и снаружи контейнера, при отображении с хоста Linux.

Примечание. Необязательно, чтобы пользователь с UID именем, которое вы назначаете в качестве владельца для файла, разрешалось устанавливать несуществующих UID:GID владельцев файлов.

В alpine производном образе postgres postgres пользователь / группа имеет UID:GID 70:70 . На debian производной postgres UID:GID является 999:999 . И не подавляя, root имеет 0:0 на них обоих.

Это означает, что либо необходимо:

  1. Измените UID:GID содержимое файла server.key после запуска контейнера, когда том уже смонтирован.
  2. Измените UID:GID содержимое файла server.key перед запуском контейнера

Поскольку установка этого параметра после запуска контейнера означала бы вмешательство в сценарии запуска образа postgres — давайте установим их перед запуском контейнера. В локальной файловой системе, из которой вы их монтируете.

Настройка 600 разрешений и postgres в качестве владельца server.key

В случае, если вы используете alpine производную, вам необходимо изменить владельца / группу на 70:70 . Если вы используете debian производную, то 999:999 .

На вашем хостинге может не быть пользователя с помощью, например, UID : 70 , но это не проблема.

Пример:

 chown 70:70 server.key # 70:70 for alpine, 999:999 for debian
chmod 600 server.key
  

Настройка 640 разрешений и root в качестве владельца server.key

Этот пример также предназначен для alpine image

Пример:

 chown 0:70 server.key
chmod 640 server.key
  

На этом этапе все готово. Вам просто нужно сопоставить ключ и сертификат с контейнером и запустить postgres, как обычно.

Решение (linux / unix / macOS)

Я включу сюда фрагмент сценария, который сделает все это за вас для производной alpine. В этом примере будет задан корневой владелец server.key и владелец группы postgres.

 # generate the server.key and server.crt
openssl req -new -text -passout pass:abcd -subj /CN=localhost -out server.req
openssl rsa -in privkey.pem -passin pass:abcd -out server.key
openssl req -x509 -in server.req -text -key server.key -out server.crt

# set postgres (alpine) user as owner of the server.key and permissions to 600
chown 0:70 server.key
chmod 640 server.key

# start a postgres docker container, mapping the .key and .crt into the image.
docker run -d --name postgres  
  -v "$PWD/server.crt:/var/lib/postgresql/server.crt:ro" 
  -v "$PWD/server.key:/var/lib/postgresql/server.key:ro" 
  postgres:11-alpine 
  -c ssl=on 
  -c ssl_cert_file=/var/lib/postgresql/server.crt 
  -c ssl_key_file=/var/lib/postgresql/server.key
  

Я надеюсь, это все прояснит?

В этом суть источника ключа, генерирующего ключ, и сертификата.

Создание образа самостоятельно (решение для Windows)

Я включу небольшое руководство о том, как вы можете создать изображение самостоятельно, чтобы у вас был контейнер базы данных postgres с ssl. Это также будет работать в Windows.

Вот файл Dockerfile, который сделает это за вас:

Dockerfile

 FROM postgres:11-alpine

# On Windows root will own the files, and they will have permissions 755
COPY server.key /var/lib/postgresql/server.key
COPY server.crt /var/lib/postgresql/server.crt

# update the privileges on the .key, no need to touch the .crt  
RUN chmod 600 /var/lib/postgresql/server.key
RUN chown postgres:postgres /var/lib/postgresql/server.key
  

Создайте образ с:

 docker build -t mypg:01 .
  

И запуск с:

 docker run -d --name postgres mypg:01 
  -c ssl=on -c ssl_cert_file=/var/lib/postgresql/server.crt 
  -c ssl_key_file=/var/lib/postgresql/server.key
  

Комментарии:

1. Я не могу заставить его работать, используя root в качестве владельца и 0640 в качестве разрешений. Сбой базы данных с «ФАТАЛЬНЫМ: не удалось загрузить файл закрытого ключа «/etc/postgresql /server.key»: отказано в разрешении`.

2. спасибо за очень подробный ответ @AndreasLorenzen! Я пробовал оба подхода ( chown 70:70 amp;amp; chmod 0600 и chown 0:70 amp;amp; chmod 640 ), и при первом подходе я получаю could not load private key file "/var/lib/postgresql/server.key": Permission denied , и при втором подходе я получаю private key file "/var/lib/postgresql/server.key" has group or world access

3. похоже, что это решение не работает в osx, по-видимому, файл не смонтирован с правильным владельцем.

4. Есть решение для mac os x?

5. Что ж, в этом случае решение «Windows» по созданию образа самостоятельно сработало бы. Я обновлю ответ, если вы сможете подтвердить, что это работает именно так. Я добавил macos, потому что прочитал, что docker не будет вести себя таким образом, когда где-то отображаются файлы сопоставления томов, но, похоже, это не так. Однако у меня нет Mac, чтобы протестировать это на себе.

Ответ №2:

В моем конкретном случае меня интересовало включение SSL при использовании стандартного образа postgres через docker-compose. Это решение позволяет initdb работать в обычном режиме, что полезно для настройки базы данных и пользователей.

docker-compose.yaml

 version: '3'
services:
  postgres:
    image: postgres:12.2
    environment:
      - POSTGRES_PASSWORD=password
      - POSTGRES_USER=myuser
      - POSTGRES_HOST_AUTH_METHOD=trust
    volumes:
      - ./postgres-initdb:/docker-entrypoint-initdb.d/
      - ./postgres-certs/:/var/lib/postgresql/certs/
  

postgres-initdb/config.sql

 ALTER SYSTEM SET ssl_cert_file TO '/var/lib/postgresql/certs/server.crt';
ALTER SYSTEM SET ssl_key_file TO '/var/lib/postgresql/certs/server.key';
ALTER SYSTEM SET ssl TO 'ON';
  

Это будет работать для любой конфигурации. Для SSL вы также захотите сгенерировать сертификаты (взятые из a Gist):

 set -euo pipefail

mkdir postgres-certs
cd postgres-certs

openssl req -new -text -passout pass:abcd -subj /CN=localhost -out server.req -keyout privkey.pem
openssl rsa -in privkey.pem -passin pass:abcd -out server.key
openssl req -x509 -in server.req -text -key server.key -out server.crt
chmod 600 server.key
test $(uname -s) == Linux amp;amp; chown 999 server.key
  

Комментарии:

1. Этот ответ предоставляет сертификат сервера / ключ, как получить сертификат клиента / ключ для подключения к postgres с использованием ssl = verify-full?

2. Боюсь, здесь я не смогу вам помочь @steve . Это было сделано только в целях разработки.

Ответ №3:

Правильное решение для macOS

В macOS из-за поведения драйвера osxfs любой uid / gid, запущенный в контейнере, также является uid / gid, которому принадлежат подключенные файлы (поэтому владелец файлов в контейнере не будет совпадать с владельцем файла хоста).

В macOS, когда мы меняем владельца файла в контейнере, он записывает данные владельца в com.docker.owner расширенный атрибут file (вместо обновления реального владельца файла).
итак, мы должны установить com.docker.owner атрибут, чтобы указать владельца файла для контейнеров в docker (только на macOS).

Примечание: Если образ вашей Postgres DB основан на alpine, измените 0:999:999 на 0:70:70

 chmod 600 server.key
xattr -w com.docker.owner 0:999:999 server.key # 0:70:70 for alpine-based image