diff --git a/charts/openhands-secrets/templates/keycloak-realm.yaml b/charts/openhands-secrets/templates/keycloak-realm.yaml index 326835f0..0143bd3f 100644 --- a/charts/openhands-secrets/templates/keycloak-realm.yaml +++ b/charts/openhands-secrets/templates/keycloak-realm.yaml @@ -6,7 +6,7 @@ metadata: type: Opaque data: realm-name: {{ .Values.config.keycloak_realm_name | b64enc | quote }} - server-url: {{ "http://keycloak" | b64enc | quote }} + server-url: {{ "http://openhands-keycloak-http" | b64enc | quote }} client-id: {{ .Values.config.keycloak_client_id | b64enc | quote }} client-secret: {{ .Values.config.keycloak_client_secret | b64enc | quote }} smtp-password: {{ .Values.config.keycloak_smtp_password | b64enc | quote }} \ No newline at end of file diff --git a/charts/openhands/Chart.lock b/charts/openhands/Chart.lock index 04e282b0..0aa92561 100644 --- a/charts/openhands/Chart.lock +++ b/charts/openhands/Chart.lock @@ -2,9 +2,9 @@ dependencies: - name: clickhouse repository: oci://registry-1.docker.io/bitnamicharts version: 9.2.5 -- name: keycloak - repository: oci://registry-1.docker.io/bitnamicharts - version: 24.7.5 +- name: keycloakx + repository: https://codecentric.github.io/helm-charts + version: 7.1.9 - name: langfuse repository: https://langfuse.github.io/langfuse-k8s version: 1.2.13 @@ -25,6 +25,9 @@ dependencies: version: 1.9.0 - name: runtime-api repository: oci://ghcr.io/all-hands-ai/helm-charts - version: 0.1.24 -digest: sha256:bca3722cdd4840a4557955ea2b80e38991cc2d0a0211855a791cf98e37410e45 -generated: "2026-03-18T00:28:58.972983917-04:00" + version: 0.2.6 +- name: automation + repository: oci://ghcr.io/all-hands-ai/helm-charts + version: 0.1.0 +digest: sha256:9704eb8e0893624e1ab033871f04966cc9446437d785a89dce7b249de8c05ac0 +generated: "2026-04-03T17:26:28.296356-04:00" diff --git a/charts/openhands/Chart.yaml b/charts/openhands/Chart.yaml index 042c0af0..e397da4c 100644 --- a/charts/openhands/Chart.yaml +++ b/charts/openhands/Chart.yaml @@ -12,9 +12,10 @@ dependencies: repository: oci://registry-1.docker.io/bitnamicharts version: 9.2.5 condition: clickhouse.enabled - - name: keycloak - version: 24.7.5 - repository: oci://registry-1.docker.io/bitnamicharts + - name: keycloakx + alias: keycloak + version: 7.1.9 + repository: https://codecentric.github.io/helm-charts condition: keycloak.enabled - name: langfuse repository: https://langfuse.github.io/langfuse-k8s diff --git a/charts/openhands/example-values.yaml b/charts/openhands/example-values.yaml index 86ab99df..3d1a5282 100644 --- a/charts/openhands/example-values.yaml +++ b/charts/openhands/example-values.yaml @@ -34,10 +34,18 @@ keycloak: enabled: true ingress: enabled: false - hostname: "auth.app.example.com" annotations: {} # Value should match your Issuer/ClusterIssuer and uncomment if you're using cert-manager for certificates # cert-manager.io/cluster-issuer: letsencrypt + rules: [] + # - host: auth.app.example.com + # paths: + # - path: / + # pathType: Prefix + tls: [] + # - secretName: keycloak-tls + # hosts: + # - auth.app.example.com postgresql: enabled: true diff --git a/charts/openhands/templates/_init-containers.yaml b/charts/openhands/templates/_init-containers.yaml index a69ad312..1fa9545c 100644 --- a/charts/openhands/templates/_init-containers.yaml +++ b/charts/openhands/templates/_init-containers.yaml @@ -30,7 +30,7 @@ done env: - name: DATABASES - value: "{{ .Values.keycloak.externalDatabase.database }}{{- if (index .Values "litellm-helm").enabled }} {{ (index .Values "litellm-helm").db.database }}{{- end }}{{- if .Values.langfuse.enabled }} {{ .Values.langfuse.postgresql.auth.database }}{{- end }}" + value: "{{ .Values.keycloak.database.database }}{{- if (index .Values "litellm-helm").enabled }} {{ (index .Values "litellm-helm").db.database }}{{- end }}{{- if .Values.langfuse.enabled }} {{ .Values.langfuse.postgresql.auth.database }}{{- end }}" {{- include "openhands.env" . | nindent 4 }} {{- end }} {{- if .Values.databaseMigrations.migrate }} diff --git a/charts/openhands/templates/troubleshoot/support-bundle.yaml b/charts/openhands/templates/troubleshoot/support-bundle.yaml index 00f1ce68..7717b47d 100644 --- a/charts/openhands/templates/troubleshoot/support-bundle.yaml +++ b/charts/openhands/templates/troubleshoot/support-bundle.yaml @@ -75,7 +75,7 @@ spec: maxAge: 168h {{- end }} {{- if .Values.keycloak.enabled }} - # Keycloak logs (Bitnami chart) + # Keycloak logs (KeycloakX chart) - logs: name: app/{{ .Release.Name }}-keycloak/logs namespace: {{ .Release.Namespace }} @@ -243,7 +243,7 @@ spec: {{- end }} {{- if .Values.keycloak.enabled }} - statefulsetStatus: - name: keycloak + name: {{ .Release.Name }}-keycloak namespace: {{ .Release.Namespace }} outcomes: - fail: diff --git a/charts/openhands/values.yaml b/charts/openhands/values.yaml index 53f19a85..14097189 100644 --- a/charts/openhands/values.yaml +++ b/charts/openhands/values.yaml @@ -287,85 +287,83 @@ clickhouse: keycloak: enabled: false - url: "http://keycloak" - fullnameOverride: keycloak - replicaCount: 1 - production: true - proxyHeaders: forwarded - ingress: - enabled: false - # REQUIRED: Update to a hostname in a DNS domain you own - # hostname: auth.app.example.com - servicePort: 80 - tls: true - annotations: {} - # UPDATE: if you use cert-manager, enter your clusterIssuer may not match. - # cert-manager.io/cluster-issuer: letsencrypt-production - ingressClassName: traefik - auth: - adminUser: tmpadmin - existingSecret: keycloak-admin - passwordSecretKey: admin-password + url: "http://openhands-keycloak-http" + replicas: 1 + + command: + - "/opt/keycloak/bin/kc.sh" + args: + - "start" + + image: + repository: quay.io/keycloak/keycloak + tag: "26.5.5" + pullPolicy: IfNotPresent + + database: + vendor: postgres + hostname: oh-main-postgresql + port: 5432 + database: bitnami_keycloak + existingSecret: postgres-password + existingSecretKey: password + + dbchecker: + enabled: true + image: + repository: docker.io/library/busybox + tag: "1.37" + + proxy: + enabled: true + mode: xforwarded + + http: + relativePath: "/" + service: type: ClusterIP + httpPort: 80 + serviceAccount: + create: true name: "keycloak-sa" - postgresql: + + ingress: enabled: false - externalDatabase: - host: oh-main-postgresql - database: bitnami_keycloak - existingSecret: postgres-password - existingSecretUserKey: username - existingSecretPasswordKey: password - extraEnvVars: + ingressClassName: traefik + annotations: {} + # UPDATE: if you use cert-manager, enter your clusterIssuer may not match. + # cert-manager.io/cluster-issuer: letsencrypt-production + rules: [] + # - host: auth.app.example.com + # paths: + # - path: / + # pathType: Prefix + tls: [] + # - secretName: keycloak-tls + # hosts: + # - auth.app.example.com + + extraEnv: | + - name: KEYCLOAK_ADMIN + value: tmpadmin + - name: KEYCLOAK_ADMIN_PASSWORD + valueFrom: + secretKeyRef: + name: keycloak-admin + key: admin-password - name: KC_FEATURES value: token-exchange,admin-fine-grained-authz - - name: KC_HTTP_ENABLED - value: "true" - - name: KC_PROXY_HEADERS - value: "xforwarded" + - name: KC_HOSTNAME_STRICT + value: "false" - name: KC_SPI_LOGIN_PROTOCOL_OPENID_CONNECT_LEGACY_LOGOUT_REDIRECT_URI value: "true" - image: - repository: bitnamilegacy/keycloak - waitForDb: - image: "bitnamilegacy/postgresql:latest" - initContainers: - - name: wait-for-db - # The Bitnami Keycloak subchart renders initContainers through common.tplvalues.render, - # so this template expression is evaluated at deploy time rather than being treated as - # a literal string. This lets us override just the image (e.g. for Replicated proxy) - # without duplicating the entire init container. - image: '{{ .Values.waitForDb.image }}' - command: ['sh', '-c'] - args: - - | - echo "Waiting for database \"$KEYCLOAK_DATABASE_NAME\" at $KEYCLOAK_DATABASE_HOST:$KEYCLOAK_DATABASE_PORT..." - until PGPASSWORD=$DB_PASS pg_isready -h "$KEYCLOAK_DATABASE_HOST" -p "$KEYCLOAK_DATABASE_PORT" -U "$DB_USER" -d "$KEYCLOAK_DATABASE_NAME" > /dev/null 2>&1; do - echo "PostgreSQL is unavailable - sleeping 5s" - sleep 5 - done - echo "PostgreSQL is ready, checking database exists..." - until PGPASSWORD=$DB_PASS psql -h "$KEYCLOAK_DATABASE_HOST" -p "$KEYCLOAK_DATABASE_PORT" -U "$DB_USER" -d "$KEYCLOAK_DATABASE_NAME" -c "SELECT 1" > /dev/null 2>&1; do - echo "Database \"$KEYCLOAK_DATABASE_NAME\" not ready - sleeping 5s" - sleep 5 - done - echo "Database \"$KEYCLOAK_DATABASE_NAME\" is ready!" - envFrom: - - configMapRef: - name: keycloak-env-vars - env: - - name: DB_USER - valueFrom: - secretKeyRef: - name: postgres-password - key: username - - name: DB_PASS - valueFrom: - secretKeyRef: - name: postgres-password - key: password + - name: KC_DB_USERNAME + valueFrom: + secretKeyRef: + name: postgres-password + key: username langfuse: # Enable this if you want to use langfuse for tracing diff --git a/replicated/application.yaml b/replicated/application.yaml index aede3aa2..966b6dd5 100644 --- a/replicated/application.yaml +++ b/replicated/application.yaml @@ -26,8 +26,8 @@ spec: - openhands/ingress/openhands-mcp-ingress # keycloak - - openhands/statefulset/keycloak - - openhands/service/keycloak + - openhands/statefulset/openhands-keycloak + - openhands/service/openhands-keycloak-http # postgres - '{{repl if ConfigOptionEquals "postgres_type" "embedded_postgres"}}openhands/statefulset/openhands-postgresql{{repl end}}' diff --git a/replicated/openhands.yaml b/replicated/openhands.yaml index 7c5b2f3c..606a6828 100644 --- a/replicated/openhands.yaml +++ b/replicated/openhands.yaml @@ -57,8 +57,7 @@ spec: keycloak: enabled: true - url: 'http://keycloak' - resourcesPreset: none + url: 'http://openhands-keycloak-http' resources: requests: cpu: 500m @@ -71,29 +70,54 @@ spec: ingress: enabled: true ingressClassName: traefik - hostname: '{{repl if ConfigOptionEquals "hostname_mode" "derive"}}auth.app.{{repl ConfigOption "base_domain"}}{{repl else}}{{repl ConfigOption "auth_hostname"}}{{repl end}}' - tls: true annotations: nginx.ingress.kubernetes.io/upstream-vhost: '{{repl if ConfigOptionEquals "hostname_mode" "derive"}}auth.app.{{repl ConfigOption "base_domain"}}{{repl else}}{{repl ConfigOption "auth_hostname"}}{{repl end}}' nginx.ingress.kubernetes.io/backend-protocol: "HTTP" - secrets: - - name: '{{repl if ConfigOptionEquals "hostname_mode" "derive"}}auth.app.{{repl ConfigOption "base_domain"}}{{repl else}}{{repl ConfigOption "auth_hostname"}}{{repl end}}-tls' - key: | - {{repl ConfigOptionData "tls_private_key" | nindent 14}} - certificate: | - {{repl ConfigOptionData "tls_certificate" | nindent 14}} - externalDatabase: - host: '{{repl if ConfigOptionEquals "postgres_type" "external_postgres"}}{{repl ConfigOption "external_postgres_host"}}{{repl else}}oh-main-postgresql{{repl end}}' + rules: + - host: '{{repl if ConfigOptionEquals "hostname_mode" "derive"}}auth.app.{{repl ConfigOption "base_domain"}}{{repl else}}{{repl ConfigOption "auth_hostname"}}{{repl end}}' + paths: + - path: / + pathType: Prefix + tls: + - secretName: '{{repl if ConfigOptionEquals "hostname_mode" "derive"}}auth.app.{{repl ConfigOption "base_domain"}}{{repl else}}{{repl ConfigOption "auth_hostname"}}{{repl end}}-tls' + hosts: + - '{{repl if ConfigOptionEquals "hostname_mode" "derive"}}auth.app.{{repl ConfigOption "base_domain"}}{{repl else}}{{repl ConfigOption "auth_hostname"}}{{repl end}}' + database: + vendor: postgres + hostname: '{{repl if ConfigOptionEquals "postgres_type" "external_postgres"}}{{repl ConfigOption "external_postgres_host"}}{{repl else}}oh-main-postgresql{{repl end}}' + port: 5432 + database: bitnami_keycloak existingSecret: postgres-password - existingSecretUserKey: username - existingSecretPasswordKey: password - image: - repository: 'proxy/{{repl LicenseFieldValue "appSlug"}}/docker.io/bitnamilegacy/keycloak' - keycloakConfigCli: + existingSecretKey: password + imagePullSecrets: + - name: '{{repl ImagePullSecretName }}' + dbchecker: + enabled: true image: - repository: 'proxy/{{repl LicenseFieldValue "appSlug"}}/docker.io/bitnamilegacy/keycloak-config-cli' - waitForDb: - image: 'images.r9.all-hands.dev/proxy/{{repl LicenseFieldValue "appSlug"}}/docker.io/bitnamilegacy/postgresql:latest' + repository: 'images.r9.all-hands.dev/proxy/{{repl LicenseFieldValue "appSlug"}}/docker.io/library/busybox' + tag: "1.37" + image: + repository: 'images.r9.all-hands.dev/proxy/{{repl LicenseFieldValue "appSlug"}}/quay.io/keycloak/keycloak' + tag: "26.5.5" + extraEnv: | + - name: KEYCLOAK_ADMIN + value: tmpadmin + - name: KEYCLOAK_ADMIN_PASSWORD + valueFrom: + secretKeyRef: + name: keycloak-admin + key: admin-password + - name: KC_FEATURES + value: token-exchange,admin-fine-grained-authz + - name: KC_HOSTNAME_STRICT + value: "false" + - name: KC_SPI_LOGIN_PROTOCOL_OPENID_CONNECT_LEGACY_LOGOUT_REDIRECT_URI + value: "true" + - name: KC_DB_USERNAME + valueFrom: + secretKeyRef: + name: postgres-password + key: username litellm: enabled: true @@ -292,7 +316,7 @@ spec: # existingSecretUserKey: username # existingSecretPasswordKey: password keycloak: - externalDatabase: + database: database: '{{repl ConfigOption "external_postgres_keycloak_database"}}' litellm-helm: db: @@ -320,10 +344,6 @@ spec: postgresql: image: repository: 'proxy/{{repl LicenseFieldValue "appSlug"}}/docker.io/bitnamilegacy/postgresql' - keycloak: - postgresql: - image: - repository: 'proxy/{{repl LicenseFieldValue "appSlug"}}/docker.io/bitnamilegacy/postgresql' - when: '{{repl ConfigOptionEquals "langfuse_enabled" "1" }}' recursiveMerge: true values: @@ -388,12 +408,10 @@ spec: fs_group: 10001 keycloak: image: - repository: '{{repl LocalRegistryNamespace }}/keycloak' - keycloakConfigCli: + repository: '{{repl LocalRegistryHost }}/{{repl LocalRegistryNamespace }}/keycloak' + dbchecker: image: - repository: '{{repl LocalRegistryNamespace }}/keycloak-config-cli' - waitForDb: - image: '{{repl LocalRegistryHost }}/{{repl LocalRegistryNamespace }}/postgresql:latest' + repository: '{{repl LocalRegistryHost }}/{{repl LocalRegistryNamespace }}/busybox' postgresql: image: repository: '{{repl LocalRegistryNamespace }}/postgresql' @@ -441,7 +459,7 @@ spec: {{repl $llmDomain := $derive | ternary (printf "llm-proxy.%s" $bd) (ConfigOption "llm_proxy_hostname") }} {{repl $runtimeApiDomain := $derive | ternary (printf "runtime-api.%s" $bd) (ConfigOption "runtime_api_hostname") }} {{repl $runtimeBaseDomain := $derive | ternary (printf "runtime.%s" $bd) (ConfigOption "runtime_base_hostname") }} - {{repl $computedNoProxy := "127.0.0.1,cluster.local,keycloak,keycloak-headless,kubernetes,localhost,oh-main-clickhouse,oh-main-langfuse,oh-main-lite-llm,oh-main-runtime-api,openhands-integrations-service,openhands-litellm,openhands-mcp-service,openhands-minio,openhands-runtime-api,openhands-service,svc" }} + {{repl $computedNoProxy := "127.0.0.1,cluster.local,openhands-keycloak-http,openhands-keycloak-headless,kubernetes,localhost,oh-main-clickhouse,oh-main-langfuse,oh-main-lite-llm,oh-main-runtime-api,openhands-integrations-service,openhands-litellm,openhands-mcp-service,openhands-minio,openhands-runtime-api,openhands-service,svc" }} {{repl if ne $bd "" }}{{repl $computedNoProxy = printf "%s,%s" $computedNoProxy $bd }}{{repl end }} {{repl if ne $appDomain "" }}{{repl $computedNoProxy = printf "%s,%s" $computedNoProxy $appDomain }}{{repl end }} {{repl if ne $authDomain "" }}{{repl $computedNoProxy = printf "%s,%s" $computedNoProxy $authDomain }}{{repl end }} @@ -459,17 +477,26 @@ spec: SSL_VERIFY: '{{repl if ConfigOptionEquals "ssl_verify" "1"}}True{{repl else}}False{{repl end}}' OH_AGENT_SERVER_ENV: '{{repl printf "{\"HTTP_PROXY\": \"%s\", \"HTTPS_PROXY\": \"%s\", \"NO_PROXY\": \"%s\", \"SSL_VERIFY\": \"%s\", \"GIT_SSL_NO_VERIFY\": \"%s\"}" (ConfigOption "http_proxy") (ConfigOption "https_proxy") $computedNoProxy (ConfigOptionEquals "ssl_verify" "1" | ternary "True" "False") (ConfigOptionEquals "ssl_verify" "1" | ternary "False" "True") }}' keycloak: - extraEnvVars: - # Existing KC env vars (must be repeated because recursiveMerge replaces arrays) + # All extraEnv vars must be repeated because recursiveMerge replaces entire keys + extraEnv: | + - name: KEYCLOAK_ADMIN + value: tmpadmin + - name: KEYCLOAK_ADMIN_PASSWORD + valueFrom: + secretKeyRef: + name: keycloak-admin + key: admin-password - name: KC_FEATURES value: token-exchange,admin-fine-grained-authz - - name: KC_HTTP_ENABLED - value: "true" - - name: KC_PROXY_HEADERS - value: "xforwarded" + - name: KC_HOSTNAME_STRICT + value: "false" - name: KC_SPI_LOGIN_PROTOCOL_OPENID_CONNECT_LEGACY_LOGOUT_REDIRECT_URI value: "true" - # Proxy env vars + - name: KC_DB_USERNAME + valueFrom: + secretKeyRef: + name: postgres-password + key: username - name: HTTP_PROXY value: '{{repl ConfigOption "http_proxy"}}' - name: HTTPS_PROXY