main.yml 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245
  1. ---
  2. # Ensures there is an instance of RHBoK running in a configurable namespace.
  3. #
  4. # Configures it with a realm, and some users.
  5. #
  6. # Required variables (some are supplied by defaults/main.yml):
  7. #
  8. # rhbk:
  9. # namespace: namespace to deploy to (keycloak)
  10. # name: name of the instance (sso)
  11. # replicas: how many instances
  12. # fqdn: fqdn of the route (hostname), detected if omitted
  13. # admin: bootstrap admin credentials
  14. # username: username (rhbk)
  15. # password: password (secret)
  16. # db: database-specific settings
  17. # image: db server image
  18. # name: database name (rhbk)
  19. # username: database owner (rhbk)
  20. # password: db owner's password (secret)
  21. # claim_modes: volume claim template access modes, list (ReadWriteOnce)
  22. # storage_class: storage class name, no default (omitted)
  23. # size: pvc size (1Gi)
  24. # replicas: how many instances (TODO ignored for now)
  25. # realm: name of the realm (sample-realm)
  26. # users: users to create in realm, no default (meaning no users)
  27. # - username: required (as it is key)
  28. # password: optional, defaults to "secret"
  29. # fullname: optional, set to username if empty
  30. # email: optional, set to username@example.com if empty
  31. #
  32. # NOTE: Must have an operator deployed in that namespace prior (use deploy-operators role for that).
  33. #
  34. - name: Tech hack. Prevent anything from blowing up because rhbk is defined somewhere, but not its structured contents.
  35. ansible.builtin.set_fact:
  36. rhbk:
  37. db: {}
  38. when:
  39. - rhbk.db is not defined
  40. - name: Ensure there is a secret containing DB credentials in the project.
  41. kubernetes.core.k8s:
  42. kubeconfig: tmp/kubeconfig-ocp4
  43. validate_certs: no
  44. api_version: v1
  45. kind: secret
  46. namespace: "{{ rhbk.namespace | default('keycloak') }}"
  47. name: "{{ rhbk.name | default('sso') }}-db-auth"
  48. resource_definition:
  49. data:
  50. username: "{{ rhbk.db.username | default('rhbk') | b64encode }}"
  51. password: "{{ rhbk.db.password | default('secret') | b64encode }}"
  52. # TODO: ensure that there is no STS to begin with, or if there is, verify that
  53. # only the allowed fields would change, if anything. Otherwise:
  54. #
  55. # Forbidden: updates to statefulset spec for fields other than
  56. # 'replicas', 'ordinals', 'template', 'updateStrategy',
  57. # 'persistentVolumeClaimRetentionPolicy' and 'minReadySeconds' are
  58. # forbidden
  59. #
  60. - name: Ensure there is a database sts in the project
  61. kubernetes.core.k8s:
  62. kubeconfig: tmp/kubeconfig-ocp4
  63. validate_certs: no
  64. api_version: apps/v1
  65. kind: statefulset
  66. namespace: "{{ rhbk.namespace | default('keycloak') }}"
  67. name: "{{ rhbk.name | default('sso') }}-db"
  68. resource_definition:
  69. spec:
  70. # TODO: implement rhbk.db.replicas at some point?
  71. replicas: 1
  72. serviceName: "{{ rhbk.name | default('sso') }}-db"
  73. selector:
  74. matchLabels:
  75. app: "{{ rhbk.name | default('sso') }}-db"
  76. template:
  77. metadata:
  78. labels:
  79. app: "{{ rhbk.name | default('sso') }}-db"
  80. spec:
  81. containers:
  82. - name: "{{ rhbk.name | default('sso') }}-db"
  83. image: "{{ rhbk.db.image | default('registry.redhat.io/rhel9/postgresql-15:latest') }}"
  84. volumeMounts:
  85. - mountPath: /var/lib/pgsql/data
  86. name: "{{ rhbk.name | default('sso') }}-db-data"
  87. env:
  88. - name: POSTGRESQL_USER
  89. valueFrom:
  90. secretKeyRef:
  91. name: "{{ rhbk.name | default('sso') }}-db-auth"
  92. key: username
  93. - name: POSTGRESQL_PASSWORD
  94. valueFrom:
  95. secretKeyRef:
  96. name: "{{ rhbk.name | default('sso') }}-db-auth"
  97. key: password
  98. - name: POSTGRESQL_DATABASE
  99. value: "{{ rhbk.db.name | default('rhbk') }}"
  100. volumeClaimTemplates:
  101. - metadata:
  102. name: "{{ rhbk.name | default('sso') }}-db-data"
  103. spec:
  104. accessModes: "{{ rhbk.db.claim_modes | default(['ReadWriteOnce']) }}"
  105. storageClassName: "{{ rhbk.db.storage_class | default(omit) }}"
  106. resources:
  107. requests:
  108. storage: "{{ rhbk.db.size | default('1Gi') }}"
  109. - name: Ensure there is a service for the database as well
  110. kubernetes.core.k8s:
  111. kubeconfig: tmp/kubeconfig-ocp4
  112. validate_certs: no
  113. api_version: v1
  114. kind: service
  115. namespace: "{{ rhbk.namespace | default('keycloak') }}"
  116. name: "{{ rhbk.name | default('sso') }}-db"
  117. resource_definition:
  118. spec:
  119. selector:
  120. app: "{{ rhbk.name | default('sso') }}-db"
  121. type: LoadBalancer
  122. ports:
  123. - port: 5432
  124. targetPort: 5432
  125. protocol: TCP
  126. - name: Ensure there is a secret containing Keycloak bootstrap credentials
  127. kubernetes.core.k8s:
  128. kubeconfig: tmp/kubeconfig-ocp4
  129. validate_certs: no
  130. api_version: v1
  131. kind: secret
  132. namespace: "{{ rhbk.namespace | default('keycloak') }}"
  133. name: "{{ rhbk.name | default('sso') }}-auth"
  134. resource_definition:
  135. data:
  136. username: "{{ rhbk.admin.username | default('rhbk') | b64encode }}"
  137. password: "{{ rhbk.admin.password | default('secret') | b64encode }}"
  138. - name: If there is no FQDN, check what the default domain is.
  139. kubernetes.core.k8s_info:
  140. kubeconfig: tmp/kubeconfig-ocp4
  141. validate_certs: no
  142. api_version: operator.openshift.io/v1
  143. kind: ingresscontroller
  144. namespace: openshift-ingress-operator
  145. name: default
  146. register: default_ingress
  147. when: rhbk.fqdn is not defined
  148. - name: Set a fact that reflects either the FQDN as set, or a composition of vars and default ingress info.
  149. ansible.builtin.set_fact:
  150. rhbk_fqdn: "{{ rhbk.fqdn | default((rhbk.name | default('sso')) + '-' + (rhbk.namespace | default('keycloak')) + '.' + default_ingress.resources[0].status.domain) }}"
  151. - name: Announce what hostname would be used.
  152. ansible.builtin.debug:
  153. msg: Using "https://{{ rhbk_fqdn }}" as the hostname.
  154. # TODO: remember if there were changes, and force delete any non-ready pod?
  155. - name: Lastly, make sure there is a Keycloak
  156. kubernetes.core.k8s:
  157. kubeconfig: tmp/kubeconfig-ocp4
  158. validate_certs: no
  159. api_version: k8s.keycloak.org/v2alpha1
  160. kind: keycloak
  161. namespace: "{{ rhbk.namespace | default('keycloak') }}"
  162. name: "{{ rhbk.name | default('sso') }}"
  163. resource_definition:
  164. spec:
  165. instances: "{{ rhbk.replicas | default(1) }}"
  166. db:
  167. vendor: postgres
  168. host: "{{ rhbk.name | default('sso') }}-db"
  169. database: "{{ rhbk.db.name | default('rhbk') }}"
  170. usernameSecret:
  171. name: "{{ rhbk.name | default('sso') }}-db-auth"
  172. key: username
  173. passwordSecret:
  174. name: "{{ rhbk.name | default('sso') }}-db-auth"
  175. key: password
  176. hostname:
  177. hostname: "https://{{ rhbk_fqdn }}"
  178. strict: false
  179. backchannelDynamic: true
  180. http:
  181. httpEnabled: true
  182. httpPort: 8080
  183. httpsPort: 8443
  184. tlsSecret: "{{ rhbk.name | default('sso') }}-tls"
  185. bootstrapAdmin:
  186. user:
  187. secret: "{{ rhbk.name | default('sso') }}-auth"
  188. ingress:
  189. enabled: false
  190. - name: Wait for the service to show up.
  191. kubernetes.core.k8s_info:
  192. kubeconfig: tmp/kubeconfig-ocp4
  193. validate_certs: no
  194. api_version: v1
  195. kind: service
  196. namespace: "{{ rhbk.namespace | default('keycloak') }}"
  197. name: "{{ rhbk.name | default('sso') }}-service"
  198. register: rhbk_svc
  199. until:
  200. - rhbk_svc.resources is defined
  201. - (rhbk_svc.resources | length) > 0
  202. retries: 24
  203. delay: 5
  204. - name: Ensure the service is correctly annotated.
  205. kubernetes.core.k8s:
  206. kubeconfig: tmp/kubeconfig-ocp4
  207. validate_certs: no
  208. api_version: v1
  209. kind: service
  210. namespace: "{{ rhbk.namespace | default('keycloak') }}"
  211. name: "{{ rhbk.name | default('sso') }}-service"
  212. state: patched
  213. resource_definition:
  214. metadata:
  215. annotations:
  216. service.beta.openshift.io/serving-cert-secret-name: "{{ rhbk.name | default('sso') }}-tls"
  217. - name: Make sure there is a re-encrypt route.
  218. kubernetes.core.k8s:
  219. kubeconfig: tmp/kubeconfig-ocp4
  220. validate_certs: no
  221. api_version: route.openshift.io/v1
  222. kind: route
  223. namespace: "{{ rhbk.namespace | default('keycloak') }}"
  224. name: "{{ rhbk.name | default('sso') }}"
  225. resource_definition:
  226. spec:
  227. to:
  228. kind: Service
  229. name: "{{ rhbk.name | default('sso') }}-service"
  230. port:
  231. targetPort: 8443
  232. tls:
  233. termination: reencrypt
  234. ...