Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
22 changes: 22 additions & 0 deletions charts/qtodo/templates/_helpers.tpl
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,25 @@ quay.io/ztvp/qtodo) so no VP --set override is needed.
{{- printf "%s:%s" $name (tpl .value.version .context) -}}
{{- end -}}
{{- end -}}

{{/*
Generate the URL of the OIDC service
*/}}
{{- define "qtodo.oidc.url" }}
{{- if not .Values.app.oidc.authServerUrl }}
{{- printf "https://keycloak.%s/realms/%s" .Values.global.localClusterDomain .Values.app.oidc.realm }}
{{- else }}
{{- print .Values.app.oidc.authServerUrl }}
{{- end }}
{{- end }}

{{/*
Generate the JWT Audience
*/}}
{{- define "qtodo.jwt.audience" }}
{{- if not .Values.app.vault.audience }}
{{- printf "https://keycloak.%s/realms/%s" .Values.global.localClusterDomain .Values.app.oidc.realm }}
{{- else }}
{{- print .Values.app.vault.audience }}
{{- end }}
{{- end }}
4 changes: 2 additions & 2 deletions charts/qtodo/templates/app-config-env.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,13 @@ metadata:
data:
{{- if eq .Values.app.spire.enabled true }}
QUARKUS_OIDC_ENABLED: "true"
QUARKUS_OIDC_AUTH_SERVER_URL: "{{ default (printf "https://keycloak.%s/realms/%s" .Values.global.localClusterDomain .Values.app.keycloak.realm) .Values.app.oidc.authServerUrl }}"
QUARKUS_OIDC_AUTH_SERVER_URL: "{{ include "qtodo.oidc.url" . }}"
Comment thread
mlorenzofr marked this conversation as resolved.
QUARKUS_OIDC_CLIENT_ID: "{{ .Values.app.oidc.clientId }}"
QUARKUS_OIDC_APPLICATION_TYPE: "{{ .Values.app.oidc.applicationType }}"
QUARKUS_HTTP_AUTH_PERMISSION_AUTHENTICATED_PATHS: "{{ .Values.app.oidc.authenticatedPaths }}"
QUARKUS_HTTP_AUTH_PERMISSION_AUTHENTICATED_POLICY: "{{ .Values.app.oidc.authenticatedPolicy }}"
QUARKUS_OIDC_AUTHENTICATION_FORCE_REDIRECT_HTTPS_SCHEME: "true"
{{- if .Values.app.oidc.clientAssertion.enabled }}
{{- if and .Values.app.oidc.clientAssertion.enabled (not .Values.app.oidc.clientSecret.enabled) }}
QUARKUS_OIDC_CREDENTIALS_JWT_SOURCE: "bearer"
QUARKUS_OIDC_CREDENTIALS_JWT_TOKEN_PATH: "{{ .Values.app.oidc.clientAssertion.jwtTokenPath }}"
{{- end }}
Expand Down
12 changes: 7 additions & 5 deletions charts/qtodo/templates/app-deployment.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ spec:
- name: qtodo-truststore-java
mountPath: /usr/local/bin
{{- end }}
{{- if and .Values.app.oidc.enabled (contains "keycloak" (include "qtodo.oidc.url" .)) }}
- name: wait-for-keycloak
image: registry.redhat.io/openshift4/ose-tools-rhel9:latest
imagePullPolicy: IfNotPresent
Expand All @@ -63,7 +64,7 @@ spec:
- -c
- |
echo "Waiting for Keycloak OIDC endpoint to be available..."
KEYCLOAK_URL="{{ default (printf "https://keycloak.%s/realms/ztvp/.well-known/openid-configuration" .Values.global.localClusterDomain) .Values.app.oidc.authServerUrl }}/.well-known/openid-configuration"
KEYCLOAK_URL="{{ include "qtodo.oidc.url" . }}/.well-known/openid-configuration"
# Remove duplicate .well-known if authServerUrl already contains realm
KEYCLOAK_URL=$(echo "$KEYCLOAK_URL" | sed 's|/.well-known/openid-configuration/.well-known/openid-configuration|/.well-known/openid-configuration|')

