From 86ea7ead58ec8ba7b609730a82751aaa90207920 Mon Sep 17 00:00:00 2001 From: Pim van Nierop Date: Wed, 25 Feb 2026 13:22:19 +0100 Subject: [PATCH 01/10] feat(self-enrollment-ui): ory update --- charts/radar-self-enrolment-ui/Chart.yaml | 4 +- charts/radar-self-enrolment-ui/README.md | 43 ++++--- .../templates/deployment.yaml | 55 ++++++--- charts/radar-self-enrolment-ui/values.yaml | 109 +++++++++++------- 4 files changed, 137 insertions(+), 74 deletions(-) diff --git a/charts/radar-self-enrolment-ui/Chart.yaml b/charts/radar-self-enrolment-ui/Chart.yaml index 8bd318cb..c09705db 100644 --- a/charts/radar-self-enrolment-ui/Chart.yaml +++ b/charts/radar-self-enrolment-ui/Chart.yaml @@ -1,8 +1,8 @@ apiVersion: v2 -appVersion: "0.0.1" +appVersion: "0.1.0" description: A Helm chart for RADAR-base Self Enrolment UI name: radar-self-enrolment-ui -version: 0.3.1 +version: 0.4.0 icon: "http://radar-base.org/wp-content/uploads/2022/09/Logo_RADAR-Base-RGB.png" sources: - https://github.com/RADAR-base/radar-helm-charts/tree/main/charts/radar-self-enrolment-ui diff --git a/charts/radar-self-enrolment-ui/README.md b/charts/radar-self-enrolment-ui/README.md index 0bf8fecf..6ca56f07 100644 --- a/charts/radar-self-enrolment-ui/README.md +++ b/charts/radar-self-enrolment-ui/README.md @@ -2,7 +2,7 @@ # radar-self-enrolment-ui -![Version: 0.3.1](https://img.shields.io/badge/Version-0.3.1-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: 0.0.1](https://img.shields.io/badge/AppVersion-0.0.1-informational?style=flat-square) +![Version: 0.4.0](https://img.shields.io/badge/Version-0.4.0-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: 0.1.0](https://img.shields.io/badge/AppVersion-0.1.0-informational?style=flat-square) A Helm chart for RADAR-base Self Enrolment UI @@ -55,7 +55,7 @@ A Helm chart for RADAR-base Self Enrolment UI | advertised_protocol | string | `"https"` | The protocol in URIs (https, http) | | ingress.enabled | bool | `true` | Enable ingress controller resource | | ingress.annotations | object | check values.yaml | Annotations that define default ingress class, certificate issuer | -| ingress.path | string | `"/kratos-ui(/|$)(.*)"` | Path within the url structure | +| ingress.path | string | `"/study(/|$)(.*)"` | Path within the url structure | | ingress.pathType | string | `"ImplementationSpecific"` | Ingress Path type | | ingress.ingressClassName | string | `"nginx"` | IngressClass that will be be used to implement the Ingress (Kubernetes 1.18+) | | ingress.hosts | list | `["{{ .Values.server_name }}"]` | Hosts to accept requests from | @@ -76,7 +76,7 @@ A Helm chart for RADAR-base Self Enrolment UI | podSecurityContext.runAsGroup | int | `10000` | | | podSecurityContext.seccompProfile.type | string | `"RuntimeDefault"` | | | deployment.resources | object | `{}` | | -| deployment.extraEnv | list | `[{"name":"HYDRA_ADMIN_URL","value":"http://radar-hydra-admin"}]` | Array of extra envs to be passed to the deployment. Kubernetes format is expected - name: FOO value: BAR | +| deployment.extraEnv | string | `nil` | Array of extra envs to be passed to the deployment. Kubernetes format is expected - name: FOO value: BAR | | deployment.extraVolumes | list | `[]` | If you want to mount external volume For example, mount a secret containing Certificate root CA to verify database TLS connection. | | deployment.extraVolumeMounts | list | `[]` | | | deployment.nodeSelector | object | `{}` | Node labels for pod assignment. | @@ -103,26 +103,35 @@ A Helm chart for RADAR-base Self Enrolment UI | readinessProbe.successThreshold | int | `1` | Success threshold for readinessProbe | | readinessProbe.failureThreshold | int | `3` | Failure threshold for readinessProbe | | customStartupProbe | object | `{}` | Custom startupProbe that overrides the default one | -| startupProbe.enabled | bool | `true` | Enable startupProbe | +| startupProbe.enabled | bool | `false` | Enable startupProbe | | startupProbe.initialDelaySeconds | int | `5` | Initial delay seconds for startupProbe | | startupProbe.periodSeconds | int | `10` | Period seconds for startupProbe | | startupProbe.timeoutSeconds | int | `10` | Timeout seconds for startupProbe | | startupProbe.successThreshold | int | `1` | Success threshold for startupProbe | | startupProbe.failureThreshold | int | `30` | Failure threshold for startupProbe | | networkpolicy | object | check `values.yaml` | Network policy defines who can access this application and who this applications has access to | -| kratosAdminUrl | string | `"http://kratos-admin:80/admin"` | Set this to ORY Kratos's Admin URL | -| kratosPublicUrl | string | `"https://localhost/kratos"` | Set this to ORY Kratos's public URL | -| kratosBrowserUrl | string | `"https://localhost/kratos"` | Set this to ORY Kratos's public URL accessible from the outside world. | -| hydraAdminUrl | string | `"http://radar-hydra-admin"` | Set this to ORY Hydra's Admin URL | -| hydraPublicUrl | string | `"http://radar-hydra-public:4444"` | Set this to ORY Hydra's public URL | -| restSourceBackendUrl | string | `"http://radar-rest-sources-backend:8080/rest-sources/backend"` | Set this to the REST source backend service URL | -| gatewayUrl | string | `"http://radar-gateway:8080"` | Set this to the RADAR Gateway service URL | -| armtClientId | string | `"aRMT"` | Client ID for ARMT authentication | -| armtClientSecret | string | `""` | Client secret for ARMT authentication | -| sepClientId | string | `"SEP"` | Client ID for SEP authentication | -| sepClientSecret | string | `""` | Client secret for SEP authentication | -| githubAuthToken | string | `""` | GitHub authentication token for API access (leave empty if not used) | -| basePath | string | `"/kratos-ui"` | The basePath | +| basePath | string | `"study"` | | +| auth.armt.clientId | string | `"aRMT"` | | +| auth.armt.clientSecret | string | `""` | | +| auth.armt.redirectUri | string | `"{{ .Values.advertised_protocol }}://{{ .Values.server_name }}/{{ .Values.basePath }}/connect/armt"` | | +| auth.prmt.clientId | string | `"pRMT"` | | +| auth.prmt.clientSecret | string | `""` | | +| auth.prmt.redirectUri | string | `"{{ .Values.advertised_protocol }}://{{ .Values.server_name }}/{{ .Values.basePath }}/connect/prmt"` | | +| auth.sep.clientId | string | `"SEP"` | | +| auth.sep.clientSecret | string | `""` | | +| auth.sep.redirectUri | string | `"{{ .Values.advertised_protocol }}://{{ .Values.server_name }}/{{ .Values.basePath }}/connect/sep"` | | +| kratos.internalUrl | string | `"http://radar-kratos-public:80"` | | +| kratos.adminUrl | string | `"http://radar-kratos-admin/admin"` | | +| hydra.internalUrl | string | `"http://radar-hydra-public:4444"` | | +| hydra.adminUrl | string | `"http://radar-hydra-admin:4445/admin"` | | +| hydra.browserUrl | string | `"{{ .Values.advertised_protocol }}://{{ .Values.server_name }}/hydra"` | | +| rest_sources_auth.backendUrl | string | `"http://radar-rest-sources-backend:8080/rest-sources/backend"` | | +| rest_sources_auth.frontendUrl | string | `"{{ .Values.advertised_protocol }}://{{ .Values.server_name }}/rest-sources/authorizer/"` | | +| github.authToken | string | `""` | | +| github.repository | string | `"radar-self-enrolment-definitions"` | | +| gatewayUrl | string | `"http://radar-gateway:8080"` | | +| studyDefinitionRepository | string | `"LOCAL"` | | +| managementportal_url | string | `"http://management-portal:8080/managementportal"` | | | test.busybox | object | `{"repository":"busybox","tag":1}` | use a busybox image from another repository | ---------------------------------------------- diff --git a/charts/radar-self-enrolment-ui/templates/deployment.yaml b/charts/radar-self-enrolment-ui/templates/deployment.yaml index a153f22f..559cf2d8 100644 --- a/charts/radar-self-enrolment-ui/templates/deployment.yaml +++ b/charts/radar-self-enrolment-ui/templates/deployment.yaml @@ -38,36 +38,61 @@ spec: image: {{ template "radar-self-enrolment-ui.image" . }} imagePullPolicy: {{ .Values.image.pullPolicy | quote }} env: + # Kratos configuration - name: KRATOS_INTERNAL_URL - value: {{ .Values.kratosPublicUrl | quote }} + value: {{ .Values.kratos.internalUrl | quote }} - name: KRATOS_ADMIN_URL - value: {{ .Values.kratosAdminUrl | quote }} + value: {{ .Values.kratos.adminUrl | quote }} + + # Hydra configuration - name: HYDRA_ADMIN_URL - value: {{ .Values.hydraAdminUrl | quote }} + value: {{ .Values.hydra.adminUrl | quote }} - name: HYDRA_PUBLIC_URL - value: {{ .Values.hydraPublicUrl | quote }} + value: {{ .Values.hydra.internalUrl | quote }} + - name: NEXT_PUBLIC_HYDRA_PUBLIC_URL + value: {{ tpl .Values.hydra.browserUrl . | quote }} + + # REST source authorizer - name: RSA_BACKEND_URL - value: {{ .Values.restSourceBackendUrl | quote }} - - name: BASE_PATH + value: {{ .Values.rest_sources_auth.backendUrl | quote }} + - name: RSA_FRONTEND_URL + value: {{ tpl .Values.rest_sources_auth.frontendUrl . | quote }} + + # Base path configuration + - name: BASEPATH value: {{ .Values.basePath | quote }} - - name: SECURITY_MODE - value: {{ .Values.securityMode | quote }} + + # Authentication clients (ARMT, PRMT, SEP) - name: ARMT_CLIENT_ID - value: {{ .Values.armtClientId | quote }} + value: {{ .Values.auth.armt.clientId | quote }} - name: ARMT_CLIENT_SECRET - value: {{ .Values.armtClientSecret | quote }} + value: {{ .Values.auth.armt.clientSecret | quote }} + - name: PRMT_CLIENT_ID + value: {{ .Values.auth.prmt.clientId | quote }} + - name: PRMT_CLIENT_SECRET + value: {{ .Values.auth.prmt.clientSecret | quote }} - name: SEP_CLIENT_ID - value: {{ .Values.sepClientId | quote }} + value: {{ .Values.auth.sep.clientId | quote }} - name: SEP_CLIENT_SECRET - value: {{ .Values.sepClientSecret | quote }} + value: {{ .Values.auth.sep.clientSecret | quote }} + + # Public redirect URIs - name: NEXT_PUBLIC_ARMT_REDIRECT_URI - value: {{ .Values.advertised_protocol }}://{{ .Values.server_name }}/{{ .Values.basePath }}/connect/armt + value: {{ tpl .Values.auth.armt.redirectUri . | quote }} + - name: NEXT_PUBLIC_PRMT_REDIRECT_URI + value: {{ tpl .Values.auth.prmt.redirectUri . | quote }} - name: NEXT_PUBLIC_SEP_REDIRECT_URI - value: {{ .Values.advertised_protocol }}://{{ .Values.server_name }}/{{ .Values.basePath }}/connect/sep + value: {{ tpl .Values.auth.sep.redirectUri . | quote }} + + # GitHub and backend configuration - name: GITHUB_AUTH_TOKEN - value: {{ .Values.githubAuthToken | quote }} + value: {{ .Values.github.authToken | quote }} - name: GATEWAY_URL value: {{ .Values.gatewayUrl | quote }} + - name: STUDY_DEFINITION_REPOSITORY + value: {{ .Values.studyDefinitionRepository | quote }} + - name: MP_CONFIG_BASE_URL + value: {{ .Values.managementportal_url | quote }} - name: COOKIE_SECRET valueFrom: secretKeyRef: diff --git a/charts/radar-self-enrolment-ui/values.yaml b/charts/radar-self-enrolment-ui/values.yaml index 661ed691..c265eab2 100644 --- a/charts/radar-self-enrolment-ui/values.yaml +++ b/charts/radar-self-enrolment-ui/values.yaml @@ -81,7 +81,7 @@ ingress: annotations: cert-manager.io/cluster-issuer: letsencrypt-prod # -- Path within the url structure - path: "/kratos-ui(/|$)(.*)" + path: "/study(/|$)(.*)" # -- Ingress Path type pathType: ImplementationSpecific # -- IngressClass that will be be used to implement the Ingress (Kubernetes 1.18+) @@ -137,8 +137,6 @@ deployment: # - name: FOO # value: BAR extraEnv: - - name: HYDRA_ADMIN_URL - value: http://radar-hydra-admin # -- If you want to mount external volume # For example, mount a secret containing Certificate root CA to verify database # TLS connection. @@ -231,7 +229,7 @@ customStartupProbe: {} startupProbe: # -- Enable startupProbe - enabled: true + enabled: false # -- Initial delay seconds for startupProbe initialDelaySeconds: 5 # -- Period seconds for startupProbe @@ -264,13 +262,31 @@ networkpolicy: kubernetes.io/metadata.name: '{{ .Release.Namespace }}' podSelector: matchLabels: - app.kubernetes.io/name: kratos-admin + app.kubernetes.io/name: kratos - namespaceSelector: matchLabels: kubernetes.io/metadata.name: '{{ .Release.Namespace }}' podSelector: matchLabels: app.kubernetes.io/name: hydra + - namespaceSelector: + matchLabels: + kubernetes.io/metadata.name: '{{ .Release.Namespace }}' + podSelector: + matchLabels: + app.kubernetes.io/name: management-portal + - namespaceSelector: + matchLabels: + kubernetes.io/metadata.name: '{{ .Release.Namespace }}' + podSelector: + matchLabels: + app.kubernetes.io/name: radar-rest-sources-backend + - namespaceSelector: + matchLabels: + kubernetes.io/metadata.name: '{{ .Release.Namespace }}' + podSelector: + matchLabels: + app.kubernetes.io/name: radar-gateway - to: - namespaceSelector: matchLabels: @@ -284,44 +300,57 @@ networkpolicy: - port: 53 protocol: TCP -# -- Set this to ORY Kratos's Admin URL -kratosAdminUrl: "http://kratos-admin:80/admin" - -# -- Set this to ORY Kratos's public URL -kratosPublicUrl: "https://localhost/kratos" - -# -- Set this to ORY Kratos's public URL accessible from the outside world. -kratosBrowserUrl: "https://localhost/kratos" - -# -- Set this to ORY Hydra's Admin URL -hydraAdminUrl: "http://radar-hydra-admin" - -# -- Set this to ORY Hydra's public URL -hydraPublicUrl: "http://radar-hydra-public:4444" - -# -- Set this to the REST source backend service URL -restSourceBackendUrl: "http://radar-rest-sources-backend:8080/rest-sources/backend" - -# -- Set this to the RADAR Gateway service URL +# Application specific configuration + +# Base path for the application +basePath: "study" + +auth: + armt: + # Client credentials for ARMT authentication + clientId: "aRMT" + clientSecret: "" + redirectUri: "{{ .Values.advertised_protocol }}://{{ .Values.server_name }}/{{ .Values.basePath }}/connect/armt" + prmt: + # Client credentials for PRMT authentication + clientId: "pRMT" + clientSecret: "" + redirectUri: "{{ .Values.advertised_protocol }}://{{ .Values.server_name }}/{{ .Values.basePath }}/connect/prmt" + sep: + # Client credentials for SEP frontend authentication + clientId: "SEP" + clientSecret: "" + redirectUri: "{{ .Values.advertised_protocol }}://{{ .Values.server_name }}/{{ .Values.basePath }}/connect/sep" + +kratos: + # Kratos urls + internalUrl: "http://radar-kratos-public:80" + adminUrl: "http://radar-kratos-admin/admin" + +hydra: + # Hydra urls + internalUrl: "http://radar-hydra-public:4444" + adminUrl: "http://radar-hydra-admin:4445/admin" + browserUrl: "{{ .Values.advertised_protocol }}://{{ .Values.server_name }}/hydra" + +rest_sources_auth: + # Rest source auth urls + backendUrl: "http://radar-rest-sources-backend:8080/rest-sources/backend" + frontendUrl: "{{ .Values.advertised_protocol }}://{{ .Values.server_name }}/rest-sources/authorizer/" + +github: + # Github authentication token + authToken: "" + # Github repository name + repository: "radar-self-enrolment-definitions" + +# Gateway url gatewayUrl: "http://radar-gateway:8080" -# -- Client ID for ARMT authentication -armtClientId: "aRMT" - -# -- Client secret for ARMT authentication -armtClientSecret: "" - -# -- Client ID for SEP authentication -sepClientId: "SEP" - -# -- Client secret for SEP authentication -sepClientSecret: "" - -# -- GitHub authentication token for API access (leave empty if not used) -githubAuthToken: "" +# Study definition repository (GITHUB, LOCAL) +studyDefinitionRepository: "LOCAL" -# -- The basePath -basePath: "/kratos-ui" +managementportal_url: http://management-portal:8080/managementportal test: # -- use a busybox image from another repository From 161eb4c6d4aa2968c04347f8d53ca19ca1f47d65 Mon Sep 17 00:00:00 2001 From: Pim van Nierop Date: Wed, 25 Feb 2026 13:23:14 +0100 Subject: [PATCH 02/10] feat(management-portal): ory update --- charts/management-portal/Chart.yaml | 2 +- charts/management-portal/README.md | 26 +++--- .../templates/deployment.yaml | 86 +++++++++++++------ .../management-portal/templates/ingress.yaml | 4 +- .../templates/secrets-config.yaml | 8 +- .../management-portal/templates/secrets.yaml | 15 +++- charts/management-portal/values.yaml | 62 ++++++++++--- 7 files changed, 143 insertions(+), 60 deletions(-) diff --git a/charts/management-portal/Chart.yaml b/charts/management-portal/Chart.yaml index 18505687..12889b99 100644 --- a/charts/management-portal/Chart.yaml +++ b/charts/management-portal/Chart.yaml @@ -2,7 +2,7 @@ apiVersion: v2 appVersion: "2.1.13" description: A Helm chart for RADAR-Base Management Portal to manage projects and participants throughout RADAR-base. name: management-portal -version: 1.6.3 +version: 1.7.0 icon: "http://radar-base.org/wp-content/uploads/2022/09/Logo_RADAR-Base-RGB.png" sources: - https://github.com/RADAR-base/radar-helm-charts/tree/main/charts/management-portal diff --git a/charts/management-portal/README.md b/charts/management-portal/README.md index 597003e8..ecce7f92 100644 --- a/charts/management-portal/README.md +++ b/charts/management-portal/README.md @@ -3,7 +3,7 @@ # management-portal [![Artifact HUB](https://img.shields.io/endpoint?url=https://artifacthub.io/badge/repository/management-portal)](https://artifacthub.io/packages/helm/radar-base/management-portal) -![Version: 1.6.3](https://img.shields.io/badge/Version-1.6.3-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: 2.1.13](https://img.shields.io/badge/AppVersion-2.1.13-informational?style=flat-square) +![Version: 1.7.0](https://img.shields.io/badge/Version-1.7.0-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: 2.1.13](https://img.shields.io/badge/AppVersion-2.1.13-informational?style=flat-square) A Helm chart for RADAR-Base Management Portal to manage projects and participants throughout RADAR-base. @@ -91,23 +91,27 @@ A Helm chart for RADAR-Base Management Portal to manage projects and participant | postgres.host | string | `nil` | host name of the postgres db | | postgres.port | string | `nil` | post of the postgres db | | postgres.database | string | `nil` | database name | -| postgres.urlSecret | object | `{"key":"jdbc-uri","name":"radar-cloudnative-postgresql-managementportal"}` | Kubernetes secret containing the database JDBC Connection url (disables use of 'host', 'port' and 'database' values). | +| postgres.urlSecret | object | `{"key":"jdbc-uri","name":null}` | Kubernetes secret containing the database JDBC Connection url (disables use of 'host', 'port' and 'database' values). Set to empty/null to use chart's own secret created from postgres.url value Otherwise e.g. name: radar-cloudnative-postgresql-managementportal | | postgres.user | string | `nil` | database user | -| postgres.userSecret | object | `{"key":"username","name":"radar-cloudnative-postgresql-managementportal"}` | Kubernetes secret containing the database username (disables use of 'user' value). | +| postgres.userSecret | object | `{"key":"username","name":null}` | Kubernetes secret containing the database username (disables use of 'user' value). Set to empty/null to use chart's own secret created from postgres.user value Otherwise e.g. name: radar-cloudnative-postgresql-managementportal | | postgres.password | string | `nil` | password of the database user | -| postgres.passwordSecret | object | `{"key":"password","name":"radar-cloudnative-postgresql-managementportal"}` | Kubernetes secret containing the database password (disables use of 'password' value). | +| postgres.passwordSecret | object | `{"key":"password","name":null}` | Kubernetes secret containing the database password (disables use of 'password' value). Set to empty/null to use chart's own secret created from postgres.password value Otherwise e.g. name: radar-cloudnative-postgresql-managementportal | | postgres.connection_parameters | string | `""` | Additional JDBC connection parameters e.g. sslmode=verify-full. Ignored when using 'urlSecret'. | | postgres.ssl.enabled | bool | `false` | set to true if the connecting to postgres using SSL | | postgres.ssl.keystore | string | `""` | base64 encoded certificate needed to connect to the PostgreSQL With helmfile, this can be set in a production.yaml.gotmpl file by setting keystore: {{ readFile "certificate.pem" | b64enc | quote }} or with SOPS keystore: {{ exec "sops" (list "-d" "certificate.pem") | b64enc | quote }} | | server_name | string | `"localhost"` | domain name of the server | | catalogue_server | string | `"catalog-server"` | Hostname of the catalogue-server | +| identity_server.internal | bool | `true` | Whether the IDP is the MP's internal IDP | +| identity_server.public_url | string | `"http://radar-kratos-public"` | The publicly accessible server URL for the IDP; needed when deviating from http(s)://server_name/kratos | +| identity_server.admin_url | string | `"http://radar-kratos-admin"` | The admin server URL for the IDP used for service-to-service requests. Only needs to be accessible from inside the cluster where the managementportal resides | +| identity_server.user_activation_flow_type | string | `"verification"` | The user activation flow type to use for Management Portal (e.g., recovery, verification) | +| identity_server.user_activation_method | string | `"link"` | The user activation method to use for Management Portal (e.g., link, code) | | identity_server.admin_email | string | `"admin@example.com"` | The admin email to link to the admin service account. This account should only be used to set up admin-users | -| identity_server.server_url | string | `nil` | The publicly accessible server URL for the IDP; needed when deviating from http(s)://server_name/kratos | -| identity_server.server_admin_url | string | `"http://radar-kratos-admin"` | The admin server URL for the IDP used for service-to-service requests. Only needs to be accessible from inside the cluster where the managementportal resides | -| identity_server.login_url | string | `nil` | The publicly accessible login URL for the IDP; needed when deviating from http(s)://server_name/kratos-ui | -| authserver.server_url | string | `"http://radar-hydra:4444"` | The publicly accessible server URL for the authserver; needed when deviating from http(s)://server_name/auth | -| authserver.server_admin_url | string | `"http://radar-hydra:4445"` | The admin server URL for the authserver used for service-to-service requests. Only needs to be accessible from inside the cluster where the managementportal resides | -| authserver.login_url | string | `"http://localhost:4444"` | The publicly accessible login URL for the authserver; needed when deviating from http(s)://server_name/auth/login | +| authserver.internal | bool | `true` | Whether the authserver is the MP's internal authserver | +| authserver.token_url | string | `"http://radar-hydra-public:4444/oauth2/token"` | The publicly accessible server URL for the authserver; needed when deviating from http(s)://server_name/auth | +| authserver.admin_url | string | `"http://radar-hydra-admin:4445"` | The admin server URL for the authserver used for service-to-service requests. Only needs to be accessible from inside the cluster where the managementportal resides | +| authserver.auth_url | string | `"{{ .Values.advertised_protocol }}://{{ .Values.server_name }}/hydra/oauth2/auth"` | The publicly accessible login URL for the authserver; needed when deviating from http(s)://server_name/auth/login | +| authserver.jwks_url | string | `"http://radar-hydra-admin:4445/admin/keys/hydra.jwt.access-token"` | The JWKS URL for the authserver; needed when deviating from http(s)://server_name/auth/jwks | | managementportal.catalogue_server_enable_auto_import | bool | `false` | set to true, if automatic source-type import from catalogue server should be enabled | | managementportal.common_privacy_policy_url | string | `"http://info.thehyve.nl/radar-cns-privacy-policy"` | Override with a publicly resolvable url of the privacy-policy url for your set-up. This can be overridden on a project basis as well. | | managementportal.oauth_checking_key_aliases_0 | string | `"radarbase-managementportal-ec"` | Keystore alias to sign JWT tokens from Management Portal | @@ -115,6 +119,8 @@ A Helm chart for RADAR-Base Management Portal to manage projects and participant | managementportal.oauth_require_aal2 | bool | `true` | Whether or not to require AAL2 level authentication (i.e. MFA) | | managementportal.frontend_client_secret | string | `"xxx"` | OAuth2 Client secret of the Management Portal frontend application | | managementportal.common_admin_password | string | `"xxx"` | Admin password of the default admin user created by the system | +| managementportal.oauth_clients_file | string | `"/secrets/oauth_client_details.csv"` | The file where the OAuth2 client details are stored | +| managementportal.base_url | string | `""` | Base URL managementportal calls from inside the application container | | smtp.enabled | bool | `false` | set to true, if SMTP server should be enabled. Required to be true for production setup | | smtp.host | string | `"smtp"` | Hostname of the SMTP server | | smtp.port | int | `25` | Port of the SMTP server | diff --git a/charts/management-portal/templates/deployment.yaml b/charts/management-portal/templates/deployment.yaml index 8a7da231..7293ff1f 100644 --- a/charts/management-portal/templates/deployment.yaml +++ b/charts/management-portal/templates/deployment.yaml @@ -58,18 +58,33 @@ spec: - name: SPRING_DATASOURCE_URL valueFrom: secretKeyRef: - name: {{ .Values.postgres.urlSecret.name | default $secretName }} - key: {{ .Values.postgres.urlSecret.key | default "databaseUrl" }} +{{- if .Values.postgres.urlSecret.name }} + name: {{ .Values.postgres.urlSecret.name }} + key: {{ .Values.postgres.urlSecret.key | default "jdbc-uri" }} +{{- else }} + name: {{ $secretName }} + key: postgres_url +{{- end }} - name: SPRING_DATASOURCE_USERNAME valueFrom: secretKeyRef: - name: {{ .Values.postgres.userSecret.name | default $secretName }} - key: {{ .Values.postgres.userSecret.key | default "databaseUser" }} +{{- if .Values.postgres.userSecret.name }} + name: {{ .Values.postgres.userSecret.name }} + key: {{ .Values.postgres.userSecret.key | default "username" }} +{{- else }} + name: {{ $secretName }} + key: postgresql_user +{{- end }} - name: SPRING_DATASOURCE_PASSWORD valueFrom: secretKeyRef: - name: {{ .Values.postgres.passwordSecret.name | default $secretName }} - key: {{ .Values.postgres.passwordSecret.key | default "databasePassword" }} +{{- if .Values.postgres.passwordSecret.name }} + name: {{ .Values.postgres.passwordSecret.name }} + key: {{ .Values.postgres.passwordSecret.key | default "password" }} +{{- else }} + name: {{ $secretName }} + key: postgresql_password +{{- end }} - name: SPRING_DATASOURCE_HIKARI_CONNECTION_TIMEOUT value: "15000" - name: SPRING_DATASOURCE_HIKARI_VALIDATION_TIMEOUT @@ -81,34 +96,48 @@ spec: - name: MANAGEMENTPORTAL_COMMON_BASEURL value: {{ printf "%s://%s" .Values.advertised_protocol .Values.server_name }} - name: MANAGEMENTPORTAL_COMMON_MANAGEMENT_PORTAL_BASE_URL + {{- if .Values.managementportal.base_url }} + value: {{ .Values.managementportal.base_url }} + {{- else }} value: {{ printf "%s://%s/managementportal" .Values.advertised_protocol .Values.server_name }} + {{- end }} + - name: MANAGEMENTPORTAL_FRONTEND_CLIENTID + value: "ManagementPortalapp" - name: MANAGEMENTPORTAL_FRONTEND_CLIENT_SECRET valueFrom: secretKeyRef: name: {{ $secretName }} key: managementportal_frontend_client_secret - - name: MANAGEMENTPORTAL_OAUTH_CLIENTS_FILE - value: /secrets/oauth_client_details.csv - name: MANAGEMENTPORTAL_CATALOGUE_SERVER_ENABLE_AUTO_IMPORT value: "{{ .Values.managementportal.catalogue_server_enable_auto_import }}" + - name: MANAGEMENTPORTAL_OAUTH_CLIENTS_FILE + value: "{{ .Values.managementportal.oauth_clients_file }}" - name: MANAGEMENTPORTAL_OAUTH_REQUIRE_AAL2 value: "{{ .Values.managementportal.oauth_require_aal2 }}" - name: MANAGEMENTPORTAL_CATALOGUE_SERVER_SERVER_URL value: http://{{ .Values.catalogue_server }}:9010/source-types - - name: MANAGEMENTPORTAL_IDENTITY_SERVER_ADMIN_EMAIL + - name: MANAGEMENTPORTAL_IDENTITYSERVER_ADMINEMAIL value: {{ .Values.identity_server.admin_email }} - - name: MANAGEMENTPORTAL_IDENTITY_SERVER_SERVER_URL - value: {{ $idpServerUrl }} - - name: MANAGEMENTPORTAL_IDENTITY_SERVER_LOGIN_URL - value: {{ $idpLoginUrl }} - - name: MANAGEMENTPORTAL_IDENTITY_SERVER_SERVER_ADMIN_URL - value: {{ .Values.identity_server.server_admin_url }} - - name: MANAGEMENTPORTAL_AUTHSERVER_SERVERURL - value: {{ $idpServerUrl }} - - name: MANAGEMENTPORTAL_AUTHSERVER_LOGINURL - value: {{ $idpLoginUrl }} - - name: MANAGEMENTPORTAL_AUTHSERVER_SERVERADMINURL - value: {{ .Values.authserver.server_admin_url | quote }} + - name: MANAGEMENTPORTAL_IDENTITYSERVER_PUBLICURL + value: {{ tpl .Values.identity_server.public_url . }} + - name: MANAGEMENTPORTAL_IDENTITYSERVER_ADMINURL + value: {{ tpl .Values.identity_server.admin_url . }} + - name: MANAGEMENTPORTAL_IDENTITYSERVER_INTERNAL + value: {{ .Values.identity_server.internal | quote }} + - name: MANAGEMENTPORTAL_IDENTITYSERVER_USER_ACTIVATION_FLOW_TYPE + value: {{ .Values.identity_server.user_activation_flow_type | quote }} + - name: MANAGEMENTPORTAL_IDENTITYSERVER_USER_ACTIVATION_METHOD + value: {{ .Values.identity_server.user_activation_method | quote }} + - name: MANAGEMENTPORTAL_AUTHSERVER_TOKENURL + value: {{ tpl .Values.authserver.token_url . }} + - name: MANAGEMENTPORTAL_AUTHSERVER_AUTHURL + value: {{ tpl .Values.authserver.auth_url . }} + - name: MANAGEMENTPORTAL_AUTHSERVER_INTERNAL + value: {{ .Values.authserver.internal | quote }} + - name: MANAGEMENTPORTAL_AUTHSERVER_ADMINURL + value: {{ tpl .Values.authserver.admin_url . }} + - name: MANAGEMENTPORTAL_AUTHSERVER_JWKSURL + value: {{ tpl .Values.authserver.jwks_url . }} - name: MANAGEMENTPORTAL_COMMON_ADMIN_PASSWORD valueFrom: secretKeyRef: @@ -138,14 +167,12 @@ spec: secretKeyRef: name: {{ $secretName }} key: smtpPassword - {{ end }} - - name: SPRING_MAIL_FROM - value: {{ .Values.smtp.from | quote }} + {{- end }} - name: SPRING_MAIL_PROPERTIES_MAIL_SMTP_AUTH value: "{{ .Values.smtp.auth }}" - name: SPRING_MAIL_PROPERTIES_MAIL_SMTP_STARTTLS_ENABLE value: {{ .Values.smtp.starttls | quote }} - {{ end }} + {{- end }} {{- with .Values.extraEnvVars }} {{- toYaml . | nindent 10 }} {{- end }} @@ -200,21 +227,26 @@ spec: volumeMounts: - name: config mountPath: /config/ + {{- if .Values.authserver.internal }} - name: secrets-config mountPath: /secrets/ + # Otherwise: Unable to read header from OAuth clients file: java.nio.file.NoSuchFileException: /mp-includes/config/oauth_client_details.csv + {{- end }} - name: keystore mountPath: /mp-includes/config/ {{- if .Values.postgres.ssl.enabled }} - name: postgres-root-cert mountPath: /root/.postgresql/ - {{ end }} + {{- end }} volumes: - name: config configMap: name: {{ include "management-portal.fullname" . }} + {{- if .Values.authserver.internal }} - name: secrets-config secret: secretName: {{ include "management-portal.fullname" . }}-config + {{- end }} - name: keystore secret: secretName: {{ include "management-portal.fullname" . }}-keystore @@ -222,7 +254,7 @@ spec: - name: postgres-root-cert secret: secretName: {{ include "management-portal.fullname" . }}-root-cert - {{ end }} + {{- end }} {{- with .Values.nodeSelector }} nodeSelector: {{- toYaml . | nindent 8 }} diff --git a/charts/management-portal/templates/ingress.yaml b/charts/management-portal/templates/ingress.yaml index e470f935..1a8a3239 100644 --- a/charts/management-portal/templates/ingress.yaml +++ b/charts/management-portal/templates/ingress.yaml @@ -24,13 +24,13 @@ spec: tls: - hosts: {{- range $hosts }} - - {{ . | quote }} + - {{ ( tpl . $ ) | quote }} {{- end }} secretName: {{ .Values.ingress.tls.secretName }} {{- end }} rules: {{- range .Values.ingress.hosts }} - - host: {{ . | quote }} + - host: {{ ( tpl . $ ) | quote }} http: paths: - path: {{ $path | quote }} diff --git a/charts/management-portal/templates/secrets-config.yaml b/charts/management-portal/templates/secrets-config.yaml index 57e13947..6fe0e379 100644 --- a/charts/management-portal/templates/secrets-config.yaml +++ b/charts/management-portal/templates/secrets-config.yaml @@ -13,9 +13,9 @@ client_id;resource_ids;client_secret;scope;authorized_grant_types;redirect_uri;a {{- range $index, $redirect_uri := $client.redirect_uri -}} {{- if gt $index 0 -}},{{- end -}} {{- if regexMatch "^/" $redirect_uri -}} - https://{{ $.Values.server_name }}{{ $redirect_uri }} + {{ $.Values.advertised_protocol }}://{{ $.Values.server_name }}{{ $redirect_uri }} {{- else -}} - {{ $redirect_uri }} + {{ tpl $redirect_uri $ }} {{- end -}} {{- end -}}; {{- $client.authorities | default "" }}; @@ -26,7 +26,8 @@ client_id;resource_ids;client_secret;scope;authorized_grant_types;redirect_uri;a {{- end -}} {{- end -}} {{- end -}} -{{- end}} +{{- end }} +{{- if .Values.authserver.internal }} apiVersion: v1 kind: Secret metadata: @@ -38,3 +39,4 @@ metadata: {{- end }} data: oauth_client_details.csv: {{ include "oauth-clients-details.csv" . | b64enc | quote }} +{{- end }} diff --git a/charts/management-portal/templates/secrets.yaml b/charts/management-portal/templates/secrets.yaml index 766c19a9..878528ad 100644 --- a/charts/management-portal/templates/secrets.yaml +++ b/charts/management-portal/templates/secrets.yaml @@ -9,17 +9,24 @@ metadata: {{- end }} type: Opaque data: - {{- if and .Values.postgres.url (not .Values.postgres.urlSecret) }} + {{- if and .Values.postgres.url (not .Values.postgres.urlSecret.name) }} {{- if .Values.postgres.connection_parameters }} postgres_url: {{ printf "%s?%s" .Values.postgres.url .Values.postgres.connection_parameters | b64enc | quote }} - {{- else -}} + {{- else }} postgres_url: {{ .Values.postgres.url | b64enc | quote }} {{- end }} + {{- else if and .Values.postgres.host .Values.postgres.port .Values.postgres.database (not .Values.postgres.urlSecret.name) }} + {{- $baseUrl := printf "jdbc:postgresql://%s:%v/%s" .Values.postgres.host .Values.postgres.port .Values.postgres.database }} + {{- if .Values.postgres.connection_parameters }} + postgres_url: {{ printf "%s?%s" $baseUrl .Values.postgres.connection_parameters | b64enc | quote }} + {{- else }} + postgres_url: {{ $baseUrl | b64enc | quote }} + {{- end }} {{- end }} - {{- if and .Values.postgres.user (not .Values.postgres.userSecret) }} + {{- if and .Values.postgres.user (not .Values.postgres.userSecret.name) }} postgresql_user: {{ .Values.postgres.user | b64enc | quote }} {{- end }} - {{- if and .Values.postgres.password (not .Values.postgres.passwordSecret) }} + {{- if and .Values.postgres.password (not .Values.postgres.passwordSecret.name) }} postgresql_password: {{ .Values.postgres.password | b64enc | quote }} {{- end }} managementportal_frontend_client_secret: {{ .Values.managementportal.frontend_client_secret | b64enc | quote }} diff --git a/charts/management-portal/values.yaml b/charts/management-portal/values.yaml index 1b662e6e..c8812b32 100644 --- a/charts/management-portal/values.yaml +++ b/charts/management-portal/values.yaml @@ -244,6 +244,18 @@ networkpolicy: podSelector: matchLabels: app.kubernetes.io/name: '{{ .Values.postgres.host | default "radar-cloudnative-postgresql-cluster" | trunc 63 | trimSuffix "-" }}' + - namespaceSelector: + matchLabels: + kubernetes.io/metadata.name: '{{ .Release.Namespace }}' + podSelector: + matchLabels: + app.kubernetes.io/name: hydra + - namespaceSelector: + matchLabels: + kubernetes.io/metadata.name: '{{ .Release.Namespace }}' + podSelector: + matchLabels: + app.kubernetes.io/name: kratos - to: - namespaceSelector: matchLabels: @@ -275,22 +287,28 @@ postgres: database: # -- Kubernetes secret containing the database JDBC Connection url # (disables use of 'host', 'port' and 'database' values). + # Set to empty/null to use chart's own secret created from postgres.url value + # Otherwise e.g. name: radar-cloudnative-postgresql-managementportal urlSecret: - name: radar-cloudnative-postgresql-managementportal + name: key: jdbc-uri # -- database user user: # -- Kubernetes secret containing the database username # (disables use of 'user' value). + # Set to empty/null to use chart's own secret created from postgres.user value + # Otherwise e.g. name: radar-cloudnative-postgresql-managementportal userSecret: - name: radar-cloudnative-postgresql-managementportal + name: key: username # -- password of the database user password: # -- Kubernetes secret containing the database password # (disables use of 'password' value). + # Set to empty/null to use chart's own secret created from postgres.password value + # Otherwise e.g. name: radar-cloudnative-postgresql-managementportal passwordSecret: - name: radar-cloudnative-postgresql-managementportal + name: key: password # -- Additional JDBC connection parameters e.g. sslmode=verify-full. @@ -314,22 +332,36 @@ catalogue_server: catalog-server # Settings pertaining to the identity provider (IDP) identity_server: - # -- The admin email to link to the admin service account. This account should only be used to set up admin-users - admin_email: admin@example.com + # -- Whether the IDP is the MP's internal IDP + internal: true + + # Set the following values if the IDP is external to the cluster (i.e. Ory Kratos) + # -- The publicly accessible server URL for the IDP; needed when deviating from http(s)://server_name/kratos - server_url: + public_url: http://radar-kratos-public # -- The admin server URL for the IDP used for service-to-service requests. Only needs to be accessible from inside the cluster where the managementportal resides - server_admin_url: http://radar-kratos-admin - # -- The publicly accessible login URL for the IDP; needed when deviating from http(s)://server_name/kratos-ui - login_url: + admin_url: http://radar-kratos-admin + # -- The user activation flow type to use for Management Portal (e.g., recovery, verification) + user_activation_flow_type: "verification" + # -- The user activation method to use for Management Portal (e.g., link, code) + user_activation_method: "link" + # -- The admin email to link to the admin service account. This account should only be used to set up admin-users + admin_email: admin@example.com authserver: + # -- Whether the authserver is the MP's internal authserver + internal: true + + # Set the following values if the authserver is external to the cluster (i.e. Ory Hydra) + # -- The publicly accessible server URL for the authserver; needed when deviating from http(s)://server_name/auth - server_url: http://radar-hydra:4444 + token_url: http://radar-hydra-public:4444/oauth2/token # -- The admin server URL for the authserver used for service-to-service requests. Only needs to be accessible from inside the cluster where the managementportal resides - server_admin_url: http://radar-hydra:4445 + admin_url: http://radar-hydra-admin:4445 # -- The publicly accessible login URL for the authserver; needed when deviating from http(s)://server_name/auth/login - login_url: http://localhost:4444 + auth_url: '{{ .Values.advertised_protocol }}://{{ .Values.server_name }}/hydra/oauth2/auth' + # -- The JWKS URL for the authserver; needed when deviating from http(s)://server_name/auth/jwks + jwks_url: http://radar-hydra-admin:4445/admin/keys/hydra.jwt.access-token managementportal: # -- set to true, if automatic source-type import from catalogue server should be enabled @@ -346,6 +378,10 @@ managementportal: frontend_client_secret: xxx # -- Admin password of the default admin user created by the system common_admin_password: xxx + # -- The file where the OAuth2 client details are stored + oauth_clients_file: /secrets/oauth_client_details.csv + # -- Base URL managementportal calls from inside the application container + base_url: '' # Configurations of the SMTP server to send activation emails from Management Portal smtp: @@ -608,7 +644,7 @@ oauth_clients: access_token_validity: 900 refresh_token_validity: 78000 redirect_uri: - - http://dashboard.localhost/login/generic_oauth + - '{{ .Values.advertised_protocol }}://dashboard.{{ .Values.server_name }}/login/generic_oauth' autoapprove: - USER.READ From c7ca717cebbf874ab0a713dd94b98dfd06760e16 Mon Sep 17 00:00:00 2001 From: Pim van Nierop Date: Wed, 25 Feb 2026 13:24:09 +0100 Subject: [PATCH 03/10] feat(fitbit-connector): ory update --- charts/radar-fitbit-connector/README.md | 6 +++--- charts/radar-fitbit-connector/values.yaml | 12 +++++++++--- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/charts/radar-fitbit-connector/README.md b/charts/radar-fitbit-connector/README.md index 940a8a34..f4a0e520 100644 --- a/charts/radar-fitbit-connector/README.md +++ b/charts/radar-fitbit-connector/README.md @@ -96,9 +96,9 @@ A Helm chart for RADAR-base fitbit connector. This application collects data fro | fitbit_api_url | string | `"https://api.fitbit.com"` | Fitbit API URL. | | fitbit_api_client | string | `""` | Fitbit API client id. | | fitbit_api_secret | string | `""` | Fitbit API client secret. | -| oauthClientId | string | `"radar_fitbit_connector"` | OAuth2 client id from Management Portal | -| oauthClientSecret | string | `"secret"` | OAuth2 client secret from Management Portal | -| auth_url | string | `"http://management-portal:8080/managementportal/oauth/token"` | OAuth2 Auth URL for connector client to get access tokens | +| oauthClientId | string | `"radar_fitbit_connector"` | OAuth2 client id from Hydra | +| oauthClientSecret | string | `"secret"` | OAuth2 client secret from Hydra | +| auth_url | string | `"http://radar-hydra-public:4444/oauth2/token"` | OAuth2 Auth URL for connector client to get access tokens | | managementportal_url | string | `"http://management-portal:8080/managementportal"` | URL of Management Portal. This will be used to create URLs to access Management Portal | | includeIntradayData | bool | `true` | Set to true, if intraday access data should be collected by the connector. This will be set in connector.properties. | | user_repository_class | string | `"ServiceUserRepository"` | Class of the user repository to use. This should be a class that implements the UserRepository interface. | diff --git a/charts/radar-fitbit-connector/values.yaml b/charts/radar-fitbit-connector/values.yaml index f541c9d0..a1fe135e 100644 --- a/charts/radar-fitbit-connector/values.yaml +++ b/charts/radar-fitbit-connector/values.yaml @@ -204,6 +204,12 @@ networkpolicy: podSelector: matchLabels: app.kubernetes.io/name: 'management-portal' + - namespaceSelector: + matchLabels: + kubernetes.io/metadata.name: '{{ .Release.Namespace }}' + podSelector: + matchLabels: + app.kubernetes.io/name: 'radar-hydra' - to: - namespaceSelector: matchLabels: @@ -247,12 +253,12 @@ fitbit_api_client: "" # -- Fitbit API client secret. fitbit_api_secret: "" -# -- OAuth2 client id from Management Portal +# -- OAuth2 client id from Hydra oauthClientId: radar_fitbit_connector -# -- OAuth2 client secret from Management Portal +# -- OAuth2 client secret from Hydra oauthClientSecret: secret # -- OAuth2 Auth URL for connector client to get access tokens -auth_url: http://management-portal:8080/managementportal/oauth/token +auth_url: http://radar-hydra-public:4444/oauth2/token # -- URL of Management Portal. This will be used to create URLs to access Management Portal managementportal_url: http://management-portal:8080/managementportal # -- Set to true, if intraday access data should be collected by the connector. This will be set in connector.properties. From 1a4cfe10682689ef902d889d700ac6b80efc2ddd Mon Sep 17 00:00:00 2001 From: Pim van Nierop Date: Wed, 25 Feb 2026 13:24:34 +0100 Subject: [PATCH 04/10] feat(radar-gateway): ory update --- charts/radar-gateway/README.md | 3 +-- charts/radar-gateway/templates/configmap.yaml | 1 - charts/radar-gateway/values.yaml | 5 +---- 3 files changed, 2 insertions(+), 7 deletions(-) diff --git a/charts/radar-gateway/README.md b/charts/radar-gateway/README.md index f56b1276..d92d587c 100644 --- a/charts/radar-gateway/README.md +++ b/charts/radar-gateway/README.md @@ -118,8 +118,7 @@ A Helm chart for RADAR-base gateway. REST Gateway to Kafka, for incoming partici | cc.apiSecret | string | `"ccApiSecret"` | Confluent Cloud cluster API secret | | cc.schemaRegistryApiKey | string | `"srApiKey"` | Confluent Cloud schema registry API key | | cc.schemaRegistryApiSecret | string | `"srApiSecret"` | Confluent Cloud schema registry API secret | -| public_key_endpoints_enabled | bool | `false` | Enables config of public key endpoints for token verification This config option is implemented to fix a compatibility issue with radar-gateway. It can be removed when the publicKeyUrls config option is merged to master. | -| public_key_endpoints | list | `[]` | List of public key endpoints for token verification | +| public_key_endpoints | list | `["http://radar-hydra-public:4444/.well-known/jwks.json"]` | List of public key endpoints for token verification | | serverName | string | `"localhost"` | Resolvable server name, needed to find the advertised URL and callback URL | | sentry.dsn | string | `nil` | DSN (Data Source Name) of the sentry server | | sentry.level | string | `"ERROR"` | Log level for sentry (TRACE, DEBUG, INFO, WARN, or ERROR) | diff --git a/charts/radar-gateway/templates/configmap.yaml b/charts/radar-gateway/templates/configmap.yaml index 43dc0008..18df9fe7 100644 --- a/charts/radar-gateway/templates/configmap.yaml +++ b/charts/radar-gateway/templates/configmap.yaml @@ -61,7 +61,6 @@ data: checkSourceId: {{ .Values.checkSourceId }} {{- if or .Values.public_key_endpoints_enabled .Values.public_key_endpoints }} publicKeyUrls: - - {{ printf "%s://%s/managementportal/oauth/token_key" .Values.advertised_protocol .Values.serverName | quote }} {{- range .Values.public_key_endpoints }} - {{ . | quote }} {{ end -}} diff --git a/charts/radar-gateway/values.yaml b/charts/radar-gateway/values.yaml index bb5bfe95..96aaae24 100644 --- a/charts/radar-gateway/values.yaml +++ b/charts/radar-gateway/values.yaml @@ -311,11 +311,8 @@ cc: schemaRegistryApiSecret: srApiSecret # -- Enables config of public key endpoints for token verification -# This config option is implemented to fix a compatibility issue with radar-gateway. -# It can be removed when the publicKeyUrls config option is merged to master. -public_key_endpoints_enabled: false # -- List of public key endpoints for token verification -public_key_endpoints: [] +public_key_endpoints: ["http://radar-hydra-public:4444/.well-known/jwks.json"] # -- Resolvable server name, needed to find the advertised URL and callback URL serverName: localhost From 2efebc03dcbfbdbaada2369eb738a6e44e1435ae Mon Sep 17 00:00:00 2001 From: Pim van Nierop Date: Wed, 25 Feb 2026 13:24:58 +0100 Subject: [PATCH 05/10] feat(radar-home): ory update --- charts/radar-home/Chart.yaml | 2 +- charts/radar-home/README.md | 14 ++++++++------ charts/radar-home/templates/deployment.yaml | 8 ++++---- charts/radar-home/templates/ingress.yaml | 4 ++-- charts/radar-home/values.yaml | 14 +++++++++----- 5 files changed, 24 insertions(+), 18 deletions(-) diff --git a/charts/radar-home/Chart.yaml b/charts/radar-home/Chart.yaml index 9f10c03d..b5b0000d 100644 --- a/charts/radar-home/Chart.yaml +++ b/charts/radar-home/Chart.yaml @@ -2,7 +2,7 @@ apiVersion: v2 appVersion: "0.1.7" description: RADAR-base home page. name: radar-home -version: 0.5.4 +version: 0.6.0 icon: "http://radar-base.org/wp-content/uploads/2022/09/Logo_RADAR-Base-RGB.png" sources: - https://github.com/RADAR-base/radar-helm-charts/tree/main/charts/radar-home diff --git a/charts/radar-home/README.md b/charts/radar-home/README.md index 0b05f110..f0f17ad6 100644 --- a/charts/radar-home/README.md +++ b/charts/radar-home/README.md @@ -3,7 +3,7 @@ # radar-home [![Artifact HUB](https://img.shields.io/endpoint?url=https://artifacthub.io/badge/repository/radar-home)](https://artifacthub.io/packages/helm/radar-base/radar-home) -![Version: 0.5.4](https://img.shields.io/badge/Version-0.5.4-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: 0.1.7](https://img.shields.io/badge/AppVersion-0.1.7-informational?style=flat-square) +![Version: 0.6.0](https://img.shields.io/badge/Version-0.6.0-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: 0.1.7](https://img.shields.io/badge/AppVersion-0.1.7-informational?style=flat-square) RADAR-base home page. @@ -48,12 +48,14 @@ RADAR-base home page. | service.type | string | `"ClusterIP"` | Kubernetes Service type | | service.port | int | `8080` | Port | | disable_tls | bool | `false` | Reconfigure Ingress to not force TLS | +| server_name | string | `"localhost"` | Hostname for the home service | +| advertised_protocol | string | `"https"` | The protocol in advertised URIs (https, http) | | ingress.enabled | bool | `true` | Enable ingress controller resource | | ingress.annotations | object | check values.yaml | Annotations that define default ingress class, certificate issuer | | ingress.path | string | `"/"` | Path within the url structure | | ingress.pathType | string | `"ImplementationSpecific"` | Ingress Path type | | ingress.ingressClassName | string | `"nginx"` | IngressClass that will be be used to implement the Ingress (Kubernetes 1.18+) | -| ingress.hosts | list | `["localhost"]` | Hosts to accept requests from | +| ingress.hosts | list | `["{{ .Values.server_name }}"]` | Hosts to accept requests from | | ingress.tls.secretName | string | `"radar-base-tls"` | TLS Secret Name | | resources.limits | object | `{"cpu":"200m"}` | CPU/Memory resource limits | | resources.requests | object | `{"cpu":"10m","memory":"5Mi"}` | CPU/Memory resource requests | @@ -84,16 +86,16 @@ RADAR-base home page. | startupProbe.failureThreshold | int | `30` | Failure threshold for startupProbe | | networkpolicy | object | check `values.yaml` | Network policy defines who can access this application and who this applications has access to | | s3.enabled | bool | `false` | Enable link to S3 | -| s3.url | string | `nil` | URL to S3 | +| s3.url | string | `"{{ .Values.advertised_protocol }}://s3.{{ .Values.server_name }}/login"` | URL to S3 | | dashboard.enabled | bool | `false` | Enable link to dashboard | -| dashboard.url | string | `nil` | URL to dashboard | +| dashboard.url | string | `"{{ .Values.advertised_protocol }}://dashboard.{{ .Values.server_name }}"` | URL to dashboard | | appConfig.enabled | bool | `false` | Enable link to app-config service | | uploadPortal.enabled | bool | `false` | Enable link to upload portal | | restAuthorizer.enabled | bool | `false` | Enable link to rest source authorizer | | monitoring.enabled | bool | `false` | Enable link to the monitoring stack, usually Prometheus | -| monitoring.url | string | `nil` | URL to the monitoring stack, usually Prometheus | +| monitoring.url | string | `"{{ .Values.advertised_protocol }}://grafana.{{ .Values.server_name }}/login"` | URL to the monitoring stack, usually Prometheus | | logging.enabled | bool | `false` | Enable link to the logging stack, usually Graylog | -| logging.url | string | `nil` | URL to the monitoring stack, usually Graylog | +| logging.url | string | `"{{ .Values.advertised_protocol }}://graylog.{{ .Values.server_name }}"` | URL to the monitoring stack, usually Graylog | | podDisruptionBudget.enabled | bool | `true` | Enable Pod Disruption Budget | | podDisruptionBudget.minAvailable | int | `1` | Minimum number of pods that must be available during disruptions | | podDisruptionBudget.maxUnavailable | string | `nil` | Maximum number of pods that can be unavailable during disruptions | diff --git a/charts/radar-home/templates/deployment.yaml b/charts/radar-home/templates/deployment.yaml index fd102333..8ce82e81 100644 --- a/charts/radar-home/templates/deployment.yaml +++ b/charts/radar-home/templates/deployment.yaml @@ -51,7 +51,7 @@ spec: - name: S3_ENABLED value: "true" - name: S3_URL - value: {{ .Values.s3.url | quote }} + value: {{ tpl .Values.s3.url . | quote }} {{- end }} {{- if .Values.restAuthorizer.enabled }} - name: REST_AUTHORIZER_ENABLED @@ -61,7 +61,7 @@ spec: - name: DASHBOARD_ENABLED value: "true" - name: DASHBOARD_URL - value: {{ .Values.dashboard.url | quote }} + value: {{ tpl .Values.dashboard.url . | quote }} {{- end }} {{- if .Values.uploadPortal.enabled }} - name: UPLOAD_PORTAL_ENABLED @@ -77,7 +77,7 @@ spec: {{- end }} {{- if .Values.logging.url }} - name: GRAYLOG_URL - value: {{ .Values.logging.url | quote }} + value: {{ tpl .Values.logging.url . | quote }} {{- end }} {{- if .Values.monitoring.enabled }} - name: MONITOR_ENABLED @@ -85,7 +85,7 @@ spec: {{- end }} {{- if .Values.monitoring.url }} - name: MONITOR_URL - value: {{ .Values.monitoring.url | quote }} + value: {{ tpl .Values.monitoring.url . | quote }} {{- end }} {{- with .Values.extraEnvVars }} {{- toYaml . | nindent 10 }} diff --git a/charts/radar-home/templates/ingress.yaml b/charts/radar-home/templates/ingress.yaml index 460be382..7048b90e 100644 --- a/charts/radar-home/templates/ingress.yaml +++ b/charts/radar-home/templates/ingress.yaml @@ -25,13 +25,13 @@ spec: tls: - hosts: {{- range $hosts }} - - {{ . | quote }} + - {{ tpl . $ | quote }} {{- end }} secretName: {{ .Values.ingress.tls.secretName }} {{- end }} rules: {{- range .Values.ingress.hosts }} - - host: {{ . | quote }} + - host: {{ tpl . $ | quote }} http: paths: - path: {{ $path | quote }} diff --git a/charts/radar-home/values.yaml b/charts/radar-home/values.yaml index 44a86d10..725318bc 100644 --- a/charts/radar-home/values.yaml +++ b/charts/radar-home/values.yaml @@ -41,6 +41,10 @@ service: # -- Reconfigure Ingress to not force TLS disable_tls: false +# -- Hostname for the home service +server_name: localhost +# -- The protocol in advertised URIs (https, http) +advertised_protocol: https ingress: # -- Enable ingress controller resource @@ -57,7 +61,7 @@ ingress: ingressClassName: nginx # -- Hosts to accept requests from hosts: - - localhost + - '{{ .Values.server_name }}' tls: # -- TLS Secret Name secretName: radar-base-tls @@ -173,13 +177,13 @@ s3: # -- Enable link to S3 enabled: false # -- URL to S3 - url: + url: '{{ .Values.advertised_protocol }}://s3.{{ .Values.server_name }}/login' dashboard: # -- Enable link to dashboard enabled: false # -- URL to dashboard - url: + url: '{{ .Values.advertised_protocol }}://dashboard.{{ .Values.server_name }}' appConfig: # -- Enable link to app-config service @@ -197,13 +201,13 @@ monitoring: # -- Enable link to the monitoring stack, usually Prometheus enabled: false # -- URL to the monitoring stack, usually Prometheus - url: + url: '{{ .Values.advertised_protocol }}://grafana.{{ .Values.server_name }}/login' logging: # -- Enable link to the logging stack, usually Graylog enabled: false # -- URL to the monitoring stack, usually Graylog - url: + url: '{{ .Values.advertised_protocol }}://graylog.{{ .Values.server_name }}' # Pod Disruption Budget configuration podDisruptionBudget: From 4e74aa0a2b06b280da4bc8e8f9fa072da96b6063 Mon Sep 17 00:00:00 2001 From: Pim van Nierop Date: Wed, 25 Feb 2026 13:25:10 +0100 Subject: [PATCH 06/10] feat(radar-hydra): ory update --- charts/radar-hydra/Chart.yaml | 2 +- charts/radar-hydra/README.md | 234 +++++++++++- charts/radar-hydra/charts/hydra-0.53.0.tgz | Bin 25520 -> 25523 bytes .../templates/hydra-clients-job-rbac.yaml | 59 +++ .../templates/hydra-clients-job.yaml | 75 ++++ charts/radar-hydra/values.yaml | 353 +++++++++++++++++- 6 files changed, 716 insertions(+), 7 deletions(-) create mode 100644 charts/radar-hydra/templates/hydra-clients-job-rbac.yaml create mode 100644 charts/radar-hydra/templates/hydra-clients-job.yaml diff --git a/charts/radar-hydra/Chart.yaml b/charts/radar-hydra/Chart.yaml index 50a12fce..9d14c4a5 100644 --- a/charts/radar-hydra/Chart.yaml +++ b/charts/radar-hydra/Chart.yaml @@ -6,7 +6,7 @@ home: https://radar-base.org icon: http://radar-base.org/wp-content/uploads/2022/09/Logo_RADAR-Base-RGB.png sources: - https://github.com/RADAR-base/radar-helm-charts/tree/main/charts/radar-hydra -version: 0.2.2 +version: 0.3.0 maintainers: - email: pim@thehyve.nl name: Pim van Nierop diff --git a/charts/radar-hydra/README.md b/charts/radar-hydra/README.md index 8278ed56..fe236b8c 100644 --- a/charts/radar-hydra/README.md +++ b/charts/radar-hydra/README.md @@ -3,7 +3,7 @@ # radar-hydra [![Artifact HUB](https://img.shields.io/endpoint?url=https://artifacthub.io/badge/repository/radar-hydra)](https://artifacthub.io/packages/helm/radar-base/radar-hydra) -![Version: 0.2.2](https://img.shields.io/badge/Version-0.2.2-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: v2.2.0](https://img.shields.io/badge/AppVersion-v2.2.0-informational?style=flat-square) +![Version: 0.3.0](https://img.shields.io/badge/Version-0.3.0-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: v2.2.0](https://img.shields.io/badge/AppVersion-v2.2.0-informational?style=flat-square) A ORY Hydra Helm chart for RADAR-base. ORY Hydra is a cloud native Identity and User Management system. @@ -43,3 +43,235 @@ Consult the [documentation](https://artifacthub.io/packages/helm/ory/hydra) of t | hydra | object | check `values.yaml` | Ory Hydra configuration | | hydra.server_name | string | `"localhost"` | Hostname for the Kratos service | | hydra.advertised_protocol | string | `"https"` | Protocol for the Kratos service (allowed values: http, https) | +| hydra_server_url | string | `"http://radar-hydra-public:4444"` | | +| hydra_admin_url | string | `"http://radar-hydra-admin:4445/admin"` | | +| oauth_clients.ManagementPortalapp.enable | bool | `true` | | +| oauth_clients.ManagementPortalapp.redirectUris[0] | string | `"{{ .Values.hydra.advertised_protocol }}://{{ .Values.hydra.server_name }}/managementportal/api/redirect/login"` | | +| oauth_clients.ManagementPortalapp.grantTypes[0] | string | `"authorization_code"` | | +| oauth_clients.ManagementPortalapp.grantTypes[1] | string | `"refresh_token"` | | +| oauth_clients.ManagementPortalapp.responseTypes[0] | string | `"code"` | | +| oauth_clients.ManagementPortalapp.responseTypes[1] | string | `"id_token"` | | +| oauth_clients.ManagementPortalapp.client_secret | string | `""` | | +| oauth_clients.ManagementPortalapp.scope | string | `"SOURCEDATA.CREATE SOURCETYPE.UPDATE SOURCETYPE.DELETE AUTHORITY.UPDATE MEASUREMENT.DELETE PROJECT.READ AUDIT.CREATE USER.DELETE AUTHORITY.DELETE SUBJECT.DELETE MEASUREMENT.UPDATE SOURCEDATA.UPDATE SUBJECT.READ USER.UPDATE SOURCETYPE.CREATE AUTHORITY.READ USER.CREATE SOURCE.CREATE SOURCE.READ SUBJECT.CREATE ROLE.UPDATE ROLE.READ MEASUREMENT.READ PROJECT.UPDATE PROJECT.DELETE ROLE.DELETE SOURCE.DELETE SOURCETYPE.READ ROLE.CREATE SOURCEDATA.DELETE SUBJECT.UPDATE SOURCE.UPDATE PROJECT.CREATE AUDIT.READ MEASUREMENT.CREATE AUDIT.DELETE AUDIT.UPDATE AUTHORITY.CREATE USER.READ SOURCEDATA.READ ORGANIZATION.READ ORGANIZATION.CREATE ORGANIZATION.UPDATE OAUTHCLIENTS.READ OAUTHCLIENTS.CREATE OAUTHCLIENTS.UPDATE"` | | +| oauth_clients.ManagementPortalapp.audience[0] | string | `"res_ManagementPortal"` | | +| oauth_clients.ManagementPortalapp.allowed_cors_origins[0] | string | `"http://localhost:3000"` | | +| oauth_clients.ManagementPortalapp.skip_consent | bool | `true` | | +| oauth_clients.ManagementPortalapp.skip_logout_consent | bool | `false` | | +| oauth_clients.pRMT.enable | bool | `false` | | +| oauth_clients.pRMT.audience[0] | string | `"res_gateway"` | | +| oauth_clients.pRMT.audience[1] | string | `"res_ManagementPortal"` | | +| oauth_clients.pRMT.audience[2] | string | `"res_appconfig"` | | +| oauth_clients.pRMT.client_secret | string | `""` | | +| oauth_clients.pRMT.scope[0] | string | `"MEASUREMENT.CREATE"` | | +| oauth_clients.pRMT.scope[1] | string | `"PROJECT.READ"` | | +| oauth_clients.pRMT.scope[2] | string | `"ROLE.READ"` | | +| oauth_clients.pRMT.scope[3] | string | `"SOURCE.READ"` | | +| oauth_clients.pRMT.scope[4] | string | `"SOURCEDATA.READ"` | | +| oauth_clients.pRMT.scope[5] | string | `"SOURCETYPE.READ"` | | +| oauth_clients.pRMT.scope[6] | string | `"SUBJECT.READ"` | | +| oauth_clients.pRMT.scope[7] | string | `"SUBJECT.UPDATE"` | | +| oauth_clients.pRMT.scope[8] | string | `"USER.READ"` | | +| oauth_clients.pRMT.grantTypes[0] | string | `"refresh_token"` | | +| oauth_clients.pRMT.grantTypes[1] | string | `"authorization_code"` | | +| oauth_clients.pRMT.access_token_validity | int | `43200` | | +| oauth_clients.pRMT.refresh_token_validity | int | `7948800` | | +| oauth_clients.pRMT.additional_information | string | `"{\"dynamic_registration\": true}"` | | +| oauth_clients.pRMT.tokenEndpointAuthMethod | string | `"client_secret_post"` | | +| oauth_clients.aRMT.enable | bool | `false` | | +| oauth_clients.aRMT.audience[0] | string | `"res_gateway"` | | +| oauth_clients.aRMT.audience[1] | string | `"res_ManagementPortal"` | | +| oauth_clients.aRMT.audience[2] | string | `"res_appconfig"` | | +| oauth_clients.aRMT.audience[3] | string | `"res_AppServer"` | | +| oauth_clients.aRMT.audience[4] | string | `"res_DataDashboardAPI"` | | +| oauth_clients.aRMT.client_secret | string | `""` | | +| oauth_clients.aRMT.scope[0] | string | `"MEASUREMENT.READ"` | | +| oauth_clients.aRMT.scope[1] | string | `"MEASUREMENT.CREATE"` | | +| oauth_clients.aRMT.scope[2] | string | `"PROJECT.READ"` | | +| oauth_clients.aRMT.scope[3] | string | `"ROLE.READ"` | | +| oauth_clients.aRMT.scope[4] | string | `"SOURCE.READ"` | | +| oauth_clients.aRMT.scope[5] | string | `"SOURCEDATA.READ"` | | +| oauth_clients.aRMT.scope[6] | string | `"SOURCETYPE.READ"` | | +| oauth_clients.aRMT.scope[7] | string | `"SUBJECT.READ"` | | +| oauth_clients.aRMT.scope[8] | string | `"SUBJECT.UPDATE"` | | +| oauth_clients.aRMT.scope[9] | string | `"USER.READ"` | | +| oauth_clients.aRMT.grantTypes[0] | string | `"refresh_token"` | | +| oauth_clients.aRMT.grantTypes[1] | string | `"authorization_code"` | | +| oauth_clients.aRMT.access_token_validity | int | `43200` | | +| oauth_clients.aRMT.refresh_token_validity | int | `7948800` | | +| oauth_clients.aRMT.additional_information | string | `"{\"dynamic_registration\": true}"` | | +| oauth_clients.aRMT.tokenEndpointAuthMethod | string | `"client_secret_post"` | | +| oauth_clients.aRMT.redirectUris[0] | string | `"{{ .Values.hydra.advertised_protocol }}://{{ .Values.hydra.server_name }}/managementportal/api/redirect/login"` | | +| oauth_clients.SEP.enable | bool | `false` | | +| oauth_clients.SEP.audience[0] | string | `"res_gateway"` | | +| oauth_clients.SEP.audience[1] | string | `"res_ManagementPortal"` | | +| oauth_clients.SEP.audience[2] | string | `"res_appconfig"` | | +| oauth_clients.SEP.audience[3] | string | `"res_AppServer"` | | +| oauth_clients.SEP.audience[4] | string | `"res_DataDashboardAPI"` | | +| oauth_clients.SEP.audience[5] | string | `"res_restAuthorizer"` | | +| oauth_clients.SEP.client_secret | string | `""` | | +| oauth_clients.SEP.scope[0] | string | `"PROJECT.READ"` | | +| oauth_clients.SEP.scope[1] | string | `"SOURCETYPE.READ"` | | +| oauth_clients.SEP.scope[2] | string | `"SUBJECT.READ"` | | +| oauth_clients.SEP.scope[3] | string | `"SUBJECT.UPDATE"` | | +| oauth_clients.SEP.scope[4] | string | `"SUBJECT.CREATE"` | | +| oauth_clients.SEP.scope[5] | string | `"USER.READ"` | | +| oauth_clients.SEP.grantTypes[0] | string | `"refresh_token"` | | +| oauth_clients.SEP.grantTypes[1] | string | `"authorization_code"` | | +| oauth_clients.SEP.grantTypes[2] | string | `"client_credentials"` | | +| oauth_clients.SEP.access_token_validity | int | `43200` | | +| oauth_clients.SEP.refresh_token_validity | int | `7948800` | | +| oauth_clients.SEP.additional_information | string | `"{\"dynamic_registration\": true}"` | | +| oauth_clients.SEP.redirectUris[0] | string | `"{{ .Values.hydra.advertised_protocol }}://{{ .Values.hydra.server_name }}/managementportal/api/redirect/login"` | | +| oauth_clients.THINC-IT.enable | bool | `false` | | +| oauth_clients.THINC-IT.audience[0] | string | `"res_gateway"` | | +| oauth_clients.THINC-IT.audience[1] | string | `"res_ManagementPortal"` | | +| oauth_clients.THINC-IT.audience[2] | string | `"res_appconfig"` | | +| oauth_clients.THINC-IT.client_secret | string | `""` | | +| oauth_clients.THINC-IT.scope[0] | string | `"MEASUREMENT.CREATE"` | | +| oauth_clients.THINC-IT.scope[1] | string | `"PROJECT.READ"` | | +| oauth_clients.THINC-IT.scope[2] | string | `"ROLE.READ"` | | +| oauth_clients.THINC-IT.scope[3] | string | `"SOURCE.READ"` | | +| oauth_clients.THINC-IT.scope[4] | string | `"SOURCEDATA.READ"` | | +| oauth_clients.THINC-IT.scope[5] | string | `"SOURCETYPE.READ"` | | +| oauth_clients.THINC-IT.scope[6] | string | `"SUBJECT.READ"` | | +| oauth_clients.THINC-IT.scope[7] | string | `"SUBJECT.UPDATE"` | | +| oauth_clients.THINC-IT.scope[8] | string | `"USER.READ"` | | +| oauth_clients.THINC-IT.grantTypes[0] | string | `"refresh_token"` | | +| oauth_clients.THINC-IT.grantTypes[1] | string | `"authorization_code"` | | +| oauth_clients.THINC-IT.access_token_validity | int | `43200` | | +| oauth_clients.THINC-IT.refresh_token_validity | int | `7948800` | | +| oauth_clients.THINC-IT.additional_information | string | `"{\"dynamic_registration\": true}"` | | +| oauth_clients.radar_redcap_integrator.enable | bool | `false` | | +| oauth_clients.radar_redcap_integrator.audience[0] | string | `"res_ManagementPortal"` | | +| oauth_clients.radar_redcap_integrator.client_secret | string | `""` | | +| oauth_clients.radar_redcap_integrator.scope[0] | string | `"PROJECT.READ"` | | +| oauth_clients.radar_redcap_integrator.scope[1] | string | `"SUBJECT.CREATE"` | | +| oauth_clients.radar_redcap_integrator.scope[2] | string | `"SUBJECT.READ"` | | +| oauth_clients.radar_redcap_integrator.scope[3] | string | `"SUBJECT.UPDATE"` | | +| oauth_clients.radar_redcap_integrator.grantTypes[0] | string | `"client_credentials"` | | +| oauth_clients.radar_redcap_integrator.access_token_validity | int | `900` | | +| oauth_clients.radar_upload_backend.enable | bool | `false` | | +| oauth_clients.radar_upload_backend.audience[0] | string | `"res_ManagementPortal"` | | +| oauth_clients.radar_upload_backend.client_secret | string | `""` | | +| oauth_clients.radar_upload_backend.scope[0] | string | `"PROJECT.READ"` | | +| oauth_clients.radar_upload_backend.scope[1] | string | `"SUBJECT.READ"` | | +| oauth_clients.radar_upload_backend.grantTypes[0] | string | `"client_credentials"` | | +| oauth_clients.radar_upload_backend.access_token_validity | int | `900` | | +| oauth_clients.radar_upload_backend.additional_information | string | `"{\"dynamic_registration\": true}"` | | +| oauth_clients.radar_upload_connect.enable | bool | `false` | | +| oauth_clients.radar_upload_connect.audience[0] | string | `"res_ManagementPortal"` | | +| oauth_clients.radar_upload_connect.audience[1] | string | `"res_upload"` | | +| oauth_clients.radar_upload_connect.client_secret | string | `""` | | +| oauth_clients.radar_upload_connect.scope[0] | string | `"MEASUREMENT.CREATE"` | | +| oauth_clients.radar_upload_connect.scope[1] | string | `"PROJECT.READ"` | | +| oauth_clients.radar_upload_connect.scope[2] | string | `"SOURCE.READ"` | | +| oauth_clients.radar_upload_connect.scope[3] | string | `"SOURCETYPE.READ"` | | +| oauth_clients.radar_upload_connect.scope[4] | string | `"SUBJECT.READ"` | | +| oauth_clients.radar_upload_connect.scope[5] | string | `"SUBJECT.UPDATE"` | | +| oauth_clients.radar_upload_connect.grantTypes[0] | string | `"client_credentials"` | | +| oauth_clients.radar_upload_connect.access_token_validity | int | `900` | | +| oauth_clients.radar_upload_frontend.enable | bool | `false` | | +| oauth_clients.radar_upload_frontend.audience[0] | string | `"res_ManagementPortal"` | | +| oauth_clients.radar_upload_frontend.audience[1] | string | `"res_upload"` | | +| oauth_clients.radar_upload_frontend.client_secret | string | `""` | | +| oauth_clients.radar_upload_frontend.scope[0] | string | `"MEASUREMENT.CREATE"` | | +| oauth_clients.radar_upload_frontend.scope[1] | string | `"PROJECT.READ"` | | +| oauth_clients.radar_upload_frontend.scope[2] | string | `"SOURCETYPE.READ"` | | +| oauth_clients.radar_upload_frontend.scope[3] | string | `"SUBJECT.READ"` | | +| oauth_clients.radar_upload_frontend.grantTypes[0] | string | `"authorization_code"` | | +| oauth_clients.radar_upload_frontend.access_token_validity | int | `900` | | +| oauth_clients.radar_upload_frontend.redirectUris[0] | string | `"{{ .Values.hydra.advertised_protocol }}://{{ .Values.hydra.server_name }}/upload/login"` | | +| oauth_clients.radar_upload_frontend.redirectUris[1] | string | `"/upload/login"` | | +| oauth_clients.radar_rest_sources_auth_backend.enable | bool | `false` | | +| oauth_clients.radar_rest_sources_auth_backend.audience[0] | string | `"res_ManagementPortal"` | | +| oauth_clients.radar_rest_sources_auth_backend.audience[1] | string | `"res_upload"` | | +| oauth_clients.radar_rest_sources_auth_backend.client_secret | string | `""` | | +| oauth_clients.radar_rest_sources_auth_backend.scope[0] | string | `"PROJECT.READ"` | | +| oauth_clients.radar_rest_sources_auth_backend.scope[1] | string | `"SUBJECT.READ"` | | +| oauth_clients.radar_rest_sources_auth_backend.grantTypes[0] | string | `"client_credentials"` | | +| oauth_clients.radar_rest_sources_auth_backend.access_token_validity | int | `900` | | +| oauth_clients.radar_rest_sources_auth_backend.tokenEndpointAuthMethod | string | `"client_secret_post"` | | +| oauth_clients.radar_rest_sources_authorizer.enable | bool | `false` | | +| oauth_clients.radar_rest_sources_authorizer.audience[0] | string | `"res_restAuthorizer"` | | +| oauth_clients.radar_rest_sources_authorizer.client_secret | string | `""` | | +| oauth_clients.radar_rest_sources_authorizer.scope[0] | string | `"PROJECT.READ"` | | +| oauth_clients.radar_rest_sources_authorizer.scope[1] | string | `"SOURCETYPE.READ"` | | +| oauth_clients.radar_rest_sources_authorizer.scope[2] | string | `"SUBJECT.READ"` | | +| oauth_clients.radar_rest_sources_authorizer.scope[3] | string | `"SUBJECT.UPDATE"` | | +| oauth_clients.radar_rest_sources_authorizer.scope[4] | string | `"SUBJECT.CREATE"` | | +| oauth_clients.radar_rest_sources_authorizer.grantTypes[0] | string | `"authorization_code"` | | +| oauth_clients.radar_rest_sources_authorizer.access_token_validity | int | `900` | | +| oauth_clients.radar_rest_sources_authorizer.redirectUris[0] | string | `"{{ .Values.hydra.advertised_protocol }}://{{ .Values.hydra.server_name }}/rest-sources/authorizer/login"` | | +| oauth_clients.radar_rest_sources_authorizer.tokenEndpointAuthMethod | string | `"client_secret_post"` | | +| oauth_clients.radar_fitbit_connector.enable | bool | `false` | | +| oauth_clients.radar_fitbit_connector.audience[0] | string | `"res_restAuthorizer"` | | +| oauth_clients.radar_fitbit_connector.client_secret | string | `""` | | +| oauth_clients.radar_fitbit_connector.scope[0] | string | `"SUBJECT.READ"` | | +| oauth_clients.radar_fitbit_connector.scope[1] | string | `"MEASUREMENT.CREATE"` | | +| oauth_clients.radar_fitbit_connector.grantTypes[0] | string | `"client_credentials"` | | +| oauth_clients.radar_fitbit_connector.access_token_validity | int | `900` | | +| oauth_clients.radar_fitbit_connector.tokenEndpointAuthMethod | string | `"client_secret_post"` | | +| oauth_clients.radar_appconfig.enable | bool | `false` | | +| oauth_clients.radar_appconfig.audience[0] | string | `"res_ManagementPortal"` | | +| oauth_clients.radar_appconfig.audience[1] | string | `"res_appconfig"` | | +| oauth_clients.radar_appconfig.client_secret | string | `""` | | +| oauth_clients.radar_appconfig.scope[0] | string | `"MEASUREMENT.CREATE"` | | +| oauth_clients.radar_appconfig.scope[1] | string | `"OAUTHCLIENTS.READ"` | | +| oauth_clients.radar_appconfig.scope[2] | string | `"PROJECT.READ"` | | +| oauth_clients.radar_appconfig.scope[3] | string | `"SOURCETYPE.READ"` | | +| oauth_clients.radar_appconfig.scope[4] | string | `"SUBJECT.READ"` | | +| oauth_clients.radar_appconfig.grantTypes[0] | string | `"client_credentials"` | | +| oauth_clients.radar_appconfig.access_token_validity | int | `900` | | +| oauth_clients.appconfig_frontend.enable | bool | `false` | | +| oauth_clients.appconfig_frontend.audience[0] | string | `"res_appconfig"` | | +| oauth_clients.appconfig_frontend.client_secret | string | `""` | | +| oauth_clients.appconfig_frontend.scope[0] | string | `"MEASUREMENT.CREATE"` | | +| oauth_clients.appconfig_frontend.scope[1] | string | `"OAUTHCLIENTS.READ"` | | +| oauth_clients.appconfig_frontend.scope[2] | string | `"PROJECT.CREATE"` | | +| oauth_clients.appconfig_frontend.scope[3] | string | `"PROJECT.READ"` | | +| oauth_clients.appconfig_frontend.scope[4] | string | `"PROJECT.UPDATE"` | | +| oauth_clients.appconfig_frontend.scope[5] | string | `"SOURCETYPE.READ"` | | +| oauth_clients.appconfig_frontend.scope[6] | string | `"SUBJECT.READ"` | | +| oauth_clients.appconfig_frontend.scope[7] | string | `"SUBJECT.UPDATE"` | | +| oauth_clients.appconfig_frontend.grantTypes[0] | string | `"authorization_code"` | | +| oauth_clients.appconfig_frontend.grantTypes[1] | string | `"refresh_token"` | | +| oauth_clients.appconfig_frontend.access_token_validity | int | `900` | | +| oauth_clients.appconfig_frontend.refresh_token_validity | int | `78000` | | +| oauth_clients.appconfig_frontend.redirectUris[0] | string | `"/appconfig/login"` | | +| oauth_clients.appconfig_frontend.autoapprove[0] | string | `"MEASUREMENT.CREATE"` | | +| oauth_clients.appconfig_frontend.autoapprove[1] | string | `"OAUTHCLIENTS.READ"` | | +| oauth_clients.appconfig_frontend.autoapprove[2] | string | `"PROJECT.CREATE"` | | +| oauth_clients.appconfig_frontend.autoapprove[3] | string | `"PROJECT.READ"` | | +| oauth_clients.appconfig_frontend.autoapprove[4] | string | `"PROJECT.UPDATE"` | | +| oauth_clients.appconfig_frontend.autoapprove[5] | string | `"SOURCETYPE.READ"` | | +| oauth_clients.appconfig_frontend.autoapprove[6] | string | `"SUBJECT.READ"` | | +| oauth_clients.appconfig_frontend.autoapprove[7] | string | `"SUBJECT.UPDATE"` | | +| oauth_clients.grafana_dashboard.enable | bool | `false` | | +| oauth_clients.grafana_dashboard.audience[0] | string | `"res_ManagementPortal"` | | +| oauth_clients.grafana_dashboard.client_secret | string | `""` | | +| oauth_clients.grafana_dashboard.scope[0] | string | `"USER.READ"` | | +| oauth_clients.grafana_dashboard.grantTypes[0] | string | `"authorization_code"` | | +| oauth_clients.grafana_dashboard.grantTypes[1] | string | `"refresh_token"` | | +| oauth_clients.grafana_dashboard.access_token_validity | int | `900` | | +| oauth_clients.grafana_dashboard.refresh_token_validity | int | `78000` | | +| oauth_clients.grafana_dashboard.redirectUris[0] | string | `"{{ .Values.hydra.advertised_protocol }}://dashboard.{{ .Values.hydra.server_name }}/login/generic_oauth"` | | +| oauth_clients.grafana_dashboard.autoapprove[0] | string | `"USER.READ"` | | +| oauth_clients.radar_push_endpoint.enable | bool | `false` | | +| oauth_clients.radar_push_endpoint.audience[0] | string | `"res_restAuthorizer"` | | +| oauth_clients.radar_push_endpoint.client_secret | string | `""` | | +| oauth_clients.radar_push_endpoint.scope[0] | string | `"SOURCETYPE.READ"` | | +| oauth_clients.radar_push_endpoint.scope[1] | string | `"SUBJECT.UPDATE"` | | +| oauth_clients.radar_push_endpoint.scope[2] | string | `"MEASUREMENT.READ"` | | +| oauth_clients.radar_push_endpoint.scope[3] | string | `"MEASUREMENT.CREATE"` | | +| oauth_clients.radar_push_endpoint.scope[4] | string | `"PROJECT.READ"` | | +| oauth_clients.radar_push_endpoint.scope[5] | string | `"SUBJECT.READ"` | | +| oauth_clients.radar_push_endpoint.grantTypes[0] | string | `"client_credentials"` | | +| oauth_clients.radar_push_endpoint.access_token_validity | int | `900` | | +| oauth_clients.radar_data_dashboard_backend.enable | bool | `false` | | +| oauth_clients.radar_data_dashboard_backend.audience[0] | string | `"res_ManagementPortal"` | | +| oauth_clients.radar_data_dashboard_backend.client_secret | string | `""` | | +| oauth_clients.radar_data_dashboard_backend.scope[0] | string | `"PROJECT.READ"` | | +| oauth_clients.radar_data_dashboard_backend.scope[1] | string | `"SUBJECT.READ"` | | +| oauth_clients.radar_data_dashboard_backend.scope[2] | string | `"MEASUREMENT.READ"` | | +| oauth_clients.radar_data_dashboard_backend.grantTypes[0] | string | `"client_credentials"` | | +| oauth_clients.radar_data_dashboard_backend.access_token_validity | int | `900` | | diff --git a/charts/radar-hydra/charts/hydra-0.53.0.tgz b/charts/radar-hydra/charts/hydra-0.53.0.tgz index 61e4e2914e49e3c5e55a34ca878a2181aacdfeec..6b99fc2d56fe246eb438e90801abd4c9aa6c98f8 100644 GIT binary patch delta 22920 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 Dm{034 delta 22911 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 diff --git a/charts/radar-hydra/templates/hydra-clients-job-rbac.yaml b/charts/radar-hydra/templates/hydra-clients-job-rbac.yaml new file mode 100644 index 00000000..48f8b04d --- /dev/null +++ b/charts/radar-hydra/templates/hydra-clients-job-rbac.yaml @@ -0,0 +1,59 @@ +# ServiceAccount for hydra-clients-job +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ .Release.Name }}-hydra-clients-job-sa + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: radar-hydra + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/component: hydra-clients-job + annotations: + "helm.sh/hook": pre-install,pre-upgrade + "helm.sh/hook-weight": "-5" + "helm.sh/hook-delete-policy": before-hook-creation +automountServiceAccountToken: true + +--- +# Role for hydra-clients-job +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: {{ .Release.Name }}-hydra-clients-job-role + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: radar-hydra + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/component: hydra-clients-job + annotations: + "helm.sh/hook": pre-install,pre-upgrade + "helm.sh/hook-weight": "-5" + "helm.sh/hook-delete-policy": before-hook-creation +rules: + - apiGroups: [""] + resources: ["secrets"] + verbs: ["get", "list"] + +--- +# RoleBinding for hydra-clients-job +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: {{ .Release.Name }}-hydra-clients-job-rolebinding + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: radar-hydra + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/component: hydra-clients-job + annotations: + "helm.sh/hook": pre-install,pre-upgrade + "helm.sh/hook-weight": "-5" + "helm.sh/hook-delete-policy": before-hook-creation +subjects: + - kind: ServiceAccount + name: {{ .Release.Name }}-hydra-clients-job-sa + namespace: {{ .Release.Namespace }} +roleRef: + kind: Role + name: {{ .Release.Name }}-hydra-clients-job-role + apiGroup: rbac.authorization.k8s.io diff --git a/charts/radar-hydra/templates/hydra-clients-job.yaml b/charts/radar-hydra/templates/hydra-clients-job.yaml new file mode 100644 index 00000000..dab9e5f8 --- /dev/null +++ b/charts/radar-hydra/templates/hydra-clients-job.yaml @@ -0,0 +1,75 @@ +{{/*Using a container that runs a client setup script after Hydra is ready, allowing setting fixed client ID, as an alternative to init containers looking up dynamic client uuid created when using Hydra client template (as init containers may not be possible in all cases.*/}} +apiVersion: batch/v1 +kind: Job +metadata: + name: {{ .Release.Name }}-hydra-clients-setup + namespace: {{ .Release.Namespace }} + annotations: + "helm.sh/hook": post-install,post-upgrade + "helm.sh/hook-weight": "0" + "helm.sh/hook-delete-policy": before-hook-creation +spec: + template: + spec: + serviceAccountName: {{ .Release.Name }}-hydra-clients-job-sa + restartPolicy: OnFailure + containers: + - name: hydra-client-manager + # Official, minimal curl image that includes /bin/sh + image: curlimages/curl:8.15.0 + command: ["sh","-eu","-c"] + args: + - | + echo "Waiting for Hydra Admin API to be available..." + until curl -s -f -o /dev/null "{{ .Values.hydra_server_url }}/health/ready"; do + echo "Hydra not ready yet, waiting 5 seconds..." + sleep 5 + done + echo "Hydra is ready! Proceeding to create/update clients." + + {{- range $name, $client := .Values.oauth_clients }} + {{- if (default false $client.enable) }} + + echo "Processing client: {{ $name }}" + CLIENT_ID="{{ $name }}" + + # Build the JSON payload (remove any comments; JSON can't contain '# ...') + JSON_PAYLOAD=$(cat <<'EOF' + { + "client_id": "{{ $name }}", + "client_name": "{{ $name }}", + "client_secret": "{{ $client.client_secret | default "secret" }}" + {{- if $client.grantTypes }}, "grant_types": {{ $client.grantTypes | toJson }}{{- end }} + {{- if $client.responseTypes }}, "response_types": {{ $client.responseTypes | toJson }}{{- end }} + {{- if kindIs "string" $client.scope }}, "scope": "{{ $client.scope }}"{{ else if $client.scope }}, "scope": "{{ join " " $client.scope }}"{{ end }} + {{- if $client.audience }}, "audience": {{ $client.audience | toJson }}{{- else if $client.resource_ids }}, "audience": {{ $client.resource_ids | toJson }}{{- end }} + {{- if $client.redirectUris }}, "redirect_uris": [{{- range $e := $client.redirectUris }}{{- tpl $e $ | toJson }}{{- end }}] + {{- end }} + {{- if $client.allowed_cors_origins }}, "allowed_cors_origins": {{ $client.allowed_cors_origins | toJson }}{{- end }} + {{- if hasKey $client "skip_consent" }}, "skip_consent": {{ $client.skip_consent | default false }}{{- end }} + {{- if hasKey $client "skip_logout_consent" }}, "skip_logout_consent": {{ $client.skip_logout_consent | default false }}{{- end }} + , "token_endpoint_auth_method": "{{ default "client_secret_basic" $client.tokenEndpointAuthMethod }}" + } + EOF + ) + + HTTP_STATUS=$(curl -s -o /dev/null -w "%{http_code}" "{{ $.Values.hydra_admin_url }}/clients/${CLIENT_ID}") + + if [ "$HTTP_STATUS" = "200" ]; then + echo "Client '${CLIENT_ID}' exists, updating it..." + METHOD="PUT" + URL="{{ $.Values.hydra_admin_url }}/clients/${CLIENT_ID}" + else + echo "Client '${CLIENT_ID}' does not exist, creating it..." + METHOD="POST" + URL="{{ $.Values.hydra_admin_url }}/clients" + fi + + printf '%s' "$JSON_PAYLOAD" | curl -sS -X "${METHOD}" --fail -H "Content-Type: application/json" -d @- "${URL}" + echo "Successfully processed client '{{ $name }}'." + echo "---" + + {{- end }} + {{- end }} + + echo "All clients processed successfully." diff --git a/charts/radar-hydra/values.yaml b/charts/radar-hydra/values.yaml index f1988fa0..9b59c230 100644 --- a/charts/radar-hydra/values.yaml +++ b/charts/radar-hydra/values.yaml @@ -9,7 +9,7 @@ hydra: ingress: admin: - enabled: true + enabled: false className: "nginx" annotations: cert-manager.io/cluster-issuer: letsencrypt-prod @@ -44,16 +44,22 @@ hydra: config: # Leave empty to use the DSN environmental variable. dsn: + secrets: + system: + cookie: urls: self: + admin: '{{ .Values.advertised_protocol }}://{{ .Values.server_name }}/admin/hydra/' issuer: '{{ .Values.advertised_protocol }}://{{ .Values.server_name }}/hydra/' - login: '{{ .Values.advertised_protocol }}://{{ .Values.server_name }}/login' - consent: '{{ .Values.advertised_protocol }}://{{ .Values.server_name }}/hydra-ui/consent' + public: '{{ .Values.advertised_protocol }}://{{ .Values.server_name }}/hydra/' + login: '{{ .Values.advertised_protocol }}://{{ .Values.server_name }}/study/auth/oauth-login' + consent: '{{ .Values.advertised_protocol }}://{{ .Values.server_name }}/study/auth/consent' + logout: '{{ .Values.advertised_protocol }}://{{ .Values.server_name }}/study/auth/logout' log: level: debug format: text - leak_sensitive_values: false + leak_sensitive_values: true strategies: access_token: jwt @@ -61,10 +67,14 @@ hydra: scope_claim: both oauth2: - allowed_top_level_claims: [scope, roles, authorities, sources, user_name] + allowed_top_level_claims: [scope, roles, authorities, sources, user_name, email] mirror_top_level_claims: false client_credentials: default_grant_allowed_scope: true + grant: + refresh_token: + # Set grace period. Omit the line below to disable. + rotation_grace_period: 300s serve: public: @@ -82,3 +92,336 @@ hydra: secretKeyRef: name: radar-cloudnative-postgresql-hydra key: uri + + maester: + enabled: false + +hydra_server_url: "http://radar-hydra-public:4444" +hydra_admin_url: "http://radar-hydra-admin:4445/admin" + +oauth_clients: + ManagementPortalapp: + enable: true + redirectUris: + - '{{ .Values.hydra.advertised_protocol }}://{{ .Values.hydra.server_name }}/managementportal/api/redirect/login' + grantTypes: + - authorization_code + - refresh_token + responseTypes: + - code + - id_token + client_secret: "" + scope: SOURCEDATA.CREATE SOURCETYPE.UPDATE SOURCETYPE.DELETE AUTHORITY.UPDATE MEASUREMENT.DELETE PROJECT.READ AUDIT.CREATE USER.DELETE AUTHORITY.DELETE SUBJECT.DELETE MEASUREMENT.UPDATE SOURCEDATA.UPDATE SUBJECT.READ USER.UPDATE SOURCETYPE.CREATE AUTHORITY.READ USER.CREATE SOURCE.CREATE SOURCE.READ SUBJECT.CREATE ROLE.UPDATE ROLE.READ MEASUREMENT.READ PROJECT.UPDATE PROJECT.DELETE ROLE.DELETE SOURCE.DELETE SOURCETYPE.READ ROLE.CREATE SOURCEDATA.DELETE SUBJECT.UPDATE SOURCE.UPDATE PROJECT.CREATE AUDIT.READ MEASUREMENT.CREATE AUDIT.DELETE AUDIT.UPDATE AUTHORITY.CREATE USER.READ SOURCEDATA.READ ORGANIZATION.READ ORGANIZATION.CREATE ORGANIZATION.UPDATE OAUTHCLIENTS.READ OAUTHCLIENTS.CREATE OAUTHCLIENTS.UPDATE + audience: + - res_ManagementPortal + allowed_cors_origins: + - http://localhost:3000 + skip_consent: true + skip_logout_consent: false + + pRMT: + enable: false + audience: + - res_gateway + - res_ManagementPortal + - res_appconfig + client_secret: "" + scope: + - MEASUREMENT.CREATE + - PROJECT.READ + - ROLE.READ + - SOURCE.READ + - SOURCEDATA.READ + - SOURCETYPE.READ + - SUBJECT.READ + - SUBJECT.UPDATE + - USER.READ + grantTypes: + - refresh_token + - authorization_code + access_token_validity: 43200 + refresh_token_validity: 7948800 + additional_information: '{"dynamic_registration": true}' + tokenEndpointAuthMethod: client_secret_post + + aRMT: + enable: false + audience: + - res_gateway + - res_ManagementPortal + - res_appconfig + - res_AppServer + - res_DataDashboardAPI + client_secret: "" + scope: + - MEASUREMENT.READ + - MEASUREMENT.CREATE + - PROJECT.READ + - ROLE.READ + - SOURCE.READ + - SOURCEDATA.READ + - SOURCETYPE.READ + - SUBJECT.READ + - SUBJECT.UPDATE + - USER.READ + grantTypes: + - refresh_token + - authorization_code + access_token_validity: 43200 + refresh_token_validity: 7948800 + additional_information: '{"dynamic_registration": true}' + tokenEndpointAuthMethod: client_secret_post + redirectUris: + - '{{ .Values.hydra.advertised_protocol }}://{{ .Values.hydra.server_name }}/managementportal/api/redirect/login' + + SEP: + enable: false + audience: + - res_gateway + - res_ManagementPortal + - res_appconfig + - res_AppServer + - res_DataDashboardAPI + - res_restAuthorizer + client_secret: "" + scope: + - PROJECT.READ + - SOURCETYPE.READ + - SUBJECT.READ + - SUBJECT.UPDATE + - SUBJECT.CREATE + - USER.READ + grantTypes: + - refresh_token + - authorization_code + - client_credentials + access_token_validity: 43200 + refresh_token_validity: 7948800 + additional_information: '{"dynamic_registration": true}' + redirectUris: + - '{{ .Values.hydra.advertised_protocol }}://{{ .Values.hydra.server_name }}/managementportal/api/redirect/login' + + THINC-IT: + enable: false + audience: + - res_gateway + - res_ManagementPortal + - res_appconfig + client_secret: "" + scope: + - MEASUREMENT.CREATE + - PROJECT.READ + - ROLE.READ + - SOURCE.READ + - SOURCEDATA.READ + - SOURCETYPE.READ + - SUBJECT.READ + - SUBJECT.UPDATE + - USER.READ + grantTypes: + - refresh_token + - authorization_code + access_token_validity: 43200 + refresh_token_validity: 7948800 + additional_information: '{"dynamic_registration": true}' + + radar_redcap_integrator: + enable: false + audience: + - res_ManagementPortal + client_secret: "" + scope: + - PROJECT.READ + - SUBJECT.CREATE + - SUBJECT.READ + - SUBJECT.UPDATE + grantTypes: + - client_credentials + access_token_validity: 900 + + radar_upload_backend: + enable: false + audience: + - res_ManagementPortal + client_secret: "" + scope: + - PROJECT.READ + - SUBJECT.READ + grantTypes: + - client_credentials + access_token_validity: 900 + additional_information: '{"dynamic_registration": true}' + + radar_upload_connect: + enable: false + audience: + - res_ManagementPortal + - res_upload + client_secret: "" + scope: + - MEASUREMENT.CREATE + - PROJECT.READ + - SOURCE.READ + - SOURCETYPE.READ + - SUBJECT.READ + - SUBJECT.UPDATE + grantTypes: + - client_credentials + access_token_validity: 900 + + radar_upload_frontend: + enable: false + audience: + - res_ManagementPortal + - res_upload + client_secret: "" + scope: + - MEASUREMENT.CREATE + - PROJECT.READ + - SOURCETYPE.READ + - SUBJECT.READ + grantTypes: + - authorization_code + access_token_validity: 900 + redirectUris: + - '{{ .Values.hydra.advertised_protocol }}://{{ .Values.hydra.server_name }}/upload/login' + - /upload/login + + radar_rest_sources_auth_backend: + enable: false + audience: + - res_ManagementPortal + - res_upload + client_secret: "" + scope: + - PROJECT.READ + - SUBJECT.READ + grantTypes: + - client_credentials + access_token_validity: 900 + # This is considered less secure, better to send client secret in Auth header, which requires changing code on the auth backend side + tokenEndpointAuthMethod: client_secret_post + + radar_rest_sources_authorizer: + enable: false + audience: + - res_restAuthorizer + client_secret: "" + scope: + - PROJECT.READ + - SOURCETYPE.READ + - SUBJECT.READ + - SUBJECT.UPDATE + - SUBJECT.CREATE + grantTypes: + - authorization_code + access_token_validity: 900 + redirectUris: + - '{{ .Values.hydra.advertised_protocol }}://{{ .Values.hydra.server_name }}/rest-sources/authorizer/login' + tokenEndpointAuthMethod: client_secret_post + + radar_fitbit_connector: + enable: false + audience: + - res_restAuthorizer + client_secret: "" + scope: + - SUBJECT.READ + - MEASUREMENT.CREATE + grantTypes: + - client_credentials + access_token_validity: 900 + tokenEndpointAuthMethod: client_secret_post + + radar_appconfig: + enable: false + audience: + - res_ManagementPortal + - res_appconfig + client_secret: "" + scope: + - MEASUREMENT.CREATE + - OAUTHCLIENTS.READ + - PROJECT.READ + - SOURCETYPE.READ + - SUBJECT.READ + grantTypes: + - client_credentials + access_token_validity: 900 + + appconfig_frontend: + enable: false + audience: + - res_appconfig + client_secret: "" + scope: + - MEASUREMENT.CREATE + - OAUTHCLIENTS.READ + - PROJECT.CREATE + - PROJECT.READ + - PROJECT.UPDATE + - SOURCETYPE.READ + - SUBJECT.READ + - SUBJECT.UPDATE + grantTypes: + - authorization_code + - refresh_token + access_token_validity: 900 + refresh_token_validity: 78000 + redirectUris: + - /appconfig/login + autoapprove: + - MEASUREMENT.CREATE + - OAUTHCLIENTS.READ + - PROJECT.CREATE + - PROJECT.READ + - PROJECT.UPDATE + - SOURCETYPE.READ + - SUBJECT.READ + - SUBJECT.UPDATE + + grafana_dashboard: + enable: false + audience: + - res_ManagementPortal + client_secret: "" + scope: + - USER.READ + grantTypes: + - authorization_code + - refresh_token + access_token_validity: 900 + refresh_token_validity: 78000 + redirectUris: + - '{{ .Values.hydra.advertised_protocol }}://dashboard.{{ .Values.hydra.server_name }}/login/generic_oauth' + autoapprove: + - USER.READ + + radar_push_endpoint: + enable: false + audience: + - res_restAuthorizer + client_secret: "" + scope: + - SOURCETYPE.READ + - SUBJECT.UPDATE + - MEASUREMENT.READ + - MEASUREMENT.CREATE + - PROJECT.READ + - SUBJECT.READ + grantTypes: + - client_credentials + access_token_validity: 900 + + radar_data_dashboard_backend: + enable: false + audience: + - res_ManagementPortal + client_secret: "" + scope: + - PROJECT.READ + - SUBJECT.READ + - MEASUREMENT.READ + grantTypes: + - client_credentials + access_token_validity: 900 From 95248f2f3b1af5369f5357653bb3c82927f6734c Mon Sep 17 00:00:00 2001 From: Pim van Nierop Date: Wed, 25 Feb 2026 13:25:20 +0100 Subject: [PATCH 07/10] feat(radar-kratos): ory update --- charts/radar-kratos/Chart.yaml | 2 +- charts/radar-kratos/README.md | 4 +- charts/radar-kratos/charts/kratos-0.52.1.tgz | Bin 19978 -> 19977 bytes charts/radar-kratos/values.yaml | 166 +++++++++++++++---- 4 files changed, 133 insertions(+), 39 deletions(-) diff --git a/charts/radar-kratos/Chart.yaml b/charts/radar-kratos/Chart.yaml index 06593b24..ef06b3c0 100644 --- a/charts/radar-kratos/Chart.yaml +++ b/charts/radar-kratos/Chart.yaml @@ -6,7 +6,7 @@ home: https://radar-base.org icon: http://radar-base.org/wp-content/uploads/2022/09/Logo_RADAR-Base-RGB.png sources: - https://github.com/RADAR-base/radar-helm-charts/tree/main/charts/radar-kratos -version: 0.1.2 +version: 0.1.3 maintainers: - email: pim@thehyve.nl name: Pim van Nierop diff --git a/charts/radar-kratos/README.md b/charts/radar-kratos/README.md index 52d30a99..355d2c77 100644 --- a/charts/radar-kratos/README.md +++ b/charts/radar-kratos/README.md @@ -3,7 +3,7 @@ # radar-kratos [![Artifact HUB](https://img.shields.io/endpoint?url=https://artifacthub.io/badge/repository/radar-kratos)](https://artifacthub.io/packages/helm/radar-base/radar-kratos) -![Version: 0.1.2](https://img.shields.io/badge/Version-0.1.2-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: v1.3.0](https://img.shields.io/badge/AppVersion-v1.3.0-informational?style=flat-square) +![Version: 0.1.3](https://img.shields.io/badge/Version-0.1.3-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: v1.3.0](https://img.shields.io/badge/AppVersion-v1.3.0-informational?style=flat-square) A ORY Kratos Helm chart for RADAR-base. ORY Kratos is a cloud native Identity and User Management system. @@ -44,4 +44,4 @@ Consult the [documentation](https://artifacthub.io/packages/helm/ory/kratos) of | kratos.server_name | string | `"localhost"` | Hostname for the Kratos service | | kratos.advertised_protocol | string | `"https"` | Protocol for the Kratos service (allowed values: http, https) | | kratos.kratos.automigration | object | `{"enabled":true}` | Enables database migration | -| kratos.kratos.identitySchemas | object | `{"identity.default.schema.json":"{\n \"$schema\": \"http://json-schema.org/draft-07/schema#\",\n \"$id\": \"default\",\n \"title\": \"user\",\n \"type\": \"object\",\n \"properties\": {\n \"traits\": {\n \"type\": \"object\",\n \"properties\": {\n \"email\": {\n \"type\": \"string\",\n \"format\": \"email\",\n \"title\": \"E-Mail\",\n \"minLength\": 5,\n \"ory.sh/kratos\": {\n \"credentials\": {\n \"password\": {\n \"identifier\": true\n },\n \"totp\": {\n \"account_name\": true\n }\n },\n \"verification\": {\n \"via\": \"email\"\n },\n \"recovery\": {\n \"via\": \"email\"\n }\n }\n }\n },\n \"required\": [ \"email\" ]\n }\n },\n \"additionalProperties\": false\n}\n","identity.user.schema.json":"{\n \"$schema\": \"http://json-schema.org/draft-07/schema#\",\n \"$id\": \"user\",\n \"title\": \"user\",\n \"type\": \"object\",\n \"properties\": {\n \"traits\": {\n \"type\": \"object\",\n \"properties\": {\n \"email\": {\n \"type\": \"string\",\n \"format\": \"email\",\n \"title\": \"E-Mail\",\n \"minLength\": 5,\n \"ory.sh/kratos\": {\n \"credentials\": {\n \"password\": {\n \"identifier\": true\n },\n \"totp\": {\n \"account_name\": true\n }\n },\n \"verification\": {\n \"via\": \"email\"\n },\n \"recovery\": {\n \"via\": \"email\"\n }\n }\n }\n },\n \"required\": [ \"email\" ]\n }\n },\n \"additionalProperties\": false\n}\n"}` | You can add multiple identity schemas here. You can pass JSON schema using `--set-file` Helm CLI argument. | +| kratos.kratos.identitySchemas | object | `{"identity.schema.admin.json":"{\n \"$schema\": \"http://json-schema.org/draft-07/schema#\",\n \"$id\": \"admin\",\n \"title\": \"admin\",\n \"type\": \"object\",\n \"properties\": {\n \"traits\": {\n \"type\": \"object\",\n \"properties\": {\n \"email\": {\n \"type\": \"string\",\n \"format\": \"email\",\n \"title\": \"E-Mail\",\n \"minLength\": 5,\n \"ory.sh/kratos\": {\n \"credentials\": {\n \"password\": {\n \"identifier\": true\n },\n \"totp\": {\n \"account_name\": true\n }\n },\n \"verification\": {\n \"via\": \"email\"\n },\n \"recovery\": {\n \"via\": \"email\"\n }\n }\n }\n },\n \"required\": [\"email\"]\n }\n },\n \"additionalProperties\": false\n}\n","identity.schema.researcher.json":"{\n \"$schema\": \"http://json-schema.org/draft-07/schema#\",\n \"$id\": \"researcher\",\n \"title\": \"researcher\",\n \"type\": \"object\",\n \"properties\": {\n \"traits\": {\n \"type\": \"object\",\n \"properties\": {\n \"email\": {\n \"type\": \"string\",\n \"format\": \"email\",\n \"title\": \"E-Mail\",\n \"minLength\": 5,\n \"ory.sh/kratos\": {\n \"credentials\": {\n \"password\": {\n \"identifier\": true\n },\n \"totp\": {\n \"account_name\": true\n }\n },\n \"verification\": {\n \"via\": \"email\"\n },\n \"recovery\": {\n \"via\": \"email\"\n }\n }\n }\n },\n \"required\": [\"email\"]\n }\n },\n \"additionalProperties\": false\n}\n","identity.schema.subject.json":"{\n \"$schema\": \"http://json-schema.org/draft-07/schema#\",\n \"$id\": \"subject\",\n \"title\": \"subject\",\n \"type\": \"object\",\n \"properties\": {\n \"traits\": {\n \"type\": \"object\",\n \"properties\": {\n \"email\": {\n \"type\": \"string\",\n \"format\": \"email\",\n \"title\": \"E-Mail\",\n \"minLength\": 5,\n \"ory.sh/kratos\": {\n \"credentials\": {\n \"password\": {\n \"identifier\": true\n },\n \"totp\": {\n \"account_name\": true\n }\n },\n \"verification\": {\n \"via\": \"email\"\n },\n \"recovery\": {\n \"via\": \"email\"\n }\n }\n }\n },\n \"required\": [\"email\"]\n }\n },\n \"additionalProperties\": false\n}\n"}` | You can add multiple identity schemas here. You can pass JSON schema using `--set-file` Helm CLI argument. | diff --git a/charts/radar-kratos/charts/kratos-0.52.1.tgz b/charts/radar-kratos/charts/kratos-0.52.1.tgz index 251e288a657b004b10b6a7cfd0815be89d3655c8..f1775a395dffe573c0b07057d5ba4bd01ca9a8f5 100644 GIT binary patch delta 19971 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 S{$Bt90RR8m6t@Kc4gvtS+ocr% delta 19972 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 T8$SOp00960CrP2;01g5Gx^CL` diff --git a/charts/radar-kratos/values.yaml b/charts/radar-kratos/values.yaml index 96dede41..f45c3bf9 100644 --- a/charts/radar-kratos/values.yaml +++ b/charts/radar-kratos/values.yaml @@ -13,16 +13,16 @@ kratos: className: "nginx" annotations: cert-manager.io/cluster-issuer: letsencrypt-prod + nginx.ingress.kubernetes.io/rewrite-target: /admin/$2 hosts: - host: '{{ .Values.server_name }}' paths: - - path: "/admin/kratos/?(.*)" + - path: "/admin/kratos(/|$)(.*)" pathType: ImplementationSpecific tls: - - hosts: + - secretName: radar-base-tls + hosts: - '{{ .Values.server_name }}' - secretName: radar-base-tls - public: enabled: true className: "nginx" @@ -35,9 +35,9 @@ kratos: - path: "/kratos/?(.*)" pathType: ImplementationSpecific tls: - - hosts: + - secretName: kratos-public-tls + hosts: - '{{ .Values.server_name }}' - secretName: kratos-public-tls kratos: # -- Enables database migration @@ -46,11 +46,11 @@ kratos: # -- You can add multiple identity schemas here. You can pass JSON schema using `--set-file` Helm CLI argument. identitySchemas: - "identity.user.schema.json": | + "identity.schema.admin.json": | { "$schema": "http://json-schema.org/draft-07/schema#", - "$id": "user", - "title": "user", + "$id": "admin", + "title": "admin", "type": "object", "properties": { "traits": { @@ -79,16 +79,16 @@ kratos: } } }, - "required": [ "email" ] + "required": ["email"] } }, "additionalProperties": false } - "identity.default.schema.json": | + "identity.schema.researcher.json": | { "$schema": "http://json-schema.org/draft-07/schema#", - "$id": "default", - "title": "user", + "$id": "researcher", + "title": "researcher", "type": "object", "properties": { "traits": { @@ -117,7 +117,45 @@ kratos: } } }, - "required": [ "email" ] + "required": ["email"] + } + }, + "additionalProperties": false + } + "identity.schema.subject.json": | + { + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "subject", + "title": "subject", + "type": "object", + "properties": { + "traits": { + "type": "object", + "properties": { + "email": { + "type": "string", + "format": "email", + "title": "E-Mail", + "minLength": 5, + "ory.sh/kratos": { + "credentials": { + "password": { + "identifier": true + }, + "totp": { + "account_name": true + } + }, + "verification": { + "via": "email" + }, + "recovery": { + "via": "email" + } + } + } + }, + "required": ["email"] } }, "additionalProperties": false @@ -133,18 +171,39 @@ kratos: cookie: ## -- If false, cookie is removed when the browser is closed --## persistent: false - courier: smtp: from_address: radar@thehyve.nl - + templates: + verification_code: + valid: + email: + body: + html: base64://SGksPGJyPjxicj5QbGVhc2XCoHZlcmlmecKgeW91csKgYWNjb3VudMKgYnnCoGVudGVyaW5nwqB0aGXCoGZvbGxvd2luZ8KgY29kZTo8YnI+PGgyPnt7IC5WZXJpZmljYXRpb25Db2RlIH19PC9oMj48YnI+PGEgaHJlZj17eyAuVmVyaWZpY2F0aW9uVVJMIH19Pnt7IC5WZXJpZmljYXRpb25VUkwgfX08L2E+ + plaintext: base64://SGksIFBsZWFzZcKgdmVyaWZ5wqB5b3VywqBhY2NvdW50wqBiecKgZW50ZXJpbmfCoHRoZcKgZm9sbG93aW5nwqBjb2RlOiB7eyAuVmVyaWZpY2F0aW9uQ29kZSB9fSB7eyAuVmVyaWZpY2F0aW9uVVJMIH19 + recovery: + valid: + email: + body: + # HTML Body: "Hi,

