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:
+14
@@ -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
@@ -39,7 +39,28 @@
|
|||||||
"root": {
|
"root": {
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"disko": "disko",
|
"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"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -7,9 +7,13 @@
|
|||||||
url = "github:nix-community/disko";
|
url = "github:nix-community/disko";
|
||||||
inputs.nixpkgs.follows = "nixpkgs";
|
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
|
let
|
||||||
system = "x86_64-linux";
|
system = "x86_64-linux";
|
||||||
in
|
in
|
||||||
@@ -22,6 +26,7 @@
|
|||||||
specialArgs = { inherit inputs; };
|
specialArgs = { inherit inputs; };
|
||||||
modules = [
|
modules = [
|
||||||
disko.nixosModules.disko
|
disko.nixosModules.disko
|
||||||
|
sops-nix.nixosModules.sops
|
||||||
./jupiter/configuration.nix
|
./jupiter/configuration.nix
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
imports = [
|
imports = [
|
||||||
./hardware-configuration.nix
|
./hardware-configuration.nix
|
||||||
./disk-config.nix # disko: OS-disk partitions + filesystems
|
./disk-config.nix # disko: OS-disk partitions + filesystems
|
||||||
|
./secrets.nix # sops-nix: samba password etc.
|
||||||
./services.nix
|
./services.nix
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|||||||
@@ -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 = { };
|
||||||
|
}
|
||||||
+12
-6
@@ -68,9 +68,10 @@
|
|||||||
# `services.samba` never sets it, so logins fail until provisioned.
|
# `services.samba` never sets it, so logins fail until provisioned.
|
||||||
# This runs AFTER samba-smbd so its state dir (/var/lib/samba/private) exists
|
# 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.
|
# — 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.
|
# Reads a single-line password from the first file that exists:
|
||||||
# VM test: vm.nix writes /etc/samba/smb-password with a throwaway value.
|
# Real host: /run/secrets/samba_password (sops-nix, see secrets.nix)
|
||||||
# Real host: supply it via sops-nix/agenix — do NOT commit plaintext.
|
# VM test: /etc/samba/smb-password (plaintext, see vm.nix)
|
||||||
|
# smbpasswd prompts new + confirm, so the value is fed twice.
|
||||||
systemd.services.samba-smbpasswd = {
|
systemd.services.samba-smbpasswd = {
|
||||||
description = "Provision Samba password for darman";
|
description = "Provision Samba password for darman";
|
||||||
after = [ "samba-smbd.service" ];
|
after = [ "samba-smbd.service" ];
|
||||||
@@ -81,9 +82,14 @@
|
|||||||
RemainAfterExit = true;
|
RemainAfterExit = true;
|
||||||
};
|
};
|
||||||
script = ''
|
script = ''
|
||||||
if [ -f /etc/samba/smb-password ]; then
|
for f in /run/secrets/samba_password /etc/samba/smb-password; do
|
||||||
${pkgs.samba}/bin/smbpasswd -a -s darman < /etc/samba/smb-password
|
if [ -f "$f" ]; then
|
||||||
fi
|
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 = {
|
services.avahi = {
|
||||||
|
|||||||
+3
-6
@@ -18,14 +18,11 @@
|
|||||||
users.users.root.initialPassword = "test";
|
users.users.root.initialPassword = "test";
|
||||||
|
|
||||||
# Throwaway SMB password for testing (samba-smbd login = darman / 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
|
# 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" = {
|
environment.etc."samba/smb-password" = {
|
||||||
text = ''
|
text = "test\n";
|
||||||
test
|
|
||||||
test
|
|
||||||
'';
|
|
||||||
mode = "0600";
|
mode = "0600";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
Reference in New Issue
Block a user