Przeglądaj źródła

deploying full rhsso as a catch-up

Grega Bremec 2 lat temu
rodzic
commit
9b61db93d9

+ 20 - 0
deploy-rhsso.yml

@@ -0,0 +1,20 @@
+---
+- name: Deploy a RHSSO instance
+  hosts: workstation.lab.example.com
+  gather_subset: min
+  become: no
+  roles:
+    - role: deploy-rhsso-operator
+      tags: operator
+    - role: deploy-rhsso-instance
+      tags: keycloak
+    - role: deploy-rhsso-crs
+      tags:
+        - realm
+        - client
+    - role: deploy-rhsso-population
+      tags:
+        - users
+        - groups
+        - roles
+...

+ 117 - 0
roles/deploy-rhsso-crs/tasks/main.yml

@@ -0,0 +1,117 @@
+---
+# Ensures that the realm and a test client in it are created.
+- name: Check for the KeyCloak resource to see it shows ready state
+  k8s_info:
+    kubeconfig: tmp/kubeconfig-ocp4
+    validate_certs: no
+    api_version: keycloak.org/v1alpha1
+    kind: keycloak
+    namespace: rhsso
+    name: rhsso
+  register: sso_cr
+
+- assert:
+    that:
+      - (sso_cr.resources | length) == 1
+      - sso_cr.resources[0].status.ready
+      - sso_cr.resources[0].status.phase == "reconciling"
+    fail_msg: "ERROR: RHSSO instance is missing or not configured correctly."
+    success_msg: "OK: RHSSO instance is configured correctly."
+
+- name: Make sure the realm resource is correctly configured
+  k8s:
+    kubeconfig: tmp/kubeconfig-ocp4
+    validate_certs: no
+    api_version: keycloak.org/v1alpha1
+    kind: keycloakrealm
+    namespace: rhsso
+    name: sample-realm
+    definition:
+      metadata:
+        labels:
+          app: sso
+          realm: sample
+      spec:
+        instanceSelector:
+          matchLabels:
+            app: sso
+        realm:
+          id: sample
+          realm: sample
+          enabled: True
+          displayName: "Sample Realm"
+  tags:
+    - realm
+
+- name: Wait for the realm resource to show ready state
+  k8s_info:
+    kubeconfig: tmp/kubeconfig-ocp4
+    validate_certs: no
+    api_version: keycloak.org/v1alpha1
+    kind: keycloakrealm
+    namespace: rhsso
+    name: sample-realm
+  register: sso_realm
+  until:
+    - (sso_realm.resources | length) == 1
+    - sso_realm.resources[0].status is defined
+    - sso_realm.resources[0].status.ready
+    - sso_realm.resources[0].status.phase == "reconciling"
+  retries: 30
+  delay: 10
+
+- name: Also ensure there is a client in the sample realm
+  k8s:
+    kubeconfig: tmp/kubeconfig-ocp4
+    validate_certs: no
+    api_version: keycloak.org/v1alpha1
+    kind: keycloakclient
+    namespace: rhsso
+    name: sample-client
+    definition:
+      metadata:
+        labels:
+          app: sso
+          realm: sample
+          client: sample
+      spec:
+        realmSelector:
+          matchLabels:
+            app: sso
+            realm: sample
+        client:
+          clientId: sample-client
+          defaultClientScopes:
+            - email
+            - offline_access
+            - profile
+            - roles
+          protocolMappers:
+            - name: groups
+              protocol: openid-connect
+              protocolMapper: oidc-usermodel-client-role-mapper
+              consentRequired: false
+          implicitFlowEnabled: False
+          standardFlowEnabled: True
+          redirectUris:
+            - https://oauth-openshift.apps.ocp4.example.com/*
+  tags:
+    - client
+
+- name: Wait for the client resource to show ready state
+  k8s_info:
+    kubeconfig: tmp/kubeconfig-ocp4
+    validate_certs: no
+    api_version: keycloak.org/v1alpha1
+    kind: keycloakclient
+    namespace: rhsso
+    name: sample-client
+  register: sso_client
+  until:
+    - (sso_client.resources | length) == 1
+    - sso_client.resources[0].status is defined
+    - sso_client.resources[0].status.ready
+    - sso_client.resources[0].status.phase == "reconciling"
+  retries: 30
+  delay: 10
+...

+ 82 - 0
roles/deploy-rhsso-instance/tasks/main.yml

