--- # Deploy Ansible Automation Platform on OpenShift # # Authenticates via the aap-deployer ServiceAccount token (not kubeadmin). # The token is stored in 1Password and loaded via vault_aap_deployer_token. # # Prerequisites: # - OpenShift cluster deployed (deploy_openshift.yml) # - aap-deployer ServiceAccount provisioned: # ansible-navigator run playbooks/deploy_openshift.yml --tags sno_deploy_service_accounts # - SA token saved to 1Password as vault_aap_deployer_token # # Keycloak OIDC prerequisites (--tags aap_configure_keycloak,aap_configure_oidc): # - Keycloak realm exists (configured via deploy_openshift.yml) # - vault_aap_oidc_client_secret in 1Password (or it will be generated and displayed) # - In host_vars for the aap host: # aap_gateway_url: "https://aap.apps.." # aap_oidc_client_id: aap # aap_oidc_issuer: "https://keycloak.example.com/realms/" # aap_oidc_public_key: "" # # Play order: # Play 0: aap_configure_keycloak — Create Keycloak OIDC client for AAP Gateway # Play 1: (default) — Install AAP via aap_operator role # Play 2: aap_configure_oidc — Configure OIDC Authentication Method in AAP Gateway # # Usage: # ansible-navigator run playbooks/deploy_aap.yml # ansible-navigator run playbooks/deploy_aap.yml --tags aap_configure_keycloak # ansible-navigator run playbooks/deploy_aap.yml --tags aap_configure_oidc # ansible-navigator run playbooks/deploy_aap.yml --tags aap_configure_keycloak,aap_configure_oidc # --------------------------------------------------------------------------- # Play 0: Create Keycloak OIDC client for AAP (optional) # Runs on openshift hosts to access keycloak_url/keycloak_realm host vars. # Creates the OIDC client in Keycloak with the correct AAP Gateway callback URI. # --------------------------------------------------------------------------- - name: Configure Keycloak OIDC client for AAP hosts: openshift gather_facts: false connection: local tags: - never - aap_configure_keycloak vars: __aap_keycloak_api_url: "{{ keycloak_url }}{{ keycloak_context | default('') }}" __aap_oidc_client_id: "{{ aap_oidc_client_id | default('aap') }}" # AAP operator generates the Gateway route as {platform_name}-{namespace}.apps.{cluster}.{domain} # e.g. platform 'aap' in namespace 'aap' → aap-aap.apps.openshift.toal.ca __aap_platform_name: "{{ aap_operator_platform_name | default('aap') }}" __aap_namespace: "{{ aap_operator_namespace | default('aap') }}" __aap_oidc_redirect_uris: - "https://{{ __aap_platform_name }}-{{ __aap_namespace }}.apps.{{ ocp_cluster_name }}.{{ ocp_base_domain }}/accounts/profile/callback/" module_defaults: middleware_automation.keycloak.keycloak_client: auth_client_id: admin-cli auth_keycloak_url: "{{ __aap_keycloak_api_url }}" auth_realm: master auth_username: "{{ keycloak_admin_user }}" auth_password: "{{ vault_keycloak_admin_password }}" validate_certs: "{{ keycloak_validate_certs | default(true) }}" tasks: - name: Set AAP OIDC client secret (vault value or generated) ansible.builtin.set_fact: __aap_oidc_client_secret: "{{ vault_aap_oidc_client_secret | default(lookup('community.general.random_string', length=32, special=false)) }}" __aap_oidc_secret_generated: "{{ vault_aap_oidc_client_secret is not defined }}" no_log: true - name: Create AAP OIDC client in Keycloak middleware_automation.keycloak.keycloak_client: realm: "{{ keycloak_realm }}" client_id: "{{ __aap_oidc_client_id }}" name: "Ansible Automation Platform" description: "OIDC client for AAP Gateway on {{ ocp_cluster_name }}.{{ ocp_base_domain }}" enabled: true protocol: openid-connect public_client: false standard_flow_enabled: true implicit_flow_enabled: false direct_access_grants_enabled: false service_accounts_enabled: false secret: "{{ __aap_oidc_client_secret }}" redirect_uris: "{{ __aap_oidc_redirect_uris }}" web_origins: - "+" protocol_mappers: - name: groups protocol: openid-connect protocolMapper: oidc-group-membership-mapper config: full.path: "false" id.token.claim: "true" access.token.claim: "true" userinfo.token.claim: "true" claim.name: groups state: present no_log: "{{ keycloak_no_log | default(true) }}" - name: Display generated client secret (save this to vault!) ansible.builtin.debug: msg: - "*** GENERATED AAP OIDC CLIENT SECRET — SAVE THIS TO VAULT ***" - "vault_aap_oidc_client_secret: {{ __aap_oidc_client_secret }}" - "" - "Save to 1Password and reference as vault_aap_oidc_client_secret." when: __aap_oidc_secret_generated | bool - name: Display Keycloak AAP OIDC configuration summary ansible.builtin.debug: msg: - "Keycloak AAP OIDC client configured:" - " Realm : {{ keycloak_realm }}" - " Client : {{ __aap_oidc_client_id }}" - " Issuer : {{ __aap_keycloak_api_url }}/realms/{{ keycloak_realm }}" - " Redirect : {{ __aap_oidc_redirect_uris | join(', ') }}" - "" - "Set in host_vars for the aap host:" - " aap_gateway_url: https://{{ __aap_platform_name }}-{{ __aap_namespace }}.apps.{{ ocp_cluster_name }}.{{ ocp_base_domain }}" - " aap_oidc_issuer: {{ __aap_keycloak_api_url }}/realms/{{ keycloak_realm }}" - "" - "Then run: --tags aap_configure_oidc to register the authenticator in AAP." verbosity: 1 # --------------------------------------------------------------------------- # Play 1: Install Ansible Automation Platform # --------------------------------------------------------------------------- - name: Install Ansible Automation Platform hosts: aap gather_facts: false connection: local pre_tasks: - name: Verify aap-deployer token is available ansible.builtin.assert: that: - vault_aap_deployer_token is defined - vault_aap_deployer_token | length > 0 fail_msg: >- vault_aap_deployer_token is not set. Provision the ServiceAccount with: ansible-navigator run playbooks/deploy_openshift.yml --tags sno_deploy_service_accounts Then save the displayed token to 1Password as vault_aap_deployer_token. # environment: # K8S_AUTH_HOST: "{{ aap_k8s_api_url }}" # K8S_AUTH_API_KEY: "{{ vault_aap_deployer_token }}" roles: - role: aap_operator # --------------------------------------------------------------------------- # Play 2: Configure Keycloak OIDC Authentication Method in AAP Gateway (optional) # Uses infra.aap_configuration.gateway_authenticators to register the OIDC # provider via the AAP Gateway API. Run after Play 1 (AAP must be Running). # # Requires in host_vars for the aap host: # aap_gateway_url: "https://aap.apps.." # aap_oidc_issuer: "https://keycloak.example.com/realms/" # aap_oidc_client_id: aap (optional, default: aap) # aap_oidc_public_key: "" # Vault: # vault_aap_oidc_client_secret — OIDC client secret from Keycloak # --------------------------------------------------------------------------- - name: Configure Keycloak OIDC Authentication in AAP Gateway hosts: aap gather_facts: false connection: local tags: - never - aap_configure_oidc vars: __aap_namespace: "{{ aap_operator_namespace | default('aap') }}" __aap_platform_name: "{{ aap_operator_platform_name | default('aap') }}" environment: K8S_AUTH_HOST: "{{ aap_k8s_api_url }}" K8S_AUTH_API_KEY: "{{ vault_aap_deployer_token }}" pre_tasks: - name: Fetch AAP admin password from K8s secret kubernetes.core.k8s_info: api_version: v1 kind: Secret namespace: "{{ __aap_namespace }}" name: "{{ __aap_platform_name }}-admin-password" register: __aap_admin_secret no_log: false - name: Set AAP admin password fact ansible.builtin.set_fact: __aap_admin_password: "{{ __aap_admin_secret.resources[0].data.password | b64decode }}" no_log: true tasks: - name: Configure Keycloak OIDC authenticator in AAP Gateway ansible.builtin.include_role: name: infra.aap_configuration.gateway_authenticators vars: aap_hostname: "{{ aap_gateway_url }}" aap_username: "{{ aap_operator_admin_user | default('admin') }}" aap_password: "{{ __aap_admin_password }}" gateway_authenticators: - name: Keycloak type: ansible_base.authentication.authenticator_plugins.keycloak slug: keycloak enabled: true configuration: KEY: "{{ aap_oidc_client_id | default('aap') }}" SECRET: "{{ vault_aap_oidc_client_secret }}" PUBLIC_KEY: "{{ aap_oidc_public_key }}" ACCESS_TOKEN_URL: "{{ aap_oidc_issuer }}/protocol/openid-connect/token" AUTHORIZATION_URL: "{{ aap_oidc_issuer }}/protocol/openid-connect/auth" GROUPS_CLAIM: "groups" state: present