Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
94 changes: 91 additions & 3 deletions charts/currents/templates/_common.tpl
Original file line number Diff line number Diff line change
Expand Up @@ -296,10 +296,98 @@ ClickHouse data is loaded from an external export (scripts/org-import).
{{- if .Values.currents.sso.saml.authnRequestsSigned }}
- name: SSO_SAML_AUTHN_REQUESTS_SIGNED
value: "true"
- name: SSO_SAML_SP_CERT_FILE
value: {{ printf "/etc/currents/sso/%s" .Values.currents.sso.saml.spCertKey | quote }}
- name: SSO_SAML_SP_KEY_FILE
value: {{ printf "/etc/currents/sso/%s" .Values.currents.sso.saml.spKeyKey | quote }}
{{- end }}
{{- end }}
{{- end -}}
{{- end -}}

{{/*
Whether the OAuth provider can run on appHost. The API refuses to start with it on
over http unless the host is loopback or in OAUTH_HTTP_ALLOWED_HOSTS, and Better
Auth advertises an https issuer for any http host but localhost and *.localhost,
so OAuth over http works only on those names.
*/}}
{{- define "currents.oauthSupported" -}}
{{- $hostname := regexReplaceAll ":[0-9]+$" (lower .Values.currents.domains.appHost) "" -}}
{{- if or .Values.currents.domains.https (eq $hostname "localhost") (hasSuffix ".localhost" $hostname) -}}
true
{{- end -}}
{{- end -}}

{{- define "currents.mcpOAuthEnv" -}}
- name: MCP_ENABLED
value: {{ .Values.currents.mcp.enabled | toString | quote }}
{{- if .Values.currents.mcp.origins }}
- name: MCP_ORIGINS
value: {{ .Values.currents.mcp.origins | quote }}
{{- end }}
{{- $oauth := .Values.currents.oauth }}
{{- if and $oauth.enabled (include "currents.oauthSupported" .) }}
- name: OAUTH_PROVIDER_ENABLED
value: "true"
{{- if not .Values.currents.domains.https }}
{{- /* Over http, appHost is localhost or *.localhost. The API checks each access
token against its own signing keys, fetched from appHost by default, and a
pod resolves neither name to the API. */}}
- name: OAUTH_JWKS_URL
Comment thread
twk3 marked this conversation as resolved.
value: {{ printf "http://localhost:%v/api/auth/jwks" .Values.server.service.port | quote }}
{{- $hostname := regexReplaceAll ":[0-9]+$" (lower .Values.currents.domains.appHost) "" }}
{{- if hasSuffix ".localhost" $hostname }}
- name: OAUTH_HTTP_ALLOWED_HOSTS
value: {{ $hostname | quote }}
{{- end }}
{{- end }}
{{- if $oauth.dynamicClientRegistration }}
- name: OAUTH_DYNAMIC_CLIENT_REGISTRATION_ENABLED
value: "true"
{{- end }}
{{- if not $oauth.clientIdMetadataDocuments }}
- name: OAUTH_CIMD_ENABLED
value: "false"
{{- end }}
{{- end }}
{{- end -}}

