Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Sovereign, high-performance data protection

Kubernetes — Helm Chart Deployment

Eviden KMS can be deployed on Kubernetes using the bundled Helm chart (charts/cosmian-kms/). The chart supports both FIPS and non-FIPS images, multiple database backends, and production-grade features such as TLS, autoscaling, network policies, and pod disruption budgets.

Once the KMS server is running on Kubernetes you can enable the other integrations:

Prerequisites

  • Kubernetes 1.24+
  • Helm 3.8+
  • An external PostgreSQL or MySQL database for production/HA deployments

Warning

The default sqlite backend is suitable for single-replica, non-HA use only. For production and high-availability deployments, use postgresql or mysql with an external database. Refer to the High Availability guide for architecture details.

Audit logging and multiple replicas

If you enable audit logging, do not point multiple replicas at the same audit file (e.g. a shared PVC). The file backend is not safe for concurrent writers from different pods: only one replica will actually log events. Keep audit files per-pod (the chart default) and ship them off with a sidecar/log agent, or use the PostgreSQL audit backend for a single consolidated trail.

Container images

The KMS container images are published to the GitHub Container Registry (GHCR), multi-arch (amd64 + arm64), and signed with Cosign:

ImageDescription
ghcr.io/cosmian/kms-fipsFIPS 140-3 compliant (default)
ghcr.io/cosmian/kmsNon-FIPS — additional algorithms (Covercrypt, Redis-findex, …)

Installing

Add the Helm repository

The chart is published to GitHub Pages. Add it once and keep it up to date:

helm repo add cosmian https://cosmian.github.io/kms
helm repo update

Minimal install

helm install my-kms cosmian/cosmian-kms \
  --set kms.database.type=postgresql \
  --set kms.database.url="postgresql://kms:kms@postgres:5432/kms"

Choosing the image variant

The chart defaults to the FIPS image (ghcr.io/cosmian/kms-fips). To use the non-FIPS image instead:

helm install my-kms cosmian/cosmian-kms \
  --set image.repository=ghcr.io/cosmian/kms

HSM

The official KMS images (FIPS and non-FIPS) load the vendor PKCS#11 client library of the HSM at runtime. The vendor HSM models are built for Linux x86_64 only: pin the pod to amd64 nodes. Keep the image unmodified and add the HSM through the chart's extension values:

  • an init container copies the vendor client library from a small image you build from the vendor package into an emptyDir volume, and the KMS loads it from there through the model's library-path environment variable;
  • the vendor configuration and credentials come from Kubernetes Secrets, mounted with extraVolumes / extraVolumeMounts;
  • extraArgs sets --hsm-model, --hsm-slot and --hsm-admin, and extraEnv passes the slot password from a Secret as KMS_HSM_PASSWORD.
  • with the FIPS image, command: [env, -u, OPENSSL_CONF, cosmian_kms] for a vendor library that embeds its own OpenSSL and cannot load the image's FIPS OPENSSL_CONF (Trustway Proteccio).

The vendor library is upgraded independently of the KMS image, no image holds a secret, and the chart's default hardening (UID 1000, read-only root filesystem) is kept. The image ships the C++ runtime (libstdc++.so.6, libgcc_s.so.1) in /usr/local/cosmian/lib/hsm, which is on LD_LIBRARY_PATH. If the vendor library needs other libraries outside glibc, copy them next to it and append that directory to LD_LIBRARY_PATH.

HSM--hsm-modelLibrary path variableVendor configurationGuide
Thales LunalunaLUNA_PKCS11_LIBChrystoki.conf in the directory set by ChrystokiConfigurationPathLuna on Kubernetes
Trustway ProteccioproteccioPROTECCIO_PKCS11_LIB/etc/proteccio (read-only); FIPS image: command overrideProteccio on Kubernetes
Trustway Crypt2paycrypt2payCRYPT2PAY_PKCS11_LIBc2p.xml set by C2P_CONF, in a writable, persistent directoryCrypt2pay on Kubernetes

Database configuration

By default the chart deploys with the sqlite backend, backed by a PersistentVolumeClaim. For production, set the database type and connection string:

# PostgreSQL
helm install my-kms cosmian/cosmian-kms \
  --set kms.database.type=postgresql \
  --set kms.database.url="postgresql://kms:kms@postgres:5432/kms"

# MySQL
helm install my-kms cosmian/cosmian-kms \
  --set kms.database.type=mysql \
  --set kms.database.url="mysql://kms:kms@mysql:3306/kms"

