Skip to content

Commit ab2b183

Browse files
Copilotphrocker
andcommitted
Implement dynamic secret injection for Keycloak realm configuration
Co-authored-by: phrocker <[email protected]>
1 parent a25559f commit ab2b183

File tree

8 files changed

+202
-19
lines changed

8 files changed

+202
-19
lines changed

docker/keycloak/Dockerfile

Lines changed: 31 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,37 @@ RUN /opt/keycloak/bin/kc.sh build
1414
FROM quay.io/keycloak/keycloak:24.0.1
1515
COPY --from=builder /opt/keycloak/ /opt/keycloak/
1616

17-
COPY ./realms/sentrius-realm.json /opt/keycloak/data/import/sentrius-realm.json
17+
# Install gettext for envsubst command
18+
USER root
19+
RUN microdnf install -y gettext && microdnf clean all
20+
USER keycloak
1821

19-
RUN ls -l /opt/keycloak/data/import/sentrius-realm.json
22+
# Copy realm template and processing script
23+
COPY ./realms/sentrius-realm.json.template /opt/keycloak/data/import/sentrius-realm.json.template
24+
COPY ./process-realm-template.sh /opt/keycloak/bin/process-realm-template.sh
2025

21-
ENTRYPOINT ["/opt/keycloak/bin/kc.sh"]
22-
CMD ["start-dev", "--proxy=passthrough", "--import-realm", "--import-realm-overwrite=true", "--health-enabled=true"]
26+
# Make the script executable
27+
USER root
28+
RUN chmod +x /opt/keycloak/bin/process-realm-template.sh
29+
USER keycloak
30+
31+
RUN ls -l /opt/keycloak/data/import/sentrius-realm.json.template
32+
33+
# Create startup script that processes template then starts Keycloak
34+
COPY <<'EOF' /opt/keycloak/bin/startup.sh
35+
#!/bin/bash
36+
echo "Starting Keycloak with dynamic realm processing..."
37+
38+
# Process the realm template
39+
/opt/keycloak/bin/process-realm-template.sh
40+
41+
# Start Keycloak with the processed realm
42+
exec /opt/keycloak/bin/kc.sh start-dev --proxy=passthrough --import-realm --import-realm-overwrite=true --health-enabled=true
43+
EOF
44+
45+
USER root
46+
RUN chmod +x /opt/keycloak/bin/startup.sh
47+
USER keycloak
48+
49+
ENTRYPOINT ["/opt/keycloak/bin/startup.sh"]
2350

docker/keycloak/README.md

Lines changed: 25 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,30 @@
11
# Keycloak Realm Configuration
22

3-
This realm configuration file contains client definitions for Sentrius.
3+
This realm configuration file contains client definitions for Sentrius with dynamic secret injection.
44

5-
⚠️ **IMPORTANT**: The client secrets in this file are set to "CHANGE_ME_AFTER_IMPORT" and must be updated after importing the realm to match the secrets configured in your Helm deployment.
5+
## 🔐 Dynamic Secret Management
66

7-
The client secrets should be configured to match:
8-
- The OAuth2 secrets generated by the Helm chart
9-
- Or the secrets you provide in your values.yaml
7+
The Keycloak container now supports dynamic secret injection through environment variables:
108

