fix: Remove unnecessary container registry step

This commit is contained in:
2026-03-20 16:17:10 -04:00
parent d31b14cd72
commit 1862f20074
13 changed files with 642 additions and 7 deletions

View File

@@ -25,5 +25,8 @@ aap_operator_hub_file_storage_size: 10Gi
aap_operator_admin_user: admin
# --- Routing (optional) ---
# Set to a custom hostname to override the auto-generated Gateway route (primary UI/API entry point)
# aap_operator_gateway_route_host: aap.example.com
# Set to a custom hostname to override the auto-generated Controller route
# aap_operator_controller_route_host: aap.example.com
# aap_operator_controller_route_host: controller.example.com

View File

@@ -58,10 +58,18 @@ argument_specs:
description: Admin username for the platform.
type: str
default: admin
aap_operator_controller_route_host:
aap_operator_gateway_route_host:
description: >
Custom hostname for the Automation Controller Route.
When set, overrides the auto-generated route hostname (e.g. aap.example.com).
Custom hostname for the AAP Gateway Route (primary UI/API entry point in AAP 2.5+).
When set, overrides the auto-generated gateway route (e.g. aap.example.com).
Leave unset to use the default apps subdomain route.
type: str
required: false
aap_operator_controller_route_host:
description: >
Custom hostname for the Automation Controller Route.
When set, overrides the auto-generated controller route hostname.
Leave unset to use the default apps subdomain route.
type: str
required: false

View File

@@ -116,6 +116,9 @@
# PostgreSQL storage for all components (RWO)
database:
postgres_storage_class: "{{ aap_operator_storage_class }}"
# Gateway is the primary UI/API entry point in AAP 2.5+
gateway:
route_host: "{{ aap_operator_gateway_route_host | default(omit) }}"
# Component toggles and per-component config
controller:
disabled: "{{ aap_operator_controller_disabled | bool }}"
@@ -129,6 +132,48 @@
eda:
disabled: "{{ aap_operator_eda_disabled | bool }}"
# ------------------------------------------------------------------
# Step 3a: Clear controller route_host if not explicitly set
# strategic-merge-patch (state: present) does not remove existing fields,
# so we must explicitly remove /spec/controller/route_host if the user
# hasn't set aap_operator_controller_route_host (e.g. after switching to
# gateway-based routing).
# ------------------------------------------------------------------
# The platform operator propagates route_host to the child AutomationController CR.
# Both must be cleared or the controller operator will continue to set the old hostname.
- name: Remove controller route_host from platform CR (use auto-generated route)
kubernetes.core.k8s_json_patch:
api_version: aap.ansible.com/v1alpha1
kind: AnsibleAutomationPlatform
namespace: "{{ aap_operator_namespace }}"
name: "{{ aap_operator_platform_name }}"
patch:
- op: remove
path: /spec/controller/route_host
when: aap_operator_controller_route_host is not defined
failed_when: false # no-op if field doesn't exist
- name: Remove controller route_host from child AutomationController CR
kubernetes.core.k8s_json_patch:
api_version: automationcontroller.ansible.com/v1beta1
kind: AutomationController
namespace: "{{ aap_operator_namespace }}"
name: "{{ aap_operator_platform_name }}-controller"
patch:
- op: remove
path: /spec/route_host
when: aap_operator_controller_route_host is not defined
failed_when: false # no-op if field doesn't exist or CR not yet created
- name: Delete aap-controller Route so operator recreates with correct hostname
kubernetes.core.k8s:
api_version: route.openshift.io/v1
kind: Route
namespace: "{{ aap_operator_namespace }}"
name: "{{ aap_operator_platform_name }}-controller"
state: absent
when: aap_operator_controller_route_host is not defined
# ------------------------------------------------------------------
# Step 4: Wait for platform to be ready
# ------------------------------------------------------------------

View File

