Проект

Общее

Профиль

Ssl-cc » История » Редакция 8

Редакция 7 (Андрей Волков, 2016-11-10 16:16) → Редакция 8/16 (Андрей Волков, 2016-11-10 16:30)

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

 h1. Дано 

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

 * *myserver1.example.com* 
 * *myserver2.example.com* 

 h1. Задача 

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

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

 h1. Решение 

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

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

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

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

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

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

 h4. 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* нужно поправить под себя. 

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

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

 *cat > openssl.cnf* 

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

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

 *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* Используется только первый раз. 

 

 h4. 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* 

 <pre> 
 [ ca ] 
 default_ca         = CA 

 [ CA ] 
 database           = index.txt 
 default_md         = default 
 default_crl_days = 30 
 </pre> 

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

 

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

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

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

 *cat >> openssl.cnf* 

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

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

 *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* Используется только первый раз. 

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

 h3. 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 

 h3. 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) 

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

 h3. postgresql.conf 

 <pre> 
 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) 
 </pre> 

 ssl_ciphers - дело вкуса 

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

 h3. pg_hba.conf 

 <pre> 
 # 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 
 </pre> 

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

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

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

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

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

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

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

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