Compare commits
2 Commits
3760908270
...
7dde0d3f2a
Author | SHA1 | Date | |
---|---|---|---|
7dde0d3f2a | |||
00cbd8830b |
15
terraform/authentik/.claude/settings.local.json
Normal file
15
terraform/authentik/.claude/settings.local.json
Normal file
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"permissions": {
|
||||
"allow": [
|
||||
"WebSearch",
|
||||
"WebFetch(domain:registry.terraform.io)",
|
||||
"Bash(C:UsersabAppDataLocalMicrosoftWinGetPackagesHashicorp.Terraform_Microsoft.Winget.Source_8wekyb3d8bbweterraform.exe apply -auto-approve)",
|
||||
"Bash(\"C:\\Users\\ab\\AppData\\Local\\Microsoft\\WinGet\\Packages\\Hashicorp.Terraform_Microsoft.Winget.Source_8wekyb3d8bbwe\\terraform.exe\" apply -auto-approve)",
|
||||
"Bash(\"C:\\Users\\ab\\AppData\\Local\\Microsoft\\WinGet\\Packages\\Hashicorp.Terraform_Microsoft.Winget.Source_8wekyb3d8bbwe\\terraform.exe\" apply -auto-approve -lock=false)",
|
||||
"Bash(\"C:\\Users\\ab\\AppData\\Local\\Microsoft\\WinGet\\Packages\\Hashicorp.Terraform_Microsoft.Winget.Source_8wekyb3d8bbwe\\terraform.exe\" plan -lock=false)",
|
||||
"Bash(\"C:\\Users\\ab\\AppData\\Local\\Microsoft\\WinGet\\Packages\\Hashicorp.Terraform_Microsoft.Winget.Source_8wekyb3d8bbwe\\terraform.exe\" apply -replace=\"authentik_outpost.outposts[\"\"kubernetes-outpost\"\"]\" -auto-approve -lock=false)"
|
||||
],
|
||||
"deny": [],
|
||||
"ask": []
|
||||
}
|
||||
}
|
44
terraform/authentik/.terraform.lock.hcl
generated
Normal file
44
terraform/authentik/.terraform.lock.hcl
generated
Normal file
@@ -0,0 +1,44 @@
|
||||
# This file is maintained automatically by "terraform init".
|
||||
# Manual edits may be lost in future updates.
|
||||
|
||||
provider "registry.terraform.io/goauthentik/authentik" {
|
||||
version = "2025.8.1"
|
||||
constraints = ">= 2023.10.0"
|
||||
hashes = [
|
||||
"h1:L3Fh0LyQ066laexCAeqLd+AVuSPDemwCmYgq1Bges6c=",
|
||||
"zh:0c3f1083fd48f20ed06959401ff1459fbb5d454d81c8175b5b6d321b308c0be3",
|
||||
"zh:21c6d93f8d26e688da38a660d121b5624e3597c426c671289f31a17a9771abbf",
|
||||
"zh:301b5763ffc4c5fe47aa7e851ce0b19f71bab4fae5c81003ad81b38775e85f78",
|
||||
"zh:4f7ee6473f6a687340538ddac0ec4a0453664186b15fdb0bb2fb5fcd8fb3ad30",
|
||||
"zh:7927f4f634c9e072d4aa6620d09e97dc83eeb1dbd0667102086779cd5fc495c1",
|
||||
"zh:84e7c2a3f3de721a54abe4c971d9a163127f5e4af91d023260fea305ac74bcf4",
|
||||
"zh:92af52aaac518c426164eb731d282f51a5825e64e6a02b0695952177a7af7d9c",
|
||||
"zh:a6920a54d5df69342f4ea2d903676145b00e7375d2f2eecc0840858d83b3b4a8",
|
||||
"zh:ac8a60801fc55fd05b3471778f908ed43072e046997c0082644c9602b84dafec",
|
||||
"zh:b1cc29e2878aa94a3827fd5e1dd8cffb98397aa4093d6a4852c6e53157e9b35f",
|
||||
"zh:c2d78f308c4d70a16ef4f6d1f4822a64f8f160d0a207f2121904cdd6f4942db4",
|
||||
"zh:ca970e5776f408059a84b4e17f6ac257ec92afae956be74f3807c548e4567eaa",
|
||||
"zh:eb2e3650ee0eec033207b6d72fcb938dc5846c6feb8a61ae30d61981ea411269",
|
||||
"zh:fcb93e51c84ba592bc2b075d7342e475126e5029620959666999b5b1bd11cb98",
|
||||
]
|
||||
}
|
||||
|
||||
provider "registry.terraform.io/hashicorp/random" {
|
||||
version = "3.7.2"
|
||||
constraints = ">= 3.5.0"
|
||||
hashes = [
|
||||
"h1:0hcNr59VEJbhZYwuDE/ysmyTS0evkfcLarlni+zATPM=",
|
||||
"zh:14829603a32e4bc4d05062f059e545a91e27ff033756b48afbae6b3c835f508f",
|
||||
"zh:1527fb07d9fea400d70e9e6eb4a2b918d5060d604749b6f1c361518e7da546dc",
|
||||
"zh:1e86bcd7ebec85ba336b423ba1db046aeaa3c0e5f921039b3f1a6fc2f978feab",
|
||||
"zh:24536dec8bde66753f4b4030b8f3ef43c196d69cccbea1c382d01b222478c7a3",
|
||||
"zh:29f1786486759fad9b0ce4fdfbbfece9343ad47cd50119045075e05afe49d212",
|
||||
"zh:4d701e978c2dd8604ba1ce962b047607701e65c078cb22e97171513e9e57491f",
|
||||
"zh:78d5eefdd9e494defcb3c68d282b8f96630502cac21d1ea161f53cfe9bb483b3",
|
||||
"zh:7b8434212eef0f8c83f5a90c6d76feaf850f6502b61b53c329e85b3b281cba34",
|
||||
"zh:ac8a23c212258b7976e1621275e3af7099e7e4a3d4478cf8d5d2a27f3bc3e967",
|
||||
"zh:b516ca74431f3df4c6cf90ddcdb4042c626e026317a33c53f0b445a3d93b720d",
|
||||
"zh:dc76e4326aec2490c1600d6871a95e78f9050f9ce427c71707ea412a2f2f1a62",
|
||||
"zh:eac7b63e86c749c7d48f527671c7aee5b4e26c10be6ad7232d6860167f99dbb0",
|
||||
]
|
||||
}
|
55
terraform/authentik/README.md
Normal file
55
terraform/authentik/README.md
Normal file
@@ -0,0 +1,55 @@
|
||||
# Authentik Terraform Module
|
||||
|
||||
Terraform module for managing Authentik applications with OAuth2/OpenID and Proxy providers, including automatic Outpost assignment.
|
||||
|
||||
## Usage
|
||||
|
||||
```hcl
|
||||
module "authentik" {
|
||||
source = "./authentik"
|
||||
|
||||
authentik_url = "https://auth.example.com"
|
||||
authentik_token = var.authentik_token
|
||||
|
||||
oauth_applications = {
|
||||
"gitlab" = {
|
||||
name = "GitLab OAuth"
|
||||
slug = "gitlab"
|
||||
redirect_uris = ["https://gitlab.example.com/users/auth/openid_connect/callback"]
|
||||
}
|
||||
}
|
||||
|
||||
proxy_applications = {
|
||||
"portainer" = {
|
||||
name = "Portainer"
|
||||
slug = "portainer"
|
||||
external_host = "https://portainer.example.com"
|
||||
internal_host = "http://portainer:9000"
|
||||
outpost = "k8s-outpost"
|
||||
}
|
||||
}
|
||||
|
||||
outposts = {
|
||||
"k8s-outpost" = {
|
||||
name = "Kubernetes Outpost"
|
||||
type = "proxy"
|
||||
service_connection = "k8s-local"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Structure
|
||||
|
||||
- `main.tf` - Main configuration
|
||||
- `variables.tf` - Input variables
|
||||
- `outputs.tf` - Output values
|
||||
- `modules/oauth-provider/` - OAuth2/OIDC provider module
|
||||
- `modules/proxy-provider/` - Proxy provider module
|
||||
- `terraform.tfvars.example` - Configuration example
|
||||
|
||||
## Requirements
|
||||
|
||||
- Terraform >= 1.0
|
||||
- Authentik provider >= 2023.10.0
|
||||
- Authentik API token with admin permissions
|
181
terraform/authentik/main.tf
Normal file
181
terraform/authentik/main.tf
Normal file
@@ -0,0 +1,181 @@
|
||||
|
||||
data "authentik_flow" "default_authorization_flow" {
|
||||
slug = var.default_authorization_flow
|
||||
}
|
||||
|
||||
data "authentik_flow" "default_authentication_flow" {
|
||||
slug = var.default_authentication_flow
|
||||
}
|
||||
|
||||
data "authentik_flow" "default_invalidation_flow" {
|
||||
slug = var.default_invalidation_flow
|
||||
}
|
||||
|
||||
resource "authentik_group" "groups" {
|
||||
for_each = var.groups
|
||||
|
||||
name = each.value.name
|
||||
is_superuser = each.value.is_superuser
|
||||
parent = each.value.parent
|
||||
attributes = jsonencode(each.value.attributes)
|
||||
}
|
||||
|
||||
resource "authentik_certificate_key_pair" "certificates" {
|
||||
for_each = var.certificates
|
||||
|
||||
name = each.value.name
|
||||
certificate_data = each.value.certificate_data
|
||||
key_data = each.value.key_data
|
||||
}
|
||||
|
||||
|
||||
data "authentik_service_connection_kubernetes" "local_k8s" {
|
||||
name = "Local Kubernetes Cluster"
|
||||
}
|
||||
|
||||
resource "authentik_flow" "flows" {
|
||||
for_each = var.flows
|
||||
|
||||
name = each.value.name
|
||||
title = each.value.title
|
||||
slug = each.value.slug
|
||||
designation = each.value.designation
|
||||
policy_engine_mode = each.value.policy_engine_mode
|
||||
compatibility_mode = each.value.compatibility_mode
|
||||
layout = each.value.layout
|
||||
denied_action = each.value.denied_action
|
||||
}
|
||||
|
||||
resource "authentik_property_mapping_provider_scope" "oidc_mappings" {
|
||||
for_each = {
|
||||
for k, v in var.property_mappings : k => v
|
||||
if v.oidc_scope != null
|
||||
}
|
||||
|
||||
name = each.value.name
|
||||
scope_name = each.value.oidc_scope
|
||||
expression = each.value.expression
|
||||
}
|
||||
|
||||
resource "authentik_property_mapping_provider_saml" "saml_mappings" {
|
||||
for_each = {
|
||||
for k, v in var.property_mappings : k => v
|
||||
if v.saml_name != null
|
||||
}
|
||||
|
||||
name = each.value.name
|
||||
saml_name = each.value.saml_name
|
||||
expression = each.value.expression
|
||||
}
|
||||
|
||||
module "oauth_applications" {
|
||||
source = "./modules/oauth-provider"
|
||||
|
||||
for_each = var.oauth_applications
|
||||
|
||||
name = each.value.name
|
||||
app_name = each.value.name
|
||||
app_slug = each.value.slug
|
||||
app_group = each.value.group
|
||||
client_id = each.value.client_id
|
||||
authorization_flow = try(authentik_flow.flows[each.value.authorization_flow].id, data.authentik_flow.default_authorization_flow.id)
|
||||
invalidation_flow = data.authentik_flow.default_invalidation_flow.id
|
||||
redirect_uris = each.value.redirect_uris
|
||||
client_type = each.value.client_type
|
||||
include_claims_in_id_token = each.value.include_claims_in_id_token
|
||||
access_code_validity = each.value.access_code_validity
|
||||
access_token_validity = each.value.access_token_validity
|
||||
refresh_token_validity = each.value.refresh_token_validity
|
||||
property_mappings = each.value.property_mappings
|
||||
signing_key = each.value.signing_key
|
||||
policy_engine_mode = each.value.policy_engine_mode
|
||||
meta_description = each.value.meta_description
|
||||
meta_launch_url = each.value.meta_launch_url
|
||||
meta_icon = each.value.meta_icon
|
||||
}
|
||||
|
||||
module "proxy_applications" {
|
||||
source = "./modules/proxy-provider"
|
||||
|
||||
for_each = var.proxy_applications
|
||||
|
||||
name = each.value.name
|
||||
app_name = each.value.name
|
||||
app_slug = each.value.slug
|
||||
app_group = each.value.group
|
||||
external_host = each.value.external_host
|
||||
internal_host = each.value.internal_host
|
||||
internal_host_ssl_validation = each.value.internal_host_ssl_validation
|
||||
authorization_flow = try(authentik_flow.flows[each.value.authorization_flow].id, data.authentik_flow.default_authorization_flow.id)
|
||||
invalidation_flow = data.authentik_flow.default_invalidation_flow.id
|
||||
mode = each.value.mode
|
||||
intercept_header_auth = each.value.intercept_header_auth
|
||||
basic_auth_enabled = each.value.basic_auth_enabled
|
||||
basic_auth_user_attribute = each.value.basic_auth_username_attribute
|
||||
basic_auth_password_attribute = each.value.basic_auth_password_attribute
|
||||
cookie_domain = each.value.cookie_domain
|
||||
skip_path_regex = each.value.skip_path_regex
|
||||
policy_engine_mode = each.value.policy_engine_mode
|
||||
meta_description = each.value.meta_description
|
||||
meta_launch_url = each.value.meta_launch_url
|
||||
meta_icon = each.value.meta_icon
|
||||
}
|
||||
|
||||
locals {
|
||||
oauth_outpost_assignments = {
|
||||
for app_key, app in var.oauth_applications : app_key => app.outpost
|
||||
if app.outpost != null
|
||||
}
|
||||
|
||||
proxy_outpost_assignments = {
|
||||
for app_key, app in var.proxy_applications : app_key => app.outpost
|
||||
if app.outpost != null
|
||||
}
|
||||
|
||||
outpost_providers = {
|
||||
for outpost_key, outpost in var.outposts : outpost_key => concat(
|
||||
[for app_key, app_outpost in local.oauth_outpost_assignments :
|
||||
module.oauth_applications[app_key].provider_id if app_outpost == outpost_key],
|
||||
[for app_key, app_outpost in local.proxy_outpost_assignments :
|
||||
module.proxy_applications[app_key].provider_id if app_outpost == outpost_key]
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
resource "authentik_outpost" "outposts" {
|
||||
for_each = {
|
||||
for k, v in var.outposts : k => v
|
||||
if length(lookup(local.outpost_providers, k, [])) > 0
|
||||
}
|
||||
|
||||
name = each.value.name
|
||||
type = "proxy"
|
||||
protocol_providers = local.outpost_providers[each.key]
|
||||
service_connection = data.authentik_service_connection_kubernetes.local_k8s.id
|
||||
config = jsonencode({
|
||||
log_level = "info"
|
||||
docker_labels = null
|
||||
authentik_host = var.authentik_url
|
||||
docker_network = null
|
||||
container_image = null
|
||||
docker_map_ports = true
|
||||
refresh_interval = "minutes=5"
|
||||
kubernetes_replicas = 1
|
||||
kubernetes_namespace = "authentik"
|
||||
authentik_host_browser = ""
|
||||
object_naming_template = "ak-outpost-%(name)s"
|
||||
authentik_host_insecure = false
|
||||
kubernetes_json_patches = null
|
||||
kubernetes_service_type = "ClusterIP"
|
||||
kubernetes_image_pull_secrets = []
|
||||
kubernetes_ingress_class_name = null
|
||||
kubernetes_disabled_components = []
|
||||
kubernetes_ingress_annotations = {}
|
||||
kubernetes_ingress_secret_name = "authentik-outpost-tls"
|
||||
})
|
||||
|
||||
depends_on = [
|
||||
module.oauth_applications,
|
||||
module.proxy_applications
|
||||
]
|
||||
}
|
59
terraform/authentik/modules/oauth-provider/main.tf
Normal file
59
terraform/authentik/modules/oauth-provider/main.tf
Normal file
@@ -0,0 +1,59 @@
|
||||
terraform {
|
||||
required_providers {
|
||||
authentik = {
|
||||
source = "goauthentik/authentik"
|
||||
version = ">= 2023.10.0"
|
||||
}
|
||||
random = {
|
||||
source = "hashicorp/random"
|
||||
version = ">= 3.5.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
resource "random_password" "client_secret" {
|
||||
count = var.client_secret == null ? 1 : 0
|
||||
length = 40
|
||||
special = true
|
||||
}
|
||||
|
||||
resource "authentik_provider_oauth2" "provider" {
|
||||
name = var.name
|
||||
client_id = var.client_id != null ? var.client_id : random_id.client_id[0].hex
|
||||
client_secret = var.client_secret != null ? var.client_secret : random_password.client_secret[0].result
|
||||
client_type = var.client_type
|
||||
authorization_flow = var.authorization_flow
|
||||
invalidation_flow = var.invalidation_flow
|
||||
include_claims_in_id_token = var.include_claims_in_id_token
|
||||
|
||||
property_mappings = var.property_mappings
|
||||
}
|
||||
|
||||
resource "random_id" "client_id" {
|
||||
count = var.client_id == null ? 1 : 0
|
||||
byte_length = 20
|
||||
}
|
||||
|
||||
resource "authentik_application" "app" {
|
||||
name = var.app_name
|
||||
slug = var.app_slug
|
||||
protocol_provider = authentik_provider_oauth2.provider.id
|
||||
group = var.app_group
|
||||
policy_engine_mode = var.policy_engine_mode
|
||||
meta_description = var.meta_description
|
||||
meta_launch_url = var.meta_launch_url
|
||||
meta_icon = var.meta_icon
|
||||
}
|
||||
|
||||
resource "authentik_policy_binding" "app_access" {
|
||||
for_each = var.access_policies
|
||||
|
||||
target = authentik_application.app.id
|
||||
policy = each.value.policy_id
|
||||
order = each.value.order
|
||||
|
||||
enabled = lookup(each.value, "enabled", true)
|
||||
timeout = lookup(each.value, "timeout", 30)
|
||||
negate = lookup(each.value, "negate", false)
|
||||
failure_result = lookup(each.value, "failure_result", true)
|
||||
}
|
30
terraform/authentik/modules/oauth-provider/outputs.tf
Normal file
30
terraform/authentik/modules/oauth-provider/outputs.tf
Normal file
@@ -0,0 +1,30 @@
|
||||
output "provider_id" {
|
||||
description = "ID of the OAuth2 provider"
|
||||
value = authentik_provider_oauth2.provider.id
|
||||
}
|
||||
|
||||
output "application_id" {
|
||||
description = "ID of the application"
|
||||
value = authentik_application.app.id
|
||||
}
|
||||
|
||||
output "application_uuid" {
|
||||
description = "UUID of the application"
|
||||
value = authentik_application.app.id
|
||||
}
|
||||
|
||||
output "client_id" {
|
||||
description = "OAuth2 Client ID"
|
||||
value = authentik_provider_oauth2.provider.client_id
|
||||
}
|
||||
|
||||
output "client_secret" {
|
||||
description = "OAuth2 Client Secret"
|
||||
value = authentik_provider_oauth2.provider.client_secret
|
||||
sensitive = true
|
||||
}
|
||||
|
||||
output "application_slug" {
|
||||
description = "Application slug"
|
||||
value = authentik_application.app.slug
|
||||
}
|
138
terraform/authentik/modules/oauth-provider/variables.tf
Normal file
138
terraform/authentik/modules/oauth-provider/variables.tf
Normal file
@@ -0,0 +1,138 @@
|
||||
variable "name" {
|
||||
description = "Name of the OAuth2 provider"
|
||||
type = string
|
||||
}
|
||||
|
||||
variable "app_name" {
|
||||
description = "Name of the application"
|
||||
type = string
|
||||
}
|
||||
|
||||
variable "app_slug" {
|
||||
description = "Slug of the application"
|
||||
type = string
|
||||
}
|
||||
|
||||
variable "app_group" {
|
||||
description = "Group for the application"
|
||||
type = string
|
||||
default = ""
|
||||
}
|
||||
|
||||
variable "client_id" {
|
||||
description = "OAuth2 Client ID"
|
||||
type = string
|
||||
default = null
|
||||
}
|
||||
|
||||
variable "client_secret" {
|
||||
description = "OAuth2 Client Secret"
|
||||
type = string
|
||||
default = null
|
||||
sensitive = true
|
||||
}
|
||||
|
||||
variable "client_type" {
|
||||
description = "OAuth2 Client type (confidential or public)"
|
||||
type = string
|
||||
default = "confidential"
|
||||
|
||||
validation {
|
||||
condition = contains(["confidential", "public"], var.client_type)
|
||||
error_message = "Client type must be either 'confidential' or 'public'."
|
||||
}
|
||||
}
|
||||
|
||||
variable "authorization_flow" {
|
||||
description = "Authorization flow UUID"
|
||||
type = string
|
||||
}
|
||||
|
||||
variable "invalidation_flow" {
|
||||
description = "Invalidation flow UUID"
|
||||
type = string
|
||||
}
|
||||
|
||||
variable "redirect_uris" {
|
||||
description = "List of allowed redirect URIs"
|
||||
type = list(string)
|
||||
default = []
|
||||
}
|
||||
|
||||
variable "access_code_validity" {
|
||||
description = "Access code validity duration"
|
||||
type = string
|
||||
default = "minutes=1"
|
||||
}
|
||||
|
||||
variable "access_token_validity" {
|
||||
description = "Access token validity duration"
|
||||
type = string
|
||||
default = "minutes=5"
|
||||
}
|
||||
|
||||
variable "refresh_token_validity" {
|
||||
description = "Refresh token validity duration"
|
||||
type = string
|
||||
default = "days=30"
|
||||
}
|
||||
|
||||
variable "include_claims_in_id_token" {
|
||||
description = "Include claims in ID token"
|
||||
type = bool
|
||||
default = true
|
||||
}
|
||||
|
||||
variable "signing_key" {
|
||||
description = "Signing key UUID"
|
||||
type = string
|
||||
default = null
|
||||
}
|
||||
|
||||
variable "property_mappings" {
|
||||
description = "List of property mapping UUIDs"
|
||||
type = list(string)
|
||||
default = []
|
||||
}
|
||||
|
||||
variable "policy_engine_mode" {
|
||||
description = "Policy engine mode"
|
||||
type = string
|
||||
default = "all"
|
||||
|
||||
validation {
|
||||
condition = contains(["all", "any"], var.policy_engine_mode)
|
||||
error_message = "Policy engine mode must be either 'all' or 'any'."
|
||||
}
|
||||
}
|
||||
|
||||
variable "meta_description" {
|
||||
description = "Application meta description"
|
||||
type = string
|
||||
default = ""
|
||||
}
|
||||
|
||||
variable "meta_launch_url" {
|
||||
description = "Application launch URL"
|
||||
type = string
|
||||
default = ""
|
||||
}
|
||||
|
||||
variable "meta_icon" {
|
||||
description = "Application icon URL"
|
||||
type = string
|
||||
default = ""
|
||||
}
|
||||
|
||||
variable "access_policies" {
|
||||
description = "Access policies for the application"
|
||||
type = map(object({
|
||||
policy_id = string
|
||||
order = number
|
||||
enabled = optional(bool, true)
|
||||
timeout = optional(number, 30)
|
||||
negate = optional(bool, false)
|
||||
failure_result = optional(bool, true)
|
||||
}))
|
||||
default = {}
|
||||
}
|
49
terraform/authentik/modules/proxy-provider/main.tf
Normal file
49
terraform/authentik/modules/proxy-provider/main.tf
Normal file
@@ -0,0 +1,49 @@
|
||||
terraform {
|
||||
required_providers {
|
||||
authentik = {
|
||||
source = "goauthentik/authentik"
|
||||
version = ">= 2023.10.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
resource "authentik_provider_proxy" "provider" {
|
||||
name = var.name
|
||||
external_host = var.external_host
|
||||
internal_host = var.internal_host
|
||||
internal_host_ssl_validation = var.internal_host_ssl_validation
|
||||
authorization_flow = var.authorization_flow
|
||||
invalidation_flow = var.invalidation_flow
|
||||
mode = var.mode
|
||||
cookie_domain = var.cookie_domain
|
||||
skip_path_regex = var.skip_path_regex
|
||||
intercept_header_auth = var.intercept_header_auth
|
||||
basic_auth_enabled = var.basic_auth_enabled
|
||||
basic_auth_password_attribute = var.basic_auth_password_attribute
|
||||
|
||||
property_mappings = var.property_mappings
|
||||
}
|
||||
|
||||
resource "authentik_application" "app" {
|
||||
name = var.app_name
|
||||
slug = var.app_slug
|
||||
protocol_provider = authentik_provider_proxy.provider.id
|
||||
group = var.app_group
|
||||
policy_engine_mode = var.policy_engine_mode
|
||||
meta_description = var.meta_description
|
||||
meta_launch_url = var.meta_launch_url
|
||||
meta_icon = var.meta_icon
|
||||
}
|
||||
|
||||
resource "authentik_policy_binding" "app_access" {
|
||||
for_each = var.access_policies
|
||||
|
||||
target = authentik_application.app.id
|
||||
policy = each.value.policy_id
|
||||
order = each.value.order
|
||||
|
||||
enabled = lookup(each.value, "enabled", true)
|
||||
timeout = lookup(each.value, "timeout", 30)
|
||||
negate = lookup(each.value, "negate", false)
|
||||
failure_result = lookup(each.value, "failure_result", true)
|
||||
}
|
35
terraform/authentik/modules/proxy-provider/outputs.tf
Normal file
35
terraform/authentik/modules/proxy-provider/outputs.tf
Normal file
@@ -0,0 +1,35 @@
|
||||
output "provider_id" {
|
||||
description = "ID of the Proxy provider"
|
||||
value = authentik_provider_proxy.provider.id
|
||||
}
|
||||
|
||||
output "application_id" {
|
||||
description = "ID of the application"
|
||||
value = authentik_application.app.id
|
||||
}
|
||||
|
||||
output "application_uuid" {
|
||||
description = "UUID of the application"
|
||||
value = authentik_application.app.id
|
||||
}
|
||||
|
||||
output "application_slug" {
|
||||
description = "Application slug"
|
||||
value = authentik_application.app.slug
|
||||
}
|
||||
|
||||
output "launch_url" {
|
||||
description = "Application launch URL"
|
||||
value = authentik_application.app.meta_launch_url
|
||||
}
|
||||
|
||||
output "external_host" {
|
||||
description = "External host URL"
|
||||
value = authentik_provider_proxy.provider.external_host
|
||||
}
|
||||
|
||||
output "internal_host" {
|
||||
description = "Internal host URL"
|
||||
value = authentik_provider_proxy.provider.internal_host
|
||||
}
|
||||
|
145
terraform/authentik/modules/proxy-provider/variables.tf
Normal file
145
terraform/authentik/modules/proxy-provider/variables.tf
Normal file
@@ -0,0 +1,145 @@
|
||||
variable "name" {
|
||||
description = "Name of the Proxy provider"
|
||||
type = string
|
||||
}
|
||||
|
||||
variable "app_name" {
|
||||
description = "Name of the application"
|
||||
type = string
|
||||
}
|
||||
|
||||
variable "app_slug" {
|
||||
description = "Slug of the application"
|
||||
type = string
|
||||
}
|
||||
|
||||
variable "app_group" {
|
||||
description = "Group for the application"
|
||||
type = string
|
||||
default = ""
|
||||
}
|
||||
|
||||
variable "external_host" {
|
||||
description = "External hostname for the proxy"
|
||||
type = string
|
||||
}
|
||||
|
||||
variable "internal_host" {
|
||||
description = "Internal hostname for the proxy"
|
||||
type = string
|
||||
default = ""
|
||||
}
|
||||
|
||||
variable "internal_host_ssl_validation" {
|
||||
description = "Enable SSL validation for internal host"
|
||||
type = bool
|
||||
default = true
|
||||
}
|
||||
|
||||
variable "authorization_flow" {
|
||||
description = "Authorization flow UUID"
|
||||
type = string
|
||||
}
|
||||
|
||||
variable "invalidation_flow" {
|
||||
description = "Invalidation flow UUID"
|
||||
type = string
|
||||
}
|
||||
|
||||
variable "mode" {
|
||||
description = "Proxy mode (proxy, forward_single, forward_domain)"
|
||||
type = string
|
||||
default = "proxy"
|
||||
|
||||
validation {
|
||||
condition = contains(["proxy", "forward_single", "forward_domain"], var.mode)
|
||||
error_message = "Mode must be one of: proxy, forward_single, forward_domain."
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
variable "cookie_domain" {
|
||||
description = "Cookie domain for the proxy"
|
||||
type = string
|
||||
default = ""
|
||||
}
|
||||
|
||||
|
||||
variable "skip_path_regex" {
|
||||
description = "Regular expression for paths to skip authentication"
|
||||
type = string
|
||||
default = ""
|
||||
}
|
||||
|
||||
variable "intercept_header_auth" {
|
||||
description = "Intercept header authentication"
|
||||
type = bool
|
||||
default = false
|
||||
}
|
||||
|
||||
variable "basic_auth_enabled" {
|
||||
description = "Enable basic authentication"
|
||||
type = bool
|
||||
default = false
|
||||
}
|
||||
|
||||
variable "basic_auth_password_attribute" {
|
||||
description = "Attribute for basic auth password"
|
||||
type = string
|
||||
default = ""
|
||||
}
|
||||
|
||||
variable "basic_auth_user_attribute" {
|
||||
description = "Attribute for basic auth username"
|
||||
type = string
|
||||
default = ""
|
||||
}
|
||||
|
||||
variable "property_mappings" {
|
||||
description = "List of property mapping UUIDs"
|
||||
type = list(string)
|
||||
default = []
|
||||
}
|
||||
|
||||
variable "policy_engine_mode" {
|
||||
description = "Policy engine mode"
|
||||
type = string
|
||||
default = "all"
|
||||
|
||||
validation {
|
||||
condition = contains(["all", "any"], var.policy_engine_mode)
|
||||
error_message = "Policy engine mode must be either 'all' or 'any'."
|
||||
}
|
||||
}
|
||||
|
||||
variable "meta_description" {
|
||||
description = "Application meta description"
|
||||
type = string
|
||||
default = ""
|
||||
}
|
||||
|
||||
variable "meta_launch_url" {
|
||||
description = "Application launch URL"
|
||||
type = string
|
||||
default = ""
|
||||
}
|
||||
|
||||
variable "meta_icon" {
|
||||
description = "Application icon URL"
|
||||
type = string
|
||||
default = ""
|
||||
}
|
||||
|
||||
|
||||
variable "access_policies" {
|
||||
description = "Access policies for the application"
|
||||
type = map(object({
|
||||
policy_id = string
|
||||
order = number
|
||||
enabled = optional(bool, true)
|
||||
timeout = optional(number, 30)
|
||||
negate = optional(bool, false)
|
||||
failure_result = optional(bool, true)
|
||||
}))
|
||||
default = {}
|
||||
}
|
70
terraform/authentik/outputs.tf
Normal file
70
terraform/authentik/outputs.tf
Normal file
@@ -0,0 +1,70 @@
|
||||
output "oauth_applications" {
|
||||
description = "OAuth2/OpenID applications details"
|
||||
value = {
|
||||
for k, v in module.oauth_applications : k => {
|
||||
application_id = v.application_id
|
||||
application_uuid = v.application_uuid
|
||||
client_id = v.client_id
|
||||
client_secret = v.client_secret
|
||||
slug = v.application_slug
|
||||
}
|
||||
}
|
||||
sensitive = true
|
||||
}
|
||||
|
||||
output "proxy_applications" {
|
||||
description = "Proxy applications details"
|
||||
value = {
|
||||
for k, v in module.proxy_applications : k => {
|
||||
application_id = v.application_id
|
||||
application_uuid = v.application_uuid
|
||||
external_host = v.external_host
|
||||
internal_host = v.internal_host
|
||||
slug = v.application_slug
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
output "outposts" {
|
||||
description = "Outposts details"
|
||||
value = {
|
||||
for k, v in authentik_outpost.outposts : k => {
|
||||
id = v.id
|
||||
name = v.name
|
||||
type = v.type
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
output "groups" {
|
||||
description = "Groups details"
|
||||
value = {
|
||||
for k, v in authentik_group.groups : k => {
|
||||
id = v.id
|
||||
name = v.name
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
output "flows" {
|
||||
description = "Custom flows details"
|
||||
value = {
|
||||
for k, v in authentik_flow.flows : k => {
|
||||
id = v.id
|
||||
slug = v.slug
|
||||
name = v.name
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
output "certificates" {
|
||||
description = "Certificates details"
|
||||
value = {
|
||||
for k, v in authentik_certificate_key_pair.certificates : k => {
|
||||
id = v.id
|
||||
name = v.name
|
||||
fingerprint_sha256 = v.fingerprint_sha256
|
||||
fingerprint_sha1 = v.fingerprint_sha1
|
||||
}
|
||||
}
|
||||
}
|
13
terraform/authentik/providers.tf
Normal file
13
terraform/authentik/providers.tf
Normal file
@@ -0,0 +1,13 @@
|
||||
terraform {
|
||||
required_providers {
|
||||
authentik = {
|
||||
source = "goauthentik/authentik"
|
||||
version = "2025.8.1"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
provider "authentik" {
|
||||
url = "https://idm.hexor.cy"
|
||||
token = "qXcuoCg77JaRgqnU6rqIIBa8MBJ4UNyLPTL89dZI8zeC2jfaWqQ7k56BJs8F"
|
||||
}
|
137
terraform/authentik/variables.tf
Normal file
137
terraform/authentik/variables.tf
Normal file
@@ -0,0 +1,137 @@
|
||||
variable "oauth_applications" {
|
||||
description = "Map of OAuth2/OpenID applications"
|
||||
type = map(object({
|
||||
name = string
|
||||
slug = string
|
||||
group = optional(string, "")
|
||||
policy_engine_mode = optional(string, "all")
|
||||
meta_description = optional(string, "")
|
||||
meta_launch_url = optional(string, "")
|
||||
meta_icon = optional(string, "")
|
||||
redirect_uris = list(string)
|
||||
client_type = optional(string, "confidential")
|
||||
client_id = optional(string, null)
|
||||
include_claims_in_id_token = optional(bool, true)
|
||||
access_code_validity = optional(string, "minutes=1")
|
||||
access_token_validity = optional(string, "minutes=5")
|
||||
refresh_token_validity = optional(string, "days=30")
|
||||
property_mappings = optional(list(string), [])
|
||||
authorization_flow = optional(string, null)
|
||||
signing_key = optional(string, null)
|
||||
outpost = optional(string, null)
|
||||
}))
|
||||
default = {}
|
||||
}
|
||||
|
||||
variable "proxy_applications" {
|
||||
description = "Map of Proxy applications"
|
||||
type = map(object({
|
||||
name = string
|
||||
slug = string
|
||||
group = optional(string, "")
|
||||
policy_engine_mode = optional(string, "all")
|
||||
meta_description = optional(string, "")
|
||||
meta_launch_url = optional(string, "")
|
||||
meta_icon = optional(string, "")
|
||||
external_host = string
|
||||
internal_host = optional(string, "")
|
||||
internal_host_ssl_validation = optional(bool, true)
|
||||
mode = optional(string, "proxy")
|
||||
intercept_header_auth = optional(bool, false)
|
||||
basic_auth_enabled = optional(bool, false)
|
||||
basic_auth_username_attribute = optional(string, "")
|
||||
basic_auth_password_attribute = optional(string, "")
|
||||
cookie_domain = optional(string, "")
|
||||
authorization_flow = optional(string, null)
|
||||
skip_path_regex = optional(string, "")
|
||||
outpost = optional(string, null)
|
||||
}))
|
||||
default = {}
|
||||
}
|
||||
|
||||
variable "outposts" {
|
||||
description = "Map of Outposts (only proxy type supported)"
|
||||
type = map(object({
|
||||
name = string
|
||||
config = optional(map(any), {})
|
||||
}))
|
||||
default = {}
|
||||
}
|
||||
|
||||
variable "flows" {
|
||||
description = "Map of authentication flows"
|
||||
type = map(object({
|
||||
name = string
|
||||
title = string
|
||||
slug = string
|
||||
designation = string
|
||||
policy_engine_mode = optional(string, "all")
|
||||
compatibility_mode = optional(bool, false)
|
||||
layout = optional(string, "stacked")
|
||||
denied_action = optional(string, "message_continue")
|
||||
}))
|
||||
default = {}
|
||||
}
|
||||
|
||||
variable "groups" {
|
||||
description = "Map of user groups"
|
||||
type = map(object({
|
||||
name = string
|
||||
is_superuser = optional(bool, false)
|
||||
parent = optional(string, null)
|
||||
attributes = optional(map(any), {})
|
||||
}))
|
||||
default = {}
|
||||
}
|
||||
|
||||
variable "certificates" {
|
||||
description = "Map of certificates for HTTPS"
|
||||
type = map(object({
|
||||
name = string
|
||||
certificate_data = string
|
||||
key_data = string
|
||||
managed = optional(string, null)
|
||||
}))
|
||||
default = {}
|
||||
}
|
||||
|
||||
variable "property_mappings" {
|
||||
description = "Custom property mappings for SAML/OAuth"
|
||||
type = map(object({
|
||||
name = string
|
||||
expression = string
|
||||
saml_name = optional(string, null)
|
||||
oidc_scope = optional(string, null)
|
||||
}))
|
||||
default = {}
|
||||
}
|
||||
|
||||
|
||||
variable "default_authorization_flow" {
|
||||
description = "Default authorization flow slug"
|
||||
type = string
|
||||
default = "default-provider-authorization-implicit-consent"
|
||||
}
|
||||
|
||||
variable "default_authentication_flow" {
|
||||
description = "Default authentication flow slug"
|
||||
type = string
|
||||
default = "default-authentication-flow"
|
||||
}
|
||||
|
||||
variable "default_invalidation_flow" {
|
||||
description = "Default invalidation flow slug"
|
||||
type = string
|
||||
default = "default-provider-invalidation-flow"
|
||||
}
|
||||
|
||||
variable "tags" {
|
||||
description = "Tags to apply to all resources"
|
||||
type = map(string)
|
||||
default = {}
|
||||
}
|
||||
|
||||
variable "authentik_url" {
|
||||
description = "Authentik URL"
|
||||
type = string
|
||||
}
|
Reference in New Issue
Block a user