@@ -0,0 +1,22 @@
---
# --- Vault API ---
vault_url: "http://nas.lan.toal.ca:8200"
vault_validate_certs: false
# --- Init ---
vault_init_key_shares: 5
vault_init_key_threshold: 3
# --- OIDC ---
vault_oidc_client_id: vault
vault_oidc_admin_group: vault-admins
vault_oidc_default_ttl: 1h
vault_oidc_max_ttl: 8h
# --- Unseal ---
# vault_unseal_keys: [] # list of 3+ unseal key strings (from 1Password)
# --- Secrets (required, set via vault or host_vars) ---
# vault_vault_root_token: # root token from 1Password (required for Play 2)
# vault_vault_oidc_client_secret: # OIDC client secret from Keycloak (required for Play 2)
# vault_oidc_issuer: # e.g. https://keycloak.apps.openshift.toal.ca/realms/toallab

View File

@@ -0,0 +1,61 @@
---
argument_specs:
main:
short_description: Configure a running HashiCorp Vault instance
description:
- Unseals Vault if sealed and unseal keys are provided.
- Enables and configures OIDC authentication using Keycloak.
- Creates an admin policy and maps a Keycloak group to it.
- Requires Vault to already be initialized (use vault_init tag first).
options:
vault_url:
description: Base URL of the Vault API.
type: str
default: "http://nas.lan.toal.ca:8200"
vault_validate_certs:
description: Whether to validate TLS certificates for Vault API calls.
type: bool
default: false
vault_vault_root_token:
description: Vault root token for API authentication. Required.
type: str
required: true
vault_oidc_issuer:
description: OIDC discovery URL base (Keycloak realm URL). Required.
type: str
required: true
vault_vault_oidc_client_secret:
description: OIDC client secret from Keycloak. Required.
type: str
required: true
vault_oidc_client_id:
description: OIDC client ID registered in Keycloak.
type: str
default: vault
vault_oidc_admin_group:
description: Keycloak group name to map to the Vault admin policy.
type: str
default: vault-admins
vault_oidc_default_ttl:
description: Default token TTL for OIDC-authenticated tokens.
type: str
default: 1h
vault_oidc_max_ttl:
description: Maximum token TTL for OIDC-authenticated tokens.
type: str
default: 8h
vault_unseal_keys:
description: >-
List of unseal key strings. If provided and Vault is sealed,
the role will attempt to unseal using these keys.
type: list
elements: str
default: []
vault_init_key_shares:
description: Number of key shares for vault operator init.
type: int
default: 5
vault_init_key_threshold:
description: Number of key shares required to unseal.
type: int
default: 3

View File

