From ba1bd6787ac0c09279cee06c74bbaca121d1e83c Mon Sep 17 00:00:00 2001 From: Evgeni Golov Date: Fri, 19 Jun 2026 14:04:45 +0200 Subject: [PATCH] My stab at a proxy deployment --- .github/workflows/test.yml | 13 ++++- Vagrantfile | 14 +++++ .../playbooks/deploy-dev/deploy-dev.yaml | 2 +- .../playbooks/fetch-bundle/fetch-bundle.yaml | 14 +++++ .../fetch-bundle/metadata.obsah.yaml | 8 +++ src/playbooks/deploy-node/deploy-node.yaml | 33 ++++++++++++ src/playbooks/deploy-node/metadata.obsah.yaml | 20 +++++++ src/playbooks/deploy/deploy.yaml | 2 +- src/roles/certificates/tasks/main.yml | 54 ++++++++++++------- src/roles/foreman/tasks/main.yaml | 9 ---- src/roles/foreman_proxy/defaults/main.yaml | 3 +- src/roles/httpd/defaults/main.yml | 3 ++ .../httpd/templates/foreman-ssl-vhost.conf.j2 | 8 ++- src/roles/pulp/tasks/main.yaml | 9 ++++ src/vars/base.yaml | 8 +++ 15 files changed, 164 insertions(+), 36 deletions(-) create mode 100644 development/playbooks/fetch-bundle/fetch-bundle.yaml create mode 100644 development/playbooks/fetch-bundle/metadata.obsah.yaml create mode 100644 src/playbooks/deploy-node/deploy-node.yaml create mode 100644 src/playbooks/deploy-node/metadata.obsah.yaml diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index e0b758de9..d438f4969 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -104,7 +104,7 @@ jobs: run: ./setup-environment - name: Start VMs run: | - ./forge vms start --vms "quadlet client ${{ matrix.database == 'external' && 'database' || '' }}" + ./forge vms start --vms "quadlet proxy client ${{ matrix.database == 'external' && 'database' || '' }}" - name: Configure remote-database if: matrix.database == 'external' run: | @@ -116,6 +116,7 @@ jobs: if: matrix.certificate_source == 'custom_server' run: | ./forge custom-certs + ./forge custom-certs --hostname proxy.example.com - name: Setup security mode ${{ matrix.security }} if: matrix.security != 'none' run: | @@ -153,6 +154,16 @@ jobs: --add-feature remote-execution \ --add-feature bmc \ ${{ matrix.iop == 'enabled' && '--add-feature iop' || '' }} + - name: Build certs bundle for proxy + run: | + ./foremanctl certificate-bundle proxy.example.com \ + ${{ matrix.certificate_source == 'custom_server' && '--certificate-server-certificate /root/custom-certificates/certs/proxy.example.com.crt --certificate-server-key /root/custom-certificates/private/proxy.example.com.key' || '' }} + - name: Deploy proxy + run: | + ./forge fetch-bundle proxy.example.com + ./foremanctl deploy-node \ + --certificate-bundle $(pwd)/.var/lib/foremanctl/proxy.example.com.tar.gz \ + --foreman-name quadlet.example.com - name: Run tests run: | ./forge test --pytest-args="--database-mode=${{ matrix.database }}" diff --git a/Vagrantfile b/Vagrantfile index da3af4e88..32a8f683f 100644 --- a/Vagrantfile +++ b/Vagrantfile @@ -30,6 +30,20 @@ Vagrant.configure("2") do |config| end end + config.vm.define "proxy" do |override| + override.vm.box = ENV.fetch("FOREMANCTL_BASE_BOX", "centos/stream9") + if override.vm.box == "centos/stream10" + override.vm.box_url = "https://cloud.centos.org/centos/10-stream/x86_64/images/CentOS-Stream-Vagrant-10-latest.x86_64.vagrant-libvirt.box" + end + override.vm.hostname = "proxy.#{DOMAIN}" + + override.vm.provider "libvirt" do |libvirt, provider| + libvirt.memory = 10240 + libvirt.cpus = 4 + libvirt.machine_virtual_size = 30 + end + end + config.vm.define "client" do |override| override.vm.box = "centos/stream9" override.vm.hostname = "client.#{DOMAIN}" diff --git a/development/playbooks/deploy-dev/deploy-dev.yaml b/development/playbooks/deploy-dev/deploy-dev.yaml index d716d3abe..0892960ed 100644 --- a/development/playbooks/deploy-dev/deploy-dev.yaml +++ b/development/playbooks/deploy-dev/deploy-dev.yaml @@ -45,12 +45,12 @@ - role: redis - role: candlepin - role: httpd - - role: pulp - role: foreman_development vars: foreman_development_oauth_consumer_key: "{{ foreman_oauth_consumer_key }}" foreman_development_oauth_consumer_secret: "{{ foreman_oauth_consumer_secret }}" foreman_development_candlepin_oauth_secret: "{{ candlepin_oauth_secret }}" + - role: pulp - role: iop_core when: - "'iop' in enabled_features" diff --git a/development/playbooks/fetch-bundle/fetch-bundle.yaml b/development/playbooks/fetch-bundle/fetch-bundle.yaml new file mode 100644 index 000000000..144c4f08d --- /dev/null +++ b/development/playbooks/fetch-bundle/fetch-bundle.yaml @@ -0,0 +1,14 @@ +--- +- name: Fetch generated bundle from server + hosts: + - quadlet + become: true + vars_files: + - "../../../src/vars/base.yaml" + - "../../../src/vars/certificates.yml" + tasks: + - name: Fetch bundle + ansible.builtin.fetch: + src: "{{ certificates_ca_directory }}/bundles/{{ hostname }}.tar.gz" + dest: "{{ obsah_state_path }}/{{ hostname }}.tar.gz" + flat: true diff --git a/development/playbooks/fetch-bundle/metadata.obsah.yaml b/development/playbooks/fetch-bundle/metadata.obsah.yaml new file mode 100644 index 000000000..f2d2d635c --- /dev/null +++ b/development/playbooks/fetch-bundle/metadata.obsah.yaml @@ -0,0 +1,8 @@ +--- +help: | + Fetch a certificate bundle + +variables: + hostname: + parameter: hostname + help: Hostname to fetch the certificate bundle for. diff --git a/src/playbooks/deploy-node/deploy-node.yaml b/src/playbooks/deploy-node/deploy-node.yaml new file mode 100644 index 000000000..532e2d574 --- /dev/null +++ b/src/playbooks/deploy-node/deploy-node.yaml @@ -0,0 +1,33 @@ +--- +- name: Setup proxy demo machine + hosts: + - proxy + become: true + vars_files: + - "../../vars/defaults.yml" + - "../../vars/flavors/{{ flavor }}.yml" + - "../../vars/certificates.yml" + - "../../vars/images.yml" + - "../../vars/tuning/{{ tuning }}.yml" + - "../../vars/database.yml" + - "../../vars/foreman.yml" + - "../../vars/base.yaml" + roles: + - role: pre_install + - role: checks + vars: + checks_databases: "{{ all_databases }}" + - role: certificates + - role: certificate_checks + vars: + certificate_checks_certificate: "{{ server_certificate }}" + certificate_checks_key: "{{ server_key }}" + certificate_checks_ca: "{{ server_ca_certificate }}" + - role: postgresql + when: + - database_mode == 'internal' + - redis + - httpd + - pulp + - role: systemd_target + - role: foreman_proxy diff --git a/src/playbooks/deploy-node/metadata.obsah.yaml b/src/playbooks/deploy-node/metadata.obsah.yaml new file mode 100644 index 000000000..c39158d7c --- /dev/null +++ b/src/playbooks/deploy-node/metadata.obsah.yaml @@ -0,0 +1,20 @@ +--- +help: | + Install infra node + +variables: + certificates_bundle: + help: Path to the certificates bundle + type: AbsolutePath + parameter: --certificate-bundle + persist: false + foreman_name: + help: Hostname of the main Foreman instance + type: FQDN + +include: + - _database_mode + - _database_connection + - _tuning + - _flavor_features + - _pulp diff --git a/src/playbooks/deploy/deploy.yaml b/src/playbooks/deploy/deploy.yaml index 29940f6ad..0352c17f8 100644 --- a/src/playbooks/deploy/deploy.yaml +++ b/src/playbooks/deploy/deploy.yaml @@ -30,8 +30,8 @@ - redis - candlepin - httpd - - pulp - foreman + - pulp - role: systemd_target - role: iop_core when: diff --git a/src/roles/certificates/tasks/main.yml b/src/roles/certificates/tasks/main.yml index a3a5e22ff..3d15a9e88 100644 --- a/src/roles/certificates/tasks/main.yml +++ b/src/roles/certificates/tasks/main.yml @@ -29,23 +29,37 @@ state: directory mode: '0755' -- name: 'Generate CA certificate' - ansible.builtin.include_tasks: ca.yml - when: certificates_ca - -- name: Issue host certificates - ansible.builtin.include_tasks: host.yml - when: certificates_hostnames is defined - with_items: "{{ certificates_hostnames }}" - loop_control: - loop_var: certificates_hostname - -- name: Create CA bundle with internal CA and custom server CA - ansible.builtin.assemble: - src: "{{ certificates_ca_directory_certs }}" - dest: "{{ certificates_ca_directory_certs }}/ca-bundle.crt" - regexp: '(ca|server-ca)\.crt$' - mode: '0444' - when: - - certificates_source == 'custom_server' - - certificates_custom_server_certificate is defined +- name: 'Main certs' + when: certificates_bundle is not defined + block: + - name: 'Generate CA certificate' + ansible.builtin.include_tasks: ca.yml + when: certificates_ca + + - name: Issue host certificates + ansible.builtin.include_tasks: host.yml + when: certificates_hostnames is defined + with_items: "{{ certificates_hostnames }}" + loop_control: + loop_var: certificates_hostname + + - name: Create CA bundle with internal CA and custom server CA + ansible.builtin.assemble: + src: "{{ certificates_ca_directory_certs }}" + dest: "{{ certificates_ca_directory_certs }}/ca-bundle.crt" + regexp: '(ca|server-ca)\.crt$' + mode: '0444' + when: + - certificates_source == 'custom_server' + - certificates_custom_server_certificate is defined + +- name: 'Bundle certs' + when: certificates_bundle is defined + block: + - name: 'Unarchive the bundle' + ansible.builtin.unarchive: + src: "{{ certificates_bundle }}" + dest: "{{ certificates_ca_directory }}" + extra_opts: + - "--strip-components" + - "1" diff --git a/src/roles/foreman/tasks/main.yaml b/src/roles/foreman/tasks/main.yaml index 34f974bb4..481b0aee7 100644 --- a/src/roles/foreman/tasks/main.yaml +++ b/src/roles/foreman/tasks/main.yaml @@ -312,12 +312,3 @@ register: foreman_tasks_status when: - "'katello' in foreman_status.json['results']" - -- name: Configure Foreman Proxy - theforeman.foreman.smart_proxy: - name: "{{ ansible_facts['fqdn'] }}-pulp" - url: "https://{{ ansible_facts['fqdn'] }}/pulp/api/v3/smart_proxy" - server_url: "{{ foreman_url }}" - oauth1_consumer_key: "{{ foreman_oauth_consumer_key }}" - oauth1_consumer_secret: "{{ foreman_oauth_consumer_secret }}" - ca_path: "{{ foreman_ca_certificate }}" diff --git a/src/roles/foreman_proxy/defaults/main.yaml b/src/roles/foreman_proxy/defaults/main.yaml index 4791507b1..fdf7f9fb2 100644 --- a/src/roles/foreman_proxy/defaults/main.yaml +++ b/src/roles/foreman_proxy/defaults/main.yaml @@ -7,8 +7,7 @@ foreman_proxy_https_port: 8443 foreman_proxy_url: "https://{{ foreman_proxy_name }}:{{ foreman_proxy_https_port }}" # Settings -foreman_proxy_trusted_hosts: - - "{{ foreman_proxy_name }}" +foreman_proxy_trusted_hosts: "{{ undef(hint='You need to provide the list of trusted hosts') }}" foreman_proxy_base_features: - logs diff --git a/src/roles/httpd/defaults/main.yml b/src/roles/httpd/defaults/main.yml index 7f4f7b35a..29258ad4e 100644 --- a/src/roles/httpd/defaults/main.yml +++ b/src/roles/httpd/defaults/main.yml @@ -20,3 +20,6 @@ httpd_ipa_manage_sssd: true httpd_ipa_keytab: /etc/httpd/conf/http.keytab httpd_ipa_pam_service: "{{ external_authentication_pam_service | default('foreman') }}" httpd_ipa_gssapi_local_name: true + +# Pulp configuration +httpd_pulp_trusted_hosts: "{{ undef(hint='You need to provide the list of trusted hosts') }}" diff --git a/src/roles/httpd/templates/foreman-ssl-vhost.conf.j2 b/src/roles/httpd/templates/foreman-ssl-vhost.conf.j2 index dfec667b5..be95a4d7e 100644 --- a/src/roles/httpd/templates/foreman-ssl-vhost.conf.j2 +++ b/src/roles/httpd/templates/foreman-ssl-vhost.conf.j2 @@ -53,7 +53,9 @@ RequestHeader unset REMOTE_USER RequestHeader unset REMOTE-USER - RequestHeader set REMOTE-USER "admin" "expr=%{SSL_CLIENT_S_DN_CN} == '{{ ansible_facts['fqdn'] }}'" + {% for httpd_pulp_trusted_host in httpd_pulp_trusted_hosts %} + RequestHeader set REMOTE-USER "admin" "expr=%{SSL_CLIENT_S_DN_CN} == '{{ httpd_pulp_trusted_host }}'" + {% endfor %} ProxyPass {{ httpd_pulp_api_backend }}/v2/ ProxyPassReverse {{ httpd_pulp_api_backend }}/v2/ @@ -75,7 +77,9 @@ RequestHeader unset REMOTE_USER RequestHeader unset REMOTE-USER - RequestHeader set REMOTE-USER "admin" "expr=%{SSL_CLIENT_S_DN_CN} == '{{ ansible_facts['fqdn'] }}'" + {% for httpd_pulp_trusted_host in httpd_pulp_trusted_hosts %} + RequestHeader set REMOTE-USER "admin" "expr=%{SSL_CLIENT_S_DN_CN} == '{{ httpd_pulp_trusted_host }}'" + {% endfor %} ProxyPass {{ httpd_pulp_api_backend }}/pulp/api/v3 timeout=600 ProxyPassReverse {{ httpd_pulp_api_backend }}/pulp/api/v3 diff --git a/src/roles/pulp/tasks/main.yaml b/src/roles/pulp/tasks/main.yaml index a9a9a7d03..bdb6e96a5 100644 --- a/src/roles/pulp/tasks/main.yaml +++ b/src/roles/pulp/tasks/main.yaml @@ -311,3 +311,12 @@ when: - pulp_existing_workers | length > 0 - (item | regex_replace('^' + pulp_worker_container_name + '@(\\d+)\\.service$', '\\1') | int) > (pulp_worker_count | int) + +- name: Configure Foreman Proxy + theforeman.foreman.smart_proxy: + name: "{{ ansible_facts['fqdn'] }}-pulp" + url: "https://{{ ansible_facts['fqdn'] }}/pulp/api/v3/smart_proxy" + server_url: "{{ pulp_foreman_url }}" + oauth1_consumer_key: "{{ pulp_foreman_oauth_consumer_key }}" + oauth1_consumer_secret: "{{ pulp_foreman_oauth_consumer_secret }}" + ca_path: "{{ pulp_foreman_ca_certificate }}" diff --git a/src/vars/base.yaml b/src/vars/base.yaml index d39164531..5fb1f9da0 100644 --- a/src/vars/base.yaml +++ b/src/vars/base.yaml @@ -30,11 +30,17 @@ httpd_client_ca_certificate: "{{ client_ca_certificate }}" httpd_server_certificate: "{{ server_certificate }}" httpd_server_key: "{{ server_key }}" httpd_enabled_pulp_snippets: "{{ ['pypi'] if 'pulp_python' in pulp_plugins else [] }}" +httpd_pulp_trusted_hosts: + - "{{ foreman_name }}" pulp_storage_path: /var/lib/pulp pulp_content_origin: "https://{{ ansible_facts['fqdn'] }}" pulp_pulp_url: "https://{{ ansible_facts['fqdn'] }}" pulp_plugins: "{{ enabled_features | select('contains', 'content/') | map('replace', 'content/', 'pulp_') | list }}" +pulp_foreman_url: "{{ foreman_url }}" +pulp_foreman_ca_certificate: "{{ foreman_ca_certificate }}" +pulp_foreman_oauth_consumer_key: "{{ foreman_oauth_consumer_key }}" +pulp_foreman_oauth_consumer_secret: "{{ foreman_oauth_consumer_secret }}" hammer_ca_certificate: "{{ server_ca_certificate }}" hammer_plugins: "{{ enabled_features | features_to_hammer_plugins }}" @@ -45,6 +51,8 @@ foreman_proxy_foreman_server_url: "{{ foreman_url }}" foreman_proxy_foreman_ca_certificate: "{{ foreman_ca_certificate }}" foreman_proxy_oauth_consumer_key: "{{ foreman_oauth_consumer_key }}" foreman_proxy_oauth_consumer_secret: "{{ foreman_oauth_consumer_secret }}" +foreman_proxy_trusted_hosts: + - "{{ foreman_name }}" iop_core_foreman_url: "{{ foreman_url }}" iop_core_foreman_oauth_consumer_key: "{{ foreman_oauth_consumer_key }}"