> ## Documentation Index
> Fetch the complete documentation index at: https://keyring.docs.composio.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Deploy on Kubernetes

> Install the Node image with Helm, Kubernetes Secrets, probes, and hardened pod defaults.

The chart at `deploy/helm/keyring` deploys the bundled Node server behind a ClusterIP Service. It includes liveness, readiness, and startup probes plus hardened pod and container security contexts.

## 1. Create the encryption configuration Secret

Create a complete `config.yaml` from the [encryption configuration reference](/configuration/encryption), then store it as a Kubernetes Secret:

```bash theme={"theme":{"light":"github-light","dark":"github-dark"}}
kubectl create namespace keyring
kubectl --namespace keyring create secret generic keyring-encryption-config \
  --from-file=config.yaml=./config.yaml
```

Kubernetes Secrets are not encrypted in etcd by default. Enable encryption at rest, restrict Secret RBAC, and consider an external secrets controller or CSI provider for your environment.

## 2. Create production values

```yaml values.production.yaml theme={"theme":{"light":"github-light","dark":"github-dark"}}
image:
  repository: composiohq/keyring
  tag: alpha

runtime:
  appEnv: production
  authAudience: <COMPOSIO_ORG_ID>
  authIssuer: https://backend.composio.dev
  authJwtAlgorithms: RS256
  authJwksUrl: https://backend.composio.dev/.well-known/jwks.json
  otelCollectorUrl: https://otel-collector.observability.svc.cluster.local:4318
  auditDurability: required
  encryptionConfigFile:
    enabled: true
    secret: keyring-encryption-config
    key: config.yaml

extraEnv:
  - name: LOG_LEVEL
    value: info
  - name: OTEL_COLLECTOR_HEADERS
    valueFrom:
      secretKeyRef:
        name: keyring-otel-auth
        key: headers

ingress:
  enabled: true
  className: nginx
  hosts:
    - host: keyring.example.com
      paths:
        - path: /
          pathType: Prefix
  tls:
    - secretName: keyring-tls
      hosts:
        - keyring.example.com
```

`runtime.encryptionConfigFile` mounts the selected Secret key read-only at `/etc/keyring/config.yaml` and sets `ENCRYPTION_CONFIG` to that path.

Deploy a collector in the same pod or behind a private service by following the
[telemetry delivery guide](/deployment/observability). Keep `auditDurability: required` in production.

## 3. Install or upgrade

```bash theme={"theme":{"light":"github-light","dark":"github-dark"}}
helm lint deploy/helm/keyring
helm template keyring deploy/helm/keyring --namespace keyring -f values.production.yaml
helm upgrade --install keyring deploy/helm/keyring \
  --namespace keyring \
  --create-namespace \
  --values values.production.yaml \
  --wait
```

Review the rendered Deployment, ServiceAccount, Service, and Ingress before applying them.

## 4. Verify rollout and health

```bash theme={"theme":{"light":"github-light","dark":"github-dark"}}
kubectl --namespace keyring rollout status deployment/keyring
kubectl --namespace keyring get pods,service,ingress
kubectl --namespace keyring port-forward service/keyring 7464:80
```

In another terminal:

```bash theme={"theme":{"light":"github-light","dark":"github-dark"}}
curl --fail http://127.0.0.1:7464/healthz
curl --fail http://127.0.0.1:7464/transfer-keys
```

## Workload identity notes

<Tabs>
  <Tab title="AWS EKS">
    Use EKS Pod Identity and set AWS adapters to `credential_source: runtime_environment`. Associate
    the chart's ServiceAccount with a role that trusts `pods.eks.amazonaws.com` and grants only the
    required KMS actions. The chart may keep `serviceAccount.automount: false`; Pod Identity injects
    its own projected token.
  </Tab>

  <Tab title="GKE">
    Use the GCP `metadata` auth method with Workload Identity and grant the Kubernetes principal
    access to the configured Cloud KMS keys. Avoid service-account JSON keys when metadata identity
    is available.
  </Tab>

  <Tab title="Vault">
    Use Vault Kubernetes auth with a narrowly scoped role. Unlike EKS Pod Identity, this method
    needs a service-account JWT at the configured `token_path`; set `serviceAccount.automount: true`
    or mount a projected token explicitly.
  </Tab>
</Tabs>

## Default security posture

The chart runs as UID/GID 10001, drops all capabilities, denies privilege escalation, uses a read-only root filesystem, applies `RuntimeDefault` seccomp, and creates two replicas. Add a namespace-level default-deny NetworkPolicy and allow inbound traffic only from the Composio-facing ingress, with the [Composio egress IP allowlist](/deployment/overview#network-access) enforced at that edge.
