PostgreSQL har siden længe understøttet SSL-forbindelser og også certifikatbaserede godkendelsesmekanismer. Selvom intet i denne henseende ser ud til at være nyt for PostgreSQL-verdenen. Et lille irriterende problem for klientforbindelse (klient-certifikatbaseret godkendelse) var imidlertid en prompt "Indtast PEM-adgangssætning:" for krypteret klientnøgle.
En ny funktion i PostgreSQL 13 komplimenterer serverparameteren 'ssl_passphrase_command'. Mens parameteren ssl_passphrase_command tillader serveradministratorer at angive en adgangssætning for krypterede servernøgler, der bruges til servercertifikater; den nyligt introducerede forbindelsesparameter 'sslpassword' giver noget lignende kontrol for klientforbindelser.
Et kig på infrastrukturen
For at gennemgå en praktisk øvelse til denne funktionsanalyse har jeg etableret et ret grundlæggende system:
- To virtuelle maskiner
- pgServer ( 172.25.130.189 )
- pgClient ( 172.25.130.178 )
- Selvsignerede certifikater på pgServer
- PostgreSQL 13 installeret på begge maskiner
- gcc til kompilering af et eksempel på libpq-program
Opsætning af serveren
For at analysere funktionen, lad os først konfigurere en PostgreSQL 13-serverinstans med relevante certifikater og den respektive konfiguration på den virtuelle pgServer-maskine.
[[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
Ovenstående kommandoer genererer et selvsigneret certifikat ved hjælp af en nøgle, der er beskyttet af en adgangssætning. Tilladelserne for server.key er begrænset som krævet af PostgreSQL. At konfigurere PostgreSQL-instansen til at bruge disse certifikater er ingen magi nu. Opret først en basis DATA-mappe ved hjælp af:
[[email protected]]$ initdb
og indsæt følgende konfigurationsparametre i den genererede 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'
Og sørg også for, at en SSL-forbindelse fra pgClient-noden accepteres og kan bruge certifikatgodkendelsesmekanismen ved at indsætte følgende linje i den genererede pg_hba.conf:
hostssl all all 172.25.130.178/32 cert clientcert=1
Alt, der er nødvendigt nu, er at starte serveren med ovenstående konfiguration ved hjælp af kommandoen pg_ctl:
[[email protected]]$ pg_ctl start
Opsætning af klienten
Det næste trin ville være at generere klientcertifikater, som er underskrevet af førnævnte servercertifikater:
[[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:
I ovenstående trin genereres en krypteret klientnøgle og en CSR for klientcertifikatet. De følgende trin fuldender et klientcertifikat ved at signere det ved hjælp af serverrodcertifikatet og servernøglen.
[[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:
Et vigtigt aspekt at huske er CN-navnet i certifikater. Betragt det som mere en identifikation eller navnet på enheden. I ovenstående klientcertifikat, hvis CN er sat til 'postgres', er det beregnet til en rolle ved navn postgres. Under opsætningen af servercertifikatet brugte vi også CN=pgServer; det kan have betydning, når vi bruger en fuld-bekræftelsestilstand for SSL-forbindelse.
Tid til at kopiere certifikaterne til klientmaskinen for at prøve SSL-forbindelsen:
[[email protected]]$ scp -r client_certs/* [email protected]:~/.postgresql
Som standard i Linux/Unix-miljøer, når psql bruges til at lave SSL-forbindelser, søger den efter certifikat/nøgler i '${HOME}/.postgresql' for den aktuelle bruger. Alle disse filer kan også specificeres i forbindelsesparametre - Det ville dog have forplumret det, vi vil teste.
På pgClient-maskinen skal du ændre tilladelsen for postgresql.key for at sikre, at PostgreSQL accepterer det samme.
[[email protected]]$ chmod 0600 ~/.postgresql/postgresql.key
Test af funktionen
PSQL-forbindelsesparameter
Vi er stort set færdige med opsætningen af miljøet. Lad os prøve at oprette en SSL-forbindelse:
[[email protected]]$ psql "host=172.25.130.189 port=5432 user=postgres dbname=postgres sslmode=prefer"
Enter PEM pass phrase:
Nå! Det hele startede kun med ovenstående prompt. Hvis vi har et batchprogram eller et automatiseringsscript, er prompten lidt vanskelig at håndtere. Med den nye tilføjelse af parameteren 'sslpassword' i forbindelsesstrengen er det nu nemt at specificere det som nedenfor:
[[email protected]]$ psql "host=172.25.130.189 port=5432 user=postgres dbname=postgres sslmode=prefer sslpassword=secretclientpass"
Forbindelsen skulle være vellykket efter dette uden nogen prompt.
Libpq Hook for SSL-adgangskode
Historien fortsætter - der er tilføjet en hook-funktion 'PQsetSSLKeyPassHook_OpenSSL' i Libpq-grænsefladen. Dette kan bruges af klientapplikationer, som muligvis ikke har adgang til nøgleadgangssætningen og skal generere/hente fra en ekstern grænseflade ved hjælp af en kompleks logik.
void PQsetSSLKeyPassHook_OpenSSL(PQsslKeyPassHook_OpenSSL_type hook);
En tilbagekaldsfunktion af typen PQsslKeyPassHook_OpenSSL_type kan registreres ved hjælp af denne hook. Tilbagekaldet vil blive påkaldt af Libpq, når der er behov for at få en adgangssætning. Signaturen for en sådan tilbagekaldsfunktion skal være:
int my_callback_function(char *buf, int size, PGconn *conn);
Herunder er et eksempelprogram 'client_conn.c' - som demonstrerer integration af sådan en krog:
#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;
}
Kompiler og kør det samme for at kontrollere, om det virkelig virker:
[[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
En sidste advarsel
Ovenstående blog viser en lille, men nyttig ændring i Libpq/psql-forbindelsesparametre for certifikatbaseret godkendelse i PostgreSQL. Men en advarsel - i ovenstående praktiske øvelse har vi brugt selvsignerede certifikater; det passer måske ikke særlig godt ind i din organisation/produktionsmiljø. Du kan søge at få nogle tredjepartscertifikater for at bruge en sådan SSL-opsætning.