diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 5fac2f81..4ea7a310 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -110,7 +110,7 @@ jobs: ./foremanctl pull-images - name: Run deployment run: | - ./foremanctl deploy --certificate-source=${{ matrix.certificate_source }} ${{ matrix.database == 'external' && '--database-mode=external --database-host=database.example.com' || '' }} --foreman-initial-admin-password=changeme --tuning development + ./foremanctl deploy --certificate-source=${{ matrix.certificate_source }} ${{ matrix.database == 'external' && '--database-mode=external --database-host=database.example.com --database-ssl-ca $(pwd)/.var/lib/foremanctl/db-ca.crt --database-ssl-mode verify-full' || '' }} --foreman-initial-admin-password=changeme --tuning development - name: Add optional feature - hammer run: | ./foremanctl deploy --add-feature hammer diff --git a/development/playbooks/remote-database/remote-database.yaml b/development/playbooks/remote-database/remote-database.yaml index bcb489eb..0ea469c1 100644 --- a/development/playbooks/remote-database/remote-database.yaml +++ b/development/playbooks/remote-database/remote-database.yaml @@ -5,6 +5,20 @@ become: true vars_files: - "../../../src/vars/database.yml" + vars: + certificates_hostnames: + - "{{ ansible_facts['fqdn'] }}" + certificates_ca_password: "CHANGEME" + postgresql_ssl_crt: "{{ certificates_ca_directory }}/certs/{{ ansible_facts['fqdn'] }}.crt" + postgresql_ssl_key: "{{ certificates_ca_directory }}/private/{{ ansible_facts['fqdn'] }}.key" roles: - role: pre_install + - role: certificates - role: postgresql + + tasks: + - name: Fetch PostgreSQL SSL CA + ansible.builtin.fetch: + src: "{{ certificates_ca_directory }}/certs/ca.crt" + dest: "{{ obsah_state_path }}/db-ca.crt" + flat: true diff --git a/src/roles/candlepin/tasks/main.yml b/src/roles/candlepin/tasks/main.yml index a3c1f88f..9398851e 100644 --- a/src/roles/candlepin/tasks/main.yml +++ b/src/roles/candlepin/tasks/main.yml @@ -47,6 +47,14 @@ notify: - Restart candlepin +- name: Create DB SSL cert + containers.podman.podman_secret: + state: present + name: candlepin-db-ca + data: "{{ lookup('ansible.builtin.file', candlepin_database_ssl_ca) if candlepin_database_ssl_ca else 'empty' }}" + notify: + - Restart candlepin + - name: Setup artemis ansible.builtin.include_tasks: file: artemis.yml @@ -76,6 +84,7 @@ - 'candlepin-artemis-cert-roles-properties,target=/etc/tomcat/cert-roles.properties,mode=440,type=mount' - 'candlepin-artemis-cert-users-properties,target=/etc/tomcat/cert-users.properties,mode=440,type=mount' - 'candlepin-artemis-jaas-conf,target=/etc/tomcat/conf.d/jaas.conf,mode=440,type=mount' + - 'candlepin-db-ca,target=/etc/candlepin/certs/db-ca.crt,mode=0440,type=mount' volumes: - /var/log/candlepin:/var/log/candlepin:Z - /var/log/tomcat:/var/log/tomcat:Z diff --git a/src/roles/candlepin/templates/candlepin.conf.j2 b/src/roles/candlepin/templates/candlepin.conf.j2 index 0a46138e..8f592abd 100644 --- a/src/roles/candlepin/templates/candlepin.conf.j2 +++ b/src/roles/candlepin/templates/candlepin.conf.j2 @@ -23,7 +23,7 @@ jpa.config.hibernate.hbm2ddl.auto=validate jpa.config.hibernate.connection.username={{ candlepin_database_user }} jpa.config.hibernate.connection.password={{ candlepin_database_password }} jpa.config.hibernate.connection.driver_class=org.postgresql.Driver -jpa.config.hibernate.connection.url=jdbc:postgresql://{{ candlepin_database_host }}:{{ candlepin_database_port }}/{{ candlepin_database_name }}?sslmode={{ candlepin_database_ssl_mode }}{% if candlepin_database_ssl_ca is defined %}&sslrootcert={{ candlepin_database_ssl_ca }}{% endif %} +jpa.config.hibernate.connection.url=jdbc:postgresql://{{ candlepin_database_host }}:{{ candlepin_database_port }}/{{ candlepin_database_name }}?sslmode={{ candlepin_database_ssl_mode }}{% if candlepin_database_ssl_ca is defined %}&sslrootcert=/etc/candlepin/certs/db-ca.crt{% endif %} org.quartz.jobStore.misfireThreshold=60000 @@ -37,4 +37,4 @@ org.quartz.dataSource.myDS.driver=org.postgresql.Driver org.quartz.dataSource.myDS.user={{ candlepin_database_user }} org.quartz.dataSource.myDS.password={{ candlepin_database_password }} org.quartz.dataSource.myDS.maxConnections=5 -org.quartz.dataSource.myDS.URL=jdbc:postgresql://{{ candlepin_database_host }}:{{ candlepin_database_port }}/{{ candlepin_database_name }}?sslmode={{ candlepin_database_ssl_mode }}{% if candlepin_database_ssl_ca is defined %}&sslrootcert={{ candlepin_database_ssl_ca }}{% endif %} +org.quartz.dataSource.myDS.URL=jdbc:postgresql://{{ candlepin_database_host }}:{{ candlepin_database_port }}/{{ candlepin_database_name }}?sslmode={{ candlepin_database_ssl_mode }}{% if candlepin_database_ssl_ca is defined %}&sslrootcert=/etc/candlepin/certs/db-ca.crt{% endif %} diff --git a/src/roles/check_database_connection/tasks/check.yaml b/src/roles/check_database_connection/tasks/check.yaml index 7979dbfe..8df0196d 100644 --- a/src/roles/check_database_connection/tasks/check.yaml +++ b/src/roles/check_database_connection/tasks/check.yaml @@ -1,14 +1,41 @@ +- name: Store CA cert to a temporary file + when: + - db_item.ca_cert is defined + - db_item.ca_cert is truthy + block: + - name: Create temporary file + ansible.builtin.tempfile: + state: file + prefix: check_database_connection_ + register: _check_database_connection_ca_cert + + - name: Write CA cert to temporary file + ansible.builtin.copy: + dest: "{{ _check_database_connection_ca_cert.path }}" + src: "{{ db_item.ca_cert }}" + mode: '0640' + - name: Check database connectivity to {{ db_item.name }} community.postgresql.postgresql_ping: login_host: "{{ db_item.host }}" login_user: "{{ db_item.user }}" login_password: "{{ db_item.password }}" login_db: "{{ db_item.dbname }}" - ca_cert: "{{ db_item.ca_cert | default(omit) }}" + ca_cert: "{{ _check_database_connection_ca_cert.path | default(omit) }}" ssl_mode: "{{ db_item.sslmode | default(omit) }}" register: check_database_connection_ping_result ignore_errors: true +- name: Delete temporary CA cert file + when: + - db_item.ca_cert is defined + - db_item.ca_cert is truthy + block: + - name: Delete temporary file + ansible.builtin.file: + state: absent + path: "{{ _check_database_connection_ca_cert.path }}" + - name: Assert database is reachable for {{ db_item.name }} ansible.builtin.assert: that: diff --git a/src/roles/check_database_connection/tasks/main.yaml b/src/roles/check_database_connection/tasks/main.yaml index 8d855d08..fa24e612 100644 --- a/src/roles/check_database_connection/tasks/main.yaml +++ b/src/roles/check_database_connection/tasks/main.yaml @@ -8,7 +8,7 @@ user: "{{ foreman_database_user }}" password: "{{ foreman_database_password }}" dbname: "{{ foreman_database_name }}" - ca_cert: "{{ foreman_database_ssl_ca | default(omit) }}" + ca_cert: "{{ foreman_database_ssl_ca | default('') }}" sslmode: "{{ foreman_database_ssl_mode | default(omit) }}" - name: Candlepin @@ -16,7 +16,7 @@ user: "{{ candlepin_database_user }}" password: "{{ candlepin_database_password }}" dbname: "{{ candlepin_database_name }}" - ca_cert: "{{ candlepin_database_ssl_ca | default(omit) }}" + ca_cert: "{{ candlepin_database_ssl_ca | default('') }}" sslmode: "{{ candlepin_database_ssl_mode | default(omit) }}" - name: Pulp @@ -24,7 +24,7 @@ user: "{{ pulp_database_user }}" password: "{{ pulp_database_password }}" dbname: "{{ pulp_database_name }}" - ca_cert: "{{ pulp_database_ssl_ca | default(omit) }}" + ca_cert: "{{ pulp_database_ssl_ca | default('') }}" sslmode: "{{ pulp_database_ssl_mode | default(omit) }}" loop_control: loop_var: db_item diff --git a/src/roles/foreman/tasks/main.yaml b/src/roles/foreman/tasks/main.yaml index a3bfdd9a..ba4db684 100644 --- a/src/roles/foreman/tasks/main.yaml +++ b/src/roles/foreman/tasks/main.yaml @@ -8,7 +8,7 @@ containers.podman.podman_secret: state: present name: foreman-database-url - data: "postgresql://{{ foreman_database_user }}:{{ foreman_database_password }}@{{ foreman_database_host }}:{{ foreman_database_port }}/{{ foreman_database_name }}?pool={{ foreman_database_pool }}&sslmode={{ foreman_database_ssl_mode }}{% if foreman_database_ssl_ca is defined %}&sslrootcert={{ foreman_database_ssl_ca }}{% endif %}" # yamllint disable-line rule:line-length + data: "postgresql://{{ foreman_database_user }}:{{ foreman_database_password }}@{{ foreman_database_host }}:{{ foreman_database_port }}/{{ foreman_database_name }}?pool={{ foreman_database_pool }}&sslmode={{ foreman_database_ssl_mode }}{% if foreman_database_ssl_ca is defined %}&sslrootcert=/etc/foreman/db-ca.crt{% endif %}" # yamllint disable-line rule:line-length notify: - Restart foreman - Restart dynflow-sidekiq@ @@ -84,6 +84,15 @@ - Restart foreman - Restart dynflow-sidekiq@ +- name: Create DB SSL cert + containers.podman.podman_secret: + state: present + name: foreman-db-ca + data: "{{ lookup('ansible.builtin.file', foreman_database_ssl_ca) if foreman_database_ssl_ca else 'empty' }}" + notify: + - Restart foreman + - Restart dynflow-sidekiq@ + - name: Deploy Foreman Container containers.podman.podman_container: name: "foreman" @@ -103,6 +112,7 @@ - 'foreman-ca-cert,type=mount,target=/etc/foreman/katello-default-ca.crt' - 'foreman-client-cert,type=mount,target=/etc/foreman/client_cert.pem' - 'foreman-client-key,type=mount,target=/etc/foreman/client_key.pem' + - 'foreman-db-ca,type=mount,target=/etc/foreman/db-ca.crt' env: FOREMAN_PUMA_THREADS_MIN: "{{ foreman_puma_threads_min }}" FOREMAN_PUMA_THREADS_MAX: "{{ foreman_puma_threads_max }}" @@ -135,6 +145,7 @@ - 'foreman-client-cert,type=mount,target=/etc/foreman/client_cert.pem' - 'foreman-client-key,type=mount,target=/etc/foreman/client_key.pem' - 'foreman-dynflow-worker-hosts-queue-yaml,type=mount,target=/etc/foreman/dynflow/worker-hosts-queue.yml' + - 'foreman-db-ca,type=mount,target=/etc/foreman/db-ca.crt' env: DYNFLOW_REDIS_URL: "redis://localhost:6379/6" REDIS_PROVIDER: "DYNFLOW_REDIS_URL" @@ -231,6 +242,7 @@ - 'foreman-seed-admin-user,type=env,target=SEED_ADMIN_USER' - 'foreman-seed-admin-password,type=env,target=SEED_ADMIN_PASSWORD' - 'foreman-settings-yaml,type=mount,target=/etc/foreman/settings.yaml' + - 'foreman-db-ca,type=mount,target=/etc/foreman/db-ca.crt' - name: Flush handlers to restart services ansible.builtin.meta: flush_handlers diff --git a/src/roles/postgresql/tasks/main.yml b/src/roles/postgresql/tasks/main.yml index baf3d553..521f606e 100644 --- a/src/roles/postgresql/tasks/main.yml +++ b/src/roles/postgresql/tasks/main.yml @@ -42,6 +42,59 @@ [Unit] PartOf=foreman.target +- name: Configure SSL certificates + when: + - postgresql_ssl_crt is defined + - postgresql_ssl_crt != '' + - postgresql_ssl_key is defined + - postgresql_ssl_key != '' + block: + - name: Create Podman secret for PostgreSQL SSL cert + containers.podman.podman_secret: + name: postgresql-ssl-crt + path: "{{ postgresql_ssl_crt }}" + notify: + - Restart postgresql + + - name: Create Podman secret for PostgreSQL SSL key + containers.podman.podman_secret: + name: postgresql-ssl-key + path: "{{ postgresql_ssl_key }}" + notify: + - Restart postgresql + + - name: Create Podman secret for PostgreSQL SSL config + containers.podman.podman_secret: + name: postgresql-ssl-conf + data: | + ssl = on + ssl_cert_file = '/opt/app-root/src/certs/ssl.crt' + ssl_key_file = '/opt/app-root/src/certs/ssl.key' + notify: + - Restart postgresql + + - name: Create postgresql.container.d folder + ansible.builtin.file: + path: /etc/containers/systemd/postgresql.container.d + state: directory + mode: '0755' + owner: 'root' + group: 'root' + + - name: Configure PostgreSQL SSL-related secrets + ansible.builtin.copy: + dest: /etc/containers/systemd/postgresql.container.d/ssl.conf + mode: '0644' + owner: root + group: root + content: | + [Container] + Secret=postgresql-ssl-crt,type=mount,target=/opt/app-root/src/certs/ssl.crt,mode=0640 + Secret=postgresql-ssl-key,type=mount,target=/opt/app-root/src/certs/ssl.key,mode=0640 + Secret=postgresql-ssl-conf,type=mount,target=/opt/app-root/src/postgresql-cfg/ssl.conf + notify: + - Restart postgresql + - name: Run daemon reload ansible.builtin.systemd: daemon_reload: true diff --git a/src/roles/pulp/defaults/main.yaml b/src/roles/pulp/defaults/main.yaml index 72db8f6c..cdea5745 100644 --- a/src/roles/pulp/defaults/main.yaml +++ b/src/roles/pulp/defaults/main.yaml @@ -35,7 +35,7 @@ pulp_database_user: pulp pulp_database_host: localhost pulp_database_port: 5432 pulp_database_ssl_mode: disabled -pulp_database_ssl_ca: None +pulp_database_ssl_ca: pulp_settings_database_env: PULP_DATABASES__default__NAME: "{{ pulp_database_name }}" @@ -43,7 +43,7 @@ pulp_settings_database_env: PULP_DATABASES__default__HOST: "{{ pulp_database_host }}" PULP_DATABASES__default__PORT: "{{ pulp_database_port }}" PULP_DATABASES__default__OPTIONS__sslmode: "{{ pulp_database_ssl_mode }}" - PULP_DATABASES__default__OPTIONS__sslrootcert: "{{ pulp_database_ssl_ca }}" + PULP_DATABASES__default__OPTIONS__sslrootcert: "/etc/pulp/certs/db-ca.crt" PULP_ENABLED_PLUGINS: >- {{ pulp_enabled_plugins }} diff --git a/src/roles/pulp/tasks/main.yaml b/src/roles/pulp/tasks/main.yaml index 79b5d563..a63ba38e 100644 --- a/src/roles/pulp/tasks/main.yaml +++ b/src/roles/pulp/tasks/main.yaml @@ -40,6 +40,16 @@ - Restart pulp-content - Restart pulp-worker +- name: Create DB SSL cert + containers.podman.podman_secret: + state: present + name: pulp-db-ca + data: "{{ lookup('ansible.builtin.file', pulp_database_ssl_ca) if pulp_database_ssl_ca else 'empty' }}" + notify: + - Restart pulp-api + - Restart pulp-content + - Restart pulp-worker + - name: Generate Django secret key ansible.builtin.command: "bash -c 'openssl rand -base64 50 | tr -d \"\\n\" | tr \"+/\" \"-_\" > /var/lib/pulp/django_secret_key'" args: @@ -92,6 +102,7 @@ secrets: - 'pulp-symmetric-key,type=mount,target=/etc/pulp/certs/database_fields.symmetric.key' - 'pulp-db-password,type=env,target=PULP_DATABASES__default__PASSWORD' + - 'pulp-db-ca,type=mount,target=/etc/pulp/certs/db-ca.crt' - 'pulp-django-secret-key,type=env,target=PULP_SECRET_KEY' env: "{{ pulp_settings_env }}" quadlet_options: @@ -122,6 +133,7 @@ secrets: - 'pulp-symmetric-key,type=mount,target=/etc/pulp/certs/database_fields.symmetric.key' - 'pulp-db-password,type=env,target=PULP_DATABASES__default__PASSWORD' + - 'pulp-db-ca,type=mount,target=/etc/pulp/certs/db-ca.crt' - 'pulp-django-secret-key,type=env,target=PULP_SECRET_KEY' env: "{{ pulp_settings_env }}" quadlet_options: @@ -152,6 +164,7 @@ secrets: - 'pulp-symmetric-key,type=mount,target=/etc/pulp/certs/database_fields.symmetric.key' - 'pulp-db-password,type=env,target=PULP_DATABASES__default__PASSWORD' + - 'pulp-db-ca,type=mount,target=/etc/pulp/certs/db-ca.crt' - 'pulp-django-secret-key,type=env,target=PULP_SECRET_KEY' env: "{{ pulp_settings_env }}" quadlet_options: @@ -202,6 +215,7 @@ secrets: - 'pulp-symmetric-key,type=mount,target=/etc/pulp/certs/database_fields.symmetric.key' - 'pulp-db-password,type=env,target=PULP_DATABASES__default__PASSWORD' + - 'pulp-db-ca,type=mount,target=/etc/pulp/certs/db-ca.crt' env: "{{ pulp_settings_database_env }}" - name: Ensure Pulp admin user exists @@ -215,6 +229,7 @@ secrets: - 'pulp-symmetric-key,type=mount,target=/etc/pulp/certs/database_fields.symmetric.key' - 'pulp-db-password,type=env,target=PULP_DATABASES__default__PASSWORD' + - 'pulp-db-ca,type=mount,target=/etc/pulp/certs/db-ca.crt' env: "{{ pulp_settings_database_env }}" - name: Flush handlers to restart services diff --git a/src/vars/database.yml b/src/vars/database.yml index ac55784d..3f4a73cd 100644 --- a/src/vars/database.yml +++ b/src/vars/database.yml @@ -2,7 +2,7 @@ database_host: localhost database_port: 5432 database_ssl_mode: disable -database_ssl_ca: None +database_ssl_ca: foreman_database_name: foreman foreman_database_user: foreman