Compare commits
1 commit
main
...
sops-imple
| Author | SHA1 | Date | |
|---|---|---|---|
| 99ad3058a3 |
10 changed files with 141 additions and 16 deletions
25
.sops.yaml
Normal file
25
.sops.yaml
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
# To set up sops-nix:
|
||||
# 1. Generate an age key on each host:
|
||||
# mkdir -p ~/.config/sops/age
|
||||
# age-keygen -o ~/.config/sops/age/keys.txt
|
||||
# Or derive from the host SSH key:
|
||||
# nix-shell -p ssh-to-age --run 'cat /etc/ssh/ssh_host_ed25519_key.pub | ssh-to-age'
|
||||
#
|
||||
# 2. Replace the placeholder age keys below with the actual public keys.
|
||||
#
|
||||
# 3. Encrypt secret files:
|
||||
# sops secrets/homelab.yaml
|
||||
#
|
||||
# 4. To re-key after changing keys:
|
||||
# sops updatekeys secrets/homelab.yaml
|
||||
|
||||
keys:
|
||||
- &homelab age1XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX # replace with: ssh-to-age < /etc/ssh/ssh_host_ed25519_key.pub
|
||||
- &admin age1XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX # replace with: age-keygen output from your admin machine
|
||||
|
||||
creation_rules:
|
||||
- path_regex: secrets/homelab\.yaml$
|
||||
key_groups:
|
||||
- age:
|
||||
- *homelab
|
||||
- *admin
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
{ homelab, ... }: {
|
||||
{ config, homelab, ... }: {
|
||||
services.pocket-id = {
|
||||
enable = true;
|
||||
credentials.ENCRYPTION_KEY = "/mnt/data/pocketid/encryption-key";
|
||||
credentials.ENCRYPTION_KEY = config.sops.secrets.pocketid_encryption_key.path;
|
||||
dataDir = "/mnt/data/pocketid/data";
|
||||
settings = {
|
||||
PORT = "1411";
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
{ timezone, homelab, ... }: let
|
||||
{ config, timezone, homelab, ... }: let
|
||||
rss = [
|
||||
"https://www.raspberrypi.com/news/feed/"
|
||||
"https://www.jeffgeerling.com/blog.xml"
|
||||
|
|
@ -96,7 +96,7 @@ in {
|
|||
};
|
||||
services.glance = {
|
||||
enable = true;
|
||||
environmentFile = "/var/lib/glance/.env";
|
||||
environmentFile = config.sops.secrets.glance_env.path;
|
||||
settings = {
|
||||
server = {
|
||||
host = "127.0.0.1";
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
{ homelab, ... }: {
|
||||
{ config, homelab, ... }: {
|
||||
services.vaultwarden = {
|
||||
enable = true;
|
||||
domain = "pass.proxy.${homelab.domain}";
|
||||
backupDir = "/mnt/data/vaultwarden/backups";
|
||||
environmentFile = "/mnt/data/vaultwarden/.env";
|
||||
environmentFile = config.sops.secrets.vaultwarden_env.path;
|
||||
config = {
|
||||
ROCKET_PORT = 8060;
|
||||
ROCKET_ADDRESS = "127.0.0.1";
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
{ homelab, lib, ... }: let
|
||||
{ config, homelab, lib, ... }: let
|
||||
base = "proxy.${homelab.domain}";
|
||||
hosts = {
|
||||
"server" = { dest = "https://server.dns.${homelab.domain}:8006"; auth = false; };
|
||||
|
|
@ -45,8 +45,7 @@ in {
|
|||
domain = "*.${base}";
|
||||
extraDomainNames = [ base ];
|
||||
dnsProvider = "cloudflare";
|
||||
environmentFile = "/var/lib/acme/cloudflare.env";
|
||||
# ^^^contents: CLOUDFLARE_DNS_API_TOKEN=XXXXX
|
||||
environmentFile = config.sops.templates."cloudflare.env".path;
|
||||
};
|
||||
};
|
||||
|
||||
|
|
@ -81,7 +80,7 @@ in {
|
|||
locations."/" = {
|
||||
proxyPass = cfg.dest;
|
||||
proxyWebsockets = true;
|
||||
basicAuthFile = if cfg.auth then "/var/lib/nginx/.htpasswd" else null;
|
||||
basicAuthFile = if cfg.auth then config.sops.secrets.nginx_htpasswd.path else null;
|
||||
extraConfig = exta-conf;
|
||||
};
|
||||
}) hosts;
|
||||
|
|
|
|||
59
modules/system/homelab/sops.nix
Normal file
59
modules/system/homelab/sops.nix
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
{ config, ... }: {
|
||||
sops = {
|
||||
defaultSopsFile = ../../../secrets/homelab.yaml;
|
||||
age.sshKeyPaths = [ "/etc/ssh/ssh_host_ed25519_key" ];
|
||||
|
||||
secrets = {
|
||||
cloudflare_dns_api_token = {
|
||||
owner = "acme";
|
||||
group = "acme";
|
||||
};
|
||||
|
||||
cloudflared_tunnel_credentials = {
|
||||
owner = "cloudflared";
|
||||
group = "cloudflared";
|
||||
};
|
||||
|
||||
cloudflared_cert = {
|
||||
owner = "cloudflared";
|
||||
group = "cloudflared";
|
||||
};
|
||||
|
||||
vaultwarden_env = {
|
||||
owner = "vaultwarden";
|
||||
group = "vaultwarden";
|
||||
restartUnits = [ "vaultwarden.service" ];
|
||||
};
|
||||
|
||||
glance_env = {
|
||||
owner = "glance";
|
||||
group = "glance";
|
||||
restartUnits = [ "glance.service" ];
|
||||
};
|
||||
|
||||
pocketid_encryption_key = {
|
||||
owner = "root";
|
||||
group = "root";
|
||||
restartUnits = [ "pocket-id.service" ];
|
||||
};
|
||||
|
||||
tailscale_authkey = {
|
||||
owner = "root";
|
||||
group = "root";
|
||||
restartUnits = [ "tailscaled.service" ];
|
||||
};
|
||||
|
||||
nginx_htpasswd = {
|
||||
owner = "nginx";
|
||||
group = "nginx";
|
||||
restartUnits = [ "nginx.service" ];
|
||||
};
|
||||
};
|
||||
|
||||
templates."cloudflare.env" = {
|
||||
owner = "acme";
|
||||
group = "acme";
|
||||
content = "CLOUDFLARE_DNS_API_TOKEN=${config.sops.placeholder.cloudflare_dns_api_token}";
|
||||
};
|
||||
};
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
{ pkgs, lib, homelab, ... }: let
|
||||
{ config, pkgs, lib, homelab, ... }: let
|
||||
routes = {
|
||||
"git.${homelab.domain}" = "http://localhost:5080";
|
||||
"auth.${homelab.domain}" = "http://localhost:1411";
|
||||
|
|
@ -10,8 +10,8 @@ in {
|
|||
services.cloudflared = {
|
||||
enable = true;
|
||||
tunnels.homelab = {
|
||||
credentialsFile = "/mnt/data/cloudflared/homelab.json";
|
||||
certificateFile = "/mnt/data/cloudflared/cert.pem";
|
||||
credentialsFile = config.sops.secrets.cloudflared_tunnel_credentials.path;
|
||||
certificateFile = config.sops.secrets.cloudflared_cert.path;
|
||||
default = "http_status:404";
|
||||
ingress = routes;
|
||||
};
|
||||
|
|
@ -31,7 +31,7 @@ in {
|
|||
|
||||
script = lib.concatMapStringsSep "\n" (domain: ''
|
||||
echo "Ensuring DNS route for ${domain}..."
|
||||
${pkgs.cloudflared}/bin/cloudflared tunnel --origincert /mnt/data/cloudflared/cert.pem route dns ${homelab.cf-tunnel-id} ${domain} || true
|
||||
${pkgs.cloudflared}/bin/cloudflared tunnel --origincert ${config.sops.secrets.cloudflared_cert.path} route dns ${homelab.cf-tunnel-id} ${domain} || true
|
||||
'') (builtins.attrNames routes);
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
{ lib, homelab, ... }: let
|
||||
{ config, lib, homelab, ... }: let
|
||||
ts-flags = [
|
||||
"--advertise-exit-node"
|
||||
"--advertise-routes=10.3.14.0/24,192.168.1.0/24"
|
||||
|
|
@ -20,6 +20,7 @@ in {
|
|||
./homelab/dns.nix
|
||||
./homelab/git.nix
|
||||
./homelab/ai.nix
|
||||
./homelab/sops.nix
|
||||
|
||||
./core/swapfile.nix
|
||||
./core/oom.nix
|
||||
|
|
@ -29,7 +30,7 @@ in {
|
|||
|
||||
services.tailscale = {
|
||||
enable = true;
|
||||
authKeyFile = "/mnt/data/tailscale/authkey";
|
||||
authKeyFile = config.sops.secrets.tailscale_authkey.path;
|
||||
useRoutingFeatures = "server";
|
||||
extraUpFlags = ts-flags;
|
||||
extraSetFlags = ts-flags;
|
||||
|
|
|
|||
30
scripts/check-sops.sh
Executable file
30
scripts/check-sops.sh
Executable file
|
|
@ -0,0 +1,30 @@
|
|||
#!/usr/bin/env bash
|
||||
# Pre-commit hook: block commits containing unencrypted sops secret files.
|
||||
# Install with: ln -sf ../../scripts/check-sops.sh .git/hooks/pre-commit
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
staged_secrets=$(git diff --cached --name-only --diff-filter=ACM -- 'secrets/*.yaml' 'secrets/*.yml' 'secrets/*.json')
|
||||
|
||||
if [ -z "$staged_secrets" ]; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
failed=0
|
||||
|
||||
for file in $staged_secrets; do
|
||||
# sops-encrypted YAML/JSON files always contain a top-level "sops" key with metadata
|
||||
if ! git show ":$file" | grep -q '"sops"\|sops:'; then
|
||||
echo "ERROR: $file is not encrypted with sops! Encrypt it first:"
|
||||
echo " sops $file"
|
||||
echo
|
||||
echo "hint: bypass with: git commit --no-verify"
|
||||
failed=1
|
||||
fi
|
||||
done
|
||||
|
||||
if [ "$failed" -ne 0 ]; then
|
||||
echo ""
|
||||
echo "Commit aborted. Encrypt secret files before committing."
|
||||
exit 1
|
||||
fi
|
||||
11
secrets/homelab.yaml
Normal file
11
secrets/homelab.yaml
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
# This file should be encrypted with sops before committing.
|
||||
# Run: sops secrets/homelab.yaml
|
||||
# All values below are placeholders. Replace them with actual values.
|
||||
cloudflare_dns_api_token: REPLACE_ME
|
||||
cloudflared_tunnel_credentials: REPLACE_ME
|
||||
cloudflared_cert: REPLACE_ME
|
||||
vaultwarden_env: REPLACE_ME
|
||||
glance_env: REPLACE_ME
|
||||
pocketid_encryption_key: REPLACE_ME
|
||||
tailscale_authkey: REPLACE_ME
|
||||
nginx_htpasswd: REPLACE_ME
|
||||
Loading…
Add table
Add a link
Reference in a new issue