11-
You can update client secrets via:
12-
1. Keycloak Admin Console
13-
2. Keycloak Admin REST API
14-
3. Environment variable substitution during realm import
9+
- **SENTRIUS_API_CLIENT_SECRET** - Secret for sentrius-api client
10+
- **SENTRIUS_LAUNCHER_CLIENT_SECRET** - Secret for sentrius-launcher-service client
11+
- **JAVA_AGENTS_CLIENT_SECRET** - Secret for java-agents client
12+
- **AI_AGENT_ASSESSOR_CLIENT_SECRET** - Secret for ai-agent-assessor client
13+
14+
## How It Works
15+
16+
1. **Template Processing**: The `sentrius-realm.json.template` file contains environment variable placeholders
17+
2. **Runtime Substitution**: During container startup, the `process-realm-template.sh` script replaces placeholders with actual values
18+
3. **Helm Integration**: The Helm chart generates OAuth2 secrets and passes them as environment variables
19+
4. **Automatic Import**: Keycloak imports the processed realm with the dynamically generated secrets
20+
21+
## Environment Variable Integration
22+
23+
The Helm chart automatically:
24+
- Generates random 32-character secrets when none are provided
25+
- Passes these secrets as environment variables to the Keycloak container
26+
- Ensures consistency between Helm-managed OAuth2 secrets and Keycloak realm configuration
27+
28+
## Fallback Behavior
29+
30+
If environment variables are not provided, the startup script generates default random secrets to ensure the container can start successfully.
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
#!/bin/bash
2+
3+
# Process realm template with environment variable substitution
4+
# This script replaces environment variable placeholders in the realm template
5+
# with actual values before Keycloak imports the realm
6+
7+
# Set paths - different for container vs local testing
8+
if [ -f "/opt/keycloak/data/import/sentrius-realm.json.template" ]; then
9+
# Container environment
10+
REALM_TEMPLATE="/opt/keycloak/data/import/sentrius-realm.json.template"
11+
REALM_OUTPUT="/opt/keycloak/data/import/sentrius-realm.json"
12+
elif [ -f "./realms/sentrius-realm.json.template" ]; then
13+
# Local testing environment
14+
REALM_TEMPLATE="./realms/sentrius-realm.json.template"
15+
REALM_OUTPUT="${REALM_OUTPUT:-./sentrius-realm.json}"
16+
else
17+
echo "Error: Realm template not found"
18+
echo " Looked for: /opt/keycloak/data/import/sentrius-realm.json.template"
19+
echo " Looked for: ./realms/sentrius-realm.json.template"
20+
exit 1
21+
fi
22+
23+
echo "Processing Keycloak realm template..."
24+
echo " Template: $REALM_TEMPLATE"
25+
echo " Output: $REALM_OUTPUT"
26+
27+
# Set default values for secrets if not provided
28+
export SENTRIUS_API_CLIENT_SECRET="${SENTRIUS_API_CLIENT_SECRET:-default-api-secret-$(openssl rand -hex 16)}"
29+
export SENTRIUS_LAUNCHER_CLIENT_SECRET="${SENTRIUS_LAUNCHER_CLIENT_SECRET:-default-launcher-secret-$(openssl rand -hex 16)}"
30+
export JAVA_AGENTS_CLIENT_SECRET="${JAVA_AGENTS_CLIENT_SECRET:-default-agents-secret-$(openssl rand -hex 16)}"
31+
export AI_AGENT_ASSESSOR_CLIENT_SECRET="${AI_AGENT_ASSESSOR_CLIENT_SECRET:-default-assessor-secret-$(openssl rand -hex 16)}"
32+
33+
# Set default values for other placeholders
34+
export ROOT_URL="${ROOT_URL:-http://localhost:8080}"
35+
export REDIRECT_URIS="${REDIRECT_URIS:-http://localhost:8080}"
36+
export GOOGLE_CLIENT_ID="${GOOGLE_CLIENT_ID:-}"
37+
export GOOGLE_CLIENT_SECRET="${GOOGLE_CLIENT_SECRET:-}"
38+
39+
echo "Substituting environment variables in realm template..."
40+
echo " SENTRIUS_API_CLIENT_SECRET: ${SENTRIUS_API_CLIENT_SECRET:0:8}..."
41+
echo " SENTRIUS_LAUNCHER_CLIENT_SECRET: ${SENTRIUS_LAUNCHER_CLIENT_SECRET:0:8}..."
42+
echo " JAVA_AGENTS_CLIENT_SECRET: ${JAVA_AGENTS_CLIENT_SECRET:0:8}..."
43+
echo " AI_AGENT_ASSESSOR_CLIENT_SECRET: ${AI_AGENT_ASSESSOR_CLIENT_SECRET:0:8}..."
44+
45+
# Use envsubst to replace environment variables
46+
envsubst < "$REALM_TEMPLATE" > "$REALM_OUTPUT"
47+
48+
if [ $? -eq 0 ]; then
49+
echo "Realm template processed successfully: $REALM_OUTPUT"
50+
else
51+
echo "Error: Failed to process realm template"
52+
exit 1
53+
fi
54+
55+
# Validate the JSON is valid
56+
if command -v jq >/dev/null 2>&1; then
57+
if ! jq empty < "$REALM_OUTPUT" >/dev/null 2>&1; then
58+
echo "Error: Generated realm JSON is invalid"
59+
exit 1
60+
fi
61+
echo "Generated realm JSON is valid"
62+
else
63+
echo "Note: jq not available, skipping JSON validation"
64+
fi

