PostgreSQL ondersteunt sinds lange tijd SSL-verbindingen en ook op certificaten gebaseerde authenticatiemechanismen. Hoewel niets in dit opzicht nieuw lijkt voor de PostgreSQL-wereld. Een klein zeurend probleem voor de clientverbinding (verificatie op basis van clientcertificaten) was echter een prompt "Voer PEM-wachtwoordzin in:" voor gecodeerde clientsleutel.
Een nieuwe functie in PostgreSQL 13 is een aanvulling op de serverparameter 'ssl_passphrase_command'. Terwijl de parameter ssl_passphrase_command serverbeheerders in staat stelt een wachtwoordzin op te geven voor gecodeerde serversleutels die worden gebruikt voor servercertificaten; de nieuw geïntroduceerde verbindingsparameter 'sslpassword' geeft enigszins vergelijkbare controle voor clientverbindingen.
Een blik op de infrastructuur
Om een praktische oefening te doen voor deze functie-analyse, heb ik een vrij eenvoudig systeem opgezet:
- Twee virtuele machines
- pgServer ( 172.25.130.189 )
- pgClient ( 172.25.130.178 )
- Zelfondertekende certificaten op pgServer
- PostgreSQL 13 geïnstalleerd op beide machines
- gcc voor het samenstellen van een voorbeeld-libpq-programma
De server instellen
Laten we, om de functie te analyseren, eerst een PostgreSQL 13-serverinstantie instellen met relevante certificaten en de respectievelijke configuratie op pgServer virtual machine.
[[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
Bovenstaande opdrachten genereren een zelfondertekend certificaat met behulp van een sleutel die wordt beschermd door een wachtwoordzin. De machtigingen van de server.key zijn beperkt zoals vereist door PostgreSQL. Het configureren van de PostgreSQL-instantie om deze certificaten te gebruiken is nu geen magie. Maak eerst een basis DATA-map met:
[[email protected]]$ initdb
en plak de volgende configuratieparameters in de gegenereerde 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'
En zorg er ook voor dat een SSL-verbinding vanaf het pgClient-knooppunt wordt geaccepteerd en het certificaatverificatiemechanisme kan gebruiken door de volgende regel in de gegenereerde pg_hba.conf te plakken:
hostssl all all 172.25.130.178/32 cert clientcert=1
Het enige dat nu nog nodig is, is om de server te starten met de bovenstaande configuratie met behulp van het pg_ctl-commando:
[[email protected]]$ pg_ctl start
De klant instellen
De volgende stap zou zijn om clientcertificaten te genereren die zijn ondertekend door bovengenoemde servercertificaten:
[[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:
In de bovenstaande stap worden een versleutelde clientsleutel en een CSR voor het clientcertificaat gegenereerd. Met de volgende stappen wordt een clientcertificaat voltooid door het te ondertekenen met behulp van het serverhoofdcertificaat en de serversleutel.
[[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:
Een belangrijk aspect om te onthouden is de CN-naam in certificaten. Beschouw het meer als een identificatie of naam van de entiteit. Als in het bovenstaande clientcertificaat de CN is ingesteld op 'postgres', is deze bedoeld voor een rol met de naam postgres. Ook bij het opzetten van het servercertificaat hebben we CN=pgServer gebruikt; het kan van belang zijn wanneer we een verificatie-volledige modus van SSL-verbinding gebruiken.
Tijd om de certificaten naar de clientcomputer te kopiëren om de SSL-verbinding uit te proberen:
[[email protected]]$ scp -r client_certs/* [email protected]:~/.postgresql
Als psql in Linux/Unix-omgevingen wordt gebruikt voor het maken van SSL-verbindingen, zoekt het standaard naar certificaat/sleutels in '${HOME}/.postgresql' van de huidige gebruiker. Al deze bestanden kunnen ook worden gespecificeerd in verbindingsparameters - maar dat zou het ding dat we willen testen vertroebeld hebben.
Wijzig op de pgClient-computer de toestemming van de postgresql.key om ervoor te zorgen dat PostgreSQL hetzelfde accepteert.
[[email protected]]$ chmod 0600 ~/.postgresql/postgresql.key
De functie testen
PSQL-verbindingsparameter
We zijn zo goed als klaar met het opzetten van de omgeving. Laten we proberen een SSL-verbinding te maken:
[[email protected]]$ psql "host=172.25.130.189 port=5432 user=postgres dbname=postgres sslmode=prefer"
Enter PEM pass phrase:
Nou! Het begon allemaal met de bovenstaande prompt. Als we een batchprogramma of een automatiseringsscript hebben, is de prompt enigszins lastig te hanteren. Met de nieuwe toevoeging van parameter 'sslpassword' in de verbindingsreeks, is het nu eenvoudig om dat op te geven, zoals hieronder:
[[email protected]]$ psql "host=172.25.130.189 port=5432 user=postgres dbname=postgres sslmode=prefer sslpassword=secretclientpass"
De verbinding zou hierna succesvol moeten zijn, zonder enige prompt.
Libpq Hook voor SSL-wachtwoord
Het verhaal gaat verder - er is een hook-functie 'PQsetSSLKeyPassHook_OpenSSL' toegevoegd in de Libpq-interface. Dit kan worden gebruikt door clienttoepassingen die mogelijk geen toegang hebben tot de sleutelwachtzin en die moeten worden gegenereerd/opgehaald van een externe interface met behulp van een complexe logica.
void PQsetSSLKeyPassHook_OpenSSL(PQsslKeyPassHook_OpenSSL_type hook);
Een call-back-functie van het type PQsslKeyPassHook_OpenSSL_type kan worden geregistreerd met deze hook. De call-back zal worden aangeroepen door Libpq wanneer een wachtwoordzin nodig is. De handtekening van een dergelijke terugbelfunctie moet zijn:
int my_callback_function(char *buf, int size, PGconn *conn);
Hieronder is een voorbeeldprogramma 'client_conn.c' - dat de integratie van zo'n hook demonstreert:
#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;
}
Compileer en voer hetzelfde uit om te controleren of het echt werkt:
[[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
Een laatste woord van voorzichtigheid
De bovenstaande blog toont een kleine maar nuttige wijziging in de Libpq/psql-verbindingsparameters voor op certificaten gebaseerde authenticatie in PostgreSQL. Maar een woord van waarschuwing - in de bovenstaande praktische oefening hebben we zelfondertekende certificaten gebruikt; het past misschien niet zo goed in uw organisatie/productieomgeving. U kunt proberen certificaten van derden te verkrijgen om een dergelijke SSL-configuratie te gebruiken.