Access model

This part gives the persons and the components that have access to the state of the system, and the limits of that access. The tables that have the label "generated" come from the code at each build of the documentation (core/docs/md/technical-design/access-model.nix). The threats and the controls are in the threat model.

Actors

Actor Definition Where the identity is
Hosting provider The organization that runs the software of this repository for its customers (Actors). It has no account of its own. Its persons are staff and administrators.
Staff A person of the hosting provider who reads the telemetry. A user in the lldap of the hosting provider, with the group fediversity-staff.
Administrator A person of the hosting provider who can administer the nodes and the shared services. A user in the lldap of the hosting provider, with the group fediversity-admins. The person logs in to the shared account admin with a short-lived SSH certificate. When no certificate is available, the holder of the offline key of ADMIN_EMERGENCY can log in to the account emergency (core/setups/nixos/users.nix).
Panel superuser An account of the panel that can see and assign the domains of all operators. A User of the panel with is_superuser. Each SSO login sets this flag and is_staff from the groups claim: a member of fediversity-admins gets them, a different user loses them (superuserGroups in panel/nix/component/oidc.nix, sync_superuser in panel/src/panel/oidc.py). A password login does not change them.
Deployer A program or a person that applies a configuration to the nodes: the CD workflows, an administrator on a workstation, and the front end (the api and Windmill), which deploys the deployments of the operators. An OpenBao token with the policy fediversity-deployer (CD and workstation) or fediversity-operator-deployer (front end), and a user of the state backend: cd, workstation-<person> or operator (core/components/hosting-provider/terraform-backend/front.nix).
Operator A customer of the hosting provider, who configures and deploys applications through the panel. A User in the database of the panel. The log-in is with a local password, or with OpenID Connect when the hosting provider sets the OIDC_* settings (panel/src/panel/settings.py).
Tenant One deployment of an operator, as an owner of names in a shared service. The code calls the name of a tenant the namespace of the deployment. The namespace is in the name of each node of the deployment and in the certificate that SPIRE gives the node.
Application user A person who uses an application of an operator. An account in the application. Each deployment has its own lldap and authelia nodes for single sign-on (core/setups/groups/operator.nix).
Node A machine of the hosting provider or of a deployment. A certificate (SVID) from SPIRE. OpenBao gives the node the policy host-<name> (core/components/hosting-provider/openbao/spire-auth.nix).

Permissions of each role

In the panel

The panel has three levels of access.

  • A visitor without an account can read the public pages.
  • An operator can read and change only the deployments for which Deployment.operator is the account of the operator (panel/src/panel/models.py). The views filter on this field.
  • A superuser has the access of an operator. A superuser can also list, claim and assign domains for all operators, and can read the audit history of each account (reads_all_history and _AUTHZ_SUPERUSER_PROCEDURES in panel/src/panel/views.py).

The admin site of Django (/admin/) shows only the User model (panel/src/panel/admin.py). The views of the panel do not use is_staff. The directory groups fediversity-staff and fediversity-admins give no permission in the panel.

In the api

The api does not keep accounts and does not decide on access. For each request, the api sends the name of the procedure, the scope and the headers to the authorization callback of the panel (authorize in api/src/fediversity_api/authz.py, AuthzCallback in panel/src/panel/views.py). The callback accepts a request only with the callback token of the api (AUTHZ_CALLBACK_TOKEN), when that token is set. The panel identifies the requester from a bearer token that the panel signed, which stays valid for API_TOKEN_TTL seconds (panel/src/panel/tokens.py).

Requester Procedures that the callback permits
No account AUTHZ_PUBLIC_PROCEDURES: the schema, the list of applications and their icons, the configuration sections and the domain terms.
Operator The procedures of AUTHZ_PROCEDURE_RULES, only for its own deployments, its own domain contact and its own audit events.
Superuser The same, and domain_assign. domain_list and domain_claim apply to the deployments of all operators.
Service token A request with the service token of the api (API_SERVICE_TOKEN) is an internal call. The callback then decides for the user that the request names. domain_terms_notice accepts only such a call (api/src/fediversity_api/routes/domains.py).

The callback denies a procedure that is not in AUTHZ_PROCEDURE_RULES. Without a callback URL, the api starts only when API_AUTHZ_ALLOW_ALL is set, and then it permits each request.

