refactor(structure): reorganize monorepo with projects, terraform hierarchy, and strict k8s namespace rules
This commit is contained in:
@@ -0,0 +1,2 @@
|
||||
.terraform
|
||||
|
||||
+104
@@ -0,0 +1,104 @@
|
||||
# This file is maintained automatically by "terraform init".
|
||||
# Manual edits may be lost in future updates.
|
||||
|
||||
provider "registry.terraform.io/goauthentik/authentik" {
|
||||
version = "2026.5.1"
|
||||
constraints = ">= 2024.12.0"
|
||||
hashes = [
|
||||
"h1:sa790BNXc5pY8vVXyFn8Y1cHY+cRDbEiHDsr9t0NdiA=",
|
||||
"zh:05f252734db99792e5d3f52b582a4e0027348ac2614d8c9621bf7e623cff8036",
|
||||
"zh:0e1cd8041650aed9bb8d4af23301e786223ed5d1a00c2a5150b7ad874ae03917",
|
||||
"zh:26b1daebd30650df411f903248e061cf963712a063b38e731782fb13a5755ddf",
|
||||
"zh:362b536ff6bf8866c7c1094c3e2322c22b8c36d8d4caa4db0397cebbcad08561",
|
||||
"zh:3d94367b853960f5e88efe3ae69d995d02a11dc8d60ec4d7413a37aabf78b379",
|
||||
"zh:3e840e204677eabe562d17c2ad12afdfa250098725bebac4e91fb8934e233c22",
|
||||
"zh:4db66139d7a9ec6f7852538573261010d48f0a939e2fe8eeb5c55b01149e3629",
|
||||
"zh:7b88a830fb26c697f9d240f498f604485454b12e56b7604eda4ca35d10660ecd",
|
||||
"zh:851bc8bd2d4a16dc71f30da17b6285aa7d85f4bc4175fde7b8319a6a8987ec65",
|
||||
"zh:8bdfc2c70271d48126eef3b1a30d0d132e868d2118ae7277323ed4c905636e4a",
|
||||
"zh:e85c03eac43f23f25ad5443a2984cc67977c3abdcb4c4c426d37342c2f25c37e",
|
||||
"zh:efc296826a700a4e90ee06f8bd3b137617486ce774772aabed3053d4ef8dd906",
|
||||
"zh:f249033dc242c51600cd3968535efa0780352d5ae7435e8ab1482a7ccc9c2f5e",
|
||||
]
|
||||
}
|
||||
|
||||
provider "registry.terraform.io/hashicorp/google" {
|
||||
version = "5.45.2"
|
||||
constraints = "~> 5.0"
|
||||
hashes = [
|
||||
"h1:y2hf6zus1eKA5vpAfoyYkNBKDBQTVqmx4OVh3iRBaRo=",
|
||||
"zh:0d09c8f20b556305192cdbe0efa6d333ceebba963a8ba91f9f1714b5a20c4b7a",
|
||||
"zh:117143fc91be407874568df416b938a6896f94cb873f26bba279cedab646a804",
|
||||
"zh:16ccf77d18dd2c5ef9c0625f9cf546ebdf3213c0a452f432204c69feed55081e",
|
||||
"zh:3e555cf22a570a4bd247964671f421ed7517970cd9765ceb46f335edc2c6f392",
|
||||
"zh:688bd5b05a75124da7ae6e885b2b92bd29f4261808b2b78bd5f51f525c1052ca",
|
||||
"zh:6db3ef37a05010d82900bfffb3261c59a0c247e0692049cb3eb8c2ef16c9d7bf",
|
||||
"zh:70316fde75f6a15d72749f66d994ccbdde5f5ed4311b6d06b99850f698c9bbf9",
|
||||
"zh:84b8e583771a4f2bd514e519d98ed7fd28dce5efe0634e973170e1cfb5556fb4",
|
||||
"zh:9d4b8ef0a9b6677935c604d94495042e68ff5489932cfd1ec41052e094a279d3",
|
||||
"zh:a2089dd9bd825c107b148dd12d6b286f71aa37dfd4ca9c35157f2dcba7bc19d8",
|
||||
"zh:f03d795c0fd9721e59839255ee7ba7414173017dc530b4ce566daf3802a0d6dd",
|
||||
"zh:f569b65999264a9416862bca5cd2a6177d94ccb0424f3a4ef424428912b9cb3c",
|
||||
]
|
||||
}
|
||||
|
||||
provider "registry.terraform.io/hashicorp/local" {
|
||||
version = "2.9.0"
|
||||
constraints = "~> 2.0"
|
||||
hashes = [
|
||||
"h1:oF4vw1rikPMqQtMMBoUjc/pERp50DlWwO+C2I6/sNI8=",
|
||||
"zh:0baa4566cf77f1ff52f4293d1c8536202dd23edc197c3196413a28343c3ac3a0",
|
||||
"zh:16b5559c3c07088ddad11a9bb9e9c0799999363c2958e9a5be2bcbbf2cd9ca64",
|
||||
"zh:197c79015a10d1cce904a8ea722cbc750c42aeae2da53f44a6a0751d9fd1aa90",
|
||||
"zh:29d0b03e5343a80677ebfeb2e2c31cbe4b1f65e736e53417454a4277fec2544c",
|
||||
"zh:4896bfa6cf1d2fd562b47ef2e87f47862ae92a04f8ad5d764380f0c6653473b8",
|
||||
"zh:531f8529cbca49f681883e57761a05a8398afaef6d1ab0d205d26bf12f4428e8",
|
||||
"zh:6aaf5011d83161c86d2bfb80c0923ec934e578288758da2f37acb7aec129004b",
|
||||
"zh:7430275253d3d3c40aa6179e0ec0d63212874dbbc06c5a51b9d07ec590f9756c",
|
||||
"zh:78d5eefdd9e494defcb3c68d282b8f96630502cac21d1ea161f53cfe9bb483b3",
|
||||
"zh:be17dc611e95e26cdf6cad79dfccf1064f0e32032a2efeb939a9bbe7fb1cbfe9",
|
||||
"zh:f0e3b0aa644202e1d79d2000dca91f6019425da71e9800fa23f27e51c034f195",
|
||||
"zh:f62bae4519e4ead49182ddc8afe8cf61e2a4c3ba3973b0fbba967736a2696aa3",
|
||||
"zh:fcafa360a5b0b96244f26f4e3a6d642b716a376557142c2442ff2fb12d11da18",
|
||||
]
|
||||
}
|
||||
|
||||
provider "registry.terraform.io/hashicorp/random" {
|
||||
version = "3.9.0"
|
||||
hashes = [
|
||||
"h1:o0s5Mk9NXMP60nlheO1r0LsDGGratFb3oL0t7bD2QnM=",
|
||||
"zh:161ad0bd9a75768c82f53fb6e7172a9d8be2d4889b012645a34795031aaf1bf1",
|
||||
"zh:19dc9a5b17729725ccfc4f45b0500af0ee5bc6b6b160c7adb8f2bf617d2c80ea",
|
||||
"zh:269eda8fe42daa7974d5a34d166c3ba9defe80cde86c01e4dadcfdf2e1f05e5f",
|
||||
"zh:373f7c65566f8f2cc7f45d698654feb9d988996957e1266a69ca00c52d6d16d0",
|
||||
"zh:5599d16804c41c83009ec621b6d6b6f74e102f5827678a4750f8809055546b61",
|
||||
"zh:583be0440469a22bff70dcfa56593b01566860b29607437264adb51060cf46fc",
|
||||
"zh:5f211d8ec3f2e1f414870d9584bfe26e6995560ef81c748f8447a48164767398",
|
||||
"zh:78d5eefdd9e494defcb3c68d282b8f96630502cac21d1ea161f53cfe9bb483b3",
|
||||
"zh:7b547fd16216761ef86efc3ed516ac5ac0c5c42b7c7eb24a08cef2d93f69ed5e",
|
||||
"zh:7e7c0679daf2a382151d05068c8c3f0dae6b7b7dccf818827b73dd08638df2ef",
|
||||
"zh:8089dec888a8038b9b4fb23b3df7e1057293dbc5b60b42cc47ff690d69d4b61b",
|
||||
"zh:c51f15a031edfd6f23ce8ced3446ca7f8d8d647e2499890d7d5d10d5016d7257",
|
||||
"zh:c94784f005708890dc6895afd53636ec00ec1e430b15d41e5aebfb1d4b39bd04",
|
||||
]
|
||||
}
|
||||
|
||||
provider "registry.terraform.io/ovh/ovh" {
|
||||
version = "2.19.0"
|
||||
hashes = [
|
||||
"h1:SUzZY0kbQQ1Z+T958n8//7u+UlItQgll3vTfxuUbdOM=",
|
||||
"zh:0ba0eec9b66d3cf3ffbb8cc753d87aebc7ddb73b975c5b2eb372ec1fcf8712fe",
|
||||
"zh:24773d4959b2fa2674760eebdda421e93a7b0e4cadf1ae135ed66d573e86b040",
|
||||
"zh:2f24103c6b132cb21f1834ee2b00ebce863118d53dc2e55b85cd5b1d154bdc46",
|
||||
"zh:3a7492ea842566601323b6ff4ee45a6ced7eb7c08ed888608acc3bc8e490c22a",
|
||||
"zh:5018841095e9677fc8e5abcdd8336b5ad20086426cc22be35fb657b3cd8c7b9d",
|
||||
"zh:62ea15a24fb26a79586c14eed2d1b8dfbdb5195288620dcd36d9c71a55b5860c",
|
||||
"zh:6847b431185ddf4e7349d2397ac9cb1659ad129b01ec1661df2cac60b031e6c4",
|
||||
"zh:7cdc7f403f10b405ef5e9a10094ce11685d2a739058e5c21c7db268dcf3c8fd8",
|
||||
"zh:9d9ae5b6afe707487230c46930a805b0bcfc4c95cb779c4dd956695dd67a7a84",
|
||||
"zh:bcc1bfd1df2546aff09726885703713dc9579f73240395cb9890140165f45d1c",
|
||||
"zh:c02e93bdd854b5814089d88c2ecf76fc22b83dda1c4785aea6765c1b72ac9897",
|
||||
"zh:e26191ff7f5ae7750d129136c0e6f13a54167fe332dc6c5f3f3ceab17c27c4df",
|
||||
"zh:f0de0de40649efc805e63fbe405055ed4c0f8149b0d530bb63d079b62f692de1",
|
||||
]
|
||||
}
|
||||
Binary file not shown.
@@ -0,0 +1,819 @@
|
||||
# --- Authentik Terraform Configuration ---
|
||||
|
||||
variable "authentik_url" {
|
||||
description = "Base URL of the Authentik instance"
|
||||
type = string
|
||||
default = "https://auth.haumdaucher.de"
|
||||
}
|
||||
|
||||
variable "authentik_token" {
|
||||
description = "Authentik API Token (create via Directory > Tokens & App passwords)"
|
||||
type = string
|
||||
sensitive = true
|
||||
default = null
|
||||
}
|
||||
|
||||
provider "authentik" {
|
||||
url = var.authentik_url
|
||||
token = var.authentik_token
|
||||
}
|
||||
|
||||
# --- Branding: Haumdaucher Custom Theme & Assets ---
|
||||
|
||||
resource "authentik_brand" "haumdaucher" {
|
||||
domain = "auth.haumdaucher.de"
|
||||
default = true
|
||||
branding_title = "HAUMDAUCHER"
|
||||
branding_logo = "https://haumdaucher.de/images/logo_classic.png"
|
||||
branding_favicon = "https://haumdaucher.de/icon-192.png"
|
||||
branding_custom_css = file("${path.module}/haumdaucher-theme.css")
|
||||
}
|
||||
|
||||
# --- Directory: User Groups ---
|
||||
|
||||
resource "authentik_group" "infra_admins" {
|
||||
name = "infra-admins"
|
||||
is_superuser = false
|
||||
}
|
||||
|
||||
resource "authentik_group" "users" {
|
||||
name = "users"
|
||||
is_superuser = false
|
||||
}
|
||||
|
||||
resource "authentik_group" "verein_mitglieder" {
|
||||
name = "verein-mitglieder"
|
||||
is_superuser = false
|
||||
}
|
||||
|
||||
data "authentik_user" "amy" {
|
||||
username = "Amy"
|
||||
}
|
||||
|
||||
resource "authentik_group" "family" {
|
||||
name = "family"
|
||||
is_superuser = false
|
||||
users = [data.authentik_user.amy.pk]
|
||||
}
|
||||
|
||||
|
||||
# --- Flows: Authorization, Invalidation & Custom Invitation Flow ---
|
||||
|
||||
data "authentik_flow" "default_authorization_flow" {
|
||||
slug = "default-provider-authorization-implicit-consent"
|
||||
}
|
||||
|
||||
data "authentik_flow" "default_invalidation_flow" {
|
||||
slug = "default-invalidation-flow"
|
||||
}
|
||||
|
||||
# 1. Prompt Fields for Member Onboarding
|
||||
resource "authentik_stage_prompt_field" "haumdaucher_enrollment_username" {
|
||||
name = "haumdaucher-enrollment-username"
|
||||
field_key = "username"
|
||||
label = "Benutzername"
|
||||
type = "username"
|
||||
required = true
|
||||
order = 10
|
||||
}
|
||||
|
||||
resource "authentik_stage_prompt_field" "haumdaucher_enrollment_email" {
|
||||
name = "haumdaucher-enrollment-email"
|
||||
field_key = "email"
|
||||
label = "E-Mail-Adresse"
|
||||
type = "email"
|
||||
required = true
|
||||
order = 15
|
||||
}
|
||||
|
||||
resource "authentik_stage_prompt_field" "haumdaucher_enrollment_name" {
|
||||
name = "haumdaucher-enrollment-name"
|
||||
field_key = "name"
|
||||
label = "Vollständiger Name"
|
||||
type = "text"
|
||||
required = true
|
||||
order = 20
|
||||
}
|
||||
|
||||
resource "authentik_stage_prompt_field" "haumdaucher_enrollment_password" {
|
||||
name = "haumdaucher-enrollment-password"
|
||||
field_key = "password"
|
||||
label = "Passwort"
|
||||
type = "password"
|
||||
required = true
|
||||
order = 30
|
||||
}
|
||||
|
||||
resource "authentik_stage_prompt_field" "haumdaucher_enrollment_password_repeat" {
|
||||
name = "haumdaucher-enrollment-password-repeat"
|
||||
field_key = "password_repeat"
|
||||
label = "Passwort wiederholen"
|
||||
type = "password"
|
||||
required = true
|
||||
order = 40
|
||||
}
|
||||
|
||||
# 2. Prompt Stage
|
||||
resource "authentik_stage_prompt" "haumdaucher_enrollment_prompt" {
|
||||
name = "haumdaucher-enrollment-prompt"
|
||||
fields = [
|
||||
authentik_stage_prompt_field.haumdaucher_enrollment_username.id,
|
||||
authentik_stage_prompt_field.haumdaucher_enrollment_email.id,
|
||||
authentik_stage_prompt_field.haumdaucher_enrollment_name.id,
|
||||
authentik_stage_prompt_field.haumdaucher_enrollment_password.id,
|
||||
authentik_stage_prompt_field.haumdaucher_enrollment_password_repeat.id,
|
||||
]
|
||||
}
|
||||
|
||||
# 3. Invitation Stage (gates the flow so only valid ?itoken=... can register)
|
||||
resource "authentik_stage_invitation" "haumdaucher_enrollment_invitation" {
|
||||
name = "haumdaucher-enrollment-invitation"
|
||||
continue_flow_without_invitation = false
|
||||
}
|
||||
|
||||
# 4. User Write Stage (creates user in database and assigns default 'users' group)
|
||||
resource "authentik_stage_user_write" "haumdaucher_enrollment_write" {
|
||||
name = "haumdaucher-enrollment-write"
|
||||
create_users_as_inactive = false
|
||||
create_users_group = authentik_group.users.id
|
||||
}
|
||||
|
||||
# 5. User Login Stage (starts the user session)
|
||||
resource "authentik_stage_user_login" "haumdaucher_enrollment_login" {
|
||||
name = "haumdaucher-enrollment-login"
|
||||
session_duration = "days=30"
|
||||
}
|
||||
|
||||
# Master Flow: Default User Login Stage (30-day persistent browser session)
|
||||
import {
|
||||
to = authentik_stage_user_login.default_authentication_login
|
||||
id = "49749dd0-3c0d-41e2-9f10-e6c66d719901"
|
||||
}
|
||||
|
||||
resource "authentik_stage_user_login" "default_authentication_login" {
|
||||
name = "default-authentication-login"
|
||||
session_duration = "days=30"
|
||||
}
|
||||
|
||||
import {
|
||||
to = authentik_stage_user_login.default_source_authentication_login
|
||||
id = "7ff5a23d-6f78-4539-b40f-d7fb24af0ae7"
|
||||
}
|
||||
|
||||
resource "authentik_stage_user_login" "default_source_authentication_login" {
|
||||
name = "default-source-authentication-login"
|
||||
session_duration = "days=30"
|
||||
}
|
||||
|
||||
# 6. Redirect Stage (redirects user to haumdaucher.de after successful registration)
|
||||
resource "authentik_stage_redirect" "haumdaucher_enrollment_redirect" {
|
||||
name = "haumdaucher-enrollment-redirect"
|
||||
mode = "static"
|
||||
target_static = "https://haumdaucher.de"
|
||||
}
|
||||
|
||||
# 7. Flow Definition
|
||||
resource "authentik_flow" "haumdaucher_invitation_flow" {
|
||||
name = "Haumdaucher Invitation Flow"
|
||||
slug = "haumdaucher-invitation-flow"
|
||||
title = "Haumdaucher Registrierung"
|
||||
designation = "enrollment"
|
||||
}
|
||||
|
||||
# 8. Flow Stage Bindings (Execution Order)
|
||||
resource "authentik_flow_stage_binding" "bind_haumdaucher_invitation" {
|
||||
target = authentik_flow.haumdaucher_invitation_flow.uuid
|
||||
stage = authentik_stage_invitation.haumdaucher_enrollment_invitation.id
|
||||
order = 10
|
||||
}
|
||||
|
||||
resource "authentik_flow_stage_binding" "bind_haumdaucher_prompt" {
|
||||
target = authentik_flow.haumdaucher_invitation_flow.uuid
|
||||
stage = authentik_stage_prompt.haumdaucher_enrollment_prompt.id
|
||||
order = 20
|
||||
}
|
||||
|
||||
resource "authentik_flow_stage_binding" "bind_haumdaucher_write" {
|
||||
target = authentik_flow.haumdaucher_invitation_flow.uuid
|
||||
stage = authentik_stage_user_write.haumdaucher_enrollment_write.id
|
||||
order = 30
|
||||
}
|
||||
|
||||
resource "authentik_flow_stage_binding" "bind_haumdaucher_login" {
|
||||
target = authentik_flow.haumdaucher_invitation_flow.uuid
|
||||
stage = authentik_stage_user_login.haumdaucher_enrollment_login.id
|
||||
order = 40
|
||||
}
|
||||
|
||||
resource "authentik_flow_stage_binding" "bind_haumdaucher_redirect" {
|
||||
target = authentik_flow.haumdaucher_invitation_flow.uuid
|
||||
stage = authentik_stage_redirect.haumdaucher_enrollment_redirect.id
|
||||
order = 50
|
||||
}
|
||||
|
||||
# --- ForwardAuth Proxy Providers & Applications ---
|
||||
|
||||
# 1. Zigbee2MQTT
|
||||
resource "authentik_provider_proxy" "zigbee2mqtt" {
|
||||
name = "Zigbee2MQTT"
|
||||
external_host = "https://zigbee2mqtt.moritzgraf.de"
|
||||
mode = "forward_single"
|
||||
authorization_flow = data.authentik_flow.default_authorization_flow.id
|
||||
invalidation_flow = data.authentik_flow.default_invalidation_flow.id
|
||||
intercept_header_auth = true
|
||||
}
|
||||
|
||||
resource "authentik_application" "zigbee2mqtt" {
|
||||
name = "Zigbee2MQTT"
|
||||
slug = "zigbee2mqtt"
|
||||
protocol_provider = authentik_provider_proxy.zigbee2mqtt.id
|
||||
}
|
||||
|
||||
# 2. Prometheus
|
||||
resource "authentik_provider_proxy" "prometheus" {
|
||||
name = "Prometheus"
|
||||
external_host = "https://prometheus.haumdaucher.de"
|
||||
mode = "forward_single"
|
||||
authorization_flow = data.authentik_flow.default_authorization_flow.id
|
||||
invalidation_flow = data.authentik_flow.default_invalidation_flow.id
|
||||
intercept_header_auth = true
|
||||
}
|
||||
|
||||
resource "authentik_application" "prometheus" {
|
||||
name = "Prometheus"
|
||||
slug = "prometheus"
|
||||
protocol_provider = authentik_provider_proxy.prometheus.id
|
||||
}
|
||||
|
||||
# 3. Alertmanager
|
||||
resource "authentik_provider_proxy" "alertmanager" {
|
||||
name = "Alertmanager"
|
||||
external_host = "https://alertmanager.haumdaucher.de"
|
||||
mode = "forward_single"
|
||||
authorization_flow = data.authentik_flow.default_authorization_flow.id
|
||||
invalidation_flow = data.authentik_flow.default_invalidation_flow.id
|
||||
intercept_header_auth = true
|
||||
}
|
||||
|
||||
resource "authentik_application" "alertmanager" {
|
||||
name = "Alertmanager"
|
||||
slug = "alertmanager"
|
||||
protocol_provider = authentik_provider_proxy.alertmanager.id
|
||||
}
|
||||
|
||||
# 4. Nextcloud phpMyAdmin
|
||||
resource "authentik_provider_proxy" "nextcloud_phpmyadmin" {
|
||||
name = "Nextcloud phpMyAdmin"
|
||||
external_host = "https://nextcloud.phpmyadmin.haumdaucher.de"
|
||||
mode = "forward_single"
|
||||
authorization_flow = data.authentik_flow.default_authorization_flow.id
|
||||
invalidation_flow = data.authentik_flow.default_invalidation_flow.id
|
||||
intercept_header_auth = true
|
||||
}
|
||||
|
||||
resource "authentik_application" "nextcloud_phpmyadmin" {
|
||||
name = "Nextcloud phpMyAdmin"
|
||||
slug = "nextcloud-phpmyadmin"
|
||||
protocol_provider = authentik_provider_proxy.nextcloud_phpmyadmin.id
|
||||
}
|
||||
|
||||
# 5. Gitea phpMyAdmin
|
||||
resource "authentik_provider_proxy" "gitea_phpmyadmin" {
|
||||
name = "Gitea phpMyAdmin"
|
||||
external_host = "https://gitea.phpmyadmin.haumdaucher.de"
|
||||
mode = "forward_single"
|
||||
authorization_flow = data.authentik_flow.default_authorization_flow.id
|
||||
invalidation_flow = data.authentik_flow.default_invalidation_flow.id
|
||||
intercept_header_auth = true
|
||||
}
|
||||
|
||||
resource "authentik_application" "gitea_phpmyadmin" {
|
||||
name = "Gitea phpMyAdmin"
|
||||
slug = "gitea-phpmyadmin"
|
||||
protocol_provider = authentik_provider_proxy.gitea_phpmyadmin.id
|
||||
}
|
||||
|
||||
# 6. Home Assistant VS Code
|
||||
resource "authentik_provider_proxy" "hass_coder" {
|
||||
name = "Home Assistant Code"
|
||||
external_host = "https://hass-coder.moritzgraf.de"
|
||||
mode = "forward_single"
|
||||
authorization_flow = data.authentik_flow.default_authorization_flow.id
|
||||
invalidation_flow = data.authentik_flow.default_invalidation_flow.id
|
||||
intercept_header_auth = true
|
||||
}
|
||||
|
||||
resource "authentik_application" "hass_coder" {
|
||||
name = "Home Assistant Code"
|
||||
slug = "hass-coder"
|
||||
protocol_provider = authentik_provider_proxy.hass_coder.id
|
||||
}
|
||||
|
||||
# 7. OpenClaw
|
||||
resource "authentik_provider_proxy" "openclaw" {
|
||||
name = "OpenClaw"
|
||||
external_host = "https://openclaw.haumdaucher.de"
|
||||
mode = "forward_single"
|
||||
authorization_flow = data.authentik_flow.default_authorization_flow.id
|
||||
invalidation_flow = data.authentik_flow.default_invalidation_flow.id
|
||||
intercept_header_auth = true
|
||||
}
|
||||
|
||||
resource "authentik_application" "openclaw" {
|
||||
name = "OpenClaw"
|
||||
slug = "openclaw"
|
||||
protocol_provider = authentik_provider_proxy.openclaw.id
|
||||
}
|
||||
|
||||
# 8. n8n
|
||||
resource "authentik_provider_proxy" "n8n" {
|
||||
name = "n8n"
|
||||
external_host = "https://n8n.moritzgraf.de"
|
||||
mode = "forward_single"
|
||||
authorization_flow = data.authentik_flow.default_authorization_flow.id
|
||||
invalidation_flow = data.authentik_flow.default_invalidation_flow.id
|
||||
intercept_header_auth = true
|
||||
}
|
||||
|
||||
resource "authentik_application" "n8n" {
|
||||
name = "n8n"
|
||||
slug = "n8n"
|
||||
protocol_provider = authentik_provider_proxy.n8n.id
|
||||
}
|
||||
|
||||
# 9. SilverBullet Wiki
|
||||
resource "authentik_provider_proxy" "silverbullet" {
|
||||
name = "SilverBullet"
|
||||
external_host = "https://wiki.moritzgraf.de"
|
||||
mode = "forward_single"
|
||||
authorization_flow = data.authentik_flow.default_authorization_flow.id
|
||||
invalidation_flow = data.authentik_flow.default_invalidation_flow.id
|
||||
intercept_header_auth = true
|
||||
skip_path_regex = "^/service_worker\\.js$|^/\\.client/.*|^/manifest\\.json$"
|
||||
access_token_validity = "days=7"
|
||||
}
|
||||
|
||||
resource "authentik_application" "silverbullet" {
|
||||
name = "SilverBullet"
|
||||
slug = "silverbullet"
|
||||
protocol_provider = authentik_provider_proxy.silverbullet.id
|
||||
}
|
||||
|
||||
# 10. Hosting Family Dashboards
|
||||
resource "authentik_provider_proxy" "hosting_family" {
|
||||
name = "Hosting Family"
|
||||
external_host = "https://hosting.haumdaucher.de"
|
||||
mode = "forward_single"
|
||||
authorization_flow = data.authentik_flow.default_authorization_flow.id
|
||||
invalidation_flow = data.authentik_flow.default_invalidation_flow.id
|
||||
intercept_header_auth = true
|
||||
access_token_validity = "days=30"
|
||||
}
|
||||
|
||||
resource "authentik_application" "hosting_family" {
|
||||
name = "Hosting Family"
|
||||
slug = "hosting-family"
|
||||
protocol_provider = authentik_provider_proxy.hosting_family.id
|
||||
}
|
||||
|
||||
# --- Outpost: Embedded Proxy Outpost ---
|
||||
|
||||
resource "authentik_outpost" "embedded" {
|
||||
name = "authentik Embedded Outpost"
|
||||
type = "proxy"
|
||||
protocol_providers = [
|
||||
authentik_provider_proxy.zigbee2mqtt.id,
|
||||
authentik_provider_proxy.prometheus.id,
|
||||
authentik_provider_proxy.alertmanager.id,
|
||||
authentik_provider_proxy.nextcloud_phpmyadmin.id,
|
||||
authentik_provider_proxy.gitea_phpmyadmin.id,
|
||||
authentik_provider_proxy.hass_coder.id,
|
||||
authentik_provider_proxy.openclaw.id,
|
||||
authentik_provider_proxy.n8n.id,
|
||||
authentik_provider_proxy.silverbullet.id,
|
||||
authentik_provider_proxy.hosting_family.id,
|
||||
]
|
||||
}
|
||||
|
||||
# --- Machine & AI Assistant: Service Account & API Token ---
|
||||
|
||||
resource "authentik_user" "ai_assistant" {
|
||||
username = "ai-assistant"
|
||||
name = "AI Assistant"
|
||||
type = "service_account"
|
||||
groups = [authentik_group.infra_admins.id]
|
||||
}
|
||||
|
||||
resource "authentik_token" "ai_assistant_token" {
|
||||
identifier = "ai-assistant-api-token"
|
||||
user = authentik_user.ai_assistant.id
|
||||
intent = "api"
|
||||
expiring = false
|
||||
retrieve_key = true
|
||||
}
|
||||
|
||||
# --- Native OIDC Providers & Applications ---
|
||||
|
||||
# Scope Mappings
|
||||
data "authentik_property_mapping_provider_scope" "openid" {
|
||||
scope_name = "openid"
|
||||
}
|
||||
|
||||
data "authentik_property_mapping_provider_scope" "email" {
|
||||
scope_name = "email"
|
||||
}
|
||||
|
||||
data "authentik_property_mapping_provider_scope" "profile" {
|
||||
scope_name = "profile"
|
||||
}
|
||||
|
||||
data "authentik_certificate_key_pair" "generated" {
|
||||
name = "authentik Self-signed Certificate"
|
||||
}
|
||||
|
||||
# 1. Gitea
|
||||
resource "random_password" "gitea_oauth_client_secret" {
|
||||
length = 40
|
||||
special = false
|
||||
}
|
||||
|
||||
resource "authentik_provider_oauth2" "gitea" {
|
||||
name = "Gitea"
|
||||
client_id = "gitea"
|
||||
client_secret = random_password.gitea_oauth_client_secret.result
|
||||
client_type = "confidential"
|
||||
authorization_flow = data.authentik_flow.default_authorization_flow.id
|
||||
invalidation_flow = data.authentik_flow.default_invalidation_flow.id
|
||||
signing_key = data.authentik_certificate_key_pair.generated.id
|
||||
grant_types = ["authorization_code", "refresh_token"]
|
||||
allowed_redirect_uris = [
|
||||
{
|
||||
matching_mode = "strict"
|
||||
url = "https://git.moritzgraf.de/user/oauth2/authentik/callback"
|
||||
},
|
||||
{
|
||||
matching_mode = "strict"
|
||||
url = "https://git.moritzgraf.de/user/oauth2/Authentik/callback"
|
||||
}
|
||||
]
|
||||
sub_mode = "user_username"
|
||||
include_claims_in_id_token = true
|
||||
property_mappings = [
|
||||
data.authentik_property_mapping_provider_scope.openid.id,
|
||||
data.authentik_property_mapping_provider_scope.email.id,
|
||||
data.authentik_property_mapping_provider_scope.profile.id,
|
||||
]
|
||||
}
|
||||
|
||||
resource "authentik_application" "gitea" {
|
||||
name = "Gitea"
|
||||
slug = "gitea"
|
||||
protocol_provider = authentik_provider_oauth2.gitea.id
|
||||
}
|
||||
|
||||
output "gitea_oauth_client_secret" {
|
||||
description = "OAuth2 Client Secret for Gitea OIDC provider"
|
||||
value = random_password.gitea_oauth_client_secret.result
|
||||
sensitive = true
|
||||
}
|
||||
|
||||
# 2. Grafana
|
||||
resource "random_password" "grafana_oauth_client_secret" {
|
||||
length = 40
|
||||
special = false
|
||||
}
|
||||
|
||||
resource "authentik_provider_oauth2" "grafana" {
|
||||
name = "Grafana"
|
||||
client_id = "grafana"
|
||||
client_secret = random_password.grafana_oauth_client_secret.result
|
||||
client_type = "confidential"
|
||||
authorization_flow = data.authentik_flow.default_authorization_flow.id
|
||||
invalidation_flow = data.authentik_flow.default_invalidation_flow.id
|
||||
signing_key = data.authentik_certificate_key_pair.generated.id
|
||||
grant_types = ["authorization_code", "refresh_token"]
|
||||
allowed_redirect_uris = [
|
||||
{
|
||||
matching_mode = "strict"
|
||||
url = "https://grafana.haumdaucher.de/login/generic_oauth"
|
||||
}
|
||||
]
|
||||
sub_mode = "user_username"
|
||||
include_claims_in_id_token = true
|
||||
property_mappings = [
|
||||
data.authentik_property_mapping_provider_scope.openid.id,
|
||||
data.authentik_property_mapping_provider_scope.email.id,
|
||||
data.authentik_property_mapping_provider_scope.profile.id,
|
||||
]
|
||||
}
|
||||
|
||||
resource "authentik_application" "grafana" {
|
||||
name = "Grafana"
|
||||
slug = "grafana"
|
||||
protocol_provider = authentik_provider_oauth2.grafana.id
|
||||
}
|
||||
|
||||
output "grafana_oauth_client_secret" {
|
||||
description = "OAuth2 Client Secret for Grafana OIDC provider"
|
||||
value = random_password.grafana_oauth_client_secret.result
|
||||
sensitive = true
|
||||
}
|
||||
|
||||
# 3. Coder v2
|
||||
resource "random_password" "coder_oauth_client_secret" {
|
||||
length = 40
|
||||
special = false
|
||||
}
|
||||
|
||||
resource "authentik_provider_oauth2" "coder" {
|
||||
name = "Coder"
|
||||
client_id = "coder"
|
||||
client_secret = random_password.coder_oauth_client_secret.result
|
||||
client_type = "confidential"
|
||||
authorization_flow = data.authentik_flow.default_authorization_flow.id
|
||||
invalidation_flow = data.authentik_flow.default_invalidation_flow.id
|
||||
signing_key = data.authentik_certificate_key_pair.generated.id
|
||||
grant_types = ["authorization_code", "refresh_token"]
|
||||
allowed_redirect_uris = [
|
||||
{
|
||||
matching_mode = "strict"
|
||||
url = "https://coder.moritzgraf.de/api/v2/users/oidc/callback"
|
||||
}
|
||||
]
|
||||
sub_mode = "user_username"
|
||||
include_claims_in_id_token = true
|
||||
property_mappings = [
|
||||
data.authentik_property_mapping_provider_scope.openid.id,
|
||||
data.authentik_property_mapping_provider_scope.email.id,
|
||||
data.authentik_property_mapping_provider_scope.profile.id,
|
||||
]
|
||||
}
|
||||
|
||||
resource "authentik_application" "coder" {
|
||||
name = "Coder"
|
||||
slug = "coder"
|
||||
protocol_provider = authentik_provider_oauth2.coder.id
|
||||
}
|
||||
|
||||
output "coder_oauth_client_secret" {
|
||||
description = "OAuth2 Client Secret for Coder OIDC provider"
|
||||
value = random_password.coder_oauth_client_secret.result
|
||||
sensitive = true
|
||||
}
|
||||
|
||||
# 4. MinIO Console
|
||||
resource "authentik_property_mapping_provider_scope" "minio_policy" {
|
||||
name = "minio-policy"
|
||||
scope_name = "policy"
|
||||
expression = <<EOF
|
||||
if "infra-admins" in [group.name for group in request.user.groups.all()]:
|
||||
return {"policy": "consoleAdmin"}
|
||||
return {"policy": "readonly"}
|
||||
EOF
|
||||
}
|
||||
|
||||
resource "random_password" "minio_oauth_client_secret" {
|
||||
length = 40
|
||||
special = false
|
||||
}
|
||||
|
||||
resource "authentik_provider_oauth2" "minio" {
|
||||
name = "MinIO"
|
||||
client_id = "minio"
|
||||
client_secret = random_password.minio_oauth_client_secret.result
|
||||
client_type = "confidential"
|
||||
authorization_flow = data.authentik_flow.default_authorization_flow.id
|
||||
invalidation_flow = data.authentik_flow.default_invalidation_flow.id
|
||||
signing_key = data.authentik_certificate_key_pair.generated.id
|
||||
grant_types = ["authorization_code", "refresh_token"]
|
||||
allowed_redirect_uris = [
|
||||
{
|
||||
matching_mode = "strict"
|
||||
url = "https://minio-console.haumdaucher.de/oauth_callback"
|
||||
}
|
||||
]
|
||||
sub_mode = "user_username"
|
||||
include_claims_in_id_token = true
|
||||
property_mappings = [
|
||||
data.authentik_property_mapping_provider_scope.openid.id,
|
||||
data.authentik_property_mapping_provider_scope.email.id,
|
||||
data.authentik_property_mapping_provider_scope.profile.id,
|
||||
authentik_property_mapping_provider_scope.minio_policy.id,
|
||||
]
|
||||
}
|
||||
|
||||
resource "authentik_application" "minio" {
|
||||
name = "MinIO"
|
||||
slug = "minio"
|
||||
protocol_provider = authentik_provider_oauth2.minio.id
|
||||
}
|
||||
|
||||
output "minio_oauth_client_secret" {
|
||||
description = "OAuth2 Client Secret for MinIO OIDC provider"
|
||||
value = random_password.minio_oauth_client_secret.result
|
||||
sensitive = true
|
||||
}
|
||||
|
||||
# 5. Nextcloud
|
||||
resource "random_password" "nextcloud_oauth_client_secret" {
|
||||
length = 40
|
||||
special = false
|
||||
}
|
||||
|
||||
resource "authentik_provider_oauth2" "nextcloud" {
|
||||
name = "Nextcloud"
|
||||
client_id = "nextcloud"
|
||||
client_secret = random_password.nextcloud_oauth_client_secret.result
|
||||
client_type = "confidential"
|
||||
authorization_flow = data.authentik_flow.default_authorization_flow.id
|
||||
invalidation_flow = data.authentik_flow.default_invalidation_flow.id
|
||||
signing_key = data.authentik_certificate_key_pair.generated.id
|
||||
grant_types = ["authorization_code", "refresh_token"]
|
||||
allowed_redirect_uris = [
|
||||
{
|
||||
matching_mode = "strict"
|
||||
url = "https://cloud.haumdaucher.de/apps/user_oidc/code"
|
||||
}
|
||||
]
|
||||
sub_mode = "user_username"
|
||||
include_claims_in_id_token = true
|
||||
property_mappings = [
|
||||
data.authentik_property_mapping_provider_scope.openid.id,
|
||||
data.authentik_property_mapping_provider_scope.email.id,
|
||||
data.authentik_property_mapping_provider_scope.profile.id,
|
||||
]
|
||||
}
|
||||
|
||||
resource "authentik_application" "nextcloud" {
|
||||
name = "Nextcloud"
|
||||
slug = "nextcloud"
|
||||
protocol_provider = authentik_provider_oauth2.nextcloud.id
|
||||
}
|
||||
|
||||
output "nextcloud_oauth_client_secret" {
|
||||
description = "OAuth2 Client Secret for Nextcloud OIDC provider"
|
||||
value = random_password.nextcloud_oauth_client_secret.result
|
||||
sensitive = true
|
||||
}
|
||||
|
||||
# 6. Home Assistant
|
||||
resource "random_password" "homeassistant_oauth_client_secret" {
|
||||
length = 40
|
||||
special = false
|
||||
}
|
||||
|
||||
resource "authentik_provider_oauth2" "homeassistant" {
|
||||
name = "Home Assistant"
|
||||
client_id = "homeassistant"
|
||||
client_secret = random_password.homeassistant_oauth_client_secret.result
|
||||
client_type = "confidential"
|
||||
authorization_flow = data.authentik_flow.default_authorization_flow.id
|
||||
invalidation_flow = data.authentik_flow.default_invalidation_flow.id
|
||||
signing_key = data.authentik_certificate_key_pair.generated.id
|
||||
grant_types = ["authorization_code", "refresh_token"]
|
||||
allowed_redirect_uris = [
|
||||
{
|
||||
matching_mode = "strict"
|
||||
url = "https://hass.moritzgraf.de/auth/oidc/callback"
|
||||
},
|
||||
{
|
||||
matching_mode = "strict"
|
||||
url = "https://hass.moritzgraf.de/auth/external/callback"
|
||||
}
|
||||
]
|
||||
sub_mode = "user_username"
|
||||
include_claims_in_id_token = true
|
||||
property_mappings = [
|
||||
data.authentik_property_mapping_provider_scope.openid.id,
|
||||
data.authentik_property_mapping_provider_scope.email.id,
|
||||
data.authentik_property_mapping_provider_scope.profile.id,
|
||||
]
|
||||
}
|
||||
|
||||
resource "authentik_application" "homeassistant" {
|
||||
name = "Home Assistant"
|
||||
slug = "homeassistant"
|
||||
protocol_provider = authentik_provider_oauth2.homeassistant.id
|
||||
}
|
||||
|
||||
output "homeassistant_oauth_client_secret" {
|
||||
description = "OAuth2 Client Secret for Home Assistant OIDC provider"
|
||||
value = random_password.homeassistant_oauth_client_secret.result
|
||||
sensitive = true
|
||||
}
|
||||
|
||||
# --- Application Policy Bindings (Access Control & RBAC) ---
|
||||
|
||||
# 1. Admin-Only Applications (Strictly restricted to infra-admins)
|
||||
resource "authentik_policy_binding" "openclaw_admin_only" {
|
||||
target = authentik_application.openclaw.uuid
|
||||
group = authentik_group.infra_admins.id
|
||||
order = 0
|
||||
}
|
||||
|
||||
resource "authentik_policy_binding" "zigbee2mqtt_admin_only" {
|
||||
target = authentik_application.zigbee2mqtt.uuid
|
||||
group = authentik_group.infra_admins.id
|
||||
order = 0
|
||||
}
|
||||
|
||||
resource "authentik_policy_binding" "prometheus_admin_only" {
|
||||
target = authentik_application.prometheus.uuid
|
||||
group = authentik_group.infra_admins.id
|
||||
order = 0
|
||||
}
|
||||
|
||||
resource "authentik_policy_binding" "alertmanager_admin_only" {
|
||||
target = authentik_application.alertmanager.uuid
|
||||
group = authentik_group.infra_admins.id
|
||||
order = 0
|
||||
}
|
||||
|
||||
resource "authentik_policy_binding" "nextcloud_phpmyadmin_admin_only" {
|
||||
target = authentik_application.nextcloud_phpmyadmin.uuid
|
||||
group = authentik_group.infra_admins.id
|
||||
order = 0
|
||||
}
|
||||
|
||||
resource "authentik_policy_binding" "gitea_phpmyadmin_admin_only" {
|
||||
target = authentik_application.gitea_phpmyadmin.uuid
|
||||
group = authentik_group.infra_admins.id
|
||||
order = 0
|
||||
}
|
||||
|
||||
resource "authentik_policy_binding" "hass_coder_admin_only" {
|
||||
target = authentik_application.hass_coder.uuid
|
||||
group = authentik_group.infra_admins.id
|
||||
order = 0
|
||||
}
|
||||
|
||||
resource "authentik_policy_binding" "n8n_admin_only" {
|
||||
target = authentik_application.n8n.uuid
|
||||
group = authentik_group.infra_admins.id
|
||||
order = 0
|
||||
}
|
||||
|
||||
resource "authentik_policy_binding" "coder_admin_only" {
|
||||
target = authentik_application.coder.uuid
|
||||
group = authentik_group.infra_admins.id
|
||||
order = 0
|
||||
}
|
||||
|
||||
resource "authentik_policy_binding" "minio_admin_only" {
|
||||
target = authentik_application.minio.uuid
|
||||
group = authentik_group.infra_admins.id
|
||||
order = 0
|
||||
}
|
||||
|
||||
resource "authentik_policy_binding" "silverbullet_admin_only" {
|
||||
target = authentik_application.silverbullet.uuid
|
||||
group = authentik_group.infra_admins.id
|
||||
order = 0
|
||||
}
|
||||
|
||||
resource "authentik_policy_binding" "silverbullet_family" {
|
||||
target = authentik_application.silverbullet.uuid
|
||||
group = authentik_group.family.id
|
||||
order = 1
|
||||
}
|
||||
|
||||
resource "authentik_policy_binding" "hosting_family_admin" {
|
||||
target = authentik_application.hosting_family.uuid
|
||||
group = authentik_group.infra_admins.id
|
||||
order = 0
|
||||
}
|
||||
|
||||
resource "authentik_policy_binding" "hosting_family_family" {
|
||||
target = authentik_application.hosting_family.uuid
|
||||
group = authentik_group.family.id
|
||||
order = 1
|
||||
}
|
||||
|
||||
|
||||
# 2. Shared & Member Applications (Accessible to all authenticated users)
|
||||
resource "authentik_policy_binding" "grafana_users" {
|
||||
target = authentik_application.grafana.uuid
|
||||
group = authentik_group.users.id
|
||||
order = 0
|
||||
}
|
||||
|
||||
resource "authentik_policy_binding" "nextcloud_users" {
|
||||
target = authentik_application.nextcloud.uuid
|
||||
group = authentik_group.users.id
|
||||
order = 0
|
||||
}
|
||||
|
||||
resource "authentik_policy_binding" "gitea_users" {
|
||||
target = authentik_application.gitea.uuid
|
||||
group = authentik_group.users.id
|
||||
order = 0
|
||||
}
|
||||
|
||||
resource "authentik_policy_binding" "homeassistant_users" {
|
||||
target = authentik_application.homeassistant.uuid
|
||||
group = authentik_group.users.id
|
||||
order = 0
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,109 @@
|
||||
locals {
|
||||
openclaw_project_id = "octobot-486812"
|
||||
}
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# 1. API Services Enablement
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
resource "google_project_service" "apikeys_api" {
|
||||
project = local.openclaw_project_id
|
||||
service = "apikeys.googleapis.com"
|
||||
disable_on_destroy = false
|
||||
}
|
||||
|
||||
resource "google_project_service" "youtube_api" {
|
||||
project = local.openclaw_project_id
|
||||
service = "youtube.googleapis.com"
|
||||
disable_on_destroy = false
|
||||
}
|
||||
|
||||
resource "google_project_service" "routes_api" {
|
||||
project = local.openclaw_project_id
|
||||
service = "routes.googleapis.com"
|
||||
disable_on_destroy = false
|
||||
}
|
||||
|
||||
resource "google_project_service" "geocoding_api" {
|
||||
project = local.openclaw_project_id
|
||||
service = "geocoding-backend.googleapis.com"
|
||||
disable_on_destroy = false
|
||||
}
|
||||
|
||||
resource "google_project_service" "static_maps_api" {
|
||||
project = local.openclaw_project_id
|
||||
service = "static-maps-backend.googleapis.com"
|
||||
disable_on_destroy = false
|
||||
}
|
||||
|
||||
resource "google_project_service" "places_api" {
|
||||
project = local.openclaw_project_id
|
||||
service = "places.googleapis.com"
|
||||
disable_on_destroy = false
|
||||
}
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# 2. Dedicated API Keys
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
resource "google_apikeys_key" "openclaw_youtube_key" {
|
||||
name = "openclaw-youtube-key"
|
||||
display_name = "OpenClaw YouTube API Key"
|
||||
project = local.openclaw_project_id
|
||||
|
||||
restrictions {
|
||||
api_targets {
|
||||
service = "youtube.googleapis.com"
|
||||
}
|
||||
}
|
||||
|
||||
depends_on = [
|
||||
google_project_service.apikeys_api,
|
||||
google_project_service.youtube_api
|
||||
]
|
||||
}
|
||||
|
||||
resource "google_apikeys_key" "openclaw_google_maps_key" {
|
||||
name = "openclaw-google-maps-key"
|
||||
display_name = "OpenClaw Google Maps API Key"
|
||||
project = local.openclaw_project_id
|
||||
|
||||
restrictions {
|
||||
api_targets {
|
||||
service = "places.googleapis.com"
|
||||
}
|
||||
api_targets {
|
||||
service = "routes.googleapis.com"
|
||||
}
|
||||
api_targets {
|
||||
service = "geocoding-backend.googleapis.com"
|
||||
}
|
||||
api_targets {
|
||||
service = "static-maps-backend.googleapis.com"
|
||||
}
|
||||
}
|
||||
|
||||
depends_on = [
|
||||
google_project_service.apikeys_api,
|
||||
google_project_service.places_api,
|
||||
google_project_service.routes_api,
|
||||
google_project_service.geocoding_api,
|
||||
google_project_service.static_maps_api
|
||||
]
|
||||
}
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# 3. Outputs
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
output "openclaw_youtube_api_key" {
|
||||
value = google_apikeys_key.openclaw_youtube_key.key_string
|
||||
description = "API Key dedicated to YouTube Data API v3 for OpenClaw"
|
||||
sensitive = true
|
||||
}
|
||||
|
||||
output "openclaw_google_maps_api_key" {
|
||||
value = google_apikeys_key.openclaw_google_maps_key.key_string
|
||||
description = "API Key dedicated to Google Maps Platform for OpenClaw"
|
||||
sensitive = true
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
variable "gcp_project_id" {
|
||||
type = string
|
||||
description = "The GCP Project ID where the Service Account should be created. If empty, a new project named 'velero-backup-xxxx' will be created."
|
||||
default = ""
|
||||
}
|
||||
|
||||
resource "random_id" "project_suffix" {
|
||||
byte_length = 4
|
||||
}
|
||||
|
||||
resource "google_project" "backup_project" {
|
||||
count = var.gcp_project_id == "" ? 1 : 0
|
||||
name = "velero-backup"
|
||||
project_id = "velero-backup-${random_id.project_suffix.hex}"
|
||||
}
|
||||
|
||||
locals {
|
||||
project_id = var.gcp_project_id == "" ? google_project.backup_project[0].project_id : var.gcp_project_id
|
||||
}
|
||||
|
||||
resource "google_project_service" "drive_api" {
|
||||
project = local.project_id
|
||||
service = "drive.googleapis.com"
|
||||
disable_on_destroy = false
|
||||
}
|
||||
|
||||
resource "google_project_organization_policy" "allow_key_creation" {
|
||||
project = local.project_id
|
||||
constraint = "iam.disableServiceAccountKeyCreation"
|
||||
|
||||
boolean_policy {
|
||||
enforced = false
|
||||
}
|
||||
}
|
||||
|
||||
resource "google_service_account" "velero_backup_sa" {
|
||||
project = local.project_id
|
||||
account_id = "velero-backup-sa"
|
||||
display_name = "Velero GDrive Backup Service Account"
|
||||
depends_on = [google_project_service.drive_api]
|
||||
}
|
||||
|
||||
resource "google_service_account_key" "velero_backup_sa_key" {
|
||||
service_account_id = google_service_account.velero_backup_sa.name
|
||||
depends_on = [google_project_organization_policy.allow_key_creation]
|
||||
}
|
||||
|
||||
resource "local_file" "gdrive_sa_key_file" {
|
||||
content = base64decode(google_service_account_key.velero_backup_sa_key.private_key)
|
||||
filename = "${path.module}/../k8s/velero/gdrive_sa.json.secret"
|
||||
}
|
||||
|
||||
output "velero_backup_sa_email" {
|
||||
value = google_service_account.velero_backup_sa.email
|
||||
description = "The email address of the Google Cloud Service Account. Share your Google Drive backup folder with this email address and grant it Editor access."
|
||||
}
|
||||
|
||||
resource "google_project_service" "photos_api" {
|
||||
project = "default-api-key-project"
|
||||
service = "photoslibrary.googleapis.com"
|
||||
disable_on_destroy = false
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
locals {
|
||||
calendar_project_id = "octobot-486812"
|
||||
}
|
||||
|
||||
resource "google_project_service" "calendar_api" {
|
||||
project = local.calendar_project_id
|
||||
service = "calendar-json.googleapis.com"
|
||||
disable_on_destroy = false
|
||||
}
|
||||
|
||||
resource "google_project_organization_policy" "allow_calendar_key_creation" {
|
||||
project = local.calendar_project_id
|
||||
constraint = "iam.disableServiceAccountKeyCreation"
|
||||
|
||||
boolean_policy {
|
||||
enforced = false
|
||||
}
|
||||
}
|
||||
|
||||
resource "google_service_account" "openclaw_calendar_sa" {
|
||||
project = local.calendar_project_id
|
||||
account_id = "openclaw-calendar"
|
||||
display_name = "OpenClaw Google Calendar Service Account"
|
||||
depends_on = [google_project_service.calendar_api]
|
||||
}
|
||||
|
||||
resource "google_service_account_key" "openclaw_calendar_sa_key" {
|
||||
service_account_id = google_service_account.openclaw_calendar_sa.name
|
||||
depends_on = [google_project_organization_policy.allow_calendar_key_creation]
|
||||
}
|
||||
|
||||
resource "local_file" "openclaw_calendar_sa_key_file" {
|
||||
content = base64decode(google_service_account_key.openclaw_calendar_sa_key.private_key)
|
||||
filename = "${path.module}/../k8s/openclaw/calendar_sa.json.secret"
|
||||
}
|
||||
|
||||
output "openclaw_calendar_sa_email" {
|
||||
value = google_service_account.openclaw_calendar_sa.email
|
||||
description = "The email address of the Google Calendar Service Account. Share your Google Calendars with this email address and grant it 'Make changes to events' access."
|
||||
}
|
||||
@@ -0,0 +1,242 @@
|
||||
# haumdaucher.de
|
||||
|
||||
resource "ovh_domain_zone_record" "haumdaucher_mx_record" {
|
||||
|
||||
zone = "haumdaucher.de"
|
||||
fieldtype = "MX"
|
||||
ttl = 60
|
||||
target = "1 SMTP.GOOGLE.COM."
|
||||
}
|
||||
|
||||
resource "ovh_domain_zone_record" "spf_haumdaucher_de" {
|
||||
zone = "haumdaucher.de"
|
||||
subdomain = "" # SPF record goes on the root domain
|
||||
fieldtype = "TXT"
|
||||
ttl = 60 # Time-to-live in seconds (1 hour is standard, but 60 is ok too)
|
||||
target = "v=spf1 include:_spf.google.com ~all"
|
||||
}
|
||||
|
||||
resource "ovh_domain_zone_record" "dmarc_haumdaucher_de" {
|
||||
zone = "haumdaucher.de"
|
||||
subdomain = "_dmarc" # DMARC record always goes on the _dmarc subdomain
|
||||
fieldtype = "TXT"
|
||||
ttl = 60 # 1 hour TTL
|
||||
target = "v=DMARC1; p=none; rua=mailto:custom-admin@haumdaucher.de; ruf=mailto:custom-admin@haumdaucher.de"
|
||||
}
|
||||
|
||||
resource "ovh_domain_zone_record" "dkim_google_haumdaucher_de" {
|
||||
zone = "haumdaucher.de"
|
||||
subdomain = "google._domainkey" # The DNS Host name provided by Google
|
||||
fieldtype = "TXT"
|
||||
ttl = 3600 # 1 hour TTL
|
||||
target = "v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAq4al3nYNZLlUBn0dcxqui5q48jjk4YvB2d2VNLfr864YdCm+3WqO6fc8Yx7sO4jKiX+OpMXnOc2RZazCCpcdCofJwTZxT+H0u2h4uyveEHq8UYqQZ66aAFLt3N1HYMT6+uFJZpKpSkFgqLagkQoW/cQHguJuu7Xjmt09fLTsBunjfJkKfUcjcyNlpnnAcVuo/TT7DKNzjB436yB1pf8QHxykUkV/lfz1/IzfRV//hR3H5pSNn4kR9qT9HqrTGgaZkPmStjoV2i2Dih4d3jO9FF1VDUNDm7W7739yiQhRZ5yelj5TaWGeRxWv+xM3YpVGqJzWI9oCuSpR2QaVKaOMQwIDAQAB"
|
||||
}
|
||||
|
||||
# moritzgraf.de
|
||||
|
||||
resource "ovh_domain_zone_record" "mx_record_moritzgraf_de" {
|
||||
|
||||
zone = "moritzgraf.de"
|
||||
fieldtype = "MX"
|
||||
ttl = 60
|
||||
target = "1 SMTP.GOOGLE.COM."
|
||||
}
|
||||
|
||||
|
||||
resource "ovh_domain_zone_record" "google_domain_verification_moritzgraf_de" {
|
||||
zone = "moritzgraf.de"
|
||||
fieldtype = "TXT"
|
||||
ttl = 60
|
||||
target = "google-site-verification=YwUd-Bmbq1-lA7uYGcowsLEMczqx1odndFZq_Nk3nvM"
|
||||
}
|
||||
|
||||
resource "ovh_domain_zone_record" "spf_moritzgraf_de" {
|
||||
zone = "moritzgraf.de"
|
||||
subdomain = "" # SPF record goes on the root domain
|
||||
fieldtype = "TXT"
|
||||
ttl = 60 # Time-to-live in seconds (1 hour is standard, but 60 is ok too)
|
||||
target = "v=spf1 include:_spf.google.com ~all"
|
||||
}
|
||||
|
||||
resource "ovh_domain_zone_record" "dmarc_moritzgraf_de" {
|
||||
zone = "moritzgraf.de"
|
||||
subdomain = "_dmarc" # DMARC record always goes on the _dmarc subdomain
|
||||
fieldtype = "TXT"
|
||||
ttl = 60 # 1 hour TTL
|
||||
target = "v=DMARC1; p=none; rua=mailto:custom-admin@haumdaucher.de; ruf=mailto:custom-admin@haumdaucher.de"
|
||||
}
|
||||
|
||||
resource "ovh_domain_zone_record" "dkim_google_moritzgraf_de" {
|
||||
zone = "moritzgraf.de"
|
||||
subdomain = "google._domainkey" # The DNS Host name provided by Google
|
||||
fieldtype = "TXT"
|
||||
ttl = 3600 # 1 hour TTL
|
||||
target = "v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAz4hYXxdgHDaNwqiUrHa4S9vbqLx/iV2avvgwwPqa5+2aOef109Ap8U7OfgFQQgwRVXx5XWbkKL69as3sdzuVA+8A8fRKbprugZEFoL9gyoTxPQveKO2s+1CsP0fUIx1c7aemfgn6mrfC0Ep17D70Y9YcQQWgiNHGHlgQDE1z6ncfUquHdipcmd0wEIAmjdNDBoqf3b1SRz5xaayKIeAsf/f2AFB1IeYwvLEaOC/mQDZWsry86RwjAfKvxbw0zAQaxSLFOho+kuxL2YUPbT55mZaB9Bi1G4VemzZUGuqXoq8xPzFOO/wxNi6Pei0Vs9wLwFahtuxriin4EVYOkjF4uwIDAQAB"
|
||||
}
|
||||
|
||||
|
||||
### ameliegraf.de
|
||||
|
||||
resource "ovh_domain_zone_record" "mx_record_ameliegraf_de" {
|
||||
|
||||
zone = "ameliegraf.de"
|
||||
fieldtype = "MX"
|
||||
ttl = 60
|
||||
target = "1 smtp.google.com."
|
||||
}
|
||||
|
||||
resource "ovh_domain_zone_record" "google_domain_verification_ameliegraf_de" {
|
||||
zone = "ameliegraf.de"
|
||||
fieldtype = "TXT"
|
||||
ttl = 60
|
||||
target = "google-site-verification=LwCbVqOp4c200QYrEEX1m4lIebOzxl5eBb2IkHbrSVA"
|
||||
}
|
||||
|
||||
resource "ovh_domain_zone_record" "spf_ameliegraf_de" {
|
||||
zone = "ameliegraf.de"
|
||||
subdomain = "" # SPF record goes on the root domain
|
||||
fieldtype = "TXT"
|
||||
ttl = 60 # Time-to-live in seconds (1 hour is standard, but 60 is ok too)
|
||||
target = "v=spf1 include:_spf.google.com ~all"
|
||||
}
|
||||
|
||||
resource "ovh_domain_zone_record" "dmarc_ameliegraf_de" {
|
||||
zone = "ameliegraf.de"
|
||||
subdomain = "_dmarc" # DMARC record always goes on the _dmarc subdomain
|
||||
fieldtype = "TXT"
|
||||
ttl = 60 # 1 hour TTL
|
||||
target = "v=DMARC1; p=none; rua=mailto:custom-admin@haumdaucher.de; ruf=mailto:custom-admin@haumdaucher.de"
|
||||
}
|
||||
|
||||
resource "ovh_domain_zone_record" "dkim_google_ameliegraf_de" {
|
||||
zone = "ameliegraf.de"
|
||||
subdomain = "google._domainkey" # The DNS Host name provided by Google
|
||||
fieldtype = "TXT"
|
||||
ttl = 3600 # 1 hour TTL
|
||||
target = "v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxkPdqXqsRT9NMioibnQJ1MmOX4Yzp/pwpJAIEGawsVLwZCkkhZEH5SyT4CSVz3AS6/XG2Qgx/a2hYctkzXSXllBhFDvixie6oXCOsjqyfr7R5s4LaKb399djFFl/GC7gSV+PUAW6sI02vJPfmn8BaVRAkrH0OrcjX3LSaTS5RRR9QGNCx0JreM+ho2Mcp8VbZCwnCMu42IjilR1d+kQX+2x0+r6mO0eJfP2QKOVpRnBXgv/FT+8jE+dmusf8MFoXxKuX6QjUh5TBH2J9W5NHUiBB4eC2DTrceuO1bM8ycmaGS95e1BmYXMcwfJknhjIgK85jESA8uDa38PIrN/b7WwIDAQAB"
|
||||
}
|
||||
|
||||
|
||||
### graf-fam.de
|
||||
|
||||
resource "ovh_domain_zone_record" "mx_record_graf_fam_de" {
|
||||
|
||||
zone = "graf-fam.de"
|
||||
fieldtype = "MX"
|
||||
ttl = 60
|
||||
target = "1 smtp.google.com."
|
||||
}
|
||||
|
||||
resource "ovh_domain_zone_record" "google_domain_verification_graf_fam_de" {
|
||||
zone = "graf-fam.de"
|
||||
fieldtype = "TXT"
|
||||
ttl = 60
|
||||
target = "google-site-verification=DcG0tKp5YXxCRvw_Ekxa-3gbzdkZvxXUVkPs8aq9yQ4"
|
||||
}
|
||||
|
||||
resource "ovh_domain_zone_record" "spf_graf_fam_de" {
|
||||
zone = "graf-fam.de"
|
||||
subdomain = "" # SPF record goes on the root domain
|
||||
fieldtype = "TXT"
|
||||
ttl = 60 # Time-to-live in seconds (1 hour is standard, but 60 is ok too)
|
||||
target = "v=spf1 include:_spf.google.com ~all"
|
||||
}
|
||||
|
||||
resource "ovh_domain_zone_record" "dmarc_graf_fam_de" {
|
||||
zone = "graf-fam.de"
|
||||
subdomain = "_dmarc" # DMARC record always goes on the _dmarc subdomain
|
||||
fieldtype = "TXT"
|
||||
ttl = 60 # 1 hour TTL
|
||||
target = "v=DMARC1; p=none; rua=mailto:custom-admin@haumdaucher.de; ruf=mailto:custom-admin@haumdaucher.de"
|
||||
}
|
||||
|
||||
resource "ovh_domain_zone_record" "dkim_google_graf_fam_de" {
|
||||
zone = "graf-fam.de"
|
||||
subdomain = "google._domainkey" # The DNS Host name provided by Google
|
||||
fieldtype = "TXT"
|
||||
ttl = 3600 # 1 hour TTL
|
||||
target = "v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqT7j2pdU/dKDp7392+67cqI54QSwQsYrbdJa0aOH94m5gcXa3B2CZvuN2iKt6mO2mUtzWUbwKcNVL0p9yVW6nHpCMNefUS3NfZ8KQfl+lVsaYZXzYZwuTy2ZMvaBZpftIQjclfChFrOtMvBOTpdu8SBJT8hXnqkOYvtuHPBG+qDsFvsV+N4jjHtYbMPMnD2w7GeYciFWzp3bM9FbYIgdzyD+jzIYkaJlph4cMJBMoOredJhK+T2F95uvsvUk43QNU6KujLTFL6F/wNM/zSmH+5hYBAgAMG3QAguhicATJHV6bxd2oM1aLWNjZt90xBkTmMMzvtLjcGGpkgNuxa35WwIDAQAB"
|
||||
}
|
||||
|
||||
|
||||
### krassescheisse.de
|
||||
|
||||
resource "ovh_domain_zone_record" "mx_record_krassescheisse_de" {
|
||||
|
||||
zone = "krassescheisse.de"
|
||||
fieldtype = "MX"
|
||||
ttl = 60
|
||||
target = "1 smtp.google.com."
|
||||
}
|
||||
|
||||
resource "ovh_domain_zone_record" "google_domain_verification_krassescheisse_de" {
|
||||
zone = "krassescheisse.de"
|
||||
fieldtype = "TXT"
|
||||
ttl = 60
|
||||
target = "google-site-verification=SHFDcMegmOoh9syhj7_xBH9dLQxA2NMnh_zvg4Ma0CM"
|
||||
}
|
||||
|
||||
resource "ovh_domain_zone_record" "spf_krassescheisse_de" {
|
||||
zone = "krassescheisse.de"
|
||||
subdomain = "" # SPF record goes on the root domain
|
||||
fieldtype = "TXT"
|
||||
ttl = 60 # Time-to-live in seconds (1 hour is standard, but 60 is ok too)
|
||||
target = "v=spf1 include:_spf.google.com ~all"
|
||||
}
|
||||
|
||||
resource "ovh_domain_zone_record" "dmarc_krassescheisse_de" {
|
||||
zone = "krassescheisse.de"
|
||||
subdomain = "_dmarc" # DMARC record always goes on the _dmarc subdomain
|
||||
fieldtype = "TXT"
|
||||
ttl = 60 # 1 hour TTL
|
||||
target = "v=DMARC1; p=none; rua=mailto:custom-admin@haumdaucher.de; ruf=mailto:custom-admin@haumdaucher.de"
|
||||
}
|
||||
|
||||
resource "ovh_domain_zone_record" "dkim_google_krassescheisse_de" {
|
||||
zone = "krassescheisse.de"
|
||||
subdomain = "google._domainkey" # The DNS Host name provided by Google
|
||||
fieldtype = "TXT"
|
||||
ttl = 3600 # 1 hour TTL
|
||||
target = "v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAp9dLGkWdBZ0YyjBdRVTf26Fo+lVag1dfHHpO4N+oFLg0xV1gRJFcSGjteHUoKbrJxgesAwSmBYsaWAZB0RCI4wbAZKgb++6NX2Tk5gxkKys9pmc3ufGhCsjQkiiNepUkgalJRU7WAsWWolHXqn69D2DkXx9fPekdwaDeJwdtozoGacdbj46Ef1btGo48CJKk5rjh39c7BDNMmYEXXMztBIK2K80Y5WrLJZFxkvEKBrEB4pVoPDa3xEYcR0olLdDwB2SOEX6HSQ2xXkNB3KxbyIiHJTSJsNxquozTzfiWoqly/AdQLCU9j3jtqP88ne61NciQcxGdvOcQ0yUtFoydOwIDAQAB"
|
||||
}
|
||||
|
||||
### grabengasse7.de
|
||||
|
||||
resource "ovh_domain_zone_record" "mx_record_grabengasse7_de" {
|
||||
|
||||
zone = "grabengasse7.de"
|
||||
fieldtype = "MX"
|
||||
ttl = 60
|
||||
target = "1 smtp.google.com."
|
||||
}
|
||||
|
||||
resource "ovh_domain_zone_record" "google_domain_verification_grabengasse7_de" {
|
||||
zone = "grabengasse7.de"
|
||||
fieldtype = "TXT"
|
||||
ttl = 60
|
||||
target = "google-site-verification=zwmmYhET0gyCJr_An22btaOVcpsE_nR2b1St0y4jn1A"
|
||||
}
|
||||
|
||||
resource "ovh_domain_zone_record" "spf_grabengasse7_de" {
|
||||
zone = "grabengasse7.de"
|
||||
subdomain = "" # SPF record goes on the root domain
|
||||
fieldtype = "TXT"
|
||||
ttl = 60 # Time-to-live in seconds (1 hour is standard, but 60 is ok too)
|
||||
target = "v=spf1 include:_spf.google.com ~all"
|
||||
}
|
||||
|
||||
resource "ovh_domain_zone_record" "dmarc_grabengasse7_de" {
|
||||
zone = "grabengasse7.de"
|
||||
subdomain = "_dmarc" # DMARC record always goes on the _dmarc subdomain
|
||||
fieldtype = "TXT"
|
||||
ttl = 60 # 1 hour TTL
|
||||
target = "v=DMARC1; p=none; rua=mailto:custom-admin@haumdaucher.de; ruf=mailto:custom-admin@haumdaucher.de"
|
||||
}
|
||||
|
||||
resource "ovh_domain_zone_record" "dkim_google_grabengasse7_de" {
|
||||
zone = "grabengasse7.de"
|
||||
subdomain = "google._domainkey" # The DNS Host name provided by Google
|
||||
fieldtype = "TXT"
|
||||
ttl = 3600 # 1 hour TTL
|
||||
target = "v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxR/e/Bc6/6Rfhos0ZQoVsq4HV8wkOdnOgkyubzvnepRDm/ARCws/CTvg9azJGFafsOsft1JZRAypj8mMovnDBjnW3mclVCyHQO34VLm13Et8ySX3GeJwwJQKx52PHsCQT1eEeEF3IjckS9wDiCkgdty9NEqpdF76N62nj6j8WY0czNxrYT0ivyiKQ6reB/mOeTiqPHiSHuB3ANxebwy5/wLilHSH320T9C+TDqcZ/Q6VTrUFpXIMjccEg93ZPaIu++FMTWZAe1pX6IWMuBXt5xRLLTamTzDUIOfwhvMxVee+d9mqwvIOc6J6ZiBhhCZpSVjiVLI5NcfNICQU4kjakwIDAQAB"
|
||||
}
|
||||
@@ -0,0 +1,685 @@
|
||||
/* ==========================================================================
|
||||
HAUMDAUCHER THEME FOR AUTHENTIK
|
||||
Wurst und Spezialitäten n.e.V.
|
||||
Core Principle: Black on White / White on Black (High Contrast & Consistency)
|
||||
========================================================================== */
|
||||
|
||||
@import url('https://fonts.googleapis.com/css2?family=Outfit:wght@300;400;500;600;700;800;900&display=swap');
|
||||
|
||||
/* ==========================================================================
|
||||
1. GLOBAL FOUNDATION & TYPOGRAPHY
|
||||
========================================================================== */
|
||||
:root {
|
||||
--hd-font: 'Outfit', -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
|
||||
--pf-global--FontFamily--sans-serif: var(--hd-font);
|
||||
--pf-v5-global--FontFamily--sans-serif: var(--hd-font);
|
||||
|
||||
/* PatternFly Button Variables (Light Mode / Default) */
|
||||
--pf-c-button--m-primary--BackgroundColor: #000000;
|
||||
--pf-c-button--m-primary--hover--BackgroundColor: #262626;
|
||||
--pf-c-button--m-primary--focus--BackgroundColor: #262626;
|
||||
--pf-c-button--m-primary--active--BackgroundColor: #000000;
|
||||
--pf-c-button--m-primary--Color: #ffffff;
|
||||
--pf-c-button--m-primary--hover--Color: #ffffff;
|
||||
--pf-c-button--m-primary--focus--Color: #ffffff;
|
||||
--pf-c-button--m-primary--active--Color: #ffffff;
|
||||
|
||||
--pf-c-button--m-secondary--BackgroundColor: #ffffff;
|
||||
--pf-c-button--m-secondary--hover--BackgroundColor: #000000;
|
||||
--pf-c-button--m-secondary--focus--BackgroundColor: #f4f5f8;
|
||||
--pf-c-button--m-secondary--active--BackgroundColor: #000000;
|
||||
--pf-c-button--m-secondary--Color: #000000;
|
||||
--pf-c-button--m-secondary--hover--Color: #ffffff;
|
||||
--pf-c-button--m-secondary--focus--Color: #000000;
|
||||
--pf-c-button--m-secondary--active--Color: #ffffff;
|
||||
--pf-c-button--m-secondary--BorderColor: #000000;
|
||||
--pf-c-button--m-secondary--hover--BorderColor: #000000;
|
||||
|
||||
--pf-c-button--m-control--Color: #000000;
|
||||
--pf-c-button--m-control--BackgroundColor: transparent;
|
||||
--pf-c-button--m-plain--Color: #000000;
|
||||
--pf-c-button--m-tertiary--Color: #000000;
|
||||
}
|
||||
|
||||
/* Dark Mode Button Variables */
|
||||
[data-theme='dark'] {
|
||||
--pf-c-button--m-primary--BackgroundColor: #ffffff;
|
||||
--pf-c-button--m-primary--hover--BackgroundColor: #e4e4e7;
|
||||
--pf-c-button--m-primary--focus--BackgroundColor: #e4e4e7;
|
||||
--pf-c-button--m-primary--active--BackgroundColor: #ffffff;
|
||||
--pf-c-button--m-primary--Color: #000000;
|
||||
--pf-c-button--m-primary--hover--Color: #000000;
|
||||
--pf-c-button--m-primary--focus--Color: #000000;
|
||||
--pf-c-button--m-primary--active--Color: #000000;
|
||||
|
||||
--pf-c-button--m-secondary--BackgroundColor: transparent;
|
||||
--pf-c-button--m-secondary--hover--BackgroundColor: #ffffff;
|
||||
--pf-c-button--m-secondary--focus--BackgroundColor: #27272a;
|
||||
--pf-c-button--m-secondary--active--BackgroundColor: #ffffff;
|
||||
--pf-c-button--m-secondary--Color: #ffffff;
|
||||
--pf-c-button--m-secondary--hover--Color: #000000;
|
||||
--pf-c-button--m-secondary--focus--Color: #ffffff;
|
||||
--pf-c-button--m-secondary--active--Color: #000000;
|
||||
--pf-c-button--m-secondary--BorderColor: #ffffff;
|
||||
--pf-c-button--m-secondary--hover--BorderColor: #ffffff;
|
||||
|
||||
--pf-c-button--m-control--Color: #ffffff;
|
||||
--pf-c-button--m-control--BackgroundColor: transparent;
|
||||
--pf-c-button--m-plain--Color: #ffffff;
|
||||
--pf-c-button--m-tertiary--Color: #ffffff;
|
||||
}
|
||||
|
||||
/* ==========================================================================
|
||||
2. UNIVERSAL BUTTON CONTRAST ENFORCEMENT
|
||||
Guarantees that button text is NEVER the same color as the button background
|
||||
in ANY state (normal, hover, focus, active, disabled).
|
||||
========================================================================== */
|
||||
|
||||
/* Ensure all inner elements (spans, icons, text) inherit button text color */
|
||||
.pf-c-button *,
|
||||
.pf-v5-c-button *,
|
||||
button * {
|
||||
color: inherit !important;
|
||||
}
|
||||
|
||||
/* --- Primary Buttons (Light Mode / Default: Solid Black with Solid White Text) --- */
|
||||
.pf-c-button.pf-m-primary,
|
||||
.pf-v5-c-button.pf-m-primary,
|
||||
button[type="submit"] {
|
||||
background-color: #000000 !important;
|
||||
color: #ffffff !important;
|
||||
border: 1px solid #000000 !important;
|
||||
font-family: var(--hd-font) !important;
|
||||
font-weight: 700 !important;
|
||||
border-radius: 12px !important;
|
||||
transition: all 0.2s ease-in-out !important;
|
||||
}
|
||||
|
||||
.pf-c-button.pf-m-primary:hover,
|
||||
.pf-v5-c-button.pf-m-primary:hover,
|
||||
button[type="submit"]:hover {
|
||||
background-color: #262626 !important;
|
||||
color: #ffffff !important;
|
||||
border-color: #262626 !important;
|
||||
}
|
||||
|
||||
.pf-c-button.pf-m-primary:focus,
|
||||
.pf-v5-c-button.pf-m-primary:focus,
|
||||
button[type="submit"]:focus {
|
||||
background-color: #262626 !important;
|
||||
color: #ffffff !important;
|
||||
outline: 2px solid #000000 !important;
|
||||
outline-offset: 2px !important;
|
||||
}
|
||||
|
||||
.pf-c-button.pf-m-primary:active,
|
||||
.pf-v5-c-button.pf-m-primary:active,
|
||||
button[type="submit"]:active {
|
||||
background-color: #000000 !important;
|
||||
color: #ffffff !important;
|
||||
}
|
||||
|
||||
.pf-c-button.pf-m-primary:disabled,
|
||||
.pf-c-button.pf-m-primary.pf-m-disabled,
|
||||
.pf-v5-c-button.pf-m-primary:disabled,
|
||||
.pf-v5-c-button.pf-m-primary.pf-m-disabled,
|
||||
button[type="submit"]:disabled {
|
||||
background-color: #e5e7eb !important;
|
||||
color: #6b7280 !important;
|
||||
border-color: #d1d5db !important;
|
||||
cursor: not-allowed !important;
|
||||
opacity: 0.8 !important;
|
||||
}
|
||||
|
||||
/* --- Primary Buttons (Dark Mode: Solid White with Solid Black Text) --- */
|
||||
[data-theme='dark'] .pf-c-button.pf-m-primary:not(ak-flow-executor *),
|
||||
[data-theme='dark'] .pf-v5-c-button.pf-m-primary:not(ak-flow-executor *),
|
||||
[data-theme='dark'] .pf-c-page button[type="submit"] {
|
||||
background-color: #ffffff !important;
|
||||
color: #000000 !important;
|
||||
border: 1px solid #ffffff !important;
|
||||
}
|
||||
|
||||
[data-theme='dark'] .pf-c-button.pf-m-primary:not(ak-flow-executor *):hover,
|
||||
[data-theme='dark'] .pf-v5-c-button.pf-m-primary:not(ak-flow-executor *):hover,
|
||||
[data-theme='dark'] .pf-c-page button[type="submit"]:hover {
|
||||
background-color: #e4e4e7 !important;
|
||||
color: #000000 !important;
|
||||
border-color: #e4e4e7 !important;
|
||||
}
|
||||
|
||||
[data-theme='dark'] .pf-c-button.pf-m-primary:not(ak-flow-executor *):focus,
|
||||
[data-theme='dark'] .pf-v5-c-button.pf-m-primary:not(ak-flow-executor *):focus,
|
||||
[data-theme='dark'] .pf-c-page button[type="submit"]:focus {
|
||||
background-color: #e4e4e7 !important;
|
||||
color: #000000 !important;
|
||||
outline: 2px solid #ffffff !important;
|
||||
outline-offset: 2px !important;
|
||||
}
|
||||
|
||||
[data-theme='dark'] .pf-c-button.pf-m-primary:not(ak-flow-executor *):disabled,
|
||||
[data-theme='dark'] .pf-v5-c-button.pf-m-primary:not(ak-flow-executor *):disabled,
|
||||
[data-theme='dark'] .pf-c-page button[type="submit"]:disabled {
|
||||
background-color: #27272a !important;
|
||||
color: #71717a !important;
|
||||
border-color: #3f3f46 !important;
|
||||
}
|
||||
|
||||
/* --- Secondary Buttons (Light Mode / Default: Solid White with Black Border & Text) --- */
|
||||
.pf-c-button.pf-m-secondary,
|
||||
.pf-v5-c-button.pf-m-secondary {
|
||||
background-color: #ffffff !important;
|
||||
color: #000000 !important;
|
||||
border: 1px solid #000000 !important;
|
||||
font-family: var(--hd-font) !important;
|
||||
font-weight: 600 !important;
|
||||
border-radius: 12px !important;
|
||||
transition: all 0.2s ease-in-out !important;
|
||||
}
|
||||
|
||||
.pf-c-button.pf-m-secondary:hover,
|
||||
.pf-v5-c-button.pf-m-secondary:hover {
|
||||
background-color: #000000 !important;
|
||||
color: #ffffff !important;
|
||||
border-color: #000000 !important;
|
||||
}
|
||||
|
||||
.pf-c-button.pf-m-secondary:focus,
|
||||
.pf-v5-c-button.pf-m-secondary:focus {
|
||||
background-color: #f4f5f8 !important;
|
||||
color: #000000 !important;
|
||||
outline: 2px solid #000000 !important;
|
||||
outline-offset: 2px !important;
|
||||
}
|
||||
|
||||
.pf-c-button.pf-m-secondary:active,
|
||||
.pf-v5-c-button.pf-m-secondary:active {
|
||||
background-color: #000000 !important;
|
||||
color: #ffffff !important;
|
||||
}
|
||||
|
||||
.pf-c-button.pf-m-secondary:disabled,
|
||||
.pf-c-button.pf-m-secondary.pf-m-disabled,
|
||||
.pf-v5-c-button.pf-m-secondary:disabled,
|
||||
.pf-v5-c-button.pf-m-secondary.pf-m-disabled {
|
||||
background-color: #f9fafb !important;
|
||||
color: #9ca3af !important;
|
||||
border-color: #e5e7eb !important;
|
||||
cursor: not-allowed !important;
|
||||
}
|
||||
|
||||
/* --- Secondary Buttons (Dark Mode) --- */
|
||||
[data-theme='dark'] .pf-c-button.pf-m-secondary:not(ak-flow-executor *),
|
||||
[data-theme='dark'] .pf-v5-c-button.pf-m-secondary:not(ak-flow-executor *) {
|
||||
background-color: transparent !important;
|
||||
color: #ffffff !important;
|
||||
border: 1px solid #ffffff !important;
|
||||
}
|
||||
|
||||
[data-theme='dark'] .pf-c-button.pf-m-secondary:not(ak-flow-executor *):hover,
|
||||
[data-theme='dark'] .pf-v5-c-button.pf-m-secondary:not(ak-flow-executor *):hover {
|
||||
background-color: #ffffff !important;
|
||||
color: #000000 !important;
|
||||
border-color: #ffffff !important;
|
||||
}
|
||||
|
||||
[data-theme='dark'] .pf-c-button.pf-m-secondary:not(ak-flow-executor *):focus,
|
||||
[data-theme='dark'] .pf-v5-c-button.pf-m-secondary:not(ak-flow-executor *):focus {
|
||||
background-color: #27272a !important;
|
||||
color: #ffffff !important;
|
||||
outline: 2px solid #ffffff !important;
|
||||
outline-offset: 2px !important;
|
||||
}
|
||||
|
||||
[data-theme='dark'] .pf-c-button.pf-m-secondary:not(ak-flow-executor *):disabled,
|
||||
[data-theme='dark'] .pf-v5-c-button.pf-m-secondary:not(ak-flow-executor *):disabled {
|
||||
background-color: transparent !important;
|
||||
color: #52525b !important;
|
||||
border-color: #27272a !important;
|
||||
}
|
||||
|
||||
/* --- Control / Plain / Tertiary Buttons (e.g. eye toggle on password fields) --- */
|
||||
.pf-c-button.pf-m-control,
|
||||
.pf-v5-c-button.pf-m-control,
|
||||
.pf-c-button.pf-m-plain,
|
||||
.pf-v5-c-button.pf-m-plain,
|
||||
.pf-c-button.pf-m-tertiary,
|
||||
.pf-v5-c-button.pf-m-tertiary {
|
||||
color: #000000 !important;
|
||||
background-color: transparent !important;
|
||||
}
|
||||
|
||||
.pf-c-button.pf-m-control:hover,
|
||||
.pf-v5-c-button.pf-m-control:hover,
|
||||
.pf-c-button.pf-m-plain:hover,
|
||||
.pf-v5-c-button.pf-m-plain:hover,
|
||||
.pf-c-button.pf-m-tertiary:hover,
|
||||
.pf-v5-c-button.pf-m-tertiary:hover {
|
||||
color: #000000 !important;
|
||||
background-color: rgba(0, 0, 0, 0.08) !important;
|
||||
}
|
||||
|
||||
[data-theme='dark'] .pf-c-button.pf-m-control:not(ak-flow-executor *),
|
||||
[data-theme='dark'] .pf-v5-c-button.pf-m-control:not(ak-flow-executor *),
|
||||
[data-theme='dark'] .pf-c-button.pf-m-plain:not(ak-flow-executor *),
|
||||
[data-theme='dark'] .pf-v5-c-button.pf-m-plain:not(ak-flow-executor *),
|
||||
[data-theme='dark'] .pf-c-button.pf-m-tertiary:not(ak-flow-executor *),
|
||||
[data-theme='dark'] .pf-v5-c-button.pf-m-tertiary:not(ak-flow-executor *) {
|
||||
color: #ffffff !important;
|
||||
background-color: transparent !important;
|
||||
}
|
||||
|
||||
[data-theme='dark'] .pf-c-button.pf-m-control:not(ak-flow-executor *):hover,
|
||||
[data-theme='dark'] .pf-v5-c-button.pf-m-control:not(ak-flow-executor *):hover,
|
||||
[data-theme='dark'] .pf-c-button.pf-m-plain:not(ak-flow-executor *):hover,
|
||||
[data-theme='dark'] .pf-v5-c-button.pf-m-plain:not(ak-flow-executor *):hover,
|
||||
[data-theme='dark'] .pf-c-button.pf-m-tertiary:not(ak-flow-executor *):hover,
|
||||
[data-theme='dark'] .pf-v5-c-button.pf-m-tertiary:not(ak-flow-executor *):hover {
|
||||
color: #ffffff !important;
|
||||
background-color: rgba(255, 255, 255, 0.12) !important;
|
||||
}
|
||||
|
||||
/* --- Link Buttons --- */
|
||||
.pf-c-button.pf-m-link,
|
||||
.pf-v5-c-button.pf-m-link {
|
||||
color: #000000 !important;
|
||||
text-decoration: underline !important;
|
||||
background-color: transparent !important;
|
||||
}
|
||||
|
||||
.pf-c-button.pf-m-link:hover,
|
||||
.pf-v5-c-button.pf-m-link:hover {
|
||||
color: #333333 !important;
|
||||
}
|
||||
|
||||
[data-theme='dark'] .pf-c-button.pf-m-link:not(ak-flow-executor *),
|
||||
[data-theme='dark'] .pf-v5-c-button.pf-m-link:not(ak-flow-executor *) {
|
||||
color: #ffffff !important;
|
||||
text-decoration: underline !important;
|
||||
}
|
||||
|
||||
[data-theme='dark'] .pf-c-button.pf-m-link:not(ak-flow-executor *):hover,
|
||||
[data-theme='dark'] .pf-v5-c-button.pf-m-link:not(ak-flow-executor *):hover {
|
||||
color: #d4d4d8 !important;
|
||||
}
|
||||
|
||||
/* ==========================================================================
|
||||
3. LOGIN & AUTHENTICATION FLOW SCOPE (Classic White Card & Black Elements)
|
||||
========================================================================== */
|
||||
|
||||
/* Page Viewport Centering & Soft Minimal Backdrop */
|
||||
ak-flow-executor,
|
||||
.pf-c-login,
|
||||
.pf-v5-c-login {
|
||||
min-height: 100vh !important;
|
||||
min-height: 100dvh !important;
|
||||
display: flex !important;
|
||||
flex-direction: column !important;
|
||||
align-items: center !important;
|
||||
justify-content: center !important;
|
||||
background-color: #f4f5f8 !important;
|
||||
background-image: radial-gradient(circle at 50% 15%, rgba(0, 0, 0, 0.03) 0%, transparent 60%) !important;
|
||||
background-attachment: fixed !important;
|
||||
background-size: cover !important;
|
||||
padding: 32px 16px 48px 16px !important;
|
||||
box-sizing: border-box !important;
|
||||
position: relative !important;
|
||||
font-family: var(--hd-font) !important;
|
||||
color: #111111 !important;
|
||||
}
|
||||
|
||||
/* Centered Login Container */
|
||||
ak-flow-executor .pf-c-login__container,
|
||||
.pf-c-login .pf-c-login__container,
|
||||
.pf-v5-c-login .pf-v5-c-login__container {
|
||||
display: flex !important;
|
||||
flex-direction: column !important;
|
||||
align-items: center !important;
|
||||
justify-content: center !important;
|
||||
width: 100% !important;
|
||||
max-width: 420px !important;
|
||||
margin: auto !important;
|
||||
padding: 0 !important;
|
||||
box-sizing: border-box !important;
|
||||
}
|
||||
|
||||
/* Header & Logo */
|
||||
ak-flow-executor .pf-c-login__header,
|
||||
.pf-c-login .pf-c-login__header,
|
||||
.pf-v5-c-login .pf-v5-c-login__header {
|
||||
display: flex !important;
|
||||
justify-content: center !important;
|
||||
align-items: center !important;
|
||||
width: 100% !important;
|
||||
margin-top: 0 !important;
|
||||
margin-bottom: 24px !important;
|
||||
padding: 0 !important;
|
||||
}
|
||||
|
||||
ak-flow-executor .pf-c-login__header ak-brand,
|
||||
ak-flow-executor .pf-c-login__header img,
|
||||
.pf-c-login .pf-c-login__header ak-brand,
|
||||
.pf-c-login .pf-c-login__header img,
|
||||
.pf-v5-c-login .pf-v5-c-login__header ak-brand,
|
||||
.pf-v5-c-login .pf-v5-c-login__header img {
|
||||
display: block !important;
|
||||
max-height: 85px !important;
|
||||
max-width: 240px !important;
|
||||
width: auto !important;
|
||||
margin: 0 auto !important;
|
||||
mix-blend-mode: multiply !important;
|
||||
filter: drop-shadow(0 2px 8px rgba(0, 0, 0, 0.08)) !important;
|
||||
transition: all 0.2s ease-in-out;
|
||||
}
|
||||
|
||||
/* The White Card */
|
||||
ak-flow-executor .pf-c-login__main,
|
||||
.pf-c-login .pf-c-login__main,
|
||||
.pf-v5-c-login .pf-v5-c-login__main,
|
||||
ak-flow-executor ak-stage,
|
||||
ak-flow-executor .ak-stage {
|
||||
background: #ffffff !important;
|
||||
border: 1px solid rgba(0, 0, 0, 0.08) !important;
|
||||
border-radius: 20px !important;
|
||||
box-shadow: 0 16px 48px rgba(0, 0, 0, 0.06), 0 1px 3px rgba(0, 0, 0, 0.04) !important;
|
||||
padding: 36px 32px 32px 32px !important;
|
||||
width: 100% !important;
|
||||
box-sizing: border-box !important;
|
||||
color: #111111 !important;
|
||||
}
|
||||
|
||||
/* Hide Redundant / Generic Flow Title */
|
||||
ak-flow-executor .pf-c-login__main-header-title,
|
||||
ak-flow-executor .pf-v5-c-login__main-header-title,
|
||||
ak-flow-executor .pf-c-title,
|
||||
ak-flow-executor .pf-v5-c-title,
|
||||
.pf-c-login .pf-c-login__main-header-title,
|
||||
.pf-v5-c-login .pf-v5-c-login__main-header-title {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
ak-flow-executor .pf-c-login__main-header,
|
||||
.pf-c-login .pf-c-login__main-header,
|
||||
.pf-v5-c-login .pf-v5-c-login__main-header {
|
||||
margin-bottom: 24px !important;
|
||||
padding: 0 !important;
|
||||
text-align: center !important;
|
||||
}
|
||||
|
||||
ak-flow-executor .pf-c-login__main-header-desc,
|
||||
.pf-c-login .pf-c-login__main-header-desc,
|
||||
.pf-v5-c-login .pf-v5-c-login__main-header-desc {
|
||||
font-family: var(--hd-font) !important;
|
||||
font-size: 0.95rem !important;
|
||||
line-height: 1.5 !important;
|
||||
margin: 0 !important;
|
||||
color: #555555 !important;
|
||||
text-align: center !important;
|
||||
}
|
||||
|
||||
ak-flow-executor .pf-c-login__main-header-desc strong,
|
||||
ak-flow-executor .pf-c-login__main-header-desc b,
|
||||
.pf-c-login .pf-c-login__main-header-desc strong,
|
||||
.pf-c-login .pf-c-login__main-header-desc b,
|
||||
.pf-v5-c-login .pf-v5-c-login__main-header-desc strong,
|
||||
.pf-v5-c-login .pf-v5-c-login__main-header-desc b {
|
||||
color: #000000 !important;
|
||||
font-weight: 700 !important;
|
||||
}
|
||||
|
||||
/* Form Groups & Labels */
|
||||
ak-flow-executor .pf-c-form__group,
|
||||
.pf-c-login .pf-c-form__group,
|
||||
.pf-v5-c-login .pf-v5-c-form__group {
|
||||
margin-bottom: 20px !important;
|
||||
}
|
||||
|
||||
ak-flow-executor .pf-c-form__label,
|
||||
ak-flow-executor .pf-v5-c-form__label,
|
||||
ak-flow-executor .pf-c-form__label-text,
|
||||
ak-flow-executor .pf-v5-c-form__label-text,
|
||||
ak-flow-executor .pf-c-form__group-label,
|
||||
ak-flow-executor .pf-v5-c-form__group-label,
|
||||
ak-flow-executor label,
|
||||
ak-flow-executor label *,
|
||||
.pf-c-login .pf-c-form__label,
|
||||
.pf-c-login .pf-v5-c-form__label,
|
||||
.pf-c-login .pf-c-form__label-text,
|
||||
.pf-c-login .pf-v5-c-form__label-text,
|
||||
.pf-c-login label,
|
||||
.pf-c-login label *,
|
||||
.pf-v5-c-login label,
|
||||
.pf-v5-c-login label * {
|
||||
font-family: var(--hd-font) !important;
|
||||
font-weight: 600 !important;
|
||||
font-size: 0.9rem !important;
|
||||
color: #000000 !important;
|
||||
margin-bottom: 6px !important;
|
||||
display: inline-block !important;
|
||||
opacity: 1 !important;
|
||||
}
|
||||
|
||||
/* Required Asterisk */
|
||||
ak-flow-executor .pf-c-form__label-required,
|
||||
ak-flow-executor .pf-v5-c-form__label-required,
|
||||
.pf-c-login .pf-c-form__label-required,
|
||||
.pf-v5-c-login .pf-v5-c-form__label-required {
|
||||
color: #c9190b !important;
|
||||
margin-left: 4px !important;
|
||||
font-weight: 700 !important;
|
||||
}
|
||||
|
||||
/* Inputs */
|
||||
ak-flow-executor .pf-c-form-control,
|
||||
ak-flow-executor .pf-v5-c-form-control,
|
||||
ak-flow-executor input[type="text"],
|
||||
ak-flow-executor input[type="password"],
|
||||
ak-flow-executor input[type="email"],
|
||||
ak-flow-executor input,
|
||||
.pf-c-login .pf-c-form-control,
|
||||
.pf-c-login .pf-v5-c-form-control,
|
||||
.pf-c-login input,
|
||||
.pf-v5-c-login input {
|
||||
font-family: var(--hd-font) !important;
|
||||
font-size: 0.98rem !important;
|
||||
border-radius: 12px !important;
|
||||
padding: 12px 14px !important;
|
||||
background-color: #f9f9fb !important;
|
||||
border: 1px solid #d0d5dd !important;
|
||||
color: #000000 !important;
|
||||
transition: all 0.2s ease-in-out !important;
|
||||
width: 100% !important;
|
||||
box-sizing: border-box !important;
|
||||
}
|
||||
|
||||
ak-flow-executor input::placeholder,
|
||||
.pf-c-login input::placeholder,
|
||||
.pf-v5-c-login input::placeholder {
|
||||
color: #666666 !important;
|
||||
font-style: normal !important;
|
||||
opacity: 1 !important;
|
||||
}
|
||||
|
||||
ak-flow-executor input:focus,
|
||||
.pf-c-login input:focus,
|
||||
.pf-v5-c-login input:focus {
|
||||
outline: none !important;
|
||||
border-color: #000000 !important;
|
||||
box-shadow: 0 0 0 3px rgba(0, 0, 0, 0.12) !important;
|
||||
background-color: #ffffff !important;
|
||||
color: #000000 !important;
|
||||
}
|
||||
|
||||
/* Autofill Fix */
|
||||
ak-flow-executor input:-webkit-autofill,
|
||||
ak-flow-executor input:-webkit-autofill:hover,
|
||||
ak-flow-executor input:-webkit-autofill:focus,
|
||||
.pf-c-login input:-webkit-autofill,
|
||||
.pf-v5-c-login input:-webkit-autofill {
|
||||
-webkit-text-fill-color: #000000 !important;
|
||||
-webkit-box-shadow: 0 0 0 1000px #f9f9fb inset !important;
|
||||
box-shadow: 0 0 0 1000px #f9f9fb inset !important;
|
||||
transition: background-color 5000s ease-in-out 0s !important;
|
||||
}
|
||||
|
||||
/* Flow Submit Button Spacing */
|
||||
ak-flow-executor button[type="submit"],
|
||||
.pf-c-login button[type="submit"],
|
||||
.pf-v5-c-login button[type="submit"] {
|
||||
width: 100% !important;
|
||||
padding: 13px 20px !important;
|
||||
margin-top: 16px !important;
|
||||
margin-bottom: 4px !important;
|
||||
display: flex !important;
|
||||
align-items: center !important;
|
||||
justify-content: center !important;
|
||||
}
|
||||
|
||||
/* Language Selector at Bottom Right */
|
||||
ak-flow-executor ak-locale-select,
|
||||
ak-flow-executor [part="locale-select"],
|
||||
ak-flow-executor::part(locale-select),
|
||||
.pf-c-login ak-locale-select,
|
||||
.pf-v5-c-login ak-locale-select {
|
||||
position: fixed !important;
|
||||
inset-block-start: auto !important;
|
||||
inset-inline-start: auto !important;
|
||||
top: auto !important;
|
||||
left: auto !important;
|
||||
bottom: 14px !important;
|
||||
right: 18px !important;
|
||||
z-index: 999 !important;
|
||||
opacity: 0.65 !important;
|
||||
transition: opacity 0.2s ease, transform 0.2s ease !important;
|
||||
}
|
||||
|
||||
ak-flow-executor ak-locale-select:hover,
|
||||
.pf-c-login ak-locale-select:hover {
|
||||
opacity: 1 !important;
|
||||
transform: translateY(-1px) !important;
|
||||
}
|
||||
|
||||
ak-flow-executor ak-locale-select select,
|
||||
.pf-c-login ak-locale-select select {
|
||||
color: #000000 !important;
|
||||
background: transparent !important;
|
||||
cursor: pointer !important;
|
||||
}
|
||||
|
||||
ak-flow-executor ak-locale-select label,
|
||||
.pf-c-login ak-locale-select label {
|
||||
color: #000000 !important;
|
||||
cursor: pointer !important;
|
||||
}
|
||||
|
||||
/* Footer & Watermark */
|
||||
ak-flow-executor ak-brand-links,
|
||||
ak-flow-executor .pf-c-login__footer,
|
||||
ak-flow-executor .pf-v5-c-login__footer,
|
||||
.pf-c-login .pf-c-login__footer,
|
||||
.pf-v5-c-login .pf-v5-c-login__footer {
|
||||
margin-top: 24px !important;
|
||||
margin-bottom: 0 !important;
|
||||
text-align: center !important;
|
||||
font-size: 0.82rem !important;
|
||||
color: #555555 !important;
|
||||
}
|
||||
|
||||
ak-flow-executor ak-brand-links a,
|
||||
ak-flow-executor .pf-c-login__footer a,
|
||||
.pf-c-login .pf-c-login__footer a,
|
||||
.pf-v5-c-login .pf-v5-c-login__footer a {
|
||||
color: #000000 !important;
|
||||
text-decoration: none !important;
|
||||
font-weight: 600 !important;
|
||||
}
|
||||
|
||||
ak-flow-executor ak-brand-links a:hover,
|
||||
ak-flow-executor .pf-c-login__footer a:hover,
|
||||
.pf-c-login .pf-c-login__footer a:hover,
|
||||
.pf-v5-c-login .pf-v5-c-login__footer a:hover {
|
||||
text-decoration: underline !important;
|
||||
}
|
||||
|
||||
ak-flow-executor .pf-c-login__container::after,
|
||||
.pf-c-login .pf-c-login__container::after,
|
||||
.pf-v5-c-login .pf-v5-c-login__container::after {
|
||||
content: "HAUMDAUCHER • Wurst und Spezialitäten n.e.V.";
|
||||
display: block;
|
||||
margin-top: 28px;
|
||||
margin-bottom: 12px;
|
||||
font-size: 0.76rem;
|
||||
letter-spacing: 1.5px;
|
||||
text-transform: uppercase;
|
||||
font-weight: 600;
|
||||
color: #888888;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
/* Mobile Responsiveness */
|
||||
@media (max-width: 480px) {
|
||||
ak-flow-executor,
|
||||
.pf-c-login,
|
||||
.pf-v5-c-login {
|
||||
padding: 24px 12px 48px 12px !important;
|
||||
}
|
||||
|
||||
ak-flow-executor .pf-c-login__container,
|
||||
.pf-c-login .pf-c-login__container,
|
||||
.pf-v5-c-login .pf-v5-c-login__container {
|
||||
padding: 0 !important;
|
||||
}
|
||||
|
||||
ak-flow-executor .pf-c-login__header,
|
||||
.pf-c-login .pf-c-login__header,
|
||||
.pf-v5-c-login .pf-v5-c-login__header {
|
||||
margin-bottom: 18px !important;
|
||||
}
|
||||
|
||||
ak-flow-executor .pf-c-login__main,
|
||||
.pf-c-login .pf-c-login__main,
|
||||
.pf-v5-c-login .pf-v5-c-login__main,
|
||||
ak-flow-executor ak-stage,
|
||||
ak-flow-executor .ak-stage {
|
||||
padding: 28px 20px 24px 20px !important;
|
||||
border-radius: 18px !important;
|
||||
}
|
||||
|
||||
ak-flow-executor .pf-c-login__header img,
|
||||
.pf-c-login .pf-c-login__header img,
|
||||
.pf-v5-c-login .pf-v5-c-login__header img {
|
||||
max-height: 72px !important;
|
||||
}
|
||||
|
||||
ak-flow-executor .pf-c-login__container::after,
|
||||
.pf-c-login .pf-c-login__container::after,
|
||||
.pf-v5-c-login .pf-v5-c-login__container::after {
|
||||
margin-top: 20px;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
ak-flow-executor ak-locale-select,
|
||||
.pf-c-login ak-locale-select,
|
||||
.pf-v5-c-login ak-locale-select {
|
||||
bottom: 10px !important;
|
||||
right: 12px !important;
|
||||
}
|
||||
}
|
||||
|
||||
/* ==========================================================================
|
||||
4. AUTHENTICATED DASHBOARD (User & Admin Interface)
|
||||
========================================================================== */
|
||||
ak-interface-user .pf-c-brand img,
|
||||
ak-interface-admin .pf-c-brand img,
|
||||
.pf-c-page__header-brand img,
|
||||
.pf-v5-c-page__header-brand img {
|
||||
max-height: 36px !important;
|
||||
width: auto !important;
|
||||
}
|
||||
|
||||
[data-theme='dark'] ak-interface-user .pf-c-brand img,
|
||||
[data-theme='dark'] ak-interface-admin .pf-c-brand img,
|
||||
[data-theme='dark'] .pf-c-page__header-brand img,
|
||||
[data-theme='dark'] .pf-v5-c-page__header-brand img {
|
||||
filter: invert(1) hue-rotate(180deg);
|
||||
}
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
# -*- encoding: utf-8 -*-
|
||||
###
|
||||
try:
|
||||
input = raw_input
|
||||
except NameError:
|
||||
pass
|
||||
|
||||
import ovh
|
||||
import json
|
||||
|
||||
# create a client using configuration from ovh.conf file
|
||||
client = ovh.Client()
|
||||
|
||||
# Request RO, /me API access
|
||||
ck = client.new_consumer_key_request()
|
||||
ck.add_recursive_rules(ovh.API_READ_ONLY, "/")
|
||||
|
||||
# Request token
|
||||
validation = ck.request()
|
||||
|
||||
print("Please visit %s to authenticate" % validation['validationUrl'])
|
||||
input("and press Enter to continue...")
|
||||
|
||||
# Print nice welcome message
|
||||
print("Welcome", client.get('/me')['firstname'])
|
||||
print("Btw, your 'consumerKey' is '%s'" % validation['consumerKey'])
|
||||
@@ -0,0 +1,46 @@
|
||||
# -*- encoding: utf-8 -*-
|
||||
'''
|
||||
List all domain relevant information to add them to Terraform
|
||||
'''
|
||||
import json
|
||||
import ovh
|
||||
import sys
|
||||
|
||||
# Instanciate an OVH Client.
|
||||
# You can generate new credentials with full access to your account on
|
||||
# the token creation page
|
||||
client = ovh.Client(
|
||||
endpoint='ovh-eu', # Endpoint of API OVH Europe (List of available endpoints)
|
||||
application_key='pSnvZrS8R4LPCLEh', # Application Key
|
||||
application_secret='CKUHMo5ZXDm8JLA6ZWWUzAolglQmvylv', # Application Secret
|
||||
consumer_key='EVBu0meA2OYvEvVWUbR0qwU2lD7uXKiM', # Consumer Key
|
||||
)
|
||||
|
||||
all_domains = client.get('/domain')
|
||||
|
||||
# Pretty print
|
||||
print("All domains: "+json.dumps(all_domains, indent=4))
|
||||
|
||||
for domain in all_domains :
|
||||
print("Looking at domain: " +domain)
|
||||
try:
|
||||
if(domain in ["moritzgraf.de"]):
|
||||
all_resources = client.get('/domain/zone/'+str(domain)+"/record")
|
||||
print("All resources:"+json.dumps(all_resources,indent=4))
|
||||
for resource in all_resources:
|
||||
try:
|
||||
record_details = client.get('/domain/zone/'+str(domain)+"/record/"+str(resource))
|
||||
if(record_details["subDomain"] and record_details["subDomain"] in ["git","auth","prometheus","alertmanager",
|
||||
"chat","mqtt", "cloud","monitoring","smtp","pop3","imap","jaeger","ldap","code","hub","grafana",
|
||||
"tt-rss","phpmyadmin","phppgadmin","www","terraformtest","rstudio","code" ]):
|
||||
#print("Domain"+str(record_details["zone"])+"Subdomain:"+str(record_details["subDomain"]))
|
||||
print("terraform import 'ovh_domain_zone_record.moritzgraf_subdomains[\""+record_details["subDomain"]+"\"]' "+ str(record_details["id"])+"."+str(record_details["zone"]))
|
||||
except Exception as e:
|
||||
print("Somthing did not work for domain:"+str(record_details))
|
||||
print(e)
|
||||
# print("###details###"+str(record_details))
|
||||
else:
|
||||
print("Domain "+str(domain)+" not on whitelist, ignoring")
|
||||
except Exception as e:
|
||||
print("Somthing did not work for domain:"+domain)
|
||||
print(e)
|
||||
@@ -0,0 +1,13 @@
|
||||
; THIS FILE IS FOR MANUALLY CHECKING THE API
|
||||
; TO BE USED WITH ovh_dev.py
|
||||
[default]
|
||||
; general configuration: default endpoint
|
||||
endpoint=ovh-eu
|
||||
|
||||
[ovh-eu]
|
||||
; configuration specific to 'ovh-eu' endpoint
|
||||
application_key=pSnvZrS8R4LPCLEh
|
||||
application_secret=CKUHMo5ZXDm8JLA6ZWWUzAolglQmvylv
|
||||
; uncomment following line when writing a script application
|
||||
; with a single consumer key.
|
||||
;consumer_key=eNrAf7toCYw6u8vIyRcHNFp4KqyYW0Tp
|
||||
@@ -0,0 +1,197 @@
|
||||
provider "ovh" {
|
||||
endpoint = "ovh-eu"
|
||||
application_key = "grBXP8S9ugOfjfpj"
|
||||
application_secret = "6mMRIUxMWaXff631ulc2jj5HybGg4ESx"
|
||||
consumer_key = "m3D43OxSD03iyfKenn1fQ1AVl3eXodKn"
|
||||
}
|
||||
|
||||
locals {
|
||||
ttl = "60"
|
||||
}
|
||||
|
||||
## old moritzgrafde
|
||||
## => 91.121.84.190
|
||||
## super old docker compose host
|
||||
## => 91.121.64.43
|
||||
|
||||
variable "subdomains_moritzgraf" {
|
||||
default = ["auth", "prometheus", "alertmanager", "chat", "mqtt", "cloud",
|
||||
"monitoring", "smtp", "pop3", "imap", "jaeger", "ldap", "code", "hub",
|
||||
"grafana", "phpmyadmin", "webapp", "kc", "phppgadmin", "www", "rstudio", "code"]
|
||||
}
|
||||
|
||||
resource "ovh_domain_zone_record" "moritzgraf_subdomains" {
|
||||
for_each = toset(var.subdomains_moritzgraf)
|
||||
zone = "moritzgraf.de"
|
||||
subdomain = each.key
|
||||
fieldtype = "CNAME"
|
||||
ttl = local.ttl
|
||||
target = "moritzgraf.de."
|
||||
}
|
||||
|
||||
|
||||
## new haumdaucher k8s
|
||||
|
||||
variable "subdomains_moritzgraf_k8s" {
|
||||
default = ["tt-rss", "git"]
|
||||
}
|
||||
|
||||
resource "ovh_domain_zone_record" "moritzgraf_subdomains_k8s" {
|
||||
for_each = toset(var.subdomains_moritzgraf_k8s)
|
||||
zone = "moritzgraf.de"
|
||||
subdomain = each.key
|
||||
fieldtype = "CNAME"
|
||||
ttl = local.ttl
|
||||
target = "haumdaucher.de."
|
||||
}
|
||||
|
||||
# Kochen
|
||||
resource "ovh_domain_zone_record" "kochen_haumdaucher" {
|
||||
zone = "haumdaucher.de"
|
||||
subdomain = "kochen"
|
||||
fieldtype = "CNAME"
|
||||
ttl = local.ttl
|
||||
target = "haumdaucher-datalab.github.io."
|
||||
}
|
||||
|
||||
## nodes
|
||||
|
||||
resource "ovh_domain_zone_record" "one" {
|
||||
zone = "haumdaucher.de"
|
||||
subdomain = "one"
|
||||
fieldtype = "A"
|
||||
ttl = local.ttl
|
||||
#target = "91.121.84.190"
|
||||
target = "136.243.23.215"
|
||||
}
|
||||
|
||||
## krassescheisse
|
||||
|
||||
resource "ovh_domain_zone_record" "krassescheisse_subdomains" {
|
||||
for_each = toset(var.subdomains_moritzgraf)
|
||||
zone = "krassescheisse.de"
|
||||
subdomain = each.key
|
||||
fieldtype = "CNAME"
|
||||
ttl = local.ttl
|
||||
target = "krassescheisse.de."
|
||||
}
|
||||
|
||||
|
||||
variable "subdomains_haumdaucher" {
|
||||
default = []
|
||||
}
|
||||
|
||||
# resource "ovh_domain_zone_record" "haumdaucher_subdomains" {
|
||||
# for_each = toset( var.subdomains_haumdaucher )
|
||||
# zone = "haumdaucher.de"
|
||||
# subdomain = each.key
|
||||
# fieldtype = "CNAME"
|
||||
# ttl = local.ttl
|
||||
# target = "haumdaucher.de."
|
||||
# }
|
||||
|
||||
# ## graf.me -> problems with domain
|
||||
variable "domains" {
|
||||
default = ["moritzgraf.de"
|
||||
, "graf-fam.de"
|
||||
, "krassescheisse.de"]
|
||||
}
|
||||
|
||||
resource "ovh_domain_zone_record" "haumdaucher_domain" {
|
||||
zone = "haumdaucher.de"
|
||||
subdomain = ""
|
||||
fieldtype = "A"
|
||||
ttl = local.ttl
|
||||
#target = "91.121.84.190"
|
||||
target = "136.243.23.215"
|
||||
}
|
||||
|
||||
resource "ovh_domain_zone_record" "haumdaucher_wildcard_domain" {
|
||||
zone = "haumdaucher.de"
|
||||
subdomain = "*"
|
||||
fieldtype = "A"
|
||||
ttl = local.ttl
|
||||
#target = "91.121.84.190"
|
||||
target = "136.243.23.215"
|
||||
}
|
||||
|
||||
resource "ovh_domain_zone_record" "moritzgraf_domain" {
|
||||
zone = "moritzgraf.de"
|
||||
subdomain = ""
|
||||
fieldtype = "A"
|
||||
ttl = local.ttl
|
||||
target = "136.243.23.215"
|
||||
}
|
||||
|
||||
resource "ovh_domain_zone_record" "moritzgraf_wildcard_domain" {
|
||||
zone = "moritzgraf.de"
|
||||
subdomain = "*"
|
||||
fieldtype = "A"
|
||||
ttl = local.ttl
|
||||
#target = "91.121.84.190"
|
||||
target = "136.243.23.215"
|
||||
}
|
||||
|
||||
######################################
|
||||
## ameliegraf.de
|
||||
|
||||
locals {
|
||||
|
||||
# adobe
|
||||
first = "151.101.128.119"
|
||||
second = "151.101.192.119"
|
||||
}
|
||||
|
||||
resource "ovh_domain_zone_record" "ameliegraf_de_first" {
|
||||
zone = "ameliegraf.de"
|
||||
subdomain = ""
|
||||
fieldtype = "A"
|
||||
ttl = local.ttl
|
||||
#target = "91.121.84.190"
|
||||
target = local.first
|
||||
}
|
||||
resource "ovh_domain_zone_record" "ameliegraf_de_second" {
|
||||
zone = "ameliegraf.de"
|
||||
subdomain = ""
|
||||
fieldtype = "A"
|
||||
ttl = local.ttl
|
||||
#target = "91.121.84.190"
|
||||
target = local.second
|
||||
}
|
||||
|
||||
resource "ovh_domain_zone_record" "wildcard_ameliegraf_de_first" {
|
||||
zone = "ameliegraf.de"
|
||||
subdomain = "*"
|
||||
fieldtype = "A"
|
||||
ttl = local.ttl
|
||||
#target = "91.121.84.190"
|
||||
target = local.first
|
||||
}
|
||||
resource "ovh_domain_zone_record" "wildcard_ameliegraf_de_second" {
|
||||
zone = "ameliegraf.de"
|
||||
subdomain = "*"
|
||||
fieldtype = "A"
|
||||
ttl = local.ttl
|
||||
#target = "91.121.84.190"
|
||||
target = local.second
|
||||
}
|
||||
|
||||
######################################
|
||||
## grabengasse7.de
|
||||
|
||||
resource "ovh_domain_zone_record" "grabengasse7_de_domain" {
|
||||
zone = "grabengasse7.de"
|
||||
subdomain = ""
|
||||
fieldtype = "A"
|
||||
ttl = local.ttl
|
||||
target = "136.243.23.215"
|
||||
}
|
||||
|
||||
resource "ovh_domain_zone_record" "grabengasse7_de_wildcard" {
|
||||
zone = "grabengasse7.de"
|
||||
subdomain = "*"
|
||||
fieldtype = "A"
|
||||
ttl = local.ttl
|
||||
target = "136.243.23.215"
|
||||
}
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1,20 @@
|
||||
terraform {
|
||||
required_providers {
|
||||
ovh = {
|
||||
source = "ovh/ovh"
|
||||
}
|
||||
google = {
|
||||
source = "hashicorp/google"
|
||||
version = "~> 5.0"
|
||||
}
|
||||
local = {
|
||||
source = "hashicorp/local"
|
||||
version = "~> 2.0"
|
||||
}
|
||||
authentik = {
|
||||
source = "goauthentik/authentik"
|
||||
version = ">= 2024.12"
|
||||
}
|
||||
}
|
||||
required_version = ">= 0.13"
|
||||
}
|
||||
Reference in New Issue
Block a user