{{/*
The app-content bucket, rendered as the PERMANENT_STORAGE_* the services read.
Unset fields take the artifact bucket's values, so one endpoint and one set of
credentials serve both buckets by default. The internal endpoint and region come
along only with the endpoint: with its own endpoint, the artifact storage's
internal endpoint would send the pods to the wrong storage.
*/}}
{{- define "currents.appContentStorageEnv" -}}
{{- $acs := .Values.currents.appContentStorage }}
{{- $os := .Values.currents.objectStorage }}
{{- if $acs.bucket }}
{{- $location := ternary $acs $os (not (empty $acs.endpoint)) }}
- name: PERMANENT_STORAGE_BUCKET
value: {{ $acs.bucket | quote }}
- name: PERMANENT_STORAGE_ENDPOINT
value: {{ required "currents.appContentStorage.endpoint or currents.objectStorage.endpoint is required when currents.appContentStorage.bucket is set" $location.endpoint | quote }}
{{- with (default $location.internalEndpoint $acs.internalEndpoint) }}
- name: PERMANENT_STORAGE_INTERNAL_ENDPOINT
value: {{ . | quote }}
{{- end }}
{{- with (default $location.region $acs.region) }}
- name: PERMANENT_STORAGE_REGION
value: {{ . | quote }}
{{- end }}
{{- with (default $os.secretName $acs.secretName) }}
- name: PERMANENT_STORAGE_ACCESS_KEY_ID
valueFrom:
secretKeyRef:
name: {{ . }}
key: {{ default $os.secretIdKey $acs.secretIdKey }}
- name: PERMANENT_STORAGE_SECRET_ACCESS_KEY
valueFrom:
secretKeyRef:
name: {{ . }}
key: {{ default $os.secretAccessKey $acs.secretAccessKey }}
{{- end }}
{{- if (kindIs "bool" $acs.pathStyle | ternary $acs.pathStyle $os.pathStyle) }}
- name: PERMANENT_STORAGE_FORCE_PATH_STYLE
value: "true"
{{- end }}
{{- end }}
{{- end -}}
1 change: 1 addition & 0 deletions charts/currents/templates/changestreams/deployment.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ spec:
{{- include "currents.connectionConfigEnv" . | nindent 12 }}
{{- include "currents.URLConfigEnv" . | nindent 12 }}
{{- include "currents.clickhouseRestoreModeEnv" . | nindent 12 }}
{{- include "currents.appContentStorageEnv" . | nindent 12 }}
{{- with (concat .Values.global.env .Values.changestreams.env) }}
{{- toYaml . | nindent 12 }}
{{- end }}
Expand Down
2 changes: 2 additions & 0 deletions charts/currents/templates/server/deployment.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,8 @@ spec:
{{- include "currents.URLConfigEnv" . | nindent 12 }}
{{- include "currents.emailEnv" . | nindent 12 }}
{{- include "currents.samlSSOEnv" . | nindent 12 }}
{{- include "currents.mcpOAuthEnv" . | nindent 12 }}
{{- include "currents.appContentStorageEnv" . | nindent 12 }}
{{- if .Values.currents.betterAuth.secretName }}
- name: BETTER_AUTH_SECRET
valueFrom:
Expand Down
1 change: 1 addition & 0 deletions charts/currents/templates/writer/deployment.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ spec:
{{- include "currents.connectionConfigEnv" . | nindent 12 }}
{{- include "currents.URLConfigEnv" . | nindent 12 }}
{{- include "currents.emailEnv" . | nindent 12 }}
{{- include "currents.appContentStorageEnv" . | nindent 12 }}
{{- with (concat .Values.global.env .Values.writer.env) }}
{{- toYaml . | nindent 12 }}
{{- end }}
Expand Down
68 changes: 63 additions & 5 deletions charts/currents/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ currents:
# -- Provider id; recommend your IdP service name (e.g. `okta`). Becomes the last path segment of the ACS callback URL.
# @section -- SAML SSO
providerId: onprem-saml
# -- K8s secret holding the IdP metadata XML (and any SP cert/key). Mounted read-only at /etc/currents/sso. See the SAML SSO guide for how to create it.
# -- K8s secret holding the IdP metadata XML (and the SP key, when signing requests). Mounted read-only at /etc/currents/sso. See the SAML SSO guide for how to create it.
# @section -- SAML SSO
metadataSecretName: ""
# -- The secret key (file name) of the IdP metadata XML
Expand All @@ -105,15 +105,37 @@ currents:
# -- Comma-separated email domains allowed to sign in via SSO (optional allow-list)
# @section -- SAML SSO
allowedDomains: ""
# -- Sign outbound AuthnRequests. Requires the SP cert/key (below) to be present in the same secret.
# -- Sign outbound AuthnRequests. Requires the SP key (below) in the same secret; upload the matching certificate to your IdP.
# @section -- SAML SSO
authnRequestsSigned: false
# -- Secret key (file name) of the SP certificate PEM (only when authnRequestsSigned=true)
# @section -- SAML SSO
spCertKey: sp-cert.pem
# -- Secret key (file name) of the SP private key PEM (only when authnRequestsSigned=true)
# @section -- SAML SSO
spKeyKey: sp-key.pem
mcp:
# -- Serve remote MCP at `/mcp`, so coding agents can use Currents tools over HTTP. Clients
# authenticate with an API key or personal access token, or with OAuth (below). Requests
# without a valid credential get a 401.
# @section -- Remote MCP and OAuth
enabled: true
# -- Other origins clients reach `/mcp` on, comma separated (e.g. `https://mcp.example.com`)
# @section -- Remote MCP and OAuth
origins: ""
oauth:
# -- Let MCP clients sign in with a Currents account instead of a key. Serves
# `/api/auth/oauth2/*` and `/.well-known/oauth-*`; the issuer and token audience come from
# `domains.appHost`. Rendered only when `domains.https` is true, or `appHost` is
# `localhost` or a `*.localhost` name (for an evaluation without TLS): on any other http host
# the API would refuse to start, so OAuth stays off there.
# @section -- Remote MCP and OAuth
enabled: true
# -- Let clients register themselves, the way to add a client without internet access
# @section -- Remote MCP and OAuth
dynamicClientRegistration: true
# -- Accept clients identified by a client ID metadata document: an https URL the API fetches.
# Hosts that resolve to private, loopback or link-local addresses are refused, so a client
# can't name a service inside the cluster.
# @section -- Remote MCP and OAuth
clientIdMetadataDocuments: true
apiInternalToken:
# -- The K8s secret to use for the internal API token
# @section -- Required
Expand Down Expand Up @@ -191,6 +213,42 @@ currents:
bucket: ""
# -- Whether to use path style access for the object storage
pathStyle: false
appContentStorage:
# -- The bucket for context shares, organization logos and session files, separate from the
# artifact bucket. Unset, context sharing and logo editing are off and session file uploads
# answer 503. Create it with the lifecycle rules in
# [App content bucket](./eks/dependencies.md#app-content-bucket).
# @section -- App Content Storage
bucket: ""
# -- Endpoint browsers reach the bucket on: session files and logos use presigned URLs
# @section -- App Content Storage
# @default -- `objectStorage.endpoint`
endpoint: ""
# -- Endpoint the pods reach the bucket on
# @section -- App Content Storage
# @default -- `objectStorage.internalEndpoint` when `endpoint` is unset
internalEndpoint: ""
# -- The bucket's region
# @section -- App Content Storage
# @default -- `objectStorage.region` when `endpoint` is unset
region: ""
# -- K8s secret holding the access key. Leave this and `objectStorage.secretName` unset to use
# the pod's IAM role (IRSA).
# @section -- App Content Storage
# @default -- `objectStorage.secretName`
secretName: ""
# -- The K8s secret key for the access key ID
# @section -- App Content Storage
# @default -- `objectStorage.secretIdKey`
secretIdKey: ""
# -- The K8s secret key for the secret access key
# @section -- App Content Storage
# @default -- `objectStorage.secretAccessKey`
secretAccessKey: ""
# -- (bool) Whether to use path style access
# @section -- App Content Storage
# @default -- `objectStorage.pathStyle`
pathStyle:
logger:
# -- The coralogix API endpoint to use
apiEndpoint: ""
Expand Down
28 changes: 25 additions & 3 deletions docs/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,14 +76,36 @@ The following table lists the configurable parameters of the `currents` chart an
| currents.sso.saml.enabled | bool | `false` | Enable SAML SSO. Requires `issuer` and `metadataSecretName` below (a K8s secret holding your IdP metadata XML). Turns on email-first SSO login. |
| currents.sso.saml.issuer | string | `""` | SP entityID / audience presented to your IdP. A stable opaque identifier (e.g. `currents-onprem:your-org`), NOT a URL. Must match the Audience / SP Entity ID configured in your IdP. |
| currents.sso.saml.providerId | string | `"onprem-saml"` | Provider id; recommend your IdP service name (e.g. `okta`). Becomes the last path segment of the ACS callback URL. |
| currents.sso.saml.metadataSecretName | string | `""` | K8s secret holding the IdP metadata XML (and any SP cert/key). Mounted read-only at /etc/currents/sso. See the SAML SSO guide for how to create it. |
| currents.sso.saml.metadataSecretName | string | `""` | K8s secret holding the IdP metadata XML (and the SP key, when signing requests). Mounted read-only at /etc/currents/sso. See the SAML SSO guide for how to create it. |
| currents.sso.saml.metadataKey | string | `"idp-metadata.xml"` | The secret key (file name) of the IdP metadata XML |
| currents.sso.saml.defaultRole | string | `"member"` | Role granted to auto-provisioned SSO users |
| currents.sso.saml.allowedDomains | string | `""` | Comma-separated email domains allowed to sign in via SSO (optional allow-list) |
| currents.sso.saml.authnRequestsSigned | bool | `false` | Sign outbound AuthnRequests. Requires the SP cert/key (below) to be present in the same secret. |
| currents.sso.saml.spCertKey | string | `"sp-cert.pem"` | Secret key (file name) of the SP certificate PEM (only when authnRequestsSigned=true) |
| currents.sso.saml.authnRequestsSigned | bool | `false` | Sign outbound AuthnRequests. Requires the SP key (below) in the same secret; upload the matching certificate to your IdP. |
| currents.sso.saml.spKeyKey | string | `"sp-key.pem"` | Secret key (file name) of the SP private key PEM (only when authnRequestsSigned=true) |

