From 2fb93cbd7f8d940a9faa7942ceaa488b2b3ed54a Mon Sep 17 00:00:00 2001 From: Sebastian Widmer Date: Wed, 6 Dec 2023 12:32:43 +0100 Subject: [PATCH 01/11] Initial implementation --- .yamllint.yml | 1 + class/defaults.yml | 121 ++++++++++++++++ class/lieutenant-keycloak-idp-controller.yml | 20 +++ ...lieutenant-keycloak-idp-controller.jsonnet | 82 +++++++++++ component/main.jsonnet | 8 +- tests/defaults.yml | 8 +- .../10_config_maps.yaml | 78 +++++++++++ .../10_secrets.yaml | 12 ++ ...oak-idp-controller-controller-manager.yaml | 132 ++++++++++++++++++ ...-keycloak-idp-controller-manager-role.yaml | 29 ++++ ...eycloak-idp-controller-metrics-reader.yaml | 16 +++ ...nt-keycloak-idp-controller-proxy-role.yaml | 24 ++++ ...ak-idp-controller-manager-rolebinding.yaml | 19 +++ ...loak-idp-controller-proxy-rolebinding.yaml | 19 +++ ...k-idp-controller-leader-election-role.yaml | 44 ++++++ ...ontroller-leader-election-rolebinding.yaml | 20 +++ ...ak-idp-controller-manager-rolebinding.yaml | 20 +++ ...yn-lieutenant-keycloak-idp-controller.yaml | 12 ++ ...controller-controller-manager-metrics.yaml | 21 +++ ...oak-idp-controller-controller-manager.yaml | 12 ++ 20 files changed, 696 insertions(+), 2 deletions(-) create mode 100644 component/lieutenant-keycloak-idp-controller.jsonnet create mode 100644 tests/golden/defaults/lieutenant-keycloak-idp-controller/lieutenant-keycloak-idp-controller/10_config_maps.yaml create mode 100644 tests/golden/defaults/lieutenant-keycloak-idp-controller/lieutenant-keycloak-idp-controller/10_secrets.yaml create mode 100644 tests/golden/defaults/lieutenant-keycloak-idp-controller/lieutenant-keycloak-idp-controller/apps_v1_deployment_lieutenant-keycloak-idp-controller-controller-manager.yaml create mode 100644 tests/golden/defaults/lieutenant-keycloak-idp-controller/lieutenant-keycloak-idp-controller/rbac.authorization.k8s.io_v1_clusterrole_lieutenant-keycloak-idp-controller-manager-role.yaml create mode 100644 tests/golden/defaults/lieutenant-keycloak-idp-controller/lieutenant-keycloak-idp-controller/rbac.authorization.k8s.io_v1_clusterrole_lieutenant-keycloak-idp-controller-metrics-reader.yaml create mode 100644 tests/golden/defaults/lieutenant-keycloak-idp-controller/lieutenant-keycloak-idp-controller/rbac.authorization.k8s.io_v1_clusterrole_lieutenant-keycloak-idp-controller-proxy-role.yaml create mode 100644 tests/golden/defaults/lieutenant-keycloak-idp-controller/lieutenant-keycloak-idp-controller/rbac.authorization.k8s.io_v1_clusterrolebinding_lieutenant-keycloak-idp-controller-manager-rolebinding.yaml create mode 100644 tests/golden/defaults/lieutenant-keycloak-idp-controller/lieutenant-keycloak-idp-controller/rbac.authorization.k8s.io_v1_clusterrolebinding_lieutenant-keycloak-idp-controller-proxy-rolebinding.yaml create mode 100644 tests/golden/defaults/lieutenant-keycloak-idp-controller/lieutenant-keycloak-idp-controller/rbac.authorization.k8s.io_v1_role_lieutenant-keycloak-idp-controller-leader-election-role.yaml create mode 100644 tests/golden/defaults/lieutenant-keycloak-idp-controller/lieutenant-keycloak-idp-controller/rbac.authorization.k8s.io_v1_rolebinding_lieutenant-keycloak-idp-controller-leader-election-rolebinding.yaml create mode 100644 tests/golden/defaults/lieutenant-keycloak-idp-controller/lieutenant-keycloak-idp-controller/rbac.authorization.k8s.io_v1_rolebinding_lieutenant-keycloak-idp-controller-manager-rolebinding.yaml create mode 100644 tests/golden/defaults/lieutenant-keycloak-idp-controller/lieutenant-keycloak-idp-controller/v1_namespace_syn-lieutenant-keycloak-idp-controller.yaml create mode 100644 tests/golden/defaults/lieutenant-keycloak-idp-controller/lieutenant-keycloak-idp-controller/v1_service_lieutenant-keycloak-idp-controller-controller-manager-metrics.yaml create mode 100644 tests/golden/defaults/lieutenant-keycloak-idp-controller/lieutenant-keycloak-idp-controller/v1_serviceaccount_lieutenant-keycloak-idp-controller-controller-manager.yaml diff --git a/.yamllint.yml b/.yamllint.yml index 92aea6c..2c299b8 100644 --- a/.yamllint.yml +++ b/.yamllint.yml @@ -22,3 +22,4 @@ ignore: | manifests/ vendor/ compiled/ + tests/golden/ diff --git a/class/defaults.yml b/class/defaults.yml index 027ac38..0171f9e 100644 --- a/class/defaults.yml +++ b/class/defaults.yml @@ -2,3 +2,124 @@ parameters: lieutenant_keycloak_idp_controller: =_metadata: {} namespace: syn-lieutenant-keycloak-idp-controller + namespaceMetadata: {} + + secrets: {} + config_maps: + lieutenant-keycloak-idp-controller-templates: + data: ${lieutenant_keycloak_idp_controller:templates} + + images: + lieutenant_keycloak_idp_controller: + registry: ghcr.io + image: projectsyn/lieutenant-keycloak-idp-controller + tag: v0.1.0-dev1 + kube_rbac_proxy: + registry: gcr.io + image: kubebuilder/kube-rbac-proxy + tag: v0.14.1 + + manifests_version: ${lieutenant_keycloak_idp_controller:images:lieutenant_keycloak_idp_controller:tag} + + kustomize_input: + namespace: ${lieutenant_keycloak_idp_controller:namespace} + + controller: + env: + KEYCLOAK_BASE_URL: + KEYCLOAK_USER: + KEYCLOAK_PASSWORD: + KEYCLOAK_REALM: + KEYCLOAK_LOGIN_REALM: master + KEYCLOAK_LEGACY_WILDFLY_SUPPORT: 'true' + VAULT_ADDRESS: + + args: + - --health-probe-bind-address=:8081 + - --metrics-bind-address=127.0.0.1:8080 + - --leader-elect + + - --keycloak-realm=$(KEYCLOAK_REALM) + - --keycloak-base-url=$(KEYCLOAK_BASE_URL) + - --keycloak-user=$(KEYCLOAK_USER) + - --keycloak-password=$(KEYCLOAK_PASSWORD) + - --keycloak-login-realm=$(KEYCLOAK_LOGIN_REALM) + - --keycloak-legacy-wildfly-support=$(KEYCLOAK_LEGACY_WILDFLY_SUPPORT) + + - --client-template-file=/templates/client.jsonnet + - --client-role-mapping-template-file=/templates/client-roles.jsonnet + + - --vault-token-file=/var/run/secrets/kubernetes.io/serviceaccount/token + - --vault-address=$(VAULT_ADDRESS) + + templates: + vars.jsonnet: | + { + clientPrefix: 'cluster_', + formatRootUrl: function(context) 'https://oauth-openshift.apps.%s.dev' % context.cluster.metadata.name, + } + client.jsonnet: | + local context = std.extVar('context'); + local vars = import 'vars.jsonnet'; + + { + clientId: '%s%s' % [ vars.clientPrefix, context.cluster.metadata.name ], + name: '%s (%s)' % [ context.cluster.spec.displayName, context.cluster.metadata.name ], + description: '', + rootUrl: vars.formatRootUrl(context), + adminUrl: '', + baseUrl: '', + surrogateAuthRequired: false, + enabled: true, + alwaysDisplayInConsole: false, + clientAuthenticatorType: 'client-secret', + redirectUris: [ + '/oauth2/callback', + ], + webOrigins: [], + notBefore: 0, + bearerOnly: false, + consentRequired: false, + standardFlowEnabled: true, + implicitFlowEnabled: false, + directAccessGrantsEnabled: true, + serviceAccountsEnabled: false, + publicClient: false, + frontchannelLogout: true, + protocol: 'openid-connect', + attributes: { + 'oidc.ciba.grant.enabled': 'false', + 'backchannel.logout.session.required': 'true', + 'oauth2.device.authorization.grant.enabled': 'false', + 'display.on.consent.screen': 'false', + 'backchannel.logout.revoke.offline.tokens': 'false', + }, + authenticationFlowBindingOverrides: {}, + fullScopeAllowed: true, + nodeReRegistrationTimeout: -1, + defaultClientScopes: [ + 'web-origins', + 'acr', + 'profile', + 'roles', + 'email', + ], + optionalClientScopes: [ + 'address', + 'phone', + 'offline_access', + 'microprofile-jwt', + ], + access: { + view: true, + configure: true, + manage: true, + }, + } + client-roles.jsonnet: | + local context = std.extVar('context'); + + [{ + // https://github.com/sventorben/keycloak-restrict-client-auth#role-based-mode + role: 'restricted-access', + }] diff --git a/class/lieutenant-keycloak-idp-controller.yml b/class/lieutenant-keycloak-idp-controller.yml index f014c28..81a3715 100644 --- a/class/lieutenant-keycloak-idp-controller.yml +++ b/class/lieutenant-keycloak-idp-controller.yml @@ -9,3 +9,23 @@ parameters: - ${_base_directory}/component/main.jsonnet input_type: jsonnet output_path: lieutenant-keycloak-idp-controller/ + + - input_paths: + - ${_base_directory}/component/lieutenant-keycloak-idp-controller.jsonnet + input_type: jsonnet + output_path: ${_base_directory}/lieutenant-keycloak-idp-controller + output_type: yaml + - input_type: external + output_path: . + input_paths: + - ${_kustomize_wrapper} + env_vars: + INPUT_DIR: ${_base_directory}/lieutenant-keycloak-idp-controller + args: + - \${compiled_target_dir}/lieutenant-keycloak-idp-controller + + # Cleanup + - input_paths: + - ${_base_directory}/lieutenant-keycloak-idp-controller + input_type: remove + output_path: . diff --git a/component/lieutenant-keycloak-idp-controller.jsonnet b/component/lieutenant-keycloak-idp-controller.jsonnet new file mode 100644 index 0000000..b1a71dc --- /dev/null +++ b/component/lieutenant-keycloak-idp-controller.jsonnet @@ -0,0 +1,82 @@ +// main template for openshift4-slos +local com = import 'lib/commodore.libjsonnet'; +local kap = import 'lib/kapitan.libjsonnet'; +local kube = import 'lib/kube.libjsonnet'; + +local slo = import 'slos.libsonnet'; + +local inv = kap.inventory(); +// The hiera parameters for the component +local params = inv.parameters.lieutenant_keycloak_idp_controller; + +local upstreamNamespace = 'lieutenant-keycloak-idp-controller-system'; + +local removeUpstreamNamespace = kube.Namespace(upstreamNamespace) { + metadata: { + name: upstreamNamespace, + } + com.makeMergeable(params.namespaceMetadata), +}; + +local controllerPatch = { + apiVersion: 'apps/v1', + kind: 'Deployment', + metadata: { + name: 'lieutenant-keycloak-idp-controller-controller-manager', + namespace: upstreamNamespace, + }, + spec: { + template: { + spec: { + containers: [ { + name: 'manager', + args: params.controller.args, + env: com.envList(params.controller.env), + volumeMounts: [ { + name: 'templates', + mountPath: '/templates', + } ], + } ], + volumes: [ { + name: 'templates', + configMap: { + name: 'lieutenant-keycloak-idp-controller-templates', + }, + } ], + }, + }, + }, +}; + +local patch = function(p) { + patch: std.manifestJsonMinified(p), +}; + +com.Kustomization( + 'https://github.com/projectsyn/lieutenant-keycloak-idp-controller//config/default', + params.manifests_version, + { + 'ghcr.io/projectsyn/lieutenant-keycloak-idp-controller': { + local image = params.images.lieutenant_keycloak_idp_controller, + newTag: image.tag, + newName: '%(registry)s/%(image)s' % image, + }, + 'gcr.io/kubebuilder/kube-rbac-proxy': { + local image = params.images.kube_rbac_proxy, + newTag: image.tag, + newName: '%(registry)s/%(image)s' % image, + }, + }, + params.kustomize_input { + patches+: [ + patch(removeUpstreamNamespace), + patch(controllerPatch), + ], + labels+: [ + { + pairs: { + 'app.kubernetes.io/managed-by': 'commodore', + }, + }, + ], + }, +) diff --git a/component/main.jsonnet b/component/main.jsonnet index b266f9c..04afd8e 100644 --- a/component/main.jsonnet +++ b/component/main.jsonnet @@ -1,10 +1,16 @@ -// main template for lieutenant-keycloak-idp-controller +// main template for lieutenant-keycloak-idp-controller\ +local com = import 'lib/commodore.libjsonnet'; local kap = import 'lib/kapitan.libjsonnet'; local kube = import 'lib/kube.libjsonnet'; local inv = kap.inventory(); // The hiera parameters for the component local params = inv.parameters.lieutenant_keycloak_idp_controller; +local secrets = com.generateResources(params.secrets, kube.Secret); +local configMaps = com.generateResources(params.config_maps, kube.ConfigMap); + // Define outputs below { + '10_secrets': secrets, + '10_config_maps': configMaps, } diff --git a/tests/defaults.yml b/tests/defaults.yml index a4da5b7..39c1251 100644 --- a/tests/defaults.yml +++ b/tests/defaults.yml @@ -1,3 +1,9 @@ # Overwrite parameters here -# parameters: {...} +parameters: + lieutenant_keycloak_idp_controller: + secrets: + keycloak-user: + stringData: + username: user + password: password diff --git a/tests/golden/defaults/lieutenant-keycloak-idp-controller/lieutenant-keycloak-idp-controller/10_config_maps.yaml b/tests/golden/defaults/lieutenant-keycloak-idp-controller/lieutenant-keycloak-idp-controller/10_config_maps.yaml new file mode 100644 index 0000000..74d779d --- /dev/null +++ b/tests/golden/defaults/lieutenant-keycloak-idp-controller/lieutenant-keycloak-idp-controller/10_config_maps.yaml @@ -0,0 +1,78 @@ +apiVersion: v1 +data: + client-roles.jsonnet: | + local context = std.extVar('context'); + + [{ + // https://github.com/sventorben/keycloak-restrict-client-auth#role-based-mode + role: 'restricted-access', + }] + client.jsonnet: | + local context = std.extVar('context'); + local vars = import 'vars.jsonnet'; + + { + clientId: '%s%s' % [ vars.clientPrefix, context.cluster.metadata.name ], + name: '%s (%s)' % [ context.cluster.spec.displayName, context.cluster.metadata.name ], + description: '', + rootUrl: vars.formatRootUrl(context), + adminUrl: '', + baseUrl: '', + surrogateAuthRequired: false, + enabled: true, + alwaysDisplayInConsole: false, + clientAuthenticatorType: 'client-secret', + redirectUris: [ + '/oauth2/callback', + ], + webOrigins: [], + notBefore: 0, + bearerOnly: false, + consentRequired: false, + standardFlowEnabled: true, + implicitFlowEnabled: false, + directAccessGrantsEnabled: true, + serviceAccountsEnabled: false, + publicClient: false, + frontchannelLogout: true, + protocol: 'openid-connect', + attributes: { + 'oidc.ciba.grant.enabled': 'false', + 'backchannel.logout.session.required': 'true', + 'oauth2.device.authorization.grant.enabled': 'false', + 'display.on.consent.screen': 'false', + 'backchannel.logout.revoke.offline.tokens': 'false', + }, + authenticationFlowBindingOverrides: {}, + fullScopeAllowed: true, + nodeReRegistrationTimeout: -1, + defaultClientScopes: [ + 'web-origins', + 'acr', + 'profile', + 'roles', + 'email', + ], + optionalClientScopes: [ + 'address', + 'phone', + 'offline_access', + 'microprofile-jwt', + ], + access: { + view: true, + configure: true, + manage: true, + }, + } + vars.jsonnet: | + { + clientPrefix: 'cluster_', + formatRootUrl: function(context) 'https://oauth-openshift.apps.%s.dev' % context.cluster.metadata.name, + } +kind: ConfigMap +metadata: + annotations: {} + labels: + name: lieutenant-keycloak-idp-controller-templates + name: lieutenant-keycloak-idp-controller-templates diff --git a/tests/golden/defaults/lieutenant-keycloak-idp-controller/lieutenant-keycloak-idp-controller/10_secrets.yaml b/tests/golden/defaults/lieutenant-keycloak-idp-controller/lieutenant-keycloak-idp-controller/10_secrets.yaml new file mode 100644 index 0000000..f424afb --- /dev/null +++ b/tests/golden/defaults/lieutenant-keycloak-idp-controller/lieutenant-keycloak-idp-controller/10_secrets.yaml @@ -0,0 +1,12 @@ +apiVersion: v1 +data: {} +kind: Secret +metadata: + annotations: {} + labels: + name: keycloak-user + name: keycloak-user +stringData: + password: password + username: user +type: Opaque diff --git a/tests/golden/defaults/lieutenant-keycloak-idp-controller/lieutenant-keycloak-idp-controller/apps_v1_deployment_lieutenant-keycloak-idp-controller-controller-manager.yaml b/tests/golden/defaults/lieutenant-keycloak-idp-controller/lieutenant-keycloak-idp-controller/apps_v1_deployment_lieutenant-keycloak-idp-controller-controller-manager.yaml new file mode 100644 index 0000000..45fce18 --- /dev/null +++ b/tests/golden/defaults/lieutenant-keycloak-idp-controller/lieutenant-keycloak-idp-controller/apps_v1_deployment_lieutenant-keycloak-idp-controller-controller-manager.yaml @@ -0,0 +1,132 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + labels: + app.kubernetes.io/component: manager + app.kubernetes.io/created-by: lieutenant-keycloak-idp-controller + app.kubernetes.io/instance: controller-manager + app.kubernetes.io/managed-by: commodore + app.kubernetes.io/name: deployment + app.kubernetes.io/part-of: lieutenant-keycloak-idp-controller + control-plane: controller-manager + name: lieutenant-keycloak-idp-controller-controller-manager + namespace: syn-lieutenant-keycloak-idp-controller +spec: + replicas: 1 + selector: + matchLabels: + control-plane: controller-manager + template: + metadata: + annotations: + kubectl.kubernetes.io/default-container: manager + labels: + control-plane: controller-manager + spec: + affinity: + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + nodeSelectorTerms: + - matchExpressions: + - key: kubernetes.io/arch + operator: In + values: + - amd64 + - arm64 + - ppc64le + - s390x + - key: kubernetes.io/os + operator: In + values: + - linux + containers: + - args: + - --health-probe-bind-address=:8081 + - --metrics-bind-address=127.0.0.1:8080 + - --leader-elect + - --keycloak-realm=$(KEYCLOAK_REALM) + - --keycloak-base-url=$(KEYCLOAK_BASE_URL) + - --keycloak-user=$(KEYCLOAK_USER) + - --keycloak-password=$(KEYCLOAK_PASSWORD) + - --keycloak-login-realm=$(KEYCLOAK_LOGIN_REALM) + - --keycloak-legacy-wildfly-support=$(KEYCLOAK_LEGACY_WILDFLY_SUPPORT) + - --client-template-file=/templates/client.jsonnet + - --client-role-mapping-template-file=/templates/client-roles.jsonnet + - --vault-token-file=/var/run/secrets/kubernetes.io/serviceaccount/token + - --vault-address=$(VAULT_ADDRESS) + env: + - name: KEYCLOAK_BASE_URL + - name: KEYCLOAK_LEGACY_WILDFLY_SUPPORT + value: "true" + - name: KEYCLOAK_LOGIN_REALM + value: master + - name: KEYCLOAK_PASSWORD + - name: KEYCLOAK_REALM + - name: KEYCLOAK_USER + - name: VAULT_ADDRESS + - name: POD_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + image: ghcr.io/projectsyn/lieutenant-keycloak-idp-controller:v0.1.0-dev1 + livenessProbe: + httpGet: + path: /healthz + port: 8081 + initialDelaySeconds: 15 + periodSeconds: 20 + name: manager + readinessProbe: + httpGet: + path: /readyz + port: 8081 + initialDelaySeconds: 5 + periodSeconds: 10 + resources: + limits: + cpu: 100m + memory: 128Mi + requests: + cpu: 10m + memory: 32Mi + securityContext: + allowPrivilegeEscalation: false + capabilities: + drop: + - ALL + volumeMounts: + - mountPath: /templates + name: templates + - args: + - --secure-listen-address=0.0.0.0:8443 + - --upstream=http://127.0.0.1:8080/ + - --logtostderr=true + - --v=0 + image: gcr.io/kubebuilder/kube-rbac-proxy:v0.14.1 + name: kube-rbac-proxy + ports: + - containerPort: 8443 + name: https + protocol: TCP + resources: + limits: + cpu: 500m + memory: 128Mi + requests: + cpu: 5m + memory: 64Mi + securityContext: + allowPrivilegeEscalation: false + capabilities: + drop: + - ALL + securityContext: + runAsNonRoot: true + seccompProfile: + type: RuntimeDefault + serviceAccountName: lieutenant-keycloak-idp-controller-controller-manager + terminationGracePeriodSeconds: 10 + volumes: + - configMap: + name: lieutenant-keycloak-idp-controller-templates + name: templates diff --git a/tests/golden/defaults/lieutenant-keycloak-idp-controller/lieutenant-keycloak-idp-controller/rbac.authorization.k8s.io_v1_clusterrole_lieutenant-keycloak-idp-controller-manager-role.yaml b/tests/golden/defaults/lieutenant-keycloak-idp-controller/lieutenant-keycloak-idp-controller/rbac.authorization.k8s.io_v1_clusterrole_lieutenant-keycloak-idp-controller-manager-role.yaml new file mode 100644 index 0000000..bb3e0e7 --- /dev/null +++ b/tests/golden/defaults/lieutenant-keycloak-idp-controller/lieutenant-keycloak-idp-controller/rbac.authorization.k8s.io_v1_clusterrole_lieutenant-keycloak-idp-controller-manager-role.yaml @@ -0,0 +1,29 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + labels: + app.kubernetes.io/managed-by: commodore + name: lieutenant-keycloak-idp-controller-manager-role +rules: +- apiGroups: + - syn.tools + resources: + - clusters + verbs: + - get + - list + - watch +- apiGroups: + - syn.tools + resources: + - clusters/finalizers + verbs: + - update +- apiGroups: + - syn.tools + resources: + - clusters/status + verbs: + - get + - patch + - update diff --git a/tests/golden/defaults/lieutenant-keycloak-idp-controller/lieutenant-keycloak-idp-controller/rbac.authorization.k8s.io_v1_clusterrole_lieutenant-keycloak-idp-controller-metrics-reader.yaml b/tests/golden/defaults/lieutenant-keycloak-idp-controller/lieutenant-keycloak-idp-controller/rbac.authorization.k8s.io_v1_clusterrole_lieutenant-keycloak-idp-controller-metrics-reader.yaml new file mode 100644 index 0000000..f9acee1 --- /dev/null +++ b/tests/golden/defaults/lieutenant-keycloak-idp-controller/lieutenant-keycloak-idp-controller/rbac.authorization.k8s.io_v1_clusterrole_lieutenant-keycloak-idp-controller-metrics-reader.yaml @@ -0,0 +1,16 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + labels: + app.kubernetes.io/component: kube-rbac-proxy + app.kubernetes.io/created-by: lieutenant-keycloak-idp-controller + app.kubernetes.io/instance: metrics-reader + app.kubernetes.io/managed-by: commodore + app.kubernetes.io/name: clusterrole + app.kubernetes.io/part-of: lieutenant-keycloak-idp-controller + name: lieutenant-keycloak-idp-controller-metrics-reader +rules: +- nonResourceURLs: + - /metrics + verbs: + - get diff --git a/tests/golden/defaults/lieutenant-keycloak-idp-controller/lieutenant-keycloak-idp-controller/rbac.authorization.k8s.io_v1_clusterrole_lieutenant-keycloak-idp-controller-proxy-role.yaml b/tests/golden/defaults/lieutenant-keycloak-idp-controller/lieutenant-keycloak-idp-controller/rbac.authorization.k8s.io_v1_clusterrole_lieutenant-keycloak-idp-controller-proxy-role.yaml new file mode 100644 index 0000000..412e442 --- /dev/null +++ b/tests/golden/defaults/lieutenant-keycloak-idp-controller/lieutenant-keycloak-idp-controller/rbac.authorization.k8s.io_v1_clusterrole_lieutenant-keycloak-idp-controller-proxy-role.yaml @@ -0,0 +1,24 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + labels: + app.kubernetes.io/component: kube-rbac-proxy + app.kubernetes.io/created-by: lieutenant-keycloak-idp-controller + app.kubernetes.io/instance: proxy-role + app.kubernetes.io/managed-by: commodore + app.kubernetes.io/name: clusterrole + app.kubernetes.io/part-of: lieutenant-keycloak-idp-controller + name: lieutenant-keycloak-idp-controller-proxy-role +rules: +- apiGroups: + - authentication.k8s.io + resources: + - tokenreviews + verbs: + - create +- apiGroups: + - authorization.k8s.io + resources: + - subjectaccessreviews + verbs: + - create diff --git a/tests/golden/defaults/lieutenant-keycloak-idp-controller/lieutenant-keycloak-idp-controller/rbac.authorization.k8s.io_v1_clusterrolebinding_lieutenant-keycloak-idp-controller-manager-rolebinding.yaml b/tests/golden/defaults/lieutenant-keycloak-idp-controller/lieutenant-keycloak-idp-controller/rbac.authorization.k8s.io_v1_clusterrolebinding_lieutenant-keycloak-idp-controller-manager-rolebinding.yaml new file mode 100644 index 0000000..cb263c1 --- /dev/null +++ b/tests/golden/defaults/lieutenant-keycloak-idp-controller/lieutenant-keycloak-idp-controller/rbac.authorization.k8s.io_v1_clusterrolebinding_lieutenant-keycloak-idp-controller-manager-rolebinding.yaml @@ -0,0 +1,19 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + labels: + app.kubernetes.io/component: rbac + app.kubernetes.io/created-by: lieutenant-keycloak-idp-controller + app.kubernetes.io/instance: manager-rolebinding + app.kubernetes.io/managed-by: commodore + app.kubernetes.io/name: clusterrolebinding + app.kubernetes.io/part-of: lieutenant-keycloak-idp-controller + name: lieutenant-keycloak-idp-controller-manager-rolebinding +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: lieutenant-keycloak-idp-controller-manager-role +subjects: +- kind: ServiceAccount + name: lieutenant-keycloak-idp-controller-controller-manager + namespace: syn-lieutenant-keycloak-idp-controller diff --git a/tests/golden/defaults/lieutenant-keycloak-idp-controller/lieutenant-keycloak-idp-controller/rbac.authorization.k8s.io_v1_clusterrolebinding_lieutenant-keycloak-idp-controller-proxy-rolebinding.yaml b/tests/golden/defaults/lieutenant-keycloak-idp-controller/lieutenant-keycloak-idp-controller/rbac.authorization.k8s.io_v1_clusterrolebinding_lieutenant-keycloak-idp-controller-proxy-rolebinding.yaml new file mode 100644 index 0000000..9707981 --- /dev/null +++ b/tests/golden/defaults/lieutenant-keycloak-idp-controller/lieutenant-keycloak-idp-controller/rbac.authorization.k8s.io_v1_clusterrolebinding_lieutenant-keycloak-idp-controller-proxy-rolebinding.yaml @@ -0,0 +1,19 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + labels: + app.kubernetes.io/component: kube-rbac-proxy + app.kubernetes.io/created-by: lieutenant-keycloak-idp-controller + app.kubernetes.io/instance: proxy-rolebinding + app.kubernetes.io/managed-by: commodore + app.kubernetes.io/name: clusterrolebinding + app.kubernetes.io/part-of: lieutenant-keycloak-idp-controller + name: lieutenant-keycloak-idp-controller-proxy-rolebinding +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: lieutenant-keycloak-idp-controller-proxy-role +subjects: +- kind: ServiceAccount + name: lieutenant-keycloak-idp-controller-controller-manager + namespace: syn-lieutenant-keycloak-idp-controller diff --git a/tests/golden/defaults/lieutenant-keycloak-idp-controller/lieutenant-keycloak-idp-controller/rbac.authorization.k8s.io_v1_role_lieutenant-keycloak-idp-controller-leader-election-role.yaml b/tests/golden/defaults/lieutenant-keycloak-idp-controller/lieutenant-keycloak-idp-controller/rbac.authorization.k8s.io_v1_role_lieutenant-keycloak-idp-controller-leader-election-role.yaml new file mode 100644 index 0000000..1038fc5 --- /dev/null +++ b/tests/golden/defaults/lieutenant-keycloak-idp-controller/lieutenant-keycloak-idp-controller/rbac.authorization.k8s.io_v1_role_lieutenant-keycloak-idp-controller-leader-election-role.yaml @@ -0,0 +1,44 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + labels: + app.kubernetes.io/component: rbac + app.kubernetes.io/created-by: lieutenant-keycloak-idp-controller + app.kubernetes.io/instance: leader-election-role + app.kubernetes.io/managed-by: commodore + app.kubernetes.io/name: role + app.kubernetes.io/part-of: lieutenant-keycloak-idp-controller + name: lieutenant-keycloak-idp-controller-leader-election-role + namespace: syn-lieutenant-keycloak-idp-controller +rules: +- apiGroups: + - "" + resources: + - configmaps + verbs: + - get + - list + - watch + - create + - update + - patch + - delete +- apiGroups: + - coordination.k8s.io + resources: + - leases + verbs: + - get + - list + - watch + - create + - update + - patch + - delete +- apiGroups: + - "" + resources: + - events + verbs: + - create + - patch diff --git a/tests/golden/defaults/lieutenant-keycloak-idp-controller/lieutenant-keycloak-idp-controller/rbac.authorization.k8s.io_v1_rolebinding_lieutenant-keycloak-idp-controller-leader-election-rolebinding.yaml b/tests/golden/defaults/lieutenant-keycloak-idp-controller/lieutenant-keycloak-idp-controller/rbac.authorization.k8s.io_v1_rolebinding_lieutenant-keycloak-idp-controller-leader-election-rolebinding.yaml new file mode 100644 index 0000000..8480d34 --- /dev/null +++ b/tests/golden/defaults/lieutenant-keycloak-idp-controller/lieutenant-keycloak-idp-controller/rbac.authorization.k8s.io_v1_rolebinding_lieutenant-keycloak-idp-controller-leader-election-rolebinding.yaml @@ -0,0 +1,20 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + labels: + app.kubernetes.io/component: rbac + app.kubernetes.io/created-by: lieutenant-keycloak-idp-controller + app.kubernetes.io/instance: leader-election-rolebinding + app.kubernetes.io/managed-by: commodore + app.kubernetes.io/name: rolebinding + app.kubernetes.io/part-of: lieutenant-keycloak-idp-controller + name: lieutenant-keycloak-idp-controller-leader-election-rolebinding + namespace: syn-lieutenant-keycloak-idp-controller +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: lieutenant-keycloak-idp-controller-leader-election-role +subjects: +- kind: ServiceAccount + name: lieutenant-keycloak-idp-controller-controller-manager + namespace: syn-lieutenant-keycloak-idp-controller diff --git a/tests/golden/defaults/lieutenant-keycloak-idp-controller/lieutenant-keycloak-idp-controller/rbac.authorization.k8s.io_v1_rolebinding_lieutenant-keycloak-idp-controller-manager-rolebinding.yaml b/tests/golden/defaults/lieutenant-keycloak-idp-controller/lieutenant-keycloak-idp-controller/rbac.authorization.k8s.io_v1_rolebinding_lieutenant-keycloak-idp-controller-manager-rolebinding.yaml new file mode 100644 index 0000000..2c0e743 --- /dev/null +++ b/tests/golden/defaults/lieutenant-keycloak-idp-controller/lieutenant-keycloak-idp-controller/rbac.authorization.k8s.io_v1_rolebinding_lieutenant-keycloak-idp-controller-manager-rolebinding.yaml @@ -0,0 +1,20 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + labels: + app.kubernetes.io/component: rbac + app.kubernetes.io/created-by: lieutenant-keycloak-idp-controller + app.kubernetes.io/instance: manager-rolebinding + app.kubernetes.io/managed-by: commodore + app.kubernetes.io/name: rolebinding + app.kubernetes.io/part-of: lieutenant-keycloak-idp-controller + name: lieutenant-keycloak-idp-controller-manager-rolebinding + namespace: syn-lieutenant-keycloak-idp-controller +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: manager-role +subjects: +- kind: ServiceAccount + name: lieutenant-keycloak-idp-controller-controller-manager + namespace: syn-lieutenant-keycloak-idp-controller diff --git a/tests/golden/defaults/lieutenant-keycloak-idp-controller/lieutenant-keycloak-idp-controller/v1_namespace_syn-lieutenant-keycloak-idp-controller.yaml b/tests/golden/defaults/lieutenant-keycloak-idp-controller/lieutenant-keycloak-idp-controller/v1_namespace_syn-lieutenant-keycloak-idp-controller.yaml new file mode 100644 index 0000000..60f3c85 --- /dev/null +++ b/tests/golden/defaults/lieutenant-keycloak-idp-controller/lieutenant-keycloak-idp-controller/v1_namespace_syn-lieutenant-keycloak-idp-controller.yaml @@ -0,0 +1,12 @@ +apiVersion: v1 +kind: Namespace +metadata: + labels: + app.kubernetes.io/component: manager + app.kubernetes.io/created-by: lieutenant-keycloak-idp-controller + app.kubernetes.io/instance: system + app.kubernetes.io/managed-by: commodore + app.kubernetes.io/name: namespace + app.kubernetes.io/part-of: lieutenant-keycloak-idp-controller + control-plane: controller-manager + name: syn-lieutenant-keycloak-idp-controller diff --git a/tests/golden/defaults/lieutenant-keycloak-idp-controller/lieutenant-keycloak-idp-controller/v1_service_lieutenant-keycloak-idp-controller-controller-manager-metrics.yaml b/tests/golden/defaults/lieutenant-keycloak-idp-controller/lieutenant-keycloak-idp-controller/v1_service_lieutenant-keycloak-idp-controller-controller-manager-metrics.yaml new file mode 100644 index 0000000..21e2078 --- /dev/null +++ b/tests/golden/defaults/lieutenant-keycloak-idp-controller/lieutenant-keycloak-idp-controller/v1_service_lieutenant-keycloak-idp-controller-controller-manager-metrics.yaml @@ -0,0 +1,21 @@ +apiVersion: v1 +kind: Service +metadata: + labels: + app.kubernetes.io/component: kube-rbac-proxy + app.kubernetes.io/created-by: lieutenant-keycloak-idp-controller + app.kubernetes.io/instance: controller-manager-metrics + app.kubernetes.io/managed-by: commodore + app.kubernetes.io/name: service + app.kubernetes.io/part-of: lieutenant-keycloak-idp-controller + control-plane: controller-manager + name: lieutenant-keycloak-idp-controller-controller-manager-metrics + namespace: syn-lieutenant-keycloak-idp-controller +spec: + ports: + - name: https + port: 8443 + protocol: TCP + targetPort: https + selector: + control-plane: controller-manager diff --git a/tests/golden/defaults/lieutenant-keycloak-idp-controller/lieutenant-keycloak-idp-controller/v1_serviceaccount_lieutenant-keycloak-idp-controller-controller-manager.yaml b/tests/golden/defaults/lieutenant-keycloak-idp-controller/lieutenant-keycloak-idp-controller/v1_serviceaccount_lieutenant-keycloak-idp-controller-controller-manager.yaml new file mode 100644 index 0000000..fdc9fe9 --- /dev/null +++ b/tests/golden/defaults/lieutenant-keycloak-idp-controller/lieutenant-keycloak-idp-controller/v1_serviceaccount_lieutenant-keycloak-idp-controller-controller-manager.yaml @@ -0,0 +1,12 @@ +apiVersion: v1 +kind: ServiceAccount +metadata: + labels: + app.kubernetes.io/component: rbac + app.kubernetes.io/created-by: lieutenant-keycloak-idp-controller + app.kubernetes.io/instance: controller-manager + app.kubernetes.io/managed-by: commodore + app.kubernetes.io/name: serviceaccount + app.kubernetes.io/part-of: lieutenant-keycloak-idp-controller + name: lieutenant-keycloak-idp-controller-controller-manager + namespace: syn-lieutenant-keycloak-idp-controller From d2fc2f38aa5f404e1fc4424663fc50c891d79638 Mon Sep 17 00:00:00 2001 From: Sebastian Widmer Date: Thu, 7 Dec 2023 16:13:03 +0100 Subject: [PATCH 02/11] Use kubelogin defaults for created clients --- class/defaults.yml | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/class/defaults.yml b/class/defaults.yml index 0171f9e..a409272 100644 --- a/class/defaults.yml +++ b/class/defaults.yml @@ -56,7 +56,12 @@ parameters: vars.jsonnet: | { clientPrefix: 'cluster_', - formatRootUrl: function(context) 'https://oauth-openshift.apps.%s.dev' % context.cluster.metadata.name, + rootUrl: function(context) null, + // Defaults for https://github.com/int128/kubelogin + redirectUris: function(context) [ + 'http://localhost:18000', + 'http://localhost:8000', + ], } client.jsonnet: | local context = std.extVar('context'); @@ -66,16 +71,14 @@ parameters: clientId: '%s%s' % [ vars.clientPrefix, context.cluster.metadata.name ], name: '%s (%s)' % [ context.cluster.spec.displayName, context.cluster.metadata.name ], description: '', - rootUrl: vars.formatRootUrl(context), + rootUrl: vars.rootUrl(context), adminUrl: '', baseUrl: '', surrogateAuthRequired: false, enabled: true, alwaysDisplayInConsole: false, clientAuthenticatorType: 'client-secret', - redirectUris: [ - '/oauth2/callback', - ], + redirectUris: vars.redirectUris(context), webOrigins: [], notBefore: 0, bearerOnly: false, From 82ad90db6a2a6a0deaefb7f46fc44a74ccc24f55 Mon Sep 17 00:00:00 2001 From: Sebastian Widmer Date: Thu, 7 Dec 2023 17:34:08 +0100 Subject: [PATCH 03/11] Add OCP integration --- class/defaults.yml | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/class/defaults.yml b/class/defaults.yml index a409272..8abce9f 100644 --- a/class/defaults.yml +++ b/class/defaults.yml @@ -56,29 +56,38 @@ parameters: vars.jsonnet: | { clientPrefix: 'cluster_', - rootUrl: function(context) null, - // Defaults for https://github.com/int128/kubelogin - redirectUris: function(context) [ - 'http://localhost:18000', - 'http://localhost:8000', - ], + ocpIntegrationName: 'idp', } + client.jsonnet: | local context = std.extVar('context'); local vars = import 'vars.jsonnet'; + local redirectUris = function(context) + local facts = context.cluster.status.facts; + if std.objectHas(facts, 'openshiftOAuthRoute') && facts.openshiftOAuthRoute then + [ + 'https://%s/oauth2callback/%s' % [ std.parseJson(facts.openshiftOAuthRoute), vars.ocpIntegrationName ], + ] + else + [ + // Defaults for https://github.com/int128/kubelogin + 'http://localhost:18000/callback', + 'http://localhost:8000/callback', + ]; + { clientId: '%s%s' % [ vars.clientPrefix, context.cluster.metadata.name ], name: '%s (%s)' % [ context.cluster.spec.displayName, context.cluster.metadata.name ], description: '', - rootUrl: vars.rootUrl(context), + rootUrl: '', adminUrl: '', baseUrl: '', surrogateAuthRequired: false, enabled: true, alwaysDisplayInConsole: false, clientAuthenticatorType: 'client-secret', - redirectUris: vars.redirectUris(context), + redirectUris: redirectUris(context), webOrigins: [], notBefore: 0, bearerOnly: false, @@ -119,6 +128,7 @@ parameters: manage: true, }, } + client-roles.jsonnet: | local context = std.extVar('context'); From e60070ba3e53d049b13d60b22c1c7feda1935ea8 Mon Sep 17 00:00:00 2001 From: Sebastian Widmer Date: Thu, 7 Dec 2023 17:47:09 +0100 Subject: [PATCH 04/11] Clusters that never had a steward connected don't have facts --- class/defaults.yml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/class/defaults.yml b/class/defaults.yml index 8abce9f..48bb90b 100644 --- a/class/defaults.yml +++ b/class/defaults.yml @@ -64,10 +64,9 @@ parameters: local vars = import 'vars.jsonnet'; local redirectUris = function(context) - local facts = context.cluster.status.facts; - if std.objectHas(facts, 'openshiftOAuthRoute') && facts.openshiftOAuthRoute then + if std.objectHas(context.cluster.status, 'facts') && std.objectHas(context.cluster.status.facts, 'openshiftOAuthRoute') then [ - 'https://%s/oauth2callback/%s' % [ std.parseJson(facts.openshiftOAuthRoute), vars.ocpIntegrationName ], + 'https://%s/oauth2callback/%s' % [ std.parseJson(context.cluster.status.facts.openshiftOAuthRoute), vars.ocpIntegrationName ], ] else [ From 2fa06826afc33f7ae61a36d74f4da27e1ce03a8e Mon Sep 17 00:00:00 2001 From: Sebastian Widmer Date: Thu, 7 Dec 2023 18:57:14 +0100 Subject: [PATCH 05/11] Disable full scope by default --- class/defaults.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/class/defaults.yml b/class/defaults.yml index 48bb90b..d4455c7 100644 --- a/class/defaults.yml +++ b/class/defaults.yml @@ -106,7 +106,7 @@ parameters: 'backchannel.logout.revoke.offline.tokens': 'false', }, authenticationFlowBindingOverrides: {}, - fullScopeAllowed: true, + fullScopeAllowed: false, nodeReRegistrationTimeout: -1, defaultClientScopes: [ 'web-origins', From 84dd0ab600fec40650ef5ea0c2298c77f4b25a44 Mon Sep 17 00:00:00 2001 From: Sebastian Widmer Date: Thu, 7 Dec 2023 19:27:49 +0100 Subject: [PATCH 06/11] Keycloak sorts weird --- class/defaults.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/class/defaults.yml b/class/defaults.yml index d4455c7..932f79f 100644 --- a/class/defaults.yml +++ b/class/defaults.yml @@ -71,8 +71,8 @@ parameters: else [ // Defaults for https://github.com/int128/kubelogin - 'http://localhost:18000/callback', 'http://localhost:8000/callback', + 'http://localhost:18000/callback', ]; { From 1ded1fc17028cdc3497532095b4aa0f05ea24b56 Mon Sep 17 00:00:00 2001 From: Sebastian Widmer Date: Thu, 7 Dec 2023 20:29:28 +0100 Subject: [PATCH 07/11] Add client role protocol mapper --- class/defaults.yml | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/class/defaults.yml b/class/defaults.yml index 932f79f..5a9958f 100644 --- a/class/defaults.yml +++ b/class/defaults.yml @@ -75,8 +75,10 @@ parameters: 'http://localhost:18000/callback', ]; + local clientId = '%s%s' % [ vars.clientPrefix, context.cluster.metadata.name ]; + { - clientId: '%s%s' % [ vars.clientPrefix, context.cluster.metadata.name ], + clientId: clientId, name: '%s (%s)' % [ context.cluster.spec.displayName, context.cluster.metadata.name ], description: '', rootUrl: '', @@ -98,6 +100,25 @@ parameters: publicClient: false, frontchannelLogout: true, protocol: 'openid-connect', + protocolMappers: [ + { + name: 'client roles', + protocol: 'openid-connect', + protocolMapper: 'oidc-usermodel-client-role-mapper', + consentRequired: false, + config: { + 'userinfo.token.claim': 'true', + multivalued: 'true', + // Yes this is somehow the default value + 'user.attribute': 'foo', + 'id.token.claim': 'true', + 'access.token.claim': 'true', + 'claim.name': 'roles', + 'jsonType.label': 'String', + 'usermodel.clientRoleMapping.clientId': clientId, + }, + }, + ], attributes: { 'oidc.ciba.grant.enabled': 'false', 'backchannel.logout.session.required': 'true', From 8023bd5bf91c75c5935f304a520e7ed1a3686fea Mon Sep 17 00:00:00 2001 From: Sebastian Widmer Date: Thu, 7 Dec 2023 20:38:24 +0100 Subject: [PATCH 08/11] Ignore protocolMappers id for client diff --- class/defaults.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/class/defaults.yml b/class/defaults.yml index 5a9958f..a2a7aff 100644 --- a/class/defaults.yml +++ b/class/defaults.yml @@ -52,6 +52,8 @@ parameters: - --vault-token-file=/var/run/secrets/kubernetes.io/serviceaccount/token - --vault-address=$(VAULT_ADDRESS) + - --keycloak-client-ignore-paths=/protocolMappers/0/id + templates: vars.jsonnet: | { From 6757c2bd3be24aa7db8d3e4a08c8f11ce5189b8c Mon Sep 17 00:00:00 2001 From: Sebastian Widmer Date: Fri, 8 Dec 2023 09:41:05 +0100 Subject: [PATCH 09/11] Auto restart on template change --- ...lieutenant-keycloak-idp-controller.jsonnet | 7 +++ .../10_config_maps.yaml | 45 ++++++++++++++++--- ...oak-idp-controller-controller-manager.yaml | 2 + ...-keycloak-idp-controller-manager-role.yaml | 2 + 4 files changed, 49 insertions(+), 7 deletions(-) diff --git a/component/lieutenant-keycloak-idp-controller.jsonnet b/component/lieutenant-keycloak-idp-controller.jsonnet index b1a71dc..f1308ea 100644 --- a/component/lieutenant-keycloak-idp-controller.jsonnet +++ b/component/lieutenant-keycloak-idp-controller.jsonnet @@ -26,6 +26,13 @@ local controllerPatch = { }, spec: { template: { + metadata: { + annotations: std.foldl( + function(prev, k) prev { ['configmap/%s' % k]: std.md5(std.manifestJsonMinified(params.config_maps[k])) }, + std.objectFields(params.config_maps), + {} + ), + }, spec: { containers: [ { name: 'manager', diff --git a/tests/golden/defaults/lieutenant-keycloak-idp-controller/lieutenant-keycloak-idp-controller/10_config_maps.yaml b/tests/golden/defaults/lieutenant-keycloak-idp-controller/lieutenant-keycloak-idp-controller/10_config_maps.yaml index 74d779d..5933d13 100644 --- a/tests/golden/defaults/lieutenant-keycloak-idp-controller/lieutenant-keycloak-idp-controller/10_config_maps.yaml +++ b/tests/golden/defaults/lieutenant-keycloak-idp-controller/lieutenant-keycloak-idp-controller/10_config_maps.yaml @@ -11,20 +11,32 @@ data: local context = std.extVar('context'); local vars = import 'vars.jsonnet'; + local redirectUris = function(context) + if std.objectHas(context.cluster.status, 'facts') && std.objectHas(context.cluster.status.facts, 'openshiftOAuthRoute') then + [ + 'https://%s/oauth2callback/%s' % [ std.parseJson(context.cluster.status.facts.openshiftOAuthRoute), vars.ocpIntegrationName ], + ] + else + [ + // Defaults for https://github.com/int128/kubelogin + 'http://localhost:8000/callback', + 'http://localhost:18000/callback', + ]; + + local clientId = '%s%s' % [ vars.clientPrefix, context.cluster.metadata.name ]; + { - clientId: '%s%s' % [ vars.clientPrefix, context.cluster.metadata.name ], + clientId: clientId, name: '%s (%s)' % [ context.cluster.spec.displayName, context.cluster.metadata.name ], description: '', - rootUrl: vars.formatRootUrl(context), + rootUrl: '', adminUrl: '', baseUrl: '', surrogateAuthRequired: false, enabled: true, alwaysDisplayInConsole: false, clientAuthenticatorType: 'client-secret', - redirectUris: [ - '/oauth2/callback', - ], + redirectUris: redirectUris(context), webOrigins: [], notBefore: 0, bearerOnly: false, @@ -36,6 +48,25 @@ data: publicClient: false, frontchannelLogout: true, protocol: 'openid-connect', + protocolMappers: [ + { + name: 'client roles', + protocol: 'openid-connect', + protocolMapper: 'oidc-usermodel-client-role-mapper', + consentRequired: false, + config: { + 'userinfo.token.claim': 'true', + multivalued: 'true', + // Yes this is somehow the default value + 'user.attribute': 'foo', + 'id.token.claim': 'true', + 'access.token.claim': 'true', + 'claim.name': 'roles', + 'jsonType.label': 'String', + 'usermodel.clientRoleMapping.clientId': clientId, + }, + }, + ], attributes: { 'oidc.ciba.grant.enabled': 'false', 'backchannel.logout.session.required': 'true', @@ -44,7 +75,7 @@ data: 'backchannel.logout.revoke.offline.tokens': 'false', }, authenticationFlowBindingOverrides: {}, - fullScopeAllowed: true, + fullScopeAllowed: false, nodeReRegistrationTimeout: -1, defaultClientScopes: [ 'web-origins', @@ -68,7 +99,7 @@ data: vars.jsonnet: | { clientPrefix: 'cluster_', - formatRootUrl: function(context) 'https://oauth-openshift.apps.%s.dev' % context.cluster.metadata.name, + ocpIntegrationName: 'idp', } kind: ConfigMap metadata: diff --git a/tests/golden/defaults/lieutenant-keycloak-idp-controller/lieutenant-keycloak-idp-controller/apps_v1_deployment_lieutenant-keycloak-idp-controller-controller-manager.yaml b/tests/golden/defaults/lieutenant-keycloak-idp-controller/lieutenant-keycloak-idp-controller/apps_v1_deployment_lieutenant-keycloak-idp-controller-controller-manager.yaml index 45fce18..bb7b66e 100644 --- a/tests/golden/defaults/lieutenant-keycloak-idp-controller/lieutenant-keycloak-idp-controller/apps_v1_deployment_lieutenant-keycloak-idp-controller-controller-manager.yaml +++ b/tests/golden/defaults/lieutenant-keycloak-idp-controller/lieutenant-keycloak-idp-controller/apps_v1_deployment_lieutenant-keycloak-idp-controller-controller-manager.yaml @@ -19,6 +19,7 @@ spec: template: metadata: annotations: + configmap/lieutenant-keycloak-idp-controller-templates: e1bf9c8a61dc2639d541a3e83ff1ac45 kubectl.kubernetes.io/default-container: manager labels: control-plane: controller-manager @@ -54,6 +55,7 @@ spec: - --client-role-mapping-template-file=/templates/client-roles.jsonnet - --vault-token-file=/var/run/secrets/kubernetes.io/serviceaccount/token - --vault-address=$(VAULT_ADDRESS) + - --keycloak-client-ignore-paths=/protocolMappers/0/id env: - name: KEYCLOAK_BASE_URL - name: KEYCLOAK_LEGACY_WILDFLY_SUPPORT diff --git a/tests/golden/defaults/lieutenant-keycloak-idp-controller/lieutenant-keycloak-idp-controller/rbac.authorization.k8s.io_v1_clusterrole_lieutenant-keycloak-idp-controller-manager-role.yaml b/tests/golden/defaults/lieutenant-keycloak-idp-controller/lieutenant-keycloak-idp-controller/rbac.authorization.k8s.io_v1_clusterrole_lieutenant-keycloak-idp-controller-manager-role.yaml index bb3e0e7..5dfc912 100644 --- a/tests/golden/defaults/lieutenant-keycloak-idp-controller/lieutenant-keycloak-idp-controller/rbac.authorization.k8s.io_v1_clusterrole_lieutenant-keycloak-idp-controller-manager-role.yaml +++ b/tests/golden/defaults/lieutenant-keycloak-idp-controller/lieutenant-keycloak-idp-controller/rbac.authorization.k8s.io_v1_clusterrole_lieutenant-keycloak-idp-controller-manager-role.yaml @@ -12,6 +12,8 @@ rules: verbs: - get - list + - patch + - update - watch - apiGroups: - syn.tools From 04bcb14ee55bca63b5e82195859f0eff28bfe5f3 Mon Sep 17 00:00:00 2001 From: Sebastian Widmer Date: Fri, 8 Dec 2023 09:56:42 +0100 Subject: [PATCH 10/11] Switch to release manifests --- class/defaults.yml | 2 +- ...t_lieutenant-keycloak-idp-controller-controller-manager.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/class/defaults.yml b/class/defaults.yml index a2a7aff..6c050ce 100644 --- a/class/defaults.yml +++ b/class/defaults.yml @@ -13,7 +13,7 @@ parameters: lieutenant_keycloak_idp_controller: registry: ghcr.io image: projectsyn/lieutenant-keycloak-idp-controller - tag: v0.1.0-dev1 + tag: v0.1.0 kube_rbac_proxy: registry: gcr.io image: kubebuilder/kube-rbac-proxy diff --git a/tests/golden/defaults/lieutenant-keycloak-idp-controller/lieutenant-keycloak-idp-controller/apps_v1_deployment_lieutenant-keycloak-idp-controller-controller-manager.yaml b/tests/golden/defaults/lieutenant-keycloak-idp-controller/lieutenant-keycloak-idp-controller/apps_v1_deployment_lieutenant-keycloak-idp-controller-controller-manager.yaml index bb7b66e..bf05bfb 100644 --- a/tests/golden/defaults/lieutenant-keycloak-idp-controller/lieutenant-keycloak-idp-controller/apps_v1_deployment_lieutenant-keycloak-idp-controller-controller-manager.yaml +++ b/tests/golden/defaults/lieutenant-keycloak-idp-controller/lieutenant-keycloak-idp-controller/apps_v1_deployment_lieutenant-keycloak-idp-controller-controller-manager.yaml @@ -70,7 +70,7 @@ spec: valueFrom: fieldRef: fieldPath: metadata.namespace - image: ghcr.io/projectsyn/lieutenant-keycloak-idp-controller:v0.1.0-dev1 + image: ghcr.io/projectsyn/lieutenant-keycloak-idp-controller:v0.1.0 livenessProbe: httpGet: path: /healthz From b794f534c37fa7f3a6dabd0a738b8f967ee0c692 Mon Sep 17 00:00:00 2001 From: Sebastian Widmer Date: Fri, 8 Dec 2023 10:33:53 +0100 Subject: [PATCH 11/11] Docs, allow overriding resources --- class/defaults.yml | 8 + ...lieutenant-keycloak-idp-controller.jsonnet | 1 + .../ROOT/pages/references/parameters.adoc | 171 +++++++++++++++++- 3 files changed, 178 insertions(+), 2 deletions(-) diff --git a/class/defaults.yml b/class/defaults.yml index 6c050ce..ecea811 100644 --- a/class/defaults.yml +++ b/class/defaults.yml @@ -54,6 +54,14 @@ parameters: - --keycloak-client-ignore-paths=/protocolMappers/0/id + resources: + limits: + cpu: 100m + memory: 128Mi + requests: + cpu: 10m + memory: 32Mi + templates: vars.jsonnet: | { diff --git a/component/lieutenant-keycloak-idp-controller.jsonnet b/component/lieutenant-keycloak-idp-controller.jsonnet index f1308ea..993673c 100644 --- a/component/lieutenant-keycloak-idp-controller.jsonnet +++ b/component/lieutenant-keycloak-idp-controller.jsonnet @@ -38,6 +38,7 @@ local controllerPatch = { name: 'manager', args: params.controller.args, env: com.envList(params.controller.env), + resources: params.controller.resources, volumeMounts: [ { name: 'templates', mountPath: '/templates', diff --git a/docs/modules/ROOT/pages/references/parameters.adoc b/docs/modules/ROOT/pages/references/parameters.adoc index 4f062e8..e80c972 100644 --- a/docs/modules/ROOT/pages/references/parameters.adoc +++ b/docs/modules/ROOT/pages/references/parameters.adoc @@ -11,9 +11,176 @@ default:: `syn-lieutenant-keycloak-idp-controller` The namespace in which to deploy this component. -== Example +== `namespaceMetadata` +[horizontal] +type:: dict +default:: `{}` + +Metadata to be added to the namespace. + + +== `images` + +[horizontal] +type:: dictionary + +The images to use for this component. + + +== `manifests_version` + +[horizontal] +type:: string +default:: `${lieutenant_keycloak_idp_controller:images:lieutenant_keycloak_idp_controller:tag}` + +The Git reference to the controller deployment manifests. +The default is the tag of the controller image. + + +== `controller.env` + +[horizontal] +type:: dict +default:: ++ +[source,yaml] +---- +KEYCLOAK_BASE_URL: +KEYCLOAK_USER: +KEYCLOAK_PASSWORD: +KEYCLOAK_REALM: +KEYCLOAK_LOGIN_REALM: master +KEYCLOAK_LEGACY_WILDFLY_SUPPORT: 'true' +VAULT_ADDRESS: +---- ++ +example:: ++ +[source,yaml] +---- +KEYCLOAK_BASE_URL: https://id.example.net +KEYCLOAK_USER: svc_lieutenant-keycloak-idp-controller +KEYCLOAK_PASSWORD: + secretKeyRef: + name: keycloak-credentials + key: password +KEYCLOAK_REALM: myrealm +KEYCLOAK_LOGIN_REALM: master +KEYCLOAK_LEGACY_WILDFLY_SUPPORT: 'true' +VAULT_ADDRESS: https://vault.syn.example.net/ +---- + +The environment variables to set for the controller container. +String values are taken verbatim as the `value` fiels, dictionary values are rendered as `valueFrom` fields. + + +== `controller.args` + +[horizontal] +type:: list +default:: ++ +[source,yaml] +---- +- --health-probe-bind-address=:8081 +- --metrics-bind-address=127.0.0.1:8080 +- --leader-elect + +- --keycloak-realm=$(KEYCLOAK_REALM) +- --keycloak-base-url=$(KEYCLOAK_BASE_URL) +- --keycloak-user=$(KEYCLOAK_USER) +- --keycloak-password=$(KEYCLOAK_PASSWORD) +- --keycloak-login-realm=$(KEYCLOAK_LOGIN_REALM) +- --keycloak-legacy-wildfly-support=$(KEYCLOAK_LEGACY_WILDFLY_SUPPORT) + +- --client-template-file=/templates/client.jsonnet +- --client-role-mapping-template-file=/templates/client-roles.jsonnet + +- --vault-token-file=/var/run/secrets/kubernetes.io/serviceaccount/token +- --vault-address=$(VAULT_ADDRESS) + +- --keycloak-client-ignore-paths=/protocolMappers/0/id +---- + +The arguments to pass to the controller container. + + +== `controller.resources` + +[horizontal] +type:: dict +default:: ++ +[source,yaml] +---- +limits: + cpu: 100m + memory: 128Mi +requests: + cpu: 10m + memory: 32Mi +---- + +The resource limits and requests for the controller container. + + +== `templates` + +[horizontal] +type:: dict +default:: See https://github.com/projectsyn/component-lieutenant-keycloak-idp-controller/blob/master/class/defaults.yml[`defaults.yml`] + +The templates for the controller to use. +Templates can include each other using the `import` function. + +Default template creates a client with the following settings: +- full scope is disabled for security reasons +- access type is confidential +- standard flow is enabled +- direct access grants are enabled +- client role `restricted-access` is created for https://github.com/sventorben/keycloak-restrict-client-auth#role-based-mode +- client roles are mapped to the `roles` key of the JWT token + + +== `secrets` + +[horizontal] +type:: dict +default:: `{}` +example:: ++ +[source,yaml] +---- +secrets: + keycloak-credentials: + stringData: + password: "?{vaultkv:${cluster:tenant}/${cluster:name}/lieutenant-keycloak-idp-controller/keycloak/password}" +---- + +This parameter allows to deploy arbitrary secrets. +Each entry is transformed into a Secret resource. +The key is used as the name of the resulting resource. +The provided value is merged with an empty Secret resource. + +[WARNING] +Always use `stringData` when using Vault references in secret configurations. + + +== `config_maps` + +[horizontal] +type:: dict +default:: ++ [source,yaml] ---- -namespace: example-namespace +config_maps: + lieutenant-keycloak-idp-controller-templates: + data: ${lieutenant_keycloak_idp_controller:templates} ---- + +This parameter allows to deploy arbitrary config maps. +Each entry is transformed into a ConfigMap resource. +The key is used as the name of the resulting resource. +The provided value is merged with an empty ConfigMap resource.