Skip to content

Commit

Permalink
Enabled TLS encryption for PostgreSQL and PgBouncer (#849)
Browse files Browse the repository at this point in the history
  • Loading branch information
klention authored Dec 19, 2024
1 parent 0c8abff commit ee6454b
Show file tree
Hide file tree
Showing 9 changed files with 113 additions and 5 deletions.
3 changes: 3 additions & 0 deletions automation/add_pgnode.yml
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,9 @@
- role: pg_probackup
when: pg_probackup_install|bool

- role: tls_certificate/copy
when: tls_cert_generate|bool

- role: pgbouncer
when: pgbouncer_install|bool

Expand Down
3 changes: 3 additions & 0 deletions automation/deploy_pgcluster.yml
Original file line number Diff line number Diff line change
Expand Up @@ -356,6 +356,9 @@

- role: cron

- role: tls_certificate
when: tls_cert_generate|bool

- role: pgbouncer
when: pgbouncer_install|bool

Expand Down
2 changes: 1 addition & 1 deletion automation/roles/patroni/tasks/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -418,7 +418,7 @@
when: postgresql_wal_dir is defined and postgresql_wal_dir | length > 0
tags: patroni, custom_wal_dir

- block: # wheh postgresql NOT exists or PITR
- block: # when postgresql NOT exists or PITR
- name: Prepare PostgreSQL | make sure PostgreSQL data directory "{{ postgresql_data_dir }}" exists
ansible.builtin.file:
path: "{{ postgresql_data_dir }}"
Expand Down
12 changes: 12 additions & 0 deletions automation/roles/pgbouncer/templates/pgbouncer.ini.j2
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,22 @@ so_reuseport = 1
client_tls_sslmode = {{ pgbouncer_client_tls_sslmode }}
client_tls_key_file = {{ pgbouncer_client_tls_key_file }}
client_tls_cert_file = {{ pgbouncer_client_tls_cert_file }}
{% if pgbouncer_client_tls_ca_file | default('') | length > 0 %}
client_tls_ca_file = {{ pgbouncer_client_tls_ca_file }}
{% endif %}
client_tls_protocols = {{ pgbouncer_client_tls_protocols }}
client_tls_ciphers = {{ pgbouncer_client_tls_ciphers }}
{% endif %}
{% if pgbouncer_server_tls_sslmode != 'disable' %}
server_tls_sslmode = {{ pgbouncer_server_tls_sslmode }}
server_tls_protocols = {{ pgbouncer_server_tls_protocols }}
server_tls_ciphers = {{ pgbouncer_server_tls_ciphers }}
server_tls_cert_file = {{ pgbouncer_server_tls_cert_file }}
server_tls_key_file = {{ pgbouncer_server_tls_key_file }}
{% if pgbouncer_server_tls_ca_file | default('') | length > 0 %}
server_tls_ca_file = {{ pgbouncer_server_tls_ca_file }}
{% endif %}
{% endif %}
log_connections = 0
log_disconnections = 0

Expand Down
42 changes: 42 additions & 0 deletions automation/roles/tls_certificate/copy/tasks/main.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
---
# for add_pgnode.yml

- name: Ensure TLS directories exist
ansible.builtin.file:
path: "{{ item | dirname }}"
state: directory
owner: "{{ tls_owner | default('postgres') }}"
group: "{{ tls_owner | default('postgres') }}"
mode: "0750"
loop:
- "{{ tls_privatekey_path | default('/etc/tls/server.key') }}"
- "{{ tls_cert_path | default('/etc/tls/server.crt') }}"

- name: Fetch TLS certificate and key from master
run_once: true
ansible.builtin.fetch:
src: "{{ item }}"
dest: "files/tls/"
validate_checksum: true
flat: true
delegate_to: "{{ groups.master[0] }}"
loop:
- "{{ tls_privatekey_path | default('/etc/tls/server.key') }}"
- "{{ tls_cert_path | default('/etc/tls/server.crt') }}"

- name: Copy TLS certificate and key to replica
ansible.builtin.copy:
src: "files/tls/{{ item.path | basename }}"
dest: "{{ item.path }}"
owner: "{{ tls_owner | default('postgres') }}"
group: "{{ tls_owner | default('postgres') }}"
mode: "{{ item.mode }}"
loop:
- { path: "{{ tls_privatekey_path | default('/etc/tls/server.key') }}", mode: "{{ tls_privatekey_mode | default('0400') }}" }
- { path: "{{ tls_cert_path | default('/etc/tls/server.crt') }}", mode: "{{ tls_cert_mode | default('0644') }}" }

- name: Delete TLS certificate and key from the ansible controller
ansible.builtin.file:
path: "files/tls/"
state: absent
delegate_to: localhost
30 changes: 30 additions & 0 deletions automation/roles/tls_certificate/tasks/main.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
---
- name: Ensure TLS directories exist
ansible.builtin.file:
path: "{{ item | dirname }}"
state: directory
owner: "{{ tls_owner | default('postgres') }}"
group: "{{ tls_owner | default('postgres') }}"
mode: "0750"
loop:
- "{{ tls_privatekey_path | default('/etc/tls/server.key') }}"
- "{{ tls_cert_path | default('/etc/tls/server.crt') }}"

- name: "Generate private TLS key {{ tls_privatekey_path | default('/etc/tls/server.key') }}"
community.crypto.openssl_privatekey:
path: "{{ tls_privatekey_path | default('/etc/tls/server.key') }}"
owner: "{{ tls_owner | default('postgres') }}"
group: "{{ tls_owner | default('postgres') }}"
mode: "{{ tls_privatekey_mode | default('0400') }}"
size: "{{ tls_privatekey_size | default(4096) }}"
type: "{{ tls_privatekey_type | default('RSA') }}"

- name: "Generate self-signed TLS certificate {{ tls_cert_path | default('/etc/tls/server.crt') }}"
community.crypto.x509_certificate:
path: "{{ tls_cert_path | default('/etc/tls/server.crt') }}"
privatekey_path: "{{ tls_privatekey_path | default('/etc/tls/server.key') }}"
owner: "{{ tls_owner | default('postgres') }}"
group: "{{ tls_owner | default('postgres') }}"
mode: "{{ tls_cert_mode | default('0644') }}"
provider: "{{ tls_cert_provider | default('selfsigned') }}"
entrust_not_after: "+{{ tls_cert_valid_days | default(3650) }}d"
1 change: 1 addition & 0 deletions automation/vars/Debian.yml
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ system_packages:
- python3-psycopg2
- python3-setuptools
- python3-pip
- python3-cryptography
- curl
- less
- sudo
Expand Down
1 change: 1 addition & 0 deletions automation/vars/RedHat.yml
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ system_packages:
- python{{ python_version }}-setuptools
- python{{ python_version }}-pip
- python{{ python_version }}-urllib3
- python3-cryptography
- less
- sudo
- vim
Expand Down
24 changes: 20 additions & 4 deletions automation/vars/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,12 @@ consul_services:
# - { http: "http://{{ inventory_hostname }}:{{ patroni_restapi_port }}/async?lag={{ patroni_maximum_lag_on_replica }}", interval: "2s" }
# - { args: ["systemctl", "status", "pgbouncer"], interval: "5s" }

# TLS certificate (for PostgreSQL & PgBouncer)
tls_cert_generate: true
tls_cert_valid_days: 3650
tls_cert_path: "{{ postgresql_home_dir }}/tls/server.crt"
tls_privatekey_path: "{{ postgresql_home_dir }}/tls/server.key"
tls_owner: "postgres"

# PostgreSQL variables
postgresql_version: 17
Expand Down Expand Up @@ -235,6 +241,10 @@ postgresql_parameters:
- { option: "max_connections", value: "1000" }
- { option: "superuser_reserved_connections", value: "5" }
- { option: "password_encryption", value: "{{ postgresql_password_encryption_algorithm }}" }
- { option: "ssl", value: "on"}
- { option: "ssl_cert_file", value: "{{ tls_cert_path }}"}
- { option: "ssl_key_file", value: "{{ tls_privatekey_path }}"}
- { option: "ssl_min_protocol_version", value: "TLSv1.2"}
- { option: "max_locks_per_transaction", value: "512" }
- { option: "max_prepared_transactions", value: "0" }
- { option: "huge_pages", value: "try" } # "vm.nr_hugepages" is auto-configured for shared_buffers >= 8GB (if huge_pages_auto_conf is true)
Expand Down Expand Up @@ -366,12 +376,18 @@ pgbouncer_auth_user: true # or 'false' if you want to manage the list of users f
pgbouncer_auth_username: pgbouncer # user who can query the database via the user_search function
pgbouncer_auth_password: "" # If not defined, a password will be generated automatically during deployment
pgbouncer_auth_dbname: "postgres"
pgbouncer_client_tls_sslmode: "disable"
pgbouncer_client_tls_key_file: ""
pgbouncer_client_tls_cert_file: ""
pgbouncer_client_tls_sslmode: "require"
pgbouncer_client_tls_key_file: "{{ tls_privatekey_path }}"
pgbouncer_client_tls_cert_file: "{{ tls_cert_path }}"
pgbouncer_client_tls_ca_file: ""
pgbouncer_client_tls_protocols: "secure" # allowed values: tlsv1.0, tlsv1.1, tlsv1.2, tlsv1.3, all, secure (tlsv1.2,tlsv1.3)
pgbouncer_client_tls_ciphers: "default" # allowed values: default, secure, fast, normal, all (not recommended)
pgbouncer_client_tls_ciphers: "secure" # allowed values: default, secure, fast, normal, all (not recommended)
pgbouncer_server_tls_sslmode: "require"
pgbouncer_server_tls_protocols: "secure"
pgbouncer_server_tls_ciphers: "secure"
pgbouncer_server_tls_cert_file: "{{ tls_cert_path }}"
pgbouncer_server_tls_key_file: "{{ tls_privatekey_path }}"
pgbouncer_server_tls_ca_file: ""

pgbouncer_pools:
- { name: "postgres", dbname: "postgres", pool_parameters: "" }
Expand Down

0 comments on commit ee6454b

Please sign in to comment.