From 262a22293c8b3c84b75038e7997d8f10008cb2a1 Mon Sep 17 00:00:00 2001 From: vdbewout Date: Fri, 2 Feb 2024 13:33:51 +0100 Subject: [PATCH 1/4] feat(shadowing): golang --- pkgs/sops-install-secrets/main.go | 115 +++++++++++++++---------- pkgs/sops-install-secrets/main_test.go | 18 ++-- 2 files changed, 77 insertions(+), 56 deletions(-) diff --git a/pkgs/sops-install-secrets/main.go b/pkgs/sops-install-secrets/main.go index 911fcb49..f8cdbbe9 100644 --- a/pkgs/sops-install-secrets/main.go +++ b/pkgs/sops-install-secrets/main.go @@ -29,7 +29,7 @@ type secret struct { Path string `json:"path"` Owner string `json:"owner"` Group string `json:"group"` - SopsFile string `json:"sopsFile"` + SopsFiles []string `json:"sopsFiles"` Format FormatType `json:"format"` Mode string `json:"mode"` RestartUnits []string `json:"restartUnits"` @@ -258,40 +258,47 @@ func recurseSecretKey(keys map[string]interface{}, wantedKey string) (string, er } func decryptSecret(s *secret, sourceFiles map[string]plainData) error { - sourceFile := sourceFiles[s.SopsFile] - if sourceFile.data == nil || sourceFile.binary == nil { - plain, err := decrypt.File(s.SopsFile, string(s.Format)) - if err != nil { - return fmt.Errorf("Failed to decrypt '%s': %w", s.SopsFile, err) - } + for i := len(s.SopsFiles) - 1; i >= 0; i-- { + sourceFile := sourceFiles[s.SopsFiles[i]] + if sourceFile.data == nil || sourceFile.binary == nil { + plain, err := decrypt.File(s.SopsFiles[i], string(s.Format)) + if err != nil { + return fmt.Errorf("Failed to decrypt '%s': %w", s.SopsFiles[i], err) + } + switch s.Format { + case Binary, Dotenv, Ini: + sourceFile.binary = plain + case Yaml: + if err := yaml.Unmarshal(plain, &sourceFile.data); err != nil { + return fmt.Errorf("Cannot parse yaml of '%s': %w", s.SopsFiles[i], err) + } + case Json: + if err := json.Unmarshal(plain, &sourceFile.data); err != nil { + return fmt.Errorf("Cannot parse json of '%s': %w", s.SopsFiles[i], err) + } + default: + return fmt.Errorf("Secret of type %s in %s is not supported", s.Format, s.SopsFiles[i]) + } + } switch s.Format { case Binary, Dotenv, Ini: - sourceFile.binary = plain - case Yaml: - if err := yaml.Unmarshal(plain, &sourceFile.data); err != nil { - return fmt.Errorf("Cannot parse yaml of '%s': %w", s.SopsFile, err) - } - case Json: - if err := json.Unmarshal(plain, &sourceFile.data); err != nil { - return fmt.Errorf("Cannot parse json of '%s': %w", s.SopsFile, err) + s.value = sourceFile.binary + case Yaml, Json: + strVal, err := recurseSecretKey(sourceFile.data, s.Key) + if err != nil { + continue } - default: - return fmt.Errorf("Secret of type %s in %s is not supported", s.Format, s.SopsFile) - } - } - switch s.Format { - case Binary, Dotenv, Ini: - s.value = sourceFile.binary - case Yaml, Json: - strVal, err := recurseSecretKey(sourceFile.data, s.Key) - if err != nil { - return fmt.Errorf("secret %s in %s is not valid: %w", s.Name, s.SopsFile, err) + s.value = []byte(strVal) } - s.value = []byte(strVal) + + sourceFiles[s.SopsFiles[i]] = sourceFile + // Secret found + return nil } - sourceFiles[s.SopsFile] = sourceFile - return nil + + // Secret not found in any of the SopsFiles + return fmt.Errorf("secret %s in %v is not valid", s.Name, s.SopsFiles) } func decryptSecrets(secrets []secret) error { @@ -395,14 +402,14 @@ func lookupKeysGroup() (int, error) { return 0, fmt.Errorf("Can't find group 'keys' nor 'nogroup' (%w).", err2) } -func (app *appContext) loadSopsFile(s *secret) (*secretFile, error) { +func (app *appContext) loadSopsFile(s *secret, sopsFile *string) (*secretFile, error) { if app.checkMode == Manifest { return &secretFile{firstSecret: s}, nil } - cipherText, err := os.ReadFile(s.SopsFile) + cipherText, err := os.ReadFile(*sopsFile) if err != nil { - return nil, fmt.Errorf("Failed reading %s: %w", s.SopsFile, err) + return nil, fmt.Errorf("Failed reading %s: %w", SopsFile, err) } var keys map[string]interface{} @@ -410,17 +417,17 @@ func (app *appContext) loadSopsFile(s *secret) (*secretFile, error) { switch s.Format { case Binary: if err := json.Unmarshal(cipherText, &keys); err != nil { - return nil, fmt.Errorf("Cannot parse json of '%s': %w", s.SopsFile, err) + return nil, fmt.Errorf("Cannot parse json of '%s': %w", *sopsFile, err) } return &secretFile{cipherText: cipherText, firstSecret: s}, nil case Yaml: if err := yaml.Unmarshal(cipherText, &keys); err != nil { - return nil, fmt.Errorf("Cannot parse yaml of '%s': %w", s.SopsFile, err) + return nil, fmt.Errorf("Cannot parse yaml of '%s': %w", *sopsFile, err) } case Dotenv: env, err := godotenv.Unmarshal(string(cipherText)) if err != nil { - return nil, fmt.Errorf("Cannot parse dotenv of '%s': %w", s.SopsFile, err) + return nil, fmt.Errorf("Cannot parse dotenv of '%s': %w", *sopsFile, err) } keys = map[string]interface{}{} for k, v := range env { @@ -428,7 +435,7 @@ func (app *appContext) loadSopsFile(s *secret) (*secretFile, error) { } case Json: if err := json.Unmarshal(cipherText, &keys); err != nil { - return nil, fmt.Errorf("Cannot parse json of '%s': %w", s.SopsFile, err) + return nil, fmt.Errorf("Cannot parse json of '%s': %w", *sopsFile, err) } } @@ -441,14 +448,14 @@ func (app *appContext) loadSopsFile(s *secret) (*secretFile, error) { func (app *appContext) validateSopsFile(s *secret, file *secretFile) error { if file.firstSecret.Format != s.Format { - return fmt.Errorf("secret %s defined the format of %s as %s, but it was specified as %s in %s before", - s.Name, s.SopsFile, s.Format, + return fmt.Errorf("secret %s defined the format of %v as %s, but it was specified as %s in %s before", + s.Name, s.SopsFiles, s.Format, file.firstSecret.Format, file.firstSecret.Name) } if app.checkMode != Manifest && (!(s.Format == Binary || s.Format == Dotenv || s.Format == Ini)) { _, err := recurseSecretKey(file.keys, s.Key) if err != nil { - return fmt.Errorf("secret %s in %s is not valid: %w", s.Name, s.SopsFile, err) + return fmt.Errorf("secret %s in %s is not valid: %v", s.Name, s.SopsFiles, err) } } return nil @@ -495,17 +502,31 @@ func (app *appContext) validateSecret(secret *secret) error { return fmt.Errorf("Unsupported format %s for secret %s", secret.Format, secret.Name) } - file, ok := app.secretFiles[secret.SopsFile] - if !ok { - maybeFile, err := app.loadSopsFile(secret) - if err != nil { - return err + files := []secretFile{} + for _, sopsFile := range secret.SopsFiles { + file, ok := app.secretFiles[sopsFile] + if !ok { + maybeFile, err := app.loadSopsFile(secret, &sopsFile) + if err != nil { + return err + } + app.secretFiles[sopsFile] = *maybeFile + file = *maybeFile } - app.secretFiles[secret.SopsFile] = *maybeFile - file = *maybeFile + files = append(files, file) } - return app.validateSopsFile(secret, &file) + for i := len(files) - 1; i >= 0; i-- { + err := app.validateSopsFile(secret, &files[i]) + if err == nil { + // Found valid sopsFile + break + } else if i == 0 { + // No valid sopsFile found in sopsFiles + return fmt.Errorf("Failed to find valid secret %s in %v", secret.Name, secret.SopsFiles) + } + } + return nil } func (app *appContext) validateManifest() error { diff --git a/pkgs/sops-install-secrets/main_test.go b/pkgs/sops-install-secrets/main_test.go index 7c4ef927..f61cba01 100644 --- a/pkgs/sops-install-secrets/main_test.go +++ b/pkgs/sops-install-secrets/main_test.go @@ -104,7 +104,7 @@ func testGPG(t *testing.T) { Key: "test_key", Owner: "nobody", Group: "nogroup", - SopsFile: path.Join(assets, "secrets.yaml"), + SopsFiles: []string{path.Join(assets, "secrets.yaml")}, Path: path.Join(testdir.path, "test-target"), Mode: "0400", RestartUnits: []string{"affected-service"}, @@ -118,14 +118,14 @@ func testGPG(t *testing.T) { jsonSecret.Owner = "root" jsonSecret.Format = "json" jsonSecret.Group = "root" - jsonSecret.SopsFile = path.Join(assets, "secrets.json") + jsonSecret.SopsFiles = []string{path.Join(assets, "secrets.json")} jsonSecret.Path = path.Join(testdir.secretsPath, "test2") jsonSecret.Mode = "0700" binarySecret = yamlSecret binarySecret.Name = "test3" binarySecret.Format = "binary" - binarySecret.SopsFile = path.Join(assets, "secrets.bin") + binarySecret.SopsFiles = []string{path.Join(assets, "secrets.bin")} binarySecret.Path = path.Join(testdir.secretsPath, "test3") dotenvSecret = yamlSecret @@ -133,7 +133,7 @@ func testGPG(t *testing.T) { dotenvSecret.Owner = "root" dotenvSecret.Group = "root" dotenvSecret.Format = "dotenv" - dotenvSecret.SopsFile = path.Join(assets, "secrets.env") + dotenvSecret.SopsFiles = []string{path.Join(assets, "secrets.env")} dotenvSecret.Path = path.Join(testdir.secretsPath, "test4") iniSecret = yamlSecret @@ -141,7 +141,7 @@ func testGPG(t *testing.T) { iniSecret.Owner = "root" iniSecret.Group = "root" iniSecret.Format = "ini" - iniSecret.SopsFile = path.Join(assets, "secrets.ini") + iniSecret.SopsFiles = []string{path.Join(assets, "secrets.ini")} iniSecret.Path = path.Join(testdir.secretsPath, "test5") manifest := manifest{ @@ -219,7 +219,7 @@ func testSSHKey(t *testing.T) { Key: "test_key", Owner: "nobody", Group: "nogroup", - SopsFile: path.Join(assets, "secrets.yaml"), + SopsFiles: []string{path.Join(assets, "secrets.yaml")}, Path: target, Mode: "0400", RestartUnits: []string{"affected-service"}, @@ -252,7 +252,7 @@ func TestAge(t *testing.T) { Key: "test_key", Owner: "nobody", Group: "nogroup", - SopsFile: path.Join(assets, "secrets.yaml"), + SopsFiles: []string{path.Join(assets, "secrets.yaml")}, Path: target, Mode: "0400", RestartUnits: []string{"affected-service"}, @@ -285,7 +285,7 @@ func TestAgeWithSSH(t *testing.T) { Key: "test_key", Owner: "nobody", Group: "nogroup", - SopsFile: path.Join(assets, "secrets.yaml"), + SopsFiles: []string{path.Join(assets, "secrets.yaml")}, Path: target, Mode: "0400", RestartUnits: []string{"affected-service"}, @@ -319,7 +319,7 @@ func TestValidateManifest(t *testing.T) { Key: "test_key", Owner: "nobody", Group: "nogroup", - SopsFile: path.Join(assets, "secrets.yaml"), + SopsFiles: []string{path.Join(assets, "secrets.yaml")}, Path: path.Join(testdir.path, "test-target"), Mode: "0400", RestartUnits: []string{}, From 8ee9a71f92459c7b24a766f187c82082fa0c9def Mon Sep 17 00:00:00 2001 From: vdbewout Date: Fri, 2 Feb 2024 13:35:14 +0100 Subject: [PATCH 2/4] feat(shadowing): nixos module --- modules/sops/default.nix | 69 ++++++++++++++++++++++++++++------------ 1 file changed, 48 insertions(+), 21 deletions(-) diff --git a/modules/sops/default.nix b/modules/sops/default.nix index a3f1c965..a1882bab 100644 --- a/modules/sops/default.nix +++ b/modules/sops/default.nix @@ -7,13 +7,18 @@ let users = config.users.users; sops-install-secrets = cfg.package; sops-install-secrets-check = cfg.validationPackage; - regularSecrets = lib.filterAttrs (_: v: !v.neededForUsers) cfg.secrets; - secretsForUsers = lib.filterAttrs (_: v: v.neededForUsers) cfg.secrets; - secretType = types.submodule ({ config, ... }: { - config = { - sopsFile = lib.mkOptionDefault cfg.defaultSopsFile; - sopsFileHash = mkOptionDefault (optionalString cfg.validateSopsFiles "${builtins.hashFile "sha256" config.sopsFile}"); - }; + secrets = mapAttrs (_: secret: removeAttrs secret ["sopsFile"]) cfg.secrets; + regularSecrets = lib.filterAttrs (_: v: !v.neededForUsers) secrets; + secretsForUsers = lib.filterAttrs (_: v: v.neededForUsers) secrets; + secretType = types.submodule ({ config, options, ... }: { + config = mkMerge [{ + sopsFile = mkOptionDefault cfg.defaultSopsFile; + sopsFiles = mkIf (length cfg.defaultSopsFiles > 0) (mkOptionDefault cfg.defaultSopsFiles); + sopsFilesHash = mkOptionDefault (optionals cfg.validateSopsFiles (forEach config.sopsFiles (builtins.hashFile "sha256"))); + } + { + sopsFiles = mkIf (config.sopsFile != null) (mkOverride options.sopsFile.highestPrio (mkBefore [config.sopsFile])); + }]; options = { name = mkOption { type = types.str; @@ -71,17 +76,24 @@ let ''; }; sopsFile = mkOption { - type = types.path; + type = types.nullOr types.path; defaultText = "\${config.sops.defaultSopsFile}"; description = '' Sops file the secret is loaded from. ''; }; - sopsFileHash = mkOption { - type = types.str; + sopsFiles = mkOption { + type = types.nonEmptyListOf types.path; + defaultText = "\${config.sops.defaultSopsFiles}"; + description = '' + Sops files the secret is loaded from. + ''; + }; + sopsFilesHash = mkOption { + type = types.nonEmptyListOf types.str; readOnly = true; description = '' - Hash of the sops file, useful in . + Hash of the sops files, useful in . ''; }; restartUnits = mkOption { @@ -167,12 +179,21 @@ in { }; defaultSopsFile = mkOption { - type = types.path; + type = types.nullOr types.path; + default = null; description = '' Default sops file used for all secrets. ''; }; + defaultSopsFiles = mkOption { + type = types.listOf types.path; + default = []; + description = '' + Default sops files used for all secrets. + ''; + }; + defaultSopsFormat = mkOption { type = types.str; default = "yaml"; @@ -331,17 +352,23 @@ in { assertion = (filterAttrs (_: v: v.owner != "root" || v.group != "root") secretsForUsers) == {}; message = "neededForUsers cannot be used for secrets that are not root-owned"; }] ++ optionals cfg.validateSopsFiles ( - concatLists (mapAttrsToList (name: secret: [{ - assertion = builtins.pathExists secret.sopsFile; - message = "Cannot find path '${secret.sopsFile}' set in sops.secrets.${strings.escapeNixIdentifier name}.sopsFile"; - } { - assertion = - builtins.isPath secret.sopsFile || - (builtins.isString secret.sopsFile && hasPrefix builtins.storeDir secret.sopsFile); - message = "'${secret.sopsFile}' is not in the Nix store. Either add it to the Nix store or set sops.validateSopsFiles to false"; - }]) cfg.secrets) + concatLists (mapAttrsToList + (name: secret: + concatMap + (sopsFile: [{ + assertion = builtins.pathExists sopsFile; + message = "Cannot find path '${sopsFile}' set in sops.secrets.${strings.escapeNixIdentifier name}.sopsFiles"; + } { + assertion = + builtins.isPath sopsFile || + (builtins.isString sopsFile && hasPrefix builtins.storeDir sopsFile); + message = "'${sopsFile}' is not in the Nix store. Either add it to the Nix store or set sops.validateSopsFiles to false"; + }]) + secret.sopsFiles) + cfg.secrets) ); + sops.environment.SOPS_GPG_EXEC = mkIf (cfg.gnupg.home != null) (mkDefault "${pkgs.gnupg}/bin/gpg"); system.activationScripts = { From 0068d615cafbc5539eccb7ffb7420b9e0ef55a97 Mon Sep 17 00:00:00 2001 From: vdbewout Date: Fri, 2 Feb 2024 13:36:00 +0100 Subject: [PATCH 3/4] feat(shadowing): home manager module --- modules/home-manager/sops.nix | 52 +++++++++++++++++++++++++++-------- 1 file changed, 40 insertions(+), 12 deletions(-) diff --git a/modules/home-manager/sops.nix b/modules/home-manager/sops.nix index a063bc61..3dd47569 100644 --- a/modules/home-manager/sops.nix +++ b/modules/home-manager/sops.nix @@ -3,7 +3,14 @@ let cfg = config.sops; sops-install-secrets = (pkgs.callPackage ../.. {}).sops-install-secrets; - secretType = lib.types.submodule ({ config, name, ... }: { + secretType = lib.types.submodule ({ config, options, name, ... }: { + config = lib.mkMerge[{ + sopsFile = lib.mkOptionDefault cfg.defaultSopsFile; + sopsFiles = lib.mkIf (lib.length cfg.defaultSopsFiles > 0) (lib.mkOptionDefault cfg.defaultSopsFiles); + } + { + sopsFiles = lib.mkIf (config.sopsFile != null) ( lib.mkOverride options.sopsFile.highestPrio (lib.mkBefore [config.sopsFile])); + }]; options = { name = lib.mkOption { type = lib.types.str; @@ -53,12 +60,19 @@ let sopsFile = lib.mkOption { type = lib.types.path; - default = cfg.defaultSopsFile; defaultText = "\${config.sops.defaultSopsFile}"; description = '' Sops file the secret is loaded from. ''; }; + + sopsFiles = lib.mkOption { + type = lib.types.nonEmptyListOf lib.types.path; + defaultText = "\${config.sops.defaultSopsFiles}"; + description = '' + Sops files the secret is loaded from. + ''; + }; }; }); @@ -110,12 +124,21 @@ in { }; defaultSopsFile = lib.mkOption { - type = lib.types.path; + type = lib.types.nullOr lib.types.path; + default = null; description = '' Default sops file used for all secrets. ''; }; + defaultSopsFiles = lib.mkOption { + type = lib.types.listOf lib.types.path; + default = []; + description = '' + Default sops files used for all secrets. + ''; + }; + defaultSopsFormat = lib.mkOption { type = lib.types.str; default = "yaml"; @@ -222,15 +245,20 @@ in { assertion = !(cfg.gnupg.home != null && cfg.gnupg.sshKeyPaths != []); message = "Exactly one of sops.gnupg.home and sops.gnupg.sshKeyPaths must be set"; }] ++ lib.optionals cfg.validateSopsFiles ( - lib.concatLists (lib.mapAttrsToList (name: secret: [{ - assertion = builtins.pathExists secret.sopsFile; - message = "Cannot find path '${secret.sopsFile}' set in sops.secrets.${lib.strings.escapeNixIdentifier name}.sopsFile"; - } { - assertion = - builtins.isPath secret.sopsFile || - (builtins.isString secret.sopsFile && lib.hasPrefix builtins.storeDir secret.sopsFile); - message = "'${secret.sopsFile}' is not in the Nix store. Either add it to the Nix store or set sops.validateSopsFiles to false"; - }]) cfg.secrets) + lib.concatLists (lib.mapAttrsToList + (name: secret: + lib.concatMap + (sopsFile: [{ + assertion = builtins.pathExists sopsFile; + message = "Cannot find path '${sopsFile}' set in sops.secrets.${lib.strings.escapeNixIdentifier name}.sopsFiles"; + } { + assertion = + builtins.isPath sopsFile || + (builtins.isString sopsFile && lib.hasPrefix builtins.storeDir sopsFile); + message = "'${sopsFile}' is not in the Nix store. Either add it to the Nix store or set sops.validateSopsFiles to false"; + }]) + secret.sopsFiles) + cfg.secrets) ); systemd.user.services.sops-nix = lib.mkIf pkgs.stdenv.hostPlatform.isLinux { From c6233857ac1f096f139ca335c003efbda6087311 Mon Sep 17 00:00:00 2001 From: vdbewout Date: Fri, 2 Feb 2024 13:37:29 +0100 Subject: [PATCH 4/4] test(shadowing): sops-install-secrets --- pkgs/sops-install-secrets/nixos-test.nix | 71 +++++++++++++++++++ .../test-assets/secrets-system.yaml | 64 +++++++++++++++++ .../test-assets/secrets-user.yaml | 65 +++++++++++++++++ 3 files changed, 200 insertions(+) create mode 100644 pkgs/sops-install-secrets/test-assets/secrets-system.yaml create mode 100644 pkgs/sops-install-secrets/test-assets/secrets-user.yaml diff --git a/pkgs/sops-install-secrets/nixos-test.nix b/pkgs/sops-install-secrets/nixos-test.nix index 487074ef..8f29dd60 100644 --- a/pkgs/sops-install-secrets/nixos-test.nix +++ b/pkgs/sops-install-secrets/nixos-test.nix @@ -377,4 +377,75 @@ inherit pkgs; inherit (pkgs) system; }; + + sops-files-shadowing = makeTest { + name = "sops-files-shadowing"; + nodes.machine = {lib,...}: + let + inherit (lib.lists) reverseList; + inherit (lib.modules) mkDefault; + + sopsFile = ./test-assets/secrets.yaml; + systemSopsFile = ./test-assets/secrets-system.yaml; + userSopsFile = ./test-assets/secrets-user.yaml; + + sopsFiles = [ sopsFile ]; + systemSopsFiles = sopsFiles ++ [ systemSopsFile ]; + userSopsFiles = systemSopsFiles ++ [ userSopsFile ]; + + mkSecretConfig = key: sopsFiles: { inherit key sopsFiles; }; + in { + imports = [ ../../modules/sops ]; + sops = { + age.keyFile = ./test-assets/age-keys.txt; + defaultSopsFile = sopsFile; + + secrets.test_key = {}; + secrets.test_key_system = mkSecretConfig "test_key" systemSopsFiles; + secrets.test_key_user = mkSecretConfig "test_key" userSopsFiles; + + secrets.test_key2_system = mkSecretConfig "test_key2" systemSopsFiles; + secrets.test_key2_user = mkSecretConfig "test_key2" userSopsFiles; + + secrets.test_key3_user = mkSecretConfig "test_key3" userSopsFiles; + + secrets.test_key3_user_reverse = mkSecretConfig "test_key3" (reverseList userSopsFiles); + secrets.test_key2_user_reverse = mkSecretConfig "test_key2" (reverseList userSopsFiles); + secrets.test_key_user_reverse = mkSecretConfig "test_key" (reverseList userSopsFiles); + + secrets.priority_file = { + key = "test_key"; + sopsFile = systemSopsFile; + sopsFiles = mkDefault userSopsFiles; + }; + secrets.priority_same = { + inherit sopsFile; + key = "nested/test/file"; + sopsFiles = [ systemSopsFile userSopsFile ]; + }; + }; + }; + + testScript = '' + start_all() + machine.succeed("cat /run/secrets/test_key | grep -qw test_value") + machine.succeed("cat /run/secrets/test_key_system | grep -qw test_value_system") + machine.succeed("cat /run/secrets/test_key_user | grep -qw test_value_user") + + machine.succeed("cat /run/secrets/test_key2_system | grep -qw test_value2_system") + machine.succeed("cat /run/secrets/test_key2_user | grep -qw test_value2_user") + + machine.succeed("cat /run/secrets/test_key3_user | grep -qw test_value3_user") + + machine.succeed("cat /run/secrets/test_key3_user_reverse | grep -qw test_value3_user") + machine.succeed("cat /run/secrets/test_key2_user_reverse | grep -qw test_value2_system") + machine.succeed("cat /run/secrets/test_key_user_reverse | grep -qw test_value") + + machine.succeed("cat /run/secrets/priority_file | grep -qw test_value_system") + machine.succeed("cat /run/secrets/priority_same | grep -qw 'another value'") + ''; + } { + inherit pkgs; + inherit (pkgs) system; + }; } diff --git a/pkgs/sops-install-secrets/test-assets/secrets-system.yaml b/pkgs/sops-install-secrets/test-assets/secrets-system.yaml new file mode 100644 index 00000000..09329b39 --- /dev/null +++ b/pkgs/sops-install-secrets/test-assets/secrets-system.yaml @@ -0,0 +1,64 @@ +test_key: ENC[AES256_GCM,data:nKT/4vbkpyYUS18rJ4na1pk=,iv:1VwaqxGdrUlquA6pr1yQV4wnq1FPlEhilK9FGPFs8SM=,tag:HUxe8+MUpyQUXuIwR3dxIQ==,type:str] +test_key2: ENC[AES256_GCM,data:IZ3XrdhsMKSAeRBxm1kiHSd+,iv:XGEBYa++pwrp3zQNGFDp7mSpQzZDEYC1oLEJOCnT5Bs=,tag:VuEURKlDst5aKTqmnPksog==,type:str] +sops: + kms: [] + gcp_kms: [] + azure_kv: [] + hc_vault: [] + age: + - recipient: age1yt3tfqlfrwdwx0z0ynwplcr6qxcxfaqycuprpmy89nr83ltx74tqdpszlw + enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBQaGJ0ZlFUMXNNSkRYeitS + TVkvU1RacHJIYzdMT1AxaldVRnNIMVVxb1hZCnFOclVlMEdJUDJWMDhaejRkU3hq + Y0tObnZYYnhidTB2Z2p0amhUaTZGeHMKLS0tIERDU3pKb1FwZk44bXBualhnS0Z5 + eWlUdXhCZGM2dzcxNEY0MTBwN3prTDgK9Sgzw8IuSnBBLS9cNlh6UnzTraxgrQe6 + qo+34EQln2Kty7Ot+8TnYo1X+8xRn3VTsQw8+iVdcr28DI0ltMcFtQ== + -----END AGE ENCRYPTED FILE----- + - recipient: age1a8pk4akrdamj7nvqy3zywgtny8dxz7t5xzu7u8v9mhrayp9freqsqatyrs + enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBWVkFidnFPQ0toY0RPeFZN + eCsxSUxlU05LUXJYVWVBb3NTblhKVExsNzN3CjkyWlJFaXE3N1RiaEJ1RjdtZncv + cERvdi9kQ3FYY2l3NmF4SUVzYlJxYUEKLS0tIFNSUzhkV0tDYWFjVUprczVCTS9Y + c3poQXZhSzZvVTY2YmdEVVVaUHVxTVkK7Y/YTczA/T5EmLJNjGkL6bh0eI0xH7aH + sjOdnuQG2vioHBYnsqWmmn0bUvY7y3q0h6y+gMDfmzYIgh6B2spUrA== + -----END AGE ENCRYPTED FILE----- + lastmodified: "2023-11-12T16:37:17Z" + mac: ENC[AES256_GCM,data:igpv/Z/VWq53sh3A+LqUl8jPOZumm3/0yaj7Tco9nAqzwJ7v/QNgUiCZlFe2tUZXXE/0kH+C990aRU8QqKR0uJJ86Jz0jyRTdHYEqPtWUabAg9kofAsU1tr+qTRJ1dfuYJ+BukF0tLNwFce00th+RRJzCjBncSHnP4go7rELyr0=,iv:reqRxtuXt/wOhDVHoYcjOpmhpTqFzMpqh8C0ZVKTwUI=,tag:F2irgrIq61xXhs4v5Y4img==,type:str] + pgp: + - created_at: "2023-11-12T16:37:09Z" + enc: | + -----BEGIN PGP MESSAGE----- + + hQEMA/m6nevQP1fAAQf9HVmJtTe34ameXLpIKgHvUmMLFzarqCTpFx1h4WZo+0Nk + 3eHw572Mm0npG5/uRqbff6fdb433dNlJXLF/O3ZFLk30+6cKsWbcDXAlrCC6fug7 + UJh3SJ+Vrp+fsPQXF+2JIkz7ktRZAJ1ktKOKh8P6UjJcrVVG0QH/2gx2wjx+0TBZ + Jem+zF+2TSvj/VQPcdfi4eBisyDGUopiSgLlvENNK6h3pStVWqQTMmMVEZw6SGvW + OwqgydTzzgsLsrZOr4RMNd0KOwhFtHZ758OMePoxdmhDMS/n06fia5TlajTidMOT + H5vosuHh3EuEyl+dKX/N2HwYToADCV+MIdMBN3n8JNJeAVJUp1Kxyh0MlMgUm/vk + g83FuYZ8u3F8MaCzk/+XlJUst0iraxPyO0DQpTuYRmtZ1seVAEidWsDmoDzqxq29 + S4GigtxlDcAFhzSMuteLjhWPXO5CHOc+h9tPFqAUCQ== + =bj6u + -----END PGP MESSAGE----- + fp: 7FB89715AADA920D65D25E63F9BA9DEBD03F57C0 + - created_at: "2023-11-12T16:37:09Z" + enc: | + -----BEGIN PGP MESSAGE----- + + hQGMA3ulPRkZxd/UAQwAqqwRqq/9n06pkZQ1TXS/4Y9s5QdoMOOYrlMwGXNIkieR + 6u6qAmJhwsEBWp03gfggFnsfAnKH7zXGdNhWumLkWMvX6DldHkv+4jG/mWOqaNUw + wnkJXNpNoff79DIpZlYZkeTLyFU+02wvbSN56WJCXUCzu+07snT8mCFVRRu6+JJH + v3AD+7K/AWsL3NeL8/eijKuse2nMyWfkSQO77lNS65rI+HAEPkPr+AcYmc0qsvk1 + nt+f/UwuLzdsx0wiJ/qoO23vpUGekA6f4Pl5sJX2vfIoroet6h/SlMEBFfgN+9uE + kHJvd31p5OWhSxGe1s+gYNpJqkRJlevcZhMw7GRY5wrlxSz+KjUysudSklAdBiDA + C2XvU9GrxKAvWLNZpmPLJgJSeEFdT3GaG0uZdkqXL3ERN+5i4xonLrmipJabLP2r + X2y4lHwTPqnJAAtzkajNbkJECl9HjXimQKIue3Adxdks48b87yn9r4jEFl5Q3jzi + 7PJRGSXxXh7IYug9oK8j0lgBR73bXlKg6NoRb60Qf+fNr1C+2/u9/oZHtMVkL9DC + GQgYMcNl/iaXwtMKrXRpXdybJiUaEVDUj1IniOKslkA+SXqYPT/GEgzsZg7N1iNj + T8HB88mqIowz + =+4j5 + -----END PGP MESSAGE----- + fp: 2504791468B153B8A3963CC97BA53D1919C5DFD4 + unencrypted_suffix: _unencrypted + version: 3.7.3 diff --git a/pkgs/sops-install-secrets/test-assets/secrets-user.yaml b/pkgs/sops-install-secrets/test-assets/secrets-user.yaml new file mode 100644 index 00000000..2a24e773 --- /dev/null +++ b/pkgs/sops-install-secrets/test-assets/secrets-user.yaml @@ -0,0 +1,65 @@ +test_key: ENC[AES256_GCM,data:JZ2xgV5SWgDZavBCIcH+,iv:kl6h4EJbivo1wVHqzM8W0vHyf4U+qEYoqH6JXIgYdTw=,tag:z0roNXcgF+dGvv4MMAO2Rw==,type:str] +test_key2: ENC[AES256_GCM,data:E43CtluUaO4EzvWrrbwIWA==,iv:AI3togB1kiYo3VEjEwNyWCWb7XC1nooN3vDj/K9wuNc=,tag:7OYaY/Htw95akdr1klYFWg==,type:str] +test_key3: ENC[AES256_GCM,data:vWP0CpCR6Mh2mcTJBsQmBA==,iv:9iZHc5m89AmfWLKGqw6RHA+M51wclGqcZzVur7ZDk5k=,tag:yfdfW7VS3eptl/YRqn61mg==,type:str] +sops: + kms: [] + gcp_kms: [] + azure_kv: [] + hc_vault: [] + age: + - recipient: age1yt3tfqlfrwdwx0z0ynwplcr6qxcxfaqycuprpmy89nr83ltx74tqdpszlw + enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBINGZkWG9TNkk3cTdvc2hh + NFNpbG11TnZjZHRZdFczSTZSRElGcHhkeFZ3CldjMXpjMFdOd1JzemFONmkya2pv + ZGlGN25DZVFpSG9waTkydjJXSUJFRjAKLS0tIFZWblk2cmtRWEdUYXo4REROTVpW + V0M4MjBaYTBrTCtSVXRtNGh0bzNaREUKsbZ9EK24APYCCC63qbI4YsJmkNFH/j88 + ROwRAXFqm0SZcwqUU6TbK9ulyyfE9dsWZ8a6Zb3iDFlFVBuEd5Yb7w== + -----END AGE ENCRYPTED FILE----- + - recipient: age1a8pk4akrdamj7nvqy3zywgtny8dxz7t5xzu7u8v9mhrayp9freqsqatyrs + enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBaaXVQeVlFU0trMGROZEdp + Y2xJNzJzWGNFcEtVS1R4ODBIWWk5dkFEeDBVCktrWkFlUkI3eksyVWRmNTcxRWpU + YllzU1NwNHZHWk9oU2FabFFSRnJuY0UKLS0tIDBaUjVaak5qUGNlRHVpSi9HTEFW + OFdHYSsyNGcvSG91dGxFdk1NYmVRSkkKEEqXuDN7gFKwUDY6O9EMbhEzGIY/BfGU + SM435jTAcR76tq10HbgYgBQ2ef2vvUmvkVzHGQV9LsTxMT+11oFSHw== + -----END AGE ENCRYPTED FILE----- + lastmodified: "2023-11-12T16:44:49Z" + mac: ENC[AES256_GCM,data:auu+8Cs8qRX5OEfCSO0m5U9rEdgKYBWninSVu0H1+VDtGOxjOPhVjAJgIa9wHGbrhp7LoDFymgiGGzbG3H4B/gZAFEhoyYn8VfJOHouT12M6kijtBUAhSqL5csbTMfiZmganvKPYN6PXg7hX2MyjJlFAGLc/Ixte61fKGoExqgA=,iv:P1uCpCO+nqS+dUXhxCcYd/2q0PHVUfbGvYm5PHVrP9s=,tag:yxlNfyTSnM0Wbj95Z/8Ffw==,type:str] + pgp: + - created_at: "2023-11-12T16:41:00Z" + enc: | + -----BEGIN PGP MESSAGE----- + + hQEMA/m6nevQP1fAAQf/XVOr/ZOZo/b5lDJ7EIeRgwejwtJLGToF6xXM0jcZvlsB + 1Vk2tuzOpAGpO8JpaTzZj0n4Da8+XXpEqLqeGFBsjPni+W0ErlYR/exIVFBZyCVM + gVFnjoAsiR7z+Y+ovYx1VBVpfav3GXXNkPOWNOQlXAhoS9Rxv04AU8XBBy5Hk5kH + is+eM9U+iVxlZfEGW3nAylSieMQdEjWG3MM8KgWr4SLSSLY+sAhiM6QwSDF0wkkn + mLcFJ4CwbWiZIa0995lbhIusTko+DJfdYB6b6e7yxftMySKskTKp0fRh6eagpLhC + oXca0MSIhdWUbgcB4MnWdXl6fGYL7YnTgwOg50ETdNJeAf6p+u/uBElu0Ym94ZRf + /DHrY/rRMx6xNtUCwxAI4ekmi/gXky9/lteZtkW87nXGaYweeQECfbDFWtNczbpn + mfQzF/LrdlaIMEyMGpLow7AgakEuIPXyH5f9hgz9IA== + =NPJP + -----END PGP MESSAGE----- + fp: 7FB89715AADA920D65D25E63F9BA9DEBD03F57C0 + - created_at: "2023-11-12T16:41:00Z" + enc: | + -----BEGIN PGP MESSAGE----- + + hQGMA3ulPRkZxd/UAQv/UWnL12QFkO1EDguYrLyzq50qAc9wtWJvYP8SS4CP/k1t + ii0cSteyxbiPnYAFFRsiW3KDfkVIOl24+qKihmOcsq+uL90VxweGHJbZwwdNLU5v + YD+bbvfAN1iO2eY0ipTL1gNSu0zl4s8bZaTaYBIBhwTMXNWLfz7CHMU2yJ1g5sWK + oZjGYkleq76zUmhDpzKONivYQiN+UayZ5XqEavdVc5omUlM26hO6jgDUxYua7Wjf + m5cDyPHLzO04d91z0hLxYl5dfK93R2/1dicFmh0yin/nyxbqGBKUAoYdpYAhuI9M + JnKgeEx1mNZnCJdXSJouAA9FakTIkkbOPr45ik087VQ8AdY/c7Ao8SGB2W2kOPqt + +G2r5GBeO/0XH7FUIAcvekOHrjPV16aQpZCouJsFOUMtXi5lnViWhyVPPxERAzIL + sCN2AHI/aFXycPEXSnwoCMvW+3KOihLDxBUPK45Pjc7HfiOPDeWCva6BhG5gFQkT + sJ2B0yeaJoNlQO2bG+AJ0lgBW4s+Q0rtoSRj52cCnVj4zlgjrArPje/aU8pj0w5k + aSl1OoqsD1a5A7vkldmVgec9rWhByRDEnHke00OhmOcPDm6hv0fROwa5qls9RhR0 + Gs6FXl5y3Cz7 + =yMyb + -----END PGP MESSAGE----- + fp: 2504791468B153B8A3963CC97BA53D1919C5DFD4 + unencrypted_suffix: _unencrypted + version: 3.7.3