Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
63 commits
Select commit Hold shift + click to select a range
eaab062
Add OpenID IngressRoute
KavanPrice Mar 13, 2025
fb59dd8
Add Keycloak deployment
KavanPrice Mar 13, 2025
45aac27
Add startup realm importing
KavanPrice Mar 17, 2025
cb867ca
Add oauth to Grafana config
KavanPrice Mar 17, 2025
614a94e
Add keytab volume
KavanPrice Mar 17, 2025
8d0668b
Add requested PR changes
djnewbould Mar 21, 2025
0d0ea83
Add local secret grafana mount
djnewbould Mar 21, 2025
127c692
Add realm creation to service-setup
KavanPrice Mar 25, 2025
f73f3b6
Add service lookup for provided client configs
KavanPrice Mar 25, 2025
da8c668
Add Grafana client config values
KavanPrice Mar 25, 2025
dd65a24
Fix keytab secret names
KavanPrice Mar 25, 2025
4205c43
Add client_secret volume mount
KavanPrice Mar 25, 2025
101fe91
Fix config and add startup backoff
KavanPrice Mar 25, 2025
7200867
Add generic client-secret fetching
KavanPrice Mar 25, 2025
acdc62a
Rename client-secret to be findable by service-setup
KavanPrice Mar 25, 2025
ac7c368
Fix misnamed grafana client ID
KavanPrice Mar 26, 2025
4f6daea
Fix misnamed grafana secret
KavanPrice Mar 26, 2025
b35cf42
Change to use realm instead of base URL in ACS config
KavanPrice Mar 26, 2025
9a80e55
Use setTimeout from timers/promises
KavanPrice Mar 26, 2025
284b8d9
Timeout bugfix
KavanPrice Mar 26, 2025
15ed6a7
Remove unused client keytab
KavanPrice Mar 26, 2025
e935fbb
Add dynamic LocalSecret generation
KavanPrice Mar 26, 2025
e0b480f
Fix helm loop bug
KavanPrice Mar 26, 2025
3493233
Remove `items` from keytabs mount
amrc-benmorrow Mar 27, 2025
e51b307
Allow OpenID errors to cause service-setup to exit
amrc-benmorrow Mar 27, 2025
47fab3e
Reference client secrets correctly
amrc-benmorrow Mar 27, 2025
b4e4963
Merge in testing/v4
amrc-benmorrow Mar 27, 2025
98af79f
Remove Grafana Basic auth middleware
amrc-benmorrow Mar 27, 2025
94e7ed0
Log realm details on creation
amrc-benmorrow Mar 27, 2025
e83d828
Give Keycloack a PVC
amrc-benmorrow Mar 27, 2025
fcb2dc1
Log full client information
amrc-benmorrow Mar 27, 2025
d075eee
Tell Grafana its external root URL
amrc-benmorrow Mar 27, 2025
4f97679
Disable Grafana auth via the middleware
amrc-benmorrow Mar 27, 2025
d9a6c76
Grafana config changes
amrc-benmorrow Mar 27, 2025
688292b
Java doesn't accept KRB5_CONFIG
amrc-benmorrow Mar 27, 2025
fea8727
Keycloak needs to use Recreate strategy
amrc-benmorrow Mar 27, 2025
8c20987
Fix login and logout for basic users
KavanPrice Mar 30, 2025
08a3193
Add client role mapping
KavanPrice Mar 31, 2025
f17aa0e
Add client role creation
KavanPrice Mar 31, 2025
edb12fc
Add admin-cli permissions to create users
KavanPrice Apr 1, 2025
7fa281d
Add default role to client
KavanPrice Apr 1, 2025
5189e03
Add creation of admin user
KavanPrice Apr 1, 2025
c4a33d2
Add client role mapping for admin user
KavanPrice Apr 1, 2025
9d44e3d
Refactor OpenID setup
amrc-benmorrow Apr 3, 2025
cf237dc
Always create client roles
amrc-benmorrow Apr 3, 2025
b7e7294
Use a LocalSecret for the admin service client
amrc-benmorrow Apr 3, 2025
28b296d
Fix some logging
amrc-benmorrow Apr 3, 2025
c177e65
Missing await
amrc-benmorrow Apr 3, 2025
ae0290b
We need to call try_fetch, not native fetch
amrc-benmorrow Apr 3, 2025
c77c634
Error in admin user creation
amrc-benmorrow Apr 3, 2025
62c36cd
The admin@ account is no longer the service account
amrc-benmorrow Apr 3, 2025
01a0585
Log if the admin user doesn't exist
amrc-benmorrow Apr 3, 2025
628e344
UserRepresentation.credentials is an array
amrc-benmorrow Apr 3, 2025
da8e5d9
We must clone a Request to reuse it
amrc-benmorrow Apr 3, 2025
fbfbdfc
Rename the Keycloak bootstrap user
amrc-benmorrow Apr 3, 2025
1461db3
Create admin@ linked to Kerberos
amrc-benmorrow Apr 4, 2025
2034cae
Assign admin user roles correctly
amrc-benmorrow Apr 4, 2025
1d6aea2
Remove Grafana admin user secret
amrc-benmorrow Apr 4, 2025
b063321
We can't remove the grafana-internal admin user
amrc-benmorrow Apr 4, 2025
e263eac
Assign Grafana roles from OAuth
amrc-benmorrow Apr 4, 2025
847a97b
Try to get OpenID roles visible in Grafana
amrc-benmorrow Apr 4, 2025
a379116
Restore OpenID role mapper
amrc-benmorrow Apr 4, 2025
b4f4da2
We need to look up the client ID.
amrc-benmorrow Apr 4, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
575 changes: 575 additions & 0 deletions acs-service-setup/lib/openid-realm.js

