Renew and Change SSL/TLS Certificates in AAP 2.7: Operator-Based OpenShift Installation
By Luca Berton · Published 2026-06-29 · Category: installation
How to renew and change SSL/TLS certificates for AAP 2.7 on OpenShift: create a TLS secret, update the AnsibleAutomationPlatform CR, and verify with openssl.
Renewing or replacing SSL/TLS certificates in an operator-managed Ansible Automation Platform 2.7 deployment on OpenShift Container Platform is a two-step process: create a new TLS secret in the namespace, then reference it from the AnsibleAutomationPlatform custom resource. The operator handles the rest automatically.
Prerequisites
Before starting, make sure you have:
- A valid signed SSL/TLS certificate and private key for your AAP FQDN
ocCLI configured and authenticated to the OpenShift cluster- Permissions to create secrets and edit custom resources in the AAP namespace
- The name of your
AnsibleAutomationPlatformCR (oc get ansibleautomationplatform -n)
Change the TLS Certificate for Automation Controller
Step 1 — Create the TLS Secret
Copy your signed certificate and key to a secure location on the host running oc, then create the secret:
oc create secret tls controller-certs-$(date +%F) \
--cert=/path/to/ssl.crt \
--key=/path/to/ssl.key \
-n ansible-automation-platformThe secret name is arbitrary. Using the date (e.g., controller-certs-2026-06-29) makes it easy to track which secret is currently active.
Verify the secret was created:
oc get secret controller-certs-$(date +%F) -n ansible-automation-platformStep 2 — Update the AnsibleAutomationPlatform CR
Edit the AnsibleAutomationPlatform custom resource to add (or update) the route_tls_secret field under spec.controller:
oc edit ansibleautomationplatform <aap-instance-name> -n ansible-automation-platformAdd or update route_tls_secret under spec.controller:
apiVersion: aap.ansible.com/v1alpha1
kind: AnsibleAutomationPlatform
metadata:
name: myaap
namespace: ansible-automation-platform
spec:
controller:
route_tls_secret: controller-certs-2026-06-29Save and exit. The operator detects the change and immediately begins applying the new certificate to the automation controller route.
Step 3 — Verify the New Certificate
Wait 2–3 minutes for the operator to reconcile, then verify:
true | openssl s_client -showcerts -connect ${CONTROLLER_FQDN}:443 2>/dev/null \
| openssl x509 -noout -dates -subjectCheck that notAfter and subject match your new certificate.
See also: Ansible troubleshooting - Kubernetes K8s or OpenShift OCP 401 Unauthorized
Change the TLS Certificate for Automation Hub
Step 1 — Create the TLS Secret
oc create secret tls hub-certs-$(date +%F) \
--cert=/path/to/ssl.crt \
--key=/path/to/ssl.key \
-n ansible-automation-platformStep 2 — Update the AnsibleAutomationPlatform CR
Add or update route_tls_secret under spec.hub:
oc edit ansibleautomationplatform <aap-instance-name> -n ansible-automation-platformapiVersion: aap.ansible.com/v1alpha1
kind: AnsibleAutomationPlatform
metadata:
name: myaap
namespace: ansible-automation-platform
spec:
hub:
route_tls_secret: hub-certs-2026-06-29Step 3 — Verify
true | openssl s_client -showcerts -connect ${HUB_FQDN}:443 2>/dev/null \
| openssl x509 -noout -dates -subjectAutomating Certificate Renewal with the ansible.platform Collection
For environments using Configuration as Code, manage TLS secrets with the kubernetes.core collection:
---
- name: Rotate AAP TLS certificates
hosts: localhost
connection: local
vars:
aap_namespace: ansible-automation-platform
cert_date: "{{ ansible_date_time.date }}"
controller_cert: "{{ lookup('file', '/path/to/controller-ssl.crt') }}"
controller_key: "{{ lookup('file', '/path/to/controller-ssl.key') }}"
hub_cert: "{{ lookup('file', '/path/to/hub-ssl.crt') }}"
hub_key: "{{ lookup('file', '/path/to/hub-ssl.key') }}"
tasks:
- name: Create controller TLS secret
kubernetes.core.k8s:
state: present
definition:
apiVersion: v1
kind: Secret
type: kubernetes.io/tls
metadata:
name: "controller-certs-{{ cert_date }}"
namespace: "{{ aap_namespace }}"
data:
tls.crt: "{{ controller_cert | b64encode }}"
tls.key: "{{ controller_key | b64encode }}"
- name: Create hub TLS secret
kubernetes.core.k8s:
state: present
definition:
apiVersion: v1
kind: Secret
type: kubernetes.io/tls
metadata:
name: "hub-certs-{{ cert_date }}"
namespace: "{{ aap_namespace }}"
data:
tls.crt: "{{ hub_cert | b64encode }}"
tls.key: "{{ hub_key | b64encode }}"
- name: Update AnsibleAutomationPlatform CR
kubernetes.core.k8s:
state: patched
api_version: aap.ansible.com/v1alpha1
kind: AnsibleAutomationPlatform
name: myaap
namespace: "{{ aap_namespace }}"
definition:
spec:
controller:
route_tls_secret: "controller-certs-{{ cert_date }}"
hub:
route_tls_secret: "hub-certs-{{ cert_date }}"
- name: Wait for operator reconciliation
ansible.builtin.pause:
seconds: 120
- name: Verify controller certificate
ansible.builtin.command:
cmd: "openssl s_client -showcerts -connect {{ controller_fqdn }}:443"
stdin: ''
register: controller_cert_check
changed_when: false
- name: Assert controller certificate updated
ansible.builtin.assert:
that: cert_date in controller_cert_check.stdout
success_msg: "Controller certificate updated successfully"
fail_msg: "Controller certificate did not update — check operator logs"See also: Deploy Kubernetes Resources with Ansible Playbook
Certificate Expiry Monitoring
Use an Ansible playbook scheduled as an AAP job template to alert before certificates expire:
---
- name: Check AAP certificate expiry
hosts: localhost
connection: local
vars:
warning_days: 30
hosts_to_check:
- fqdn: "{{ controller_fqdn }}"
name: "Automation Controller"
- fqdn: "{{ hub_fqdn }}"
name: "Automation Hub"
tasks:
- name: Check certificate expiry dates
ansible.builtin.command:
cmd: >
openssl s_client -connect {{ item.fqdn }}:443 -servername {{ item.fqdn }}
stdin: ''
register: cert_results
loop: "{{ hosts_to_check }}"
changed_when: false
- name: Parse expiry dates
ansible.builtin.set_fact:
expiry_dates: >-
{{ cert_results.results | map(attribute='stdout') |
map('regex_search', 'notAfter=(.+)', '\\1') | list }}
- name: Alert on certificates expiring soon
ansible.builtin.fail:
msg: "Certificate for {{ item.item.name }} expires soon: {{ item.stdout | regex_search('notAfter=(.+)', '\\1') }}"
when: >-
(item.stdout | regex_search('notAfter=(.+)', '\\1') | first |
to_datetime('%b %d %H:%M:%S %Y %Z') - now()).days < warning_days
loop: "{{ cert_results.results }}"Post-Rotation Checklist
- ☐ Verify new certificate is served on automation controller
- ☐ Verify new certificate is served on automation hub
- ☐ Test login to the AAP gateway with the new certificate
- ☐ Confirm browser shows the cert as trusted (no SSL warnings)
- ☐ Update any monitoring systems that check certificate expiry
- ☐ Delete the old TLS secret if it is no longer referenced
- ☐ Update your secrets manager (Vault/CyberArk) with the new cert/key
FAQ
Can I use a wildcard certificate?
Yes. Create the TLS secret with your wildcard certificate (*.example.com) and reference it from both spec.controller.route_tls_secret and spec.hub.route_tls_secret. The same secret name can be referenced from multiple components.
What happens if I reference a secret that doesn't exist?
The operator will fail to reconcile and log an error. The existing certificate remains in place — the old cert continues to serve until the referenced secret is found.
How do I check the current secret being used?
oc get ansibleautomationplatform <name> -n <namespace> -o jsonpath='{.spec.controller.route_tls_secret}'Does the operator restart the pods during certificate rotation?
The operator updates the Route TLS termination configuration directly. Automation controller pods are not restarted for a certificate change — the new cert takes effect on new TLS connections without service interruption.
Is a CA certificate needed?
If your certificate is signed by an internal CA, add the CA bundle to the secret:
cat ssl.crt intermediate.crt > ssl-chain.crt
oc create secret tls controller-certs-$(date +%F) \
--cert=ssl-chain.crt \
--key=ssl.key \
-n ansible-automation-platformSee also: Optimize Kubernetes CPU Resources with Ansible Playbooks
Related Articles
Category: installation