Skip to content

Install sluis with Helm

Install oci://ghcr.io/truvity/charts/sluis and sign in. One Deployment runs, configured by two documents from sluisctl render. To move from the previous chart, see its migration.

Before you start

Needed For Notes
Kubernetes the pod recovery sign-in asks this cluster's API server to review a ServiceAccount token
AWS: DynamoDB table, S3 bucket, KMS key state, blobs, signing preset k8s-aws; k8s-minimal and k8s-openbao are unavailable (adapters)
a pod identity for the AWS role the above EKS Pod Identity, or serviceAccount.awsIdentity: irsa with awsRoleArn
SSM parameters or OpenBao OAuth client, state secret, client secrets layout in secrets
Gateway API and a GatewayClass controller the route without route.host no route renders: port-forward for a trial
cert-manager and a ClusterIssuer the Gateway's TLS certificate KMS signing renders no signing Certificate
a Google Workspace and an OAuth client sign-in and the directory Google Workspace
sluisctl, helm, kubectl rendering and installing
an audit installation the audit trail, optional without audit.writer records stay in the log line
  • Never edit the rendered documents: the chart does not re-validate them.

  • release in the installation must equal the Helm release name, or the render fails.

  • Seed every Secret before the pod starts. A missing name stops the start.

1. Write the installation and render it

# installation.yaml
apiVersion: sluis.truvity.github.io/installation/v1
instance: example                 # the SSM root is /sluis/example
shape: kubernetes
preset: k8s-aws
release: sluis                    # the Helm release name
issuer:
  url: https://access.example.com # stable for the life of the installation
aws: {region: eu-west-1, bucket: sluis-blobs}
adapters:
  state: {adapter: dynamodb, settings: {region: eu-west-1, tables: {oidc: sluis-example-oidc, github: sluis-example-github, slack: sluis-example-slack, google: sluis-example-google, cloudflare: sluis-example-cloudflare, backup: sluis-example-backup}}}
signingKey:
  kmsWrapped: {keyId: alias/sluis-example-sign}
recovery: {enabled: true, serviceAccount: sluis-recovery, audience: sluis-recovery}
console: {client: access-console}
oauthClient: {provider: default}
access:
  groups:
    all:sluis:operator:
      members: [[email protected]]
      matchers:
        - service_account: {namespace: sluis, name: sluis-recovery}   # how the first operator gets in
    all:sluis:viewer:
      matchers: [{email_domain: example.com}]
  clients:
    access-console:
      kind: public
      display_name: sluis
      redirects: [https://access.example.com/console/]
      requires: [all:sluis:operator, all:sluis:viewer]
sluisctl render --installation installation.yaml --out rendered/

The render writes rendered/sluis.yaml and rendered/policy.yaml (installation keys, policy keys). Commit both and run --check in CI: it exits 1 with a diff when one is stale.

2. Create the namespace and seed the secrets

kubectl create namespace sluis
# each value is a {"value":"<base64>"} document at the oidc module's address
put() { aws ssm put-parameter --type SecureString --name "/sluis/example/internal/oidc/$1" \
  --value "{\"value\":\"$(printf %s "$2" | base64 | tr -d '\n')\"}"; }
put signin/default/client-id     '<google client id>'
put signin/default/client-secret '<google client secret>'
put state-secret                 "$(openssl rand -base64 32)"
put clients/<client-id>          '<random>'   # one per confidential client in the policy
# list the names, never the values
aws ssm get-parameters-by-path --path /sluis/example/internal/oidc/ --recursive --query 'Parameters[].Name'

3. Write the deployment values

Put only deployment-level keys in values.yaml. The chart refuses config, policy and the exchange lists beside the documents. The chart README lists the keys.

route:
  host: access.example.com
  rootRedirect: /console/
  gatewayClassName: example-gateway-class   # a GatewayClass your controller serves
  certificate: {issuerName: example-ca, issuerKind: ClusterIssuer}
serviceAccount:
  awsIdentity: pod-identity                  # or irsa, with awsRoleArn
replicaCount: 2

4. Preview, then install

helm template sluis oci://ghcr.io/truvity/charts/sluis --version X.Y.Z --namespace sluis \
  -f values.yaml --set-file documents.service=rendered/sluis.yaml --set-file documents.policy=rendered/policy.yaml

Read the output, then run the same arguments with helm install. Check kubectl -n sluis rollout status deploy/sluis and that curl -s https://access.example.com/.well-known/openid-configuration returns the issuer's URL. To roll back, run helm uninstall sluis -n sluis. The SSM parameters and DynamoDB state stay.

5. First sign-in

kubectl -n sluis create token sluis-recovery --audience sluis-recovery --duration 10m

Open https://access.example.com/login, expand Recovery sign-in and paste the token. Finish as in day one. The OAuth client needs the redirect URIs https://access.example.com/connect/google/callback and https://access.example.com/login/google/callback.

Once the directory works, set recovery.enabled: false, render and upgrade. To act in GitHub or Slack, set controllers.github and controllers.slack, then list targets in enabledOrgs or enabledWorkspaces. Connect a cluster next.

Afterwards

Keep the installation, rendered documents and values.yaml in your repository. To take a release, render and compare the old and new chart. Only the image tag and version labels should move; read other changes in the CHANGELOG. Then helm upgrade.

for v in OLD NEW; do helm template sluis oci://ghcr.io/truvity/charts/sluis --version $v --namespace sluis \
  -f values.yaml --set-file documents.service=rendered/sluis.yaml --set-file documents.policy=rendered/policy.yaml > $v.yaml; done
diff -u OLD.yaml NEW.yaml

Back up what the console adds (back up and restore) and enable point-in-time recovery on the DynamoDB table.

Decided in

ADR 0037, ADR 0038.