From 87029ef2905d6b982a87a34fca9eddb9343c0bdb Mon Sep 17 00:00:00 2001
From: Tine <tine@tjo.space>
Date: Fri, 7 Mar 2025 12:13:53 +0100
Subject: [PATCH] feat(id.tjo.space): changes

---
 .gitignore                                    |  12 ++-
 example.env                                   |   4 +
 id.tjo.space/configs/authentik/authentik.env  |  23 ++++++
 id.tjo.space/configs/caddy/Caddyfile          |   2 +-
 id.tjo.space/configure.sh                     |  72 ++++++++++++++++++
 .../containers/authentik-ldap.container       |   3 +
 .../containers/authentik-server.container     |   3 +
 .../containers/authentik-worker.container     |   2 +
 id.tjo.space/containers/caddy.container       |   2 +-
 id.tjo.space/containers/postgresql.container  |   5 +-
 id.tjo.space/install.sh                       |  51 -------------
 id.tjo.space/justfile                         |  29 +++++--
 id.tjo.space/provision.sh                     |  16 ++++
 id.tjo.space/secrets.env.encrypted            | Bin 0 -> 642 bytes
 id.tjo.space/terraform/main.tf                |  26 ++++---
 15 files changed, 172 insertions(+), 78 deletions(-)
 create mode 100644 example.env
 create mode 100644 id.tjo.space/configs/authentik/authentik.env
 create mode 100755 id.tjo.space/configure.sh
 delete mode 100755 id.tjo.space/install.sh
 create mode 100755 id.tjo.space/provision.sh
 create mode 100644 id.tjo.space/secrets.env.encrypted

diff --git a/.gitignore b/.gitignore
index 0d77d87..2ae0a64 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,11 +1,9 @@
-# Encrypted environment variables
-env
-*.env
-!root/**/*.env
+# ---> Dot ENV
+.env
 
-# Encrypted ssh keys
-ssh
-*.ssh
+# ---> Secrets
+**/secrets.env
+!**/secrets.env.encrypted
 
 # ---> Terraform
 # Local .terraform directories
diff --git a/example.env b/example.env
new file mode 100644
index 0000000..c7c59e2
--- /dev/null
+++ b/example.env
@@ -0,0 +1,4 @@
+TF_VAR_hcloud_token=your_hcloud_token
+
+TF_VAR_dnsimple_token=your_dnsimple_token
+TF_VAR_dnsimple_account_id=your_dnsimple_account_id
diff --git a/id.tjo.space/configs/authentik/authentik.env b/id.tjo.space/configs/authentik/authentik.env
new file mode 100644
index 0000000..d9a9d84
--- /dev/null
+++ b/id.tjo.space/configs/authentik/authentik.env
@@ -0,0 +1,23 @@
+AUTHENTIK_DISABLE_UPDATE_CHECK: false
+AUTHENTIK_ERROR_REPORTING__ENABLED: false
+AUTHENTIK_DISABLE_STARTUP_ANALYTICS: true
+
+AUTHENTIK_AVATARS: initials
+
+# AUTHENTIK_SECRET_KEY: "via secrets.env file"
+
+AUTHENTIK_IMPERSONATION: "false"
+
+AUTHENTIK_REDIS__HOST: valkey
+
+AUTHENTIK_POSTGRESQL__HOST: postgresql
+AUTHENTIK_POSTGRESQL__USER: id.tjo.space
+AUTHENTIK_POSTGRESQL__NAME: id.tjo.space
+# AUTHENTIK_POSTGRESQL__PASSWORD: "via secrets.env file"
+
+AUTHENTIK_EMAIL__HOST: mail.tjo.space
+AUTHENTIK_EMAIL__PORT: "587"
+AUTHENTIK_EMAIL__USE_TLS: "true"
+AUTHENTIK_EMAIL__FROM: id@tjo.space
+AUTHENTIK_EMAIL__USERNAME: id@tjo.space
+# AUTHENTIK_EMAIL__PASSWORD: "via secrets.env file"
diff --git a/id.tjo.space/configs/caddy/Caddyfile b/id.tjo.space/configs/caddy/Caddyfile
index 6fbe323..b5ea00d 100644
--- a/id.tjo.space/configs/caddy/Caddyfile
+++ b/id.tjo.space/configs/caddy/Caddyfile
@@ -2,7 +2,7 @@
     acme_ca https://acme-staging-v02.api.letsencrypt.org/directory
 }
 
-{$DOMAIN_NAME}
+next.id.tjo.space
 
 respond /tjo-space/status "OK"
 
diff --git a/id.tjo.space/configure.sh b/id.tjo.space/configure.sh
new file mode 100755
index 0000000..85efc61
--- /dev/null
+++ b/id.tjo.space/configure.sh
@@ -0,0 +1,72 @@
+#!/bin/bash
+set -euo pipefail
+
+SERVICE_DIR="/root/service"
+mkdir -p ${SERVICE_DIR}
+cd ${SERVICE_DIR}
+
+echo "== Fetch Source Code (from git)"
+# Clone if not yet cloned
+if [ ! -d .git ]; then
+  git clone \
+    --depth 1 \
+    --no-checkout \
+    --filter=tree:0 \
+    https://github.com/tjo-space/tjo-space-infrastructure.git .
+  git sparse-checkout set --no-cone /id.tjo.space
+  git checkout
+else
+  git fetch --depth=1
+  git reset --hard origin/main
+fi
+
+echo "=== Configure Firewall"
+ufw --force reset
+
+ufw default deny incoming
+ufw default allow outgoing
+
+ufw allow 22/tcp  # SSH
+ufw allow 80/tcp  # HTTP
+ufw allow 443/tcp # HTTPS
+ufw allow 636/tcp # LDAPS
+
+ufw --force enable
+
+echo "=== Copy Configuration Files"
+rsync -a id.tjo.space/containers/ /etc/containers/systemd/
+rsync -a id.tjo.space/configs/ /etc/
+systemctl daemon-reload
+
+echo "=== Read Secrets"
+age -d -i /etc/age/key.txt id.tjo.space/secrets.env.encrypted >id.tjo.space/secrets.env
+set -a && source id.tjo.space/secrets.env && set +a
+
+echo "=== Setup Caddy"
+systemctl start caddy
+
+echo "=== Setup Postgresql"
+cat <<EOF >/etc/postgresql/secrets.env
+POSTGRES_PASSWORD=${POSTGRESQL_PASSWORD}
+EOF
+systemctl start postgresql
+
+echo "=== Setup Redis"
+systemctl start redis
+
+echo "=== Setup Authentik Server"
+cat <<EOF >/etc/authentik/secrets.env
+AUTHENTIK_SECRET_KEY=${AUTHENTIK_SECRET_KEY}
+AUTHENTIK_EMAIL__PASSWORD=${AUTHENTIK_EMAIL__PASSWORD}
+AUTHENTIK_POSTGRESQL__PASSWORD=${POSTGRESQL_PASSWORD}
+EOF
+systemctl start authentik-server
+
+echo "=== Setup Authentik Worker"
+systemctl start authentik-worker
+
+echo "=== Setup Authentik LDAP"
+cat <<EOF >/etc/authentik/ldap.secrets.env
+AUTHENTIK_TOKEN=${AUTHENTIK_LDAP_TOKEN}
+EOF
+systemctl start authentik-ldap
diff --git a/id.tjo.space/containers/authentik-ldap.container b/id.tjo.space/containers/authentik-ldap.container
index bad2054..622db3d 100644
--- a/id.tjo.space/containers/authentik-ldap.container
+++ b/id.tjo.space/containers/authentik-ldap.container
@@ -3,6 +3,9 @@ Description=An Authentik LDAP Server
 
 [Container]
 Image=ghcr.io/goauthentik/ldap:2025.2.1
+Environment=AUTHENTIK_HOST=https://next.id.tjo.space
+Environment=AUTHENTIK_INSECURE=false
+EnvironmentFile=/etc/authentik/ldap.secrets.env
 
 [Service]
 Restart=always
