mirror of
https://github.com/nmasur/dotfiles
synced 2024-11-25 13:45:37 +00:00
new secrets management system
This commit is contained in:
parent
e2c351098b
commit
69a54b99c8
19
apps/encrypt-secret.nix
Normal file
19
apps/encrypt-secret.nix
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
{ pkgs, ... }: {
|
||||||
|
|
||||||
|
# nix run github:nmasur/dotfiles#encrypt-secret > private/mysecret.age
|
||||||
|
|
||||||
|
type = "app";
|
||||||
|
|
||||||
|
program = builtins.toString (pkgs.writeShellScript "encrypt-secret" ''
|
||||||
|
printf "\nEnter the secret data to encrypt for all hosts...\n\n" 1>&2
|
||||||
|
read -p "Secret: " secret
|
||||||
|
printf "\nEncrypting...\n\n" 1>&2
|
||||||
|
tmpfile=$(mktemp)
|
||||||
|
echo "''${secret}" > ''${tmpfile}
|
||||||
|
${pkgs.age}/bin/age --encrypt --armor --recipients-file ${
|
||||||
|
builtins.toString ../hosts/public-keys
|
||||||
|
} $tmpfile
|
||||||
|
rm $tmpfile
|
||||||
|
'');
|
||||||
|
|
||||||
|
}
|
27
apps/reencrypt-secrets.nix
Normal file
27
apps/reencrypt-secrets.nix
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
{ pkgs, ... }: {
|
||||||
|
|
||||||
|
# nix run github:nmasur/dotfiles#reencrypt-secrets ./private
|
||||||
|
|
||||||
|
type = "app";
|
||||||
|
|
||||||
|
program = builtins.toString (pkgs.writeShellScript "reencrypt-secrets" ''
|
||||||
|
if [ $# -eq 0 ]; then
|
||||||
|
echo "Must provide directory to reencrypt."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
encrypted=$1
|
||||||
|
for encryptedfile in ''${1}/*; do
|
||||||
|
tmpfile=$(mktemp)
|
||||||
|
echo "Decrypting ''${encryptedfile}..."
|
||||||
|
${pkgs.age}/bin/age --decrypt \
|
||||||
|
--identity ~/.ssh/id_ed25519 $encryptedfile > $tmpfile
|
||||||
|
echo "Encrypting ''${encryptedfile}..."
|
||||||
|
${pkgs.age}/bin/age --encrypt --armor --recipients-file ${
|
||||||
|
builtins.toString ../hosts/public-keys
|
||||||
|
} $tmpfile > $encryptedfile
|
||||||
|
rm $tmpfile
|
||||||
|
done
|
||||||
|
echo "Finished."
|
||||||
|
'');
|
||||||
|
|
||||||
|
}
|
@ -92,6 +92,13 @@
|
|||||||
# Load the SSH key for this machine
|
# Load the SSH key for this machine
|
||||||
loadkey = import ./apps/loadkey.nix { inherit pkgs; };
|
loadkey = import ./apps/loadkey.nix { inherit pkgs; };
|
||||||
|
|
||||||
|
# Encrypt secret for all machines
|
||||||
|
encrypt-secret = import ./apps/encrypt-secret.nix { inherit pkgs; };
|
||||||
|
|
||||||
|
# Re-encrypt secrets for all machines
|
||||||
|
reencrypt-secrets =
|
||||||
|
import ./apps/reencrypt-secrets.nix { inherit pkgs; };
|
||||||
|
|
||||||
# Connect machine metrics to Netdata Cloud
|
# Connect machine metrics to Netdata Cloud
|
||||||
netdata = import ./apps/netdata-cloud.nix { inherit pkgs; };
|
netdata = import ./apps/netdata-cloud.nix { inherit pkgs; };
|
||||||
|
|
||||||
|
4
hosts/public-keys
Normal file
4
hosts/public-keys
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
# Scan hosts: ssh-keyscan -t ed25519 <hostnames>
|
||||||
|
|
||||||
|
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIB+AbmjGEwITk5CK9y7+Rg27Fokgj9QEjgc9wST6MA3s noah
|
||||||
|
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIHVknmPi7sG6ES0G0jcsvebzKGWWaMfJTYgvOue6EULI oracle.masu.rs
|
97
modules/services/secrets.nix
Normal file
97
modules/services/secrets.nix
Normal file
@ -0,0 +1,97 @@
|
|||||||
|
# Secrets management method taken from here:
|
||||||
|
# https://xeiaso.net/blog/nixos-encrypted-secrets-2021-01-20
|
||||||
|
|
||||||
|
# In my case, I pre-encrypt my secrets and commit them to git.
|
||||||
|
|
||||||
|
{ config, pkgs, lib, ... }: {
|
||||||
|
|
||||||
|
options = {
|
||||||
|
|
||||||
|
identityFile = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
description = "Path to existing identity file.";
|
||||||
|
default = "/etc/ssh/ssh_host_ed25519_key";
|
||||||
|
};
|
||||||
|
|
||||||
|
# secretsDirectory = lib.mkOption {
|
||||||
|
# type = lib.types.str;
|
||||||
|
# description = "Default path to place secrets.";
|
||||||
|
# default = "/var/lib/private";
|
||||||
|
# };
|
||||||
|
|
||||||
|
secrets = lib.mkOption {
|
||||||
|
type = lib.types.attrsOf (lib.types.submodule {
|
||||||
|
options = {
|
||||||
|
source = lib.mkOption {
|
||||||
|
type = lib.types.path;
|
||||||
|
description = "Path to encrypted secret.";
|
||||||
|
};
|
||||||
|
dest = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
description = "Resulting path for decrypted secret.";
|
||||||
|
};
|
||||||
|
owner = lib.mkOption {
|
||||||
|
default = "root";
|
||||||
|
type = lib.types.str;
|
||||||
|
description = "User to own the secret.";
|
||||||
|
};
|
||||||
|
group = lib.mkOption {
|
||||||
|
default = "root";
|
||||||
|
type = lib.types.str;
|
||||||
|
description = "Group to own the secret.";
|
||||||
|
};
|
||||||
|
permissions = lib.mkOption {
|
||||||
|
default = "0400";
|
||||||
|
type = lib.types.str;
|
||||||
|
description = "Permissions expressed as octal.";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
});
|
||||||
|
description = "Set of secrets to decrypt to disk.";
|
||||||
|
default = { };
|
||||||
|
};
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
config = {
|
||||||
|
|
||||||
|
# Create a default directory to place secrets
|
||||||
|
|
||||||
|
# systemd.tmpfiles.rules = [ "d ${config.secretsDirectory} 0750 root wheel" ];
|
||||||
|
|
||||||
|
# Declare oneshot service to decrypt secret using SSH host key
|
||||||
|
# - Requires that the secret is already encrypted for the host
|
||||||
|
# - Encrypt secrets: nix run github:nmasur/dotfiles#encrypt-secret
|
||||||
|
|
||||||
|
systemd.services = lib.mapAttrs' (name: attrs: {
|
||||||
|
name = "${name}-secret";
|
||||||
|
value = {
|
||||||
|
|
||||||
|
description = "Decrypt secret for ${name}";
|
||||||
|
wantedBy = [ "multi-user.target" ];
|
||||||
|
serviceConfig.Type = "oneshot";
|
||||||
|
script = ''
|
||||||
|
${pkgs.age}/bin/age --decrypt \
|
||||||
|
--identity ${config.identityFile} \
|
||||||
|
--output ${attrs.dest} \
|
||||||
|
${attrs.source}
|
||||||
|
|
||||||
|
chown '${attrs.owner}':'${attrs.group}' '${attrs.dest}'
|
||||||
|
chmod '${attrs.permissions}' '${attrs.dest}'
|
||||||
|
'';
|
||||||
|
|
||||||
|
};
|
||||||
|
}) config.secrets;
|
||||||
|
|
||||||
|
# Example declaration
|
||||||
|
# config.secrets.my-secret = {
|
||||||
|
# source = ../../private/my-secret.age;
|
||||||
|
# dest = "/var/lib/private/my-secret";
|
||||||
|
# owner = "my-app";
|
||||||
|
# group = "my-app";
|
||||||
|
# permissions = "0440";
|
||||||
|
# };
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
@ -1,10 +1,6 @@
|
|||||||
{ config, pkgs, lib, ... }:
|
{ config, pkgs, lib, ... }: {
|
||||||
|
|
||||||
let credentialsFile = "/var/lib/private/transmission.json";
|
imports = [ ./wireguard.nix ./secrets.nix ];
|
||||||
|
|
||||||
in {
|
|
||||||
|
|
||||||
imports = [ ./wireguard.nix ];
|
|
||||||
|
|
||||||
options = {
|
options = {
|
||||||
transmissionServer = lib.mkOption {
|
transmissionServer = lib.mkOption {
|
||||||
@ -33,14 +29,14 @@ in {
|
|||||||
rpc-whitelist = "127.0.0.1,${vpnIp}";
|
rpc-whitelist = "127.0.0.1,${vpnIp}";
|
||||||
rpc-whitelist-enabled = true;
|
rpc-whitelist-enabled = true;
|
||||||
};
|
};
|
||||||
credentialsFile = credentialsFile;
|
credentialsFile = config.secrets.transmission.dest;
|
||||||
};
|
};
|
||||||
|
|
||||||
# Bind transmission to wireguard namespace
|
# Bind transmission to wireguard namespace
|
||||||
systemd.services.transmission = {
|
systemd.services.transmission = {
|
||||||
bindsTo = [ "netns@${namespace}.service" ];
|
bindsTo = [ "netns@${namespace}.service" ];
|
||||||
requires = [ "network-online.target" ];
|
requires = [ "network-online.target" "transmission-secret.service" ];
|
||||||
after = [ "wireguard-wg0.service" ];
|
after = [ "wireguard-wg0.service" "transmission-secret.service" ];
|
||||||
unitConfig.JoinsNamespaceOf = "netns@${namespace}.service";
|
unitConfig.JoinsNamespaceOf = "netns@${namespace}.service";
|
||||||
serviceConfig.NetworkNamespacePath = "/var/run/netns/${namespace}";
|
serviceConfig.NetworkNamespacePath = "/var/run/netns/${namespace}";
|
||||||
};
|
};
|
||||||
@ -71,21 +67,11 @@ in {
|
|||||||
};
|
};
|
||||||
|
|
||||||
# Create credentials file for transmission
|
# Create credentials file for transmission
|
||||||
systemd.services.transmission-creds = {
|
secrets.transmission = {
|
||||||
requiredBy = [ "transmission.service" ];
|
source = ../../private/transmission.json.age;
|
||||||
before = [ "transmission.service" ];
|
dest = "/var/lib/private/transmission.json";
|
||||||
serviceConfig = { Type = "oneshot"; };
|
owner = "transmission";
|
||||||
script = ''
|
group = "transmission";
|
||||||
if [ ! -f "${credentialsFile}" ]; then
|
|
||||||
mkdir --parents ${builtins.dirOf credentialsFile}
|
|
||||||
${pkgs.age}/bin/age --decrypt \
|
|
||||||
--identity ${config.identityFile} \
|
|
||||||
--output ${credentialsFile} \
|
|
||||||
${builtins.toString ../../private/transmission.json.age}
|
|
||||||
chown transmission:transmission ${credentialsFile}
|
|
||||||
chmod 0700 ${credentialsFile}
|
|
||||||
fi
|
|
||||||
'';
|
|
||||||
};
|
};
|
||||||
|
|
||||||
};
|
};
|
||||||
|
@ -1,25 +1,25 @@
|
|||||||
{ config, pkgs, lib, ... }: {
|
{ config, pkgs, lib, ... }: {
|
||||||
|
|
||||||
options = {
|
options = {
|
||||||
identityFile = lib.mkOption {
|
# identityFile = lib.mkOption {
|
||||||
type = lib.types.str;
|
# type = lib.types.str;
|
||||||
description = "Path to SSH key for age";
|
# description = "Path to SSH key for age";
|
||||||
default = "${config.homePath}/.ssh/id_ed25519";
|
# default = "${config.homePath}/.ssh/id_ed25519";
|
||||||
};
|
# };
|
||||||
};
|
};
|
||||||
|
|
||||||
config = {
|
config = {
|
||||||
home-manager.users.${config.user}.home.packages = with pkgs; [ age ];
|
home-manager.users.${config.user}.home.packages = with pkgs; [ age ];
|
||||||
|
|
||||||
system.activationScripts.age.text = ''
|
# system.activationScripts.age.text = ''
|
||||||
if [ ! -f "${config.identityFile}" ]; then
|
# if [ ! -f "${config.identityFile}" ]; then
|
||||||
$DRY_RUN_CMD echo -e \nEnter the seed phrase for your SSH key...\n
|
# $DRY_RUN_CMD echo -e \nEnter the seed phrase for your SSH key...\n
|
||||||
$DRY_RUN_CMD echo -e \nThen press ^D when complete.\n\n
|
# $DRY_RUN_CMD echo -e \nThen press ^D when complete.\n\n
|
||||||
$DRY_RUN_CMD ${pkgs.melt}/bin/melt restore ${config.identityFile}
|
# $DRY_RUN_CMD ${pkgs.melt}/bin/melt restore ${config.identityFile}
|
||||||
$DRY_RUN_CMD chown ${config.user}:wheel ${config.identityFile}*
|
# $DRY_RUN_CMD chown ${config.user}:wheel ${config.identityFile}*
|
||||||
$DRY_RUN_CMD echo -e \n\nContinuing activation.\n\n
|
# $DRY_RUN_CMD echo -e \n\nContinuing activation.\n\n
|
||||||
fi
|
# fi
|
||||||
'';
|
# '';
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,10 @@
|
|||||||
age-encryption.org/v1
|
-----BEGIN AGE ENCRYPTED FILE-----
|
||||||
-> ssh-ed25519 MgHaOw PAAWnpc5bJ5S972U+L6YgHpI2a7aqwxWaNZrvQIODVg
|
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IHNzaC1lZDI1NTE5IE1nSGFPdyBSYUU2
|
||||||
A6zRWD6TmlVb8b5J3gdMf3JAeHIHgUQA3C8PpR8GveQ
|
OWp1ZDRLVTJrR1k3SVdXZnRPN3RUNDY5RFM2WEZaTzRmdU1zSWdrCjV1VHpNMG81
|
||||||
--- xP8vbUGtTlvaZ0K2J0+J0ICoL9gvCbhQg6GxG8ZYCS0
|
VHA4LzdsN3FpOUNoTGNlWmlHS3E4dTVvWTVoZHJMSlNYTHMKLT4gc3NoLWVkMjU1
|
||||||
±7¸½½5åL2céJ¿œÄ€»eÅ,÷ßÝ<C39F>ÉTù°§n$Mó<4D>ýi4þêYßiæ[á!¸Å<C2B8>L%ß(Ði‰§F;‡ù6<C3B9>·¨¡†ã¹ÄÂÍÔŠjO
|
MTkgWXlTVU1RIDVjM1JmclgxQThKcU1XQWptWmN0MjlKU1NvMEpwMnYyd3Y4czBT
|
||||||
|
RTVkQ0UKc0pOYkRxZldsWnloQnBYMWk1eFU0M3R5SkZVTUYyaldIcENONE1PWVJv
|
||||||
|
NAotLS0gclZDQndaREZpZ2Z0R0d0alBPeW1tZFVOVHhSaHNlQTRXdTRoZmFDUFFK
|
||||||
|
SQqueOUzTFuhSryWW4Do+NAUcq2YdOtN8gmP5Zcp1oMe/9+JIs6Upjsc3eWn+dSA
|
||||||
|
7QwbGlTyd6D0+PLJxHA18Xfgpj5owGeTDtwykFPgdO1BjE8C3KlgzUfN
|
||||||
|
-----END AGE ENCRYPTED FILE-----
|
||||||
|
Loading…
Reference in New Issue
Block a user