@@ -0,0 +1,136 @@
---
# Configure Keycloak OIDC authentication in Vault.
#
# Creates:
# - OIDC auth method (auth/oidc)
# - OIDC config pointing to Keycloak realm
# - Default OIDC role with groups claim
# - Admin ACL policy
# - External identity group mapped to vault_oidc_admin_group Keycloak group
- name: Set Vault API auth headers
ansible.builtin.set_fact:
__vault_headers:
X-Vault-Token: "{{ vault_vault_root_token }}"
- name: Enable OIDC auth method
ansible.builtin.uri:
url: "{{ vault_url }}/v1/sys/auth/oidc"
method: POST
headers: "{{ __vault_headers }}"
validate_certs: "{{ vault_validate_certs }}"
body_format: json
body:
type: oidc
description: Keycloak OIDC
status_code: [200, 204, 400]
register: __vault_enable_oidc
no_log: true
changed_when: __vault_enable_oidc.status in [200, 204]
- name: Configure OIDC provider (Keycloak)
ansible.builtin.uri:
url: "{{ vault_url }}/v1/auth/oidc/config"
method: POST
headers: "{{ __vault_headers }}"
validate_certs: "{{ vault_validate_certs }}"
body_format: json
body:
oidc_discovery_url: "{{ vault_oidc_issuer }}"
oidc_client_id: "{{ vault_oidc_client_id }}"
oidc_client_secret: "{{ vault_vault_oidc_client_secret }}"
default_role: default
status_code: [200, 204]
no_log: true
- name: Create default OIDC role
ansible.builtin.uri:
url: "{{ vault_url }}/v1/auth/oidc/role/default"
method: POST
headers: "{{ __vault_headers }}"
validate_certs: "{{ vault_validate_certs }}"
body_format: json
body:
bound_audiences:
- "{{ vault_oidc_client_id }}"
allowed_redirect_uris:
- "{{ vault_url }}/ui/vault/auth/oidc/oidc/callback"
- "http://localhost:8250/oidc/callback"
user_claim: preferred_username
groups_claim: groups
token_policies:
- default
token_ttl: "{{ vault_oidc_default_ttl }}"
token_max_ttl: "{{ vault_oidc_max_ttl }}"
status_code: [200, 204]
no_log: true
- name: Create admin ACL policy
ansible.builtin.uri:
url: "{{ vault_url }}/v1/sys/policies/acl/admin"
method: POST
headers: "{{ __vault_headers }}"
validate_certs: "{{ vault_validate_certs }}"
body_format: json
body:
policy: |
path "*" {
capabilities = ["create", "read", "update", "delete", "list", "sudo"]
}
status_code: [200, 204]
no_log: true
- name: Create external identity group for admin
ansible.builtin.uri:
url: "{{ vault_url }}/v1/identity/group"
method: POST
headers: "{{ __vault_headers }}"
validate_certs: "{{ vault_validate_certs }}"
body_format: json
body:
name: "{{ vault_oidc_admin_group }}"
type: external
policies:
- admin
status_code: [200, 204]
register: __vault_admin_group
no_log: true
- name: Get OIDC auth method accessor
ansible.builtin.uri:
url: "{{ vault_url }}/v1/sys/auth"
method: GET
headers: "{{ __vault_headers }}"
validate_certs: "{{ vault_validate_certs }}"
status_code: 200
register: __vault_auth_list
no_log: true
- name: Set OIDC accessor fact
ansible.builtin.set_fact:
__vault_oidc_accessor: "{{ __vault_auth_list.json['oidc/'].accessor }}"
- name: Create group alias mapping Keycloak group to Vault admin group
ansible.builtin.uri:
url: "{{ vault_url }}/v1/identity/group-alias"
method: POST
headers: "{{ __vault_headers }}"
validate_certs: "{{ vault_validate_certs }}"
body_format: json
body:
name: "{{ vault_oidc_admin_group }}"
mount_accessor: "{{ __vault_oidc_accessor }}"
canonical_id: "{{ __vault_admin_group.json.data.id }}"
status_code: [200, 204]
no_log: true
- name: Display OIDC configuration summary
ansible.builtin.debug:
msg:
- "Vault OIDC configured:"
- " Provider : {{ vault_oidc_issuer }}"
- " Client : {{ vault_oidc_client_id }}"
- " Admin group: {{ vault_oidc_admin_group }}"
- ""
- "Login at: {{ vault_url }}/ui"
- "Select: OIDC → Sign in with Keycloak"

View File

@@ -0,0 +1,54 @@
---
# Initialize Vault. Idempotent: skips if already initialized.
# On success, displays root token and unseal keys for manual saving to 1Password.
# After saving, rerun the playbook (default play) to complete configuration.
- name: Check Vault initialization status
ansible.builtin.uri:
url: "{{ vault_url }}/v1/sys/init"
method: GET
validate_certs: "{{ vault_validate_certs }}"
register: __vault_init_status
- name: Skip init (already initialized)
ansible.builtin.debug:
msg: "Vault is already initialized. Skipping init."
when: __vault_init_status.json.initialized | bool
- name: Initialize Vault
ansible.builtin.uri:
url: "{{ vault_url }}/v1/sys/init"
method: POST
validate_certs: "{{ vault_validate_certs }}"
body_format: json
body:
secret_shares: "{{ vault_init_key_shares }}"
secret_threshold: "{{ vault_init_key_threshold }}"
status_code: 200
register: __vault_init_result
no_log: true
when: not __vault_init_status.json.initialized | bool
- name: Display init output — SAVE TO 1PASSWORD NOW
ansible.builtin.debug:
msg:
- "*** VAULT INITIALIZED — SAVE THE FOLLOWING TO 1PASSWORD IMMEDIATELY ***"
- ""
- "Root Token:"
- " vault_vault_root_token: {{ __vault_init_result.json.root_token }}"
- ""
- "Unseal Keys (need {{ vault_init_key_threshold }} of {{ vault_init_key_shares }}):"
- "{% for key in __vault_init_result.json.keys_base64 %} unseal_key_{{ loop.index }}: {{ key }}{% endfor %}"
- ""
- "Save vault_unseal_keys as a list of {{ vault_init_key_threshold }} key strings in 1Password."
- "Save vault_vault_root_token to 1Password."
when: not __vault_init_status.json.initialized | bool
- name: Fail after init — save credentials before continuing
ansible.builtin.fail:
msg: >-
Vault initialization complete.
SAVE the root token and unseal keys to 1Password before continuing.
Then run the default play to unseal and configure OIDC:
ansible-navigator run playbooks/deploy_vault.yml
when: not __vault_init_status.json.initialized | bool

