The installation document¶
One installation, written once, from which both documents are rendered (ADR 0038): apiVersion: sluis.truvity.github.io/installation/v1, held to schemas/config/installation.schema.json. It holds no secret.
sluisctl render --installation <file> --out <dir> writes sluis.yaml and policy.yaml (sluisctl). --check exits 1 when the files differ. The Pulumi library takes it as LambdaArgs.Installation. Go programs call config.Render from github.com/truvity/sluis/config.
It is a superset of the service and policy documents: each section sits under its document's key with that document's schema.
| Key | What it is |
|---|---|
instance, shape |
the installation's name (its SSM root is /sluis/<instance>) and where it runs: lambda, kubernetes or server. Required. |
preset, release, cluster, policyFile |
the service document's own keys. preset follows the shape when unset: aws-hybrid for lambda, k8s-aws for kubernetes with aws. The other defaults, k8s-openbao (with openbao), k8s-minimal and server, are unavailable: loading one fails naming the missing adapters (adapters). policyFile follows the shape too (lambda: /opt/sluis/policy.yaml, in the layer; kubernetes: /var/run/access-issuer/policy/policy.yaml, where the chart mounts it; server: /etc/sluis/policy.yaml). |
issuer |
url (required), consoleURL (default <url>/console), rootURL, secureCookies, groupsScoping. |
log, lifetimes, freshness, hsts, secrets, keys, signingKey, recovery, conformance, login, console, oauthClient, valkey, directory, audit |
the service document's, unchanged. For a KMS signer the state secret is named issuer/state-secret when left out. |
aws |
account, region (required for lambda), functionName, functions (the functions' names by module, issuer, github, slack, google, cloudflare or backup; default sluis-<instance>-<module>; used by RenderModules, which writes a document for each function and has the issuer's call them), and the resources bucket, auditQueueURL, each becoming the setting of the adapter that uses it (blobs: s3, audit: sqs). The DynamoDB tables are adapters.state settings (tables, one per module); on lambda the library writes them. |
openbao |
the openbao secrets adapter's settings (address, caFile, mount, namespace, root, auth); it chooses that adapter for secrets. |
adapters |
names single concerns, over what the preset and the resources above give. |
cloudflare |
the accounts and presets for the service document's cloudflare, and grants for the policy document's. |
exchange |
audience (the service document's) and the policy document's clusters, aws and github.owners. |
apps |
the policy document's, unchanged. |
controllers |
github and slack, each present when the controller is on: its own keys go to the service document's controllers, enabledOrgs and enabledWorkspaces to the policy document's. |
access |
the access model's tables (groups, clients, resources, github, slack, ...), the policy document's, unchanged. config.FromAccess builds it. |
For shape lambda the renderer writes what the library owns (secrets as ssm with the instance's root, region and layout: v5, recovery.verifierSecret, the invoke trigger's function) and refuses a different value. A named adapter replaces what a resource stands for. The output is deterministic and held to the service's loader. Start checks adapter platform answers and OpenBao reachability.
Write one¶
config.MarshalInstallation(in, MarshalOptions{Header}) writes the canonical document; config.CheckInstallation(existing, in, opts) reports whether existing is that document. When it is not, it returns a line diff, for a --check mode.
apiVersion comes first and the other keys are sorted. Durations are 1h or 15m, never 1h0m0s. Unset fields and empty lists are left out. A set but empty section is kept, as controllers.github: {} is a controller that is on. Header is a comment block. An installation the loader would refuse is not written.