config

package
v1.76.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 12, 2026 License: MIT Imports: 31 Imported by: 0

Documentation

Overview

Package config is what each process of this repository is configured with: four documents, each read from one file and validated against a JSON Schema before anything starts.

  • three service documents, one per process: `serve`, `controller-github` and `controller-slack`, saying how the process runs: listeners, storage, signing, lifetimes;
  • one policy document, `policy`, saying what the installation decides: the access model's tables, whom the token exchange trusts, which Apps an operator may make, what each controller may change, and what is copied out. Every service document names it (`policy.file`).

Each document carries `apiVersion`. This build writes v2 and reads v2 and v1: a v1 document (one with no apiVersion) is converted as it is loaded, so a deployment moves on its own schedule. Configuration and policy are immutable for an instance: a change is a new instance (a rollout on Kubernetes, a new configuration layer on Lambda). What stays live is credentials and state.

Layering happens only when a policy is rendered (`sluisctl policy render`, Render); a process loads exactly one policy document.

Secrets are never in a document. Telemetry is not here at all; it is OpenTelemetry's own environment (OTEL_*).

The types are written by hand and the schemas are generated from schema/ into schemas/config/, which is committed; a test holds the two files to one another, and a second holds each type to its schema. The decision is docs/decisions/0032-one-configuration-file-one-binary-one-chart.md and, for the shared rules, truvity/policy 0002 and 0006.

Index

Constants

View Source
const (
	// BackupRoleBackup is the scheduled export, the default.
	BackupRoleBackup = "backup"
	// BackupRoleRestore is the restore function, which only an administrator or
	// the break-glass role may invoke.
	BackupRoleRestore = "restore"
)

The roles of the backup module's zip. The binary is one; the document picks the function it is deployed as (docs/decisions/0072, point 10).

View Source
const (
	BackupDefaultKeep   = 7
	BackupDefaultMaxAge = 30 * 24 * time.Hour
	// BackupMaxKeep bounds Keep: a rule of thousands is a typo.
	BackupMaxKeep = 1000
)

The retention defaults.

View Source
const (
	// CloudflareMinLifetime is the shortest lifetime and rotation: the tick
	// is a minute at best on Lambda.
	CloudflareMinLifetime = time.Minute
	// CloudflareMaxLifetime is the longest a minted token lives. A short-lived
	// credential that outlives a day is a long-lived one under another name.
	CloudflareMaxLifetime = 24 * time.Hour
)

The limits of a preset's two settings.

View Source
const (
	AWSAlgES384 = "ES384"
	AWSAlgRS256 = "RS256"
	// MaxAWSMaxAge is the longest exchange.aws.maxAge may be: AWS lets a
	// token live an hour.
	MaxAWSMaxAge = time.Hour
)

The algorithms an AWS account's outbound identity tokens are signed with.

View Source
const (
	// SecretRecoveryPassword is the password of the recovery sign-in.
	SecretRecoveryPassword = "recovery-password"
	// SecretStateSecret is the sign-in state's secret of a KMS-signed issuer.
	SecretStateSecret = "state-secret"
	// SecretSignInClientID is the Google sign-in client's id.
	SecretSignInClientID = "signin-client-id"
	// SecretSignInClientSecret is the Google sign-in client's secret.
	SecretSignInClientSecret = "signin-client-secret"
	// SecretClient is a seeded confidential client's secret.
	SecretClient = "client-secret"
	// SecretWorkspaceKey is a declared workspace's service-account key.
	SecretWorkspaceKey = "workspace-key"
	// SecretMinter is a Cloudflare account's minter credential.
	SecretMinter = "cloudflare-minter"
	// SecretBlobCredentials is the S3-compatible blob store's credential document.
	SecretBlobCredentials = "blob-credentials"
)

The kinds of a DeclaredSecret.

View Source
const (
	SecretsLayoutV4 = "v4"
	SecretsLayoutV5 = "v5"
)

The values of Secrets.Layout.

View Source
const BackupAPIVersion = Group + "/sluis-backup/v1"

BackupAPIVersion is the apiVersion of the backup module's document.

View Source
const BackupDefaultIdentity = "restore-identity"

BackupDefaultIdentity is the restore identity's secret when backup.identity names none.

View Source
const EnvConfig = "SLUIS_CONFIG"

EnvConfig is the variable that names the service document when no --config is given.

View Source
const GoogleAPIVersion = Group + "/sluis-google/v1"

GoogleAPIVersion is the apiVersion of the Google module's document.

View Source
const Group = "sluis.truvity.github.io"

Group is the group of this repository's document kinds: an apiVersion is `sluis.truvity.github.io/<document>/v<N>`.

Variables

View Source
var (
	// CloudflareNamePattern is the name of a preset or an account: a DNS label.
	CloudflareNamePattern = regexp.MustCompile(`^[a-z0-9]([a-z0-9-]{0,30}[a-z0-9])?$`)
)

Functions

func APIVersion added in v1.62.0

func APIVersion(document string) string

APIVersion is the apiVersion this build writes for one document: `sluis` (v3), `sluis-backup` and `sluis-google` (v1), or `serve`, `controller-github`, `controller-slack` or `policy` (v2).

func CheckCloudflare added in v1.74.0

func CheckCloudflare(cf *Cloudflare, p *PolicyDocument) error

CheckCloudflare holds the policy's grants to the service document's presets: a grant for a preset that does not exist would read as a right nobody can use.

func CheckCloudflareMinterRef added in v1.74.0

func CheckCloudflareMinterRef(ref string) error

CheckCloudflareMinterRef refuses a minter address that is not below internal/.

func Command

func Command(command, schema string, args []string, out io.Writer) (file string, done bool, err error)

Command reads one subcommand's command line, which is `--config <file>` and nothing else but `--version` and `--help`; with no --config, SLUIS_CONFIG names the file. command is what the person typed to get here ("sluis serve"), and schema names the document it reads: schemas/config/<schema>.schema.json. A flag that overrides a key, or stands in for one, is a second source of truth: the service document, and the policy document it names, are the whole of the configuration.

It returns the file to read. done is true when the command line asked for something answered here (the version, the help) and the process should stop without error.

func IsBackup added in v1.75.0

func IsBackup(file string) bool

IsBackup reports whether the file is the backup module's document, by its apiVersion alone.

func IsGoogle added in v1.76.0

func IsGoogle(file string) bool

IsGoogle reports whether the file is the Google module's document, by its apiVersion alone.

func IsSluis added in v1.63.0

func IsSluis(file string) bool

IsSluis reports whether the file is the one service document (v3), by its apiVersion alone. A file that cannot be read is not: the loader reports it.

func Load added in v1.62.0

func Load[T Document](file string) (*T, error)

Load reads one document from a file, holds it to its schema and decodes it, through truvity/policy's versioned loader (config.LoadKind): a binary reads its documents' version N and N-1.

A v2 document is validated and decoded as it stands, after a key v2 retired is refused with a message saying where it went. A v1 document (no apiVersion) is held to the v1 schema it was written against and converted: what v1 kept in a service document and v2 keeps in the policy document is remembered, and PolicyOf reads it from the files v1 named.

func RefuseRetired

func RefuseRetired(binary string, environ []string) error

RefuseRetired is the start-up check: it fails when the environment still holds a variable the subcommand no longer reads, naming each with what replaces it. environ is os.Environ's shape.

func Retired

func Retired(binary string) map[string]string

Retired returns, for one binary, every retired variable and what replaces it. The documentation's migration table is this, and a test holds them together.

func RetiredKeys added in v1.62.0

func RetiredKeys(document string) map[string]string

RetiredKeys returns, for one document, every key v2 retired and where it went.

func Validate

func Validate(name string, doc any) error

Validate checks a decoded v2 document against its schema. The chart's tests call it on what the chart renders, which is what stops the two drifting.

Types

type AWSAccount added in v1.62.0

type AWSAccount struct {
	Account string   `yaml:"account"`
	Name    string   `yaml:"name"`
	Issuer  string   `yaml:"issuer"`
	JWKSURI string   `yaml:"jwksUri,omitempty"`
	OrgID   string   `yaml:"orgId,omitempty"`
	Algs    []string `yaml:"algs,omitempty"`
}

AWSAccount is one account's row.

type AWSFederation added in v1.62.0

type AWSFederation struct {
	// Audience the role must request from sts:GetWebIdentityToken.
	// Required whenever an account is listed: it is the trust boundary.
	Audience string `yaml:"audience,omitempty"`
	// MaxAge refuses a token whose `iat` is older. Default 5m, at most 1h.
	MaxAge *Duration `yaml:"maxAge,omitempty"`
	// Accounts are the trusted accounts.
	Accounts []AWSAccount `yaml:"accounts,omitempty"`
}

AWSFederation is the AWS accounts whose roles may exchange their outbound identity federation token.

type AdapterChoice added in v1.58.0

type AdapterChoice struct {
	Adapter  string         `json:"adapter"`
	Settings map[string]any `json:"settings,omitempty"`
}

AdapterChoice names the adapter of one concern and its settings.

type Address

type Address struct {
	Address string `json:"address"`
}

