mirror of
https://github.com/Mic92/sops-nix.git
synced 2025-12-26 14:14:58 +08:00
Add age support
This commit is contained in:
parent
9d47d2e3e4
commit
f5a2ba217b
6 changed files with 145 additions and 39 deletions
|
|
@ -85,7 +85,7 @@ let
|
|||
# Does this need to be configurable?
|
||||
secretsMountPoint = "/run/secrets.d";
|
||||
symlinkPath = "/run/secrets";
|
||||
inherit (cfg) gnupgHome sshKeyPaths;
|
||||
inherit (cfg) gnupgHome sshKeyPaths ageKeyFile;
|
||||
});
|
||||
|
||||
checkedManifest = let
|
||||
|
|
@ -130,6 +130,25 @@ in {
|
|||
'';
|
||||
};
|
||||
|
||||
ageKeyFile = mkOption {
|
||||
type = types.nullOr types.path;
|
||||
default = null;
|
||||
example = "/var/lib/sops-nix/key.txt";
|
||||
description = ''
|
||||
Path to age key file used for sops decryption.
|
||||
'';
|
||||
};
|
||||
|
||||
generateAgeKey = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = ''
|
||||
Whether or not to generate the age key. If this
|
||||
option is set to false, the key must already be
|
||||
present at the specified location.
|
||||
'';
|
||||
};
|
||||
|
||||
gnupgHome = mkOption {
|
||||
type = types.nullOr types.str;
|
||||
default = null;
|
||||
|
|
@ -152,8 +171,11 @@ in {
|
|||
};
|
||||
config = mkIf (cfg.secrets != {}) {
|
||||
assertions = [{
|
||||
assertion = (cfg.gnupgHome == null) != (cfg.sshKeyPaths == []);
|
||||
assertion = cfg.ageKeyFile == null -> (cfg.gnupgHome == null) != (cfg.sshKeyPaths == []);
|
||||
message = "Exactly one of sops.gnupgHome and sops.sshKeyPaths must be set";
|
||||
} {
|
||||
assertion = (cfg.sshKeyPaths != [] || cfg.gnupgHome != null) != (cfg.ageKeyFile != null);
|
||||
message = "sops.ageKeyFile is mutually exclusive with sops.gnupgHome and sops.sshKeyPaths";
|
||||
}] ++ optionals cfg.validateSopsFiles (
|
||||
concatLists (mapAttrsToList (name: secret: [{
|
||||
assertion = builtins.pathExists secret.sopsFile;
|
||||
|
|
@ -168,9 +190,18 @@ in {
|
|||
|
||||
system.activationScripts.setup-secrets = let
|
||||
sops-install-secrets = (pkgs.callPackage ../.. {}).sops-install-secrets;
|
||||
in stringAfter [ "specialfs" "users" "groups" ] ''
|
||||
in stringAfter ([ "specialfs" "users" "groups" ] ++ optional cfg.generateAgeKey "generate-age-key") ''
|
||||
echo setting up secrets...
|
||||
${optionalString (cfg.gnupgHome != null) "SOPS_GPG_EXEC=${pkgs.gnupg}/bin/gpg"} ${sops-install-secrets}/bin/sops-install-secrets ${checkedManifest}
|
||||
'';
|
||||
|
||||
system.activationScripts.generate-age-key = (mkIf cfg.generateAgeKey) (stringAfter [] ''
|
||||
if [[ ! -f "${cfg.ageKeyFile}" ]]; then;
|
||||
echo generating machine-specific age key...
|
||||
mkdir -p $(dirname ${cfg.ageKeyFile})
|
||||
# age-keygen sets 0600 by default, no need to chmod.
|
||||
${pkgs.age}/bin/age-keygen -o ${cfg.ageKeyFile}
|
||||
fi
|
||||
'');
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@ package main
|
|||
import (
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"flag"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
|
|
@ -47,6 +46,7 @@ type manifest struct {
|
|||
SymlinkPath string `json:"symlinkPath"`
|
||||
SSHKeyPaths []string `json:"sshKeyPaths"`
|
||||
GnupgHome string `json:"gnupgHome"`
|
||||
AgeKeyFile string `json:"ageKeyFile"`
|
||||
}
|
||||
|
||||
type secretFile struct {
|
||||
|
|
@ -437,10 +437,17 @@ func (app *appContext) validateManifest() error {
|
|||
if m.SymlinkPath == "" {
|
||||
m.SymlinkPath = "/run/secrets"
|
||||
}
|
||||
if len(m.SSHKeyPaths) > 0 && m.GnupgHome != "" {
|
||||
return errors.New("gnupgHome and sshKeyPaths were specified in the manifest. " +
|
||||
"Both options are mutual exclusive.")
|
||||
if m.GnupgHome != "" {
|
||||
errorFmt := "gnupgHome and %s were specified in the manifest. " +
|
||||
"Both options are mutually exclusive."
|
||||
if len(m.SSHKeyPaths) > 0 {
|
||||
return fmt.Errorf(errorFmt, "sshKeyPaths")
|
||||
}
|
||||
if m.AgeKeyFile != "" {
|
||||
return fmt.Errorf(errorFmt, "ageKeyFile")
|
||||
}
|
||||
}
|
||||
|
||||
for i := range m.Secrets {
|
||||
if err := app.validateSecret(&m.Secrets[i]); err != nil {
|
||||
return err
|
||||
|
|
@ -604,6 +611,8 @@ func installSecrets(args []string) error {
|
|||
defer keyring.Remove()
|
||||
} else if manifest.GnupgHome != "" {
|
||||
os.Setenv("GNUPGHOME", manifest.GnupgHome)
|
||||
} else if manifest.AgeKeyFile != "" {
|
||||
os.Setenv("SOPS_AGE_KEY_FILE", manifest.AgeKeyFile)
|
||||
}
|
||||
|
||||
if err := decryptSecrets(manifest.Secrets); err != nil {
|
||||
|
|
|
|||
|
|
@ -219,10 +219,44 @@ func testSSHKey(t *testing.T) {
|
|||
testInstallSecret(t, testdir, &m)
|
||||
}
|
||||
|
||||
func testAge(t *testing.T) {
|
||||
assets := testAssetPath()
|
||||
|
||||
testdir := newTestDir(t)
|
||||
defer testdir.Remove()
|
||||
|
||||
target := path.Join(testdir.path, "existing-target")
|
||||
file, err := os.Create(target)
|
||||
ok(t, err)
|
||||
file.Close()
|
||||
|
||||
s := secret{
|
||||
Name: "test",
|
||||
Key: "test_key",
|
||||
Owner: "nobody",
|
||||
Group: "nogroup",
|
||||
SopsFile: path.Join(assets, "secrets.yaml"),
|
||||
Path: target,
|
||||
Mode: "0400",
|
||||
RestartServices: []string{"affected-service"},
|
||||
ReloadServices: make([]string, 0),
|
||||
}
|
||||
|
||||
m := manifest{
|
||||
Secrets: []secret{s},
|
||||
SecretsMountPoint: testdir.secretsPath,
|
||||
SymlinkPath: testdir.symlinkPath,
|
||||
AgeKeyFile: path.Join(assets, "age-keys.txt"),
|
||||
}
|
||||
|
||||
testInstallSecret(t, testdir, &m)
|
||||
}
|
||||
|
||||
func TestAll(t *testing.T) {
|
||||
// we can't test in parallel because we rely on GNUPGHOME environment variable
|
||||
testGPG(t)
|
||||
testSSHKey(t)
|
||||
testAge(t)
|
||||
}
|
||||
|
||||
func TestValidateManifest(t *testing.T) {
|
||||
|
|
|
|||
|
|
@ -23,6 +23,26 @@
|
|||
inherit (pkgs) system;
|
||||
};
|
||||
|
||||
age-keys = makeTest {
|
||||
name = "sops-age-keys";
|
||||
machine = {
|
||||
imports = [ ../../modules/sops ];
|
||||
sops = {
|
||||
ageKeyFile = ./test-assets/age-keys.txt;
|
||||
defaultSopsFile = ./test-assets/secrets.yaml;
|
||||
secrets.test_key = {};
|
||||
};
|
||||
};
|
||||
|
||||
testScript = ''
|
||||
start_all()
|
||||
machine.succeed("cat /run/secrets/test_key | grep -q test_value")
|
||||
'';
|
||||
} {
|
||||
inherit pkgs;
|
||||
inherit (pkgs) system;
|
||||
};
|
||||
|
||||
pgp-keys = makeTest {
|
||||
name = "sops-pgp-keys";
|
||||
nodes.server = { pkgs, lib, config, ... }: {
|
||||
|
|
|
|||
3
pkgs/sops-install-secrets/test-assets/age-keys.txt
Normal file
3
pkgs/sops-install-secrets/test-assets/age-keys.txt
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
# created: 2020-07-18T03:16:47-07:00
|
||||
# public key: age1yt3tfqlfrwdwx0z0ynwplcr6qxcxfaqycuprpmy89nr83ltx74tqdpszlw
|
||||
AGE-SECRET-KEY-1NJT5YCS2LWU4V4QAJQ6R4JNU7LXPDX602DZ9NUFANVU5GDTGUWCQ5T59M6
|
||||
|
|
@ -1,47 +1,56 @@
|
|||
test_key: ENC[AES256_GCM,data:4cC2PTi7xVPZPA==,iv:voX4IQemcgt0O97oLExy5r2V85nn687cIyWmHNDhUag=,tag:ZaKi9m6ziFKNV+gx7XedTw==,type:str]
|
||||
test_key: ENC[AES256_GCM,data:6aaSGYcvIY1+lQ==,iv:voX4IQemcgt0O97oLExy5r2V85nn687cIyWmHNDhUag=,tag:/FSMgXuX8TnbxRxpcuwGEA==,type:str]
|
||||
a_list:
|
||||
- ENC[AES256_GCM,data:5K0=,iv:5P+1UQyIYOW8xXgsvTXC17msGcA6IGB3N8n+pstfqjo=,tag:Op0+iEYzV+gfYGveN3VKKg==,type:str]
|
||||
- ENC[AES256_GCM,data:9dM=,iv:LbGS8DjM6Vnr2nU7QokzQlg0gL+XMWhqbN+ypP7ZIZo=,tag:HvbERoLZcUOjEd4AwLVNEg==,type:str]
|
||||
- ENC[AES256_GCM,data:IBI=,iv:5P+1UQyIYOW8xXgsvTXC17msGcA6IGB3N8n+pstfqjo=,tag:7A4l/SgzgxK9sqi+/15A6w==,type:str]
|
||||
- ENC[AES256_GCM,data:tLE=,iv:LbGS8DjM6Vnr2nU7QokzQlg0gL+XMWhqbN+ypP7ZIZo=,tag:cmhMaddcY2bhydWrPDWNlQ==,type:str]
|
||||
sops:
|
||||
kms: []
|
||||
gcp_kms: []
|
||||
azure_kv: []
|
||||
hc_vault: []
|
||||
lastmodified: '2021-01-27T06:12:22Z'
|
||||
mac: ENC[AES256_GCM,data:/lwT78drEKdCoWW9TPU2H/IWlq/9uEmJocrTvftKTD1Au9e/7AMCUWGWMPGJKMg9R0FWV2pn3tgwli5YXRrIe4L9tIkeM5vJvz85IeQIc+vviby7PM8VtbO1ArisHh95cVwZuASR3KSbumnxURjayZ61J9Jiz0viBeuEmCP50u4=,iv:FX6XDUqetDaRTtLLfMaJAkPZmiZx59wnuDRm0SvmTJM=,tag:HnQ4dHsCCNim2v8WPXyLdw==,type:str]
|
||||
age:
|
||||
- recipient: age1yt3tfqlfrwdwx0z0ynwplcr6qxcxfaqycuprpmy89nr83ltx74tqdpszlw
|
||||
enc: |
|
||||
-----BEGIN AGE ENCRYPTED FILE-----
|
||||
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBuY2RtdnhrMEtOeEUvRmFr
|
||||
SU5uRm1xaU12R3F5TnJvbzI5YlNYMDFycGxvCnRBQVNwY2cxMDVicUNZWlpFdStp
|
||||
ZTYxcUJkNEFHVkxTbGdrdkIxN3ZMNkUKLS0tIHd2K2ZhaFVoTmlhNDBKeXZyVHBh
|
||||
ZXFnRy9hUTFNQm9rWVA3YnJXaWV0S2cKBpGxzhth36fab8KDKFBoweQO9L0juys4
|
||||
cMjz2X/hXVMLvDeCLVBTZTj3K/lXAo4v2qMUGZsR2Idpw3FOPxfSGg==
|
||||
-----END AGE ENCRYPTED FILE-----
|
||||
lastmodified: "2021-08-26T22:38:49Z"
|
||||
mac: ENC[AES256_GCM,data:1TNMF0HIfIOetCF4F268N5k2DFQ28JBYOdjPxfOuw03udJ1eKcTZrlBAGGFEgMdu1FuW+ZC+gLHW/b0GpfZWAtkiLuWP9SUof01rrFPYse6LvqWvlY1mLK6unbMveGeD9My3QTkZmt962I9tEHQW+ph35j80egGnN1f6stiJdlY=,iv:KEa/Q6q+B0F2Dv+/Km+2WeztYij0Of1pCSygGXM2fG4=,tag:TzuiTyYwTor36eGPKvTcwQ==,type:str]
|
||||
pgp:
|
||||
- created_at: '2020-07-12T08:03:51Z'
|
||||
enc: |
|
||||
- created_at: "2020-07-12T08:03:51Z"
|
||||
enc: |
|
||||
-----BEGIN PGP MESSAGE-----
|
||||
|
||||
hQEMA/m6nevQP1fAAQgAnGLEGUnWgYTLGGZN7sEETu14MJjr4TY7JDhs8VOrA9ng
|
||||
x9ivSF1dPw6arewal70OgxMLnS55HY6L81vRCbu8d0rdfXkdzO6oeMAo79/udKc8
|
||||
F5CDSkdrBImK5xpEQ0stpt1zmmKMAPGuPSbSc48YEt4OYUdpoIO+PesYUUgGerL7
|
||||
4UvXtbhYjIhZL7Sgst/coOUNUWjpQgVRSeza6qcuVfS3gVBvxNCed51n+Cr3/rnD
|
||||
5PXjeWQ8aayLDDV32CjGf+s3+LG0gvJ7A6eq0THjsvgkY4qGHNSMobkN7npFI4lX
|
||||
KZG68Scu5d11IY2N3y0ijRQQxYlPPPpukWvw3CK8htJeAZltLDHzh0bpISpc7gqU
|
||||
xzATRG/LmJk7yS9Vej/B0NGmkVlbB+lFnLZG3lVmDiaQUsgePp2Ho1/j6ysit3/C
|
||||
i87IM8B71y1brldk2mcr1oAoNSVE4dg+/C2HrDRKxA==
|
||||
=Qyuq
|
||||
hQEMA/m6nevQP1fAAQf/Zih3JJl/L/ApqkwdhIv7iUQsbebXV+WRwlslwOz6by/t
|
||||
Sf6CH3b5FHLaBQtPEUh6QNLpQSqm52Rs4MoJxML0Tan8eu6Q313lS09XP5mQP1yc
|
||||
d1FN4Tsg8V/xaGMGAtJHM/bj+6vfimGtnnQvNZ7N7PW2U+fxpq51NmqIXMmG+jOw
|
||||
2Tw+04oNoK6lrG89y0dzJrTvP9ph0wM+hwOgBthfhr0X6/UF7vS9fgEod+HFEqGn
|
||||
MfAW4CiijXDvFYI5unwseeUE8IosOaq2VTW57eBSteLWIyJqmLUxvVSoMP0emitN
|
||||
4T0DkzTxywq5KPUMIEISEZrxYEskatqlTdQBmcjEAdJcAQl/u1OGCn7YRIJbXjMP
|
||||
8/UvlFVfaT3L19sgEg8rSVpo3GiwlwbP0KTcb4jVMu0mHhd70VciNKojtDVlZg9n
|
||||
0V8Z2LwPHY0+IzcTJu5IS7sO/fuyYJohWQ4ZV7Y=
|
||||
=1olg
|
||||
-----END PGP MESSAGE-----
|
||||
fp: 7FB89715AADA920D65D25E63F9BA9DEBD03F57C0
|
||||
- created_at: '2020-07-12T08:03:51Z'
|
||||
enc: |
|
||||
fp: 7FB89715AADA920D65D25E63F9BA9DEBD03F57C0
|
||||
- created_at: "2020-07-12T08:03:51Z"
|
||||
enc: |
|
||||
-----BEGIN PGP MESSAGE-----
|
||||
|
||||
hQGMA3ulPRkZxd/UAQv/d1ExCl7gVIe0GeH8bc0xl8gt4hvR2ujH0BmmHpQ7SDLa
|
||||
tS7lH3ennlLlN+owN3DkCKqm/BNEQ7Wy5y0oTvmQSo2BdSMYOvHrLKoPK3OsDLPH
|
||||
vtXUKZ+NLKSV2xCSiqrcu4GRki8klLgDNEgna8T21erCXZM8W/ehcOd7gLSUiatd
|
||||
wQTGEhNAA0RO04kf0NoPcNrPak7e0bGbwEc88RdM2QyxSXi6SVrKVHvYVPE3pfFB
|
||||
VkUcWZU2edLUEKIAFRAtmb9s3DSjECMMuoVXR6lrPx4c6OMRKvxtlZh0uOOcRpoG
|
||||
M5KL8O4ZXNxUVNRzPisgqe0hkh2AsnMLIQeWrVLfOLXUdDjr9x42vga/P8WU7AzT
|
||||
/Lxmlu9cY0KKsXpv7yXibZfFJ/K/4Mo9WsNk6tGAmiSUg1hr/NJPha3PDHyX0ER7
|
||||
6dPFeMrvs4VngC0I27v6rlEjU+HiRv3/uLnn04z9DRQEk6a+YpLZTpHvAbzfb1Dg
|
||||
EBpKCQePm2rIzywLE8d60lABXSQKG4/LSH6WgxfRFibORME2z5DD2G7ibiDbVg8j
|
||||
YbrH0E0KeRxYJMJ28FVDlLgoUL+JbNr70uHkdvz8S0hqCYwo+K4KqUOIsiPc6iIL
|
||||
tA==
|
||||
=XoKf
|
||||
hQGMA3ulPRkZxd/UAQv+LSFG7a6XqqW7GYdYLb1H0bv3NkxJeBYGohsMrEC4AXnA
|
||||
RdhJ2B55WqiNyDmVmylalUKAPFpD7RJ4c6HDZcRLx6doy5wgA+oFvKCe8FcYy5YS
|
||||
abSUhNoT0TwWlDQ4Bc4Q/QSu9kMCica56Bc10tz5Pvb5JEYApoLfL0kTO7mBI+w4
|
||||
hKovAxlp9aoT9cky/7WFhmFn1+mYz//ejDKPuyVSYhM/2eIosDE9maPootLQMrIX
|
||||
cqnsCDCOgMDwIOXt5/W4Cab799Pop4SQcFDSDa4FU4kN12vmNwJu7HPxpR+W80bL
|
||||
GOUu35gVyykig9XCaTA/UCc85URtOMYmXPBsdTVoMVAgfxkji3ovJCEFBcI7wYgd
|
||||
XudLQw5tJ9Pwz+5EeNw771ISaTBO7bWazSq+q3HrKW9kKLFJV4kVt7zLr+yZ1kNu
|
||||
jEjTFmaKYl3p9AYh6yxb6n9PuTosk1ZJE8gv8ME+b4z21BVxfZsDfYWVhT9thZz5
|
||||
q2LHw+E/fmf0EXz9tviS0k4BimrDWSnYNyuDqTImB+v7baY0rEoYhQY2ZLAbUsew
|
||||
wg+KC2RjkapaZ7CFbCMs7xaWzZ5p/nfWOtsb1GvmvCUZcHK5MYeVM5S+Xf0GnYg=
|
||||
=7cg6
|
||||
-----END PGP MESSAGE-----
|
||||
fp: 2504791468B153B8A3963CC97BA53D1919C5DFD4
|
||||
fp: 2504791468B153B8A3963CC97BA53D1919C5DFD4
|
||||
unencrypted_suffix: _unencrypted
|
||||
version: 3.6.1
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue