Something went wrong. Try again.
This repository has no description
Something went wrong. Try again.
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879# terraform/nodes passes the secret manager ids a vm may read as `secrets`, and this fetches# them into /etc/secrets on boot and whenever that list changes, so adding a secret only takes# a deploy. a new version of an existing one waits for a reboot or `systemctl restart node-secrets`{ config, lib, pkgs, secrets, ...}: let readBy = config.nodeSecrets.readBy;in { options.nodeSecrets.readBy = lib.mkOption { type = lib.types.attrsOf lib.types.str; default = {}; description = "the unit that reads each secret, which waits for it on a fresh vm"; };
# the list comes from terraform. so a secret nix doesn't know about fails the build config.assertions = [ { assertion = lib.sort lib.lessThan (lib.attrNames readBy) == lib.sort lib.lessThan secrets; message = "nodeSecrets.readBy names [${toString (lib.attrNames readBy)}] but terraform passes [${toString secrets}]"; } ];
config.systemd.services = lib.mkIf (secrets != []) ( { node-secrets = { wantedBy = ["multi-user.target"]; wants = ["network-online.target"]; after = ["network-online.target"]; path = [pkgs.coreutils pkgs.curl pkgs.jq]; environment.SECRETS = toString secrets; serviceConfig = { Type = "oneshot"; RemainAfterExit = true; # if any secret has no value or smth, don't hang a deploy TimeoutStartSec = "1min"; }; script = '' set -o pipefail metadata=http://169.254.169.254/computeMetadata/v1 # set -e is off inside an until, so every step returns by hand, or a failed read # would still move an empty file over the good one fetch() { token=$(curl -sf -H 'Metadata-Flavor: Google' "$metadata/instance/service-accounts/default/token" | jq -er .access_token) || return project=$(curl -sf -H 'Metadata-Flavor: Google' "$metadata/project/project-id") || return curl -sf -H "authorization: Bearer $token" \ "https://secretmanager.googleapis.com/v1/projects/$project/secrets/$1/versions/latest:access" | jq -er .payload.data | base64 -d >"/etc/secrets/.$1.new" || return mv -f "/etc/secrets/.$1.new" "/etc/secrets/$1" }
install -d -m 0700 /etc/secrets umask 077 for name in $SECRETS; do tries=0 until fetch "$name"; do tries=$((tries + 1)) # keep last copy if api can't be reached or is down if [ -e "/etc/secrets/$name" ] && [ "$tries" -ge 5 ]; then echo "couldn't fetch $name, keeping the copy from before" break fi sleep 5 done done rm -f /etc/secrets/.*.new ''; }; } // lib.genAttrs (lib.unique (lib.attrValues readBy)) (_: { wants = ["node-secrets.service"]; after = ["node-secrets.service"]; }) );}