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 CheckInstallation(existing []byte, in *Installation, opts MarshalOptions) (equal bool, diff string, err error)
- func CloudflareStoredRef(ref string) (preset string, ok bool)
- func ConsoleAudience(in *Installation) string
- func DefaultSignKeyAlias(instance string) string
- func FunctionNameOf(in *Installation, module string) string
- func InstallationSchema() []byte
- func Load[T Document](file string) (*T, error)
- func MarshalInstallation(in *Installation, opts MarshalOptions) ([]byte, error)
- func Modules() []string
- 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
- func ValidateModule(module string, doc, policy []byte) error
- func ZipModules() []string
- func ZipName(module, version string) string
- func ZipPrefix(module string) string
- type AWS
- type AWSAccount
- type Access
- type AdapterChoice
- type AgentLifetimes
- type Apps
- type Audit
- type Bootstrap
- type BootstrapControllers
- type BootstrapProbe
- type BootstrapRecovery
- type BootstrapServiceAccount
- type BootstrapViewers
- 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 MarshalOptions
- type ModuleDocuments
- type ModuleOptions
- 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 ( CloudflareStoreExternal = internal.CloudflareStoreExternal CloudflareStoreNone = internal.CloudflareStoreNone )
The values of a Cloudflare preset's `store`: `external` (the default) has the schedule rotate the preset into external/cloudflare/<preset>; `none` makes it on-demand only, with nothing stored.
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 ( ModuleGitHub = "github" ModuleSlack = "slack" ModuleGoogle = "google" ModuleCloudflare = "cloudflare" // ModuleIssuer names the issuer for [ModuleSecrets]; it has no entry in // [ModuleDocuments.Modules]. ModuleIssuer = "issuer" // ModuleBackup names the backup function for [FunctionNameOf]; it has no // entry in [ModuleDocuments.Modules]. ModuleBackup = "backup" )
The modules a Lambda installation runs as functions of their own, by the name the installation's `aws.functions` and ModuleDocuments.Modules give them. The issuer is the other function, and its document is ModuleDocuments.Issuer.
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 CloudflareStoredRefPrefix = internal.CloudflareStoredRefPrefix
CloudflareStoredRefPrefix begins the address of the credential the Cloudflare module rotates for a preset with `store: external`: `external/cloudflare/<preset>`, which `ports.blob.s3.credentialsRef` may name.
const DefaultFunctionName = "sluis"
DefaultFunctionName is the Lambda function an installation that names none and has no instance is rendered for. With an instance the default is `sluis-<instance>-issuer`.
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.
const ZipNameTemplate = "sluis-%s_%s_linux_arm64.zip"
ZipNameTemplate is the file name of a module's Lambda zip, `%s` being the module and the version following it: `sluis-<module>_<version>_linux_arm64.zip`. An estate pins one digest per zip, found in the release's checksums.txt under this name.
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 CheckInstallation ¶ added in v1.76.10
func CheckInstallation(existing []byte, in *Installation, opts MarshalOptions) (equal bool, diff string, err error)
CheckInstallation reports whether existing is what MarshalInstallation writes for in with opts. When it is not, diff is a line diff from existing (`-`) to the written document (`+`) with three lines of context. It returns an error, and no verdict, when the installation cannot be written.
It compares bytes, so a header the caller changed, or a hand edit that the loader reads the same, is a difference: that is what a `--check` mode is for.
func CloudflareStoredRef ¶ added in v1.76.8
CloudflareStoredRef reports whether ref is a stored preset credential's address, and the preset it names.
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 FunctionNameOf ¶ added in v1.76.0
func FunctionNameOf(in *Installation, module string) string
FunctionNameOf is the name of a function: `aws.functions.<module>`, else `sluis-<instance>-<module>`. The module is one of Modules, ModuleIssuer (the issuer, whose name `aws.functionName` also sets, as it did before the default was `sluis-<instance>-issuer`; an installation with no instance is `sluis`, DefaultFunctionName) or ModuleBackup.
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 MarshalInstallation ¶ added in v1.76.10
func MarshalInstallation(in *Installation, opts MarshalOptions) ([]byte, error)
MarshalInstallation writes an installation as its canonical YAML document: the form a person reviews and `sluisctl render` reads.
The form is fixed. `apiVersion` is the first key; every other key, at every level, is sorted by name. The indent is two spaces, the style is block, and a duration is written as Go spells it with the zero trailing units dropped (`1h`, `15m`, `336h`, `1h30m`), never `1h0m0s`. A field that is unset, or zero, is left out; so is an empty list or map. A section that is set but empty (`controllers.github: {}` is a controller that is on) is kept, because leaving it out would turn it off.
The installation is refused when the loader would refuse the document, so a writer cannot produce a document that sluis will not start with: the document is held to the installation schema (ValidateInstallation), to the checks Render makes before it renders, and is decoded back into the types. An empty APIVersion is written as InstallationVersion.
The output is a function of the installation alone, and loading it gives an installation that writes the same bytes again.
func Modules ¶ added in v1.76.0
func Modules() []string
Modules are the module functions, in a fixed order.
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.
func ValidateModule ¶ added in v1.76.0
ValidateModule loads a module's service document as its function does: the schema, the decode and the checks a schema cannot make. policy, when given, is the policy document the Cloudflare module's grants are held to.
func ZipModules ¶ added in v1.76.0
func ZipModules() []string
ZipModules are the modules a release publishes a Lambda zip for, in a fixed order: the issuer, the module functions of Modules and backup (which is deployed twice, as the backup and the restore function). It is the one list the goreleaser configuration, the release lists and the Pulumi library's default package names are held to. There is no zip for the signer, the mint (the github function serves it) or restore.
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-<instance>-issuer`. Prefer Functions["issuer"]; this one is kept for
// estates that already set it.
FunctionName string `json:"functionName,omitempty"`
// Functions name the functions by module (issuer, github, slack, google,
// cloudflare, backup) when [RenderModules] is the renderer. Unset is
// `sluis-<instance>-<module>`. The issuer's call to each names it
// (`<module>.remote`).
Functions map[string]string `json:"functions,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 FromAccess ¶ added in v1.76.10
FromAccess builds the installation's `access` section from an access document's derived part and the installation's bootstrap rows. It is the reshaping policy.AccessDocument.Policy does (lists to tables, camelCase to the policy's own keys) with the rows appended to their groups, and nothing else: no field of the access part is dropped, except the seven of a client that describe the relying party's own deployment and are read by whatever deploys it (policy.AccessClient).
The result is not validated as a policy; Render does that. FromAccess refuses a Bootstrap that is malformed, names a workload twice in one list, uses a group or client of its own that the access part also declares, or uses one name for two rows.
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 Bootstrap ¶ added in v1.76.10
type Bootstrap struct {
// Recovery is the account that holds the break-glass groups.
Recovery *BootstrapRecovery
// Viewers is the group of everyone who may look, and the people and
// workloads it admits beside the matrix's own.
Viewers *BootstrapViewers
// Controllers are the workloads that run the directory controllers.
Controllers *BootstrapControllers
// Probe is the workload that proves the exchange.
Probe *BootstrapProbe
// GenerateSecrets writes every confidential client's secret as
// `{generate: true}` and not as the name the access document gives. The
// issuer then makes and keeps the value.
GenerateSecrets bool
// Claims is the claims table: what a group adds to a token. The access
// document has no such table, so it is carried through unchanged.
Claims map[string]policy.Fragment
}
Bootstrap is what an installation adds to the access model's derived part: how it is reached before a directory can vouch for anybody. Every row is typed and checked by FromAccess; a nil row adds nothing.
The rows fold into the groups the way an estate's own renderer has done it: matchers are appended after what the access matrix derived, in the order the fields below list them, and a group the matrix never produced is created with only these.
type BootstrapControllers ¶ added in v1.76.10
type BootstrapControllers struct {
// Group is that group's name. It must not be a group of the access
// matrix: a person placed there would be served as a controller.
Group string
// ServiceAccounts is the release's ServiceAccount on Kubernetes.
ServiceAccounts []BootstrapServiceAccount
// RoleARNs are the functions' roles on Lambda.
RoleARNs []string
}
BootstrapControllers are the workloads of the GitHub and Slack controllers. They join the viewers, and, when Group is set, a group of their own that the console reads to serve them unrecorded and that grants no role.
type BootstrapProbe ¶ added in v1.76.10
type BootstrapProbe struct {
// Group is the group the workload joins. It must not be a group of the
// access matrix.
Group string
// Client is the exchange client, which requires Group. It must not be a
// client of the access matrix.
Client string
// ServiceAccount is the probe's account. Its cluster is required.
ServiceAccount BootstrapServiceAccount
}
BootstrapProbe is the workload that proves a token minted by another cluster is verified against the key set that cluster publishes. Its client is an exchange target that grants nothing.
type BootstrapRecovery ¶ added in v1.76.10
type BootstrapRecovery struct {
ServiceAccount BootstrapServiceAccount
// Groups are the groups the account joins, for example the operator
// group and one cluster's auditor group. They may be groups of the
// access matrix.
Groups []string
}
BootstrapRecovery admits one ServiceAccount to each of the named groups. Where recovery is the password (Lambda) the row is left out.
type BootstrapServiceAccount ¶ added in v1.76.10
type BootstrapServiceAccount struct {
// Cluster narrows the account to one named cluster. Empty matches any.
Cluster string
// Namespace and Name are the account's, both required.
Namespace string
Name string
}
BootstrapServiceAccount is one Kubernetes ServiceAccount.
type BootstrapViewers ¶ added in v1.76.10
type BootstrapViewers struct {
// Group is the group's name. It may be a group of the access matrix.
Group string
// EmailDomain admits every signed-in address of one domain.
EmailDomain string
// ServiceAccounts and RoleARNs are the workloads admitted besides the
// controllers, which join the group on their own row.
ServiceAccounts []BootstrapServiceAccount
// RoleARNs are IAM roles, `arn:aws:iam::<account>:role/[path/]<name>`.
RoleARNs []string
}
BootstrapViewers is the group that may look at the installation.
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) AnyStored ¶ added in v1.76.7
func (c *Cloudflare) AnyStored() bool
AnyStored reports whether some declared preset is rotated by the schedule (`store` unset or `external`). The library schedules the rotation and grants the stored credentials only then: presets that are all `store: none` are minted on demand and nothing is kept for them.
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.
func ModuleSecrets ¶ added in v1.76.0
func ModuleSecrets(module string, doc, policy []byte) ([]DeclaredSecret, error)
ModuleSecrets are the secrets a module's function declares and checks, from its document: the kinds the function reads and no other module's. The GitHub and Slack modules declare none (an App's credential is made at run time), the Google module its workspaces' keys, the Cloudflare module its accounts' minters, and the issuer the rest (the recovery password, the state secret, the sign-in client, the policy's client secrets, the blob store's credential). The blob store's credential is the one both the issuer and the Google module read.
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 MarshalOptions ¶ added in v1.76.10
type MarshalOptions struct {
// Header is a comment block written before the document. Each line is
// written as a YAML comment (`# ` is added to a line that does not start
// with `#`), and the block ends with a line break. The caller owns its
// text; it is not part of the document and the loader ignores it.
Header string
}
MarshalOptions are the caller's choices for MarshalInstallation.
type ModuleDocuments ¶ added in v1.76.0
type ModuleDocuments struct {
// Issuer is the issuer's service document (sluis/v3): [Render]'s with the
// modules it calls elsewhere, `github.remote`, `slack.remote`, `google.remote`
// and `cloudflare.remote`, naming the functions; what the modules own
// (`controllers`, `directory`, the Cloudflare accounts and presets) is not in it.
Issuer []byte
// Policy is the policy document (policy/v2) every function that decides by
// it reads from the same file.
Policy []byte
// Modules are the service documents of the module functions, by
// [Modules]: controller-github/v2, controller-slack/v2, sluis-google/v1 and sluis/v3 with `cloudflare.serve`. The Cloudflare module has one only when
// the installation declares a preset: a module with nothing to do has no
// function.
Modules map[string][]byte
}
ModuleDocuments are the documents of a Lambda installation that runs a function per module.
func RenderModules ¶ added in v1.76.0
func RenderModules(in *Installation, opts ModuleOptions) (*ModuleDocuments, error)
RenderModules writes the documents of an installation that runs a function per module: Render's two documents, with the issuer's calling the modules by their functions, and a service document for each module that holds what is the module's own and nothing else.
A module document opens only its own table (`ports.dynamodb.tables` has the module's alone, since the readiness probe describes each table it lists), reads its secrets as layout v5 (`secrets.layout: v5`), and names the same policy file as the issuer's, where the module reads one. The documents hold no secret, and the secrets they name are disjoint but for the blob store's credential (see ModuleSecrets).
It is deterministic and leaves in alone. Every document it returns has been loaded as the module's function loads it.
type ModuleOptions ¶ added in v1.76.0
type ModuleOptions struct {
// Tables are the DynamoDB table of each module of layout v5, by the module's
// name (oidc, github, slack, cloudflare, google, backup). A module not listed
// has `sluis-<instance>-<module>`.
Tables map[string]string
}
ModuleOptions say what an installation cannot: the names the infrastructure gave.
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.