Address is a TCP listener: host:port, an empty host binding every interface. It is the shared shape of truvity/policy's fragments/listen.json and probes.json.

type AgentLifetimes added in v1.69.0

type AgentLifetimes struct {
	Refresh  *Duration `json:"refresh,omitempty"`
	Absolute *Duration `json:"absolute,omitempty"`
	Access   *Duration `json:"access,omitempty"`
}

AgentLifetimes are the agent class's own lifetimes (docs/decisions/0040-agent-class-sessions.md): its idle limit, its absolute limit from `auth_time`, and the mandatory cap on its access and ID tokens. A pointer is "not set", which is the default.

type AppsGitHub added in v1.62.0

type AppsGitHub struct {
	// Apps is every GitHub App the installation declares, of every purpose:
	// the link App, the catalogue Apps an operator creates and installs from
	// the console, and the runner tiers an operator may create an App for.
	Apps []GitHubApp `yaml:"apps,omitempty"`
	// RunnerTiers is DEPRECATED, read for one release: each tier is a
	// runner entry of Apps.
	RunnerTiers []string `yaml:"runnerTiers,omitempty"`
	// Catalogue is DEPRECATED, read for one release: each App is a catalogue
	// entry of Apps.
	Catalogue []catalogue.App `yaml:"catalogue,omitempty"`
	// contains filtered or unexported fields
}

AppsGitHub is the GitHub Apps an operator may make.

type AppsSlack added in v1.62.0

type AppsSlack struct {
	// Catalogue is every catalogue Slack App.
	Catalogue []slackcatalogue.App `yaml:"catalogue,omitempty"`
}

AppsSlack is the Slack Apps an operator may make.

type Audit

type Audit struct {
	Writer                  string `json:"writer,omitempty"`
	TokenFile               string `json:"tokenFile,omitempty"`
	QueryURL                string `json:"queryURL,omitempty"`
	Audience                string `json:"audience,omitempty"`
	ForwardedForTrustedHops int    `json:"forwardedForTrustedHops,omitempty"`
}

Audit is the audit installation this process records to.

type Backup added in v1.75.0

type Backup struct {
	// Role is [BackupRoleBackup] (the default) or [BackupRoleRestore].
	Role string `json:"role,omitempty"`
	// Recipients are the age X25519 public keys (age1...) every backup is
	// encrypted to. The backup role requires at least one.
	Recipients []string `json:"recipients,omitempty"`
	// Identity names the restore role's secret that holds the age identity
	// (AGE-SECRET-KEY-1...): internal/backup/<identity> in the secret store,
	// [BackupDefaultIdentity] when unset.
	Identity string `json:"identity,omitempty"`
	// Key and Region were the KMS archive key of format 1. Deprecated: they
	// are accepted for one release and ignored.
	Key    *keys.Entry `json:"key,omitempty"`
	Region string      `json:"region,omitempty"`
	// Target is the bucket the archive is written to.
	Target BackupTarget `json:"target"`
	// Retention is how many backups are kept and for how long.
	Retention *BackupRetention `json:"retention,omitempty"`
}

Backup is `backup`.

type BackupRetention added in v1.75.0

type BackupRetention struct {
	// Keep is how many of the newest completed backups are always kept.
	Keep *int `json:"keep,omitempty"`
	// MaxAge is how old a backup beyond Keep may be before it is deleted.
	MaxAge *Duration `json:"maxAge,omitempty"`
}

BackupRetention is the retention rule of Backup.Retention.

func (*BackupRetention) Rule added in v1.75.0

func (r *BackupRetention) Rule() (keep int, maxAge time.Duration)

Rule is the retention in force: the defaults fill what is unset.

type BackupTarget added in v1.75.0

type BackupTarget struct {
	Bucket string `json:"bucket"`
	// Prefix is put before `backup/<installation>/` in the bucket.
	Prefix string `json:"prefix,omitempty"`
	Region string `json:"region,omitempty"`
	// KMSKey is the SSE-KMS key of every write; unset leaves the bucket's own
	// default encryption.
	KMSKey    string `json:"kmsKey,omitempty"`
	Endpoint  string `json:"endpoint,omitempty"`
	PathStyle bool   `json:"pathStyle,omitempty"`
	// Checksum is the integrity header of every upload: sha256 (the default),
	// md5 (Content-MD5) or none, for a store that refuses SHA-256.
	Checksum string `json:"checksum,omitempty"`
}

BackupTarget is the S3 (or S3-compatible) bucket of the archive. Credentials are the platform's: the function's role.

type Cloudflare added in v1.74.0

type Cloudflare struct {
	// Accounts are the Cloudflare accounts sluis mints in, by the name presets
	// use.
	Accounts map[string]CloudflareAccount `json:"accounts,omitempty"`
	// Presets are what may be minted, by name.
	Presets map[string]CloudflarePreset `json:"presets,omitempty"`
	// ForbiddenPermissionGroups ADD to the built-in list of permission groups
	// a prototype may never grant (token admin, billing, account settings,
	// memberships, Access identity providers), by the name Cloudflare lists
	// them under. They cannot remove from it: nothing in a document shortens
	// the built-in list.
	ForbiddenPermissionGroups []string `json:"forbiddenPermissionGroups,omitempty"`
	// Tick is how often the rotation looks at the presets: the schedule's
	// interval on Lambda (the library fills it from CloudflareRotation when it
	// is unset), a minute for the Kubernetes loop. A credential rotates up to
	// one Tick after its preset's `rotation`, so the console calls one overdue
	// only past `rotation + tick`. Zero means a minute.
	Tick Duration `json:"tick,omitempty"`
	// Remote is where the minter is when it is not this process: the on-demand
	// exchange then calls the Cloudflare module there, and this process holds no
	// account and no preset.
	Remote *CloudflareRemote `json:"remote,omitempty"`
	// Serve makes the Cloudflare module answer other modules' calls: on
	// Kubernetes a listener that verifies the caller's projected token, on
	// Lambda the function's `rpc` events (docs/decisions/0071).
	Serve *CloudflareServe `json:"serve,omitempty"`
}

Cloudflare is `cloudflare`: sluis as the STS for Cloudflare API tokens and R2 credentials (docs/guides/sluis/cloudflare-tokens.md). An account names the minter credential sluis holds; a preset names a disabled prototype token in that account whose policies and condition are the rights a minted token has.

func (*Cloudflare) AccountNames added in v1.74.0

func (c *Cloudflare) AccountNames() []string

AccountNames are the accounts' names, sorted.

func (*Cloudflare) PresetNames added in v1.74.0

func (c *Cloudflare) PresetNames() []string

PresetNames are the presets' names, sorted.

func (*Cloudflare) PresetOf added in v1.74.0

func (c *Cloudflare) PresetOf(name string) (CloudflarePreset, bool)

PresetOf is a preset by name. A nil section has none.

func (*Cloudflare) Validate added in v1.74.0

func (c *Cloudflare) Validate() error

Validate holds the section to what its schema cannot say. A nil section is valid: Cloudflare is off.

type CloudflareAccount added in v1.74.0

type CloudflareAccount struct {
	// ID is the account id.
	ID string `json:"id"`
	// Minter is the internal address of the minter credential, a
	// cloudflare-minter/v1 document: an account token that holds Account API
	// Tokens Read and Edit and nothing else.
	Minter string `json:"minter"`
}

CloudflareAccount is one Cloudflare account.

type CloudflareGrant added in v1.74.0

type CloudflareGrant struct {
	// Group is an internal group of the policy (a person group, or a declared CI
	// job group); every holder may ask.
	Group string `yaml:"group,omitempty" json:"group,omitempty"`
	// Presets are the presets the row opens.
	Presets []string `yaml:"presets" json:"presets"`
}

CloudflareGrant is one row of grants.

type CloudflarePreset added in v1.74.0

type CloudflarePreset struct {
	// Account is a key of Accounts.
	Account string `json:"account"`
	// Prototype is the id of the DISABLED account token whose policies and
	// condition every minted token copies.
	Prototype string `json:"prototype"`
	// Description says what the preset is for; the console and sluisctl show it.
	Description string `json:"description"`
	// Lifetime is how long a minted token lives (its expires_on).
	Lifetime Duration `json:"lifetime"`
	// Rotation is how often the stored token is replaced. Shorter than Lifetime.
	Rotation Duration `json:"rotation"`
	// Endpoint, when set, makes this an R2 preset: the S3 endpoint of the
	// account (and jurisdiction) the credentials are for.
	Endpoint string `json:"endpoint,omitempty"`
}

CloudflarePreset is one thing sluis mints.

func (CloudflarePreset) R2 added in v1.74.0

func (p CloudflarePreset) R2() bool

R2 reports whether the preset hands out R2 (S3) credentials.

type CloudflareRemote added in v1.75.0

type CloudflareRemote struct {
	// Function is the module's Lambda function, name or ARN; it is invoked
	// through its `live-issuer` alias.
	Function string `json:"function,omitempty"`
	// URL is the module's Service, called with the pod's projected token.
	URL string `json:"url,omitempty"`
	// Audience is the audience of that token; the module's name when unset.
	Audience string `json:"audience,omitempty"`
	// TokenFile is where the projected token is mounted.
	TokenFile string `json:"tokenFile,omitempty"`
}

