mirror of
https://github.com/ghndrx/authentik-terraform.git
synced 2026-02-10 06:44:58 +00:00
feat: Add custom MFA authentication flow with configurable enforcement
- Add authentication-flow.tf with complete MFA auth flow: - Identification -> Password -> MFA validation -> Session stages - Brute-force reputation policy binding - Evaluates policies on plan for user context - Add configuration variables: - enable_mfa_flow: Toggle custom MFA flow (default: false) - mfa_enforcement: skip/configure/deny (default: configure) - Fix existing issues: - rbac-groups.tf: parent -> parents (list) - source-google.tf: Use variables instead of deprecated sops - Google source now conditional (created only if credentials provided) - Update README: - Document MFA enforcement levels - Add authentication-flow.tf to file structure - Explain Option 1 (Terraform) vs Option 2 (manual UI) for MFA setup Security: Custom flow includes brute-force protection policy bound at flow level, not just stage level.
This commit is contained in:
24
README.md
24
README.md
@@ -78,6 +78,7 @@ terraform apply
|
|||||||
├── .github/workflows/deploy.yml # CI/CD pipeline
|
├── .github/workflows/deploy.yml # CI/CD pipeline
|
||||||
├── main.tf # Authentik provider & brand config
|
├── main.tf # Authentik provider & brand config
|
||||||
├── variables.tf # All configurable variables
|
├── variables.tf # All configurable variables
|
||||||
|
├── authentication-flow.tf # Custom MFA authentication flow
|
||||||
├── security-policies.tf # Password, MFA, brute-force policies
|
├── security-policies.tf # Password, MFA, brute-force policies
|
||||||
├── rbac-groups.tf # RBAC groups and access policies
|
├── rbac-groups.tf # RBAC groups and access policies
|
||||||
├── app-*.tf # Application configurations
|
├── app-*.tf # Application configurations
|
||||||
@@ -170,11 +171,34 @@ This configuration includes enterprise-grade security controls:
|
|||||||
- Execution logging for audit trail
|
- Execution logging for audit trail
|
||||||
|
|
||||||
### To Enable MFA Enforcement:
|
### To Enable MFA Enforcement:
|
||||||
|
|
||||||
|
**Option 1: Use the Custom MFA Authentication Flow (Recommended)**
|
||||||
|
|
||||||
|
Set in `terraform.tfvars`:
|
||||||
|
```hcl
|
||||||
|
enable_mfa_flow = true
|
||||||
|
mfa_enforcement = "configure" # or "deny" for strict enforcement
|
||||||
|
```
|
||||||
|
|
||||||
|
This creates a complete authentication flow with:
|
||||||
|
- User identification → Password → MFA validation → Session creation
|
||||||
|
- Brute-force protection policy binding
|
||||||
|
- Configurable MFA enforcement level
|
||||||
|
|
||||||
|
**Option 2: Manual Configuration**
|
||||||
1. Deploy these policies with `terraform apply`
|
1. Deploy these policies with `terraform apply`
|
||||||
2. In Authentik UI: Edit your authentication flow
|
2. In Authentik UI: Edit your authentication flow
|
||||||
3. Add the `mfa-validation` stage after the password stage
|
3. Add the `mfa-validation` stage after the password stage
|
||||||
4. Set `not_configured_action` to `deny` for strict enforcement
|
4. Set `not_configured_action` to `deny` for strict enforcement
|
||||||
|
|
||||||
|
### MFA Enforcement Levels
|
||||||
|
|
||||||
|
| Level | Behavior |
|
||||||
|
|-------|----------|
|
||||||
|
| `skip` | MFA optional, no prompt if not configured |
|
||||||
|
| `configure` | Prompts users to set up MFA on login (recommended for rollout) |
|
||||||
|
| `deny` | Blocks login if MFA not configured (use after users have set up MFA) |
|
||||||
|
|
||||||
## RBAC Groups (rbac-groups.tf)
|
## RBAC Groups (rbac-groups.tf)
|
||||||
|
|
||||||
Role-based access control with three predefined groups:
|
Role-based access control with three predefined groups:
|
||||||
|
|||||||
109
authentication-flow.tf
Normal file
109
authentication-flow.tf
Normal file
@@ -0,0 +1,109 @@
|
|||||||
|
# =============================================================================
|
||||||
|
# Custom Authentication Flow with MFA
|
||||||
|
# Creates a secure authentication flow that requires MFA
|
||||||
|
# =============================================================================
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
# Custom Authentication Flow - With MFA Enforcement
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
resource "authentik_flow" "mfa_authentication" {
|
||||||
|
name = "mfa-authentication-flow"
|
||||||
|
title = "Welcome! Please sign in."
|
||||||
|
slug = "mfa-authentication-flow"
|
||||||
|
designation = "authentication"
|
||||||
|
|
||||||
|
# Background and styling
|
||||||
|
background = "/static/dist/assets/images/flow_background.jpg"
|
||||||
|
|
||||||
|
# Policy behavior
|
||||||
|
policy_engine_mode = "all"
|
||||||
|
|
||||||
|
# Compatibility mode for older clients
|
||||||
|
compatibility_mode = true
|
||||||
|
}
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
# Stage: User Identification
|
||||||
|
# First stage - user enters username/email
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
data "authentik_stage" "identification" {
|
||||||
|
name = "default-authentication-identification"
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "authentik_flow_stage_binding" "identification" {
|
||||||
|
target = authentik_flow.mfa_authentication.uuid
|
||||||
|
stage = data.authentik_stage.identification.id
|
||||||
|
order = 10
|
||||||
|
}
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
# Stage: Password Authentication
|
||||||
|
# Second stage - user enters password
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
data "authentik_stage" "password" {
|
||||||
|
name = "default-authentication-password"
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "authentik_flow_stage_binding" "password" {
|
||||||
|
target = authentik_flow.mfa_authentication.uuid
|
||||||
|
stage = data.authentik_stage.password.id
|
||||||
|
order = 20
|
||||||
|
}
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
# Stage: MFA Validation
|
||||||
|
# Third stage - require MFA (TOTP, WebAuthn, or recovery code)
|
||||||
|
# Uses the mfa_validation stage from security-policies.tf
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
resource "authentik_flow_stage_binding" "mfa" {
|
||||||
|
target = authentik_flow.mfa_authentication.uuid
|
||||||
|
stage = authentik_stage_authenticator_validate.mfa_validation.id
|
||||||
|
order = 30
|
||||||
|
|
||||||
|
# Optional: Evaluate on plan to check user context
|
||||||
|
evaluate_on_plan = true
|
||||||
|
|
||||||
|
# Re-evaluate policies each time
|
||||||
|
re_evaluate_policies = true
|
||||||
|
}
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
# Stage: User Login (Session Creation)
|
||||||
|
# Final stage - create user session after successful auth
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
data "authentik_stage" "user_login" {
|
||||||
|
name = "default-authentication-login"
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "authentik_flow_stage_binding" "login" {
|
||||||
|
target = authentik_flow.mfa_authentication.uuid
|
||||||
|
stage = data.authentik_stage.user_login.id
|
||||||
|
order = 40
|
||||||
|
}
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
# Policy Binding: Reputation Check (Anti-Brute Force)
|
||||||
|
# Bound to the flow, checks reputation before allowing auth
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
resource "authentik_policy_binding" "reputation_check" {
|
||||||
|
target = authentik_flow.mfa_authentication.uuid
|
||||||
|
policy = authentik_policy_reputation.brute_force_protection.id
|
||||||
|
order = 0
|
||||||
|
|
||||||
|
# Fail closed - if policy errors, deny access
|
||||||
|
negate = false
|
||||||
|
timeout = 30
|
||||||
|
}
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
# Outputs
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
output "mfa_authentication_flow_id" {
|
||||||
|
description = "ID of the MFA authentication flow"
|
||||||
|
value = authentik_flow.mfa_authentication.uuid
|
||||||
|
}
|
||||||
|
|
||||||
|
output "mfa_authentication_flow_slug" {
|
||||||
|
description = "Slug of the MFA authentication flow - use in brand configuration"
|
||||||
|
value = authentik_flow.mfa_authentication.slug
|
||||||
|
}
|
||||||
3
main.tf
3
main.tf
@@ -58,7 +58,8 @@ resource "authentik_brand" "main" {
|
|||||||
branding_logo = "/static/dist/assets/icons/icon_left_brand.svg"
|
branding_logo = "/static/dist/assets/icons/icon_left_brand.svg"
|
||||||
branding_favicon = "/static/dist/assets/icons/icon.png"
|
branding_favicon = "/static/dist/assets/icons/icon.png"
|
||||||
|
|
||||||
flow_authentication = data.authentik_flow.default_authentication.id
|
# Use MFA auth flow if enabled, otherwise default
|
||||||
|
flow_authentication = var.enable_mfa_flow ? authentik_flow.mfa_authentication.uuid : data.authentik_flow.default_authentication.id
|
||||||
flow_invalidation = data.authentik_flow.default_invalidation.id
|
flow_invalidation = data.authentik_flow.default_invalidation.id
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -10,19 +10,19 @@
|
|||||||
# Media group - access to Sonarr, Radarr, Prowlarr, etc.
|
# Media group - access to Sonarr, Radarr, Prowlarr, etc.
|
||||||
resource "authentik_group" "media" {
|
resource "authentik_group" "media" {
|
||||||
name = "Media"
|
name = "Media"
|
||||||
parent = authentik_group.users.id
|
parents = [authentik_group.users.id]
|
||||||
}
|
}
|
||||||
|
|
||||||
# Infrastructure group - access to monitoring, CI/CD tools
|
# Infrastructure group - access to monitoring, CI/CD tools
|
||||||
resource "authentik_group" "infrastructure" {
|
resource "authentik_group" "infrastructure" {
|
||||||
name = "Infrastructure"
|
name = "Infrastructure"
|
||||||
parent = authentik_group.users.id
|
parents = [authentik_group.users.id]
|
||||||
}
|
}
|
||||||
|
|
||||||
# Home Automation group - Home Assistant access
|
# Home Automation group - Home Assistant access
|
||||||
resource "authentik_group" "home_automation" {
|
resource "authentik_group" "home_automation" {
|
||||||
name = "Home Automation"
|
name = "Home Automation"
|
||||||
parent = authentik_group.users.id
|
parents = [authentik_group.users.id]
|
||||||
}
|
}
|
||||||
|
|
||||||
# -----------------------------------------------------------------------------
|
# -----------------------------------------------------------------------------
|
||||||
|
|||||||
@@ -99,7 +99,7 @@ resource "authentik_stage_authenticator_validate" "mfa_validation" {
|
|||||||
# - skip: Don't require MFA if not configured
|
# - skip: Don't require MFA if not configured
|
||||||
# - deny: Block login if MFA not configured (after enabling, users need MFA)
|
# - deny: Block login if MFA not configured (after enabling, users need MFA)
|
||||||
# - configure: Force users to set up MFA if not configured
|
# - configure: Force users to set up MFA if not configured
|
||||||
not_configured_action = "configure"
|
not_configured_action = var.mfa_enforcement
|
||||||
|
|
||||||
# Supported authenticator types
|
# Supported authenticator types
|
||||||
device_classes = [
|
device_classes = [
|
||||||
|
|||||||
@@ -3,16 +3,18 @@
|
|||||||
# Allow users to sign in with their Google Workspace accounts
|
# Allow users to sign in with their Google Workspace accounts
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
|
|
||||||
# Google OAuth Source
|
# Google OAuth Source - Only created if credentials are provided
|
||||||
resource "authentik_source_oauth" "google" {
|
resource "authentik_source_oauth" "google" {
|
||||||
|
count = var.google_client_id != "" ? 1 : 0
|
||||||
|
|
||||||
name = "Google Workspace"
|
name = "Google Workspace"
|
||||||
slug = "google"
|
slug = "google"
|
||||||
authentication_flow = data.authentik_flow.default_authentication.id
|
authentication_flow = data.authentik_flow.default_authentication.id
|
||||||
enrollment_flow = data.authentik_flow.default_enrollment.id
|
enrollment_flow = data.authentik_flow.default_enrollment.id
|
||||||
|
|
||||||
provider_type = "google"
|
provider_type = "google"
|
||||||
consumer_key = data.sops_file.secrets.data["google_client_id"]
|
consumer_key = var.google_client_id
|
||||||
consumer_secret = data.sops_file.secrets.data["google_client_secret"]
|
consumer_secret = var.google_client_secret
|
||||||
|
|
||||||
# PKCE method - S256 is recommended
|
# PKCE method - S256 is recommended
|
||||||
pkce = "S256"
|
pkce = "S256"
|
||||||
|
|||||||
@@ -22,3 +22,10 @@ portainer_url = "https://portainer.example.com"
|
|||||||
|
|
||||||
# LDAP Configuration
|
# LDAP Configuration
|
||||||
ldap_base_dn = "dc=ldap,dc=example,dc=com"
|
ldap_base_dn = "dc=ldap,dc=example,dc=com"
|
||||||
|
|
||||||
|
# Security Configuration
|
||||||
|
enable_mfa_flow = false # Set to true to enable MFA authentication flow
|
||||||
|
mfa_enforcement = "configure" # Options: skip, configure, deny
|
||||||
|
# - skip: MFA optional, no prompt if not configured
|
||||||
|
# - configure: Prompt users to set up MFA on login
|
||||||
|
# - deny: Block login if MFA not configured (use after users have set up MFA)
|
||||||
|
|||||||
17
variables.tf
17
variables.tf
@@ -94,3 +94,20 @@ variable "ldap_base_dn" {
|
|||||||
default = "dc=ldap,dc=example,dc=com"
|
default = "dc=ldap,dc=example,dc=com"
|
||||||
description = "LDAP base DN"
|
description = "LDAP base DN"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Security Configuration
|
||||||
|
variable "enable_mfa_flow" {
|
||||||
|
type = bool
|
||||||
|
default = false
|
||||||
|
description = "Use custom MFA authentication flow instead of default"
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "mfa_enforcement" {
|
||||||
|
type = string
|
||||||
|
default = "configure"
|
||||||
|
description = "MFA enforcement mode: 'skip' (optional), 'configure' (prompt to set up), 'deny' (required)"
|
||||||
|
validation {
|
||||||
|
condition = contains(["skip", "configure", "deny"], var.mfa_enforcement)
|
||||||
|
error_message = "MFA enforcement must be one of: skip, configure, deny"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user