diff --git a/.dockerignore b/.dockerignore index 7f2c6dd2..7b5b8793 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,6 +1,6 @@ .git .github -.k8s +.kube-workflow *.md **/node_modules **/.next/cache diff --git a/.kube-workflow/dev/templates/keycloak.sealed-secret.yaml b/.kube-workflow/dev/templates/keycloak.sealed-secret.yaml new file mode 100644 index 00000000..114b24d7 --- /dev/null +++ b/.kube-workflow/dev/templates/keycloak.sealed-secret.yaml @@ -0,0 +1,16 @@ +apiVersion: bitnami.com/v1alpha1 +kind: SealedSecret +metadata: + annotations: + sealedsecrets.bitnami.com/cluster-wide: "true" + name: keycloak-secrets +spec: + encryptedData: + KEYCLOAK_USER: AgCL3rNZDDIPXICgZBDxiFUI+HbvE5OZFOEO7HW4+eb8sofMHXWiAp5fSdYjus3MxB2qZFIBEpRRaELMEkRS/ZpLzVejejRxd/sm3wTgxnim2D6AHXhco/1qKs3eY1xZQ94TBPiynK6qXVP5xKor+LC/JZS6rjg7GJOqdP1Yc8TTia2d2g3VfBsXv/cipOH8hAeEO8If+ZoEcPrEGfDLHBFznaYWWZvaeTBCmGDBCqu3TZ1m2KbWy6sNfaIPU9oBsR3UiXql4MJ99GzDjAlF80tTHYBZjrkHtuMRoD/iLw93ToRduVJCTldONaYkZUyE7vPAWi3zOQDS67U0f5r52ylKuQ5jgdwbhIVe5zp6/MTgzZhFsmU8a0q/i7OzGUm1UxXGV+iCu6R65+wB1gSt2NTUSlPzMrEtZvudMDgter7sEw9SCFcXOWcraLCbGZhk/GiAX00HoCihIgc7Z9Pju/LsoCo4V9s0yU3mIS/BOdp+yK4rv8UnL0e1yRO1gwYk/cwIcKSdE2QmcpB9D7LgoTje93pVHGdi4MELoZuzLaO2MHB6W9fiEuMDcxeYMVj+1bVpMP5NLSa0XcCkZiQiMm3pVy6WU78Xbw7shr39CxfcVFSS4/HmmFsw1+rneqUke4aFW5dNVeMhrRt+UULkQp149tojkRL9YwRgeubAvqaBiOSetzNgGP88M7Ckyl9vnrDW7523yQ== + KEYCLOAK_PASSWORD: AgAB6/v5qwO1vAaHTaFR0yuCIK8gVNXVatkxOvX1T1kYqP1w2XtZUWqPBzYZxSnFTCNSBJTiLaAXrQjDhGt/z5rK/OnjqjjhcIx/vONNo+3m1npiFCuYnTlUSXtshqZ2G4I3qw4zncT49EPwZdZmWD8SniqCJ7f8ZEqvViQfofjYUcnWUU1EvpZOT7mTu3iQP5/MjzhprPEXrPvgRt9YyV+zMBV1q265VAdVoH+neCQl2bDgHY+2cdOgYn/+mU1Jx/eXw/2bcL3UMuJt78ochOn76icFW0yQi6U8/gRVrJbjRftvdjCHF1gtf/x0978ZCesUoUuYwXg3Dw1JlodI+I36TutXyq4Nuv2ubO1KIozZ5xfuTCZubsN2VCfZdVY9LxxVpIPx9u4uLyd96vkctyPzp3iltnUGfnKbIiNrf9jIKaEO8ZBCx0ZyM81+vm6IEIaD3zMXN7FPnWy5qrpSmw+cNPqAXiQ67uAAr+RC9tJgfYR0dml0kOdlvWtIL7JHSxR6p48w3pyupxcCCjYiB24Nw/sxm+lKEvkzG07RXS9IYKkqDAii1TkhCr3CRfh+aBg1EDZy3Glsw2TiBFBesYuSOyAo/zeux221oojG4/pCIXYeqkXjfgllnct7CAvX8JKYBcgPpjvnjRa+8+8qlAFCpT96FtfZmz68KOWi8iU53iZUG4IBlG/DPZcbFvCdNP+0tDO0OuaajjduNarGVT7la7D4VwQxvvIM + template: + metadata: + annotations: + sealedsecrets.bitnami.com/cluster-wide: "true" + name: keycloak-secrets + type: Opaque diff --git a/.kube-workflow/dev/values.yaml b/.kube-workflow/dev/values.yaml index 02776d6a..2c2185aa 100644 --- a/.kube-workflow/dev/values.yaml +++ b/.kube-workflow/dev/values.yaml @@ -3,11 +3,11 @@ app: jobs: runs: - - name: db - use: SocialGouv/kube-workflow/jobs/create-db@v1 + db: + use: SocialGouv/kube-workflow/jobs/create-db with: pgAdminSecretRefName: azure-pg-admin-user - - name: seed + seed: checkout: false # no need to checkout the repo as we use the docker image needs: [db] shell: sh @@ -16,3 +16,21 @@ jobs: envFrom: - secretRef: name: "pg-user-{{ .Values.global.branchSlug }}" + + db-keycloak: + use: SocialGouv/kube-workflow/jobs/create-db + with: + pgAdminSecretRefName: azure-pg-admin-user + pgSecretName: "keycloak-db-{{ .Values.global.branchSlug32 }}" + database: "keycloak_{{ .Values.global.branchSlug32 }}" + pgUser: "keycloak_{{ .Values.global.branchSlug32 }}" + +keycloak: + statefulsetAnnotations: + # need db-keycloak + kapp.k14s.io/change-rule: "upsert after upserting kube-workflow/db-keycloak.{{ .Values.global.namespace }}" + extraEnvFrom: | + - secretRef: + name: "keycloak-db-{{ .Values.global.branchSlug32 }}" + - secretRef: + name: keycloak-secrets diff --git a/.kube-workflow/prod/values.yaml b/.kube-workflow/prod/values.yaml index 1d3b8cc4..27553be8 100644 --- a/.kube-workflow/prod/values.yaml +++ b/.kube-workflow/prod/values.yaml @@ -10,3 +10,14 @@ app: requests: cpu: 200m memory: 256Mi + +keycloak: + ingress: + annotations: + cert-manager.io: cluster-issuer + cert-manager.io/cluster-issuer: letsencrypt-prod + kubernetes.io/tls-acme: 'true' + tls: + - hosts: + - "keycloak-{{ .Values.global.host }}" + secretName: keycloak-crt diff --git a/.kube-workflow/templates/realm.configmap.yaml b/.kube-workflow/templates/realm.configmap.yaml new file mode 100644 index 00000000..1a0887a2 --- /dev/null +++ b/.kube-workflow/templates/realm.configmap.yaml @@ -0,0 +1,121 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: keycloak-realm +data: + realm.json.envtpl: | + { + "id": "app", + "realm": "app", + "enabled": true, + "sslRequired": "external", + "registrationAllowed": false, + "registrationEmailAsUsername": true, + "rememberMe": true, + "verifyEmail": false, + "loginWithEmailAllowed": false, + "duplicateEmailsAllowed": false, + "resetPasswordAllowed": true, + "editUsernameAllowed": false, + "bruteForceProtected": true, + "passwordPolicy": "forceExpiredPasswordChange(90) and length(8) and specialChars(1) and digits(1)", + "groups": [ + { + "name": "anonymous", + "path": "/anonymous", + "attributes": { + "default-role": ["anonymous"], + "allowed-roles": ["anonymous##book-creator##book-reader"] + }, + "realmRoles": [], + "clientRoles": {}, + "subGroups": [] + } + ], + "defaultRole": { + "name": "default-roles", + "description": "${role_default-roles}", + "composite": true, + "clientRole": false + }, + "smtpServer": { + "password": "{{`{{ getenv "SMTP_PASSWORD" }}`}}", + "starttls": "{{`{{ or (getenv "SMTP_STARTTLS") "true" }}`}}", + "auth": "{{`{{ or (getenv "SMTP_AUTH") "true" }}`}}", + "host": "{{`{{ getenv "SMTP_HOST" }}`}}", + "from": "{{`{{ or (getenv "SMTP_FROM") "" }}`}}", + "port": "{{`{{ or (getenv "SMTP_PORT") "587" }}`}}", + "ssl": "{{`{{ or (getenv "SMTP_SSL") "true" }}`}}", + "user": "{{`{{ getenv "SMTP_USER" }}`}}" + }, + "roles": { + "realm": [ + { + "name": "default-roles", + "description": "${role_default-roles}", + "composite": true, + "composites": { + "realm": [], + "client": { + "account": ["view-profile", "manage-account"] + } + }, + "clientRole": false, + "attributes": {} + } + ], + "client": { + "app": [ + { + "name": "book-creator", + "composite": false, + "clientRole": true, + "attributes": {} + }, + { + "name": "book-reader", + "composite": false, + "clientRole": true, + "attributes": {} + } + ] + } + }, + "clients": [ + { + "clientId": "app", + "surrogateAuthRequired": false, + "enabled": true, + "alwaysDisplayInConsole": false, + "clientAuthenticatorType": "client-secret", + "redirectUris": ["*"], + "webOrigins": ["*"], + "notBefore": 0, + "bearerOnly": false, + "consentRequired": false, + "standardFlowEnabled": true, + "implicitFlowEnabled": false, + "directAccessGrantsEnabled": false, + "serviceAccountsEnabled": false, + "publicClient": true, + "frontchannelLogout": false, + "protocol": "openid-connect", + "attributes": {}, + "authenticationFlowBindingOverrides": {}, + "fullScopeAllowed": true, + "nodeReRegistrationTimeout": -1, + "protocolMappers": [], + "defaultClientScopes": ["web-origins", "roles", "profile", "email"], + "optionalClientScopes": [ + "address", + "phone", + "offline_access", + "microprofile-jwt" + ] + } + ], + "keycloakVersion": "14.0.0", + "userManagedAccessAllowed": false, + "eventsListeners": ["jboss-logging"], + "identityProviders": [] + } diff --git a/.kube-workflow/values.yaml b/.kube-workflow/values.yaml index ece728a5..16e6e83a 100644 --- a/.kube-workflow/values.yaml +++ b/.kube-workflow/values.yaml @@ -5,3 +5,94 @@ app: name: "{{ .Values.global.pgSecretName }}" - secretRef: name: app-sealed-secret + +keycloak: + postgresql: + enabled: false + + statefulsetAnnotations: + kapp.k14s.io/nonce: '' + kapp.k14s.io/update-strategy: fallback-on-replace + kapp.k14s.io/change-group: "kube-workflow/keycloak.{{ .Values.global.namespace }}" + kapp.k14s.io/disable-original: '' + kapp.k14s.io/create-strategy: fallback-on-update + + extraEnvFrom: | + - secretRef: + name: keycloak-db + - secretRef: + name: keycloak-secrets + + extraEnv: | + - name: KEYCLOAK_IMPORT + value: /realm/realm.json + - name: PROXY_ADDRESS_FORWARDING + value: "true" + - name: DB_VENDOR + value: postgres + - name: DB_ADDR + value: "$(PGHOST)" + - name: DB_PORT + value: "5432" + - name: DB_DATABASE + value: "$(PGDATABASE)" + - name: DB_USER + value: "$(PGUSER)" + - name: DB_PASSWORD + value: "$(PGPASSWORD)" + + extraVolumes: | + - name: keycloak-realm-tpl + configMap: + name: keycloak-realm + - name: keycloak-realm + emptyDir: {} + + extraVolumeMounts: | + - name: keycloak-realm + mountPath: "/realm/" + readOnly: true + + + extraInitContainers: | + - name: compile-realm + image: hairyhenderson/gomplate:v3.10.0-alpine + imagePullPolicy: IfNotPresent + volumeMounts: + - name: keycloak-realm-tpl + mountPath: "/realm-tpl/" + readOnly: true + - name: keycloak-realm + mountPath: "/realm/" + envFrom: + - secretRef: + name: app-sealed-secret + env: + - name: SMTP_HOST + value: "smtp.tipimail.com" + - name: SMTP_PORT + value: "587" + - name: SMTP_USER + value: "$(MAIL_AUTH_USER)" + - name: SMTP_PASSWORD + value: "$(MAIL_AUTH_PASS)" + command: + - sh + args: + - -c + - "cat /realm-tpl/realm.json.envtpl | gomplate > /realm/realm.json" + + ingress: + enabled: true + annotations: + nginx.ingress.kubernetes.io/proxy-buffer-size: "128k" + kubernetes.io/ingress.class: nginx + tls: + - hosts: + - "keycloak-{{ .Values.global.host }}" + secretName: wildcard-crt + rules: + - host: "keycloak-{{ .Values.global.host }}" + paths: + - path: / + pathType: Prefix