CloudflareRemote is the Cloudflare module in another process: a Lambda function or a Kubernetes Service (docs/decisions/0071).

func (*CloudflareRemote) Target added in v1.76.0

func (r *CloudflareRemote) Target() ModuleRemote

Target is the Cloudflare module's remote as a ModuleRemote.

type CloudflareServe added in v1.75.0

type CloudflareServe struct {
	// Address is the listener on Kubernetes: host:port. Lambda ignores it.
	Address string `json:"address,omitempty"`
	// Audience is the audience a caller's projected token must have been
	// minted for; the module's name when unset.
	Audience string `json:"audience,omitempty"`
	// Issuers are the subjects of the issuer's ServiceAccount
	// (`system:serviceaccount:<namespace>:<name>`) that may call the listener
	// on Kubernetes; each is both the issuer class (the mint) and the console
	// class. Required by the listener; Lambda ignores it.
	Issuers []string `json:"issuers,omitempty"`
}

CloudflareServe is where the Cloudflare module answers other modules.

type Config added in v1.62.0

type Config[S Service] struct {
	Service *S
	// Policy is nil when the service document names none and no fallback was
	// given.
	Policy *PolicyDocument
}

Config is one process's whole configuration, by section: the service document it was started with and the policy document that names. Nothing is overlaid: each section is one document.

func LoadConfig added in v1.62.0

func LoadConfig[S Service](file string, fallback *policy.Policy) (Config[S], error)

