Commit 815f84aa authored by Bruce Momjian's avatar Bruce Momjian

doc: update intermediate certificate instructions

Document how to properly create root and intermediate certificates using
v3_ca extensions and where to place intermediate certificates so they
are properly transferred to the remote side with the leaf certificate to
link to the remote root certificate.  This corrects docs that used to
say that intermediate certificates must be stored with the root
certificate.

Also add instructions on how to create root, intermediate, and leaf
certificates.

Discussion: https://postgr.es/m/20180116002238.GC12724@momjian.us

Reviewed-by: Michael Paquier

Backpatch-through: 9.3
parent 918e02a2
...@@ -7574,17 +7574,37 @@ ldap://ldap.acme.com/cn=dbserver,cn=hosts?pgconnectinfo?base?(objectclass=*) ...@@ -7574,17 +7574,37 @@ ldap://ldap.acme.com/cn=dbserver,cn=hosts?pgconnectinfo?base?(objectclass=*)
the server certificate. This means that it is possible to spoof the server the server certificate. This means that it is possible to spoof the server
identity (for example by modifying a DNS record or by taking over the server identity (for example by modifying a DNS record or by taking over the server
IP address) without the client knowing. In order to prevent spoofing, IP address) without the client knowing. In order to prevent spoofing,
<acronym>SSL</acronym> certificate verification must be used. the client must be able to verify the server's identity via a chain of
trust. A chain of trust is established by placing a root (self-signed)
certificate authority (<acronym>CA</acronym>) certificate on one
computer and a leaf certificate <emphasis>signed</emphasis> by the
root certificate on another computer. It is also possible to use an
<quote>intermediate</quote> certificate which is signed by the root
certificate and signs leaf certificates.
</para> </para>
<para> <para>
To allow the client to verify the identity of the server, place a root
certificate on the client and a leaf certificate signed by the root
certificate on the server. To allow the server to verify the identity
of the client, place a root certificate on the server and a leaf and
optional intermediate certificates signed by the root certificate on
the client. Intermediate certificates (usually stored with the leaf
certificate) can also be used to link the leaf certificate to the
root certificate.
</para>
<para>
Once a chain of trust has been established, there are two ways for
the client to validate the leaf certificate sent by the server.
If the parameter <literal>sslmode</literal> is set to <literal>verify-ca</literal>, If the parameter <literal>sslmode</literal> is set to <literal>verify-ca</literal>,
libpq will verify that the server is trustworthy by checking the libpq will verify that the server is trustworthy by checking the
certificate chain up to a trusted certificate authority certificate chain up to the root certificate stored on the client.
(<acronym>CA</acronym>). If <literal>sslmode</literal> is set to <literal>verify-full</literal>, If <literal>sslmode</literal> is set to <literal>verify-full</literal>,
libpq will <emphasis>also</emphasis> verify that the server host name matches its libpq will <emphasis>also</emphasis> verify that the server host
certificate. The SSL connection will fail if the server certificate cannot name matches the name stored in the server certificate. The
be verified. <literal>verify-full</literal> is recommended in most SSL connection will fail if the server certificate cannot be
verified. <literal>verify-full</literal> is recommended in most
security-sensitive environments. security-sensitive environments.
</para> </para>
...@@ -7601,13 +7621,13 @@ ldap://ldap.acme.com/cn=dbserver,cn=hosts?pgconnectinfo?base?(objectclass=*) ...@@ -7601,13 +7621,13 @@ ldap://ldap.acme.com/cn=dbserver,cn=hosts?pgconnectinfo?base?(objectclass=*)
</para> </para>
<para> <para>
To allow server certificate verification, the certificate(s) of one or more To allow server certificate verification, one or more root certificates
trusted <acronym>CA</acronym>s must be must be placed in the file <filename>~/.postgresql/root.crt</filename>
placed in the file <filename>~/.postgresql/root.crt</filename> in the user's home in the user's home directory. (On Microsoft Windows the file is named
directory. If intermediate <acronym>CA</acronym>s appear in <filename>%APPDATA%\postgresql\root.crt</filename>.) Intermediate
<filename>root.crt</filename>, the file must also contain certificate certificates should also be added to the file if they are needed to link
chains to their root <acronym>CA</acronym>s. (On Microsoft Windows the file is named the certificate chain sent by the server to the root certificates
<filename>%APPDATA%\postgresql\root.crt</filename>.) stored on the client.
</para> </para>
<para> <para>
...@@ -7641,11 +7661,12 @@ ldap://ldap.acme.com/cn=dbserver,cn=hosts?pgconnectinfo?base?(objectclass=*) ...@@ -7641,11 +7661,12 @@ ldap://ldap.acme.com/cn=dbserver,cn=hosts?pgconnectinfo?base?(objectclass=*)
<title>Client Certificates</title> <title>Client Certificates</title>
<para> <para>
If the server requests a trusted client certificate, If the server attempts to verify the identity of the
<application>libpq</application> will send the certificate stored in client by requesting the client's leaf certificate,
<application>libpq</application> will send the certificates stored in
file <filename>~/.postgresql/postgresql.crt</filename> in the user's home file <filename>~/.postgresql/postgresql.crt</filename> in the user's home
directory. The certificate must be signed by one of the certificate directory. The certificates must chain to the root certificate trusted
authorities (<acronym>CA</acronym>) trusted by the server. A matching by the server. A matching
private key file <filename>~/.postgresql/postgresql.key</filename> must also private key file <filename>~/.postgresql/postgresql.key</filename> must also
be present. The private be present. The private
key file must not allow any access to world or group; achieve this by the key file must not allow any access to world or group; achieve this by the
...@@ -7660,23 +7681,17 @@ ldap://ldap.acme.com/cn=dbserver,cn=hosts?pgconnectinfo?base?(objectclass=*) ...@@ -7660,23 +7681,17 @@ ldap://ldap.acme.com/cn=dbserver,cn=hosts?pgconnectinfo?base?(objectclass=*)
</para> </para>
<para> <para>
In some cases, the client certificate might be signed by an The first certificate in <filename>postgresql.crt</filename> must be the
<quote>intermediate</quote> certificate authority, rather than one that is client's certificate because it must match the client's private key.
directly trusted by the server. To use such a certificate, append the <quote>Intermediate</quote> certificates can be optionally appended
certificate of the signing authority to the <filename>postgresql.crt</filename> to the file &mdash; doing so avoids requiring storage of intermediate
file, then its parent authority's certificate, and so on up to a certificate certificates on the server (<xref linkend="guc-ssl-ca-file"/>).
authority, <quote>root</quote> or <quote>intermediate</quote>, that is trusted by
the server, i.e. signed by a certificate in the server's root CA file
(<xref linkend="guc-ssl-ca-file"/>).
</para> </para>
<para> <para>
Note that the client's <filename>~/.postgresql/root.crt</filename> lists the top-level CAs For instructions on creating certificates, see <xref
that are considered trusted for signing server certificates. In principle it need linkend="ssl-certificate-creation"/>.
not list the CA that signed the client's certificate, though in most cases
that CA would also be trusted for server certificates.
</para> </para>
</sect2> </sect2>
<sect2 id="libpq-ssl-protection"> <sect2 id="libpq-ssl-protection">
......
...@@ -2247,40 +2247,46 @@ pg_dumpall -p 5432 | psql -d postgres -p 5433 ...@@ -2247,40 +2247,46 @@ pg_dumpall -p 5432 | psql -d postgres -p 5433
</para> </para>
<para> <para>
In some cases, the server certificate might be signed by an The first certificate in <filename>server.crt</filename> must be the
<quote>intermediate</quote> certificate authority, rather than one that is server's certificate because it must match the server's private key.
directly trusted by clients. To use such a certificate, append the The certificates of <quote>intermediate</quote> certificate authorities
certificate of the signing authority to the <filename>server.crt</filename> file, can also be appended to the file. Doing this avoids the necessity of
then its parent authority's certificate, and so on up to a certificate storing intermediate certificates on clients, assuming the root and
authority, <quote>root</quote> or <quote>intermediate</quote>, that is trusted by intermediate certificates were created with <literal>v3_ca</literal>
clients, i.e. signed by a certificate in the clients' extensions. This allows easier expiration of intermediate certificates.
<filename>root.crt</filename> files. </para>
<para>
It is not necessary to add the root certificate to
<filename>server.crt</filename>. Instead, clients must have the root
certificate of the server's certificate chain.
</para> </para>
<sect2 id="ssl-client-certificates"> <sect2 id="ssl-client-certificates">
<title>Using Client Certificates</title> <title>Using Client Certificates</title>
<para> <para>
To require the client to supply a trusted certificate, place To require the client to supply a trusted certificate,
certificates of the certificate authorities (<acronym>CA</acronym>s) place certificates of the root certificate authorities
you trust in a file named <filename>root.crt</filename> in the data (<acronym>CA</acronym>s) you trust in a file in the data
directory, set the parameter <xref linkend="guc-ssl-ca-file"/> in directory, set the parameter <xref linkend="guc-ssl-ca-file"/> in
<filename>postgresql.conf</filename> to <literal>root.crt</literal>, <filename>postgresql.conf</filename> to the new file name, and add the
and add the authentication option <literal>clientcert=1</literal> to the authentication option <literal>clientcert=1</literal> to the appropriate
appropriate <literal>hostssl</literal> line(s) in <filename>pg_hba.conf</filename>. <literal>hostssl</literal> line(s) in <filename>pg_hba.conf</filename>.
A certificate will then be requested from the client during A certificate will then be requested from the client during SSL
SSL connection startup. (See <xref linkend="libpq-ssl"/> for a connection startup. (See <xref linkend="libpq-ssl"/> for a description
description of how to set up certificates on the client.) The server will of how to set up certificates on the client.) The server will
verify that the client's certificate is signed by one of the trusted verify that the client's certificate is signed by one of the trusted
certificate authorities. certificate authorities.
</para> </para>
<para> <para>
If intermediate <acronym>CA</acronym>s appear in Intermediate certificates that chain up to existing root certificates
<filename>root.crt</filename>, the file must also contain certificate can also appear in the <xref linkend="guc-ssl-ca-file"/> file if
chains to their root <acronym>CA</acronym>s. Certificate Revocation List you wish to avoid storing them on clients (assuming the root and
(CRL) entries intermediate certificates were created with <literal>v3_ca</literal>
are also checked if the parameter <xref linkend="guc-ssl-crl-file"/> is set. extensions). Certificate Revocation List (CRL) entries are also
checked if the parameter <xref linkend="guc-ssl-crl-file"/> is set.
<!-- If this URL changes replace it with a URL to www.archive.org. --> <!-- If this URL changes replace it with a URL to www.archive.org. -->
(See <ulink (See <ulink
url="http://h71000.www7.hp.com/doc/83final/ba554_90007/ch04s02.html"></ulink> url="http://h71000.www7.hp.com/doc/83final/ba554_90007/ch04s02.html"></ulink>
...@@ -2296,14 +2302,6 @@ pg_dumpall -p 5432 | psql -d postgres -p 5433 ...@@ -2296,14 +2302,6 @@ pg_dumpall -p 5432 | psql -d postgres -p 5433
it will not insist that a client certificate be presented. it will not insist that a client certificate be presented.
</para> </para>
<para>
Note that the server's <filename>root.crt</filename> lists the top-level
CAs that are considered trusted for signing client certificates.
In principle it need
not list the CA that signed the server's certificate, though in most cases
that CA would also be trusted for client certificates.
</para>
<para> <para>
If you are setting up client certificates, you may wish to use If you are setting up client certificates, you may wish to use
the <literal>cert</literal> authentication method, so that the certificates the <literal>cert</literal> authentication method, so that the certificates
...@@ -2385,15 +2383,16 @@ pg_dumpall -p 5432 | psql -d postgres -p 5433 ...@@ -2385,15 +2383,16 @@ pg_dumpall -p 5432 | psql -d postgres -p 5433
</sect2> </sect2>
<sect2 id="ssl-certificate-creation"> <sect2 id="ssl-certificate-creation">
<title>Creating a Self-signed Certificate</title> <title>Creating Certificates</title>
<para> <para>
To create a quick self-signed certificate for the server, valid for 365 To create a simple self-signed certificate for the server, valid for 365
days, use the following <productname>OpenSSL</productname> command, days, use the following <productname>OpenSSL</productname> command,
replacing <replaceable>yourdomain.com</replaceable> with the server's host name: replacing <replaceable>dbhost.yourdomain.com</replaceable> with the
server's host name:
<programlisting> <programlisting>
openssl req -new -x509 -days 365 -nodes -text -out server.crt \ openssl req -new -x509 -days 365 -nodes -text -out server.crt \
-keyout server.key -subj "/CN=<replaceable>yourdomain.com</replaceable>" -keyout server.key -subj "/CN=<replaceable>dbhost.yourdomain.com</replaceable>"
</programlisting> </programlisting>
Then do: Then do:
<programlisting> <programlisting>
...@@ -2406,14 +2405,86 @@ chmod og-rwx server.key ...@@ -2406,14 +2405,86 @@ chmod og-rwx server.key
</para> </para>
<para> <para>
A self-signed certificate can be used for testing, but a certificate While a self-signed certificate can be used for testing, a certificate
signed by a certificate authority (<acronym>CA</acronym>) (either one of the signed by a certificate authority (<acronym>CA</acronym>) (usually an
global <acronym>CAs</acronym> or a local one) should be used in production enterprise-wide root <acronym>CA</acronym>) should be used in production.
so that clients can verify the server's identity. If all the clients
are local to the organization, using a local <acronym>CA</acronym> is
recommended.
</para> </para>
<para>
To create a server certificate whose identity can be validated
by clients, first create a certificate signing request
(<acronym>CSR</acronym>) and a public/private key file:
<programlisting>
openssl req -new -nodes -text -out root.csr \
-keyout root.key -subj "/CN=<replaceable>root.yourdomain.com</replaceable>"
chmod og-rwx root.key
</programlisting>
Then, sign the request with the key to create a root certificate
authority (using the default <productname>OpenSSL</productname>
configuration file location on <productname>Linux</productname>):
<programlisting>
openssl x509 -req -in root.csr -text -days 3650 \
-extfile /etc/ssl/openssl.cnf -extensions v3_ca \
-signkey root.key -out root.crt
</programlisting>
Finally, create a server certificate signed by the new root certificate
authority:
<programlisting>
openssl req -new -nodes -text -out server.csr \
-keyout server.key -subj "/CN=<replaceable>dbhost.yourdomain.com</replaceable>"
chmod og-rwx server.key
openssl x509 -req -in server.csr -text -days 365 \
-CA root.crt -CAkey root.key -CAcreateserial \
-out server.crt
</programlisting>
<filename>server.crt</filename> and <filename>server.key</filename>
should be stored on the server, and <filename>root.crt</filename> should
be stored on the client so the client can verify that the server's leaf
certificate was signed by its trusted root certificate.
<filename>root.key</filename> should be stored offline for use in
creating future certificates.
</para>
<para>
It is also possible to create a chain of trust that includes
intermediate certificates:
<programlisting>
# root
openssl req -new -nodes -text -out root.csr \
-keyout root.key -subj "/CN=<replaceable>root.yourdomain.com</replaceable>"
chmod og-rwx root.key
openssl x509 -req -in root.csr -text -days 3650 \
-extfile /etc/ssl/openssl.cnf -extensions v3_ca \
-signkey root.key -out root.crt
# intermediate
openssl req -new -nodes -text -out intermediate.csr \
-keyout intermediate.key -subj "/CN=<replaceable>intermediate.yourdomain.com</replaceable>"
chmod og-rwx intermediate.key
openssl x509 -req -in intermediate.csr -text -days 1825 \
-extfile /etc/ssl/openssl.cnf -extensions v3_ca \
-CA root.crt -CAkey root.key -CAcreateserial \
-out intermediate.crt
# leaf
openssl req -new -nodes -text -out server.csr \
-keyout server.key -subj "/CN=<replaceable>dbhost.yourdomain.com</replaceable>"
chmod og-rwx server.key
openssl x509 -req -in server.csr -text -days 365 \
-CA intermediate.crt -CAkey intermediate.key -CAcreateserial \
-out server.crt
</programlisting>
<filename>server.crt</filename> and
<filename>intermediate.crt</filename> should be concatenated
into a certificate file bundle and stored on the server.
<filename>server.key</filename> should also be stored on the server.
<filename>root.crt</filename> should be stored on the client so
the client can verify that the server's leaf certificate was signed
by a chain of certificates linked to its trusted root certificate.
<filename>root.key</filename> and <filename>intermediate.key</filename>
should be stored offline for use in creating future certificates.
</para>
</sect2> </sect2>
</sect1> </sect1>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment