Personal Homelab
1data "bitwarden_secret" "vmauth_traefik_bearer_token" {
2 id = var.containers_secret_config.vmauth_traefik_bearer_token
3}
4
5data "bitwarden_secret" "vmauth_proxmox_bearer_token" {
6 id = var.containers_secret_config.vmauth_proxmox_bearer_token
7}
8
9data "bitwarden_secret" "immich_map_key" {
10 id = var.containers_secret_config.immich_map_key
11}
12
13// Matrix secrets
14data "bitwarden_secret" "coturn_turn_shared_secret" {
15 id = var.containers_secret_config.coturn_turn_shared_secret
16}
17data "bitwarden_secret" "synapse_postgres_password" {
18 id = var.containers_secret_config.synapse_postgres_password
19}
20data "bitwarden_secret" "synapse_registration_shared_secret" {
21 id = var.containers_secret_config.synapse_registration_shared_secret
22}
23data "bitwarden_secret" "synapse_macaroon_secret_key" {
24 id = var.containers_secret_config.synapse_macaroon_secret_key
25}
26data "bitwarden_secret" "synapse_form_secret" {
27 id = var.containers_secret_config.synapse_form_secret
28}
29data "bitwarden_secret" "synapse_oidc_client_secret" {
30 id = var.containers_secret_config.synapse_oidc_client_secret
31}
32data "bitwarden_secret" "matrix_authentication_service_postgres_password" {
33 id = var.containers_secret_config.matrix_authentication_service_postgres_password
34}
35data "bitwarden_secret" "matrix_authentication_service_secret" {
36 id = var.containers_secret_config.matrix_authentication_service_secret
37}
38data "bitwarden_secret" "matrix_authentication_service_secrets_encryption" {
39 id = var.containers_secret_config.matrix_authentication_service_secrets_encryption
40}
41data "bitwarden_secret" "matrix_authentication_service_secrets_rsa_key" {
42 id = var.containers_secret_config.matrix_authentication_service_secrets_rsa_key
43}
44data "bitwarden_secret" "matrix_authentication_service_secrets_p256_key" {
45 id = var.containers_secret_config.matrix_authentication_service_secrets_p256_key
46}
47data "bitwarden_secret" "matrix_authentication_service_secrets_p384_key" {
48 id = var.containers_secret_config.matrix_authentication_service_secrets_p384_key
49}
50data "bitwarden_secret" "matrix_authentication_service_secrets_secp256k1_key" {
51 id = var.containers_secret_config.matrix_authentication_service_secrets_secp256k1_key
52}
53data "bitwarden_secret" "matrix_authentication_service_smtp_password" {
54 id = var.containers_secret_config.matrix_authentication_service_smtp_password
55}
56data "bitwarden_secret" "matrix_rtc_livekit_key" {
57 id = var.containers_secret_config.matrix_rtc_livekit_key
58}
59data "bitwarden_secret" "matrix_rtc_livekit_secret" {
60 id = var.containers_secret_config.matrix_rtc_livekit_secret
61}
62
63locals {
64 // Add secrets into quadlets config
65 containers_config = merge(var.containers_config, {
66 proxmox_ip : var.proxmox_config.host,
67 truenas_ip : var.fcos_config.truenas_ip,
68 fcos_ip : var.fcos_config.ip,
69 secrets : {
70 vmauth_traefik_bearer_token : data.bitwarden_secret.vmauth_traefik_bearer_token.value
71 vmauth_proxmox_bearer_token : data.bitwarden_secret.vmauth_proxmox_bearer_token.value
72 immich_map_key : data.bitwarden_secret.immich_map_key.value
73 coturn_turn_shared_secret : data.bitwarden_secret.coturn_turn_shared_secret.value
74 synapse_postgres_password : data.bitwarden_secret.synapse_postgres_password.value
75 synapse_registration_shared_secret : data.bitwarden_secret.synapse_registration_shared_secret.value
76 synapse_macaroon_secret_key : data.bitwarden_secret.synapse_macaroon_secret_key.value
77 synapse_form_secret : data.bitwarden_secret.synapse_form_secret.value
78 synapse_oidc_client_secret : data.bitwarden_secret.synapse_oidc_client_secret.value
79 matrix_authentication_service_postgres_password : data.bitwarden_secret.matrix_authentication_service_postgres_password.value
80 matrix_authentication_service_secret : data.bitwarden_secret.matrix_authentication_service_secret.value
81 matrix_authentication_service_secrets_encryption : data.bitwarden_secret.matrix_authentication_service_secrets_encryption.value
82 matrix_authentication_service_secrets_rsa_key : data.bitwarden_secret.matrix_authentication_service_secrets_rsa_key.value
83 matrix_authentication_service_secrets_p256_key : data.bitwarden_secret.matrix_authentication_service_secrets_p256_key.value
84 matrix_authentication_service_secrets_p384_key : data.bitwarden_secret.matrix_authentication_service_secrets_p384_key.value
85 matrix_authentication_service_secrets_secp256k1_key : data.bitwarden_secret.matrix_authentication_service_secrets_secp256k1_key.value
86 matrix_authentication_service_smtp_password : data.bitwarden_secret.matrix_authentication_service_smtp_password.value
87 matrix_rtc_livekit_key : data.bitwarden_secret.matrix_rtc_livekit_key.value
88 matrix_rtc_livekit_secret : data.bitwarden_secret.matrix_rtc_livekit_secret.value
89 }
90 })
91
92 # Get a list of all files in the specified directory
93 config_paths = fileset("${path.module}/configs", "**")
94 config_files = {
95 for cfgpath in local.config_paths :
96 replace(cfgpath, ".tftpl", "") => templatefile("${path.module}/configs/${cfgpath}", local.containers_config)
97 }
98 # Terraform hasn't directory alternative for fileset method
99 config_dirs = provider::homelab-helpers::dirset("${path.module}/configs", "**")
100
101 butane_config = merge(var.fcos_config, {
102 config_files : local.config_files
103 config_dirs : local.config_dirs,
104 })
105
106 config_rendered_files = {
107 for path, content in local.config_files :
108 path => content
109 }
110
111 init_script_path = "${path.module}/scripts/init_fcos.sh.tftpl"
112}
113
114output "directories_to_create" {
115 value = local.config_dirs
116}
117
118data "ct_config" "fcos_ignition" {
119 content = templatefile("${path.module}/butane/fcos.yml.tftpl", local.butane_config)
120 strict = true
121}
122
123resource "proxmox_virtual_environment_vm" "fcos" {
124 node_name = "pve"
125 name = "fcos"
126 description = "Managed by OpenTofu"
127
128 lifecycle {
129 ignore_changes = [
130 disk["file_id"],
131 kvm_arguments
132 ]
133 }
134
135 # Use modern platform
136 machine = "q35"
137 bios = "ovmf"
138
139 startup {
140 order = 20
141 }
142
143 cpu {
144 cores = 16
145 type = "Skylake-Client-v4"
146 units = 1024
147 }
148
149 memory {
150 dedicated = 32768
151 floating = 32768
152 }
153
154 efi_disk {
155 datastore_id = "local-zfs"
156 type = "4m"
157 }
158
159 disk {
160 interface = "virtio0"
161 datastore_id = "local-zfs"
162 file_id = proxmox_virtual_environment_file.fcos_qcow2.id
163 size = 32
164 }
165
166 tpm_state {
167 datastore_id = "local-zfs"
168 }
169
170 network_device {
171 bridge = "vmbr0"
172 vlan_id = 100
173 mac_address = var.fcos_config.mac_address
174 }
175
176 # Linux 6.x
177 operating_system {
178 type = "l26"
179 }
180
181 # Intel Arc Pro B50 video
182 hostpci {
183 device = "hostpci0"
184 id = "0000:03:00.0"
185 pcie = true
186 rombar = true
187 }
188
189 # Intel Arc Pro B50 audio
190 hostpci {
191 device = "hostpci1"
192 id = "0000:04:00.0"
193 pcie = true
194 rombar = true
195 }
196
197 agent {
198 enabled = true
199 }
200
201 kvm_arguments = "-fw_cfg 'name=opt/com.coreos/config,string=${replace(data.ct_config.fcos_ignition.rendered, ",", ",,")}'"
202}
203
204resource "null_resource" "fcos_provision_secrets" {
205 depends_on = [proxmox_virtual_environment_vm.fcos]
206
207 triggers = {
208 checksum = sha256(file(local.init_script_path))
209 }
210
211 connection {
212 type = "ssh"
213 user = "core"
214 agent = true
215 host = var.fcos_config.ip
216 }
217
218 provisioner "file" {
219 destination = "/tmp/init.sh"
220 content = templatefile(local.init_script_path, {
221 bws_access_token : var.bws_access_token
222 config_files : local.config_files
223 secrets : var.containers_secret_config
224 })
225 }
226
227 provisioner "remote-exec" {
228 inline = ["sh /tmp/init.sh"]
229 on_failure = fail
230 }
231}
232
233resource "null_resource" "sync_configs" {
234 depends_on = [proxmox_virtual_environment_vm.fcos]
235
236 triggers = {
237 configs_hash = provider::homelab-helpers::dirhash("${path.module}/configs", "**")
238 }
239
240 connection {
241 type = "ssh"
242 user = "core"
243 private_key = file(pathexpand(var.fcos_config.ssh_private_key_path))
244 host = var.fcos_config.ip
245 }
246
247 // Create directories if not exist
248 provisioner "remote-exec" {
249 inline = distinct([
250 for path, _ in local.config_rendered_files :
251 "mkdir -p /var/home/core/.config/${replace(dirname(path), "\\", "/")}"
252 ])
253 }
254
255 // Copy files, but remove the last byte to avoid double newline
256 provisioner "remote-exec" {
257 inline = [
258 for path, content in local.config_rendered_files : <<-EOT
259 cat <<'EOF' | head -c -1 > "/var/home/core/.config/${path}"
260 ${content}
261 EOF
262 EOT
263 ]
264 }
265
266 provisioner "remote-exec" {
267 inline = [
268 "systemctl --user daemon-reload"
269 ]
270 }
271}