{"id":504,"date":"2024-07-29T12:12:53","date_gmt":"2024-07-29T11:12:53","guid":{"rendered":"https:\/\/blog.inplico.uk\/?p=504"},"modified":"2024-07-29T23:39:25","modified_gmt":"2024-07-29T22:39:25","slug":"securing-postgresql","status":"publish","type":"post","link":"https:\/\/blog.inplico.uk\/?p=504","title":{"rendered":"Securing Postgresql"},"content":{"rendered":"<p>In an ideal world Postgresql ports would not be open to the internet however it is never a bad idea to add a layer of security.\u00a0 If you do have public facing postgresql ports then it is essential.<\/p>\n<p>For this tutorial I have written a couple of script to help with creating a Certificate authority so that you can better manage your ssl certificates.<\/p>\n<p>As with all the tutorials on this site it assumes that you have your postgresql database in <strong>\/pgsql<\/strong> rather than the standard location.\u00a0 You will be creating the certificate authority in <strong>\/pgsql\/CA<\/strong>.<\/p>\n<p>Theoretically this method can be used to create a CA for any purpose you like, albeit you may wish to amend the paths.<\/p>\n<h3>Setting up the certificate authority<\/h3>\n<p>The initial setup has been taken from these instructions: <a href=\"https:\/\/help.ubuntu.com\/community\/OpenSSL\">https:\/\/help.ubuntu.com\/community\/OpenSSL<\/a><\/p>\n<p>If you create your certificate authority in &#8220;\/pgsql\/postgresCA&#8221; then you should not have to modify these files however if you wish to locate it elsewhere, for branding reasons etc. then modification of the process will be required. These instructions are assuming that you wish to create a certificate authority called &#8220;inplicareCA&#8221; in the afore mentioned path.<\/p>\n<p>First and foremost create some directories:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"bash\">cd \/pgsql &amp;&amp; mkdir -p \/pgsql\/CA\/signedcerts &amp;&amp; mkdir \/pgsql\/CA\/private &amp;&amp; cd \/pgsql\/CA<\/pre>\n<p>The previous command will create a folder in <strong>\/pgsq<\/strong>l called &#8220;CA&#8221; containing 2 subfolders &#8220;<strong>signedcerts<\/strong>&#8221; and &#8220;<strong>private<\/strong>&#8220;.<\/p>\n<p>Within this initial working environment, the significance of the subdirectories, and their contents is as follows:<\/p>\n<ul>\n<li>\/pgsql\/CA : contains CA certificate, certificates database, generated certificates, keys, and requests<\/li>\n<li>\/pgsql\/CA\/signedcerts : contains copies of each signed certificate<\/li>\n<li>\/pgsql\/CA\/private : contains the private key<\/li>\n<\/ul>\n<p>In order to ensure that the permissions are mostly automatically set, for the rest of this process you need to su to the postgres user.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\">su postgres<\/pre>\n<p>Next, create an initial certificate database in the \/pgsql\/CA subdirectory with the following command at a terminal prompt:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"bash\">echo '01' &gt; serial  &amp;&amp; touch index.txt<\/pre>\n<p>The certificate database is literally a handful of text files, the serial file initially contains 01 which the CA uses as the serial number for the first signed certificate. Once it has singed that certificate it increments the value, but once you have done the preliminary setup the rest is done automatically for you.<\/p>\n<p>Now create an initial postgresCA.cnf (you can name it anything you like, just as long as you remember) file suitable for the creation of CA certificates. Using your favorite editor, edit the file \/pgsql\/CA\/postgresCA.cnf<\/p>\n<p>This file content is in essence a configuration file for your new certificate authority that contains information about the directories and the files that it will rely on in order to operate. If you are giving your certificate authority a different name then you are likely going to have to change directives in the &#8220;[ local_ca ]&#8221; stanza and in nearly all instances you are going to need to change some directives in the &#8220;[ req ]&#8221; and &#8220;[ root_ca_distinguished_name ]&#8221; stanza&#8217;s. The directives to change are all fairly obvious.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\"># My sample caconfig.cnf file.\r\n#\r\n# Default configuration to use when one is not provided on the command line.\r\n#\r\n[ ca ]\r\ndefault_ca      = local_ca\r\n#\r\n#\r\n# Default location of directories and files needed to generate certificates.\r\n#\r\n[ local_ca ]\r\ndir             = \/pgsql\/CA\r\ncertificate     = $dir\/postgresCA.pem\r\ndatabase        = $dir\/index.txt\r\nnew_certs_dir   = $dir\/signedcerts\r\nprivate_key     = $dir\/private\/postgresCA.pem\r\nserial          = $dir\/serial\r\n#       \r\n#\r\n# Default expiration and encryption policies for certificates.\r\n#\r\ndefault_crl_days        = 365\r\ndefault_days            = 1825\r\ndefault_md              = sha256\r\n#       \r\npolicy          = local_ca_policy\r\nx509_extensions = local_ca_extensions\r\n#\r\n#\r\n# Copy extensions specified in the certificate request\r\n#\r\ncopy_extensions = copy\r\n#       \r\n#\r\n# Default policy to use when generating server certificates.  The following\r\n# fields must be defined in the server certificate.\r\n#\r\n[ local_ca_policy ]\r\ncommonName              = supplied\r\nstateOrProvinceName     = supplied\r\ncountryName             = supplied\r\nemailAddress            = supplied\r\norganizationName        = supplied\r\norganizationalUnitName  = supplied\r\n#       \r\n#\r\n# x509 extensions to use when generating server certificates.\r\n#\r\n[ local_ca_extensions ]\r\nbasicConstraints        = CA:false\r\n#       \r\n#\r\n# The default root certificate generation policy.\r\n#\r\n[ req ]\r\ndefault_bits    = 4096\r\ndefault_keyfile = \/pgsql\/CA\/private\/postgresCA.pem\r\ndefault_md      = sha256\r\n#       \r\nprompt                  = no\r\ndistinguished_name      = root_ca_distinguished_name\r\nx509_extensions         = root_ca_extensions\r\n#\r\n#\r\n# Root Certificate Authority distinguished name.  Change these fields to match\r\n# your local environment!\r\n#\r\n[ root_ca_distinguished_name ]\r\ncommonName              = CHANGE ME\r\nstateOrProvinceName     = CHANGE ME\r\ncountryName             = CHANGE ME\r\nemailAddress            = CHANGE_MY@EMAIL.ADDRESS \r\norganizationName        = CHANGE ME\r\norganizationalUnitName  = CHANGE ME\r\n#       \r\n[ root_ca_extensions ]\r\nbasicConstraints        = CA:true\r\n<\/pre>\n<p>Directives marked &#8220;CHANGE&#8221; should be amended to reflect your organisation then save the file as <strong>postgresCA.cnf<\/strong> in <strong>\/pgsql\/CA<\/strong>.<\/p>\n<p>Once you have the configuration file you need to tell the terminal where to look for it; Alternatively it can form part of the command line to generate the certificate using the &#8220;-config&#8221; directive, but the instructions that I initially used did it this way so I am sticking to it.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"bash\">export OPENSSL_CONF=~\/inplicareCA\/inplicareCA.cnf<\/pre>\n<p>Next create an empty text file for the revocation list.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\">touch postgresCRL.pem<\/pre>\n<p>Now you can generate your certificate authority&#8217;s own certrificate.<\/p>\n<p><span style=\"color: #ff0000;\">IMPORTANT!!!<\/span> The name of the certificate **MUST** match that given in the &#8220;certificate&#8221; directive of the previously created configuration file (in our example &#8220;postgresCA.cnf&#8221;).<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\">openssl req -x509 -newkey rsa:4096 -out postgresCA.pem -outform PEM -days 3650<\/pre>\n<p>The above commend will generate a certificate that will be valid for around 10 years. During the generation process openssl will ask you to provide a password. You will need this every time you wish to sign a certificate with your certificate authority so do not forget it.<\/p>\n<p>When complete you should have two files, one in <strong>\/pgsql\/CA<\/strong> called <strong>postgresCA.pem<\/strong> and another in<strong> \/pgsql\/CA\/private<\/strong> named in accordance with the name provided under the the &#8220;<strong>private_key<\/strong>&#8221; directive in the <strong>postgresCA.cnf<\/strong> configuration file (in our example <strong>postgresCA.pem<\/strong>).<\/p>\n<p>Next, while not strictly necessary, strip the text from the certificate by running:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\">openssl x509 -in postgresCA.pem -out postgresCA.crt<\/pre>\n<p><strong>NOTE<\/strong>: the suffix has changed to <strong>.crt<\/strong> When I did this I ended up with 2 identical files so I am not sure what benefit this might be, but you will be using the postgresCA.crt file on the client in later steps.<\/p>\n<p>Congratulations, you now have a working certificate authority.<\/p>\n<h3>Client Certificates<\/h3>\n<p>Getting this right annoyed me off so much that I wrote a script to do it for me. If you wish to know how to do it the manual way then read the wiki here: https:\/\/help.ubuntu.com\/community\/OpenSSL, or read the script. We are only going to deal with what we need to use the script here.<\/p>\n<p>The script is as follows; just save it to a file named <strong>\/pgsql\/CA\/newcert.sh<\/strong> and make it executable.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"bash\">#!\/bin\/bash\r\n#\r\n\r\nprompt_confirm() {\r\n  while true; do\r\n    read -r -n 1 -p \"${1:-Continue?} [y\/n]: \" REPLY\r\n    case $REPLY in\r\n      [yY]) echo ; return 0 ;;\r\n      [nN]) echo ; return 1 ;;\r\n      *) printf \" \\033[31m %s \\n\\033[0m\" \"invalid input\"\r\n    esac \r\n  done  \r\n}\r\n\r\nif [[ $# -eq 0 ]] ; then\r\n    echo 'USAGE:    You need to pass a valid configuration (.cnf) file to the script.  e.g. \".\/newcert -c mycert.cnf\"  Use -h flag for more help. '\r\n    exit 1\r\nfi\r\n\r\nCONF_FILE=$1 \r\nTMP_KEYFILE='ictempkey.pem'\r\nTMP_REQFILE='ictempreq.pem'\r\nBUFFER_FILE='buffer.pem'\r\nCA_CNF='postgresCA.cnf'\r\nCRL='postgresCRL.pem'\r\n\r\nPASSWORD=''\r\n\r\nwhile getopts c:hp option\r\ndo\r\ncase \"${option}\"\r\nin\r\np) PASSWORD=\"FAKEPASS\";;\r\nc) CONF_FILE=${OPTARG};;\r\nh)  echo \"*----------------------------------------------------------------------------------------*\"\r\n    echo \"*                                                                                        *\"\r\n    echo \"* USAGE                                                                                  *\"\r\n    echo \"* .\/newcert.sh -c filename.cnf -p                                                        *\"\r\n    echo \"*                                                                                        *\"\r\n    echo \"* -c      (required) The openssl configuration file for the certificate you wish to      *\"\r\n    echo \"*         create.                                                                        *\"\r\n    echo \"*                                                                                        *\"\r\n    echo \"*         NOTE: The name of this file will determine the name of the certificate         *\"\r\n    echo \"*                                                                                        *\"\r\n    echo \"*                                                                                        *\"\r\n    echo \"* -p      (optional) Do not prompt for a password the script will use a fake password    *\"\r\n    echo \"*         to create the certificate and then remove it automatically without prompting.  *\"\r\n    echo \"*                                                                                        *\"\r\n    echo \"*----------------------------------------------------------------------------------------*\"\r\n    exit 0\r\nesac\r\ndone\r\n\r\n\r\nif [[ $CONF_FILE == *.cnf ]]; then\r\n\r\n        if [[ -f $CONF_FILE ]]; then\r\n            echo 'Building certificate using ' $CONF_FILE\r\n\r\n            export OPENSSL_CONF=.\/$CONF_FILE \r\n        if [[ -z \"$PASSWORD\" ]]; then\r\n            openssl req -newkey rsa:4096 -keyout $TMP_KEYFILE -keyform PEM -out $TMP_REQFILE -outform PEM\r\n        else\r\n            openssl req -newkey rsa:4096 -passout pass:$PASSWORD -keyout $TMP_KEYFILE -keyform PEM -out $TMP_REQFILE -outform PEM\r\n        fi\r\n            status=$? \r\n            if [[ status -eq 0 ]]; then\r\n            if [[ -z \"$PASSWORD\" ]]; then\r\n                if prompt_confirm \"Would you like to remove the password from the certificate (You will be prompted for a password every time you use the certificate if you don't)\"; then\r\n                    echo 'Removing password'\r\n                    openssl rsa &lt; $TMP_KEYFILE &gt; $BUFFER_FILE\r\n                fi\r\n            else\r\n                openssl rsa -passin pass:$PASSWORD &lt; $TMP_KEYFILE &gt; $BUFFER_FILE\r\n            fi\r\n            \r\n            status=$?\r\n            if [[ status -eq 0 ]]; then\r\n                mv $BUFFER_FILE $TMP_KEYFILE\r\n                if prompt_confirm \"Would you like to sign the certificate\"; then\r\n                    export OPENSSL_CONF=.\/$CA_CNF\r\n                    CERTNAME=${CONF_FILE%.*}\r\n                    echo 'Signing Certificate \"'$CERTNAME'\"'\r\n                    openssl ca -in $TMP_REQFILE -out $CERTNAME.crt\r\n                    status=$?\r\n                    if [[ status -eq 0 ]]; then\r\n                        mv $TMP_KEYFILE $CERTNAME.key \r\n                        echo 'SUCCESS CERTIFICATE SIGNED'\r\n                        echo 'Congratulations, the following files have now been created: \"' $CERTNAME'.crt\" and \"'$CERTNAME'.key\"' \r\n                        if prompt_confirm \"Would you like to test the certificate?\"; then\r\n                            openssl verify -CRLfile .\/$CRL -crl_check_all -CAfile .\/${CA_CNF%.*}.crt $CERTNAME.crt\r\n                        fi\r\n                    else\r\n                        echo 'ERROR or SIGNING CERTIFICATE ABORTED'\r\n                        echo 'If you wish to create a certificate later please re run this script, the current unsigned and invalid certificates have been deleted'\r\n                        rm $TMP_REQFILE\r\n                        rm $TMP_KEYFILE\r\n                    fi\r\n                else\r\n                    echo 'CERTIFICATE SIGNING ABORTED'\r\n                    echo 'If you wish to create a certificate later please re run this script, the current unsigned and invalid certificates have been deleted'\r\n                    rm $TMP_REQFILE\r\n                    rm $TMP_KEYFILE\r\n                fi\r\n            else\r\n                echo 'ERROR: An  error occurred while removeing the password, exiting!'\r\n                exit 1\r\n            fi\r\n        else\r\n            echo 'ERROR: Building the certificate failed, exiting!' \r\n            exit 1\r\n        fi\r\n\r\n    else\r\n        echo 'ERROR: ' $CONF_FILE ' does not exist, exiting!'\r\n        exit 1\r\n    fi\r\n\r\nelse\r\n    echo 'ERROR:    Invalid file format, you need to pass a .cnf file to the script, exiting!'\r\n    exit 1\r\nfi\r\nexit 1\r\n<\/pre>\n<p>&nbsp;<\/p>\n<p>Now we need a configuration file. The name of this file will determine the name of the certificate so think about it carefully. In this example I am simply going to call it server.<\/p>\n<p>In \/pgsql\/CA create a file called server.cnf.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\">touch server.cnf<\/pre>\n<p><strong>NOTE<\/strong>: The .cnf suffix is important, the script will not work without it.<\/p>\n<p>Now edit this file with the appropriate information. The only things that are of importance are the &#8220;<strong>commonName<\/strong>&#8221; and any &#8220;<strong>alt_names<\/strong>&#8220;. The reason these are important is that they are not reusable so in order to issue a further certificate using the same <strong>commonName<\/strong> or <strong>alt_name<\/strong> you will first need to revoke this one.<\/p>\n<p>The file should look something like:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\">#\r\n# server.cnf\r\n#\r\n\r\n[ req ]\r\nprompt                  = no\r\ndistinguished_name      = server_distinguished_name\r\nreq_extensions          = v3_req\r\n\r\n[ server_distinguished_name ]\r\ncommonName              = CHANGE.ME.FQDN\r\nstateOrProvinceName     = CHANGE ME\r\ncountryName             = CHANGE ME\r\nemailAddress            = CHANGE.ME.EMAIL\r\norganizationName        = CHANGE ME\r\norganizationalUnitName  = CHANGE ME\r\n\r\n[ v3_req ]\r\nbasicConstraints        = CA:FALSE\r\nkeyUsage                = nonRepudiation, digitalSignature, keyEncipherment\r\nsubjectAltName          = @alt_names\r\n\r\n[ alt_names ]\r\nDNS.1                   = CHANGE ME<\/pre>\n<p>When it is finished; you can have as many alt_names as you like, you simply increment the DNS. directive on a new line. i.e. DNS.1, DNS.2 etc..<\/p>\n<p>Save the file as <strong>\/pgsql\/CA\/server.cnf<\/strong> and then run the script to generate the the certificate and sign it.<\/p>\n<p><strong>NOTE<\/strong>: this script is not bomb proof, but as long as you haven&#8217;t done anything too daft it should work ok.<\/p>\n<h4>Method 1<\/h4>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\">.\/newcert.sh server.cnf<\/pre>\n<p>and follow the instructions in the terminal.<\/p>\n<p>You will be prompted for a password for the client certificate, then you will be asked if you want to remove it; it is all part of the process, just provide any password of 5 characters or more, but make sure you remember it as you will be prompted for it one more time in order to remove it. THE SCRIPT HAS BEEN UPDATED NOW SO THAT YOU DO NOT HAVE TO DO THIS IF YOU PASS IT THE -p FLAG; IF YOU CHOOSE THIS METHOD THEN YOU WILL NEED TO PASS THE -c FLAG ALONG WITH THE FILENAME.<\/p>\n<h4>Method 2<\/h4>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\">.\/newcert.sh -p -c server.cnf<\/pre>\n<p>You will still be prompted for the CA password.<\/p>\n<p><strong>NOTE<\/strong>: If you are having trouble running this script then you may need to edit it; This will most likely be the case if your configuration file for your CA is something other than<strong> postgresCA.cnf<\/strong>, you will have to change the CA_CNF= directive in the script to match.<\/p>\n<p>In our example the script should have generated 2 files: &#8220;server.crt&#8221; and &#8220;server.key&#8221; you will need these along with the public key of your certificate authority &#8220;postgresCA.crt to use them with your postgresql servers.<\/p>\n<p>The last thing you need to do is change the permissions on your .key file.<\/p>\n<p><span style=\"color: #ff0000;\">WARNING<\/span>: Failure to do this will prevent postgresql from starting correctly when you assign the certificates.<\/p>\n<p>I recommend creating a certificate for each\u00a0 individual client.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\">chmod 400 .\/server.key<\/pre>\n<p>Setting up postgresql for SSL authentication<\/p>\n<p>You will need your certificates somewhere where postgresql can access them; if you are using them on the server that you set the CA up on then you can leave them where they are.\u00a0 If it is on a replication server then I usually put them directly in the \/pgsql directory.<\/p>\n<p>If you are still logged in as the postgres user then exit and change the user to root or use sudo as is your desire.<\/p>\n<p>The first file you need to edit is <strong>\/etc\/postgresql\/15\/main\/postgresql.conf<\/strong>.(remember this path is version specific).<\/p>\n<p>Look for the ssl directives and change\/uncomment them so it looks like<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\"># - SSL -\r\n\r\nssl = on\r\nssl_ca_file = '\/pgsql\/CA\/postgresCA.crt'\r\nssl_cert_file = '\/pgsql\/CA\/server.crt'\r\nssl_crl_file = ''\r\nssl_key_file = '\/pgsql\/CA\/server.key'\r\nssl_ciphers = 'HIGH:MEDIUM:+3DES:!aNULL' # allowed SSL ciphers\r\nssl_prefer_server_ciphers = on\r\n#ssl_ecdh_curve = 'prime256v1'\r\n#ssl_dh_params_file = ''\r\n#ssl_passphrase_command = ''\r\n#ssl_passphrase_command_supports_reload = off\r\n<\/pre>\n<p>then save the file.<\/p>\n<p>The next bit is somewhat specific to your user setup as you are amending pg_hba.conf to tell your configuration to use ssl when negotiating connections.\u00a0 This is on a per user basis so if you have user &#8220;foo&#8221; and user &#8220;bar&#8221; you will have to turn on ssl for each individually.<\/p>\n<p>To do so simply change <strong>host<\/strong> to <strong>hostssl<\/strong><\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\">hostssl mydatabase     foo      XXX.XXX.XXX.XXX\/XX        scram-sha-256\r\nhostssl mydatabase     bar      XXX.XXX.XXX.XXX\/XX        scram-sha-256\r\n<\/pre>\n<p>Now if you restart postgresql when you log in to psql as one of the hostssl users you should see something like:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\">psql (15.7 (Debian 15.7-0+deb12u1))\r\nSSL connection (protocol: TLSv1.3, cipher: TLS_AES_256_GCM_SHA384, compression: off)\r\nType \"help\" for help.\r\n<\/pre>\n<p>This means that your connection is secure.<\/p>\n<h3>Revoking client certificates<\/h3>\n<p>Every certificate generated will authenticate against the server until either it is revoked or it runs out. The server is reliant on a certificate revocation list in order to determine which certificates have been revoked by the CA so we need to generate a certificate revocation list every time we revoke a certificate.<\/p>\n<p>Again I have wrote a small script to do this as it is so easy to miss a step if you do it manually.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\">#!\/bin\/bash\r\n#\r\n# REVOKE A CERTIFICATE\r\nprompt_confirm() {\r\n  while true; do\r\n    read -r -n 1 -p \"${1:-Continue?} [y\/n]: \" REPLY\r\n    case $REPLY in\r\n      [yY]) echo ; return 0 ;;\r\n      [nN]) echo ; return 1 ;;\r\n      *) printf \" \\033[31m %s \\n\\033[0m\" \"invalid input\"\r\n    esac\r\n  done \r\n}\r\n\r\nif [[ $# -eq 0 ]] ; then\r\n    echo 'USAGE:  \".\/revoke -c mycert.crt -p capassword\"'\r\n    exit 1\r\nfi\r\n\r\nCERTFILE=$1\r\n\r\nwhile getopts c:p: option\r\ndo\r\ncase \"${option}\"\r\nin\r\nc) CERTFILE=${OPTARG};;\r\np) PASSWORD=${OPTARG};;\r\nesac\r\ndone\r\n\r\necho $PASSWORD\r\n\r\n#You may need to change these directives to reflect your real CAServer name (not to be confused with the \r\n#actual server name) and the name that you have given to your certificate revocation list.\r\nCA='postgresCA'\r\nCRL='postgresCRL'\r\n\r\n\r\n\r\nif [[ $CERTFILE == *.crt ]]; then\r\n    if [[ -f $CERTFILE ]]; then\r\n        echo 'Revoking '$CERTFILE\r\n        export OPENSSL_CONF=.\/$CA.cnf\r\n        if [[ -z \"$PASSWORD\" ]]; then\r\n            openssl ca -config $CA.cnf -revoke .\/$CERTFILE\r\n        else\r\n            echo 'openssl ca -config '$CA.cnf' -passin pass:'$PASSWORD' -revoke .\/'$CERTFILE\r\n            openssl ca -config $CA.cnf -passin pass:$PASSWORD -revoke .\/$CERTFILE \r\n        fi\r\n        status=$?\r\n        if [[ status -eq 0 ]]; then\r\n            if prompt_confirm \"Would you like to update the CERTIFICATE REVOCATION LIST?\"; then\r\n                if [[ -z \"$PASSWORD\" ]]; then\r\n                    openssl ca -config $CA.cnf -gencrl -keyfile .\/private\/$CA.pem -cert $CA.pem -out $CRL.pem\r\n                else\r\n                    openssl ca -config $CA.cnf -gencrl -keyfile .\/private\/$CA.pem -cert $CA.pem -out $CRL.pem -passin pass:$PASSWORD\r\n                fi\r\n                status=$?\r\n                if [[ status -eq 0 ]]; then\r\n                    echo 'CERTIFCATE REVOKED:  The certificate file ' $CRL'.pem has been updated.'\r\n                    echo 'Additional steps my be required in order to propogate the changes'\r\n                    if prompt_confirm \"The certificate and private key can now be safely deleted, would you like to do this automatically now?\"; then\r\n                        rm .\/$CERTFILE\r\n                        rm .\/${CERTFILE%.*}.key\r\n                    \r\n                    fi\r\n                fi\r\n            \r\n            fi\r\n        else\r\n            echo 'ERROR:  The certificate revocation failed, exiting.'\r\n            exit 1\r\n        fi\r\n    else\r\n        echo 'The file \"'$CERTFILE'\" does not exist; exiting!'\r\n        exit 1\r\n    fi\r\nelse\r\n    echo 'You need to provide the script with a certificate file with the extension \".crt\" in order to proceed.'\r\n    exit 1\r\nfi\r\n<\/pre>\n<p>Copy the above and save it to a file called <strong>\/pgsql\/CA\/revoke.sh<\/strong> and make it executable.<\/p>\n<p>This script requires the name of the certificate to be revoked to passed as an argument.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\">.\/revoke.sh -c server.crt -p secretpassword<\/pre>\n<p>Follow the instructions on the screen and you will revoke the certificate created earlier.<\/p>\n<p>NOTE: When a certificate expires you will need to revoke it before creating a new one.<\/p>\n<h3>Showing revoked certificates<\/h3>\n<p>You can do this from the command line quite simply by passing running the following:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\">openssl crl -in postgresCRL.pem -noout -text<\/pre>\n<p>This will display the certificates that have been revoked according to the certificate revocation list. If for some reason the CRL has not been updated then the crl will not display the revoked certificates. The serial numbers of the revoked certificates should match those marked with an &#8220;R&#8221; in the database (index.txt file).<\/p>\n<p>NOTE: The CRL can be updated any time by running:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\">openssl ca -config inplicareCA.cnf -gencrl -keyfile .\/private\/postgresCA.pem -cert postgresCA.pem -out postgresCRL.pem<\/pre>\n<p>however this should not ordinarily be necessary as is done in the script.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>In an ideal world Postgresql ports would not be open to the internet however it is never a bad idea to add a layer of security.\u00a0 If you do have public facing postgresql ports then it is essential. For this tutorial I have written a couple of script to help with creating a Certificate authority [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[10,4],"tags":[],"class_list":["post-504","post","type-post","status-publish","format-standard","hentry","category-debian-server","category-a-series-of-hints-and-tips-when-using-the-postgresql-library-libpq-fe-h"],"_links":{"self":[{"href":"https:\/\/blog.inplico.uk\/index.php?rest_route=\/wp\/v2\/posts\/504","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blog.inplico.uk\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.inplico.uk\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.inplico.uk\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.inplico.uk\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=504"}],"version-history":[{"count":7,"href":"https:\/\/blog.inplico.uk\/index.php?rest_route=\/wp\/v2\/posts\/504\/revisions"}],"predecessor-version":[{"id":518,"href":"https:\/\/blog.inplico.uk\/index.php?rest_route=\/wp\/v2\/posts\/504\/revisions\/518"}],"wp:attachment":[{"href":"https:\/\/blog.inplico.uk\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=504"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.inplico.uk\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=504"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.inplico.uk\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=504"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}