@@ -0,0 +1,82 @@
+---
+# Ensures the RHSSO instance (driven by a KeyCloak resource) is there.
+#
+- name: Check that the CSV is there and completed
+  k8s_info:
+    kubeconfig: tmp/kubeconfig-ocp4
+    validate_certs: no
+    api_version: operators.coreos.com/v1alpha1
+    kind: clusterserviceversion
+    namespace: rhsso
+    name: rhsso-operator.7.6.0-opr-003
+  register: sso_csv
+
+- assert:
+    that:
+      - sso_csv.resources is defined
+      - (sso_csv.resources | length) == 1
+      - sso_csv.resources[0].status.phase == "Succeeded"
+    fail_msg: "ERROR: RHSSO operator not deployed or not registered correctly."
+    success_msg: "OK: RHSSO operator deployed correctly."
+
+- name: Check for the presence of stray KeyCloak resources
+  k8s_info:
+    kubeconfig: tmp/kubeconfig-ocp4
+    validate_certs: no
+    api_version: keycloak.org/v1alpha1
+    kind: keycloak
+    namespace: rhsso
+  register: sso_cr
+
+- assert:
+    that:
+      - (sso_cr.resources | length) == 1
+      - sso_cr.resources[0].metadata.name == "rhsso"
+    fail_msg: "ERROR: RHSSO instances other than the required one exist."
+    success_msg: "OK: Required RHSSO instance exists."
+  when:
+    - sso_cr.resources is defined
+    - (sso_cr.resources | length) > 0
+
+- name: Make sure there is a KeyCloak resource in the project
+  k8s:
+    kubeconfig: tmp/kubeconfig-ocp4
+    validate_certs: no
+    api_version: keycloak.org/v1alpha1
+    kind: keycloak
+    namespace: rhsso
+    name: rhsso
+    definition:
+      metadata:
+        labels:
+          app: sso
+      spec:
+        instances: 1
+        externalAccess:
+          enabled: true
+
+- name: Wait for the KeyCloak resource to show ready state
+  k8s_info:
+    kubeconfig: tmp/kubeconfig-ocp4
+    validate_certs: no
+    api_version: keycloak.org/v1alpha1
+    kind: keycloak
+    namespace: rhsso
+    name: rhsso
+  register: sso_cr
+  until:
+    - (sso_cr.resources | length) == 1
+    - sso_cr.resources[0].status.ready
+    - sso_cr.resources[0].status.phase == "reconciling"
+  retries: 30
+  delay: 10
+
+- name: Show some basic information about the instance.
+  pause:
+    prompt: |-
+      *******************************************************************************************************
+      KeyCloak instance rhsso is now available at {{ sso_cr.resources[0].status.externalURL }}
+      You can obtain the necessary credentials from secrets/{{ sso_cr.resources[0].status.credentialSecret }}
+      *******************************************************************************************************
+    seconds: 5
+...

+ 120 - 0
roles/deploy-rhsso-operator/tasks/main.yml

