Add playbooks/setup_awx_https.yml that deploys a host-level nginx reverse proxy in front of the AWX LoadBalancer service, terminating TLS on 443 and proxying to the existing HTTP service on 80. Why a reverse proxy and not in-pod TLS: the AWX Operator only wires nginx for HTTPS on the OpenShift Route passthrough code path (ingress_type: route + route_tls_termination_mechanism: passthrough), which requires the Route CRD and fails on k3s. The cluster has no ingress controller either. A host nginx proxy is the lowest-risk option and is trivially swappable when the internal CA / an ingress controller + cert-manager arrive. The self-signed cert (CN=tsys-awx.knel.net) carries SANs for the FQDN, short hostname, and both LAN and Tailscale IPs. Re-run the playbook to rotate the cert once the internal CA is rolled out. Also update scripts/awx_create_job_templates.py to use https by default and add AWX_VERIFY_TLS / AWX_CA_BUNDLE env vars so it works with the self-signed cert now and verifies properly once the internal CA bundle is distributed. 🤖 Generated with [Crush](https://github.com/charmassociates/crush) Assisted-by: GLM-5 via Crush <crush@charm.land>
133 lines
4.7 KiB
YAML
133 lines
4.7 KiB
YAML
---
|
|
# Put AWX behind HTTPS with a host-level nginx TLS-termination reverse proxy.
|
|
#
|
|
# Why a reverse proxy instead of in-pod TLS:
|
|
# The AWX Operator only wires nginx for HTTPS on the OpenShift Route
|
|
# "passthrough" code path (ingress_type: route + route_tls_termination_mechanism:
|
|
# passthrough), which requires the Route CRD and breaks on k3s. There is also no
|
|
# ingress controller on the cluster. Terminating TLS at a host nginx proxy in
|
|
# front of the existing LoadBalancer service is the lowest-risk option and is
|
|
# trivially swappable once an internal CA / ingress controller + cert-manager
|
|
# arrive.
|
|
#
|
|
# Topology after this playbook:
|
|
# client --https:443--> host nginx (TLS terminate) --http:80--> k3s ServiceLB
|
|
# |
|
|
# v
|
|
# tsys-awx-service (LB) -> awx-web:8052
|
|
#
|
|
# The cert is self-signed (CN=tsys-awx.knel.net) with SANs covering the FQDN,
|
|
# the short hostname, and both the LAN and Tailscale IPs. Re-run this playbook
|
|
# after rotating the cert (e.g. when the internal CA is rolled out).
|
|
|
|
- name: AWX HTTPS reverse proxy
|
|
hosts: tsys-awx
|
|
gather_facts: true
|
|
become: true
|
|
|
|
vars:
|
|
# Cert subject / SANs. Extend these lists as more names are needed.
|
|
awx_tls_cn: tsys-awx.knel.net
|
|
awx_tls_sans:
|
|
- "DNS:tsys-awx.knel.net"
|
|
- "DNS:tsys-awx"
|
|
- "IP:192.168.3.200"
|
|
- "IP:100.91.39.53"
|
|
awx_tls_dir: /etc/nginx/ssl
|
|
awx_tls_cert: "{{ awx_tls_dir }}/awx-self-signed.crt"
|
|
awx_tls_key: "{{ awx_tls_dir }}/awx-self-signed.key"
|
|
|
|
tasks:
|
|
- name: Install nginx
|
|
ansible.builtin.apt:
|
|
name: nginx
|
|
state: present
|
|
update_cache: true
|
|
|
|
- name: Ensure TLS cert directory exists
|
|
ansible.builtin.file:
|
|
path: "{{ awx_tls_dir }}"
|
|
state: directory
|
|
owner: root
|
|
group: root
|
|
mode: "0755"
|
|
|
|
- name: Generate self-signed certificate (only if missing) # noqa no-changed-when
|
|
ansible.builtin.shell: |
|
|
set -o pipefail
|
|
openssl req -x509 -newkey rsa:2048 -nodes -days 825 \
|
|
-keyout {{ awx_tls_key }} -out {{ awx_tls_cert }} \
|
|
-subj "/CN={{ awx_tls_cn }}" \
|
|
-addext "subjectAltName={{ awx_tls_sans | join(',') }}"
|
|
args:
|
|
creates: "{{ awx_tls_cert }}"
|
|
|
|
- name: Lock down private key permissions
|
|
ansible.builtin.file:
|
|
path: "{{ awx_tls_key }}"
|
|
owner: root
|
|
group: root
|
|
mode: "0600"
|
|
|
|
- name: Deploy nginx TLS proxy site config
|
|
ansible.builtin.copy:
|
|
dest: /etc/nginx/sites-available/awx-tls.conf
|
|
owner: root
|
|
group: root
|
|
mode: "0644"
|
|
content: |
|
|
# Ansible-managed: TLS termination for AWX.
|
|
# Proxies https://tsys-awx.knel.net -> http://127.0.0.1:80 (k3s ServiceLB -> AWX).
|
|
# map must live in the http{} context; sites-enabled/* are included inside http.
|
|
map $http_upgrade $awx_connection_upgrade {
|
|
default upgrade;
|
|
'' close;
|
|
}
|
|
|
|
server {
|
|
listen 443 ssl;
|
|
listen [::]:443 ssl;
|
|
http2 on;
|
|
|
|
server_name tsys-awx.knel.net tsys-awx 192.168.3.200 100.91.39.53;
|
|
|
|
ssl_certificate /etc/nginx/ssl/awx-self-signed.crt;
|
|
ssl_certificate_key /etc/nginx/ssl/awx-self-signed.key;
|
|
ssl_protocols TLSv1.2 TLSv1.3;
|
|
ssl_ciphers HIGH:!aNULL:!MD5;
|
|
ssl_session_cache shared:SSL:10m;
|
|
ssl_session_timeout 1d;
|
|
|
|
client_max_body_size 50M;
|
|
|
|
location / {
|
|
proxy_pass http://127.0.0.1:80;
|
|
proxy_http_version 1.1;
|
|
proxy_set_header Host $http_host;
|
|
proxy_set_header X-Real-IP $remote_addr;
|
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
|
proxy_set_header X-Forwarded-Proto https;
|
|
proxy_set_header Upgrade $http_upgrade;
|
|
proxy_set_header Connection $awx_connection_upgrade;
|
|
proxy_read_timeout 300s;
|
|
proxy_redirect off;
|
|
}
|
|
}
|
|
notify: Reload nginx
|
|
|
|
- name: Enable the AWX TLS site
|
|
ansible.builtin.file:
|
|
src: /etc/nginx/sites-available/awx-tls.conf
|
|
dest: /etc/nginx/sites-enabled/awx-tls.conf
|
|
state: link
|
|
|
|
- name: Test nginx configuration # noqa no-changed-when
|
|
ansible.builtin.command: nginx -t
|
|
|
|
handlers:
|
|
- name: Reload nginx
|
|
ansible.builtin.systemd:
|
|
name: nginx
|
|
state: reloaded
|
|
enabled: true
|