diff --git a/id.tjo.space/containers/authentik-server.container b/id.tjo.space/containers/authentik-server.container
index 3b36969..f68891d 100644
--- a/id.tjo.space/containers/authentik-server.container
+++ b/id.tjo.space/containers/authentik-server.container
@@ -3,6 +3,9 @@ Description=An Authentik Server
 
 [Container]
 Image=ghcr.io/goauthentik/authentik:2025.2.1
+EnvironmentFile=/etc/authentik/authentik.env
+EnvironmentFile=/etc/authentik/secrets.env
+Volume=/media:/srv/authentik/media
 
 [Service]
 Restart=always
diff --git a/id.tjo.space/containers/authentik-worker.container b/id.tjo.space/containers/authentik-worker.container
index db8643c..98a2b1f 100644
--- a/id.tjo.space/containers/authentik-worker.container
+++ b/id.tjo.space/containers/authentik-worker.container
@@ -4,6 +4,8 @@ Description=An Authentik Worker
 [Container]
 Image=ghcr.io/goauthentik/authentik:2025.2.1
 Exec=worker
+EnvironmentFile=/etc/authentik/authentik.env
+EnvironmentFile=/etc/authentik/secrets.env
 
 [Service]
 Restart=always
diff --git a/id.tjo.space/containers/caddy.container b/id.tjo.space/containers/caddy.container
index e7c86d3..11b65d4 100644
--- a/id.tjo.space/containers/caddy.container
+++ b/id.tjo.space/containers/caddy.container
@@ -5,7 +5,7 @@ Description=A Caddy Container
 Image=docker.io/caddy:2.9
 PublishPort=443:443
 PublishPort=80:80
-Volume=/etc/caddy:/etc/caddy
+Volume=/etc/caddy:/etc/caddy:ro
 EnvironmentFile=/etc/caddy/env
 
 [Service]
diff --git a/id.tjo.space/containers/postgresql.container b/id.tjo.space/containers/postgresql.container
index e189655..acda9d7 100644
--- a/id.tjo.space/containers/postgresql.container
+++ b/id.tjo.space/containers/postgresql.container
@@ -3,7 +3,10 @@ Description=A Postgresql Container
 
 [Container]
 Image=docker.io/postgresql:17.4
-Volime=/var/lib/postgresql/data:/srv/postgresql/data
+Volume=/var/lib/postgresql/data:/srv/postgresql/data
+EnvironmentFile=/etc/postgresql/secrets.env
+Environment=POSTGRES_USER=id.tjo.space
+Environment=POSTGRES_DB=id.tjo.space
 
 [Service]
 Restart=always
diff --git a/id.tjo.space/install.sh b/id.tjo.space/install.sh
deleted file mode 100755
index a535441..0000000
--- a/id.tjo.space/install.sh
+++ /dev/null
@@ -1,51 +0,0 @@
-#!/bin/bash
-set -euo pipefail
-
-SERVICE_DIR="/root/service"
-mkdir -p ${SERVICE_DIR}
-cd ${SERVICE_DIR}
-
-echo "== Fetch Source Code (from git)"
-# Clone if not yet cloned
-if [ ! -d .git ]; then
-  git clone \
-    --depth 1 \
-    --no-checkout \
-    --filter=tree:0 \
-    https://github.com/tjo-space/tjo-space-infrastructure.git .
-  git sparse-checkout set --no-cone /id.tjo.space
-  git checkout
-else
-  git fetch --depth=1
-  git reset --hard origin/main
-fi
-
-echo "=== Installing Dependencies"
-DEBIAN_FRONTEND=noninteractive apt update -y
-DEBIAN_FRONTEND=noninteractive apt install -y \
-  rsync \
-  jq \
-  podman
-
-echo "=== Configure Firewall"
-ufw allow 22/tcp  # SSH
-ufw allow 80/tcp  # HTTP
-ufw allow 443/tcp # HTTPS
-ufw allow 636/tcp # LDAPS
-ufw --force enable
-
-echo "== Configure Metadata"
-DOMAIN_NAME=$(jq -r ".domain" /etc/tjo.space/meta.json)
-
-echo "=== Copy Configuration Files"
-rsync -av id.tjo.space/containers/ /etc/containers/systemd/
-rsync -av id.tjo.space/configs/ /etc/
-
-systemctl daemon-reload
-
-echo "=== Setup Caddy"
-cat <<EOF >/etc/caddy/env
-DOMAIN_NAME=${DOMAIN_NAME}
-EOF
-
-systemctl start caddy
diff --git a/id.tjo.space/justfile b/id.tjo.space/justfile
index db76c49..42dd647 100644
--- a/id.tjo.space/justfile
+++ b/id.tjo.space/justfile
@@ -1,6 +1,19 @@
 default:
   @just --list
 
