From 0b6146ad6f7be9ca0ed2ddd2acaa98dc85d72860 Mon Sep 17 00:00:00 2001 From: Ewoud Kohl van Wijngaarden Date: Thu, 13 Mar 2025 18:53:57 +0100 Subject: [PATCH 1/7] Use systemd socket activation for Foreman --- src/roles/foreman/defaults/main.yaml | 1 + src/roles/foreman/tasks/main.yaml | 8 ++++++++ src/roles/foreman/templates/foreman.socket.j2 | 8 ++++++++ 3 files changed, 17 insertions(+) create mode 100644 src/roles/foreman/templates/foreman.socket.j2 diff --git a/src/roles/foreman/defaults/main.yaml b/src/roles/foreman/defaults/main.yaml index 2069b796b..cdbc12ae7 100644 --- a/src/roles/foreman/defaults/main.yaml +++ b/src/roles/foreman/defaults/main.yaml @@ -12,6 +12,7 @@ foreman_database_ssl_ca: # noqa: no-empty-defaults foreman_database_ssl_ca_path: /etc/foreman/db-ca.crt foreman_name: "{{ ansible_facts['fqdn'] }}" +foreman_listen_stream: localhost:3000 foreman_url: "http://{{ ansible_facts['fqdn'] }}:3000" foreman_aliases: [] diff --git a/src/roles/foreman/tasks/main.yaml b/src/roles/foreman/tasks/main.yaml index 00eab74a7..d31fa5ba8 100644 --- a/src/roles/foreman/tasks/main.yaml +++ b/src/roles/foreman/tasks/main.yaml @@ -100,6 +100,12 @@ - Restart foreman - Restart dynflow-sidekiq@ +- name: Deploy Foreman socket + ansible.builtin.template: + src: foreman.socket.j2 + dest: /etc/systemd/system/foreman.socket + mode: '0644' + - name: Deploy Foreman Container containers.podman.podman_container: name: "foreman" @@ -130,6 +136,8 @@ FOREMAN_ENABLED_PLUGINS: "{{ foreman_plugins | join(' ') }}" quadlet_options: - | + [Unit] + Requires=foreman.socket [Install] WantedBy=default.target foreman.target [Unit] diff --git a/src/roles/foreman/templates/foreman.socket.j2 b/src/roles/foreman/templates/foreman.socket.j2 new file mode 100644 index 000000000..b40cc96f4 --- /dev/null +++ b/src/roles/foreman/templates/foreman.socket.j2 @@ -0,0 +1,8 @@ +[Unit] +Description=Foreman socket + +[Socket] +ListenStream={{ foreman_listen_stream }} + +[Install] +WantedBy=sockets.target From 46facb13f4b8db9df89e1351995246f9771a0907 Mon Sep 17 00:00:00 2001 From: Ewoud Kohl van Wijngaarden Date: Tue, 11 Mar 2025 20:50:58 +0100 Subject: [PATCH 2/7] Use unix socket for httpd -> Foreman communication --- src/roles/foreman/templates/foreman.socket.j2 | 6 ++++++ src/roles/httpd/tasks/main.yml | 7 +++++++ src/vars/base.yaml | 3 +++ tests/foreman_test.py | 13 ++++++------- 4 files changed, 22 insertions(+), 7 deletions(-) diff --git a/src/roles/foreman/templates/foreman.socket.j2 b/src/roles/foreman/templates/foreman.socket.j2 index b40cc96f4..a2b1d2ddc 100644 --- a/src/roles/foreman/templates/foreman.socket.j2 +++ b/src/roles/foreman/templates/foreman.socket.j2 @@ -3,6 +3,12 @@ Description=Foreman socket [Socket] ListenStream={{ foreman_listen_stream }} +SocketUser=apache +SocketMode=0600 + +NoDelay=false +ReusePort=true +Backlog=1024 [Install] WantedBy=sockets.target diff --git a/src/roles/httpd/tasks/main.yml b/src/roles/httpd/tasks/main.yml index 1c79c4d6b..517830ce6 100644 --- a/src/roles/httpd/tasks/main.yml +++ b/src/roles/httpd/tasks/main.yml @@ -13,6 +13,13 @@ persistent: true when: ansible_facts['selinux']['status'] == "enabled" +# TODO: probably not the right boolean +- name: Set daemons_enable_cluster_mode so Apache can connect to unix sockets + ansible.posix.seboolean: + name: daemons_enable_cluster_mode + state: true + persistent: true + - name: Disable welcome page ansible.builtin.file: path: /etc/httpd/conf.d/welcome.conf diff --git a/src/vars/base.yaml b/src/vars/base.yaml index ed3023aa9..947f91c11 100644 --- a/src/vars/base.yaml +++ b/src/vars/base.yaml @@ -23,6 +23,9 @@ foreman_plugins: "{{ enabled_features | features_to_foreman_plugins }}" foreman_name: "{{ ansible_facts['fqdn'] }}" foreman_url: "https://{{ foreman_name }}" +foreman_listen_stream: /run/httpd.foreman.sock +httpd_foreman_backend: "unix://{{ foreman_listen_stream }}|http://%{HTTP_HOST}" + httpd_server_ca_certificate: "{{ server_ca_certificate }}" httpd_client_ca_certificate: "{{ client_ca_certificate }}" httpd_server_certificate: "{{ server_certificate }}" diff --git a/tests/foreman_test.py b/tests/foreman_test.py index ad808d052..5d939a7f7 100644 --- a/tests/foreman_test.py +++ b/tests/foreman_test.py @@ -5,7 +5,7 @@ pytestmark = pytest.mark.feature('foreman') FOREMAN_HOST = 'localhost' -FOREMAN_PORT = 3000 +FOREMAN_SOCKET = '/run/httpd.foreman.sock' RECURRING_INSTANCES = [ "hourly", @@ -16,8 +16,8 @@ @pytest.fixture(scope="module") -def foreman_status_curl(server, server_fqdn): - return server.run(f"curl --header 'X-FORWARDED-PROTO: https' --silent --write-out '%{{stderr}}%{{http_code}}' http://{server_fqdn}:{FOREMAN_PORT}/api/v2/ping") +def foreman_status_curl(server): + return server.run(f"curl --header 'X-FORWARDED-PROTO: https' --silent --write-out '%{{stderr}}%{{http_code}}' --unix-socket {FOREMAN_SOCKET} http://{FOREMAN_HOST}/api/v2/ping") @pytest.fixture(scope="module") @@ -30,9 +30,8 @@ def test_foreman_service(server): assert foreman.is_running -def test_foreman_port(server): - foreman = server.addr(FOREMAN_HOST) - assert foreman.port(FOREMAN_PORT).is_reachable +def test_foreman_socket(server): + assert server.socket(f"unix://{FOREMAN_SOCKET}").is_listening def test_foreman_status(foreman_status_curl): @@ -99,6 +98,6 @@ def test_foreman_domain_in_mail_settings(foremanapi, server_fqdn, setting): def test_foreman_host_injection(server): - cmd = server.run(f"curl --header 'X-FORWARDED-PROTO: https' --silent --write-out '%{{stderr}}%{{http_code}}' --resolve evil.hackers.test:{FOREMAN_PORT}:127.0.0.1 http://evil.hackers.test:{FOREMAN_PORT}/api/v2/ping") + cmd = server.run(f"curl --header 'X-FORWARDED-PROTO: https' --silent --write-out '%{{stderr}}%{{http_code}}' --unix-socket {FOREMAN_SOCKET} --header 'Host: evil.hackers.test' http://{FOREMAN_HOST}/api/v2/ping") assert cmd.succeeded assert cmd.stderr == '403' From 8069c7222b3bcc91eb1fee9a59a8cfdd7e5a7611 Mon Sep 17 00:00:00 2001 From: Gaurav Talreja Date: Tue, 30 Jun 2026 05:40:29 +0530 Subject: [PATCH 3/7] Fix SELinux configuration for httpd unix socket support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add missing `when` guard for daemons_enable_cluster_mode so it doesn't fail on systems with SELinux disabled - Remove httpd_can_network_connect boolean — no longer needed since all backends (Foreman, Pulp API, Pulp Content) now use unix sockets instead of TCP - Remove uncertain TODO comment — the boolean works with /run/httpd.* socket paths that get httpd_var_run_t context Signed-off-by: Gaurav Talreja --- src/roles/httpd/tasks/main.yml | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/src/roles/httpd/tasks/main.yml b/src/roles/httpd/tasks/main.yml index 517830ce6..e88b6f5d5 100644 --- a/src/roles/httpd/tasks/main.yml +++ b/src/roles/httpd/tasks/main.yml @@ -6,19 +6,12 @@ - mod_ssl state: present -- name: Set httpd_can_network_connect so Apache can connect to Puma and Gunicorn - ansible.posix.seboolean: - name: httpd_can_network_connect - state: true - persistent: true - when: ansible_facts['selinux']['status'] == "enabled" - -# TODO: probably not the right boolean - name: Set daemons_enable_cluster_mode so Apache can connect to unix sockets ansible.posix.seboolean: name: daemons_enable_cluster_mode state: true persistent: true + when: ansible_facts['selinux']['status'] == "enabled" - name: Disable welcome page ansible.builtin.file: From 3b5c8c737c07dbf0c48ec4d0fd29680405920394 Mon Sep 17 00:00:00 2001 From: Gaurav Talreja Date: Tue, 30 Jun 2026 05:41:39 +0530 Subject: [PATCH 4/7] Use unix socket for httpd -> Pulp communication Same approach as Foreman: replace TCP proxy backends with unix sockets to eliminate IPv4/IPv6 address mismatch on IPv6-only hosts. - Add systemd socket units for pulp-api and pulp-content - Override container commands to bind Gunicorn to unix sockets at /run/httpd.pulp-api.sock and /run/httpd.pulp-content.sock - Mount /run into Pulp containers for socket file visibility - Update httpd backend defaults in base.yaml - Update tests to verify socket connectivity instead of TCP ports Signed-off-by: Gaurav Talreja --- src/roles/pulp/defaults/main.yaml | 3 ++ src/roles/pulp/tasks/main.yaml | 46 ++++++++++++++++++++++++++++--- src/vars/base.yaml | 5 ++++ tests/pulp_test.py | 16 +++++------ 4 files changed, 57 insertions(+), 13 deletions(-) diff --git a/src/roles/pulp/defaults/main.yaml b/src/roles/pulp/defaults/main.yaml index e898dcabf..c437b229c 100644 --- a/src/roles/pulp/defaults/main.yaml +++ b/src/roles/pulp/defaults/main.yaml @@ -20,6 +20,9 @@ pulp_api_container_name: pulp-api pulp_content_container_name: pulp-content pulp_worker_container_name: pulp-worker +pulp_api_listen_stream: localhost:24817 +pulp_content_listen_stream: localhost:24816 + pulp_content_origin: "http://{{ ansible_facts['fqdn'] }}:24816" pulp_pulp_url: "http://{{ ansible_facts['fqdn'] }}:24817" diff --git a/src/roles/pulp/tasks/main.yaml b/src/roles/pulp/tasks/main.yaml index c39e955fa..3e1d9ccd2 100644 --- a/src/roles/pulp/tasks/main.yaml +++ b/src/roles/pulp/tasks/main.yaml @@ -92,16 +92,37 @@ - Restart pulp-content - Restart pulp-worker +- name: Deploy Pulp API socket + ansible.builtin.template: + src: pulp-api.socket.j2 + dest: /etc/systemd/system/pulp-api.socket + mode: '0644' + +# TODO: The --bind argument is passed here to override pulpcore-api's default +# bind address (0.0.0.0:24817) with a unix socket. This duplicates arguments +# from the container's pulp-api entry point script, which is fragile if the +# image changes. The proper fix is to add a PULP_API_BIND environment variable +# to the pulp-oci-images container (like PULP_API_WORKERS already works), +# then set it via env: instead of overriding the command. +# See: https://github.com/theforeman/pulp-oci-images - name: Deploy Pulp API Container containers.podman.podman_container: name: "{{ pulp_api_container_name }}" image: pulp.image state: quadlet sdnotify: true - command: pulp-api + command: >- + /usr/bin/pulpcore-api + --bind unix:{{ pulp_api_listen_stream }} + --timeout 90 + --workers {{ pulp_api_service_worker_count }} + --max-requests 800 + --max-requests-jitter 100 + --access-logfile - + --access-logformat 'pulp [%({correlation-id}o)s]: %(h)s %(l)s %(u)s %(t)s "%(r)s" %(s)s %(b)s "%(f)s" "%(a)s"' network: host hostname: "pulp-api.{{ ansible_facts['hostname'] }}.local" - volumes: "{{ pulp_volumes }}" + volumes: "{{ pulp_volumes + ['/run:/run:rw'] }}" security_opt: - "label=disable" secrets: @@ -112,6 +133,8 @@ env: "{{ pulp_settings_env }}" quadlet_options: - | + [Unit] + Requires=pulp-api.socket [Install] WantedBy=default.target foreman.target [Unit] @@ -123,16 +146,29 @@ RestartSec=3 notify: Restart pulp-api +- name: Deploy Pulp Content socket + ansible.builtin.template: + src: pulp-content.socket.j2 + dest: /etc/systemd/system/pulp-content.socket + mode: '0644' + +# TODO: Same as pulp-api above — add PULP_CONTENT_BIND to pulp-oci-images +# and use env: instead of overriding the command. - name: Deploy Pulp Content Container containers.podman.podman_container: name: "{{ pulp_content_container_name }}" image: pulp.image state: quadlet sdnotify: true - command: pulp-content + command: >- + /usr/bin/pulpcore-content + --bind unix:{{ pulp_content_listen_stream }} + --timeout 90 + --workers {{ pulp_content_service_worker_count }} + --access-logfile - network: host hostname: "pulp-content.{{ ansible_facts['hostname'] }}.local" - volumes: "{{ pulp_volumes }}" + volumes: "{{ pulp_volumes + ['/run:/run:rw'] }}" security_opt: - "label=disable" secrets: @@ -143,6 +179,8 @@ env: "{{ pulp_settings_env }}" quadlet_options: - | + [Unit] + Requires=pulp-content.socket [Install] WantedBy=default.target foreman.target [Unit] diff --git a/src/vars/base.yaml b/src/vars/base.yaml index 947f91c11..3357d4bfb 100644 --- a/src/vars/base.yaml +++ b/src/vars/base.yaml @@ -26,6 +26,11 @@ foreman_url: "https://{{ foreman_name }}" foreman_listen_stream: /run/httpd.foreman.sock httpd_foreman_backend: "unix://{{ foreman_listen_stream }}|http://%{HTTP_HOST}" +pulp_api_listen_stream: /run/httpd.pulp-api.sock +pulp_content_listen_stream: /run/httpd.pulp-content.sock +httpd_pulp_api_backend: "unix://{{ pulp_api_listen_stream }}|http://%{HTTP_HOST}" +httpd_pulp_content_backend: "unix://{{ pulp_content_listen_stream }}|http://%{HTTP_HOST}" + httpd_server_ca_certificate: "{{ server_ca_certificate }}" httpd_client_ca_certificate: "{{ client_ca_certificate }}" httpd_server_certificate: "{{ server_certificate }}" diff --git a/tests/pulp_test.py b/tests/pulp_test.py index 8e1f7fc46..8859d0dbd 100644 --- a/tests/pulp_test.py +++ b/tests/pulp_test.py @@ -5,8 +5,8 @@ import yaml PULP_HOST = 'localhost' -PULP_API_PORT = 24817 -PULP_CONTENT_PORT = 24816 +PULP_API_SOCKET = '/run/httpd.pulp-api.sock' +PULP_CONTENT_SOCKET = '/run/httpd.pulp-content.sock' def load_pulp_paths_from_parameters(): @@ -25,7 +25,7 @@ def load_pulp_paths_from_parameters(): @pytest.fixture(scope="module") def pulp_status_curl(server): - return server.run(f"curl -k -s -w '%{{stderr}}%{{http_code}}' http://{PULP_HOST}:{PULP_API_PORT}/pulp/api/v3/status/") + return server.run(f"curl -k -s -w '%{{stderr}}%{{http_code}}' --unix-socket {PULP_API_SOCKET} http://{PULP_HOST}/pulp/api/v3/status/") @pytest.fixture(scope="module") @@ -58,14 +58,12 @@ def test_pulp_worker_services(server): assert worker.is_running -def test_pulp_api_port(server): - pulp_api = server.addr(PULP_HOST) - assert pulp_api.port(PULP_API_PORT).is_reachable +def test_pulp_api_socket(server): + assert server.socket(f"unix://{PULP_API_SOCKET}").is_listening -def test_pulp_content_port(server): - pulp_content = server.addr(PULP_HOST) - assert pulp_content.port(PULP_CONTENT_PORT).is_reachable +def test_pulp_content_socket(server): + assert server.socket(f"unix://{PULP_CONTENT_SOCKET}").is_listening def test_pulp_status(pulp_status_curl): From 1d354a826aad74661f254067ae95313ab64500df Mon Sep 17 00:00:00 2001 From: Gaurav Talreja Date: Tue, 7 Jul 2026 05:28:34 +0530 Subject: [PATCH 5/7] Address review feedback for unix socket support - Use systemd socket activation for Pulp instead of --bind, remove /run volume mount (fd passing, not file access) - Add pulp-api.socket and pulp-content.socket templates - Match upstream foreman.socket: NoDelay=true (Puma default), and, Backlog=4294967295 (default on EL10/v254+, needed for EL9/v252) - Rebased and replaced %{HTTP_HOST} with static hostnames (foreman, pulpcore-api, pulpcore-content) Signed-off-by: Gaurav Talreja --- src/roles/foreman/templates/foreman.socket.j2 | 5 ++-- src/roles/pulp/tasks/main.yaml | 30 +++---------------- src/roles/pulp/templates/pulp-api.socket.j2 | 15 ++++++++++ .../pulp/templates/pulp-content.socket.j2 | 15 ++++++++++ src/vars/base.yaml | 6 ++-- tests/foreman_test.py | 7 ++--- tests/pulp_test.py | 5 ++-- 7 files changed, 45 insertions(+), 38 deletions(-) create mode 100644 src/roles/pulp/templates/pulp-api.socket.j2 create mode 100644 src/roles/pulp/templates/pulp-content.socket.j2 diff --git a/src/roles/foreman/templates/foreman.socket.j2 b/src/roles/foreman/templates/foreman.socket.j2 index a2b1d2ddc..7e58319f4 100644 --- a/src/roles/foreman/templates/foreman.socket.j2 +++ b/src/roles/foreman/templates/foreman.socket.j2 @@ -6,9 +6,10 @@ ListenStream={{ foreman_listen_stream }} SocketUser=apache SocketMode=0600 -NoDelay=false +NoDelay=true ReusePort=true -Backlog=1024 +# Default on EL10 (v254+), needed explicitly for EL9 (v252) +Backlog=4294967295 [Install] WantedBy=sockets.target diff --git a/src/roles/pulp/tasks/main.yaml b/src/roles/pulp/tasks/main.yaml index 3e1d9ccd2..a2430b990 100644 --- a/src/roles/pulp/tasks/main.yaml +++ b/src/roles/pulp/tasks/main.yaml @@ -98,31 +98,16 @@ dest: /etc/systemd/system/pulp-api.socket mode: '0644' -# TODO: The --bind argument is passed here to override pulpcore-api's default -# bind address (0.0.0.0:24817) with a unix socket. This duplicates arguments -# from the container's pulp-api entry point script, which is fragile if the -# image changes. The proper fix is to add a PULP_API_BIND environment variable -# to the pulp-oci-images container (like PULP_API_WORKERS already works), -# then set it via env: instead of overriding the command. -# See: https://github.com/theforeman/pulp-oci-images - name: Deploy Pulp API Container containers.podman.podman_container: name: "{{ pulp_api_container_name }}" image: pulp.image state: quadlet sdnotify: true - command: >- - /usr/bin/pulpcore-api - --bind unix:{{ pulp_api_listen_stream }} - --timeout 90 - --workers {{ pulp_api_service_worker_count }} - --max-requests 800 - --max-requests-jitter 100 - --access-logfile - - --access-logformat 'pulp [%({correlation-id}o)s]: %(h)s %(l)s %(u)s %(t)s "%(r)s" %(s)s %(b)s "%(f)s" "%(a)s"' + command: pulp-api network: host hostname: "pulp-api.{{ ansible_facts['hostname'] }}.local" - volumes: "{{ pulp_volumes + ['/run:/run:rw'] }}" + volumes: "{{ pulp_volumes }}" security_opt: - "label=disable" secrets: @@ -152,23 +137,16 @@ dest: /etc/systemd/system/pulp-content.socket mode: '0644' -# TODO: Same as pulp-api above — add PULP_CONTENT_BIND to pulp-oci-images -# and use env: instead of overriding the command. - name: Deploy Pulp Content Container containers.podman.podman_container: name: "{{ pulp_content_container_name }}" image: pulp.image state: quadlet sdnotify: true - command: >- - /usr/bin/pulpcore-content - --bind unix:{{ pulp_content_listen_stream }} - --timeout 90 - --workers {{ pulp_content_service_worker_count }} - --access-logfile - + command: pulp-content network: host hostname: "pulp-content.{{ ansible_facts['hostname'] }}.local" - volumes: "{{ pulp_volumes + ['/run:/run:rw'] }}" + volumes: "{{ pulp_volumes }}" security_opt: - "label=disable" secrets: diff --git a/src/roles/pulp/templates/pulp-api.socket.j2 b/src/roles/pulp/templates/pulp-api.socket.j2 new file mode 100644 index 000000000..ce0bab132 --- /dev/null +++ b/src/roles/pulp/templates/pulp-api.socket.j2 @@ -0,0 +1,15 @@ +[Unit] +Description=Pulp API socket + +[Socket] +ListenStream={{ pulp_api_listen_stream }} +SocketUser=apache +SocketMode=0600 + +NoDelay=false +ReusePort=true +# Default on EL10 (v254+), needed explicitly for EL9 (v252) +Backlog=4294967295 + +[Install] +WantedBy=sockets.target diff --git a/src/roles/pulp/templates/pulp-content.socket.j2 b/src/roles/pulp/templates/pulp-content.socket.j2 new file mode 100644 index 000000000..7d1210854 --- /dev/null +++ b/src/roles/pulp/templates/pulp-content.socket.j2 @@ -0,0 +1,15 @@ +[Unit] +Description=Pulp Content socket + +[Socket] +ListenStream={{ pulp_content_listen_stream }} +SocketUser=apache +SocketMode=0600 + +NoDelay=false +ReusePort=true +# Default on EL10 (v254+), needed explicitly for EL9 (v252) +Backlog=4294967295 + +[Install] +WantedBy=sockets.target diff --git a/src/vars/base.yaml b/src/vars/base.yaml index 3357d4bfb..2d6f4d4d1 100644 --- a/src/vars/base.yaml +++ b/src/vars/base.yaml @@ -24,12 +24,12 @@ foreman_name: "{{ ansible_facts['fqdn'] }}" foreman_url: "https://{{ foreman_name }}" foreman_listen_stream: /run/httpd.foreman.sock -httpd_foreman_backend: "unix://{{ foreman_listen_stream }}|http://%{HTTP_HOST}" +httpd_foreman_backend: "unix://{{ foreman_listen_stream }}|http://foreman" pulp_api_listen_stream: /run/httpd.pulp-api.sock pulp_content_listen_stream: /run/httpd.pulp-content.sock -httpd_pulp_api_backend: "unix://{{ pulp_api_listen_stream }}|http://%{HTTP_HOST}" -httpd_pulp_content_backend: "unix://{{ pulp_content_listen_stream }}|http://%{HTTP_HOST}" +httpd_pulp_api_backend: "unix://{{ pulp_api_listen_stream }}|http://pulpcore-api" +httpd_pulp_content_backend: "unix://{{ pulp_content_listen_stream }}|http://pulpcore-content" httpd_server_ca_certificate: "{{ server_ca_certificate }}" httpd_client_ca_certificate: "{{ client_ca_certificate }}" diff --git a/tests/foreman_test.py b/tests/foreman_test.py index 5d939a7f7..c5140227a 100644 --- a/tests/foreman_test.py +++ b/tests/foreman_test.py @@ -4,7 +4,6 @@ pytestmark = pytest.mark.feature('foreman') -FOREMAN_HOST = 'localhost' FOREMAN_SOCKET = '/run/httpd.foreman.sock' RECURRING_INSTANCES = [ @@ -16,8 +15,8 @@ @pytest.fixture(scope="module") -def foreman_status_curl(server): - return server.run(f"curl --header 'X-FORWARDED-PROTO: https' --silent --write-out '%{{stderr}}%{{http_code}}' --unix-socket {FOREMAN_SOCKET} http://{FOREMAN_HOST}/api/v2/ping") +def foreman_status_curl(server, server_fqdn): + return server.run(f"curl --header 'X-FORWARDED-PROTO: https' --silent --write-out '%{{stderr}}%{{http_code}}' --unix-socket {FOREMAN_SOCKET} http://{server_fqdn}/api/v2/ping") @pytest.fixture(scope="module") @@ -98,6 +97,6 @@ def test_foreman_domain_in_mail_settings(foremanapi, server_fqdn, setting): def test_foreman_host_injection(server): - cmd = server.run(f"curl --header 'X-FORWARDED-PROTO: https' --silent --write-out '%{{stderr}}%{{http_code}}' --unix-socket {FOREMAN_SOCKET} --header 'Host: evil.hackers.test' http://{FOREMAN_HOST}/api/v2/ping") + cmd = server.run(f"curl --header 'X-FORWARDED-PROTO: https' --silent --write-out '%{{stderr}}%{{http_code}}' --unix-socket {FOREMAN_SOCKET} http://evil.hackers.test/api/v2/ping") assert cmd.succeeded assert cmd.stderr == '403' diff --git a/tests/pulp_test.py b/tests/pulp_test.py index 8859d0dbd..d2fa1fc1b 100644 --- a/tests/pulp_test.py +++ b/tests/pulp_test.py @@ -4,7 +4,6 @@ import pytest import yaml -PULP_HOST = 'localhost' PULP_API_SOCKET = '/run/httpd.pulp-api.sock' PULP_CONTENT_SOCKET = '/run/httpd.pulp-content.sock' @@ -24,8 +23,8 @@ def load_pulp_paths_from_parameters(): @pytest.fixture(scope="module") -def pulp_status_curl(server): - return server.run(f"curl -k -s -w '%{{stderr}}%{{http_code}}' --unix-socket {PULP_API_SOCKET} http://{PULP_HOST}/pulp/api/v3/status/") +def pulp_status_curl(server, server_fqdn): + return server.run(f"curl -k -s -w '%{{stderr}}%{{http_code}}' --unix-socket {PULP_API_SOCKET} http://{server_fqdn}/pulp/api/v3/status/") @pytest.fixture(scope="module") From 941fbe1ef61181a74e5195417505a97d71a04e3e Mon Sep 17 00:00:00 2001 From: Gaurav Talreja Date: Thu, 9 Jul 2026 22:02:10 +0530 Subject: [PATCH 6/7] Enable httpd_can_network_relay just for proxy hosts On proxy hosts, httpd reverse proxies /rhsm and other paths to the remote Foreman server over HTTPS. With unix sockets replacing httpd_can_network_connect, this outbound access was blocked by SELinux. Use httpd_can_network_relay instead of httpd_can_network_connect as it only allows connections to http_port_t ports (80, 443), following the principle of least privilege. Signed-off-by: Gaurav Talreja --- src/roles/httpd/tasks/main.yml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/roles/httpd/tasks/main.yml b/src/roles/httpd/tasks/main.yml index e88b6f5d5..3f1c15ca1 100644 --- a/src/roles/httpd/tasks/main.yml +++ b/src/roles/httpd/tasks/main.yml @@ -13,6 +13,15 @@ persistent: true when: ansible_facts['selinux']['status'] == "enabled" +- name: Set httpd_can_network_relay so Apache can reverse proxy to remote servers + ansible.posix.seboolean: + name: httpd_can_network_relay + state: true + persistent: true + when: + - ansible_facts['selinux']['status'] == "enabled" + - not httpd_with_foreman + - name: Disable welcome page ansible.builtin.file: path: /etc/httpd/conf.d/welcome.conf From 50300547274679fb0fcccf80a025daf690d3874f Mon Sep 17 00:00:00 2001 From: Gaurav Talreja Date: Fri, 10 Jul 2026 04:34:25 +0530 Subject: [PATCH 7/7] Notify handlers when socket templates change Ensure socket units restart on re-deploy when their templates are modified, so changes to ListenStream, Backlog, or other socket options take effect without a manual restart. Signed-off-by: Gaurav Talreja --- src/roles/foreman/handlers/main.yml | 5 +++++ src/roles/foreman/tasks/main.yaml | 1 + src/roles/pulp/handlers/main.yml | 10 ++++++++++ src/roles/pulp/tasks/main.yaml | 2 ++ 4 files changed, 18 insertions(+) diff --git a/src/roles/foreman/handlers/main.yml b/src/roles/foreman/handlers/main.yml index 4bfc00a01..bacd77d1e 100644 --- a/src/roles/foreman/handlers/main.yml +++ b/src/roles/foreman/handlers/main.yml @@ -1,4 +1,9 @@ --- +- name: Restart foreman socket + ansible.builtin.systemd: + name: foreman.socket + state: restarted + - name: Restart foreman ansible.builtin.systemd: name: foreman diff --git a/src/roles/foreman/tasks/main.yaml b/src/roles/foreman/tasks/main.yaml index d31fa5ba8..d8f4ffdf3 100644 --- a/src/roles/foreman/tasks/main.yaml +++ b/src/roles/foreman/tasks/main.yaml @@ -105,6 +105,7 @@ src: foreman.socket.j2 dest: /etc/systemd/system/foreman.socket mode: '0644' + notify: Restart foreman socket - name: Deploy Foreman Container containers.podman.podman_container: diff --git a/src/roles/pulp/handlers/main.yml b/src/roles/pulp/handlers/main.yml index ac363b9d5..4308ec08e 100644 --- a/src/roles/pulp/handlers/main.yml +++ b/src/roles/pulp/handlers/main.yml @@ -1,9 +1,19 @@ --- +- name: Restart pulp-api socket + ansible.builtin.systemd: + name: pulp-api.socket + state: restarted + - name: Restart pulp-api ansible.builtin.systemd: name: pulp-api state: restarted +- name: Restart pulp-content socket + ansible.builtin.systemd: + name: pulp-content.socket + state: restarted + - name: Restart pulp-content ansible.builtin.systemd: name: pulp-content diff --git a/src/roles/pulp/tasks/main.yaml b/src/roles/pulp/tasks/main.yaml index a2430b990..0e4a68306 100644 --- a/src/roles/pulp/tasks/main.yaml +++ b/src/roles/pulp/tasks/main.yaml @@ -97,6 +97,7 @@ src: pulp-api.socket.j2 dest: /etc/systemd/system/pulp-api.socket mode: '0644' + notify: Restart pulp-api socket - name: Deploy Pulp API Container containers.podman.podman_container: @@ -136,6 +137,7 @@ src: pulp-content.socket.j2 dest: /etc/systemd/system/pulp-content.socket mode: '0644' + notify: Restart pulp-content socket - name: Deploy Pulp Content Container containers.podman.podman_container: