276 Commits

Author SHA1 Message Date
be8e50d590 deploy hermes 2026-05-25 20:21:24 -05:00
e309acd67d fix typo 2026-05-24 21:15:08 -05:00
4e7f14ea5a additional service name changes 2026-05-24 21:12:10 -05:00
b79f0505b7 update pbs to timekeeper 2026-05-24 19:46:19 -05:00
045ac85353 update glance configmap 2026-05-24 19:43:13 -05:00
60af4304b6 fix url 2026-05-24 18:35:52 -05:00
96e946ac09 change to https 2026-05-24 18:33:16 -05:00
6584ed9dc4 added glance dashboard 2026-05-24 17:04:49 -05:00
3017c27910 fix port 2026-05-19 23:03:49 -05:00
c25c2a25ad update referencegrant 2026-05-19 22:41:41 -05:00
0476e489d4 more 2026-05-19 22:35:05 -05:00
bf0d7a20a7 update gateway 2026-05-19 22:31:22 -05:00
ed0091cd05 adjust session duration 2026-05-19 22:25:00 -05:00
402f93ab38 add ingnore 2026-05-19 22:16:31 -05:00
8944da8c99 folder rename 2026-05-19 22:06:48 -05:00
d671700466 deploy headlamp 2026-05-19 22:00:34 -05:00
562e102a9b enable metrics 2026-05-19 21:34:46 -05:00
f4c60d7560 add grafana dashboards 2026-05-19 21:12:54 -05:00
0dae8327eb update prometheus scrape 2026-05-18 22:57:07 -05:00
39b7b91f45 update snmp exporter 2026-05-18 22:32:13 -05:00
a7f77514d6 additional monitoring scrapes 2026-05-18 22:28:14 -05:00
b45dcea4c3 update gateway spec 2026-05-18 22:01:18 -05:00
2ed70b4964 Deploy monitoring stack 2026-05-18 21:42:32 -05:00
dbf0b18f07 authentik for argo 2026-05-18 19:43:21 -05:00
1cfc9b5f5d align gateway spec 2026-05-18 19:28:50 -05:00
c8f75bef8a fix referencegrant 2026-05-18 19:25:41 -05:00
fc171b48e9 deploy gateway 2026-05-18 19:11:42 -05:00
5504d0c6f4 add gateway to external dns 2026-05-18 18:15:33 -05:00
025e9a8f1c Added bootstrap folder and gateway controller 2026-05-18 18:07:35 -05:00
06db61c6c0 enable nfs csi 2026-05-18 17:19:39 -05:00
8601ad9cd9 move archive 2026-05-18 15:15:36 -05:00
1f7318f1c3 repo cleanup 2026-05-18 15:13:12 -05:00
cdc78955b1 cilium, argo 2026-05-18 13:20:42 -05:00
6f0c751f63 fix: set enforce:privileged for Cilium compatibility 2026-05-18 10:43:27 -05:00
f1ef759206 fix(cilium): update LB pool API from v2alpha1 to v2 2026-05-18 00:59:17 -05:00
5f5f8cb173 fix argocd 2026-05-18 00:45:47 -05:00
eb93eb7352 fix(argocd): remove conflicting server patch, params-cm handles insecure mode 2026-05-18 00:39:43 -05:00
9cd9a30fbe fix(argocd): switch to ingress-nginx, fix shared resource warning, add insecure mode 2026-05-18 00:34:21 -05:00
5a30521d66 fix(argocd): use env var for insecure mode instead of args 2026-05-18 00:23:03 -05:00
725d403d34 helm fix 2026-05-18 00:08:30 -05:00
9a604042ca update cilium 2026-05-18 00:01:03 -05:00
10406e1705 remove gateway api 2026-05-17 23:48:22 -05:00
4717f63bc3 cilium 2026-05-17 23:46:44 -05:00
2ff74cdc7c cilium TS 2026-05-17 23:39:11 -05:00
87f2d6bf95 fix cilium 2026-05-17 23:32:24 -05:00
88ec796267 ext dns and cert manager 2026-05-17 22:59:45 -05:00
344a29a374 fix directory for 1p 2026-05-17 22:55:32 -05:00
c7fbe8e963 fix(platform): move gateway and namespace into manifests/ directory 2026-05-17 22:48:51 -05:00
03acab784a fix(argocd): use args not command for --insecure flag 2026-05-17 22:24:26 -05:00
3ce3ecac66 feat(platform): vendor gateway-api CRDs v1.2.1 2026-05-17 22:19:04 -05:00
bc24c00c50 final apps 2026-05-17 21:41:28 -05:00
3e9a843e1b cert manager and 1p 2026-05-17 21:37:17 -05:00
5e99408c1f change pattern for external secrets 2026-05-17 21:33:24 -05:00
e4a2c47da2 fix(platform): correct helm valueFiles field name for ArgoCD 3.x 2026-05-17 21:18:47 -05:00
13ebe67a35 update 2026-05-17 21:10:45 -05:00
ca1cdd0634 fix(argocd): restore SSH repo credentials for Gitea 2026-05-17 21:10:10 -05:00
74e53d1364 fix(platform): valuesFile → valuesFiles for ArgoCD 3.x compatibility 2026-05-17 21:04:21 -05:00
e946bd71f0 feat(platform): vendor gateway-api CRDs v1.2.1 2026-05-17 20:45:53 -05:00
905b4619d6 Initial argo deployment 2026-05-17 20:44:31 -05:00
97e9889251 feat(fastpass): Talos cluster provisioning and bootstrap
- Terraform: VM provisioning, Unifi DHCP, Technitium DNS
- talhelper: cluster config for 6-node Talos cluster
- Cilium 1.19.4 CNI with Talos-compatible security context
- docs: city-hall setup guide and bootstrap runbook
2026-05-17 16:08:19 -05:00
9f3ac95d8d gitea and authentik 2026-05-16 16:22:14 -05:00
84523d0054 configure prometheus for ubiquiti and proxmox cluster 2026-05-08 00:25:55 -05:00
f8c6b327f9 Deploy gites 2026-05-07 22:07:53 -05:00
79662aa545 Deployed prometheus/grafana 2026-04-26 23:00:37 -05:00
69b91a2e1d Move nextcloud external access to traefik. 2026-04-18 21:51:28 -05:00
9961fe1ed4 deploy nextcloud 2026-04-18 00:36:40 -05:00
4db6f0b06f added test playbook 2026-03-22 23:47:47 -05:00
307413f3f2 Ansible deployed via boilerplates and playbooks 2026-03-22 18:15:55 -05:00
836ef66cf0 fix dash 2026-03-21 19:48:17 -05:00
4cbaebc98b rename playbook 2026-03-21 19:46:59 -05:00
c1d85b7f89 Remove NetBox Traefik config - deferred until Compose rebuild 2026-03-21 19:10:10 -05:00
c087f32355 redeploy authentic policies as code. 2026-03-21 14:00:37 -05:00
9ad585681f fix ssh handler 2026-03-19 16:53:45 -05:00
40ab77f061 update test file 2026-03-19 16:44:59 -05:00
1d0adb7689 step enrollment 2026-03-19 16:29:09 -05:00
1d6b216b74 remove step-ca from traefik 2026-03-14 22:39:35 -05:00
df0d81ec4d fix directory permissions 2026-03-14 22:32:40 -05:00
ea7d079f27 update step playbook 2026-03-14 22:30:18 -05:00
5022fc90ab update ansible inventory 2026-03-14 22:27:20 -05:00
45c478bede fixed terraform 2026-03-14 22:21:22 -05:00
03b8abbe4d fix terraform 2026-03-14 22:18:28 -05:00
42ea1e2d03 deploy step 2026-03-14 22:15:28 -05:00
b85b237129 rename turnstile to guest-relations 2026-03-14 21:08:35 -05:00
1d6a8c154c updated documentation 2026-03-10 20:41:34 -05:00
6f14d48d5e oidc again 2026-03-10 20:34:00 -05:00
fa9fd9c65f fix oidc 2026-03-10 20:30:07 -05:00
86cf979453 debugging 2026-03-10 20:28:06 -05:00
cc0fd647ab update ansible user for proxmox 2026-03-10 20:21:53 -05:00
591522f643 updated ansible inventory (proxmox) 2026-03-09 22:41:13 -05:00
643fefb4bf ansible for proxmox config 2026-03-09 22:36:42 -05:00
e8810195cd updwated documentation 2026-03-09 16:27:30 -05:00
3d2669497a update traefik config 2026-03-08 20:39:34 -05:00
42f7a2773d updated inventory 2026-03-08 20:34:59 -05:00
35c1bdb3bf ansible for authentik deployment. 2026-03-08 20:30:51 -05:00
9605b9d3bd Added authentic boilerplate 2026-03-08 16:23:11 -05:00
dfa219191d add terraform definition for turnstile 2026-03-08 16:12:16 -05:00
14502df261 update tradfik networking 2026-03-08 15:54:15 -05:00
ea7e05dcc2 fixed docker install 2026-03-08 15:47:18 -05:00
26f7d3214f switched ntp client to chrony 2026-03-08 15:41:09 -05:00
173a36c518 changed hosts 2026-03-08 15:31:23 -05:00
fcb1777336 move roles 2026-03-08 15:28:09 -05:00
f82c13cd09 updated ansible 2026-03-07 23:08:06 -06:00
e9a854faed moved boilerplates 2026-03-07 22:49:59 -06:00
344e8dff69 updated ansible for lightning-lane 2026-03-07 22:47:37 -06:00
36c2e9540c updated tfvars 2026-03-07 22:00:41 -06:00
40dda3241f update vm initialization 2026-03-07 21:56:49 -06:00
db67f71a3c added variables 2026-03-07 21:53:56 -06:00
920ea80261 terraform files in the right folder 2026-03-07 21:46:44 -06:00
ad03943339 added tfvars 2026-03-07 21:25:54 -06:00
a349ce13f8 Added terraform for lightning-lane 2026-03-07 21:18:36 -06:00
7d7129632f updated technical tdp 2026-03-07 17:50:08 -06:00
e3b3401544 VM provisioning idempotency 2026-03-06 23:10:56 -06:00
bba9278895 n8n workflow to create a VM from Netbox 2026-02-28 20:06:41 -06:00
d941557e88 Update terraform to use vm_id from n8n. 2026-02-28 00:00:56 -06:00
4964552483 fix(terraform): set OVMF bios, correct DNS domain, remove VLAN from interface 2026-02-27 19:56:15 -06:00
7e0b0a859b feat(terraform): add Proxmox VM and Unifi DHCP modules (Phase 2) 2026-02-27 19:12:25 -06:00
b33bd5f252 feat(netbox): add custom field, VLAN, and prefix initializers (Phase 1.1-1.4) 2026-02-25 21:43:47 -06:00
63b9a8fd13 docs: rewrite README for mk-labs architecture 2026-02-25 20:55:38 -06:00
6350cb681f chore: update .gitignore for new repo structure (fix terraform/ exclusion) 2026-02-25 20:53:01 -06:00
676fc02c91 feat: create pipeline directory structure (terraform, n8n, netbox, docs) 2026-02-25 20:51:26 -06:00
75e0d99495 refactor: move Packer templates to top-level packer/ directory 2026-02-25 20:51:20 -06:00
b51cd1a868 refactor: move ansible.cfg to ansible/ directory 2026-02-25 20:51:12 -06:00
7187dc8280 refactor: move shared Ansible tasks to ansible/tasks/ 2026-02-25 20:51:02 -06:00
86708542c9 refactor: move Ansible roles to standard ansible/roles/ location 2026-02-25 20:46:33 -06:00
74172c4e5a chore: archive deprecated infra-config content (SNO cluster, duplicate ansible, old playbooks) 2026-02-25 20:45:01 -06:00
8c8835d1d5 chore: archive deprecated Ansible content (OpenShift, Fastpass, FreeIPA, k8s) 2026-02-25 20:44:49 -06:00
286d20f8c1 chore: archive OpenShift/ACM cluster content, hub-bootstrap, and applications 2026-02-25 20:44:37 -06:00
05ba1bbdb3 chore: remove misc files 2026-02-25 20:43:28 -06:00
7c2ef04d47 Sync before Archive 2026-02-25 20:36:50 -06:00
73eee46101 ansible vm creation (depreciated) 2025-11-21 05:48:43 -08:00
510da9c2a4 Sync 11-19 2025-11-19 09:36:59 -08:00
702c71fcff sync 2025-10-19 17:02:16 -05:00
3f31f77bc8 moving 2025-09-30 11:23:27 -05:00
6f5bc65171 ansible scripts done to install kubewrnetes prequesites 2025-09-27 16:05:33 -05:00
6107e474c1 sync all 2025-09-26 11:55:32 -05:00
e7f8fd2ccd fix logic 2025-09-23 18:26:13 -05:00
1272fa3cb3 reapply password 2025-09-23 16:52:02 -05:00
a76c99e825 .. 2025-09-23 15:30:38 -05:00
d1b6df7d94 typo 2025-09-23 15:29:12 -05:00
14d28f7937 re-enable cloud-init 2025-09-23 15:27:53 -05:00
a67818c0f3 ssh 2025-09-22 22:08:39 -05:00
0d03a42337 Merge branch 'main' of https://github.com/rblundon/homelab 2025-09-22 20:10:24 -05:00
853cd90148 upsate ssh 2025-09-22 20:10:22 -05:00
4108600a57 disable cloud-init on guest 2025-09-22 15:26:31 -05:00
59826cb7a9 update key to variable 2025-09-22 10:40:52 -05:00
cb99f1f5d2 added key 2025-09-22 10:29:33 -05:00
a61491acf3 fix path 2025-09-22 10:26:25 -05:00
7b483364be trying with ssh key 2025-09-22 10:25:20 -05:00
9a8978d046 disable swap 2025-09-22 09:42:35 -05:00
72b943ee04 update password 2025-09-22 09:36:13 -05:00
dd3cf2cd0f revert user file 2025-09-21 18:42:01 -05:00
dbd1c94ada remove packages 2025-09-21 18:18:37 -05:00
c532e7b7de add machine type 2025-09-21 18:00:31 -05:00
3c90b68896 packer bug resolved 2025-09-21 17:27:24 -05:00
36c5215ed4 :( 2025-09-21 15:03:45 -05:00
d7d0027b64 new user-data file 2025-09-20 21:24:07 -05:00
428809719a enable reboot 2025-09-19 11:46:44 -05:00
45d8c51a75 remove package 2025-09-19 11:25:23 -05:00
7c605a7337 get rid of swap 2025-09-19 10:14:32 -05:00
a3cd499297 fix auto 2025-09-19 09:44:43 -05:00
ac0a4c0580 increase timeout 2025-09-19 09:24:02 -05:00
932beed25a more TS 2025-09-19 08:50:30 -05:00
79f5a9d129 more CI 2025-09-18 22:26:52 -05:00
b2ebe28397 CI 2025-09-18 22:16:45 -05:00
6c300ca545 increase ssh timeout 2025-09-18 21:16:24 -05:00
eea499a32c fix 2025-09-18 09:36:40 -05:00
fcd839a00e set http port 2025-09-18 09:35:20 -05:00
45b5e65e36 fix boot command 2025-09-18 09:32:07 -05:00
900098b9c1 fix 2025-09-18 09:30:17 -05:00
1b5213af1d http port 2025-09-18 09:28:25 -05:00
efcd022d27 troubleshoot cloud init 2025-09-18 09:03:37 -05:00
9f328a01a4 update user-data 2025-09-17 23:28:44 -05:00
97e9c8c037 fixed build issue 2025-09-17 23:21:42 -05:00
b885d1d707 fix ISO 2025-09-17 23:16:50 -05:00
a084340ce0 fix filename 2025-09-17 23:04:49 -05:00
1b5597ac09 fix filename 2025-09-17 23:00:27 -05:00
8710665255 updated packer files 2025-09-17 22:48:49 -05:00
81e292dc2b typo 2025-09-16 22:16:43 -05:00
aa5087882d tweak 2025-09-16 22:09:00 -05:00
1959a667d4 create ubuntu small packer config 2025-09-16 21:55:49 -05:00
405aae5209 sync current state 2025-09-15 22:27:42 -05:00
b7e090ed7c Merge branch 'main' of https://github.com/rblundon/homelab 2025-08-20 09:55:43 -05:00
02b788ee63 ansible kubernetes deployment 2025-08-20 09:52:28 -05:00
a642d2382d start ansible scripts 2025-08-19 17:06:29 -05:00
6ea3611e08 sync 2025-08-18 12:21:05 -05:00
a255908108 fix name 2025-08-18 09:09:43 -05:00
9b85eabf41 additional vm template changes and k8s node definitions 2025-08-18 09:07:03 -05:00
1fb37b2da9 added new template for large-plus 2025-08-17 22:48:39 -05:00
4193f33183 updated packer templates for new proxmox cluster 2025-08-16 21:50:04 -05:00
2ae45aca00 wrong cluster 2025-08-14 22:40:25 -05:00
19f7af6b1c fix issuer 2025-08-14 22:30:26 -05:00
94f609140b change ceert 2025-08-14 22:26:25 -05:00
d60f24183b change ingress 2025-08-14 22:18:00 -05:00
1728ede010 Merge branch 'main' of https://github.com/rblundon/homelab 2025-08-14 22:11:27 -05:00
1d828f455c add monetnaildesign 2025-08-14 22:08:45 -05:00
a12ff980c5 more 2025-08-07 14:39:08 -05:00
9cb44fb15c ? 2025-08-07 14:35:50 -05:00
ffd5e085e1 change ingress controller name 2025-08-07 14:24:49 -05:00
0403077495 undo 2025-08-07 14:13:54 -05:00
2124f86879 ing 2025-08-07 14:12:53 -05:00
86c03c882d create ingress 2025-08-07 14:03:46 -05:00
2725aecb58 update route 2025-08-07 13:58:13 -05:00
0c99612913 fix repo 2025-08-07 13:43:15 -05:00
7e93e9b1b1 updates to homepage 2025-08-07 13:41:09 -05:00
d2d3ee7c78 deploy homepage 2025-08-07 13:37:40 -05:00
8dc2243140 add loadbalancer 2025-08-07 12:14:01 -05:00
2a323f5675 add routeselector 2025-08-07 12:06:49 -05:00
cfc70229ee redeploy 2025-08-07 12:04:17 -05:00
593e71509b remove nginx 2025-08-07 12:02:55 -05:00
bca855046f ingress 2025-08-07 12:01:51 -05:00
7aa29a3f67 change name and namespace 2025-08-07 11:55:53 -05:00
0f27698fef update ingress controller 2025-08-07 11:53:46 -05:00
a493cb75f9 deploy nginx operator 2025-08-07 10:38:10 -05:00
31a4d7e3d3 fix directory structure 2025-08-04 14:06:32 -05:00
79706c90ff deploy metallb to internal cluster and rebove ingress 2025-08-04 14:04:50 -05:00
fabc113c84 fix 2025-08-02 18:48:58 -05:00
01bc13e0a2 change to operator 2025-08-02 18:44:39 -05:00
1eb12c2582 veersion 2025-08-02 18:07:31 -05:00
6d43a0c7a8 fix repo 2025-08-02 18:05:49 -05:00
c85d4f7a3d deploy nginx ingress to internal cluster 2025-08-02 18:04:16 -05:00
7ffc2c983b staged next wave of operators to add and configure 2025-08-01 13:43:38 -05:00
4fd272ddf7 change nfs provisioner 2025-08-01 09:26:48 -05:00
99fb15f8f0 remove nfs via synology 2025-08-01 09:15:07 -05:00
bd27975bf3 change nfs storageclass 2025-07-31 21:28:11 -05:00
ee3f2d7fcf fix yaml 2025-07-31 20:39:42 -05:00
81accaf9a2 image registry 2025-07-31 20:36:10 -05:00
23052096f2 image registry 2025-07-31 20:30:44 -05:00
0fc6bc340b storageclass 2025-07-31 19:58:38 -05:00
36ccbcbab1 fix dir 2025-07-31 15:42:31 -05:00
574fdfe25c open image registry 2025-07-31 15:39:11 -05:00
0987226b0d removed sync wave 2025-07-31 14:52:31 -05:00
b200294ebc yaml formatting 2025-07-31 14:48:25 -05:00
27553fc4d1 remove applications pattern 2025-07-31 14:44:15 -05:00
7925990631 fix cluster target 2025-07-31 14:42:12 -05:00
4639725099 deploy Synology CSI 2025-07-31 14:35:35 -05:00
edb019c38e enable iscsi on cluster 2025-07-31 11:53:16 -05:00
1742dff512 deploy lightspeed and cert manager 2025-07-31 00:18:41 -05:00
01e02a6687 external secrets 2025-07-30 23:41:26 -05:00
bca03f901a remove external secrets 2025-07-30 23:36:54 -05:00
4c72e35707 fix nmstate appset 2025-07-30 22:56:21 -05:00
ff925aee83 apply external secrets operator 2025-07-30 22:44:51 -05:00
05fa4eaa43 updated ansible templates for single node clusters 2025-07-30 21:59:01 -05:00
48b8548528 Move ansible to it's own directory structure 2025-07-30 12:41:18 -05:00
0764cc8bd7 wrong app name 2025-07-29 21:56:08 -05:00
28e57361e2 typo 2025-07-29 21:54:53 -05:00
5e1522fefb refactor nmstate to appset 2025-07-29 21:53:30 -05:00
4a2120f830 uninstall all 2025-07-27 22:08:58 -05:00
e09c33d307 fi values file variable 2025-07-27 21:48:09 -05:00
943795984f fix 2025-07-27 21:45:37 -05:00
796881ecc5 time to break cert manager 2025-07-27 21:37:52 -05:00
cf507a70af added applicarions App of Apps pattern 2025-07-27 21:10:50 -05:00
c104009aaa just internal cluster 2025-07-27 21:06:58 -05:00
d085f80ea7 chhange ESO name 2025-07-27 20:58:39 -05:00
8121e5c048 add lightspeed to hub cluster 2025-07-27 20:51:23 -05:00
c51615543b fix target namespace 2025-07-27 20:40:50 -05:00
625c4b8fe1 ? 2025-07-27 20:36:23 -05:00
23b43a16b3 changed default namespace 2025-07-27 20:26:56 -05:00
44b9d099c7 wrong name 2025-07-27 20:11:06 -05:00
350a149645 change to list generator 2025-07-27 20:10:21 -05:00
b358c93c16 fix appset 2025-07-27 19:46:45 -05:00
6feea89ec1 add lightspeed to internal cluster 2025-07-27 18:36:13 -05:00
b09f8e1ad5 added sync wave tp ESO appset 2025-07-27 16:49:58 -05:00
06b28b1297 added sync waves to ESO 2025-07-27 16:36:01 -05:00
f807f47642 fix cluster 2025-07-27 01:14:08 -05:00
79f231eaa1 fix 2025-07-27 01:12:14 -05:00
e6abae943d switching external secrets to app set 2025-07-27 01:10:47 -05:00
e5f84ccbf2 again 2025-07-27 00:41:09 -05:00
9d482087e5 rename 2025-07-27 00:39:30 -05:00
face668dfc deploy external secrets to internal cluster 2025-07-27 00:38:39 -05:00
8293c842e6 Created Ansible templates for OpenShift nodes and cluster 2025-07-26 21:14:15 -05:00
fc31dd2a5a sync to move 2025-07-26 16:55:43 -05:00
efecef6832 Updated mac addresses and disabled boot interfaces 2025-07-26 14:51:44 -05:00
5612932691 Updated cluster creation playbook 2025-07-26 01:06:44 -05:00
0f4d2dcb7c sync repo to git 2025-07-25 10:36:32 -05:00
c625e48dee Update ansible and add python3-libdnf5 to template installed packages 2025-07-18 14:20:58 -05:00
23bdd17e25 final update to creating VMs 2025-07-14 10:50:29 -05:00
618 changed files with 19353 additions and 14144 deletions

61
.gitignore vendored
View File

@@ -1,15 +1,9 @@
# macOS system files # macOS
.DS_Store .DS_Store
.AppleDouble .AppleDouble
.LSOverride .LSOverride
# Icon must end with two \r
Icon Icon
# Thumbnails
._* ._*
# Files that might appear in the root of a volume
.DocumentRevisions-V100 .DocumentRevisions-V100
.fseventsd .fseventsd
.Spotlight-V100 .Spotlight-V100
@@ -17,36 +11,53 @@ Icon
.Trashes .Trashes
.VolumeIcon.icns .VolumeIcon.icns
.com.apple.timemachine.donotpresent .com.apple.timemachine.donotpresent
# Directories potentially created on remote AFP share
.AppleDB .AppleDB
.AppleDesktop .AppleDesktop
Network Trash Folder Network Trash Folder
Temporary Items Temporary Items
.apdisk .apdisk
# VS Code
.vscode/
# macOS metadata
*.icloud *.icloud
# Terraform # IDE
terraform/ .vscode/
.idea/
.kiro/
# Terraform (track .tf files, ignore state and runtime)
.terraform/ .terraform/
*.tfstate *.tfstate
*.tfstate.backup *.tfstate.backup
# *.tfvars
# Crash log files !*.tfvars.example
!*.pkrvars.hcl
crash.log crash.log
# Ignore override files as they are usually used to override resources locally
*.override.tf *.override.tf
*.override.tf.json *.override.tf.json
# Ignore CLI configuration files
.terraformrc .terraformrc
.terraformrc.json terraform.rc
# Ignore secrets # Ansible
doppler-token.yaml *.retry
ansible/vault/*.vault
# Packer
packer_cache/
# Secrets
*.pem
*.key
# Environment files with secrets
boilerplates/**/.env
# Local paths
~/
# Misc
doppler-token.yaml
# talhelper generated machine configs — contain secrets, never commit
talos/talhelper/clusterconfig/
# talenv.yaml plaintext — only commit the SOPS-encrypted version
talos/talhelper/talenv.yaml
!talos/talhelper/talenv.sops.yaml

3
.sops.yaml Normal file
View File

@@ -0,0 +1,3 @@
creation_rules:
- path_regex: talos/talhelper/talenv.yaml
age: age1xkyuv8r8ce6lu3d64jfspz4e50k6pxlaxwmuplzrtnpfnnrnycaq6mfsrn

166
README.md
View File

@@ -1,102 +1,102 @@
# A Homelab based on Red Hat Technologies # mk-labs
This repository is the configuration of my homelab. In addition to providing services, the purpose of my homelab is to learn advanced concepts primarily based on Red Hat OpenShift. Automated infrastructure provisioning and configuration for a personal homelab, built on GitOps practices with clear tool responsibility boundaries.
This implementation is built on easily accessible consumer based hardware and will focus heavily on GitOps practices and automation will be used wherever possible. ## Architecture
This repo is a mono-repo that is broken up into three sections: A single operator action — setting a VM record's status to **Staged** in NetBox — triggers a fully automated provisioning pipeline:
```
NetBox (webhook) → n8n (validate & orchestrate) → Terraform (create VM + DHCP)
→ Ansible (OS config + DNS + status update)
```
- infra-config | Tool | Host | IP | Responsibility |
- apps |------|------|----|---------------|
- cluster | NetBox | fire-station | 10.1.71.102 | Source of truth — VM records, IP allocation, VLAN data |
| n8n | tiki-room | 10.1.71.23 | Event orchestration, validation, pipeline sequencing |
| Terraform | city-hall | 10.1.71.35 | Proxmox VM lifecycle, Unifi DHCP reservations |
| Ansible / Semaphore | imagineering | 10.1.71.22 | OS configuration, DNS records, NetBox status updates |
| Proxmox | fantasyland | 10.1.71.13 | Target hypervisor |
All systems on the Server Trusted VLAN (10.1.71.0/24).
## Repository Structure
```
homelab/
├── ansible/
│ ├── inventory/ # NetBox dynamic inventory + static
│ ├── playbooks/ # Runnable playbooks (vm-provision, DNS, OS updates)
│ ├── roles/ # vm-baseline, dns-manager, common, haproxy, n8n, observer, etc.
│ ├── tasks/ # Shared includable task files
│ ├── group_vars/ # Group variable definitions
│ ├── host_vars/ # Per-host variable definitions
│ ├── templates/ # Jinja2 templates
│ └── ansible.cfg
├── terraform/
│ ├── proxmox/vm/ # bpg/proxmox provider — VM creation from templates
│ ├── unifi/dhcp/ # Unifi provider — DHCP static reservations on UDM Pro
│ └── dns/ # DNS record management
├── packer/
│ ├── ubuntu-24.04/ # Ubuntu 24.04 VM template (small → xlarge-plus sizes)
│ └── fedora-42/ # Fedora 42 VM template
├── n8n/
│ └── workflows/ # Exported n8n workflow JSON (vm-provisioning)
├── netbox/
│ └── initializers/ # Custom fields, VLANs, IP prefixes as code
└── docs/
└── decisions/ # Architecture decision records
```
## Pipeline Flow
| # | System | Action |
|---|--------|--------|
| 1 | NetBox | Operator sets VM status to Staged → webhook fires |
| 2 | n8n | Validates payload (hostname, IP, VLAN, template, proxmox_node) |
| 3 | n8n → city-hall | SSH + `terraform apply` — creates VM on Proxmox |
| 4 | n8n | Queries Proxmox API for MAC address |
| 5 | n8n → NetBox | Writes MAC to VM interface record |
| 6 | n8n → city-hall | SSH + `terraform apply` — creates DHCP reservation on UDM Pro |
| 7 | n8n → imagineering | Triggers Ansible via Semaphore API |
| 8 | Ansible | OS baseline, SSH hardening, Technitium DNS A record |
| 9 | Ansible → NetBox | Sets VM status to Active |
On any failure, NetBox status is set to **Failed**. No auto-retry — operator investigates.
## Hardware ## Hardware
- Dell 7050 SFF (7) - 7× Dell 7050 SFF
- Minisforum TH60 (3) - 3× Minisforum TH60
- Minisforum MS01 (2) - 2× Minisforum MS01
- Synology 1621+ - Synology DS1621+
- Ubiquiti UDM Pro
## Software ## Software Stack
- Proxmox (Virtualization) - **Virtualization**: Proxmox
- Cloudflare (Domain Hosting, Public DNS) - **Automation**: Terraform, Ansible, n8n, Semaphore
- Unbound (Recursive DNS) - **DNS**: Technitium (authoritative), Unbound (recursive)
- FreeIPA (Identity management, Authoritive DNS) - **IPAM/DCIM**: NetBox
- Matchbox (iPXE) - **Networking**: Ubiquiti UDM Pro
- Red Hat OpenShift - **Templates**: Packer (Ubuntu 24.04, Fedora 42)
- OpenShift Agent Based Installer (Install OpenShift)
- [Red Hat Advanced Cluster Management for Kubernetes](https://www.redhat.com/en/technologies/management/advanced-cluster-management)
- [Vault](https://www.hashicorp.com/en/products/vault)
- [OpenShift GitOps (ArgoCD)](https://www.redhat.com/en/technologies/cloud-computing/openshift/gitops)
- [Red Hat Ansible Automation Platform](https://www.redhat.com/en/technologies/management/ansible)
## Prerequisites
- Ansible user created
- Ansible configured
- [Networking](docs/networks.md)
- [Proxmox](docs/proxmox.md) (In my homelab, internal DNS, identity manangement, and ipxe are hosted here.)
- Matchbox
- DNS
- Domain Registration
## Assumptions
There are a dozen different architectures you could use to deploy OpenShift in every which way.
For the sake of this documentation we'll assume the following:
## Getting Started ## Getting Started
[Step-by-Step Walkthrough](step-by-step.md) See [docs/decisions/vm-provisioning-flow.md](docs/decisions/vm-provisioning-flow.md) for the full architecture decision record.
### Hub Cluster Previous OpenShift/ACM/Fastpass content is preserved in the `archive/pre-mk-labs` branch.
You'll need an OpenShift "Hub Cluster" with access to persistant storage. ## Security
A Single Node OpenShift (SNO) instance, installed on bare metal, will act as a Hub cluster and run:
- Advanced Cluster Management No sensitive data is stored in this repository. Secrets are managed via Ansible Vault and environment variables on pipeline hosts.
- Ansible Automation Platform
- Vault
- ~~OpenShift GitOps~~
#### Network Prerequisites
The prerequisites for OpenShift in traditional and HCP patterns are largely the same - it just kind of depends on where your DNS records go to.
| Cluster | Endpoint | VIP | DNS A Record | Notes |
|------------------|-------------|---------------|-----------------------------------|----------------------------------|
| Hub Cluster (SNO) | App Ingress | 192.168.0.10 | *.apps.hub-cluster.example.com | SNO App VIP goes to IP of node |
| Hub Cluster (SNO) | API | 192.168.0.10 | api.hub-cluster.example.com | SNO API goes to IP of node |
These DNS entries should be put in your Authoratitive DNS.
#### ACM & GitOps Configuration
Before you start creating clusters you may want to create some Policies, integrate ACM and ArgoCD, etc. This step is optional in case you're just interested in trying out Hosted Control Planes or copy/paste around a cluster for testing purposes.
Find additional details in the ./02-rhacm-config folder.
#### Creating a Cluster
With everything in its right place, you can now start to declaratively create clusters
./05-clusters/hcp-bmh - HCP to Bare Metal Hosts
### Internal Cluster
Two additional bare metal nodes, to be added to Advanced Cluster Management (ACM) running on the SNO Hub. These will be used to create another HCP cluster.
These servers have a BMC interface with Redfish - if not, then you'll need to manually manage the boot and installation of those servers.
This makes it to where you just need 3 bare metal nodes. You could run one HCP Bare Metal cluster with both of the other nodes, but then you have a shared storage requirement that can't be satisfied by ODF since that needs at least 3 nodes.
### External Cluster
You'll also either need you just need at least 2 bare metal nodes.
--- ---
## Credits **Status**: 🚧 Active Development — VM Provisioning Pipeline
- Ken Moini - As I used his [repo](https://github.com/kenmoini/ztp-for-you-and-me) as the baseline for this project. **Last Updated**: February 2026
- Ryan Etten
- Andrew Potozniak

View File

@@ -0,0 +1,193 @@
# DNS Management Refactor - Modular & Repeatable
This document explains the refactoring of DNS management from standalone playbooks to modular, reusable tasks.
## 🎯 **What Changed**
### **Before (Monolithic)**
```yaml
# Standalone playbook: add_technitium_dns_entry.yml
- name: Add entry to Technitium DNS
hosts: all
tasks:
- name: Create DNS entry
effectivelywild.technitium_dns.technitium_dns_add_record:
# ... hardcoded parameters
```
### **After (Modular)**
```yaml
# Reusable task: tasks/add_technitium_dns_entry.yml
- name: Create DNS entry for {{ dns_record_name }}
effectivelywild.technitium_dns.technitium_dns_add_record:
# ... parameterized with variables
```
## 📁 **New Structure**
```
ansible/
├── playbooks/
│ ├── tasks/
│ │ └── add_technitium_dns_entry.yml # ✅ Reusable task file
│ ├── add_dns_entry.yml # ✅ New playbook using task
│ ├── add_technitium_dns_entry.yml.backup # 📦 Backed up old version
│ └── roles/
│ └── dns-manager/ # ✅ Enhanced role
│ ├── tasks/main.yml # Uses task file
│ └── defaults/main.yml # Technitium defaults
└── scripts/
└── migrate-dns-references.sh # ✅ Migration helper
```
## 🚀 **Usage Examples**
### **1. In Playbooks (Direct Task Include)**
```yaml
- name: Add DNS entry for my server
hosts: my_servers
tasks:
- name: Create DNS entry
ansible.builtin.include_tasks: tasks/add_technitium_dns_entry.yml
vars:
dns_record_name: "{{ inventory_hostname }}"
dns_zone: "{{ base_domain }}"
dns_ip_address: "{{ ansible_default_ipv4.address }}"
```
### **2. Using the DNS Manager Role**
```yaml
- name: Setup cluster DNS
hosts: control_plane[0]
roles:
- role: dns-manager
vars:
cluster_endpoint: "my-cluster.local.mk-labs.cloud"
cluster_vip: "10.1.71.100"
```
### **3. Using the New Playbook**
```yaml
# Import the new modular playbook
- import_playbook: add_dns_entry.yml
```
### **4. In Cluster Network Setup**
```yaml
- name: Setup complete cluster network
ansible.builtin.include_role:
name: cluster-network-setup
vars:
cluster_name: "fastpass"
cluster_endpoint: "fastpass.local.mk-labs.cloud"
cluster_vip: "10.1.71.53"
```
## 🔧 **Migration Guide**
### **Automatic Migration**
```bash
# Run the migration script to find references
./scripts/migrate-dns-references.sh
```
### **Manual Updates**
1. **Replace playbook imports:**
```yaml
# OLD
- import_playbook: add_technitium_dns_entry.yml
# NEW
- import_playbook: add_dns_entry.yml
```
2. **Use task includes in roles:**
```yaml
- ansible.builtin.include_tasks: tasks/add_technitium_dns_entry.yml
vars:
dns_record_name: "my-server"
dns_ip_address: "10.1.71.100"
```
3. **Use the dns-manager role:**
```yaml
- ansible.builtin.include_role:
name: dns-manager
```
## 📋 **Variable Reference**
### **Task Variables (`tasks/add_technitium_dns_entry.yml`)**
| Variable | Default | Description |
|----------|---------|-------------|
| `dns_record_name` | `inventory_hostname` | DNS record name |
| `dns_zone` | `base_domain` | DNS zone |
| `dns_ip_address` | `ip_address` | IP address for A record |
| `dns_record_type` | `A` | DNS record type |
| `dns_ttl` | `360` | TTL in seconds |
| `dns_create_ptr` | `true` | Create PTR record |
| `dns_debug` | `true` | Show debug output |
### **DNS Manager Role Variables**
| Variable | Default | Description |
|----------|---------|-------------|
| `cluster_endpoint` | - | Full cluster FQDN |
| `cluster_vip` | - | Cluster VIP address |
| `dns_management_enabled` | `true` | Enable DNS management |
| `use_hosts_file_fallback` | `true` | Add to /etc/hosts |
| `dns_ttl` | `360` | DNS TTL |
| `create_ptr_record` | `true` | Create PTR record |
## 🎯 **Benefits**
### ✅ **Modularity**
- Single task file used across multiple contexts
- Consistent DNS management approach
- Easy to maintain and update
### ✅ **Flexibility**
- Works in playbooks, roles, and standalone
- Parameterized for different use cases
- Supports multiple DNS providers (extensible)
### ✅ **Maintainability**
- One place to update DNS logic
- Clear variable interface
- Better error handling and debugging
### ✅ **Integration**
- Seamlessly integrates with cluster setup
- Works with existing homelab infrastructure
- Compatible with Traefik load balancer setup
## 🔄 **Integration with Cluster Setup**
The DNS management now integrates seamlessly with your cluster deployment:
```yaml
# In fastpass-first-control-plane role
- name: Setup network infrastructure for FastPass cluster
ansible.builtin.include_role:
name: cluster-network-setup
vars:
cluster_name: "{{ cluster_name }}"
cluster_endpoint: "{{ control_plane_endpoint }}"
cluster_vip: "{{ ansible_default_ipv4.address }}"
control_plane_nodes: "{{ groups['fastpass_control_plane'] }}"
```
This automatically:
1. ✅ Creates DNS entry for `fastpass.local.mk-labs.cloud`
2. ✅ Configures Traefik load balancer
3. ✅ Tests connectivity
4. ✅ Provides fallback to /etc/hosts
## 🚀 **Next Steps**
1. **Test the refactored approach** with your FastPass cluster
2. **Extend to other clusters** (Hub, Internal) using the same pattern
3. **Add support for other DNS providers** if needed
4. **Create monitoring** for DNS health checks
This modular approach makes your homelab's DNS management much more maintainable and repeatable across all your Kubernetes clusters!

View File

@@ -209,7 +209,7 @@ private_key_file=~/.ssh/ansible
remote_user=wed remote_user=wed
# (pathspec) Colon-separated paths in which Ansible will search for Roles. # (pathspec) Colon-separated paths in which Ansible will search for Roles.
;roles_path=/Users/rblundon/.ansible/roles:/usr/share/ansible/roles:/etc/ansible/roles roles_path=/opt/git/homelab/ansible/playbooks/roles:/Users/rblundon/.ansible/roles:/usr/share/ansible/roles:/etc/ansible/roles
# (string) Set the main callback used to display Ansible output. You can only have one at a time. # (string) Set the main callback used to display Ansible output. You can only have one at a time.
# You can have many other callbacks, but just one can be in charge of stdout. # You can have many other callbacks, but just one can be in charge of stdout.

View File

@@ -0,0 +1,4 @@
---
step_ca_url: "https://turnstile.local.mk-labs.cloud:9000"
step_ca_fingerprint: "f63c44e76381e359978bd2dca07c928d04ad44b575f0364fa66b5725c7e7891b"
step_ca_provisioner_name: "admin"

View File

@@ -0,0 +1,32 @@
---
# file: group_vars/all
# Proxmox variables
proxmox_user: "root@pam"
proxmox_password: "{{ vault_proxmox_root_password }}"
proxmox_host: "main-street-usa.local.mk-labs.cloud"
# DNS variables
dns_server: "monorail" # .local.mk-labs.cloud"
#dns_admin: "admin"
base_domain: "local.mk-labs.cloud"
# DHCP server
#dhcp_server: "matchbox"
# Terraform variables
terraform_server: "infra01"
# Traefik variables
traefik_server: "lightning-lane"
step_ca_principal_mappings:
- local_user: wed
principals:
- ryan.blundon@protonmail.com
- ryan.blundon
- ryanblundon
- local_user: rblundon
principals:
- ryan.blundon@protonmail.com
- ryan.blundon
- ryanblundon

View File

@@ -0,0 +1,306 @@
$ANSIBLE_VAULT;1.1;AES256
33333438373661633337383161343862383963623736636136653339363064386538386437323135
6436666330363032616365656434356161396530363363610a333864313064633232366133366232
37316636366334346536663337663065303635626638666264666435393933343832653061323237
6663333736386636350a653931626665346234323832393334373563303130626262646565653231
30326263623965356639386438636531306430343239313162383065386135653534636134376333
64616432303732646535643530353963363734663538393539633034326535643539356561656632
36363330346131393262326561356631343631356434666264616134643136646238376336373665
65346361636435316437353235393263313766623438336662353532306463353134366435326364
36613865343264616364333631353238663238313338333232626262313637633662633163366638
61323166393739656536656435336538303439636561363961353832313431666432393463636537
62323939376265353330356334303334303532643136376531343765613738656562386665336132
36346232313432396431666535663362333332613037623531636135376439393936353261653863
65373061316461303866363338376131343736323933383636626338616431656533363833663266
62363935313262393733333566386337633630666332353263666462373164346362313034636239
33656462396238343065613965613232623132343562323364653366313231323531326364376631
65643961303862653030343364326533356336393031636437393465636263626236303633326139
65643432663037333332346261323663613031386563383533336538383133373332343363326530
66643231666636366435623639643166333863376533633537363364396663363732333932663333
62333239613264353233303064333931326236396538323130353061366139623362393734323434
36343537393363343861633131346561353637646336313233376162656561623362653565623339
63386337613461343534643964323932356661383436303966346339386131336133643132376330
38656535353335303966636235643666306336396435636434363733313665366234393032333065
37633231376134636435343233363032666231666134623365653238373836326237373831326262
66303234303164303961316166623062616139353264343864363938313733653563663661633535
37326636346435626362336437666364623264363565653935336438386262376663303230313265
62663665666132313436663330616230383235346333623563313262376530356535613263316436
35313766363763386234333733636464326134633136346532346632623534646365623136343363
30316435613031333036383835656230353430636135343961356363613139353763343233633834
38656431363139396535653565633631393462316334666464333839343035616531643466643531
35613733373331643961353830376266376433363938373563653833343464633465663766333066
34633364313762633034633461623232656537653762623532613332386132333365383062653136
63323234626266336462333534636236653230343530336532653831313339613531343731313237
39653737663665373361326433643364656434393838326339636238303964366336363961653366
36643938633635313432663765316130326238306163346566313062626439626263633033623731
63323532346366653238663931653334613734633963363632643462316130393138363436666532
32373833323330356164626332646232623031326365653765336261323661616137373732356164
63383633353764643233323430333233306337623834353934643864636339646239636430316166
33643030333261323461643031613730343131343830353463313766353035326436306566343161
35643534323763316165343832346433356364343061383036306434386631356537363331303035
34303430393034393763343964613935383739656662643066363633333839396465386231383837
30336331393365346636363732616661633635326364366435366466383639353839343731616365
65326633636263653438343561633632646234316461616666363630333966326230356331373335
31353665626233663433633563623765343431376639316232346666663065656462616438663333
62663662336662346563333935333261626635343764356631356363356362346231306535376466
36393932666662653934626134613065623461303834393231616332363461306534303666353632
35646363333065356631393863396536633838343365343238636332303862306631346639656166
30373735336361653863326331373834663164393863666631623866353338366561326635323132
35306535626564376666623837666435663337613164623966306138353161313239373436346239
36656266323233636233326139326266346464353665323465663666646264613466636132626464
37353762306538643233663338613062353134323832653139663036666337643131613062643936
37633363376365356333353433613839653130323036643737633163336531323032393937333432
39343238396534353330346664346135326333333638666261396463656663323935643337313462
32396137613432623664323134356361323861306230353165663162663732326563626162346630
34626536393962393764393764393234373138656432346332633963393135386238313563353761
34366438353337396264373032336166663937343931633635666166343638386237396333626133
38383766616566336163363931393438366566386565663938356630366430393830653037363738
30666465326266363834653934643434666466326632366463303965303366326364316430366561
32636631663232373163636535366333623261366466623262393631626334626263656534386536
66323833353264623538663232376138346361646362313565333534363535663031643833373064
38313062346339636335633962323933383230623634303431383236626166636535326465316439
38646636336130373763646635386265373065326263616438646565313439613830316135616435
62326430336337643265306261343036653938633634626561333664313035393933646533326661
62626437306432353938356338616462663130646530623636393233373837336138383963323165
35643231613565313434386163643637633130626435376561376235346438303234386637383835
37356238616263646665336435306233396436666664396532373063626162346237376662393639
35373665373638396434353062666430633362653163633639623836346438323632643164653638
62623463343465303236346562386338646536656438633966643430343266313935323630616633
62313531343764343966333439343866613965303036616634363162303434643533366465313562
62393666313838313938356265633531326431333730626632343139666338656465306431636162
66343532346238393464366134656334363964626264623263353537633638346239396539653538
37303339613036306533353132326534306433353364613536316263326363323134333639346236
39376263313431666462383863336638306631663563313364333235333338323364613361633532
38313263353539633662353533646333353262356436353938303036663130306362303935356136
63313234363138383864613664666635613464653765636461383738356135623662313866383036
64626437343465333563346434323762313232643230323336366539326631396463303961666461
61656338643532616337653362636362373837373836666535633762343335623033316264366261
62633137356132306430623537616135613965393737323263343463633839393165646630383331
36616339346534346636396532333836633436323232323364303963313030656330386336633538
34383534313236396461653462306130376462396138303561636331663062303864326238303335
65663832333631613963326639386665643135366632393438666361376334636233336239633837
36383761616364363262306535653065303536363066316431303464373230326436336661396231
66333438376664333731333630383031366237396638326534636532343535303964653436633438
64616263366561653334346138393866353437393037343930623237326231303261383733336232
37646533393439653965386563333232656565663531396663303334313839323361363864396332
61656638303130303433666561646663323139643337326561333832373538306236326538363637
38666534633330653564653066643335623938373331376339393338343533366436333330313165
65366562386366666632653064663637343536313462326562626436356363306134306237613265
32366338643237333739626331393763323934396265383138633035646533353536633866313432
38336137383036373434363530353833653938663035306337643638316463373762613931373038
32373361326136616331663733616133623936663530356566383461336334663937383230386462
38656332613763653339363565613762383735333163633831356364333563363630623666616430
30353237653730613361643233386139303639666137653733353334326530306431376666663664
34633531393261343165663330373961646665396139323762313663376639366464306533623333
62326432623334336166656565656230313063656163636561326632666438633966323930316264
66373866663461616336336264356561373232313737353836646632383438333162383832616662
30636437613163613631623165366631306438643765383263626133653231333361383633363136
36653831623562653838633133646633393038666164346461333531373034356435363336636338
62623464376264363537306166613461396630303039373239656664396564333435303164613235
61346238386233653462616632303337663036626465663361636130333566303337313237626237
65636633316366343064663636383362316665633263633136323563363935346138356635653036
36383835323838366363363335323731333066393334373265653563336533616362633163343661
66326630353537653633316631343332303231373630363635623136386537666434383032323165
33333633643064376239346139633664633330323966366430353135616633633465363030386665
36353164623564343934323063313763316566373830643163616633643937323732333561353832
66623364666335316230346665353631663465633034323265666663653866623037353935393262
61623065656637636666383239343661616233396663333038393963366537326136653863333235
65633137626134383763663366396438366634313465363965343830333966373930333134353339
35396538303537316636333339613731623636646230323662613663306537326566656666323434
65346531623533336535393530373963343864313963666335636334396663393837396665373565
39646138356134313732666633663061646330643438393736653433313238373135656636643337
39396362383363333434376336613933613438653636663334336337653633613433623336623461
32373565306435646438306365343465653863656434663937653938393839333739363639326536
64303534383961333333386237366239386330386533343939613664363439373135333731393739
39363166306636333766333332393265613133356262356666343039666237663664636266626664
65316339323638353333653631363365356562623535666235313234613236326130616261663830
34663063626539363734313562656233656131326265626637353239636638396564313561383761
62663638623135343333316464346236353364616239633566393039633339306334623234616331
34366435663938346335323932633330366639653636336636373562306561656536653363366233
39383064623435356338636335343662343435336564363965646439393964323162363736346637
65323765333364353831396433666561376437333834313334316165386631616332633533666336
37313533623535313934393230353439363231623063663961376537393638636237623134323337
30393032333530316330333736616463633262616631353238323933303766646137386465643366
33356665396437623732373437373537303034353431353031313162323730316566396238653038
30366234663037653736353137376264363934646366353761323364663538346662323934343266
30373662613461663561623466633939396439653663353365346133623933613462623231616562
66643738643661643766323266626266313330633936313964366536323263373666303130623738
32323230356665323439646532343930333936373536626466656566363161646663616266326133
32393137663562613531323832313565346632303131646432363961613331346636653830323136
36323436373964313737313131346131353630636561636639316464323666636336656265343565
65303936353165326137613638366532303265356537343337656165366663383961643134656435
61383565306265333939613561613035616663336361396536343939343761663833346134646365
34323233666439623436323261616432363838616437386138393735383364393164646638373630
33386632346239383037633132636431366264383633333365306338333661303662363533376339
62633663366362303038616666336335346332316366353136323666346531393938666236343163
31663665643839313439663839353431343061386465366331663637373532613266383065393639
62613565626135363133623261333061373738633333623337396631356332643039306638303434
65663762373630323263333239613939346133626534613632396433376234663636363062656537
62386664343462346334663662663865653766373738306438316533643962356136653565373761
62393437326138323065396630653838326138653865643937353431656137393732346361353734
31326634653331353232633061303230393462363065613832303630383237366463363666613864
37643135303034326335326563353064343835323863313134616262386564313235653762376332
36636533646235343138396537623266333566633466393764353731393935306432313266636133
63326362653033613264333139633638643638326532313239646239386332323330306538366362
37646432363535396161336465376363343430333261396536346464356135343462663462613136
36666238633663326230373834303431336566366666666534343537313635366537396262656236
36646639643730393134613662383238623835626230313833653932303832323366343765343434
34363033323836663035363166313630313062663162313165636138373261386636623831666632
33373962626237666130373031633437653966386561363232363332333633303961323864333263
39666230383332376537313137643635623336316336646537333137633564376432356432326639
61383565313233376435636366366531363462306535636131636163636130663732383161616364
37343064333264663533343739356139353365386565383833363165326536306431393764303632
30653865623566363965306636366530303261616663306433393135656366383138356337383365
36323736643035383231663034626564643235646237623632383164633062326132363331353634
61653761346439326665366565383534393635616365353361353863363763383664303166383434
33393732313837373336616564343864633330663566653933356237613538653366663838383132
33303437323438313837616134616466626562313262653866313034383764656566373331343738
30613062303630663365636230396231313065356662376163353632613564363066316239636434
66356535386263353737383838653538316366343935323337386561353533353161636538646363
63643739376366326536333261306263653563353331393133323964653764373932663136316335
36333535626231373864316634613366353535393932373039646161646466363663626561373033
64333133353931303361363466346666376431363336323166356162363537633536336638653838
35323562653138393833383130353232616564393738326638366565616233633634336438303632
30353765623565336330386335306162336662643466663335623836383238316161633339373137
32393165323735643034633464313337386362363331353432363233396538393835383933313637
65656330383732633537646361666439303266653165313233636464313964383639346635376538
64633861623439626331643431326336646135656539313836323135373862316438393237663564
31373135356135356662336265633862343435356530393835376430666566653036373338636332
64663230323361356262356537656262396665663538386664363735646234306231613339636338
34366433326535353965376236643661646339366566663531653864316533356466653864373633
33363330333765373662646634326236313434383433653563383436316635353461386662646165
31626566616163373137326165323066646535663766636265386435633965326165303831323633
39613139623835316165326138386431383530383035653931616334353235636138303761383037
39336163373332346365333935656563343939623335313461363138656239666263366236663464
32303732663937363964346639323236623166373334386239613564643834316536363634326461
64623939363635613863613065656363303734643766306564326437663037623839303734393036
64326363626562363934313930383766383462663766336666663338653765656137393362643366
36326336323638393161353464396637633566383262333234656233653334623131323532376637
62613064626532616631646232386631623839326665346431333232333463373031316237363462
30643731653666643331643839343865646437613135346363646131383262396134376363303335
34303164303236383139326264623462363062313139653465346435336163653863633764613631
33623666316530353163396539323238663935643764643939333966336137353034663164643733
34393132323339626331626532643266336435653636353930393738363134353661653636643263
30313138393263383837333438356463636162383938396137363035646433663932613066386138
37316535373939326131643930353435383232623366393630663463633233393232373730333631
37623837373533383462323431323335316231356436303239313535633837353931613730303363
31613765626466636636613366346166393766373834643337353764666532376335376139316138
38646133643736636363363434306334373933633264366530373534666637393835366266306633
66653966613136653936313732396366323830376236626530306139333030323966383035643733
36353833323539393136303035393866366563323430636336356639623734656135356566373062
34666433316139316664643234623530363732373338623162363636303463346463323131333065
64656566353837336266386233323439623237366364343635306137663038326434366531623062
64613365323339613465326464653965613439653766623762363139366264663765363862323839
63346539323961343532626465363266626234363964313531353662636635623165376130616536
64363361383766636333626366616531343833633033643965626435313130653938316430313532
64363731633139383236326231653434663132313463326563393739393132663765396337643035
32373963393830356362366130376135353935396631393533333430363531636234333832373939
36656233343663623262346337323034653036373432303266353333626434353137353939346665
37633432303162323538343339643635636464353333313063363662663033396630303162333639
31633537373364666234653938633461343738333464653736316331343038393333643936646462
36373232373962653031333730363166393463313232616631383233386533373464366465623335
65393462353638633931353331313233356230303565313030663739626230323766666466326339
35303361383065353333666161306433383139366439633730666364383130316637633464646336
66643065303934663765623233333261313939373236396136366566306438626439393163636430
30656334663361396230303239663338373664346362623934313130343064353435626439356562
35653638613037656133313765313165333066353732363361386234353635626563323932356237
31363333326536353536323931643739333764323637356164663566343563633761333462383735
66383134646139373130386366316532656139336231303931656265636130643130616531366530
62383132643236623835323362383866613765343762333536333365336338373264633130656438
36343331666431326530626137333665623836636136303031333965356366396239396534663263
35343730303534313830623430666566386564653036356635623038303133623231616635396463
65626137633033663631373366373238353766323533643462396562633164633730633135396266
36316362353964306463336237383232306530613539653462326137383938333638353038396132
66343265643162363735663235353161393732326530373735363662633165316265323065396163
31663761303637616566396262346238366631663562323566323364663464373930373831323630
39333165336264336539353634633936396561626363353466303931343436306636356663346438
64373561666638656439353964626436613164643663336336333337393332346132313830316430
37336139333539316639646337383737373530643533336133633135333936343165303764623366
35346432656263396439663635653066303861643938633033393334336336396133626237336432
31393061653839653964613239353336653666366163616163616230396661313233613934326339
36333733663032613633613037343337646237666565316239303231313163383264376636336338
37656532373634383132346163316337336534316465383531316465353861633062336235376631
33333963313730653164313866323461353334653231333762336232366434333631396135333466
36643362653137323934323966303734316334306133656139613763336431323236643264663530
38633730346531396435666530316563386566323737343766653135386537393165356264356534
62323962306332393063313062313230333334353833393362656166353638323366353934656263
38633531306438663134616262323332323338653361356336353962376331323537623734316532
35306434383336633436656437663765626530626535383464356532613536356533646332646135
39613030323432643161366363313262633261366566613931303663636262353466313933303162
66373535353934626135326439653630303437666535396266303532626636613563616633623237
38623938323137393065616136376663363234633735363264356438353534616338393832386337
66663339313062613766666435626364353935643932633233643630323464336135336339376437
30323536373639343738613463613466396335626339343135306666663931656564393664643761
65396336613465313035396134636438636134316236636566333031646666383939383264303437
38656337326233363866336363363161333236326137393465633935626165663136316661316131
66393764313130373766386235663134376239323037373365333730643336656532316434663265
35646664383338326366386536616339393938336539373762643839613763323434363037326330
66353738643735656165396138343262653563353934376237366564636638623630393238373530
39336335303564616232393165653639326166333536343966353933633365326539383632646639
37636238376137646239353731343933346562613630656130653865633834626363656231373162
65333662653962373139633466383834626566336234316161633038653137393266393564376439
62343365666637396639326438326631613664666662653935346230316632396361663038663239
63336335643665353162393330623635663839666162333561376265363330383530653733333239
37373665646562343562313764386534663239636130646564333433313661363338326439363865
63353064613161366461383862623363333637633430376361366566383332636634646630363139
65303139396539323336313666336362626339326666343061303431356361343438313365353431
30303266363664373233303231346166643839343564306363613236316665306437333636343131
61303234666664323138376335623639393939633836353664343232316630393263323233343366
32393736336166323166616139323066613062646139656236343233623630616262343034383631
61653662383537646364363764353335333630353431633534313731633265626263303863326565
37616534303164316162353165396236656565303532326235393237366434323739633662663261
33383635653734303233356438636132343731383439623463633732373833303339353662386435
63316138353766303962616435383138373739383835353662613666356565366237353932393263
34326561613234356537343234303166613534356134643766383332646263623430653632386365
61376165656366366532346465343932313032643163313362373633373066653036346238343938
66626133306163353966386662363039323166353330633239386264306337386361653430633838
66366636616661313939316562373330313564383033643035393738353939613066316138643238
35376336633238636463376234376364386464396461636336313562616361396435323639666433
34653139613962623235613035363634383735326564333332333632656237333238356566646536
62346435303932363231306634643037623935653235613330666666656433396463656231643364
34313235613064646432633935656231643162363530313761303339323830653564303963643532
39326163396461613161363031616336666564326630323465663831653431353566643661656435
35636238633663346139343732353233663930353664623636303134303633356232313063346566
30633762653239356131613539396435396235326431633062616436613266353266636133656531
63346533383764393733396436306136383830313265656539376136343536353737313365333865
61653665393037346231656663363432666332383837393264656231386435323333376633333265
39633563653161663531303330393237316132653339653531316538316534353334383161623833
63656534643833656366623031326132343732663536393636393537383338613462336638626334
39326264623032393661303335356235343736613964636261633038333236623232613633343263
34363865306233346433393664363038303464363834313463636363366333313433333930336634
65396232663031323965343336366339623239386566323362396564333932336134336231646430
34376236636536626264663532323530656634333137363431313339643164333236303337373639
31326131636161386665623838303939616337636666346363616465323263373061633832363839
39343131386333666231643931353330343136363732396465383336303866623733316235646234
65613531613333653231666234353532313738363266353336303564613061393639323933646339
64396334396431313563326136656539613535663334323330326566613264393965623065616634
32313333663535313531343363656230656334346430643365363838656430616366653766333136
32346137656136666432383934313865613535303962333464316465313464333233646162376165
37363265316139643332393761663164346537663064346133323661393030393533396633646134
39383539333364626263323364353764316539323162346434656234393562326133613632633137
34323537393838393534643861356365376461636235386638376661623439303832643231616431
32663264306166366336396130326435346432343732323764346232356439633361663937313233
62636130663238333433396335356331653166366130626632663162653736656238343134353134
39373663633437626661393734363264313137663138643665353633366663366562386337396561
38383464333531306138316266626461326531616364303732343337386464366464633834383439
66303334333234306166396235666164313833333164356561663063326563303934373933313334
32326466343761333666373936373332663939643662363665323534333638316637666665326564
63616134623530333739633265343637626561383831663836626538313539653536373165636133
62396432376332356133336461633664336264616566376664643861363838313766393833343366
31386636343835663062396232646663363935396366343361633462643734373437666331383035
30373963323834343138653063313635643062396130373861643134363062363135623730663335
34373935623239363866393932363966366233643732646461343964383563393064396331353331
31646662323364376639316562666465356438386637393130616330663563633839326661643239
62346633353963336239633738336431326638626232313965336361636430323739653734636436
39316363316137366233616431346639663335393737653562356532363634346237336266333132
31343836326538653164653163653738656238326366313532613433333337383263646439326661
65306135363138646665363463636436303864316432663734393130313932643833356161373139
65376334376136313237393336636630643933373165336432643233306366633663333930396364
31393739333730326434313639376365356432376338386430363133666436643837633533616333
36363464633233343130656163353137663165343064373039363439346631393436393430383361
61353563346531353561303935363531333235313731303237326334363763646131653961613334
33306534663238343433363237393234643236393931343230656438353866313638636633396464
61636561333562383964663261316135373235313234613564333333336438646636303561616634
63363033613238323463646165373361613834353230653138623132303731393436386139663533
38393263306139303231626363353931646163323364666161653861643739353262313561393165
6262

View File

@@ -0,0 +1,18 @@
---
# file: group_vars/ntp_servers/vars
#Ansible vars template for NTP servers.
ntp_servers:
- 0.us.pool.ntp.org
- 1.us.pool.ntp.org
allowed_networks:
- "192.168.1.0/24"
- "192.168.2.0/24"
- "192.168.3.0/24"
- "192.168.5.0/24"
- "192.168.9.0/24"
- "192.168.10.0/24"
- "192.168.250.0/24"
- "10.1.71.0/24"
- "10.1.82.0/24"

View File

@@ -0,0 +1,19 @@
---
# ansible/group_vars/proxmox/oidc.yml
#
# Proxmox OIDC configuration for Authentik integration.
# Client credentials come from vault.yml.
proxmox_oidc_realm_name: "authentik"
proxmox_oidc_issuer_url: "https://authentik.local.mk-labs.cloud/application/o/proxmox/"
proxmox_oidc_username_claim: "username"
proxmox_oidc_scopes: "openid email profile"
proxmox_oidc_autocreate: true
proxmox_oidc_default_realm: false
proxmox_oidc_comment: "Authentik SSO"
# ACL entries - grant your Authentik user admin access
proxmox_oidc_acl_entries:
- path: "/"
user: "rblundon@authentik"
role: "Administrator"

View File

@@ -0,0 +1,17 @@
$ANSIBLE_VAULT;1.1;AES256
64613361376364346139313833613465663361336634326430393261366630306466363935613139
3634363235343736643230623865386436333734663531310a343965396534336262356234623966
39353332626662636666383935383530613139626439373664323063633063316264383331646533
3366333837613731310a656462633638376432326365343135373863313665346566383933353630
37303565323630633739396433323165326262363863386233343134636236646366633765616432
33633165613239653762343935386637393437386431383961306436373765343736313634333933
30376463646464303066613561613564353938306664373464333966383664383034616439343735
38363966323366343465393530383736393364373361326234356365363163356632393834393464
39393530356235383830323065636535383138353864373237333164323436623737383435313261
64366362626232386438376131633533633162356432613835656465623762633464353936303236
63353633633262633461353963653534663336396134373435303266386162393965343165303335
65313436666334383965373837376664323861376162373834363439653539383231346634633737
30626431373739633930313937643938343165383536373465613535366562313439396533643864
36323032316131333962373732306334373939333363386564653465303261393337333466316130
32326533353165393635393130396164636363623937313566343333386562616662383038613565
35386638383365633362

View File

@@ -0,0 +1,59 @@
---
# file: host_vars/vm_template/vars
# Ansible vars template for hosts created via cloning.
# Supported hypervisors:
# - Proxmox
platform: "proxmox"
# This is the Proxmox node where all the VM templates are stored. (Templates are not global.)
proxmox_clone_node: "fantasyland"
# Templates are named in the following format (all lower case): <OS Distribution>-<OS Version>-<VM Size>
# Current OS offerings are:
# - Ubuntu
# - 24.04
# - Fedora
# - 42
vm_os_distribution: "ubuntu"
vm_os_version: "24.04"
# Current VM sizes are:
# - Small: 2 cores, 2GB memory, 8 GiB virtual disk
# - Medium: 2 cores, 4GB memory, 16 GiB virtual disk
# - Large: 4 cores, 4GB memory, 32 GiB virtual disk
# - Large Plus: 4 cores, 4GB memory, 48 GiB virtual disk
# - Xlarge: 4 cores, 8GB memory, 64 GiB virtual disk
# - Xlarge Plus: 4 cores, 8GB memory, 128 GiB virtual disk
vm_size: "large"
# Proxmox storage target.
vm_storage: "liberty-tree"
# Proxmox does not yet do dynamic load balancing, the host target sets the target for HA groups
# and backup groups. (ha_group will be factored out in the next functionality update.)
ha_group: "pve03"
proxmox_host_target: "pve03"
# Currently, only single NIC VMs using IPv4 are supported via cloning. The IP address also
# sets the Proxmox VMID. The VMID is a combination of the 3rd and 4th octet of the IPv4 address.
ip_address: 10.1.71.111
# vm_mac_address: 'BC:24:11:11:BC:58'
# Software
# Future enhancement will allow specification of additional software to automatically deploy to
# the VM after creation.
#terraform_version: "1.11.3"
# ---
vm_clone_source: "{{ vm_os_distribution }}-{{ vm_os_version }}-{{ vm_size }}"
hostname: "{{ inventory_hostname }}.{{ base_domain }}" # Change variable to fqdn

View File

@@ -0,0 +1,25 @@
---
# ------------------------------------------------------------------------------
# FILE: ansible/host_vars/astro_orbiter/vars.yml
# HOST: astro-orbiter (10.1.71.130)
# ROLE: Ollama inference host with AMD RX 5700 GPU passthrough
# ------------------------------------------------------------------------------
ansible_host: 10.1.71.130
ansible_user: wed
ansible_become: true
# LVM root expansion — xlarge template uses sda3 partition, standard VG/LV names
common_expand_root_lvm: true
common_root_pv: /dev/sda3
common_root_vg: ubuntu-vg
common_root_lv: ubuntu-lv
# Ollama — all defaults apply; explicitly documented here for visibility
ollama_rocm_version: "6.2"
ollama_default_model: "qwen3:8b"
ollama_hsa_override_gfx_version: "10.1.0"
ollama_data_disk: /dev/sdb
ollama_data_vg: ollama-vg
ollama_data_lv: ollama-lv
ollama_data_dir: /var/lib/ollama

View File

@@ -0,0 +1,58 @@
---
# file: host_vars/vm_template/vars
# Ansible vars template for hosts created via cloning.
# Supported hypervisors:
# - Proxmox
platform: "proxmox"
# This is the Proxmox node where all the VM templates are stored. (Templates are not global.)
proxmox_clone_node: "fantasyland"
# Templates are named in the following format (all lower case): <OS Distribution>-<OS Version>-<VM Size>
# Current OS offerings are:
# - Ubuntu
# - 24.04
# - Fedora
# - 42
vm_os_distribution: "ubuntu"
vm_os_version: "24.04"
# Current VM sizes are:
# - Small: 2 cores, 2GB memory, 8 GiB virtual disk
# - Medium: 2 cores, 4GB memory, 16 GiB virtual disk
# - Large: 4 cores, 4GB memory, 32 GiB virtual disk
# - Large Plus: 4 cores, 4GB memory, 48 GiB virtual disk
# - Xlarge: 4 cores, 8GB memory, 64 GiB virtual disk
# - Xlarge Plus: 4 cores, 8GB memory, 128 GiB virtual disk
vm_size: "large-plus"
# Proxmox storage target.
vm_storage: "general"
# Proxmox does not yet do dynamic load balancing, the host target sets the target for HA groups
# and backup groups. (ha_group will be factored out in the next functionality update.)
ha_group: "pve03"
proxmox_host_target: "pve03"
# Currently, only single NIC VMs using IPv4 are supported via cloning. The IP address also
# sets the Proxmox VMID. The VMID is a combination of the 3rd and 4th octet of the IPv4 address.
ip_address: 10.1.71.52
vm_mac_address: 'BC:24:11:11:BC:58'
# Software
# Future enhancement will allow specification of additional software to automatically deploy to
# the VM after creation.
#terraform_version: "1.11.3"
# ---
vm_clone_source: "{{ vm_os_distribution }}-{{ vm_os_version }}-{{ vm_size }}"
hostname: "{{ inventory_hostname }}.{{ base_domain }}" # Change variable to fqdn

View File

@@ -0,0 +1,99 @@
---
# file: host_vars/vm_template/vars
# Ansible vars template for hosts created via cloning.
# Supported hypervisors:
# - Proxmox
platform: "proxmox"
# Templates are named in the following format (all lower case): <OS Distribution>-<OS Version>-<VM Size>
# Current OS offerings are:
# - Ubuntu (clone)
# - 24.04
# - Fedora (clone)
# - 42
# - Talos (create)
# - 1.11.5
vm_os_distribution: "talos"
vm_os_version: "1.11.5"
# VM ISO
# Talos: talos-v1.11.5-nocloud-amd64.iso
vm_iso_storage: "templates"
vm_iso: "talos-v{{ vm_os_version }}-nocloud-amd64.iso"
# This is the Proxmox node where all the VM templates are stored. (Templates are not global.)
# Comment out for VM create
proxmox_clone_node: "fantasyland"
# Proxmox storage target.
vm_storage: "liberty-tree"
# Current VM sizes are:
# - Small: 2 cores, 2GB memory, 8 GiB virtual disk
# - Medium: 2 cores, 4GB memory, 16 GiB virtual disk
# - Large: 4 cores, 4GB memory, 32 GiB virtual disk
# - Large Plus: 4 cores, 4GB memory, 48 GiB virtual disk
# - Xlarge: 4 cores, 8GB memory, 64 GiB virtual disk
# - Xlarge Plus: 4 cores, 8GB memory, 128 GiB virtual disk
vm_size: "large-plus"
# Proxmox does not yet do dynamic load balancing, the host target sets the target for HA groups
# and backup groups. (ha_group will be factored out in the next functionality update.)
ha_group: "pve03"
proxmox_host_target: "pve03"
# Currently, only single NIC VMs using IPv4 are supported via cloning. The IP address also
# sets the Proxmox VMID. The VMID is a combination of the 3rd and 4th octet of the IPv4 address.
ip_address: 10.1.71.52
vm_mac_address: 'BC:24:11:11:BC:58'
# Software
# Future enhancement will allow specification of additional software to automatically deploy to
# the VM after creation.
#terraform_version: "1.11.3"
# ---
vm_clone_source: "{{ vm_os_distribution }}-{{ vm_os_version }}-{{ vm_size }}"
hostname: "{{ inventory_hostname }}.{{ base_domain }}" # Change variable to fqdn
# Dictionaries for VM resources
# - cores (quantity)
# - memory (MB)
# - virtual disk (GiB)
vm_definitions:
small:
cores: 2
memory: 2048
disk: 8
medium:
cores: 2
memory: 4096
disk: 16
large:
cores: 4
memory: 4096
disk: 32
large-plus:
cores: 4
memory: 4096
disk: 48
xlarge:
cores: 4
memory: 8192
disk: 64
xlarge-plus:
cores: 4
memory: 8192
disk: 128

View File

@@ -0,0 +1,48 @@
---
# file: host_vars/vm_template/vars
# Ansible vars template for hosts created via cloning.
# Supported hypervisors:
# - Proxmox
platform: "proxmox"
# This is the Proxmox node where all the VM templates are stored. (Templates are not global.)
proxmox_clone_node: "fantasyland"
# Templates are named in the following format (all lower case): <OS Distribution>-<OS Version>-<VM Size>
# Current OS offerings are:
# - Fedora (42)
# Current VM sizes are:
# - Small: 2 cores, 2GB memory, 8 GiB virtual disk
# - Medium: 2 cores, 4GB memory, 16 GiB virtual disk
# - Large: 4 cores, 4GB memory, 32 GiB virtual disk
# - Xlarge: 4 cores, 8GB memory, 64 GiB virtual disk
vm_clone_source: "fedora-42-small"
# Proxmox storage target.
vm_storage: "mk-general"
# Proxmox does not yet do dynamic load balancing, the host target sets the target for HA groups
# and backup groups. (ha_group will be factored out in the next functionality update.)
ha_group: "pve03"
proxmox_host_target: "pve03"
# Currently, only single NIC VMs using IPv4 are supported via cloning. The IP address also
# sets the Proxmox VMID. The VMID is a combination of the 3rd and 4th octet of the IPv4 address.
ip_address: 10.1.71.21
# Software
# Future enhancement will allow specification of additional software to automatically deploy to
# the VM after creation.
#terraform_version: "1.11.3"
# ---
hostname: "{{ inventory_hostname }}.{{ base_domain }}" # Change variable to fqdn

View File

@@ -1,9 +1,9 @@
--- ---
# file: host_vars/matchbox/vars # file: host_vars/docker01/vars
# Networking # Networking
# primary_interface: "enp1s0f0" # primary_interface: "enp1s0f0"
mac_address: "BC:24:11:03:A9:7B" #mac_address: "BC:24:11:03:A9:7B"
ip_address: 10.1.71.211 ip_address: 10.1.71.211
hostname: "{{ inventory_hostname }}.{{ base_domain }}" hostname: "{{ inventory_hostname }}.{{ base_domain }}"

View File

@@ -0,0 +1,12 @@
---
# file: host_vars/guest-relations/vars
# guest-relations — Guest Relations
# VM provisioned by Terraform (pre-pipeline bootstrap)
# ─── Network ─────────────────────────────────────────────────────────────────
ip_address: 10.1.71.40
# ─── Application ─────────────────────────────────────────────────────────────
app_role: identity_provider
app_name: authentik
app_deployment: docker_compose

View File

@@ -0,0 +1,60 @@
---
# file: host_vars/vm_template/vars
# Ansible vars template for hosts created via cloning.
# Supported hypervisors:
# - Proxmox
platform: "proxmox"
# This is the Proxmox node where all the VM templates are stored. (Templates are not global.)
proxmox_clone_node: "fantasyland"
# Templates are named in the following format (all lower case): <OS Distribution>-<OS Version>-<VM Size>
# Current OS offerings are:
# - Ubuntu
# - 24.04
# - Fedora
# - 42
vm_os_distribution: "ubuntu"
vm_os_version: "24.04"
# Current VM sizes are:
# - Small: 2 cores, 2GB memory, 8 GiB virtual disk
# - Medium: 2 cores, 4GB memory, 16 GiB virtual disk
# - Large: 4 cores, 4GB memory, 32 GiB virtual disk
# - Large Plus: 4 cores, 4GB memory, 48 GiB virtual disk
# - Xlarge: 4 cores, 8GB memory, 64 GiB virtual disk
# - Xlarge Plus: 4 cores, 8GB memory, 128 GiB virtual disk
vm_size: "xlarge"
# Proxmox storage target.
vm_storage: "general"
# Proxmox does not yet do dynamic load balancing, the host target sets the target for HA groups
# and backup groups. (ha_group will be factored out in the next functionality update.)
ha_group: "pve03"
proxmox_host_target: "pve03"
# Currently, only single NIC VMs using IPv4 are supported via cloning. The IP address also
# sets the Proxmox VMID. The VMID is a combination of the 3rd and 4th octet of the IPv4 address.
ip_address: 10.1.71.61
vm_mac_address: 'BC:24:11:C9:3A:13'
# Software
# Future enhancement will allow specification of additional software to automatically deploy to
# the VM after creation.
#terraform_version: "1.11.3"
# ---
vm_clone_source: "{{ vm_os_distribution }}-{{ vm_os_version }}-{{ vm_size }}"
hostname: "{{ inventory_hostname }}.{{ base_domain }}" # Change variable to fqdn

View File

@@ -0,0 +1,99 @@
---
# file: host_vars/vm_template/vars
# Ansible vars template for hosts created via cloning.
# Supported hypervisors:
# - Proxmox
platform: "proxmox"
# Templates are named in the following format (all lower case): <OS Distribution>-<OS Version>-<VM Size>
# Current OS offerings are:
# - Ubuntu (clone)
# - 24.04
# - Fedora (clone)
# - 42
# - Talos (create)
# - 1.11.5
vm_os_distribution: "talos"
vm_os_version: "1.11.5"
# VM ISO
# Talos: talos-v1.11.5-nocloud-amd64.iso
vm_iso_storage: "templates"
vm_iso: "talos-v{{ vm_os_version }}-nocloud-amd64.iso"
# This is the Proxmox node where all the VM templates are stored. (Templates are not global.)
# Comment out for VM create
proxmox_clone_node: "fantasyland"
# Proxmox storage target.
vm_storage: "liberty-tree"
# Current VM sizes are:
# - Small: 2 cores, 2GB memory, 8 GiB virtual disk
# - Medium: 2 cores, 4GB memory, 16 GiB virtual disk
# - Large: 4 cores, 4GB memory, 32 GiB virtual disk
# - Large Plus: 4 cores, 4GB memory, 48 GiB virtual disk
# - Xlarge: 4 cores, 8GB memory, 64 GiB virtual disk
# - Xlarge Plus: 4 cores, 8GB memory, 128 GiB virtual disk
vm_size: "xlarge"
# Proxmox does not yet do dynamic load balancing, the host target sets the target for HA groups
# and backup groups. (ha_group will be factored out in the next functionality update.)
ha_group: "pve03"
proxmox_host_target: "pve03"
# Currently, only single NIC VMs using IPv4 are supported via cloning. The IP address also
# sets the Proxmox VMID. The VMID is a combination of the 3rd and 4th octet of the IPv4 address.
ip_address: 10.1.71.61
vm_mac_address: 'BC:24:11:C9:3A:13'
# Software
# Future enhancement will allow specification of additional software to automatically deploy to
# the VM after creation.
#terraform_version: "1.11.3"
# ---
vm_clone_source: "{{ vm_os_distribution }}-{{ vm_os_version }}-{{ vm_size }}"
hostname: "{{ inventory_hostname }}.{{ base_domain }}" # Change variable to fqdn
# Dictionaries for VM resources
# - cores (quantity)
# - memory (MB)
# - virtual disk (GiB)
vm_definitions:
small:
cores: 2
memory: 2048
disk: 8
medium:
cores: 2
memory: 4096
disk: 16
large:
cores: 4
memory: 4096
disk: 32
large-plus:
cores: 4
memory: 4096
disk: 48
xlarge:
cores: 4
memory: 8192
disk: 64
xlarge-plus:
cores: 4
memory: 8192
disk: 128

View File

@@ -0,0 +1,12 @@
---
# file: host_vars/lightning_lane/vars
# lightning-lane — Traefik Reverse Proxy / Load Balancer
# VM provisioned by Terraform (pre-pipeline bootstrap)
# ─── Network ─────────────────────────────────────────────────────────────────
ip_address: 10.1.71.35
# ─── Application ─────────────────────────────────────────────────────────────
app_role: reverse_proxy
app_name: traefik
app_deployment: docker_compose

View File

@@ -0,0 +1,59 @@
---
# file: host_vars/vm_template/vars
# Ansible vars template for hosts created via cloning.
# Supported hypervisors:
# - Proxmox
platform: "proxmox"
# This is the Proxmox node where all the VM templates are stored. (Templates are not global.)
proxmox_clone_node: "fantasyland"
# Templates are named in the following format (all lower case): <OS Distribution>-<OS Version>-<VM Size>
# Current OS offerings are:
# - Ubuntu
# - 24.04
# - Fedora
# - 42
vm_os_distribution: "ubuntu"
vm_os_version: "24.04"
# Current VM sizes are:
# - Small: 2 cores, 2GB memory, 8 GiB virtual disk
# - Medium: 2 cores, 4GB memory, 16 GiB virtual disk
# - Large: 4 cores, 4GB memory, 32 GiB virtual disk
# - Large Plus: 4 cores, 4GB memory, 48 GiB virtual disk
# - Xlarge: 4 cores, 8GB memory, 64 GiB virtual disk
# - Xlarge Plus: 4 cores, 8GB memory, 128 GiB virtual disk
vm_size: "xlarge"
# Proxmox storage target.
vm_storage: "general"
# Proxmox does not yet do dynamic load balancing, the host target sets the target for HA groups
# and backup groups. (ha_group will be factored out in the next functionality update.)
ha_group: "pve03"
proxmox_host_target: "pve03"
# Currently, only single NIC VMs using IPv4 are supported via cloning. The IP address also
# sets the Proxmox VMID. The VMID is a combination of the 3rd and 4th octet of the IPv4 address.
ip_address: 10.1.71.62
vm_mac_address: 'BC:24:11:AA:8F:3A'
# Software
# Future enhancement will allow specification of additional software to automatically deploy to
# the VM after creation.
#terraform_version: "1.11.3"
# ---
vm_clone_source: "{{ vm_os_distribution }}-{{ vm_os_version }}-{{ vm_size }}"
hostname: "{{ inventory_hostname }}.{{ base_domain }}" # Change variable to fqdn

View File

@@ -0,0 +1,99 @@
---
# file: host_vars/vm_template/vars
# Ansible vars template for hosts created via cloning.
# Supported hypervisors:
# - Proxmox
platform: "proxmox"
# Templates are named in the following format (all lower case): <OS Distribution>-<OS Version>-<VM Size>
# Current OS offerings are:
# - Ubuntu (clone)
# - 24.04
# - Fedora (clone)
# - 42
# - Talos (create)
# - 1.11.5
vm_os_distribution: "talos"
vm_os_version: "1.11.5"
# VM ISO
# Talos: talos-v1.11.5-nocloud-amd64.iso
vm_iso_storage: "templates"
vm_iso: "talos-v{{ vm_os_version }}-nocloud-amd64.iso"
# This is the Proxmox node where all the VM templates are stored. (Templates are not global.)
# Comment out for VM create
proxmox_clone_node: "fantasyland"
# Proxmox storage target.
vm_storage: "liberty-tree"
# Current VM sizes are:
# - Small: 2 cores, 2GB memory, 8 GiB virtual disk
# - Medium: 2 cores, 4GB memory, 16 GiB virtual disk
# - Large: 4 cores, 4GB memory, 32 GiB virtual disk
# - Large Plus: 4 cores, 4GB memory, 48 GiB virtual disk
# - Xlarge: 4 cores, 8GB memory, 64 GiB virtual disk
# - Xlarge Plus: 4 cores, 8GB memory, 128 GiB virtual disk
vm_size: "xlarge"
# Proxmox does not yet do dynamic load balancing, the host target sets the target for HA groups
# and backup groups. (ha_group will be factored out in the next functionality update.)
ha_group: "pve03"
proxmox_host_target: "pve03"
# Currently, only single NIC VMs using IPv4 are supported via cloning. The IP address also
# sets the Proxmox VMID. The VMID is a combination of the 3rd and 4th octet of the IPv4 address.
ip_address: 10.1.71.62
vm_mac_address: 'BC:24:11:AA:8F:3A'
# Software
# Future enhancement will allow specification of additional software to automatically deploy to
# the VM after creation.
#terraform_version: "1.11.3"
# ---
vm_clone_source: "{{ vm_os_distribution }}-{{ vm_os_version }}-{{ vm_size }}"
hostname: "{{ inventory_hostname }}.{{ base_domain }}" # Change variable to fqdn
# Dictionaries for VM resources
# - cores (quantity)
# - memory (MB)
# - virtual disk (GiB)
vm_definitions:
small:
cores: 2
memory: 2048
disk: 8
medium:
cores: 2
memory: 4096
disk: 16
large:
cores: 4
memory: 4096
disk: 32
large-plus:
cores: 4
memory: 4096
disk: 48
xlarge:
cores: 4
memory: 8192
disk: 64
xlarge-plus:
cores: 4
memory: 8192
disk: 128

View File

@@ -0,0 +1,59 @@
---
# file: host_vars/vm_template/vars
# Ansible vars template for hosts created via cloning.
# Supported hypervisors:
# - Proxmox
platform: "proxmox"
# This is the Proxmox node where all the VM templates are stored. (Templates are not global.)
proxmox_clone_node: "fantasyland"
# Templates are named in the following format (all lower case): <OS Distribution>-<OS Version>-<VM Size>
# Current OS offerings are:
# - Ubuntu
# - 24.04
# - Fedora
# - 42
vm_os_distribution: "ubuntu"
vm_os_version: "24.04"
# Current VM sizes are:
# - Small: 2 cores, 2GB memory, 8 GiB virtual disk
# - Medium: 2 cores, 4GB memory, 16 GiB virtual disk
# - Large: 4 cores, 4GB memory, 32 GiB virtual disk
# - Large Plus: 4 cores, 4GB memory, 48 GiB virtual disk
# - Xlarge: 4 cores, 8GB memory, 64 GiB virtual disk
# - Xlarge Plus: 4 cores, 8GB memory, 128 GiB virtual disk
vm_size: "large-plus"
# Proxmox storage target.
vm_storage: "general"
# Proxmox does not yet do dynamic load balancing, the host target sets the target for HA groups
# and backup groups. (ha_group will be factored out in the next functionality update.)
ha_group: "pve03"
proxmox_host_target: "pve03"
# Currently, only single NIC VMs using IPv4 are supported via cloning. The IP address also
# sets the Proxmox VMID. The VMID is a combination of the 3rd and 4th octet of the IPv4 address.
ip_address: 10.1.71.51
vm_mac_address: 'BC:24:11:1A:E8:8C'
# Software
# Future enhancement will allow specification of additional software to automatically deploy to
# the VM after creation.
#terraform_version: "1.11.3"
# ---
vm_clone_source: "{{ vm_os_distribution }}-{{ vm_os_version }}-{{ vm_size }}"
hostname: "{{ inventory_hostname }}.{{ base_domain }}" # Change variable to fqdn

View File

@@ -0,0 +1,99 @@
---
# file: host_vars/vm_template/vars
# Ansible vars template for hosts created via cloning.
# Supported hypervisors:
# - Proxmox
platform: "proxmox"
# Templates are named in the following format (all lower case): <OS Distribution>-<OS Version>-<VM Size>
# Current OS offerings are:
# - Ubuntu (clone)
# - 24.04
# - Fedora (clone)
# - 42
# - Talos (create)
# - 1.11.5
vm_os_distribution: "talos"
vm_os_version: "1.11.5"
# VM ISO
# Talos: talos-v1.11.5-nocloud-amd64.iso
vm_iso_storage: "templates"
vm_iso: "talos-v{{ vm_os_version }}-nocloud-amd64.iso"
# This is the Proxmox node where all the VM templates are stored. (Templates are not global.)
# Comment out for VM create
proxmox_clone_node: "fantasyland"
# Proxmox storage target.
vm_storage: "liberty-tree"
# Current VM sizes are:
# - Small: 2 cores, 2GB memory, 8 GiB virtual disk
# - Medium: 2 cores, 4GB memory, 16 GiB virtual disk
# - Large: 4 cores, 4GB memory, 32 GiB virtual disk
# - Large Plus: 4 cores, 4GB memory, 48 GiB virtual disk
# - Xlarge: 4 cores, 8GB memory, 64 GiB virtual disk
# - Xlarge Plus: 4 cores, 8GB memory, 128 GiB virtual disk
vm_size: "large-plus"
# Proxmox does not yet do dynamic load balancing, the host target sets the target for HA groups
# and backup groups. (ha_group will be factored out in the next functionality update.)
ha_group: "pve03"
proxmox_host_target: "pve03"
# Currently, only single NIC VMs using IPv4 are supported via cloning. The IP address also
# sets the Proxmox VMID. The VMID is a combination of the 3rd and 4th octet of the IPv4 address.
ip_address: 10.1.71.51
vm_mac_address: 'BC:24:11:1A:E8:8C'
# Software
# Future enhancement will allow specification of additional software to automatically deploy to
# the VM after creation.
#terraform_version: "1.11.3"
# ---
vm_clone_source: "{{ vm_os_distribution }}-{{ vm_os_version }}-{{ vm_size }}"
hostname: "{{ inventory_hostname }}.{{ base_domain }}" # Change variable to fqdn
# Dictionaries for VM resources
# - cores (quantity)
# - memory (MB)
# - virtual disk (GiB)
vm_definitions:
small:
cores: 2
memory: 2048
disk: 8
medium:
cores: 2
memory: 4096
disk: 16
large:
cores: 4
memory: 4096
disk: 32
large-plus:
cores: 4
memory: 4096
disk: 48
xlarge:
cores: 4
memory: 8192
disk: 64
xlarge-plus:
cores: 4
memory: 8192
disk: 128

View File

@@ -0,0 +1,59 @@
---
# file: host_vars/vm_template/vars
# Ansible vars template for hosts created via cloning.
# Supported hypervisors:
# - Proxmox
platform: "proxmox"
# This is the Proxmox node where all the VM templates are stored. (Templates are not global.)
proxmox_clone_node: "fantasyland"
# Templates are named in the following format (all lower case): <OS Distribution>-<OS Version>-<VM Size>
# Current OS offerings are:
# - Ubuntu
# - 24.04
# - Fedora
# - 42
vm_os_distribution: "ubuntu"
vm_os_version: "24.04"
# Current VM sizes are:
# - Small: 2 cores, 2GB memory, 8 GiB virtual disk
# - Medium: 2 cores, 4GB memory, 16 GiB virtual disk
# - Large: 4 cores, 4GB memory, 32 GiB virtual disk
# - Large Plus: 4 cores, 4GB memory, 48 GiB virtual disk
# - Xlarge: 4 cores, 8GB memory, 64 GiB virtual disk
# - Xlarge Plus: 4 cores, 8GB memory, 128 GiB virtual disk
vm_size: "large-plus"
# Proxmox storage target.
vm_storage: "general"
# Proxmox does not yet do dynamic load balancing, the host target sets the target for HA groups
# and backup groups. (ha_group will be factored out in the next functionality update.)
ha_group: "pve03"
proxmox_host_target: "pve03"
# Currently, only single NIC VMs using IPv4 are supported via cloning. The IP address also
# sets the Proxmox VMID. The VMID is a combination of the 3rd and 4th octet of the IPv4 address.
ip_address: 10.1.71.53
vm_mac_address: 'BC:24:11:84:D7:2F'
# Software
# Future enhancement will allow specification of additional software to automatically deploy to
# the VM after creation.
#terraform_version: "1.11.3"
# ---
vm_clone_source: "{{ vm_os_distribution }}-{{ vm_os_version }}-{{ vm_size }}"
hostname: "{{ inventory_hostname }}.{{ base_domain }}" # Change variable to fqdn

View File

@@ -0,0 +1,99 @@
---
# file: host_vars/vm_template/vars
# Ansible vars template for hosts created via cloning.
# Supported hypervisors:
# - Proxmox
platform: "proxmox"
# Templates are named in the following format (all lower case): <OS Distribution>-<OS Version>-<VM Size>
# Current OS offerings are:
# - Ubuntu (clone)
# - 24.04
# - Fedora (clone)
# - 42
# - Talos (create)
# - 1.11.5
vm_os_distribution: "talos"
vm_os_version: "1.11.5"
# VM ISO
# Talos: talos-v1.11.5-nocloud-amd64.iso
vm_iso_storage: "templates"
vm_iso: "talos-v{{ vm_os_version }}-nocloud-amd64.iso"
# This is the Proxmox node where all the VM templates are stored. (Templates are not global.)
# Comment out for VM create
proxmox_clone_node: "fantasyland"
# Proxmox storage target.
vm_storage: "liberty-tree"
# Current VM sizes are:
# - Small: 2 cores, 2GB memory, 8 GiB virtual disk
# - Medium: 2 cores, 4GB memory, 16 GiB virtual disk
# - Large: 4 cores, 4GB memory, 32 GiB virtual disk
# - Large Plus: 4 cores, 4GB memory, 48 GiB virtual disk
# - Xlarge: 4 cores, 8GB memory, 64 GiB virtual disk
# - Xlarge Plus: 4 cores, 8GB memory, 128 GiB virtual disk
vm_size: "large-plus"
# Proxmox does not yet do dynamic load balancing, the host target sets the target for HA groups
# and backup groups. (ha_group will be factored out in the next functionality update.)
ha_group: "pve03"
proxmox_host_target: "pve03"
# Currently, only single NIC VMs using IPv4 are supported via cloning. The IP address also
# sets the Proxmox VMID. The VMID is a combination of the 3rd and 4th octet of the IPv4 address.
ip_address: 10.1.71.53
vm_mac_address: 'BC:24:11:84:D7:2F'
# Software
# Future enhancement will allow specification of additional software to automatically deploy to
# the VM after creation.
#terraform_version: "1.11.3"
# ---
vm_clone_source: "{{ vm_os_distribution }}-{{ vm_os_version }}-{{ vm_size }}"
hostname: "{{ inventory_hostname }}.{{ base_domain }}" # Change variable to fqdn
# Dictionaries for VM resources
# - cores (quantity)
# - memory (MB)
# - virtual disk (GiB)
vm_definitions:
small:
cores: 2
memory: 2048
disk: 8
medium:
cores: 2
memory: 4096
disk: 16
large:
cores: 4
memory: 4096
disk: 32
large-plus:
cores: 4
memory: 4096
disk: 48
xlarge:
cores: 4
memory: 8192
disk: 64
xlarge-plus:
cores: 4
memory: 8192
disk: 128

View File

@@ -0,0 +1,100 @@
---
# file: host_vars/vm_template/vars
# Ansible vars template for hosts creation via clone or create.
# Supported hypervisors:
# - Proxmox
platform: "proxmox"
# Templates are named in the following format (all lower case): <OS Distribution>-<OS Version>-<VM Size>
# Current OS offerings are:
# - Ubuntu (clone)
# - 24.04
# - Fedora (clone)
# - 42
# - Talos (create)
# - 1.11.5
vm_os_distribution: "talos"
vm_os_version: "1.11.5"
# VM ISO
# Talos: talos-v1.11.5-nocloud-amd64.iso
vm_iso_storage: "templates"
vm_iso: "talos-v{{ vm_os_version }}-nocloud-amd64.iso"
# This is the Proxmox node where all the VM templates are stored. (Templates are not global.)
# Comment out for VM create
proxmox_clone_node: "fantasyland"
# Proxmox storage target.
vm_storage: "liberty-tree"
# Current VM sizes are:
# - Small: 2 cores, 2GB memory, 8 GiB virtual disk
# - Medium: 2 cores, 4GB memory, 16 GiB virtual disk
# - Large: 4 cores, 4GB memory, 32 GiB virtual disk
# - Large Plus: 4 cores, 4GB memory, 48 GiB virtual disk
# - Xlarge: 4 cores, 8GB memory, 64 GiB virtual disk
# - Xlarge Plus: 4 cores, 8GB memory, 128 GiB virtual disk
vm_size: "small"
# Proxmox does not yet do dynamic load balancing, the host target sets the target for HA groups
# and backup groups. (ha_group will be factored out in the next functionality update.)
ha_group: "pve03"
proxmox_host_target: "tomorrowland"
# Currently, only single NIC VMs using IPv4 are supported via cloning. The IP address also
# sets the Proxmox VMID. The VMID is a combination of the 3rd and 4th octet of the IPv4 address.
# Comment out vm_mac_address if new MAC address should be generated
ip_address: 10.1.71.99
vm_mac_address: 'BC:24:11:97:C3:AA'
# Software
# Future enhancement will allow specification of additional software to automatically deploy to
# the VM after creation.
#terraform_version: "1.11.3"
# ---
vm_clone_source: "{{ vm_os_distribution }}-{{ vm_os_version }}-{{ vm_size }}"
hostname: "{{ inventory_hostname }}.{{ base_domain }}" # Change variable to fqdn
# Dictionaries for VM resources
# - cores (quantity)
# - memory (MB)
# - virtual disk (GiB)
vm_definitions:
small:
cores: 2
memory: 2048
disk: 8
medium:
cores: 2
memory: 4096
disk: 16
large:
cores: 4
memory: 4096
disk: 32
large-plus:
cores: 4
memory: 4096
disk: 48
xlarge:
cores: 4
memory: 8192
disk: 64
xlarge-plus:
cores: 4
memory: 8192
disk: 128

View File

@@ -0,0 +1,50 @@
---
# file: host_vars/vm_template/vars
# Ansible vars template for hosts created via cloning.
# Supported hypervisors:
# - Proxmox
platform: "proxmox"
# This is the Proxmox node where all the VM templates are stored. (Templates are not global.)
proxmox_clone_node: "fantasyland"
# Templates are named in the following format (all lower case): <OS Distribution>-<OS Version>-<VM Size>
# Current OS offerings are:
# - Fedora (42)
# Current VM sizes are:
# - Small: 2 cores, 2GB memory, 8 GiB virtual disk
# - Medium: 2 cores, 4GB memory, 16 GiB virtual disk
# - Large: 4 cores, 4GB memory, 32 GiB virtual disk
# - Large Plus: 4 cores, 4GB memory, 48 GiB virtual disk
# - Xlarge: 4 cores, 8GB memory, 64 GiB virtual disk
# - Xlarge Plus: 4 cores, 8GB memory, 128 GiB virtual disk
vm_clone_source: "fedora-42-small"
# Proxmox storage target.
vm_storage: "general"
# Proxmox does not yet do dynamic load balancing, the host target sets the target for HA groups
# and backup groups. (ha_group will be factored out in the next functionality update.)
ha_group: "fantasyland"
proxmox_host_target: "fantasyland"
# Currently, only single NIC VMs using IPv4 are supported via cloning. The IP address also
# sets the Proxmox VMID. The VMID is a combination of the 3rd and 4th octet of the IPv4 address.
ip_address: 10.1.71.21
# Software
# Future enhancement will allow specification of additional software to automatically deploy to
# the VM after creation.
#terraform_version: "1.11.3"
# ---
hostname: "{{ inventory_hostname }}.{{ base_domain }}" # Change variable to fqdn

View File

@@ -0,0 +1,59 @@
---
# file: host_vars/vm_template/vars
# Ansible vars template for hosts created via cloning.
# Supported hypervisors:
# - Proxmox
platform: "proxmox"
# This is the Proxmox node where all the VM templates are stored. (Templates are not global.)
proxmox_clone_node: "fantasyland"
# Templates are named in the following format (all lower case): <OS Distribution>-<OS Version>-<VM Size>
# Current OS offerings are:
# - Ubuntu
# - 24.04
# - Fedora
# - 42
vm_os_distribution: "ubuntu"
vm_os_version: "24.04"
# Current VM sizes are:
# - Small: 2 cores, 2GB memory, 8 GiB virtual disk
# - Medium: 2 cores, 4GB memory, 16 GiB virtual disk
# - Large: 4 cores, 4GB memory, 32 GiB virtual disk
# - Large Plus: 4 cores, 4GB memory, 48 GiB virtual disk
# - Xlarge: 4 cores, 8GB memory, 64 GiB virtual disk
# - Xlarge Plus: 4 cores, 8GB memory, 128 GiB virtual disk
vm_size: "large"
# Proxmox storage target.
vm_storage: "general"
# Proxmox does not yet do dynamic load balancing, the host target sets the target for HA groups
# and backup groups. (ha_group will be factored out in the next functionality update.)
ha_group: "pve03"
proxmox_host_target: "pve03"
# Currently, only single NIC VMs using IPv4 are supported via cloning. The IP address also
# sets the Proxmox VMID. The VMID is a combination of the 3rd and 4th octet of the IPv4 address.
ip_address: 10.1.71.23
# vm_mac_address: 'BC:24:11:11:BC:58'
# Software
# Future enhancement will allow specification of additional software to automatically deploy to
# the VM after creation.
#terraform_version: "1.11.3"
# ---
vm_clone_source: "{{ vm_os_distribution }}-{{ vm_os_version }}-{{ vm_size }}"
hostname: "{{ inventory_hostname }}.{{ base_domain }}" # Change variable to fqdn

View File

@@ -0,0 +1,27 @@
---
# file: host_vars/turnstile/vars
# turnstile — Smallstep step-ca SSH Certificate Authority
# VM provisioned by Terraform (pre-pipeline bootstrap)
# ─── Network ─────────────────────────────────────────────────────────────────
ip_address: 10.1.71.34
# ─── Application ─────────────────────────────────────────────────────────────
app_role: ssh_certificate_authority
app_name: step-ca
app_deployment: docker_compose
# ─── step-ca Configuration ───────────────────────────────────────────────────
stepca_hostname: turnstile.local.mk-labs.cloud
stepca_dns_names: "turnstile.local.mk-labs.cloud,10.1.71.34"
stepca_ssh_enabled: true
stepca_listen_port: 9000
# ─── OIDC Provisioner (Authentik) ────────────────────────────────────────────
# Client ID and secret stored in vault
stepca_oidc_provisioner_name: authentik
stepca_oidc_configuration_endpoint: "https://authentik.local.mk-labs.cloud/application/o/step-ca/.well-known/openid-configuration"
stepca_oidc_listen_address: ":10000"
stepca_oidc_domains:
- "local.mk-labs.cloud"
- "protonmail.com"

View File

@@ -0,0 +1,17 @@
$ANSIBLE_VAULT;1.1;AES256
30383930323363386234333433636465393263613336646464666365643730386430353864616334
3865343031653162313736656437373666636136653263360a613961646133376262633164393535
31363434633634303035663133316230633538363936303266373931313661346563333832653032
6239376363646530620a303231363333363233623038326165316463383662656565626534396232
62333133623530643932643430663166373930353733363866336533643233373261333130613635
31633337376337663833613634666436383862386431636537373363343333323932363761653366
61353166613162346436396138316561646165303566376366323462663861616364336539313138
30386430373566353761383636626335393463376661356666303861353564313832346333396134
30653861363866336331336164323130623230666237356165613934333239386536373664643065
33643139346562346663313533643433353462363665323166313364373335366665373435643935
65303863663864393238393732303065343364306264396333376233666233346664323334336532
38373164383835663163363137643531303163396236623565666436363261393563343133333161
36663934303633663062346161636333396135336135616136303664636562363862353764343562
39643430396636313139336130656363306562363430346233313530663963366238326334623135
62383632613061316262323038303333323739303137363334626637666663666263613132336433
65346266393733633632

View File

@@ -0,0 +1,104 @@
---
# file: host_vars/vm_template/vars
# Ansible vars template for hosts creation via clone or create.
# Supported hypervisors:
# - Proxmox
platform: "proxmox"
# Templates are named in the following format (all lower case): <OS Distribution>-<OS Version>-<VM Size>
# Current OS offerings are:
# - Ubuntu (clone)
# - 24.04
# - Fedora (clone)
# - 42
# - Talos (create)
# - 1.11.5
vm_os_distribution: "ubuntu"
vm_os_version: "24.04"
# VM ISO
# Talos: talos-v1.11.5-nocloud-amd64.iso
vm_iso_storage: "templates"
vm_iso: "talos-v{{ vm_os_version }}-nocloud-amd64.iso"
# This is the Proxmox node where all the VM templates are stored. (Templates are not global.)
# Comment out for VM create
proxmox_clone_node: "fantasyland"
# Proxmox storage target.
vm_storage: "general"
# Current VM sizes are:
# - Small: 2 cores, 2GB memory, 8 GiB virtual disk
# - Medium: 2 cores, 4GB memory, 16 GiB virtual disk
# - Large: 4 cores, 4GB memory, 32 GiB virtual disk
# - Large Plus: 4 cores, 4GB memory, 48 GiB virtual disk
# - Xlarge: 4 cores, 8GB memory, 64 GiB virtual disk
# - Xlarge Plus: 4 cores, 8GB memory, 128 GiB virtual disk
vm_size: "large-plus"
# Proxmox does not yet do dynamic load balancing, the host target sets the target for HA groups
# and backup groups. (ha_group will be factored out in the next functionality update.)
ha_group: "pve03"
proxmox_host_target: "tomorrowland"
# Currently, only single NIC VMs using IPv4 are supported via cloning. The IP address also
# sets the Proxmox VMID. The VMID is a combination of the 3rd and 4th octet of the IPv4 address.
# Comment out vm_mac_address if new MAC address should be generated
ip_address: 10.1.71.249
# vm_mac_address: 'BC:24:11:11:BC:58'
# Software
# Future enhancement will allow specification of additional software to automatically deploy to
# the VM after creation.
#terraform_version: "1.11.3"
# ---
vm_clone_source: "{{ vm_os_distribution }}-{{ vm_os_version }}-{{ vm_size }}"
hostname: "{{ inventory_hostname }}.{{ base_domain }}" # Change variable to fqdn
# Dictionaries for VM resources
# - cores (quantity)
# - memory (MB)
# - virtual disk (GiB)
small:
cores: 2
memory: 2048
disk: 8
medium:
cores: 2
memory: 4096
disk: 16
large:
cores: 4
memory: 4096
disk: 32
large-plus:
cores: 4
memory: 4096
disk: 48
xlarge:
cores: 4
memory: 8192
disk: 64
xlarge-plus:
cores: 4
memory: 8192
disk: 128

99
ansible/inventory.yml Executable file
View File

@@ -0,0 +1,99 @@
# file: inventory.yml
proxmox:
hosts:
main-street-usa:
ansible_host: 10.1.71.11
ansible_user: wed
ansible_become: true
tomorrowland:
fantasyland:
magic_kingdom:
hosts:
main-street-usa:
tomorrowland:
fantasyland:
dns_server:
hosts:
monorail:
ntp_servers:
hosts:
sundial:
load_balancers:
hosts:
lightning-lane:
ansible_become: true
step_ca_server:
hosts:
turnstile:
ansible_become: true
authentik_server:
hosts:
guest-relations:
ansible_become: true
gitea_servers:
hosts:
mad-tea-party:
ansible_user: wed
ansible_become: true
nextcloud_server:
hosts:
the-grid:
ansible_become: true
semaphore_server:
hosts:
imagineering:
ansible_host: 10.1.71.37
ansible_become: true
n8n_server:
hosts:
tiki-room:
ollama_server:
hosts:
astro-orbiter:
ansible_host: 10.1.71.130
ansible_user: wed
ansible_become: true
papermc_server:
# ansible-galaxy role install engonzal.papermc
hosts:
arcade:
dev_servers:
hosts:
scrim:
# dhcp_server:
# hosts:
# matchbox:
backup_servers:
hosts:
timekeeper:
talos_control:
hosts:
city-hall:
ansible_become: true
vars:
talosctl_version: "v1.12.4"
talos_cluster_name: "fastpass"
# matchbox_server:
# hosts:
# matchbox:
terraform_server:
hosts:
infra01:

5
ansible/mk Executable file
View File

@@ -0,0 +1,5 @@
space-mountain
splash-mountain
big-thunder-mountain
peter-pans-flight
haunted-mansion

View File

@@ -0,0 +1,84 @@
---
- name: Bind VM MAC address to IP address on Ubiquiti
hosts: all
gather_facts: false
tasks:
- name: Set VM MAC address (if defined in vars)
delegate_to: "localhost"
community.proxmox.proxmox_kvm:
api_user: "{{ proxmox_user }}"
api_password: "{{ proxmox_password }}"
api_host: "{{ proxmox_host }}"
node: "{{ proxmox_clone_node }}"
vmid: "{{ vm_id }}"
net:
net0: "virtio={{ vm_mac_address }},bridge=vmbr0,firewall=1"
update: true
update_unsafe: true
when: vm_mac_address is defined
- name: Get VM MAC address from Proxmox (not defined in vars)
when: vm_mac_address is not defined
block:
- name: Retrieve information about specific VM by name and get current configuration
delegate_to: "localhost"
community.proxmox.proxmox_vm_info:
api_user: "{{ proxmox_user }}"
api_password: "{{ proxmox_password }}"
api_host: "{{ proxmox_host }}"
name: "{{ inventory_hostname }}"
config: current
register: proxmox_vm_info
- name: Extract net0 information
ansible.builtin.set_fact:
vm_net0: "{{ proxmox_vm_info.proxmox_vms[0].config.net0 }}"
- name: Extract MAC address using regex
ansible.builtin.set_fact:
vm_mac_address: "{{ vm_net0 | regex_search('([0-9A-Fa-f]{2}:){5}[0-9A-Fa-f]{2}') }}"
- name: Assign VM MAC address to IP address on Ubiquiti with Terraform
when: vm_mac_address is defined
delegate_to: "{{ groups['terraform_server'][0] }}"
block:
- name: Create a directory if it does not exist
ansible.builtin.file:
path: "~/homelab/terraform/unifi-dhcp"
state: directory
mode: '0755'
- name: Create Unifi provider file from template
ansible.builtin.template:
src: templates/unifi_provider.tf.j2
dest: ~/homelab/terraform/unifi-dhcp/provider.tf
mode: '0644'
- name: Create Unifi user (host) file from template
ansible.builtin.template:
src: templates/unifi-user.tf.j2
dest: ~/homelab/terraform/unifi-dhcp/{{ inventory_hostname }}.tf
mode: '0644'
- name: Configure Unifi via Terraform
community.general.terraform:
project_path: ~/homelab/terraform/unifi-dhcp
state: present
force_init: true
# - name: Add line to hosts file
# delegate_to: "{{ groups['dhcp_server'][0] }}"
# become: true
# ansible.builtin.lineinfile:
# path: /etc/dnsmasq.d/hosts.conf
# regexp: "# {{ inventory_hostname }}$"
# line: "dhcp-host={{ vm_mac_address | lower }},{{ ip_address }} # {{ inventory_hostname }}"
# state: present
# # restart dnsmasq service
# - name: Restart service dnsmasq
# delegate_to: "{{ groups['dhcp_server'][0] }}"
# become: true
# ansible.builtin.service:
# name: dnsmasq
# state: restarted

View File

@@ -0,0 +1,13 @@
---
# Replacement for add_technitium_dns_entry.yml
# This playbook uses the modular task file approach
- name: Add DNS entry using Technitium DNS
hosts: all
gather_facts: false
tasks:
- name: Include Technitium DNS entry task
ansible.builtin.include_tasks: tasks/add_technitium_dns_entry.yml
vars:
host_name: "{{ inventory_hostname }}"

View File

@@ -0,0 +1,90 @@
---
# ------------------------------------------------------------------------------
# FILE: playbooks/add_service_route.yml
# DESCRIPTION: Ensures all services in the Traefik dynamic config directory
# are routed and have DNS CNAME records on monorail.
#
# 1. Syncs boilerplates/traefik/dynamic/ to lightning-lane
# 2. Scans the directory for service configs
# 3. Creates CNAME records for each service -> lightning-lane
#
# PREREQUISITES:
# - Service dynamic config YAML committed to boilerplates/traefik/dynamic/
# - vault_technitium_api_key defined in group_vars/all/vault
#
# USAGE:
# ansible-playbook -i inventory.yml playbooks/add_service_route.yml
#
# ADDING A NEW SERVICE:
# 1. Create boilerplates/traefik/dynamic/<service>.yml
# 2. Commit and push
# 3. Run this playbook
#
# EXCLUDING FILES:
# Files that are not service routes (e.g., default.yml for middleware
# definitions) should be added to the exclude_configs list below.
# ------------------------------------------------------------------------------
- name: Sync Traefik routes and ensure DNS records
hosts: localhost
connection: local
gather_facts: false
vars:
base_domain: "local.mk-labs.cloud"
dns_server: "monorail"
traefik_host: "10.1.71.35"
traefik_user: "wed"
traefik_dynamic_path: "/opt/docker/traefik/dynamic/"
dynamic_config_dir: "{{ playbook_dir }}/../../boilerplates/traefik/dynamic"
# Files in the dynamic directory that are NOT service routes
# (middleware definitions, TLS options, etc.)
exclude_configs:
- default.yml
tasks:
# ── Step 1: Sync dynamic config to lightning-lane ──
- name: Sync Traefik dynamic configuration to lightning-lane
ansible.builtin.shell: >
rsync -av --delete
{{ dynamic_config_dir }}/
{{ traefik_user }}@{{ traefik_host }}:{{ traefik_dynamic_path }}
register: sync_result
changed_when: "'sending incremental file list' in sync_result.stdout"
# ── Step 2: Discover service configs ──
- name: Find all dynamic config files
ansible.builtin.find:
paths: "{{ dynamic_config_dir }}"
patterns: "*.yml"
register: config_files
- name: Build service list from config filenames
ansible.builtin.set_fact:
service_names: >-
{{ config_files.files
| map(attribute='path')
| map('basename')
| reject('in', exclude_configs)
| map('regex_replace', '\.yml$', '')
| list }}
- name: Display services to route
ansible.builtin.debug:
msg: "Services found: {{ service_names }}"
# ── Step 3: Create DNS CNAME records ──
- name: Create DNS CNAME record for each service
effectivelywild.technitium_dns.technitium_dns_add_record:
api_url: "http://{{ dns_server }}.{{ base_domain }}"
api_token: "{{ vault_technitium_api_key }}"
zone: "{{ base_domain }}"
name: "{{ item }}.{{ base_domain }}"
type: "CNAME"
cname: "lightning-lane.{{ base_domain }}"
ttl: 360
validate_certs: false
loop: "{{ service_names }}"
loop_control:
label: "{{ item }}.{{ base_domain }}"

View File

@@ -0,0 +1,18 @@
---
- name: Add entry to Technitium DNS
hosts: all
gather_facts: false
tasks:
- name: "Create DNS entry for {{ inventory_hostname }}"
delegate_to: localhost
effectivelywild.technitium_dns.technitium_dns_add_record:
api_url: "http://{{ dns_server }}.{{ base_domain }}"
api_token: "{{ vault_technitium_api_key }}"
zone: "{{ base_domain }}"
name: "{{ inventory_hostname }}.{{ base_domain }}"
type: "A"
ipAddress: "{{ ip_address }}"
ptr: true
ttl: 360
# validate_certs: false

View File

@@ -0,0 +1,20 @@
---
# ansible/playbooks/configure_proxmox_oidc.yml
#
# Configures Proxmox OIDC authentication with Authentik.
# Only targets one node since realm config is cluster-wide.
#
# Usage:
# cd ansible
# ansible-playbook -i inventory.yml playbooks/configure_proxmox_oidc.yml
#
# To also set up ACL entries for your user:
# ansible-playbook -i inventory.yml playbooks/configure_proxmox_oidc.yml \
# -e '{"proxmox_oidc_acl_entries": [{"path": "/", "user": "rblundon@authentik", "role": "Administrator"}]}'
- name: Configure Proxmox Authentik OIDC
hosts: main-street-usa
become: true
roles:
- role: proxmox
tags: [proxmox-oidc]

View File

@@ -0,0 +1,37 @@
---
- name: Master playbook to install and configure unbound
hosts: unbound_servers
become: true
tasks:
- name: Permit traffic in default zone for dns service
ansible.posix.firewalld:
service: dns
permanent: true
immediate: true
state: enabled
- name: Create the directory
ansible.builtin.file:
path: /etc/systemd/resolved.conf.d
state: directory
mode: '0755'
owner: root
group: root
- name: Put `unbound.conf` in the correct place
ansible.builtin.copy:
src: ../roles/common/files/unbound.conf
dest: /etc/systemd/resolved.conf.d/unbound.conf
mode: '0644'
owner: root
group: root
- name: Restart service systemd-resolved
ansible.builtin.service:
name: systemd-resolved
state: restarted
- name: Install unbound via role
ansible.builtin.import_role:
name: Anthony25.unbound

23
ansible/playbooks/create_vm.yml Executable file
View File

@@ -0,0 +1,23 @@
---
- name: Master playbook to create VM
hosts: all
gather_facts: false
- name: Proxmox Create VM Playbook
ansible.builtin.import_playbook: proxmox_create_vm.yml
- name: Set cloud-init network
ansible.builtin.import_playbook: populate_cloud_init.yml
when: vm_os_distribution == "ubuntu"
- name: DNS Playbook
ansible.builtin.import_playbook: add_dns_entry.yml
- name: DHCP Playbook
ansible.builtin.import_playbook: add_dhcp_reservation.yml
- name: Start VM Playbook
ansible.builtin.import_playbook: proxmox_start_vm.yml
- name: Set Hostname Playbook
ansible.builtin.import_playbook: set_hostname.yml

View File

@@ -6,11 +6,15 @@
- name: Proxmox Clone VM Playbook - name: Proxmox Clone VM Playbook
ansible.builtin.import_playbook: proxmox_clone_vm.yml ansible.builtin.import_playbook: proxmox_clone_vm.yml
- name: Set cloud-init network
ansible.builtin.import_playbook: populate_cloud_init.yml
when: vm_os_distribution == "ubuntu"
- name: DNS Playbook - name: DNS Playbook
ansible.builtin.import_playbook: add_dns_entry.yml ansible.builtin.import_playbook: add_dns_entry.yml
- name: DHCP Playbook - name: DHCP Playbook
ansible.builtin.import_playbook: add_dhcp_entry.yml ansible.builtin.import_playbook: add_dhcp_reservation.yml
- name: Start VM Playbook - name: Start VM Playbook
ansible.builtin.import_playbook: proxmox_start_vm.yml ansible.builtin.import_playbook: proxmox_start_vm.yml

View File

@@ -0,0 +1,6 @@
---
- name: Apply common role
hosts: "{{ target | default('all') }}"
become: true
roles:
- common

View File

@@ -0,0 +1,400 @@
---
# ansible/playbooks/day1_configure_netbox_catalog.yml
#
# Creates the tag taxonomy and custom fields in NetBox for service catalog
# documentation. Run once (idempotent — uses name-based checks).
#
# Usage (from ansible/ directory):
# ansible-playbook playbooks/day1_configure_netbox_catalog.yml
#
# Requires:
# - vault_netbox_token in Ansible Vault
# - netbox reachable at http://fire-station.local.mk-labs.cloud
- name: Configure NetBox service catalog taxonomy
hosts: localhost
gather_facts: false
vars_files:
- "{{ playbook_dir }}/../group_vars/all/vault"
vars:
netbox_url: "http://fire-station.local.mk-labs.cloud"
netbox_token: "{{ vault_netbox_token }}"
netbox_api: "{{ netbox_url }}/api"
headers:
Authorization: "Token {{ netbox_token }}"
Content-Type: "application/json"
Accept: "application/json"
# ── Tag definitions ───────────────────────────────────────────────────
tags:
# Infrastructure type
- name: k8s
slug: k8s
color: "2196f3" # blue
description: "Workload running in the fastpass Kubernetes cluster"
- name: vm
slug: vm
color: "4caf50" # green
description: "Traditional VM or LXC on Proxmox"
# Service tier
- name: platform
slug: platform
color: "9c27b0" # purple
description: "Platform/infrastructure service (not user-facing)"
- name: application
slug: application
color: "ff9800" # orange
description: "User-facing application workload"
# Service categories
- name: monitoring
slug: monitoring
color: "607d8b" # grey
description: "Metrics, logging, alerting"
- name: auth
slug: auth
color: "607d8b"
description: "Authentication and SSO"
- name: gitops
slug: gitops
color: "607d8b"
description: "GitOps and CI/CD"
- name: dashboard
slug: dashboard
color: "607d8b"
description: "Dashboard and portal services"
- name: storage
slug: storage
color: "607d8b"
description: "Storage and file services"
- name: dns
slug: dns
color: "607d8b"
description: "DNS and name resolution"
- name: automation
slug: automation
color: "607d8b"
description: "Automation and orchestration"
- name: networking
slug: networking
color: "607d8b"
description: "Network infrastructure services"
- name: inference
slug: inference
color: "607d8b"
description: "AI/ML inference workloads"
# ── Custom field definitions ──────────────────────────────────────────
# object_types use app_label.model format
custom_fields:
- name: hostnames
label: Hostnames
type: longtext
object_types:
- ipam.ipaddress
- virtualization.virtualmachine
description: "All DNS names that resolve to this service (comma-separated)"
ui_visible: always
ui_editable: yes
- name: namespace
label: Namespace
type: text
object_types:
- ipam.ipaddress
- virtualization.virtualmachine
description: "Kubernetes namespace (blank for VM-based services)"
ui_visible: always
ui_editable: yes
- name: managed_by
label: Managed By
type: select
object_types:
- ipam.ipaddress
- virtualization.virtualmachine
description: "How this service is managed"
choices:
- ArgoCD
- Ansible
- Manual
ui_visible: always
ui_editable: yes
- name: thematic_name
label: Thematic Name
type: text
object_types:
- ipam.ipaddress
- virtualization.virtualmachine
description: "Disney/Magic Kingdom thematic hostname for this service"
ui_visible: always
ui_editable: yes
tasks:
# ── Tags ─────────────────────────────────────────────────────────────
- name: Fetch existing tags
ansible.builtin.uri:
url: "{{ netbox_api }}/extras/tags/?limit=200"
method: GET
headers: "{{ headers }}"
return_content: true
status_code: 200
register: existing_tags_response
- name: Set existing tag slugs fact
ansible.builtin.set_fact:
existing_tag_slugs: "{{ existing_tags_response.json.results | map(attribute='slug') | list }}"
- name: Create tags
ansible.builtin.uri:
url: "{{ netbox_api }}/extras/tags/"
method: POST
headers: "{{ headers }}"
body_format: json
body:
name: "{{ item.name }}"
slug: "{{ item.slug }}"
color: "{{ item.color }}"
description: "{{ item.description }}"
status_code: 201
loop: "{{ tags }}"
when: item.slug not in existing_tag_slugs
register: tag_creation
changed_when: tag_creation.status == 201
# ── Custom Fields ─────────────────────────────────────────────────────
- name: Fetch existing custom fields
ansible.builtin.uri:
url: "{{ netbox_api }}/extras/custom-fields/?limit=200"
method: GET
headers: "{{ headers }}"
return_content: true
status_code: 200
register: existing_cf_response
- name: Set existing custom field names fact
ansible.builtin.set_fact:
existing_cf_names: "{{ existing_cf_response.json.results | map(attribute='name') | list }}"
- name: Create custom field — hostnames
ansible.builtin.uri:
url: "{{ netbox_api }}/extras/custom-fields/"
method: POST
headers: "{{ headers }}"
body_format: json
body:
name: hostnames
label: Hostnames
type: longtext
object_types: "{{ custom_fields[0].object_types }}"
description: "{{ custom_fields[0].description }}"
ui_visible: always
ui_editable: yes
status_code: 201
when: "'hostnames' not in existing_cf_names"
register: cf_hostnames
changed_when: cf_hostnames.status == 201
- name: Create custom field — namespace
ansible.builtin.uri:
url: "{{ netbox_api }}/extras/custom-fields/"
method: POST
headers: "{{ headers }}"
body_format: json
body:
name: namespace
label: Namespace
type: text
object_types: "{{ custom_fields[1].object_types }}"
description: "{{ custom_fields[1].description }}"
ui_visible: always
ui_editable: yes
status_code: 201
when: "'namespace' not in existing_cf_names"
register: cf_namespace
changed_when: cf_namespace.status == 201
- name: Create choice set for managed_by field
ansible.builtin.uri:
url: "{{ netbox_api }}/extras/custom-field-choice-sets/"
method: POST
headers: "{{ headers }}"
body_format: json
body:
name: managed-by-choices
extra_choices:
- - ArgoCD
- ArgoCD
- - Ansible
- Ansible
- - Manual
- Manual
status_code: [201, 400]
register: choice_set
changed_when: choice_set.status == 201
- name: Fetch choice set ID
ansible.builtin.uri:
url: "{{ netbox_api }}/extras/custom-field-choice-sets/?name=managed-by-choices"
method: GET
headers: "{{ headers }}"
return_content: true
status_code: 200
register: choice_set_response
- name: Create custom field — managed_by
ansible.builtin.uri:
url: "{{ netbox_api }}/extras/custom-fields/"
method: POST
headers: "{{ headers }}"
body_format: json
body:
name: managed_by
label: Managed By
type: select
object_types: "{{ custom_fields[2].object_types }}"
description: "{{ custom_fields[2].description }}"
choice_set: "{{ choice_set_response.json.results[0].id }}"
ui_visible: always
ui_editable: yes
status_code: 201
when: "'managed_by' not in existing_cf_names"
register: cf_managed_by
changed_when: cf_managed_by.status == 201
- name: Create custom field — thematic_name
ansible.builtin.uri:
url: "{{ netbox_api }}/extras/custom-fields/"
method: POST
headers: "{{ headers }}"
body_format: json
body:
name: thematic_name
label: Thematic Name
type: text
object_types: "{{ custom_fields[3].object_types }}"
description: "{{ custom_fields[3].description }}"
ui_visible: always
ui_editable: yes
status_code: 201
when: "'thematic_name' not in existing_cf_names"
register: cf_thematic_name
changed_when: cf_thematic_name.status == 201
# ── Provisioning Pipeline Fields ──────────────────────────────────────
# These fields drive the NetBox → n8n → Terraform pipeline.
# proxmox_datastore already exists — PATCH it to add utilidor choice.
# data_disk_enabled and data_disk_size_gb are new POSTs.
- name: Fetch proxmox_datastore field ID
ansible.builtin.uri:
url: "{{ netbox_api }}/extras/custom-fields/?name=proxmox_datastore"
method: GET
headers: "{{ headers }}"
return_content: true
status_code: 200
register: proxmox_datastore_cf_response
- name: Fetch proxmox-datastore-choices choice set ID
ansible.builtin.uri:
url: "{{ netbox_api }}/extras/custom-field-choice-sets/?name=proxmox-datastore-choices"
method: GET
headers: "{{ headers }}"
return_content: true
status_code: 200
register: datastore_choice_set_response
- name: Create proxmox-datastore-choices choice set if missing
ansible.builtin.uri:
url: "{{ netbox_api }}/extras/custom-field-choice-sets/"
method: POST
headers: "{{ headers }}"
body_format: json
body:
name: proxmox-datastore-choices
extra_choices:
- - liberty-tree
- liberty-tree
- - utilidor
- utilidor
status_code: [201, 400]
register: datastore_choice_set_create
changed_when: datastore_choice_set_create.status == 201
when: datastore_choice_set_response.json.count == 0
- name: Re-fetch proxmox-datastore-choices choice set ID after possible creation
ansible.builtin.uri:
url: "{{ netbox_api }}/extras/custom-field-choice-sets/?name=proxmox-datastore-choices"
method: GET
headers: "{{ headers }}"
return_content: true
status_code: 200
register: datastore_choice_set_response
- name: Patch proxmox_datastore field to use choice set with utilidor
ansible.builtin.uri:
url: "{{ netbox_api }}/extras/custom-fields/{{ proxmox_datastore_cf_response.json.results[0].id }}/"
method: PATCH
headers: "{{ headers }}"
body_format: json
body:
choice_set: "{{ datastore_choice_set_response.json.results[0].id }}"
status_code: 200
when: proxmox_datastore_cf_response.json.count > 0
register: cf_datastore_patch
changed_when: cf_datastore_patch.status == 200
- name: Create custom field — data_disk_enabled
ansible.builtin.uri:
url: "{{ netbox_api }}/extras/custom-fields/"
method: POST
headers: "{{ headers }}"
body_format: json
body:
name: data_disk_enabled
label: Data Disk Enabled
type: boolean
object_types:
- virtualization.virtualmachine
description: "When true, Terraform provisions a second disk for application data storage."
default: false
ui_visible: always
ui_editable: yes
status_code: 201
when: "'data_disk_enabled' not in existing_cf_names"
register: cf_data_disk_enabled
changed_when: cf_data_disk_enabled.status == 201
- name: Create custom field — data_disk_size_gb
ansible.builtin.uri:
url: "{{ netbox_api }}/extras/custom-fields/"
method: POST
headers: "{{ headers }}"
body_format: json
body:
name: data_disk_size_gb
label: Data Disk Size (GB)
type: integer
object_types:
- virtualization.virtualmachine
description: "Size in GB for the optional second data disk. Only used when data_disk_enabled is true."
ui_visible: always
ui_editable: yes
status_code: 201
when: "'data_disk_size_gb' not in existing_cf_names"
register: cf_data_disk_size
changed_when: cf_data_disk_size.status == 201
# ── Summary ───────────────────────────────────────────────────────────
- name: Summary
ansible.builtin.debug:
msg:
- "Tags created: {{ tag_creation.results | selectattr('status', 'equalto', 201) | list | length }}"
- "Tags skipped (already exist): {{ tag_creation.results | selectattr('skipped', 'defined') | list | length }}"
- "Custom fields configured: hostnames, namespace, managed_by, thematic_name, proxmox_datastore (patched), data_disk_enabled, data_disk_size_gb"

View File

@@ -0,0 +1,18 @@
---
# ------------------------------------------------------------------------------
# FILE: playbooks/deploy_authentik.yml
# DESCRIPTION: Deploys Authentik identity provider on guest-relations.
# Installs Docker and configures Authentik with PostgreSQL and Redis.
#
# USAGE:
# ansible-playbook -i inventory.yml playbooks/deploy_authentik.yml
# ------------------------------------------------------------------------------
- name: Deploy Authentik identity provider
hosts: authentik_server
become: true
roles:
- common
- docker-host
- authentik

View File

@@ -0,0 +1,23 @@
---
# ------------------------------------------------------------------------------
# FILE: ansible/playbooks/day1_deploy_gitea.yml
# DESCRIPTION: Deploys Gitea + PostgreSQL on mad-tea-party (10.1.71.129)
# Role chain: common → docker-host → gitea
#
# USAGE:
# ansible-playbook -i ansible/inventory.yml ansible/playbooks/day1_deploy_gitea.yml
#
# SECRETS REQUIRED IN VAULT (group_vars/all/vault):
# vault_gitea_db_password
# ------------------------------------------------------------------------------
- name: Deploy Gitea on mad-tea-party
hosts: gitea_servers
become: true
vars:
gitea_db_password: "{{ vault_gitea_db_password }}"
roles:
- role: docker-host
- role: gitea

View File

@@ -0,0 +1,91 @@
---
# ------------------------------------------------------------------------------
# FILE: playbooks/day1_deploy_nextcloud.yml
# DESCRIPTION: Deploys Nextcloud on the-grid
# Runs: docker-host → nextcloud
#
# USAGE:
# ansible-playbook -i inventory.yml playbooks/day1_deploy_nextcloud.yml
# ansible-playbook -i inventory.yml playbooks/day1_deploy_nextcloud.yml --limit the-grid
#
# SECRETS REQUIRED IN VAULT (group_vars/all/vault):
# vault_nextcloud_db_root_password
# vault_nextcloud_db_password
# vault_nextcloud_admin_user
# vault_nextcloud_admin_password
# ------------------------------------------------------------------------------
- name: Deploy Nextcloud on the-grid
hosts: the-grid
become: true
vars:
# NFS prerequisite
nfs_packages:
- nfs-common
# Compose stack location
nextcloud_base_dir: /opt/docker/nextcloud
# Secrets from vault
nextcloud_db_root_password: "{{ vault_nextcloud_db_root_password }}"
nextcloud_db_password: "{{ vault_nextcloud_db_password }}"
nextcloud_admin_user: "{{ vault_nextcloud_admin_user }}"
nextcloud_admin_password: "{{ vault_nextcloud_admin_password }}"
pre_tasks:
- name: Install NFS client
ansible.builtin.apt:
name: "{{ nfs_packages }}"
state: present
update_cache: true
roles:
- role: docker-host
tasks:
- name: Create Nextcloud directory
ansible.builtin.file:
path: "{{ nextcloud_base_dir }}"
state: directory
owner: "{{ ansible_user }}"
group: docker
mode: "0775"
- name: Deploy Compose file
ansible.builtin.copy:
src: "{{ playbook_dir }}/../../boilerplates/nextcloud/compose.yml"
dest: "{{ nextcloud_base_dir }}/compose.yml"
owner: "{{ ansible_user }}"
group: docker
mode: "0644"
- name: Deploy .env from vault
ansible.builtin.copy:
content: |
# Managed by Ansible — do not edit manually
MYSQL_ROOT_PASSWORD={{ nextcloud_db_root_password }}
MYSQL_PASSWORD={{ nextcloud_db_password }}
NEXTCLOUD_ADMIN_USER={{ nextcloud_admin_user }}
NEXTCLOUD_ADMIN_PASSWORD={{ nextcloud_admin_password }}
dest: "{{ nextcloud_base_dir }}/.env"
owner: "{{ ansible_user }}"
group: docker
mode: "0600"
- name: Start Nextcloud stack
community.docker.docker_compose_v2:
project_src: "{{ nextcloud_base_dir }}"
state: present
- name: Wait for Nextcloud to become ready
ansible.builtin.uri:
url: "http://the-grid.local.mk-labs.cloud/status.php"
status_code: 200
return_content: true
register: nextcloud_status
until: >
nextcloud_status.status == 200 and
(nextcloud_status.content | from_json).installed == true
retries: 20
delay: 15

View File

@@ -0,0 +1,35 @@
---
# ------------------------------------------------------------------------------
# FILE: ansible/playbooks/day1_deploy_ollama.yml
# DESCRIPTION: Deploys Ollama with ROCm GPU acceleration on astro-orbiter.
# Assumes day0_baseline.yml has already run (common role complete).
# PCIe passthrough for the RX 5700 must be configured in Proxmox
# and the GPU must be visible to the VM before running this playbook.
#
# Pre-flight check:
# ssh wed@astro-orbiter 'lspci | grep -i amd'
# Should show the RX 5700 before proceeding.
#
# Usage (from ansible/ directory):
# ansible-playbook playbooks/day1_deploy_ollama.yml
# ------------------------------------------------------------------------------
- name: Deploy Ollama with ROCm on astro-orbiter
hosts: astro-orbiter
become: true
pre_tasks:
- name: Verify AMD GPU is visible to the VM
command: lspci
register: lspci_output
changed_when: false
- name: Fail if no AMD GPU detected
fail:
msg: >
No AMD GPU detected via lspci. Verify PCIe passthrough is configured
in Proxmox and the RX 5700 is visible to the VM before proceeding.
when: "'AMD' not in lspci_output.stdout and 'Radeon' not in lspci_output.stdout"
roles:
- ollama

View File

@@ -0,0 +1,22 @@
---
# ------------------------------------------------------------------------------
# FILE: playbooks/day1_deploy_semaphore.yml
# DESCRIPTION: Deploys Semaphore on imagineering
# Runs: common → docker-host → semaphore
#
# USAGE:
# ansible-playbook -i inventory.yml playbooks/day1_deploy_semaphore.yml
#
# SECRETS REQUIRED IN VAULT (group_vars/all/vault):
# vault_semaphore_database_password
# vault_semaphore_admin_password
# vault_semaphore_access_key_encryption
# ------------------------------------------------------------------------------
- name: Deploy Semaphore
hosts: semaphore_server
become: true
roles:
- docker-host
- semaphore

View File

@@ -0,0 +1,18 @@
---
# ------------------------------------------------------------------------------
# FILE: playbooks/deploy_traefik.yml
# DESCRIPTION: Deploys Traefik reverse proxy on lightning-lane.
# Installs Docker and configures Traefik with Cloudflare DNS-01
# certificate resolution for *.local.mk-labs.cloud
#
# USAGE:
# ansible-playbook -i inventory.yml playbooks/deploy_traefik.yml
# ------------------------------------------------------------------------------
- name: Deploy Traefik reverse proxy
hosts: load_balancers
become: true
roles:
- docker-host
- traefik

View File

@@ -0,0 +1,7 @@
---
- name: Apply common role
hosts: "{{ target | default('all') }}"
become: true
roles:
- common
- docker-host

View File

@@ -0,0 +1,80 @@
---
# ------------------------------------------------------------------------------
# FILE: ansible/playbooks/day2_install_node_exporter.yml
# DESCRIPTION: Install and configure Prometheus Node Exporter on Linux hosts.
#
# Targets two groups with different firewall managers:
# - proxmox_nodes : Proxmox hypervisors (Debian, firewalld not present,
# uses iptables/no firewall — just open the port via UFW
# if present, otherwise skip)
# - monitored_vms : Ubuntu VMs managed by UFW
#
# After installing on new hosts, re-runs day1_deploy_monitoring.yml to refresh
# the Prometheus scrape config is NOT needed — targets are already statically
# defined in prometheus.yaml.j2 for the Proxmox nodes. For new VMs, add the
# IP to the prometheus.yaml.j2 proxmox-vms job and re-run day1_deploy_monitoring.yml.
#
# Usage:
# ansible-playbook -i inventory.yml playbooks/day2_install_node_exporter.yml
# ansible-playbook -i inventory.yml playbooks/day2_install_node_exporter.yml --limit proxmox_nodes
# ansible-playbook -i inventory.yml playbooks/day2_install_node_exporter.yml --limit monitored_vms
# ------------------------------------------------------------------------------
# ── Play 1: Proxmox hypervisors ───────────────────────────────────────────────
# Proxmox runs Debian. The prometheus.prometheus.node_exporter role installs
# a binary + systemd service without touching apt, which is what we want on
# hypervisors (keep the package footprint clean).
# Note: Proxmox does not run UFW. Port 9100 is open by default on VLAN 71.
- name: Install Node Exporter on Proxmox hypervisors
hosts: proxmox_nodes
become: true
vars:
node_exporter_version: "1.9.1"
node_exporter_web_listen_address: "0.0.0.0:9100"
node_exporter_enabled_collectors:
- systemd
- processes
- filesystem
- meminfo
- cpu
- diskstats
- netdev
- loadavg
- uname
roles:
- role: prometheus.prometheus.node_exporter
# ── Play 2: Ubuntu VMs ────────────────────────────────────────────────────────
# Standard Ubuntu hosts with UFW. Same role, adds UFW allow rule for 9100.
- name: Install Node Exporter on monitored VMs
hosts: monitored_vms
become: true
vars:
node_exporter_version: "1.9.1"
node_exporter_web_listen_address: "0.0.0.0:9100"
node_exporter_enabled_collectors:
- systemd
- processes
- filesystem
- meminfo
- cpu
- diskstats
- netdev
- loadavg
- uname
pre_tasks:
- name: Open Node Exporter port in UFW
community.general.ufw:
rule: allow
port: "9100"
proto: tcp
comment: "Prometheus Node Exporter"
roles:
- role: prometheus.prometheus.node_exporter

View File

@@ -0,0 +1,5 @@
- name: 1. Deploy n8n server
hosts: n8n_server
gather_facts: true
roles:
- role: n8n

View File

@@ -0,0 +1,5 @@
- name: 1. Deploy NTP servers
hosts: ntp_servers
gather_facts: true
roles:
- role: ntp-server

View File

@@ -0,0 +1,29 @@
---
# ------------------------------------------------------------------------------
# FILE: playbooks/deploy_step_ca.yml
# DESCRIPTION: Deploys Smallstep step-ca SSH Certificate Authority on turnstile.
# Installs Docker and configures step-ca with SSH certificate support.
#
# PREREQUISITES:
# - VM provisioned via Terraform
# - DNS record for turnstile.local.mk-labs.cloud on monorail
# - Authentik OIDC application created (for post-init provisioner setup)
#
# USAGE:
# ansible-playbook -i inventory.yml playbooks/deploy_step_ca.yml
#
# POST-DEPLOY:
# 1. Note the CA fingerprint from the init output
# 2. Add the OIDC provisioner (see docs/guides/step-ca-setup.md)
# 3. Deploy Traefik route via update_traefik_routes.yml
# 4. Bootstrap client workstations with: step ca bootstrap
# ------------------------------------------------------------------------------
- name: Deploy step-ca SSH Certificate Authority
hosts: step_ca_server
become: true
roles:
- common
- docker-host
- step-ca

View File

@@ -0,0 +1,7 @@
---
- name: Enroll host as step-ca SSH client
hosts: "{{ target | default('all') }}"
become: true
tasks:
- name: Include step-ca client enrollment
ansible.builtin.include_tasks: roles/common/tasks/step_ca_client.yml

View File

@@ -0,0 +1,67 @@
---
- name: Master playbook to install and configure prometheus
hosts: prometheus_server
become: true
tasks:
- name: Install prerequisite software
ansible.builtin.dnf:
name:
- tar
- python3-dnf
state: present
- name: Permit prometheus metrics in default zone for dns service
ansible.posix.firewalld:
port: 9100/tcp
permanent: true
immediate: true
state: enabled
- name: Permit traffic in default zone for dns service
ansible.posix.firewalld:
port: 9090/tcp
permanent: true
immediate: true
state: enabled
- name: Install prometheus via role
ansible.builtin.import_role:
name: prometheus.prometheus.prometheus
vars:
prometheus_targets:
node:
- targets:
- localhost:9100
labels:
env: mk-labs
- name: Permit grafana in default zone for dns service
ansible.posix.firewalld:
port: 3000/tcp
permanent: true
immediate: true
state: enabled
- name: Install grafana via role
ansible.builtin.import_role:
name: grafana.grafana.grafana
# - name: Create/Update Data sources
# grafana.grafana.datasource:
# dataSource: |
# {
# "name": "Prometheus",
# "type": "prometheus",
# "access": "proxy",
# "url": "http://localhost:9090",
# "jsonData": {
# "httpMethod": "POST",
# "manageAlerts": true,
# "prometheusType": "Prometheus",
# "cacheLevel": "High"
# }
# }
# grafana_url: "{{ grafana_url }}"
# grafana_api_key: "{{ grafana_api_key }}"
# state: present

View File

@@ -0,0 +1,15 @@
---
# ------------------------------------------------------------------------------
# FILE: playbooks/install_talosctl.yml
# DESCRIPTION: Install talosctl on city-hall for managing the fastpass cluster.
# USAGE:
# cd ansible
# ansible-playbook -i inventory.yml playbooks/install_talosctl.yml
# ------------------------------------------------------------------------------
- name: Install talosctl
hosts: talos_control
become: true
roles:
- talosctl

View File

@@ -0,0 +1,16 @@
---
- name: Master playbook to install and configure prometheus node explorer
hosts: prometheus_server
become: true
tasks:
- name: Permit prometheus metrics in default zone for dns service
ansible.posix.firewalld:
port: 9100/tcp
permanent: true
immediate: true
state: enabled
- name: Install prometheus node exporter via role
ansible.builtin.import_role:
name: prometheus.prometheus.node_exporter

View File

@@ -0,0 +1,31 @@
---
- name: Create VM ID from IP address for Proxmox hosts
hosts: all
gather_facts: false
tasks:
- name: Modify Proxmox Ubuntu VM
delegate_to: "localhost"
when: platform is defined and platform == "proxmox"
block:
- name: Update cloud-init file
community.proxmox.proxmox_kvm:
api_user: "{{ proxmox_user }}"
api_password: "{{ proxmox_password }}"
api_host: "{{ proxmox_host }}"
node: "{{ proxmox_clone_node }}"
vmid: "{{ vm_id }}"
ipconfig:
ipconfig0: "ip=dhcp"
update: true
# - name: Add VM to HA group
# community.proxmox.proxmox_cluster_ha_resources:
# api_user: "{{ proxmox_user }}"
# api_password: "{{ proxmox_password }}"
# api_host: "{{ proxmox_host }}"
# name: vm:"{{ vm_id }}"
# state: "present"
# group: "{{ ha_group }}"
# max_relocate: 2
# max_restart: 2

View File

@@ -0,0 +1,143 @@
---
- name: Install Prometheus and Grafana on control node
hosts: prometheus_server
become: true
# vars_files:
# - vars.yml
tasks:
- name: Install prerequisite software
ansible.builtin.dnf:
name:
- tar
- wget
state: present
- name: Download Prometheus
ansible.builtin.get_url:
url: "{{ prometheus_installer_download_url }}"
dest: "/tmp/{{ prometheus_installer_file }}"
- name: Extract Prometheus
ansible.builtin.unarchive:
src: "/tmp/{{ prometheus_installer_file }}"
dest: "/usr/local/bin/"
remote_src: true
- name: Create Prometheus user
user:
name: prometheus
shell: /bin/false
state: present
- name: Create Prometheus directories
ansible.builtin.file:
path: "{{ item }}"
state: directory
owner: prometheus
group: prometheus
with_items:
- /etc/prometheus
- /var/lib/prometheus
- name: Move Prometheus binaries
ansible.builtin.command: "mv /usr/local/bin/prometheus-{{ prometheus_version }}.linux-amd64/prometheus /usr/local/bin/prometheus"
- name: Move Prometheus tool
ansible.builtin.command: "mv /usr/local/bin/prometheus-{{ prometheus_version }}.linux-amd64/promtool /usr/local/bin/promtool"
- name: Create Prometheus configuration file
ansible.builtin.copy:
dest: "/etc/prometheus/prometheus.yml"
content: |
global:
scrape_interval: 15s
evaluation_interval: 15s
scrape_configs:
- job_name: 'prometheus'
static_configs:
- targets: ['localhost:9090']
- job_name: 'nodes'
static_configs:
- targets:
{% for ip in prometheus_nodes %}
- '{{ ip }}:9100'
{% endfor %}
- name: Create Prometheus service file
ansible.builtin.copy:
dest: "/etc/systemd/system/prometheus.service"
content: |
[Unit]
Description=Prometheus
Wants=network-online.target
After=network-online.target
[Service]
User=prometheus
Group=prometheus
Type=simple
ExecStart=/usr/local/bin/prometheus \
--config.file=/etc/prometheus/prometheus.yml \
--storage.tsdb.path=/var/lib/prometheus/ \
--web.console.templates=/etc/prometheus/consoles \
--web.console.libraries=/etc/prometheus/console_libraries
[Install]
WantedBy=multi-user.target
register: prometheus_service_status
ignore_errors: true
- name: Check if Prometheus service is running
ansible.builtin.command: systemctl is-active prometheus
register: prometheus_status
changed_when: false
ignore_errors: true
- name: Permit prometheus endpoint in default zone for dns service
firewalld:
port: 9090/tcp
permanent: true
immediate: true
state: enabled
- name: Permit prometheus metrics in default zone for dns service
firewalld:
port: 9100/tcp
permanent: true
immediate: true
state: enabled
- name: Permit grafana traffic in default zone for dns service
firewalld:
port: 3000/tcp
permanent: true
immediate: true
state: enabled
- name: Manage Prometheus service state
systemd:
name: prometheus
state: "{{ 'restarted' if prometheus_status.rc == 0 else 'started' }}"
enabled: true
- name: Add repository
ansible.builtin.yum_repository:
name: grafana
description: Grafana OSS repo
baseurl: https://rpm.grafana.com
gpgkey: https://rpm.grafana.com/gpg.key
- name: Install Grafana
ansible.builtin.dnf:
name:
- grafana
state: present
- name: Start Grafana service
systemd:
name: grafana-server
state: started
enabled: true

View File

@@ -22,7 +22,8 @@
name: "{{ inventory_hostname }}" name: "{{ inventory_hostname }}"
node: "{{ proxmox_clone_node }}" node: "{{ proxmox_clone_node }}"
storage: "{{ vm_storage }}" storage: "{{ vm_storage }}"
format: raw format: qcow2 # raw
timeout: 600
# - name: Add VM to HA group # - name: Add VM to HA group
# community.proxmox.proxmox_cluster_ha_resources: # community.proxmox.proxmox_cluster_ha_resources:

View File

@@ -0,0 +1,50 @@
---
- name: Create VM ID from IP address for Proxmox hosts
hosts: all
gather_facts: false
tasks:
- name: Create Proxmox VMs
delegate_to: "localhost"
when: platform is defined and platform == "proxmox"
block:
- name: Create VM ID from IP address
ansible.builtin.set_fact:
vm_id: "{{ ip_address.split('.')[-2] }}{{ '%03d' % (ip_address.split('.')[-1] | int) }}"
- name: Create VM with an EFI disk, with Secure Boot disabled by default
community.proxmox.proxmox_kvm:
api_user: "{{ proxmox_user }}"
api_password: "{{ proxmox_password }}"
api_host: "{{ proxmox_host }}"
name: "{{ inventory_hostname }}"
node: "{{ proxmox_clone_node }}"
vmid: "{{ vm_id }}"
net:
net0: "virtio,bridge=vmbr0"
ide:
ide0: "{{ vm_iso_storage }}:iso/{{ vm_iso }},media=cdrom"
scsihw: "virtio-scsi-single"
scsi:
scsi0: "{{ vm_storage }}:{{ vm_definitions[vm_size]['disk'] }},format=qcow2"
bios: "ovmf"
cpu: "x86-64-v2"
cores: "{{ vm_definitions[vm_size]['cores'] }}"
memory: "{{ vm_definitions[vm_size]['memory'] }}"
efidisk0:
storage: "{{ vm_storage }}"
format: raw
efitype: 4m
pre_enrolled_keys: false
timeout: 600
# - name: Add VM to HA group
# community.proxmox.proxmox_cluster_ha_resources:
# api_user: "{{ proxmox_user }}"
# api_password: "{{ proxmox_password }}"
# api_host: "{{ proxmox_host }}"
# name: vm:"{{ vm_id }}"
# state: "present"
# group: "{{ ha_group }}"
# max_relocate: 2
# max_restart: 2

View File

@@ -0,0 +1,40 @@
---
- name: Create VM ID from IP address for Proxmox hosts
hosts: all
gather_facts: false
tasks:
- name: Start Proxmox VM
delegate_to: "localhost"
when: platform is defined and platform == "proxmox"
community.proxmox.proxmox_kvm:
api_user: "{{ proxmox_user }}"
api_password: "{{ proxmox_password }}"
api_host: "{{ proxmox_host }}"
name: "{{ inventory_hostname }}"
node: "{{ proxmox_clone_node }}"
state: started
- name: Wait for SSH service to be ready
delegate_to: "localhost"
when: platform is defined and platform == "proxmox"
ansible.builtin.wait_for:
port: 22
host: "{{ inventory_hostname }}"
search_regex: OpenSSH
timeout: 300
msg: "Waiting for SSH service to be ready on {{ inventory_hostname }}"
- name: Wait for VM to be fully booted and responsive
delegate_to: "localhost"
when: platform is defined and platform == "proxmox"
ansible.builtin.wait_for_connection:
connect_timeout: 10
sleep: 5
timeout: 300
- name: Display VM startup completion
delegate_to: "localhost"
when: platform is defined and platform == "proxmox"
ansible.builtin.debug:
msg: "✅ {{ inventory_hostname }} is now running and accessible via SSH"

View File

@@ -0,0 +1,11 @@
---
# ------------------------------------------------------------------------------
# FILE: roles/authentik/defaults/main.yml
# ------------------------------------------------------------------------------
authentik_base_dir: /opt/docker/authentik
# All secrets MUST be set in vault
authentik_secret_key: ""
authentik_admin_password: ""
authentik_database_password: ""

View File

@@ -0,0 +1,8 @@
# ------------------------------------------------------------------------------
# FILE: roles/authentik/handlers/main.yml
# ------------------------------------------------------------------------------
- name: restart authentik
community.docker.docker_compose_v2:
project_src: "{{ authentik_base_dir }}"
state: restarted

View File

@@ -0,0 +1,51 @@
---
# ──────────────────────────────────────────────────────────────────────────────
# FILE: roles/authentik/tasks/main.yml
# DESCRIPTION: Deploys Authentik from boilerplate-generated files in the repo.
# The compose.yaml lives in boilerplates/authentik/.
# The .env file is templated to inject secrets from Ansible vault.
# Custom blueprints are synced from boilerplates/authentik/blueprints/.
# ──────────────────────────────────────────────────────────────────────────────
- name: Create Authentik directory structure
ansible.builtin.file:
path: "{{ item }}"
state: directory
owner: "{{ ansible_user }}"
group: docker
mode: '0775'
loop:
- "{{ authentik_base_dir }}"
- "{{ authentik_base_dir }}/blueprints"
- name: Copy compose.yaml from boilerplate
ansible.builtin.copy:
src: "{{ playbook_dir }}/../../boilerplates/authentik/compose.yaml"
dest: "{{ authentik_base_dir }}/compose.yaml"
owner: "{{ ansible_user }}"
group: docker
mode: '0644'
notify: restart authentik
- name: Sync custom blueprints
ansible.builtin.copy:
src: "{{ playbook_dir }}/../../boilerplates/authentik/blueprints/"
dest: "{{ authentik_base_dir }}/blueprints/"
owner: "{{ ansible_user }}"
group: docker
mode: '0644'
notify: restart authentik
- name: Deploy .env with secrets from vault
ansible.builtin.template:
src: env.j2
dest: "{{ authentik_base_dir }}/.env"
owner: "{{ ansible_user }}"
group: docker
mode: '0600'
notify: restart authentik
- name: Start Authentik
community.docker.docker_compose_v2:
project_src: "{{ authentik_base_dir }}"
state: present

View File

@@ -0,0 +1,13 @@
# Managed by Ansible — do not edit manually
AUTHENTIK_SECRET_KEY={{ authentik_secret_key }}
DATABASE_PASSWORD={{ authentik_database_password }}
AUTHENTIK_ADMIN_PASSWORD={{ authentik_admin_password }}
# OIDC client credentials for blueprints
# These are substituted into blueprint YAML via ${VAR} syntax
PROXMOX_OIDC_CLIENT_ID={{ vault_proxmox_oidc_client_id }}
PROXMOX_OIDC_CLIENT_SECRET={{ vault_proxmox_oidc_client_secret }}
STEPCA_OIDC_CLIENT_ID={{ vault_stepca_oidc_client_id }}
STEPCA_OIDC_CLIENT_SECRET={{ vault_stepca_oidc_client_secret }}
GITEA_OIDC_CLIENT_ID={{ vault_gitea_oidc_client_id }}
GITEA_OIDC_CLIENT_SECRET={{ vault_gitea_oidc_client_secret }}

View File

@@ -0,0 +1,34 @@
---
# ------------------------------------------------------------------------------
# FILE: roles/common/defaults/main.yml
# ------------------------------------------------------------------------------
common_timezone: America/Chicago
common_ntp_server: "sundial.local.mk-labs.cloud"
common_packages:
- curl
- wget
- vim
- htop
- git
- jq
- unzip
- ca-certificates
- gnupg
- lsb-release
- net-tools
- dnsutils
- lvm2
# ------------------------------------------------------------------------------
# LVM root volume expansion
# Override common_root_pv/vg/lv per host if the template uses different names.
# Ubuntu 24.04 cloud templates use ubuntu-vg/ubuntu-lv by default.
# ------------------------------------------------------------------------------
common_expand_root_lvm: true
common_root_pv: /dev/sda3 # Ubuntu cloud-init partition layout
common_root_vg: ubuntu-vg
common_root_lv: ubuntu-lv

View File

@@ -0,0 +1,9 @@
---
# ------------------------------------------------------------------------------
# FILE: roles/common/handlers/main.yml
# ------------------------------------------------------------------------------
- name: restart chrony
systemd:
name: chrony
state: restarted

View File

@@ -0,0 +1,22 @@
---
# ------------------------------------------------------------------------------
# FILE: roles/common/defaults/main.yml
# ------------------------------------------------------------------------------
common_timezone: America/Chicago
common_ntp_server: sundial.local.mk-labs.cloud
common_packages:
- curl
- wget
- vim
- htop
- git
- jq
- unzip
- ca-certificates
- gnupg
- lsb-release
- net-tools
- dnsutils

View File

@@ -0,0 +1,77 @@
---
# ------------------------------------------------------------------------------
# FILE: roles/common/tasks/main.yml
# DESCRIPTION: Baseline configuration applied to all managed Ubuntu hosts.
# Handles hostname, timezone, core packages, NTP, ansible user,
# and optional LVM root volume expansion.
# ------------------------------------------------------------------------------
- name: Set hostname
hostname:
name: "{{ inventory_hostname | replace('_', '-') }}"
- name: Set timezone
timezone:
name: "{{ common_timezone }}"
- name: Update apt cache
apt:
update_cache: yes
cache_valid_time: 3600
- name: Install base utility packages
apt:
name: "{{ common_packages }}"
state: present
- name: Install chrony
apt:
name: chrony
state: present
- name: Configure chrony to use sundial
template:
src: chrony.conf.j2
dest: /etc/chrony/chrony.conf
mode: '0644'
notify: restart chrony
- name: Ensure chrony is enabled and running
systemd:
name: chrony
state: started
enabled: yes
- name: Ensure ansible user has passwordless sudo
lineinfile:
path: /etc/sudoers.d/{{ ansible_user }}
line: "{{ ansible_user }} ALL=(ALL) NOPASSWD:ALL"
create: yes
mode: '0440'
validate: 'visudo -cf %s'
# ------------------------------------------------------------------------------
# LVM root volume expansion
# Extends the root PV to the full disk size and grows the LV + filesystem.
# This codifies what was previously done manually after provisioning.
# Runs only when common_expand_root_lvm is true (default: true).
# Safe to re-run — pvresize and lvextend are idempotent when already at max.
# ------------------------------------------------------------------------------
- name: Expand root PV to full disk size
command: pvresize {{ common_root_pv }}
register: pvresize_result
changed_when: "'changed' in pvresize_result.stdout or pvresize_result.rc == 0"
when: common_expand_root_lvm | bool
- name: Extend root LV to 100% of free VG space
lvol:
vg: "{{ common_root_vg }}"
lv: "{{ common_root_lv }}"
size: +100%FREE
resizefs: yes
when:
- common_expand_root_lvm | bool
ignore_errors: yes
# ignore_errors because lvextend returns non-zero when already at max size.
# resizefs: yes handles the resize2fs call inline — no separate task needed.

View File

@@ -0,0 +1,136 @@
# ------------------------------------------------------------------------------
# FILE: roles/common/tasks/step_ca_client.yml
# DESCRIPTION: Enroll host as a step-ca SSH client. Installs the step CLI,
# bootstraps trust with the CA, configures sshd to accept
# CA-signed user certificates, signs a host certificate, and
# sets up automated renewal via systemd timer.
# ------------------------------------------------------------------------------
- name: Install step CLI
apt:
deb: "https://dl.smallstep.com/cli/docs-ca-install/latest/step-cli_amd64.deb"
state: present
- name: Bootstrap step-ca trust
command: >
step ca bootstrap
--ca-url {{ step_ca_url }}
--fingerprint {{ step_ca_fingerprint }}
--install
args:
creates: /root/.step/certs/root_ca.crt
- name: Get SSH user CA public key
command: step ssh config --roots
register: ssh_user_ca_key
changed_when: false
- name: Write SSH user CA public key
copy:
content: "{{ ssh_user_ca_key.stdout }}"
dest: /etc/ssh/ssh_user_key.pub
mode: '0644'
notify: restart sshd
- name: Configure sshd to trust CA-signed user certificates
lineinfile:
path: /etc/ssh/sshd_config
line: "TrustedUserCAKeys /etc/ssh/ssh_user_key.pub"
regexp: "^#?TrustedUserCAKeys"
state: present
notify: restart sshd
# --- Host certificate signing ---
- name: Write provisioner password to temp file on controller
copy:
content: "{{ stepca_ca_password }}"
dest: /tmp/step_provisioner_pw
mode: '0600'
delegate_to: localhost
run_once: true
no_log: true
- name: Generate one-time host token
command: >
step ca token {{ inventory_hostname }}.local.mk-labs.cloud
--ssh --host
--provisioner {{ step_ca_provisioner_name }}
--password-file /tmp/step_provisioner_pw
delegate_to: localhost
register: host_token
changed_when: false
- name: Sign host certificate
command: >
step ssh certificate {{ inventory_hostname }}.local.mk-labs.cloud
/etc/ssh/ssh_host_ecdsa_key.pub
--host --sign
--token {{ host_token.stdout }}
--no-password --insecure
args:
creates: /etc/ssh/ssh_host_ecdsa_key-cert.pub
notify: restart sshd
- name: Configure sshd to present host certificate
blockinfile:
path: /etc/ssh/sshd_config
marker: "# {mark} STEP-CA HOST CERTIFICATE"
block: |
HostCertificate /etc/ssh/ssh_host_ecdsa_key-cert.pub
HostKey /etc/ssh/ssh_host_ecdsa_key
notify: restart sshd
- name: Clean up provisioner password from controller
file:
path: /tmp/step_provisioner_pw
state: absent
delegate_to: localhost
run_once: true
no_log: true
# --- Automated renewal via systemd ---
- name: Create host cert renewal script
copy:
content: |
#!/bin/bash
step ssh renew --force /etc/ssh/ssh_host_ecdsa_key-cert.pub /etc/ssh/ssh_host_ecdsa_key
systemctl restart sshd
dest: /usr/local/bin/step-renew-host-cert.sh
mode: '0755'
- name: Create systemd timer for host cert renewal
copy:
content: |
[Unit]
Description=Renew step-ca SSH host certificate
[Timer]
OnCalendar=weekly
Persistent=true
RandomizedDelaySec=3600
[Install]
WantedBy=timers.target
dest: /etc/systemd/system/step-renew-host-cert.timer
mode: '0644'
- name: Create systemd service for host cert renewal
copy:
content: |
[Unit]
Description=Renew step-ca SSH host certificate
[Service]
Type=oneshot
ExecStart=/usr/local/bin/step-renew-host-cert.sh
dest: /etc/systemd/system/step-renew-host-cert.service
mode: '0644'
- name: Enable and start renewal timer
systemd:
name: step-renew-host-cert.timer
state: started
enabled: yes
daemon_reload: yes

View File

@@ -0,0 +1,5 @@
# Managed by Ansible — do not edit manually
server {{ common_ntp_server }} iburst
driftfile /var/lib/chrony/chrony.drift
makestep 1.0 3
rtcsync

View File

@@ -0,0 +1,59 @@
# ------------------------------------------------------------------------------
# FILE: roles/control-plane/tasks/main.yml
# ------------------------------------------------------------------------------
- name: Check if cluster is already initialized
stat:
path: /etc/kubernetes/admin.conf
register: kube_init_stat
- name: Initialize the Kubernetes cluster
when: not kube_init_stat.stat.exists
command: >
kubeadm init
--pod-network-cidr=10.244.0.0/16
--control-plane-endpoint={{ inventory_hostname }}
register: kubeadm_init
- name: Create .kube directory for the user
become: no
file:
path: "{{ ansible_env.HOME }}/.kube"
state: directory
mode: '0755'
delegate_to: localhost
run_once: true
- name: Copy admin.conf to user's .kube directory on controller
when: not kube_init_stat.stat.exists
fetch:
src: /etc/kubernetes/admin.conf
dest: "{{ ansible_env.HOME }}/.kube/config"
flat: yes
- name: Install Calico CNI
become: no
command: kubectl apply -f https://raw.githubusercontent.com/projectcalico/calico/v3.28.0/manifests/calico.yaml
delegate_to: localhost
run_once: true
when: not kube_init_stat.stat.exists
- name: Generate join command for control plane nodes
when: not kube_init_stat.stat.exists
command: kubeadm token create --print-join-command
register: control_plane_join_command_raw
- name: Generate certificate key for control plane join
when: not kube_init_stat.stat.exists
command: kubeadm init phase upload-certs --upload-certs
register: control_plane_cert_key
- name: Store control plane join command
set_fact:
control_plane_join_command: "{{ control_plane_join_command_raw.stdout }} --control-plane --certificate-key {{ control_plane_cert_key.stdout_lines[-1] }}"
when: not kube_init_stat.stat.exists
- name: Join other control plane nodes to the cluster
when:
- inventory_hostname != groups['control_plane'][0]
- not kube_init_stat.stat.exists
command: "{{ hostvars[groups['control_plane'][0]].control_plane_join_command }}"

View File

@@ -0,0 +1,18 @@
---
# Default variables for dns-manager role
# DNS Configuration
dns_management_enabled: true
use_hosts_file_fallback: false
dns_ttl: 360
dns_propagation_wait: 2
create_ptr_record: true
# Cluster Configuration (to be provided by calling role)
# cluster_endpoint: "fastpass.local.mk-labs.cloud"
# cluster_vip: "10.1.71.53"
# DNS Server Configuration (from group_vars)
# dns_server: "monorail"
# base_domain: "local.mk-labs.cloud"
# vault_technitium_api_key: "{{ vault_technitium_api_key }}"

View File

@@ -0,0 +1,17 @@
---
# role: dns-manager
# description: Reusable role for managing DNS entries across clusters using Technitium DNS
# author: mk-labs
# version: 1.0.0
- name: Create DNS entry using Technitium DNS task
ansible.builtin.include_tasks: "{{ playbook_dir }}/tasks/add_technitium_dns_entry.yml"
- name: Wait for DNS propagation
ansible.builtin.pause:
seconds: "{{ dns_propagation_wait | default(10) }}"
when: dns_management_enabled | default(true)
- name: Look up A (IPv4) records for example.org
ansible.builtin.debug:
msg: "{{ query('community.dns.lookup', 'fastpass') }}"

View File

@@ -0,0 +1,8 @@
# ------------------------------------------------------------------------------
# FILE: roles/docker-host/handlers/main.yml
# ------------------------------------------------------------------------------
- name: restart docker
systemd:
name: docker
state: restarted

View File

@@ -0,0 +1,88 @@
# ------------------------------------------------------------------------------
# FILE: roles/docker-host/tasks/main.yml
# DESCRIPTION: Prepares an Ubuntu VM to run Docker Compose workloads.
# Installs Docker CE, configures the daemon, and ensures
# the ansible user (wed) can manage containers.
# ------------------------------------------------------------------------------
- name: Install prerequisite packages
apt:
name:
- ca-certificates
- curl
- gnupg
- lsb-release
state: present
update_cache: yes
- name: Create keyrings directory
file:
path: /etc/apt/keyrings
state: directory
mode: '0755'
- name: Add Docker GPG key
get_url:
url: https://download.docker.com/linux/ubuntu/gpg
dest: /etc/apt/keyrings/docker.asc
mode: '0644'
- name: Add Docker repository
apt_repository:
repo: >-
deb [arch={{ ansible_architecture | replace('x86_64', 'amd64') }}
signed-by=/etc/apt/keyrings/docker.asc]
https://download.docker.com/linux/ubuntu
{{ ansible_distribution_release }} stable
state: present
filename: docker
- name: Install Docker CE and Compose plugin
apt:
name:
- docker-ce
- docker-ce-cli
- containerd.io
- docker-compose-plugin
state: present
update_cache: yes
- name: Ensure Docker service is started and enabled
systemd:
name: docker
state: started
enabled: yes
- name: Add ansible user to docker group
user:
name: "{{ ansible_user }}"
groups: docker
append: yes
- name: Configure Docker daemon
copy:
dest: /etc/docker/daemon.json
content: |
{
"log-driver": "json-file",
"log-opts": {
"max-size": "10m",
"max-file": "3"
},
"default-address-pools": [
{
"base": "172.17.0.0/16",
"size": 24
}
]
}
mode: '0644'
notify: restart docker
- name: Create Docker Compose project directory
file:
path: /opt/docker
state: directory
owner: "{{ ansible_user }}"
group: docker
mode: '0775'

View File

@@ -0,0 +1,72 @@
---
# Container runtime setup for Kubernetes
- name: Add containerd repository
become: true
ansible.builtin.yum_repository:
name: docker-ce
description: "Docker CE Repository"
baseurl: "https://download.docker.com/linux/fedora/{{ ansible_distribution_major_version }}/x86_64/stable"
gpgkey: "https://download.docker.com/linux/fedora/gpg"
gpgcheck: true
enabled: true
state: present
- name: Install containerd
become: true
ansible.builtin.dnf:
name: containerd
state: present
disable_excludes: docker-ce-stable
- name: Create containerd config directory
become: true
ansible.builtin.file:
path: /etc/containerd
state: directory
mode: '0755'
- name: Generate default containerd config
become: true
ansible.builtin.shell: |
containerd config default > /etc/containerd/config.toml
args:
creates: /etc/containerd/config.toml
- name: Configure containerd for Kubernetes
become: true
ansible.builtin.replace:
path: /etc/containerd/config.toml
regexp: 'SystemdCgroup = false'
replace: 'SystemdCgroup = true'
- name: Create containerd service override directory
become: true
ansible.builtin.file:
path: /etc/systemd/system/containerd.service.d
state: directory
mode: '0755'
- name: Configure containerd service override
become: true
ansible.builtin.copy:
dest: /etc/systemd/system/containerd.service.d/override.conf
content: |
[Service]
ExecStartPre=-/sbin/modprobe overlay
ExecStartPre=-/sbin/modprobe br_netfilter
mode: '0644'
- name: Restart and enable containerd service
become: true
ansible.builtin.systemd:
name: containerd
state: restarted
enabled: true
daemon_reload: true
- name: Verify containerd is running
become: true
ansible.builtin.systemd:
name: containerd
state: started

View File

@@ -0,0 +1,16 @@
---
# FastPass Kubernetes Cluster Preparation for Fedora
# This role prepares all nodes for Kubernetes installation
- name: Include preflight checks
ansible.builtin.include_tasks: preflight.yml
when: preflight_checks | default(true)
- name: Include system preparation
ansible.builtin.include_tasks: system-prep.yml
- name: Include container runtime setup
ansible.builtin.include_tasks: container-runtime.yml
- name: Include Kubernetes installation
ansible.builtin.include_tasks: kubernetes-install.yml

View File

@@ -0,0 +1,40 @@
---
# Preflight checks for Kubernetes installation
- name: Check if running on supported OS
ansible.builtin.assert:
that:
- ansible_os_family == "RedHat"
- ansible_distribution == "Fedora"
fail_msg: "This role only supports Fedora"
success_msg: "OS check passed"
- name: Check minimum memory requirement (2GB)
ansible.builtin.assert:
that: ansible_memtotal_mb >= 2048
fail_msg: "Minimum 2GB RAM required, found {{ ansible_memtotal_mb }}MB"
success_msg: "Memory check passed: {{ ansible_memtotal_mb }}MB"
- name: Check minimum CPU cores (2)
ansible.builtin.assert:
that: ansible_processor_cores >= 2
fail_msg: "Minimum 2 CPU cores required, found {{ ansible_processor_cores }}"
success_msg: "CPU check passed: {{ ansible_processor_cores }} cores"
- name: Check available disk space (10GB)
ansible.builtin.assert:
that: ansible_mounts | selectattr('mount', 'equalto', '/') | map(attribute='size_available') | first >= 10737418240
fail_msg: "Minimum 10GB free space required on root filesystem"
success_msg: "Disk space check passed"
- name: Check if system is 64-bit
ansible.builtin.assert:
that: ansible_architecture in ['x86_64', 'amd64']
fail_msg: "Only 64-bit architectures are supported"
success_msg: "Architecture check passed: {{ ansible_architecture }}"
- name: Check if running as root or with sudo
ansible.builtin.assert:
that: ansible_become | default(false)
fail_msg: "This role requires root privileges (become: true)"
success_msg: "Privilege check passed"

View File

@@ -0,0 +1,83 @@
---
# System preparation for Kubernetes
- name: Disable swap
ansible.builtin.command: swapoff -a
become: true
changed_when: false
when: disable_swap | default(true)
- name: Persist swap off by commenting out swap in fstab
become: true
ansible.builtin.replace:
path: /etc/fstab
regexp: '^(\s*)([^#\n]+\s+swap\s+.*)$'
replace: '#\2'
backup: true
when: disable_swap | default(true)
- name: Load required kernel modules
become: true
community.general.modprobe:
name: "{{ item }}"
state: present
loop:
- overlay
- br_netfilter
- name: Persist kernel modules on boot
become: true
ansible.builtin.copy:
dest: /etc/modules-load.d/k8s.conf
content: |
overlay
br_netfilter
mode: '0644'
- name: Configure required sysctl params for Kubernetes
become: true
ansible.builtin.copy:
dest: /etc/sysctl.d/k8s.conf
content: |
net.bridge.bridge-nf-call-iptables = 1
net.bridge.bridge-nf-call-ip6tables = 1
net.ipv4.ip_forward = 1
mode: '0644'
- name: Apply sysctl params without reboot
become: true
ansible.builtin.command: sysctl --system
changed_when: false
- name: Install required packages
become: true
ansible.builtin.dnf:
name:
- python3-libselinux
- dnf-plugins-core
- curl
- wget
- ca-certificates
state: present
- name: Set SELinux to permissive mode
become: true
ansible.posix.selinux:
policy: targeted
state: "{{ selinux_mode | default('permissive') }}"
- name: Stop and disable firewalld
become: true
ansible.builtin.systemd:
name: firewalld
state: stopped
enabled: false
when: not firewall_enabled | default(false)
- name: Update system packages
become: true
ansible.builtin.dnf:
name: "*"
state: latest
async: 300
poll: 10

View File

@@ -0,0 +1,39 @@
---
# ------------------------------------------------------------------------------
# FILE: ansible/playbooks/roles/gitea/defaults/main.yml
# ------------------------------------------------------------------------------
# Directory layout on mad-tea-party
gitea_compose_dir: /opt/gitea
# Gitea application settings
gitea_domain: gitea.mk-labs.cloud
gitea_root_url: "https://{{ gitea_domain }}"
gitea_http_port: 3000
gitea_ssh_port: 2221
# Trusted proxy (lightning-lane)
gitea_trusted_proxies: 10.1.71.35
# Timezone
gitea_timezone: America/Chicago
# Database
gitea_db_name: gitea
gitea_db_user: gitea
# Traefik dynamic config destination on lightning-lane
traefik_dynamic_config_dir: /opt/traefik/dynamic
# DNS
gitea_cname_name: gitea
gitea_cname_domain: mk-labs.cloud
gitea_cname_target: mad-tea-party.local.mk-labs.cloud
# OIDC / Authentik SSO
gitea_oidc_enabled: true
gitea_oidc_client_id: "{{ vault_gitea_oidc_client_id }}"
gitea_oidc_client_secret: "{{ vault_gitea_oidc_client_secret }}"
gitea_oidc_discovery_url: "https://authentik.local.mk-labs.cloud/application/o/gitea/.well-known/openid-configuration"
gitea_oidc_admin_group: "mk-labs-admins"
gitea_admin_api_token: "{{ vault_gitea_admin_api_token }}"

View File

@@ -0,0 +1,10 @@
---
# ------------------------------------------------------------------------------
# FILE: ansible/playbooks/roles/gitea/handlers/main.yml
# ------------------------------------------------------------------------------
- name: restart gitea
community.docker.docker_compose_v2:
project_src: "{{ gitea_compose_dir }}"
state: present
recreate: always

View File

@@ -0,0 +1,27 @@
---
# ------------------------------------------------------------------------------
# FILE: ansible/playbooks/roles/gitea/tasks/configure_oidc.yml
# DESCRIPTION: Registers Authentik as an OAuth2 source in Gitea via the admin
# API. Idempotent — skips creation if source already exists.
# ------------------------------------------------------------------------------
- name: Check if authentik auth source already exists
ansible.builtin.command:
cmd: docker exec -u git gitea-gitea-1 gitea admin auth list
register: _auth_list
changed_when: false
- name: Create Authentik OAuth2 auth source
ansible.builtin.command:
cmd: >
docker exec -u git gitea-gitea-1 gitea admin auth add-oauth
--name authentik
--provider openidConnect
--key {{ gitea_oidc_client_id }}
--secret {{ gitea_oidc_client_secret }}
--auto-discover-url {{ gitea_oidc_discovery_url }}
--scopes "email profile"
--group-claim-name groups
--admin-group {{ gitea_oidc_admin_group }}
--skip-local-2fa false
when: "'authentik' not in _auth_list.stdout"

View File

@@ -0,0 +1,67 @@
---
# ------------------------------------------------------------------------------
# FILE: ansible/playbooks/roles/gitea/tasks/main.yml
# ------------------------------------------------------------------------------
# ── Directories ────────────────────────────────────────────────────────────────
- name: Create Gitea compose directory
ansible.builtin.file:
path: "{{ gitea_compose_dir }}"
state: directory
owner: root
group: root
mode: "0755"
# ── Compose & env ──────────────────────────────────────────────────────────────
- name: Deploy Gitea compose file from boilerplate
ansible.builtin.copy:
src: "{{ playbook_dir }}/../../boilerplates/gitea/compose.yaml"
dest: "{{ gitea_compose_dir }}/compose.yaml"
owner: root
group: root
mode: "0644"
notify: restart gitea
- name: Deploy .env file with secrets from vault
ansible.builtin.template:
src: env.j2
dest: "{{ gitea_compose_dir }}/.env"
owner: root
group: root
mode: "0600"
notify: restart gitea
# ── Compose stack ──────────────────────────────────────────────────────────────
- name: Start Gitea stack
community.docker.docker_compose_v2:
project_src: "{{ gitea_compose_dir }}"
state: present
recreate: always
# ── Traefik route ──────────────────────────────────────────────────────────────
# - name: Deploy Traefik dynamic config for Gitea
# ansible.builtin.copy:
# src: "{{ playbook_dir }}/../../boilerplates/traefik/dynamic/gitea.yml"
# dest: "{{ traefik_dynamic_config_dir }}/gitea.yml"
# owner: root
# group: root
# mode: "0644"
# delegate_to: localhost
# ── DNS ────────────────────────────────────────────────────────────────────────
# - name: Create DNS CNAME for Gitea
# ansible.builtin.include_role:
# name: add_service_route
# vars:
# service_name: "{{ gitea_cname_name }}"
# service_domain: "{{ gitea_cname_domain }}"
# target_host: "{{ gitea_cname_target }}"
- name: Configure Authentik OIDC source
ansible.builtin.import_tasks: configure_oidc.yml
when: gitea_oidc_enabled | bool
tags: oidc

View File

@@ -0,0 +1,12 @@
# ------------------------------------------------------------------------------
# FILE: ansible/playbooks/roles/gitea/templates/env.j2
# DESCRIPTION: Environment file for Gitea Docker Compose stack.
# Populated from Ansible Vault at deploy time.
# ------------------------------------------------------------------------------
DATABASE_PASSWORD={{ gitea_db_password }}
# OIDC auto-registration (Gitea reads these at runtime)
GITEA__oauth2__ENABLE_AUTO_REGISTRATION=true
GITEA__oauth2__UPDATE_AVATAR=true
GITEA__oauth2__ACCOUNT_LINKING=login

Some files were not shown because too many files have changed in this diff Show More