mirror of
https://github.com/ghndrx/authentik-terraform.git
synced 2026-02-09 22:34:56 +00:00
feat: Authentik Terraform configuration for homelab SSO
Infrastructure as Code for Authentik identity provider managing: OAuth2/OIDC Applications: - Grafana, Home Assistant, Immich - Uptime Kuma (proxy auth) - Sonarr, Radarr, Prowlarr (*arr stack proxy auth) - ArgoCD Identity Sources: - Google Workspace federation LDAP: - TrueNAS LDAP provider and outpost CI/CD: - GitHub Actions workflow for plan/apply - Secrets managed via GitHub Actions secrets Provider: beryju/authentik v2025.2
This commit is contained in:
105
.github/workflows/deploy.yml
vendored
Normal file
105
.github/workflows/deploy.yml
vendored
Normal file
@@ -0,0 +1,105 @@
|
||||
name: Deploy Authentik Configuration
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
pull_request:
|
||||
branches: [main]
|
||||
workflow_dispatch:
|
||||
|
||||
env:
|
||||
TF_VERSION: "1.7.0"
|
||||
|
||||
jobs:
|
||||
plan:
|
||||
name: Terraform Plan
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup Terraform
|
||||
uses: hashicorp/setup-terraform@v3
|
||||
with:
|
||||
terraform_version: ${{ env.TF_VERSION }}
|
||||
|
||||
- name: Create secrets.auto.tfvars
|
||||
run: |
|
||||
cat > secrets.auto.tfvars << EOF
|
||||
authentik_url = "${{ secrets.AUTHENTIK_URL }}"
|
||||
authentik_token = "${{ secrets.AUTHENTIK_TOKEN }}"
|
||||
|
||||
# Google OAuth (optional)
|
||||
google_client_id = "${{ secrets.GOOGLE_CLIENT_ID }}"
|
||||
google_client_secret = "${{ secrets.GOOGLE_CLIENT_SECRET }}"
|
||||
|
||||
# Application URLs
|
||||
argocd_url = "${{ secrets.ARGOCD_URL }}"
|
||||
grafana_url = "${{ secrets.GRAFANA_URL }}"
|
||||
home_assistant_url = "${{ secrets.HOME_ASSISTANT_URL }}"
|
||||
immich_url = "${{ secrets.IMMICH_URL }}"
|
||||
uptime_kuma_url = "${{ secrets.UPTIME_KUMA_URL }}"
|
||||
sonarr_url = "${{ secrets.SONARR_URL }}"
|
||||
radarr_url = "${{ secrets.RADARR_URL }}"
|
||||
prowlarr_url = "${{ secrets.PROWLARR_URL }}"
|
||||
EOF
|
||||
|
||||
- name: Terraform Init
|
||||
run: terraform init
|
||||
|
||||
- name: Terraform Validate
|
||||
run: terraform validate
|
||||
|
||||
- name: Terraform Plan
|
||||
run: terraform plan -out=tfplan
|
||||
|
||||
- name: Upload Plan
|
||||
uses: actions/upload-artifact@v4
|
||||
if: github.event_name == 'pull_request'
|
||||
with:
|
||||
name: tfplan
|
||||
path: tfplan
|
||||
|
||||
apply:
|
||||
name: Terraform Apply
|
||||
runs-on: ubuntu-latest
|
||||
needs: plan
|
||||
if: github.ref == 'refs/heads/main' && github.event_name == 'push'
|
||||
environment: production
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup Terraform
|
||||
uses: hashicorp/setup-terraform@v3
|
||||
with:
|
||||
terraform_version: ${{ env.TF_VERSION }}
|
||||
|
||||
- name: Create secrets.auto.tfvars
|
||||
run: |
|
||||
cat > secrets.auto.tfvars << EOF
|
||||
authentik_url = "${{ secrets.AUTHENTIK_URL }}"
|
||||
authentik_token = "${{ secrets.AUTHENTIK_TOKEN }}"
|
||||
|
||||
# Google OAuth (optional)
|
||||
google_client_id = "${{ secrets.GOOGLE_CLIENT_ID }}"
|
||||
google_client_secret = "${{ secrets.GOOGLE_CLIENT_SECRET }}"
|
||||
|
||||
# Application URLs
|
||||
argocd_url = "${{ secrets.ARGOCD_URL }}"
|
||||
grafana_url = "${{ secrets.GRAFANA_URL }}"
|
||||
home_assistant_url = "${{ secrets.HOME_ASSISTANT_URL }}"
|
||||
immich_url = "${{ secrets.IMMICH_URL }}"
|
||||
uptime_kuma_url = "${{ secrets.UPTIME_KUMA_URL }}"
|
||||
sonarr_url = "${{ secrets.SONARR_URL }}"
|
||||
radarr_url = "${{ secrets.RADARR_URL }}"
|
||||
prowlarr_url = "${{ secrets.PROWLARR_URL }}"
|
||||
EOF
|
||||
|
||||
- name: Terraform Init
|
||||
run: terraform init
|
||||
|
||||
- name: Terraform Apply
|
||||
run: terraform apply -auto-approve
|
||||
30
.gitignore
vendored
Normal file
30
.gitignore
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
# Terraform
|
||||
.terraform/
|
||||
.terraform.lock.hcl
|
||||
*.tfstate
|
||||
*.tfstate.*
|
||||
*.tfplan
|
||||
crash.log
|
||||
override.tf
|
||||
override.tf.json
|
||||
*_override.tf
|
||||
*_override.tf.json
|
||||
|
||||
# Secrets - NEVER commit these
|
||||
*.tfvars
|
||||
!*.tfvars.example
|
||||
secrets.yaml
|
||||
secrets*.yaml
|
||||
*.pem
|
||||
*.key
|
||||
|
||||
# IDE
|
||||
.idea/
|
||||
.vscode/
|
||||
*.swp
|
||||
*.swo
|
||||
*~
|
||||
|
||||
# OS
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
162
README.md
Normal file
162
README.md
Normal file
@@ -0,0 +1,162 @@
|
||||
# Authentik Terraform Configuration
|
||||
|
||||
Infrastructure as Code for Authentik identity provider - manage applications, providers, and SSO via Terraform.
|
||||
|
||||
## Features
|
||||
|
||||
- **OAuth2/OIDC Applications**: ArgoCD, Grafana
|
||||
- **Proxy Authentication**: Home Assistant, Immich, Uptime Kuma, *arr stack
|
||||
- **LDAP Outpost**: For legacy application support
|
||||
- **Google OAuth Source**: Social login integration
|
||||
|
||||
## Quick Start
|
||||
|
||||
### 1. Fork/Clone This Repo
|
||||
|
||||
```bash
|
||||
git clone https://github.com/ghndrx/authentik-terraform.git
|
||||
cd authentik-terraform
|
||||
```
|
||||
|
||||
### 2. Configure GitHub Secrets
|
||||
|
||||
Go to **Settings > Secrets and variables > Actions** and add:
|
||||
|
||||
| Secret | Description | Example |
|
||||
|--------|-------------|---------|
|
||||
| `AUTHENTIK_URL` | Your Authentik server URL | `https://auth.example.com` |
|
||||
| `AUTHENTIK_TOKEN` | API token from Authentik | `ak-...` |
|
||||
| `GOOGLE_CLIENT_ID` | Google OAuth client ID | `xxx.apps.googleusercontent.com` |
|
||||
| `GOOGLE_CLIENT_SECRET` | Google OAuth secret | `GOCSPX-...` |
|
||||
| `ARGOCD_URL` | ArgoCD URL | `https://argocd.example.com` |
|
||||
| `GRAFANA_URL` | Grafana URL | `https://grafana.example.com` |
|
||||
| `HOME_ASSISTANT_URL` | Home Assistant URL | `https://home.example.com` |
|
||||
| `IMMICH_URL` | Immich URL | `https://photos.example.com` |
|
||||
| `UPTIME_KUMA_URL` | Uptime Kuma URL | `https://status.example.com` |
|
||||
| `SONARR_URL` | Sonarr URL | `https://sonarr.example.com` |
|
||||
| `RADARR_URL` | Radarr URL | `https://radarr.example.com` |
|
||||
| `PROWLARR_URL` | Prowlarr URL | `https://prowlarr.example.com` |
|
||||
|
||||
### 3. Create Authentik API Token
|
||||
|
||||
1. Log into Authentik as admin
|
||||
2. Go to **Directory > Tokens and App passwords**
|
||||
3. Create a new token with **API Access** intent
|
||||
4. Copy the token value
|
||||
|
||||
### 4. (Optional) Set Up Google OAuth
|
||||
|
||||
1. Go to [Google Cloud Console](https://console.cloud.google.com)
|
||||
2. Create OAuth 2.0 credentials
|
||||
3. Add authorized redirect URI: `https://auth.example.com/source/oauth/callback/google/`
|
||||
|
||||
### 5. Deploy
|
||||
|
||||
Push to `main` branch to trigger deployment, or run manually:
|
||||
|
||||
```bash
|
||||
# Local development
|
||||
cp terraform.tfvars.example terraform.tfvars
|
||||
# Edit terraform.tfvars with your values
|
||||
|
||||
terraform init
|
||||
terraform plan
|
||||
terraform apply
|
||||
```
|
||||
|
||||
## GitHub Actions Workflow
|
||||
|
||||
- **On PR**: Runs `terraform plan` for review
|
||||
- **On Push to main**: Runs `terraform apply` automatically
|
||||
- **Manual**: Can trigger via Actions tab
|
||||
|
||||
## File Structure
|
||||
|
||||
```
|
||||
├── .github/workflows/deploy.yml # CI/CD pipeline
|
||||
├── main.tf # Authentik provider & brand config
|
||||
├── variables.tf # All configurable variables
|
||||
├── app-*.tf # Application configurations
|
||||
├── ldap-outpost.tf # LDAP outpost config
|
||||
├── source-google.tf # Google OAuth source
|
||||
└── outputs.tf # Useful outputs
|
||||
```
|
||||
|
||||
## Adding New Applications
|
||||
|
||||
### OAuth2/OIDC Application
|
||||
|
||||
```hcl
|
||||
# app-myapp.tf
|
||||
resource "authentik_provider_oauth2" "myapp" {
|
||||
name = "MyApp"
|
||||
authorization_flow = data.authentik_flow.default_authorization.id
|
||||
client_id = "myapp"
|
||||
client_type = "confidential"
|
||||
|
||||
redirect_uris = [
|
||||
"${var.myapp_url}/oauth/callback"
|
||||
]
|
||||
|
||||
property_mappings = data.authentik_property_mapping_provider_scope.oauth2.ids
|
||||
}
|
||||
|
||||
resource "authentik_application" "myapp" {
|
||||
name = "MyApp"
|
||||
slug = "myapp"
|
||||
protocol_provider = authentik_provider_oauth2.myapp.id
|
||||
|
||||
meta_launch_url = var.myapp_url
|
||||
meta_icon = "https://example.com/icon.png"
|
||||
}
|
||||
```
|
||||
|
||||
### Proxy Authentication
|
||||
|
||||
```hcl
|
||||
resource "authentik_provider_proxy" "myapp" {
|
||||
name = "MyApp Proxy"
|
||||
authorization_flow = data.authentik_flow.default_authorization.id
|
||||
external_host = var.myapp_url
|
||||
mode = "forward_single"
|
||||
}
|
||||
|
||||
resource "authentik_application" "myapp" {
|
||||
name = "MyApp"
|
||||
slug = "myapp"
|
||||
protocol_provider = authentik_provider_proxy.myapp.id
|
||||
}
|
||||
```
|
||||
|
||||
## Terraform State
|
||||
|
||||
By default, state is stored locally. For production, configure remote backend:
|
||||
|
||||
```hcl
|
||||
# backend.tf
|
||||
terraform {
|
||||
backend "s3" {
|
||||
bucket = "your-terraform-state"
|
||||
key = "authentik/terraform.tfstate"
|
||||
region = "us-east-1"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Security Notes
|
||||
|
||||
- Never commit `terraform.tfvars` or any file with secrets
|
||||
- Use GitHub Actions secrets for CI/CD
|
||||
- API tokens should have minimal required permissions
|
||||
- Rotate tokens periodically
|
||||
|
||||
## Requirements
|
||||
|
||||
| Name | Version |
|
||||
|------|---------|
|
||||
| terraform | >= 1.5.0 |
|
||||
| authentik | >= 2024.0 |
|
||||
|
||||
## License
|
||||
|
||||
MIT
|
||||
52
app-argocd.tf
Normal file
52
app-argocd.tf
Normal file
@@ -0,0 +1,52 @@
|
||||
# =============================================================================
|
||||
# ArgoCD - GitOps Continuous Delivery
|
||||
# =============================================================================
|
||||
|
||||
data "authentik_property_mapping_provider_scope" "argocd" {
|
||||
managed_list = [
|
||||
"goauthentik.io/providers/oauth2/scope-openid",
|
||||
"goauthentik.io/providers/oauth2/scope-email",
|
||||
"goauthentik.io/providers/oauth2/scope-profile",
|
||||
]
|
||||
}
|
||||
|
||||
resource "authentik_provider_oauth2" "argocd" {
|
||||
name = "ArgoCD"
|
||||
client_id = "argocd"
|
||||
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.argocd.ids
|
||||
|
||||
# ArgoCD callback URLs - TODO: Update to your domains
|
||||
allowed_redirect_uris = [
|
||||
{ matching_mode = "strict", url = "https://argo.your-tailnet.ts.net/auth/callback" },
|
||||
{ matching_mode = "strict", url = "https://argocd.example.com/auth/callback" },
|
||||
]
|
||||
|
||||
signing_key = data.authentik_certificate_key_pair.generated.id
|
||||
}
|
||||
|
||||
resource "authentik_application" "argocd" {
|
||||
name = "ArgoCD"
|
||||
slug = "argocd"
|
||||
protocol_provider = authentik_provider_oauth2.argocd.id
|
||||
|
||||
meta_description = "GitOps Continuous Delivery"
|
||||
meta_launch_url = "https://argocd.your-tailnet.ts.net" # TODO: Update
|
||||
|
||||
group = "DevOps"
|
||||
}
|
||||
|
||||
output "argocd_client_id" {
|
||||
value = authentik_provider_oauth2.argocd.client_id
|
||||
}
|
||||
|
||||
output "argocd_client_secret" {
|
||||
value = authentik_provider_oauth2.argocd.client_secret
|
||||
sensitive = true
|
||||
}
|
||||
52
app-grafana.tf
Normal file
52
app-grafana.tf
Normal file
@@ -0,0 +1,52 @@
|
||||
# =============================================================================
|
||||
# Grafana - Monitoring Dashboards
|
||||
# =============================================================================
|
||||
|
||||
data "authentik_property_mapping_provider_scope" "grafana" {
|
||||
managed_list = [
|
||||
"goauthentik.io/providers/oauth2/scope-openid",
|
||||
"goauthentik.io/providers/oauth2/scope-email",
|
||||
"goauthentik.io/providers/oauth2/scope-profile",
|
||||
]
|
||||
}
|
||||
|
||||
resource "authentik_provider_oauth2" "grafana" {
|
||||
name = "Grafana"
|
||||
client_id = "grafana"
|
||||
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.grafana.ids
|
||||
|
||||
# TODO: Update to your domains
|
||||
allowed_redirect_uris = [
|
||||
{ matching_mode = "strict", url = "https://grafana.your-tailnet.ts.net/login/generic_oauth" },
|
||||
{ matching_mode = "strict", url = "https://grafana.example.com/login/generic_oauth" },
|
||||
]
|
||||
|
||||
signing_key = data.authentik_certificate_key_pair.generated.id
|
||||
}
|
||||
|
||||
resource "authentik_application" "grafana" {
|
||||
name = "Grafana"
|
||||
slug = "grafana"
|
||||
protocol_provider = authentik_provider_oauth2.grafana.id
|
||||
|
||||
meta_description = "Monitoring & Observability Dashboards"
|
||||
meta_launch_url = "https://grafana.your-tailnet.ts.net" # TODO: Update
|
||||
|
||||
group = "Monitoring"
|
||||
}
|
||||
|
||||
output "grafana_client_id" {
|
||||
value = authentik_provider_oauth2.grafana.client_id
|
||||
}
|
||||
|
||||
output "grafana_client_secret" {
|
||||
value = authentik_provider_oauth2.grafana.client_secret
|
||||
sensitive = true
|
||||
}
|
||||
51
app-home-assistant.tf
Normal file
51
app-home-assistant.tf
Normal file
@@ -0,0 +1,51 @@
|
||||
# =============================================================================
|
||||
# Home Assistant - Smart Home
|
||||
# =============================================================================
|
||||
|
||||
data "authentik_property_mapping_provider_scope" "home_assistant" {
|
||||
managed_list = [
|
||||
"goauthentik.io/providers/oauth2/scope-openid",
|
||||
"goauthentik.io/providers/oauth2/scope-email",
|
||||
"goauthentik.io/providers/oauth2/scope-profile",
|
||||
]
|
||||
}
|
||||
|
||||
resource "authentik_provider_oauth2" "home_assistant" {
|
||||
name = "Home Assistant"
|
||||
client_id = "home-assistant"
|
||||
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.home_assistant.ids
|
||||
|
||||
# TODO: Update to your domain
|
||||
allowed_redirect_uris = [
|
||||
{ matching_mode = "strict", url = "https://home.your-tailnet.ts.net/auth/external/callback" },
|
||||
]
|
||||
|
||||
signing_key = data.authentik_certificate_key_pair.generated.id
|
||||
}
|
||||
|
||||
resource "authentik_application" "home_assistant" {
|
||||
name = "Home Assistant"
|
||||
slug = "home-assistant"
|
||||
protocol_provider = authentik_provider_oauth2.home_assistant.id
|
||||
|
||||
meta_description = "Smart Home Control"
|
||||
meta_launch_url = "https://home.your-tailnet.ts.net" # TODO: Update
|
||||
|
||||
group = "Home"
|
||||
}
|
||||
|
||||
output "home_assistant_client_id" {
|
||||
value = authentik_provider_oauth2.home_assistant.client_id
|
||||
}
|
||||
|
||||
output "home_assistant_client_secret" {
|
||||
value = authentik_provider_oauth2.home_assistant.client_secret
|
||||
sensitive = true
|
||||
}
|
||||
53
app-immich.tf
Normal file
53
app-immich.tf
Normal file
@@ -0,0 +1,53 @@
|
||||
# =============================================================================
|
||||
# Immich - Photo Management
|
||||
# =============================================================================
|
||||
|
||||
data "authentik_property_mapping_provider_scope" "immich" {
|
||||
managed_list = [
|
||||
"goauthentik.io/providers/oauth2/scope-openid",
|
||||
"goauthentik.io/providers/oauth2/scope-email",
|
||||
"goauthentik.io/providers/oauth2/scope-profile",
|
||||
]
|
||||
}
|
||||
|
||||
resource "authentik_provider_oauth2" "immich" {
|
||||
name = "Immich"
|
||||
client_id = "immich"
|
||||
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.immich.ids
|
||||
|
||||
# TODO: Update to your domain
|
||||
allowed_redirect_uris = [
|
||||
{ matching_mode = "strict", url = "https://immich.your-tailnet.ts.net/auth/login" },
|
||||
{ matching_mode = "strict", url = "https://immich.your-tailnet.ts.net/user-settings" },
|
||||
{ matching_mode = "strict", url = "app.immich:///oauth-callback" },
|
||||
]
|
||||
|
||||
signing_key = data.authentik_certificate_key_pair.generated.id
|
||||
}
|
||||
|
||||
resource "authentik_application" "immich" {
|
||||
name = "Immich"
|
||||
slug = "immich"
|
||||
protocol_provider = authentik_provider_oauth2.immich.id
|
||||
|
||||
meta_description = "Photo & Video Backup"
|
||||
meta_launch_url = "https://immich.your-tailnet.ts.net" # TODO: Update
|
||||
|
||||
group = "Media"
|
||||
}
|
||||
|
||||
output "immich_client_id" {
|
||||
value = authentik_provider_oauth2.immich.client_id
|
||||
}
|
||||
|
||||
output "immich_client_secret" {
|
||||
value = authentik_provider_oauth2.immich.client_secret
|
||||
sensitive = true
|
||||
}
|
||||
66
app-proxy-arr-stack.tf
Normal file
66
app-proxy-arr-stack.tf
Normal file
@@ -0,0 +1,66 @@
|
||||
# =============================================================================
|
||||
# Proxy Provider for Arr Stack (Sonarr, Radarr, Prowlarr)
|
||||
# These apps don't support OIDC natively, use Authentik proxy auth
|
||||
#
|
||||
# Note: Each app needs its own provider in Authentik due to 1:1 mapping
|
||||
# =============================================================================
|
||||
|
||||
# Forward auth provider - Sonarr
|
||||
resource "authentik_provider_proxy" "sonarr" {
|
||||
name = "Sonarr Proxy"
|
||||
authorization_flow = data.authentik_flow.default_authorization.id
|
||||
invalidation_flow = data.authentik_flow.default_invalidation.id
|
||||
mode = "forward_single"
|
||||
external_host = "https://sonarr.your-tailnet.ts.net" # TODO: Update
|
||||
access_token_validity = "hours=24"
|
||||
}
|
||||
|
||||
resource "authentik_application" "sonarr" {
|
||||
name = "Sonarr"
|
||||
slug = "sonarr"
|
||||
protocol_provider = authentik_provider_proxy.sonarr.id
|
||||
meta_description = "TV Show Automation"
|
||||
meta_launch_url = "https://sonarr.your-tailnet.ts.net" # TODO: Update
|
||||
group = "Media"
|
||||
}
|
||||
|
||||
# Forward auth provider - Radarr
|
||||
resource "authentik_provider_proxy" "radarr" {
|
||||
name = "Radarr Proxy"
|
||||
authorization_flow = data.authentik_flow.default_authorization.id
|
||||
invalidation_flow = data.authentik_flow.default_invalidation.id
|
||||
mode = "forward_single"
|
||||
external_host = "https://radarr.your-tailnet.ts.net" # TODO: Update
|
||||
access_token_validity = "hours=24"
|
||||
}
|
||||
|
||||
resource "authentik_application" "radarr" {
|
||||
name = "Radarr"
|
||||
slug = "radarr"
|
||||
protocol_provider = authentik_provider_proxy.radarr.id
|
||||
meta_description = "Movie Automation"
|
||||
meta_launch_url = "https://radarr.your-tailnet.ts.net" # TODO: Update
|
||||
group = "Media"
|
||||
}
|
||||
|
||||
# Forward auth provider - Prowlarr
|
||||
resource "authentik_provider_proxy" "prowlarr" {
|
||||
name = "Prowlarr Proxy"
|
||||
authorization_flow = data.authentik_flow.default_authorization.id
|
||||
invalidation_flow = data.authentik_flow.default_invalidation.id
|
||||
mode = "forward_single"
|
||||
external_host = "https://prowlarr.your-tailnet.ts.net" # TODO: Update
|
||||
access_token_validity = "hours=24"
|
||||
}
|
||||
|
||||
resource "authentik_application" "prowlarr" {
|
||||
name = "Prowlarr"
|
||||
slug = "prowlarr"
|
||||
protocol_provider = authentik_provider_proxy.prowlarr.id
|
||||
meta_description = "Indexer Manager"
|
||||
meta_launch_url = "https://prowlarr.your-tailnet.ts.net" # TODO: Update
|
||||
group = "Media"
|
||||
}
|
||||
|
||||
# Note: To use forward auth with Traefik/nginx, configure the embedded outpost
|
||||
# and add middleware to forward auth requests to Authentik
|
||||
30
app-uptime-kuma.tf
Normal file
30
app-uptime-kuma.tf
Normal file
@@ -0,0 +1,30 @@
|
||||
# =============================================================================
|
||||
# Uptime Kuma - Status Monitoring
|
||||
# Uses proxy authentication (UK doesn't support native OIDC login)
|
||||
# =============================================================================
|
||||
|
||||
resource "authentik_provider_proxy" "uptime_kuma" {
|
||||
name = "Uptime Kuma Proxy"
|
||||
authorization_flow = data.authentik_flow.default_authorization.id
|
||||
invalidation_flow = data.authentik_flow.default_invalidation.id
|
||||
mode = "forward_single"
|
||||
|
||||
external_host = "https://uptime.example.com" # TODO: Update
|
||||
access_token_validity = "hours=24"
|
||||
}
|
||||
|
||||
resource "authentik_application" "uptime_kuma" {
|
||||
name = "Uptime Kuma"
|
||||
slug = "uptime-kuma"
|
||||
protocol_provider = authentik_provider_proxy.uptime_kuma.id
|
||||
|
||||
meta_description = "Service Status Monitoring"
|
||||
meta_launch_url = "https://uptime.example.com" # TODO: Update
|
||||
|
||||
group = "Monitoring"
|
||||
}
|
||||
|
||||
# Note: Configure your reverse proxy (nginx/traefik/cloudflare)
|
||||
# to use Authentik forward auth before proxying to Uptime Kuma
|
||||
#
|
||||
# With disableAuth=true in UK, Authentik handles all authentication
|
||||
49
ldap-outpost.tf
Normal file
49
ldap-outpost.tf
Normal file
@@ -0,0 +1,49 @@
|
||||
# =============================================================================
|
||||
# LDAP Provider and Outpost for TrueNAS
|
||||
# Allows LDAP-based authentication against Authentik
|
||||
# =============================================================================
|
||||
|
||||
# LDAP Provider
|
||||
resource "authentik_provider_ldap" "truenas" {
|
||||
name = "TrueNAS LDAP"
|
||||
base_dn = "dc=ldap,dc=example,dc=com" # TODO: Update to your domain
|
||||
bind_flow = data.authentik_flow.default_authentication.id
|
||||
unbind_flow = data.authentik_flow.default_invalidation.id
|
||||
|
||||
# Bind mode - direct means users bind with their own credentials
|
||||
bind_mode = "direct"
|
||||
|
||||
# Search mode
|
||||
search_mode = "direct"
|
||||
|
||||
# MFA support (optional)
|
||||
mfa_support = false
|
||||
}
|
||||
|
||||
# Application for LDAP
|
||||
resource "authentik_application" "truenas_ldap" {
|
||||
name = "TrueNAS LDAP"
|
||||
slug = "truenas-ldap"
|
||||
protocol_provider = authentik_provider_ldap.truenas.id
|
||||
|
||||
meta_description = "LDAP authentication for TrueNAS"
|
||||
|
||||
group = "Infrastructure"
|
||||
}
|
||||
|
||||
# LDAP Outpost (standalone container needed for LDAP)
|
||||
resource "authentik_outpost" "ldap" {
|
||||
name = "LDAP Outpost"
|
||||
type = "ldap"
|
||||
protocol_providers = [authentik_provider_ldap.truenas.id]
|
||||
|
||||
config = jsonencode({
|
||||
authentik_host = "https://authentik.example.com" # TODO: Update
|
||||
authentik_host_insecure = false
|
||||
log_level = "info"
|
||||
})
|
||||
}
|
||||
|
||||
output "ldap_base_dn" {
|
||||
value = "dc=ldap,dc=example,dc=com" # TODO: Update to match above
|
||||
}
|
||||
80
main.tf
Normal file
80
main.tf
Normal file
@@ -0,0 +1,80 @@
|
||||
# =============================================================================
|
||||
# Authentik Terraform Configuration
|
||||
# Update the domain below to match your Authentik instance
|
||||
# =============================================================================
|
||||
|
||||
# Decrypt secrets with SOPS
|
||||
data "sops_file" "secrets" {
|
||||
source_file = "secrets.enc.yaml"
|
||||
}
|
||||
|
||||
provider "authentik" {
|
||||
url = var.authentik_url
|
||||
token = data.sops_file.secrets.data["authentik_token"]
|
||||
}
|
||||
|
||||
# =============================================================================
|
||||
# Data Sources - Existing Resources
|
||||
# =============================================================================
|
||||
|
||||
# Default authentication flow
|
||||
data "authentik_flow" "default_authentication" {
|
||||
slug = "default-authentication-flow"
|
||||
}
|
||||
|
||||
# Default authorization flow (implicit consent)
|
||||
data "authentik_flow" "default_authorization" {
|
||||
slug = "default-provider-authorization-implicit-consent"
|
||||
}
|
||||
|
||||
# Default invalidation flow
|
||||
data "authentik_flow" "default_invalidation" {
|
||||
slug = "default-invalidation-flow"
|
||||
}
|
||||
|
||||
# Default enrollment flow (for social login)
|
||||
data "authentik_flow" "default_enrollment" {
|
||||
slug = "default-source-enrollment"
|
||||
}
|
||||
|
||||
# Get certificate for signing
|
||||
data "authentik_certificate_key_pair" "generated" {
|
||||
name = "authentik Self-signed Certificate"
|
||||
}
|
||||
|
||||
# =============================================================================
|
||||
# Brand Configuration
|
||||
# =============================================================================
|
||||
|
||||
data "authentik_brand" "default" {
|
||||
domain = "authentik-default"
|
||||
}
|
||||
|
||||
# Update brand with proper domain
|
||||
resource "authentik_brand" "main" {
|
||||
domain = "authentik.example.com" # TODO: Update to your domain
|
||||
default = false
|
||||
branding_title = "My Lab" # TODO: Update to your org name
|
||||
branding_logo = "/static/dist/assets/icons/icon_left_brand.svg"
|
||||
branding_favicon = "/static/dist/assets/icons/icon.png"
|
||||
|
||||
flow_authentication = data.authentik_flow.default_authentication.id
|
||||
flow_invalidation = data.authentik_flow.default_invalidation.id
|
||||
}
|
||||
|
||||
# =============================================================================
|
||||
# Groups
|
||||
# =============================================================================
|
||||
|
||||
resource "authentik_group" "admins" {
|
||||
name = "Admins"
|
||||
is_superuser = true
|
||||
}
|
||||
|
||||
resource "authentik_group" "users" {
|
||||
name = "Users"
|
||||
}
|
||||
|
||||
# =============================================================================
|
||||
# Applications are defined in applications/*.tf
|
||||
# =============================================================================
|
||||
14
outputs.tf
Normal file
14
outputs.tf
Normal file
@@ -0,0 +1,14 @@
|
||||
output "authentik_url" {
|
||||
description = "Authentik instance URL"
|
||||
value = var.authentik_url
|
||||
}
|
||||
|
||||
output "admin_group_id" {
|
||||
description = "Admin group ID for RBAC"
|
||||
value = authentik_group.admins.id
|
||||
}
|
||||
|
||||
output "users_group_id" {
|
||||
description = "Users group ID"
|
||||
value = authentik_group.users.id
|
||||
}
|
||||
31
source-google.tf
Normal file
31
source-google.tf
Normal file
@@ -0,0 +1,31 @@
|
||||
# =============================================================================
|
||||
# Google Workspace Federation
|
||||
# Allow users to sign in with their Google Workspace accounts
|
||||
# =============================================================================
|
||||
|
||||
# Google OAuth Source
|
||||
resource "authentik_source_oauth" "google" {
|
||||
name = "Google Workspace"
|
||||
slug = "google"
|
||||
authentication_flow = data.authentik_flow.default_authentication.id
|
||||
enrollment_flow = data.authentik_flow.default_enrollment.id
|
||||
|
||||
provider_type = "google"
|
||||
consumer_key = data.sops_file.secrets.data["google_client_id"]
|
||||
consumer_secret = data.sops_file.secrets.data["google_client_secret"]
|
||||
|
||||
# PKCE method - S256 is recommended
|
||||
pkce = "S256"
|
||||
|
||||
# User matching - link by email
|
||||
user_matching_mode = "email_link"
|
||||
|
||||
# Policy engine
|
||||
policy_engine_mode = "any"
|
||||
|
||||
# Enable for login page
|
||||
enabled = true
|
||||
}
|
||||
|
||||
# Note: After applying, the Google login button will appear on the Authentik login page.
|
||||
# Users with matching emails will be linked; new users will be enrolled.
|
||||
23
terraform.tfvars.example
Normal file
23
terraform.tfvars.example
Normal file
@@ -0,0 +1,23 @@
|
||||
# Example terraform.tfvars - Copy to terraform.tfvars and fill in your values
|
||||
# NEVER commit terraform.tfvars to git!
|
||||
|
||||
# Authentik Connection (required)
|
||||
authentik_url = "https://auth.example.com"
|
||||
authentik_token = "your-api-token-here"
|
||||
|
||||
# Google OAuth (optional - leave empty to skip)
|
||||
google_client_id = ""
|
||||
google_client_secret = ""
|
||||
|
||||
# Application URLs (set the ones you want to configure)
|
||||
argocd_url = "https://argocd.example.com"
|
||||
grafana_url = "https://grafana.example.com"
|
||||
home_assistant_url = "https://home.example.com"
|
||||
immich_url = "https://photos.example.com"
|
||||
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"
|
||||
|
||||
# LDAP Configuration
|
||||
ldap_base_dn = "dc=ldap,dc=example,dc=com"
|
||||
90
variables.tf
Normal file
90
variables.tf
Normal file
@@ -0,0 +1,90 @@
|
||||
################################################################################
|
||||
# Authentik Terraform Variables
|
||||
#
|
||||
# Set these via:
|
||||
# - GitHub Actions secrets (recommended)
|
||||
# - terraform.tfvars (local dev only - never commit!)
|
||||
# - Environment variables (TF_VAR_*)
|
||||
################################################################################
|
||||
|
||||
# Authentik Connection
|
||||
variable "authentik_url" {
|
||||
type = string
|
||||
description = "Authentik server URL (e.g., https://auth.example.com)"
|
||||
}
|
||||
|
||||
variable "authentik_token" {
|
||||
type = string
|
||||
sensitive = true
|
||||
description = "Authentik API token"
|
||||
}
|
||||
|
||||
# Google OAuth (optional)
|
||||
variable "google_client_id" {
|
||||
type = string
|
||||
default = ""
|
||||
description = "Google OAuth client ID"
|
||||
}
|
||||
|
||||
variable "google_client_secret" {
|
||||
type = string
|
||||
sensitive = true
|
||||
default = ""
|
||||
description = "Google OAuth client secret"
|
||||
}
|
||||
|
||||
# Application URLs
|
||||
variable "argocd_url" {
|
||||
type = string
|
||||
default = ""
|
||||
description = "ArgoCD URL for SSO"
|
||||
}
|
||||
|
||||
variable "grafana_url" {
|
||||
type = string
|
||||
default = ""
|
||||
description = "Grafana URL for SSO"
|
||||
}
|
||||
|
||||
variable "home_assistant_url" {
|
||||
type = string
|
||||
default = ""
|
||||
description = "Home Assistant URL for proxy auth"
|
||||
}
|
||||
|
||||
variable "immich_url" {
|
||||
type = string
|
||||
default = ""
|
||||
description = "Immich URL for proxy auth"
|
||||
}
|
||||
|
||||
variable "uptime_kuma_url" {
|
||||
type = string
|
||||
default = ""
|
||||
description = "Uptime Kuma URL for proxy auth"
|
||||
}
|
||||
|
||||
variable "sonarr_url" {
|
||||
type = string
|
||||
default = ""
|
||||
description = "Sonarr URL for proxy auth"
|
||||
}
|
||||
|
||||
variable "radarr_url" {
|
||||
type = string
|
||||
default = ""
|
||||
description = "Radarr URL for proxy auth"
|
||||
}
|
||||
|
||||
variable "prowlarr_url" {
|
||||
type = string
|
||||
default = ""
|
||||
description = "Prowlarr URL for proxy auth"
|
||||
}
|
||||
|
||||
# LDAP Configuration
|
||||
variable "ldap_base_dn" {
|
||||
type = string
|
||||
default = "dc=ldap,dc=example,dc=com"
|
||||
description = "LDAP base DN"
|
||||
}
|
||||
14
versions.tf
Normal file
14
versions.tf
Normal file
@@ -0,0 +1,14 @@
|
||||
terraform {
|
||||
required_version = ">= 1.5.0"
|
||||
|
||||
required_providers {
|
||||
authentik = {
|
||||
source = "goauthentik/authentik"
|
||||
version = "~> 2025.2"
|
||||
}
|
||||
sops = {
|
||||
source = "carlpett/sops"
|
||||
version = "~> 1.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user