@@ -0,0 +1,120 @@
+---
+# Ensures all the operator artifacts are created and waits for CSV to succeed.
+#
+# NOTE: Do NOT test by checking for presence of API resources in the
+#       keycloak.org API group. They do not always get cleaned up.
+#
+- name: Check if the RHSSO CSV exists already
+  k8s_info:
+    kubeconfig: tmp/kubeconfig-ocp4
+    validate_certs: no
+    api_version: operators.coreos.com/v1alpha1
+    kind: clusterserviceversion
+  register: all_csv
+
+- name: Find RHSSO CSV among all CSVs
+  set_fact:
+    rhsso_csv: "{{ (all_csv | community.general.json_query(\"resources[?metadata.name == 'rhsso-operator.7.6.0-opr-003']\")) }}"
+  when:
+    - all_csv.resources is defined
+    - (all_csv.resources | length) > 0
+
+- name: Get details about RHSSO CSV if found
+  set_fact:
+    rhsso_csv_ns: "{{ rhsso_csv[0] | community.general.json_query('metadata.namespace') }}"
+    rhsso_csv_name: "{{ rhsso_csv[0] | community.general.json_query('metadata.name') }}"
+  when:
+    - rhsso_csv is defined
+    - (rhsso_csv | length) > 0
+
+- assert:
+    that:
+      - ((rhsso_csv_ns | default("")) == "") or ((rhsso_csv_ns | default("")) == "rhsso")
+      - ((rhsso_csv_name | default("")) == "") or ((rhsso_csv_name | default("")) == "rhsso-operator.7.6.0-opr-003")
+    fail_msg: "ERROR: RHSSO CSV already present in {{ rhsso_csv_ns | default('NA') }}/{{ rhsso_csv_name | default('NA') }} - please remove manually!"
+    success_msg: "OK: RHSSO CSV not present or configured correctly."
+
+- name: Make sure the namespace is there
+  k8s:
+    kubeconfig: tmp/kubeconfig-ocp4
+    validate_certs: no
+    api_version: v1
+    kind: namespace
+    name: rhsso
+
+- name: Make sure it has a properly configured OperatorGroup
+  k8s:
+    kubeconfig: tmp/kubeconfig-ocp4
+    validate_certs: no
+    api_version: operators.coreos.com/v1
+    kind: operatorgroup
+    namespace: rhsso
+    name: rhsso-operator-group
+    definition:
+      spec:
+        targetNamespaces:
+          - rhsso
+
+- name: Also make sure there is a subscription
+  k8s:
+    kubeconfig: tmp/kubeconfig-ocp4
+    validate_certs: no
+    api_version: operators.coreos.com/v1alpha1
+    kind: subscription
+    namespace: rhsso
+    name: rhsso-subscription
+    definition:
+      spec:
+        source: do280-sso
+        sourceNamespace: openshift-marketplace
+        name: rhsso-operator
+        channel: stable
+        installPlanApproval: Automatic
+
+- name: Wait for installPlan to show up
+  k8s_info:
+    kubeconfig: tmp/kubeconfig-ocp4
+    validate_certs: no
+    api_version: operators.coreos.com/v1alpha1
+    kind: installplan
+    namespace: rhsso
+  register: sso_ip
+  until:
+    - sso_ip.resources is defined
+    - (sso_ip.resources | length) > 0
+    - sso_ip.resources[0].spec.approved
+  retries: 12
+  delay: 10
+
+- name: Wait for CSV to show up and complete
+  k8s_info:
+    kubeconfig: tmp/kubeconfig-ocp4
+    validate_certs: no
+    api_version: operators.coreos.com/v1alpha1
+    kind: clusterserviceversion
+    namespace: rhsso
+  register: sso_csv
+  until:
+    - sso_csv.resources is defined
+    - (sso_csv.resources | length) > 0
+    - sso_csv.resources[0].status.phase == "Succeeded"
+  retries: 30
+  delay: 10
+
+- name: Finally, wait for the pod
+  k8s_info:
+    kubeconfig: tmp/kubeconfig-ocp4
+    validate_certs: no
+    api_version: v1
+    kind: pod
+    namespace: rhsso
+    label_selectors:
+      - name = rhsso-operator
+  register: sso_pod
+  until:
+    - sso_pod.resources is defined
+    - (sso_pod.resources | length) > 0
+    - sso_pod.resources[0].status.phase == "Running"
+  retries: 30
+  delay: 10
+...

+ 160 - 0
roles/deploy-rhsso-population/tasks/main.yml