Large diffs are not rendered by default.

4 changes: 4 additions & 0 deletions acs-service-setup/lib/service-setup.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { DumpLoader } from "./dumps.js";
import { fixups } from "./fixups.js";
import { setup_git_repos } from "./git-repos.js";
import { setup_local_uuids } from "./local-uuids.js";
import { create_openid_realm } from "./openid-realm.js";

export class ServiceSetup {
constructor (opts) {
Expand Down Expand Up @@ -58,6 +59,9 @@ export class ServiceSetup {
this.log("Migrating legacy Auth groups");
await migrate_auth_groups(this);

this.log("Creating OpenID realm");
await create_openid_realm(this);

this.log("Finished setup");
}
}
51 changes: 51 additions & 0 deletions deploy/crds/local-secret.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
name: localsecrets.factoryplus.app.amrc.co.uk
spec:
group: factoryplus.app.amrc.co.uk
names:
kind: LocalSecret
plural: localsecrets
categories:
- all
scope: Namespaced
versions:
- name: v1
served: true
storage: true
additionalPrinterColumns:
- name: Secret
jsonPath: ".spec.secret"
type: string
- name: Key
jsonPath: ".spec.key"
type: string
- name: Format
jsonPath: ".spec.format"
type: string
schema:
openAPIV3Schema:
type: object
required: [spec]
properties:
spec:
type: object
required: [secret, key, format]
properties:
secret:
description: The name of the Secret to edit.
type: string
key:
description: The key to create within the Secret.
type: string
format:
description: >
The format of the secret value. Currently must be Password.
type: string
enum: [Password]
status:
type: object
x-kubernetes-preserve-unknown-fields: true
subresources:
status: {}
12 changes: 3 additions & 9 deletions deploy/templates/grafana/grafana-admin-user.yaml
Original file line number Diff line number Diff line change
@@ -1,17 +1,11 @@
{{ if .Values.grafana.enabled }}
{{- if not (lookup "v1" "Secret" .Release.Namespace "grafana-admin-user") }}

apiVersion: v1
kind: Secret
metadata:
name: "grafana-admin-user"
namespace: {{ .Release.Namespace }}
annotations:
"helm.sh/resource-policy": "keep"
type: Opaque
data:
admin-user: {{ (printf "admin@%s" (.Values.identity.realm | required "values.identity.realm is required!") | b64enc) | quote }}
admin-password: {{ (printf "" | b64enc) | quote }}

{{- end }}
stringData:
admin-user: "_bootstrap"
admin-password: {{ randAlphaNum 20 | quote }}
{{- end -}}
2 changes: 0 additions & 2 deletions deploy/templates/grafana/grafana-ingress.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,6 @@ spec:
routes:
- match: Host(`grafana.{{.Values.acs.baseUrl | required "values.acs.baseUrl is required"}}`)
kind: Rule
middlewares:
- name: basic-auth
services:
- name: acs-grafana
port: 80
Expand Down
11 changes: 11 additions & 0 deletions deploy/templates/grafana/grafana-ini.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
apiVersion: v1
kind: ConfigMap
metadata:
namespace: {{ .Release.Namespace }}
name: acs-grafana-config
data:
auth_url: {{ .Values.acs.secure | ternary "https://" "http://" }}openid.{{.Values.acs.baseUrl}}/realms/factory_plus/protocol/openid-connect/auth
token_url: {{ .Values.acs.secure | ternary "https://" "http://" }}openid.{{.Values.acs.baseUrl}}/realms/factory_plus/protocol/openid-connect/token
api_url: {{ .Values.acs.secure | ternary "https://" "http://" }}openid.{{.Values.acs.baseUrl}}/realms/factory_plus/protocol/openid-connect/userinfo
root_url: {{ .Values.acs.secure | ternary "https://" "http://" }}grafana.{{.Values.acs.baseUrl}}
signout_redirect_url: {{ .Values.acs.secure | ternary "https://" "http://" }}openid.{{.Values.acs.baseUrl}}/realms/factory_plus/protocol/openid-connect/logout?post_logout_redirect_uri={{ .Values.acs.secure | ternary "https://" "http://" }}grafana.{{.Values.acs.baseUrl}}&client_id=grafana
3 changes: 2 additions & 1 deletion deploy/templates/hooks/post-delete.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ spec:
- |
echo "Starting cleanup..."
for i in $(kubectl -n {{ .Release.Namespace }} get kerberos-keys -o name); do kubectl -n {{ .Release.Namespace }} patch $i --type=json -p='[{"op": "remove", "path": "/metadata/finalizers"}]'; done
for i in $(kubectl -n {{ .Release.Namespace }} get localsecrets -o name); do kubectl -n {{ .Release.Namespace }} patch $i --type=json -p='[{"op": "remove", "path": "/metadata/finalizers"}]'; done
echo "Cleanup complete!"
restartPolicy: Never
backoffLimit: 3
Expand Down Expand Up @@ -45,7 +46,7 @@ metadata:
"helm.sh/hook-delete-policy": before-hook-creation
rules:
- apiGroups: [ "factoryplus.app.amrc.co.uk" ]
resources: [ "kerberos-keys" ]
resources: [ "kerberos-keys", "localsecrets" ]
verbs: [ "get", "list", "patch" ] # Specify only necessary actions

---
Expand Down
4 changes: 2 additions & 2 deletions deploy/templates/identity/rbac.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,10 @@ metadata:
name: krb-keys-operator
rules:
- apiGroups: [factoryplus.app.amrc.co.uk]
resources: [kerberos-keys]
resources: [kerberos-keys, localsecrets]
verbs: [list, get, watch, patch]
- apiGroups: [factoryplus.app.amrc.co.uk]
resources: [kerberos-keys/status]
resources: [kerberos-keys/status, localsecrets/status]
verbs: [list, get, create, update, delete, watch, patch]
- apiGroups: [""]
resources: [secrets]
Expand Down
2 changes: 2 additions & 0 deletions deploy/templates/mqtt/mqtt.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@ spec:
- name: VERBOSE
value: {{.Values.mqtt.verbosity | quote | required "values.mqtt.verbosity is required!"}}
volumeMounts:
# XXX This would be better without the subPath, but we need
# to use a Java system property to move krb5.conf.
- mountPath: /etc/krb5.conf
name: krb5-conf
subPath: krb5.conf
Expand Down
35 changes: 35 additions & 0 deletions deploy/templates/openid/local-secrets.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
{{ if .Values.openid.enabled }}
{{ range $clientName, $client := .Values.serviceSetup.config.openidClients }}
---
apiVersion: factoryplus.app.amrc.co.uk/v1
kind: LocalSecret
metadata:
namespace: {{ $.Release.Namespace }}
name: "keycloak-client-{{ $clientName }}"
spec:
format: Password
secret: "keycloak-clients"
key: "{{ $clientName }}"
{{ end }}
---
apiVersion: factoryplus.app.amrc.co.uk/v1
kind: LocalSecret
metadata:
namespace: {{ $.Release.Namespace }}
name: "keycloak-admin-bootstrap"
spec:
format: Password
secret: "keycloak-clients"
key: "_bootstrap"
---
apiVersion: factoryplus.app.amrc.co.uk/v1
kind: LocalSecret
metadata:
namespace: {{ $.Release.Namespace }}
name: "keycloak-admin-admin"
spec:
format: Password
secret: "keycloak-clients"
key: "_admin"

{{ end }}
23 changes: 23 additions & 0 deletions deploy/templates/openid/openid-ingress.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
{{ if .Values.openid.enabled }}
apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
name: openid-ingressroute
namespace: {{ .Release.Namespace }}
spec:
entryPoints:
- {{ .Values.acs.secure | ternary "websecure" "web" }}
routes:
- match: Host(`openid.{{.Values.acs.baseUrl | required "values.acs.baseUrl is required"}}`)
kind: Rule
services:
- name: openid
port: 80
namespace: {{ .Release.Namespace }}
{{- if .Values.acs.secure }}
tls:
secretName: {{ coalesce .Values.openid.tlsSecretName .Values.acs.tlsSecretName }}
domains:
- main: openid.{{.Values.acs.baseUrl | required "values.acs.baseUrl is required"}}
{{- end -}}
{{- end -}}
111 changes: 111 additions & 0 deletions deploy/templates/openid/openid.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
{{ if .Values.openid.enabled }}
apiVersion: apps/v1
kind: Deployment
metadata:
name: openid
namespace: {{ .Release.Namespace }}
labels:
component: openid
spec:
strategy:
type: Recreate
# We cannot allow more replicas with a RWO PVC backend
replicas: 1
selector:
matchLabels:
component: openid
template:
metadata:
labels:
component: openid
factory-plus.service: openid
spec:
{{- with .Values.acs.imagePullSecrets }}
imagePullSecrets:
{{- toYaml . | nindent 8 }}
{{- end }}
containers:
- name: openid
image: "{{ .Values.openid.image.repository }}:{{ .Values.openid.image.tag }}"
imagePullPolicy: {{ .Values.openid.image.pullPolicy }}
args: ["start-dev"]
env:
- name: KEYCLOAK_ADMIN
value: "_bootstrap"
- name: KEYCLOAK_ADMIN_PASSWORD
valueFrom:
secretKeyRef:
name: keycloak-clients
key: _bootstrap
- name: KC_PROXY
value: "edge"
- name: KC_HEALTH_ENABLED
value: "true"
ports:
- name: http
containerPort: 8080
readinessProbe:
httpGet:
path: /health/ready
port: 9000
volumeMounts:
# XXX This would be better without the subPath, but we need
# to use a Java system property to move krb5.conf.
- name: krb5-conf
mountPath: /etc/krb5.conf
subPath: krb5.conf
- name: openid-keytabs
mountPath: /etc/keytabs
- name: data
mountPath: /opt/keycloak/data
volumes:
- name: krb5-conf
configMap:
name: krb5-conf
- name: openid-keytabs
secret:
secretName: openid-keytabs
- name: data
persistentVolumeClaim:
claimName: keycloak-data
---
# XXX Could we use Postgres here instead?
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: keycloak-data
namespace: {{ .Release.Namespace }}
labels:
component: openid
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 2Gi
---
apiVersion: v1
kind: Service
metadata:
name: openid
namespace: {{ .Release.Namespace }}
spec:
ports:
- name: http
port: 80
targetPort: 8080
selector:
factory-plus.service: openid
---
apiVersion: factoryplus.app.amrc.co.uk/v1
kind: KerberosKey
metadata:
name: http.openid
namespace: {{ .Release.Namespace }}
spec:
type: Random
principal: HTTP/openid.{{ .Release.Namespace }}.svc.cluster.local@{{ .Values.identity.realm | required "values.identity.realm is required!" }}
additionalPrincipals:
- HTTP/openid.{{.Values.acs.baseUrl | required "values.acs.baseUrl is required"}}@{{ .Values.identity.realm | required "values.identity.realm is required!" }}
secret: openid-keytabs/server
{{- end }}
14 changes: 12 additions & 2 deletions deploy/templates/service-setup.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ spec:
name: krb5-conf
- name: manager-ccache-storage
emptyDir: { }
- name: client-secrets
secret:
secretName: keycloak-clients
initContainers:
- name: service-setup
{{ include "amrc-connectivity-stack.image" (list . .Values.serviceSetup) | indent 10 }}
Expand All @@ -32,6 +35,10 @@ spec:
value: http://directory.{{ .Release.Namespace }}.svc.cluster.local
- name: SERVICE_USERNAME
value: admin
# Currently the openid realm setup relies on having the
# admin@ credentials available, with a password rather than
# a keytab. If service-setup is ever moved over to using its
# own account there will need to be changes to that code.
- name: SERVICE_PASSWORD
valueFrom:
secretKeyRef:
Expand All @@ -53,12 +60,15 @@ spec:
"secure" (.Values.acs.secure | ternary "s" "")
"realm" .Values.identity.realm
"directory"
(include "amrc-connectivity-stack.external-url"
(include "amrc-connectivity-stack.external-url"
(list . "directory"))
| toRawJson | quote }}
volumeMounts:
- mountPath: /data
name: git-checkouts
- name: client-secrets
mountPath: /etc/secret
readOnly: true
- name: edge-helm-charts
{{ include "amrc-connectivity-stack.image" (list . .Values.edgeHelm) | indent 10 }}
env:
Expand All @@ -78,7 +88,7 @@ spec:
- name: manager
image: "{{ include "amrc-connectivity-stack.image-name" (list . .Values.manager ) }}-backend"
imagePullPolicy: {{ .Values.manager.image.pullPolicy }}
command:
command:
- /bin/sh
- "-c"
- |
Expand Down
Loading