]> granicus.if.org Git - postgresql/commitdiff
doc: update intermediate certificate instructions
authorBruce Momjian <bruce@momjian.us>
Sun, 21 Jan 2018 02:47:02 +0000 (21:47 -0500)
committerBruce Momjian <bruce@momjian.us>
Sun, 21 Jan 2018 02:47:02 +0000 (21:47 -0500)
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

doc/src/sgml/libpq.sgml
doc/src/sgml/runtime.sgml

index 7a90cb09a9be9702438ba1837a242a3616cb1128..5762ef8acc5056c174c4289d4eda5ad46d7f8151 100644 (file)
@@ -7333,17 +7333,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
    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,
-   <acronym>SSL</> 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</>) certificate on one
+   computer and a leaf certificate <emphasis>signed</> by the
+   root certificate on another computer.  It is also possible to use an
+   <quote>intermediate</> certificate which is signed by the root
+   certificate and signs leaf certificates.
   </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</> is set to <literal>verify-ca</>,
    libpq will verify that the server is trustworthy by checking the
-   certificate chain up to a trusted certificate authority
-   (<acronym>CA</>). If <literal>sslmode</> is set to <literal>verify-full</>,
-   libpq will <emphasis>also</> verify that the server host name matches its
-   certificate. The SSL connection will fail if the server certificate cannot
-   be verified. <literal>verify-full</> is recommended in most
+   certificate chain up to the root certificate stored on the client.
+   If <literal>sslmode</> is set to <literal>verify-full</>,
+   libpq will <emphasis>also</> verify that the server host
+   name matches the name stored in the server certificate. The
+   SSL connection will fail if the server certificate cannot be
+   verified. <literal>verify-full</> is recommended in most
    security-sensitive environments.
   </para>
 
@@ -7360,13 +7380,13 @@ ldap://ldap.acme.com/cn=dbserver,cn=hosts?pgconnectinfo?base?(objectclass=*)
   </para>
 
   <para>
-   To allow server certificate verification, the certificate(s) of one or more
-   trusted <acronym>CA</>s must be
-   placed in the file <filename>~/.postgresql/root.crt</> in the user's home
-   directory. If intermediate <acronym>CA</>s appear in
-   <filename>root.crt</filename>, the file must also contain certificate
-   chains to their root <acronym>CA</>s. (On Microsoft Windows the file is named
-   <filename>%APPDATA%\postgresql\root.crt</filename>.)
+   To allow server certificate verification, one or more root certificates
+   must be placed in the file <filename>~/.postgresql/root.crt</>
+   in the user's home directory.  (On Microsoft Windows the file is named
+   <filename>%APPDATA%\postgresql\root.crt</>.)  Intermediate
+   certificates should also be added to the file if they are needed to link
+   the certificate chain sent by the server to the root certificates
+   stored on the client.
   </para>
 
   <para>
@@ -7400,11 +7420,12 @@ ldap://ldap.acme.com/cn=dbserver,cn=hosts?pgconnectinfo?base?(objectclass=*)
   <title>Client Certificates</title>
 
   <para>
-   If the server requests a trusted client certificate,
-   <application>libpq</application> will send the certificate stored in
+   If the server attempts to verify the identity of the
+   client by requesting the client's leaf certificate,
+   <application>libpq</> will send the certificates stored in
    file <filename>~/.postgresql/postgresql.crt</> in the user's home
-   directory.  The certificate must be signed by one of the certificate
-   authorities (<acronym>CA</acronym>) trusted by the server.  A matching
+   directory.  The certificates must chain to the root certificate trusted
+   by the server.  A matching
    private key file <filename>~/.postgresql/postgresql.key</> must also
    be present. The private
    key file must not allow any access to world or group; achieve this by the
@@ -7419,23 +7440,17 @@ ldap://ldap.acme.com/cn=dbserver,cn=hosts?pgconnectinfo?base?(objectclass=*)
   </para>
 
   <para>