### Remote MCP and OAuth

| Key | Type | Default | Description |
|-----|------|---------|-------------|
| currents.mcp.enabled | bool | `true` | Serve remote MCP at `/mcp`, so coding agents can use Currents tools over HTTP. Clients authenticate with an API key or personal access token, or with OAuth (below). Requests without a valid credential get a 401. |
| currents.mcp.origins | string | `""` | Other origins clients reach `/mcp` on, comma separated (e.g. `https://mcp.example.com`) |
| currents.oauth.enabled | bool | `true` | Let MCP clients sign in with a Currents account instead of a key. Serves `/api/auth/oauth2/*` and `/.well-known/oauth-*`; the issuer and token audience come from `domains.appHost`. Rendered only when `domains.https` is true, or `appHost` is `localhost` or a `*.localhost` name (for an evaluation without TLS): on any other http host the API would refuse to start, so OAuth stays off there. |
| currents.oauth.dynamicClientRegistration | bool | `true` | Let clients register themselves, the way to add a client without internet access |
| currents.oauth.clientIdMetadataDocuments | bool | `true` | Accept clients identified by a client ID metadata document: an https URL the API fetches. Hosts that resolve to private, loopback or link-local addresses are refused, so a client can't name a service inside the cluster. |

### App Content Storage

| Key | Type | Default | Description |
|-----|------|---------|-------------|
| currents.appContentStorage.bucket | string | `""` | The bucket for context shares, organization logos and session files, separate from the artifact bucket. Unset, context sharing and logo editing are off and session file uploads answer 503. Create it with the lifecycle rules in [App content bucket](./eks/dependencies.md#app-content-bucket). |
| currents.appContentStorage.endpoint | string | `objectStorage.endpoint` | Endpoint browsers reach the bucket on: session files and logos use presigned URLs |
| currents.appContentStorage.internalEndpoint | string | `objectStorage.internalEndpoint` when `endpoint` is unset | Endpoint the pods reach the bucket on |
| currents.appContentStorage.region | string | `objectStorage.region` when `endpoint` is unset | The bucket's region |
| currents.appContentStorage.secretName | string | `objectStorage.secretName` | K8s secret holding the access key. Leave this and `objectStorage.secretName` unset to use the pod's IAM role (IRSA). |
| currents.appContentStorage.secretIdKey | string | `objectStorage.secretIdKey` | The K8s secret key for the access key ID |
| currents.appContentStorage.secretAccessKey | string | `objectStorage.secretAccessKey` | The K8s secret key for the secret access key |
| currents.appContentStorage.pathStyle | bool | `objectStorage.pathStyle` | Whether to use path style access |

### Other Values

| Key | Type | Default | Description |
Expand Down
2 changes: 1 addition & 1 deletion docs/developer-guide/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ Install RustFS
helm install rustfs rustfs --repo https://charts.rustfs.com --version 1.0.1 -f samples/rustfs-helm-config.yaml
```

Create the `currents` bucket
Create the `currents` and `currents-app-content` buckets

```sh
kubectl apply -f samples/rustfs-create-bucket-job.yaml
Expand Down
Loading
Loading