forked from mirrors_public/oddlama_nix-config
feat: rekeying module finished, sandbox still flaky
This commit is contained in:
parent
24a8795226
commit
92cf272cd1
6 changed files with 138 additions and 30 deletions
|
@ -1,6 +1,7 @@
|
|||
{
|
||||
lib,
|
||||
pkgs,
|
||||
config,
|
||||
...
|
||||
}: let
|
||||
dummyConfig = pkgs.writeText "configuration.nix" ''
|
||||
|
@ -26,6 +27,14 @@ in {
|
|||
services.udisks2.enable = false;
|
||||
security.sudo.enable = false;
|
||||
|
||||
rekey.hostPubkey = ../../secrets/pubkeys + "/${config.networking.hostName}.pub";
|
||||
rekey.hostPrivkey = lib.head (map (e: e.path) (lib.filter (e: e.type == "ed25519") config.services.openssh.hostKeys));
|
||||
rekey.masterIdentityPaths = [../../secrets/yk1-nix-rage.pub];
|
||||
rekey.agePlugins = with pkgs; [age-plugin-yubikey];
|
||||
|
||||
rekey.secrets.yolo.file = ./yolo.age;
|
||||
environment.etc."YOLO" = config.rekey.secrets.yolo.path;
|
||||
|
||||
home-manager = {
|
||||
useGlobalPkgs = true;
|
||||
useUserPackages = true;
|
||||
|
|
|
@ -5,38 +5,129 @@
|
|||
pkgs,
|
||||
...
|
||||
}:
|
||||
let
|
||||
rekeySecrets = ageLikeSecrets: let
|
||||
#srcs = map (x: x.file) age; [./secrets/backup.txt ./secrets/recipients.txt];
|
||||
secretFiles = [ ../../secrets/backup.txt ../../secrets/recipients.txt ];
|
||||
masterIdentityPaths = [ ../../secrets/yk1-nix-rage.txt ../../secrets/backup.txt ];
|
||||
masterIdentities = builtins.concatStringsSep " " (map (x: "-i ${x}") masterIdentityPaths);
|
||||
rekeyCommand = secret: ''
|
||||
${pkgs.rage}/bin/rage -d ${masterIdentities} ${secret} \
|
||||
| ${pkgs.rage}/bin/rage -e -i ${rekey.key} -o "$out/${builtins.baseNameOf secret}"
|
||||
'';
|
||||
rekeyedSecrets = pkgs.stdenv.mkDerivation {
|
||||
name = "host-secrets";
|
||||
dontUnpack = true;
|
||||
dontConfigure = true;
|
||||
dontBuild = true;
|
||||
installPhase = ''
|
||||
set -euo pipefail
|
||||
mkdir "$out"
|
||||
# Temporarily
|
||||
${builtins.concatStringsSep "\n" (map rekeyCommand ageLikeSecrets)}
|
||||
'';
|
||||
};
|
||||
in
|
||||
rekeyedSecrets;
|
||||
in {
|
||||
with lib; {
|
||||
config.environment.systemPackages = with pkgs; [rage];
|
||||
# TODO age.identityPaths = [ (generateKeyForHost config.network.hostName) ];
|
||||
config.age = {
|
||||
secrets = let
|
||||
rekeyedSecrets = lazyDerivation {
|
||||
derivation = pkgs.stdenv.mkDerivation rec {
|
||||
pname = "host-secrets";
|
||||
version = "1.0.0";
|
||||
description = "Rekeyed secrets for this host.";
|
||||
|
||||
# Produce a rekeyed age secret for each of the secrets defined in rekey secrets
|
||||
options.rekey.secrets = options.age.secrets;
|
||||
config.age.secrets = rekeySecrets config.rekey.secrets;
|
||||
allSecrets = mapAttrsToList (_: value: value.file) config.rekey.secrets;
|
||||
hostPubkeyStr =
|
||||
if isPath config.rekey.hostPubkey
|
||||
then readFile config.rekey.hostPubkey
|
||||
else config.rekey.hostPubkey;
|
||||
|
||||
dontMakeSourcesWritable = true;
|
||||
dontUnpack = true;
|
||||
dontConfigure = true;
|
||||
dontBuild = true;
|
||||
|
||||
installPhase = let
|
||||
masterIdentityArgs = concatMapStrings (x: ''-i "${x}" '') config.rekey.masterIdentityPaths;
|
||||
rekeyCommand = secret: ''
|
||||
echo "Rekeying ${secret}" >&2
|
||||
${pkgs.rage}/bin/rage ${masterIdentityArgs} -d ${secret}
|
||||
| ${pkgs.rage}/bin/rage -r "${hostPubkeyStr}" -o "$out/${baseNameOf secret}" -e
|
||||
'';
|
||||
in ''
|
||||
set -euo pipefail
|
||||
mkdir "$out"
|
||||
|
||||
# Enable selected age plugins
|
||||
export PATH="$PATH${concatMapStrings (x: ":${x}/bin") config.rekey.agePlugins}"
|
||||
|
||||
${concatStringsSep "\n" (map rekeyCommand allSecrets)}
|
||||
'';
|
||||
};
|
||||
};
|
||||
rekeyedSecretPath = secret: "${rekeyedSecrets}/${baseNameOf secret}";
|
||||
in
|
||||
# Produce a rekeyed age secret for each of the secrets defined in our secrets
|
||||
mapAttrs (_: secret:
|
||||
mapAttrs (name: value:
|
||||
if name == "file"
|
||||
then rekeyedSecretPath value
|
||||
else value)
|
||||
secret)
|
||||
config.rekey.secrets;
|
||||
|
||||
identityPaths = mkForce config.rekey.agePubkey;
|
||||
};
|
||||
config.assertions = mkIf (config.rekey.secrets != {}) [
|
||||
{
|
||||
assertion = pathExists config.rekey.hostPubkey;
|
||||
message = "The public key required to rekey secrets for this host doesn't exist. If this is the first deploy, use a mock key until you know the real one.";
|
||||
}
|
||||
{
|
||||
assertion = config.rekey.masterIdentityPaths != [];
|
||||
message = "rekey.masterIdentityPaths must be set.";
|
||||
}
|
||||
];
|
||||
config.warnings = let
|
||||
hasGoodSuffix = x: strings.hasSuffix ".age" x || strings.hasSuffix ".pub" x;
|
||||
in
|
||||
mkIf (!all hasGoodSuffix config.rekey.masterIdentityPaths) [
|
||||
''
|
||||
It seems like at least one of your rekey.masterIdentityPaths contains an
|
||||
unencrypted age identity. These files will be copied to the nix store, so
|
||||
make sure they don't contain any secret information!
|
||||
|
||||
To silence this warning, encrypt your keys and name them *.pub or *.age.
|
||||
''
|
||||
];
|
||||
|
||||
options = {
|
||||
rekey.secrets = options.age.secrets;
|
||||
rekey.hostPubkey = mkOption {
|
||||
type = types.either types.path types.str;
|
||||
description = ''
|
||||
The age public key to use as a recipient when rekeying.
|
||||
This either has to be the path to an age public key file,
|
||||
or the public key itself in string form.
|
||||
|
||||
Make sure to NEVER use a private key here, as it will end
|
||||
up in the public nix store!
|
||||
'';
|
||||
#example = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIEyH9Vx7WJZWW+6tnDsF7JuflcxgjhAQHoCWVrjLXQ2U my-host";
|
||||
#example = "age159tavn5rcfnq30zge2jfq4yx60uksz8udndp0g3njzhrns67ca5qq3n0tj";
|
||||
example = /etc/ssh/ssh_host_ed25519_key.pub;
|
||||
};
|
||||
rekey.hostPrivkey = mkOption {
|
||||
# Str to prevent privkeys from entering the nix store
|
||||
type = types.str;
|
||||
description = ''
|
||||
The age identity (private key) that should be used to decrypt the secrets on the target machine.
|
||||
This corresponds to age.identityPaths and must match the pubkey set in rekey.hostPubkey.
|
||||
'';
|
||||
example = head (map (e: e.path) (filter (e: e.type == "ed25519") config.services.openssh.hostKeys));
|
||||
};
|
||||
rekey.masterIdentityPaths = mkOption {
|
||||
type = types.listOf types.path;
|
||||
description = ''
|
||||
The age identity used to decrypt the secrets stored in the repository, so they can be rekeyed for a specific host.
|
||||
This identity will be stored in the nix store, so be sure to use a split-identity (like a yubikey identity, which is public),
|
||||
or an encrypted age identity. You can encrypt an age identity using `rage -p -o privkey.age privkey` to protect it in your store.
|
||||
|
||||
All identities given here will be passed to age, which will select one of them for decryption.
|
||||
'';
|
||||
default = [];
|
||||
example = [./secrets/my-yubikey-identity.txt];
|
||||
};
|
||||
rekey.agePlugins = mkOption {
|
||||
type = types.listOf types.package;
|
||||
default = [];
|
||||
description = ''
|
||||
A list of plugins that should be available to rage while rekeying.
|
||||
They will be added to the PATH before rage is invoked.
|
||||
'';
|
||||
example = [pkgs.age-plugin-yubikey];
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
#rekey.secrets.my_secret.file = ./secrets/somekey.age;
|
||||
#pwdfile = rekey.secrets.mysecret.path;
|
||||
|
||||
|
|
7
modules/core/yolo.age
Normal file
7
modules/core/yolo.age
Normal file
|
@ -0,0 +1,7 @@
|
|||
age-encryption.org/v1
|
||||
-> X25519 saA0VOfRsGeQ7wIJ4SF80v3rvmf7rRbZcxTbRbWrRn4
|
||||
NNs7fIU09lYiKZ1R5KE3fJhHM1MlNxC7H6Cz2oAOyus
|
||||
-> piv-p256 xqSe8Q AgPVLX/r+nz6PWZFJW90BcPVU9kFrLV1PZge80Fyd0og
|
||||
OGvcmxsXWqwxDOGUy9Slw7zEkgeiHblldbYw4UilPC0
|
||||
--- wi4PRgJNO6O1TgA3qobLX0wP14vreWRccvuR9wWNN+k
|
||||
@…�RFJ[½®—(I‡ªu½¯mLSÂ¨Š¾«|P&þð2ú—ævñŠŽ’×2ÓÙ(àüW¦�I^ÞR:¿p�|Zty0óÊ�?ãìivAÛ…§©$ˆ¤Œ‘ÆèÍZZüMÂ�LÂpÿÒÏ Éi›¥ëø„½š<û‹àQÕÙ
|
1
secrets/pubkeys/nom.pub
Normal file
1
secrets/pubkeys/nom.pub
Normal file
|
@ -0,0 +1 @@
|
|||
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAICOdYhY/DnXpizajoeLefH6gsc/RX9x3Y6T3C1a+0sb0
|
Loading…
Add table
Add a link
Reference in a new issue