Warning

Never use --set kms.database.clearDatabase=true in production. It wipes the database on every pod restart.

Referencing an existing Secret

To avoid storing database credentials in values.yaml, reference an existing Kubernetes Secret:

helm install my-kms cosmian/cosmian-kms \
  --set kms.database.type=postgresql \
  --set kms.database.existingSecret=my-db-secret

The Secret must contain a database-url key. For redis-findex backends, a redis-master-password key is also expected.

Accessing the web UI

The KMS container serves the bundled web UI on the same port as the KMIP/REST API (default 9998), at the application root and its client-side routes (/login, /sym, /rsa, /certificates, etc.). No separate Service or port is required.

The UI is enabled by default (kms.uiEnabled: true).

Local access via port-forward

kubectl port-forward svc/my-kms-cosmian-kms 9998:9998
# then open http://127.0.0.1:9998

External access

Enable the Ingress or set the Service type to LoadBalancer:

# Ingress
helm install my-kms cosmian/cosmian-kms \
  --set ingress.enabled=true \
  --set ingress.hosts[0].host=kms.example.com \
  --set ingress.hosts[0].paths[0].path=/ \
  --set ingress.hosts[0].paths[0].pathType=Prefix

# LoadBalancer
helm install my-kms cosmian/cosmian-kms \
  --set service.type=LoadBalancer

Tip

If the KMS is reachable at a hostname other than localhost/127.0.0.1, add that origin to kms.corsAllowedOrigins — the browser sends an Origin header on every API request, and the server rejects requests from origins not in the list.

Configuration

See values.yaml for the full list of configurable parameters. Key settings:

KeyDescription
image.repository / image.tagKMS container image; tag defaults to the chart appVersion
kms.database.typesqlite, postgresql, mysql, or redis-findex (non-FIPS only)
kms.database.url / kms.database.existingSecretConnection string or existing Secret for non-sqlite backends
kms.uiEnabledServe the bundled web UI (default true)
kms.tls.enabled / kms.tls.existingSecretTerminate TLS on the KMS listener using a kubernetes.io/tls Secret
kms.corsAllowedOriginsComma-separated CORS allowed origins (required for UI with non-localhost access)
persistence.*PVC settings for the sqlite backend
ingress.*Optional Ingress in front of the Service
autoscaling.*Optional HorizontalPodAutoscaler
podDisruptionBudget.*Optional PodDisruptionBudget
networkPolicy.*Optional NetworkPolicy restricting ingress to the KMS port
resourcesCPU/memory requests and limits
extraEnv / extraEnvFrom / extraArgsEscape hatches for settings not covered by a dedicated value (e.g. --hsm-model)
initContainers / extraVolumes / extraVolumeMountsExtra init containers and volumes (e.g. HSM client runtime and configuration)
commandReplaces the image entrypoint; the chart-built args are passed to it (e.g. Proteccio with the FIPS image)

Every kms.* value maps to a KMS_* environment variable or CLI flag consumed directly by the cosmian_kms binary. See crate/server/src/config/command_line/ in the main repository for the authoritative list.

Upgrading

helm repo update
helm upgrade my-kms cosmian/cosmian-kms \
  --set kms.database.type=postgresql \
  --set kms.database.url="postgresql://kms:kms@postgres:5432/kms"

Uninstalling

helm uninstall my-kms

Uninstalling does not delete the PVC created for the sqlite backend. Delete it manually if the data is no longer needed:

kubectl delete pvc my-kms-cosmian-kms

Implementation notes

  • The chart always passes explicit --database-type / --hostname / --port arguments, because the Docker image's entrypoint script only reads $COSMIAN_KMS_CONF or environment-only configuration when invoked with zero arguments.
  • The container runs as the image's built-in kms user (uid/gid 1000); this is pinned explicitly via podSecurityContext.runAsUser/runAsGroup because the image has no USER directive of its own (it defaults to root), which Kubernetes rejects when runAsNonRoot: true is set without a matching UID.
  • KMS_ROOT_DATA_PATH is pinned to a dedicated emptyDir volume (/var/lib/cosmian-kms/workspace). Its server-side default is a relative path resolved against $HOME, which is not writable for the container's non-root user.

How the Helm chart is published

On every KMS release tag (v*), a GitHub Actions workflow packages the chart with helm/chart-releaser-action and pushes it to a GitHub Pages–hosted Helm repository at https://cosmian.github.io/kms. No manual action is required.