Compare commits

...

1 Commits

Author SHA1 Message Date
Test User daf8a7bd56 fix(GRO-693): add UAT Terraform infrastructure with correct GitRepository
- Add terraform workspace at apps/overlays/uat/terraform/ (backend.tf,
  main.tf, variables.tf, users.tf, imports.tf, terraform.tfvars)
- Add Terraform CRD (authentik-terraform.yaml) with correct path
  ./apps/overlays/uat/terraform relative to groombook/app repo root
- Add GitRepository CRD (gitrepository-groombook.yaml) pointing to
  groombook/app at fix/gro-844-network-policy branch (NOT groombook/infra
  which no longer exists)
- Add kustomization.yaml to tie it together

Root cause: the GitRepository was pointing to https://github.com/groombook/infra
which no longer exists, and the terraform files were not committed to the
current repository at the correct path.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-04-21 19:55:35 +00:00
9 changed files with 374 additions and 0 deletions
@@ -0,0 +1,53 @@
# =============================================================================
# Terraform CRD for Flux ToFu Controller — Authentik groombook-uat
# =============================================================================
# This CRD tells the Flux ToFu Controller to reconcile the Terraform
# workspace at apps/overlays/uat/terraform/
#
# The ToFu Controller will:
# 1. Clone the groombook/app GitRepository
# 2. Run tofu init + tofu plan/apply in the specified path
# 3. Store Terraform state in a Kubernetes secret (backend.tf)
# 4. Inject TF_VAR_authentik_token from the authentik-credentials secret
# via tf-controller varsFrom (maps secret key to Terraform variable)
#
# ApiVersion: infra.contrib.fluxcd.io/v1alpha2 (tf-controller)
# =============================================================================
apiVersion: infra.contrib.fluxcd.io/v1alpha2
kind: Terraform
metadata:
name: authentik-uat
namespace: groombook-uat
labels:
app.kubernetes.io/name: authentik
app.kubernetes.io/part-of: groombook
app.kubernetes.io/env: uat
spec:
# Reconcile every hour
interval: 1h
# Path within the GitRepository (groombook/app)
path: ./apps/overlays/uat/terraform
# Source reference — must match the GitRepository name watching this repo
sourceRef:
kind: GitRepository
name: groombook
# Auto-approve plans (no manual intervention needed for infrastructure)
approvePlan: "auto"
# Clean up Terraform resources when this CRD is deleted
destroyResourcesOnDeletion: true
# Inject TF_VAR_authentik_token from the sealed secret via tf-controller varsFrom
# (maps secret key "authentik_token" to Terraform var.authentik_token)
varsFrom:
- kind: Secret
name: authentik-credentials
- kind: Secret
name: authentik-uat-users-credentials
runnerPodTemplate:
spec: {}
@@ -0,0 +1,19 @@
---
apiVersion: source.toolkit.fluxcd.io/v1
kind: GitRepository
metadata:
name: groombook
namespace: groombook-uat
labels:
app.kubernetes.io/name: groombook
app.kubernetes.io/part-of: groombook
app.kubernetes.io/env: uat
spec:
interval: 15m
provider: github
ref:
branch: fix/gro-844-network-policy
secretRef:
name: cpfarhood-k8s
timeout: 60s
url: https://github.com/groombook/app
+6
View File
@@ -0,0 +1,6 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namespace: groombook-uat
resources:
- gitrepository-groombook.yaml
- authentik-terraform.yaml
+21
View File
@@ -0,0 +1,21 @@
# =============================================================================
# Backend configuration for Terraform state
# =============================================================================
# Uses Kubernetes backend with tf-controller managed state secret.
# tf-controller creates a Kubernetes Secret named:
# tfstate-<name>-<secret_suffix>
# i.e. tfstate-authentik-uat-authentik-uat-tf-state
# in the namespace specified by the Terraform CRD metadata.namespace (groombook-uat).
#
# Valid Kubernetes backend attributes for tf-controller:
# secret_suffix, namespace, config_path, cluster_ca_cert, client_certificate,
# client_key, token, exec, host, insecure, username, password,
# in_cluster, load_config, config_paths
# =============================================================================
terraform {
backend "kubernetes" {
secret_suffix = "authentik-uat-tf-state"
namespace = "groombook-uat"
}
}
+12
View File
@@ -0,0 +1,12 @@
# Import existing Authentik resources into Terraform state.
# These blocks are consumed on the first apply and become no-ops thereafter.
import {
to = authentik_oauth2_provider.groombook-uat
id = "284"
}
import {
to = authentik_application.groombook-uat
id = "e77a9c45-bed6-4a23-bc62-178f166f099e"
}
+99
View File
@@ -0,0 +1,99 @@
# =============================================================================
# Terraform configuration for Authentik groombook-uat application
# =============================================================================
# This Terraform workspace manages the Authentik OAuth2 application and provider
# for the groombook-uat environment.
#
# The authentik_token used for authentication is sourced from the
# `authentik-credentials` SealedSecret (injected as TF_VAR_authentik_token
# by the Terraform CRD runnerPodTemplate.spec.varsFrom).
#
# To import existing resources (run via tf-controller exec or locally with
# AUTHENTIK_TOKEN set):
# tofu import authentik_oauth2_provider.groombook-uat pk-284
# tofu import authentik_application.groombook-uat e77a9c45-bed6-4a23-bc62-178f166f099e
# =============================================================================
# -----------------------------------------------------------------------------
# Provider configuration
# -----------------------------------------------------------------------------
terraform {
required_providers {
authentik = {
source = "goauthentik/authentik"
version = "~> 2024.12"
}
}
}
provider "authentik" {
url = var.authentik_url
api_token = var.authentik_token
tls_verify = true
}
# -----------------------------------------------------------------------------
# OAuth2 Provider for groombook-uat
# pk = 284 (existing — imported, not recreated)
# -----------------------------------------------------------------------------
resource "authentik_oauth2_provider" "groombook-uat" {
name = "groombook-uat-provider"
slug = "groombook-uat"
client_id = "" # managed by imported resource; tracked via ignore_changes
client_secret = "" # managed by imported resource; tracked via ignore_changes
client_type = "confidential"
redirect_uris = ["https://uat.groombook.dev/api/auth/oauth2/callback/authentik"]
signing_key = "authentik signing key"
# Keep Terraform from overwriting the client_id, client_secret, and signing_key
# which are managed by the imported existing resource
lifecycle {
ignore_changes = [
client_id,
client_secret,
signing_key,
]
}
}
# -----------------------------------------------------------------------------
# Application for groombook-uat
# pk = e77a9c45-bed6-4a23-bc62-178f166f099e (existing — imported, not recreated)
# -----------------------------------------------------------------------------
resource "authentik_application" "groombook-uat" {
name = "groombook-uat"
slug = "groombook-uat"
group = "groombook"
policy_ids = []
description = "GroomBook UAT application"
# Link to the OAuth2 provider
oauth2_provider = authentik_oauth2_provider.groombook-uat.id
# Track name, slug, group, and oauth2_provider for drift detection;
# ignore policy_ids and description which may be updated out-of-band
lifecycle {
ignore_changes = [
policy_ids,
description,
]
}
}
# -----------------------------------------------------------------------------
# Outputs (for reference / verification)
# -----------------------------------------------------------------------------
output "oauth2_provider_pk" {
description = "Authentik OAuth2 Provider primary key"
value = authentik_oauth2_provider.groombook-uat.pk
}
output "application_pk" {
description = "Authentik Application primary key"
value = authentik_application.groombook-uat.pk
}
output "application_slug" {
description = "Authentik Application slug"
value = authentik_application.groombook-uat.slug
}
@@ -0,0 +1,10 @@
# =============================================================================
# Terraform variable values for groombook-uat
# =============================================================================
# NOTE: authentik_token should be provided via AUTHENTIK_TOKEN env var,
# sourced from the authentik-credentials SealedSecret.
# The placeholder value here is not used when running via tf-controller.
# =============================================================================
authentik_url = "https://auth.farh.net"
# authentik_token = "<set via AUTHENTIK_TOKEN env var from authentik-credentials secret>"
+121
View File
@@ -0,0 +1,121 @@
# =============================================================================
# Authentik UAT user personas — Terraform resources
# =============================================================================
# Creates three Authentik users bound to the groombook-uat application:
# - UAT Super User (manager role, superuser)
# - UAT Groomer (staff/groomer role)
# - UAT Customer (no staff record — auth identity only)
#
# Passwords are sourced from sensitive Terraform variables which are injected
# via tf-controller varsFrom from the authentik-uat-users-credentials SealedSecret.
#
# User PKs are exported as outputs — these are the OIDC sub claims in Authentik.
# =============================================================================
# -----------------------------------------------------------------------------
# Group: groombook-uat-users
# -----------------------------------------------------------------------------
resource "authentik_group" "groombook-uat-users" {
name = "groombook-uat-users"
}
# -----------------------------------------------------------------------------
# User: UAT Super User
# -----------------------------------------------------------------------------
resource "authentik_user" "uat-super" {
name = "UAT Super User"
username = "uat-super"
email = "uat-super@groombook.dev"
password = var.uat_super_password
active = true
# Attributes stored as JSON string per authentik_user schema
attributes_json = jsonencode({
role = "manager"
})
}
# Add uat-super to the group
resource "authentik_group_membership" "uat-super" {
group = authentik_group.groombook-uat-users.id
user = authentik_user.uat-super.pk
}
# Bind the group to the groombook-uat application via policy binding
# This grants group members authentication access to the application
resource "authentik_policy_binding" "uat-super-group-binding" {
policy = authentik_group.groombook-uat-users.id
target = authentik_application.groombook-uat.pk
binding_type = "group_whitelist"
}
# -----------------------------------------------------------------------------
# User: UAT Groomer (Staff)
# -----------------------------------------------------------------------------
resource "authentik_user" "uat-groomer" {
name = "UAT Groomer"
username = "uat-groomer"
email = "uat-groomer@groombook.dev"
password = var.uat_groomer_password
active = true
attributes_json = jsonencode({
role = "groomer"
})
}
# Add uat-groomer to the group
resource "authentik_group_membership" "uat-groomer" {
group = authentik_group.groombook-uat-users.id
user = authentik_user.uat-groomer.pk
}
# Bind the group to the groombook-uat application
resource "authentik_policy_binding" "uat-groomer-group-binding" {
policy = authentik_group.groombook-uat-users.id
target = authentik_application.groombook-uat.pk
binding_type = "group_whitelist"
}
# -----------------------------------------------------------------------------
# User: UAT Customer
# -----------------------------------------------------------------------------
resource "authentik_user" "uat-customer" {
name = "UAT Customer"
username = "uat-customer"
email = "uat-customer@groombook.dev"
password = var.uat_customer_password
active = true
attributes_json = jsonencode({
role = "customer"
})
}
# Add uat-customer to the group
resource "authentik_group_membership" "uat-customer" {
group = authentik_group.groombook-uat-users.id
user = authentik_user.uat-customer.pk
}
# Bind the group to the groombook-uat application
resource "authentik_policy_binding" "uat-customer-group-binding" {
policy = authentik_group.groombook-uat-users.id
target = authentik_application.groombook-uat.pk
binding_type = "group_whitelist"
}
# -----------------------------------------------------------------------------
# Outputs — OIDC sub claims (= user PK in Authentik)
# -----------------------------------------------------------------------------
output "uat_super_user_pk" {
description = "UAT Super User primary key (OIDC sub)"
value = authentik_user.uat-super.pk
}
output "uat_groomer_user_pk" {
description = "UAT Groomer primary key (OIDC sub)"
value = authentik_user.uat-groomer.pk
}
output "uat_customer_user_pk" {
description = "UAT Customer primary key (OIDC sub)"
value = authentik_user.uat-customer.pk
}
+33
View File
@@ -0,0 +1,33 @@
# =============================================================================
# Variables for Authentik groombook-uat Terraform workspace
# =============================================================================
variable "authentik_url" {
description = "Base URL of the Authentik instance"
type = string
default = "https://auth.farh.net"
}
variable "authentik_token" {
description = "API token for Authentik (from authentik-credentials secret via AUTHENTIK_TOKEN env var)"
type = string
sensitive = true
}
variable "uat_super_password" {
description = "Password for the UAT Super User account"
type = string
sensitive = true
}
variable "uat_groomer_password" {
description = "Password for the UAT Groomer staff account"
type = string
sensitive = true
}
variable "uat_customer_password" {
description = "Password for the UAT Customer account"
type = string
sensitive = true
}