PostgreSQL отдавна поддържа SSL връзки, а също и механизми за удостоверяване, базирани на сертификати. Въпреки че нищо в това отношение не изглежда ново за света на PostgreSQL. Въпреки това, малък проблем с клиентската връзка (удостоверяване на базата на клиентски сертификати) беше подкана „Въведете PEM парола:“ за шифрован клиентски ключ.
Нова функция в PostgreSQL 13 допълва сървърния параметър 'ssl_passphrase_command'. Докато параметърът ssl_passphrase_command позволява на администраторите на сървъра да определят парола за криптирани сървърни ключове, използвани за сървърни сертификати; нововъведеният параметър за връзка „sslpassword“ дава донякъде подобен контрол за клиентски връзки.
Поглед към инфраструктурата
За да премина през практическо упражнение за този анализ на характеристиките, създадох доста основна система:
- Две виртуални машини
- pgServer (172.25.130.189)
- pgClient ( 172.25.130.178 )
- Самоподписани сертификати на pgServer
- PostgreSQL 13, инсталиран и на двете машини
- gcc за компилиране на примерна програма libpq
Настройване на сървъра
За да анализираме функцията, нека първо настроим сървърен екземпляр на PostgreSQL 13 със съответните сертификати и съответната конфигурация на виртуална машина pgServer.
[[email protected]]$ echo ${HOME}
/var/lib/pgsql/
[[email protected]]$ mkdir ~/server_certs/
[[email protected]]$ openssl genrsa -des3 -passout pass:secretserverpass -out ~/server_certs/server.key
[[email protected]]$ openssl req -new -key ~/server_certs/server.key -days 365 -out ~/server_certs/server.crt -x509 -subj "/C=AU/ST=NSW/L=DY/O=MyOrg/OU=Dev/CN=pgServer"
Enter pass phrase for /var/lib/pgsql/server_certs/server.key:
[[email protected]]$ chmod 0600 /var/lib/pgsql/server_certs/server.key
[[email protected]]$ cp ~/server_certs/server.crt ~/server_certs/root.crt
По-горе команди генерират самоподписан сертификат с помощта на ключ, който е защитен с парола. Разрешенията на server.key са ограничени, както се изисква от PostgreSQL. Конфигурирането на екземпляра на PostgreSQL да използва тези сертификати сега не е магия. Първо създайте основна папка DATA, като използвате:
[[email protected]]$ initdb
и поставете следните конфигурационни параметри в генерирания postgresql.conf:
ssl=on
ssl_cert_file='/var/lib/pgsql/server_certs/server.crt'
ssl_key_file='/var/lib/pgsql/server_certs/server.key'
ssl_ca_file='/var/lib/pgsql/server_certs/root.crt'
ssl_passphrase_command = 'echo secretserverpass'
listen_addresses = '172.25.130.189'
И също така се уверете, че SSL връзка от възела pgClient е приета и може да използва механизма за удостоверяване на сертификат, като поставите следния ред в генерирания pg_hba.conf:
hostssl all all 172.25.130.178/32 cert clientcert=1
Всичко, което е необходимо сега, е да стартирате сървъра с горната конфигурация с помощта на командата pg_ctl:
[[email protected]]$ pg_ctl start
Настройване на клиента
Следващата стъпка би била генерирането на клиентски сертификати, които са подписани от гореспоменатите сървърни сертификати:
[[email protected]]$ mkdir ~/client_certs/
[[email protected]]$ openssl genrsa -des3 -passout pass:secretclientpass -out ~/client_certs/postgresql.key
[[email protected]]$ openssl req -new -key ~/client_certs/postgresql.key -out ~/client_certs/postgresql.csr -subj "/C=AU/ST=NSW/L=DY/O=MyOrg/OU=Dev/CN=postgres"
Enter pass phrase for ~/client_certs/postgresql.key:
В горната стъпка се генерират криптиран клиентски ключ и CSR за клиентския сертификат. Следните стъпки завършват клиентски сертификат, като го подписват с помощта на основния сертификат на сървъра и сървърния ключ.
[[email protected]]$ openssl x509 -req -in ~/client_certs/postgresql.csr -CA ~/server_certs/root.crt -CAkey ~/server_certs/server.key -out ~/client_certs/postgresql.crt -CAcreateserial
Signature ok
subject=/C=AU/ST=NSW/L=DY/O=MyOrg/OU=Dev/CN=postgres
Getting CA Private Key
Enter pass phrase for /var/lib/pgsql/server_certs/server.key:
Един важен аспект, който трябва да запомните, е името на CN в сертификатите. Считайте го по-скоро за идентификация или име на субекта. В горния клиентски сертификат, ако CN е настроен на „postgres“, той е предназначен за роля с име postgres. Също така, докато настройваме сертификата на сървъра, използвахме CN=pgServer; може да има значение, когато използваме пълен режим на проверка на SSL връзка.
Време за копиране на сертификатите на клиентската машина, за да изпробвате SSL връзката:
[[email protected]]$ scp -r client_certs/* [email protected]:~/.postgresql
По подразбиране в Linux/Unix среди, когато psql се използва за създаване на SSL връзки, той търси сертификат/ключове в „${HOME}/.postgresql“ на текущия потребител. Всички тези файлове могат да бъдат посочени и в параметрите на връзката - това обаче би замъглило нещото, което искаме да тестваме.
На pgClient машината променете разрешението на postgresql.key, за да сте сигурни, че PostgreSQL приема същото.
[[email protected]]$ chmod 0600 ~/.postgresql/postgresql.key
Тестване на функцията
Параметър за PSQL връзка
До голяма степен сме готови с настройката на средата. Нека опитаме да направим SSL връзка:
[[email protected]]$ psql "host=172.25.130.189 port=5432 user=postgres dbname=postgres sslmode=prefer"
Enter PEM pass phrase:
Е! Всичко започна само с горната подкана. Ако имаме пакетна програма или скрипт за автоматизация, подканата е малко трудна за обработка. С новото добавяне на параметър 'sslpassword' в низа за връзка, вече е лесно да посочите това, както следва:
[[email protected]]$ psql "host=172.25.130.189 port=5432 user=postgres dbname=postgres sslmode=prefer sslpassword=secretclientpass"
Връзката трябва да е успешна след това, без никаква подкана.
Libpq Hook за SSL парола
Историята продължава - има добавена функция за кука „PQsetSSLKeyPassHook_OpenSSL“ в интерфейса на Libpq. Това може да се използва от клиентски приложения, които може да нямат достъп до ключовата парола и трябва да генерират/извличат от външен интерфейс, използвайки някаква сложна логика.
void PQsetSSLKeyPassHook_OpenSSL(PQsslKeyPassHook_OpenSSL_type hook);
Функция за обратно извикване от тип PQsslKeyPassHook_OpenSSL_type може да бъде регистрирана с помощта на тази кука. Обратното повикване ще бъде извикано от Libpq, когато се нуждаете от получаване на парола. Подписът на такава функция за обратно извикване трябва да бъде:
int my_callback_function(char *buf, int size, PGconn *conn);
По-долу е една примерна програма „client_conn.c“ – която демонстрира интегриране на такава кука:
#include <stdlib.h>
#include <string.h>
#include "libpq-fe.h"
void do_exit(PGconn *conn) {
PQfinish(conn);
exit(1);
}
/**
* For PQsetSSLKeyPassHook_OpenSSL to provide password for SSL Key
**/
int ssl_password_provider(char *buf, int size, PGconn *conn)
{
const char * default_key_password = "secretclientpass";
strcpy(buf, default_key_password);
return strlen(default_key_password);
}
/**
* Sample program to make a connection and check server version
*/
int main()
{
PQsetSSLKeyPassHook_OpenSSL( ssl_password_provider );
PGconn *conn = PQconnectdb("host=172.25.130.189 port=5413 user=postgres dbname=postgres sslmode=prefer");
if (PQstatus(conn) == CONNECTION_BAD)
{
fprintf(stderr, "Connection to DB failed: %s\n", PQerrorMessage(conn));
do_exit(conn);
}
printf("Server version: %d\n", PQserverVersion(conn));
PQfinish(conn);
return 0;
}
Компилирайте и стартирайте същото, за да проверите дали наистина работи:
[[email protected]]$ gcc -DUSE_OPENSSL -I/usr/pgsql-13/include/ -lpq -L/usr/pgsql-13/lib/ client_conn.c -o client_conn
[[email protected]]$ client_conn
[[email protected]]$ ./client_conn
Server version: 130000
Последна дума на внимание
Горният блог показва малка, но полезна промяна в параметрите на връзката на Libpq/psql за удостоверяване на базата на сертификат в PostgreSQL. Но една дума за внимание – в горното практическо упражнение използвахме самоподписани сертификати; може да не се вписва много добре във вашата организация/производствена среда. Може да поискате да получите сертификати на трети страни, за да използвате такава настройка на SSL.