-   In some cases, the client certificate might be signed by an
-   <quote>intermediate</> certificate authority, rather than one that is
-   directly trusted by the server.  To use such a certificate, append the
-   certificate of the signing authority to the <filename>postgresql.crt</>
-   file, then its parent authority's certificate, and so on up to a certificate
-   authority, <quote>root</> or <quote>intermediate</>, that is trusted by
-   the server, i.e. signed by a certificate in the server's
-   <filename>root.crt</filename> file.
+   The first certificate in <filename>postgresql.crt</> must be the
+   client's certificate because it must match the client's private key.
+   <quote>Intermediate</> certificates can be optionally appended
+   to the file &mdash; doing so avoids requiring storage of intermediate
+   certificates on the server's <filename>root.crt</filename> file.
   </para>
 
   <para>
-   Note that the client's <filename>~/.postgresql/root.crt</> lists the top-level CAs
-   that are considered trusted for signing server certificates.  In principle it need
-   not list the CA that signed the client's certificate, though in most cases
-   that CA would also be trusted for server certificates.
+   For instructions on creating certificates, see <xref
+   linkend="ssl-certificate-creation">.
   </para>
-
  </sect2>
 
  <sect2 id="libpq-ssl-protection">
index 08e678ecccbcd4b395c61ae509f3fdbbd41e3722..aa313c9636d68fef7ff83c4a80c9c358ef12f1f3 100644 (file)
@@ -2276,40 +2276,46 @@ pg_dumpall -p 5432 | psql -d postgres -p 5433
   </para>
 
   <para>
-   In some cases, the server certificate might be signed by an
-   <quote>intermediate</> certificate authority, rather than one that is
-   directly trusted by clients.  To use such a certificate, append the
-   certificate of the signing authority to the <filename>server.crt</> file,
-   then its parent authority's certificate, and so on up to a certificate
-   authority, <quote>root</> or <quote>intermediate</>, that is trusted by
-   clients, i.e. signed by a certificate in the clients'
-   <filename>root.crt</filename> files.
+   The first certificate in <filename>server.crt</> must be the
+   server's certificate because it must match the server's private key.
+   The certificates of <quote>intermediate</> certificate authorities
+   can also be appended to the file.  Doing this avoids the necessity of
+   storing intermediate certificates on clients, assuming the root and
+   intermediate certificates were created with <literal>v3_ca</>
+   extensions.  This allows easier expiration of intermediate certificates.
+  </para>
+
+  <para>
+   It is not necessary to add the root certificate to
+   <filename>server.crt</>.  Instead, clients must have the root
+   certificate of the server's certificate chain.
   </para>
 
   <sect2 id="ssl-client-certificates">
    <title>Using Client Certificates</title>
 
   <para>
-   To require the client to supply a trusted certificate, place
-   certificates of the certificate authorities (<acronym>CA</acronym>s)
-   you trust in the file <filename>root.crt</filename> in the data
+   To require the client to supply a trusted certificate,
+   place certificates of the root certificate authorities
+   (<acronym>CA</>s) you trust in a file in the data
    directory, set the parameter <xref linkend="guc-ssl-ca-file"> in
