Проект

Общее

Профиль

Действия

Подключение к postgres с обязательным использованием SSL и клиентского сертификата

Дано

Cервера postgresql с адресами:

  • myserver1.example.com
  • myserver2.example.com

Задача

Предоставить клиентам доступ к серверам через публичную сеть (Интернет).

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

Решение

Данное решение реализовывалось на серверах postgresql-9.2+ и было актуально на 2016 год.

1. Генерация сертификатов

Если в вашем случае за настройку серверов и выдачу клиентских сертификатов отвечает один человек, то можно использовать одну CA для подписания, как клиентских так и серверных сертификатов.

Я рассмотрю вариант, когда CA отличаются

1.1. Генерация сертификатов серверов

Одним из вариантов решения могла бы быть покупка серверного сертификата
Но здесь это нецелесообразно, потому что клиенты не всегда используют системные ca-bundle, и раз уж нам все равно нужно передавать пользователям клиентские сертификаты, то передадим и CA сервера.

1.1.1. CA сертификат для подписания серверных сертификатов

Не буду вдаваться в подробности создания CA

openssl genrsa -out server-ca.key -camellia256 2048
chmod 400 server-ca.key
openssl req -new -x509 -days 3650 -key server-ca.key -out server-ca.crt -subj '/C=RU/O=EKB-Info/CN=server-CA' -extensions v3_ca -sha256

ШИфр для ключа -camellia256 - дело вкуса.
Можно выбрать и что-то другое из:

  • -aes128
  • -aes192
  • -aes256
  • -camellia128
  • -camellia192
  • -camellia256
  • -des
  • -des3
  • -idea

Тип ЭЦП для сертификата -sha256 - тоже дело вкуса.
По большому счету здесь можно использовать другой тип ЭЦП, т.к. на корневом сертификате ЭЦП не проверяется.

Значение параметра -subj нужно поправить под себя.

1.1.2 Создаем серверные сертификаты

Создаем файл настроек для генерации серверного сертификата:

cat > openssl.cnf

[ server ]
basicConstraints = CA:FALSE
extendedKeyUsage = serverAuth
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid,issuer:always
keyUsage = digitalSignature

Генерируем запросы на серверные сертификаты:

openssl req -new -nodes -newkey rsa:2048 -keyout myserver1.example.com.key -out myserver1.example.com.csr -subj '/C=RU/O=EKB-Info/CN=myserver1.example.com/' -sha256

openssl req -new -nodes -newkey rsa:2048 -keyout myserver2.example.com.key -out myserver1.example.com.csr -subj '/C=RU/O=EKB-Info/CN=myserver2.example.com/' -sha256

chmod 400 myserver1.example.com.key
chmod 400 myserver2.example.com.key

Здесь важно указать CN= в виде реального имени, по которому клиенты будут соединяться к серверу. Иначе не будет работать verify-full
https://www.postgresql.org/docs/9.5/static/libpq-ssl.html#LIBPQ-SSL-SSLMODE-STATEMENTS

Тип ЭЦП -sha256 здесь не очень важен, потому что используется только для подписи запроса, а не самого сертификата.

Подписываем сертификаты:

openssl x509 -req -days 3650 -in myserver1.example.com.csr -CA server-ca.crt -CAkey server-ca.key -CAserial server-ca.srl -CAcreateserial -out myserver1.example.com.crt -extfile openssl.cnf -extensions server -sha256

openssl x509 -req -days 3650 -in myserver2.example.com.csr -CA server-ca.crt -CAkey server-ca.key -CAserial server-ca.srl -out myserver1.example.com.crt -extfile openssl.cnf -extensions server -sha256

Тип ЭЦП -sha256 здесь важен с точки зрения надежности. В 2016 году некоторые распространенные ранее типы ЭЦП, например sha1 не считается надежными.

Параметр -CAcreateserial Используется только первый раз.

1.2.1 CA сертификат для подписания клиентских сертификатов

Тут все по аналогии с пунктом 1.1.1.

Приведу только команды

openssl genrsa -out client-ca.key -camellia256 2048
chmod 400 client-ca.key
openssl req -new -x509 -days 3650 -key client-ca.key -out client-ca.crt -subj '/C=RU/O=EKB-Info/CN=client-CA' -extensions v3_ca -sha256

Возможно в будущем нам потребуется отзывать сертификаты у пользователей:

Создадим файл отозванных сертификатов

cat >> openssl.cnf

[ ca ]
default_ca       = CA

[ CA ]
database         = index.txt
default_md       = default
default_crl_days = 30

touch index.txt
touch index.txt.attr
openssl ca -config openssl.cnf -cert client-ca.crt -keyfile client-ca.key -gencrl -out client-ca.crl

1.2.2 Создаем серверные сертификаты

Тут все по аналогии с пунктом 1.1.2.

Создаем файл настроек для генерации клиентского сертификата:

cat >> openssl.cnf

[ client ]
basicConstraints = CA:FALSE
extendedKeyUsage = clientAuth
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid,issuer:always
keyUsage = digitalSignature

Генерируем запросы на клиентские сертификаты:

openssl req -new -nodes -newkey rsa:2048 -keyout ivanov_ii.key -out ivanov_ii.csr -subj '/C=RU/O=EKB-Info/CN=ivanov_ii/' -sha256

