feat: sops-nix for samba password secret

- add sops-nix input + module (jupiter only, not the VM)
- secrets/jupiter.yaml: age-encrypted samba_password (safe to commit)
- .sops.yaml: encryption rule for admin age key
- secrets.nix: decrypt samba_password to /run/secrets on the host
- provisioning oneshot reads sops secret (host) or plaintext (VM), single value
- .sops private key stays off-repo (~/.config, /var/lib/sops-nix on host)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
erik
2026-07-12 20:16:17 +02:00
co-authored by Claude Opus 4.8
parent 9fb32fd454
commit 10387fdbee
8 changed files with 90 additions and 14 deletions
+14
View File
@@ -0,0 +1,14 @@
# sops-nix encryption rules.
# Secrets under secrets/ are encrypted to the age recipient(s) below.
# The matching PRIVATE key lives OFF-repo (~/.config/sops/age/keys.txt for
# editing; /var/lib/sops-nix/key.txt on the host for decryption).
#
# Add the host's own age key here later (derived from its ssh host key) so the
# machine can decrypt without shipping a separate key.
keys:
- &admin age1cekcqyf7073fsytcjxaa9dr9zwkmn4vjg36rv2tgxdglzfv4jvxqvcj6z2
creation_rules:
- path_regex: secrets/.*\.yaml$
key_groups:
- age:
- *admin
Generated
+22 -1
View File
@@ -39,7 +39,28 @@
"root": {
"inputs": {
"disko": "disko",
"nixpkgs": "nixpkgs"
"nixpkgs": "nixpkgs",
"sops-nix": "sops-nix"
}
},
"sops-nix": {
"inputs": {
"nixpkgs": [
"nixpkgs"
]
},
"locked": {
"lastModified": 1783174389,
"narHash": "sha256-aCWC8ngycU7OdJrU2+Je3qf+1a2ykuBvpPhZT/9tXMc=",
"owner": "Mic92",
"repo": "sops-nix",
"rev": "f1406619a3884cd5c47992a70b8b35c9c0fcb4c9",
"type": "github"
},
"original": {
"owner": "Mic92",
"repo": "sops-nix",
"type": "github"
}
}
},
+6 -1
View File
@@ -7,9 +7,13 @@
url = "github:nix-community/disko";
inputs.nixpkgs.follows = "nixpkgs";
};
sops-nix = {
url = "github:Mic92/sops-nix";
inputs.nixpkgs.follows = "nixpkgs";
};
};
outputs = { self, nixpkgs, disko, ... }@inputs:
outputs = { self, nixpkgs, disko, sops-nix, ... }@inputs:
let
system = "x86_64-linux";
in
@@ -22,6 +26,7 @@
specialArgs = { inherit inputs; };
modules = [
disko.nixosModules.disko
sops-nix.nixosModules.sops
./jupiter/configuration.nix
];
};
+1
View File
@@ -5,6 +5,7 @@
imports = [
./hardware-configuration.nix
./disk-config.nix # disko: OS-disk partitions + filesystems
./secrets.nix # sops-nix: samba password etc.
./services.nix
];
+16
View File
@@ -0,0 +1,16 @@
{ ... }:
# sops-nix secret wiring (real host only; not imported by vm.nix).
# Encrypted values live in ../secrets/jupiter.yaml, decrypted at activation to
# /run/secrets/<name>. The host needs the age PRIVATE key at the keyFile path.
#
# Deploy the private key with the install, e.g. nixos-anywhere:
# --extra-files, placing your key at /var/lib/sops-nix/key.txt
# or later derive a host age key from its ssh host key and add it to .sops.yaml.
{
sops.defaultSopsFile = ../secrets/jupiter.yaml;
sops.age.keyFile = "/var/lib/sops-nix/key.txt";
# Decrypts to /run/secrets/samba_password (root-only by default).
sops.secrets.samba_password = { };
}
+11 -5
View File
@@ -68,9 +68,10 @@
# `services.samba` never sets it, so logins fail until provisioned.
# This runs AFTER samba-smbd so its state dir (/var/lib/samba/private) exists
# — an activation script runs too early and smbpasswd fails to init the passdb.
# The secret file must contain the password twice (new + confirm), one per line.
# VM test: vm.nix writes /etc/samba/smb-password with a throwaway value.
# Real host: supply it via sops-nix/agenix — do NOT commit plaintext.
# Reads a single-line password from the first file that exists:
# Real host: /run/secrets/samba_password (sops-nix, see secrets.nix)
# VM test: /etc/samba/smb-password (plaintext, see vm.nix)
# smbpasswd prompts new + confirm, so the value is fed twice.
systemd.services.samba-smbpasswd = {
description = "Provision Samba password for darman";
after = [ "samba-smbd.service" ];
@@ -81,9 +82,14 @@
RemainAfterExit = true;
};
script = ''
if [ -f /etc/samba/smb-password ]; then
${pkgs.samba}/bin/smbpasswd -a -s darman < /etc/samba/smb-password
for f in /run/secrets/samba_password /etc/samba/smb-password; do
if [ -f "$f" ]; then
pw=$(head -n1 "$f")
printf '%s\n%s\n' "$pw" "$pw" | ${pkgs.samba}/bin/smbpasswd -a -s darman
exit 0
fi
done
echo "no samba password source found" >&2
'';
};
services.avahi = {
+3 -6
View File
@@ -18,14 +18,11 @@
users.users.root.initialPassword = "test";
# Throwaway SMB password for testing (samba-smbd login = darman / test).
# Two lines: smbpasswd wants the new password + confirmation.
# Single line — the provisioning oneshot feeds it twice for smbpasswd.
# Real host must NOT do this — plaintext lands in the world-readable Nix
# store. Use sops-nix/agenix to place /etc/samba/smb-password instead.
# store. It uses sops-nix (secrets.nix) instead.
environment.etc."samba/smb-password" = {
text = ''
test
test
'';
text = "test\n";
mode = "0600";
};
+16
View File
@@ -0,0 +1,16 @@
samba_password: ENC[AES256_GCM,data:Ur5CuAlJhdw=,iv:po7oxygUqKS9yoJS8efQJe2mTr7e5zYkZjAVRgeoUB0=,tag:Mf0K3rIga5I4jnNU3glDyg==,type:str]
sops:
age:
- enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBlL0E3cWNIby95Q3RBcjlm
QklPREM4cWRaelZEckFGUWpKUWExYmxrcWdrClByTVBlWDNlRGhMUkhEQzJONzFn
alJVSzRMODN3U0cyRG93T3lHZkhXTWcKLS0tIFJ2V3I0V1NwakVlc2dCUW1iMHdR
RlNsWnJJaDkvVnJnVlcyRXZmK1VkMUUKnv02m3vGjy8nTZV9ouItOEWmfZOABKDP
VCvWcSy8R0NikkQ004XrBd1WhvyrUvqC6X9f4N9208BvmyDxEpKZbw==
-----END AGE ENCRYPTED FILE-----
recipient: age1cekcqyf7073fsytcjxaa9dr9zwkmn4vjg36rv2tgxdglzfv4jvxqvcj6z2
lastmodified: "2026-07-12T18:10:45Z"
mac: ENC[AES256_GCM,data:ynQU/B5RvwGw1ILJJexrZWtzNr7z3IUyy86v8q0KhRsMH2qSHF0BK0Pzq/DcT3vru+MwKat1hJfO21Pdu+HRsqtzUZRViTCbjtz+vmnjwyQvBqBPhEtxDeBoTgd5RqjXxzcuOADfv0NkfvU9p06x8YF8AVYq9ONvOEZiC4MamoY=,iv:1Wm4JP5Djyc9jdExMBcSjWw/zF1EXexjjMhePOEWCt8=,tag:A51vbK8fpb8sg+eCLwbWmg==,type:str]
unencrypted_suffix: _unencrypted
version: 3.13.1