PostgreSQLは長い間、SSL接続と証明書ベースの認証メカニズムをサポートしてきました。この点に関しては、PostgreSQLの世界にとって新しいことは何もないようですが。ただし、クライアント接続(クライアント証明書ベースの認証)の小さな問題は、暗号化されたクライアントキーの「EnterPEMpassphrase:」というプロンプトでした。
PostgreSQL 13の新機能は、「ssl_passphrase_command」サーバーパラメーターを補完します。 ssl_passphrase_commandパラメーターを使用すると、サーバー管理者はサーバー証明書に使用される暗号化されたサーバーキーのパスフレーズを指定できます。新しく導入された接続パラメータ「sslpassword」は、クライアント接続に対していくらか同様の制御を提供します。
この機能分析の実践的な演習を行うために、私はかなり基本的なシステムを確立しました:
- 2台の仮想マシン
- pgServer(172.25.130.189)
- pgClient(172.25.130.178)
- pgServerの自己署名証明書
機能を分析するために、まず、関連する証明書とpgServer仮想マシン上のそれぞれの構成を使用してPostgreSQL13サーバーインスタンスをセットアップしましょう。
[[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'
また、pgClientノードからのSSL接続が受け入れられ、生成された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:
覚えておくべき重要な側面の1つは、証明書のCN名です。それは、エンティティの識別または名前であると考えてください。上記のクライアント証明書で、CNが「postgres」に設定されている場合、それはpostgresという名前のロールを対象としています。また、サーバー証明書の設定中に、CN=pgServerを使用しました。 SSL接続の完全検証モードを使用する場合は問題になる可能性があります。
[[email protected]]$ scp -r client_certs/* [email protected]:~/.postgresql
Linux / Unix環境では、デフォルトで、SSL接続を確立するためにpsqlが使用されると、現在のユーザーの「${HOME}/。postgresql」で証明書/キーが検索されます。これらのファイルはすべて、接続パラメーターで指定することもできます-ただし、テストしたいものが曇っていたでしょう。
pgClientマシンで、postgresql.keyの権限を変更して、PostgreSQLが同じものを受け入れるようにします。
[[email protected]]$ chmod 0600 ~/.postgresql/postgresql.key
PSQL接続パラメータ
[[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"
この後、プロンプトなしで接続が成功するはずです。
SSLパスワード用のLibpqフック
void PQsetSSLKeyPassHook_OpenSSL(PQsslKeyPassHook_OpenSSL_type hook);
タイプPQsslKeyPassHook_OpenSSL_typeのコールバック関数は、このフックを使用して登録できます。パスフレーズを取得する必要がある場合、コールバックはLibpqによって呼び出されます。このようなコールバック関数のシグネチャは次のとおりです。
int my_callback_function(char *buf, int size, PGconn *conn);
以下は、そのようなフックの統合を示す1つのサンプルプログラム「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
上記のブログは、PostgreSQLでの証明書ベースの認証のためのLibpq/psql接続パラメーターの小さいながらも便利な変更を示しています。ただし、注意が必要です。上記の実践的な演習では、自己署名証明書を使用しています。組織/本番環境にうまく適合しない場合があります。このようなSSL設定を使用するために、サードパーティの証明書を取得しようとする場合があります。