feat: initial homelab-gitops declarative structure (Terraform & ArgoCD)
This commit is contained in:
131
terraform/authentik/applications.tf
Normal file
131
terraform/authentik/applications.tf
Normal file
@@ -0,0 +1,131 @@
|
||||
# 1. Argo CD
|
||||
resource "authentik_application" "argocd" {
|
||||
name = "Argo CD"
|
||||
slug = "argo-cd"
|
||||
protocol_provider = authentik_provider_oauth2.argocd.id
|
||||
meta_icon = "https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons/png/argo.png"
|
||||
meta_launch_url = "https://argo.snarfnet.net"
|
||||
group = "Infrastructure"
|
||||
open_in_new_tab = true
|
||||
}
|
||||
|
||||
# 2. Gitea
|
||||
resource "authentik_application" "gitea" {
|
||||
name = "Gitea"
|
||||
slug = "gitea"
|
||||
protocol_provider = authentik_provider_oauth2.gitea.id
|
||||
meta_icon = "https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons/png/gitea.png"
|
||||
meta_launch_url = "https://git.snarfnet.net"
|
||||
group = "Development"
|
||||
open_in_new_tab = true
|
||||
}
|
||||
|
||||
# 3. AWX
|
||||
resource "authentik_application" "awx" {
|
||||
name = "AWX Automation"
|
||||
slug = "awx"
|
||||
protocol_provider = authentik_provider_oauth2.awx.id
|
||||
meta_icon = "https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons/png/ansible.png"
|
||||
meta_launch_url = "https://awx.snarfnet.net"
|
||||
group = "Infrastructure"
|
||||
open_in_new_tab = true
|
||||
}
|
||||
|
||||
# 4. Grafana
|
||||
resource "authentik_application" "grafana" {
|
||||
name = "Grafana"
|
||||
slug = "grafana"
|
||||
protocol_provider = authentik_provider_oauth2.grafana.id
|
||||
meta_icon = "https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons/png/grafana.png"
|
||||
meta_launch_url = "https://grafana.snarfnet.net"
|
||||
group = "Observability"
|
||||
open_in_new_tab = true
|
||||
}
|
||||
|
||||
# 5. Zabbix
|
||||
resource "authentik_application" "zabbix" {
|
||||
name = "Zabbix"
|
||||
slug = "zabbix"
|
||||
protocol_provider = authentik_provider_oauth2.zabbix.id
|
||||
meta_icon = "https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons/png/zabbix.png"
|
||||
meta_launch_url = "https://zabbix.snarfnet.net"
|
||||
group = "Observability"
|
||||
open_in_new_tab = true
|
||||
}
|
||||
|
||||
# 6. Coder
|
||||
resource "authentik_application" "coder" {
|
||||
name = "Coder"
|
||||
slug = "coder"
|
||||
protocol_provider = authentik_provider_oauth2.coder.id
|
||||
meta_icon = "https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons/png/coder.png"
|
||||
meta_launch_url = "https://coder.snarfnet.net"
|
||||
group = "Development"
|
||||
open_in_new_tab = true
|
||||
}
|
||||
|
||||
# 7. Semaphore
|
||||
resource "authentik_application" "semaphore" {
|
||||
name = "Semaphore UI"
|
||||
slug = "semaphore"
|
||||
protocol_provider = authentik_provider_oauth2.semaphore.id
|
||||
meta_icon = "https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons/png/ansible.png"
|
||||
meta_launch_url = "https://semaphore.snarfnet.net"
|
||||
group = "Infrastructure"
|
||||
open_in_new_tab = true
|
||||
}
|
||||
|
||||
# 8. Synology DSM
|
||||
resource "authentik_application" "synology" {
|
||||
name = "Synology DSM"
|
||||
slug = "synology"
|
||||
protocol_provider = authentik_provider_oauth2.synology.id
|
||||
meta_icon = "https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons/png/synology.png"
|
||||
meta_launch_url = "https://nas.snarfnet.net"
|
||||
group = "Storage"
|
||||
open_in_new_tab = true
|
||||
}
|
||||
|
||||
# 9. Gotify
|
||||
resource "authentik_application" "gotify" {
|
||||
name = "Gotify"
|
||||
slug = "gotify"
|
||||
protocol_provider = authentik_provider_proxy.gotify.id
|
||||
meta_icon = "https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons/png/gotify.png"
|
||||
meta_launch_url = "https://gotify.snarfnet.net"
|
||||
group = "Observability"
|
||||
open_in_new_tab = true
|
||||
}
|
||||
|
||||
# 10. Peanut
|
||||
resource "authentik_application" "peanut" {
|
||||
name = "Peanut UPS"
|
||||
slug = "peanut"
|
||||
protocol_provider = authentik_provider_proxy.peanut.id
|
||||
meta_icon = "https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons/png/ups.png"
|
||||
meta_launch_url = "https://peanut.snarfnet.net"
|
||||
group = "Power & Environment"
|
||||
open_in_new_tab = true
|
||||
}
|
||||
|
||||
# 11. Homebox
|
||||
resource "authentik_application" "homebox" {
|
||||
name = "Homebox"
|
||||
slug = "homebox"
|
||||
protocol_provider = authentik_provider_proxy.homebox.id
|
||||
meta_icon = "https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons/png/homebox.png"
|
||||
meta_launch_url = "https://homebox.snarfnet.net"
|
||||
group = "Management"
|
||||
open_in_new_tab = true
|
||||
}
|
||||
|
||||
# 12. NPM
|
||||
resource "authentik_application" "npm" {
|
||||
name = "Nginx Proxy Manager"
|
||||
slug = "nginx-proxy-manager"
|
||||
protocol_provider = authentik_provider_proxy.npm.id
|
||||
meta_icon = "https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons/png/nginx-proxy-manager.png"
|
||||
meta_launch_url = "https://nginx.snarfnet.net"
|
||||
group = "Infrastructure"
|
||||
open_in_new_tab = true
|
||||
}
|
||||
140
terraform/authentik/oauth2_providers.tf
Normal file
140
terraform/authentik/oauth2_providers.tf
Normal file
@@ -0,0 +1,140 @@
|
||||
# Scopes
|
||||
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"
|
||||
}
|
||||
|
||||
# 1. Argo CD
|
||||
resource "authentik_provider_oauth2" "argocd" {
|
||||
name = "Argo CD"
|
||||
client_id = "argocd-client-id"
|
||||
client_secret = "SnarfNetArgoCDPermanentSecret2026"
|
||||
authorization_flow = var.default_authorization_flow_uuid
|
||||
invalidation_flow = var.default_invalidation_flow_uuid
|
||||
signing_key = var.default_signing_key_uuid
|
||||
redirect_uris = ["https://argo.snarfnet.net/auth/callback"]
|
||||
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,
|
||||
]
|
||||
}
|
||||
|
||||
# 2. Gitea
|
||||
resource "authentik_provider_oauth2" "gitea" {
|
||||
name = "Gitea"
|
||||
client_id = "gitea-client-id"
|
||||
client_secret = "SnarfNetGiteaPermanentSecret2026"
|
||||
authorization_flow = var.default_authorization_flow_uuid
|
||||
invalidation_flow = var.default_invalidation_flow_uuid
|
||||
signing_key = var.default_signing_key_uuid
|
||||
redirect_uris = ["https://git.snarfnet.net/user/oauth2/authentik/callback"]
|
||||
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,
|
||||
]
|
||||
}
|
||||
|
||||
# 3. AWX
|
||||
resource "authentik_provider_oauth2" "awx" {
|
||||
name = "AWX Automation"
|
||||
client_id = "awx-client-id"
|
||||
client_secret = "SnarfNetAWXPermanentSecret2026"
|
||||
authorization_flow = var.default_authorization_flow_uuid
|
||||
invalidation_flow = var.default_invalidation_flow_uuid
|
||||
signing_key = var.default_signing_key_uuid
|
||||
redirect_uris = ["https://awx.snarfnet.net/sso/complete/authentik/"]
|
||||
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,
|
||||
]
|
||||
}
|
||||
|
||||
# 4. Grafana
|
||||
resource "authentik_provider_oauth2" "grafana" {
|
||||
name = "Grafana Monitoring"
|
||||
client_id = "grafana-client-id"
|
||||
client_secret = "SnarfNetGrafanaPermanentSecret2026"
|
||||
authorization_flow = var.default_authorization_flow_uuid
|
||||
invalidation_flow = var.default_invalidation_flow_uuid
|
||||
signing_key = var.default_signing_key_uuid
|
||||
redirect_uris = ["https://grafana.snarfnet.net/login/generic_oauth"]
|
||||
property_mappings = [
|
||||
data.authentik_provider_mapping_provider_scope.openid.id,
|
||||
data.authentik_property_mapping_provider_scope.email.id,
|
||||
data.authentik_property_mapping_provider_scope.profile.id,
|
||||
]
|
||||
}
|
||||
|
||||
# 5. Zabbix
|
||||
resource "authentik_provider_oauth2" "zabbix" {
|
||||
name = "Zabbix Monitoring"
|
||||
client_id = "zabbix-client-id"
|
||||
client_secret = "SnarfNetZabbixPermanentSecret2026"
|
||||
authorization_flow = var.default_authorization_flow_uuid
|
||||
invalidation_flow = var.default_invalidation_flow_uuid
|
||||
signing_key = var.default_signing_key_uuid
|
||||
redirect_uris = ["https://zabbix.snarfnet.net/index_sso.php"]
|
||||
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,
|
||||
]
|
||||
}
|
||||
|
||||
# 6. Coder Workspaces
|
||||
resource "authentik_provider_oauth2" "coder" {
|
||||
name = "Coder Workspaces"
|
||||
client_id = "coder-client-id"
|
||||
client_secret = "SnarfNetCoderPermanentSecret2026"
|
||||
authorization_flow = var.default_authorization_flow_uuid
|
||||
invalidation_flow = var.default_invalidation_flow_uuid
|
||||
signing_key = var.default_signing_key_uuid
|
||||
redirect_uris = ["https://coder.snarfnet.net/api/v2/users/oidc/callback"]
|
||||
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,
|
||||
]
|
||||
}
|
||||
|
||||
# 7. Semaphore UI
|
||||
resource "authentik_provider_oauth2" "semaphore" {
|
||||
name = "Semaphore UI"
|
||||
client_id = "semaphore-client-id"
|
||||
client_secret = "SnarfNetSemaphorePermanentSecret2026"
|
||||
authorization_flow = var.default_authorization_flow_uuid
|
||||
invalidation_flow = var.default_invalidation_flow_uuid
|
||||
signing_key = var.default_signing_key_uuid
|
||||
redirect_uris = ["https://semaphore.snarfnet.net/api/auth/oidc/authentik/redirect"]
|
||||
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,
|
||||
]
|
||||
}
|
||||
|
||||
# 8. Synology DSM
|
||||
resource "authentik_provider_oauth2" "synology" {
|
||||
name = "Synology DSM"
|
||||
client_id = "synology-client-id"
|
||||
client_secret = "SnarfNetSynologyPermanentSecret2026"
|
||||
authorization_flow = var.default_authorization_flow_uuid
|
||||
invalidation_flow = var.default_invalidation_flow_uuid
|
||||
signing_key = var.default_signing_key_uuid
|
||||
redirect_uris = ["https://nas.snarfnet.net/entry.cgi", "https://snarfnas.snarfnet.net/entry.cgi"]
|
||||
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,
|
||||
]
|
||||
}
|
||||
17
terraform/authentik/outputs.tf
Normal file
17
terraform/authentik/outputs.tf
Normal file
@@ -0,0 +1,17 @@
|
||||
output "authentik_applications" {
|
||||
description = "Configured Authentik application slugs"
|
||||
value = [
|
||||
authentik_application.argocd.slug,
|
||||
authentik_application.gitea.slug,
|
||||
authentik_application.awx.slug,
|
||||
authentik_application.grafana.slug,
|
||||
authentik_application.zabbix.slug,
|
||||
authentik_application.coder.slug,
|
||||
authentik_application.semaphore.slug,
|
||||
authentik_application.synology.slug,
|
||||
authentik_application.gotify.slug,
|
||||
authentik_application.peanut.slug,
|
||||
authentik_application.homebox.slug,
|
||||
authentik_application.npm.slug,
|
||||
]
|
||||
}
|
||||
7
terraform/authentik/policies.tf
Normal file
7
terraform/authentik/policies.tf
Normal file
@@ -0,0 +1,7 @@
|
||||
# Conditional MFA & Security Policies
|
||||
resource "authentik_policy_password" "default" {
|
||||
name = "homelab-password-policy"
|
||||
length_min = 12
|
||||
error_message = "Password must be at least 12 characters long."
|
||||
check_have_i_been_pwned = false
|
||||
}
|
||||
21
terraform/authentik/providers.tf
Normal file
21
terraform/authentik/providers.tf
Normal file
@@ -0,0 +1,21 @@
|
||||
terraform {
|
||||
required_version = ">= 1.5.0"
|
||||
required_providers {
|
||||
authentik = {
|
||||
source = "goauthentik/authentik"
|
||||
version = "~> 2024.10"
|
||||
}
|
||||
}
|
||||
|
||||
backend "http" {
|
||||
address = "https://git.snarfnet.net/api/packages/snarf/terraform/state/authentik"
|
||||
lock_address = "https://git.snarfnet.net/api/packages/snarf/terraform/state/authentik/lock"
|
||||
unlock_address = "https://git.snarfnet.net/api/packages/snarf/terraform/state/authentik/lock"
|
||||
username = "snarf"
|
||||
}
|
||||
}
|
||||
|
||||
provider "authentik" {
|
||||
url = var.authentik_url
|
||||
token = var.authentik_token
|
||||
}
|
||||
35
terraform/authentik/proxy_providers.tf
Normal file
35
terraform/authentik/proxy_providers.tf
Normal file
@@ -0,0 +1,35 @@
|
||||
# 1. Gotify Web UI ForwardAuth
|
||||
resource "authentik_provider_proxy" "gotify" {
|
||||
name = "Gotify ForwardAuth"
|
||||
authorization_flow = var.default_authorization_flow_uuid
|
||||
invalidation_flow = var.default_invalidation_flow_uuid
|
||||
external_host = "https://gotify.snarfnet.net"
|
||||
mode = "forward_single"
|
||||
}
|
||||
|
||||
# 2. Peanut UPS Dashboard ForwardAuth
|
||||
resource "authentik_provider_proxy" "peanut" {
|
||||
name = "Peanut ForwardAuth"
|
||||
authorization_flow = var.default_authorization_flow_uuid
|
||||
invalidation_flow = var.default_invalidation_flow_uuid
|
||||
external_host = "https://peanut.snarfnet.net"
|
||||
mode = "forward_single"
|
||||
}
|
||||
|
||||
# 3. Homebox Inventory ForwardAuth
|
||||
resource "authentik_provider_proxy" "homebox" {
|
||||
name = "Homebox ForwardAuth"
|
||||
authorization_flow = var.default_authorization_flow_uuid
|
||||
invalidation_flow = var.default_invalidation_flow_uuid
|
||||
external_host = "https://homebox.snarfnet.net"
|
||||
mode = "forward_single"
|
||||
}
|
||||
|
||||
# 4. Nginx Proxy Manager Admin ForwardAuth
|
||||
resource "authentik_provider_proxy" "npm" {
|
||||
name = "NPM Admin ForwardAuth"
|
||||
authorization_flow = var.default_authorization_flow_uuid
|
||||
invalidation_flow = var.default_invalidation_flow_uuid
|
||||
external_host = "https://nginx.snarfnet.net"
|
||||
mode = "forward_single"
|
||||
}
|
||||
30
terraform/authentik/variables.tf
Normal file
30
terraform/authentik/variables.tf
Normal file
@@ -0,0 +1,30 @@
|
||||
variable "authentik_url" {
|
||||
type = string
|
||||
description = "Base URL for the Authentik instance"
|
||||
default = "https://authentik.snarfnet.net"
|
||||
}
|
||||
|
||||
variable "authentik_token" {
|
||||
type = string
|
||||
description = "API Token for Authentik automation"
|
||||
default = "SnarfNetPermanentAutomationToken2026"
|
||||
sensitive = true
|
||||
}
|
||||
|
||||
variable "default_authorization_flow_uuid" {
|
||||
type = string
|
||||
description = "Default OAuth authorization flow UUID"
|
||||
default = "38a86ef3-f43a-4756-8f54-ca008a8eef6e"
|
||||
}
|
||||
|
||||
variable "default_invalidation_flow_uuid" {
|
||||
type = string
|
||||
description = "Default OAuth invalidation flow UUID"
|
||||
default = "7a8145b8-2476-4636-9901-825f826df805"
|
||||
}
|
||||
|
||||
variable "default_signing_key_uuid" {
|
||||
type = string
|
||||
description = "Default RSA signing key certificate UUID"
|
||||
default = "6d48ba88-4b51-428f-903c-93334988a941"
|
||||
}
|
||||
37
terraform/harvester/networks.tf
Normal file
37
terraform/harvester/networks.tf
Normal file
@@ -0,0 +1,37 @@
|
||||
# Declarative Harvester VLAN Networks
|
||||
resource "harvester_network" "vlan20_infra" {
|
||||
name = "vlan20-infra"
|
||||
namespace = "default"
|
||||
vlan_id = 20
|
||||
route {
|
||||
mode = "auto"
|
||||
gateway = "140.44.4.1"
|
||||
}
|
||||
}
|
||||
|
||||
resource "harvester_network" "vlan40_storage" {
|
||||
name = "vlan40-storage"
|
||||
namespace = "default"
|
||||
vlan_id = 40
|
||||
route {
|
||||
mode = "auto"
|
||||
gateway = "14.10.10.1"
|
||||
}
|
||||
}
|
||||
|
||||
resource "harvester_network" "vlan50_smarthome" {
|
||||
name = "vlan50-smarthome"
|
||||
namespace = "default"
|
||||
vlan_id = 50
|
||||
route {
|
||||
mode = "auto"
|
||||
gateway = "14.4.4.1"
|
||||
}
|
||||
}
|
||||
|
||||
# SSH Key Pair for Virtual Machines
|
||||
resource "harvester_ssh_key" "snarfnet_master" {
|
||||
name = "snarfnet-master-key"
|
||||
namespace = "default"
|
||||
public_key = var.master_ssh_public_key
|
||||
}
|
||||
8
terraform/harvester/outputs.tf
Normal file
8
terraform/harvester/outputs.tf
Normal file
@@ -0,0 +1,8 @@
|
||||
output "harvester_vlan_networks" {
|
||||
description = "Configured Harvester VLAN networks"
|
||||
value = [
|
||||
harvester_network.vlan20_infra.name,
|
||||
harvester_network.vlan40_storage.name,
|
||||
harvester_network.vlan50_smarthome.name,
|
||||
]
|
||||
}
|
||||
20
terraform/harvester/providers.tf
Normal file
20
terraform/harvester/providers.tf
Normal file
@@ -0,0 +1,20 @@
|
||||
terraform {
|
||||
required_version = ">= 1.5.0"
|
||||
required_providers {
|
||||
harvester = {
|
||||
source = "harvester/harvester"
|
||||
version = "~> 0.6"
|
||||
}
|
||||
}
|
||||
|
||||
backend "http" {
|
||||
address = "https://git.snarfnet.net/api/packages/snarf/terraform/state/harvester"
|
||||
lock_address = "https://git.snarfnet.net/api/packages/snarf/terraform/state/harvester/lock"
|
||||
unlock_address = "https://git.snarfnet.net/api/packages/snarf/terraform/state/harvester/lock"
|
||||
username = "snarf"
|
||||
}
|
||||
}
|
||||
|
||||
provider "harvester" {
|
||||
kubeconfig = var.harvester_kubeconfig
|
||||
}
|
||||
11
terraform/harvester/variables.tf
Normal file
11
terraform/harvester/variables.tf
Normal file
@@ -0,0 +1,11 @@
|
||||
variable "harvester_kubeconfig" {
|
||||
type = string
|
||||
description = "Path to Harvester cluster kubeconfig file"
|
||||
default = "~/.kube/harvester.yaml"
|
||||
}
|
||||
|
||||
variable "master_ssh_public_key" {
|
||||
type = string
|
||||
description = "Snarfnet Master SSH Public Key"
|
||||
default = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPqgXJd84m12yNq1gqjAOm6n8sK1l9K3eK0Y7Y+V8V7/ snarfnet-master"
|
||||
}
|
||||
11
terraform/harvester/vms.tf
Normal file
11
terraform/harvester/vms.tf
Normal file
@@ -0,0 +1,11 @@
|
||||
# Harvester Virtual Machine Templates / Definitions
|
||||
# Note: Baremetal Harvester HCI nodes remain outside destructive automation scope.
|
||||
# VM resources defined declaratively for state tracking.
|
||||
|
||||
resource "harvester_image" "ubuntu_focal" {
|
||||
name = "ubuntu-20.04-server-cloudimg-arm64"
|
||||
namespace = "default"
|
||||
display_name = "Ubuntu 20.04 ARM64 Cloud Image"
|
||||
source_type = "download"
|
||||
url = "https://cloud-images.ubuntu.com/releases/focal/release/ubuntu-20.04-server-cloudimg-arm64.img"
|
||||
}
|
||||
9
terraform/shipyard-swarm/outputs.tf
Normal file
9
terraform/shipyard-swarm/outputs.tf
Normal file
@@ -0,0 +1,9 @@
|
||||
output "swarm_services" {
|
||||
description = "Configured Docker Swarm services"
|
||||
value = [
|
||||
docker_service.gotify.name,
|
||||
docker_service.peanut.name,
|
||||
docker_service.homebox.name,
|
||||
docker_service.nginx_proxy_manager.name,
|
||||
]
|
||||
}
|
||||
20
terraform/shipyard-swarm/providers.tf
Normal file
20
terraform/shipyard-swarm/providers.tf
Normal file
@@ -0,0 +1,20 @@
|
||||
terraform {
|
||||
required_version = ">= 1.5.0"
|
||||
required_providers {
|
||||
docker = {
|
||||
source = "kreuzwerker/docker"
|
||||
version = "~> 3.0"
|
||||
}
|
||||
}
|
||||
|
||||
backend "http" {
|
||||
address = "https://git.snarfnet.net/api/packages/snarf/terraform/state/shipyard-swarm"
|
||||
lock_address = "https://git.snarfnet.net/api/packages/snarf/terraform/state/shipyard-swarm/lock"
|
||||
unlock_address = "https://git.snarfnet.net/api/packages/snarf/terraform/state/shipyard-swarm/lock"
|
||||
username = "snarf"
|
||||
}
|
||||
}
|
||||
|
||||
provider "docker" {
|
||||
host = var.docker_host
|
||||
}
|
||||
173
terraform/shipyard-swarm/stacks.tf
Normal file
173
terraform/shipyard-swarm/stacks.tf
Normal file
@@ -0,0 +1,173 @@
|
||||
# Swarm Overlay Network
|
||||
resource "docker_network" "homelab_public" {
|
||||
name = "homelab_public"
|
||||
driver = "overlay"
|
||||
attachable = true
|
||||
}
|
||||
|
||||
# 1. Gotify Notification Service
|
||||
resource "docker_service" "gotify" {
|
||||
name = "gotify"
|
||||
|
||||
task_spec {
|
||||
container_spec {
|
||||
image = "gotify/server:latest"
|
||||
env = {
|
||||
GOTIFY_SERVER_PORT = "80"
|
||||
TZ = "America/New_York"
|
||||
}
|
||||
mounts {
|
||||
target = "/app/data"
|
||||
source = "${var.swarm_storage_base}/gotify"
|
||||
type = "bind"
|
||||
}
|
||||
}
|
||||
restart_policy {
|
||||
condition = "any"
|
||||
}
|
||||
}
|
||||
|
||||
mode {
|
||||
replicated {
|
||||
replicas = 1
|
||||
}
|
||||
}
|
||||
|
||||
endpoint_spec {
|
||||
ports {
|
||||
target_port = 80
|
||||
published_port = 8090
|
||||
publish_mode = "ingress"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# 2. Peanut UPS Service
|
||||
resource "docker_service" "peanut" {
|
||||
name = "peanut"
|
||||
|
||||
task_spec {
|
||||
container_spec {
|
||||
image = "brandawg93/peanut:latest"
|
||||
env = {
|
||||
TZ = "America/New_York"
|
||||
}
|
||||
mounts {
|
||||
target = "/config"
|
||||
source = "${var.swarm_storage_base}/peanut"
|
||||
type = "bind"
|
||||
}
|
||||
}
|
||||
restart_policy {
|
||||
condition = "any"
|
||||
}
|
||||
}
|
||||
|
||||
mode {
|
||||
replicated {
|
||||
replicas = 1
|
||||
}
|
||||
}
|
||||
|
||||
endpoint_spec {
|
||||
ports {
|
||||
target_port = 8080
|
||||
published_port = 8050
|
||||
publish_mode = "ingress"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# 3. Homebox Inventory Service
|
||||
resource "docker_service" "homebox" {
|
||||
name = "homebox"
|
||||
|
||||
task_spec {
|
||||
container_spec {
|
||||
image = "ghcr.io/sysadminsmedia/homebox:latest"
|
||||
env = {
|
||||
HBOX_MODE = "production"
|
||||
HBOX_STORAGE_DATA = "/data"
|
||||
TZ = "America/New_York"
|
||||
}
|
||||
mounts {
|
||||
target = "/data"
|
||||
source = "${var.swarm_storage_base}/homebox"
|
||||
type = "bind"
|
||||
}
|
||||
}
|
||||
restart_policy {
|
||||
condition = "any"
|
||||
}
|
||||
}
|
||||
|
||||
mode {
|
||||
replicated {
|
||||
replicas = 1
|
||||
}
|
||||
}
|
||||
|
||||
endpoint_spec {
|
||||
ports {
|
||||
target_port = 7745
|
||||
published_port = 7745
|
||||
publish_mode = "ingress"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# 4. Nginx Proxy Manager Service (Node-pinned to snshpd4lnxswm04)
|
||||
resource "docker_service" "nginx_proxy_manager" {
|
||||
name = "nginx-proxy-manager"
|
||||
|
||||
task_spec {
|
||||
container_spec {
|
||||
image = "jc21/nginx-proxy-manager:latest"
|
||||
env = {
|
||||
TZ = "America/New_York"
|
||||
PUID = "1000"
|
||||
PGID = "1000"
|
||||
}
|
||||
mounts {
|
||||
target = "/data"
|
||||
source = "${var.swarm_storage_base}/nginx-proxy-manager_nginx-data/_data"
|
||||
type = "bind"
|
||||
}
|
||||
mounts {
|
||||
target = "/etc/letsencrypt"
|
||||
source = "${var.swarm_storage_base}/nginx-proxy-manager_nginx-letsencrypt/_data"
|
||||
type = "bind"
|
||||
}
|
||||
}
|
||||
placement {
|
||||
constraints = ["node.hostname == snshpd4lnxswm04"]
|
||||
}
|
||||
restart_policy {
|
||||
condition = "any"
|
||||
}
|
||||
}
|
||||
|
||||
mode {
|
||||
replicated {
|
||||
replicas = 1
|
||||
}
|
||||
}
|
||||
|
||||
endpoint_spec {
|
||||
ports {
|
||||
target_port = 80
|
||||
published_port = 80
|
||||
publish_mode = "host"
|
||||
}
|
||||
ports {
|
||||
target_port = 443
|
||||
published_port = 443
|
||||
publish_mode = "host"
|
||||
}
|
||||
ports {
|
||||
target_port = 81
|
||||
published_port = 81
|
||||
publish_mode = "host"
|
||||
}
|
||||
}
|
||||
}
|
||||
11
terraform/shipyard-swarm/variables.tf
Normal file
11
terraform/shipyard-swarm/variables.tf
Normal file
@@ -0,0 +1,11 @@
|
||||
variable "docker_host" {
|
||||
type = string
|
||||
description = "Docker daemon SSH / TCP connection string"
|
||||
default = "ssh://snarf@140.44.4.71:22"
|
||||
}
|
||||
|
||||
variable "swarm_storage_base" {
|
||||
type = string
|
||||
description = "Path to NFS persistent storage mount"
|
||||
default = "/mnt/swarm_shared/legacy_volumes"
|
||||
}
|
||||
9
terraform/synology/outputs.tf
Normal file
9
terraform/synology/outputs.tf
Normal file
@@ -0,0 +1,9 @@
|
||||
output "configured_shares" {
|
||||
description = "Configured Synology NFS shares"
|
||||
value = [
|
||||
synology_filestation_share.kubernetes.name,
|
||||
synology_filestation_share.docker.name,
|
||||
synology_filestation_share.backups.name,
|
||||
synology_filestation_share.media.name,
|
||||
]
|
||||
}
|
||||
25
terraform/synology/providers.tf
Normal file
25
terraform/synology/providers.tf
Normal file
@@ -0,0 +1,25 @@
|
||||
terraform {
|
||||
required_version = ">= 1.5.0"
|
||||
required_providers {
|
||||
synology = {
|
||||
source = "synology-community/synology"
|
||||
version = "~> 0.2"
|
||||
}
|
||||
}
|
||||
|
||||
backend "http" {
|
||||
address = "https://git.snarfnet.net/api/packages/snarf/terraform/state/synology"
|
||||
lock_address = "https://git.snarfnet.net/api/packages/snarf/terraform/state/synology/lock"
|
||||
unlock_address = "https://git.snarfnet.net/api/packages/snarf/terraform/state/synology/lock"
|
||||
username = "snarf"
|
||||
}
|
||||
}
|
||||
|
||||
provider "synology" {
|
||||
host = var.synology_host
|
||||
port = var.synology_port
|
||||
username = var.synology_user
|
||||
password = var.synology_password
|
||||
https = true
|
||||
insecure = true
|
||||
}
|
||||
31
terraform/synology/shares.tf
Normal file
31
terraform/synology/shares.tf
Normal file
@@ -0,0 +1,31 @@
|
||||
# 1. Kubernetes Longhorn Backup Target Shared Folder
|
||||
resource "synology_filestation_share" "kubernetes" {
|
||||
name = "kubernetes"
|
||||
vol_path = "/volume1"
|
||||
description = "Kubernetes Longhorn Backup Target and Persistent RWX storage"
|
||||
enable_recycle_bin = false
|
||||
}
|
||||
|
||||
# 2. Docker Swarm Persistent Volumes Shared Folder
|
||||
resource "synology_filestation_share" "docker" {
|
||||
name = "docker"
|
||||
vol_path = "/volume1"
|
||||
description = "Docker Swarm shared persistent storage"
|
||||
enable_recycle_bin = false
|
||||
}
|
||||
|
||||
# 3. Homelab Backups Shared Folder
|
||||
resource "synology_filestation_share" "backups" {
|
||||
name = "backups"
|
||||
vol_path = "/volume1"
|
||||
description = "Automated SQLite and system config backup bundles"
|
||||
enable_recycle_bin = true
|
||||
}
|
||||
|
||||
# 4. Media Shared Folder
|
||||
resource "synology_filestation_share" "media" {
|
||||
name = "media"
|
||||
vol_path = "/volume1"
|
||||
description = "Media and storage pool"
|
||||
enable_recycle_bin = false
|
||||
}
|
||||
24
terraform/synology/variables.tf
Normal file
24
terraform/synology/variables.tf
Normal file
@@ -0,0 +1,24 @@
|
||||
variable "synology_host" {
|
||||
type = string
|
||||
description = "Synology DSM IP address"
|
||||
default = "14.10.10.71"
|
||||
}
|
||||
|
||||
variable "synology_port" {
|
||||
type = number
|
||||
description = "Synology DSM HTTPS port"
|
||||
default = 5001
|
||||
}
|
||||
|
||||
variable "synology_user" {
|
||||
type = string
|
||||
description = "Synology DSM management user"
|
||||
default = "admin"
|
||||
}
|
||||
|
||||
variable "synology_password" {
|
||||
type = string
|
||||
description = "Synology DSM management password"
|
||||
default = ""
|
||||
sensitive = true
|
||||
}
|
||||
Reference in New Issue
Block a user