dotfiles/hosts/h001/mods/openbao.nix
RingOfStorms (Joshua Bell) b7330b4c09 openbao auto unseal
2025-12-08 10:55:35 -06:00

153 lines
3.9 KiB
Nix

{
pkgs,
...
}:
{
environment.variables = {
# For CLI
BAO_ADDR = "http://127.0.0.1:8200";
};
services.nginx = {
virtualHosts = {
"sec.joshuabell.xyz" = {
addSSL = true;
sslCertificate = "/var/lib/acme/joshuabell.xyz/fullchain.pem";
sslCertificateKey = "/var/lib/acme/joshuabell.xyz/key.pem";
locations."/" = {
proxyWebsockets = true;
proxyPass = "http://localhost:8200";
recommendedProxySettings = true;
};
};
};
};
services.openbao = {
enable = true;
package = pkgs.openbao;
settings = {
ui = true;
listener.default = {
type = "tcp";
address = "127.0.0.1:8200";
tls_disable = true; # nginx will handle TLS
};
storage.file = {
path = "/var/lib/openbao";
};
# Disable mlock requirement for development
# In production, you may want to enable this
disable_mlock = true;
};
};
# Ensure the data directory exists with proper permissions
# systemd.tmpfiles.rules = [
# "d /var/lib/openbao 0700 openbao openbao - -"
# ];
# Additional systemd service hardening
systemd.services.openbao = {
serviceConfig = {
# Security hardening
NoNewPrivileges = true;
PrivateTmp = true;
ProtectSystem = "strict";
ProtectHome = true;
ReadWritePaths = [ "/var/lib/openbao" ];
# Resource limits
LimitNOFILE = 65536;
LimitNPROC = 4096;
};
};
# AUTO UNSEAL
systemd.services.openbao-auto-unseal = {
description = "Auto-unseal OpenBao using stored unseal key shares";
partOf = [ "openbao.service" ];
after = [ "openbao.service" ];
wants = [ "openbao.service" ];
wantedBy = [ "multi-user.target" "openbao.service" ];
path = [
pkgs.openbao
pkgs.gnugrep
];
environment = {
BAO_ADDR = "http://127.0.0.1:8200";
};
serviceConfig = {
Type = "oneshot";
User = "root";
Group = "root";
PrivateTmp = true;
ProtectSystem = "strict";
ProtectHome = true;
ReadOnlyPaths = [ "/bao-keys" ];
NoNewPrivileges = true;
ExecStart = pkgs.writeShellScript "openbao-auto-unseal" ''
#!/usr/bin/env bash
echo "Auto-unseal: waiting for OpenBao to be reachable"
# Wait for OpenBao to be listening & initialized
for i in {1..30}; do
BAO_STATUS=$(bao status 2>/dev/null);
# echo "Current status:"
# echo "$BAO_STATUS"
# Check if initialized
if grep -qi 'initialized.*true' <<< "$BAO_STATUS"; then
echo "OpenBao is initialized"
break
fi
sleep 1
done
# Check again; if still not initialized, bail
BAO_STATUS=$(bao status 2>/dev/null);
if ! grep -qi 'initialized.*true' <<< "$BAO_STATUS"; then
echo "OpenBao is not initialized yet; skipping auto-unseal" >&2
exit 1
fi
# If it's already unsealed, exit
if grep -qi 'sealed.*false' <<< "$BAO_STATUS"; then
echo "OpenBao already unsealed; nothing to do"
exit 0
fi
echo "OpenBao is sealed; applying unseal key shares"
# Apply each unseal key share; ignore "already unsealed" errors
for key in /bao-keys/openbao-unseal-*; do
if [ -f "$key" ]; then
echo "Unsealing with key $key"
bao operator unseal "$(cat "$key")" || true
fi
done
# Final status check
if ! BAO_STATUS=$(bao status 2>/dev/null); then
echo "OpenBao not responding after unseal attempts" >&2
exit 1
fi
# echo "Final status:"
# echo "$BAO_STATUS"
if grep -qi 'sealed.*true' <<< "$BAO_STATUS"; then
echo "OpenBao is still sealed after applying unseal keys" >&2
exit 1
fi
echo "Successfully unsealed OpenBao"
'';
};
};
}