Wire Forge-native release infrastructure
Some checks failed
Cache: Publish Nix / Publish Nix Cache (push) Waiting to run
Build Rust / Cargo Test (push) Successful in 4m14s
Build Site / Next.js Build (push) Failing after 6s
Infra: OpenTofu / OpenTofu (grafana) (push) Successful in 5s
Lint Governance / BEP Metadata (push) Successful in 0s
Build: Android / Android Rust Core Stub (push) Failing after 23s

This commit is contained in:
Conrad Kramer 2026-06-07 05:51:12 -07:00
parent 97c569fb35
commit 002bd382e9
199 changed files with 14268 additions and 185 deletions

View file

@ -0,0 +1,284 @@
{ config, lib, pkgs, ... }:
let
cfg = config.services.burrow.garage;
in
{
options.services.burrow.garage = {
enable = lib.mkEnableOption "Burrow Garage S3-compatible object storage";
environmentFile = lib.mkOption {
type = lib.types.path;
default = "/var/lib/burrow/garage/env";
description = "Host-local environment file containing Garage and S3 bootstrap secrets.";
};
region = lib.mkOption {
type = lib.types.str;
default = "garage";
description = "S3 region name advertised by Garage.";
};
apiListenAddress = lib.mkOption {
type = lib.types.str;
default = "127.0.0.1";
description = "Address used by the Garage S3 API listener.";
};
apiPort = lib.mkOption {
type = lib.types.port;
default = 3900;
description = "Port used by the Garage S3 API listener.";
};
webListenAddress = lib.mkOption {
type = lib.types.str;
default = "127.0.0.1";
description = "Address used by the Garage static-web listener.";
};
webPort = lib.mkOption {
type = lib.types.port;
default = 3902;
description = "Port used by the Garage static-web listener.";
};
adminListenAddress = lib.mkOption {
type = lib.types.str;
default = "127.0.0.1";
description = "Address used by the Garage admin listener.";
};
adminPort = lib.mkOption {
type = lib.types.port;
default = 3903;
description = "Port used by the Garage admin listener.";
};
zone = lib.mkOption {
type = lib.types.str;
default = "burrow-forge";
description = "Garage layout zone assigned to the forge host.";
};
layoutCapacity = lib.mkOption {
type = lib.types.str;
default = "100GB";
description = "Initial Garage layout capacity assigned to the forge host.";
};
s3RootDomain = lib.mkOption {
type = lib.types.str;
default = "s3.burrow.net";
description = "Wildcard root domain used for bucket-style S3 API requests.";
};
webRootDomain = lib.mkOption {
type = lib.types.str;
default = "web.burrow.net";
description = "Wildcard root domain used for bucket static website requests.";
};
apiDomain = lib.mkOption {
type = lib.types.str;
default = "objects.burrow.net";
description = "Public S3 API reverse-proxy domain.";
};
enableApiProxy = lib.mkOption {
type = lib.types.bool;
default = false;
description = "Expose the Garage S3 API through Caddy.";
};
enableWebProxy = lib.mkOption {
type = lib.types.bool;
default = false;
description = "Expose the Garage static-web listener through Caddy wildcard routes.";
};
atticBucket = lib.mkOption {
type = lib.types.str;
default = "attic";
description = "Garage bucket used by the Burrow Nix cache.";
};
releaseBucket = lib.mkOption {
type = lib.types.str;
default = "burrow-releases";
description = "Garage bucket used for release artifacts.";
};
packageBucket = lib.mkOption {
type = lib.types.str;
default = "burrow-packages";
description = "Garage bucket used for signed package repositories.";
};
};
config = lib.mkIf cfg.enable {
services.garage = {
enable = true;
package = pkgs.garage;
environmentFile = cfg.environmentFile;
settings = {
metadata_dir = "/var/lib/garage/meta";
data_dir = "/var/lib/garage/data";
rpc_bind_addr = "127.0.0.1:3901";
rpc_public_addr = "127.0.0.1:3901";
replication_factor = 1;
s3_api = {
s3_region = cfg.region;
api_bind_addr = "${cfg.apiListenAddress}:${toString cfg.apiPort}";
root_domain = ".${cfg.s3RootDomain}";
};
s3_web = {
bind_addr = "${cfg.webListenAddress}:${toString cfg.webPort}";
root_domain = ".${cfg.webRootDomain}";
index = "index.html";
};
admin.api_bind_addr = "${cfg.adminListenAddress}:${toString cfg.adminPort}";
};
};
systemd.services.burrow-garage-env = {
description = "Create Burrow Garage bootstrap environment";
before = [ "garage.service" ];
wantedBy = [ "garage.service" ];
requiredBy = [ "garage.service" ];
path = [
pkgs.coreutils
pkgs.gnugrep
pkgs.openssl
];
serviceConfig = {
Type = "oneshot";
User = "root";
Group = "root";
RemainAfterExit = true;
};
script = ''
set -euo pipefail
install -d -m 0700 "$(dirname ${lib.escapeShellArg cfg.environmentFile})"
touch ${lib.escapeShellArg cfg.environmentFile}
chmod 0600 ${lib.escapeShellArg cfg.environmentFile}
chown root:root ${lib.escapeShellArg cfg.environmentFile}
has_var() {
grep -q "^$1=" ${lib.escapeShellArg cfg.environmentFile}
}
add_var() {
local name="$1"
local value="$2"
if ! has_var "$name"; then
printf '%s=%s\n' "$name" "$value" >> ${lib.escapeShellArg cfg.environmentFile}
fi
}
add_var GARAGE_RPC_SECRET "$(${pkgs.openssl}/bin/openssl rand -hex 32)"
add_var GARAGE_ATTIC_ACCESS_KEY_ID "GK$(${pkgs.openssl}/bin/openssl rand -hex 12)"
add_var GARAGE_ATTIC_SECRET_ACCESS_KEY "$(${pkgs.openssl}/bin/openssl rand -hex 32)"
add_var GARAGE_RELEASE_ACCESS_KEY_ID "GK$(${pkgs.openssl}/bin/openssl rand -hex 12)"
add_var GARAGE_RELEASE_SECRET_ACCESS_KEY "$(${pkgs.openssl}/bin/openssl rand -hex 32)"
add_var GARAGE_PACKAGE_ACCESS_KEY_ID "GK$(${pkgs.openssl}/bin/openssl rand -hex 12)"
add_var GARAGE_PACKAGE_SECRET_ACCESS_KEY "$(${pkgs.openssl}/bin/openssl rand -hex 32)"
add_var GARAGE_BACKUP_ACCESS_KEY_ID "GK$(${pkgs.openssl}/bin/openssl rand -hex 12)"
add_var GARAGE_BACKUP_SECRET_ACCESS_KEY "$(${pkgs.openssl}/bin/openssl rand -hex 32)"
add_var ATTIC_SERVER_TOKEN_RS256_SECRET_BASE64 "$(${pkgs.openssl}/bin/openssl genrsa -traditional 4096 | ${pkgs.coreutils}/bin/base64 -w0)"
. ${lib.escapeShellArg cfg.environmentFile}
add_var AWS_ACCESS_KEY_ID "$GARAGE_ATTIC_ACCESS_KEY_ID"
add_var AWS_SECRET_ACCESS_KEY "$GARAGE_ATTIC_SECRET_ACCESS_KEY"
'';
};
systemd.services.burrow-garage-bootstrap = {
description = "Bootstrap Burrow Garage layout, keys, and buckets";
after = [ "garage.service" ];
requires = [ "garage.service" ];
wantedBy = [ "multi-user.target" ];
path = [
config.services.garage.package
pkgs.coreutils
pkgs.gawk
pkgs.gnugrep
];
serviceConfig = {
Type = "oneshot";
User = "root";
Group = "root";
};
script = ''
set -euo pipefail
set -a
. ${lib.escapeShellArg cfg.environmentFile}
set +a
for _ in $(seq 1 60); do
if garage status >/dev/null 2>&1; then
break
fi
sleep 1
done
node_id="$(garage status | tail -n1 | awk '{ print $1 }')"
if [ -n "$node_id" ]; then
garage layout assign -c ${lib.escapeShellArg cfg.layoutCapacity} -z ${lib.escapeShellArg cfg.zone} "$node_id" >/dev/null 2>&1 || true
garage layout apply --version 1 >/dev/null 2>&1 || true
fi
ensure_key() {
local key_id="$1"
local secret="$2"
if ! garage key info "$key_id" >/dev/null 2>&1; then
garage key import "$key_id" "$secret" --yes >/dev/null
fi
}
ensure_bucket() {
local bucket="$1"
local key_id="$2"
if ! garage bucket info "$bucket" >/dev/null 2>&1; then
garage bucket create "$bucket" >/dev/null
fi
garage bucket allow --read --write --owner "$bucket" --key "$key_id" >/dev/null
}
ensure_bucket_reader() {
local bucket="$1"
local key_id="$2"
garage bucket allow --read "$bucket" --key "$key_id" >/dev/null
}
ensure_key "$GARAGE_ATTIC_ACCESS_KEY_ID" "$GARAGE_ATTIC_SECRET_ACCESS_KEY"
ensure_key "$GARAGE_RELEASE_ACCESS_KEY_ID" "$GARAGE_RELEASE_SECRET_ACCESS_KEY"
ensure_key "$GARAGE_PACKAGE_ACCESS_KEY_ID" "$GARAGE_PACKAGE_SECRET_ACCESS_KEY"
ensure_key "$GARAGE_BACKUP_ACCESS_KEY_ID" "$GARAGE_BACKUP_SECRET_ACCESS_KEY"
ensure_bucket ${lib.escapeShellArg cfg.atticBucket} "$GARAGE_ATTIC_ACCESS_KEY_ID"
ensure_bucket ${lib.escapeShellArg cfg.releaseBucket} "$GARAGE_RELEASE_ACCESS_KEY_ID"
ensure_bucket ${lib.escapeShellArg cfg.packageBucket} "$GARAGE_PACKAGE_ACCESS_KEY_ID"
ensure_bucket_reader ${lib.escapeShellArg cfg.atticBucket} "$GARAGE_BACKUP_ACCESS_KEY_ID"
ensure_bucket_reader ${lib.escapeShellArg cfg.releaseBucket} "$GARAGE_BACKUP_ACCESS_KEY_ID"
ensure_bucket_reader ${lib.escapeShellArg cfg.packageBucket} "$GARAGE_BACKUP_ACCESS_KEY_ID"
'';
};
services.caddy.virtualHosts = lib.mkMerge [
(lib.mkIf cfg.enableApiProxy {
"${cfg.apiDomain}".extraConfig = ''
encode gzip zstd
reverse_proxy ${cfg.apiListenAddress}:${toString cfg.apiPort}
'';
})
(lib.mkIf cfg.enableWebProxy {
"*.${cfg.webRootDomain}".extraConfig = ''
encode gzip zstd
reverse_proxy ${cfg.webListenAddress}:${toString cfg.webPort}
'';
})
];
};
}