Please click the link below to set your password:

Set Password" + html: base64://SGksPGJyPjxicj5QbGVhc2UgY2xpY2sgdGhlIGxpbmsgYmVsb3cgdG8gc2V0IHlvdXIgcGFzc3dvcmQ6PGJyPjxicj48YSBocmVmPSJ7eyAuUmVjb3ZlcnlVUkwgfX0iPlNldCBQYXNzd29yZDwvYT4= + # Plain Text Body: "Hi, Please click the following link to set your password: {{ .RecoveryURL }}" + plaintext: base64://SGksLCBQbGVhc2UgY2xpY2sgdGhlIGZvbGxvd2luZyBsaW5rIHRvIHNldCB5b3VyIHBhc3N3b3JkOiB7eyAuUmVjb3ZlcnlVUkwgfX0= + recovery_code: + valid: + email: + body: + # HTML Body: "Hi,

Please click the link below to set your password:

Set Password" + html: base64://SGksPGJyPjxicj5QbGVhc2UgY2xpY2sgdGhlIGxpbmsgYmVsb3cgdG8gc2V0IHlvdXIgcGFzc3dvcmQ6PGJyPjxicj48YSBocmVmPSJ7eyAuUmVjb3ZlcnlVUkwgfX0iPlNldCBQYXNzd29yZDwvYT4= + # Plain Text Body: "Hi, Please click the following link to set your password: {{ .RecoveryURL }}" + plaintext: base64://SGksLCBQbGVhc2UgY2xpY2sgdGhlIGZvbGxvd2luZyBsaW5rIHRvIHNldCB5b3VyIHBhc3N3b3JkOiB7eyAuUmVjb3ZlcnlVUkwgfX0= serve: public: base_url: '{{ .Values.advertised_protocol }}://{{ .Values.server_name }}/kratos/' cors: enabled: true allowed_origins: - - '{{ .Values.advertised_protocol }}://{{ .Values.server_name }}/kratos-ui/' + - '{{ .Values.advertised_protocol }}://{{ .Values.server_name }}/study/' allowed_methods: - POST - GET @@ -184,86 +243,121 @@ kratos: issuer: Radar enabled: true link: + config: + lifespan: 1h + enabled: true + code: + config: + lifespan: 1h enabled: true flows: error: - ui_url: '{{ .Values.advertised_protocol }}://{{ .Values.server_name }}/kratos-ui/error' + ui_url: '{{ .Values.advertised_protocol }}://{{ .Values.server_name }}/study/error' settings: - ui_url: '{{ .Values.advertised_protocol }}://{{ .Values.server_name }}/kratos-ui/settings' + ui_url: '{{ .Values.advertised_protocol }}://{{ .Values.server_name }}/study/account/settings' required_aal: highest_available recovery: enabled: true - ui_url: '{{ .Values.advertised_protocol }}://{{ .Values.server_name }}/kratos-ui/recovery' - use: link + ui_url: '{{ .Values.advertised_protocol }}://{{ .Values.server_name }}/study/recovery' + use: code verification: # our current flow necessitates that users reset their password after they activate an account in managementportal, # this works as verification - ui_url: '{{ .Values.advertised_protocol }}://{{ .Values.server_name }}/kratos-ui/verification' - enabled: false - use: link + ui_url: '{{ .Values.advertised_protocol }}://{{ .Values.server_name }}/study/auth/verification' + enabled: true + use: code after: - default_browser_return_url: '{{ .Values.advertised_protocol }}://{{ .Values.server_name }}/kratos-ui' + default_browser_return_url: '{{ .Values.advertised_protocol }}://{{ .Values.server_name }}/study/auth/login' + hooks: + - hook: web_hook + config: + method: POST + url: '{{ .Values.advertised_protocol }}://{{ .Values.server_name }}/managementportal/api/webhook/kratos/subjects/activate' + body: base64://ZnVuY3Rpb24oY3R4KSB7CiAgICBpZGVudGl0eTogaWYgc3RkLm9iamVjdEhhcyhjdHgsICJpZGVudGl0eSIpIHRoZW4gY3R4LmlkZW50aXR5IGVsc2UgbnVsbCwKICAgIHBheWxvYWQ6IGlmIHN0ZC5vYmplY3RIYXMoY3R4LCAiZmxvdyIpICYmIHN0ZC5vYmplY3RIYXMoY3R4LmZsb3csICJ0cmFuc2llbnRfcGF5bG9hZCIpIHRoZW4gY3R4LmZsb3cudHJhbnNpZW50X3BheWxvYWQgZWxzZSBudWxsLAogICAgY29va2llczogY3R4LnJlcXVlc3RfY29va2llcwp9Cg== + response: + ignore: true logout: after: - default_browser_return_url: '{{ .Values.advertised_protocol }}://{{ .Values.server_name }}/kratos-ui/login' + default_browser_return_url: '{{ .Values.advertised_protocol }}://{{ .Values.server_name }}/study/auth/login' login: - ui_url: '{{ .Values.advertised_protocol }}://{{ .Values.server_name }}/kratos-ui/login' + ui_url: '{{ .Values.advertised_protocol }}://{{ .Values.server_name }}/study/auth/login' registration: - ui_url: '{{ .Values.advertised_protocol }}://{{ .Values.server_name }}/kratos-ui/registration' + ui_url: '{{ .Values.advertised_protocol }}://{{ .Values.server_name }}/study/auth/registration' after: password: hooks: + - hook: web_hook + config: + method: POST + url: '{{ .Values.advertised_protocol }}://{{ .Values.server_name }}/managementportal/api/webhook/kratos/subjects' + body: base64://ZnVuY3Rpb24oY3R4KSB7CiAgICBpZGVudGl0eTogaWYgc3RkLm9iamVjdEhhcyhjdHgsICJpZGVudGl0eSIpIHRoZW4gY3R4LmlkZW50aXR5IGVsc2UgbnVsbCwKICAgIHBheWxvYWQ6IGlmIHN0ZC5vYmplY3RIYXMoY3R4LCAiZmxvdyIpICYmIHN0ZC5vYmplY3RIYXMoY3R4LmZsb3csICJ0cmFuc2llbnRfcGF5bG9hZCIpIHRoZW4gY3R4LmZsb3cudHJhbnNpZW50X3BheWxvYWQgZWxzZSBudWxsLAogICAgY29va2llczogY3R4LnJlcXVlc3RfY29va2llcwp9Cg== + response: + ignore: true - hook: session oidc: hooks: - hook: session identity: - default_schema_id: user + default_schema_id: subject schemas: - # identitySchemas: - - id: user - url: file:///etc/config/identity.user.schema.json + - id: subject + url: file:///etc/config/identity.schema.subject.json + - id: researcher + url: file:///etc/config/identity.schema.researcher.json + - id: admin + url: file:///etc/config/identity.schema.admin.json log: level: debug format: text leak_sensitive_values: true + oauth2_provider: + url: http://radar-hydra-admin + # Register cloudnativepg secret to be used by Kratos. deployment: extraEnv: - - name: DSN + - name: POSTGRES_URI valueFrom: secretKeyRef: name: radar-cloudnative-postgresql-kratos key: uri + - name: DSN + value: "$(POSTGRES_URI)?sslmode=disable&max_conns=20&max_idle_conns=4" statefulSet: extraEnv: - - name: DSN + - name: POSTGRES_URI valueFrom: secretKeyRef: name: radar-cloudnative-postgresql-kratos key: uri + - name: DSN + value: "$(POSTGRES_URI)?sslmode=disable&max_conns=20&max_idle_conns=4" job: extraEnv: - - name: DSN + - name: POSTGRES_URI valueFrom: secretKeyRef: name: radar-cloudnative-postgresql-kratos key: uri + - name: DSN + value: "$(POSTGRES_URI)?sslmode=disable&max_conns=20&max_idle_conns=4" cronjob: cleanup: extraEnv: - - name: DSN + - name: POSTGRES_URI valueFrom: secretKeyRef: name: radar-cloudnative-postgresql-kratos key: uri + - name: DSN + value: "$(POSTGRES_URI)?sslmode=disable&max_conns=20&max_idle_conns=4" From 879c9693e5712865721c064a41c798f4bee36d8d Mon Sep 17 00:00:00 2001 From: Pim van Nierop Date: Wed, 25 Feb 2026 13:25:33 +0100 Subject: [PATCH 08/10] feat(radar-kafka): ory update --- charts/radar-kafka/templates/kafka.yaml | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/charts/radar-kafka/templates/kafka.yaml b/charts/radar-kafka/templates/kafka.yaml index e251014f..62a4a78d 100644 --- a/charts/radar-kafka/templates/kafka.yaml +++ b/charts/radar-kafka/templates/kafka.yaml @@ -78,11 +78,13 @@ spec: - mode: remove-brokers template: name: {{ template "common.names.fullname" . }}-rebalance-template - {{- with .Values.kafka.cruiseControl.javaOptions }} - jvmOptions: {{ toYaml . | nindent 6 | trim }} + {{- if .Values.kafka.cruiseControl.javaOptions }} + javaOptions: + {{- toYaml .Values.kafka.cruiseControl.javaOptions | nindent 6 }} {{- end }} - {{- with .Values.kafka.cruiseControl.resources }} - resources: {{ toYaml . | nindent 6 | trim }} + {{- if .Values.kafka.cruiseControl.resources }} + resources: + {{ toYaml .Values.kafka.cruiseControl.resources | nindent 6 }} {{- end }} {{- end }} {{ if .Values.metrics.enabled }} From f70c4f2e6c27c6e0d8b64f3e88e7bb5d1db26e9d Mon Sep 17 00:00:00 2001 From: Pim van Nierop Date: Wed, 25 Feb 2026 13:25:56 +0100 Subject: [PATCH 09/10] feat(radar-rest-sources-authorizer): ory update --- charts/radar-rest-sources-authorizer/Chart.yaml | 2 +- charts/radar-rest-sources-authorizer/README.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/charts/radar-rest-sources-authorizer/Chart.yaml b/charts/radar-rest-sources-authorizer/Chart.yaml index be7c8397..79352550 100644 --- a/charts/radar-rest-sources-authorizer/Chart.yaml +++ b/charts/radar-rest-sources-authorizer/Chart.yaml @@ -1,5 +1,5 @@ apiVersion: v2 -appVersion: "4.4.11" +appVersion: "4.4.13" description: A Helm chart for the front-end application of RADAR-base Rest Sources Authorizer which is a portal to authorize the Fitbit connector to read data from Fitbit accounts. name: radar-rest-sources-authorizer version: 2.3.1 diff --git a/charts/radar-rest-sources-authorizer/README.md b/charts/radar-rest-sources-authorizer/README.md index c7adb261..50b6bb6b 100644 --- a/charts/radar-rest-sources-authorizer/README.md +++ b/charts/radar-rest-sources-authorizer/README.md @@ -3,7 +3,7 @@ # radar-rest-sources-authorizer [![Artifact HUB](https://img.shields.io/endpoint?url=https://artifacthub.io/badge/repository/radar-rest-sources-authorizer)](https://artifacthub.io/packages/helm/radar-base/radar-rest-sources-authorizer) -![Version: 2.3.1](https://img.shields.io/badge/Version-2.3.1-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: 4.4.11](https://img.shields.io/badge/AppVersion-4.4.11-informational?style=flat-square) +![Version: 2.3.1](https://img.shields.io/badge/Version-2.3.1-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: 4.4.13](https://img.shields.io/badge/AppVersion-4.4.13-informational?style=flat-square) A Helm chart for the front-end application of RADAR-base Rest Sources Authorizer which is a portal to authorize the Fitbit connector to read data from Fitbit accounts. From 43fc9bd54de6b597f96a5438cd20f03600e16737 Mon Sep 17 00:00:00 2001 From: Pim van Nierop Date: Wed, 25 Feb 2026 13:26:12 +0100 Subject: [PATCH 10/10] feat(radar-rest-sources-backend): ory update --- charts/radar-rest-sources-backend/Chart.yaml | 2 +- charts/radar-rest-sources-backend/README.md | 3 +-- charts/radar-rest-sources-backend/templates/configmap.yaml | 4 +--- charts/radar-rest-sources-backend/values.yaml | 5 +---- 4 files changed, 4 insertions(+), 10 deletions(-) diff --git a/charts/radar-rest-sources-backend/Chart.yaml b/charts/radar-rest-sources-backend/Chart.yaml index 7d206a11..2ec46f17 100644 --- a/charts/radar-rest-sources-backend/Chart.yaml +++ b/charts/radar-rest-sources-backend/Chart.yaml @@ -2,7 +2,7 @@ apiVersion: v2 appVersion: "4.4.13" description: A Helm chart for the backend application of RADAR-base Rest Sources Authorizer name: radar-rest-sources-backend -version: 1.5.8 +version: 1.6.0 icon: "http://radar-base.org/wp-content/uploads/2022/09/Logo_RADAR-Base-RGB.png" sources: - https://github.com/RADAR-base/radar-helm-charts/tree/main/charts/radar-rest-sources-backend diff --git a/charts/radar-rest-sources-backend/README.md b/charts/radar-rest-sources-backend/README.md index d53a9e98..1467325c 100644 --- a/charts/radar-rest-sources-backend/README.md +++ b/charts/radar-rest-sources-backend/README.md @@ -3,7 +3,7 @@ # radar-rest-sources-backend [![Artifact HUB](https://img.shields.io/endpoint?url=https://artifacthub.io/badge/repository/radar-rest-sources-backend)](https://artifacthub.io/packages/helm/radar-base/radar-rest-sources-backend) -![Version: 1.5.8](https://img.shields.io/badge/Version-1.5.8-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: 4.4.13](https://img.shields.io/badge/AppVersion-4.4.13-informational?style=flat-square) +![Version: 1.6.0](https://img.shields.io/badge/Version-1.6.0-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: 4.4.13](https://img.shields.io/badge/AppVersion-4.4.13-informational?style=flat-square) A Helm chart for the backend application of RADAR-base Rest Sources Authorizer @@ -100,7 +100,6 @@ A Helm chart for the backend application of RADAR-base Rest Sources Authorizer | postgres.ssl.keystorepassword | string | `"keystorepassword"` | | | redis.uri | string | `"redis://radar-redis-replication-master:6379"` | URI of the redis database | | serverName | string | `"localhost"` | Resolvable server name, needed to find the advertised URL and callback URL | -| managementportal_url | string | `"http://management-portal:8080/managementportal"` | URL of the Management Portal | | client_secret | string | `"secret"` | OAuth2 client secret of the radar-rest-sources-backend client from Management Portal | | public_key_endpoints | list | `["http://radar-hydra-public:4444/.well-known/jwks.json"]` | List of public key endpoints for token verification | | auth_url | string | `"http://radar-hydra-public:4444/oauth2/token"` | Auth url for MP client | diff --git a/charts/radar-rest-sources-backend/templates/configmap.yaml b/charts/radar-rest-sources-backend/templates/configmap.yaml index a5e4a52b..0a5a925b 100644 --- a/charts/radar-rest-sources-backend/templates/configmap.yaml +++ b/charts/radar-rest-sources-backend/templates/configmap.yaml @@ -21,9 +21,7 @@ data: {{- end }} auth: - # Management Portal URL - managementPortalUrl: {{ .Values.managementportal_url }} - # OAuth2 Auth URL for MP Client + # OAuth2 Auth URL authUrl: {{ .Values.auth_url }} # OAuth2 Client id of rest sources authorizer backend clientId: radar_rest_sources_auth_backend diff --git a/charts/radar-rest-sources-backend/values.yaml b/charts/radar-rest-sources-backend/values.yaml index 8ef76aa2..b003f0af 100644 --- a/charts/radar-rest-sources-backend/values.yaml +++ b/charts/radar-rest-sources-backend/values.yaml @@ -281,16 +281,13 @@ redis: # -- Resolvable server name, needed to find the advertised URL and callback URL serverName: localhost -# -- URL of the Management Portal -managementportal_url: http://management-portal:8080/managementportal - # -- OAuth2 client secret of the radar-rest-sources-backend client from Management Portal client_secret: secret # -- List of public key endpoints for token verification public_key_endpoints: - http://radar-hydra-public:4444/.well-known/jwks.json - # - https://localhost/managementportal/oauth/token_key +# - http://management-portal:8080/managementportal/oauth/token_key # -- Auth url for MP client auth_url: http://radar-hydra-public:4444/oauth2/token