Directory groups of the hosting provider

The groups are in the lldap of the hosting provider. The section Manage users and groups of the hosting-provider guide tells how to give a group to a user.

Service fediversity-staff fediversity-admins Source
Grafana of the hosting provider The Viewer role. Grafana has one organization, thus a viewer can read the telemetry of all deployments. The Admin role. core/components/hosting-provider/telemetry/
OpenBao None. The policy fediversity-admins: read of the full KV. With ADMIN_UI_WRITE=1, also write and delete. core/components/hosting-provider/openbao/oidc.nix
OpenBao, deploy token None. A token with the policy fediversity-deployer. core/components/hosting-provider/openbao/oidc.nix
SSH to the nodes None. A certificate for the shared account admin, which is in wheel. Each node accepts the certificate when ADMIN_SSH_CA_KEYS is set. core/components/hosting-provider/openbao/ssh-certificates.nix, core/setups/nixos/users.nix
Incus None. Administrator of all containers. The authorization scriptlet of Incus refuses an OIDC user outside the group. core/components/hosting-provider/incus/default.nix
Windmill None. The UI, from which a person starts and cancels deployments. core/components/hosting-provider/windmill/default.nix
pgweb None. The UI, which connects as the postgres superuser. A member can read the databases of all deployments. core/components/hosting-provider/postgresql/default.nix
UI of Valkey None. The UI. core/components/shared/valkey/default.nix
UI of Garage None. The UI, only when ADMIN_UI_WRITE=1. core/components/hosting-provider/garage/default.nix

When ADMIN_SOURCES is set, the firewall of each node accepts the administrative ports (port 22 by default) only from those addresses (core/resources/firewall/default.nix). An operator gets no shell access to the nodes of its deployment. The persons who can read each log, trace and audit channel are in Logs, traces and audit records.

Application roles

Each deployment of an operator has its own lldap, with the same group names. The lldap of a deployment has the groups application-admins and application-moderators (core/resources/ldap/application-role-groups.nix), and the groups of each application. Each application gives a role to the members of a group at log-in. The Grafana of a deployment accepts the members of fediversity-admins in the lldap of that deployment (core/components/operator/grafana/oidc.nix).

Generated from the role-groups.nix file of each application in core/components/operator/:

Application Directory group Role in the application The first administrator is a member
mastodon mastodon-owners Owner yes
mastodon application-admins Admin yes
mastodon mastodon-admins Admin no
mastodon application-moderators Moderator no
mastodon mastodon-moderators Moderator no
peertube application-admins 0 yes
peertube peertube-admins 0 no
peertube application-moderators 1 no
peertube peertube-moderators 1 no
pixelfed application-admins admin yes
pixelfed pixelfed-admins admin no

Access of each component to each store

The tables in this section are generated from the configuration of the nodes, with the groups of core/testers/groups.nix. That evaluation knows no deployment. Thus <own deployment> shows where a name has the namespace of the deployment of the node, and <each deployment> shows a path that applies to all deployments.

Secrets in the KV of OpenBao

Each node logs in to OpenBao with its SPIRE certificate and gets the policy host-<name>. The entries of the hosting provider are below secret/data/vars/. The entries of a deployment are below secret/data/vars/operator-deployments/<namespace>/. Each entry has a public half and a secret half. The credentials register gives the lifetime and the rotation of each credential. The table gives the name of the entry when a policy has the same capabilities on the two halves, and <half>/<entry> when it has them on one half. The table gives a grant on secret/metadata/ only when the policy has no grant on the data of the same entry.