+secrets-encrypt:
+  #!/usr/bin/env sh
+  age --encrypt \
+    -r age1cl3d4wtrrqrgldmrzpu53q2mk60r7hrhrymsrwss8s57z4mdv9fst4a55h \
+    -r age1a4t9l73au9fqfk0x5kw6v06ewwpl0lurw73f3m60c5ly58r3hp5q6shdfr \
+    secrets.env > secrets.env.encrypted
+
+secrets-decrypt:
+  #!/usr/bin/env sh
+  age --decrypt \
+    -i ${HOME}/.config/sops/age/keys.txt \
+    secrets.env.encrypted > secrets.env
+
 apply:
   #!/usr/bin/env sh
   cd {{source_directory()}}/terraform
@@ -17,20 +30,24 @@ outputs:
   cd {{source_directory()}}/terraform
   tofu output
 
-ssh node:
+provision node:
   #!/usr/bin/env sh
+  set -eou pipefail
+
   pushd {{source_directory()}}/terraform > /dev/null
-  IPV4=$(tofu output -json | jq -r '.ipv4[{{node}}]')
+  IPV4=$(tofu output -json | jq -r '.ipv4.value["{{node}}"]')
   popd > /dev/null
-  ssh root@${IPV4}
+
+  echo "= Provision node: {{node}} (${IPV4})"
+  cat provision.sh | ssh -o StrictHostKeyChecking=no root@${IPV4} 'sudo bash -s'
 
 configure node:
   #!/usr/bin/env sh
   set -eou pipefail
 
   pushd {{source_directory()}}/terraform > /dev/null
-  IPV4=$(tofu output -json | jq -r '.ipv4[{{node}}]')
+  IPV4=$(tofu output -json | jq -r '.ipv4.value["{{node}}"]')
   popd > /dev/null
 