docker/keycloak/realms/sentrius-realm.json renamed to docker/keycloak/realms/sentrius-realm.json.template

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
"clientId": "sentrius-api",
77
"enabled": true,
88
"clientAuthenticatorType": "client-secret",
9-
"secret": "CHANGE_ME_AFTER_IMPORT",
9+
"secret": "${SENTRIUS_API_CLIENT_SECRET}",
1010
"rootUrl": "${ROOT_URL}",
1111
"baseUrl": "${ROOT_URL}",
1212
"serviceAccountsEnabled": true,
@@ -40,7 +40,7 @@
4040
"clientId": "sentrius-launcher-service",
4141
"enabled": true,
4242
"clientAuthenticatorType": "client-secret",
43-
"secret": "CHANGE_ME_AFTER_IMPORT",
43+
"secret": "${SENTRIUS_LAUNCHER_CLIENT_SECRET}",
4444
"rootUrl": "${ROOT_URL}",
4545
"baseUrl": "${ROOT_URL}",
4646

@@ -81,7 +81,7 @@
8181
"enabled": true,
8282
"alwaysDisplayInConsole": false,
8383
"clientAuthenticatorType": "client-secret",
84-
"secret": "CHANGE_ME_AFTER_IMPORT",
84+
"secret": "${JAVA_AGENTS_CLIENT_SECRET}",
8585
"redirectUris": [
8686
"${REDIRECT_URIS}/*"
8787
],
@@ -168,7 +168,7 @@
168168
"enabled": true,
169169
"alwaysDisplayInConsole": false,
170170
"clientAuthenticatorType": "client-secret",
171-
"secret": "CHANGE_ME_AFTER_IMPORT",
171+
"secret": "${AI_AGENT_ASSESSOR_CLIENT_SECRET}",
172172
"redirectUris": [
173173
"${REDIRECT_URIS}/*"
174174
],

docs/secret-management.md

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,28 @@ Application properties files now use environment variables with fallback default
4949
- `DATABASE_PASSWORD` - Database password (defaults to "password")
5050
- `KEYSTORE_PASSWORD` - Keystore password (defaults to "keystorepassword")
5151

52+
## Keycloak Realm Dynamic Configuration
53+
54+
The Keycloak Docker container now supports dynamic realm configuration with automatic secret injection:
55+
56+
### How It Works
57+
58+
1. **Template Processing**: The Keycloak realm configuration uses a template file (`sentrius-realm.json.template`) with environment variable placeholders
59+
2. **Runtime Substitution**: During container startup, secrets are injected via environment variables:
60+
- `SENTRIUS_API_CLIENT_SECRET` - Secret for sentrius-api client
61+
- `SENTRIUS_LAUNCHER_CLIENT_SECRET` - Secret for sentrius-launcher-service client
62+
- `JAVA_AGENTS_CLIENT_SECRET` - Secret for java-agents client
63+
- `AI_AGENT_ASSESSOR_CLIENT_SECRET` - Secret for ai-agent-assessor client
64+
3. **Helm Integration**: The Helm chart automatically generates these secrets and passes them to the Keycloak container
65+
4. **Fallback Generation**: If no secrets are provided, the container generates secure random defaults
66+
67+
### Build Integration
68+
69+
When building the Keycloak container with `./build-images.sh --sentrius-keycloak`, the system:
70+
- Includes the realm template and processing script
71+
- Configures automatic secret substitution during startup
72+
- Ensures consistency between Helm-generated OAuth2 secrets and Keycloak realm configuration
73+
5274
## Production Deployment
5375