View File

@@ -0,0 +1,51 @@
---
# Configures a running, initialized HashiCorp Vault instance.
#
# Expects Vault to already be initialized (run --tags vault_init first).
# Unseals if sealed and vault_unseal_keys is defined.
# Then configures OIDC authentication with Keycloak.
- name: Validate required variables
ansible.builtin.assert:
that:
- vault_url | length > 0
- vault_vault_root_token | default('') | length > 0
- vault_oidc_issuer | default('') | length > 0
- vault_vault_oidc_client_secret | default('') | length > 0
fail_msg: >-
vault_vault_root_token, vault_oidc_issuer, and vault_vault_oidc_client_secret
are required. Run --tags vault_init first, save credentials to 1Password,
then run --tags vault_configure_keycloak,vault_configure_oidc or default play.
- name: Check Vault status
ansible.builtin.uri:
url: "{{ vault_url }}/v1/sys/health"
method: GET
validate_certs: "{{ vault_validate_certs }}"
status_code: [200, 429, 472, 473, 501, 503]
register: __vault_health
- name: Assert Vault is initialized
ansible.builtin.assert:
that:
- __vault_health.json.initialized | bool
fail_msg: >-
Vault is not initialized. Run:
ansible-navigator run playbooks/deploy_vault.yml --tags vault_init
- name: Unseal Vault if sealed
ansible.builtin.include_tasks: unseal.yml
when:
- __vault_health.json.sealed | bool
- vault_unseal_keys | default([]) | length > 0
- name: Assert Vault is unsealed
ansible.builtin.assert:
that:
- not __vault_health.json.sealed | bool or __vault_unsealed | default(false) | bool
fail_msg: >-
Vault is sealed. Provide vault_unseal_keys (list of unseal key strings) or
unseal manually via the Vault UI, then rerun.
- name: Configure OIDC authentication
ansible.builtin.include_tasks: configure_oidc.yml

View File

@@ -0,0 +1,37 @@
---
# Unseal Vault using keys from vault_unseal_keys list.
# Submits keys one at a time until Vault reports unsealed.
# Requires vault_init_key_threshold keys in vault_unseal_keys.
- name: Submit unseal keys
ansible.builtin.uri:
url: "{{ vault_url }}/v1/sys/unseal"
method: POST
validate_certs: "{{ vault_validate_certs }}"
body_format: json
body:
key: "{{ item }}"
status_code: 200
loop: "{{ vault_unseal_keys[:vault_init_key_threshold] }}"
register: __vault_unseal_result
no_log: true
- name: Check unseal status
ansible.builtin.uri:
url: "{{ vault_url }}/v1/sys/health"
method: GET
validate_certs: "{{ vault_validate_certs }}"
status_code: [200, 429]
register: __vault_health
- name: Assert Vault unsealed successfully
ansible.builtin.assert:
that:
- not __vault_health.json.sealed | bool
fail_msg: >-
Vault is still sealed after submitting {{ vault_init_key_threshold }} keys.
Check that vault_unseal_keys contains the correct keys and try again.
- name: Register unseal success
ansible.builtin.set_fact:
__vault_unsealed: true