-  echo "= Provisioning id.tjo.space"
-  cat install.sh | ssh root@${IPV4} 'sudo bash -s'
+  echo "= Configuring node: {{node}} (${IPV4})"
+  cat configure.sh | ssh -o StrictHostKeyChecking=no root@${IPV4} 'sudo bash -s'
diff --git a/id.tjo.space/provision.sh b/id.tjo.space/provision.sh
new file mode 100755
index 0000000..da9184b
--- /dev/null
+++ b/id.tjo.space/provision.sh
@@ -0,0 +1,16 @@
+#!/bin/bash
+set -euo pipefail
+
+pushd "$(mktemp -d)"
+
+echo "=== Installing Dependencies"
+DEBIAN_FRONTEND=noninteractive apt update -y
+DEBIAN_FRONTEND=noninteractive apt install -y \
+  rsync \
+  jq \
+  podman \
+  age
+
+echo "=== Generating Age Key"
+mkdir -p /etc/age
+age-keygen -o /etc/age/key.txt
diff --git a/id.tjo.space/secrets.env.encrypted b/id.tjo.space/secrets.env.encrypted
new file mode 100644
index 0000000000000000000000000000000000000000..83a34560f9fc164300e567137e9a0512896925e1
GIT binary patch
literal 642
zcmV-|0)72qXJsvAZewzJaCB*JZZ2<fXD@a!3N1b$STZ#=F*zV}ct=u7NOns?I9XaS
zO=&AJPgZ(TOjk8?Yjan2YEegVVRcz`Z9+<6GC>MOH&J4CXJS`YQ$l8MF>iWCcScV|
zGHFC-bVDmwF?BClFk??_YG+AMI5Y|^J|I{!H8n9gAUQ-aFi$i`Rxw3lFHvnULw0m}
zFnUpWL2i0UQb=TYWH2&NGjCQ%R4YeK3RZPFXG=;|S43x5a&B)pYiKYuL~%4yc1lKV
zOHXD|VmM-GWHLxbG&X5x3N0-yAT}~sP%~OpXE-@bHEMG>QC3TOV{deGML2R<Ggfw0
zL^ez{VPRG^XIU>v3NayJv`oemYuiqPQQdjXpP#GTV!`&Lx~URkj9*!$_AuVZMMtJo
zVP4773Qk6oGN7>!5pZm;w>bKxc&idhnnYBB*+4xBVmugzpl+L24&vALte#2rJs0aY
zhu|}wd^t#IF++vOcVG)@<Y{AmY|9p+%i{WQ1jcEETtTU7h*xS>{Z2NvaVSoY`5XPc
zmp}KkRg?*NJ~EILRcyB$queoJp#rFMaAuAI2NP*4=TbQ7n~D@n9~l$Zb0qr+5$qQp
z_3$p@$q^`No1~3Y{dxP6Q{${M)FQh&zu?{7F6D(64L6bdFudHLTvQc87bqbmitM{e
zF+5hmtfsBqnxxbj-GHRBOJaQ+V!9a{Gk!FfG~N(Pd+KkKZw!9`Z!9Xy^_YAmOVu5U
zmZ+;Lx`@tA*SmLjg&HQ-eH<)op-7b9QLPSGe_%YQ+N3ENvurxL(4t43zF=TyNf$it
ceg@CoO1k`?65k`s!>A>hC{*yV=HusFg$wNlqW}N^

literal 0
HcmV?d00001

diff --git a/id.tjo.space/terraform/main.tf b/id.tjo.space/terraform/main.tf
index 4438af4..92ef5fb 100644
--- a/id.tjo.space/terraform/main.tf
+++ b/id.tjo.space/terraform/main.tf
@@ -40,6 +40,9 @@ resource "hcloud_server" "main" {
     - path: /etc/tjo.space/meta.json
       encoding: base64
       content: ${base64encode(jsonencode(each.value.meta))}
+    - path: /tmp/provision.sh
+      encoding: base64
+      content: ${base64encode(file("${path.module}/../provision.sh"))}
     packages:
       - git
       - curl
@@ -51,7 +54,9 @@ resource "hcloud_server" "main" {
       filename: /swapfile
       size: 512M
     runcmd:
-      - "curl -sL https://raw.githubusercontent.com/tjo-space/tjo-space-infrastructure/refs/heads/main/id.tjo.space/install.sh | bash"
+      - "chmod +x /tmp/provision.sh"
+      - "/tmp/provision.sh"
+      - "rm /tmp/provision.sh"
     EOF
 }
 
@@ -65,13 +70,12 @@ resource "dnsimple_zone_record" "a" {
   ttl       = 300
 }
 
-# Podman is PITA!
-#resource "dnsimple_zone_record" "aaaa" {
-#  for_each = local.nodes
-#
-#  zone_name = "tjo.space"
-#  name      = trimsuffix(each.value.meta.domain, ".tjo.space")
-#  value     = hcloud_server.main[each.key].ipv6_address
-#  type      = "AAAA"
-#  ttl       = 300
-#}
+resource "dnsimple_zone_record" "aaaa" {
+  for_each = local.nodes
+
+  zone_name = "tjo.space"
+  name      = trimsuffix(each.value.meta.domain, ".tjo.space")
+  value     = hcloud_server.main[each.key].ipv6_address
+  type      = "AAAA"
+  ttl       = 300
+}