Provide your own internal TLS certificates

By default, the operator generates a self-signed CA and per-service certificates for internal mutual TLS (mTLS). You can replace these with certificates from your own certificate authority (CA) when your organization requires it.

Before you begin

  • You have cluster administrator access to the OpenShift namespace where automation orchestrator is deployed.
  • You have installed and authenticated the oc CLI.
  • You have installed OpenSSL 1.1.1 or later.
  • You have a CA certificate and key, or you plan to generate a new CA for internal use.

About this task

For the required Secrets, DNS Subject Alternative Names (SANs), and certificate specifications, see Internal TLS.

If you already have certificates that meet the requirements, skip to step 5.

Procedure

  1. Set shell variables to match your deployment:
    $ INSTANCE_NAME=my-orchestrator
    $ NAMESPACE=automation-orchestrator
    $ CERT_DIR=$(mktemp -d)
  2. Generate the CA:
    $ openssl req -x509 -newkey rsa:2048 -nodes \
        -keyout "${CERT_DIR}/ca.key" \
        -out "${CERT_DIR}/ca.crt" \
        -days 3650 \
        -subj "/CN=my-internal-ca"
  3. Generate a certificate for each component.

    The following script creates all five:

    $ for COMPONENT in backend worker background-worker temporal ui; do
    
      cat > "${CERT_DIR}/${COMPONENT}.cnf" <<EOF
    [req]
    req_extensions = v3_req
    distinguished_name = req_dn
    prompt = no
    
    [req_dn]
    CN = ${COMPONENT}.ao.svc
    
    [v3_req]
    keyUsage = digitalSignature, keyEncipherment
    extendedKeyUsage = serverAuth, clientAuth
    subjectAltName = @alt_names
    
    [alt_names]
    DNS.1 = ${INSTANCE_NAME}-${COMPONENT}.${NAMESPACE}.svc.cluster.local
    DNS.2 = ${INSTANCE_NAME}-${COMPONENT}
    DNS.3 = localhost
    IP.1 = 127.0.0.1
    EOF
    
      openssl req -newkey rsa:2048 -nodes \
        -keyout "${CERT_DIR}/${COMPONENT}.key" \
        -out "${CERT_DIR}/${COMPONENT}.csr" \
        -config "${CERT_DIR}/${COMPONENT}.cnf"
    
      openssl x509 -req \
        -in "${CERT_DIR}/${COMPONENT}.csr" \
        -CA "${CERT_DIR}/ca.crt" \
        -CAkey "${CERT_DIR}/ca.key" \
        -CAcreateserial \
        -out "${CERT_DIR}/${COMPONENT}.crt" \
        -days 3650 \
        -extensions v3_req \
        -extfile "${CERT_DIR}/${COMPONENT}.cnf"
    
    done
  4. Verify that each certificate is signed by your CA and has the correct SANs and extended key usage (EKU):
    $ for COMPONENT in backend worker background-worker temporal ui; do
      echo "=== ${COMPONENT} ==="
      openssl verify -CAfile "${CERT_DIR}/ca.crt" "${CERT_DIR}/${COMPONENT}.crt"
      openssl x509 -in "${CERT_DIR}/${COMPONENT}.crt" -noout -text \
        | grep -A1 "Subject Alternative Name"
      openssl x509 -in "${CERT_DIR}/${COMPONENT}.crt" -noout -text \
        | grep -A1 "Extended Key Usage"
      echo
    
    done

    Each certificate should show:

    • Verification: OK
    • SANs: the three DNS names and 127.0.0.1
    • Extended Key Usage: TLS Web Server Authentication, TLS Web Client Authentication
  5. Create the Kubernetes Secrets.

    Create the CA Secret as an Opaque Secret:

    $ oc create secret generic my-internal-ca \
        --from-file=ca.crt="${CERT_DIR}/ca.crt" \
        -n "${NAMESPACE}"

    Create the service certificate Secrets as kubernetes.io/tls Secrets:

    $ oc create secret tls my-backend-tls \
        --cert="${CERT_DIR}/backend.crt" \
        --key="${CERT_DIR}/backend.key" \
        -n "${NAMESPACE}"
    
    $ oc create secret tls my-worker-tls \
        --cert="${CERT_DIR}/worker.crt" \
        --key="${CERT_DIR}/worker.key" \
        -n "${NAMESPACE}"
    
    $ oc create secret tls my-background-worker-tls \
        --cert="${CERT_DIR}/background-worker.crt" \
        --key="${CERT_DIR}/background-worker.key" \
        -n "${NAMESPACE}"
    
    $ oc create secret tls my-temporal-tls \
        --cert="${CERT_DIR}/temporal.crt" \
        --key="${CERT_DIR}/temporal.key" \
        -n "${NAMESPACE}"
    
    $ oc create secret tls my-ui-tls \
        --cert="${CERT_DIR}/ui.crt" \
        --key="${CERT_DIR}/ui.key" \
        -n "${NAMESPACE}"
  6. Add the spec.tls block to your AutomationOrchestrator custom resource, referencing the Secrets you created:
    apiVersion: aap.ansible.com/v1alpha1
    kind: AutomationOrchestrator
    metadata:
      name: my-orchestrator
      namespace: automation-orchestrator
    spec:
      tls:
        caSecretRef:
          name: my-internal-ca
        backendCertSecretRef:
          name: my-backend-tls
        workerCertSecretRef:
          name: my-worker-tls
        backgroundWorkerCertSecretRef:
          name: my-background-worker-tls
        temporalCertSecretRef:
          name: my-temporal-tls
        uiCertSecretRef:
          name: my-ui-tls
      # ... other spec fields
  7. Apply the custom resource:
    $ oc apply -f orchestrator-cr.yaml

    The operator validates that all six Secrets exist and contain the required keys before deploying. If any Secret is missing or incomplete, the operator sets ConfigurationValid=False and does not proceed.

  8. Verify the deployment.
    1. Confirm that TLSReady shows "True" with reason "CustomerCertificates":
      $ oc get automationorchestrator my-orchestrator -n automation-orchestrator \
          -o jsonpath='{.status.conditions[?(@.type=="TLSReady")]}' | jq .

      If the reason shows SelfSignedCertificates, the operator did not detect spec.tls.caSecretRef and fell back to auto-generated certificates. If TLSReady is False, check the message field to identify which Secret is unhealthy.

    2. Confirm that ConfigurationValid and Ready are also True:
      $ oc get automationorchestrator my-orchestrator -n automation-orchestrator \
          -o jsonpath='{.status.conditions}' | jq .
    3. Verify that all pods are running:
      $ oc get pods -n automation-orchestrator -l app.kubernetes.io/instance=my-orchestrator
    4. Verify that the backend certificate issuer matches your CA, not the default automation-orchestrator-internal-ca. Run this command from your workstation because the backend container image does not include the OpenSSL CLI.
      $ oc get secret my-backend-tls -n automation-orchestrator \
          -o jsonpath='{.data.tls\.crt}' | base64 -d | openssl x509 -noout -issuer
    5. Log in to the web interface and run a workflow to confirm end-to-end functionality.