Archived
Initial infrastructure mono-repo scaffold
Consolidates nixos, docker, raspi, and debian-configuration into a single infrastructure-as-code repo. Includes: - ansible/: full inventory + proxmox-hardening, freeipa, and raspberrypi roles (converted from debian-configuration bash scripts) - terraform/: Proxmox VMs, Dynu DNS, Pi-hole (decommissioned stub), Docker container catalog — migrated from docker/infrastructure/terraform/ - stacks/docker/, stacks/raspi/, nixos/: placeholder READMEs pending git subtree population (see implementation plan) - docs/: internal MkDocs site with architecture, network topology, runbooks, and drift-detection guide; external sanitized site - scripts/: drift-detect.sh, docs-build.sh, install-hooks.sh, check-secrets.sh - CI: secret-scan (push/PR), drift-detect (daily), docs-build (on change) - Pi-hole removed throughout — DNS is FreeIPA, DHCP is router See docs/internal/implementation-plan.md for the phased rollout after pushing to Gitea. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UvNjoxTWEDkhXsd1Dq2ETP
This commit is contained in:
commit
f85c65870f
125 files changed
+8186
No files matched your search
@@ -0,0 +1,44 @@
|
||||
# Terraform Proxmox Inventory Layer
|
||||
|
||||
This directory codifies existing Proxmox infrastructure using an import-first reconciliation model.
|
||||
|
||||
## Purpose
|
||||
|
||||
- Track existing Proxmox VMs in Terraform.
|
||||
- Reconcile imported VM configuration into maintainable, explicit files.
|
||||
- Represent physical host metadata as structured Terraform locals/outputs.
|
||||
- Support documentation inventory and future downstream tooling.
|
||||
|
||||
## Current repository status
|
||||
|
||||
This directory already contains imported/reconciled VM resources (for example `docker`, `server-nixos`, `nix-cache`, `pbs`, `pihole`) plus host metadata locals/outputs.
|
||||
|
||||
This means it is no longer just a scaffold; treat it as active infrastructure inventory code.
|
||||
|
||||
## Workflow standard (brownfield)
|
||||
|
||||
1. Import one existing VM at a time.
|
||||
2. Confirm provider-specific import ID format.
|
||||
3. Inspect state/plan details.
|
||||
4. Keep hand-maintained `.tf` files focused and readable.
|
||||
5. Use `ignore_changes` only where drift noise is unavoidable.
|
||||
6. Stop when plan is sane/no-op for intended scope.
|
||||
|
||||
## File organization expectations
|
||||
|
||||
- Prefer one-resource-per-file patterns when practical.
|
||||
- Keep shared metadata in `locals`/outputs with clear descriptions.
|
||||
- Keep generated comments/config under ongoing cleanup rather than assuming generated output is final.
|
||||
|
||||
## Safety notes
|
||||
|
||||
- Do not run broad applies casually.
|
||||
- Do not commit real credentials or `.tfstate*`.
|
||||
- Keep changes incremental and reviewable.
|
||||
|
||||
## Related docs
|
||||
|
||||
- [../README.md](../README.md)
|
||||
- [../../../docs/source-of-truth.md](../../../docs/source-of-truth.md)
|
||||
- [../../../docs/terraform-workflows.md](../../../docs/terraform-workflows.md)
|
||||
- [../../../docs/infrastructure-inventory.md](../../../docs/infrastructure-inventory.md)
|
||||
@@ -0,0 +1,76 @@
|
||||
# proxmox_virtual_environment_vm.docker:
|
||||
resource "proxmox_virtual_environment_vm" "docker" {
|
||||
name = "docker"
|
||||
node_name = "pve"
|
||||
scsi_hardware = "virtio-scsi-single"
|
||||
vm_id = 103
|
||||
|
||||
agent {
|
||||
enabled = true
|
||||
timeout = "15m"
|
||||
trim = false
|
||||
}
|
||||
|
||||
cpu {
|
||||
cores = 4
|
||||
numa = false
|
||||
sockets = 1
|
||||
type = "host"
|
||||
units = 1024
|
||||
}
|
||||
|
||||
disk {
|
||||
backup = true
|
||||
cache = "none"
|
||||
datastore_id = "local-lvm"
|
||||
discard = "ignore"
|
||||
file_format = "raw"
|
||||
interface = "scsi0"
|
||||
iothread = false
|
||||
path_in_datastore = "vm-103-disk-0"
|
||||
replicate = true
|
||||
size = 120
|
||||
ssd = false
|
||||
}
|
||||
disk {
|
||||
backup = true
|
||||
cache = "none"
|
||||
datastore_id = "local-lvm"
|
||||
discard = "ignore"
|
||||
file_format = "raw"
|
||||
interface = "scsi1"
|
||||
iothread = false
|
||||
path_in_datastore = "vm-103-disk-1"
|
||||
replicate = true
|
||||
size = 250
|
||||
ssd = false
|
||||
}
|
||||
|
||||
memory {
|
||||
dedicated = 8192
|
||||
floating = 4096
|
||||
keep_hugepages = false
|
||||
shared = 0
|
||||
}
|
||||
|
||||
network_device {
|
||||
bridge = "vmbr0"
|
||||
disconnected = false
|
||||
enabled = true
|
||||
firewall = true
|
||||
}
|
||||
|
||||
operating_system {
|
||||
type = "l26"
|
||||
}
|
||||
|
||||
lifecycle {
|
||||
ignore_changes = [
|
||||
vga,
|
||||
keyboard_layout,
|
||||
tablet_device,
|
||||
agent,
|
||||
]
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
# Proxmox import-first workflow
|
||||
#
|
||||
# 1) Add one minimal resource block for one existing VM.
|
||||
# 2) Add an import block for that VM using the provider's required import ID format.
|
||||
# 3) Run:
|
||||
# terraform init
|
||||
# terraform plan
|
||||
# or:
|
||||
# ../scripts/reconcile_from_plan.sh -- -var-file=terraform.tfvars
|
||||
# 4) Review generated config carefully.
|
||||
# 5) Move only the useful arguments into a hand-maintained .tf file.
|
||||
# 6) Repeat until `terraform plan` is a no-op.
|
||||
|
||||
# IMPORTANT:
|
||||
# - Start with exactly ONE existing VM.
|
||||
# - Do not apply until plan is clean.
|
||||
# - Confirm the provider's exact import ID format before running import/plan.
|
||||
# - Do not import your whole environment at once.
|
||||
|
||||
# Example placeholder for one existing VM
|
||||
#resource "proxmox_virtual_environment_vm" "server-nixos" {
|
||||
# name = "server-nixos"
|
||||
# node_name = "pve"
|
||||
#}
|
||||
|
||||
# Example import block
|
||||
# REPLACE the id below with the exact import ID format required by your provider.
|
||||
# This is provider-specific and must be confirmed before use.
|
||||
#
|
||||
# Commonly this will involve the Proxmox node name and VM ID in some form.
|
||||
#
|
||||
import {
|
||||
to = proxmox_virtual_environment_vm.nix-cache
|
||||
id = "pve/105"
|
||||
}
|
||||
import {
|
||||
to = proxmox_virtual_environment_vm.server-nixos
|
||||
id = "pve/104"
|
||||
}
|
||||
import {
|
||||
to = proxmox_virtual_environment_vm.pihole
|
||||
id = "pve/108"
|
||||
}
|
||||
import {
|
||||
to = proxmox_virtual_environment_vm.pbs
|
||||
id = "pve/106"
|
||||
}
|
||||
import {
|
||||
to = proxmox_virtual_environment_vm.docker
|
||||
id = "pve/103"
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
# proxmox_virtual_environment_vm.nix-cache:
|
||||
resource "proxmox_virtual_environment_vm" "nix-cache" {
|
||||
name = "nix-cache"
|
||||
node_name = "pve"
|
||||
scsi_hardware = "virtio-scsi-single"
|
||||
vm_id = 105
|
||||
|
||||
agent {
|
||||
enabled = true
|
||||
timeout = "15m"
|
||||
trim = false
|
||||
}
|
||||
|
||||
cpu {
|
||||
cores = 2
|
||||
numa = false
|
||||
sockets = 1
|
||||
type = "x86-64-v2-AES"
|
||||
units = 1024
|
||||
}
|
||||
|
||||
disk {
|
||||
backup = true
|
||||
cache = "none"
|
||||
datastore_id = "local-lvm"
|
||||
discard = "ignore"
|
||||
file_format = "raw"
|
||||
interface = "scsi0"
|
||||
iothread = false
|
||||
path_in_datastore = "vm-105-disk-0"
|
||||
replicate = true
|
||||
size = 100
|
||||
ssd = false
|
||||
}
|
||||
|
||||
memory {
|
||||
dedicated = 2048
|
||||
floating = 0
|
||||
keep_hugepages = false
|
||||
shared = 0
|
||||
}
|
||||
|
||||
network_device {
|
||||
bridge = "vmbr0"
|
||||
disconnected = false
|
||||
enabled = true
|
||||
firewall = true
|
||||
}
|
||||
|
||||
operating_system {
|
||||
type = "l26"
|
||||
}
|
||||
lifecycle {
|
||||
ignore_changes = [
|
||||
vga,
|
||||
keyboard_layout,
|
||||
tablet_device,
|
||||
agent,
|
||||
]
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
output "proxmox_scaffold_ready" {
|
||||
description = "Indicates this directory is a placeholder scaffold for future Proxmox adoption."
|
||||
value = true
|
||||
}
|
||||
|
||||
output "proxmox_endpoint_configured" {
|
||||
description = "Whether a non-empty endpoint has been provided."
|
||||
value = var.proxmox_endpoint != ""
|
||||
}
|
||||
|
||||
output "physical_hosts" {
|
||||
description = "Physical host inventory used for documentation"
|
||||
value = local.physical_hosts
|
||||
}
|
||||
|
||||
output "virtual_hosts" {
|
||||
description = "Virtual host/VM inventory used for documentation"
|
||||
value = local.virtual_hosts
|
||||
}
|
||||
|
||||
|
||||
output "infrastructure_inventory" {
|
||||
description = "Combined infrastructure inventory"
|
||||
value = {
|
||||
physical_hosts = local.physical_hosts
|
||||
virtual_hosts = local.virtual_hosts
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
# __generated__ by Terraform
|
||||
# Please review these resources and move them into your main configuration files.
|
||||
|
||||
# __generated__ by Terraform
|
||||
resource "proxmox_virtual_environment_vm" "pbs" {
|
||||
name = "pbs"
|
||||
node_name = "pve"
|
||||
scsi_hardware = "virtio-scsi-single"
|
||||
vm_id = 106
|
||||
agent {
|
||||
enabled = true
|
||||
timeout = "15m"
|
||||
trim = false
|
||||
}
|
||||
cpu {
|
||||
cores = 4
|
||||
numa = false
|
||||
sockets = 1
|
||||
type = "x86-64-v2-AES"
|
||||
units = 1024
|
||||
}
|
||||
disk {
|
||||
backup = true
|
||||
cache = "none"
|
||||
datastore_id = "local-lvm"
|
||||
discard = "ignore"
|
||||
file_format = "raw"
|
||||
interface = "scsi0"
|
||||
iothread = false
|
||||
path_in_datastore = "vm-106-disk-0"
|
||||
replicate = true
|
||||
size = 100
|
||||
ssd = false
|
||||
}
|
||||
disk {
|
||||
backup = true
|
||||
cache = "none"
|
||||
datastore_id = "local-lvm"
|
||||
discard = "ignore"
|
||||
file_format = "raw"
|
||||
interface = "scsi1"
|
||||
iothread = false
|
||||
path_in_datastore = "vm-106-disk-1"
|
||||
replicate = true
|
||||
size = 700
|
||||
ssd = false
|
||||
}
|
||||
memory {
|
||||
dedicated = 8192
|
||||
floating = 4096
|
||||
keep_hugepages = false
|
||||
shared = 0
|
||||
}
|
||||
network_device {
|
||||
bridge = "vmbr0"
|
||||
disconnected = false
|
||||
enabled = true
|
||||
firewall = true
|
||||
}
|
||||
operating_system {
|
||||
type = "l26"
|
||||
}
|
||||
lifecycle {
|
||||
ignore_changes = [
|
||||
vga,
|
||||
keyboard_layout,
|
||||
tablet_device,
|
||||
agent,
|
||||
]
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
# Pi-hole VM — DECOMMISSIONED
|
||||
# Pi-hole was decommissioned. DNS is now handled by FreeIPA (domain-controller.sweet.home).
|
||||
# DHCP is on the router. PXE DHCP is handled by the pxe-boot LXC.
|
||||
#
|
||||
# This resource block is kept as historical documentation of VMID 108.
|
||||
# If the VM has been destroyed on Proxmox, remove this file entirely.
|
||||
# If it still exists and needs to be removed via Terraform:
|
||||
# terraform destroy -target=proxmox_virtual_environment_vm.pihole
|
||||
|
||||
# resource "proxmox_virtual_environment_vm" "pihole" {
|
||||
# name = "pihole"
|
||||
# node_name = "pve"
|
||||
# vm_id = 108
|
||||
# }
|
||||
@@ -0,0 +1,11 @@
|
||||
provider "proxmox" {
|
||||
# Placeholder-only scaffold.
|
||||
# Confirm exact provider auth mode and endpoint details before real use.
|
||||
endpoint = var.proxmox_endpoint
|
||||
insecure = var.proxmox_insecure
|
||||
|
||||
# username = var.proxmox_username
|
||||
# password = var.proxmox_password
|
||||
|
||||
api_token = "${var.proxmox_api_token_id}=${var.proxmox_api_token_secret}"
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
locals {
|
||||
physical_hosts = {
|
||||
pve = {
|
||||
hostname = "pve"
|
||||
type = "physical"
|
||||
role = "proxmox"
|
||||
management_ip = "pve.sweet.home"
|
||||
os_family = "debian"
|
||||
hypervisor = "proxmox"
|
||||
location = "home"
|
||||
notes = "Primary Proxmox VE host"
|
||||
}
|
||||
raspberrypi = {
|
||||
hostname = "raspberrypi"
|
||||
type = "physical"
|
||||
role = "edge"
|
||||
management_ip = "raspberrypi.tail13f623.ts.net"
|
||||
os_family = "debian"
|
||||
hypervisor = null
|
||||
location = "riverglades"
|
||||
notes = "Raspberry Pi host"
|
||||
}
|
||||
}
|
||||
|
||||
# Virtual host inventory for documentation output. This is intentionally
|
||||
# concise and shaped for docs tooling (not a full provider object dump).
|
||||
virtual_hosts = {
|
||||
docker = {
|
||||
name = "docker"
|
||||
type = "virtual"
|
||||
role = "docker-host"
|
||||
proxmox_node = "pve"
|
||||
vm_id = 103
|
||||
management_ip = ""
|
||||
os_family = "linux"
|
||||
notes = "Primary Docker VM"
|
||||
}
|
||||
server_nixos = {
|
||||
name = "server-nixos"
|
||||
type = "virtual"
|
||||
role = "nixos-server"
|
||||
proxmox_node = "pve"
|
||||
vm_id = 104
|
||||
management_ip = ""
|
||||
os_family = "nixos"
|
||||
notes = "General-purpose NixOS VM"
|
||||
}
|
||||
nix_cache = {
|
||||
name = "nix-cache"
|
||||
type = "virtual"
|
||||
role = "cache"
|
||||
proxmox_node = "pve"
|
||||
vm_id = 105
|
||||
management_ip = ""
|
||||
os_family = "linux"
|
||||
notes = "Nix binary cache VM"
|
||||
}
|
||||
pbs = {
|
||||
name = "pbs"
|
||||
type = "virtual"
|
||||
role = "backup"
|
||||
proxmox_node = "pve"
|
||||
vm_id = 106
|
||||
management_ip = ""
|
||||
os_family = "linux"
|
||||
notes = "Proxmox Backup Server VM"
|
||||
}
|
||||
pihole = {
|
||||
name = "pihole"
|
||||
type = "virtual"
|
||||
role = "dns"
|
||||
proxmox_node = "pve"
|
||||
vm_id = 108
|
||||
management_ip = ""
|
||||
os_family = "linux"
|
||||
notes = "DNS filtering VM"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
# __generated__ by Terraform
|
||||
# Please review these resources and move them into your main configuration files.
|
||||
|
||||
# __generated__ by Terraform
|
||||
resource "proxmox_virtual_environment_vm" "server-nixos" {
|
||||
name = "server-nixos"
|
||||
node_name = "pve"
|
||||
scsi_hardware = "virtio-scsi-single"
|
||||
vm_id = 104
|
||||
agent {
|
||||
enabled = true
|
||||
timeout = "15m"
|
||||
trim = false
|
||||
}
|
||||
cpu {
|
||||
cores = 4
|
||||
numa = false
|
||||
sockets = 1
|
||||
type = "x86-64-v2-AES"
|
||||
units = 1024
|
||||
}
|
||||
disk {
|
||||
aio = "io_uring"
|
||||
backup = true
|
||||
cache = "none"
|
||||
datastore_id = "local-lvm"
|
||||
discard = "ignore"
|
||||
file_format = "raw"
|
||||
interface = "scsi0"
|
||||
iothread = false
|
||||
path_in_datastore = "vm-104-disk-0"
|
||||
replicate = true
|
||||
size = 32
|
||||
ssd = false
|
||||
}
|
||||
disk {
|
||||
aio = "io_uring"
|
||||
backup = true
|
||||
cache = "none"
|
||||
datastore_id = "local-lvm"
|
||||
discard = "ignore"
|
||||
file_format = "raw"
|
||||
interface = "scsi1"
|
||||
iothread = false
|
||||
path_in_datastore = "vm-104-disk-1"
|
||||
replicate = true
|
||||
size = 200
|
||||
ssd = false
|
||||
}
|
||||
disk {
|
||||
aio = "io_uring"
|
||||
backup = true
|
||||
cache = "none"
|
||||
datastore_id = "local-lvm"
|
||||
discard = "ignore"
|
||||
file_format = "raw"
|
||||
interface = "scsi2"
|
||||
iothread = false
|
||||
path_in_datastore = "vm-104-disk-2"
|
||||
replicate = true
|
||||
size = 200
|
||||
ssd = false
|
||||
}
|
||||
memory {
|
||||
dedicated = 4096
|
||||
floating = 2048
|
||||
keep_hugepages = false
|
||||
shared = 0
|
||||
}
|
||||
network_device {
|
||||
bridge = "vmbr0"
|
||||
disconnected = false
|
||||
enabled = true
|
||||
firewall = true
|
||||
}
|
||||
operating_system {
|
||||
type = "l26"
|
||||
}
|
||||
lifecycle {
|
||||
ignore_changes = [
|
||||
vga,
|
||||
keyboard_layout,
|
||||
tablet_device,
|
||||
agent,
|
||||
]
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
# Example placeholders only. Do not commit real credentials.
|
||||
|
||||
proxmox_endpoint = "https://pve.example.local:8006/api2/json"
|
||||
proxmox_insecure = false
|
||||
|
||||
# Use either username/password or API token based on your chosen auth flow.
|
||||
proxmox_username = "root@pam"
|
||||
proxmox_password = "REPLACE_ME"
|
||||
proxmox_api_token = "REPLACE_ME"
|
||||
@@ -0,0 +1,37 @@
|
||||
variable "proxmox_endpoint" {
|
||||
description = "Proxmox API endpoint URL, for example https://pve.example.local:8006/api2/json"
|
||||
type = string
|
||||
default = ""
|
||||
}
|
||||
|
||||
variable "proxmox_insecure" {
|
||||
description = "Set true only for local testing with self-signed TLS; prefer false in stable environments."
|
||||
type = bool
|
||||
default = false
|
||||
}
|
||||
|
||||
#variable "proxmox_username" {
|
||||
# description = "Username for password-based auth (placeholder; optional if token auth is used)."
|
||||
# type = string
|
||||
# default = ""
|
||||
#}
|
||||
|
||||
#variable "proxmox_password" {
|
||||
# description = "Password for password-based auth (placeholder; optional if token auth is used)."
|
||||
# type = string
|
||||
# default = ""
|
||||
# sensitive = true
|
||||
#}
|
||||
|
||||
variable "proxmox_api_token_id" {
|
||||
type = string
|
||||
description = "Proxmox API token ID, e.g. terraform@pve!tf"
|
||||
sensitive = true
|
||||
}
|
||||
|
||||
variable "proxmox_api_token_secret" {
|
||||
description = "API token for token-based auth (placeholder; optional if username/password is used)."
|
||||
type = string
|
||||
default = ""
|
||||
sensitive = true
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
terraform {
|
||||
required_version = ">= 1.6.0"
|
||||
|
||||
required_providers {
|
||||
proxmox = {
|
||||
source = "bpg/proxmox"
|
||||
version = "0.68.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user