-   <filename>postgresql.conf</filename> to <literal>root.crt</literal>,
-   and add the authentication option <literal>clientcert=1</literal> to the
-   appropriate <literal>hostssl</> line(s) in <filename>pg_hba.conf</>.
-   A certificate will then be requested from the client during
-   SSL connection startup.  (See <xref linkend="libpq-ssl"> for a
-   description of how to set up certificates on the client.)  The server will
+   <filename>postgresql.conf</> to the new file name, and add the
+   authentication option <literal>clientcert=1</> to the appropriate
+   <literal>hostssl</> line(s) in <filename>pg_hba.conf</>.
+   A certificate will then be requested from the client during SSL
+   connection startup.  (See <xref linkend="libpq-ssl"> for a description
+   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
    certificate authorities.
   </para>
 
   <para>
-   If intermediate <acronym>CA</>s appear in
-   <filename>root.crt</filename>, the file must also contain certificate
-   chains to their root <acronym>CA</>s.  Certificate Revocation List
-   (CRL) entries
-   are also checked if the parameter <xref linkend="guc-ssl-crl-file"> is set.
+   Intermediate certificates that chain up to existing root certificates
+   can also appear in the file <filename>root.crt</filename> if
+   you wish to avoid storing them on clients (assuming the root and
+   intermediate certificates were created with <literal>v3_ca</>
+   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. -->
    (See <ulink
    url="http://h71000.www7.hp.com/doc/83final/ba554_90007/ch04s02.html"></>
@@ -2325,14 +2331,6 @@ pg_dumpall -p 5432 | psql -d postgres -p 5433
    it will not insist that a client certificate be presented.
   </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>
    If you are setting up client certificates, you may wish to use
    the <literal>cert</> authentication method, so that the certificates
@@ -2405,31 +2403,18 @@ pg_dumpall -p 5432 | psql -d postgres -p 5433
   </sect2>
 
   <sect2 id="ssl-certificate-creation">
-   <title>Creating a Self-signed Certificate</title>
+   <title>Creating Certificates</title>
 
    <para>
-    To create a quick self-signed certificate for the server, use the
-    following <productname>OpenSSL</productname> command:
-<programlisting>
-openssl req -new -text -out server.req
-</programlisting>
-    Fill out the information that <application>openssl</> asks for. Make sure
-    you enter the local host name as <quote>Common Name</>; the challenge
-    password can be left blank. The program will generate a key that is
-    passphrase protected; it will not accept a passphrase that is less
-    than four characters long. To remove the passphrase (as you must if
-    you want automatic start-up of the server), run the commands:
-<programlisting>
-openssl rsa -in privkey.pem -out server.key
-rm privkey.pem
-</programlisting>
-    Enter the old passphrase to unlock the existing key. Now do:
+     To create a simple self-signed certificate for the server, valid for 365
+     days, use the following <productname>OpenSSL</productname> command,
+     replacing <replaceable>dbhost.yourdomain.com</> with the
+     server's host name:
 <programlisting>
-openssl req -x509 -in server.req -text -key server.key -out server.crt
+openssl req -new -x509 -days 365 -nodes -text -out server.crt \
+  -keyout server.key -subj "/CN=<replaceable>dbhost.yourdomain.com</>"
 </programlisting>
-    to turn the certificate into a self-signed certificate and to copy
-    the key and certificate to where the server will look for them.
-    Finally do:
+    Then do:
 <programlisting>
 chmod og-rwx server.key
 </programlisting>
@@ -2440,14 +2425,86 @@ chmod og-rwx server.key
    </para>
 
    <para>
-    A self-signed certificate can be used for testing, but a certificate
-    signed by a certificate authority (<acronym>CA</>) (either one of the
-    global <acronym>CAs</> or a local one) 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</> is
-    recommended.
+    While a self-signed certificate can be used for testing, a certificate
+    signed by a certificate authority (<acronym>CA</>) (usually an
+    enterprise-wide root <acronym>CA</>) should be used in production.
    </para>
 
+   <para>
+    To create a server certificate whose identity can be validated
+    by clients, first create a certificate signing request
+    (<acronym>CSR</>) and a public/private key file:
+<programlisting>
+openssl req -new -nodes -text -out root.csr \
+  -keyout root.key -subj "/CN=<replaceable>root.yourdomain.com</>"
+chmod og-rwx root.key
+</programlisting>
+    Then, sign the request with the key to create a root certificate
+    authority (using the default <productname>OpenSSL</>
+    configuration file location on <productname>Linux</>):
+<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</>"
+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</> and <filename>server.key</>
+    should be stored on the server, and <filename>root.crt</> 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</> 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</>"
+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</>"
+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</>"
+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</> and
+    <filename>intermediate.crt</> should be concatenated
+    into a certificate file bundle and stored on the server.
+    <filename>server.key</> should also be stored on the server.
+    <filename>root.crt</> 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</> and <filename>intermediate.key</>
+    should be stored offline for use in creating future certificates.
+   </para>
   </sect2>
 
  </sect1>