Move all files to root
This commit is contained in:
60
src/main/infra/dns.cljs
Normal file
60
src/main/infra/dns.cljs
Normal file
@@ -0,0 +1,60 @@
|
||||
(ns infra.dns
|
||||
(:require
|
||||
[clojure.string :as str]
|
||||
["@pulumi/cloudflare" :as cloudflare]
|
||||
["@pulumi/command/local" :as local]))
|
||||
|
||||
(defn get-record-type
|
||||
"Determines the DNS record type (A or AAAA) based on IP address format."
|
||||
[ip-address]
|
||||
(if (.includes ip-address ":")
|
||||
"AAAA"
|
||||
"A"))
|
||||
|
||||
(defn- get-node-ips []
|
||||
(str "kubectl get nodes -o jsonpath='{range .items[*]}{.status.addresses[?(@.type==\"ExternalIP\")].address}{\"\\n\"}{end}'"))
|
||||
|
||||
(defn setup-dns [{:keys [pulumi-cfg secrets dependencies]}]
|
||||
(let [get-node-ips (local/Command.
|
||||
"get-node-ips"
|
||||
(clj->js {:create (get-node-ips)
|
||||
:environment {:KUBECONFIG "./kubeconfig.yaml"}}))
|
||||
token (.requireSecret pulumi-cfg "apiToken")
|
||||
cloudflare-provider (new cloudflare/Provider "cloudflare-provider"
|
||||
(clj->js {:apiToken token}))
|
||||
node-ips-output (.-stdout get-node-ips)]
|
||||
|
||||
|
||||
(.apply node-ips-output
|
||||
(fn [command-output]
|
||||
(let [node-ips (-> command-output
|
||||
str/split-lines
|
||||
(->> (map #(first (str/split % #" ")))
|
||||
(filter seq)))]
|
||||
(.apply secrets
|
||||
(fn [secret-data]
|
||||
(let [hostname-to-zone (js->clj secret-data :keywordize-keys true)]
|
||||
(vec
|
||||
(for [[hostname zone-id] hostname-to-zone
|
||||
[index ip] (map-indexed vector node-ips)
|
||||
:when (and hostname zone-id ip)]
|
||||
|
||||
|
||||
(new cloudflare/DnsRecord
|
||||
(str "dns-" (name hostname) "-node-" index)
|
||||
(clj->js {:zoneId zone-id
|
||||
:name hostname
|
||||
:content ip
|
||||
:type (get-record-type ip)
|
||||
:ttl 1
|
||||
:proxied true})
|
||||
(clj->js {:provider cloudflare-provider})
|
||||
(clj->js {:dependsOn dependencies}))))))))))))
|
||||
|
||||
(def config
|
||||
{:stack [:vault:prepare :generic:execute]
|
||||
:app-name "dns"
|
||||
:no-namespace true
|
||||
:exec-fn setup-dns})
|
||||
|
||||
|
||||
172
src/main/infra/init.cljs
Normal file
172
src/main/infra/init.cljs
Normal file
@@ -0,0 +1,172 @@
|
||||
(ns infra.init
|
||||
(:require ["@pulumi/pulumi" :as pulumi]
|
||||
["@pulumi/hcloud" :as hcloud]
|
||||
["@pulumi/command/remote" :as remote]
|
||||
["@pulumi/command/local" :as local]
|
||||
["fs" :as fs]))
|
||||
|
||||
(defn- setup-master-script []
|
||||
(str "# Create manifests dir\n"
|
||||
"mkdir -p /var/lib/rancher/k3s/server/manifests\n\n"
|
||||
"# Traefik NodePort config\n"
|
||||
"cat <<EOF > /var/lib/rancher/k3s/server/manifests/traefik-config.yaml\n"
|
||||
"apiVersion: helm.cattle.io/v1\n"
|
||||
"kind: HelmChartConfig\n"
|
||||
"metadata:\n"
|
||||
" name: traefik\n"
|
||||
" namespace: kube-system\n"
|
||||
"spec:\n"
|
||||
" valuesContent: |-\n"
|
||||
" service:\n"
|
||||
" spec:\n"
|
||||
" type: NodePort\n"
|
||||
" ports:\n"
|
||||
" web:\n"
|
||||
" nodePort: 30080\n"
|
||||
" websecure:\n"
|
||||
" nodePort: 30443\n"
|
||||
"EOF\n\n"))
|
||||
|
||||
(defn- install-master-script [public-ip]
|
||||
(str "# Install k3s if not present\n"
|
||||
"if ! command -v k3s >/dev/null; then\n"
|
||||
" curl -sfL https://get.k3s.io | INSTALL_K3S_EXEC=\"--disable=traefik --flannel-backend=wireguard-native --node-external-ip=" public-ip "\" sh -\n"
|
||||
"fi\n\n"
|
||||
"# Wait for node readiness\n"
|
||||
"until sudo k3s kubectl get node >/dev/null 2>&1; do\n"
|
||||
" echo 'Waiting for master node...'\n"
|
||||
" sleep 5\n"
|
||||
"done\n"))
|
||||
|
||||
(defn- install-worker-script [master-ip token]
|
||||
(str "#!/bin/bash\n"
|
||||
"exec > /root/k3s-install.log 2>&1\n"
|
||||
"set -x\n"
|
||||
"echo '--- Starting worker install ---'\n\n"
|
||||
"until ping -c1 " master-ip "; do\n"
|
||||
" echo 'Waiting for master...'\n"
|
||||
" sleep 2\n"
|
||||
"done\n\n"
|
||||
"WORKER_PUBLIC_IP=$(curl -s https://ifconfig.me/ip)\n"
|
||||
"echo \"Public IP: $WORKER_PUBLIC_IP\"\n\n"
|
||||
"if ! command -v k3s >/dev/null; then\n"
|
||||
" curl -sfL https://get.k3s.io | "
|
||||
"K3S_URL=https://" master-ip ":6443 "
|
||||
"K3S_TOKEN=\"" token "\" "
|
||||
"INSTALL_K3S_EXEC=\"--node-external-ip=$WORKER_PUBLIC_IP\" sh -\n"
|
||||
"fi\n\n"
|
||||
"echo '--- Finished worker install ---'\n"))
|
||||
|
||||
(defn create-cluster [{:keys [pulumi-cfg]}]
|
||||
(let [ssh-key (.require pulumi-cfg "sshKeyName")
|
||||
personal-key (.require pulumi-cfg "sshPersonalKeyName")
|
||||
priv-key (.requireSecret pulumi-cfg "privateKeySsh")
|
||||
|
||||
firewall (hcloud/Firewall.
|
||||
"k3s-firewall"
|
||||
(clj->js {:rules [{:direction "in" :protocol "tcp" :port "22" :sourceIps ["0.0.0.0/0" "::/0"]}
|
||||
{:direction "in" :protocol "tcp" :port "6443" :sourceIps ["0.0.0.0/0" "::/0"]}
|
||||
{:direction "in" :protocol "udp" :port "51820" :sourceIps ["0.0.0.0/0" "::/0"]}
|
||||
{:direction "in" :protocol "tcp" :port "80" :sourceIps ["0.0.0.0/0" "::/0"]}
|
||||
{:direction "in" :protocol "tcp" :port "443" :sourceIps ["0.0.0.0/0" "::/0"]}
|
||||
{:direction "in" :protocol "icmp" :sourceIps ["0.0.0.0/0" "::/0"]}]}))
|
||||
|
||||
master (hcloud/Server.
|
||||
"k3s-master-de"
|
||||
(clj->js {:serverType "cx22"
|
||||
:image "ubuntu-22.04"
|
||||
:location "fsn1"
|
||||
:sshKeys [ssh-key personal-key]
|
||||
:firewallIds [(.-id firewall)]}))
|
||||
|
||||
master-ip (.-ipv4Address master)
|
||||
|
||||
master-conn (clj->js {:host master-ip
|
||||
:user "root"
|
||||
:privateKey priv-key})
|
||||
|
||||
setup-master
|
||||
(remote/Command.
|
||||
"setup-master"
|
||||
(clj->js {:connection master-conn
|
||||
:create (.apply setup-master-script)})
|
||||
(clj->js {:dependsOn [master]}))
|
||||
|
||||
install-master
|
||||
(remote/Command.
|
||||
"install-master"
|
||||
(clj->js {:connection master-conn
|
||||
:create (.apply master-ip install-master-script)})
|
||||
(clj->js {:dependsOn [setup-master]}))
|
||||
|
||||
token-cmd
|
||||
(remote/Command.
|
||||
"get-token"
|
||||
(clj->js {:connection master-conn
|
||||
:create "sudo cat /var/lib/rancher/k3s/server/node-token"})
|
||||
(clj->js {:dependsOn [install-master]}))
|
||||
|
||||
worker-script
|
||||
(.apply master-ip
|
||||
(fn [ip]
|
||||
(.apply (.-stdout token-cmd)
|
||||
(fn [token]
|
||||
(install-worker-script ip (.trim token))))))
|
||||
|
||||
worker-de (hcloud/Server.
|
||||
"k3s-worker-de"
|
||||
(clj->js {:serverType "cx22"
|
||||
:image "ubuntu-22.04"
|
||||
:location "fsn1"
|
||||
:sshKeys [ssh-key personal-key]
|
||||
:userData worker-script
|
||||
:firewallIds [(.-id firewall)]}))
|
||||
|
||||
worker-us (hcloud/Server.
|
||||
"k3s-worker-us"
|
||||
(clj->js {:serverType "cpx11"
|
||||
:image "ubuntu-22.04"
|
||||
:location "ash"
|
||||
:sshKeys [ssh-key personal-key]
|
||||
:userData worker-script
|
||||
:firewallIds [(.-id firewall)]}))
|
||||
|
||||
kubeconfig-cmd
|
||||
(remote/Command.
|
||||
"get-kubeconfig"
|
||||
(clj->js {:connection master-conn
|
||||
:create (.apply master-ip
|
||||
(fn [ip]
|
||||
(str "sudo sed 's/127.0.0.1/" ip "/' /etc/rancher/k3s/k3s.yaml")))})
|
||||
(clj->js {:dependsOn [install-master worker-de worker-us]}))
|
||||
|
||||
label-node
|
||||
(local/Command.
|
||||
"label-german-node-alt"
|
||||
(clj->js
|
||||
{:create (.apply (.-stdout kubeconfig-cmd)
|
||||
(fn [kubeconfig]
|
||||
(.apply (.-name worker-de)
|
||||
(fn [worker-name]
|
||||
(let [path "./kubeconfig.yaml"]
|
||||
(.writeFileSync fs path kubeconfig)
|
||||
(str
|
||||
"for i in {1..30}; do "
|
||||
" if kubectl --kubeconfig=" path " get node " worker-name " > /dev/null 2>&1; then "
|
||||
" echo 'Node " worker-name " found, proceeding with label.' && "
|
||||
" kubectl --kubeconfig=" path " label node " worker-name " location=de --overwrite && "
|
||||
" exit 0; "
|
||||
" else "
|
||||
" echo 'Node " worker-name " not ready yet. Waiting 10s... (Attempt: '\"$i\"'/30)'; "
|
||||
" sleep 10; "
|
||||
" fi; "
|
||||
"done; "
|
||||
"echo 'Error: Timed out waiting for node " worker-name ".' >&2 && "
|
||||
"exit 1;"))))))})
|
||||
(clj->js {:dependsOn [kubeconfig-cmd worker-de]}))]
|
||||
{:kubeconfig (pulumi/secret (.-stdout kubeconfig-cmd))}))
|
||||
|
||||
(def config
|
||||
{:stack [:generic:execute]
|
||||
:app-name "cluster"
|
||||
:exec-fn create-cluster})
|
||||
317
src/main/infra/openbao.cljs
Normal file
317
src/main/infra/openbao.cljs
Normal file
@@ -0,0 +1,317 @@
|
||||
(ns infra.openbao
|
||||
(:require
|
||||
["@pulumi/pulumi" :as pulumi]
|
||||
["@pulumi/command/local" :as local]))
|
||||
|
||||
(defn- create-wait-for-ready-script [namespace]
|
||||
"Script to wait for OpenBao pod to exist, then to be running, then for the service to be operational."
|
||||
(str "#!/bin/bash\n"
|
||||
"set -e\n\n"
|
||||
"NAMESPACE=\"" namespace "\"\n"
|
||||
"MAX_RETRIES=60\n"
|
||||
"RETRY_INTERVAL=10\n\n"
|
||||
|
||||
"## -- NEW SECTION: Wait for the pod to even exist -- ##\n"
|
||||
"echo 'Waiting for OpenBao pod to be created...'\n"
|
||||
"POD_FOUND=false\n"
|
||||
"for i in $(seq 1 $MAX_RETRIES); do\n"
|
||||
" # Check if a pod with the label exists. We redirect output to /dev/null.\n"
|
||||
" if kubectl get pod -l app.kubernetes.io/instance=openbao -n \"$NAMESPACE\" -o jsonpath='{.items[0].metadata.name}' >/dev/null 2>&1; then\n"
|
||||
" echo 'Pod has been created.'\n"
|
||||
" POD_FOUND=true\n"
|
||||
" break\n"
|
||||
" fi\n"
|
||||
" echo \"Attempt $i/$MAX_RETRIES: Pod not found yet, retrying in $RETRY_INTERVAL seconds...\"\n"
|
||||
" sleep $RETRY_INTERVAL\n"
|
||||
"done\n\n"
|
||||
"if [ \"$POD_FOUND\" = false ]; then\n"
|
||||
" echo 'Error: Timed out waiting for OpenBao pod to be created.' >&2\n"
|
||||
" exit 1\n"
|
||||
"fi\n"
|
||||
"## -- END NEW SECTION -- ##\n\n"
|
||||
|
||||
"echo 'Waiting for OpenBao pod to enter Running state...'\n"
|
||||
;; Now this command is safe to run because we know the pod exists.
|
||||
"kubectl wait --for=jsonpath='{.status.phase}'=Running pod -l app.kubernetes.io/instance=openbao -n \"$NAMESPACE\" --timeout=600s\n\n"
|
||||
|
||||
"echo 'Pod is Running. Now waiting for OpenBao service to be fully operational...'\n"
|
||||
"for i in $(seq 1 $MAX_RETRIES); do\n"
|
||||
" echo \"Attempt $i/$MAX_RETRIES: Checking if OpenBao is responding...\"\n"
|
||||
" \n"
|
||||
" # Start a temporary port-forward to test connectivity\n"
|
||||
" kubectl port-forward -n \"$NAMESPACE\" svc/openbao 8200:8200 &\n"
|
||||
" PF_PID=$!\n"
|
||||
" sleep 5 # Give port-forward a moment to establish\n"
|
||||
" \n"
|
||||
" # Test if OpenBao health endpoint responds\n"
|
||||
" if curl -s --max-time 5 http://127.0.0.1:8200/v1/sys/health >/dev/null 2>&1; then\n"
|
||||
" echo 'OpenBao is responding!'\n"
|
||||
" kill $PF_PID 2>/dev/null || true\n"
|
||||
" sleep 2 # Let port-forward cleanup\n"
|
||||
" exit 0\n"
|
||||
" fi\n"
|
||||
" \n"
|
||||
" kill $PF_PID 2>/dev/null || true\n"
|
||||
" echo ' (not yet responding, will retry...)'\n"
|
||||
" sleep $RETRY_INTERVAL\n"
|
||||
"done\n\n"
|
||||
"echo 'OpenBao failed to become ready after maximum retries'\n"
|
||||
"exit 1\n"))
|
||||
|
||||
(defn- create-init-script [namespace]
|
||||
"Robust script to initialize and unseal OpenBao with proper error handling"
|
||||
(str "#!/bin/bash\n"
|
||||
"set -e\n\n"
|
||||
"NAMESPACE=\"" namespace "\"\n"
|
||||
"BAO_ADDR='http://127.0.0.1:8200'\n"
|
||||
"PID_FILE=\"/tmp/openbao-pf.pid\"\n\n"
|
||||
"# Cleanup function\n"
|
||||
"cleanup() {\n"
|
||||
" echo 'Cleaning up...'\n"
|
||||
" if [ -f \"$PID_FILE\" ]; then\n"
|
||||
" PID=$(cat \"$PID_FILE\")\n"
|
||||
" kill $PID 2>/dev/null || true\n"
|
||||
" rm -f \"$PID_FILE\"\n"
|
||||
" fi\n"
|
||||
"}\n"
|
||||
"trap cleanup EXIT\n\n"
|
||||
"# Start port-forward in background with better error handling\n"
|
||||
"echo 'Starting port-forward...'\n"
|
||||
"kubectl port-forward -n \"$NAMESPACE\" svc/openbao 8200:8200 > /tmp/pf.log 2>&1 &\n"
|
||||
"echo $! > \"$PID_FILE\"\n\n"
|
||||
"# Wait for port-forward to be ready with timeout\n"
|
||||
"echo 'Waiting for port-forward to be active...'\n"
|
||||
"for i in {1..30}; do\n"
|
||||
" if curl -s --max-time 2 \"$BAO_ADDR/v1/sys/health\" >/dev/null 2>&1; then\n"
|
||||
" echo 'Port-forward is active!'\n"
|
||||
" break\n"
|
||||
" fi\n"
|
||||
" if [ $i -eq 30 ]; then\n"
|
||||
" echo 'Port-forward failed to become active'\n"
|
||||
" echo 'Port-forward log:'\n"
|
||||
" cat /tmp/pf.log || true\n"
|
||||
" exit 1\n"
|
||||
" fi\n"
|
||||
" printf '.'\n"
|
||||
" sleep 2\n"
|
||||
"done\n\n"
|
||||
"# Check initialization status\n"
|
||||
"echo 'Checking OpenBao initialization status...'\n"
|
||||
"HEALTH_RESPONSE=$(curl -s \"$BAO_ADDR/v1/sys/health\" || echo '{}')\n"
|
||||
"INITIALIZED=$(echo \"$HEALTH_RESPONSE\" | jq -r '.initialized // false')\n"
|
||||
"SEALED=$(echo \"$HEALTH_RESPONSE\" | jq -r '.sealed // true')\n\n"
|
||||
"echo \"Current status: initialized=$INITIALIZED, sealed=$SEALED\"\n\n"
|
||||
"if [ \"$INITIALIZED\" = \"false\" ]; then\n"
|
||||
" echo 'Initializing OpenBao...'\n"
|
||||
" \n"
|
||||
" INIT_RESPONSE=$(curl -s -w '%{http_code}' -X POST \"$BAO_ADDR/v1/sys/init\" \\\n"
|
||||
" -H 'Content-Type: application/json' \\\n"
|
||||
" -d '{\"secret_shares\":1,\"secret_threshold\":1}')\n"
|
||||
" \n"
|
||||
" HTTP_CODE=${INIT_RESPONSE: -3}\n"
|
||||
" INIT_DATA=${INIT_RESPONSE%???}\n"
|
||||
" \n"
|
||||
" if [ \"$HTTP_CODE\" != \"200\" ]; then\n"
|
||||
" echo \"Failed to initialize OpenBao. HTTP code: $HTTP_CODE\"\n"
|
||||
" echo \"Response: $INIT_DATA\"\n"
|
||||
" exit 1\n"
|
||||
" fi\n"
|
||||
" \n"
|
||||
" UNSEAL_KEY=$(echo \"$INIT_DATA\" | jq -r '.keys_base64[0]')\n"
|
||||
" ROOT_TOKEN=$(echo \"$INIT_DATA\" | jq -r '.root_token')\n"
|
||||
" \n"
|
||||
" if [ \"$UNSEAL_KEY\" = \"null\" ] || [ \"$ROOT_TOKEN\" = \"null\" ]; then\n"
|
||||
" echo 'Failed to extract keys from initialization response'\n"
|
||||
" echo \"Response: $INIT_DATA\"\n"
|
||||
" exit 1\n"
|
||||
" fi\n"
|
||||
" \n"
|
||||
" echo 'OpenBao initialized successfully!'\n"
|
||||
" \n"
|
||||
" # Save credentials securely\n"
|
||||
" echo \"$ROOT_TOKEN\" > /tmp/openbao-root-token\n"
|
||||
" echo \"$UNSEAL_KEY\" > /tmp/openbao-unseal-key\n"
|
||||
" chmod 600 /tmp/openbao-root-token /tmp/openbao-unseal-key\n"
|
||||
" \n"
|
||||
" echo 'Unsealing OpenBao...'\n"
|
||||
" UNSEAL_RESPONSE=$(curl -s -w '%{http_code}' -X POST \"$BAO_ADDR/v1/sys/unseal\" \\\n"
|
||||
" -H 'Content-Type: application/json' \\\n"
|
||||
" -d \"{\\\"key\\\":\\\"$UNSEAL_KEY\\\"}\")\n"
|
||||
" \n"
|
||||
" UNSEAL_HTTP_CODE=${UNSEAL_RESPONSE: -3}\n"
|
||||
" UNSEAL_DATA=${UNSEAL_RESPONSE%???}\n"
|
||||
" \n"
|
||||
" if [ \"$UNSEAL_HTTP_CODE\" != \"200\" ]; then\n"
|
||||
" echo \"Failed to unseal OpenBao. HTTP code: $UNSEAL_HTTP_CODE\"\n"
|
||||
" echo \"Response: $UNSEAL_DATA\"\n"
|
||||
" exit 1\n"
|
||||
" fi\n"
|
||||
" \n"
|
||||
" echo 'OpenBao unsealed successfully!'\n"
|
||||
" \n"
|
||||
"elif [ \"$SEALED\" = \"true\" ]; then\n"
|
||||
" echo '⚠OpenBao is initialized but sealed'\n"
|
||||
" \n"
|
||||
" if [ -f \"/tmp/openbao-unseal-key\" ]; then\n"
|
||||
" echo 'Attempting to unseal with existing key...'\n"
|
||||
" UNSEAL_KEY=$(cat /tmp/openbao-unseal-key)\n"
|
||||
" \n"
|
||||
" curl -s -X POST \"$BAO_ADDR/v1/sys/unseal\" \\\n"
|
||||
" -H 'Content-Type: application/json' \\\n"
|
||||
" -d \"{\\\"key\\\":\\\"$UNSEAL_KEY\\\"}\"\n"
|
||||
" \n"
|
||||
" echo 'OpenBao unsealed with existing key!'\n"
|
||||
" else\n"
|
||||
" echo 'OpenBao is sealed but no unseal key found'\n"
|
||||
" echo ' Manual intervention required'\n"
|
||||
" exit 1\n"
|
||||
" fi\n"
|
||||
"else\n"
|
||||
" echo 'OpenBao is already initialized and unsealed!'\n"
|
||||
" \n"
|
||||
" # Ensure we have the root token available\n"
|
||||
" if [ ! -f \"/tmp/openbao-root-token\" ]; then\n"
|
||||
" echo 'Root token not found locally. OpenBao is ready but you may need to provide the root token manually.'\n"
|
||||
" fi\n"
|
||||
"fi\n\n"
|
||||
"# Final verification\n"
|
||||
"echo 'Final status verification...'\n"
|
||||
"FINAL_STATUS=$(curl -s \"$BAO_ADDR/v1/sys/health\")\n"
|
||||
"FINAL_SEALED=$(echo \"$FINAL_STATUS\" | jq -r '.sealed')\n"
|
||||
"FINAL_INITIALIZED=$(echo \"$FINAL_STATUS\" | jq -r '.initialized')\n\n"
|
||||
"if [ \"$FINAL_SEALED\" = \"false\" ] && [ \"$FINAL_INITIALIZED\" = \"true\" ]; then\n"
|
||||
" echo 'OpenBao is fully ready!'\n"
|
||||
" echo 'Address: http://127.0.0.1:8200'\n"
|
||||
" \n"
|
||||
" if [ -f \"/tmp/openbao-root-token\" ]; then\n"
|
||||
" echo 'Root token: Available at /tmp/openbao-root-token'\n"
|
||||
" fi\n"
|
||||
"else\n"
|
||||
" echo 'OpenBao is not in the expected ready state'\n"
|
||||
" echo \"Final status: $FINAL_STATUS\"\n"
|
||||
" exit 1\n"
|
||||
"fi\n"))
|
||||
|
||||
(defn- create-setup-secrets-script [namespace]
|
||||
"Script to set up initial secrets after OpenBao is ready"
|
||||
(str "#!/bin/bash\n"
|
||||
"set -e\n\n"
|
||||
"NAMESPACE=\"" namespace "\"\n"
|
||||
"BAO_ADDR='http://127.0.0.1:8200'\n"
|
||||
"PID_FILE=\"/tmp/openbao-setup-pf.pid\"\n\n"
|
||||
"if [ ! -f \"/tmp/openbao-root-token\" ]; then\n"
|
||||
" echo 'Root token not found. Cannot set up secrets.'\n"
|
||||
" exit 1\n"
|
||||
"fi\n\n"
|
||||
"ROOT_TOKEN=$(cat /tmp/openbao-root-token)\n\n"
|
||||
"# Cleanup function\n"
|
||||
"cleanup() {\n"
|
||||
" if [ -f \"$PID_FILE\" ]; then\n"
|
||||
" PID=$(cat \"$PID_FILE\")\n"
|
||||
" kill $PID 2>/dev/null || true\n"
|
||||
" rm -f \"$PID_FILE\"\n"
|
||||
" fi\n"
|
||||
"}\n"
|
||||
"trap cleanup EXIT\n\n"
|
||||
"# Start port-forward\n"
|
||||
"echo 'Starting port-forward for secrets setup...'\n"
|
||||
"kubectl port-forward -n \"$NAMESPACE\" svc/openbao 8200:8200 > /tmp/setup-pf.log 2>&1 &\n"
|
||||
"echo $! > \"$PID_FILE\"\n\n"
|
||||
"# Wait for port-forward\n"
|
||||
"for i in {1..15}; do\n"
|
||||
" if curl -s --max-time 2 \"$BAO_ADDR/v1/sys/health\" >/dev/null 2>&1; then\n"
|
||||
" break\n"
|
||||
" fi\n"
|
||||
" if [ $i -eq 15 ]; then\n"
|
||||
" echo 'Port-forward failed for secrets setup'\n"
|
||||
" exit 1\n"
|
||||
" fi\n"
|
||||
" sleep 2\n"
|
||||
"done\n\n"
|
||||
"echo 'Setting up OpenBao secrets...'\n\n"
|
||||
"# Enable KV secrets engine (ignore error if already exists)\n"
|
||||
"echo 'Enabling KV secrets engine...'\n"
|
||||
"curl -s -H \"X-Vault-Token: $ROOT_TOKEN\" \\\n"
|
||||
" -X POST \"$BAO_ADDR/v1/sys/mounts/secret\" \\\n"
|
||||
" -d '{\"type\":\"kv-v2\"}' || echo ' (KV engine may already exist)'\n\n"
|
||||
"echo 'OpenBao secrets setup complete!'\n"))
|
||||
|
||||
(defn execute-fn [{:keys [dependencies]}]
|
||||
(let [wait-ready-command
|
||||
(new local/Command
|
||||
"openbao-wait-ready"
|
||||
(clj->js {:create (create-wait-for-ready-script "vault")
|
||||
:environment (clj->js {:KUBECONFIG "./kubeconfig.yaml"})})
|
||||
(clj->js {:dependsOn dependencies}))
|
||||
|
||||
init-command
|
||||
(new local/Command
|
||||
"openbao-init"
|
||||
(clj->js {:create (create-init-script "vault")
|
||||
:environment (clj->js {:KUBECONFIG "./kubeconfig.yaml"})})
|
||||
(clj->js {:dependsOn [wait-ready-command]}))
|
||||
|
||||
|
||||
setup-secrets-command
|
||||
(new local/Command
|
||||
"openbao-setup-secrets"
|
||||
(clj->js {:create (create-setup-secrets-script "vault")
|
||||
:environment (clj->js {:KUBECONFIG "./kubeconfig.yaml"})})
|
||||
(clj->js {:dependsOn [init-command]}))
|
||||
|
||||
root-token-command
|
||||
(new local/Command
|
||||
"get-root-token"
|
||||
(clj->js {:create "cat /tmp/openbao-root-token 2>/dev/null || echo 'TOKEN_NOT_FOUND'"})
|
||||
(clj->js {:dependsOn [setup-secrets-command]}))]
|
||||
{:root-token (.-stdout root-token-command)
|
||||
:address "http://127.0.0.1:8200"}))
|
||||
|
||||
|
||||
(def config
|
||||
{:stack [:k8s:namespace :k8s:chart :generic:execute]
|
||||
:app-namespace "vault"
|
||||
:app-name "openbao"
|
||||
:exec-fn execute-fn
|
||||
:vault-load-yaml false
|
||||
:k8s:chart-opts {:fetchOpts {:repo "https://openbao.github.io/openbao-helm"}
|
||||
:transformations [(fn [props opts]
|
||||
(let [kind (:kind props)]
|
||||
(if (= kind "StatefulSet")
|
||||
{:props props
|
||||
:opts (assoc opts :skipAwait true)}
|
||||
{:props props
|
||||
:opts opts})))]
|
||||
:values {:ui {:enabled true}
|
||||
:server {:standalone {:enabled true}
|
||||
:ha {:enabled false}
|
||||
:dataStorage {:enabled true
|
||||
:size "2Gi"
|
||||
:storageClass "hcloud-volumes"}
|
||||
|
||||
:readinessProbe {:enabled true
|
||||
:path "/v1/sys/health"}
|
||||
:nodeSelector {:location "de"}}}}})
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
(defn configure-vault-access
|
||||
"Configure Pulumi config with OpenBao credentials after deployment"
|
||||
[openbao-deployment]
|
||||
(let [config-command
|
||||
(new local/Command
|
||||
"configure-pulumi-vault"
|
||||
(clj->js {:create (.apply (aget openbao-deployment "root_token")
|
||||
(fn [token]
|
||||
(if (= token "TOKEN_NOT_FOUND")
|
||||
"echo 'Warning: Root token not available for Pulumi config'"
|
||||
(str "pulumi config set vault:address 'http://127.0.0.1:8200'\n"
|
||||
"pulumi config set --secret vault:token '" token "'\n"
|
||||
"echo 'Pulumi vault config updated successfully'"))))})
|
||||
(clj->js {:dependsOn [(aget openbao-deployment "setup_secrets")]}))]
|
||||
config-command))
|
||||
Reference in New Issue
Block a user