Skip to main content

Deploy with Helm

The helm/main chart deploys Krypton via the helm/krypton subchart, with templated RBAC scope, restart wiring, access config, and NetworkPolicy.

Minimal values​

# Minimal Helm values for Krypton (chart: helm/main, subchart: helm/krypton).
# Secret values (OIDC_CLIENT_SECRET, SESSION_SECRET) belong in a Kubernetes
# Secret referenced by envSecretName — never in values files.
global:
env: {}

krypton:
enabled: true
replicaCount: 2
# kubectl create secret generic krypton-oidc -n krypton \
# --from-literal=OIDC_CLIENT_SECRET='...' \
# --from-literal=SESSION_SECRET="$(openssl rand -hex 32)"
envSecretName: krypton-oidc
env:
KRYPTON_SCOPE: namespace
KRYPTON_ETCD_ENCRYPTED: 'false' # set 'true' once apiserver encryption is on
KRYPTON_ADMIN_GROUPS: krypton-admin
OIDC_ISSUER: https://keycloak.example.com/realms/company
OIDC_CLIENT_ID: krypton
OIDC_SCOPES: openid profile email groups
NEXT_PUBLIC_APP_URL: https://krypton.example.com
# Derives the default KRYPTON_SCOPE (explicit entries must match):
# namespace (default) or cluster. Curated extras add a derived allowlist.
rbac:
create: true
scope: namespace
# "Restart apps" (API + UI + apps RBAC rule). Default false.
restartEnabled: false
# Namespace fallback rules (krypton-access / access.json).
accessConfig:
enabled: false

networkPolicy:
enabled: true
# MUST be true on OpenShift (routes arrive from openshift-ingress).
allowOpenShiftIngress: false

Create the referenced Secret out-of-band (never commit values):

kubectl create secret generic krypton-oidc -n krypton \
--from-literal=OIDC_CLIENT_SECRET='...' \
--from-literal=SESSION_SECRET="$(openssl rand -hex 32)"

Key knobs​

ValuePurpose
krypton.envNon-secret Krypton config (full reference: app/.env.example)
krypton.envSecretNameK8s Secret with OIDC_CLIENT_SECRET + SESSION_SECRET
krypton.rbac.scopenamespace (default) or cluster — the chart derives KRYPTON_SCOPE from it (explicit entries must match)
krypton.rbac.extraNamespacesCurated extra namespaces (namespace scope): Roles plus a derived KRYPTON_NAMESPACES allowlist, no ClusterRole
krypton.restartEnabledSingle effective value wiring KRYPTON_RESTART_ENABLED and the apps RBAC rule together
krypton.accessConfig.enabledRenders the access ConfigMap and derives KRYPTON_ACCESS_CONFIGMAP from its name (access.json key)
krypton.replicaCountStateless — more than one replica is always safe (default 2)
krypton.ingress.enabled / route.enabled / httpRoute.enabledExpose via Ingress / OpenShift Route / Gateway API HTTPRoute
networkPolicy.enabledLocks down pod traffic (DNS + K8s API egress allowed)
networkPolicy.allowOpenShiftIngressMust be true on OpenShift (routes arrive from openshift-ingress)

See helm/main/values-example.yaml and helm/main/values-k8s-prod.example.yaml for fuller examples, including topology spread and IdP egress CIDRs.

RBAC scope​

