mirror of
https://github.com/Mic92/sops-nix.git
synced 2026-07-17 14:35:25 +08:00
Emit plain file when key is empty
Co-Authored-By: Slaier <slaier@users.noreply.github.com>
This commit is contained in:
parent
aa5caa129b
commit
f21c31dadf
4 changed files with 83 additions and 11 deletions
38
README.md
38
README.md
|
|
@ -707,6 +707,44 @@ This is how it can be included in your `configuration.nix`:
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Emit plain file for yaml and json formats
|
||||||
|
|
||||||
|
By default, sops-nix extracts a single key from yaml and json files. If you
|
||||||
|
need the plain file instead of extracting a specific key from the input document,
|
||||||
|
you can set `key` to an empty string.
|
||||||
|
|
||||||
|
For example, the input document `my-config.yaml` likes this:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
my-secret1: ENC[AES256_GCM,data:tkyQPQODC3g=,iv:yHliT2FJ74EtnLIeeQtGbOoqVZnF0q5HiXYMJxYx6HE=,tag:EW5LV4kG4lcENaN2HIFiow==,type:str]
|
||||||
|
my-secret2: ENC[AES256_GCM,data:tkyQPQODC3g=,iv:yHliT2FJ74EtnLIeeQtGbOoqVZnF0q5HiXYMJxYx6HE=,tag:EW5LV4kG4lcENaN2HIFiow==,type:str]
|
||||||
|
sops:
|
||||||
|
kms: []
|
||||||
|
gcp_kms: []
|
||||||
|
azure_kv: []
|
||||||
|
hc_vault: []
|
||||||
|
...
|
||||||
|
```
|
||||||
|
|
||||||
|
This is how it can be included in your NixOS module:
|
||||||
|
|
||||||
|
```nix
|
||||||
|
{
|
||||||
|
sops.secrets.my-config = {
|
||||||
|
format = "yaml";
|
||||||
|
sopsFile = ./my-config.yaml;
|
||||||
|
key = "";
|
||||||
|
};
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Then, it will be mounted as `/run/secrets/my-config`:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
my-secret1: hello
|
||||||
|
my-secret2: hello
|
||||||
|
```
|
||||||
|
|
||||||
## Use with home manager
|
## Use with home manager
|
||||||
|
|
||||||
sops-nix also provides a home-manager module.
|
sops-nix also provides a home-manager module.
|
||||||
|
|
|
||||||
|
|
@ -15,11 +15,12 @@ let
|
||||||
|
|
||||||
key = lib.mkOption {
|
key = lib.mkOption {
|
||||||
type = lib.types.str;
|
type = lib.types.str;
|
||||||
default = name;
|
default = if cfg.defaultSopsKey != null then cfg.defaultSopsKey else name;
|
||||||
description = ''
|
description = ''
|
||||||
Key used to lookup in the sops file.
|
Key used to lookup in the sops file.
|
||||||
No tested data structures are supported right now.
|
No tested data structures are supported right now.
|
||||||
This option is ignored if format is binary.
|
This option is ignored if format is binary.
|
||||||
|
"" means whole file.
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -131,6 +132,16 @@ in {
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
|
defaultSopsKey = mkOption {
|
||||||
|
type = lib.types.nullOr lib.types.str;
|
||||||
|
default = null;
|
||||||
|
description = ''
|
||||||
|
Default key used to lookup in all secrets.
|
||||||
|
This option is ignored if format is binary.
|
||||||
|
"" means whole file.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
validateSopsFiles = lib.mkOption {
|
validateSopsFiles = lib.mkOption {
|
||||||
type = lib.types.bool;
|
type = lib.types.bool;
|
||||||
default = true;
|
default = true;
|
||||||
|
|
|
||||||
|
|
@ -41,11 +41,12 @@ let
|
||||||
};
|
};
|
||||||
key = lib.mkOption {
|
key = lib.mkOption {
|
||||||
type = lib.types.str;
|
type = lib.types.str;
|
||||||
default = config._module.args.name;
|
default = if cfg.defaultSopsKey != null then cfg.defaultSopsKey else config._module.args.name;
|
||||||
description = ''
|
description = ''
|
||||||
Key used to lookup in the sops file.
|
Key used to lookup in the sops file.
|
||||||
No tested data structures are supported right now.
|
No tested data structures are supported right now.
|
||||||
This option is ignored if format is binary.
|
This option is ignored if format is binary.
|
||||||
|
"" means whole file.
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
path = lib.mkOption {
|
path = lib.mkOption {
|
||||||
|
|
@ -176,6 +177,16 @@ in {
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
|
defaultSopsKey = lib.mkOption {
|
||||||
|
type = lib.types.nullOr lib.types.str;
|
||||||
|
default = null;
|
||||||
|
description = ''
|
||||||
|
Default key used to lookup in all secrets.
|
||||||
|
This option is ignored if format is binary.
|
||||||
|
"" means whole file.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
validateSopsFiles = lib.mkOption {
|
validateSopsFiles = lib.mkOption {
|
||||||
type = lib.types.bool;
|
type = lib.types.bool;
|
||||||
default = true;
|
default = true;
|
||||||
|
|
|
||||||
|
|
@ -294,12 +294,20 @@ func decryptSecret(s *secret, sourceFiles map[string]plainData) error {
|
||||||
case Binary, Dotenv, Ini:
|
case Binary, Dotenv, Ini:
|
||||||
sourceFile.binary = plain
|
sourceFile.binary = plain
|
||||||
case Yaml:
|
case Yaml:
|
||||||
if err := yaml.Unmarshal(plain, &sourceFile.data); err != nil {
|
if s.Key == "" {
|
||||||
return fmt.Errorf("cannot parse yaml of '%s': %w", s.SopsFile, err)
|
sourceFile.binary = plain
|
||||||
|
} else {
|
||||||
|
if err := yaml.Unmarshal(plain, &sourceFile.data); err != nil {
|
||||||
|
return fmt.Errorf("Cannot parse yaml of '%s': %w", s.SopsFile, err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
case JSON:
|
case JSON:
|
||||||
if err := json.Unmarshal(plain, &sourceFile.data); err != nil {
|
if s.Key == "" {
|
||||||
return fmt.Errorf("cannot parse json of '%s': %w", s.SopsFile, err)
|
sourceFile.binary = plain
|
||||||
|
} else {
|
||||||
|
if err := json.Unmarshal(plain, &sourceFile.data); err != nil {
|
||||||
|
return fmt.Errorf("Cannot parse json of '%s': %w", s.SopsFile, err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
return fmt.Errorf("secret of type %s in %s is not supported", s.Format, s.SopsFile)
|
return fmt.Errorf("secret of type %s in %s is not supported", s.Format, s.SopsFile)
|
||||||
|
|
@ -309,11 +317,15 @@ func decryptSecret(s *secret, sourceFiles map[string]plainData) error {
|
||||||
case Binary, Dotenv, Ini:
|
case Binary, Dotenv, Ini:
|
||||||
s.value = sourceFile.binary
|
s.value = sourceFile.binary
|
||||||
case Yaml, JSON:
|
case Yaml, JSON:
|
||||||
strVal, err := recurseSecretKey(sourceFile.data, s.Key)
|
if s.Key == "" {
|
||||||
if err != nil {
|
s.value = sourceFile.binary
|
||||||
return fmt.Errorf("secret %s in %s is not valid: %w", s.Name, s.SopsFile, err)
|
} else {
|
||||||
|
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.SopsFile] = sourceFile
|
sourceFiles[s.SopsFile] = sourceFile
|
||||||
return nil
|
return nil
|
||||||
|
|
@ -482,7 +494,7 @@ func (app *appContext) validateSopsFile(s *secret, file *secretFile) error {
|
||||||
s.Name, s.SopsFile, s.Format,
|
s.Name, s.SopsFile, s.Format,
|
||||||
file.firstSecret.Format, file.firstSecret.Name)
|
file.firstSecret.Format, file.firstSecret.Name)
|
||||||
}
|
}
|
||||||
if app.checkMode != Manifest && (s.Format != Binary && s.Format != Dotenv && s.Format != Ini) {
|
if app.checkMode != Manifest && !(s.Format == Binary || s.Format == Dotenv || s.Format == Ini) && s.Key != "" {
|
||||||
_, err := recurseSecretKey(file.keys, s.Key)
|
_, err := recurseSecretKey(file.keys, s.Key)
|
||||||
if err != nil {
|
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: %w", s.Name, s.SopsFile, err)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue