Files
toallab-automation/playbooks/deploy_openshift.yml

294 lines
11 KiB
YAML

---
# Deploy and configure Single Node OpenShift (SNO) on Proxmox
#
# Prerequisites:
# ansible-galaxy collection install -r collections/requirements.yml
# openshift-install is downloaded automatically during the sno_deploy_install play
#
# Inventory requirements:
# sno.openshift.toal.ca - in 'openshift' group
# host_vars: ocp_cluster_name, ocp_base_domain, ocp_version, sno_ip,
# sno_gateway, sno_nameserver, sno_prefix_length, sno_vm_name,
# sno_bridge, sno_vlan, proxmox_node, keycloak_url, keycloak_realm,
# oidc_admin_groups, sno_deploy_letsencrypt_email, ...
# secrets: vault_ocp_pull_secret, vault_keycloak_admin_password,
# vault_oidc_client_secret (optional)
# proxmox_api - inventory host (ansible_host, ansible_port)
# proxmox_host - inventory host (ansible_host, ansible_connection: ssh)
# gate.toal.ca - in 'opnsense' group
# host_vars: opnsense_host, opnsense_api_key, opnsense_api_secret,
# opnsense_api_port, haproxy_public_ip
# group_vars/all: dme_account_key, dme_account_secret
#
# Play order (intentional — DNS must precede VM boot):
# Play 1: sno_deploy_vm — Create SNO VM
# Play 2: opnsense — Configure OPNsense local DNS overrides
# Play 3: dns — Configure public DNS records in DNS Made Easy
# Play 4: sno_deploy_install — Generate ISO, boot VM, wait for install
# Play 5: keycloak — Configure Keycloak OIDC client
# Play 6: sno_deploy_oidc / sno_deploy_certmanager / sno_deploy_delete_kubeadmin
#
# Usage:
# ansible-navigator run playbooks/deploy_openshift.yml
# ansible-navigator run playbooks/deploy_openshift.yml --tags sno_deploy_vm
# ansible-navigator run playbooks/deploy_openshift.yml --tags sno_deploy_install
# ansible-navigator run playbooks/deploy_openshift.yml --tags opnsense,dns
# ansible-navigator run playbooks/deploy_openshift.yml --tags keycloak,sno_deploy_oidc
# ansible-navigator run playbooks/deploy_openshift.yml --tags sno_deploy_certmanager
# ---------------------------------------------------------------------------
# Play 1: Create SNO VM in Proxmox
# ---------------------------------------------------------------------------
- name: Create SNO VM in Proxmox
hosts: sno.openshift.toal.ca
gather_facts: false
connection: local
tags: sno_deploy_vm
tasks:
- name: Create VM
ansible.builtin.include_role:
name: sno_deploy
tasks_from: create_vm.yml
# ---------------------------------------------------------------------------
# Play 2: Configure OPNsense - Local DNS Overrides
# Must run BEFORE booting the VM so that api.openshift.toal.ca resolves
# from within the SNO node during bootstrap.
# ---------------------------------------------------------------------------
- name: Configure OPNsense DNS overrides for OpenShift
hosts: gate.toal.ca
gather_facts: false
connection: local
module_defaults:
group/oxlorg.opnsense.all:
firewall: "{{ opnsense_host }}"
api_key: "{{ opnsense_api_key }}"
api_secret: "{{ opnsense_api_secret }}"
ssl_verify: "{{ opnsense_ssl_verify | default(false) }}"
api_port: "{{ opnsense_api_port | default(omit) }}"
vars:
__deploy_ocp_cluster_name: "{{ hostvars['sno.openshift.toal.ca']['ocp_cluster_name'] }}"
__deploy_ocp_base_domain: "{{ hostvars['sno.openshift.toal.ca']['ocp_base_domain'] }}"
__deploy_sno_ip: "{{ hostvars['sno.openshift.toal.ca']['sno_ip'] }}"
tags: opnsense
roles:
- role: opnsense_dns_override
opnsense_dns_override_entries:
- hostname: "api.{{ __deploy_ocp_cluster_name }}"
domain: "{{ __deploy_ocp_base_domain }}"
value: "{{ __deploy_sno_ip }}"
type: host
- hostname: "api-int.{{ __deploy_ocp_cluster_name }}"
domain: "{{ __deploy_ocp_base_domain }}"
value: "{{ __deploy_sno_ip }}"
type: host
- domain: "apps.{{ __deploy_ocp_cluster_name }}.{{ __deploy_ocp_base_domain }}"
value: "{{ __deploy_sno_ip }}"
type: forward
# ---------------------------------------------------------------------------
# Play 3: Configure Public DNS Records in DNS Made Easy
# ---------------------------------------------------------------------------
- name: Configure public DNS records for OpenShift
hosts: sno.openshift.toal.ca
gather_facts: false
connection: local
vars:
__deploy_public_ip: "{{ hostvars['gate.toal.ca']['haproxy_public_ip'] }}"
tags: dns
roles:
- role: dnsmadeeasy_record
dnsmadeeasy_record_account_key: "{{ dme_account_key }}"
dnsmadeeasy_record_account_secret: "{{ dme_account_secret }}"
dnsmadeeasy_record_entries:
- domain: "{{ ocp_base_domain }}"
record_name: "api.{{ ocp_cluster_name }}"
record_type: A
record_value: "{{ __deploy_public_ip }}"
record_ttl: "{{ ocp_dns_ttl }}"
- domain: "{{ ocp_base_domain }}"
record_name: "*.apps.{{ ocp_cluster_name }}"
record_type: A
record_value: "{{ __deploy_public_ip }}"
record_ttl: "{{ ocp_dns_ttl }}"
# ---------------------------------------------------------------------------
# Play 4: Generate Agent ISO and Deploy SNO
# ---------------------------------------------------------------------------
- name: Generate Agent ISO and Deploy SNO
hosts: sno.openshift.toal.ca
gather_facts: false
connection: local
tags: sno_deploy_install
tasks:
- name: Install SNO
ansible.builtin.include_role:
name: sno_deploy
tasks_from: install.yml
# ---------------------------------------------------------------------------
# Play 5: Configure Keycloak OIDC client for OpenShift
# ---------------------------------------------------------------------------
- name: Configure Keycloak OIDC client for OpenShift
hosts: openshift
gather_facts: false
connection: local
tags: keycloak
vars:
keycloak_context: ""
oidc_client_id: openshift
oidc_redirect_uri: "https://oauth-openshift.apps.{{ ocp_cluster_name }}.{{ ocp_base_domain }}/oauth2callback/{{ oidc_provider_name }}"
__oidc_keycloak_api_url: "{{ keycloak_url }}{{ keycloak_context }}"
module_defaults:
middleware_automation.keycloak.keycloak_realm:
auth_client_id: admin-cli
auth_keycloak_url: "{{ __oidc_keycloak_api_url }}"
auth_realm: master
auth_username: "{{ keycloak_admin_user }}"
auth_password: "{{ vault_keycloak_admin_password }}"
validate_certs: "{{ keycloak_validate_certs | default(true) }}"
middleware_automation.keycloak.keycloak_client:
auth_client_id: admin-cli
auth_keycloak_url: "{{ __oidc_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 OIDC client secret (use vault value or generate random)
ansible.builtin.set_fact:
__oidc_client_secret: "{{ vault_oidc_client_secret | default(lookup('community.general.random_string', length=32, special=false)) }}"
__oidc_secret_generated: "{{ vault_oidc_client_secret is not defined }}"
no_log: true
- name: Ensure Keycloak realm exists
middleware_automation.keycloak.keycloak_realm:
realm: "{{ keycloak_realm }}"
id: "{{ keycloak_realm }}"
display_name: "{{ keycloak_realm_display_name | default(keycloak_realm | title) }}"
enabled: true
state: present
no_log: "{{ keycloak_no_log | default(true) }}"
- name: Create OpenShift OIDC client in Keycloak
middleware_automation.keycloak.keycloak_client:
realm: "{{ keycloak_realm }}"
client_id: "{{ oidc_client_id }}"
name: "OpenShift - {{ ocp_cluster_name }}"
description: "OIDC client for OpenShift cluster {{ 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: "{{ __oidc_client_secret }}"
redirect_uris:
- "{{ oidc_redirect_uri }}"
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 OIDC CLIENT SECRET — SAVE THIS TO VAULT ***"
- "vault_oidc_client_secret: {{ __oidc_client_secret }}"
- ""
- "Set this in host_vars or pass as --extra-vars on future runs."
when: __oidc_secret_generated | bool
- name: Display Keycloak configuration summary
ansible.builtin.debug:
msg:
- "Keycloak OIDC client configured:"
- " Realm : {{ keycloak_realm }}"
- " Client : {{ oidc_client_id }}"
- " Issuer : {{ keycloak_url }}{{ keycloak_context }}/realms/{{ keycloak_realm }}"
- " Redirect: {{ oidc_redirect_uri }}"
verbosity: 1
# ---------------------------------------------------------------------------
# Play 6: Post-install OpenShift configuration
# Configure OIDC OAuth, cert-manager, and delete kubeadmin
# ---------------------------------------------------------------------------
- name: Configure OpenShift post-install
hosts: sno.openshift.toal.ca
gather_facts: false
connection: local
environment:
KUBECONFIG: "{{ sno_install_dir }}/auth/kubeconfig"
K8S_AUTH_VERIFY_SSL: "false"
tags:
- sno_deploy_oidc
- sno_deploy_certmanager
- sno_deploy_delete_kubeadmin
tasks:
- name: Configure OpenShift OAuth with OIDC
ansible.builtin.include_role:
name: sno_deploy
tasks_from: configure_oidc.yml
tags: sno_deploy_oidc
- name: Configure cert-manager and LetsEncrypt certificates
ansible.builtin.include_role:
name: sno_deploy
tasks_from: configure_certmanager.yml
tags: sno_deploy_certmanager
- name: Delete kubeadmin user
ansible.builtin.include_role:
name: sno_deploy
tasks_from: delete_kubeadmin.yml
tags:
- never
- sno_deploy_delete_kubeadmin
# ---------------------------------------------------------------------------
# Play 7: Install Ansible Automation Platform (opt-in via --tags aap)
# ---------------------------------------------------------------------------
- name: Install Ansible Automation Platform
hosts: sno.openshift.toal.ca
gather_facts: false
connection: local
environment:
KUBECONFIG: "{{ sno_install_dir }}/auth/kubeconfig"
K8S_AUTH_VERIFY_SSL: "false"
tags:
- never
- aap
roles:
- role: aap_operator