populate: add passage source type

This commit is contained in:
tv 2024-01-11 04:37:02 +01:00
parent cbc475bdf4
commit a6c7ecd8ba
3 changed files with 82 additions and 1 deletions

View File

@ -6,6 +6,7 @@ krops is a lightweight toolkit to deploy NixOS systems, remotely or locally.
## Some Features ## Some Features
- store your secrets in [password store](https://www.passwordstore.org/) - store your secrets in [password store](https://www.passwordstore.org/)
or [passage](https://github.com/FiloSottile/passage)
- build your systems remotely - build your systems remotely
- minimal overhead (it's basically just `nixos-rebuild switch`!) - minimal overhead (it's basically just `nixos-rebuild switch`!)
- run from custom nixpkgs branch/checkout/fork - run from custom nixpkgs branch/checkout/fork
@ -298,6 +299,29 @@ Supported attributes:
sub-directory in the password store. sub-directory in the password store.
### `passage`
The passage source type decrypts files from a local
[passage store](https://github.com/FiloSottile/passage)
and transfers them to the target using
[`rsync`](https://rsync.samba.org/).
Supported attributes:
* `dir` -
Path to the passage store.
For a partial transfer, this may point to a subdirectory.
Example: `~/.passage/store/hosts/MYHOSTNAME`
* `identities_file` (optional) -
Path to the identities file.
Defaults to `~/.passage/identities`.
* `age` (optional) -
Path of the age binary.
Defaults to `age` (absolute path gets resolved using `passage`'s search path.)
### `pipe` ### `pipe`
Executes a local command, capture its stdout, and send that as a file to the Executes a local command, capture its stdout, and send that as a file to the

View File

@ -39,6 +39,17 @@
default = null; default = null;
type = lib.types.nullOr source-types.pass; type = lib.types.nullOr source-types.pass;
}; };
passage = lib.mkOption {
apply = x:
if lib.types.pathname.check x
then { dir = x; }
else x;
default = null;
type = lib.types.nullOr (lib.types.oneOf [
lib.types.pathname
source-types.passage
]);
};
pipe = lib.mkOption { pipe = lib.mkOption {
apply = x: apply = x:
if lib.types.absolute-pathname.check x if lib.types.absolute-pathname.check x
@ -160,6 +171,21 @@
}; };
}; };
}; };
passage = lib.types.submodule {
options = {
age = lib.mkOption {
default = "age";
type = lib.types.pathname;
};
dir = lib.mkOption {
type = lib.types.pathname;
};
identities_file = lib.mkOption {
default = toString ~/.passage/identities;
type = lib.types.pathname;
};
};
};
pipe = lib.types.submodule { pipe = lib.types.submodule {
options = { options = {
command = lib.mkOption { command = lib.mkOption {

View File

@ -1,7 +1,7 @@
with import ../../lib; with import ../../lib;
with shell; with shell;
{ coreutils, dash, findutils, git, jq, openssh, pass, rsync, writers }: { coreutils, dash, findutils, git, jq, openssh, pass, passage, rsync, writers }:
let let
check = { force, target }: let check = { force, target }: let
@ -171,6 +171,37 @@ let
${rsync' target rsyncDefaultConfig /* sh */ "$tmp_dir"} ${rsync' target rsyncDefaultConfig /* sh */ "$tmp_dir"}
''; '';
pop.passage = target: source: /* sh */ ''
set -efu
export PASSAGE_AGE=${quote source.age}
export PASSAGE_DIR=${quote source.dir}
export PASSAGE_IDENTITIES_FILE=${quote source.identities_file}
umask 0077
tmp_dir=$(${coreutils}/bin/mktemp -dt populate-passage.XXXXXXXX)
trap cleanup EXIT
cleanup() {
rm -fR "$tmp_dir"
}
${findutils}/bin/find "$PASSAGE_DIR" -type f -name \*.age -follow |
while read -r age_path; do
rel_name=''${age_path#$PASSAGE_DIR}
rel_name=''${rel_name%.age}
tmp_path=$tmp_dir/$rel_name
${coreutils}/bin/mkdir -p "$(${coreutils}/bin/dirname "$tmp_path")"
${passage}/bin/passage show "$rel_name" > "$tmp_path"
${coreutils}/bin/touch -r "$age_path" "$tmp_path"
done
${rsync' target rsyncDefaultConfig /* sh */ "$tmp_dir"}
'';
pop.pipe = target: source: /* sh */ '' pop.pipe = target: source: /* sh */ ''
${quote source.command} | { ${quote source.command} | {
${runShell target /* sh */ "cat > ${quote target.path}"} ${runShell target /* sh */ "cat > ${quote target.path}"}