Expand All @@ -87,6 +88,7 @@ spec:
- name: ztvp-trusted-ca
mountPath: /etc/pki/ca-trust/extracted/pem
readOnly: true
{{- end }}
- name: init-spiffe-helper
image: {{ template "qtodo.image" (dict "value" .Values.app.images.spiffeHelper "context" $) }}
imagePullPolicy: {{ .Values.app.images.spiffeHelper.pullPolicy }}
Expand Down Expand Up @@ -123,7 +125,7 @@ spec:
- name: CREDENTIALS_FILE
value: /run/secrets/db-credentials/credentials.properties
- name: JWT_TOKEN_FILE
value: /svids/jwt.token
value: {{ .Values.app.oidc.clientAssertion.jwtTokenPath }}
- name: ZTVP_CA_BUNDLE
value: /etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem
volumeMounts:
Expand Down Expand Up @@ -176,7 +178,7 @@ spec:
- name: CREDENTIALS_FILE
value: /run/secrets/db-credentials/credentials.properties
- name: JWT_TOKEN_FILE
value: /svids/jwt.token
value: {{ .Values.app.oidc.clientAssertion.jwtTokenPath }}
- name: ZTVP_CA_BUNDLE
value: /etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem
volumeMounts:
Expand Down Expand Up @@ -234,11 +236,11 @@ spec:
{{- else }}
- name: QUARKUS_CONFIG_LOCATIONS
value: file:/run/secrets/db-credentials/credentials.properties
{{- if not .Values.app.oidc.clientAssertion.enabled }}
{{- if .Values.app.oidc.clientSecret.enabled }}
- name: QUARKUS_OIDC_CREDENTIALS_SECRET
valueFrom:
secretKeyRef:
name: oidc-client-secret
name: {{ .Values.app.oidc.clientSecret.name }}
key: client-secret
{{- end }}
{{- if .Values.app.truststore.enabled }}
Expand Down
10 changes: 5 additions & 5 deletions charts/qtodo/templates/oidc-client-secret-external-secret.yaml
Original file line number Diff line number Diff line change
@@ -1,23 +1,23 @@
{{- if .Values.app.oidcSecret.enabled }}
{{- if .Values.app.oidc.clientSecret.enabled }}
apiVersion: "external-secrets.io/v1beta1"
kind: ExternalSecret
metadata:
name: {{ .Values.app.oidcSecret.name }}
name: {{ .Values.app.oidc.clientSecret.name }}
namespace: {{ .Release.Namespace }}
spec:
refreshInterval: 15s
secretStoreRef:
name: {{ .Values.global.secretStore.name }}
kind: {{ .Values.global.secretStore.kind }}
target:
name: {{ .Values.app.oidcSecret.name }}
name: {{ .Values.app.oidc.clientSecret.name }}
template:
type: Opaque
data:
client-secret: "{{ `{{ .client_secret }}` }}"
client-secret: "{{ `{{ .client_secret | trim }}` }}"
data:
- secretKey: client_secret
remoteRef:
key: {{ .Values.app.oidcSecret.vaultPath }}
key: {{ .Values.app.oidc.clientSecret.vaultPath }}
property: client-secret
{{- end }}
3 changes: 1 addition & 2 deletions charts/qtodo/templates/spiffe-helper-config.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
{{- if eq .Values.app.spire.enabled true }}
{{- $keycloakRealmUrl := default (printf "https://keycloak.%s/realms/%s" .Values.global.localClusterDomain .Values.app.keycloak.realm) .Values.app.keycloak.realmUrl }}
kind: ConfigMap
apiVersion: v1
metadata:
Expand All @@ -16,6 +15,6 @@ data:
svid_file_name = "svid.pem"
svid_key_file_name = "svid_key.pem"
svid_bundle_file_name = "svid_bundle.pem"
jwt_svids = [{jwt_audience="{{ $keycloakRealmUrl }}", jwt_svid_file_name="jwt.token"}]
jwt_svids = [{jwt_audience="{{ include "qtodo.jwt.audience" . }}", jwt_svid_file_name="jwt.token"}]
jwt_bundle_file_name = "jwt_bundle.json"
{{- end }}
23 changes: 8 additions & 15 deletions charts/qtodo/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -48,20 +48,19 @@ app:
oidc:
enabled: false # Will be enabled when SPIFFE is enabled
authServerUrl: ""
clientId: qtodo-app
realm: "ztvp"
clientId: "qtodo-app"
applicationType: "web-app"
authenticatedPaths: "/*"
authenticatedPolicy: "authenticated"
# Federated client assertion using SPIFFE JWT SVID
clientAssertion:
enabled: true
jwtTokenPath: "/svids/jwt.token"