One effective configuration (krypton.effectiveConfig in the subchart) derives the chart-managed runtime env from the RBAC/feature values, so the rendered Deployment env, Role/ClusterRole scope, subjects, and apps permissions always agree. Local krypton.env wins over global.env per key. Omit the managed keys (KRYPTON_SCOPE, KRYPTON_NAMESPACES, KRYPTON_RESTART_ENABLED, KRYPTON_ACCESS_CONFIGMAP) to use the derived defaults; an explicit entry must equal the derived effective value, otherwise rendering fails with actionable guidance instead of deploying disagreeing runtime/RBAC behavior.

  • namespace: own namespace only (least privilege, the default). The chart derives KRYPTON_SCOPE=namespace and renders a Role + RoleBinding.
  • namespace + krypton.rbac.extraNamespaces: [team-a]: curated multi-namespace access. The chart renders a Role + RoleBinding pair per entry (subject stays this release's ServiceAccount) and derives KRYPTON_SCOPE=cluster with the bounded allowlist KRYPTON_NAMESPACES=<release-namespace>,team-a — served by these namespaced Roles only, no ClusterRole is rendered. Previously the extra Roles were unusable because the namespace runtime scope only exposed the pod namespace.
  • cluster: centralized dashboard (KRYPTON_SCOPE=cluster); narrow with KRYPTON_NAMESPACES="team-a,team-b" in krypton.env. extraNamespaces is rejected with cluster scope.
  • rbac.create: false: RBAC is managed out-of-band. Set KRYPTON_SCOPE / KRYPTON_NAMESPACES in krypton.env yourself to match your external grants (rbac.scope/extraNamespaces are then ignored), and grant the apps permissions yourself to match krypton.restartEnabled.

Restart + access config in one place​

Unlike the raw manifests (where the flag and the RBAC rule are separate manual steps), the chart wires them together: krypton.restartEnabled is the single effective value driving both the KRYPTON_RESTART_ENABLED runtime flag and the apps RBAC rule (an explicit env entry must parse to the same value — runtime truthy strings are 1/true/yes/on — or rendering fails). Similarly, krypton.accessConfig.enabled renders the namespace fallback ConfigMap instead of applying app/k8s/configmap-access.yaml by hand, and derives KRYPTON_ACCESS_CONFIGMAP from accessConfig.name so the runtime policy reader finds it. The key must stay access.json (hardcoded by the reader); with accessConfig.enabled: false, point KRYPTON_ACCESS_CONFIGMAP at an externally managed ConfigMap. extraEnv entries must not set managed keys (they render last and would shadow the derived values).

NetworkPolicy notes​

  • Pod DNS (UDP/TCP 53) is allowed for both upstream Kubernetes (kube-system) and OpenShift (openshift-dns).
  • Egress to the Kubernetes API (https://kubernetes.default.svc, a ClusterIP) is allowed on ports 443/6443 via allowKubeApiEgress.
  • Standard NetworkPolicy cannot match DNS names: add your IdP's CIDR ranges under networkPolicy.krypton.idpEgressIpBlocks when you tighten API egress.
  • On OpenShift, allowOpenShiftIngress must be true or all ingress is denied.

Installing with the chart Makefile​

helm/main/Makefile wraps the standard flow. Secret values live in a values-<namespace>.secret.yaml file (see values-ai-poc.secret.yaml for the shape; never commit real ones):

cd helm/main
make upgrade NAMESPACE=krypton IMAGE_TAG=0.1.0 # helm dependency update + upgrade --install
make lint NAMESPACE=krypton IMAGE_TAG=0.1.0 # render + validate
make template NAMESPACE=krypton IMAGE_TAG=0.1.0 # render to template.yaml

The packaged subchart (helm/main/charts/krypton-0.1.0.tgz) is refreshed by the helm-dep step (helm dependency update) before every install, upgrade, lint, and template run.

OCI chart releases​

Every v*.*.* tag publishes the helm/krypton chart to oci://ghcr.io/egose/charts/krypton (see the Publish Helm chart workflow). Chart version and appVersion are both set from the release tag, so chart 1.2.3 deploys app 1.2.3 (ghcr.io/egose/krypton:1.2.3 by default — override with image.tag).

Install it directly, without the umbrella chart:

helm install krypton oci://ghcr.io/egose/charts/krypton --version 1.2.3 \
--namespace krypton --create-namespace

Or consume it as a dependency (helm registry login ghcr.io first if the package is private):

# Chart.yaml
dependencies:
- name: krypton
version: '1.2.3'
repository: oci://ghcr.io/egose/charts
# values.yaml
krypton:
enabled: true
env:
KRYPTON_SCOPE: namespace

See helm/krypton/README.md for the full values reference (image, exposure, autoscaling, PDB, security contexts, extra volumes).

Exposure and health​

  • One of ingress, route (OpenShift), or httpRoute (Gateway API) exposes the ClusterIP Service — enable exactly what your platform provides.
  • Liveness and readiness probes hit /api/config: unauthenticated and K8s/OIDC-free, so it is safe to probe (the raw manifests in app/k8s/ probe the same endpoint).
  • The ServiceAccount token must stay auto-mounted (serviceAccount.automount: true) — Krypton talks to the Kubernetes API with its own token.

Chart CI​

The Helm workflow lints both charts and templates them on every helm/** change, including a full-flag matrix for the subchart (cluster scope, restart, ingress + route + HTTPRoute, access config, autoscaling, PDB, external ServiceAccount) and both umbrella example values files. It also runs the rendered-object regressions in helm/krypton/tests/render-regressions.sh (default, cluster, curated namespaces, local/global conflicts, false overrides, external RBAC, custom access config, and every contradiction error). Run the same locally with helm lint / helm template and the regression script before opening a PR.