diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..66df410 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +.terraform* \ No newline at end of file diff --git a/ak-gatekeeper/ak_provider.tf b/ak-gatekeeper/ak_provider.tf index a32f86a..9f04fc5 100644 --- a/ak-gatekeeper/ak_provider.tf +++ b/ak-gatekeeper/ak_provider.tf @@ -2,6 +2,10 @@ data "authentik_flow" "proxy_authorization_flow" { depends_on = [data.kubernetes_secret_v1.authentik] slug = "default-provider-authorization-implicit-consent" } +data "authentik_flow" "default_invalidation_flow" { + depends_on = [data.kubernetes_secret_v1.authentik] + slug = "default-provider-invalidation-flow" +} resource "authentik_provider_proxy" "app_proxy_provider" { name = "${local.app_slug}-provider" @@ -9,4 +13,5 @@ resource "authentik_provider_proxy" "app_proxy_provider" { authorization_flow = data.authentik_flow.proxy_authorization_flow.id mode = "forward_single" access_token_validity = var.access_token_validity + invalidation_flow = data.authentik_flow.default_invalidation_flow.id } diff --git a/ak-gatekeeper/providers.tf b/ak-gatekeeper/providers.tf index f3da28e..af63d4c 100644 --- a/ak-gatekeeper/providers.tf +++ b/ak-gatekeeper/providers.tf @@ -10,8 +10,8 @@ terraform { version = "~> 1.14.0" } authentik = { - source = "goauthentik/authentik" - version = "~> 2023.5.0" + source = "registry.terraform.io/goauthentik/authentik" + version = "~> 2024.10.0" } http = { source = "hashicorp/http" diff --git a/application/providers.tf b/application/providers.tf index 250b1a1..f519fcc 100644 --- a/application/providers.tf +++ b/application/providers.tf @@ -1,12 +1,13 @@ terraform { + required_version = ">= 1.0" required_providers { kubectl = { source = "gavinbunney/kubectl" version = "~> 1.14.0" } authentik = { - source = "goauthentik/authentik" - version = "~> 2023.5.0" + source = "registry.terraform.io/goauthentik/authentik" + version = "~> 2024.10.0" } } } diff --git a/oauth2/oauth2.tf b/oauth2/oauth2.tf index f43d2e1..20b11c1 100644 --- a/oauth2/oauth2.tf +++ b/oauth2/oauth2.tf @@ -3,22 +3,38 @@ locals { oauth2_labels = merge(var.labels, { "app.kubernetes.io/component" = "authentik-oauth2" }) + cert_signing = var.cert_sign_secret_name != "" + signing_id = local.cert_signing ? authentik_certificate_key_pair.name[0].id : data.authentik_certificate_key_pair.ca.id } -resource "random_password" "client_id" { - length = 32 - special = false +resource "kubectl_manifest" "secret_gen" { + yaml_body = <<-EOF + apiVersion: "secretgenerator.mittwald.de/v1alpha1" + kind: "StringSecret" + metadata: + name: "${local.app_slug}-oauth2" + namespace: "${var.namespace}" + labels: ${jsonencode(local.oauth2_labels)} + ownerReferences: ${jsonencode(var.owner_references)} + spec: + forceRegenerate: false + fields: + - fieldName: "client_id" + length: "32" + EOF +} +data "kubernetes_secret_v1" "secret_gen" { + metadata { + name = kubectl_manifest.secret_gen.name + namespace = var.namespace + } } - data "authentik_certificate_key_pair" "ca" { name = "authentik Self-signed Certificate" } - -data "authentik_scope_mapping" "oauth2" { +data "authentik_property_mapping_provider_scope" "oauth2" { managed_list = [ - "goauthentik.io/providers/oauth2/scope-email", - "goauthentik.io/providers/oauth2/scope-openid", - "goauthentik.io/providers/oauth2/scope-profile" + for scope in var.scopes : "goauthentik.io/providers/oauth2/${scope}" ] } data "authentik_flow" "default_authorization_flow" { @@ -27,16 +43,50 @@ data "authentik_flow" "default_authorization_flow" { data "authentik_flow" "default_authentication_flow" { slug = "default-authentication-flow" } +data "authentik_flow" "default_invalidation_flow" { + slug = "default-provider-invalidation-flow" +} + +resource "authentik_group" "app_group" { + name = local.app_slug + attributes = jsonencode({ "app_slug" = local.app_slug }) +} + +resource "authentik_group" "groups" { + for_each = var.group_mapping + name = each.key + parent = authentik_group.app_group.id + attributes = jsonencode({ + "app_slug" = local.app_slug + "gen_group_name" = each.value + }) +} + +data "kubernetes_secret_v1" "signing_cert" { + count = var.cert_sign_secret_name != "" ? 1 : 0 + metadata { + name = var.cert_sign_secret_name + namespace = var.namespace + } +} + +resource "authentik_certificate_key_pair" "name" { + count = local.cert_signing ? 1 : 0 + name = "${local.app_slug} Signing" + certificate_data = try(data.kubernetes_secret_v1.signing_cert[0].data, { "tls.crt" = "" })["tls.crt"] + key_data = try(data.kubernetes_secret_v1.signing_cert[0].data, { "tls.key" = "" })["tls.key"] +} resource "authentik_provider_oauth2" "oauth2" { name = local.app_slug - client_id = random_password.client_id.result + client_id = data.kubernetes_secret_v1.secret_gen.data.client_id authentication_flow = data.authentik_flow.default_authentication_flow.id authorization_flow = data.authentik_flow.default_authorization_flow.id - client_type = "confidential" + invalidation_flow = data.authentik_flow.default_invalidation_flow.id + client_type = var.client_type sub_mode = "user_username" - signing_key = data.authentik_certificate_key_pair.ca.id - property_mappings = data.authentik_scope_mapping.oauth2.ids + signing_key = local.signing_id + property_mappings = data.authentik_property_mapping_provider_scope.oauth2.ids redirect_uris = [ "https://${var.redirect_path != "" ? "${var.dns_name}/${var.redirect_path}" : var.dns_name}" ] @@ -49,15 +99,32 @@ data "kubernetes_ingress_v1" "authentik" { } } -resource "kubernetes_secret" "oauth2_client_secret" { - metadata { - name = "${local.app_slug}-oauth2" - namespace = var.namespace - labels = local.oauth2_labels - } - data = { - oidc_endpoint = "https://${data.kubernetes_ingress_v1.authentik.spec[0].rule[0].host}/application/o/${local.app_slug}/" - client_id = random_password.client_id.result - client_secret = authentik_provider_oauth2.oauth2.client_secret - } +resource "kubectl_manifest" "oauth2_client_secret" { + force_new = true + yaml_body = <<-EOF + apiVersion: v1 + kind: Secret + metadata: + name: "${local.app_slug}-oauth2" + namespace: "${var.namespace}" + labels: ${jsonencode(local.oauth2_labels)} + ownerReferences: ${jsonencode(var.owner_references)} + data: + oidc_endpoint: "${base64encode("https://${data.kubernetes_ingress_v1.authentik.spec[0].rule[0].host}/application/o/${local.app_slug}/")}" + client_id: "${base64encode(data.kubernetes_secret_v1.secret_gen.data.client_id)}" + client_secret: "${base64encode(authentik_provider_oauth2.oauth2.client_secret)}" + EOF } + +# resource "kubernetes_secret" "oauth2_client_secret" { +# metadata { +# name = "${local.app_slug}-oauth2" +# namespace = var.namespace +# labels = local.oauth2_labels +# } +# data = { +# oidc_endpoint = "https://${data.kubernetes_ingress_v1.authentik.spec[0].rule[0].host}/application/o/${local.app_slug}/" +# client_id = data.kubernetes_secret_v1.secret_gen.data["client_id"] +# client_secret = authentik_provider_oauth2.oauth2.client_secret +# } +# } diff --git a/oauth2/outputs.tf b/oauth2/outputs.tf index efbd298..4747ab1 100644 --- a/oauth2/outputs.tf +++ b/oauth2/outputs.tf @@ -23,7 +23,7 @@ output "sso_token_url" { } output "client_id" { - value = random_password.client_id.result + value = data.kubernetes_secret_v1.secret_gen.data.client_id } output "client_secret" { @@ -31,6 +31,6 @@ output "client_secret" { } output "oauth2_secret_name" { - value = kubernetes_secret.oauth2_client_secret.metadata[0].name + value = kubectl_manifest.oauth2_client_secret.name } diff --git a/oauth2/providers.tf b/oauth2/providers.tf index fd4545c..902248d 100644 --- a/oauth2/providers.tf +++ b/oauth2/providers.tf @@ -1,5 +1,6 @@ terraform { + required_version = ">= 1.0" required_providers { kubernetes = { source = "hashicorp/kubernetes" @@ -10,8 +11,8 @@ terraform { version = "~> 1.14.0" } authentik = { - source = "goauthentik/authentik" - version = "~> 2023.5.0" + source = "registry.terraform.io/goauthentik/authentik" + version = "~> 2024.10.0" } } } diff --git a/oauth2/variables.tf b/oauth2/variables.tf index 176185b..d092bee 100644 --- a/oauth2/variables.tf +++ b/oauth2/variables.tf @@ -20,3 +20,36 @@ variable "redirect_path" { type = string default = "" } +variable "group_mapping" { + type = map(string) + default = {} + description = "Group mapping where key application group and value the generic group name" +} +variable "owner_references" { + type = list(object({})) + description = "Adding owner references" + default = [] +} +variable "scopes" { + type = list(string) + description = "List of default scope allowed" + default = [ + "scope-email", + "scope-openid", + "scope-profile", + ] +} +variable "client_type" { + type = string + description = "OAuth client type confidential / public(PKCE)" + default = "confidential" + validation { + condition = contains(["confidential", "public"], var.client_type) + error_message = "Only empty confidential or public is allowed" + } +} +variable "cert_sign_secret_name" { + type = string + description = "The name of the secret for signing JWT (if empty use authentik default)" + default = "" +} diff --git a/pvc/providers.tf b/pvc/providers.tf index 852127e..af814dc 100644 --- a/pvc/providers.tf +++ b/pvc/providers.tf @@ -1,8 +1,13 @@ terraform { + required_version = ">= 1.0" required_providers { - kubectl = { - source = "gavinbunney/kubectl" - version = "~> 1.14.0" + kubernetes = { + source = "hashicorp/kubernetes" + version = "~> 2.20.0" } + # kubectl = { + # source = "gavinbunney/kubectl" + # version = "~> 1.14.0" + # } } } diff --git a/pvc/pvc.tf b/pvc/pvc.tf index 5d72593..c540e2d 100644 --- a/pvc/pvc.tf +++ b/pvc/pvc.tf @@ -3,30 +3,60 @@ locals { pvc_labels = merge(var.labels, { "app.kubernetes.io/component" = "pvc" }) - pvc_spec = merge({ - "accessModes" = [var.storage.access_mode] - "volumeMode" = var.storage.type - "resources" = { - "requests" = { - "storage" = var.storage.size + pvc_annotations = { + "k8up.io/backup" = var.backup + "resize.kubesphere.io/storage_limit" = var.storage.max_size + } + # pvc_spec = merge({ + # "accessModes" = [var.storage.access_mode] + # "volumeMode" = var.storage.type + # "resources" = { + # "requests" = { + # "storage" = var.storage.size + # } + # } + # }, var.storage.class != "" ? { + # "storageClassName" = var.storage.class + # } : {}) +} +# resource "kubectl_manifest" "pvc" { +# ignore_fields = [ +# "spec.resources.requests.storage", +# "spec.storageClassName", +# ] +# yaml_body = <<-EOF +# apiVersion: v1 +# kind: PersistentVolumeClaim +# metadata: +# name: ${local.app_slug} +# namespace: "${var.namespace}" +# annotations: +# k8up.io/backup: "${var.backup}" +# resize.kubesphere.io/storage_limit: "${var.storage.max_size}" +# labels: ${jsonencode(local.pvc_labels)} +# spec: ${jsonencode(local.pvc_spec)} +# EOF +# } +resource "kubernetes_persistent_volume_claim_v1" "pvc" { + metadata { + name = local.app_slug + namespace = var.namespace + annotations = local.pvc_annotations + labels = local.pvc_labels + } + spec { + access_modes = [var.storage.access_mode] + resources { + requests = { + storage = var.storage.size } } - }, var.storage.class != "" ? { - "storageClassName" = var.storage.class - } : {}) -} -resource "kubectl_manifest" "pvc" { - ignore_fields = ["spec.resources.requests.storage"] - yaml_body = <<-EOF - apiVersion: v1 - kind: PersistentVolumeClaim - metadata: - name: ${local.app_slug} - namespace: "${var.namespace}" - annotations: - k8up.io/backup: "${var.backup}" - resize.kubesphere.io/storage_limit: "${var.storage.max_size} - labels: ${jsonencode(local.pvc_labels)} - spec: ${jsonencode(local.pvc_spec)} - EOF -} + storage_class_name = var.storage.class + } + lifecycle { + ignore_changes = [ + spec[0].resources[0].requests[0], + spec[0].storage_class_name, + ] + } +} \ No newline at end of file diff --git a/pvc/variables.tf b/pvc/variables.tf index 08492d4..aa8cf73 100644 --- a/pvc/variables.tf +++ b/pvc/variables.tf @@ -12,19 +12,12 @@ variable "labels" { } variable "storage" { type = object({ - access_mode = optional(string), - class = optional(string), - size = optional(string), - max_size = optional(string), - type = optional(string) + access_mode = optional(string, "ReadWriteOnce"), + class = optional(string, ""), + size = optional(string, "2Gi"), + max_size = optional(string, "10Gi"), + type = optional(string, "Filesystem") }) - default = { - "access_mode" = "ReadWriteOnce" - "class" = "" - "size" = "2Gi" - "max_size" = "10Gi" - "type" = "Filesystem" - } } variable "backup" { diff --git a/redis/outputs.tf b/redis/outputs.tf index 6595f1a..fd67d35 100644 --- a/redis/outputs.tf +++ b/redis/outputs.tf @@ -1,5 +1,5 @@ output "conn_string" { - value = "redis://${local.app_slug}-redis.${var.namespace}.svc:6379" + value = "tcp://${local.app_slug}-redis.${var.namespace}.svc:6379" } output "service" {