Ssl-cc » История » Версия 16
Андрей Волков, 2016-11-10 17:23
| 1 | 1 | Андрей Волков | h1. Подключение к postgres с обязательным использованием SSL и клиентского сертификата |
|---|---|---|---|
| 2 | |||
| 3 | h1. Дано |
||
| 4 | |||
| 5 | Cервера postgresql с адресами: |
||
| 6 | |||
| 7 | * *myserver1.example.com* |
||
| 8 | * *myserver2.example.com* |
||
| 9 | |||
| 10 | h1. Задача |
||
| 11 | |||
| 12 | Предоставить клиентам доступ к серверам через публичную сеть (Интернет). |
||
| 13 | |||
| 14 | - Включить шифрование канала между клиентом и сервером |
||
| 15 | - Требовать от клиента клиентский сертификат |
||
| 16 | - Требовать от клиента пароль |
||
| 17 | - Проверять, что сервер действительно то, за кого он себя выдает |
||
| 18 | |||
| 19 | h1. Решение |
||
| 20 | |||
| 21 | Данное решение реализовывалось на серверах postgresql-9.2+ и было актуально на 2016 год. |
||
| 22 | |||
| 23 | h2. 1. Генерация сертификатов |
||
| 24 | |||
| 25 | Если в вашем случае за настройку серверов и выдачу клиентских сертификатов отвечает один человек, то можно использовать одну CA для подписания, как клиентских так и серверных сертификатов. |
||
| 26 | |||
| 27 | Я рассмотрю вариант, когда CA отличаются |
||
| 28 | |||
| 29 | h3. 1.1. Генерация сертификатов серверов |
||
| 30 | |||
| 31 | Одним из вариантов решения могла бы быть покупка серверного сертификата |
||
| 32 | Но здесь это нецелесообразно, потому что клиенты не всегда используют системные ca-bundle, и раз уж нам все равно нужно передавать пользователям клиентские сертификаты, то передадим и CA сервера. |
||
| 33 | |||
| 34 | h4. 1.1.1. CA сертификат для подписания серверных сертификатов |
||
| 35 | |||
| 36 | Не буду вдаваться в подробности создания CA |
||
| 37 | |||
| 38 | *openssl genrsa -out server-ca.key -camellia256 2048* |
||
| 39 | *chmod 400 server-ca.key* |
||
| 40 | *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* |
||
| 41 | |||
| 42 | ШИфр для ключа *-camellia256* - дело вкуса. |
||
| 43 | Можно выбрать и что-то другое из: |
||
| 44 | |||
| 45 | * -aes128 |
||
| 46 | * -aes192 |
||
| 47 | * -aes256 |
||
| 48 | * -camellia128 |
||
| 49 | * -camellia192 |
||
| 50 | * -camellia256 |
||
| 51 | * -des |
||
| 52 | * -des3 |
||
| 53 | * -idea |
||
| 54 | |||
| 55 | Тип ЭЦП для сертификата *-sha256* - тоже дело вкуса. |
||
| 56 | По большому счету здесь можно использовать другой тип ЭЦП, т.к. на корневом сертификате ЭЦП не проверяется. |
||
| 57 | |||
| 58 | Значение параметра *-subj* нужно поправить под себя. |
||
| 59 | |||
| 60 | h4. 1.1.2 Создаем серверные сертификаты |
||
| 61 | |||
| 62 | 3 | Андрей Волков | +Создаем файл настроек для генерации серверного сертификата:+ |
| 63 | 1 | Андрей Волков | |
| 64 | *cat > openssl.cnf* |
||
| 65 | |||
| 66 | <pre> |
||
| 67 | [ server ] |
||
| 68 | basicConstraints = CA:FALSE |
||
| 69 | extendedKeyUsage = serverAuth |
||
| 70 | subjectKeyIdentifier = hash |
||
| 71 | authorityKeyIdentifier = keyid,issuer:always |
||
| 72 | 2 | Андрей Волков | keyUsage = digitalSignature |
| 73 | 1 | Андрей Волков | </pre> |
| 74 | |||
| 75 | 3 | Андрей Волков | +Генерируем запросы на серверные сертификаты:+ |
| 76 | 1 | Андрей Волков | |
| 77 | *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* |
||
| 78 | 2 | Андрей Волков | |
| 79 | 1 | Андрей Волков | *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* |
| 80 | |||
| 81 | 2 | Андрей Волков | *chmod 400 myserver1.example.com.key* |
| 82 | *chmod 400 myserver2.example.com.key* |
||
| 83 | 1 | Андрей Волков | |
| 84 | Здесь важно указать CN= в виде реального имени, по которому клиенты будут соединяться к серверу. Иначе не будет работать verify-full |
||
| 85 | https://www.postgresql.org/docs/9.5/static/libpq-ssl.html#LIBPQ-SSL-SSLMODE-STATEMENTS |
||
| 86 | |||
| 87 | Тип ЭЦП *-sha256* здесь не очень важен, потому что используется только для подписи запроса, а не самого сертификата. |
||
| 88 | |||
| 89 | 3 | Андрей Волков | +Подписываем сертификаты:+ |
| 90 | 1 | Андрей Волков | |
| 91 | *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* |
||
| 92 | |||
| 93 | *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* |
||
| 94 | |||
| 95 | 2 | Андрей Волков | Тип ЭЦП *-sha256* здесь важен с точки зрения надежности. В 2016 году некоторые распространенные ранее типы ЭЦП, например sha1 не считается надежными. |
| 96 | 1 | Андрей Волков | |
| 97 | Параметр *-CAcreateserial* Используется только первый раз. |
||
| 98 | |||
| 99 | h4. 1.2.1 CA сертификат для подписания клиентских сертификатов |
||
| 100 | |||
| 101 | Тут все по аналогии с пунктом 1.1.1. |
||
| 102 | |||
| 103 | Приведу только команды |
||
| 104 | |||
| 105 | *openssl genrsa -out client-ca.key -camellia256 2048* |
||
| 106 | *chmod 400 client-ca.key* |
||
| 107 | *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* |
||
| 108 | 2 | Андрей Волков | |
| 109 | 5 | Андрей Волков | Возможно в будущем нам потребуется отзывать сертификаты у пользователей: |
| 110 | |||
| 111 | Создадим файл отозванных сертификатов |
||
| 112 | |||
| 113 | *cat >> openssl.cnf* |
||
| 114 | |||
| 115 | <pre> |
||
| 116 | 6 | Андрей Волков | [ ca ] |
| 117 | 7 | Андрей Волков | default_ca = CA |
| 118 | 5 | Андрей Волков | |
| 119 | 6 | Андрей Волков | [ CA ] |
| 120 | 7 | Андрей Волков | database = index.txt |
| 121 | default_md = default |
||
| 122 | default_crl_days = 30 |
||
| 123 | 5 | Андрей Волков | </pre> |
| 124 | |||
| 125 | 10 | Андрей Волков | *touch index.txt* |
| 126 | *touch index.txt.attr* |
||
| 127 | *openssl ca -config openssl.cnf -cert client-ca.crt -keyfile client-ca.key -gencrl -out client-ca.crl* |
||
| 128 | |||
| 129 | 5 | Андрей Волков | |
| 130 | 4 | Андрей Волков | h4. 1.2.2 Создаем серверные сертификаты |
| 131 | 2 | Андрей Волков | |
| 132 | Тут все по аналогии с пунктом 1.1.2. |
||
| 133 | |||
| 134 | 3 | Андрей Волков | +Создаем файл настроек для генерации клиентского сертификата:+ |
| 135 | 2 | Андрей Волков | |
| 136 | *cat >> openssl.cnf* |
||
| 137 | |||
| 138 | <pre> |
||
| 139 | [ client ] |
||
| 140 | basicConstraints = CA:FALSE |
||
| 141 | extendedKeyUsage = clientAuth |
||
| 142 | subjectKeyIdentifier = hash |
||
| 143 | authorityKeyIdentifier = keyid,issuer:always |
||
| 144 | keyUsage = digitalSignature |
||
| 145 | </pre> |
||
| 146 | |||
| 147 | 3 | Андрей Волков | +Генерируем запросы на клиентские сертификаты:+ |
| 148 | 2 | Андрей Волков | |
| 149 | *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* |
||
| 150 | |||
| 151 | *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* |
||
| 152 | |||
| 153 | *chmod 400 ivanov_ii.key* |
||
| 154 | *chmod 400 petrov_pp.key* |
||
| 155 | |||
| 156 | Здесь желательно указать CN= в виде реального фио, чтобы потом можно было различать принадлежность сертификатов сотрудников. |
||
| 157 | |||
| 158 | 3 | Андрей Волков | +Подписываем сертификаты:+ |
| 159 | 2 | Андрей Волков | |
| 160 | *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* |
||
| 161 | |||
| 162 | *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* |
||
| 163 | |||
| 164 | Параметр *-CAcreateserial* Используется только первый раз. |
||
| 165 | 5 | Андрей Волков | |
| 166 | h2. 2. Раскладываем ключи и сертификаты |
||
| 167 | |||
| 168 | h3. 2.1. Сертификаты на серверах |
||
| 169 | |||
| 170 | myserver1.example.com.crt => /etc/postgresql-9.5/ssl/server.crt |
||
| 171 | myserver1.example.com.key => /etc/postgresql-9.5/ssl/server.key |
||
| 172 | client-ca.crt => /etc/postgresql-9.5/ssl/client-ca.crt |
||
| 173 | client-ca.crl => /etc/postgresql-9.5/ssl/client-ca.crl |
||
| 174 | |||
| 175 | myserver2.example.com.crt => /etc/postgresql-9.2/ssl/server.crt |
||
| 176 | myserver2.example.com.key => /etc/postgresql-9.2/ssl/server.key |
||
| 177 | client-ca.crt => /etc/postgresql-9.2/ssl/client-ca.crt |
||
| 178 | client-ca.crl => /etc/postgresql-9.5/ssl/client-ca.crl |
||
| 179 | |||
| 180 | h3. 2.1. Сертификаты на клиентcких машинах |
||
| 181 | |||
| 182 | Настройки для psql |
||
| 183 | |||
| 184 | ivanov_ii.crt => ~ivanov/.postgresql/postgresql.crt |
||
| 185 | ivanov_ii.key => ~ivanov/.postgresql/postgresql.key |
||
| 186 | 8 | Андрей Волков | server-ca.crt => ~ivanov/.postgresql/root.crt (нужен только для sslmode=verify-full или sslmode=verify-ca) |
| 187 | 5 | Андрей Волков | |
| 188 | petrov_pp.crt => ~petrov/.postgresql/postgresql.crt |
||
| 189 | petrov_pp.key => ~petrov/.postgresql/postgresql.key |
||
| 190 | 8 | Андрей Волков | server-ca.crt => ~petrov/.postgresql/root.crt (нужен только для sslmode=verify-full или sslmode=verify-ca) |
| 191 | 5 | Андрей Волков | |
| 192 | h2. 3. Настраиваем серверы: |
||
| 193 | |||
| 194 | h3. postgresql.conf |
||
| 195 | |||
| 196 | <pre> |
||
| 197 | ssl = on # (change requires restart) |
||
| 198 | ssl_ciphers = 'DHE-RSA-AES256-SHA' # allowed SSL ciphers |
||
| 199 | # (change requires restart) |
||
| 200 | ssl_prefer_server_ciphers = on # (change requires restart) |
||
| 201 | ssl_cert_file = 'server.crt' # (change requires restart) |
||
| 202 | ssl_key_file = 'server.key' # (change requires restart) |
||
| 203 | ssl_ca_file = 'client-ca.crt' # (change requires restart) |
||
| 204 | ssl_crl_file = 'client-ca.crl' # (change requires restart) |
||
| 205 | </pre> |
||
| 206 | |||
| 207 | ssl_ciphers - дело вкуса |
||
| 208 | |||
| 209 | Для применения настроек потребуется перезапуск базы =( |
||
| 210 | Для смены содержимого серверного сертификата потребуется перезапуск базы =(( |
||
| 211 | |||
| 212 | h3. pg_hba.conf |
||
| 213 | |||
| 214 | <pre> |
||
| 215 | # TYPE DATABASE USER ADDRESS METHOD [OPTIONS] |
||
| 216 | hostssl production ivanov 10.10.20.20/32 md5 clientcert=1 |
||
| 217 | hostssl production petrov 10.10.20.50/32 md5 clientcert=1 |
||
| 218 | </pre> |
||
| 219 | 1 | Андрей Волков | |
| 220 | Для добавления пользователей достаточно попросить postgres перечитать настройки. |
||
| 221 | 8 | Андрей Волков | |
| 222 | h2. 4. Настраиваем клиентов: |
||
| 223 | |||
| 224 | 14 | Андрей Волков | h3. 4.1. psql |
| 225 | |||
| 226 | 8 | Андрей Волков | *psql -U ivanov_ii -h myserver1.example.com -d "dbname=production sslmode=verify-full"* |
| 227 | |||
| 228 | Если вместо DNS имени указать IP(55.66.77.88), то будет ошибка вида |
||
| 229 | |||
| 230 | <pre> |
||
| 231 | psql: server certificate for "myserver2.example.com" does not match host name "55.66.77.88" |
||
| 232 | </pre> |
||
| 233 | |||
| 234 | Если иначе никак, то можно более слабый режим проверки доверия клиента серверу (verify-ca) |
||
| 235 | |||
| 236 | *psql -U petrov_pp -h 55.66.77.88 -d "dbname=production sslmode=verify-ca"* |
||
| 237 | |||
| 238 | В этом случае если у вас несколько серверов смотрят во внешний мир через один IP маршрутизатора, но с разными портами, есть риск, нечаянно, подключиться не к тому серверу. |
||
| 239 | 14 | Андрей Волков | |
| 240 | h3. 4.2. pgadmin3 |
||
| 241 | |||
| 242 | !cut-2016-11-10_17-08-52_Un7NIqZdQgd.png! |
||
| 243 | 9 | Андрей Волков | |
| 244 | 16 | Андрей Волков | !cut-2016-11-10_17-20-19_ImpLeQ4kIhI.png! |
| 245 | 15 | Андрей Волков | |
| 246 | +Для параноиков:+ |
||
| 247 | |||
| 248 | Сжатие SSL Compression уязвимо к атаке CRIME |
||
| 249 | https://threatpost.com/crime-attack-uses-compression-ratio-tls-requests-side-channel-hijack-secure-sessions-091312/77006/ |
||
| 250 | |||
| 251 | 13 | Андрей Волков | h2. 5. Отзыв сертификатов: |
| 252 | 1 | Андрей Волков | |
| 253 | 13 | Андрей Волков | +Пополняем список отозванных сертификатов:+ |
| 254 | |||
| 255 | 1 | Андрей Волков | *openssl ca -config openssl.cnf -cert client-ca.crt -keyfile client-ca.key -revoke ivanov_ii.crt* |
| 256 | 13 | Андрей Волков | *openssl ca -config openssl.cnf -cert client-ca.crt -keyfile client-ca.key -revoke petrov_pp.crt* |
| 257 | |||
| 258 | +Перегенерируем crl файл:+ |
||
| 259 | |||
| 260 | 11 | Андрей Волков | *openssl ca -config openssl.cnf -cert ca.crt -keyfile ca.key -gencrl -out ca.crl* |
| 261 | |||
| 262 | 12 | Андрей Волков | +Самое печальное:+ |
| 263 | |||
| 264 | 11 | Андрей Волков | Для того чтобы postgres перечитал файл отозванных сертификатов, необходимо перезапустить postgres. |
| 265 | |||
| 266 | Потому, доступ лучше забирать сначала через pg_hba.conf |
||
| 267 | 1 | Андрей Волков | А отзыв сертификата применить при очередном плановом перезапуске базы |
| 268 | 11 | Андрей Волков | |
| 269 | 12 | Андрей Волков | +Сообщение на стороне клиента:+ |
| 270 | 11 | Андрей Волков | |
| 271 | <pre> |
||
| 272 | psql: SSL error: sslv3 alert certificate revoked |
||
| 273 | </pre> |