@@ -0,0 +1,160 @@
+---
+# Ensures that there are also users, groups, and roles in the test realm.
+- name: Check for the KeyCloak resource
+  k8s_info:
+    kubeconfig: tmp/kubeconfig-ocp4
+    validate_certs: no
+    api_version: keycloak.org/v1alpha1
+    kind: keycloak
+    namespace: rhsso
+    name: rhsso
+  register: sso_cr
+
+- assert:
+    that:
+      - (sso_cr.resources | length) == 1
+      - sso_cr.resources[0].status.ready
+      - sso_cr.resources[0].status.phase == "reconciling"
+    fail_msg: "ERROR: RHSSO instance is missing or not configured correctly."
+    success_msg: "OK: RHSSO instance is configured correctly."
+
+- name: Store RHSSO URL as a fact
+  set_fact:
+    sso_url: "{{ sso_cr.resources[0].status.externalURL }}"
+
+- name: Check for the realm resource
+  k8s_info:
+    kubeconfig: tmp/kubeconfig-ocp4
+    validate_certs: no
+    api_version: keycloak.org/v1alpha1
+    kind: keycloakrealm
+    namespace: rhsso
+    name: sample-realm
+  register: sso_realm
+
+- assert:
+    that:
+      - (sso_realm.resources | length) == 1
+      - sso_realm.resources[0].spec.realm.id == "sample"
+      - sso_realm.resources[0].spec.realm.realm == "sample"
+      - sso_realm.resources[0].status.ready
+      - sso_realm.resources[0].status.phase == "reconciling"
+    fail_msg: "ERROR: RHSSO sample realm is missing or not configured correctly."
+    success_msg: "OK: RHSSO sample realm is configured correctly."
+
+# Authentication bits from here until we can get group list.
+- name: Read the SSO admin pass
+  k8s_info:
+    kubeconfig: tmp/kubeconfig-ocp4
+    validate_certs: no
+    api_version: v1
+    kind: secret
+    namespace: rhsso
+    name: "{{ sso_cr.resources[0].status.credentialSecret }}"
+  register: sso_secret
+
+- name: Store RHSSO admin pass as fact
+  set_fact:
+    sso_pass: "{{ sso_secret.resources[0].data.ADMIN_PASSWORD }}"
+
+- name: Get an auth token from RHSSO
+  uri:
+    method: POST
+    return_content: true
+    validate_certs: false
+    url: "{{ sso_url }}/auth/realms/master/protocol/openid-connect/token"
+    headers:
+      Accept: application/json
+    body: "client_id=admin-cli&username=admin&password={{ sso_pass | string | b64decode }}&grant_type=password"
+  register: sso_token_rsp
+
+- assert:
+    that: sso_token_rsp.json is defined and sso_token_rsp.json.access_token is defined
+    fail_msg: "ERROR: Failed to obtain authentication token from RHSSO."
+    success_msg: "OK: got authentication token."
+
+- name: Store the token as a fact
+  set_fact:
+    sso_token: "{{ sso_token_rsp.json.access_token }}"
+
+# Back to business as usual from here on.
+- name: Get existing group list
+  uri:
+    method: GET
+    return_content: true
+    validate_certs: false
+    url: "{{ sso_url }}/auth/admin/realms/sample/groups"
+    headers:
+      Authorization: Bearer {{ sso_token }}
+      Accept: application/json
+  register: sso_groups_raw
+  tags:
+    - groups
+
+- name: Store existing groups as a list
+  set_fact:
+    sso_groups: "{{ sso_groups_raw.json | items2dict(key_name='name', value_name='id') }}"
+  tags:
+    - groups
+
+- name: Create missing groups
+  uri:
+    method: POST
+    return_content: true
+    validate_certs: false
+    url: "{{ sso_url }}/auth/admin/realms/sample/groups"
+    headers:
+      Authorization: Bearer {{ sso_token }}
+      Accept: application/json
+      Content-Type: application/json
+    body_format: json
+    body: '{"name": "{{ item | string }}"}'
+    status_code:
+      - 200
+      - 201
+  loop: "{{ pop_groups }}"
+  when: item not in sso_groups.keys()
+  tags:
+    - groups
+
+# You need offline_access in realmRoles to be able to use OCP OIDC.
+- name: Make sure KeycloakUser resources exist
+  k8s:
+    kubeconfig: tmp/kubeconfig-ocp4
+    validate_certs: no
+    api_version: keycloak.org/v1alpha1
+    kind: keycloakuser
+    namespace: rhsso
+    name: "user-{{ item.username }}"
+    definition:
+      metadata:
+        labels:
+          app: sso
+          realm: sample
+      spec:
+        realmSelector:
+          matchLabels:
+            app: sso
+            realm: sample
+        user:
+          username: "{{ item.username }}"
+          credentials:
+            - temporary: False
+              type: password
+              value: "{{ item.password }}"
+          firstName: "{{ item.firstname }}"
+          lastName: "{{ item.lastname }}"
+          email: "{{ item.username }}@example.com"
+          enabled: True
+          emailVerified: True
+          groups: "{{ item.groups | list }}"
+          realmRoles:
+            - offline_access
+  loop: "{{ pop_users }}"
+  tags:
+    - users
+
+# TODO: assign roles to groups?
+# TODO: remove any stale identities / openshift users if keycloakuser resources have been created?
+
+...

+ 26 - 0
roles/deploy-rhsso-population/vars/main.yml

@@ -0,0 +1,26 @@
+---
+# The users this role will create, along with their group memberships:
+pop_users:
+  - username: johndoe
+    password: redhat
+    firstname: John
+    lastname: Doe
+    groups:
+      - developer
+  - username: janedoe
+    password: redhat
+    firstname: Jane
+    lastname: Doe
+    groups:
+      - admin
+  - username: tomjones
+    password: redhat
+    firstname: Tom
+    lastname: Jones
+    groups:
+      - guest
+pop_groups:
+  - admin
+  - developer
+  - guest
+...