5476
For production environments, it is recommended to:

sentrius-chart/templates/keycloak-deployment.yaml

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -87,5 +87,23 @@ spec:
8787
secretKeyRef:
8888
name: {{ .Release.Name }}-keycloak-secrets
8989
key: client-secret
90-
command: ["/opt/keycloak/bin/kc.sh"]
91-
args: ["start-dev", "--proxy=edge", "--import-realm", "--health-enabled=true"]
90+
- name: SENTRIUS_API_CLIENT_SECRET
91+
valueFrom:
92+
secretKeyRef:
93+
name: {{ .Release.Name }}-oauth2-secrets
94+
key: sentrius-api-client-secret
95+
- name: SENTRIUS_LAUNCHER_CLIENT_SECRET
96+
valueFrom:
97+
secretKeyRef:
98+
name: {{ .Release.Name }}-oauth2-secrets
99+
key: sentrius-launcher-service-client-secret
100+
- name: JAVA_AGENTS_CLIENT_SECRET
101+
valueFrom:
102+
secretKeyRef:
103+
name: {{ .Release.Name }}-oauth2-secrets
104+
key: java-agents-client-secret
105+
- name: AI_AGENT_ASSESSOR_CLIENT_SECRET
106+
valueFrom:
107+
secretKeyRef:
108+
name: {{ .Release.Name }}-oauth2-secrets
109+
key: ai-agent-assessor-client-secret

sentrius-chart/templates/oauth2-secrets.yaml

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,4 +37,29 @@ data:
3737
launcherservice-client-secret: {{ .Values.launcherservice.oauth2.client_secret | b64enc }}
3838
{{- else }}
3939
launcherservice-client-secret: {{ randAlphaNum 32 | b64enc }}
40+
{{- end }}
41+
42+
# Keycloak Realm Client Secrets - These are used by Keycloak realm configuration
43+
{{- if .Values.keycloak.realm.clients.sentriusApi.client_secret }}
44+
sentrius-api-client-secret: {{ .Values.keycloak.realm.clients.sentriusApi.client_secret | b64enc }}
45+
{{- else }}
46+
sentrius-api-client-secret: {{ randAlphaNum 32 | b64enc }}
47+
{{- end }}
48+
49+
{{- if .Values.keycloak.realm.clients.sentriusLauncher.client_secret }}
50+
sentrius-launcher-service-client-secret: {{ .Values.keycloak.realm.clients.sentriusLauncher.client_secret | b64enc }}
51+
{{- else }}
52+
sentrius-launcher-service-client-secret: {{ randAlphaNum 32 | b64enc }}
53+
{{- end }}
54+
55+
{{- if .Values.keycloak.realm.clients.javaAgents.client_secret }}
56+
java-agents-client-secret: {{ .Values.keycloak.realm.clients.javaAgents.client_secret | b64enc }}
57+
{{- else }}
58+
java-agents-client-secret: {{ randAlphaNum 32 | b64enc }}
59+
{{- end }}
60+
61+
{{- if .Values.keycloak.realm.clients.aiAgentAssessor.client_secret }}
62+
ai-agent-assessor-client-secret: {{ .Values.keycloak.realm.clients.aiAgentAssessor.client_secret | b64enc }}
63+
{{- else }}
64+
ai-agent-assessor-client-secret: {{ randAlphaNum 32 | b64enc }}
4065
{{- end }}

sentrius-chart/values.yaml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,17 @@ keycloak:
194194
database: keycloak
195195
storageSize: 10Gi
196196
replicas: 1
197+
# Realm client secrets - used for Keycloak realm template processing
198+
realm:
199+
clients:
200+
sentriusApi:
201+
client_secret: "" # Dynamically generated if not provided
202+
sentriusLauncher:
203+
client_secret: "" # Dynamically generated if not provided
204+
javaAgents:
205+
client_secret: "" # Dynamically generated if not provided
206+
aiAgentAssessor:
207+
client_secret: "" # Dynamically generated if not provided
197208
annotations:
198209
gke:
199210
cloud.google.com/backend-config: '{"default": "sentrius-backend-config"}'

0 commit comments

Comments
 (0)