Documentation
¶
Overview ¶
Package config is sluis's configuration as a public, stable surface: the documents a process is started with, how to load and check them, and the installation document an estate writes once and renders them from.
An estate knows one thing about an installation (where it runs, which AWS resources and which OpenBao it is built on, whom it trusts, what its clients are) and sluis needs two documents of it: the service document (`sluis.yaml`, apiVersion sluis.truvity.github.io/sluis/v3) and the policy document (`policy.yaml`, .../policy/v2). The installation (apiVersion sluis.truvity.github.io/installation/v1, Installation) is the estate's side of that line and Render is sluis's: the same function `sluisctl render` runs, and the one the Pulumi library (github.com/truvity/sluis/deploy/pulumi) calls, so a Lambda estate and a Kubernetes estate write the documents the same way and neither hand-renders them.
in, err := config.LoadInstallation("installation.yaml")
service, policy, err := config.Render(in)
Render is deterministic (sorted keys, a fixed layout) and holds both outputs to the loader the service runs at start, so a document it returns is one the service accepts. Nothing here reads a secret: a document names each secret and the installation never carries a value.
The documents' own types are the binary's, re-exported: a field of one is reachable by value, and the types are held to their schemas (schemas/config/) by the tests of this repository. A key this package does not name is refused by the schema, never dropped.
Index ¶
- Constants
- func APIVersion(document string) string
- func ConsoleAudience(in *Installation) string
- func DefaultSignKeyAlias(instance string) string
- func InstallationSchema() []byte
- func Load[T Document](file string) (*T, error)
- func Render(in *Installation) (service, policy []byte, err error)
- func SSMRoot(instance string) string
- func Validate(name string, doc any) error
- func ValidateInstallation(doc any) error
- type AWS
- type AWSAccount
- type Access
- type AdapterChoice
- type AgentLifetimes
- type Apps
- type Audit
- type Cloudflare
- type CloudflareAccount
- type CloudflareGrant
- type CloudflarePreset
- type CloudflareSection
- type Console
- type Controllers
- type DeclaredSecret
- type Directory
- type Document
- type Duration
- type Exchange
- type ExchangeGitHub
- type FederatedAWS
- type FederatedCluster
- type Freshness
- type GitHubController
- type Installation
- type Issuer
- type Lifetimes
- type Log
- type Login
- type OAuthClient
- type OpenBao
- type OpenBaoLogin
- type Policy
- type PolicyDocument
- type Recovery
- type Secrets
- type Shape
- type SigningKey
- type SlackController
- type Sluis
- type Valkey
Constants ¶
const ( // LambdaPolicyFile is the policy in the configuration layer. LambdaPolicyFile = "/opt/sluis/policy.yaml" // KubernetesPolicyFile is where the chart mounts the policy document. KubernetesPolicyFile = "/var/run/access-issuer/policy/policy.yaml" // ServerPolicyFile is the policy of a process on a host. ServerPolicyFile = "/etc/sluis/policy.yaml" )
Where each shape finds the policy document, unless the installation says.
const ( // StateSecretName is the issuer's sign-in state secret. StateSecretName = "issuer/state-secret" // RecoveryPasswordName is the recovery password, where there is no cluster // to prove access to. RecoveryPasswordName = "recovery/password" )
The names the layout gives the secrets sluis itself writes. They are fixed, so an installation never repeats them.
const DefaultFunctionName = "sluis"
DefaultFunctionName is the Lambda function an installation that names none is rendered for.
const EnvConfig = internal.EnvConfig
EnvConfig is the variable that names the service document when a process is given no --config.
const Group = internal.Group
Group is the group of the documents' kinds: an apiVersion is `<Group>/<document>/v<N>`.
const InstallationVersion = Group + "/installation/v1"
InstallationVersion is the apiVersion of the installation document.
const LiveAlias = "live"
LiveAlias is the alias of the Lambda function that every caller uses: the API, the schedules and a run-now. The Lambda shape's `invoke` trigger names `<function>:live`, so that a run-now runs the version the schedules run.
Variables ¶
This section is empty.
Functions ¶
func APIVersion ¶
APIVersion is the apiVersion this build writes for one document: `sluis` (v3), `policy` (v2) or `installation` (v1).
func ConsoleAudience ¶
func ConsoleAudience(in *Installation) string
ConsoleAudience is the audience an AWS role's web identity token is minted for to be a bearer at the console: `console.awsAudience`, else the console's URL (the service's own default).
func DefaultSignKeyAlias ¶ added in v1.74.0
DefaultSignKeyAlias is the alias of an installation's `keys.sign` key when the installation names none: the one the Pulumi library's grants are written for.
func InstallationSchema ¶
func InstallationSchema() []byte
InstallationSchema is the authored schema of the installation document, the file schemas/config/installation.schema.json: the one `sluisctl render` holds a document to, and the one an estate's CI can validate against without this package.
func Load ¶
Load reads one document from a file, holds it to its schema and decodes it. A v2 document is validated as it stands; an older one the binary still reads is converted. For the policy document the semantic checks run too.
func Render ¶
func Render(in *Installation) (service, policy []byte, err error)
Render writes the two documents of an installation: the service document (`sluis.yaml`, sluis/v3) and the policy document (`policy.yaml`, policy/v2).
It is deterministic: the keys of both are sorted, `apiVersion` comes first, and nothing but the installation decides a byte of the output, so a renderer run twice, or by `sluisctl render` and by the Pulumi library, writes the same documents. It does not change in.
Render writes only what the installation says or the shape implies, and says in its error which key is wrong. Both outputs are then loaded by the loader the service runs at start (the schema, then the semantic checks), so a document Render returns is one the service accepts. What only a running process can check, such as an adapter that needs a platform answer the platform does not give, is still checked at start.
What the shape implies:
- the preset, when none is named;
- `policy.file`, `publicURL`, `publicRootURL` and `inCluster`;
- the adapters the AWS resources and the OpenBao settings stand for, for each concern `adapters` does not name;
- for shape lambda, the library-owned names: `secrets` (ssm, the instance's root), `recovery.passwordSecret`, and the `invoke` trigger's function; and for any signing by KMS, the state secret.
A value the installation writes that disagrees with what the shape fixes is an error, not a choice.
func Validate ¶
Validate checks a decoded document against its authored schema: name is `sluis`, `policy` or `installation`. The chart's tests call it on what the chart renders.
func ValidateInstallation ¶
ValidateInstallation checks a decoded installation document (a generic YAML or JSON value) against the schema.
Types ¶
type AWS ¶
type AWS struct {
Account string `json:"account,omitempty"`
Region string `json:"region,omitempty"`
// FunctionName is the Lambda function the `invoke` trigger names (through its `live` alias). Unset is
// `sluis`.
FunctionName string `json:"functionName,omitempty"`
// Table is the DynamoDB table of the `dynamodb` state adapter.
Table string `json:"table,omitempty"`
// Bucket is the S3 bucket of the `s3` blobs adapter.
Bucket string `json:"bucket,omitempty"`
// AuditQueueURL is the SQS queue of the `sqs` audit adapter.
AuditQueueURL string `json:"auditQueueURL,omitempty"`
}
AWS is the account and the resources an installation is built on. Each resource becomes the setting of the adapter that uses it.
type AWSAccount ¶
type AWSAccount struct {
Account string `json:"account"`
Name string `json:"name"`
Issuer string `json:"issuer"`
JWKSURI string `json:"jwksUri,omitempty"`
OrgID string `json:"orgId,omitempty"`
Algs []string `json:"algs,omitempty"`
}
AWSAccount is one trusted account.
type Access ¶
Access is the access model's tables, as the policy document holds them.
func (Access) MarshalJSON ¶
MarshalJSON writes the tables as the access model writes them.
func (*Access) UnmarshalJSON ¶
UnmarshalJSON reads the tables as the policy document does (JSON is YAML): through the access model's own strict parser.
type AdapterChoice ¶
type AdapterChoice = internal.AdapterChoice
AdapterChoice names the adapter of one concern and its settings.
type AgentLifetimes ¶ added in v1.69.0
type AgentLifetimes = internal.AgentLifetimes
AgentLifetimes is `lifetimes.agent`: the agent session class's own.
type Apps ¶
type Apps struct{ internal.PolicyApps }
Apps is what an operator may make on the console: the policy document's `apps`, under the same keys.
func (Apps) MarshalJSON ¶
MarshalJSON writes the section under the keys the policy document gives it.
func (*Apps) UnmarshalJSON ¶
UnmarshalJSON reads the section as the policy document does. The retired `runnerTiers` and `catalogue` of the GitHub section are read as entries of its `apps` list, with a warning.
type Cloudflare ¶ added in v1.74.0
type Cloudflare struct {
internal.Cloudflare
// Grants say which group or CI job may ask for which preset.
Grants []internal.CloudflareGrant `json:"grants,omitempty"`
}
Cloudflare is the service document's `cloudflare` section and, beside it, the grants the policy document's `cloudflare` holds.
func (*Cloudflare) Declared ¶ added in v1.74.0
func (c *Cloudflare) Declared() bool
Declared reports whether the installation declares any preset: the library then schedules the rotation and grants the function what it needs.
type CloudflareAccount ¶ added in v1.74.0
type CloudflareAccount = internal.CloudflareAccount
CloudflareAccount is one Cloudflare account and its minter credential's address.
type CloudflareGrant ¶ added in v1.74.0
type CloudflareGrant = internal.CloudflareGrant
CloudflareGrant opens presets to a group or a CI job.
type CloudflarePreset ¶ added in v1.74.0
type CloudflarePreset = internal.CloudflarePreset
CloudflarePreset is one thing sluis mints.
type CloudflareSection ¶ added in v1.74.0
type CloudflareSection = internal.Cloudflare
CloudflareSection is the service document's `cloudflare`: the accounts and presets. Cloudflare adds the policy's grants to it.
type Controllers ¶
type Controllers struct {
GitHub *GitHubController `json:"github,omitempty"`
Slack *SlackController `json:"slack,omitempty"`
}
Controllers are the controllers the installation runs. A nil one is off.
type DeclaredSecret ¶ added in v1.75.0
type DeclaredSecret = internal.DeclaredSecret
DeclaredSecret is one secret the service document and the policy declare: the installation must hold it, and a deploy-time check looks for it. Name is where layout v4 keeps it below `internal/config/`; for a Ref (a Cloudflare minter, the S3 credentials document) it is the internal address the document gives, the same on every layout.
func DeclaredSecrets ¶ added in v1.75.0
func DeclaredSecrets(svc *Sluis, pol *PolicyDocument) []DeclaredSecret
DeclaredSecrets is the set of secrets svc and pol declare, sorted and without repeats; pol may be nil. It reads nothing, and no value is in it. It is what a deploy-time check (`{"kind":"check"}`, `sluis check`) looks for.
type Exchange ¶
type Exchange struct {
Audience string `json:"audience,omitempty"`
Clusters []FederatedCluster `json:"clusters,omitempty"`
AWS *FederatedAWS `json:"aws,omitempty"`
GitHub *ExchangeGitHub `json:"github,omitempty"`
}
Exchange is how the token exchange verifies workloads. Audience is the service document's; the rest is the policy document's `exchange`.
type ExchangeGitHub ¶
type ExchangeGitHub struct {
Owners []string `json:"owners,omitempty"`
}
ExchangeGitHub is whose GitHub Actions tokens are verified.
type FederatedAWS ¶
type FederatedAWS struct {
Audience string `json:"audience,omitempty"`
MaxAge *Duration `json:"maxAge,omitempty"`
Accounts []AWSAccount `json:"accounts,omitempty"`
}
FederatedAWS is the AWS accounts whose roles' outbound identity tokens are verified.
type FederatedCluster ¶
type FederatedCluster struct {
Name string `json:"name"`
Issuer string `json:"issuer"`
JWKSURI string `json:"jwksUri,omitempty"`
}
FederatedCluster is one cluster whose ServiceAccount tokens are verified.
type GitHubController ¶
type GitHubController struct {
internal.GitHubController
EnabledOrgs []string `json:"enabledOrgs,omitempty"`
// AppRefs names, by organisation, the catalogue App whose key the
// organisation's record refers to. Optional: an organisation that was
// connected with an App of its own keeps naming it, so an entry is
// needed only to name another App or to declare an organisation anew.
AppRefs map[string]string `json:"appRefs,omitempty"`
// AppNames names, by organisation, the App created for an organisation
// the github table binds (at most 34 characters). Optional: an
// organisation with no entry gets the built-in default.
AppNames map[string]string `json:"appNames,omitempty"`
}
GitHubController is the GitHub controller: its own keys go to the service document's `controllers.github`, EnabledOrgs to the policy document's.
type Installation ¶
type Installation struct {
// APIVersion is [InstallationVersion].
APIVersion string `json:"apiVersion"`
// Instance is the installation's name (`acme`, `prod`). Its SSM root is
// /sluis/<instance>.
Instance string `json:"instance"`
// Shape is where it runs.
Shape Shape `json:"shape"`
// Preset names the adapters of a whole platform. Unset follows the shape:
// aws-hybrid (lambda), k8s-aws (kubernetes with `aws`), k8s-openbao
// (kubernetes with `openbao`), k8s-minimal, server.
Preset string `json:"preset,omitempty"`
// Release is the name the installation's objects carry. Unset is `sluis`.
Release string `json:"release,omitempty"`
// Cluster names the cluster in a ServiceAccount's subject.
Cluster string `json:"cluster,omitempty"`
// PolicyFile is where the service finds the policy document. Unset follows
// the shape.
PolicyFile string `json:"policyFile,omitempty"`
Issuer Issuer `json:"issuer"`
Log *Log `json:"log,omitempty"`
Lifetimes *Lifetimes `json:"lifetimes,omitempty"`
Freshness *Freshness `json:"freshness,omitempty"`
// Secrets is the service document's `secrets`, for a platform with no
// secrets adapter of its own. Shape lambda fills it (ssm, the instance's
// root) and refuses another value.
Secrets *Secrets `json:"secrets,omitempty"`
// AWS is the account and the resources the installation is built on.
AWS *AWS `json:"aws,omitempty"`
// OpenBao is the OpenBao the secrets are kept in.
OpenBao *OpenBao `json:"openbao,omitempty"`
// Adapters name single concerns over what the preset and the resources
// above give.
Adapters map[string]AdapterChoice `json:"adapters,omitempty"`
// Keys says which key serves which purpose (the service document's
// `keys`). With `signingKey.kmsWrapped` and no `keys`, the sign key is
// alias/sluis-<instance>-sign on kms.
Keys *keys.Config `json:"keys,omitempty"`
SigningKey *SigningKey `json:"signingKey,omitempty"`
Recovery *Recovery `json:"recovery,omitempty"`
Login *Login `json:"login,omitempty"`
Console *Console `json:"console,omitempty"`
OAuthClient *OAuthClient `json:"oauthClient,omitempty"`
Valkey *Valkey `json:"valkey,omitempty"`
Directory *Directory `json:"directory,omitempty"`
Audit *Audit `json:"audit,omitempty"`
// Cloudflare is sluis as the STS for Cloudflare tokens and R2 credentials:
// the accounts and presets go to the service document's `cloudflare`, the
// grants to the policy document's.
Cloudflare *Cloudflare `json:"cloudflare,omitempty"`
// Exchange is how the token exchange verifies workloads and whom it trusts.
Exchange *Exchange `json:"exchange,omitempty"`
// Apps is what an operator may make on the console.
Apps *Apps `json:"apps,omitempty"`
// Controllers are the controllers that run, and what each may change.
Controllers *Controllers `json:"controllers,omitempty"`
// Access is the access model's tables: groups, clients, resources and the
// GitHub and Slack bindings.
Access *Access `json:"access,omitempty"`
}
Installation is everything an estate knows about one installation of sluis. It is a superset of the service document and the policy document: a section is under the key the document gives it (the types are the documents' own), and the installation adds what a document cannot say, which is the shape it runs in and the AWS and OpenBao resources it is built on. Render splits it into the two documents.
It holds no secret. A document names each secret, and where the names are read from is `secrets` or the secrets adapter.
func LoadInstallation ¶
func LoadInstallation(file string) (*Installation, error)
LoadInstallation reads an installation document from a file and holds it to its schema.
func (*Installation) String ¶
func (in *Installation) String() string
String names the installation without printing any of it.
type Issuer ¶
type Issuer struct {
// URL is the issuer (`issuerURL`).
URL string `json:"url"`
// ConsoleURL is `publicURL`. Unset is URL plus /console.
ConsoleURL string `json:"consoleURL,omitempty"`
// RootURL is `publicRootURL`. Unset is URL.
RootURL string `json:"rootURL,omitempty"`
// SecureCookies is `secureCookies`.
SecureCookies *bool `json:"secureCookies,omitempty"`
// GroupsScoping is `groupsScoping`: off, report or enforce.
GroupsScoping string `json:"groupsScoping,omitempty"`
}
Issuer is the issuer and where a browser reaches the console.
type OAuthClient ¶
type OAuthClient = internal.OAuthClient
OAuthClient is `oauthClient`: the client registered with the directory backend.
type OpenBao ¶
type OpenBao struct {
Address string `json:"address"`
CAFile string `json:"caFile,omitempty"`
Mount string `json:"mount,omitempty"`
Namespace string `json:"namespace,omitempty"`
Root string `json:"root"`
Auth OpenBaoLogin `json:"auth"`
}
OpenBao is the OpenBao the secrets are kept in: the settings of the `openbao` secrets adapter.
type OpenBaoLogin ¶
type OpenBaoLogin struct {
Method string `json:"method"`
Mount string `json:"mount,omitempty"`
Role string `json:"role"`
TokenFile string `json:"tokenFile,omitempty"`
}
OpenBaoLogin is how the service logs in to the OpenBao.
type PolicyDocument ¶
type PolicyDocument = internal.PolicyDocument
PolicyDocument is the policy document (v2): the access model's tables and whom the exchange trusts, what an operator may make, what each controller may change and what is copied out.
func RenderPolicyLayers ¶
func RenderPolicyLayers(path string) (*PolicyDocument, error)
RenderPolicyLayers builds the one canonical policy document from a file or a directory of layers (a v1 policy file, an access document, or a policy document fragment), merged in name order and held to every check the service runs at start. It is what `sluisctl policy render` runs; an estate that writes an Installation has no layers to merge and calls Render.
type Shape ¶
type Shape string
Shape is where an installation runs.
const ( // ShapeLambda is one AWS Lambda function behind an HTTP API; the documents // are an immutable configuration layer mounted at /opt/sluis. ShapeLambda Shape = "lambda" // ShapeKubernetes is one Deployment; the chart mounts the documents. ShapeKubernetes Shape = "kubernetes" // ShapeServer is one process on a host. ShapeServer Shape = "server" )
The shapes.
type SigningKey ¶
type SigningKey = internal.SigningKey
SigningKey is `signingKey`: where the issuer's keys are and how they rotate.
type SlackController ¶
type SlackController struct {
internal.SlackController
EnabledWorkspaces []string `json:"enabledWorkspaces,omitempty"`
}
SlackController is GitHubController for Slack.