From d55a52a8d5e1e2838bc0cd2f48b72e03df6a2b39 Mon Sep 17 00:00:00 2001 From: Greg Hendrickson Date: Thu, 5 Feb 2026 16:03:40 +0000 Subject: [PATCH] feat: Add Portainer OAuth2 + enable RBAC policy bindings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add app-portainer.tf: OAuth2 provider for Portainer container management - Add portainer_url variable - Enable RBAC policy bindings for Grafana, ArgoCD, Home Assistant - Portainer bound to Infrastructure group policy RBAC Summary: - Infrastructure group → Grafana, ArgoCD, Portainer - Home Automation group → Home Assistant - Media group → arr stack (existing in app-proxy-arr-stack.tf) --- app-portainer.tf | 57 ++++++++++++++++++++++++++++++++++++++++ rbac-groups.tf | 37 +++++++++++++++++--------- terraform.tfvars.example | 1 + variables.tf | 6 +++++ 4 files changed, 88 insertions(+), 13 deletions(-) create mode 100644 app-portainer.tf diff --git a/app-portainer.tf b/app-portainer.tf new file mode 100644 index 0000000..f09b79c --- /dev/null +++ b/app-portainer.tf @@ -0,0 +1,57 @@ +# ============================================================================= +# Portainer - Container Management +# ============================================================================= + +data "authentik_property_mapping_provider_scope" "portainer" { + managed_list = [ + "goauthentik.io/providers/oauth2/scope-openid", + "goauthentik.io/providers/oauth2/scope-email", + "goauthentik.io/providers/oauth2/scope-profile", + ] +} + +resource "authentik_provider_oauth2" "portainer" { + name = "Portainer" + client_id = "portainer" + client_type = "confidential" + authorization_flow = data.authentik_flow.default_authorization.id + invalidation_flow = data.authentik_flow.default_invalidation.id + + access_token_validity = "hours=1" + refresh_token_validity = "days=30" + + property_mappings = data.authentik_property_mapping_provider_scope.portainer.ids + + allowed_redirect_uris = [ + { matching_mode = "strict", url = "${var.portainer_url}/" }, + ] + + signing_key = data.authentik_certificate_key_pair.generated.id +} + +resource "authentik_application" "portainer" { + name = "Portainer" + slug = "portainer" + protocol_provider = authentik_provider_oauth2.portainer.id + + meta_description = "Container Management Platform" + meta_launch_url = var.portainer_url + + group = "Infrastructure" +} + +# Bind Infrastructure group policy to Portainer +resource "authentik_policy_binding" "portainer_infrastructure" { + target = authentik_application.portainer.uuid + policy = authentik_policy_expression.infrastructure_access.id + order = 0 +} + +output "portainer_client_id" { + value = authentik_provider_oauth2.portainer.client_id +} + +output "portainer_client_secret" { + value = authentik_provider_oauth2.portainer.client_secret + sensitive = true +} diff --git a/rbac-groups.tf b/rbac-groups.tf index 770a315..0fb03ec 100644 --- a/rbac-groups.tf +++ b/rbac-groups.tf @@ -55,20 +55,31 @@ resource "authentik_policy_expression" "home_automation_access" { } # ----------------------------------------------------------------------------- -# Example: Bind policy to an application -# Uncomment and modify for your applications +# Application Policy Bindings +# Restrict app access by group membership # ----------------------------------------------------------------------------- -# resource "authentik_policy_binding" "sonarr_media_access" { -# target = authentik_application.sonarr.uuid -# policy = authentik_policy_expression.media_access.id -# order = 0 -# } -# -# resource "authentik_policy_binding" "grafana_infra_access" { -# target = authentik_application.grafana.uuid -# policy = authentik_policy_expression.infrastructure_access.id -# order = 0 -# } + +# Infrastructure apps - require Infrastructure group +resource "authentik_policy_binding" "grafana_infra_access" { + target = authentik_application.grafana.uuid + policy = authentik_policy_expression.infrastructure_access.id + order = 0 +} + +resource "authentik_policy_binding" "argocd_infra_access" { + target = authentik_application.argocd.uuid + policy = authentik_policy_expression.infrastructure_access.id + order = 0 +} + +# Home Automation apps +resource "authentik_policy_binding" "homeassistant_access" { + target = authentik_application.home_assistant.uuid + policy = authentik_policy_expression.home_automation_access.id + order = 0 +} + +# Media apps - require Media group (handled in app-proxy-arr-stack.tf) # ----------------------------------------------------------------------------- # Outputs diff --git a/terraform.tfvars.example b/terraform.tfvars.example index c4ba057..efba978 100644 --- a/terraform.tfvars.example +++ b/terraform.tfvars.example @@ -18,6 +18,7 @@ uptime_kuma_url = "https://status.example.com" sonarr_url = "https://sonarr.example.com" radarr_url = "https://radarr.example.com" prowlarr_url = "https://prowlarr.example.com" +portainer_url = "https://portainer.example.com" # LDAP Configuration ldap_base_dn = "dc=ldap,dc=example,dc=com" diff --git a/variables.tf b/variables.tf index 89d58e5..783fd2a 100644 --- a/variables.tf +++ b/variables.tf @@ -82,6 +82,12 @@ variable "prowlarr_url" { description = "Prowlarr URL for proxy auth" } +variable "portainer_url" { + type = string + default = "" + description = "Portainer URL for SSO" +} + # LDAP Configuration variable "ldap_base_dn" { type = string