Policy Scope Capabilities Entries
fediversity-admins not in vars read *
fediversity-deployer hosting provider create, read, update secret/deployer/adminSources, secret/deployer/dnsApiToken, secret/deployer/netboxApiToken, secret/deployer/openproviderPassword, secret/deployer/openproviderUsername, secret/deployer/zonesManagerToken, secret/smarthost-upstream
fediversity-deployer hosting provider read secret/incus-store, secret/netbox, secret/octodns, public/*
fediversity-operator-deployer <each deployment> create, read, update, delete, list authelia-backups-s3, secret/authelia-operator-secrets, desec-zone, domain-claims, lldap-backups-s3, mastodon-backups-s3, secret/mastodon-operator-secrets, mastodon-s3, migration, operator-authelia-cache-backups-s3, operator-mastodon-cache-backups-s3, operator-peertube-cache-backups-s3, operator-pixelfed-cache-backups-s3, operator-valkey-cache-backups-s3, peertube-backups-s3, peertube-s3, pixelfed-backups-s3, secret/pixelfed-operator-secrets, pixelfed-s3
fediversity-operator-deployer <each deployment> deny secret/authelia-backups-restic, secret/ldap-key-operator, secret/lldap-backups-restic, secret/mastodon-backups-restic, secret/mastodon-keys, secret/mastodon-media-backup, secret/operator-authelia-cache-backups-restic, secret/operator-authelia-oidc, secret/operator-mastodon-cache-backups-restic, secret/operator-peertube-cache-backups-restic, secret/operator-pixelfed-cache-backups-restic, secret/operator-valkey-cache-backups-restic, secret/peertube-backups-restic, secret/peertube-media-backup, secret/peertube-secret, secret/pixelfed-app, secret/pixelfed-backups-restic, secret/pixelfed-media-backup, secret/pixelfed-passport
fediversity-operator-deployer <each deployment> metadata only: list, delete *
fediversity-operator-deployer <each deployment> read public/*
fediversity-operator-deployer hosting provider create, read, update, delete, list authelia-backups-s3, desec-zone, domain-claims, lldap-backups-s3, mastodon-backups-s3, mastodon-s3, operator-authelia-cache-backups-s3, operator-mastodon-cache-backups-s3, operator-peertube-cache-backups-s3, operator-pixelfed-cache-backups-s3, operator-valkey-cache-backups-s3, peertube-backups-s3, peertube-s3, pixelfed-backups-s3, pixelfed-s3
fediversity-operator-deployer hosting provider metadata only: read secret/smarthost-upstream
fediversity-operator-deployer hosting provider read secret/netbox, secret/postgresql-admin, public/*
fediversity-operator-deployer not in vars metadata only: create retained-backups/*
host-authelia hosting provider create, read, update, delete, list authelia-backups-restic, authelia-oidc, authelia-session
host-authelia hosting provider read authelia-backups-s3, secret/smtp
host-bind hosting provider create, read, update, delete, list acme-dns, bind-backups-restic, dnssec, octodns, operator-dns
host-bind hosting provider read secret/authelia-oidc, bind-backups-s3
host-garage <each deployment> metadata only: read, list, delete authelia-backups-restic, ldap-key-operator, lldap-backups-restic, mastodon-backups-restic, mastodon-keys, mastodon-media-backup, operator-authelia-cache-backups-restic, operator-authelia-oidc, operator-mastodon-cache-backups-restic, operator-peertube-cache-backups-restic, operator-pixelfed-cache-backups-restic, operator-valkey-cache-backups-restic, peertube-backups-restic, peertube-media-backup, peertube-secret, pixelfed-app, pixelfed-backups-restic, pixelfed-media-backup, pixelfed-passport
host-garage hosting provider create, read, update, delete, list authelia-backups-s3, bind-backups-s3, garage-admin, grafana-backups-s3, hosting-provider-authelia-cache-backups-s3, hosting-provider-valkey-cache-backups-s3, lldap-backups-s3, netbox-backups-s3, openbao-backups-s3, postgresql-backups-s3, terraform-backend-backups-s3, windmill-backups-s3
host-garage hosting provider read secret/acme-dns, secret/authelia-oidc, telemetry-s3
host-garage not in vars metadata only: read, list, delete retained-backups/*
host-incus hosting provider create, read, update, delete, list incus-deploy, incus-store
host-incus hosting provider read secret/authelia-oidc
host-lldap hosting provider create, read, update, delete, list ldap-bind-hosting-provider, ldap-jwt-hosting-provider, ldap-key-hosting-provider, lldap-backups-restic
host-lldap hosting provider read secret/authelia-oidc, lldap-backups-s3, secret/smtp
host-netbox hosting provider create, read, update, delete, list netbox, netbox-backups-restic
host-netbox hosting provider read secret/authelia-oidc, netbox-backups-s3, secret/smtp
host-openbao hosting provider read secret/authelia-oidc, openbao-backups-s3, secret/postgresql-admin
host-operator-authelia <own deployment> create, read, update, delete, list authelia-backups-restic, authelia-session, operator-authelia-oidc
host-operator-authelia <own deployment> read authelia-backups-s3, secret/authelia-operator-secrets, secret/node-telemetry, secret/operator-smtp
host-operator-grafana <own deployment> create, read, update, delete, list grafana-secret, metrics-query, node-telemetry
host-operator-grafana <own deployment> read secret/operator-authelia-oidc
host-operator-lldap <own deployment> create, read, update, delete, list ldap-bind-operator, ldap-jwt-operator, ldap-key-operator, ldap-roles-operator, lldap-backups-restic
host-operator-lldap <own deployment> read lldap-backups-s3, secret/node-telemetry, secret/operator-authelia-oidc, secret/operator-smtp
host-operator-mastodon <own deployment> create, read, update, delete, list mastodon-backups-restic, mastodon-keys, mastodon-media-backup, metrics
host-operator-mastodon <own deployment> read secret/ldap-roles-operator, mastodon-backups-s3, secret/mastodon-operator-secrets, mastodon-s3, secret/node-telemetry, secret/operator-authelia-oidc, secret/operator-smtp
host-operator-peertube <own deployment> create, read, update, delete, list metrics, peertube-backups-restic, peertube-media-backup, peertube-secret
host-operator-peertube <own deployment> read secret/ldap-roles-operator, secret/node-telemetry, secret/operator-authelia-oidc, secret/operator-smtp, peertube-backups-s3, peertube-s3
host-operator-pixelfed <own deployment> create, read, update, delete, list metrics, pixelfed-app, pixelfed-app-previous, pixelfed-backups-restic, pixelfed-media-backup, pixelfed-passport
host-operator-pixelfed <own deployment> read secret/ldap-roles-operator, secret/node-telemetry, secret/operator-authelia-oidc, secret/operator-smtp, pixelfed-backups-s3, secret/pixelfed-operator-secrets, pixelfed-s3
host-operator-smtp <own deployment> create, read, update, delete, list operator-smtp, operator-smtp-dkim
host-operator-smtp <own deployment> read secret/node-telemetry, secret/operator-authelia-oidc
host-operator-smtp hosting provider read secret/smarthost-upstream
host-operator-valkey <own deployment> create, read, update, delete, list operator-authelia-cache-backups-restic, operator-mastodon-cache-backups-restic, operator-peertube-cache-backups-restic, operator-pixelfed-cache-backups-restic, operator-valkey-cache-backups-restic, valkey-operator-authelia, valkey-operator-mastodon, valkey-operator-peertube, valkey-operator-pixelfed, valkey-operator-valkey
host-operator-valkey <own deployment> read secret/node-telemetry, operator-authelia-cache-backups-s3, secret/operator-authelia-oidc, operator-mastodon-cache-backups-s3, operator-peertube-cache-backups-s3, operator-pixelfed-cache-backups-s3, operator-valkey-cache-backups-s3
host-otel-collector metadata only: list ``
host-otel-collector <each deployment> read public/metrics
host-otel-collector hosting provider read secret/authelia-oidc, secret/telemetry-ingest
host-postgresql hosting provider create, read, update, delete, list postgresql-admin, postgresql-backups-restic
host-postgresql hosting provider read secret/authelia-oidc, postgresql-backups-s3
host-smtp hosting provider create, read, update, delete, list smtp, smtp-dkim
host-smtp hosting provider read secret/authelia-oidc, secret/smarthost-upstream
host-telemetry metadata only: list ``
host-telemetry <each deployment> read public/metrics-query/htpasswd, public/node-telemetry/htpasswd
host-telemetry hosting provider create, read, update, delete, list audit-ingest-api, grafana-backups-restic, telemetry-grafana, telemetry-grafana-previous, telemetry-ingest, telemetry-s3
host-telemetry hosting provider read secret/authelia-oidc, grafana-backups-s3, secret/smtp
host-terraform-backend hosting provider create, read, update, delete, list terraform-backend-operator
host-terraform-backend hosting provider read secret/authelia-oidc, terraform-backend-backups-s3
host-valkey hosting provider create, read, update, delete, list hosting-provider-authelia-cache-backups-restic, hosting-provider-valkey-cache-backups-restic, valkey-hosting-provider-authelia, valkey-hosting-provider-valkey
host-valkey hosting provider read secret/authelia-oidc, hosting-provider-authelia-cache-backups-s3, hosting-provider-valkey-cache-backups-s3
host-windmill hosting provider create, read, update, delete, list windmill, windmill-backups-restic, windmill-superadmin
host-windmill hosting provider read secret/authelia-oidc, public/domain-claims, secret/incus-deploy, secret/incus-store, secret/operator-dns, secret/deployer/adminSources, secret/deployer/dnsApiToken, secret/deployer/netboxApiToken, secret/deployer/openbaoToken, secret/deployer/openproviderPassword, secret/deployer/openproviderUsername, secret/garage-admin/adminToken, secret/terraform-backend-operator/password, secret/smtp, windmill-backups-s3

The policy fediversity-admins in this table is that of the evaluation, where ADMIN_UI_WRITE is not set.

Other paths in OpenBao

These paths give certificates (pki), database passwords (database, postgresql), directory passwords (ldap, ldap-operator) and child tokens.

Policy Path Capabilities
fediversity-admins identity/* read, list
fediversity-admins sys/auth read
fediversity-admins sys/mounts read
fediversity-admins sys/policies/acl read, list
fediversity-admins sys/policies/acl/* read
fediversity-deployer auth/token/create update
fediversity-operator-deployer postgresql/static-roles/operator-authelia-* create, read, update, delete
fediversity-operator-deployer postgresql/static-roles/operator-lldap-* create, read, update, delete
fediversity-operator-deployer postgresql/static-roles/operator-mastodon-* create, read, update, delete
fediversity-operator-deployer postgresql/static-roles/operator-peertube-* create, read, update, delete
fediversity-operator-deployer postgresql/static-roles/operator-pixelfed-* create, read, update, delete
fediversity-operator-deployer ldap-operator/<each deployment>/rotate-role/authelia-bind update
fediversity-operator-deployer auth/token/create update
host-authelia pki/issue/internal update
host-authelia database/static-creds/hosting-provider-authelia read
host-authelia ldap/static-cred/authelia-bind read
host-authelia postgresql/static-creds/hosting-provider-authelia read
host-bind pki/issue/internal update
host-garage pki/issue/internal update
host-incus pki/issue/internal update
host-lldap pki/issue/internal update
host-lldap postgresql/static-creds/hosting-provider-lldap read
host-netbox pki/issue/internal update
host-netbox postgresql/static-creds/hosting-provider-netbox read
host-openbao pki/issue/internal update
host-operator-authelia pki/issue/internal update
host-operator-authelia database/static-creds/operator-authelia-<own deployment> read
host-operator-authelia ldap-operator/<own deployment>/static-cred/authelia-bind read
host-operator-authelia postgresql/static-creds/operator-authelia-<own deployment> read
host-operator-grafana pki/issue/internal update
host-operator-lldap pki/issue/internal update
host-operator-lldap postgresql/static-creds/operator-lldap-<own deployment> read
host-operator-mastodon pki/issue/internal update
host-operator-mastodon database/static-creds/operator-mastodon-<own deployment> read
host-operator-mastodon postgresql/static-creds/operator-mastodon-<own deployment> read
host-operator-peertube pki/issue/internal update
host-operator-peertube database/static-creds/operator-peertube-<own deployment> read
host-operator-peertube postgresql/static-creds/operator-peertube-<own deployment> read
host-operator-pixelfed pki/issue/internal update
host-operator-pixelfed database/static-creds/operator-pixelfed-<own deployment> read
host-operator-pixelfed postgresql/static-creds/operator-pixelfed-<own deployment> read
host-operator-smtp pki/issue/internal update
host-operator-valkey pki/issue/internal update
host-operator-valkey database/static-creds/operator-valkey-<own deployment> read
host-operator-valkey database/static-creds/operator-authelia-<own deployment> read
host-operator-valkey database/static-creds/operator-mastodon-<own deployment> read
host-operator-valkey database/static-creds/operator-peertube-<own deployment> read
host-operator-valkey database/static-creds/operator-pixelfed-<own deployment> read
host-otel-collector pki/issue/internal update
host-postgresql pki/issue/internal update
host-smtp pki/issue/internal update
host-telemetry pki/issue/internal update
host-terraform-backend pki/issue/internal update
host-valkey pki/issue/internal update
host-valkey database/static-creds/hosting-provider-valkey read
host-valkey database/static-creds/hosting-provider-authelia read
host-windmill pki/issue/internal update
host-windmill postgresql/static-creds/hosting-provider-windmill read

PostgreSQL

The database engine of OpenBao owns the password of each role and changes it at the interval in the table. A node reads the password of its role from OpenBao (core/setups/wiring/postgresql-roster.nix). The database and the role of a deployment have the namespace of the deployment as a suffix, and the OpenTofu graph of the deployment creates and drops them (core/effects/tf/incus/operator/postgresql.tf).

Nodes that read the password Role Database Scope Credential
authelia hosting-provider-authelia hosting-provider-authelia hosting provider rotating, 24h
lldap hosting-provider-lldap hosting-provider-lldap hosting provider rotating, 24h
netbox hosting-provider-netbox hosting-provider-netbox hosting provider rotating, 24h
windmill hosting-provider-windmill hosting-provider-windmill hosting provider rotating, 24h
operator-authelia operator-authelia-<own deployment> operator-authelia-<own deployment> each operator deployment rotating, 24h
operator-lldap operator-lldap-<own deployment> operator-lldap-<own deployment> each operator deployment rotating, 24h
operator-mastodon operator-mastodon-<own deployment> operator-mastodon-<own deployment> each operator deployment rotating, 24h
operator-peertube operator-peertube-<own deployment> operator-peertube-<own deployment> each operator deployment rotating, 24h
operator-pixelfed operator-pixelfed-<own deployment> operator-pixelfed-<own deployment> each operator deployment rotating, 24h

The postgresql node also has these group roles:

Group role Members Privileges on the database Privileges on the objects Bypasses row-level security
windmill_admin hosting-provider-windmill each sequence of hosting-provider-windmill: ALL; each table of hosting-provider-windmill: ALL yes
windmill_user windmill_admin hosting-provider-windmill: CONNECT, CREATE, TEMPORARY each sequence of hosting-provider-windmill: ALL; each table of hosting-provider-windmill: ALL no

Two actors have access to all databases of the node: the front-end deployer, which reads the password of the postgres superuser (the entry secret/postgresql-admin in the KV table), and a member of fediversity-admins through pgweb.

Buckets in Garage

Each row is one ensureAccess entry of a key that a node requests. owner lets the key change the configuration of the bucket.

Group Node Key Bucket Access
hosting-provider authelia hosting-provider-authelia-backups hosting-provider-authelia-backups read, write, owner
hosting-provider authelia hosting-provider-authelia-cache-backups hosting-provider-authelia-cache-backups read, write, owner
hosting-provider bind hosting-provider-bind-backups hosting-provider-bind-backups read, write, owner
hosting-provider lldap hosting-provider-lldap-backups hosting-provider-lldap-backups read, write, owner
hosting-provider netbox hosting-provider-netbox-backups hosting-provider-netbox-backups read, write, owner
hosting-provider openbao hosting-provider-openbao-backups hosting-provider-openbao-backups read, write, owner
hosting-provider postgresql hosting-provider-postgresql-backups hosting-provider-postgresql-backups read, write, owner
hosting-provider telemetry hosting-provider-grafana-backups hosting-provider-grafana-backups read, write, owner
hosting-provider telemetry hosting-provider-telemetry hosting-provider-loki read, write, owner
hosting-provider telemetry hosting-provider-telemetry hosting-provider-mimir read, write, owner
hosting-provider telemetry hosting-provider-telemetry hosting-provider-tempo read, write, owner
hosting-provider terraform-backend hosting-provider-terraform-backend-backups hosting-provider-terraform-backend-backups read, write, owner
hosting-provider valkey hosting-provider-valkey-cache-backups hosting-provider-valkey-cache-backups read, write, owner
hosting-provider windmill hosting-provider-windmill-backups hosting-provider-windmill-backups read, write, owner
operator authelia <own deployment>-authelia-backups <own deployment>-authelia-backups read, write, owner
operator authelia <own deployment>-authelia-cache-backups <own deployment>-authelia-cache-backups read, write, owner
operator lldap <own deployment>-lldap-backups <own deployment>-lldap-backups read, write, owner
operator mastodon <own deployment>-mastodon <own deployment>-mastodon read, write, owner
operator mastodon <own deployment>-mastodon-backups <own deployment>-mastodon read
operator mastodon <own deployment>-mastodon-backups <own deployment>-mastodon-backups read, write, owner
operator mastodon <own deployment>-mastodon-cache-backups <own deployment>-mastodon-cache-backups read, write, owner
operator peertube <own deployment>-peertube <own deployment>-peertube-playlists read, write, owner
operator peertube <own deployment>-peertube <own deployment>-peertube-videos read, write, owner
operator peertube <own deployment>-peertube-backups <own deployment>-peertube-backups read, write, owner
operator peertube <own deployment>-peertube-backups <own deployment>-peertube-playlists read
operator peertube <own deployment>-peertube-backups <own deployment>-peertube-videos read
operator peertube <own deployment>-peertube-cache-backups <own deployment>-peertube-cache-backups read, write, owner
operator pixelfed <own deployment>-pixelfed <own deployment>-pixelfed read, write, owner
operator pixelfed <own deployment>-pixelfed-backups <own deployment>-pixelfed read
operator pixelfed <own deployment>-pixelfed-backups <own deployment>-pixelfed-backups read, write, owner
operator pixelfed <own deployment>-pixelfed-cache-backups <own deployment>-pixelfed-cache-backups read, write, owner
operator valkey <own deployment>-valkey-cache-backups <own deployment>-valkey-cache-backups read, write, owner

How the system keeps the tenants apart

  • Nodes. Each deployment has its own nodes for each application and for valkey, authelia, smtp, lldap and grafana (core/setups/groups/operator.nix). The users, the sessions and the cache of a deployment are thus not in a store that a different deployment uses.
  • Network. All nodes are on one Incus bridge. Each deployment gets a /28 of its own, and an Incus network ACL on each NIC drops the traffic to and from the other deployments (core/effects/tf/incus/operator/bridge-isolation.tf). The Incus host declares the ACL of each /28 (core/components/hosting-provider/incus-bridge-acls.nix), thus the certificate of a deploy runner is restricted to the Incus project of the deployments and cannot change an ACL. Each NIC has MAC and IP address filtering (core/effects/tf/incus/instance.tf). A second ACL and the firewall of each node of the hosting provider permit only the ports that a deployment uses (core/components/hosting-provider/operator-reach.nix). The second ACL holds only the IPv4 addresses of the nodes of the hosting provider. The bridge has no IPv6 subnet (ipv6.address = none in core/components/hosting-provider/incus.nix), thus Incus drops all IPv6 on eth0. A node of a deployment sends IPv6 only on its public eth1, which has no NAT, thus the firewall of the destination node sees the real source address and applies the port limit.
  • Secrets. The policy of a node of a deployment names the KV paths with a template that OpenBao replaces with the namespace from the certificate of the node. Thus a node reads only the entries of its own deployment (core/components/hosting-provider/openbao/spire-auth.nix).
  • Databases. All deployments use the PostgreSQL node of the hosting provider. Each deployment has its own database and role for each application, and a node can read only the password of the role that has its own namespace.
  • Buckets. All deployments use the Garage cluster of the hosting provider. Each bucket and key has the namespace of the deployment as a prefix (tenant in core/resources/garage/default.nix), and a key has access only to the buckets in the table above.
  • Metrics. The query path for the metrics of an application adds the deployment_id label to each query (core/components/hosting-provider/metrics-query.nix).
  • Panel and api. An operator gets only the deployments that it owns (see In the panel).

These components are common to all tenants, and the separation there is weaker:

  • The front-end deployer is one identity for all deployments. Its OpenBao policy can write the entries of each deployment that the KV table gives, and it can read the password of the postgres superuser. The state backend has one user operator for the states of all deployments (core/components/hosting-provider/terraform-backend/front.nix).
  • The Grafana of the hosting provider has one organization, thus fediversity-staff and fediversity-admins can read the telemetry of all deployments.
  • A member of fediversity-admins can read the secrets, the databases and the containers of all deployments.