Compare commits
18 Commits
6d014ce913
..
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 9508c151c4 | |||
| 405dede578 | |||
| 4fceaeeee6 | |||
| 1e42fdfc2c | |||
| e2d7de4148 | |||
| 331330872d | |||
| 3f6a046dff | |||
| 3662ff15ca | |||
| d848d9ae86 | |||
| fedbb2fa42 | |||
| e5dbcb56a6 | |||
| cd31cb6fa1 | |||
| 4e164014d7 | |||
| 0d17dc2cf1 | |||
| a6d6681bc9 | |||
| 93c634e4c4 | |||
| 3977f6f86b | |||
| 2f80c4a536 |
@@ -22,7 +22,7 @@ endef
|
||||
|
||||
init:
|
||||
@$(call vault_env) && \
|
||||
terragrunt run --all --non-interactive init -- -upgrade
|
||||
terragrunt run --all --non-interactive init
|
||||
|
||||
plan: init
|
||||
@$(call vault_env) && \
|
||||
|
||||
@@ -4,7 +4,8 @@ Terraform configuration for managing the Authentik identity provider at identity
|
||||
|
||||
## Managed Resources
|
||||
|
||||
- **Groups** — roles and group hierarchy (users are invited manually)
|
||||
- **Groups** — roles and group hierarchy (accounts themselves are created elsewhere)
|
||||
- **User role membership** — which `akR-*` roles a human holds (see `config/users/`)
|
||||
- **SAML providers** — SAML application integrations
|
||||
- **OAuth2/OIDC providers** — OAuth2 and OpenID Connect integrations
|
||||
- **LDAP providers** — LDAP provider and outpost configuration
|
||||
@@ -21,7 +22,8 @@ config/
|
||||
├── providers_saml/ # SAML provider definitions
|
||||
├── providers_oauth2/ # OAuth2/OIDC provider definitions
|
||||
├── providers_ldap/ # LDAP provider definitions
|
||||
└── service_accounts/ # Automation service accounts + API tokens
|
||||
├── service_accounts/ # Automation service accounts + API tokens
|
||||
└── users/ # Human role membership (authoritative per named role)
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
@@ -42,5 +42,10 @@ locals {
|
||||
trimsuffix(basename(file_path), ".yaml") => content
|
||||
if startswith(file_path, "service_accounts/")
|
||||
}
|
||||
users = {
|
||||
for file_path, content in local.all_configs :
|
||||
trimsuffix(basename(file_path), ".yaml") => content
|
||||
if startswith(file_path, "users/")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
# Permission group akP-artifactapi-admin (name = filename). Grants admin
|
||||
# access to artifactapi: bound to the artifactapi application, gating the web UI.
|
||||
application: artifactapi
|
||||
@@ -0,0 +1,3 @@
|
||||
# Permission group akP-repospawner-admin (name = filename). Grants admin
|
||||
# access to repospawner: bound to the repospawner application, gating the UI.
|
||||
application: repospawner
|
||||
@@ -1,9 +1,18 @@
|
||||
# OAuth2/OIDC provider + application for the in-cluster ArgoCD
|
||||
# (argocd.k8s.syd1.au.unkin.net). client_secret is read from Vault, not committed.
|
||||
# (argocd.k8s.syd1.au.unkin.net), serving the web UI, the `argocd` CLI and the
|
||||
# ArgoCD mobile app.
|
||||
#
|
||||
# public, not confidential: the native clients cannot hold a secret, and they
|
||||
# cannot have their own client either -- Authentik derives the `iss` claim from
|
||||
# the application slug, while ArgoCD validates every token against the single
|
||||
# issuer in oidc.config, so a second application would issue tokens ArgoCD
|
||||
# rejects. One client for all three; the strict redirect URIs below are the
|
||||
# control. Authentik ignores the secret for public clients, but the Vault read
|
||||
# stays so argocd-cm's `$argocd-oidc:client_secret` keeps resolving.
|
||||
name: ArgoCD
|
||||
authorization_flow: default-provider-authorization-implicit-consent
|
||||
invalidation_flow: default-provider-invalidation-flow
|
||||
client_type: confidential
|
||||
client_type: public
|
||||
client_id: argocd
|
||||
client_secret_vault:
|
||||
mount: kv
|
||||
@@ -19,3 +28,6 @@ redirect_uris:
|
||||
# `argocd login --sso` CLI callback (local listener).
|
||||
- matching_mode: strict
|
||||
url: http://localhost:8085/auth/callback
|
||||
# Mobile app callback (custom URL scheme, PKCE).
|
||||
- matching_mode: strict
|
||||
url: argocd://auth/callback
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
# OAuth2/OIDC provider + application for the artifactapi web UI
|
||||
# (https://artifactapi.k8s.syd1.au.unkin.net/ui in the artifactapi namespace).
|
||||
# An oauth2-proxy fronts ONLY /ui and /oauth2; access is gated on the user's
|
||||
# hierarchical ak_groups claim (akP-artifactapi-admin). The package-manager
|
||||
# surfaces (/api/v1, /api/v2, /v2, /terraform, /.well-known) are NOT behind this
|
||||
# provider -- yum, containerd, docker, terraform and CI cannot do a browser flow.
|
||||
# client_secret is read from Vault (seeded out of band), never committed.
|
||||
name: artifactapi
|
||||
authorization_flow: default-provider-authorization-implicit-consent
|
||||
invalidation_flow: default-provider-invalidation-flow
|
||||
client_type: confidential
|
||||
client_id: artifactapi
|
||||
launch_url: https://artifactapi.k8s.syd1.au.unkin.net/ui/
|
||||
client_secret_vault:
|
||||
mount: kv
|
||||
path: kubernetes/namespace/artifactapi/default/oauth-credentials
|
||||
scope_mappings:
|
||||
- goauthentik.io/providers/oauth2/scope-openid
|
||||
- goauthentik.io/providers/oauth2/scope-email
|
||||
- goauthentik.io/providers/oauth2/scope-profile
|
||||
redirect_uris:
|
||||
- matching_mode: strict
|
||||
url: https://artifactapi.k8s.syd1.au.unkin.net/oauth2/callback
|
||||
@@ -0,0 +1,25 @@
|
||||
# OAuth2/OIDC provider + application for repospawner (the internal repository
|
||||
# provisioning admin tool, served at
|
||||
# https://repospawner.k8s.syd1.au.unkin.net (cluster hostname) and
|
||||
# https://repospawner.unkin.net (external hostname) in the repospawner namespace).
|
||||
# An oauth2-proxy in front of the UI performs the OIDC login; access is gated on
|
||||
# the user's hierarchical ak_groups claim (akP-repospawner-admin).
|
||||
# client_secret is read from Vault (seeded out of band), never committed.
|
||||
name: repospawner
|
||||
authorization_flow: default-provider-authorization-implicit-consent
|
||||
invalidation_flow: default-provider-invalidation-flow
|
||||
client_type: confidential
|
||||
client_id: repospawner
|
||||
launch_url: https://repospawner.unkin.net/
|
||||
client_secret_vault:
|
||||
mount: kv
|
||||
path: kubernetes/namespace/repospawner/default/oauth-credentials
|
||||
scope_mappings:
|
||||
- goauthentik.io/providers/oauth2/scope-openid
|
||||
- goauthentik.io/providers/oauth2/scope-email
|
||||
- goauthentik.io/providers/oauth2/scope-profile
|
||||
redirect_uris:
|
||||
- matching_mode: strict
|
||||
url: https://repospawner.k8s.syd1.au.unkin.net/oauth2/callback
|
||||
- matching_mode: strict
|
||||
url: https://repospawner.unkin.net/oauth2/callback
|
||||
@@ -1,4 +1,6 @@
|
||||
# Role akR-global-admin (name = filename): full admin across all onboarded apps.
|
||||
# Nests akP-media-fafflix / akP-media-cheeztv so admins pass the jellyfin
|
||||
# application gate and can reach the akP-jellyfin-admin rights nested below.
|
||||
permissions:
|
||||
- akP-grafana-admin
|
||||
- akP-argocd-admin
|
||||
@@ -8,10 +10,14 @@ permissions:
|
||||
- akP-traefik-admin
|
||||
- akP-logviewer-admin
|
||||
- akP-watchstate-admin
|
||||
- akP-repospawner-admin
|
||||
- akP-vault-admin
|
||||
- akP-artifactapi-admin
|
||||
# arrstack has no admin tier (it is a proxy front door); grant global admins
|
||||
# the front door plus every per-app entitlement so they reach all media apps.
|
||||
- akP-arrstack-user
|
||||
- akP-arrstack-sonarr
|
||||
- akP-arrstack-radarr
|
||||
- akP-arrstack-prowlarr
|
||||
- akP-media-fafflix
|
||||
- akP-media-cheeztv
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
# users
|
||||
|
||||
One file per human, `<username>.yaml`, listing the `akR-*` roles they hold:
|
||||
|
||||
```yaml
|
||||
# Human user jane (username = filename). The account itself is not managed here
|
||||
# (humans come from LDAP sync / invite); only its role membership is.
|
||||
roles:
|
||||
- akR-media-adult
|
||||
```
|
||||
|
||||
The account is looked up by username and must already exist — nothing here
|
||||
creates users. A role that has no `config/roles/<name>.yaml` fails the plan.
|
||||
|
||||
**Naming a role here makes Terraform authoritative over that role's entire
|
||||
member list**: members added by hand in the Authentik UI for that role are
|
||||
removed on the next apply. Roles no user file names are left untouched.
|
||||
@@ -24,4 +24,5 @@ inputs = {
|
||||
providers_oauth2 = local.config.providers_oauth2
|
||||
providers_ldap = local.config.providers_ldap
|
||||
service_accounts = local.config.service_accounts
|
||||
users = local.config.users
|
||||
}
|
||||
|
||||
Generated
+50
-50
@@ -2,68 +2,68 @@
|
||||
# Manual edits may be lost in future updates.
|
||||
|
||||
provider "registry.opentofu.org/goauthentik/authentik" {
|
||||
version = "2026.5.0"
|
||||
constraints = ">= 2026.5.0"
|
||||
version = "2026.5.1"
|
||||
constraints = "2026.5.1"
|
||||
hashes = [
|
||||
"h1:SeznjPKBzSrgo8WasRnuxiGMDSeQHEKsv3U/xw8bhQE=",
|
||||
"zh:0dc1706f6fbff866f4a96de56a4934b9a277954bcdd0713549a29a9b8ec85153",
|
||||
"zh:218417ec4e864f2d7e585d6c08d39bccb96d8f3bca16c6f762be15365e434234",
|
||||
"zh:24f9afa7a1174316da3478811848cd76ef348d8a983310b8d75ed6f45abe1a92",
|
||||
"zh:560092e47cb8a72b890b3eeafe1803202cd25cf27f5f5a6e2c370f645f5d86ae",
|
||||
"zh:5bc69d8de198007ad1587e146f98cffacf0d1a571800da549b308ff5f4541474",
|
||||
"zh:65248dce941472ad2a30d0754d2f3c2db6bb6fe5080946316fb097d6ba7cc79f",
|
||||
"zh:79c9a59a8d3c60280e27a064668889594da44c60f940b046b7c8e63be01067d0",
|
||||
"zh:87f26cadcd842d6e6d0af94ef0e56860557f5d07f487b10d69d38b63af68bea5",
|
||||
"zh:8e42c9d0e77d61cc2e5f8c8b761f6e484774d93771927b4cb5fbdae41209dd33",
|
||||
"zh:94ff632b9b4841527c6b652d51a850a8a47c84c0308a3efc189e0ff7e2558f87",
|
||||
"zh:b8d32d9f17a905b63c87a23306c02c295b7c8b70f72950071aa3086396932816",
|
||||
"zh:c91982af99474fc2e4e69be36ed3a68847f261963ed79f6a546fc75703992f99",
|
||||
"zh:eb9c1fd3020cf61e9b7a6a38d2965f4b521495a9928705e963459a4af857f97d",
|
||||
"h1:L9q3pjCoeKQdn0/OApv4O1HiC/PDLDqcnM7Ff5XFB+0=",
|
||||
"zh:05f252734db99792e5d3f52b582a4e0027348ac2614d8c9621bf7e623cff8036",
|
||||
"zh:0e1cd8041650aed9bb8d4af23301e786223ed5d1a00c2a5150b7ad874ae03917",
|
||||
"zh:26b1daebd30650df411f903248e061cf963712a063b38e731782fb13a5755ddf",
|
||||
"zh:362b536ff6bf8866c7c1094c3e2322c22b8c36d8d4caa4db0397cebbcad08561",
|
||||
"zh:3d94367b853960f5e88efe3ae69d995d02a11dc8d60ec4d7413a37aabf78b379",
|
||||
"zh:3e840e204677eabe562d17c2ad12afdfa250098725bebac4e91fb8934e233c22",
|
||||
"zh:4db66139d7a9ec6f7852538573261010d48f0a939e2fe8eeb5c55b01149e3629",
|
||||
"zh:7b88a830fb26c697f9d240f498f604485454b12e56b7604eda4ca35d10660ecd",
|
||||
"zh:851bc8bd2d4a16dc71f30da17b6285aa7d85f4bc4175fde7b8319a6a8987ec65",
|
||||
"zh:8bdfc2c70271d48126eef3b1a30d0d132e868d2118ae7277323ed4c905636e4a",
|
||||
"zh:e85c03eac43f23f25ad5443a2984cc67977c3abdcb4c4c426d37342c2f25c37e",
|
||||
"zh:efc296826a700a4e90ee06f8bd3b137617486ce774772aabed3053d4ef8dd906",
|
||||
"zh:f249033dc242c51600cd3968535efa0780352d5ae7435e8ab1482a7ccc9c2f5e",
|
||||
]
|
||||
}
|
||||
|
||||
provider "registry.opentofu.org/hashicorp/random" {
|
||||
version = "3.9.0"
|
||||
version = "3.9.1"
|
||||
constraints = ">= 3.6.0"
|
||||
hashes = [
|
||||
"h1:8EQU5KSxezcjo/phRSe69rDOI0lk4pSaggj7FsskYp8=",
|
||||
"zh:03f1114cc20b8913523735ab76e0f0a2b16ce13c92923a53304bf85f07fc0dbc",
|
||||
"zh:105b678ee72322a3067f105d7e05e940f6143238f377f6e87ff4ec909246ac2a",
|
||||
"zh:55f3bbf13ea18cbace61a706566a80f25f33fe2b1780b6f3d7b582af2a05b6d2",
|
||||
"zh:63adf996db48f082f7a6351eb485e219cd88795fc71e6ec60a837263ab0d2cb1",
|
||||
"zh:7e99550738a4e3cc68b8a467714b0d69371025fe95e3326d5323d026d55653e9",
|
||||
"zh:8342b54af3a18a37e075eeae61be57f4de2ba71b35d95c5075d402dd2c1f289d",
|
||||
"zh:83ee18e32ac9dd5fc91298554b7c4cfa4c3a1db50f4c797945637cc93c0844ae",
|
||||
"zh:993ecc0adbf6bd535a59fbc9b735d8c33950e6f6eb5e621d750da9b71d65d80a",
|
||||
"zh:ad722bc59d4edbf1415e827fc007c0efe6e0e9462d5568bae20b34be1058a261",
|
||||
"zh:ae9448e1f87b2f9a6c5197a0e9862162ec6b137cb3a3835e11522995d8939e7c",
|
||||
"zh:bc9cdd3aac784f759125c6627f6f6416e8726a1c184eb9cf3e55b9edbc94c627",
|
||||
"zh:c8e35b89572ba1c40a9b20022e033a3395fb8d42e7604d50c900f193ba10382e",
|
||||
"zh:e2deaa8a9975ef81d9f62baed12c41286918b0a10908e0e031f13f69a3b730a1",
|
||||
"zh:ee39707557210a0ab1098aa357d2cdfe502e5a312d0dbdffb09d08facc4d3fc5",
|
||||
"zh:f81afe4eb63e8aa9e0ea71be6c990f0dc69cb360e7191c0742a991f4a5081b64",
|
||||
"h1:CEQeHfnUDB3uqAkKoEWfWgbj+kpoQHgcuPbAjPzbh+U=",
|
||||
"zh:09aaf19b0d22726d2378e0e89fbbefc183494d7bd585759d6c4e69ba50951a2f",
|
||||
"zh:31575ca9bc0db20337096d178ea73bce3ebca343ed071c67f78cf39f800c9ec6",
|
||||
"zh:624fb6ed552abc34a5aaac41e76a373da65ac08e524b09b672f29c60e6ac896a",
|
||||
"zh:6a4760d55132b9750ac1a04f6fc32e247034daa999f71452dba9cbca225a529a",
|
||||
"zh:768a6047cfb8958e7b0b120c580aa3de6624a7fbb2c56ad6df85cd559ed26ec7",
|
||||
"zh:8983c788ba660bcb587e64ff9c3e4323515caf78facbe0abe6432e7aff8df893",
|
||||
"zh:8d570eb026a4f00b58a1d36be0ce3c13adf4d973efcd4162b05cb295bbc14257",
|
||||
"zh:a2259540854d5f699c36b89244fb202ebb2c219b64669a51072687d04fb47152",
|
||||
"zh:aaa51d905b0e80a28e02f9bee2cf6c91ffade7389d77ab9198aa12809ed04955",
|
||||
"zh:afb60995e98573facddfb47baedf7e288408680eb00b5d3df570611758947c72",
|
||||
"zh:b9a46d852ce53fa037f47537a7de53f37b759ccf211600b7ba44c66ba4b616b7",
|
||||
"zh:bafcfeeefcd0dfefeff120b655b45edb0497c4717534ffe5201b3cb556d1ffe6",
|
||||
"zh:c3ac24d397eae054aca2290e20943e0c767592cc661c890850c25ac01829308d",
|
||||
"zh:eafba4127ebadcc5ed0e427935c66fb5e2da7cfdaae39a66d52f4a50d51faf1e",
|
||||
"zh:f39d4bce213ed9bba3474bad468136af08ff6c4c33adaafcc10c1f78067adfe3",
|
||||
]
|
||||
}
|
||||
|
||||
provider "registry.opentofu.org/hashicorp/vault" {
|
||||
version = "5.10.1"
|
||||
version = "5.12.0"
|
||||
constraints = ">= 4.0.0"
|
||||
hashes = [
|
||||
"h1:wo5cTkl/1nlxMfdn1yEDIHNoRLMczuK6COH2Id4/zeY=",
|
||||
"zh:0abf976c01f0c0732d0ccc6481e52008be5ee9c8e3d9b5eba0573c640fcf7019",
|
||||
"zh:2aff4d7ee7ba9eb3de2cd5cda16ba92b4ec7a2b43232aec180984241a323b216",
|
||||
"zh:2cc186fd0bfc44e100a22b0b40ae8ddcd0ec210a53c1da65d310ee758b1d2b08",
|
||||
"zh:3f8fb8594736b34af4b26437dd4df4dd4042ad4905223995cfebb8a1f10682ec",
|
||||
"zh:47fb41b18b74073f557dbcd6aad2183e416293405ccd70c0691a279cfe97f8cd",
|
||||
"zh:517e2f2764d671c22d22def0384fdfc521b456458189189c0363375495d114dc",
|
||||
"zh:5a49a2003636f2b8a547d494a6c06d43d62a68299775305408c52eff22b1c11f",
|
||||
"zh:66d4e716920ada84b0c768f4aca4c8948388995462923349a01bd3818d82b618",
|
||||
"zh:7599f652e89a3f18fa4b76a59d115cc63255cc36ce6b273850509ba25031abca",
|
||||
"zh:9c3e38ae7e670de973b6255d7050f526cd2b3ca7c383d7ba7226fc204d97c507",
|
||||
"zh:d04b046023fa9fd69def678f27e001c298ea34fc99ba51f835cda82e496fdb57",
|
||||
"zh:d9acd8810f6660cd51bb4c25596632984ae18e93340c82a102d074c6eac95151",
|
||||
"zh:e161bcb9a22607270b980eeff2ba693335fb62d6978516dff93dd4c91cda99b3",
|
||||
"zh:ef47502f08cfcb5311b7b16a7905e0052bf28359e07cc00ed080ef454e0946cf",
|
||||
"zh:f0640ddb52e7e90c5006ff571f6ad0554e593665320c764c57a3d8b7ec31b490",
|
||||
"h1:HVdhw1ShP/LlYuDOdVKmLO/kLVfngw9VHM2YfDl879Y=",
|
||||
"zh:070709539eeff2dbf6af13269e6a3c14cea0ee4e5a5fff237d574805df2787e9",
|
||||
"zh:0e017e993252c37008dcf1848deb32f15a14b303335c3e06885d7efea07fef1d",
|
||||
"zh:1717ba0a0f8d906ced0eb5a3ed1e2a1808d824868da5095ea1da12d60904777d",
|
||||
"zh:218f879c5f3f97564f4867bcbb419197c4aa4e41ce5bc3eed50c71926f0519f9",
|
||||
"zh:2437d8f76d6220883c96a073801af973db957c8b1c79187256c204437f4ed08e",
|
||||
"zh:9dce3198d2f03ce05c3fb4cb90433de5863f0d1818fc4abc3e3576f562409c85",
|
||||
"zh:a51d00c192e6cf86d588501d8c4a2a37a258679784651909d55f64d28011b28d",
|
||||
"zh:c99586f88b0166d5522dedfbec9d246a51efae346bbdfcaeb296ff72b5c80f94",
|
||||
"zh:cee10cca2a295e4fd9ce2779239f7f79ab97328d9e30833924cceb349e509051",
|
||||
"zh:d9b5cde1c02db0b211ec3f77b519122f93b442594ce9f20d386ab5d0d05ead93",
|
||||
"zh:deafe53fa413e71dac120177a58b678e81a64279a692ba77eca09a9bce0bff1a",
|
||||
"zh:f372b83c70ee5dabd892bd9ec1eb9127fe6331d88178b7b84fa5f52f616b59df",
|
||||
"zh:f47e4fd82b72e62a5e1eeaaa1b72cc2709545a8431964123b24ed5c03a03e492",
|
||||
"zh:f629a86c98be3fd2aacb58336d26ce268a76fe754b048f58a3faa0712bb4a837",
|
||||
"zh:feaef85debc4a4a72d7a23988b18fff0b4dbc47f37e31a0b51022df071ac7b85",
|
||||
]
|
||||
}
|
||||
|
||||
@@ -16,6 +16,31 @@ resource "authentik_group" "permission" {
|
||||
attributes = jsonencode(each.value.attributes)
|
||||
}
|
||||
|
||||
# Humans are created outside this module (LDAP sync / invite), so they are
|
||||
# looked up rather than declared: resolve the username to the numeric pk that
|
||||
# group membership is keyed on. A missing account fails the plan; nothing here
|
||||
# can create a user.
|
||||
data "authentik_user" "human" {
|
||||
for_each = var.users
|
||||
username = each.key
|
||||
|
||||
lifecycle {
|
||||
precondition {
|
||||
condition = length(setsubtract(each.value.roles, keys(var.role_groups))) == 0
|
||||
error_message = "config/users/${each.key}.yaml names a role with no config/roles/<name>.yaml."
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
locals {
|
||||
# Invert user -> roles into role -> member pks. Only roles some user file
|
||||
# names appear here; every other role falls through to a null `users` below.
|
||||
role_members = {
|
||||
for role in distinct(flatten([for u, v in var.users : v.roles])) :
|
||||
role => [for u, v in var.users : data.authentik_user.human[u].pk if contains(v.roles, role)]
|
||||
}
|
||||
}
|
||||
|
||||
# Role groups (akR-*): what users are assigned to. Each nests permission groups
|
||||
# as parents, so a role member is an effective member of every permission it
|
||||
# grants. Separate resource from permissions so this reference is not a
|
||||
@@ -27,6 +52,10 @@ resource "authentik_group" "role" {
|
||||
is_superuser = each.value.is_superuser
|
||||
parents = [for p in each.value.permissions : authentik_group.permission[p].id]
|
||||
attributes = jsonencode(each.value.attributes)
|
||||
# Authoritative: a role claimed by config/users/ has exactly these members, so
|
||||
# one dropped from a user file is removed. null (every unclaimed role) leaves
|
||||
# the attribute computed, i.e. membership stays whatever Authentik holds.
|
||||
users = lookup(local.role_members, each.key, null)
|
||||
}
|
||||
|
||||
# Emit an `ak_groups` claim containing the user's groups AND all inherited
|
||||
@@ -284,6 +313,13 @@ resource "authentik_policy_binding" "app_access" {
|
||||
order = 0
|
||||
}
|
||||
|
||||
# Created server-side, but its post-create read-back hit the Authentik Postgres
|
||||
# read replica before the row replicated and 404'd, so it never reached state.
|
||||
import {
|
||||
to = authentik_policy_binding.app_access["akP-artifactapi-admin"]
|
||||
id = "c9f22628-d48c-477b-b9ac-a952c7d081ce"
|
||||
}
|
||||
|
||||
# Service accounts: non-human identities for automation. Kept out of the group
|
||||
# hierarchy above (which models human app access) and given capabilities through
|
||||
# RBAC roles instead.
|
||||
|
||||
@@ -156,3 +156,18 @@ variable "service_accounts" {
|
||||
}))
|
||||
default = {}
|
||||
}
|
||||
|
||||
# Human role membership. The username is the map key (the config filename). The
|
||||
# account itself is never managed here — humans are created by LDAP sync/invite
|
||||
# and only looked up — so this grants and revokes roles, it does not make users.
|
||||
#
|
||||
# OWNERSHIP: naming a role in any user file makes Terraform authoritative over
|
||||
# that role's entire member list, so members added by hand in the UI for that
|
||||
# role are removed on the next apply. Roles no user file names are left alone.
|
||||
variable "users" {
|
||||
type = map(object({
|
||||
# keys into var.role_groups (akR-*) this user is a member of.
|
||||
roles = optional(list(string), [])
|
||||
}))
|
||||
default = {}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
terraform {
|
||||
required_version = ">= 1.10"
|
||||
required_providers {
|
||||
# 2026.8.0 requires pbm_uuid on applications; the deployed 2026.5.3 server does not return it.
|
||||
authentik = {
|
||||
source = "goauthentik/authentik"
|
||||
version = ">= 2026.5.0"
|
||||
version = "2026.5.1"
|
||||
}
|
||||
vault = {
|
||||
source = "hashicorp/vault"
|
||||
|
||||
Reference in New Issue
Block a user