openssl req -new -nodes -newkey rsa:2048 -keyout petrov_pp.key -out petrov_pp.csr -subj '/C=RU/O=EKB-Info/CN=petrov_pp/' -sha256

chmod 400 ivanov_ii.key
chmod 400 petrov_pp.key

Здесь желательно указать CN= в виде реального фио, чтобы потом можно было различать принадлежность сертификатов сотрудников.

Подписываем сертификаты:

openssl x509 -req -days 3650 -in ivanov_ii.csr -CA client-ca.crt -CAkey client-ca.key -CAserial client-ca.srl -CAcreateserial -out ivanov_ii.crt -extfile openssl.cnf -extensions client -sha256

openssl x509 -req -days 3650 -in petrov_pp.csr -CA client-ca.crt -CAkey client-ca.key -CAserial client-ca.srl -out petrov_pp.crt -extfile openssl.cnf -extensions client -sha256

Параметр -CAcreateserial Используется только первый раз.

2. Раскладываем ключи и сертификаты

2.1. Сертификаты на серверах

myserver1.example.com.crt => /etc/postgresql-9.5/ssl/server.crt
myserver1.example.com.key => /etc/postgresql-9.5/ssl/server.key
client-ca.crt => /etc/postgresql-9.5/ssl/client-ca.crt
client-ca.crl => /etc/postgresql-9.5/ssl/client-ca.crl

myserver2.example.com.crt => /etc/postgresql-9.2/ssl/server.crt
myserver2.example.com.key => /etc/postgresql-9.2/ssl/server.key
client-ca.crt => /etc/postgresql-9.2/ssl/client-ca.crt
client-ca.crl => /etc/postgresql-9.5/ssl/client-ca.crl

2.1. Сертификаты на клиентcких машинах

Настройки для psql

ivanov_ii.crt => ~ivanov/.postgresql/postgresql.crt
ivanov_ii.key => ~ivanov/.postgresql/postgresql.key
server-ca.crt => ~ivanov/.postgresql/root.crt (нужен только для sslmode=verify-full или sslmode=verify-ca)

petrov_pp.crt => ~petrov/.postgresql/postgresql.crt
petrov_pp.key => ~petrov/.postgresql/postgresql.key
server-ca.crt => ~petrov/.postgresql/root.crt (нужен только для sslmode=verify-full или sslmode=verify-ca)

3. Настраиваем серверы:

postgresql.conf

ssl = on                                # (change requires restart)
ssl_ciphers = 'DHE-RSA-AES256-SHA'      # allowed SSL ciphers
                                        # (change requires restart)
ssl_prefer_server_ciphers = on          # (change requires restart)
ssl_cert_file = 'server.crt'            # (change requires restart)
ssl_key_file = 'server.key'             # (change requires restart)
ssl_ca_file = 'client-ca.crt'           # (change requires restart)
ssl_crl_file = 'client-ca.crl'          # (change requires restart)

ssl_ciphers - дело вкуса

Для применения настроек потребуется перезапуск базы =(
Для смены содержимого серверного сертификата потребуется перезапуск базы =((

pg_hba.conf

# TYPE  DATABASE        USER            ADDRESS                 METHOD      [OPTIONS]
hostssl production      ivanov          10.10.20.20/32          md5         clientcert=1
hostssl production      petrov          10.10.20.50/32          md5         clientcert=1

Для добавления пользователей достаточно попросить postgres перечитать настройки.

4. Настраиваем клиентов:

4.1. psql

psql -U ivanov_ii -h myserver1.example.com -d "dbname=production sslmode=verify-full"

Если вместо DNS имени указать IP, то будет ошибка вида

psql: server certificate for "myserver2.example.com" does not match host name "55.66.77.88" 

Если иначе никак, то можно более слабый режим проверки доверия клиента серверу (verify-ca)

psql -U petrov_pp -h 55.66.77.88 -d "dbname=production sslmode=verify-ca"

В этом случае если у вас несколько серверов смотрят во внешний мир через один IP маршрутизатора, но с разными портами, есть риск, нечаянно, подключиться не к тому серверу.

4.2. pgadmin3

Для параноиков:

Сжатие SSL Compression уязвимо к атаке CRIME
https://threatpost.com/crime-attack-uses-compression-ratio-tls-requests-side-channel-hijack-secure-sessions-091312/77006/

5. Отзыв сертификатов:

Пополняем список отозванных сертификатов:

openssl ca -config openssl.cnf -cert client-ca.crt -keyfile client-ca.key -revoke ivanov_ii.crt
openssl ca -config openssl.cnf -cert client-ca.crt -keyfile client-ca.key -revoke petrov_pp.crt

Перегенерируем crl файл:

openssl ca -config openssl.cnf -cert ca.crt -keyfile ca.key -gencrl -out ca.crl

Самое печальное:

Для того чтобы postgres перечитал файл отозванных сертификатов, необходимо перезапустить postgres.

Потому, доступ лучше забирать сначала через pg_hba.conf
А отзыв сертификата применить при очередном плановом перезапуске базы

Сообщение на стороне клиента:

psql: SSL error: sslv3 alert certificate revoked

Обновлено Андрей Волков около 8 лет назад · 16 изменени(я, ий)