diff --git a/.talismanrc b/.talismanrc index 58b311a..41b9b21 100644 --- a/.talismanrc +++ b/.talismanrc @@ -3,9 +3,15 @@ fileignoreconfig: ignore_detectors: [filecontent] - filename: molecule/common/verify.yml ignore_detectors: [filecontent] - - filename: templates/postgres.conf.j2 + - filename: templates/postgresql.conf.j2 + ignore_detectors: [filecontent, filename] + - filename: templates/pg_hba.conf.j2 + ignore_detectors: [filecontent] + - filename: molecule/databases/molecule.yml ignore_detectors: [filecontent] - filename: tasks/vars.yml ignore_detectors: [filecontent] + - filename: tasks/configure.yml + ignore_detectors: [filecontent] - filename: tasks/roles.yml ignore_detectors: [filecontent] diff --git a/Makefile b/Makefile index a17fab3..5d44395 100644 --- a/Makefile +++ b/Makefile @@ -34,7 +34,7 @@ collections: requirements: roles collections -dependency create prepare converge idempotence side-effect verify destroy login reset: +dependency create prepare converge idempotence side-effect verify destroy login list reset: MOLECULE_DOCKER_IMAGE=${MOLECULE_DOCKER_IMAGE} \ MOLECULE_DOCKER_COMMAND=${MOLECULE_DOCKER_COMMAND} \ poetry run molecule $@ -s ${MOLECULE_SCENARIO} diff --git a/README.md b/README.md index 62bd0c2..087a693 100644 --- a/README.md +++ b/README.md @@ -15,16 +15,15 @@ The following is the list of end-user serviceable parameters: Global PostgreSQL configuration -| Parameter | Default | Type | Description | -|:---------------------------|-------------------------:|:-------|:--------------------------------| -| postgresql_release | 16 | string | Target PostgreSQL major release | -| postgresql_package_state | present | string | PostgreSQL package state | -| postgresql_service_state | started | string | PostgreSQL service state | -| postgresql_service_enabled | true | bool | Start PostgreSQL on boot | -| postgresql_datadir | /var/lib/postgresql/data | string | PostgreSQL database location | -| postgresql_roles | [] | list | List of PostgreSQL roles | -| postgresql_databases | [] | list | List of PostgreSQL databases | -| postgresql_hba_entries | [] | list | List of HBA entries | +| Parameter | Default | Type | Description | Required | +|:---------------------------|-------------------------:|:-------|:-----------------------------------|:---------| +| postgresql_release | 16 | string | Target PostgreSQL major release | false | +| postgresql_package_state | present | string | PostgreSQL package state | false | +| postgresql_service_state | started | string | PostgreSQL service state | false | +| postgresql_service_enabled | true | bool | Start PostgreSQL on boot | false | +| postgresql_roles | [] | list | List of PostgreSQL roles | false | +| postgresql_databases | [] | list | List of PostgreSQL databases | false | +| postgresql_hba_entries | [] | list | List of HBA entries | false | Please refer to the [defaults directory](/defaults/main/) for an up to date list of input parameters. diff --git a/defaults/main/conf.yml b/defaults/main/conf.yml index d5f99f6..e925bf9 100644 --- a/defaults/main/conf.yml +++ b/defaults/main/conf.yml @@ -2,13 +2,12 @@ postgresql_conf_basename: "postgresql.conf" __postgresql_conf_main: - redhat: "{{ postgresql_datadir }}/{{ postgresql_conf_basename }}" + redhat: "/var/lib/pgsql/{{ postgresql_release }}/main/data/{{ postgresql_conf_basename }}" debian: "/etc/postgresql/{{ postgresql_release }}/main/{{ postgresql_conf_basename }}" __postgresql_conf_pgaudit: 10-pgaudit.conf __postgresql_conf_pgcron: 20-pgcron.conf __postgresql_conf_pgstat_statements: 30-pgstat_statements.conf __postgresql_conf_local: 70-local.conf -__postgresql_conf_standby: 80-standby.conf __postgresql_conf_ansible: 90-ansible.conf __postgresql_conf_exclude: - "{{ __postgresql_conf_pgaudit }}" @@ -16,4 +15,3 @@ __postgresql_conf_exclude: - "{{ __postgresql_conf_pgstat_statements }}" - "{{ __postgresql_conf_local }}" - "{{ __postgresql_conf_ansible }}" - - "{{ __postgresql_conf_standby }}" diff --git a/defaults/main/package.yml b/defaults/main/package.yml index e14031e..3b8afe0 100644 --- a/defaults/main/package.yml +++ b/defaults/main/package.yml @@ -6,11 +6,6 @@ __postgresql_os_search: - "{{ ansible_os_family | lower }}" - "default" __postgresql_package_name: - debian: - - "postgresql-{{ postgresql_release }}" - - "postgresql-client-{{ postgresql_release }}" - - "postgresql-{{ postgresql_release }}-pgaudit" - - "postgresql-{{ postgresql_release }}-cron" redhat: - "postgresql{{ postgresql_release }}-server" - "postgresql{{ postgresql_release }}-contrib" @@ -18,7 +13,18 @@ __postgresql_package_name: - "pgaudit_{{ postgresql_release }}" - "pg_cron_{{ postgresql_release }}" - "glibc-langpack-{{ postgresql_locale | regex_replace('_.*', '') }}" + debian: + - "postgresql-{{ postgresql_release }}" + - "postgresql-client-{{ postgresql_release }}" + - "postgresql-{{ postgresql_release }}-pgaudit" + - "postgresql-{{ postgresql_release }}-cron" __postgresql_bindir: redhat: "/usr/pgsql-{{ postgresql_release }}/bin" debian: "/usr/lib/postgresql/{{ postgresql_release }}/bin" +__postgresql_datadir: + redhat: "/var/lib/pgsql/{{ postgresql_release }}/main/data" + debian: "/var/lib/postgresql/{{ postgresql_release }}/main" +__postgresql_socketdir: + redhat: "/run/postgresql" + debian: "/var/run/postgresql" diff --git a/defaults/main/params.yml b/defaults/main/params.yml index f304ab2..bdfa287 100644 --- a/defaults/main/params.yml +++ b/defaults/main/params.yml @@ -8,11 +8,31 @@ postgresql_service_enabled: true postgresql_service_masked: false postgresql_user: postgres postgresql_group: postgres -postgresql_waldir: "/var/lib/postgresql/wal" -postgresql_datadir: "/var/lib/postgresql/data" postgresql_roles: [] +postgresql_initdb: true postgresql_databases: [] +postgresql_profile: '/etc/profile.d/postgresql.sh' postgresql_auth_method: md5 # [ scram-sha-256 | md5 ] postgresql_default_database: postgres postgresql_locale: en_US.UTF-8 -postgresql_hba_entries: [] +postgresql_hba_entries: + - type: "host" + database: "all" + user: "all" + address: "127.0.0.1/32" + auth_method: "{{ _postgresql_auth_method }}" + - type: "host" + database: "all" + user: "all" + address: "::1/128" + auth_method: "{{ _postgresql_auth_method }}" + - type: "host" + database: "all" + user: "all" + address: "0.0.0.0/0" + auth_method: "{{ _postgresql_auth_method }}" + - type: "host" + database: "all" + user: "all" + address: "::0/0" + auth_method: "{{ _postgresql_auth_method }}" diff --git a/molecule/common/verify.yml b/molecule/common/verify.yml index c497a85..d021b2f 100644 --- a/molecule/common/verify.yml +++ b/molecule/common/verify.yml @@ -4,6 +4,11 @@ gather_facts: true become: true tasks: + - name: Import role defaults + ansible.builtin.include_role: + name: nephelaiio.postgresql + tasks_from: vars.yml + - name: Gather service facts ansible.builtin.service_facts: @@ -124,3 +129,37 @@ loop_control: label: "{{ item.name }}" loop: "{{ postgresql_roles | default([]) | selectattr('groups', 'defined') }}" + + - name: Crate molecule user + ansible.builtin.user: + name: molecule + + - name: Query data checksum + community.postgresql.postgresql_query: + db: postgres + query: 'SHOW data_checksums' + become: true + become_user: postgres + register: postgresql_checksums + + - name: Verify data checksum + ansible.builtin.assert: + that: postgresql_checksums.query_result[0].data_checksums == "on" + + - name: Attempt remote admin access + ansible.builtin.command: + cmd: "psql -h {{ ansible_default_ipv4.address }} -p 5432 -U postgres -c 'SHOW data_checksums'" + become: true + become_user: molecule + register: postgresql_query_nopasswd + ignore_errors: true + + - name: Check unauthenticated access + ansible.builtin.assert: + that: + - postgresql_query_nopasswd is failed + - postgresql_query_nopasswd.stderr is search('no password supplied') + + - name: Execute postgresql bin command from path + ansible.builtin.command: + cmd: "{{ _postgresql_bindir }}/pg_ctl --help" diff --git a/tasks/configure.yml b/tasks/configure.yml index 656dba5..be61d3e 100644 --- a/tasks/configure.yml +++ b/tasks/configure.yml @@ -33,14 +33,6 @@ when: postgresql_locale != _locale_config changed_when: false -- name: Create PostgreSQL wal directory - ansible.builtin.file: - path: "{{ _postgresql_waldir }}" - owner: "{{ postgresql_user }}" - group: "{{ postgresql_group }}" - state: directory - mode: 0700 - - name: Create PostgreSQL data directory ansible.builtin.file: path: "{{ _postgresql_datadir }}" @@ -55,6 +47,13 @@ creates: "{{ _postgresql_datadir }}/PG_VERSION" become: true become_user: "{{ postgresql_user }}" + when: _postgresql_initdb | bool + +- name: Enable PostgreSQL checksums + ansible.builtin.command: + cmd: "{{ _postgresql_bindir }}/pg_checksums -D {{ _postgresql_datadir }} --enable" + when: _postgresql_checksum_enable | bool + changed_when: false - name: Create PostgreSQL include directory ansible.builtin.file: @@ -91,16 +90,6 @@ mode: 0644 changed_when: false -- name: Create PostgreSQL standby config - ansible.builtin.file: - path: "{{ _postgresql_conf_standby }}" - state: touch - modification_time: preserve - owner: "{{ postgresql_user }}" - group: "{{ postgresql_group }}" - mode: 0644 - changed_when: false - - name: List PostgreSQL alien config files ansible.builtin.find: path: "{{ _postgresql_conf_include }}" @@ -113,32 +102,38 @@ path: "{{ item }}" loop: "{{ _query_includes.files | map(attribute='path') }}" -- name: Manage PostgreSQL hba config - community.postgresql.postgresql_pg_hba: - dest: "{{ _postgresql_conf_hba }}" - contype: "{{ item.type }}" - databases: "{{ item.databases }}" - users: "{{ item.users }}" - source: "{{ item.address | default(omit) }}" - method: "{{ item.method }}" - create: "{{ postgresql_hba_manage | default(true) }}" +- name: Manage PostgreSQL main config + ansible.builtin.template: + src: postgresql.conf.j2 + dest: "{{ _postgresql_conf_main }}" owner: "{{ postgresql_user }}" group: "{{ postgresql_group }}" - loop: "{{ postgresql_hba_entries }}" - loop_control: - label: "{{ item.type }} {{ item.databases }} {{ item.users }} {{ item.method }}" - notify: postgresql_reload + backup: true + mode: 0644 + notify: postgresql_restart -- name: Manage PostgreSQL main config +- name: Manage PostgreSQL hba config ansible.builtin.template: - src: postgres.conf.j2 - dest: "{{ _postgresql_conf_main }}" + src: pg_hba.conf.j2 + dest: "{{ _postgresql_conf_hba }}" owner: "{{ postgresql_user }}" group: "{{ postgresql_group }}" backup: true mode: 0644 + vars: + _entries: "{{ postgresql_hba_entries }}" notify: postgresql_restart +- name: Manage PostgreSQL profile configuration + ansible.builtin.lineinfile: + path: "{{ postgresql_profile }}" + line: "PATH={{ _postgresql_bindir }}:$PATH" + state: "{{ (postgresql_package_state == 'absent') | ternary('absent', 'present') }}" + create: true + owner: root + group: root + mode: 0644 + - name: Manage PostgreSQL service configuration when: ansible_os_family == 'RedHat' block: diff --git a/tasks/install.yml b/tasks/install.yml index 0a3cb0e..809879d 100644 --- a/tasks/install.yml +++ b/tasks/install.yml @@ -5,6 +5,15 @@ state: "{{ postgresql_pip_state }}" when: postgresql_pip_manage +- name: Stat postgres datadir + ansible.builtin.stat: + path: "{{ _postgresql_datadir }}" + register: _datadir_query + +- name: Set database initialization flags + ansible.builtin.set_fact: + _postgresql_checksum_enable: "{{ not _datadir_query.stat.exists }}" + - name: Release package holds ansible.builtin.include_tasks: lock.yml vars: diff --git a/tasks/lock.yml b/tasks/lock.yml index ec7bfca..e0a8c9e 100644 --- a/tasks/lock.yml +++ b/tasks/lock.yml @@ -5,7 +5,8 @@ selection: "{{ _lock_state }}" vars: _version_regex: ".*=.*" - _package_versions: "{{ [_postgresql_package_name] | flatten | map('regex_search', _version_regex) }}" + _packages: "{{ ([_postgresql_package_name] | flatten) }}" + _package_versions: "{{ _packages | map('regex_search', _version_regex) }}" _package_holds: "{{ _package_versions | select('string') }}" loop: "{{ _package_holds }}" when: ansible_os_family == "Debian" @@ -17,7 +18,8 @@ state: "{{ 'absent' if _lock_state == 'install' else 'present' }}" vars: _version_regex: ".*=.*" - _package_versions: "{{ [_postgresql_package_name] | flatten | map('regex_search', _version_regex) }}" + _packages: "{{ ([_postgresql_package_name] | flatten) }}" + _package_versions: "{{ _packages | map('regex_search', _version_regex) }}" _package_holds: "{{ _package_versions | select('string') }}" loop: "{{ _package_holds }}" when: ansible_os_family == "RedHat" diff --git a/tasks/vars.yml b/tasks/vars.yml index 69f97fb..dcbc076 100644 --- a/tasks/vars.yml +++ b/tasks/vars.yml @@ -1,29 +1,32 @@ --- - name: Set global facts ansible.builtin.set_fact: - _postgresql_package_name: "{{ postgresql_package_name | default(_default_package) }}" + _postgresql_package_name: "{{ postgresql_package_name | default(_default_package_name) }}" _postgresql_service_name: "{{ postgresql_service_name | default(_default_service) }}" _postgresql_bindir: "{{ __postgresql_bindir | nephelaiio.plugins.sorted_get(_conf_search) }}" - _postgresql_datadir: "{{ postgresql_datadir }}" - _postgresql_waldir: "{{ postgresql_waldir }}" + _postgresql_datadir: "{{ _conf_datadir }}" + _postgresql_socketdir: "{{ _conf_socketdir }}" + _postgresql_initdb: "{{ postgresql_initdb }}" + _postgresql_auth_method: "{{ _auth_method }}" _postgresql_pgoptions: "{{ (_auth_method == _auth_scram_sha256) | ternary(_auth_scram_option, '') }}" _postgresql_conf_include: "{{ _conf_include }}" _postgresql_conf_main: "{{ _conf_main }}" - _postgresql_conf_hba: "{{ postgresql_datadir }}/pg_hba.conf" - _postgresql_conf_ident: "{{ postgresql_datadir }}/pg_ident.conf" + _postgresql_conf_hba: "{{ _conf_datadir }}/pg_hba.conf" + _postgresql_conf_ident: "{{ _conf_datadir }}/pg_ident.conf" _postgresql_conf_ansible: "{{ _conf_include }}/{{ __postgresql_conf_ansible }}" _postgresql_conf_pgaudit: "{{ _conf_include }}/{{ __postgresql_conf_pgaudit }}" _postgresql_conf_pgcron: "{{ _conf_include }}/{{ __postgresql_conf_pgcron }}" _postgresql_conf_pgstat_statements: "{{ _conf_include }}/{{ __postgresql_conf_pgstat_statements }}" - _postgresql_conf_standby: "{{ _conf_include }}/{{ __postgresql_conf_standby }}" _postgresql_conf_local: "{{ _conf_include }}/{{ __postgresql_conf_local }}" _postgresql_conf_exclude: "{{ __postgresql_conf_exclude }}" vars: - _default_package: "{{ __postgresql_package_name | nephelaiio.plugins.sorted_get(_conf_search) }}" + _default_package_name: "{{ __postgresql_package_name | nephelaiio.plugins.sorted_get(_conf_search) }}" _default_service: "{{ __postgresql_service_name | nephelaiio.plugins.sorted_get(_conf_search) }}" + _conf_datadir: "{{ __postgresql_datadir | nephelaiio.plugins.sorted_get(_conf_search) }}" + _conf_socketdir: "{{ __postgresql_socketdir | nephelaiio.plugins.sorted_get(_conf_search) }}" _conf_search: "{{ __postgresql_os_search }}" - _conf_include: "{{ postgresql_datadir }}/conf.d" _conf_main: "{{ __postgresql_conf_main | nephelaiio.plugins.sorted_get(_conf_search) }}" + _conf_include: "{{ _conf_main | dirname }}/conf.d" _auth_scram_sha256: "scram-sha-256" _auth_scram_option: '-c password_encryption={{ _auth_scram_sha256 }}' _auth_method: "{{ postgresql_auth_method }}" diff --git a/templates/pg_hba.conf.j2 b/templates/pg_hba.conf.j2 new file mode 100644 index 0000000..2f7d3e2 --- /dev/null +++ b/templates/pg_hba.conf.j2 @@ -0,0 +1,6 @@ +{{ ansible_managed | comment }} + +local all all peer +{% for e in _entries -%} +{{ '%-20s %-20s %-20s %-20s %s %s' | format(e.type, e.database, e.user, e.address | default(''), e.auth_method, e.auth_options|default("")) }} +{% endfor -%} diff --git a/templates/postgres.sh.j2 b/templates/postgres.sh.j2 deleted file mode 100644 index 3c2f26e..0000000 --- a/templates/postgres.sh.j2 +++ /dev/null @@ -1 +0,0 @@ -export PGDATA={{ _postgresql_datadir }} diff --git a/templates/postgres.conf.j2 b/templates/postgresql.conf.j2 similarity index 61% rename from templates/postgres.conf.j2 rename to templates/postgresql.conf.j2 index 58d5e0f..827bcc1 100644 --- a/templates/postgres.conf.j2 +++ b/templates/postgresql.conf.j2 @@ -1,7 +1,10 @@ +{{ ansible_managed | comment }} + include_dir = '{{ _postgresql_conf_include | basename }}' +listen_addresses = '*' + data_directory = '{{ _postgresql_datadir }}' +unix_socket_directories = '{{ _postgresql_socketdir }}, /tmp' hba_file = '{{ _postgresql_conf_hba }}' ident_file = '{{ _postgresql_conf_ident }}' - -shared_preload_libraries = 'pgaudit,pg_cron,pg_stat_statements'