aboutsummaryrefslogtreecommitdiff
path: root/flakes
diff options
context:
space:
mode:
Diffstat (limited to 'flakes')
-rw-r--r--flakes/private/openarc/flake.lock14
-rw-r--r--flakes/private/openarc/flake.nix9
-rw-r--r--flakes/private/opendmarc/flake.lock14
-rw-r--r--flakes/private/opendmarc/flake.nix9
-rw-r--r--flakes/secrets/flake.nix124
5 files changed, 162 insertions, 8 deletions
diff --git a/flakes/private/openarc/flake.lock b/flakes/private/openarc/flake.lock
index f0f56c7..744d002 100644
--- a/flakes/private/openarc/flake.lock
+++ b/flakes/private/openarc/flake.lock
@@ -140,7 +140,19 @@
140 "files-watcher": "files-watcher", 140 "files-watcher": "files-watcher",
141 "my-lib": "my-lib", 141 "my-lib": "my-lib",
142 "nix-lib": "nix-lib", 142 "nix-lib": "nix-lib",
143 "openarc": "openarc" 143 "openarc": "openarc",
144 "secrets": "secrets"
145 }
146 },
147 "secrets": {
148 "locked": {
149 "narHash": "sha256-aRHKDVHDpnqpmgGhLGQxXwyTwmPuhUJTVcOLBYtY2ks=",
150 "path": "../../secrets",
151 "type": "path"
152 },
153 "original": {
154 "path": "../../secrets",
155 "type": "path"
144 } 156 }
145 } 157 }
146 }, 158 },
diff --git a/flakes/private/openarc/flake.nix b/flakes/private/openarc/flake.nix
index 5c4b73c..b4ab4c8 100644
--- a/flakes/private/openarc/flake.nix
+++ b/flakes/private/openarc/flake.nix
@@ -3,6 +3,10 @@
3 path = "../../openarc"; 3 path = "../../openarc";
4 type = "path"; 4 type = "path";
5 }; 5 };
6 inputs.secrets = {
7 path = "../../secrets";
8 type = "path";
9 };
6 inputs.files-watcher = { 10 inputs.files-watcher = {
7 path = "../../files-watcher"; 11 path = "../../files-watcher";
8 type = "path"; 12 type = "path";
@@ -14,14 +18,13 @@
14 inputs.nix-lib.url = "github:NixOS/nixpkgs"; 18 inputs.nix-lib.url = "github:NixOS/nixpkgs";
15 19
16 description = "Private configuration for openarc"; 20 description = "Private configuration for openarc";
17 outputs = { self, nix-lib, my-lib, files-watcher, openarc }: 21 outputs = { self, nix-lib, my-lib, files-watcher, openarc, secrets }:
18 let 22 let
19 cfg = name': { config, lib, pkgs, name, ... }: { 23 cfg = name': { config, lib, pkgs, name, ... }: {
20 imports = [ 24 imports = [
21 (my-lib.lib.withNarKey files-watcher "nixosModule") 25 (my-lib.lib.withNarKey files-watcher "nixosModule")
22 (my-lib.lib.withNarKey openarc "nixosModule") 26 (my-lib.lib.withNarKey openarc "nixosModule")
23 #FIXME: 27 (my-lib.lib.withNarKey secrets "nixosModule")
24 #(my-lib.lib.withNarKey secrets "nixosModule")
25 ]; 28 ];
26 config = lib.mkIf (name == name') { 29 config = lib.mkIf (name == name') {
27 services.openarc = { 30 services.openarc = {
diff --git a/flakes/private/opendmarc/flake.lock b/flakes/private/opendmarc/flake.lock
index 121f51d..bd5019c 100644
--- a/flakes/private/opendmarc/flake.lock
+++ b/flakes/private/opendmarc/flake.lock
@@ -123,7 +123,19 @@
123 "files-watcher": "files-watcher", 123 "files-watcher": "files-watcher",
124 "my-lib": "my-lib", 124 "my-lib": "my-lib",
125 "nix-lib": "nix-lib", 125 "nix-lib": "nix-lib",
126 "opendmarc": "opendmarc" 126 "opendmarc": "opendmarc",
127 "secrets": "secrets"
128 }
129 },
130 "secrets": {
131 "locked": {
132 "narHash": "sha256-aRHKDVHDpnqpmgGhLGQxXwyTwmPuhUJTVcOLBYtY2ks=",
133 "path": "../../secrets",
134 "type": "path"
135 },
136 "original": {
137 "path": "../../secrets",
138 "type": "path"
127 } 139 }
128 } 140 }
129 }, 141 },
diff --git a/flakes/private/opendmarc/flake.nix b/flakes/private/opendmarc/flake.nix
index debcfbd..2b73070 100644
--- a/flakes/private/opendmarc/flake.nix
+++ b/flakes/private/opendmarc/flake.nix
@@ -3,6 +3,10 @@
3 path = "../../opendmarc"; 3 path = "../../opendmarc";
4 type = "path"; 4 type = "path";
5 }; 5 };
6 inputs.secrets = {
7 path = "../../secrets";
8 type = "path";
9 };
6 inputs.files-watcher = { 10 inputs.files-watcher = {
7 path = "../../files-watcher"; 11 path = "../../files-watcher";
8 type = "path"; 12 type = "path";
@@ -14,14 +18,13 @@
14 inputs.nix-lib.url = "github:NixOS/nixpkgs"; 18 inputs.nix-lib.url = "github:NixOS/nixpkgs";
15 19
16 description = "Private configuration for opendmarc"; 20 description = "Private configuration for opendmarc";
17 outputs = { self, nix-lib, opendmarc, my-lib, files-watcher }: 21 outputs = { self, nix-lib, opendmarc, my-lib, files-watcher, secrets }:
18 let 22 let
19 cfg = name': { config, lib, pkgs, name, ... }: { 23 cfg = name': { config, lib, pkgs, name, ... }: {
20 imports = [ 24 imports = [
21 (my-lib.lib.withNarKey files-watcher "nixosModule") 25 (my-lib.lib.withNarKey files-watcher "nixosModule")
22 (my-lib.lib.withNarKey opendmarc "nixosModule") 26 (my-lib.lib.withNarKey opendmarc "nixosModule")
23 #FIXME: 27 (my-lib.lib.withNarKey secrets "nixosModule")
24 #(my-lib.lib.withNarKey secrets "nixosModule")
25 ]; 28 ];
26 config = lib.mkIf (name == name') { 29 config = lib.mkIf (name == name') {
27 users.users."${config.services.opendmarc.user}".extraGroups = [ "keys" ]; 30 users.users."${config.services.opendmarc.user}".extraGroups = [ "keys" ];
diff --git a/flakes/secrets/flake.nix b/flakes/secrets/flake.nix
new file mode 100644
index 0000000..0ee6a40
--- /dev/null
+++ b/flakes/secrets/flake.nix
@@ -0,0 +1,124 @@
1{
2 description = "Secrets handling";
3
4 outputs = { self }: {
5 nixosModule = { config, lib, pkgs, ... }: {
6 options.secrets = with lib; {
7 keys = mkOption {
8 type = types.listOf types.unspecified;
9 default = [];
10 description = "Keys to upload to server";
11 };
12 gpgKeys = mkOption {
13 type = types.listOf types.path;
14 default = [];
15 description = "GPG public keys files to encrypt to";
16 };
17 ageKeys = mkOption {
18 type = types.listOf types.str;
19 default = [];
20 description = "AGE keys to encrypt to";
21 };
22 decryptKey = mkOption {
23 type = types.str;
24 default = "/etc/ssh/ssh_host_ed25519_key";
25 description = "ed25519 key used to decrypt with AGE";
26 };
27 location = mkOption {
28 type = types.path;
29 default = "/var/secrets";
30 description = "Location where to put the keys";
31 };
32 secretsVars = mkOption {
33 type = types.path;
34 description = "Location where the secrets variables are defined, to be used to fill the templates in secrets";
35 };
36 deleteSecretsVars = mkOption {
37 type = types.bool;
38 default = false;
39 description = "Delete secrets file after deployment";
40 };
41 # Read-only variables
42 fullPaths = mkOption {
43 type = types.attrsOf types.path;
44 default = builtins.listToAttrs
45 (map (v: { name = v.dest; value = "${config.secrets.location}/${v.dest}"; }) config.secrets.keys);
46 readOnly = true;
47 description = "set of full paths to secrets";
48 };
49 };
50
51 config = let
52 location = config.secrets.location;
53 keys = config.secrets.keys;
54 empty = pkgs.runCommand "empty" { preferLocalBuild = true; } "mkdir -p $out && touch $out/done";
55 fpath = v: "secrets/${v.dest}${lib.optionalString (v.isTemplated or true) ".gucci.tpl"}";
56 dumpKey = v:
57 if v.isDir or false then
58 ''
59 mkdir -p secrets/${v.dest}
60 cat >> mods <<EOF
61 ${v.user or "root"} ${v.group or "root"} ${v.permissions or "0600"} secrets/${v.dest}
62 EOF
63 ''
64 else ''
65 mkdir -p secrets/$(dirname ${v.dest})
66 echo -n ${lib.strings.escapeShellArg v.text} > ${fpath v}
67 cat >> mods <<EOF
68 ${v.user or "root"} ${v.group or "root"} ${v.permissions or "0600"} ${fpath v}
69 EOF
70 '';
71 secrets = pkgs.runCommand "secrets.tar.enc" {
72 buildInputs = [ pkgs.gnupg pkgs.sops ];
73 } ''
74 touch mods
75 tar --format=ustar --mtime='1970-01-01' -P --transform="s@${empty}@secrets@" -cf $out ${empty}/done
76 ${builtins.concatStringsSep "\n" (map dumpKey keys)}
77 cat mods | while read u g p k; do
78 tar --no-recursion --format=ustar --mtime='1970-01-01' --owner="$u" --group="$g" --mode="$p" --append -f $out "$k"
79 done
80 export HOME=$(pwd)
81 fingerprints=
82 for key in ${builtins.concatStringsSep " " config.secrets.gpgKeys}; do
83 gpg --import $key 2>/dev/null
84 fingerprints=$fingerprints,$(cat $key | gpg --with-colons --import-options show-only --import 2>/dev/null | grep ^fpr | cut -d: -f10 | head -n1)
85 done
86
87 sops --age ${builtins.concatStringsSep "," config.secrets.ageKeys} --pgp ''${fingerprints#,} --input-type binary -i -e $out 2>/dev/null
88 '';
89 pathChmodExcl =
90 let
91 dirs = builtins.filter (v: v.isDir or false) keys;
92 exclPath = builtins.concatStringsSep " -o " (map (d: " -path $TMP/${d.dest}") dirs);
93 in
94 lib.optionalString (builtins.length dirs > 0) " -not \\( ${exclPath} \\) ";
95 in lib.mkIf (builtins.length keys > 0) {
96 system.activationScripts.secrets = {
97 deps = [ "users" "wrappers" ];
98 text = ''
99 install -m0750 -o root -g keys -d ${location}
100 TMP=$(${pkgs.coreutils}/bin/mktemp -d)
101 TMPWORK=$(${pkgs.coreutils}/bin/mktemp -d)
102 chmod go-rwx $TMPWORK
103 if [ -n "$TMP" -a -n "$TMPWORK" ]; then
104 install -m0750 -o root -g keys -d $TMP
105 ${pkgs.ssh-to-age}/bin/ssh-to-age -private-key -i ${config.secrets.decryptKey} -o $TMPWORK/keys.txt
106 SOPS_AGE_KEY_FILE=$TMPWORK/keys.txt ${pkgs.sops}/bin/sops -d ${secrets} | ${pkgs.gnutar}/bin/tar --strip-components 1 -C $TMP -x
107 if [ -f ${config.secrets.secretsVars} ]; then
108 SOPS_AGE_KEY_FILE=$TMPWORK/keys.txt ${pkgs.sops}/bin/sops -d ${config.secrets.secretsVars} > $TMPWORK/vars.yml
109 fi
110 if [ -f $TMPWORK/vars.yml ]; then
111 find $TMP -name "*.gucci.tpl" -exec \
112 /bin/sh -c 'f="{}"; ${pkgs.gucci}/bin/gucci -f '$TMPWORK'/vars.yml "$f" > "''${f%.gucci.tpl}"; touch --reference "$f" ''${f%.gucci.tpl} ; chmod --reference="$f" ''${f%.gucci.tpl} ; chown --reference="$f" ''${f%.gucci.tpl}' \;
113 fi
114 find $TMP -type d ${pathChmodExcl}-exec chown root:keys {} \; -exec chmod o-rx {} \;
115 ${pkgs.rsync}/bin/rsync --exclude="*.gucci.tpl" -O -c -av --delete $TMP/ ${location}
116 rm -rf $TMP $TMPWORK ${lib.optionalString config.secrets.deleteSecretsVars config.secrets.secretsVars}
117 fi
118 '';
119 };
120
121 };
122 };
123 };
124}