diff --git a/infrastructure/charts/agent/Chart.lock b/infrastructure/charts/agent/Chart.lock index bb4e27f18a..9993ab14a0 100644 --- a/infrastructure/charts/agent/Chart.lock +++ b/infrastructure/charts/agent/Chart.lock @@ -2,5 +2,8 @@ dependencies: - name: vault repository: https://helm.releases.hashicorp.com version: 0.24.1 -digest: sha256:f9ee9a8708d36ff7fcf9334fe17404147be8c124ead65830ee72bd4f43c262cd -generated: "2023-06-16T14:40:33.224500592+10:00" +- name: keycloak + repository: https://charts.bitnami.com/bitnami + version: 17.2.0 +digest: sha256:33f82ebad234a60fd00365d1dcc6ed884beeac1c13ee4cbeca08a1478eded850 +generated: "2023-11-16T20:59:38.47688305+07:00" diff --git a/infrastructure/charts/agent/Chart.yaml b/infrastructure/charts/agent/Chart.yaml index 1f8628ced1..a65216b8be 100644 --- a/infrastructure/charts/agent/Chart.yaml +++ b/infrastructure/charts/agent/Chart.yaml @@ -23,3 +23,7 @@ dependencies: - name: vault version: 0.24.1 repository: https://helm.releases.hashicorp.com + - name: keycloak + version: "17.2.0" + repository: "https://charts.bitnami.com/bitnami" + condition: keycloak.enabled diff --git a/infrastructure/charts/agent/templates/configmap.yaml b/infrastructure/charts/agent/templates/configmap.yaml new file mode 100644 index 0000000000..832a197063 --- /dev/null +++ b/infrastructure/charts/agent/templates/configmap.yaml @@ -0,0 +1,92 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: keycloak-bootstrap-script +data: + init.sh: | + #!/usr/bin/env bash + + set -e + set -u + + KEYCLOAK_BASE_URL=$KEYCLOAK_BASE_URL + KEYCLOAK_ADMIN_USER=$KEYCLOAK_ADMIN_USER + KEYCLOAK_ADMIN_PASSWORD=$KEYCLOAK_ADMIN_PASSWORD + REALM_NAME=$REALM_NAME + PRISM_AGENT_CLIENT_ID=$PRISM_AGENT_CLIENT_ID + PRISM_AGENT_CLIENT_SECRET=$PRISM_AGENT_CLIENT_SECRET + + function get_admin_token() { + local response=$( + curl --request POST "$KEYCLOAK_BASE_URL/realms/master/protocol/openid-connect/token" \ + --fail -s -v \ + --data-urlencode "grant_type=password" \ + --data-urlencode "client_id=admin-cli" \ + --data-urlencode "username=$KEYCLOAK_ADMIN_USER" \ + --data-urlencode "password=$KEYCLOAK_ADMIN_PASSWORD" + ) + local access_token=$(echo $response | jq -r '.access_token') + echo $access_token + } + + function is_client_exists() { + local access_token=$1 + local client_id=$2 + + local http_status=$( + curl --request GET "$KEYCLOAK_BASE_URL/admin/realms/$REALM_NAME/clients/$client_id" \ + -s -w "%{http_code}" \ + -o /dev/null \ + -H "Authorization: Bearer $access_token" + ) + + if [ $http_status == 200 ]; then + echo "true" + else + echo "false" + fi + } + + function create_client() { + local access_token=$1 + local client_id=$2 + local client_secret=$3 + + curl --request POST "$KEYCLOAK_BASE_URL/admin/realms/$REALM_NAME/clients" \ + --fail -s \ + -H "Authorization: Bearer $access_token" \ + -H "Content-Type: application/json" \ + --data-raw "{ + \"id\": \"$client_id\", + \"directAccessGrantsEnabled\": true, + \"authorizationServicesEnabled\": true, + \"serviceAccountsEnabled\": true, + \"secret\": \"$client_secret\" + }" + } + + echo "Getting admin access token ..." + ADMIN_ACCESS_TOKEN=$(get_admin_token) + + CLIENT_EXIST=$(is_client_exists $ADMIN_ACCESS_TOKEN $PRISM_AGENT_CLIENT_ID) + if [ $CLIENT_EXIST == "false" ]; then + echo "Creating a new $PRISM_AGENT_CLIENT_ID client ..." + create_client $ADMIN_ACCESS_TOKEN $PRISM_AGENT_CLIENT_ID $PRISM_AGENT_CLIENT_SECRET + fi + +{{- if .Values.keycloak.enabled }} + +--- + +apiVersion: v1 +kind: ConfigMap +metadata: + name: prism-agent-realm-import +data: + prism-agent.json: | + { + "realm": {{ .Values.server.keycloak.realm | quote }}, + "enabled": true + } + +{{- end }} diff --git a/infrastructure/charts/agent/templates/deployment.yaml b/infrastructure/charts/agent/templates/deployment.yaml index 459079739c..2860639eee 100644 --- a/infrastructure/charts/agent/templates/deployment.yaml +++ b/infrastructure/charts/agent/templates/deployment.yaml @@ -22,6 +22,35 @@ spec: - name: wait-postgress-ready image: busybox command: ['sh', '-c', "until nc -z {{ .Values.database.postgres.managingTeam }}-prism-agent-postgres-cluster.{{.Release.Namespace}} 5432; do echo waiting for postgress-operator; sleep 2; done;"] + {{- if .Values.server.keycloak.enabled }} + - name: wait-keycloak-ready + image: badouralix/curl-jq:ubuntu + command: ['/bin/bash', '-c', 'until curl http://{{ .Release.Name }}-keycloak/health/ready; do sleep 2; done && echo "Keycloak is ready."'] + {{- if .Values.server.keycloak.bootstrap }} + - name: keycloak-bootstrap + image: badouralix/curl-jq:ubuntu + command: ['/bin/bash', '-c', '/scripts/init.sh'] + env: + - name: KEYCLOAK_BASE_URL + value: http://{{ .Release.Name }}-keycloak + - name: KEYCLOAK_ADMIN_USER + value: {{ .Values.server.keycloak.admin.username }} + - name: KEYCLOAK_ADMIN_PASSWORD + valueFrom: + {{- toYaml .Values.server.keycloak.admin.password | nindent 12 }} + - name: REALM_NAME + value: {{ .Values.server.keycloak.realm }} + - name: PRISM_AGENT_CLIENT_ID + value: {{ .Values.server.keycloak.client.clientId }} + - name: PRISM_AGENT_CLIENT_SECRET + valueFrom: + {{- toYaml .Values.server.keycloak.client.clientSecret | nindent 12 }} + volumeMounts: + - name: keycloak-bootstrap-script + mountPath: /scripts + readOnly: true + {{- end }} + {{- end }} containers: - name: prism-agent-server image: "{{ .Values.server.image.repository }}/{{ .Values.server.image.tag }}:{{ .Values.server.image.version | default .Chart.AppVersion }}" @@ -165,7 +194,30 @@ spec: key: root-token optional: false {{- end }} + {{- if .Values.server.keycloak.enabled }} + - name: KEYCLOAK_ENABLED + value: "true" + - name: KEYCLOAK_URL + value: http://{{ .Release.Name }}-keycloak + - name: KEYCLOAK_REALM + value: {{ .Values.server.keycloak.realm }} + - name: KEYCLOAK_CLIENT_ID + value: {{ .Values.server.keycloak.client.clientId }} + - name: KEYCLOAK_CLIENT_SECRET + valueFrom: + {{- toYaml .Values.server.keycloak.client.clientSecret | nindent 14 }} + {{- end }} {{- range $key, $value := .Values.server.additionalEnvVariables }} - name: {{ $key }} value: {{ $value | quote }} {{- end }} + {{- if .Values.server.keycloak.bootstrap }} + volumes: + - name: keycloak-bootstrap-script + configMap: + name: keycloak-bootstrap-script + defaultMode: 0500 + items: + - key: "init.sh" + path: "init.sh" + {{- end }} diff --git a/infrastructure/charts/agent/templates/postgresql.yaml b/infrastructure/charts/agent/templates/postgresql.yaml index d65da0554e..15b2a77e8b 100644 --- a/infrastructure/charts/agent/templates/postgresql.yaml +++ b/infrastructure/charts/agent/templates/postgresql.yaml @@ -32,3 +32,30 @@ spec: agent: agent-admin postgresql: version: "14" + +{{- if .Values.keycloak.enabled }} +--- + +apiVersion: "acid.zalan.do/v1" +kind: postgresql +metadata: + name: "{{ .Values.database.postgres.managingTeam }}-keycloak-postgres-cluster" + namespace: {{ .Release.Namespace }} + labels: + {{ template "labels.common" . }} +spec: + teamId: "{{ .Values.database.postgres.managingTeam }}" + volume: + size: "{{ .Values.database.postgres.databaseSize }}" + numberOfInstances: {{ .Values.database.postgres.numberOfInstances }} + users: + keycloak-admin: + - superuser + - createdb + keycloak-user: [] + databases: + keycloak: keycloak-admin + postgresql: + version: "14" + +{{- end }} diff --git a/infrastructure/charts/agent/templates/stringsecret-agent-keycloak-secret.yaml b/infrastructure/charts/agent/templates/stringsecret-agent-keycloak-secret.yaml new file mode 100644 index 0000000000..85d6045ee7 --- /dev/null +++ b/infrastructure/charts/agent/templates/stringsecret-agent-keycloak-secret.yaml @@ -0,0 +1,30 @@ +apiVersion: "secretgenerator.mittwald.de/v1alpha1" +kind: StringSecret +metadata: + name: "agent-keycloak-client-secret" + namespace: {{ .Release.Namespace }} +spec: + forceRegenerate: false + fields: + - fieldName: "secret" + encoding: "base64" + length: "16" + +--- + +apiVersion: "secretgenerator.mittwald.de/v1alpha1" +kind: StringSecret +metadata: + name: "keycloak-admin-secret" + namespace: {{ .Release.Namespace }} + labels: + {{ template "labels.common" . }} +spec: + forceRegenerate: false + fields: + - fieldName: "password" + encoding: "base64" + length: "32" + - fieldName: "postgres-password" + encoding: "base64" + length: "32" diff --git a/infrastructure/charts/agent/values.yaml b/infrastructure/charts/agent/values.yaml index 99abbefecb..b8d462c347 100644 --- a/infrastructure/charts/agent/values.yaml +++ b/infrastructure/charts/agent/values.yaml @@ -29,8 +29,23 @@ server: cpu: 250m memory: 512Mi additionalEnvVariables: [] - devMode: false useVault: true + keycloak: + enabled: false + realm: prism-agent + bootstrap: true + admin: + username: atala + password: + secretKeyRef: + name: keycloak-admin-secret + key: password + client: + clientId: prism-agent + clientSecret: + secretKeyRef: + name: agent-keycloak-client-secret + key: secret database: postgres: @@ -86,3 +101,36 @@ vault: backend = "kv" version = 2 } + +keycloak: + enabled: false + # --hostname-url should be the frontend url that user will be logging in with keycloak + extraStartupArgs: "--hostname-url=http://localhost:8080 --import-realm --features=declarative-user-profile" + tls: + enabled: true + autoGenerated: true + # this section controls the admin username/password for getting on keycloak + auth: + existingSecret: keycloak-admin-secret + passwordSecretKey: password + adminUser: atala + postgresql: + enabled: false + externalDatabase: + existingSecret: "keycloak-admin.atala-keycloak-postgres-cluster.credentials.postgresql.acid.zalan.do" + existingSecretPasswordKey: password + host: "atala-keycloak-postgres-cluster.{{.Release.Namespace}}" + port: "5432" + user: keycloak-admin + database: keycloak + extraVolumes: + - name: prism-agent-realm-import-volume + configMap: + name: prism-agent-realm-import + items: + - key: prism-agent.json + path: prism-agent.json + extraVolumeMounts: + - name: prism-agent-realm-import-volume + mountPath: /opt/bitnami/keycloak/data/import + readOnly: true diff --git a/infrastructure/shared/docker-compose-mt-keycloak.yml b/infrastructure/shared/docker-compose-mt-keycloak.yml index d441ef8dc7..d4f367b75d 100644 --- a/infrastructure/shared/docker-compose-mt-keycloak.yml +++ b/infrastructure/shared/docker-compose-mt-keycloak.yml @@ -107,6 +107,12 @@ services: API_KEY_ENABLED: API_KEY_AUTHENTICATE_AS_DEFAULT_USER: API_KEY_AUTO_PROVISIONING: + KEYCLOAK_ENABLED: true + KEYCLOAK_URL: http://keycloak:8080 + KEYCLOAK_REALM: atala-demo + KEYCLOAK_CLIENT_ID: prism-agent + KEYCLOAK_CLIENT_SECRET: prism-agent-demo-secret + KEYCLOAK_UMA_AUTO_UPGRADE_RPT: true depends_on: db: condition: service_healthy @@ -147,7 +153,7 @@ services: environment: KEYCLOAK_ADMIN: admin KEYCLOAK_ADMIN_PASSWORD: admin - command: start-dev --health-enabled=true + command: start-dev --hostname-url=http://localhost:9980 --health-enabled=true keycloak-wait: image: badouralix/curl-jq:ubuntu