Use a self-signed TLS certificate for PostgreSQL

This commit is contained in:
Greg Karékinian
2020-05-13 19:10:14 +02:00
parent 84cb3de4a0
commit 8d2ab785fc
4 changed files with 101 additions and 63 deletions

View File

@@ -6,7 +6,6 @@
Usage:
When the `tls` attribute is set to true, a TLS certificate for the FQDN
(`node['fqdn']`, for example `andromeda.kosmos.org`) is generated using Let's
Encrypt and copied to the PostgreSQL data directory and added to the
`postgresql.conf` file
@@ -16,7 +15,6 @@ Encrypt and copied to the PostgreSQL data directory and added to the
```ruby
postgresql_custom_server "12" do
role "primary"
tls true
end
```
@@ -25,7 +23,6 @@ end
```ruby
postgresql_custom_server "12" do
role "replica"
tls true
end
```
@@ -47,3 +44,47 @@ about PostgreSQL client authentication, see the
The primary opens up the PostgreSQL port (5432 TCP) to replicas, and replicas
to the primary.
## TLS self-signed certificate
A wildcard (`*.kosmos.org` certificate) was generated with the following
commands:
```
openssl req -new -nodes -text -out root.csr -keyout root.key \
-subj "/CN=root.kosmos.org"
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
openssl req -new -nodes -text -out server.csr \
-keyout server.key -subj "/CN=*.kosmos.org"
chmod og-rwx server.key
openssl x509 -req -in server.csr -text -days 1825 \
-CA root.crt -CAkey root.key -CAcreateserial \
-out server.crt
```
It is valid until May 12 2025.
The content of `server.crt`, `server.key` and `root.crt` an stored in the
`postgresql` encrypted data bag. The root key is stored in LastPass
("Self-signed TLS root certificate"). `server.crt` & `server.key` are used by
the PostgreSQL server.
The root certificate needs to be deployed to clients so they verify the cert
can be trusted.
For example:
```ruby
postgresql_data_bag_item = data_bag_item('credentials', 'postgresql')
root_cert_path = "/etc/ssl/certs/root.kosmos.org.crt"
file root_cert_path do
content postgresql_data_bag_item['ssl_root_cert']
mode "0644"
end
```
`/etc/ssl/certs/root.kosmos.org.crt` can be used as the CA root cert path in
the client's configuration

View File

@@ -2,7 +2,6 @@ resource_name :postgresql_custom_server
property :postgresql_version, String, required: true, name_property: true
property :role, String, required: true # Can be primary or replica
property :tls, [TrueClass, FalseClass], default: false
action :create do
postgresql_version = new_resource.postgresql_version
@@ -63,56 +62,33 @@ action :create do
additional_config[:promote_trigger_file] = "#{postgresql_data_dir}/failover.trigger"
end
if new_resource.tls
include_recipe "kosmos-nginx"
include_recipe "kosmos-base::letsencrypt"
ssl_cert = postgresql_data_bag_item['ssl_cert']
ssl_cert_path = "#{postgresql_data_dir}/server.crt"
ssl_key = postgresql_data_bag_item['ssl_key']
ssl_key_path = "#{postgresql_data_dir}/server.key"
domain = node[:fqdn]
postgresql_post_hook = <<-EOF
#!/usr/bin/env bash
set -e
# Copy the postgresql certificate and restart the server if it has been renewed
# This is necessary because the postgresql user doesn't have access to the
# letsencrypt live folder
for domain in $RENEWED_DOMAINS; do
case $domain in
#{domain})
cp "${RENEWED_LINEAGE}/privkey.pem" #{postgresql_data_dir}/#{domain}.key
cp "${RENEWED_LINEAGE}/fullchain.pem" #{postgresql_data_dir}/#{domain}.crt
chown postgres:postgres #{postgresql_data_dir}/#{domain}.*
chmod 600 #{postgresql_data_dir}/#{domain}.*
systemctl reload #{postgresql_service}
;;
esac
done
EOF
# This hook will be executed by certbot after every successful certificate
# creation or renewal
file "/etc/letsencrypt/renewal-hooks/post/postgresql" do
content postgresql_post_hook
mode 0755
owner "root"
group "root"
end
template "#{node['nginx']['dir']}/sites-available/#{domain}" do
source 'nginx_conf_empty.erb'
owner node["nginx"]["user"]
mode 0640
notifies :reload, 'service[nginx]', :delayed
end
nginx_certbot_site domain
additional_config[:ssl] = "on"
additional_config[:ssl_cert_file] = "#{postgresql_data_dir}/#{domain}.crt"
additional_config[:ssl_key_file] = "#{postgresql_data_dir}/#{domain}.key"
file ssl_cert_path do
content ssl_cert
owner "postgres"
group "postgres"
mode "0640"
sensitive true
end
file ssl_key_path do
content ssl_key
owner "postgres"
group "postgres"
mode "0600"
sensitive true
end
additional_config[:ssl] = "on"
additional_config[:ssl_cert_file] = ssl_cert_path
additional_config[:ssl_key_file] = ssl_key_path
# ejabberd does not support 1.3 yet
additional_config[:ssl_min_protocol_version] = "TLSv1.2"
postgresql_server_conf "main" do
version postgresql_version
additional_config additional_config