From 549b14dc7ee658d0c2672f775be2f8b0f99a7077 Mon Sep 17 00:00:00 2001 From: Eugene Zamriy Date: Mon, 18 Dec 2023 15:35:49 +0300 Subject: [PATCH] Adds kerberos_principal and koji_server roles --- CHANGELOG.rst | 15 ++ README.md | 2 + changelogs/.plugin-cache.yaml | 14 +- changelogs/changelog.yaml | 19 ++ .../1-koji_db_server-pg15-support.yml | 0 galaxy.yml | 2 +- roles/kerberos_principal/README.md | 31 +++ roles/kerberos_principal/defaults/main.yml | 5 + .../meta/argument_specs.yml | 29 +++ roles/kerberos_principal/meta/main.yml | 15 ++ roles/kerberos_principal/tasks/main.yml | 51 +++++ roles/koji_server/README.md | 32 +++ roles/koji_server/defaults/main.yml | 17 ++ roles/koji_server/handlers/main.yml | 10 + roles/koji_server/meta/argument_specs.yml | 96 +++++++++ roles/koji_server/meta/main.yml | 15 ++ roles/koji_server/tasks/koji_hub.yml | 120 +++++++++++ roles/koji_server/tasks/koji_web.yml | 51 +++++ roles/koji_server/tasks/kojira.yml | 66 ++++++ roles/koji_server/tasks/main.yml | 116 ++++++++++ .../etc/httpd/conf.d/kojihub.conf.j2 | 57 +++++ .../etc/httpd/conf.d/kojiweb.conf.j2 | 53 +++++ .../templates/etc/httpd/conf.d/ssl.conf.j2 | 202 ++++++++++++++++++ .../templates/etc/koji-hub/hub.conf.j2 | 37 ++++ .../templates/etc/kojira/kojira.conf.j2 | 36 ++++ .../templates/etc/kojiweb/web.conf.j2 | 18 ++ 26 files changed, 1107 insertions(+), 2 deletions(-) rename changelogs/{fragments => fragments-archive}/1-koji_db_server-pg15-support.yml (100%) create mode 100644 roles/kerberos_principal/README.md create mode 100644 roles/kerberos_principal/defaults/main.yml create mode 100644 roles/kerberos_principal/meta/argument_specs.yml create mode 100644 roles/kerberos_principal/meta/main.yml create mode 100644 roles/kerberos_principal/tasks/main.yml create mode 100644 roles/koji_server/README.md create mode 100644 roles/koji_server/defaults/main.yml create mode 100644 roles/koji_server/handlers/main.yml create mode 100644 roles/koji_server/meta/argument_specs.yml create mode 100644 roles/koji_server/meta/main.yml create mode 100644 roles/koji_server/tasks/koji_hub.yml create mode 100644 roles/koji_server/tasks/koji_web.yml create mode 100644 roles/koji_server/tasks/kojira.yml create mode 100644 roles/koji_server/tasks/main.yml create mode 100644 roles/koji_server/templates/etc/httpd/conf.d/kojihub.conf.j2 create mode 100644 roles/koji_server/templates/etc/httpd/conf.d/kojiweb.conf.j2 create mode 100644 roles/koji_server/templates/etc/httpd/conf.d/ssl.conf.j2 create mode 100644 roles/koji_server/templates/etc/koji-hub/hub.conf.j2 create mode 100644 roles/koji_server/templates/etc/kojira/kojira.conf.j2 create mode 100644 roles/koji_server/templates/etc/kojiweb/web.conf.j2 diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 1500262..7953e6d 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -5,6 +5,21 @@ msvsphere.ci Release Notes .. contents:: Topics +v0.1.4 +====== + +Bugfixes +-------- + +- koji_db_server - added PostgreSQL 15 support by granting schema usage and create privileges to Koji user. + +New Roles +--------- + +- msvsphere.ci.kerberos_principal - A role that creates a kerberos principal. +- msvsphere.ci.koji_cli - A role that installs and configures Koji CLI tools. +- msvsphere.ci.koji_server - A role that installs and configures a Koji server. + v0.1.3 ====== diff --git a/README.md b/README.md index d60f00c..18dafc5 100644 --- a/README.md +++ b/README.md @@ -4,8 +4,10 @@ The MSVSphere OS CI/CD collection. ## Roles +* [kerberos_principal](roles/kerberos_principal/README.md) * [koji_cli](roles/koji_cli/README.md) * [koji_db_server](roles/koji_db_server/README.md) +* [koji_server](roles/koji_server/README.md) * [koji_server_ca](roles/koji_server_ca/README.md) * [koji_tools](roles/koji_tools/README.md) * [postgresql_server](roles/postgresql_server/README.md) diff --git a/changelogs/.plugin-cache.yaml b/changelogs/.plugin-cache.yaml index aa6b1d4..9ef25bf 100644 --- a/changelogs/.plugin-cache.yaml +++ b/changelogs/.plugin-cache.yaml @@ -1,9 +1,21 @@ objects: role: + kerberos_principal: + description: A role that creates a kerberos principal. + name: kerberos_principal + version_added: 0.1.4 + koji_cli: + description: A role that installs and configures Koji CLI tools. + name: koji_cli + version_added: 0.1.4 koji_db_server: description: A role that configures a PostgreSQL server for Koji. name: koji_db_server version_added: 0.1.3 + koji_server: + description: A role that installs and configures a Koji server. + name: koji_server + version_added: 0.1.4 koji_server_ca: description: A role that creates a Koji server CA and issues an HTTPS certificate. name: koji_server_ca @@ -32,4 +44,4 @@ plugins: strategy: {} test: {} vars: {} -version: 0.1.3 +version: 0.1.4 diff --git a/changelogs/changelog.yaml b/changelogs/changelog.yaml index a8f870e..37a9479 100644 --- a/changelogs/changelog.yaml +++ b/changelogs/changelog.yaml @@ -32,3 +32,22 @@ releases: name: koji_db_server namespace: null release_date: '2023-12-14' + 0.1.4: + changes: + bugfixes: + - koji_db_server - added PostgreSQL 15 support by granting schema usage and + create privileges to Koji user. + fragments: + - 1-koji_db_server-pg15-support.yml + objects: + role: + - description: A role that creates a kerberos principal. + name: kerberos_principal + namespace: null + - description: A role that installs and configures Koji CLI tools. + name: koji_cli + namespace: null + - description: A role that installs and configures a Koji server. + name: koji_server + namespace: null + release_date: '2023-12-18' diff --git a/changelogs/fragments/1-koji_db_server-pg15-support.yml b/changelogs/fragments-archive/1-koji_db_server-pg15-support.yml similarity index 100% rename from changelogs/fragments/1-koji_db_server-pg15-support.yml rename to changelogs/fragments-archive/1-koji_db_server-pg15-support.yml diff --git a/galaxy.yml b/galaxy.yml index 6b6f56d..d7d8056 100644 --- a/galaxy.yml +++ b/galaxy.yml @@ -1,6 +1,6 @@ namespace: msvsphere name: ci -version: 0.1.3 +version: 0.1.4 readme: README.md authors: - Eugene Zamriy diff --git a/roles/kerberos_principal/README.md b/roles/kerberos_principal/README.md new file mode 100644 index 0000000..99629e4 --- /dev/null +++ b/roles/kerberos_principal/README.md @@ -0,0 +1,31 @@ +# msvsphere.ci.kerberos_principal + +An Ansible role that creates a kerberos principal. + +## Variables + +| Variable | Default value | Type | Description | Required | +| ------------------------------ | ------------- | ---- | ------------------------------- | -------- | +| kerberos_principal_name | | str | Kerberos principal. | yes | +| kerberos_principal_password | | str | Kerberos principal password. | no | +| kerberos_principal_keytab_path | | str | Kerberos principal keytab path. | no | +| kerberos_principal_realm | | str | Kerberos realm. | no | + +## Example playbook + +```yaml +--- +- hosts: all + roles: + - role: msvsphere.ci.kerberos_principal + kerberos_principal_name: kojiroot + kerberos_principal_password: 'USER_PASSWORD' +``` + +## License + +MIT. + +## Authors + +* [Eugene Zamriy](mailto:ezamriy@msvsphere-os.ru) diff --git a/roles/kerberos_principal/defaults/main.yml b/roles/kerberos_principal/defaults/main.yml new file mode 100644 index 0000000..a385fca --- /dev/null +++ b/roles/kerberos_principal/defaults/main.yml @@ -0,0 +1,5 @@ +--- +kerberos_principal_name: +kerberos_principal_realm: '' +kerberos_principal_password: '' +kerberos_principal_keytab_path: '' diff --git a/roles/kerberos_principal/meta/argument_specs.yml b/roles/kerberos_principal/meta/argument_specs.yml new file mode 100644 index 0000000..5fa41d6 --- /dev/null +++ b/roles/kerberos_principal/meta/argument_specs.yml @@ -0,0 +1,29 @@ +--- +argument_specs: + main: + short_description: A role that creates a kerberos principal. + author: Eugene Zamriy + version_added: '0.1.4' + options: + kerberos_principal_name: + description: Kerberos principal name. + type: 'str' + required: true + + kerberos_principal_password: + description: Kerberos principal password. + default: '' + type: 'str' + required: false + + kerberos_principal_keytab_path: + description: Kerberos principal keytab path. + default: '' + type: 'str' + required: false + + kerberos_principal_realm: + description: Kerberos realm. + default: '' + type: 'str' + required: false diff --git a/roles/kerberos_principal/meta/main.yml b/roles/kerberos_principal/meta/main.yml new file mode 100644 index 0000000..c348c7e --- /dev/null +++ b/roles/kerberos_principal/meta/main.yml @@ -0,0 +1,15 @@ +--- +galaxy_info: + author: Eugene Zamriy + description: A role that creates a kerberos principal. + company: Softline PJSC + license: MIT + min_ansible_version: 2.13 + platforms: + - name: EL + versions: + - "9" + galaxy_tags: + - kerberos + +dependencies: [] diff --git a/roles/kerberos_principal/tasks/main.yml b/roles/kerberos_principal/tasks/main.yml new file mode 100644 index 0000000..2c5aa85 --- /dev/null +++ b/roles/kerberos_principal/tasks/main.yml @@ -0,0 +1,51 @@ +--- +- name: Check if principal name is defined + ansible.builtin.fail: + msg: 'Kerberos principal name is required' + when: | + kerberos_principal_name is undefined or + kerberos_principal_name is none or + (kerberos_principal_name | trim | length == 0) + +- block: + - name: Check if principal exists + ansible.builtin.command: + argv: + - /sbin/kadmin.local + - list_principals + - "{{ principal }}" + register: principal_check + changed_when: "principal_check.stdout == ''" + + - name: Create principal with password + ansible.builtin.command: + argv: + - /sbin/kadmin.local + - addprinc + - -pw + - "{{ kerberos_principal_password }}" + - "{{ principal }}" + when: principal_check.changed and kerberos_principal_password + + - name: Create principal without password + ansible.builtin.command: + argv: + - /sbin/kadmin.local + - addprinc + - -randkey + - "{{ principal }}" + when: principal_check.changed and not kerberos_principal_password + + - name: Generate principal keytab + ansible.builtin.command: + argv: + - /sbin/kadmin.local + - ktadd + - -k + - "{{ kerberos_principal_keytab_path }}" + - -norandkey + - "{{ principal }}" + creates: "{{ kerberos_principal_keytab_path }}" + when: kerberos_principal_keytab_path + vars: + principal: "{{ kerberos_principal_name }}{{ kerberos_principal_realm | ternary('@' + kerberos_principal_realm, '') }}" diff --git a/roles/koji_server/README.md b/roles/koji_server/README.md new file mode 100644 index 0000000..cd93f21 --- /dev/null +++ b/roles/koji_server/README.md @@ -0,0 +1,32 @@ +# msvsphere.ci.koji_server + +An Ansible role that configures a Koji server. + +## Variables + +| Variable | Default value | Type | Description | Required | +| -------- | ------------- | ---- | ----------- | -------- | +| koji_domain_name | | str | Koji server domain name. | yes | +| koji_db_name | "koji" | str | Koji PostgreSQL database name. | no | +| koji_db_user | "koji" | str | Koji PostgreSQL database user. | no | +| koji_db_password | | str | Koji PostgreSQL database user password. | yes | +| koji_db_server_ip | | str | Koji PostgreSQL server IP address. | yes | +| koji_kerberos_realm | | str | Koji Kerberos realm. | yes | +| koji_admin_user | "kojiroot" | str | Koji administrator user name. | no | +| koji_admin_principal | "{{ koji_admin_user }}@{{ koji_kerberos_realm }}" | str | Koji administrator Kerberos principal name. | no | +| koji_admin_password | | str | Koji administrator password. | yes | +| koji_hub_principal | "HTTP/{{ koji_domain_name }}@{{ koji_kerberos_realm }}" | str | Koji Hub Kerberos principal name. | no | +| koji_hub_keytab | "/etc/koji-hub/http.{{ koji_domain_name }}.keytab" | str | Koji Hub Kerberos keytab file path. | no | +| koji_web_principal | "koji/{{ koji_domain_name }}@{{ koji_kerberos_realm }}" | str | Koji Web Kerberos principal name. | no | +| koji_web_keytab | "/etc/kojiweb/koji.{{ koji_domain_name }}.keytab" | str | Koji Web Kerberos keytab file path. | no | +| koji_kojira_principal | "kojira/{{ koji_domain_name }}@{{ koji_kerberos_realm }}" | str | Koji Kojira user Kerberos principal name. | no | +| koji_kojira_keytab | "/etc/kojira/kojira.{{ koji_domain_name }}.keytab" | str | Koji Kojira user Kerberos keytab file path. | no | +| koji_web_secret | | str | Koji web server secret token. | yes | + +## License + +MIT. + +## Authors + +* [Eugene Zamriy](mailto:ezamriy@msvsphere-os.ru) diff --git a/roles/koji_server/defaults/main.yml b/roles/koji_server/defaults/main.yml new file mode 100644 index 0000000..0fe0d1c --- /dev/null +++ b/roles/koji_server/defaults/main.yml @@ -0,0 +1,17 @@ +--- +koji_domain_name: +koji_db_name: koji +koji_db_user: koji +koji_db_password: +koji_db_server_ip: +koji_kerberos_realm: +koji_admin_user: 'kojiroot' +koji_admin_principal: "{{ koji_admin_user }}@{{ koji_kerberos_realm }}" +koji_admin_password: +koji_hub_principal: "HTTP/{{ koji_domain_name }}@{{ koji_kerberos_realm }}" +koji_hub_keytab: "/etc/koji-hub/http.{{ koji_domain_name }}.keytab" +koji_kojira_principal: "kojira/{{ koji_domain_name }}@{{ koji_kerberos_realm }}" +koji_kojira_keytab: "/etc/kojira/kojira.{{ koji_domain_name }}.keytab" +koji_web_principal: "koji/{{ koji_domain_name }}@{{ koji_kerberos_realm }}" +koji_web_keytab: "/etc/kojiweb/koji.{{ koji_domain_name }}.keytab" +koji_web_secret: diff --git a/roles/koji_server/handlers/main.yml b/roles/koji_server/handlers/main.yml new file mode 100644 index 0000000..fd22913 --- /dev/null +++ b/roles/koji_server/handlers/main.yml @@ -0,0 +1,10 @@ +--- +- name: restart httpd + ansible.builtin.service: + name: httpd + state: restarted + +- name: restart kojira + ansible.builtin.service: + name: kojira + state: restarted diff --git a/roles/koji_server/meta/argument_specs.yml b/roles/koji_server/meta/argument_specs.yml new file mode 100644 index 0000000..22da4e9 --- /dev/null +++ b/roles/koji_server/meta/argument_specs.yml @@ -0,0 +1,96 @@ +--- +argument_specs: + main: + short_description: A role that installs and configures a Koji server. + author: Eugene Zamriy + version_added: '0.1.4' + options: + koji_db_name: + description: Koji database name. + default: koji + type: str + required: false + + koji_db_user: + description: Koji database user. + default: koji + type: str + required: false + + koji_db_password: + description: Koji database user password. + type: str + required: true + + koji_db_server_ip: + description: Koji database server IP address or domain name. + type: str + required: true + + koji_domain_name: + description: Koji server domain name. + type: str + required: true + + koji_kerberos_realm: + description: Koji kerberos realm. + type: str + required: true + + koji_web_secret: + description: Koji web server secret token. + type: str + required: true + + koji_admin_user: + description: Koji administrator user name. + default: 'kojiroot' + type: str + required: false + + koji_admin_password: + description: Koji administrator user password. + type: str + required: true + + koji_admin_principal: + description: Koji administrator Kerberos principal name. + default: '{{ koji_admin_user }}@{{ koji_kerberos_realm }}' + type: str + required: false + + koji_hub_principal: + description: Koji Hub Kerberos principal name. + default: 'HTTP/{{ koji_domain_name }}@{{ koji_kerberos_realm }}' + type: str + required: false + + koji_hub_keytab: + description: Koji Hub Kerberos keytab file path. + default: '/etc/koji-hub/http.{{ koji_domain_name }}.keytab' + type: str + required: false + + koji_web_principal: + description: Koji Web Kerberos principal name. + default: 'koji/{{ koji_domain_name }}@{{ koji_kerberos_realm }}' + type: str + required: false + + koji_web_keytab: + description: Koji Web Kerberos keytab file path. + default: '/etc/kojiweb/koji.{{ koji_domain_name }}.keytab' + type: str + required: false + + koji_kojira_principal: + description: Koji Kojira user Kerberos principal name. + default: 'kojira/{{ koji_domain_name }}@{{ koji_kerberos_realm }}' + type: str + required: false + + koji_kojira_keytab: + description: Koji Kojira user Kerberos keytab file path. + default: '/etc/kojira/kojira.{{ koji_domain_name }}.keytab' + type: str + required: false diff --git a/roles/koji_server/meta/main.yml b/roles/koji_server/meta/main.yml new file mode 100644 index 0000000..8020948 --- /dev/null +++ b/roles/koji_server/meta/main.yml @@ -0,0 +1,15 @@ +--- +galaxy_info: + author: Eugene Zamriy + description: A role that installs and configures a Koji server. + company: Softline PJSC + license: MIT + min_ansible_version: 2.13 + platforms: + - name: EL + versions: + - "9" + galaxy_tags: + - koji + +dependencies: [] diff --git a/roles/koji_server/tasks/koji_hub.yml b/roles/koji_server/tasks/koji_hub.yml new file mode 100644 index 0000000..89013ce --- /dev/null +++ b/roles/koji_server/tasks/koji_hub.yml @@ -0,0 +1,120 @@ +--- +- name: Install koji-hub and dependencies + ansible.builtin.dnf: + name: + - koji-hub + - koji-hub-plugins + - mod_ssl + # NOTE: python3-libsemanage is the ansible.posix.seboolean dependency + - python3-libsemanage + state: installed + +# TODO: add FreeIPA support +- name: Generate koji-hub HTTP principal keytab + ansible.builtin.include_role: + name: msvsphere.ci.kerberos_principal + vars: + kerberos_principal_name: "{{ koji_hub_principal }}" + kerberos_principal_keytab_path: "{{ koji_hub_keytab }}" + +- name: Grant httpd read access to koji-hub keytab + ansible.builtin.file: + path: "{{ koji_hub_keytab }}" + owner: root + group: apache + mode: 0o640 + setype: httpd_config_t + notify: + - restart httpd + +- name: Configure koji-hub + ansible.builtin.template: + src: etc/koji-hub/hub.conf.j2 + dest: /etc/koji-hub/hub.conf + owner: root + group: apache + mode: 0o640 + notify: + - restart httpd + +- name: Configure koji-hub httpd + ansible.builtin.template: + src: etc/httpd/conf.d/kojihub.conf.j2 + dest: /etc/httpd/conf.d/kojihub.conf + owner: root + group: root + mode: 0o644 + notify: + - restart httpd + +- name: Configure SSL in httpd + ansible.builtin.template: + src: etc/httpd/conf.d/ssl.conf.j2 + dest: /etc/httpd/conf.d/ssl.conf + owner: root + group: root + mode: 0o644 + notify: + - restart httpd + +- name: Enable httpd database connections in SELinux + ansible.posix.seboolean: + name: httpd_can_network_connect_db + state: true + persistent: true + +- name: Allow httpd writing files in SELinux + ansible.posix.seboolean: + name: allow_httpd_anon_write + state: true + persistent: true + +- name: Create /mnt/koji directory + ansible.builtin.file: + path: /mnt/koji + state: directory + owner: root + group: root + mode: 0o755 + setype: public_content_rw_t + +- name: Create Koji working directories + ansible.builtin.file: + path: "/mnt/koji/{{ item }}" + state: directory + owner: apache + group: apache + mode: 0o755 + setype: public_content_rw_t + with_items: + - packages + - repos + - work + - scratch + - repos-dist + +- name: Copy Koji CA certificate to /mnt/koji + ansible.builtin.copy: + src: /etc/pki/koji/koji-ca.crt + dest: /mnt/koji/koji-ca.crt + remote_src: yes + +- name: Enable and start httpd service + ansible.builtin.service: + name: httpd + enabled: true + state: started + +- name: Get firewalld service status + ansible.builtin.systemd: + name: firewalld + register: firewalld_service_status + +- name: Open HTTPs port on firewall + ansible.posix.firewalld: + zone: public + service: https + immediate: true + permanent: true + state: enabled + when: firewalld_service_status.status.ActiveState == 'active' diff --git a/roles/koji_server/tasks/koji_web.yml b/roles/koji_server/tasks/koji_web.yml new file mode 100644 index 0000000..fa25a27 --- /dev/null +++ b/roles/koji_server/tasks/koji_web.yml @@ -0,0 +1,51 @@ +--- +- name: Install koji-web and dependencies + ansible.builtin.dnf: + name: + - koji-web + - mod_ssl + state: installed + +# TODO: add FreeIPA support +- name: Generate koji-web HTTP principal keytab + ansible.builtin.include_role: + name: msvsphere.ci.kerberos_principal + vars: + kerberos_principal_name: "{{ koji_web_principal }}" + kerberos_principal_keytab_path: "{{ koji_web_keytab }}" + +- name: Grant httpd read access to koji-web keytab + ansible.builtin.file: + path: "{{ koji_web_keytab }}" + owner: root + group: apache + mode: 0o640 + setype: httpd_config_t + notify: + - restart httpd + +- name: Configure koji-web httpd + ansible.builtin.template: + src: etc/httpd/conf.d/kojiweb.conf.j2 + dest: /etc/httpd/conf.d/kojiweb.conf + owner: root + group: root + mode: 0o644 + notify: + - restart httpd + +- name: Configure koji-web + ansible.builtin.template: + src: etc/kojiweb/web.conf.j2 + dest: /etc/kojiweb/web.conf + owner: root + group: apache + mode: 0o640 + notify: + - restart httpd + +- name: Enable httpd network connections in SELinux + ansible.posix.seboolean: + name: httpd_can_network_connect + state: true + persistent: true diff --git a/roles/koji_server/tasks/kojira.yml b/roles/koji_server/tasks/kojira.yml new file mode 100644 index 0000000..80528ad --- /dev/null +++ b/roles/koji_server/tasks/kojira.yml @@ -0,0 +1,66 @@ +--- +- name: Install koji-utils + ansible.builtin.dnf: + name: koji-utils + state: installed + +- name: Generate /etc/kojira/kojira.conf config + ansible.builtin.template: + src: etc/kojira/kojira.conf.j2 + dest: /etc/kojira/kojira.conf + owner: root + group: root + mode: 0o644 + notify: restart kojira + +# TODO: add FreeIPA support +- name: Generate kojira principal keytab + ansible.builtin.include_role: + name: msvsphere.ci.kerberos_principal + vars: + kerberos_principal_name: "{{ koji_kojira_principal }}" + kerberos_principal_keytab_path: "{{ koji_kojira_keytab }}" + +- name: Check if kojira DB user exists + community.postgresql.postgresql_query: + db: "{{ koji_db_name }}" + login_user: "{{ koji_db_user }}" + login_password: "{{ koji_db_password }}" + login_host: "{{ koji_db_server_ip }}" + query: > + SELECT krb_principal FROM user_krb_principals + WHERE krb_principal = %(krb_principal)s + named_args: + krb_principal: "{{ koji_kojira_principal }}" + register: kojira_user_initialized + +- name: Configure kojira Koji user + block: + - name: Obtain Koji admin kerberos ticket + ansible.builtin.shell: "echo '{{ koji_admin_password }}' | kinit {{ koji_admin_principal }}" + + - name: Check if kojira Koji user exist + command: koji userinfo kojira + register: koji_kojira_userinfo + changed_when: koji_kojira_userinfo.stderr is search('No\s+such\s+user') + + - name: Create kojira Koji user + command: "koji add-user kojira --principal='{{ koji_kojira_principal }}'" + register: koji_kojira_add_user + when: koji_kojira_userinfo.changed + notify: restart kojira + + - name: Grant kojira Koji user repo permissions + command: koji grant-permission repo kojira + when: koji_kojira_add_user.changed + always: + - name: Destroy Koji admin kerberos ticket + ansible.builtin.command: "kdestroy -p {{ koji_admin_principal }}" + ignore_errors: true + when: kojira_user_initialized.rowcount == 0 + +- name: Enable and start kojira service + ansible.builtin.service: + name: kojira + enabled: true + state: started diff --git a/roles/koji_server/tasks/main.yml b/roles/koji_server/tasks/main.yml new file mode 100644 index 0000000..2f98d97 --- /dev/null +++ b/roles/koji_server/tasks/main.yml @@ -0,0 +1,116 @@ +--- +- name: Check if required variables are defined + ansible.builtin.fail: + msg: "{{ item }} is not defined or empty" + when: | + (vars[item] is undefined) + or (vars[item] is none) + or (vars[item] | trim | length == 0) + with_items: + - koji_domain_name + - koji_db_name + - koji_db_user + - koji_db_password + - koji_db_server_ip + - koji_kerberos_realm + - koji_admin_user + - koji_admin_principal + - koji_admin_password + - koji_hub_principal + - koji_hub_keytab + - koji_web_principal + - koji_web_keytab + - koji_kojira_principal + - koji_kojira_keytab + - koji_web_secret + +- name: Install koji package and dependencies + ansible.builtin.dnf: + name: + - koji + - python3-psycopg2 + state: installed + +- name: Check if Koji database is initialized + community.postgresql.postgresql_query: + db: "{{ koji_db_name }}" + login_user: "{{ koji_db_user }}" + login_password: "{{ koji_db_password }}" + login_host: "{{ koji_db_server_ip }}" + query: SELECT COUNT(*) FROM users + ignore_errors: true + register: koji_database_initialized + changed_when: "koji_database_initialized.failed" + +- name: Initialize Koji database + community.postgresql.postgresql_query: + db: "{{ koji_db_name }}" + login_user: "{{ koji_db_user }}" + login_password: "{{ koji_db_password }}" + login_host: "{{ koji_db_server_ip }}" + path_to_script: /usr/share/doc/koji/docs/schema.sql + when: koji_database_initialized.failed + +- name: Check if Koji admin DB user exists + community.postgresql.postgresql_query: + db: "{{ koji_db_name }}" + login_user: "{{ koji_db_user }}" + login_password: "{{ koji_db_password }}" + login_host: "{{ koji_db_server_ip }}" + query: SELECT name FROM users WHERE name = %(name)s + named_args: + name: "{{ koji_admin_user }}" + register: koji_admin_initialized + +- name: Create Koji admin DB user + community.postgresql.postgresql_query: + db: "{{ koji_db_name }}" + login_user: "{{ koji_db_user }}" + login_password: "{{ koji_db_password }}" + login_host: "{{ koji_db_server_ip }}" + query: > + INSERT INTO users (name, status, usertype) + VALUES (%(name)s, %(status)s, %(usertype)s) + RETURNING id + named_args: + name: "{{ koji_admin_user }}" + status: 0 + usertype: 0 + register: koji_admin_insert + when: koji_admin_initialized.rowcount == 0 + +- name: Set permissions for Koji admin DB user + community.postgresql.postgresql_query: + db: "{{ koji_db_name }}" + login_user: "{{ koji_db_user }}" + login_password: "{{ koji_db_password }}" + login_host: "{{ koji_db_server_ip }}" + query: > + INSERT INTO user_perms (user_id, perm_id, creator_id) + VALUES (%(user_id)s, 1, %(user_id)s) + named_args: + user_id: "{{ koji_admin_insert.query_result[0]['id'] }}" + when: koji_admin_insert.changed + +- name: Configure Kerberos for Koji admin DB user + community.postgresql.postgresql_query: + db: "{{ koji_db_name }}" + login_user: "{{ koji_db_user }}" + login_password: "{{ koji_db_password }}" + login_host: "{{ koji_db_server_ip }}" + query: > + INSERT INTO user_krb_principals (user_id, krb_principal) + VALUES (%(user_id)s, %(krb_principal)s) + named_args: + user_id: "{{ koji_admin_insert.query_result[0]['id'] }}" + krb_principal: "{{ koji_admin_user }}@{{ koji_kerberos_realm }}" + when: koji_admin_insert.changed + +- name: Install and configure koji-hub + import_tasks: koji_hub.yml + +- name: Install and configure koji-web + import_tasks: koji_web.yml + +- name: Install and configure kojira + import_tasks: kojira.yml diff --git a/roles/koji_server/templates/etc/httpd/conf.d/kojihub.conf.j2 b/roles/koji_server/templates/etc/httpd/conf.d/kojihub.conf.j2 new file mode 100644 index 0000000..2ce674e --- /dev/null +++ b/roles/koji_server/templates/etc/httpd/conf.d/kojihub.conf.j2 @@ -0,0 +1,57 @@ +# +# koji-hub is an xmlrpc interface to the Koji database +# + +Alias /kojihub /usr/share/koji-hub/kojiapp.py + + + Options ExecCGI + SetHandler wsgi-script + WSGIApplicationGroup %{GLOBAL} + # ^ works around a hub issue with OpenSSL + # see: https://cryptography.io/en/latest/faq/#starting-cryptography-using-mod-wsgi-produces-an-internalerror-during-a-call-in-register-osrandom-engine + WSGIScriptReloading Off + # ^ reloading breaks hub "firstcall" check + # see: https://pagure.io/koji/issue/875 + + Order allow,deny + Allow from all + + = 2.4> + Require all granted + + + +# Also serve /mnt/koji +Alias /kojifiles "/mnt/koji/" + + + #Options Indexes SymLinksIfOwnerMatch + #If your top /mnt/koji directory is not owned by the httpd user, then + #you will need to follow all symlinks instead, e.g. + Options Indexes FollowSymLinks + AllowOverride None + IndexOptions +NameWidth=* + + Order allow,deny + Allow from all + + = 2.4> + Require all granted + + + +# uncomment this to enable authentication via SSL client certificates +# +# SSLVerifyClient require +# SSLVerifyDepth 10 +# SSLOptions +StdEnvVars +# + +# uncomment this to enable authentication via GSSAPI + + AuthType GSSAPI + AuthName "GSSAPI Single Sign On Login" + GssapiCredStore keytab:{{ koji_hub_keytab }} + Require valid-user + diff --git a/roles/koji_server/templates/etc/httpd/conf.d/kojiweb.conf.j2 b/roles/koji_server/templates/etc/httpd/conf.d/kojiweb.conf.j2 new file mode 100644 index 0000000..37a4ead --- /dev/null +++ b/roles/koji_server/templates/etc/httpd/conf.d/kojiweb.conf.j2 @@ -0,0 +1,53 @@ +#We use wsgi by default +Alias /koji "/usr/share/koji-web/scripts/wsgi_publisher.py" +#(configuration goes in /etc/kojiweb/web.conf) + +# Python 3 Cheetah expectes unicode everywhere, apache's default lang is C +# which is not sufficient to open our templates +WSGIDaemonProcess koji lang=C.UTF-8 + + + Options ExecCGI + SetHandler wsgi-script + WSGIProcessGroup koji + WSGIApplicationGroup %{GLOBAL} + # ^ works around an OpenSSL issue + # see: https://cryptography.io/en/latest/faq/#starting-cryptography-using-mod-wsgi-produces-an-internalerror-during-a-call-in-register-osrandom-engine + + Order allow,deny + Allow from all + + = 2.4> + Require all granted + + + +# uncomment this to enable authentication via Kerberos + + AuthType GSSAPI + AuthName "Koji Web UI" + GssapiCredStore keytab:{{ koji_hub_keytab }} + Require valid-user + ErrorDocument 401 /koji-static/errors/unauthorized.html + + +# uncomment this to enable authentication via SSL client certificates +# +# SSLVerifyClient require +# SSLVerifyDepth 10 +# SSLOptions +StdEnvVars +# + +Alias /koji-static/ "/usr/share/koji-web/static/" + + + Options None + AllowOverride None + + Order allow,deny + Allow from all + + = 2.4> + Require all granted + + diff --git a/roles/koji_server/templates/etc/httpd/conf.d/ssl.conf.j2 b/roles/koji_server/templates/etc/httpd/conf.d/ssl.conf.j2 new file mode 100644 index 0000000..def4c29 --- /dev/null +++ b/roles/koji_server/templates/etc/httpd/conf.d/ssl.conf.j2 @@ -0,0 +1,202 @@ +# +# When we also provide SSL we have to listen to the +# standard HTTPS port in addition. +# +Listen 443 https + +## +## SSL Global Context +## +## All SSL configuration in this context applies both to +## the main server and all SSL-enabled virtual hosts. +## + +# Pass Phrase Dialog: +# Configure the pass phrase gathering process. +# The filtering dialog program (`builtin' is a internal +# terminal dialog) has to provide the pass phrase on stdout. +SSLPassPhraseDialog exec:/usr/libexec/httpd-ssl-pass-dialog + +# Inter-Process Session Cache: +# Configure the SSL Session Cache: First the mechanism +# to use and second the expiring timeout (in seconds). +SSLSessionCache shmcb:/run/httpd/sslcache(512000) +SSLSessionCacheTimeout 300 + +# +# Use "SSLCryptoDevice" to enable any supported hardware +# accelerators. Use "openssl engine -v" to list supported +# engine names. NOTE: If you enable an accelerator and the +# server does not start, consult the error logs and ensure +# your accelerator is functioning properly. +# +SSLCryptoDevice builtin +#SSLCryptoDevice ubsec + +## +## SSL Virtual Host Context +## + + + +# General setup for the virtual host, inherited from global configuration +#DocumentRoot "/var/www/html" +#ServerName www.example.com:443 + +# Use separate log files for the SSL virtual host; note that LogLevel +# is not inherited from httpd.conf. +ErrorLog logs/ssl_error_log +TransferLog logs/ssl_access_log +LogLevel warn + +# SSL Engine Switch: +# Enable/Disable SSL for this virtual host. +SSLEngine on + +# List the protocol versions which clients are allowed to connect with. +# The OpenSSL system profile is used by default. See +# update-crypto-policies(8) for more details. +#SSLProtocol all -SSLv3 +#SSLProxyProtocol all -SSLv3 + +# User agents such as web browsers are not configured for the user's +# own preference of either security or performance, therefore this +# must be the prerogative of the web server administrator who manages +# cpu load versus confidentiality, so enforce the server's cipher order. +SSLHonorCipherOrder on + +# SSL Cipher Suite: +# List the ciphers that the client is permitted to negotiate. +# See the mod_ssl documentation for a complete list. +# The OpenSSL system profile is configured by default. See +# update-crypto-policies(8) for more details. +SSLCipherSuite PROFILE=SYSTEM +SSLProxyCipherSuite PROFILE=SYSTEM + +# Point SSLCertificateFile at a PEM encoded certificate. If +# the certificate is encrypted, then you will be prompted for a +# pass phrase. Note that restarting httpd will prompt again. Keep +# in mind that if you have both an RSA and a DSA certificate you +# can configure both in parallel (to also allow the use of DSA +# ciphers, etc.) +# Some ECC cipher suites (http://www.ietf.org/rfc/rfc4492.txt) +# require an ECC certificate which can also be configured in +# parallel. +SSLCertificateFile /etc/pki/koji/{{ koji_domain_name }}.chain.crt + +# Server Private Key: +# If the key is not combined with the certificate, use this +# directive to point at the key file. Keep in mind that if +# you've both a RSA and a DSA private key you can configure +# both in parallel (to also allow the use of DSA ciphers, etc.) +# ECC keys, when in use, can also be configured in parallel +SSLCertificateKeyFile /etc/pki/koji/{{ koji_domain_name }}.key + +# Server Certificate Chain: +# Point SSLCertificateChainFile at a file containing the +# concatenation of PEM encoded CA certificates which form the +# certificate chain for the server certificate. Alternatively +# the referenced file can be the same as SSLCertificateFile +# when the CA certificates are directly appended to the server +# certificate for convenience. +SSLCertificateChainFile /etc/pki/koji/{{ koji_domain_name }}.chain.crt + +# Certificate Authority (CA): +# Set the CA certificate verification path where to find CA +# certificates for client authentication or alternatively one +# huge file containing all of them (file must be PEM encoded) +SSLCACertificateFile /etc/pki/koji/koji-ca.crt + +# Client Authentication (Type): +# Client certificate verification type and depth. Types are +# none, optional, require and optional_no_ca. Depth is a +# number which specifies how deeply to verify the certificate +# issuer chain before deciding the certificate is not valid. +#SSLVerifyClient require +#SSLVerifyDepth 10 + +# Access Control: +# With SSLRequire you can do per-directory access control based +# on arbitrary complex boolean expressions containing server +# variable checks and other lookup directives. The syntax is a +# mixture between C and Perl. See the mod_ssl documentation +# for more details. +# +#SSLRequire ( %{SSL_CIPHER} !~ m/^(EXP|NULL)/ \ +# and %{SSL_CLIENT_S_DN_O} eq "Snake Oil, Ltd." \ +# and %{SSL_CLIENT_S_DN_OU} in {"Staff", "CA", "Dev"} \ +# and %{TIME_WDAY} >= 1 and %{TIME_WDAY} <= 5 \ +# and %{TIME_HOUR} >= 8 and %{TIME_HOUR} <= 20 ) \ +# or %{REMOTE_ADDR} =~ m/^192\.76\.162\.[0-9]+$/ +# + +# SSL Engine Options: +# Set various options for the SSL engine. +# o FakeBasicAuth: +# Translate the client X.509 into a Basic Authorisation. This means that +# the standard Auth/DBMAuth methods can be used for access control. The +# user name is the `one line' version of the client's X.509 certificate. +# Note that no password is obtained from the user. Every entry in the user +# file needs this password: `xxj31ZMTZzkVA'. +# o ExportCertData: +# This exports two additional environment variables: SSL_CLIENT_CERT and +# SSL_SERVER_CERT. These contain the PEM-encoded certificates of the +# server (always existing) and the client (only existing when client +# authentication is used). This can be used to import the certificates +# into CGI scripts. +# o StdEnvVars: +# This exports the standard SSL/TLS related `SSL_*' environment variables. +# Per default this exportation is switched off for performance reasons, +# because the extraction step is an expensive operation and is usually +# useless for serving static content. So one usually enables the +# exportation for CGI and SSI requests only. +# o StrictRequire: +# This denies access when "SSLRequireSSL" or "SSLRequire" applied even +# under a "Satisfy any" situation, i.e. when it applies access is denied +# and no other module can change it. +# o OptRenegotiate: +# This enables optimized SSL connection renegotiation handling when SSL +# directives are used in per-directory context. +#SSLOptions +FakeBasicAuth +ExportCertData +StrictRequire + + SSLOptions +StdEnvVars + + + SSLOptions +StdEnvVars + + +# SSL Protocol Adjustments: +# The safe and default but still SSL/TLS standard compliant shutdown +# approach is that mod_ssl sends the close notify alert but doesn't wait for +# the close notify alert from client. When you need a different shutdown +# approach you can use one of the following variables: +# o ssl-unclean-shutdown: +# This forces an unclean shutdown when the connection is closed, i.e. no +# SSL close notify alert is sent or allowed to be received. This violates +# the SSL/TLS standard but is needed for some brain-dead browsers. Use +# this when you receive I/O errors because of the standard approach where +# mod_ssl sends the close notify alert. +# o ssl-accurate-shutdown: +# This forces an accurate shutdown when the connection is closed, i.e. a +# SSL close notify alert is sent and mod_ssl waits for the close notify +# alert of the client. This is 100% SSL/TLS standard compliant, but in +# practice often causes hanging connections with brain-dead browsers. Use +# this only for browsers where you know that their SSL implementation +# works correctly. +# Notice: Most problems of broken clients are also related to the HTTP +# keep-alive facility, so you usually additionally want to disable +# keep-alive for those clients, too. Use variable "nokeepalive" for this. +# Similarly, one has to force some clients to use HTTP/1.0 to workaround +# their broken HTTP/1.1 implementation. Use variables "downgrade-1.0" and +# "force-response-1.0" for this. +BrowserMatch "MSIE [2-5]" \ + nokeepalive ssl-unclean-shutdown \ + downgrade-1.0 force-response-1.0 + +# Per-Server Logging: +# The home of a custom SSL log file. Use this when you want a +# compact non-error SSL logfile on a virtual host basis. +CustomLog logs/ssl_request_log \ + "%t %h %{SSL_PROTOCOL}x %{SSL_CIPHER}x \"%r\" %b" + + diff --git a/roles/koji_server/templates/etc/koji-hub/hub.conf.j2 b/roles/koji_server/templates/etc/koji-hub/hub.conf.j2 new file mode 100644 index 0000000..ec8c1a1 --- /dev/null +++ b/roles/koji_server/templates/etc/koji-hub/hub.conf.j2 @@ -0,0 +1,37 @@ +[hub] +DBName = {{ koji_db_name }} +DBUser = {{ koji_db_user }} +DBPass = {{ koji_db_password }} +DBHost = {{ koji_db_server_ip }} +DBPort = 5432 + +AuthPrincipal = {{ koji_hub_principal }} +AuthKeytab = {{ koji_hub_keytab }} +ProxyPrincipals = {{ koji_web_principal }} +HostPrincipalFormat = compile/%s@{{ koji_kerberos_realm }} + +KojiDir = /mnt/koji + +LoginCreatesUser = On +KojiWebURL = https://{{ koji_domain_name }}/koji + +# disable notifications +NotifyOnSuccess = False +DisableNotifications = True + +# +# Plugins configuration +# +PluginPath = /usr/lib/koji-hub-plugins +Plugins = sidetag_hub + +[policy] +sidetag = + all :: deny + +package_list = + # allow admins modifying package lists + has_perm admin :: allow + # allow blocking for owners in their sidetags + match action block && is_sidetag_owner :: allow + all :: deny diff --git a/roles/koji_server/templates/etc/kojira/kojira.conf.j2 b/roles/koji_server/templates/etc/kojira/kojira.conf.j2 new file mode 100644 index 0000000..88e660a --- /dev/null +++ b/roles/koji_server/templates/etc/kojira/kojira.conf.j2 @@ -0,0 +1,36 @@ +[kojira] +; The URL for the koji hub server +server=https://{{ koji_domain_name }}/kojihub + +; The directory containing the repos/ directory +topdir=/mnt/koji + +; Logfile +logfile=/var/log/kojira.log + +;the kerberos principal to use +principal = {{ koji_kojira_principal }} + +;location of the keytab +keytab = {{ koji_kojira_keytab }} + +;how soon (in seconds) to clean up expired repositories. 1 week default +;deleted_repo_lifetime = 604800 + +;how soon (in seconds) to clean up dist repositories. 1 week default here too +;dist_repo_lifetime = 604800 + +;turn on debugging statements in the log +;debug = false + +; ignored repositories according to glob. Multiple masks separated by space. +; ignore_tags = + +; Monitor external repos and trigger the appropriate Koji repo regenerations +; when they change. Note that you need to have your database set to use UTC, +; as otherwise you can end with weird behaviour. For details see +; https://pagure.io/koji/issue/2159 +check_external_repos = true + +; don't attempt to remove repos on non-default volumes +; ignore_other_volumes = false diff --git a/roles/koji_server/templates/etc/kojiweb/web.conf.j2 b/roles/koji_server/templates/etc/kojiweb/web.conf.j2 new file mode 100644 index 0000000..82c24a7 --- /dev/null +++ b/roles/koji_server/templates/etc/kojiweb/web.conf.j2 @@ -0,0 +1,18 @@ +[web] +SiteName = Inferit OS Build System +KojiHubURL = https://{{ koji_domain_name }}/kojihub +KojiFilesURL = https://{{ koji_domain_name }}/kojifiles + +WebPrincipal = {{ koji_web_principal }} +WebKeytab = {{ koji_web_keytab }} +WebCCache = /var/tmp/kojiweb.ccache + +KojiHubCA = /etc/pki/koji/koji-ca.crt + +LoginTimeout = 72 + +Secret = {{ koji_web_secret }} + +LibPath = /usr/share/koji-web/lib + +LiteralFooter = True