Hosting resources
This page documents the two sides of each resource module:
- the request options: the options a component sets to request a resource from a hosting provider;
- the policy options: the options a hosting provider sets in an environment to supply that resource.
It also gives an example of each side for each resource. For the
generic request/policy pattern these build on, see the
data model page. For where a provider writes a policy, see
how a hosting provider configures these
below, which ties these options to the data model's
environments.
The data model declares the request and the policy of each resource as a
deferred module, so the concrete sub-options live in the resource configuration
rather than in the option type. This page surfaces them by building a submodule
from each module, giving the <name>.request.* and <name>.policy.*
options below.
The page builds a section for each resource that the data model loads from
core/resources, so the list below always agrees with the code.
Each policy also has the options that the data model declares for all
policies, such as apply, process and routing. The
data model page documents those one time, as
resources.<name>.policy, so the <name>.policy.* options below do not repeat
them.
How a hosting provider configures these
The <name>.request.* options below are the component-facing half of a
resource. A hosting provider does not set them directly; they configure the
environment a component is deployed to, with the <name>.policy.* options.
An environment is one entry of the
data model's environments option, and the environments
section of the example at examples/hosting-config.nix shows the shape: an
attrset keyed by environment name.
A provider points the HOSTING_CONFIG environment variable at such a file. The
file has two sections: environments (the provider resources described here) and
effect-defaults (operator-form leaf defaults, a map keyed by effect tag). The
environments attrset is
lib.recursiveUpdate-merged on top of the defaults (the hosting configuration wins). The
file may be a .nix, a .toml or a .json file -- the loader dispatches on the
extension. examples/hosting-config.toml shows the TOML form of the same
override. JSON is there for a generator rather than a hand: it is what
services.fediversity-api.hostingConfig renders the provider's curation to.
TOML is sufficient for the common case because the override surface is plain
data, but it cannot represent function values, derivations/packages, or null;
those only appear in resource policies (defaults), not the override. Reach for
the .nix form when you need any of them (or .json, for null alone). Two
TOML hand-authoring caveats:
- Override values are type-checked against the resource policy's option types after the merge, so encode each as the plain-data equivalent the option coerces from; mismatches surface as normal module eval errors.
- Use dotted-table headers (
[mastodon.resources.garage.external]), not array-of-tables ([[...]]) -- the latter parses to a list and fails the merge. The example file demonstrates the correct form.
Each environment is more than its resources. Besides the resources sub-option
(where the policies matching the requests below are declared, each under a name
of the provider's choice and tagged with its resource), an environment also carries the functions that turn a configuration into
a deployment:
resources-- the per-resource policies the provider offers; this is the sub-option that takes the policy options below.implementation-- maps the components' required resources to this environment's resources.resource-mapping-- the function type ofimplementation.config-mapping-- maps an operator configuration to a deployment.deployment-- the end-to-end entry point applying the environment's policies to the components' resource mappings.
Those sibling options are config-dependent functions rather than concrete
values, so they are documented informally on the
data model page rather than shown with concrete
types here. The options on this page are the request shape a component
declares, and the policy shape that an environment's resources supply for it.
Examples
A component states a request in its resources function, as
<key>.<resource>, where the key is a name of its choice. An environment
states a policy as resources.<name>.<resource>, where the name is of the
provider's choice. The setups in core/setups write the policies of the
in-tree groups.
The build takes each request below from a component in core/components, and
each policy from the example values of the policy options that have no
default.
dns
A request of the windmill component, without the options
that have their default value:
dns.dns = {
consumerName = "windmill";
enable = true;
};
The smallest policy, in an environment:
environments.<environment>.resources.<name>.dns = {
enable = true;
};
firewall
A request of the authelia component, without the options
that have their default value:
web.firewall = {
publicTCPPorts = [
80
443
];
};
The smallest policy, in an environment:
environments.<environment>.resources.<name>.firewall = { };
garage
A request of the bind component, without the options
that have their default value:
bind-backups.garage = {
ensureBuckets = {
bind-backups = {
corsRules = { };
retainKvStems = [
"bind-backups-restic"
];
};
};
ensureKeys = {
bind-backups = {
ensureAccess = {
bind-backups = {
owner = true;
read = true;
write = true;
};
};
kvName = "bind-backups";
};
};
};
The smallest policy, in an environment:
environments.<environment>.resources.<name>.garage = {
enable = true;
domain = "garage.example.org";
};
generateFiles
A request of the netbox component, without the options
that have their default value:
secrets.generateFiles = {
writtenInstances = [
"netbox"
];
};
The smallest policy, in an environment:
environments.<environment>.resources.<name>.generateFiles = { };
ldap
A request of the pixelfed component, without the options
that have their default value:
pixelfed-roles.ldap = {
roleGroups = {
application-admins = {
seedAdmin = true;
};
pixelfed-admins = { };
};
};
The smallest policy, in an environment:
environments.<environment>.resources.<name>.ldap = {
enable = true;
adminUser = "operator";
domain = "ldap.example.org";
email = "admin@example.org";
};
netbox
A request of the windmill component, without the options
that have their default value:
ipam.netbox = {
consumerName = "windmill";
enable = true;
};
The smallest policy, in an environment:
environments.<environment>.resources.<name>.netbox = {
enable = true;
};
network
No component of the in-tree groups makes a request to this resource.
The smallest policy, in an environment:
environments.<environment>.resources.<name>.network = {
domain = "example.org";
};
nixos-module
A request of the lldap component, without the options
that have their default value:
ui-reset-limit.nixos-module = {
module = {
services = {
nginx = {
appendHttpConfig = ''
limit_req_zone $binary_remote_addr zone=lldap-reset:1m rate=6r/m;
'';
};
};
};
};
The smallest policy, in an environment:
environments.<environment>.resources.<name>.nixos-module = { };
oidc
A request of the netbox component, without the options
that have their default value:
netbox-oidc.oidc = {
clientID = "netbox";
enable = true;
redirectURI = "https://netbox.example.org/oauth/complete/oidc/";
};
The smallest policy, in an environment:
environments.<environment>.resources.<name>.oidc = {
enable = true;
domain = "auth.example.org";
};
otel
A request of the netbox component, without the options
that have their default value:
otel.otel = {
consumerName = "netbox";
enable = true;
};
The smallest policy, in an environment:
environments.<environment>.resources.<name>.otel = { };
pod-roles
A request of the mastodon component, without the options
that have their default value:
pods.pod-roles = {
roles = {
sidekiq = { };
};
};
The smallest policy, in an environment:
environments.<environment>.resources.<name>.pod-roles = { };
postgresql
A request of the lldap component, without the options
that have their default value:
lldap-db.postgresql = {
consumerName = "lldap";
database = "lldap";
enable = true;
urlEnvironment = {
units = [
"lldap"
];
variable = "LLDAP_DATABASE_URL";
};
username = "lldap";
};
The smallest policy, in an environment:
environments.<environment>.resources.<name>.postgresql = {
enable = true;
domain = "postgresql.example.org";
};
redis
A request of the valkey component, without the options
that have their default value:
valkey-cache.redis = {
consumerName = "valkey";
namespace = "valkey";
};
The smallest policy, in an environment:
environments.<environment>.resources.<name>.redis = {
enable = true;
host = "valkey.example.org";
};
secrets
No component of the in-tree groups makes a request to this resource.
The smallest policy, in an environment:
environments.<environment>.resources.<name>.secrets = { };
smtp
A request of the netbox component, without the options
that have their default value:
netbox-smtp.smtp = {
enable = true;
sender = "noreply@netbox.example.org";
};
The smallest policy, in an environment:
environments.<environment>.resources.<name>.smtp = {
enable = true;
domain = "mail.example.org";
};
spiffe
A request of the authelia component, without the options
that have their default value:
spiffe.spiffe = {
enable = true;
};
The smallest policy, in an environment:
environments.<environment>.resources.<name>.spiffe = { };
ssl
A request of the incus component, without the options
that have their default value:
tls.ssl = {
domains = [
"incus.example.org"
];
};
The smallest policy, in an environment:
environments.<environment>.resources.<name>.ssl = { };
Options
dns
Authoritative-DNS coordinates for an application, fulfilled by either a self-hosted bind node or an external service, through the local dns contract.
Type: submodule
dns.policy
Options a hosting provider sets in an environment to supply this resource. The options that all policies share are on the data model page.
Type: submodule
dns.policy.enable
Whether to enable authoritative-DNS provisioning for this deployment.
Type: boolean
Default:
false
Example:
true
Declared by:
dns.policy.domain
The domain the deployment publishes its records under. Must already be a zone at whichever provider is routed – the effect writes records and creates no zones.
Type: string
Default:
""
Declared by:
dns.request
Options a component sets to request this resource.
Type: submodule
dns.request.enable
Whether to enable authoritative-DNS coordinates on this application’s host.
Type: boolean
Default:
false
Example:
true
Declared by:
dns.request.consumerName
Unique consumer name for this app (analog of ldap’s/redis’s
consumerName), used as the contracts.dns.want.<consumerName>
key. The node gets the contract result ({ provider; host; port; scheme; apiTokenFile; domain; }) at
contracts.dns.results.<consumerName>.default.
Type: string
Declared by:
firewall
Which sources reach a node, and which of the ports it serves are published beyond them.
Type: submodule
firewall.policy
Options a hosting provider sets in an environment to supply this resource. The options that all policies share are on the data model page.
Type: submodule
firewall.policy.adminSources
The operator’s own sources: allowed to reach every port a node
serves, exactly like internalSources. Same dual-stack
inference.
Every port, not only adminTCPPorts – a source reaching nothing
but :22 would be a second SSH allow-list rather than a trusted
source. This is what an operator’s VPN comes in on, and what makes
a management node reachable at its own public name: those nodes
publish none of their ports, so being an admitted source is the
only way in (notes/private-access.md has the recipe).
Deployment data, not repository data: it arrives with the rest of
the deployment’s coordinates (ADMIN_SOURCES,
core/effects/env-config.nix).
Leaving it empty publishes the admin surface (adminTCPPorts)
instead, so forgetting to state it does not lock anyone out.
Type: list of string
Default:
[ ]
Example:
[
"185.206.235.36/32"
"2a00:51c0:13:1100::4/128"
]
Declared by:
firewall.policy.adminTCPPorts
What counts as the administrative surface in this environment: the
ways IN to a node, :22 by default.
These are always served, a node’s own way in being a property of
the node rather than of who arrives on it; who may reach them is
the gate’s decision, which adminSources turns on. Empty, they
are published to everyone; stated, they are reachable from
adminSources alone – which reach every port the node serves
regardless, so this list narrows nothing.
An environment-level answer, since the ways in to a node belong to
whoever runs it. A host with one of its own – the hypervisor’s
incus API on :8443 – gets it from the environment too.
Type: list of 16 bit unsigned integer; between 0 and 65535 (both inclusive)
Default:
[
22
]
Example:
[
22
8443
]
Declared by:
firewall.policy.bridgeInterfaces
Interfaces whose traffic reaches only bridgeTCPPorts,
bridgeUDPPorts, the public ports of the node, and ICMP, e.g. a
hypervisor’s container bridge. The limit also holds for a source
in internalSources or adminSources, and the traffic of
operatorSources stays limited to the operator ports.
The bridge ports are also fed into
networking.firewall.interfaces.<name>, since nixos-fw’s
input is an independent base chain that has to be told that the
node serves them there.
Type: list of string
Default:
[ ]
Example:
[
"incusbr0"
]
Declared by:
firewall.policy.bridgeTCPPorts
TCP ports that the traffic on bridgeInterfaces reaches, in addition to the public ports.
Type: list of 16 bit unsigned integer; between 0 and 65535 (both inclusive)
Default:
[ ]
Example:
[
5000
]
Declared by:
firewall.policy.bridgeUDPPorts
UDP counterpart of bridgeTCPPorts.
Type: list of 16 bit unsigned integer; between 0 and 65535 (both inclusive)
Default:
[ ]
Example:
[
67
]
Declared by:
firewall.policy.internalSources
Sources allowed to reach every port a node serves – the
deployment’s own peers. Dual-stack: the family of each entry is
inferred from whether it contains a :.
This carries the hosting-provider mesh (spire’s trust-bundle fetch, openbao, the TF state backend, postgres, valkey), none of it published. Which addresses those are is a fact about where the deployment runs, not about any application.
Type: list of string
Default:
[ ]
Example:
[
"10.0.100.0/24"
]
Declared by:
firewall.policy.operatorSources
Sources that reach only operatorTCPPorts, operatorUDPPorts and
the public ports of the node, and ICMP. Same dual-stack inference.
The gate reads these before bridgeInterfaces,
trustedInterfaces, internalSources and adminSources, thus a
source here stays limited when it is also in one of them. This is
the case for the operator deployments on the hosting provider’s
bridge: their range is in the bridge subnet, and on the hypervisor
they come in on the bridge interface. The addresses of a cluster
(CLUSTER_SOURCES) are also here.
Type: list of string
Default:
[ ]
Example:
[
"10.0.104.0/21"
]
Declared by:
firewall.policy.operatorTCPPorts
TCP ports that operatorSources reach, in addition to the public ports.
Type: list of 16 bit unsigned integer; between 0 and 65535 (both inclusive)
Default:
[ ]
Example:
[
5432
]
Declared by:
firewall.policy.operatorUDPPorts
UDP counterpart of operatorTCPPorts.
Type: list of 16 bit unsigned integer; between 0 and 65535 (both inclusive)
Default:
[ ]
Example:
[
67
]
Declared by:
firewall.policy.publicTCPPorts
Ports this environment publishes on the node regardless of any application request, because the reason to publish them is a fact about the environment rather than about what the node serves.
The ACME challenge port is the case: whether a node’s names take a
publicly trusted leaf follows from the deployment’s uplink and its
published zone (core/setups/wiring/tls-routing.nix), and where they do,
the node must answer an HTTP-01 challenge on :80. The same
application behind no public uplink publishes nothing.
Concatenated with the applications’ requests of the same name, and subject to the same conjunction: it says who may reach the port, not that anything serves it.
Type: list of 16 bit unsigned integer; between 0 and 65535 (both inclusive)
Default:
[ ]
Example:
[
80
]
Declared by:
firewall.policy.publicUDPPorts
UDP counterpart of the policy’s publicTCPPorts.
Type: list of 16 bit unsigned integer; between 0 and 65535 (both inclusive)
Default:
[ ]
Example:
[
443
]
Declared by:
firewall.policy.trustedInterfaces
Interfaces whose traffic bypasses the gate. The traffic of
operatorSources stays limited on them. Also fed into
networking.firewall.trustedInterfaces, since nixos-fw’s
input is an independent base chain that has to be told the same
thing.
Type: list of string
Default:
[ ]
Example:
[
"wg0"
]
Declared by:
firewall.request
Options a component sets to request this resource.
Type: submodule
firewall.request.publicTCPPorts
TCP ports this application needs reachable from the whole internet rather than from the deployment’s own peers only.
Request this only for a port whose users are outside the
deployment by nature – an ingest, a federation endpoint, a
browser-facing listener. Everything else is reachable from
internalSources without asking.
The application still has to serve the port the ordinary way
(networking.firewall.allowedTCPPorts, or an upstream module’s
openFirewall); this says who may reach it, not that it exists.
Type: list of 16 bit unsigned integer; between 0 and 65535 (both inclusive)
Default:
[ ]
Example:
[
1935
]
Declared by:
firewall.request.publicUDPPorts
UDP counterpart of publicTCPPorts.
Type: list of 16 bit unsigned integer; between 0 and 65535 (both inclusive)
Default:
[ ]
Example:
[
53
]
Declared by:
garage
Garage storage configuration for an application.
Type: submodule
garage.policy
Options a hosting provider sets in an environment to supply this resource. The options that all policies share are on the data model page.
Type: submodule
garage.policy.enable
Whether to enable S3-compatible storage provider Garage.
Type: boolean
Default:
false
Example:
true
Declared by:
garage.policy.api.domain
The domain of the S3 API.
Type: string
Default:
"s3.${config.domain}"
Declared by:
garage.policy.api.domainForBucket
Gives the domain of a bucket on the S3 API (virtual-host style) from the name of the bucket.
Type: function that evaluates to a(n) string
Declared by:
garage.policy.api.port
The port on which Garage serves the S3 API.
Type: signed integer
Default:
3900
Declared by:
garage.policy.api.publicUrl
The URL of the S3 API for clients outside the internal network,
for example the target of a migration: HTTPS through the nginx
virtual host of bucketEndpointVhosts.
Type: string
Default:
"https://${config.api.domain}"
Declared by:
garage.policy.api.url
The URL of the S3 API for clients on the internal network:
plain HTTP to api.port, which the firewall opens only to
internal sources.
Type: string
Default:
"http://${config.api.domain}:${toString config.api.port}"
Declared by:
garage.policy.bucketEndpointVhosts
The NixOS modules with the nginx virtual hosts in front of the bucket endpoints. There is one virtual host for each family, not one for each bucket, because no evaluation knows all the buckets.
Type: list of unspecified value
Default:
One module with three nginx virtual hosts: *.<web.rootDomain>
for the website buckets, and <api.domain> and *.<api.domain>
for the S3 API.
Declared by:
garage.policy.cacheBackupRequestFor
Gives, from a list of { namespace, bucket ? ..., s3AccessKeyFile, s3SecretKeyFile }, the requests for the offsite cache-backup
bucket and key of each namespace. The requests have final names,
thus the caller adds them after apply and does not send them
through it.
Type: function that evaluates to a(n) list of unspecified value
Declared by:
garage.policy.domain
The domain of the Garage node. The domains of the S3 API
(api.domain) and of the websites (web.rootDomain) are below
it by default.
Type: string
Example:
"garage.example.org"
Declared by:
garage.policy.externalCopy
The S3 target outside this group for a daily copy of the
*-backups buckets (./external-copy.nix). With null, the node
makes no copy.
Type: null or (submodule)
Default:
null
Declared by:
garage.policy.externalCopy.bucket
The bucket at the target. A person makes it: the node does not make a bucket, thus the key of the target needs no right to do so.
Type: string
Example:
"fediversity-offsite"
Declared by:
garage.policy.externalCopy.credentialsSeed
The label of the S3 key of the target. The node reads the fields
accessKeyId and secretAccessKey of the KV entry
vars/secret/backup-external-copy/<label>, which a person seeds
(notes/bootstrap-seeds.md).
Type: string
Declared by:
garage.policy.externalCopy.endpoint
The S3 endpoint of the target, as <scheme>://<host>[:<port>]. The
target must not depend on the hosting provider of the group: a loss of
that site must not also lose the target.
Type: string
Example:
"https://s3.offsite.example.net"
Declared by:
garage.policy.externalCopy.historyDays
The days that an object stays at the target below history/ after it
changes or goes away in the source. This adds to the retention of the
source: see the retention section of the hosting provider guide.
Type: unsigned integer, meaning >=0
Default:
7
Declared by:
garage.policy.externalCopy.prefix
The path in bucket below which this garage writes. It must be unique
for each garage that shares bucket.
Type: string
Example:
"example.org"
Declared by:
garage.policy.externalCopy.region
The S3 region of the target.
Type: string
Example:
"eu-central-1"
Declared by:
garage.policy.provisionFor
Gives, from a list of requests with final names, the NixOS module
that makes their buckets, keys and grants on the Garage node
(./provision.nix).
Type: function that evaluates to a(n) unspecified value
Declared by:
garage.policy.provisioning
Who makes the buckets and the keys of this cluster.
in-nix: a oneshot on the Garage node makes them, and each consumer generates its own S3 key pair. Use it when the Garage node is in the same group as its consumers.tf: the operator TF graph makes them and publishes the key pairs at the same KV paths. Use it when the Garage node is in a different group, where a provisioner on the node cannot reach.
The setup sets one of them with mkDefault, thus a test can
set the other.
Type: one of “in-nix”, “tf”
Default:
"tf"
Declared by:
garage.policy.rpc.port
The port for the RPC traffic between the Garage nodes.
Type: signed integer
Default:
3901
Declared by:
garage.policy.tenant
A prefix for the names in a cluster that more than one group
uses. When it is not empty, each bucket name, key name and
ensureAccess bucket key gets the physical name
<tenant>-<name>, thus the objects of one group stay apart from
those of a different group. When it is empty, the names do not
change.
The setup supplies the deployment where there is one, and the
group otherwise (core/setups/hosts-common.nix).
Type: string
Default:
""
Example:
"operator"
Declared by:
garage.policy.web.domainForBucket
Gives the domain of the website of a bucket from the name of the bucket.
Type: function that evaluates to a(n) string
Declared by:
garage.policy.web.internalPort
The local port on which Garage serves the website buckets. The nginx virtual host of bucketEndpointVhosts sends requests to it.
Type: signed integer
Default:
3902
Declared by:
garage.policy.web.rootDomain
The domain below which Garage serves each website bucket (s3_web.root_domain).
Type: string
Default:
"web.${config.domain}"
Declared by:
garage.policy.web.urlForBucket
Gives the URL of the website of a bucket from the name of the bucket.
Type: function that evaluates to a(n) string
Declared by:
garage.request
Options a component sets to request this resource.
Type: submodule
garage.request.enable
Whether to enable Enable a Garage server on the machine.
Type: boolean
Default:
false
Example:
true
Declared by:
garage.request.ensureBuckets
S3 buckets to create on Garage for this application, keyed by bucket name. Each entry is created with its website access when the deployment runs. CORS rules apply under each provisioning mode: on the co-located test path (ensure-garage), in the operator TF graph and on the garage node’s own reconciler.
Type: attribute set of (submodule)
Default:
{ }
Declared by:
garage.request.ensureBuckets.<name>.corsRules.enable
Whether to enable CORS rules on this bucket, allowing other origins (e.g. a frontend) to fetch its objects from the browser.
Type: boolean
Default:
false
Example:
true
Declared by:
garage.request.ensureBuckets.<name>.corsRules.allowedHeaders
Request headers permitted by the bucket’s CORS policy (the AllowedHeaders of the S3 CORS rule).
Type: list of string
Default:
[ ]
Declared by:
garage.request.ensureBuckets.<name>.corsRules.allowedMethods
HTTP methods (e.g. GET, PUT) permitted by the bucket’s CORS policy.
Type: list of string
Default:
[ ]
Declared by:
garage.request.ensureBuckets.<name>.corsRules.allowedOrigins
Origins (e.g. https://app.example.org) allowed to make cross-origin requests to the bucket.
Type: list of string
Default:
[ ]
Declared by:
garage.request.ensureBuckets.<name>.retainKvStems
The vars instances of the deployment that the data in this bucket cannot be used without, such as the password of a restic repository or the keys of an offsite backup. When the operator TF graph retires a *-backups bucket, it keeps these instances (their secret/ and public/ halves) for the grace period of the retained bucket, and the garage node deletes them together with the bucket.
Type: list of string
Default:
[ ]
Declared by:
garage.request.ensureBuckets.<name>.serveAsWebsite
Whether to serve this bucket’s contents as a static website over HTTP, so its objects are publicly reachable by URL.
Type: boolean
Default:
false
Declared by:
garage.request.ensureKeys
S3 access keys to provision on Garage for this application, keyed by key name. Each key is imported from the given credential files and granted the configured per-bucket access.
Type: attribute set of (submodule)
Default:
{ }
Declared by:
garage.request.ensureKeys.<name>.ensureAccess
Per-bucket access this key is granted, keyed by bucket name. Each entry must set at least one of read/write/owner.
Type: attribute set of (submodule)
Default:
{ }
Declared by:
garage.request.ensureKeys.<name>.ensureAccess.<name>.owner
Grant this key owner permission on the bucket (manage the bucket itself, not just its objects).
Type: boolean
Default:
false
Declared by:
garage.request.ensureKeys.<name>.ensureAccess.<name>.read
Grant this key permission to read objects from the bucket.
Type: boolean
Default:
false
Declared by:
garage.request.ensureKeys.<name>.ensureAccess.<name>.write
Grant this key permission to write objects to the bucket.
Type: boolean
Default:
false
Declared by:
garage.request.ensureKeys.<name>.kvName
OpenBao KV instance stem the key’s credentials publish under (<kvName>-s3). Defaults to the key name; not tenant-prefixed.
Type: string
Default:
"‹name›"
Declared by:
garage.request.ensureKeys.<name>.s3AccessKeyFile
Path to a file holding the S3 access key id to import
for this key. The in-Nix (garageSide) provisioner and
the garage node’s own reconciler (provisionFor)
import a pre-generated key from it; the operator TF
graph has garage create the key and captures the
secret from state, so it leaves this null. The path is
the rendered read-back location, not a generation
source.
Type: null or absolute path
Default:
null
Declared by:
garage.request.ensureKeys.<name>.s3SecretKeyFile
Path to a file containing the S3 secret access key paired with s3AccessKeyFile. Null for the tf provisioner (see s3AccessKeyFile).
Type: null or absolute path
Default:
null
Declared by:
generateFiles
Declarative generation of an application’s secret files, via the generateFiles contract.
Type: submodule
generateFiles.policy
Options a hosting provider sets in an environment to supply this resource. The options that all policies share are on the data model page.
Type: submodule
generateFiles.policy.address
Address of the OpenBao server backing vars and the shared agent.
Type: string
Default:
"http://127.0.0.1:8200"
Example:
"http://openbao:8200"
Declared by:
generateFiles.policy.caCertFile
CA certificate the vars-openbao upload and the shared openbao agent verify the server’s TLS against. Set in production, where
the openbao node’s PKI leaf chains to it; empty in tests, which
use plain http://.
Type: string
Default:
""
Declared by:
generateFiles.policy.consumerModule
The bare OpenBao consumer plumbing – the vars/vars-openbao
modules, shared agent, production extraModules and routing – with
no generateFiles request. A node that only reads a shared
vars-openbao secret back through the agent needs this body but has
no generation of its own to trigger apply. This resource exposes
the body; the consuming resource owns whether to emit it (the setup
feeds it into the oidc resource’s consumerAgent).
Type: unspecified value (read only)
Declared by:
generateFiles.policy.extraModules
Extra NixOS modules emitted alongside the consumer – e.g. ./spire-login.nix, which in production publishes the SPIRE SVID pair the agent logs in with, and populates tokenFile for the units that use a token.
Type: list of unspecified value
Default:
[ ]
Declared by:
generateFiles.policy.tokenFile
File holding the OpenBao token for vars-openbao and the agent’s token_file auto-auth.
Type: absolute path
Default:
"/run/keys/vars-openbao-token"
Declared by:
generateFiles.request
Options a component sets to request this resource.
Type: submodule
generateFiles.request.instances
Generation instances this application needs run on its host, keyed
by name. Each mirrors a contracts.generateFiles request: a
script producing the named files under $out/. The vars
provider bridges each generated file into
contracts.fileSecrets.want.vars.<name>_<file>, read back via
config.contracts.fileSecrets.results.vars.<name>_<file>.path.
Type: attribute set of (submodule)
Default:
{ }
Declared by:
generateFiles.request.instances.<name>.dependencies
Names of other instances whose outputs are made available under $in/<name>/.
Type: list of string
Default:
[ ]
Declared by:
generateFiles.request.instances.<name>.files
Files to generate; keys are file names the script must write under $out/.
Type: attribute set of (submodule)
Declared by:
generateFiles.request.instances.<name>.files.<name>.group
Unix group that must own the generated file.
Type: string
Default:
"root"
Declared by:
generateFiles.request.instances.<name>.files.<name>.mode
File permissions as an octal string.
Type: string
Default:
"0400"
Declared by:
generateFiles.request.instances.<name>.files.<name>.owner
Unix user that must own the generated file.
Type: string
Default:
"root"
Declared by:
generateFiles.request.instances.<name>.files.<name>.secret
Whether the file contains sensitive data.
Type: boolean
Default:
true
Declared by:
generateFiles.request.instances.<name>.independent
Whether the instance’s files stand on their own. An atomic instance (the default) refuses to run in a partial state; an independent one generates only what is missing, so it can grow a file without rotating its siblings.
Type: boolean
Default:
false
Declared by:
generateFiles.request.instances.<name>.runtimeInputs
Attribute paths in pkgs of the packages available in PATH during script execution, such as "openssl". They are names because the plan of a node must hold no derivation.
Type: list of string
Default:
[ ]
Declared by:
generateFiles.request.instances.<name>.script
Shell script writing each declared file to $out/<name>.
Dependency outputs are available under $in/<dep>/.
Type: string
Declared by:
generateFiles.request.readInstances
Names of instances that another application writes and this
application reads, such as a token that the two share. This
resource generates nothing for them; the setup only grants the
application’s host read access under vars/secret/<name>/.
Type: list of string
Default:
[ ]
Declared by:
generateFiles.request.readKeys
Single keys, as <instance>/<key>, of instances that another
application writes and this application reads, where the
instance also holds keys that this application must not read.
This resource generates nothing for them; the setup only grants
the application’s host read access on
vars/secret/<instance>/<key>.
Type: list of string
Default:
[ ]
Declared by:
generateFiles.request.writtenInstances
Names of instances this application writes to the vars backend by
its own means, such as a contracts.generateFiles.want in its
module or a oneshot that publishes a runtime value. This resource
generates nothing for them; the setup only grants the application’s
host write access under vars/secret/<name>/, as it does for
instances.
Type: list of string
Default:
[ ]
Declared by:
ldap
LDAP directory access for an application, fulfilled by an lldap-backed provider of the nixpkgs ldap contract.
Type: submodule
ldap.policy
Options a hosting provider sets in an environment to supply this resource. The options that all policies share are on the data model page.
Type: submodule
ldap.policy.enable
Whether to enable LDAP directory provider.
Type: boolean
Default:
false
Example:
true
Declared by:
ldap.policy.adminUser
Name of the seeded directory administrator. The setup reads it
from ldap.adminUser in the group data. The in-tree groups use
the group name, so the account says which group it administers
and two groups’ directories never read as one.
An lldap user id is its immutable primary key, so a changed name
arrives as a second account and the first one needs a manual
removal.
Pixelfed refuses an account named on its own RestrictedNames
list, admin and administrator among them, so a group that runs
pixelfed needs a name pixelfed permits.
Type: string
Example:
"operator"
Declared by:
ldap.policy.baseDN
Base distinguished name for the directory. Defaults to the
domain with its leading subdomain label dropped and each
remaining label turned into a dc= component
(e.g. ldap.fediversity.net -> dc=fediversity,dc=net).
Type: string
Default:
concatMapStringsSep "," (label: "dc=${label}") (drop 1 (splitString "." config.domain))
Declared by:
ldap.policy.bindInstanceName
Name of the generateFiles/vars instance carrying the directory’s
admin (management-bind) password, and so the stem of both its
central-OpenBao KV path and the rendered file path. The setup
group-qualifies it to ldap-bind-<group> so two groups’ lldap
nodes never overwrite each other’s admin password on the one
shared central OpenBao KV.
Type: string
Default:
"ldap-bind"
Declared by:
ldap.policy.crossNode
Cross-node factory: { consumer, group } -> { result; bridge; ... }, the crossNodeWant answer. result holds url, host, port, caFile, baseDN, userBaseDN, groupBaseDN, bindDN and bindPasswordFile; bridge gives the result to the ldap contract of the consumer node.
Type: unspecified value (read only)
Declared by:
ldap.policy.domain
Service domain the LDAP directory is named under; baseDN derives from it.
Type: string
Example:
"ldap.example.org"
Declared by:
ldap.policy.email
Email address of the seeded directory administrator (adminUser).
The directory is seeded with a single administrator at deploy
time, added to authelia-users so it can authenticate through
authelia OIDC.
The account is created password-less, and the administrator establishes its password with “Forgot password?” on the authelia portal, which mails a single-use link here, so this address has to be deliverable.
lldap-provision reconciles the account on each deploy with
OpenTofu. When this option becomes empty, the unit deletes the
account. Directory users that the deployment did not seed stay.
Type: string
Example:
"admin@example.org"
Declared by:
ldap.policy.host
Reachable address consumers connect to the lldap daemon at – the
lldap node’s deployment FQDN, supplied by hosts-common.nix.
Defaults to the domain for the single-node behaviorTest.
Type: string
Default:
config.domain
Declared by:
ldap.policy.httpPort
HTTP/GraphQL port the lldap web interface and CLI use.
Type: 16 bit unsigned integer; between 0 and 65535 (both inclusive)
Default:
17170
Declared by:
ldap.policy.jwtSecretInstanceName
Name of the generateFiles/vars instance carrying the secret
with which lldap signs the tokens of its sessions, and so the
stem of both its central-OpenBao KV path and the rendered file
path. All pods and nodes of a group that serve the same directory
must have the same secret. The setup group-qualifies it to
ldap-jwt-<group>, for the same reason as bindInstanceName.
Type: string
Default:
"ldap-jwt"
Declared by:
ldap.policy.keySeedInstanceName
Name of the generateFiles/vars instance carrying the seed of
the OPAQUE server key of lldap, and so the stem of both its
central-OpenBao KV path and the rendered file path. The key
encrypts the password of each user, thus a key that is not the
same after a rebuild or a restore makes all passwords unusable.
The setup group-qualifies it to ldap-key-<group>, for the same
reason as bindInstanceName.
Type: string
Default:
"ldap-key"
Declared by:
ldap.policy.port
Plaintext LDAP port the lldap daemon listens on.
Type: 16 bit unsigned integer; between 0 and 65535 (both inclusive)
Default:
3890
Declared by:
ldap.policy.rolesInstanceName
Name of the vars instance that holds the members of the
roleGroups of the applications, as the file members, and so
the stem of its central-OpenBao KV path. The lldap node writes
it, and each application node with roleGroups reads it. The
setup group-qualifies it to ldap-roles-<group>, for the same
reason as bindInstanceName.
Type: string
Default:
"ldap-roles"
Declared by:
ldap.policy.tls.enable
Whether the lldap daemon also serves LDAPS. Consumers then
connect with ldaps:// on tls.port, and verify the listener
against tls.caFile. The setup supplies the certificate on the
lldap node, with fediversity.lldap.tls.certFile and keyFile.
Type: boolean
Default:
false
Declared by:
ldap.policy.tls.caFile
Path, on a consumer node, to the PEM CA certificate that signs
the LDAPS certificate. Given to consumers as the contract
result.caFile.
Type: null or string
Default:
null
Declared by:
ldap.policy.tls.port
LDAPS port the lldap daemon listens on.
Type: 16 bit unsigned integer; between 0 and 65535 (both inclusive)
Default:
6360
Declared by:
ldap.request
Options a component sets to request this resource.
Type: submodule
ldap.request.enable
Whether to enable LDAP directory access for the application.
Type: boolean
Default:
false
Example:
true
Declared by:
ldap.request.consumerName
Unique consumer name for this app (analog of oidc’s clientID),
used as the contracts.ldap.want.<consumerName> key. Necessary
when group is not null.
Type: null or string
Default:
null
Declared by:
ldap.request.group
LDAP group the application requires. The provider creates this
group. Carried verbatim by the nixpkgs ldap contract request.
If null, the request asks for no directory access, and only
roleGroups applies.
Type: null or string
Default:
null
Declared by:
ldap.request.roleGroups
The directory groups that give a role in the application, by
group name. The provider creates each group, and publishes the
user ids of its members to the KV stem rolesInstanceName. The
application node gets a read grant for that stem, and the
application syncs the roles of its accounts from it. The
application does not get a password of the directory.
Type: attribute set of (submodule)
Default:
{ }
Declared by:
ldap.request.roleGroups.<name>.seedAdmin
Whether the seeded directory administrator (adminUser)
is a member of this group.
Type: boolean
Default:
false
Declared by:
netbox
NetBox IPAM coordinates for an application, fulfilled by either a self-hosted NetBox node or an external instance, through the local netbox contract.
Type: submodule
netbox.policy
Options a hosting provider sets in an environment to supply this resource. The options that all policies share are on the data model page.
Type: submodule
netbox.policy.enable
Whether to enable NetBox IPAM provisioning for this deployment.
Type: boolean
Default:
false
Example:
true
Declared by:
netbox.policy.allocateIpv4
Whether a public node is allocated a v4 address from the pool. Off
(the default), the deployment is v6-only, apart from a v4 address
that a node’s machines entry pins.
Type: boolean
Default:
false
Declared by:
netbox.policy.clusterName
Name of the NetBox cluster the deployment’s virtual machines are
recorded under. Must already exist at whichever provider is routed
– the deploy reads it and creates no NetBox infrastructure. At the
external provider this today means naming one of their clusters;
a dedicated Fediversity cluster there is a follow-up (see
notes/bootstrap-full-ladder.md).
A deployment’s node names are its own – every deployment has an
openbao – so either this names a cluster per deployment, or the
deployments sharing one are told apart by tenant.
Type: string
Default:
"incus"
Declared by:
netbox.policy.prefixSelector
How the deployment discovers the prefix(es) to allocate from, without naming a subnet.
Type: submodule
Default:
{ }
Declared by:
netbox.policy.prefixSelector.kind
How to select the prefix pool: cidr, id, or the name of a NetBox prefix filter (tag, status, site_id, …).
Type: string
Default:
"tag"
Declared by:
netbox.policy.prefixSelector.value
The value of the selector: a CIDR, a comma-separated list of prefix IDs, or the value of the filter.
Type: string
Default:
"fediversity"
Declared by:
netbox.policy.rangeSelector
How the deployment discovers an IP range to allocate from instead
of the whole prefix, for the family that range covers. Where the
NetBox instance is shared with its owner, the prefix is theirs and
only a range within it is ours. An empty kind (the default)
selects no range and allocates from the prefix.
Type: submodule
Default:
{ }
Declared by:
netbox.policy.rangeSelector.kind
How to select the range: id, or the name of a NetBox IP range filter such as tag. When it is empty, the deployment selects no range.
Type: string
Default:
""
Example:
"tag"
Declared by:
netbox.policy.rangeSelector.value
The value of the selector: a comma-separated list of range IDs, or the value of the filter.
Type: string
Default:
""
Example:
"fediversity"
Declared by:
netbox.policy.tenant
Name of the NetBox tenant the deployment’s virtual machines are
recorded under, which is what makes two deployments able to share
one cluster: NetBox keys a virtual machine’s uniqueness on cluster,
tenant and name together, so without one the second deployment’s
openbao collides with the first’s. Must already exist at whichever
provider is routed, on the same read-never-create footing as
clusterName.
Empty (the default) records the virtual machines untenanted, which is correct wherever the deployment has a cluster to itself.
Type: string
Default:
""
Declared by:
netbox.request
Options a component sets to request this resource.
Type: submodule
netbox.request.enable
Whether to enable NetBox IPAM coordinates on this application’s host.
Type: boolean
Default:
false
Example:
true
Declared by:
netbox.request.consumerName
Unique consumer name for this app (analog of ldap’s/redis’s
consumerName), used as the contracts.netbox.want.<consumerName>
key. The node gets the contract result ({ serverUrl; apiTokenFile; clusterName; tenant; prefixSelector; rangeSelector; allocateIpv4; }) at
contracts.netbox.results.<consumerName>.default.
Type: string
Declared by:
network
Networking info.
Type: submodule
network.policy
Options a hosting provider sets in an environment to supply this resource. The options that all policies share are on the data model page.
Type: submodule
network.policy.domain
The apex this machine’s FQDN suffix and resolv.conf search
domain hang off, i.e. networking.domain.
Deliberately undefaulted: it is the deployment’s apex, which only
the setup knows, and a module default here is silent when wrong –
a short peer name still resolves, just possibly to another
deployment’s node. core/setups/hosts-common.nix supplies the
group’s own domain for every node it deploys.
Type: unspecified value
Example:
"example.org"
Declared by:
network.policy.ipv4
The IPv4 settings of the machine.
Type: submodule
Default:
{ }
Declared by:
network.policy.ipv4.address
The IPv4 address of the machine, with or without a prefix
length (default 24). The machine gets it on interface, and
the gates of the group admit it
(core/setups/hosts-common.nix). An incus machine
reads the address that NetBox allocates at run time
(./run-time.nix), and uses this address when it finds
none.
Type: unspecified value
Default:
null
Declared by:
network.policy.ipv4.gateway
The IP address of the default gateway. With null, the
machine gets no static default route, and takes it from
somewhere else, for example a DHCP lease.
Type: unspecified value
Default:
null
Declared by:
network.policy.ipv4.interface
The interface that carries the machine’s IPv4 network.
Type: unspecified value
Default:
"eth0"
Declared by:
network.policy.ipv6
The IPv6 settings of the machine.
Type: submodule
Default:
{ }
Declared by:
network.policy.ipv6.address
The IPv6 address of the machine, with or without a prefix
length (default 64). The machine gets it on interface, and
the gates of the group admit it
(core/setups/hosts-common.nix). An incus machine
reads the address that NetBox allocates at run time
(./run-time.nix), and uses this address when it finds
none.
Type: unspecified value
Default:
null
Declared by:
network.policy.ipv6.gateway
The IP address of the default gateway. With null, the
machine gets no static default route, and takes it from
somewhere else, for example a DHCP lease.
Type: unspecified value
Default:
null
Declared by:
network.policy.ipv6.interface
The interface that carries the machine’s IPv6 network.
Type: unspecified value
Default:
"eth0"
Declared by:
network.policy.name
The name of the machine. Most of the time, this will look like vm02XXX
or fediYYY.
Type: unspecified value
Default:
"nixos"
Declared by:
network.policy.nameservers
Resolvers this machine asks before the upstream ones
(fediversity.resolvers, core/setups/nixos/networking.nix),
i.e. the head of networking.nameservers.
“Before” only in the rendered list: it goes to
systemd-resolved’s global DNS=, where position carries no
preference, and every server there is eligible for every name.
So a resolver here gets every name it is willing to answer, and
the list must hold only resolvers that agree with the group zone.
What keeps the apex off the upstream resolvers is the routing
domain on the bridge link, not this order.
core/setups/hosts-common.nix sets it to the group’s own DNS
nodes where they hold the apex.
Type: list of string
Default:
[ ]
Declared by:
network.policy.needsPublicIp
Whether this node exposes public services and therefore needs a
routed/public IP allocated from NetBox. Internal-only nodes (which
settle for internal/PKI TLS and are reached over the private
network) set this false, so hosts-common.nix skips NetBox
allocation for them. Defaults to true.
Type: unspecified value
Default:
true
Declared by:
network.policy.publicUplink
How the machine’s public address is DELIVERED to it, and hence
whether the gateway its machines entry states is reachable
from the machine at all.
bridged(the default): the address is delivered on-link, on the interface the machine sees – a physical segment, or a VLAN tagged onto it. The stated gateway is a neighbour, so it is rendered as the default route. This is what a machine on a hosting provider’s own network has always had.nat: the address is only an ALIAS on a NAT bridge that has no uplink to the public segment. The stated gateway is NOT reachable, and rendering it installs a metric-0 default route that shadows the bridge’s own DHCP default – taking the machine’s egress away entirely. So it is suppressed, and the address stays what it is: a label the outside world resolves, which nothing yet delivers.
This is a property of the hosting provider’s topology rather than
of the machine, so it arrives with the rest of the deployment’s
coordinates (PUBLIC_UPLINK, core/effects/env-config.nix)
rather than being stated per machine.
Type: one of “bridged”, “nat”
Default:
"bridged"
Declared by:
network.request
Options a component sets to request this resource.
Type: submodule
nixos-module
A NixOS configuration module to include as-is.
Type: submodule
nixos-module.policy
Options a hosting provider sets in an environment to supply this resource. The options that all policies share are on the data model page.
Type: submodule
nixos-module.policy.module
The NixOS configuration module to include.
Type: unspecified value
Default:
{ }
Declared by:
nixos-module.request
Options a component sets to request this resource.
Type: submodule
nixos-module.request.module
The NixOS configuration module to include.
Type: unspecified value
Declared by:
oidc
Single sign-on (OIDC) for an application, fulfilled by an authelia-backed provider of the nixpkgs oidc contract.
Type: submodule
oidc.policy
Options a hosting provider sets in an environment to supply this resource. The options that all policies share are on the data model page.
Type: submodule
oidc.policy.enable
Whether to enable single sign-on (OIDC) provider.
Type: boolean
Default:
false
Example:
true
Declared by:
oidc.policy.cookieDomain
Domain the authelia session cookie is scoped to. Defaults to the
provider domain (e.g. auth.example.org), which is correct for
pure OIDC. Forward-auth needs the cookie to reach the protected UI
subdomains, so the setup widens this to the registrable parent
(example.org) when forward-auth consumers exist – authelia_url
stays the portal subdomain, which authelia allows as long as it is a
subdomain of the cookie domain. Kept default (== domain) otherwise
so an OIDC-only deployment is byte-unchanged.
Type: string
Default:
config.domain
Declared by:
oidc.policy.deployAdminUIs
Whether to deploy the hosting provider’s forward-auth admin UIs
(garage-webui, pgweb, redis-commander) – plain services fronted by
authelia forward-auth for backends with no native OIDC. A single
policy switch for the whole admin-UI category rather than a per-app
option: the UIs are prod conveniences with no test value, so a
focused deployment test drops them all at once (keeping the UI
packages + their nginx forward-auth vhosts out of the node closures)
by routing this policy to false. Defaults true so a real
deployment is unchanged.
It gates that CATEGORY alone: a forwardAuth request that states
adminUI = false is part of the service it fronts and is deployed
whatever this says. core/setups/hosts-common.nix reads the same
rule, so a UI dropped here is not a name it counts as served.
Type: boolean
Default:
true
Declared by:
oidc.policy.deploymentDomain
The domain this deployment is configured for, which a
forwardAuth request’s subdomain is hung off.
Distinct from the static apex (core/apex.nix): a tenant
deployment names its own domain in its deployment configuration,
long after the hosting provider whose apex the nodes sit under was
deployed. Set by core/setups/hosts-common.nix, the one reader of
the resolved deployment configuration.
Type: string
Default:
""
Declared by:
oidc.policy.domain
Domain the OIDC provider (authelia) is served under.
Type: string
Example:
"auth.example.org"
Declared by:
oidc.policy.instanceName
Name of the generateFiles/vars instance holding the authelia
daemon’s secrets and the shared OIDC client secret, and so the
stem of their central OpenBao KV paths. Reaches the authelia node
and every consumer of it alike, the consumer reading the client
secret back from that path.
The setup qualifies it by the group running the authelia, which is
what keeps two groups’ client registrations apart on the one
shared KV; see the provider module’s own instanceName for what a
collision costs.
Type: string
Default:
"authelia-oidc"
Declared by:
oidc.policy.issuer
OIDC issuer URL (the provider’s discovery endpoint base).
Type: string
Default:
"https://${config.domain}"
Declared by:
oidc.policy.port
Local port the authelia daemon listens on.
Type: signed integer
Default:
9091
Declared by:
oidc.request
Options a component sets to request this resource.
Type: submodule
oidc.request.enable
Whether to enable an OIDC single-sign-on client for the application.
Type: boolean
Default:
false
Example:
true
Declared by:
oidc.request.accessTokenClaims
Claims that the provider also puts in the JWT access token of
this client, such as groups. Each claim needs a scope in
scopes that grants it. For a consumer that reads the claims
of the access token, e.g. the authorization scriptlet of the
incus daemon. Needs jwtAccessTokens.
Type: list of string
Default:
[ ]
Declared by:
oidc.request.allowedGroups
Directory groups whose members can log in to this client. Membership of one group is sufficient. An empty list sets no group limit, and each user of the directory can log in.
Set this for a client that gives access to all users that
complete the login and has no group check of its own.
authorizationPolicy must be one_factor or two_factor
when this list is not empty.
Type: list of string
Default:
[ ]
Declared by:
oidc.request.authorizationPolicy
Authelia authorization policy applied to the client
(one_factor, two_factor, or a named policy).
one_factor is the default, matching authelia’s
access_control.default_policy and the forward-auth default: a
directory account alone opens the client. A client that demands
MFA sets two_factor itself, and then every user of that client
has to enroll a second factor before the authorize request
succeeds – authelia refuses it with “The resource you’re
attempting to access requires two-factor authentication”.
Type: string
Default:
"one_factor"
Declared by:
oidc.request.clientID
Client ID to register with the OIDC provider. Null for a
forwardAuth request (which registers no OIDC client – authelia
protects the vhost through nginx auth_request, not a redirect
flow).
Type: null or string
Default:
null
Declared by:
oidc.request.forwardAuth
Forward-auth protection for a plain (non-OIDC) admin UI vhost,
instead of an OIDC client. A request is EITHER an OIDC client
(clientID/redirectURI set) OR a forward-auth protection
(forwardAuth.enable). When set, nginx fronts upstream with an
auth_request to authelia’s /api/authz/auth-request endpoint, so
only authenticated sessions reach the UI – used for services with
no native OIDC (garage-webui, pgweb, redis-commander, windmill).
Type: null or (submodule)
Default:
null
Declared by:
oidc.request.forwardAuth.enable
Whether to enable forward-auth protection for this UI vhost.
Type: boolean
Default:
false
Example:
true
Declared by:
oidc.request.forwardAuth.adminUI
Whether this vhost belongs to the hosting provider’s
admin-UI category, which deployAdminUIs gates as a whole.
True for a prod convenience fronting a backend with no native OIDC (garage-webui, pgweb, redis-commander). Set false for a UI that is part of the service it fronts and that every group running that service needs – lldap’s own web UI, which is the directory’s self-service surface.
Type: boolean
Default:
true
Declared by:
oidc.request.forwardAuth.allowedGroups
Restrict access to members of these authelia groups. Empty
(the default) allows any authenticated user (subject to
authorizationPolicy).
Type: list of string
Default:
[ ]
Declared by:
oidc.request.forwardAuth.authorizationPolicy
Authelia authorization policy for this domain (one_factor
suffices for any authenticated user; two_factor for MFA).
Type: string
Default:
"one_factor"
Declared by:
oidc.request.forwardAuth.domain
Public domain the protected UI is served under, stated in
full (e.g. garage-webui.example.org). For a UI published
in a zone this deployment does not own; subdomain below
is what names one under the deployment’s own domain.
Exactly one of the two is set – see
./forward-auth-domain.nix, which resolves them.
Type: null or string
Default:
null
Declared by:
oidc.request.forwardAuth.proxyWebsockets
Pass websocket upgrades through to the protected UI. Needed by a UI that streams over a websocket – the windmill UI’s job logs – and off by default, since the plain admin UIs (garage-webui, pgweb, redis-commander, lldap) do not.
Type: boolean
Default:
false
Declared by:
oidc.request.forwardAuth.subdomain
The label the protected UI is served under, hung off the
deployment’s own deploymentDomain.
What a component SHARED between groups states: a tenant
deployment’s domain is the tenant’s own name, and a shared
component that instead reaches for the static apex
(core/apex.nix) names the hosting provider’s node from
inside the tenant’s deployment – a name the tenant may
neither publish nor hold a certificate for.
Type: null or string
Default:
null
Declared by:
oidc.request.forwardAuth.unauthenticatedLocations
nginx location keys that the gate proxies to upstream
without auth_request, each with extra nginx config for
that location (usually empty). For a flow of the
protected UI that a user must reach without a session,
such as the password reset of lldap. On these locations
the gate sends empty Remote-* headers, so a client
cannot set them.
Keep each key as narrow as the flow. An exempt prefix that also covers a login of the UI lets a user log in without the portal.
Type: attribute set of strings concatenated with “\n”
Default:
{ }
Example:
{
"^~ /reset-password/" = "";
}
Declared by:
oidc.request.forwardAuth.upstream
Proxy target nginx forwards to once authenticated (e.g. 127.0.0.1:3909).
Type: string
Declared by:
oidc.request.forwardAuth.upstreamAuthorizationInclude
nginx include pattern pulled into location /, for a
protected UI that cannot log a user in itself: one who has
just cleared the portal would otherwise be met by a second,
unrelated login form. A unit on the node drops a
proxy_set_header Authorization ...; line matching this
pattern once it holds a token to present, and the gate then
presents it on that user’s behalf.
A glob rather than a fixed path, because nginx has to start
before that unit has ever run: an include of a missing
file refuses to load, while one whose mask matches nothing
is not an error.
Null (the default) leaves the gate a plain proxy, which is
what a UI that authenticates the forwarded Remote-User
itself wants.
Type: null or string
Default:
null
Declared by:
oidc.request.jwtAccessTokens
Issue RFC 9068 JWT-profile access tokens to this client
(access_token_signed_response_alg: RS256) instead of
authelia’s default opaque tokens. For consumers that verify
the bearer access token locally as a JWT against the issuer’s
JWKS, e.g. the incus daemon, which parses every bearer token
and rejects an opaque one with “token contains an invalid
number of segments”.
Type: boolean
Default:
false
Declared by:
oidc.request.public
Register the client as a public OIDC client (no client
secret; token_endpoint_auth_method: none, PKCE enforced).
For consumers that cannot hold a secret, e.g. the incus UI,
whose token exchange sends no client authentication.
Type: boolean
Default:
false
Declared by:
oidc.request.redirectURI
Primary callback URI the provider should redirect to after
authentication. This is the value carried by the nixpkgs oidc
contract request; additional URIs go in redirectURIs. Null for a
forwardAuth request (no redirect flow).
Type: null or string
Default:
null
Declared by:
oidc.request.redirectURIs
Extra callback URIs to register on the OIDC client, beyond
redirectURI. Authelia registers the union of redirectURI and
these. The contract request carries them, so the client reads
them from contracts.oidc.results.<clientID>.default.
Type: list of string
Default:
[ ]
Declared by:
oidc.request.scopes
OIDC scopes the client may request. Defaults to the standard
OpenID Connect profile scopes. The contract request carries them,
so the client reads them from
contracts.oidc.results.<clientID>.default and requests the
scopes that authelia lets it request.
Type: list of string
Default:
[
"openid"
"profile"
"email"
]
Declared by:
otel
OpenTelemetry collector endpoint for emitting telemetry signals from an
application. The policy carries the collector’s OTLP endpoint. When an
application on a node requests the resource, the resource sets
fediversity.otel.endpoints.<consumerName> on that node, and the OTel
module of the application renders its per-service settings from it.
Type: submodule
otel.policy
Options a hosting provider sets in an environment to supply this resource. The options that all policies share are on the data model page.
Type: submodule
otel.policy.endpoint
OTLP HTTP endpoint of the fediversity collector (e.g.
http://otel-collector.vpn:4318). When null, per-app OTel
wiring stays disabled even if applications request the resource.
Type: null or string
Default:
null
Example:
"http://otel-collector.vpn:4318"
Declared by:
otel.request
Options a component sets to request this resource.
Type: submodule
otel.request.enable
Whether to enable emitting OpenTelemetry signals from this application to the configured collector.
Type: boolean
Default:
false
Example:
true
Declared by:
otel.request.consumerName
The name of the application under fediversity.otel.endpoints,
where the OTel module of the application reads the endpoint.
Type: string
Example:
"windmill"
Declared by:
pod-roles
Roles of a node, each with pods of its own when the node runs as a pod.
Type: submodule
pod-roles.policy
Options a hosting provider sets in an environment to supply this resource. The options that all policies share are on the data model page.
Type: submodule
pod-roles.request
Options a component sets to request this resource.
Type: submodule
pod-roles.request.roles
The roles of the node. The name of a role is a part of the name of its Deployment.
Type: attribute set of (submodule)
Default:
{ }
Declared by:
pod-roles.request.roles.<name>.companion
Whether each pod of the role has a second container, from the image of the service, for work that connects to the service on the loopback address of the pod. The node module of the application gives the program in fediversity.podRoles.services.
Type: boolean
Default:
false
Declared by:
pod-roles.request.roles.<name>.metrics
The port at which each pod of a role serves its Prometheus metrics, on the address of the pod. The deploy makes a headless Service <node>-<role>-metrics for the port, and lets only the main pod of the node reach it. The metrics shipper of the main pod scrapes each pod of the role and pushes the series with the series of the node. null when the pods of the role have no metrics to scrape.
Type: null or (submodule)
Default:
null
Declared by:
pod-roles.request.roles.<name>.metrics.path
The HTTP path of the metrics.
Type: string
Default:
"/metrics"
Declared by:
pod-roles.request.roles.<name>.metrics.port
The TCP port of the metrics.
Type: 16 bit unsigned integer; between 0 and 65535 (both inclusive)
Declared by:
pod-roles.request.roles.<name>.ports
The ports at which the pods of a role receive connections. The deploy makes a Service <node>-<role> in the cluster for them, and a NetworkPolicy that lets in the sources that reach the ports that the node serves. With no ports, the pods of the role receive no connections.
Type: list of (submodule)
Default:
[ ]
Declared by:
pod-roles.request.roles.<name>.ports.*.port
The number of the port.
Type: 16 bit unsigned integer; between 0 and 65535 (both inclusive)
Declared by:
pod-roles.request.roles.<name>.ports.*.protocol
The protocol of the port.
Type: one of “TCP”, “UDP”
Default:
"TCP"
Declared by:
pod-roles.request.roles.<name>.replicas
The number of pods of the role.
Type: positive integer, meaning >0
Default:
1
Declared by:
pod-roles.request.roles.<name>.secrets
The secrets that the pods of a role with a service read, by the name of the file in /run/secrets. A sidecar of the pod gets them from OpenBao, and writes each secret again when its value changes. The service restarts only for a secret with restart.
Type: attribute set of (submodule)
Default:
{ }
Declared by:
pod-roles.request.roles.<name>.secrets.<name>.encoding
The encoding of the field in OpenBao. The file holds the decoded value. A file of generateFiles of the vars-openbao contract has the field content with the encoding base64.
Type: one of “none”, “base64”
Default:
"none"
Declared by:
pod-roles.request.roles.<name>.secrets.<name>.field
The field of the secret that the file holds.
Type: string
Default:
"value"
Declared by:
pod-roles.request.roles.<name>.secrets.<name>.parameters
The parameters of the request to OpenBao, for an engine that issues a value at each read, such as PKI. The response of such an engine has no KV fields, thus a secret with parameters needs a template.
Type: attribute set of string
Default:
{ }
Example:
{
common_name = "web-lldap.example.svc.cluster.local";
}
Declared by:
pod-roles.request.roles.<name>.secrets.<name>.path
The full API path of the secret in OpenBao. A path in the KV v2 engine has /data/. A path in a different engine needs a template.
Type: string
Example:
"secret/data/vars/secret/web/hello"
Declared by:
pod-roles.request.roles.<name>.secrets.<name>.restart
Restart the container of the service when the sidecar writes a new value of this file. Use it when the service reads the file only when it starts. The pod then shares its process namespace, and its sidecar has the capability KILL.
Type: boolean
Default:
false
Declared by:
pod-roles.request.roles.<name>.secrets.<name>.template
If not null, the file holds this text, which is a template of the agent of OpenBao. The template reads the response of OpenBao as .Data. Use it for a secret that is not in the KV v2 engine. field, encoding and variable do not apply to a secret with a template.
Type: null or string
Default:
null
Example:
"{{ .Data.password }}"
Declared by:
pod-roles.request.roles.<name>.secrets.<name>.variable
If not null, the field is a line <variable>=<value> of an environment file, and the file holds only <value>, with no line end. This lets a service that reads the bare value use a secret that is stored for an EnvironmentFile, thus OpenBao has one copy of the value.
Type: null or string matching the pattern [A-Za-z_][A-Za-z0-9_]*
Default:
null
Declared by:
pod-roles.request.roles.<name>.service
The name of the modular service whose image the pods of the role run. null when they run the image of the node.
Type: null or string
Default:
null
Declared by:
postgresql
PostgreSQL database access for an application, fulfilled by a postgres-backed provider of the postgresql contract on a dedicated database node.
Type: submodule
postgresql.policy
Options a hosting provider sets in an environment to supply this resource. The options that all policies share are on the data model page.
Type: submodule
postgresql.policy.enable
Whether to enable PostgreSQL database provider.
Type: boolean
Default:
false
Example:
true
Declared by:
postgresql.policy.crossNode
Cross-node factory: { consumer, database, username } -> { result; bridge; ... }, the crossNodeWant answer. result holds host, port, database, username, passwordFile, urlFile and sslMode; bridge gives the result to the postgresql contract of the consumer node.
Type: unspecified value (read only)
Declared by:
postgresql.policy.domain
Service domain the database node is named under (drives its TLS cert).
Type: string
Example:
"postgresql.example.org"
Declared by:
postgresql.policy.host
Reachable address consumers connect to the postgres daemon at: the
postgres node’s deployment FQDN, supplied by the setup. Defaults to
the domain for the single-node behaviorTest.
Type: string
Default:
config.domain
Declared by:
postgresql.policy.namespacePrefix
Operator id prefixed onto every request’s database and username,
so the created database, the OpenBao static/dynamic role, and the
credential the consumer reads are all keyed on
<namespacePrefix>-<app>. Empty is identity.
Type: string
Default:
""
Declared by:
postgresql.policy.namespaceSuffix
Deployment namespace appended to every request’s database and
username, so one group deployed per tenant gets a database, a
role and a rotated credential of its own per deployment rather than
one shared set keyed on the group alone.
NOT appended to consumerName: that stays the app node name the
per-host grant keys on, which the deployment namespace already
scopes. The on-disk /run/vars/secret/<username>-db paths key on
the namespaced username, so they carry the suffix.
Empty is identity, which is what a group deployed once (the hosting provider) wants.
Type: string
Default:
""
Declared by:
postgresql.policy.port
TCP port the postgres daemon listens on.
Type: 16 bit unsigned integer; between 0 and 65535 (both inclusive)
Default:
5432
Declared by:
postgresql.policy.provisioning
Who creates the database and the login role behind every request:
-
in-nix(default): the postgres node itself, with its OpenTofu reconcilerpostgresql-provision, which also drops what leaves its config. Right for a group deployed once, whose set of databases is fixed by its own configuration. -
tf: the consuming group’s OpenTofu graph, which creates the database, the role and the engine’s static role on apply and DROPs all three on destroy. Required wherevernamespaceSuffixis set: the postgres node reconciles only when its own group deploys, so a per-deployment database created that way outlives the deployment that asked for it, and the next deployment of the same group inherits its rows.
Under tf this resource emits no providerSide module, so the
postgres node’s declarative convergence leaves those names alone,
and the roster entry is marked so the OpenBao engine states the
SHAPE of the role name (<stem>-*) rather than the name.
Type: one of “in-nix”, “tf”
Default:
"in-nix"
Declared by:
postgresql.policy.sslMode
libpq sslmode consumers use (the contract result.sslMode).
Type: string
Default:
"require"
Declared by:
postgresql.request
Options a component sets to request this resource.
Type: submodule
postgresql.request.enable
Whether to enable PostgreSQL database access for the application.
Type: boolean
Default:
false
Example:
true
Declared by:
postgresql.request.bootstrapSQL
Application-specific SQL run as the postgres superuser against this
app’s database, after it is created and before any consumer
connects. For a one-time statement that groupRoles cannot
declare, for example a REASSIGN OWNED. A grant or a setting must
not go here: when the statement leaves the code, nothing reverses
it. Has to be idempotent, being re-applied every deploy.
@username@ and
@database@ are replaced by the request’s username and
database as created, namespacePrefix included; quote them as
identifiers, since a prefixed name carries a hyphen.
Type: strings concatenated with “\n”
Default:
""
Declared by:
postgresql.request.consumerName
Unique consumer name for this app (analog of oidc’s clientID),
used as the contracts.postgresql.want.<consumerName> key.
Type: string
Declared by:
postgresql.request.credentialMode
How the central OpenBao database engine issues this consumer’s credential:
-
rotating(default): a fixed-namedatabase/static-roles/<role>whose password the engine rotates onrotation_period; the consumer readsdatabase/static-creds/<role>and the login name never changes. Required wherever a consumer pins a fixed database user. -
dynamic: adatabase/roles/<role>minting a short-lived role with a random per-lease username on each read ofdatabase/creds/<role>. Usable by a consumer that takes the full DSN (result.urlFile) and pins no user, buying per-lease revocation at the cost of a stable username.
A consumer that puts a fixed user in its configuration uses
rotating: a dynamic lease changes the username, and dynamic
renders no passwordFile.
Type: one of “rotating”, “dynamic”
Default:
"rotating"
Declared by:
postgresql.request.database
PostgreSQL database the application requires; the provider creates
it. Carried verbatim by the postgresql contract request.
Type: string
Declared by:
postgresql.request.dynamicOwnerRole
Persistent NOLOGIN role owning every object this app creates
under dynamic credentials. Each lease role is granted membership
in it and gets ALTER ROLE ... SET role = '<owner>', so objects
land on the persistent role rather than the random per-lease role,
whose objects become unreachable once revoked. The provider node
creates the role with postgresql-provision and re-owns stranded
objects to it. Empty derives <username>_owner. Must not name a
role of groupRoles. Ignored for rotating consumers.
Type: string
Default:
""
Declared by:
postgresql.request.dynamicRoleGrants
Existing roles each freshly-minted dynamic lease role is granted
membership in, folded into the engine’s dynamic
creation_statements as GRANT <role> TO "{{name}}". A dynamic
consumer connects as a random per-lease role, so any group role it
expects to SET ROLE to has to be granted per lease rather than
once to a fixed user. The roles have to exist when a lease is
minted, or role creation fails. The groups of groupRoles with
grantToUser are added. Ignored for rotating consumers.
Type: list of string
Default:
[ ]
Declared by:
postgresql.request.gateUnits
Units that must not start until the openbao agent has rendered
this consumer’s credential. Each named unit gets an ExecStartPre
probe (./wait-password-file.sh), which spends a short budget
inside that unit’s own start timeout.
Ordering after openbao-agent-default.service does not give this.
The agent goes active carrying a template it could not render, and
a unit that cats the credential then fails on a file that does
not exist. Where that unit is a Type = "oneshot" upstream gives
no Restart=, systemd drops the start job of every unit that
Requires= it and re-queues none of them when the render lands,
which leaves the application behind an nginx 502 for the life of
the deployment.
The gate reads whether the file has contents, so a render from an
earlier generation satisfies it. It covers the FIRST render;
reloadUnits is what carries a consumer over a rotation.
Type: list of string
Default:
[ ]
Declared by:
postgresql.request.groupRoles
NOLOGIN group roles that the postgres node creates with
postgresql-provision, keyed by role name. Some upstream service
modules ship migrations that assume group roles which their NixOS
module creates only under a createLocally = true path, and a
remote consumer disables that path. The name gets no operator id,
so the role is shared by all requests that declare it, and these
requests must declare the same attributes for it. A role that
leaves all requests is dropped.
Type: attribute set of (submodule)
Default:
{ }
Declared by:
postgresql.request.groupRoles.<name>.bypassRowLevelSecurity
Whether the role bypasses row-level security (BYPASSRLS).
Type: boolean
Default:
false
Declared by:
postgresql.request.groupRoles.<name>.databasePrivileges
Privileges of this role on this request’s database, for
example CONNECT, CREATE and TEMPORARY. The list is
complete: other privileges of the role on the database
are revoked.
Type: list of string
Default:
[ ]
Declared by:
postgresql.request.groupRoles.<name>.grantToUser
Whether the request’s login role is a member of this
role. For a dynamic consumer, each lease role is a
member, as with dynamicRoleGrants.
Type: boolean
Default:
false
Declared by:
postgresql.request.groupRoles.<name>.memberOf
Roles that this role is a member of.
Type: list of string
Default:
[ ]
Declared by:
postgresql.request.groupRoles.<name>.sequencePrivileges
Privileges of this role on the sequences in schema
public of this request’s database, as tablePrivileges
states them for tables.
Type: list of string
Default:
[ ]
Declared by:
postgresql.request.groupRoles.<name>.tablePrivileges
Privileges of this role on the tables in schema public
of this request’s database, for example SELECT or
ALL. They cover all tables that exist when
postgresql-provision runs, and the tables that the
login role of this request makes later. The list is
complete: other privileges of the role on the tables are
revoked.
Type: list of string
Default:
[ ]
Declared by:
postgresql.request.passwordFileMode
Mode of the rendered passwordFile/urlFile. Defaults to 0640,
root-owned and group-readable, which suits consumers reading it
via systemd LoadCredential. Set 0400 with a non-root
passwordFileOwner for an app reading the file as its own service
user.
Type: string
Default:
"0640"
Declared by:
postgresql.request.passwordFileOwner
Owner of the rendered passwordFile/urlFile. Defaults to root;
set to the app’s service user when that user cats the file
directly. The agent gives the file to this owner on every render,
and again before it starts, so a change to this value reaches a
file the render leaves alone.
Type: string
Default:
"root"
Declared by:
postgresql.request.reloadUnits
Systemd units the openbao agent restarts after it re-renders this
consumer’s credential. Every consumer reads the credential once at
process start, so one holding the previous credential starts
failing with password authentication failed.
List the app service plus any unit baking the credential into a
derived file the app reads; they are restarted in one systemd
transaction, which honors their own After=. Empty means the
consumer does not converge on rotation, correct only where it reads
the credential afresh on each use.
Type: list of string
Default:
[ ]
Declared by:
postgresql.request.urlEnvironment
Give the DSN to units as the environment variable variable,
for an application that reads its database from the environment
and not from a file. A oneshot <app>-db-env writes
<variable>=<DSN> to an EnvironmentFile of each unit in
units, and each unit starts after it. On each re-render of the
DSN, the openbao agent restarts the oneshot and units, so do not
put them in reloadUnits.
The oneshot retries until the DSN is rendered. On a fleet that is new all at once, the agent cannot render the DSN until the central database engine is configured, which can be many minutes after the first start, and the restart on a re-render cannot help before the first render.
systemd reads an EnvironmentFile after Environment=, so the
variable overrides a static value from the application’s module.
Type: null or (submodule)
Default:
null
Declared by:
postgresql.request.urlEnvironment.oneshotUnits
Systemd services, without the .service suffix, that also
get the variable, but that a re-render of the DSN does not
restart: oneshots that a timer starts, which read the file
at each start. A restart would run them out of their
schedule, and its reset-failed would clear a failure that
they report. Each one requires the oneshot <app>-db-env,
so it does not run without the variable.
Type: list of string
Default:
[ ]
Declared by:
postgresql.request.urlEnvironment.units
Systemd services, without the .service suffix, that get the variable.
Type: list of string
Default:
[ ]
Declared by:
postgresql.request.urlEnvironment.variable
Name of the environment variable that holds the DSN.
Type: string
Example:
"DATABASE_URL"
Declared by:
postgresql.request.username
PostgreSQL role the application connects as. Defaults to the
consumerName. Carried by the postgresql contract request.
Type: string
Default:
config.consumerName
Declared by:
redis
Redis-compatible cache access for an application, fulfilled by an external provider (shared valkey node, OpenBao-brokered per-namespace credentials) of the nixpkgs redis contract.
Type: submodule
redis.policy
Options a hosting provider sets in an environment to supply this resource. The options that all policies share are on the data model page.
Type: submodule
redis.policy.enable
Whether to enable shared redis (valkey) cache provider.
Type: boolean
Default:
false
Example:
true
Declared by:
redis.policy.crossNode
Cross-node factory: { consumer, namespace } -> { result; bridge; ... }, the crossNodeWant answer. result holds host, namespace, port, username, passwordFile, tls and caFile; bridge gives the result to the redis contract of the consumer node.
Type: unspecified value (read only)
Declared by:
redis.policy.host
Address consumers connect to the group’s valkey node at: its
deployment FQDN, supplied by core/setups/hosts-common.nix. Each
namespace’s valkey@<namespace> instance lives on this node at its
own namespace-derived port (./port.nix).
Type: string
Example:
"valkey.example.org"
Declared by:
redis.policy.namespacePrefix
Operator id prefixed onto every request’s namespace, so the
physical instance – valkey@<namespace>, its namespace-derived port
and its OpenBao static role – is keyed on <namespacePrefix>-<app>
and two operators’ same-named apps stay distinct. Empty is identity.
Supplied by the deployment (core/setups/hosts-common.nix), and must
match the prefix the valkey node and OpenBao engine use, or a
consumer’s static-role name matches no rotated instance.
Type: string
Default:
""
Declared by:
redis.policy.passwordDir
Directory the openbao-agent renders per-namespace rotated passwords
into on each consumer node (one file per namespace). Off
/nix/store (rotates; peertube asserts off-store).
Type: string
Default:
"/run/redis-external"
Declared by:
redis.policy.roleSuffix
Deployment namespace put after every request’s namespace in the
name of its OpenBao static role, as <namespace>-<roleSuffix>.
The instance, its port and its KV entries keep <namespace>.
Empty is identity. Supplied by the deployment
(core/setups/hosts-common.nix), and must match the role name the
OpenBao engine uses for the deployment, or the consumer reads a
role that does not exist.
Type: string
Default:
""
Declared by:
redis.policy.tls.enable
Whether the group’s valkey node serves each namespace with TLS
only, and each consumer connects with TLS (rediss://). The
deployment sets it to whether its PKI plan holds the valkey
host (core/setups/hosts-common.nix). The server gate and every
consumer read this one value, so they agree. False means plain
text (redis://) and no CA.
Type: boolean
Default:
false
Declared by:
redis.policy.tls.caFile
CA bundle on each consumer node that signs the certificate of
the valkey node. Used only when enable is true.
Type: null or string
Default:
null
Declared by:
redis.request
Options a component sets to request this resource.
Type: submodule
redis.request.consumerName
Unique consumer name for this app (analog of ldap’s consumerName),
used as the contracts.redis.want.<consumerName> key.
Type: string
Declared by:
redis.request.gateUnits
Units that must not start until this namespace’s valkey listener
answers. When the result has tls, the listener must also
complete a TLS handshake the consumer node can verify.
Each named unit gets an ExecStartPre probe
(./wait-reachable.sh), which spends a short budget inside that
unit’s own start timeout.
For a database migration runner. A Laravel migration can change the schema and then dispatch a queued job, and MySQL does not roll back DDL, so a dispatch that fails on a TLS error leaves the schema changed and the ledger row unwritten. Each later run then stops on a duplicate column, a state no configuration repairs. The gate makes the unit fail before its first statement instead.
Type: list of string
Default:
[ ]
Declared by:
redis.request.namespace
The application’s logical cache identity. Selects the application’s
own valkey@<namespace> instance – its own process and port on the
group’s valkey node – so namespaces are isolated by process, not by
an ACL key-scope. Also the name of the OpenBao static role that
rotates the instance’s password, with roleSuffix after it. The
multi-operator case folds the operator id in via namespacePrefix.
Type: string
Declared by:
secrets
Secrets provisioning for an application, via the fileSecrets contract.
Type: submodule
secrets.policy
Options a hosting provider sets in an environment to supply this resource. The options that all policies share are on the data model page.
Type: submodule
secrets.request
Options a component sets to request this resource.
Type: submodule
secrets.request.secrets
Secrets this application needs provisioned on its host, keyed by
name. Each becomes a contracts.fileSecrets.want.<app>.<name>
request, read back from
config.contracts.fileSecrets.results.<app>.<name>.path.
Type: attribute set of (submodule)
Default:
{ }
Declared by:
secrets.request.secrets.<name>.file
Encrypted .age source for the agenix provider. The consumer states it, because this resource holds the secrets of no deployment.
Type: absolute path
Declared by:
secrets.request.secrets.<name>.group
Linux group that must own the secret file. Defaults to the owner’s primary group, as agenix does.
Type: string
Default:
owner
Declared by:
secrets.request.secrets.<name>.mode
Mode the secret file must have.
Type: string
Default:
"0400"
Declared by:
secrets.request.secrets.<name>.owner
Linux user that must own the secret file.
Type: string
Declared by:
smtp
Outbound SMTP mail submission for an application, fulfilled by a maddy-backed (or external) provider of the nixpkgs smtp contract.
Type: submodule
smtp.policy
Options a hosting provider sets in an environment to supply this resource. The options that all policies share are on the data model page.
Type: submodule
smtp.policy.enable
Whether to enable outbound SMTP mail submission provider.
Type: boolean
Default:
false
Example:
true
Declared by:
smtp.policy.domain
Mail domain the relay serves (maddy hostname/primaryDomain and the TLS domain).
Type: string
Example:
"mail.example.org"
Declared by:
smtp.policy.instanceName
Stem the relay’s generateFiles/vars instances – and so their
central OpenBao KV paths – are named from. The setup
group-qualifies it outside the hosting provider, so two groups’
relays neither overwrite each other’s per-consumer submission
passwords nor share a DKIM signing key on the one shared KV.
Provider-agnostic in name only: the external-relay provider
generates nothing and ignores it.
Type: string
Default:
"smtp"
Declared by:
smtp.policy.port
Submission port the relay listens on.
Type: signed integer
Default:
587
Declared by:
smtp.request
Options a component sets to request this resource.
Type: submodule
smtp.request.enable
Whether to enable outbound SMTP mail submission for the application.
Type: boolean
Default:
false
Example:
true
Declared by:
smtp.request.sender
Email address used as the sender (From header), carried verbatim
by the nixpkgs smtp contract request.
Type: string
Example:
"noreply@example.com"
Declared by:
spiffe
SPIFFE workload identity (spire-agent) provisioning for an application’s host.
Type: submodule
spiffe.policy
Options a hosting provider sets in an environment to supply this resource. The options that all policies share are on the data model page.
Type: submodule
spiffe.request
Options a component sets to request this resource.
Type: submodule
spiffe.request.enable
Whether to enable a spire-agent on this host for SPIFFE workload identity.
Type: boolean
Default:
false
Example:
true
Declared by:
ssl
TLS certificate provisioning for an application’s vhosts.
Type: submodule
ssl.policy
Options a hosting provider sets in an environment to supply this resource. The options that all policies share are on the data model page.
Type: submodule
ssl.policy.crossNode
Cross-node trust factory: { consumer, domains } -> { results; bakeableDomains; pkiCaCertFiles; } from one eval.
Type: unspecified value (read only)
Declared by:
ssl.request
Options a component sets to request this resource.
Type: submodule
ssl.request.domains
Domains this application terminates TLS for (its own vhosts).
Type: list of string
Default:
[ ]
Declared by:
ssl.request.trustDomains
Domains served by another node this node must trust as a client (e.g. the garage bucket endpoints). Drives cross-node trust baking.
Type: list of string
Default:
[ ]
Declared by: