Add more columns to pg_stat_ssl
Add columns client_serial and issuer_dn to pg_stat_ssl. These allow uniquely identifying the client certificate. Rename the existing column clientdn to client_dn, to make the naming more consistent and easier to read. Discussion: https://www.postgresql.org/message-id/flat/398754d8-6bb5-c5cf-e7b8-22e5f0983caf@2ndquadrant.com/
This commit is contained in:
parent
00d1e88d36
commit
f60a0e9677
|
@ -2201,15 +2201,31 @@ SELECT pid, wait_event_type, wait_event FROM pg_stat_activity WHERE wait_event i
|
||||||
or NULL if SSL is not in use on this connection</entry>
|
or NULL if SSL is not in use on this connection</entry>
|
||||||
</row>
|
</row>
|
||||||
<row>
|
<row>
|
||||||
<entry><structfield>clientdn</structfield></entry>
|
<entry><structfield>client_dn</structfield></entry>
|
||||||
<entry><type>text</type></entry>
|
<entry><type>text</type></entry>
|
||||||
<entry>Distinguished Name (DN) field from the client certificate
|
<entry>Distinguished Name (DN) field from the client certificate
|
||||||
used, or NULL if no client certificate was supplied or if SSL
|
used, or NULL if no client certificate was supplied or if SSL
|
||||||
is not in use on this connection. This field is truncated if the
|
is not in use on this connection. This field is truncated if the
|
||||||
DN field is longer than <symbol>NAMEDATALEN</symbol> (64 characters
|
DN field is longer than <symbol>NAMEDATALEN</symbol> (64 characters
|
||||||
in a standard build)
|
in a standard build).
|
||||||
</entry>
|
</entry>
|
||||||
</row>
|
</row>
|
||||||
|
<row>
|
||||||
|
<entry><structfield>client_serial</structfield></entry>
|
||||||
|
<entry><type>numeric</type></entry>
|
||||||
|
<entry>Serial number of the client certificate, or NULL if no client
|
||||||
|
certificate was supplied or if SSL is not in use on this connection. The
|
||||||
|
combination of certificate serial number and certificate issuer uniquely
|
||||||
|
identifies a certificate (unless the issuer erroneously reuses serial
|
||||||
|
numbers).</entry>
|
||||||
|
</row>
|
||||||
|
<row>
|
||||||
|
<entry><structfield>issuer_dn</structfield></entry>
|
||||||
|
<entry><type>text</type></entry>
|
||||||
|
<entry>DN of the issuer of the client certificate, or NULL if no client
|
||||||
|
certificate was supplied or if SSL is not in use on this connection.
|
||||||
|
This field is truncated like <structfield>client_dn</structfield>.</entry>
|
||||||
|
</row>
|
||||||
</tbody>
|
</tbody>
|
||||||
</tgroup>
|
</tgroup>
|
||||||
</table>
|
</table>
|
||||||
|
|
|
@ -782,7 +782,9 @@ CREATE VIEW pg_stat_ssl AS
|
||||||
S.sslcipher AS cipher,
|
S.sslcipher AS cipher,
|
||||||
S.sslbits AS bits,
|
S.sslbits AS bits,
|
||||||
S.sslcompression AS compression,
|
S.sslcompression AS compression,
|
||||||
S.sslclientdn AS clientdn
|
S.ssl_client_dn AS client_dn,
|
||||||
|
S.ssl_client_serial AS client_serial,
|
||||||
|
S.ssl_issuer_dn AS issuer_dn
|
||||||
FROM pg_stat_get_activity(NULL) AS S;
|
FROM pg_stat_get_activity(NULL) AS S;
|
||||||
|
|
||||||
CREATE VIEW pg_replication_slots AS
|
CREATE VIEW pg_replication_slots AS
|
||||||
|
|
|
@ -1109,7 +1109,7 @@ be_tls_get_cipher(Port *port)
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
be_tls_get_peerdn_name(Port *port, char *ptr, size_t len)
|
be_tls_get_peer_subject_name(Port *port, char *ptr, size_t len)
|
||||||
{
|
{
|
||||||
if (port->peer)
|
if (port->peer)
|
||||||
strlcpy(ptr, X509_NAME_to_cstring(X509_get_subject_name(port->peer)), len);
|
strlcpy(ptr, X509_NAME_to_cstring(X509_get_subject_name(port->peer)), len);
|
||||||
|
@ -1117,6 +1117,35 @@ be_tls_get_peerdn_name(Port *port, char *ptr, size_t len)
|
||||||
ptr[0] = '\0';
|
ptr[0] = '\0';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
be_tls_get_peer_issuer_name(Port *port, char *ptr, size_t len)
|
||||||
|
{
|
||||||
|
if (port->peer)
|
||||||
|
strlcpy(ptr, X509_NAME_to_cstring(X509_get_issuer_name(port->peer)), len);
|
||||||
|
else
|
||||||
|
ptr[0] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
be_tls_get_peer_serial(Port *port, char *ptr, size_t len)
|
||||||
|
{
|
||||||
|
if (port->peer)
|
||||||
|
{
|
||||||
|
ASN1_INTEGER *serial;
|
||||||
|
BIGNUM *b;
|
||||||
|
char *decimal;
|
||||||
|
|
||||||
|
serial = X509_get_serialNumber(port->peer);
|
||||||
|
b = ASN1_INTEGER_to_BN(serial, NULL);
|
||||||
|
decimal = BN_bn2dec(b);
|
||||||
|
BN_free(b);
|
||||||
|
strlcpy(ptr, decimal, len);
|
||||||
|
OPENSSL_free(decimal);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
ptr[0] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef HAVE_X509_GET_SIGNATURE_NID
|
#ifdef HAVE_X509_GET_SIGNATURE_NID
|
||||||
char *
|
char *
|
||||||
be_tls_get_certificate_hash(Port *port, size_t *len)
|
be_tls_get_certificate_hash(Port *port, size_t *len)
|
||||||
|
|
|
@ -2906,7 +2906,9 @@ pgstat_bestart(void)
|
||||||
beentry->st_sslstatus->ssl_compression = be_tls_get_compression(MyProcPort);
|
beentry->st_sslstatus->ssl_compression = be_tls_get_compression(MyProcPort);
|
||||||
strlcpy(beentry->st_sslstatus->ssl_version, be_tls_get_version(MyProcPort), NAMEDATALEN);
|
strlcpy(beentry->st_sslstatus->ssl_version, be_tls_get_version(MyProcPort), NAMEDATALEN);
|
||||||
strlcpy(beentry->st_sslstatus->ssl_cipher, be_tls_get_cipher(MyProcPort), NAMEDATALEN);
|
strlcpy(beentry->st_sslstatus->ssl_cipher, be_tls_get_cipher(MyProcPort), NAMEDATALEN);
|
||||||
be_tls_get_peerdn_name(MyProcPort, beentry->st_sslstatus->ssl_clientdn, NAMEDATALEN);
|
be_tls_get_peer_subject_name(MyProcPort, beentry->st_sslstatus->ssl_client_dn, NAMEDATALEN);
|
||||||
|
be_tls_get_peer_serial(MyProcPort, beentry->st_sslstatus->ssl_client_serial, NAMEDATALEN);
|
||||||
|
be_tls_get_peer_issuer_name(MyProcPort, beentry->st_sslstatus->ssl_issuer_dn, NAMEDATALEN);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
|
@ -541,7 +541,7 @@ pg_stat_get_progress_info(PG_FUNCTION_ARGS)
|
||||||
Datum
|
Datum
|
||||||
pg_stat_get_activity(PG_FUNCTION_ARGS)
|
pg_stat_get_activity(PG_FUNCTION_ARGS)
|
||||||
{
|
{
|
||||||
#define PG_STAT_GET_ACTIVITY_COLS 24
|
#define PG_STAT_GET_ACTIVITY_COLS 26
|
||||||
int num_backends = pgstat_fetch_stat_numbackends();
|
int num_backends = pgstat_fetch_stat_numbackends();
|
||||||
int curr_backend;
|
int curr_backend;
|
||||||
int pid = PG_ARGISNULL(0) ? -1 : PG_GETARG_INT32(0);
|
int pid = PG_ARGISNULL(0) ? -1 : PG_GETARG_INT32(0);
|
||||||
|
@ -652,15 +652,29 @@ pg_stat_get_activity(PG_FUNCTION_ARGS)
|
||||||
values[20] = CStringGetTextDatum(beentry->st_sslstatus->ssl_cipher);
|
values[20] = CStringGetTextDatum(beentry->st_sslstatus->ssl_cipher);
|
||||||
values[21] = Int32GetDatum(beentry->st_sslstatus->ssl_bits);
|
values[21] = Int32GetDatum(beentry->st_sslstatus->ssl_bits);
|
||||||
values[22] = BoolGetDatum(beentry->st_sslstatus->ssl_compression);
|
values[22] = BoolGetDatum(beentry->st_sslstatus->ssl_compression);
|
||||||
if (beentry->st_sslstatus->ssl_clientdn[0])
|
|
||||||
values[23] = CStringGetTextDatum(beentry->st_sslstatus->ssl_clientdn);
|
if (beentry->st_sslstatus->ssl_client_dn[0])
|
||||||
|
values[23] = CStringGetTextDatum(beentry->st_sslstatus->ssl_client_dn);
|
||||||
else
|
else
|
||||||
nulls[23] = true;
|
nulls[23] = true;
|
||||||
|
|
||||||
|
if (beentry->st_sslstatus->ssl_client_serial[0])
|
||||||
|
values[24] = DirectFunctionCall3(numeric_in,
|
||||||
|
CStringGetDatum(beentry->st_sslstatus->ssl_client_serial),
|
||||||
|
ObjectIdGetDatum(InvalidOid),
|
||||||
|
Int32GetDatum(-1));
|
||||||
|
else
|
||||||
|
nulls[24] = true;
|
||||||
|
|
||||||
|
if (beentry->st_sslstatus->ssl_issuer_dn[0])
|
||||||
|
values[25] = CStringGetTextDatum(beentry->st_sslstatus->ssl_issuer_dn);
|
||||||
|
else
|
||||||
|
nulls[25] = true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
values[18] = BoolGetDatum(false); /* ssl */
|
values[18] = BoolGetDatum(false); /* ssl */
|
||||||
nulls[19] = nulls[20] = nulls[21] = nulls[22] = nulls[23] = true;
|
nulls[19] = nulls[20] = nulls[21] = nulls[22] = nulls[23] = nulls[24] = nulls[25] = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Values only available to role member or pg_read_all_stats */
|
/* Values only available to role member or pg_read_all_stats */
|
||||||
|
|
|
@ -53,6 +53,6 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* yyyymmddN */
|
/* yyyymmddN */
|
||||||
#define CATALOG_VERSION_NO 201901041
|
#define CATALOG_VERSION_NO 201902011
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -5058,9 +5058,9 @@
|
||||||
proname => 'pg_stat_get_activity', prorows => '100', proisstrict => 'f',
|
proname => 'pg_stat_get_activity', prorows => '100', proisstrict => 'f',
|
||||||
proretset => 't', provolatile => 's', proparallel => 'r',
|
proretset => 't', provolatile => 's', proparallel => 'r',
|
||||||
prorettype => 'record', proargtypes => 'int4',
|
prorettype => 'record', proargtypes => 'int4',
|
||||||
proallargtypes => '{int4,oid,int4,oid,text,text,text,text,text,timestamptz,timestamptz,timestamptz,timestamptz,inet,text,int4,xid,xid,text,bool,text,text,int4,bool,text}',
|
proallargtypes => '{int4,oid,int4,oid,text,text,text,text,text,timestamptz,timestamptz,timestamptz,timestamptz,inet,text,int4,xid,xid,text,bool,text,text,int4,bool,text,numeric,text}',
|
||||||
proargmodes => '{i,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o}',
|
proargmodes => '{i,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o}',
|
||||||
proargnames => '{pid,datid,pid,usesysid,application_name,state,query,wait_event_type,wait_event,xact_start,query_start,backend_start,state_change,client_addr,client_hostname,client_port,backend_xid,backend_xmin,backend_type,ssl,sslversion,sslcipher,sslbits,sslcompression,sslclientdn}',
|
proargnames => '{pid,datid,pid,usesysid,application_name,state,query,wait_event_type,wait_event,xact_start,query_start,backend_start,state_change,client_addr,client_hostname,client_port,backend_xid,backend_xmin,backend_type,ssl,sslversion,sslcipher,sslbits,sslcompression,ssl_client_dn,ssl_client_serial,ssl_issuer_dn}',
|
||||||
prosrc => 'pg_stat_get_activity' },
|
prosrc => 'pg_stat_get_activity' },
|
||||||
{ oid => '3318',
|
{ oid => '3318',
|
||||||
descr => 'statistics: information about progress of backends running maintenance command',
|
descr => 'statistics: information about progress of backends running maintenance command',
|
||||||
|
|
|
@ -258,7 +258,9 @@ extern int be_tls_get_cipher_bits(Port *port);
|
||||||
extern bool be_tls_get_compression(Port *port);
|
extern bool be_tls_get_compression(Port *port);
|
||||||
extern const char *be_tls_get_version(Port *port);
|
extern const char *be_tls_get_version(Port *port);
|
||||||
extern const char *be_tls_get_cipher(Port *port);
|
extern const char *be_tls_get_cipher(Port *port);
|
||||||
extern void be_tls_get_peerdn_name(Port *port, char *ptr, size_t len);
|
extern void be_tls_get_peer_subject_name(Port *port, char *ptr, size_t len);
|
||||||
|
extern void be_tls_get_peer_issuer_name(Port *port, char *ptr, size_t len);
|
||||||
|
extern void be_tls_get_peer_serial(Port *port, char *ptr, size_t len);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Get the server certificate hash for SCRAM channel binding type
|
* Get the server certificate hash for SCRAM channel binding type
|
||||||
|
|
|
@ -950,15 +950,25 @@ typedef enum ProgressCommandType
|
||||||
*
|
*
|
||||||
* For each backend, we keep the SSL status in a separate struct, that
|
* For each backend, we keep the SSL status in a separate struct, that
|
||||||
* is only filled in if SSL is enabled.
|
* is only filled in if SSL is enabled.
|
||||||
|
*
|
||||||
|
* All char arrays must be null-terminated.
|
||||||
*/
|
*/
|
||||||
typedef struct PgBackendSSLStatus
|
typedef struct PgBackendSSLStatus
|
||||||
{
|
{
|
||||||
/* Information about SSL connection */
|
/* Information about SSL connection */
|
||||||
int ssl_bits;
|
int ssl_bits;
|
||||||
bool ssl_compression;
|
bool ssl_compression;
|
||||||
char ssl_version[NAMEDATALEN]; /* MUST be null-terminated */
|
char ssl_version[NAMEDATALEN];
|
||||||
char ssl_cipher[NAMEDATALEN]; /* MUST be null-terminated */
|
char ssl_cipher[NAMEDATALEN];
|
||||||
char ssl_clientdn[NAMEDATALEN]; /* MUST be null-terminated */
|
char ssl_client_dn[NAMEDATALEN];
|
||||||
|
|
||||||
|
/*
|
||||||
|
* serial number is max "20 octets" per RFC 5280, so this size should be
|
||||||
|
* fine
|
||||||
|
*/
|
||||||
|
char ssl_client_serial[NAMEDATALEN];
|
||||||
|
|
||||||
|
char ssl_issuer_dn[NAMEDATALEN];
|
||||||
} PgBackendSSLStatus;
|
} PgBackendSSLStatus;
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1731,7 +1731,7 @@ pg_stat_activity| SELECT s.datid,
|
||||||
s.backend_xmin,
|
s.backend_xmin,
|
||||||
s.query,
|
s.query,
|
||||||
s.backend_type
|
s.backend_type
|
||||||
FROM ((pg_stat_get_activity(NULL::integer) s(datid, pid, usesysid, application_name, state, query, wait_event_type, wait_event, xact_start, query_start, backend_start, state_change, client_addr, client_hostname, client_port, backend_xid, backend_xmin, backend_type, ssl, sslversion, sslcipher, sslbits, sslcompression, sslclientdn)
|
FROM ((pg_stat_get_activity(NULL::integer) s(datid, pid, usesysid, application_name, state, query, wait_event_type, wait_event, xact_start, query_start, backend_start, state_change, client_addr, client_hostname, client_port, backend_xid, backend_xmin, backend_type, ssl, sslversion, sslcipher, sslbits, sslcompression, ssl_client_dn, ssl_client_serial, ssl_issuer_dn)
|
||||||
LEFT JOIN pg_database d ON ((s.datid = d.oid)))
|
LEFT JOIN pg_database d ON ((s.datid = d.oid)))
|
||||||
LEFT JOIN pg_authid u ON ((s.usesysid = u.oid)));
|
LEFT JOIN pg_authid u ON ((s.usesysid = u.oid)));
|
||||||
pg_stat_all_indexes| SELECT c.oid AS relid,
|
pg_stat_all_indexes| SELECT c.oid AS relid,
|
||||||
|
@ -1863,7 +1863,7 @@ pg_stat_replication| SELECT s.pid,
|
||||||
w.sync_priority,
|
w.sync_priority,
|
||||||
w.sync_state,
|
w.sync_state,
|
||||||
w.reply_time
|
w.reply_time
|
||||||
FROM ((pg_stat_get_activity(NULL::integer) s(datid, pid, usesysid, application_name, state, query, wait_event_type, wait_event, xact_start, query_start, backend_start, state_change, client_addr, client_hostname, client_port, backend_xid, backend_xmin, backend_type, ssl, sslversion, sslcipher, sslbits, sslcompression, sslclientdn)
|
FROM ((pg_stat_get_activity(NULL::integer) s(datid, pid, usesysid, application_name, state, query, wait_event_type, wait_event, xact_start, query_start, backend_start, state_change, client_addr, client_hostname, client_port, backend_xid, backend_xmin, backend_type, ssl, sslversion, sslcipher, sslbits, sslcompression, ssl_client_dn, ssl_client_serial, ssl_issuer_dn)
|
||||||
JOIN pg_stat_get_wal_senders() w(pid, state, sent_lsn, write_lsn, flush_lsn, replay_lsn, write_lag, flush_lag, replay_lag, sync_priority, sync_state, reply_time) ON ((s.pid = w.pid)))
|
JOIN pg_stat_get_wal_senders() w(pid, state, sent_lsn, write_lsn, flush_lsn, replay_lsn, write_lag, flush_lag, replay_lag, sync_priority, sync_state, reply_time) ON ((s.pid = w.pid)))
|
||||||
LEFT JOIN pg_authid u ON ((s.usesysid = u.oid)));
|
LEFT JOIN pg_authid u ON ((s.usesysid = u.oid)));
|
||||||
pg_stat_ssl| SELECT s.pid,
|
pg_stat_ssl| SELECT s.pid,
|
||||||
|
@ -1872,8 +1872,10 @@ pg_stat_ssl| SELECT s.pid,
|
||||||
s.sslcipher AS cipher,
|
s.sslcipher AS cipher,
|
||||||
s.sslbits AS bits,
|
s.sslbits AS bits,
|
||||||
s.sslcompression AS compression,
|
s.sslcompression AS compression,
|
||||||
s.sslclientdn AS clientdn
|
s.ssl_client_dn AS client_dn,
|
||||||
FROM pg_stat_get_activity(NULL::integer) s(datid, pid, usesysid, application_name, state, query, wait_event_type, wait_event, xact_start, query_start, backend_start, state_change, client_addr, client_hostname, client_port, backend_xid, backend_xmin, backend_type, ssl, sslversion, sslcipher, sslbits, sslcompression, sslclientdn);
|
s.ssl_client_serial AS client_serial,
|
||||||
|
s.ssl_issuer_dn AS issuer_dn
|
||||||
|
FROM pg_stat_get_activity(NULL::integer) s(datid, pid, usesysid, application_name, state, query, wait_event_type, wait_event, xact_start, query_start, backend_start, state_change, client_addr, client_hostname, client_port, backend_xid, backend_xmin, backend_type, ssl, sslversion, sslcipher, sslbits, sslcompression, ssl_client_dn, ssl_client_serial, ssl_issuer_dn);
|
||||||
pg_stat_subscription| SELECT su.oid AS subid,
|
pg_stat_subscription| SELECT su.oid AS subid,
|
||||||
su.subname,
|
su.subname,
|
||||||
st.pid,
|
st.pid,
|
||||||
|
|
|
@ -315,8 +315,8 @@ command_like([
|
||||||
'-d', "$common_connstr sslrootcert=invalid",
|
'-d', "$common_connstr sslrootcert=invalid",
|
||||||
'-c', "SELECT * FROM pg_stat_ssl WHERE pid = pg_backend_pid()"
|
'-c', "SELECT * FROM pg_stat_ssl WHERE pid = pg_backend_pid()"
|
||||||
],
|
],
|
||||||
qr{^pid,ssl,version,cipher,bits,compression,clientdn\n
|
qr{^pid,ssl,version,cipher,bits,compression,client_dn,client_serial,issuer_dn\n
|
||||||
^\d+,t,TLSv[\d.]+,[\w-]+,\d+,f,_null_$}mx,
|
^\d+,t,TLSv[\d.]+,[\w-]+,\d+,f,_null_,_null_,_null_$}mx,
|
||||||
'pg_stat_ssl view without client certificate');
|
'pg_stat_ssl view without client certificate');
|
||||||
|
|
||||||
### Server-side tests.
|
### Server-side tests.
|
||||||
|
@ -347,8 +347,8 @@ command_like([
|
||||||
'-d', "$common_connstr user=ssltestuser sslcert=ssl/client.crt sslkey=ssl/client_tmp.key",
|
'-d', "$common_connstr user=ssltestuser sslcert=ssl/client.crt sslkey=ssl/client_tmp.key",
|
||||||
'-c', "SELECT * FROM pg_stat_ssl WHERE pid = pg_backend_pid()"
|
'-c', "SELECT * FROM pg_stat_ssl WHERE pid = pg_backend_pid()"
|
||||||
],
|
],
|
||||||
qr{^pid,ssl,version,cipher,bits,compression,clientdn\n
|
qr{^pid,ssl,version,cipher,bits,compression,client_dn,client_serial,issuer_dn\n
|
||||||
^\d+,t,TLSv[\d.]+,[\w-]+,\d+,f,/CN=ssltestuser$}mx,
|
^\d+,t,TLSv[\d.]+,[\w-]+,\d+,f,/CN=ssltestuser,1,\Q/CN=Test CA for PostgreSQL SSL regression test client certs\E$}mx,
|
||||||
'pg_stat_ssl with client certificate');
|
'pg_stat_ssl with client certificate');
|
||||||
|
|
||||||
# client key with wrong permissions
|
# client key with wrong permissions
|
||||||
|
|
Loading…
Reference in New Issue