1
0

secrets.nix: Remove age secrets management

This commit is contained in:
clerie 2024-05-10 16:23:41 +02:00
parent e094afc4a0
commit d0bd09896a
12 changed files with 9 additions and 203 deletions

View File

@ -14,7 +14,6 @@
# Deployment # Deployment
bij bij
colmena colmena
agenix
clerie-sops clerie-sops
clerie-sops-edit clerie-sops-edit
sops sops

View File

@ -1,26 +1,5 @@
{ {
"nodes": { "nodes": {
"agenix": {
"inputs": {
"darwin": "darwin",
"nixpkgs": [
"nixpkgs"
]
},
"locked": {
"lastModified": 1682101079,
"narHash": "sha256-MdAhtjrLKnk2uiqun1FWABbKpLH090oeqCSiWemtuck=",
"owner": "ryantm",
"repo": "agenix",
"rev": "2994d002dcff5353ca1ac48ec584c7f6589fe447",
"type": "github"
},
"original": {
"owner": "ryantm",
"repo": "agenix",
"type": "github"
}
},
"bij": { "bij": {
"inputs": { "inputs": {
"nixpkgs": [ "nixpkgs": [
@ -59,28 +38,6 @@
"url": "https://git.clerie.de/clerie/chaosevents.git" "url": "https://git.clerie.de/clerie/chaosevents.git"
} }
}, },
"darwin": {
"inputs": {
"nixpkgs": [
"agenix",
"nixpkgs"
]
},
"locked": {
"lastModified": 1673295039,
"narHash": "sha256-AsdYgE8/GPwcelGgrntlijMg4t3hLFJFCRF3tL5WVjA=",
"owner": "lnl7",
"repo": "nix-darwin",
"rev": "87b9d090ad39b25b2400029c64825fc2a8868943",
"type": "github"
},
"original": {
"owner": "lnl7",
"ref": "master",
"repo": "nix-darwin",
"type": "github"
}
},
"fernglas": { "fernglas": {
"inputs": { "inputs": {
"flake-utils": "flake-utils", "flake-utils": "flake-utils",
@ -299,7 +256,6 @@
}, },
"root": { "root": {
"inputs": { "inputs": {
"agenix": "agenix",
"bij": "bij", "bij": "bij",
"chaosevents": "chaosevents", "chaosevents": "chaosevents",
"fernglas": "fernglas", "fernglas": "fernglas",

View File

@ -3,10 +3,6 @@
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
nixpkgs-krypton.url = "github:NixOS/nixpkgs/nixos-unstable"; nixpkgs-krypton.url = "github:NixOS/nixpkgs/nixos-unstable";
nixos-hardware.url = "github:NixOS/nixos-hardware/master"; nixos-hardware.url = "github:NixOS/nixos-hardware/master";
agenix = {
url = "github:ryantm/agenix";
inputs.nixpkgs.follows = "nixpkgs";
};
bij = { bij = {
url = "git+https://git.clerie.de/clerie/bij.git"; url = "git+https://git.clerie.de/clerie/bij.git";
inputs.nixpkgs.follows = "nixpkgs"; inputs.nixpkgs.follows = "nixpkgs";
@ -37,7 +33,7 @@
inputs.nixpkgs.follows = "nixpkgs"; inputs.nixpkgs.follows = "nixpkgs";
}; };
}; };
outputs = { self, agenix, nixpkgs, nixos-hardware, chaosevents, fernglas, nixos-exporter, solid-xmpp-alarm, ssh-to-age, ... }@inputs: let outputs = { self, nixpkgs, nixos-hardware, chaosevents, fernglas, nixos-exporter, solid-xmpp-alarm, ssh-to-age, ... }@inputs: let
lib = import ./lib inputs; lib = import ./lib inputs;
helper = lib.flake-helper; helper = lib.flake-helper;
in { in {
@ -115,8 +111,6 @@
overlays = [ overlays = [
self.overlays.clerie self.overlays.clerie
(_: _: { (_: _: {
inherit (agenix.packages.${system})
agenix;
inherit (chaosevents.packages.${system}) inherit (chaosevents.packages.${system})
chaosevents; chaosevents;
inherit (ssh-to-age.packages.${system}) inherit (ssh-to-age.packages.${system})
@ -136,9 +130,7 @@
chromium-incognito chromium-incognito
iot-data iot-data
nix-remove-result-links nix-remove-result-links
nixfiles-add-secret
nixfiles-auto-install nixfiles-auto-install
nixfiles-generate-backup-secrets
nixfiles-generate-config nixfiles-generate-config
nixfiles-update-ssh-host-keys nixfiles-update-ssh-host-keys
print-afra print-afra

View File

@ -1,4 +1,4 @@
{ self, nixpkgs, agenix, bij, chaosevents, fernglas, fieldpoc, nixos-exporter, solid-xmpp-alarm, sops-nix, ... }@inputs: { self, nixpkgs, bij, chaosevents, fernglas, fieldpoc, nixos-exporter, solid-xmpp-alarm, sops-nix, ... }@inputs:
rec { rec {
generateNixosSystem = { generateNixosSystem = {
@ -28,8 +28,6 @@ rec {
nixpkgs.overlays = [ nixpkgs.overlays = [
self.overlays.clerie self.overlays.clerie
(_: _: { (_: _: {
inherit (agenix.packages."x86_64-linux")
agenix;
inherit (bij.packages."${system}") inherit (bij.packages."${system}")
bij; bij;
inherit (chaosevents.packages."x86_64-linux") inherit (chaosevents.packages."x86_64-linux")
@ -38,21 +36,12 @@ rec {
]; ];
clerie.monitoring = nixpkgs.lib.attrsets.optionalAttrs (group != null) { serviceLevel = group; }; clerie.monitoring = nixpkgs.lib.attrsets.optionalAttrs (group != null) { serviceLevel = group; };
}) })
agenix.nixosModules.default
fernglas.nixosModules.default fernglas.nixosModules.default
fieldpoc.nixosModules.default fieldpoc.nixosModules.default
nixos-exporter.nixosModules.default nixos-exporter.nixosModules.default
solid-xmpp-alarm.nixosModules.solid-xmpp-alarm solid-xmpp-alarm.nixosModules.solid-xmpp-alarm
sops-nix.nixosModules.sops sops-nix.nixosModules.sops
(../hosts + "/${name}/configuration.nix") (../hosts + "/${name}/configuration.nix")
# Automatically load secrets from the hosts secrets directory
({ lib, ... }: let
secretsPath = ../hosts + "/${name}/secrets";
in {
age.secrets = lib.mapAttrs' (filename: _: lib.nameValuePair (lib.removeSuffix ".age" filename) {
file = secretsPath + "/${filename}";
}) (lib.filterAttrs (name: type: (type == "regular") && (lib.hasSuffix ".age" name) ) (if builtins.pathExists secretsPath then builtins.readDir secretsPath else {}));
})
# Automatically load secrets from sops file for host # Automatically load secrets from sops file for host
({ config, lib, ... }: { ({ config, lib, ... }: {
sops.defaultSopsFile = ../hosts + "/${name}/secrets.json"; sops.defaultSopsFile = ../hosts + "/${name}/secrets.json";

View File

@ -23,12 +23,10 @@ let
backupServiceUnits = listToAttrs (map ({jobName, jobOptions, targetName, targetOptions}: let backupServiceUnits = listToAttrs (map ({jobName, jobOptions, targetName, targetOptions}: let
jobPasswordFile = if jobOptions.passwordFile != null then jobOptions.passwordFile else jobPasswordFile = if jobOptions.passwordFile != null then jobOptions.passwordFile else
if builtins.elem "clerie-backup-job-${jobName}" (attrNames config.sops.secrets) then config.sops.secrets."clerie-backup-job-${jobName}".path else config.sops.secrets."clerie-backup-job-${jobName}".path;
config.age.secrets."clerie-backup-job-${jobName}".path;
repoPath = if jobOptions.repoPath == null then "/${config.networking.hostName}/${jobName}" else jobOptions.repoPath; repoPath = if jobOptions.repoPath == null then "/${config.networking.hostName}/${jobName}" else jobOptions.repoPath;
targetPasswordFile = if targetOptions.passwordFile != null then targetOptions.passwordFile else targetPasswordFile = if targetOptions.passwordFile != null then targetOptions.passwordFile else
if builtins.elem "clerie-backup-target-${targetName}" (attrNames config.sops.secrets) then config.sops.secrets."clerie-backup-target-${targetName}".path else config.sops.secrets."clerie-backup-target-${targetName}".path;
config.age.secrets."clerie-backup-target-${targetName}".path;
targetUsername = if targetOptions.username == null then config.networking.hostName else targetOptions.username; targetUsername = if targetOptions.username == null then config.networking.hostName else targetOptions.username;
in in
nameValuePair "clerie-backup-${jobName}-${targetName}" { nameValuePair "clerie-backup-${jobName}-${targetName}" {
@ -73,12 +71,10 @@ let
backupCommands = map ({jobName, jobOptions, targetName, targetOptions}: let backupCommands = map ({jobName, jobOptions, targetName, targetOptions}: let
jobPasswordFile = if jobOptions.passwordFile != null then jobOptions.passwordFile else jobPasswordFile = if jobOptions.passwordFile != null then jobOptions.passwordFile else
if builtins.elem "clerie-backup-job-${jobName}" (attrNames config.sops.secrets) then config.sops.secrets."clerie-backup-job-${jobName}".path else config.sops.secrets."clerie-backup-job-${jobName}".path;
config.age.secrets."clerie-backup-job-${jobName}".path;
repoPath = if jobOptions.repoPath == null then "/${config.networking.hostName}/${jobName}" else jobOptions.repoPath; repoPath = if jobOptions.repoPath == null then "/${config.networking.hostName}/${jobName}" else jobOptions.repoPath;
targetPasswordFile = if targetOptions.passwordFile != null then targetOptions.passwordFile else targetPasswordFile = if targetOptions.passwordFile != null then targetOptions.passwordFile else
if builtins.elem "clerie-backup-target-${targetName}" (attrNames config.sops.secrets) then config.sops.secrets."clerie-backup-target-${targetName}".path else config.sops.secrets."clerie-backup-target-${targetName}".path;
config.age.secrets."clerie-backup-target-${targetName}".path;
targetUsername = if targetOptions.username == null then config.networking.hostName else targetOptions.username; targetUsername = if targetOptions.username == null then config.networking.hostName else targetOptions.username;
in pkgs.writeShellApplication { in pkgs.writeShellApplication {
name = "clerie-backup-${jobName}-${targetName}"; name = "clerie-backup-${jobName}-${targetName}";

View File

@ -55,8 +55,7 @@ in
} }
]; ];
privateKeyFile = if cfg.privateKeyFile != null then cfg.privateKeyFile else privateKeyFile = if cfg.privateKeyFile != null then cfg.privateKeyFile else
if builtins.elem "wg-monitoring" (attrNames config.sops.secrets) then config.sops.secrets.wg-monitoring.path else config.sops.secrets.wg-monitoring.path;
config.age.secrets.wg-monitoring.path;
}; };
}; };

View File

@ -66,8 +66,7 @@ in
networking.wireguard.interfaces = { networking.wireguard.interfaces = {
wg-clerie = { wg-clerie = {
privateKeyFile = if cfg.privateKeyFile != null then cfg.privateKeyFile else privateKeyFile = if cfg.privateKeyFile != null then cfg.privateKeyFile else
if builtins.elem "wg-clerie" (attrNames config.sops.secrets) then config.sops.secrets.wg-clerie.path else config.sops.secrets.wg-clerie.path;
config.age.secrets.wg-clerie.path;
ips = cfg.ipv6s ++ cfg.ipv4s; ips = cfg.ipv6s ++ cfg.ipv4s;
table = "wg-clerie"; table = "wg-clerie";
peers = [ peers = [

View File

@ -98,7 +98,7 @@ in
''; '';
boot.initrd.secrets = { boot.initrd.secrets = {
"/var/src/secrets/wireguard/wg-initrd" = if cfg.privateKeyFile == null then config.age.secrets.wg-clerie.path else cfg.privateKeyFile; "/var/src/secrets/wireguard/wg-initrd" = cfg.privateKeyFile;
}; };
}; };
} }

View File

@ -1,11 +0,0 @@
{ pkgs, ... }:
pkgs.writeShellApplication {
name = "nixfiles-add-secret";
text = builtins.readFile ./nixfiles-add-secret.sh;
runtimeInputs = with pkgs; [
agenix
git
];
}

View File

@ -1,15 +0,0 @@
#!/usr/bin/env bash
set -euo pipefail
cd "$(git rev-parse --show-toplevel)"
host="$1"
secret="$2"
mkdir -p "hosts/${host}/secrets"
agenix -e "hosts/${host}/secrets/new"
mv "hosts/${host}/secrets/new" "hosts/${host}/secrets/${secret}.age"

View File

@ -9,9 +9,7 @@ final: prev: {
chromium-incognito = final.callPackage ./chromium-incognito {}; chromium-incognito = final.callPackage ./chromium-incognito {};
iot-data = final.python3.pkgs.callPackage ./iot-data {}; iot-data = final.python3.pkgs.callPackage ./iot-data {};
nix-remove-result-links = final.callPackage ./nix-remove-result-links {}; nix-remove-result-links = final.callPackage ./nix-remove-result-links {};
nixfiles-add-secret = final.callPackage ./nixfiles/nixfiles-add-secret.nix {};
nixfiles-auto-install = final.callPackage ./nixfiles/nixfiles-auto-install.nix {}; nixfiles-auto-install = final.callPackage ./nixfiles/nixfiles-auto-install.nix {};
nixfiles-generate-backup-secrets = final.callPackage ./nixfiles/nixfiles-generate-backup-secrets.nix {};
nixfiles-generate-config = final.callPackage ./nixfiles/nixfiles-generate-config.nix {}; nixfiles-generate-config = final.callPackage ./nixfiles/nixfiles-generate-config.nix {};
nixfiles-update-ssh-host-keys = final.callPackage ./nixfiles/nixfiles-update-ssh-host-keys.nix {}; nixfiles-update-ssh-host-keys = final.callPackage ./nixfiles/nixfiles-update-ssh-host-keys.nix {};
print-afra = final.callPackage ./print-afra {}; print-afra = final.callPackage ./print-afra {};

View File

@ -1,96 +0,0 @@
/*
Because I'm way too lazy I'm automatically generating the secret files config.
Secrets can be found below
hosts/${hostname}/secrets/*.age
Pubkeys can be found for the specific host below
hosts/${hostname}/ssh.pub
The users have their keys below
users/${username}/ssh.pub
Secrets get encrypted for the host they are in and the users specified.
Every host with a secrets directory has an entry for a secret called "new".
This exist to overcome the chicken and egg problem.
Create a secret with them name new in the specific secrets directory and rename it afterwards with the suffix .age.
*/
let
/*
Returns an attrset for a given directory,
having the name of a subdirectory as its attribute names
and the contents of the containing ssh.pub file as their value
{
clerie = "ssh-ed25519 AAAA...";
}
*/
pubkeysFor = directory: let
instances = builtins.attrNames (builtins.readDir directory);
instancesWithPubkey = builtins.filter (i: builtins.pathExists (directory + "/${i}/ssh.pub")) instances;
in
builtins.listToAttrs (map (i: { name = i; value = builtins.readFile (directory + "/${i}/ssh.pub"); }) instancesWithPubkey);
users = pubkeysFor ./users;
hosts = pubkeysFor ./hosts;
/*
Returns secret configuration for a given hostname
*/
secretsForHost = hostname: let
/*
Returns a list of all file names in the secrets directory of the specified host
*/
secretsFiles = builtins.attrNames (builtins.readDir (./hosts + "/${hostname}/secrets"));
/*
Returns all file names that end with .age
*/
listOfSecrets = builtins.filter (i:
# Make sure the file name is longer than the file extension
(builtins.stringLength i) > 4
# Take the last four letters of the file name and check if it is .age
&& builtins.substring ((builtins.stringLength i) - 4) (builtins.stringLength i) i == ".age"
) secretsFiles;
in
if
# Make sure the host has a secrets directory
builtins.pathExists (./hosts + "/${hostname}/secrets")
# Make sure the host has a public ssh key provided
&& builtins.pathExists (./hosts + "/${hostname}/ssh.pub")
then
/*
This map specifies all public keys for which a given secret file should be encrypted
It returns a list of name value pairs
The name is the path to the secret file
The value is an attribute set containing a list of public keys as a string
*/
map
(secret: {
name = "hosts/${hostname}/secrets/${secret}";
value = {
publicKeys = [
# Hardcode clerie's public key here
(builtins.readFile (./users + "/clerie/ssh.pub"))
# No other user should have access to any secrets
# A host should only have access to their own secrets
hosts."${hostname}"
];
};
})
# All file names of already existing secrets plus the magic "new" secret
(listOfSecrets ++ [ "new" ])
else
# Answer with an empty list, if no secrets are provided for a host
[];
in
# We just have a list of name value pairs that need to get transformed into an attribute set
builtins.listToAttrs (
builtins.concatMap
# Provide a list of secrets for a given hostname
(hostname: secretsForHost hostname)
# Names of all hosts
(builtins.attrNames (builtins.readDir ./hosts))
)