# Keycloak realm configuration
keycloak:
realm: "ztvp"
# Keycloak realm URL (auto-generated from global.localClusterDomain and realm if empty)
realmUrl: ""
clientSecret:
enabled: false
name: "oidc-client-secret"
vaultPath: "secret/data/apps/qtodo/qtodo-oidc-client"

spire:
enabled: true # Enable SPIFFE + OIDC integration by default
Expand All @@ -72,17 +71,11 @@ app:
vault:
url: ""
role: "qtodo"
# JWT Audience (auto-generated if not set)
# audience: "api://client-id"
# QTodo secrets path (app-level isolation)
secretPath: "secret/data/apps/qtodo/qtodo-db"

# OIDC External Secret configuration
# Disabled when using federated client assertion (no client secret needed)
oidcSecret:
enabled: false
name: "oidc-client-secret"
# QTodo OIDC secret path (app-level isolation)
vaultPath: "secret/data/apps/qtodo/qtodo-oidc-client"

# Seed image Job: mirrors the upstream qtodo image into the configured
# registry so the deployment can pull before the supply-chain pipeline runs.
seedImage:
Expand Down
81 changes: 81 additions & 0 deletions docs/entraid.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
# Azure Entra ID integration

This document describes the steps required to integrate the **Zero Trust Validated Pattern** (ZTVP) with **Azure Entra ID**, trusting this service as the Identity Provider for the following components:

* Qtodo demo application
* Red Hat Trusted Artifact Signer (RHTAS)
* Red Hat Trusted Profile Analyzer (RHTPA)

## Configuration

To configure the components we will need access to Azure Portal with permissions to create App Registrations and a Microsoft Entra ID tenant.

### Qtodo

#### Azure setup

1. Go to [Azure Portal](https://portal.azure.com)
2. Navigate to **Microsoft Entra ID**
3. Click **App registrations** in the left menu
4. Click **New registration**
5. Fill in the details:
* **Name**: `qtodo`
* **Supported account types**: Choose based on your needs
* **Single tenant**: Only users in your organization
* **Multi-tenant**: Users from any organization
* **Redirect URI**: Add the URL of the qtodo application here (for example `https://qtodo-qtodo.apps.ztvp.example.com`)/
6. Click **Register**

After the creation, you will see the _Overview_ page:

* **Application (client) ID**: `xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx`
* **Directory (tenant) ID**: `xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx`

**Save these values** - you will need them later.

Let's create a new secret for our app:

1. Click **Certificates & secrets** in the left menu
2. Click **New client secret**
3. Add a description: `qtodo secret`
4. Choose expiration: 6 months, 12 months, 24 months, or custom
5. Click **Add**
6. **IMPORTANT**: Copy the **Value** immediately - it will not be shown again

**Save this value securely** - We will need to add this secret to the Hashicorp Vault in the OpenShift cluster.

#### ZTVP setup

In the `values-secret.yaml` file, we add a new entry with the secret we generated in the Azure portal. For example:

```yaml
- name: qtodo-oidc-entraid
vaultPrefixes:
- apps/qtodo
fields:
- name: client-secret
path: ~/.azure/ztvp-qtodo-entraid-secret
```

In the `values-hub.yaml file`, we add the following configuration for the qtodo application:

```yaml
qtodo:
overrides:
- name: app.oidc.authServerUrl
value: https://login.microsoftonline.com/<YOUR_TENANT_ID>/v2.0
- name: app.oidc.clientId
value: <YOUR_CLIENT_ID>
- name: app.oidc.clientSecret.enabled
value: true
- name: app.oidc.clientSecret.vaultPath
value: secret/data/apps/qtodo/qtodo-oidc-entraid
```

### RHTAS

### RHTPA

#### API

#### UI
Loading