name: dis-resources description: >- Create and configure Altinn DIS platform custom resources as GitOps-ready Kubernetes manifests — PostgreSQL Database and DatabaseServer, Azure Key Vault, and ApplicationIdentity. Use this whenever the user wants to provision or wire up DIS infrastructure for an Altinn app: creating a database, standing up a postgres server (dedicated or shared), requesting a key vault or secret store, or creating an application / managed identity — even when they don't name the CRD or the operator. Do NOT use this for developing the dis-* operators themselves (controller/reconciler code, regenerating CRD manifests).
Authoring Altinn DIS resources
DIS ("Declarative Infrastructure Services") is a set of Kubernetes operators
that reconcile custom resources into Azure infrastructure. App teams get
self-service infra by committing a manifest to GitOps — the operator does the
Azure provisioning and reports back through the resource's status.
Your job with this skill is to produce correct, minimal, GitOps-ready manifests for these resources, getting the cross-resource wiring and the cross-field validation rules right the first time. The schemas live in this repo, so prefer reading them over guessing.
Resource catalog
| Kind | apiVersion | Operator | Purpose | Reference |
|---|---|---|---|---|
| ApplicationIdentity | application.dis.altinn.cloud/v1alpha1 |
dis-identity-operator | Azure managed identity + workload-identity federation for an app | references/applicationidentity.md |
| DatabaseServer | storage.dis.altinn.cloud/v1alpha1 |
dis-pgsql-operator | Azure PostgreSQL Flexible Server (dedicated or shared) | references/databaseserver.md |
| Database | storage.dis.altinn.cloud/v1alpha1 |
dis-pgsql-operator | A PostgreSQL database on a server, with role-based access | references/database.md |
| Vault | vault.dis.altinn.cloud/v1alpha1 |
dis-vault-operator | Azure Key Vault owned by an identity or service account | references/vault.md |
Dependency graph
ApplicationIdentity is the foundation: its status exposes the
principalId/clientId that the other resources resolve. Most useful setups
need an identity first, then the resource that references it.
ApplicationIdentity
├─ DatabaseServer.spec.auth.admin.identity.identityRef (server admin)
├─ Database.spec.access.principals[].identityRef (app access)
└─ Vault.spec.identityRef (vault owner)
DatabaseServer ──< Database.spec.server.name (a Database lives on a server)
All references are by name within the same namespace. There is no cross-namespace referencing.
Decision guide
Translate the request into the set of resources to author, in order:
- "A database for one app" → an
ApplicationIdentityfor the app + aDatabaseServer(if the team has none yet) + aDatabasethat references both. Giving the app its own server is the single-tenant layout. The operator then publishes a connection ConfigMap the app's workload consumes — always tell the user how to connect (see references/database.md). - "Databases for several apps that share infrastructure" → one
DatabaseServerwithmode: Shared(plusnetwork) + oneDatabaseper app, each with its ownaccess.principals. This is the multitenant layout. - "A secret store / key vault" → an
ApplicationIdentity(if the app has none) + aVaultthat references it (or an existingServiceAccount). - "Just an identity / workload identity" → an
ApplicationIdentityalone.
If an identity, server, or service account the user names already exists in their repo, reference it rather than recreating it — ask if you're unsure.
Authoring workflow
- Use the decision guide to list the resources needed and the order to apply them.
- Open the matching reference file(s) for each Kind.
- Read the live sample(s) the reference points to before finalizing — the
in-repo
config/samples/*.yamlandconfig/crd/bases/*.yamlare the source of truth and may have moved past these notes. - Copy the template, fill in real values, and keep cross-resource names consistent and in a single namespace.
- Validate (below).
- Place the manifest at the team's GitOps path for that namespace.
- For a
Database, the app's connection details are published by the operator as a ConfigMap, not set in the manifest — surface its deterministic name and keys and give the user the workload snippet that consumes it (see references/database.md).
Validation
- Best (with a cluster): from the operator directory run
make install-cacheto install the CRDs, thenkubectl apply --dry-run=server -f <file>.yaml. Server-side dry-run enforces enums, ranges, required fields, and the cross-field (XValidation) rules. - Offline: check field names, enums, and ranges against the CRD schema at
services/<operator>/config/crd/bases/<group>_<plural>.yaml(theopenAPIV3Schemablock). Watch these cross-field rules in particular — they are the easiest things to get wrong:- Vault: exactly one of
identityRef/serviceAccountRef. - DatabaseServer:
networkis required whenmode: Sharedand must be omitted whenmode: Dedicated;modeis immutable once created. - Database access principal: exactly one of
identityRef/group/servicePrincipal. - Server admin identity: either
identityRef, or bothnameandprincipalId— not a mix.
- Vault: exactly one of
Conventions
- Write manifests as pure YAML with no inline comments — rationale belongs in the PR description, not the file.
- Always set
metadata.namespaceexplicitly; every cross-resource reference resolves within that namespace. - Use the same name for a resource and the references that point at it (e.g. an
app's
ApplicationIdentityname and theidentityRef.namethat uses it), so the wiring is obvious.
Where these are heading
These CRDs are the low-level building blocks. A higher-level DisApp resource
(via kro) is planned to compose them into a single app abstraction, so treat the
names and labels you set here as a stable contract other tooling will depend on.