From 73c02d24741721730eb8a04436b2eb4ab8d3b92c Mon Sep 17 00:00:00 2001 From: Evgeni Golov Date: Wed, 17 Dec 2025 15:26:00 +0100 Subject: [PATCH 01/14] exclude collection tests from the tarball --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 71c578db..90038ef6 100644 --- a/Makefile +++ b/Makefile @@ -6,7 +6,7 @@ dist: $(NAME)-$(VERSION).tar.gz $(NAME)-$(VERSION).tar.gz: build/collections/foremanctl git archive --prefix $(NAME)-$(VERSION)/ --output $(NAME)-$(VERSION).tar HEAD - tar --append --file $(NAME)-$(VERSION).tar --transform='s#^#$(NAME)-$(VERSION)/#' build/collections/foremanctl + tar --append --file $(NAME)-$(VERSION).tar --transform='s#^#$(NAME)-$(VERSION)/#' --exclude='build/collections/foremanctl/ansible_collections/*/*/tests/*' build/collections/foremanctl gzip $(NAME)-$(VERSION).tar build/collections/foremanctl: $(REQUIREMENTS_YML) From c3eae31f088b38ef44f4c81d00a49cf7b8710628 Mon Sep 17 00:00:00 2001 From: Adam Ruzicka Date: Thu, 20 Nov 2025 14:28:09 +0100 Subject: [PATCH 02/14] Kerberos-based authentication --- docs/parameters.md | 7 +- src/playbooks/deploy/metadata.obsah.yaml | 13 ++ src/requirements.yml | 1 + src/roles/foreman/templates/settings.yaml.j2 | 8 ++ src/roles/httpd/defaults/main.yml | 7 ++ src/roles/httpd/handlers/main.yml | 5 + src/roles/httpd/tasks/main.yml | 112 ++++++++++++++++++ src/roles/httpd/tasks/sssd.yml | 48 ++++++++ .../httpd/templates/external_auth.conf.j2 | 69 +++++++++++ src/roles/httpd/templates/pam_service.j2 | 3 + 10 files changed, 271 insertions(+), 2 deletions(-) create mode 100644 src/roles/httpd/tasks/sssd.yml create mode 100644 src/roles/httpd/templates/external_auth.conf.j2 create mode 100644 src/roles/httpd/templates/pam_service.j2 diff --git a/docs/parameters.md b/docs/parameters.md index b8746b7f..a635cbd4 100644 --- a/docs/parameters.md +++ b/docs/parameters.md @@ -86,8 +86,11 @@ There are multiple use cases from the users perspective that dictate what parame | `--certs-reset` | Parameter to reset all certificates to default | foreman-installer | No | | `--foreman-initial-location` | | | | `--foreman-initial-organization` | | | -| `--foreman-ipa-authentication` | | | -| `--foreman-ipa-authentication-api` | | | +| `--foreman-ipa-authentication` | | foreman | ipa_authentication | `--external-authentication=ipa` | +| `--foreman-ipa-authentication-api` | | foreman | ipa_authentication_api | `--external-authentication=ipa_with_api` | +| `--foreman-ipa-manage-sssd` | | foreman | ipa_manage_sssd | `--foreman-ipa-manage-sssd` | +| `--foreman-pam-service` | | foreman | pam_service | `--foreman-pam-service` | +| `--foreman-gssapi-local-name` | | foreman | gssapi_local_name | `--gssapi-local-name` | | `--foreman-keycloak` | | | | `--foreman-keycloak-app-name` | | | | `--foreman-keycloak-realm` | | | diff --git a/src/playbooks/deploy/metadata.obsah.yaml b/src/playbooks/deploy/metadata.obsah.yaml index 997aaec9..0e55ca35 100644 --- a/src/playbooks/deploy/metadata.obsah.yaml +++ b/src/playbooks/deploy/metadata.obsah.yaml @@ -11,6 +11,19 @@ variables: help: Number of workers for Puma. pulp_worker_count: help: Number of Pulp workers. Defaults to 8 or the number of CPU cores, whichever is smaller. + external_authentication: + help: External authentication method to use + choices: + - ipa + - ipa_with_api + ipa_manage_sssd: + help: Whether to manage SSSD service and configuration for IPA authentication + action: store_true + pam_service: + help: Name of the PAM service to use for IPA authentication + gssapi_local_name: + help: Whether to use the local name for GSSAPI authentication + action: store_true include: - _certificate_source diff --git a/src/requirements.yml b/src/requirements.yml index 01a19ec6..1587cb83 100644 --- a/src/requirements.yml +++ b/src/requirements.yml @@ -1,6 +1,7 @@ collections: - community.postgresql - community.crypto + - community.general - ansible.posix - name: containers.podman version: ">=1.16.4" diff --git a/src/roles/foreman/templates/settings.yaml.j2 b/src/roles/foreman/templates/settings.yaml.j2 index 321426c6..c5527cb3 100644 --- a/src/roles/foreman/templates/settings.yaml.j2 +++ b/src/roles/foreman/templates/settings.yaml.j2 @@ -20,3 +20,11 @@ :oauth_consumer_key: {{ foreman_oauth_consumer_key }} :oauth_consumer_secret: {{ foreman_oauth_consumer_secret }} {% endif %} + +{% if httpd_external_authentication in ['ipa', 'ipa_with_api'] %} +:authorize_login_delegation: true +:authorize_login_delegation_auth_source_user_autocreate: External +{% endif %} +{% if httpd_external_authentication == 'ipa_with_api' %} +:authorize_login_delegation_api: true +{% endif %} diff --git a/src/roles/httpd/defaults/main.yml b/src/roles/httpd/defaults/main.yml index d8172964..e4c16761 100644 --- a/src/roles/httpd/defaults/main.yml +++ b/src/roles/httpd/defaults/main.yml @@ -3,3 +3,10 @@ httpd_pulp_api_backend: http://localhost:24817 httpd_pulp_content_backend: http://localhost:24816 httpd_foreman_backend: http://localhost:3000 httpd_pub_dir: /var/www/html/pub + +# External authentication configuration +httpd_external_authentication: "{{ external_authentication | default(None) }}" +httpd_ipa_manage_sssd: "{{ ipa_manage_sssd | default(true) }}" +httpd_ipa_keytab: /etc/httpd/conf/http.keytab +httpd_ipa_pam_service: "{{ pam_service | default('foreman') }}" +httpd_ipa_gssapi_local_name: "{{ gssapi_local_name | default(true) }}" diff --git a/src/roles/httpd/handlers/main.yml b/src/roles/httpd/handlers/main.yml index f171e66b..8c444312 100644 --- a/src/roles/httpd/handlers/main.yml +++ b/src/roles/httpd/handlers/main.yml @@ -3,3 +3,8 @@ ansible.builtin.systemd: name: httpd state: restarted + +- name: Restart sssd + ansible.builtin.systemd: + name: sssd + state: restarted diff --git a/src/roles/httpd/tasks/main.yml b/src/roles/httpd/tasks/main.yml index 1ee492fd..d68e93f8 100644 --- a/src/roles/httpd/tasks/main.yml +++ b/src/roles/httpd/tasks/main.yml @@ -58,6 +58,118 @@ remote_src: true mode: "0644" +- name: Configure external authentication + when: httpd_external_authentication in ['ipa', 'ipa_with_api'] + block: + - name: Install Apache modules for IPA authentication + ansible.builtin.package: + name: + - mod_authnz_pam + - mod_intercept_form_submit + - mod_lookup_identity + - mod_auth_gssapi + state: present + + - name: Create directory for Apache module configuration + ansible.builtin.file: + path: /etc/httpd/conf.modules.d + state: directory + mode: "0755" + + - name: Load Apache modules for IPA authentication + ansible.builtin.copy: + dest: /etc/httpd/conf.modules.d/55-{{ item }}.conf + content: | + LoadModule {{ item }}_module modules/mod_{{ item }}.so + mode: "0644" + loop: + - authnz_pam + - intercept_form_submit + - lookup_identity + - auth_gssapi + notify: + - Restart httpd + + - name: Set SELinux booleans for IPA authentication + ansible.posix.seboolean: + name: "{{ item }}" + state: true + persistent: true + loop: + - allow_httpd_mod_auth_pam + - httpd_dbus_sssd + when: ansible_facts['selinux']['status'] == "enabled" + + - name: Configure SSSD for IPA authentication + ansible.builtin.import_tasks: sssd.yml + when: httpd_ipa_manage_sssd | bool + + - name: Create PAM service file for IPA authentication + ansible.builtin.template: + src: pam_service.j2 + dest: "/etc/pam.d/{{ httpd_ipa_pam_service }}" + mode: "0644" + + - name: Ensure keytab directory exists + ansible.builtin.file: + path: "{{ httpd_ipa_keytab | dirname }}" + state: directory + mode: "0755" + + - name: Get keytab for HTTP service + ansible.builtin.shell: + cmd: | + KRB5CCNAME=KEYRING:session:get-http-service-keytab kinit -k || true + KRB5CCNAME=KEYRING:session:get-http-service-keytab /usr/sbin/ipa-getkeytab -k {{ httpd_ipa_keytab }} -p HTTP/{{ ansible_facts['fqdn'] }} + kdestroy -c KEYRING:session:get-http-service-keytab || true + creates: "{{ httpd_ipa_keytab }}" + changed_when: false + + - name: Set keytab file permissions + ansible.builtin.file: + path: "{{ httpd_ipa_keytab }}" + owner: apache + group: apache + mode: "0600" + + - name: Create directory for Apache configuration fragments + ansible.builtin.file: + path: /etc/httpd/conf.d/05-foreman-ssl.d + state: directory + mode: "0755" + + - name: Deploy external authentication configuration + ansible.builtin.template: + src: external_auth.conf.j2 + dest: /etc/httpd/conf.d/05-foreman-ssl.d/external_auth.conf + mode: "0644" + notify: + - Restart httpd + +- name: Remove external authentication configuration if not enabled + when: httpd_external_authentication not in ['ipa', 'ipa_with_api'] + block: + - name: Remove external authentication configuration + ansible.builtin.file: + path: /etc/httpd/conf.d/05-foreman-ssl.d/external_auth.conf + state: absent + notify: + - Restart httpd + + - name: Load Apache modules for IPA authentication + ansible.builtin.copy: + dest: /etc/httpd/conf.modules.d/55-{{ item }}.conf + content: | + # LoadModule {{ item }}_module modules/mod_{{ item }}.so + mode: "0644" + loop: + - authnz_pam + - intercept_form_submit + - lookup_identity + - auth_gssapi + notify: + - Restart httpd + - name: Configure foreman vhost ansible.builtin.template: src: foreman-vhost.conf.j2 diff --git a/src/roles/httpd/tasks/sssd.yml b/src/roles/httpd/tasks/sssd.yml new file mode 100644 index 00000000..cc931c1c --- /dev/null +++ b/src/roles/httpd/tasks/sssd.yml @@ -0,0 +1,48 @@ +--- +- name: Install sssd-dbus package + ansible.builtin.package: + name: sssd-dbus + state: present + +- name: Ensure SSSD service is running and enabled + ansible.builtin.systemd: + name: sssd + state: started + enabled: true + +- name: Configure SSSD services to include ifp + community.general.ini_file: + path: /etc/sssd/sssd.conf + section: sssd + option: services + value: >- + {{ + ( + (lookup('ini', 'services section=sssd file=/etc/sssd/sssd.conf', errors='ignore') | default('', true) + | string | trim | split(',') | map('trim') | reject('equalto', '') | list) + + ['ifp'] + ) | unique | join(', ') + }} + mode: "0600" + notify: + - Restart sssd + +- name: Configure SSSD IFP allowed_uids + community.general.ini_file: + path: /etc/sssd/sssd.conf + section: ifp + option: allowed_uids + value: "root, apache" + mode: "0600" + notify: + - Restart sssd + +- name: Configure SSSD IFP user_attributes + community.general.ini_file: + path: /etc/sssd/sssd.conf + section: ifp + option: user_attributes + value: "+email, +firstname, +lastname" + mode: "0600" + notify: + - Restart sssd diff --git a/src/roles/httpd/templates/external_auth.conf.j2 b/src/roles/httpd/templates/external_auth.conf.j2 new file mode 100644 index 00000000..05e1d7d2 --- /dev/null +++ b/src/roles/httpd/templates/external_auth.conf.j2 @@ -0,0 +1,69 @@ +{% if httpd_external_authentication in ['ipa', 'ipa_with_api'] %} +# Intercept form submissions for PAM authentication + + InterceptFormPAMService {{ httpd_ipa_pam_service }} + InterceptFormLogin login[login] + InterceptFormPassword login[password] + + +# Lookup user attributes from SSSD + + LookupUserAttr email REMOTE_USER_EMAIL + LookupUserAttr firstname REMOTE_USER_FIRSTNAME + LookupUserAttr lastname REMOTE_USER_LASTNAME + LookupUserGroups REMOTE_USER_GROUPS : + LookupUserGroupsIter REMOTE_USER_GROUP + + # Set headers for proxy requests + RequestHeader set REMOTE_USER %{REMOTE_USER}e + RequestHeader set REMOTE_USER_EMAIL %{REMOTE_USER_EMAIL}e + RequestHeader set REMOTE_USER_FIRSTNAME %{REMOTE_USER_FIRSTNAME}e + RequestHeader set REMOTE_USER_LASTNAME %{REMOTE_USER_LASTNAME}e + RequestHeader set REMOTE_USER_GROUPS %{REMOTE_USER_GROUPS}e + + +# GSSAPI/Kerberos authentication for web UI + + SSLRequireSSL + AuthType GSSAPI + AuthName "GSSAPI Single Sign On Login" + GssapiCredStore keytab:{{ httpd_ipa_keytab }} + GssapiSSLonly On + GssapiLocalName {{ httpd_ipa_gssapi_local_name | ternary('On', 'Off') }} + # require valid-user + require pam-account {{ httpd_ipa_pam_service }} + ErrorDocument 401 'Kerberos authentication did not pass.' + # The following is needed as a workaround for https://bugzilla.redhat.com/show_bug.cgi?id=1020087 + ErrorDocument 500 'Kerberos authentication did not pass.' + + +# External authentication for API endpoints + + SSLRequireSSL +{% if httpd_external_authentication == 'ipa_with_api' %} + + AuthType Basic + AuthName "PAM Authentication" + AuthBasicProvider PAM + AuthPAMService {{ httpd_ipa_pam_service }} + + + AuthType GSSAPI + AuthName "GSSAPI Single Sign On Login" + GssapiCredStore keytab:{{ httpd_ipa_keytab }} + GssapiSSLonly On + GssapiLocalName {{ httpd_ipa_gssapi_local_name | ternary('On', 'Off') }} + +{% else %} + AuthType Basic + AuthName "PAM Authentication" + AuthBasicProvider PAM + AuthPAMService {{ httpd_ipa_pam_service }} +{% endif %} + require pam-account {{ httpd_ipa_pam_service }} + ErrorDocument 401 '{ "error": "External authentication did not pass." }' + # The following is needed as a workaround for https://bugzilla.redhat.com/show_bug.cgi?id=1020087 + ErrorDocument 500 '{ "error": "External authentication did not pass." }' + +{% endif %} + diff --git a/src/roles/httpd/templates/pam_service.j2 b/src/roles/httpd/templates/pam_service.j2 new file mode 100644 index 00000000..f2a6a054 --- /dev/null +++ b/src/roles/httpd/templates/pam_service.j2 @@ -0,0 +1,3 @@ +auth required pam_sss.so +account required pam_sss.so + From 0ebcb232eace403ca0592d62c1505185548876fb Mon Sep 17 00:00:00 2001 From: Adam Ruzicka Date: Fri, 21 Nov 2025 11:05:25 +0100 Subject: [PATCH 03/14] Reorganize things --- .../httpd/tasks/external_auth/cleanup.yml | 19 +++ src/roles/httpd/tasks/external_auth/ipa.yml | 85 ++++++++++++++ .../tasks/external_auth/ipa_with_api.yml | 3 + src/roles/httpd/tasks/main.yml | 110 +----------------- 4 files changed, 110 insertions(+), 107 deletions(-) create mode 100644 src/roles/httpd/tasks/external_auth/cleanup.yml create mode 100644 src/roles/httpd/tasks/external_auth/ipa.yml create mode 100644 src/roles/httpd/tasks/external_auth/ipa_with_api.yml diff --git a/src/roles/httpd/tasks/external_auth/cleanup.yml b/src/roles/httpd/tasks/external_auth/cleanup.yml new file mode 100644 index 00000000..b1913c7b --- /dev/null +++ b/src/roles/httpd/tasks/external_auth/cleanup.yml @@ -0,0 +1,19 @@ +--- +- name: Remove external authentication configuration + ansible.builtin.file: + path: /etc/httpd/conf.d/05-foreman-ssl.d/external_auth.conf + state: absent + notify: + - Restart httpd + +- name: Remove Apache module configuration files for IPA authentication + ansible.builtin.file: + path: /etc/httpd/conf.modules.d/55-{{ item }}.conf + state: absent + loop: + - authnz_pam + - intercept_form_submit + - lookup_identity + - auth_gssapi + notify: + - Restart httpd diff --git a/src/roles/httpd/tasks/external_auth/ipa.yml b/src/roles/httpd/tasks/external_auth/ipa.yml new file mode 100644 index 00000000..d3492daf --- /dev/null +++ b/src/roles/httpd/tasks/external_auth/ipa.yml @@ -0,0 +1,85 @@ +--- +- name: Install Apache modules for IPA authentication + ansible.builtin.package: + name: + - mod_authnz_pam + - mod_intercept_form_submit + - mod_lookup_identity + - mod_auth_gssapi + state: present + +- name: Create directory for Apache module configuration + ansible.builtin.file: + path: /etc/httpd/conf.modules.d + state: directory + mode: "0755" + +- name: Load Apache modules for IPA authentication + ansible.builtin.copy: + dest: /etc/httpd/conf.modules.d/55-{{ item }}.conf + content: | + LoadModule {{ item }}_module modules/mod_{{ item }}.so + mode: "0644" + loop: + - authnz_pam + - intercept_form_submit + - lookup_identity + - auth_gssapi + notify: + - Restart httpd + +- name: Set SELinux booleans for IPA authentication + ansible.posix.seboolean: + name: "{{ item }}" + state: true + persistent: true + loop: + - allow_httpd_mod_auth_pam + - httpd_dbus_sssd + when: ansible_facts['selinux']['status'] == "enabled" + +- name: Configure SSSD for IPA authentication + ansible.builtin.import_tasks: ../sssd.yml + when: httpd_ipa_manage_sssd | bool + +- name: Create PAM service file for IPA authentication + ansible.builtin.template: + src: pam_service.j2 + dest: "/etc/pam.d/{{ httpd_ipa_pam_service }}" + mode: "0644" + +- name: Ensure keytab directory exists + ansible.builtin.file: + path: "{{ httpd_ipa_keytab | dirname }}" + state: directory + mode: "0755" + +- name: Get keytab for HTTP service + ansible.builtin.shell: + cmd: | + KRB5CCNAME=KEYRING:session:get-http-service-keytab kinit -k || true + KRB5CCNAME=KEYRING:session:get-http-service-keytab /usr/sbin/ipa-getkeytab -k {{ httpd_ipa_keytab }} -p HTTP/{{ ansible_facts['fqdn'] }} + kdestroy -c KEYRING:session:get-http-service-keytab || true + creates: "{{ httpd_ipa_keytab }}" + changed_when: false + +- name: Set keytab file permissions + ansible.builtin.file: + path: "{{ httpd_ipa_keytab }}" + owner: apache + group: apache + mode: "0600" + +- name: Create directory for Apache configuration fragments + ansible.builtin.file: + path: /etc/httpd/conf.d/05-foreman-ssl.d + state: directory + mode: "0755" + +- name: Deploy external authentication configuration + ansible.builtin.template: + src: external_auth.conf.j2 + dest: /etc/httpd/conf.d/05-foreman-ssl.d/external_auth.conf + mode: "0644" + notify: + - Restart httpd diff --git a/src/roles/httpd/tasks/external_auth/ipa_with_api.yml b/src/roles/httpd/tasks/external_auth/ipa_with_api.yml new file mode 100644 index 00000000..e8106648 --- /dev/null +++ b/src/roles/httpd/tasks/external_auth/ipa_with_api.yml @@ -0,0 +1,3 @@ +--- +- name: Configure IPA authentication with API support + ansible.builtin.import_tasks: ipa.yml diff --git a/src/roles/httpd/tasks/main.yml b/src/roles/httpd/tasks/main.yml index d68e93f8..ae436413 100644 --- a/src/roles/httpd/tasks/main.yml +++ b/src/roles/httpd/tasks/main.yml @@ -59,116 +59,12 @@ mode: "0644" - name: Configure external authentication + ansible.builtin.include_tasks: "external_auth/{{ httpd_external_authentication }}.yml" when: httpd_external_authentication in ['ipa', 'ipa_with_api'] - block: - - name: Install Apache modules for IPA authentication - ansible.builtin.package: - name: - - mod_authnz_pam - - mod_intercept_form_submit - - mod_lookup_identity - - mod_auth_gssapi - state: present - - - name: Create directory for Apache module configuration - ansible.builtin.file: - path: /etc/httpd/conf.modules.d - state: directory - mode: "0755" - - - name: Load Apache modules for IPA authentication - ansible.builtin.copy: - dest: /etc/httpd/conf.modules.d/55-{{ item }}.conf - content: | - LoadModule {{ item }}_module modules/mod_{{ item }}.so - mode: "0644" - loop: - - authnz_pam - - intercept_form_submit - - lookup_identity - - auth_gssapi - notify: - - Restart httpd - - - name: Set SELinux booleans for IPA authentication - ansible.posix.seboolean: - name: "{{ item }}" - state: true - persistent: true - loop: - - allow_httpd_mod_auth_pam - - httpd_dbus_sssd - when: ansible_facts['selinux']['status'] == "enabled" - - - name: Configure SSSD for IPA authentication - ansible.builtin.import_tasks: sssd.yml - when: httpd_ipa_manage_sssd | bool - - - name: Create PAM service file for IPA authentication - ansible.builtin.template: - src: pam_service.j2 - dest: "/etc/pam.d/{{ httpd_ipa_pam_service }}" - mode: "0644" - - - name: Ensure keytab directory exists - ansible.builtin.file: - path: "{{ httpd_ipa_keytab | dirname }}" - state: directory - mode: "0755" - - - name: Get keytab for HTTP service - ansible.builtin.shell: - cmd: | - KRB5CCNAME=KEYRING:session:get-http-service-keytab kinit -k || true - KRB5CCNAME=KEYRING:session:get-http-service-keytab /usr/sbin/ipa-getkeytab -k {{ httpd_ipa_keytab }} -p HTTP/{{ ansible_facts['fqdn'] }} - kdestroy -c KEYRING:session:get-http-service-keytab || true - creates: "{{ httpd_ipa_keytab }}" - changed_when: false - - - name: Set keytab file permissions - ansible.builtin.file: - path: "{{ httpd_ipa_keytab }}" - owner: apache - group: apache - mode: "0600" - - - name: Create directory for Apache configuration fragments - ansible.builtin.file: - path: /etc/httpd/conf.d/05-foreman-ssl.d - state: directory - mode: "0755" - - - name: Deploy external authentication configuration - ansible.builtin.template: - src: external_auth.conf.j2 - dest: /etc/httpd/conf.d/05-foreman-ssl.d/external_auth.conf - mode: "0644" - notify: - - Restart httpd - name: Remove external authentication configuration if not enabled - when: httpd_external_authentication not in ['ipa', 'ipa_with_api'] - block: - - name: Remove external authentication configuration - ansible.builtin.file: - path: /etc/httpd/conf.d/05-foreman-ssl.d/external_auth.conf - state: absent - notify: - - Restart httpd - - - name: Load Apache modules for IPA authentication - ansible.builtin.copy: - dest: /etc/httpd/conf.modules.d/55-{{ item }}.conf - content: | - # LoadModule {{ item }}_module modules/mod_{{ item }}.so - mode: "0644" - loop: - - authnz_pam - - intercept_form_submit - - lookup_identity - - auth_gssapi - notify: - - Restart httpd + ansible.builtin.include_tasks: external_auth/cleanup.yml + when: httpd_external_authentication is none - name: Configure foreman vhost ansible.builtin.template: From 81c85ffbe88df072930275d9382b9a61ec27e43b Mon Sep 17 00:00:00 2001 From: Adam Ruzicka Date: Thu, 20 Nov 2025 14:53:25 +0100 Subject: [PATCH 04/14] Kerberos support in hammer --- src/roles/hammer/README.md | 1 + src/roles/hammer/defaults/main.yml | 1 + src/roles/hammer/templates/cli.modules.d-foreman.yml.j2 | 6 +++++- src/roles/hammer/templates/hammer-root.yml.j2 | 6 ++++++ 4 files changed, 13 insertions(+), 1 deletion(-) diff --git a/src/roles/hammer/README.md b/src/roles/hammer/README.md index 603a4f35..21987741 100644 --- a/src/roles/hammer/README.md +++ b/src/roles/hammer/README.md @@ -8,6 +8,7 @@ variables - `hammer_foreman_server_url`: The URL of the Foreman server to configure (default: `https://{{ ansible_facts['fqdn'] }}`) - `hammer_ca_certificate`: The CA bundle to verify the connection to Foreman. By default this is empty and Hammer uses the system store. Alternatively you can use `hammer --fetch-ca-cert` to obtain the cert of the configured Foreman server. - `hammer_packages`: Which plugin packages to install. +- `hammer_kerberos_auth_enabled`: Enable Kerberos/negotiate authentication for Hammer CLI (default: `false`). When enabled, Hammer will use session-based authentication with negotiate auth type, allowing users to authenticate using `kinit`. usage inside foremanctl ----------------------- diff --git a/src/roles/hammer/defaults/main.yml b/src/roles/hammer/defaults/main.yml index ab69142d..ea6c4b96 100644 --- a/src/roles/hammer/defaults/main.yml +++ b/src/roles/hammer/defaults/main.yml @@ -5,3 +5,4 @@ hammer_default_plugins: - foreman hammer_plugins: [] hammer_packages: "{{ (hammer_default_plugins+hammer_plugins) | map('regex_replace', '^', 'hammer-cli-plugin-') }}" +hammer_kerberos_auth_enabled: "{{ kerberos_auth_enabled | default(false) }}" diff --git a/src/roles/hammer/templates/cli.modules.d-foreman.yml.j2 b/src/roles/hammer/templates/cli.modules.d-foreman.yml.j2 index ebf50a31..dbc8ac60 100644 --- a/src/roles/hammer/templates/cli.modules.d-foreman.yml.j2 +++ b/src/roles/hammer/templates/cli.modules.d-foreman.yml.j2 @@ -8,7 +8,11 @@ # Enable using sessions # When sessions are enabled, hammer ignores credentials stored in the config file # and asks for them interactively at the begining of each session. - :use_sessions: false + :use_sessions: {{ hammer_kerberos_auth_enabled | ternary(true, false) }} +{% if hammer_kerberos_auth_enabled %} + # Default authentication type for Kerberos/negotiate authentication + :default_auth_type: 'Negotiate_Auth' +{% endif %} # Check API documentation cache status on each request :refresh_cache: false diff --git a/src/roles/hammer/templates/hammer-root.yml.j2 b/src/roles/hammer/templates/hammer-root.yml.j2 index c8f0b3e9..c1c1a0f9 100644 --- a/src/roles/hammer/templates/hammer-root.yml.j2 +++ b/src/roles/hammer/templates/hammer-root.yml.j2 @@ -2,3 +2,9 @@ # Credentials. You'll be asked for them interactively if you leave them blank here :username: '{{ foreman_initial_admin_username }}' :password: '{{ foreman_initial_admin_password }}' +{% if hammer_kerberos_auth_enabled %} + # Enable using sessions for Kerberos authentication + :use_sessions: true + # Default authentication type for Kerberos/negotiate authentication + :default_auth_type: 'Negotiate_Auth' +{% endif %} From 033256372b345f38928a13029a777aad937dd7ef Mon Sep 17 00:00:00 2001 From: Adam Ruzicka Date: Fri, 21 Nov 2025 12:52:52 +0100 Subject: [PATCH 05/14] Saner ifp service handling --- src/roles/httpd/tasks/sssd.yml | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/src/roles/httpd/tasks/sssd.yml b/src/roles/httpd/tasks/sssd.yml index cc931c1c..f401a824 100644 --- a/src/roles/httpd/tasks/sssd.yml +++ b/src/roles/httpd/tasks/sssd.yml @@ -15,15 +15,9 @@ path: /etc/sssd/sssd.conf section: sssd option: services - value: >- - {{ - ( - (lookup('ini', 'services section=sssd file=/etc/sssd/sssd.conf', errors='ignore') | default('', true) - | string | trim | split(',') | map('trim') | reject('equalto', '') | list) + - ['ifp'] - ) | unique | join(', ') - }} + value: "{{ lookup('ini', 'services section=sssd file=/etc/sssd/sssd.conf', errors='ignore') }} , ifp" mode: "0600" + when: not lookup('ini', 'services section=sssd file=/etc/sssd/sssd.conf', errors='ignore') | default('', true) | string | regex_search('ifp') | bool notify: - Restart sssd From c8f68e28a78bb18888d03e4ee21f084c083db361 Mon Sep 17 00:00:00 2001 From: Adam Ruzicka Date: Fri, 21 Nov 2025 13:55:32 +0100 Subject: [PATCH 06/14] Do not expose ipa_manage_sssd and gssapi_local_name --- docs/parameters.md | 2 -- src/playbooks/deploy/metadata.obsah.yaml | 6 ------ src/roles/httpd/defaults/main.yml | 4 ++-- 3 files changed, 2 insertions(+), 10 deletions(-) diff --git a/docs/parameters.md b/docs/parameters.md index a635cbd4..396c51ef 100644 --- a/docs/parameters.md +++ b/docs/parameters.md @@ -88,9 +88,7 @@ There are multiple use cases from the users perspective that dictate what parame | `--foreman-initial-organization` | | | | `--foreman-ipa-authentication` | | foreman | ipa_authentication | `--external-authentication=ipa` | | `--foreman-ipa-authentication-api` | | foreman | ipa_authentication_api | `--external-authentication=ipa_with_api` | -| `--foreman-ipa-manage-sssd` | | foreman | ipa_manage_sssd | `--foreman-ipa-manage-sssd` | | `--foreman-pam-service` | | foreman | pam_service | `--foreman-pam-service` | -| `--foreman-gssapi-local-name` | | foreman | gssapi_local_name | `--gssapi-local-name` | | `--foreman-keycloak` | | | | `--foreman-keycloak-app-name` | | | | `--foreman-keycloak-realm` | | | diff --git a/src/playbooks/deploy/metadata.obsah.yaml b/src/playbooks/deploy/metadata.obsah.yaml index 0e55ca35..daf1914e 100644 --- a/src/playbooks/deploy/metadata.obsah.yaml +++ b/src/playbooks/deploy/metadata.obsah.yaml @@ -16,14 +16,8 @@ variables: choices: - ipa - ipa_with_api - ipa_manage_sssd: - help: Whether to manage SSSD service and configuration for IPA authentication - action: store_true pam_service: help: Name of the PAM service to use for IPA authentication - gssapi_local_name: - help: Whether to use the local name for GSSAPI authentication - action: store_true include: - _certificate_source diff --git a/src/roles/httpd/defaults/main.yml b/src/roles/httpd/defaults/main.yml index e4c16761..591b6301 100644 --- a/src/roles/httpd/defaults/main.yml +++ b/src/roles/httpd/defaults/main.yml @@ -6,7 +6,7 @@ httpd_pub_dir: /var/www/html/pub # External authentication configuration httpd_external_authentication: "{{ external_authentication | default(None) }}" -httpd_ipa_manage_sssd: "{{ ipa_manage_sssd | default(true) }}" +httpd_ipa_manage_sssd: true httpd_ipa_keytab: /etc/httpd/conf/http.keytab httpd_ipa_pam_service: "{{ pam_service | default('foreman') }}" -httpd_ipa_gssapi_local_name: "{{ gssapi_local_name | default(true) }}" +httpd_ipa_gssapi_local_name: true From 2c204d21151b32060b0c2b2afba785ff38056723 Mon Sep 17 00:00:00 2001 From: Adam Ruzicka Date: Fri, 21 Nov 2025 14:35:25 +0100 Subject: [PATCH 07/14] Move parameters to mapped --- docs/parameters.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/parameters.md b/docs/parameters.md index 396c51ef..12215a4e 100644 --- a/docs/parameters.md +++ b/docs/parameters.md @@ -51,6 +51,9 @@ There are multiple use cases from the users perspective that dictate what parame | `--foreman-initial-admin-password` | Initial password for the admin user | `--foreman-initial-admin-password` | | `--foreman-puma-workers` | Number of workers for Puma | `--foreman-foreman-service-puma-workers` | | `--pulp-worker-count` | Number of pulp workers | `--foreman-proxy-content-pulpcore-worker-count` | +| `--foreman-ipa-authentication` | Enable configuration for external authentication via IPA for web UI | `--external-authentication=ipa` | +| `--foreman-ipa-authentication-api` | Enable configuration for external authentication via IPA for web UI and API | `--external-authentication=ipa_with_api` | +| `--pam-service` | PAM service used for host-based access control in IPA | `--foreman-pam-service` | #### Certs @@ -86,9 +89,6 @@ There are multiple use cases from the users perspective that dictate what parame | `--certs-reset` | Parameter to reset all certificates to default | foreman-installer | No | | `--foreman-initial-location` | | | | `--foreman-initial-organization` | | | -| `--foreman-ipa-authentication` | | foreman | ipa_authentication | `--external-authentication=ipa` | -| `--foreman-ipa-authentication-api` | | foreman | ipa_authentication_api | `--external-authentication=ipa_with_api` | -| `--foreman-pam-service` | | foreman | pam_service | `--foreman-pam-service` | | `--foreman-keycloak` | | | | `--foreman-keycloak-app-name` | | | | `--foreman-keycloak-realm` | | | From 9ed48d96b2a7dbbbd885f1df2fc12dbb166f49aa Mon Sep 17 00:00:00 2001 From: Adam Ruzicka Date: Fri, 21 Nov 2025 15:34:24 +0100 Subject: [PATCH 08/14] ini lookup shenanigans --- src/roles/httpd/tasks/sssd.yml | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/src/roles/httpd/tasks/sssd.yml b/src/roles/httpd/tasks/sssd.yml index f401a824..3dae192b 100644 --- a/src/roles/httpd/tasks/sssd.yml +++ b/src/roles/httpd/tasks/sssd.yml @@ -10,14 +10,27 @@ state: started enabled: true +- name: Read existing SSSD configuration + ansible.builtin.slurp: + src: /etc/sssd/sssd.conf + register: httpd_sssd_config + ignore_errors: true + +- name: Parse SSSD services configuration + ansible.builtin.set_fact: + httpd_sssd_existing_services: "{{ (httpd_sssd_config.content | default('') | b64decode | + regex_search('\\[sssd\\][\\s\\S]*?services\\s*=\\s*([^\\n]+)', '\\1', multiline=True) | + default(['']) | first) | trim }}" + when: httpd_sssd_config.content is defined + - name: Configure SSSD services to include ifp community.general.ini_file: path: /etc/sssd/sssd.conf section: sssd option: services - value: "{{ lookup('ini', 'services section=sssd file=/etc/sssd/sssd.conf', errors='ignore') }} , ifp" + value: "{{ httpd_sssd_existing_services }}{% if httpd_sssd_existing_services != '' %}, {% endif %}ifp" mode: "0600" - when: not lookup('ini', 'services section=sssd file=/etc/sssd/sssd.conf', errors='ignore') | default('', true) | string | regex_search('ifp') | bool + when: httpd_sssd_existing_services | regex_search('\\bifp\\b') != 'ifp' notify: - Restart sssd From 4912a18da2f57e7d2ab6580a92823a34e1050743 Mon Sep 17 00:00:00 2001 From: Adam Ruzicka Date: Fri, 21 Nov 2025 15:34:45 +0100 Subject: [PATCH 09/14] s/kerberos_auth_enabled/enable_kerberos_authentication --- src/roles/hammer/defaults/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/roles/hammer/defaults/main.yml b/src/roles/hammer/defaults/main.yml index ea6c4b96..690f4584 100644 --- a/src/roles/hammer/defaults/main.yml +++ b/src/roles/hammer/defaults/main.yml @@ -5,4 +5,4 @@ hammer_default_plugins: - foreman hammer_plugins: [] hammer_packages: "{{ (hammer_default_plugins+hammer_plugins) | map('regex_replace', '^', 'hammer-cli-plugin-') }}" -hammer_kerberos_auth_enabled: "{{ kerberos_auth_enabled | default(false) }}" +hammer_kerberos_auth_enabled: false From 126629b7e2219a19fd030e119d304b55fa3a588b Mon Sep 17 00:00:00 2001 From: Adam Ruzicka Date: Mon, 24 Nov 2025 11:20:12 +0100 Subject: [PATCH 10/14] Polish parameters --- docs/parameters.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/docs/parameters.md b/docs/parameters.md index 12215a4e..755edfff 100644 --- a/docs/parameters.md +++ b/docs/parameters.md @@ -51,8 +51,7 @@ There are multiple use cases from the users perspective that dictate what parame | `--foreman-initial-admin-password` | Initial password for the admin user | `--foreman-initial-admin-password` | | `--foreman-puma-workers` | Number of workers for Puma | `--foreman-foreman-service-puma-workers` | | `--pulp-worker-count` | Number of pulp workers | `--foreman-proxy-content-pulpcore-worker-count` | -| `--foreman-ipa-authentication` | Enable configuration for external authentication via IPA for web UI | `--external-authentication=ipa` | -| `--foreman-ipa-authentication-api` | Enable configuration for external authentication via IPA for web UI and API | `--external-authentication=ipa_with_api` | +| `--external-authentication={ipa,ipa_with_api}` | Enable configuration for external authentication via IPA for web UI (or webUI and API for `ipa_with_api`), expects the target machine to [be enrolled into FreeIPA/IDM](https://docs.theforeman.org/3.16/Configuring_User_Authentication/index-katello.html#enrolling-foreman-server-in-freeipa-domain) | `--foreman-ipa-authentication`
`--foreman-ipa-authentication-api` | | `--pam-service` | PAM service used for host-based access control in IPA | `--foreman-pam-service` | #### Certs From 19b310a7053c612e062cc0615a0cf848ff671d70 Mon Sep 17 00:00:00 2001 From: Adam Ruzicka Date: Thu, 4 Dec 2025 15:11:09 +0100 Subject: [PATCH 11/14] Also configure for non-ssl vhost --- src/roles/httpd/tasks/external_auth/cleanup.yml | 5 ++++- src/roles/httpd/tasks/external_auth/ipa.yml | 10 ++++++++-- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/src/roles/httpd/tasks/external_auth/cleanup.yml b/src/roles/httpd/tasks/external_auth/cleanup.yml index b1913c7b..11fb4199 100644 --- a/src/roles/httpd/tasks/external_auth/cleanup.yml +++ b/src/roles/httpd/tasks/external_auth/cleanup.yml @@ -1,10 +1,13 @@ --- - name: Remove external authentication configuration ansible.builtin.file: - path: /etc/httpd/conf.d/05-foreman-ssl.d/external_auth.conf + path: "/etc/httpd/conf.d/05-{{ item }}.d/external_auth.conf" state: absent notify: - Restart httpd + loop: + - foreman + - foreman-ssl - name: Remove Apache module configuration files for IPA authentication ansible.builtin.file: diff --git a/src/roles/httpd/tasks/external_auth/ipa.yml b/src/roles/httpd/tasks/external_auth/ipa.yml index d3492daf..a732263f 100644 --- a/src/roles/httpd/tasks/external_auth/ipa.yml +++ b/src/roles/httpd/tasks/external_auth/ipa.yml @@ -72,14 +72,20 @@ - name: Create directory for Apache configuration fragments ansible.builtin.file: - path: /etc/httpd/conf.d/05-foreman-ssl.d + path: /etc/httpd/conf.d/05-{{ item }}.d state: directory mode: "0755" + loop: + - foreman + - foreman-ssl - name: Deploy external authentication configuration ansible.builtin.template: src: external_auth.conf.j2 - dest: /etc/httpd/conf.d/05-foreman-ssl.d/external_auth.conf + dest: /etc/httpd/conf.d/05-{{ item }}.d/external_auth.conf mode: "0644" notify: - Restart httpd + loop: + - foreman + - foreman-ssl From 735a3ce2966044f31739274181c9573742b3bb4e Mon Sep 17 00:00:00 2001 From: Adam Ruzicka Date: Wed, 17 Dec 2025 14:00:45 +0100 Subject: [PATCH 12/14] Derive hammer kerberos settings from external authentication --- src/roles/hammer/defaults/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/roles/hammer/defaults/main.yml b/src/roles/hammer/defaults/main.yml index 690f4584..98171f78 100644 --- a/src/roles/hammer/defaults/main.yml +++ b/src/roles/hammer/defaults/main.yml @@ -5,4 +5,4 @@ hammer_default_plugins: - foreman hammer_plugins: [] hammer_packages: "{{ (hammer_default_plugins+hammer_plugins) | map('regex_replace', '^', 'hammer-cli-plugin-') }}" -hammer_kerberos_auth_enabled: false +hammer_kerberos_auth_enabled: "{{ external_authentication is defined and external_authentication == 'ipa_with_api' }}" From 4979f6ca984168eb37bb1176ee691fa3262f3495 Mon Sep 17 00:00:00 2001 From: Adam Ruzicka Date: Wed, 17 Dec 2025 14:40:43 +0100 Subject: [PATCH 13/14] Rename pam service option --- docs/parameters.md | 2 +- src/playbooks/deploy/metadata.obsah.yaml | 2 +- src/roles/httpd/defaults/main.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/parameters.md b/docs/parameters.md index 755edfff..0ebd0453 100644 --- a/docs/parameters.md +++ b/docs/parameters.md @@ -52,7 +52,7 @@ There are multiple use cases from the users perspective that dictate what parame | `--foreman-puma-workers` | Number of workers for Puma | `--foreman-foreman-service-puma-workers` | | `--pulp-worker-count` | Number of pulp workers | `--foreman-proxy-content-pulpcore-worker-count` | | `--external-authentication={ipa,ipa_with_api}` | Enable configuration for external authentication via IPA for web UI (or webUI and API for `ipa_with_api`), expects the target machine to [be enrolled into FreeIPA/IDM](https://docs.theforeman.org/3.16/Configuring_User_Authentication/index-katello.html#enrolling-foreman-server-in-freeipa-domain) | `--foreman-ipa-authentication`
`--foreman-ipa-authentication-api` | -| `--pam-service` | PAM service used for host-based access control in IPA | `--foreman-pam-service` | +| `--external-authentication-pam-service` | PAM service used for host-based access control in IPA | `--foreman-pam-service` | #### Certs diff --git a/src/playbooks/deploy/metadata.obsah.yaml b/src/playbooks/deploy/metadata.obsah.yaml index daf1914e..f36a827f 100644 --- a/src/playbooks/deploy/metadata.obsah.yaml +++ b/src/playbooks/deploy/metadata.obsah.yaml @@ -16,7 +16,7 @@ variables: choices: - ipa - ipa_with_api - pam_service: + external_authentication_pam_service: help: Name of the PAM service to use for IPA authentication include: diff --git a/src/roles/httpd/defaults/main.yml b/src/roles/httpd/defaults/main.yml index 591b6301..19961685 100644 --- a/src/roles/httpd/defaults/main.yml +++ b/src/roles/httpd/defaults/main.yml @@ -8,5 +8,5 @@ httpd_pub_dir: /var/www/html/pub httpd_external_authentication: "{{ external_authentication | default(None) }}" httpd_ipa_manage_sssd: true httpd_ipa_keytab: /etc/httpd/conf/http.keytab -httpd_ipa_pam_service: "{{ pam_service | default('foreman') }}" +httpd_ipa_pam_service: "{{ external_authentication_pam_service | default('foreman') }}" httpd_ipa_gssapi_local_name: true From 9b015c69aa482ad224d4a178c9ad1dec5056ce3e Mon Sep 17 00:00:00 2001 From: Adam Ruzicka Date: Thu, 18 Dec 2025 16:09:18 +0100 Subject: [PATCH 14/14] Some notes on external auth --- docs/deployment.md | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/docs/deployment.md b/docs/deployment.md index 3efd1f8f..0aebfbbd 100644 --- a/docs/deployment.md +++ b/docs/deployment.md @@ -213,3 +213,21 @@ For secure connections with certificate verification: --candlepin-database-password=secure_candlepin_password \ --pulp-database-password=secure_pulp_password ``` + +## External authentication support + +The deployment utility supports setting up necessary services to allow leveraging kerberos for user authentication if the host machine is enrolled in a FreeIPA/IDM or Active Directory realm. + +### Prerequisites + +Before configuring external authentication support, ensure the following requirements are met: +- the host machine is enrolled in FreeIPA/IDM or Active Directory realm +- a keytab for the Kerberos service principal is available at the host machine + +### External Database Configuration Parameters + +The external authentication configuration is managed through `foremanctl` command line parameters: +- `--external-authentication`: Set to `ipa` to enable kerberos authentication in WebUI, set to `ipa_with_api` to enable kerberos authentication in WebUI, API and hammer CLI +- `--external-authentication-pam-server`: PAM service name to use when authenticating users, can be changed in case a specific FreeIPA/IDM HBAC service should be used (default: `foreman`) + +If `hammer` feature is enabled and `--external-authentication` is set to `ipa_with_api`, `hammer` will be configured to use negotiate-based authentication.