LoadConfig reads a process's service document and the policy document it names. fallback is the access model's tables a process decides by when the document names no policy (the service's built-in two groups); nil leaves the policy nil.

type Console

type Console struct {
	Origin string `json:"origin,omitempty"`
	Client string `json:"client,omitempty"`
	// AWSAudience is the audience an AWS role's web identity token must be
	// minted for to be a bearer at the console: its OWN, distinct from
	// `exchange`'s, so a token for one door is no proof at the other.
	AWSAudience string `json:"awsAudience,omitempty"`
	// Backup connects the console's Backups page to the backup module and
	// the restore function (docs/decisions/0071). Unset has no page.
	Backup *ConsoleBackup `json:"backup,omitempty"`
}

Console is where the console is published, for the sign-in that starts there.

type ConsoleBackup added in v1.75.0

type ConsoleBackup struct {
	// Function and URL name the backup module: exactly one of the two.
	Function string `json:"function,omitempty"`
	URL      string `json:"url,omitempty"`
	// RestoreFunction and RestoreURL name the restore function: at most one
	// of the two. Without either the page says there is none.
	RestoreFunction string `json:"restoreFunction,omitempty"`
	RestoreURL      string `json:"restoreURL,omitempty"`
	// Audience is the audience of the projected token a Service call
	// carries; each module's name when unset.
	Audience string `json:"audience,omitempty"`
	// TokenFile is where that token is mounted.
	TokenFile string `json:"tokenFile,omitempty"`
}

ConsoleBackup is where the backup module and the restore function are when the console calls them as the caller class `console`: a Lambda function (through its `live-console` alias) or a Kubernetes Service each. The console only reads from them.

func (*ConsoleBackup) Validate added in v1.75.0

func (b *ConsoleBackup) Validate() error

Validate holds `console.backup` to what its schema cannot say. A nil section is valid: the console has no Backups page.

type ControllerCommon added in v1.63.0

type ControllerCommon struct {
	// ConsoleURL is the console's API. Unset is the document's `publicURL`.
	ConsoleURL string `json:"consoleURL,omitempty"`
	TokenFile  string `json:"tokenFile,omitempty"`
	// Console says how the controller proves itself to the console when the
	// pod's token file is not the way (AWS Lambda).
	Console    *RosterConsole `json:"console,omitempty"`
	RecordsDir string         `json:"recordsDir,omitempty"`
	Interval   *Duration      `json:"interval,omitempty"`
}

ControllerCommon is what both controllers' sections share.

type ControllerGitHub

type ControllerGitHub struct {
	Roster
	AppsDir string `json:"appsDir,omitempty"`
}

ControllerGitHub is the configuration of `sluis controller github`.

type ControllerSlack

type ControllerSlack struct {
	Roster
	CredentialsDir string `json:"credentialsDir,omitempty"`
}

ControllerSlack is the configuration of `sluis controller slack`.

type Controllers added in v1.63.0

type Controllers struct {
	GitHub *GitHubController `json:"github,omitempty"`
	Slack  *SlackController  `json:"slack,omitempty"`
}

Controllers are the controllers the one process runs. A nil one is off.

type ControllersGitHub added in v1.62.0

type ControllersGitHub struct {
	// EnabledOrgs are the organisations it changes. Each must be bound
	// by the policy's github table.
	EnabledOrgs []string `yaml:"enabledOrgs,omitempty"`
	// AppRefs names, by organisation, the catalogue App whose key the
	// organisation's record refers to (`app_ref`). Optional: a record that
	// already names an App keeps it, and an entry overrides it or declares
	// an organisation anew.
	AppRefs map[string]string `yaml:"appRefs,omitempty"`
	// AppNames names, by organisation, the App this service creates for
	// it when an operator connects it (the organisation App's name on
	// GitHub). Optional: an organisation with no entry is created as
	// <org>-access-roster. GitHub's limit is 34 characters.
	AppNames map[string]string `yaml:"appNames,omitempty"`
}

ControllersGitHub is what the GitHub controller may change.

type ControllersSlack added in v1.62.0

type ControllersSlack struct {
	// EnabledWorkspaces are the workspaces it changes, by the policy's
	// key. Each must be declared by the policy's slack table.
	EnabledWorkspaces []string `yaml:"enabledWorkspaces,omitempty"`
}

ControllersSlack is what the Slack controller may change.

type DeclaredSecret added in v1.75.0

type DeclaredSecret struct {
	// Kind is one of the Secret* constants.
	Kind string
	// Subject is what the secret belongs to: a Google provider, a client id, a
	// workspace id, a Cloudflare account; empty when there is one of the kind.
	Subject string
	// Name is where layout v4 keeps it. For a Ref it is the internal address
	// (`internal/<module>/<name>`) the document gives, the same in every
	// layout; otherwise it is the secret's name below `internal/config/`.
	Name string
	// Ref says Name is an address and not a name.
	Ref bool
}

DeclaredSecret is one secret a service document and its policy declare, and the installation must therefore hold: it is read at the first request that needs it, so a missing or mistyped one is found by a check at deploy time or by a person at the first sign-in.

Only what a document DECLARES is here. What sluis creates at run time (the console's session key, a GitHub or Slack App's credential, which the console writes when an operator makes the App) is not: no document names it before it exists.

func DeclaredSecrets added in v1.75.0

func DeclaredSecrets(doc *Serve, pol *PolicyDocument) []DeclaredSecret

DeclaredSecrets is the set of secrets doc and pol declare, sorted by kind, subject and name, without repeats. pol may be nil. It reads nothing, and no value is ever in it.

The rules:

  • the recovery password, when `recovery.passwordSecret` names it and `recovery.enabled` is not false;
  • the state secret, when `signingKey.kms` or `signingKey.kmsWrapped` is set (a file signer has none);
  • the Google sign-in client: its secret, and its id unless `oauthClient.id` gives it;
  • the secret of every confidential client of the policy that names one (a generated secret is the issuer's to make);
  • the key of every declared workspace;
  • the minter of every Cloudflare account, and the S3 credentials document `ports.blob.s3.credentialsRef` names.

type Directory added in v1.62.0

type Directory struct {
	Workspaces []DirectoryWorkspace `json:"workspaces,omitempty"`
}

Directory is the corporate directories the deployment declares, which the service adopts at start (the console connects the others).

type DirectoryWorkspace added in v1.62.0

type DirectoryWorkspace struct {
	ID         string   `json:"id,omitempty"`
	Backend    string   `json:"backend"`
	Admin      string   `json:"admin"`
	KeySecret  string   `json:"keySecret"`
	Serve      []string `json:"serve,omitempty"`
	SyncGroups []string `json:"syncGroups,omitempty"`
}

DirectoryWorkspace is one declared workspace. It is deliberately thin: an id the deployment may know, a backend, an admin to act as, and where the credential is. Everything else, the domains and the tenant's own id, is discovered.

type Document added in v1.62.0

type Document interface {
	Sluis | Serve | ControllerGitHub | ControllerSlack | PolicyDocument
}

Document is what Load reads: a service document or the policy document.

type Duration

type Duration = duration.Duration

Duration is a time span as the file spells it: a Go duration string such as "30s", "2m" or "168h".

type DynamoDB

type DynamoDB struct {
	Table string `json:"table,omitempty"`
	// Tables is layout v5: the table of each module, by module name
	// (`secrets.layout: v5`). Exclusive with Table.
	Tables   map[string]string `json:"tables,omitempty"`
	Region   string            `json:"region,omitempty"`
	Endpoint string            `json:"endpoint,omitempty"`
	Create   bool              `json:"create,omitempty"`
}

DynamoDB is where the `dynamodb` adapter keeps State, the transitional Index and the Trigger: one table. Credentials are the platform's (Pod Identity, IRSA, a Lambda role), never configured.

type Exchange

type Exchange struct {
	Audience string `json:"audience,omitempty"`
}

Exchange is what the token exchange verifies workloads against.

type ExchangeGitHub added in v1.62.0

type ExchangeGitHub struct {
	// Owners are the organisations whose repositories' CI tokens are
	// verified. None verifies none: an empty list would admit every
	// repository there is.
	Owners []string `yaml:"owners,omitempty"`
}

ExchangeGitHub is whose GitHub Actions tokens are verified.

type FederatedCluster added in v1.62.0

type FederatedCluster struct {
	// Name is the estate's own word for the cluster; it becomes the
	// cluster in a `service_account` matcher and in a minted token's
	// subject.
	Name string `yaml:"name"`
	// Issuer is the `iss` its ServiceAccount tokens carry.
	Issuer string `yaml:"issuer"`
	// JWKSURI is where its keys are. Empty discovers it from the issuer.
	JWKSURI string `yaml:"jwksUri,omitempty"`
}

FederatedCluster is one cluster's row.

type Forwarded

type Forwarded struct {
	Issuer      string `json:"issuer,omitempty"`
	Audience    string `json:"audience,omitempty"`
	EmailHeader string `json:"emailHeader,omitempty"`
}

Forwarded is a sign-in an authenticating proxy in front of the console has already done.

type Freshness

type Freshness struct {
	RefreshInterval *Duration `json:"refreshInterval,omitempty"`
	FreshnessWindow *Duration `json:"freshnessWindow,omitempty"`
	ProbeInterval   *Duration `json:"probeInterval,omitempty"`
}

Freshness is how the directory's snapshot is kept current.

type GitHubApp added in v1.75.0

type GitHubApp struct {
	// ID is the App's key in storage: `link`, a catalogue App's own id, or
	// `runner-<tier>` (`runner-<tier>-<org>` with an `org`), which a runner entry
	// may leave out.
	ID      string            `yaml:"id,omitempty"`
	Purpose appid.Purpose     `yaml:"purpose"`
	Labels  map[string]string `yaml:"labels,omitempty"`
	// Export places the installed App's key at external/github/<id>. A runner
	// App is always exported.
	Export bool `yaml:"export,omitempty"`
	// Org is the organisation a catalogue App is created under, or a runner
	// entry's only organisation.
	Org  string `yaml:"org,omitempty"`
	Tier string `yaml:"tier,omitempty"`

	// Name is the App's name on GitHub, at most 34 characters: a catalogue
	// App's (default <org>-<id>) or the link App's (default
	// <org>-access-roster-link).
	Name string `yaml:"name,omitempty"`

	// The rest is a catalogue App's alone.
	Description  string             `yaml:"description,omitempty"`
	Public       bool               `yaml:"public,omitempty"`
	Permissions  map[string]string  `yaml:"permissions,omitempty"`
	Events       []string           `yaml:"events,omitempty"`
	Webhook      *catalogue.Webhook `yaml:"webhook,omitempty"`
	Installation string             `yaml:"installation,omitempty"`
	Grants       []catalogue.Grant  `yaml:"grants,omitempty"`
}

GitHubApp is one declared GitHub App of any purpose: the one list `apps.github.apps` (ADR 0072) that replaces the separate catalogue and runner tiers.

A `catalogue` App carries the whole of catalogue.App. A `runner` entry declares a tier an operator may make a runner App for, in one organisation (`org`) or in any (no `org`), and its Apps are `runner-<tier>-<org>`. The `link` entry is the App that links a person's GitHub account; it has the id `link` and declares its labels, whether it is exported, the owner `org` and a `name` for the App it is created as.

func (*GitHubApp) Catalogue added in v1.75.0

func (a *GitHubApp) Catalogue() catalogue.App

Catalogue is the entry as a catalogue App.

type GitHubController added in v1.63.0

type GitHubController struct {
	ControllerCommon
	AppsDir string `json:"appsDir,omitempty"`
}

GitHubController is `controllers.github`.

type Google added in v1.76.0

type Google struct {
	// Workspaces are the workspaces the deployment declares.
	Workspaces []DirectoryWorkspace `json:"workspaces,omitempty"`
	// OAuthClient is the client that reopens a workspace connected by consent,
	// and the one the console's consent and the issuer's sign-in use.
	OAuthClient *GoogleOAuthClient `json:"oauthClient,omitempty"`
	// PublicURL is where a browser reaches the issuer, including its mount:
	// the consent and sign-in redirect URIs are built from it. The same value
	// as the issuer's `publicURL`.
	PublicURL string `json:"publicURL,omitempty"`
	// RefreshInterval, FreshnessWindow and ProbeInterval are the hub's knobs.
	RefreshInterval *Duration `json:"refreshInterval,omitempty"`
	FreshnessWindow *Duration `json:"freshnessWindow,omitempty"`
	ProbeInterval   *Duration `json:"probeInterval,omitempty"`
}

Google is `google`.

func (Google) Intervals added in v1.76.0

func (g Google) Intervals() (refresh, freshness, probe time.Duration)

Intervals are the hub's, with the defaults the unset ones take (the issuer's).

type GoogleOAuthClient added in v1.76.0

type GoogleOAuthClient struct {
	ID       string `json:"id,omitempty"`
	Provider string `json:"provider,omitempty"`
}

GoogleOAuthClient is `google.oauthClient`: the id (not a secret) or the provider whose secrets hold it, and the provider whose client-secret it is.

type Lifetimes

type Lifetimes struct {
	Token    *Duration `json:"token,omitempty"`
	Refresh  *Duration `json:"refresh,omitempty"`
	Absolute *Duration `json:"absolute,omitempty"`
	Hold     *Duration `json:"hold,omitempty"`
	Session  *Duration `json:"session,omitempty"`
	// Agent is `lifetimes.agent`: how long the refresh chains of clients
	// the policy marks `session: agent` live.
	Agent *AgentLifetimes `json:"agent,omitempty"`
}

Lifetimes are how long what the issuer hands out lives. A pointer is "not set": zero is a value a file can state, and the absolute lifetime refuses it.

type Log

type Log struct {
	Level string `json:"level,omitempty"`
}

Log is the shared shape of truvity/policy's fragments/log.json.

type Login

type Login struct {
	Directory  *bool      `json:"directory,omitempty"`
	SignOutURL string     `json:"signOutURL,omitempty"`
	Forwarded  *Forwarded `json:"forwarded,omitempty"`
}

Login is how a person signs in to the console.

type ModuleRemote added in v1.76.0

type ModuleRemote struct {
	// Function is the module's Lambda function, name or ARN; it is invoked
	// through the `live-<class>` alias of the caller's class.
	Function string `json:"function,omitempty"`
	// URL is the module's Service, called with the pod's projected token.
	URL string `json:"url,omitempty"`
	// Audience is the audience of that token; the module's name when unset.
	Audience string `json:"audience,omitempty"`
	// TokenFile is where the projected token is mounted;
	// /var/run/secrets/sluis/<module>/token when unset.
	TokenFile string `json:"tokenFile,omitempty"`
}

ModuleRemote is a module in another process: a Lambda function or a Kubernetes Service (docs/decisions/0071). It has the shape of CloudflareRemote.

type ModuleRoute added in v1.76.0

type ModuleRoute struct {
	// Remote is where the module is when it is not this process. Unset keeps
	// the module in this process.
	Remote *ModuleRemote `json:"remote,omitempty"`
	// Serve makes the module answer other modules' calls on Kubernetes: a
	// listener that verifies the caller's projected ServiceAccount token. Only
	// the module's own document sets it (`github.serve` for the GitHub
	// module, `slack.serve` for the Slack one).
	Serve *ModuleServe `json:"serve,omitempty"`
}

ModuleRoute is the section of a module that is not its own settings: `github`, `slack` and `google` each carry one. It holds where the module is when it is not this process.

func (*ModuleRoute) Validate added in v1.76.0

func (r *ModuleRoute) Validate(module string) error

Validate holds the section to what its schema cannot say. A nil section, or one with no remote, keeps the module in this process.

type ModuleServe added in v1.76.0

type ModuleServe struct {
	// Address is the listener: host:port. :8081 when unset.
	Address string `json:"address,omitempty"`
	// Audience is the audience a caller's projected token must have been minted
	// for; the module's name when unset.
	Audience string `json:"audience,omitempty"`
	// Issuers are the subjects of the issuer's ServiceAccount
	// (`system:serviceaccount:<namespace>:<name>`). Each is both the issuer
	// class (`mint_installation`) and the console class (`*.console.*`); a
	// token of any other subject is a 401. At least one is required.
	Issuers []string `json:"issuers,omitempty"`
}

ModuleServe is where the GitHub or Slack module answers the issuer on Kubernetes (docs/decisions/0071): `POST /rpc` with a bearer that a TokenReview accepts for Audience and that belongs to one of Issuers. Lambda ignores it: the function answers `rpc` events and IAM decides who invokes it.

func (*ModuleServe) Validate added in v1.76.0

func (s *ModuleServe) Validate(at string) error

Validate holds the listener to what its schema cannot say.

type OAuthClient

type OAuthClient struct {
	ID string `json:"id,omitempty"`
	// Provider names the client's two secrets,
	// providers/google/<provider>/client-id and .../client-secret. The
	// id may instead be ID, which is not a secret.
	Provider   string `json:"provider,omitempty"`
	SecretName string `json:"secretName,omitempty"`
	IDKey      string `json:"idKey,omitempty"`
	SecretKey  string `json:"secretKey,omitempty"`
}

OAuthClient is the client registered once with the directory backend. Its secret is a file or a declared variable, never a value.

type OpenBaoAuth

type OpenBaoAuth struct {
	Method    string `json:"method,omitempty"`
	Mount     string `json:"mount,omitempty"`
	Role      string `json:"role,omitempty"`
	TokenFile string `json:"tokenFile,omitempty"`
}

OpenBaoAuth is how the service logs in to OpenBao inside each namespace it writes to: the kubernetes or the jwt auth method, as a role, with a token read from a file.

type Platform added in v1.58.0

type Platform struct {
	AWS        bool   `json:"aws,omitempty"`
	Kubernetes bool   `json:"kubernetes,omitempty"`
	OpenBao    bool   `json:"openbao,omitempty"`
	Runtime    string `json:"runtime,omitempty"`
	Replicas   int    `json:"replicas,omitempty"`
}

Platform is the answers to the questions that pick a preset: what the installation has to build on (docs/concepts/sluis/ports.md, "Adapters").

type PolicyApps added in v1.62.0

type PolicyApps struct {
	GitHub *AppsGitHub `yaml:"github,omitempty"`
	Slack  *AppsSlack  `yaml:"slack,omitempty"`
}

PolicyApps is what an operator may make on the console.

func (*PolicyApps) FoldLegacy added in v1.75.0

func (a *PolicyApps) FoldLegacy()

FoldLegacy folds the retired sections of the GitHub Apps into the list. The sections are read for one release (removed in v1.77, like the layout they come with); the canonical document `sluisctl policy render` writes carries the list only. How many entries it made is PolicyDocument.LegacyAppEntries, for the process to warn on.

type PolicyCloudflare added in v1.74.0

type PolicyCloudflare struct {
	// Grants say which presets the holders of a group may have a token for. A
	// CI job is a group like any other: the policy declares it as a group with
	// `github` matchers (repository, ref, event, job_workflow_ref), and the
	// verified token is evaluated against them by the same group evaluation
	// as everything else.
	Grants []CloudflareGrant `yaml:"grants,omitempty" json:"grants,omitempty"`
}

PolicyCloudflare is the policy document's `cloudflare` section: who may ask for which preset.

func (*PolicyCloudflare) Allows added in v1.74.0

func (c *PolicyCloudflare) Allows(preset string, groups []string) bool

Allows reports whether a holder of groups may ask for preset.

func (*PolicyCloudflare) PresetsForGroups added in v1.74.0

func (c *PolicyCloudflare) PresetsForGroups(groups []string) []string

PresetsForGroups are the presets a holder of any of groups may ask for, sorted and without repeats.

type PolicyControllers added in v1.62.0

type PolicyControllers struct {
	GitHub *ControllersGitHub `yaml:"github,omitempty"`
	Slack  *ControllersSlack  `yaml:"slack,omitempty"`
}

PolicyControllers is what each controller may change. Everything else the policy binds is derived and reported, and left alone.

type PolicyDocument added in v1.62.0

type PolicyDocument struct {
	// APIVersion is sluis.truvity.github.io/policy/v2. A v1 policy file (`version:
	// 1`, or an access document) is converted as it is loaded.
	APIVersion string
	// Policy is the access model's tables. Its Version is always 1: the
	// document's own version is APIVersion.
	Policy policy.Policy
	// Exchange is whom the token exchange trusts.
	Exchange *PolicyExchange `yaml:"exchange,omitempty"`
	// Apps is what an operator may make on the console.
	Apps *PolicyApps `yaml:"apps,omitempty"`
	// Controllers is what each controller may change.
	Controllers *PolicyControllers `yaml:"controllers,omitempty"`
	// CloudflareGrants is who may ask for which Cloudflare preset
	// (`cloudflare.grants`); the presets are the service document's.
	CloudflareGrants *PolicyCloudflare `yaml:"cloudflare,omitempty"`
}

PolicyDocument is the policy document: what an installation decides, in one file every process of it reads (`policy.file`).

Its tables are the access model's (package policy, docs/reference/sluis/policy.md), unchanged; beside them are the decisions that used to be spread over the service documents and the files they named:

exchange     whom the token exchange trusts: the federated clusters, the
             AWS accounts, the GitHub owners whose CI tokens are verified
apps         what an operator may make: runner tiers, the GitHub and Slack
             App catalogues
controllers  what each controller may change (the dry-run gate)

It is rendered, never layered at run time: `sluisctl policy render` (and the Pulumi library) merge a directory of layers, access documents and fragments into one canonical document (Render), and a process reads that one file.

func NewPolicyDocument added in v1.62.0

func NewPolicyDocument(p policy.Policy) *PolicyDocument

NewPolicyDocument is a v2 document holding only the access model's tables.

func PolicyOf added in v1.62.0

func PolicyOf[S Service](svc *S, fallback *policy.Policy) (*PolicyDocument, error)

PolicyOf reads the policy document a service document names: its `policy.file`, or, for a converted v1 document, the files v1 named. With neither, fallback's tables, or nil.

func Render added in v1.62.0

func Render(path string) (*PolicyDocument, error)

Render builds the one canonical policy document from the layers a deployment declares, and holds it to every check the binary would: it is what `sluisctl policy render` and the Pulumi library call, and the only place layering happens. A process loads the document a render wrote, and nothing else.

path is a file or a directory. Every YAML file in a directory is one layer, read in name order, and each is one of:

  • a policy file of v1 (`version: 1`): tables;
  • an access document (`access:` and `overlay:`), reshaped into tables;
  • a policy document fragment (`apiVersion: sluis.truvity.github.io/policy/v2`): tables and any of the sections, `exchange`, `apps`, `controllers`, `cloudflare`.

Tables merge by key and a key declared twice is an error naming the file, as they always have. Of the sections, a list concatenates and a list of names unions (the checks refuse a name or an id twice); a scalar declared by two layers is an error.

func (*PolicyDocument) AWS added in v1.62.0

func (d *PolicyDocument) AWS() AWSFederation

AWS is the AWS federation, empty when none is declared.

func (*PolicyDocument) AppRef added in v1.75.0

func (d *PolicyDocument) AppRef(org string) string

AppRef is the id of the App an organisation uses (`app_ref` of its record), or empty when the configuration names none.

func (*PolicyDocument) Cloudflare added in v1.74.0

func (d *PolicyDocument) Cloudflare() *PolicyCloudflare

Cloudflare is the policy's section, never nil.

func (*PolicyDocument) Clusters added in v1.62.0

func (d *PolicyDocument) Clusters() []FederatedCluster

Clusters are the federated clusters, or none.

func (*PolicyDocument) EnabledOrgs added in v1.62.0

func (d *PolicyDocument) EnabledOrgs() []string

EnabledOrgs are the organisations the GitHub controller changes.

func (*PolicyDocument) EnabledWorkspaces added in v1.62.0

func (d *PolicyDocument) EnabledWorkspaces() []string

EnabledWorkspaces are the workspaces the Slack controller changes.

func (*PolicyDocument) Encode added in v1.62.0

func (d *PolicyDocument) Encode() ([]byte, error)

Encode is the canonical document as YAML.

func (*PolicyDocument) GitHubAppExported added in v1.75.0

func (d *PolicyDocument) GitHubAppExported(id string) bool

GitHubAppExported reports whether the link or catalogue App with the id is declared `export: true`. A runner App is always exported and is not asked here.

func (*PolicyDocument) GitHubAppLabels added in v1.75.0

func (d *PolicyDocument) GitHubAppLabels(id string) map[string]string

GitHubAppLabels are the labels declared for the link or catalogue App with the id, or nil.

func (*PolicyDocument) GitHubApps added in v1.75.0

func (d *PolicyDocument) GitHubApps() []GitHubApp

GitHubApps are the declared GitHub Apps of every purpose, in declaration order.

func (*PolicyDocument) GitHubCatalogue added in v1.62.0

func (d *PolicyDocument) GitHubCatalogue() *catalogue.Catalogue

GitHubCatalogue is the catalogue Apps of the list, never nil.

func (*PolicyDocument) GitHubOwners added in v1.62.0

func (d *PolicyDocument) GitHubOwners() []string

GitHubOwners are the organisations whose CI tokens are verified.

func (*PolicyDocument) LegacyAppEntries added in v1.75.0

func (d *PolicyDocument) LegacyAppEntries() int

LegacyAppEntries is how many entries of apps.github.apps came from the retired runnerTiers and catalogue sections: nonzero means the document is to be moved to the list.

func (*PolicyDocument) LinkAppName added in v1.75.0

func (d *PolicyDocument) LinkAppName() string

LinkAppName is the name the link App is created with, or empty for the default (<owner>-access-roster-link).

func (PolicyDocument) MarshalYAML added in v1.62.0

func (d PolicyDocument) MarshalYAML() (any, error)

MarshalYAML writes the canonical document: apiVersion first, the tables as the access model writes them, then the sections. Map keys are sorted, so two renders of one policy are the same bytes.

func (*PolicyDocument) OrganisationAppName added in v1.75.0

func (d *PolicyDocument) OrganisationAppName(org string) string

OrganisationAppName is the name the organisation's App is created with (`controllers.github.appNames`), or empty for the default (<org>-access-roster).

func (*PolicyDocument) RunnerLabels added in v1.75.0

func (d *PolicyDocument) RunnerLabels(tier, org string) map[string]string

RunnerLabels are the labels of the runner App of a tier in an organisation: those of the entry for the tier in any organisation, and then those of the entry for this organisation, which win.

func (*PolicyDocument) RunnerTiers added in v1.62.0

func (d *PolicyDocument) RunnerTiers() []string

RunnerTiers are the tiers an operator may create a runner App for: those of the runner entries, each once.

func (*PolicyDocument) SlackCatalogue added in v1.62.0

func (d *PolicyDocument) SlackCatalogue() *slackcatalogue.Catalogue

SlackCatalogue is the Slack App catalogue, never nil.

func (*PolicyDocument) Unconsumed added in v1.62.0

func (d *PolicyDocument) Unconsumed() []string

Unconsumed is the access model's lint, with the GitHub catalogue's grants counted as consumers.

func (*PolicyDocument) UnmarshalJSON added in v1.62.0

func (d *PolicyDocument) UnmarshalJSON(raw []byte) error

UnmarshalJSON reads a document already held to its schema (JSON is YAML): what the versioned loader decodes into.

func (*PolicyDocument) Validate added in v1.62.0

func (d *PolicyDocument) Validate() error

Validate holds the document to what a schema cannot say: the access model's own rules, and every reference from a section to the tables or to another section. Everything is checked before a process starts, and the checks are the same wherever the document is read: the binary, `sluisctl policy render`, and the Pulumi library before it publishes one.

type PolicyExchange added in v1.62.0

type PolicyExchange struct {
	// Clusters are the clusters whose ServiceAccount tokens are verified,
	// each against the key set it publishes for itself.
	Clusters []FederatedCluster `yaml:"clusters,omitempty"`
	// AWS is the AWS accounts whose roles' outbound identity tokens are
	// verified.
	AWS *AWSFederation `yaml:"aws,omitempty"`
	// GitHub is whose CI tokens are verified.
	GitHub *ExchangeGitHub `yaml:"github,omitempty"`
}

PolicyExchange is whom the token exchange trusts. Nothing here is a secret: every row is a name and a URL.

type PolicyRef added in v1.62.0

type PolicyRef struct {
	File string `json:"file,omitempty"`
}

PolicyRef names the one policy document a process decides by: the canonical document `sluisctl policy render` writes. It is read once, at start; a change is a new instance.

type Ports

type Ports struct {
	Adapter string     `json:"adapter,omitempty"`
	Blob    *PortsBlob `json:"blob,omitempty"`
	// DynamoDB is the table of the `dynamodb` adapter.
	DynamoDB *DynamoDB `json:"dynamodb,omitempty"`
}

Ports chooses the adapter behind the storage ports of docs/concepts/sluis/ports.md.

Adapter picks the State, Index and Trigger (and, unless overridden below, the Blob). Blob replaces one port with an adapter that composes with any of them: State legacy with Blob s3 is valid.

type PortsBlob

type PortsBlob struct {
	Adapter string       `json:"adapter,omitempty"`
	S3      *PortsBlobS3 `json:"s3,omitempty"`
}

PortsBlob names the adapter behind the Blob port.

type PortsBlobCredentials added in v1.74.0

type PortsBlobCredentials struct {
	// Preset is a key of `cloudflare.presets` with an `endpoint` (an R2
	// preset).
	Preset string `json:"preset"`
}

PortsBlobCredentials names the preset an S3-compatible store's credentials are minted from.

type PortsBlobS3

type PortsBlobS3 struct {
	Bucket    string `json:"bucket,omitempty"`
	Prefix    string `json:"prefix,omitempty"`
	Region    string `json:"region,omitempty"`
	KMSKey    string `json:"kmsKey,omitempty"`
	Endpoint  string `json:"endpoint,omitempty"`
	PathStyle bool   `json:"pathStyle,omitempty"`
	// Checksum is the integrity header of every upload: sha256 (the
	// default, x-amz-checksum-sha256), md5 (Content-MD5) or none, for a
	// store that refuses SHA-256.
	Checksum string `json:"checksum,omitempty"`
	// CredentialsRef is the internal address (`internal/<kind>/<id>`) of
	// the s3-credentials/v1 document the installation's secrets store
	// holds for Endpoint. It needs Endpoint and the ssm secrets source.
	CredentialsRef string `json:"credentialsRef,omitempty"`
	// Credentials makes sluis mint its own R2 credentials from a
	// `cloudflare.presets` entry instead of reading a static document. It
	// is exclusive with CredentialsRef, which stays the simple default
	// and needs no `cloudflare` section.
	Credentials *PortsBlobCredentials `json:"credentials,omitempty"`
}

PortsBlobS3 is where the S3 Blob adapter keeps its objects. Credentials are the platform's (Pod Identity, IRSA, a Lambda role), never configured; an S3-compatible endpoint with no such identity names them by address (CredentialsRef), never by value.

type Recovery

type Recovery struct {
	Enabled        *bool  `json:"enabled,omitempty"`
	ServiceAccount string `json:"serviceAccount,omitempty"`
	Audience       string `json:"audience,omitempty"`
	// LoginSecret (`passwordSecret`) names the recovery password, for a hub that is not
	// in a cluster: `recovery/password` in the layout.
	LoginSecret string `json:"passwordSecret,omitempty"`
}

Recovery is the sign-in that needs no directory. A pointer for Enabled: unset is the hub's default (on) and the issuer's (off), as it has always been.

type Roster

type Roster struct {
	// APIVersion is the document's version: v2. A document without one is v1,
	// which [Load] converts.
	APIVersion string `json:"apiVersion"`
	Release    string `json:"release,omitempty"`
	// Policy names the policy document: the bindings are its github or slack
	// table, and its `controllers` section is what the controller may change.
	Policy     *PolicyRef `json:"policy"`
	ConsoleURL string     `json:"consoleURL"`
	TokenFile  string     `json:"tokenFile,omitempty"`
	// Console says how the controller proves itself to the console when the
	// pod's token file is not the way (AWS Lambda).
	Console    *RosterConsole `json:"console,omitempty"`
	RecordsDir string         `json:"recordsDir,omitempty"`
	Interval   *Duration      `json:"interval,omitempty"`
	Log        *Log           `json:"log,omitempty"`
	Ports      *Ports         `json:"ports,omitempty"`
	// Platform, Preset and Adapters choose the adapters by name, per concern, as
	// they do in the serve configuration; the Lambda controllers need them for
	// the audit sink (`sqs`) and the state they share with the service.
	Platform *Platform                `json:"platform,omitempty"`
	Preset   string                   `json:"preset,omitempty"`
	Adapters map[string]AdapterChoice `json:"adapters,omitempty"`
	Audit    *RosterAudit             `json:"audit,omitempty"`
	// GitHub, Slack and Google say where those modules are when they are not
	// in the controller's process.
	GitHub *ModuleRoute `json:"github,omitempty"`
	Slack  *ModuleRoute `json:"slack,omitempty"`
	Google *ModuleRoute `json:"google,omitempty"`
	// Secrets says how the secrets the module reads are delivered, for a
	// module that runs as a function of its own (the one service document's
	// `secrets` is what a controller inside it uses).
	Secrets *Secrets `json:"secrets,omitempty"`
	// Probes is where /healthz and /readyz answer.
	Probes *Address `json:"probes,omitempty"`
	// contains filtered or unexported fields
}

Roster is what the two controllers share.

func (*Roster) Converted added in v1.62.0

func (r *Roster) Converted() bool

Converted reports whether the document was v1, converted as it was loaded.

func (*Roster) Targets added in v1.76.0

func (r *Roster) Targets() map[string]ModuleRemote

Targets is the routing a controller document says.

func (*Roster) ValidateRoutes added in v1.76.0

func (r *Roster) ValidateRoutes() error

ValidateRoutes is Sluis.ValidateRoutes for a controller document.

type RosterAudit

type RosterAudit struct {
	Writer    string `json:"writer,omitempty"`
	TokenFile string `json:"tokenFile,omitempty"`
}

RosterAudit is the audit installation a controller records to.

type RosterConsole added in v1.59.0

type RosterConsole struct {
	Auth *RosterConsoleAuth `json:"auth,omitempty"`
}

RosterConsole is how a controller authenticates to the console.

type RosterConsoleAWS added in v1.59.0

type RosterConsoleAWS struct {
	// Audience is the one the issuer's AWS federation file names.
	Audience string `json:"audience"`
}

RosterConsoleAWS is the AWS proof.

type RosterConsoleAuth added in v1.59.0

type RosterConsoleAuth struct {
	AWS *RosterConsoleAWS `json:"aws,omitempty"`
}

RosterConsoleAuth chooses the proof; `aws` is the function role's web identity token.

type SecretLocation added in v1.62.0

type SecretLocation struct {
	Env  string
	File string
}

SecretLocation is where a converted v1 document said one secret was: a variable or a file.

type Secrets added in v1.62.0

type Secrets struct {
	Source   string    `json:"source"`
	Root     string    `json:"root,omitempty"`
	Region   string    `json:"region,omitempty"`
	Endpoint string    `json:"endpoint,omitempty"`
	Refresh  *Duration `json:"refresh,omitempty"`
	// KMSKeyID is `ssm`'s customer-managed key for the parameters the
	// service writes (credentials, exports). Unset is the AWS-managed key.
	KMSKeyID string `json:"kmsKeyId,omitempty"`
	// Layout is the storage layout of an `ssm` installation: `v4` (ADR
	// 0041), the default, or `v5` (ADR 0072), module first.
	Layout string `json:"layout,omitempty"`
	// Grace is how long a rotated client secret's previous value is still
	// accepted (default 24h). It is the overlap of a
	// rotation: the previous revision of the document, while the current
	// one is younger than this.
	Grace *Duration `json:"grace,omitempty"`
	// ReadCache is how long one process keeps a decrypted document it read
	// from the `ssm` store (default 5m; 0s turns the cache off). A write
	// through the process drops the copy at once; a document that carries
	// its own expiry is not kept past it. SLUIS_SECRETS_READ_CACHE_TTL
	// overrides it.
	ReadCache *Duration `json:"readCache,omitempty"`
}

Secrets is how the secrets a document names are delivered: `env` (SLUIS_SECRET_<NAME>), `file` (<root>/<name>, read on every use) or `ssm` (<root>/internal/config/<name>, read at once and again after `refresh`). See internal/secrets.

type Serve

type Serve struct {
	// APIVersion is the document's version: v2. A document without one is v1,
	// which [Load] converts.
	APIVersion    string `json:"apiVersion"`
	IssuerURL     string `json:"issuerURL"`
	Release       string `json:"release,omitempty"`
	Cluster       string `json:"cluster,omitempty"`
	AllowInsecure bool   `json:"allowInsecure,omitempty"`
	Demo          bool   `json:"demo,omitempty"`
	InCluster     bool   `json:"inCluster,omitempty"`
	// Instance names this installation in the default encryption context of
	// `keys` ({instance, purpose}). Unset is `release`.
	Instance string `json:"instance,omitempty"`
	// Keys says which key serves which purpose (`keys.sign` wraps the signing
	// key ring). Unset leaves every purpose to its older setting.
	Keys *keys.Config `json:"keys,omitempty"`

	Listen *Address `json:"listen,omitempty"`
	Probes *Address `json:"probes,omitempty"`
	Log    *Log     `json:"log,omitempty"`

	Store string `json:"store,omitempty"`
	Ports *Ports `json:"ports,omitempty"`
	// Platform, Preset and Adapters choose the adapters by name, per concern.
	// Absent, the `ports` keys decide, exactly as before they existed.
	Platform *Platform `json:"platform,omitempty"`
	Preset   string    `json:"preset,omitempty"`
	// Adapters maps a concern (state, secrets, blobs, signing, trigger,
	// schedule, audit) to the adapter that replaces the preset's.
	Adapters map[string]AdapterChoice `json:"adapters,omitempty"`
	// Policy names the policy document. Unset is the built-in two groups, or
	// the demonstration policy under `demo`.
	Policy        *PolicyRef `json:"policy,omitempty"`
	PublicURL     string     `json:"publicURL,omitempty"`
	PublicRootURL string     `json:"publicRootURL,omitempty"`
	SecureCookies *bool      `json:"secureCookies,omitempty"`
	GroupsScoping string     `json:"groupsScoping,omitempty"`

	// Secrets says how the secrets this document names are delivered.
	Secrets *Secrets `json:"secrets,omitempty"`

	Lifetimes   *Lifetimes   `json:"lifetimes,omitempty"`
	Freshness   *Freshness   `json:"freshness,omitempty"`
	Directory   *Directory   `json:"directory,omitempty"`
	Exchange    *Exchange    `json:"exchange,omitempty"`
	Recovery    *Recovery    `json:"recovery,omitempty"`
	Login       *Login       `json:"login,omitempty"`
	Console     *Console     `json:"console,omitempty"`
	OAuthClient *OAuthClient `json:"oauthClient,omitempty"`
	SigningKey  *SigningKey  `json:"signingKey,omitempty"`
	Valkey      *Valkey      `json:"valkey,omitempty"`
	Audit       *Audit       `json:"audit,omitempty"`
	// Cloudflare is sluis as the STS for Cloudflare API tokens and R2
	// credentials: the accounts it mints in and the presets it mints.
	Cloudflare *Cloudflare `json:"cloudflare,omitempty"`
	// contains filtered or unexported fields
}

Serve is the configuration of `sluis serve`: the issuer, the console and the directory hub, which run as one process.

func (*Serve) Converted added in v1.62.0

func (s *Serve) Converted() bool

Converted reports whether the document was v1, converted as it was loaded.

func (*Serve) LegacySecrets added in v1.62.0

func (s *Serve) LegacySecrets() (map[string]SecretLocation, string)

LegacySecrets is, for a document converted from v1, where v1 said each secret it names was (by the name v2 gives it), and v1's clientSecretsDir. Both are empty for a v2 document.

func (*Serve) Targets added in v1.76.0

func (s *Serve) Targets() map[string]ModuleRemote

Targets is the routing a v2 `serve` document says: `cloudflare.remote` alone, since the per-module sections came with v3.

func (*Serve) ValidateCloudflare added in v1.74.0

func (s *Serve) ValidateCloudflare() error

ValidateCloudflare holds the cloudflare section, and what else in the service document names one of its presets (ports.blob.s3.credentials), to the checks a schema cannot make. A document that never mentions Cloudflare passes: the static credentials of `ports.blob.s3.credentialsRef` need no section.

type Service added in v1.62.0

type Service interface {
	Sluis | Serve | ControllerGitHub | ControllerSlack
}

Service is a service document: what a process is started with.

type SigningKey

type SigningKey struct {
	File            string    `json:"file,omitempty"`
	AdditionalFiles []string  `json:"additionalFiles,omitempty"`
	PollInterval    *Duration `json:"pollInterval,omitempty"`
	ActivationDelay *Duration `json:"activationDelay,omitempty"`
	Overlap         *Duration `json:"overlap,omitempty"`
	// KMS signs with AWS KMS keys instead of a file. Exclusive with File.
	KMS *SigningKeyKMS `json:"kms,omitempty"`
	// KMSWrapped signs with key pairs KMS generates and wraps under one
	// symmetric key, rotated automatically. Exclusive with File and KMS.
	KMSWrapped *SigningKeyKMSWrapped `json:"kmsWrapped,omitempty"`
	// VerifyOnly are public keys published in the JWKS and never signed
	// with, for a bounded overlap (a cutover from file keys to KMS ones).
	VerifyOnly []SigningKeyVerifyOnly `json:"verifyOnly,omitempty"`
}

SigningKey is where the issuer's keys are and how they rotate.

type SigningKeyKMS added in v1.58.0

type SigningKeyKMS struct {
	Keys        []string `json:"keys,omitempty"`
	Region      string   `json:"region,omitempty"`
	StateSecret string   `json:"stateSecret,omitempty"`
	// Additional is every OTHER algorithm signed at once, each on its own
	// ordered key list, beside Keys (ES384).
	Additional []SigningKeyKMSAlg `json:"additional,omitempty"`
}

SigningKeyKMS is the AWS KMS source of the primary signing key.

type SigningKeyKMSAlg added in v1.58.0

type SigningKeyKMSAlg struct {
	Alg  string   `json:"alg"`
	Keys []string `json:"keys"`
}

SigningKeyKMSAlg is one more algorithm's KMS keys.

type SigningKeyKMSWrapped added in v1.61.0

type SigningKeyKMSWrapped struct {
	// KeyID is DEPRECATED: the symmetric application key. `keys.sign`
	// replaces it; an alias given here is mapped onto `keys.sign` with a
	// warning for one release.
	KeyID  string `json:"keyId,omitempty"`
	Region string `json:"region,omitempty"`
	// StateSecret names the sign-in state's secret, as for `kms`.
	StateSecret string `json:"stateSecret,omitempty"`
	// Algorithms are ES384 and/or RS256, the first the default. Unset is
	// ES384 and RS256.
	Algorithms []string `json:"algorithms,omitempty"`
	// RotateEvery is how often a new key pair is generated. Default 24h.
	RotateEvery *Duration `json:"rotateEvery,omitempty"`
	// Prepublish is how long a new key is published before it signs.
	// Default `signingKey.activationDelay` (15m).
	Prepublish *Duration `json:"prepublish,omitempty"`
	// Retain is how long a superseded key stays published. Default
	// `signingKey.overlap`, which is `lifetimes.token` plus a skew margin.
	Retain *Duration `json:"retain,omitempty"`
}

SigningKeyKMSWrapped is the `kms-wrapped` signing adapter's settings: one symmetric KMS key, the algorithms signed with, and the rotation schedule.

type SigningKeyVerifyOnly added in v1.64.0

type SigningKeyVerifyOnly struct {
	// File is a PEM public key (or a certificate's) or a JWK. A private key
	// is refused at start.
	File string `json:"file"`
	// KeyID is the `kid` the old tokens carry. Unset is the RFC 7638
	// thumbprint, which is what a file signer derived for the key.
	KeyID string `json:"kid,omitempty"`
	// Alg is the key's algorithm. Unset follows the key.
	Alg string `json:"alg,omitempty"`
	// Until is an RFC 3339 instant after which the key is not published.
	Until string `json:"until,omitempty"`
}

SigningKeyVerifyOnly is one public key published and never signed with.

type SlackController added in v1.63.0

type SlackController struct {
	ControllerCommon
	CredentialsDir string `json:"credentialsDir,omitempty"`
}

SlackController is `controllers.slack`.

type Sluis added in v1.63.0

type Sluis struct {
	Serve
	// GitHub, Slack and Google say where those modules are when they are not in
	// this process: `<module>.remote`, shaped as `cloudflare.remote`.
	GitHub      *ModuleRoute `json:"github,omitempty"`
	Slack       *ModuleRoute `json:"slack,omitempty"`
	Google      *ModuleRoute `json:"google,omitempty"`
	Controllers *Controllers `json:"controllers,omitempty"`
}

Sluis is the one service document: the process that serves the issuer, the console and the directory hub and, beside them, runs the controllers it names. Every key of Serve is a key of it, at the top level, and `controllers` is what it adds. apiVersion is v3 (`sluis.truvity.github.io/ sluis/v3`); a v2 `serve` document, or a v1 one, loads as a Sluis with no controllers.

A controller shares what the process already says: the release, the policy, the storage ports and adapters, the audit installation, the log level and the probes. Its own section holds what is its own, and a section that is absent is a controller that is off.

func (*Sluis) GitHubController added in v1.63.0

func (s *Sluis) GitHubController() *ControllerGitHub

GitHubController is the split GitHub controller's document that this one says, or nil when `controllers.github` is absent. The controller's assembly reads it as it reads the document of `sluis controller github`.

func (*Sluis) SlackController added in v1.63.0

func (s *Sluis) SlackController() *ControllerSlack

SlackController is Sluis.GitHubController for Slack.

func (*Sluis) Targets added in v1.76.0

func (s *Sluis) Targets() map[string]ModuleRemote

Targets are the modules this process reaches elsewhere, by name: `cloudflare.remote` and the `remote` of `github`, `slack` and `google`.

func (*Sluis) ValidateRoutes added in v1.76.0

func (s *Sluis) ValidateRoutes() error

ValidateRoutes holds `github.remote`, `slack.remote` and `google.remote` to what the schema cannot say.

type SluisBackup added in v1.75.0

type SluisBackup struct {
	APIVersion string `json:"apiVersion"`
	// Instance names the installation: the path of its backups in the archive
	// bucket and the default encryption context of the archive key.
	Instance string `json:"instance,omitempty"`
	Log      *Log   `json:"log,omitempty"`
	// Keys is the key service block every product shares. Since format 2 the
	// backup module uses none of it: `keys.archive` is accepted for one release
	// and ignored (deprecated).
	Keys     *keys.Config             `json:"keys,omitempty"`
	Secrets  *Secrets                 `json:"secrets,omitempty"`
	Ports    *Ports                   `json:"ports,omitempty"`
	Platform *Platform                `json:"platform,omitempty"`
	Preset   string                   `json:"preset,omitempty"`
	Adapters map[string]AdapterChoice `json:"adapters,omitempty"`
	Audit    *Audit                   `json:"audit,omitempty"`
	Backup   Backup                   `json:"backup"`
}

SluisBackup is the backup module's service document (apiVersion sluis.truvity.github.io/sluis-backup/v1, schemas/config/sluis-backup.schema.json). It holds what the module reads and nothing of the issuer, the console or a policy: the storage it reads an installation from (`ports`, `secrets`), the audit trail, the age recipients a backup is encrypted to, and the bucket it is written to.

func LoadBackup added in v1.75.0

func LoadBackup(file string) (*SluisBackup, error)

LoadBackup reads the backup module's document, holds it to its schema and to SluisBackup.Validate.

func (*SluisBackup) Deprecated added in v1.76.1

func (s *SluisBackup) Deprecated() []string

Deprecated reports the keys the document sets that format 2 ignores (backup.key, backup.region, keys.archive), for a warning at start.

func (*SluisBackup) IdentityRef added in v1.76.1

func (s *SluisBackup) IdentityRef() string

IdentityRef is the name of the restore identity's secret.

func (*SluisBackup) Name added in v1.75.0

func (s *SluisBackup) Name() string

Name is the installation's name: `instance`, else "sluis".

func (*SluisBackup) RoleOf added in v1.75.0

func (s *SluisBackup) RoleOf() string

RoleOf is the role the document is deployed as: `backup.role`, else backup.

func (*SluisBackup) Serve added in v1.75.0

func (s *SluisBackup) Serve() *Serve

Serve is the part of the document the storage ports and the audit trail are opened from, in the shape the shared builders (internal/store, internal/audit) read.

func (*SluisBackup) Validate added in v1.75.0

func (s *SluisBackup) Validate() error

Validate refuses what the schema cannot say.

type SluisGoogle added in v1.76.0

type SluisGoogle struct {
	APIVersion string `json:"apiVersion"`
	// Instance names the installation, as in every module's document.
	Instance string   `json:"instance,omitempty"`
	Log      *Log     `json:"log,omitempty"`
	Probes   *Address `json:"probes,omitempty"`

	Secrets *Secrets `json:"secrets,omitempty"`
	// Audit is the audit installation the module records to: the connections
	// it makes and the changes it makes to them, as its own workload. Unset
	// only logs what it did.
	Audit    *RosterAudit             `json:"audit,omitempty"`
	Ports    *Ports                   `json:"ports,omitempty"`
	Platform *Platform                `json:"platform,omitempty"`
	Preset   string                   `json:"preset,omitempty"`
	Adapters map[string]AdapterChoice `json:"adapters,omitempty"`
	Google   Google                   `json:"google"`
}

SluisGoogle is the Google module's service document (apiVersion sluis.truvity.github.io/sluis-google/v1, schemas/config/sluis-google.schema.json). It holds what the module reads and nothing of the issuer, the console, the signer or a policy: the storage it keeps its workspaces and the snapshots in (`ports`, `secrets`), and the workspaces it reads (`google`).

func LoadGoogle added in v1.76.0

func LoadGoogle(file string) (*SluisGoogle, error)

LoadGoogle reads the Google module's document, holds it to its schema and to SluisGoogle.Validate.

func (*SluisGoogle) DeclaredSecrets added in v1.76.0

func (s *SluisGoogle) DeclaredSecrets() []DeclaredSecret

DeclaredSecrets are the secrets the document declares the module reads: the key of every declared workspace and the OAuth client that reopens one connected by consent (its id too, unless the document gives it). Every one is of a kind the Google module owns; the policy's client secrets and the issuer's keys are not named here because the module has no policy and no signer.

func (*SluisGoogle) Name added in v1.76.0

func (s *SluisGoogle) Name() string

Name is the installation's name: `instance`, else "sluis".

func (*SluisGoogle) Serve added in v1.76.0

func (s *SluisGoogle) Serve() *Serve

Serve is the part of the document the storage ports are opened from, in the shape the shared builders (internal/store, internal/secrets) read.

func (*SluisGoogle) Validate added in v1.76.0

func (s *SluisGoogle) Validate() error

Validate refuses what the schema cannot say.

type Valkey

type Valkey struct {
	Address     string `json:"address,omitempty"`
	LoginSecret string `json:"passwordSecret,omitempty"`
	TLS         bool   `json:"tls,omitempty"`
	Cluster     *bool  `json:"cluster,omitempty"`
}

Valkey is the shared store for logins in progress and snapshots.

Directories

Path Synopsis
Package duration is the time span a configuration document spells as a Go duration string.
Package duration is the time span a configuration document spells as a Go duration string.
Command gen writes the configuration schemas into schemas/config/, and embeds them in the chart's values schema.
Command gen writes the configuration schemas into schemas/config/, and embeds them in the chart's values schema.
Package schema builds the JSON Schema of each binary's configuration file.
Package schema builds the JSON Schema of each binary's configuration file.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL