Skip to content

Commit

Permalink
doc: sops additional_flags
Browse files Browse the repository at this point in the history
  • Loading branch information
PierreBeucher committed Dec 27, 2023
1 parent 3869e7b commit 2bc749e
Show file tree
Hide file tree
Showing 4 changed files with 50 additions and 17 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ Create `.novops.yml` and commit it safely - it does not contain any secret:
environments:

# Your development environment.
# Novops support multiple environments:
# Novops supports multiple environments:
# you can add integ, preprod, prod...
# with their own config.
dev:
Expand Down Expand Up @@ -88,7 +88,7 @@ environments:
path: app/dev
key: ssh_key

# Generate temporary AWS credentials for IAM Role
# Generate temporary AWS credentials for an IAM Role
# Provide environment variables:
# - AWS_ACCESS_KEY_ID
# - AWS_SECRET_ACCESS_KEY
Expand Down
4 changes: 2 additions & 2 deletions docs/schema/config-schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -586,7 +586,7 @@
"file"
],
"properties": {
"additional_flag": {
"additional_flags": {
"description": "Additional flags passed to sops",
"type": [
"array",
Expand Down Expand Up @@ -615,7 +615,7 @@
"file"
],
"properties": {
"additional_flag": {
"additional_flags": {
"description": "Additional flags passed to sops after --decrypt --extract",
"type": [
"array",
Expand Down
36 changes: 32 additions & 4 deletions docs/src/config/sops.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@

Load SOPS encryped values as files or environment variables.

- [Decryption](#decryption)
- [Requirements](#requirements)
- [Load a single value](#load-a-single-value)
- [Load entire file as dotenv](#load-entire-file-as-dotenv)
- [Pass additional flags to SOPS](#pass-additional-flags-to-sops)

Example below consider example files:

Expand All @@ -21,7 +22,9 @@ APP_TOKEN: secret
APP_PASSWORD: xxx
```
## Decryption
## Requirements
You need `sops` CLI available locally as Novops will wrap calls to `sops --decrypt` under the hood.

All SOPS decryptions methods are supported as would be done using CLI command `sops --decrypt`. See [SOPS official doc](https://github.com/getsops/sops) for details.

Expand Down Expand Up @@ -53,9 +56,9 @@ environments:
files:

# Load SOPS decrypted content into secure temporary file
# SOPS_FILE_CONTENT would point to decrypted file content such as SOPS_FILE_CONTENT=/run/...
# SOPS_DECRYPTED would point to decrypted file content such as SOPS_DECRYPTED=/run/...
# Equivalent of `sops --decrypt path/to/encrypted.yml`
- variable: SOPS_FILE_CONTENT
- variable: SOPS_DECRYPTED
content:
sops:
file: path/to/encrypted.yml
Expand Down Expand Up @@ -83,3 +86,28 @@ environments:

_Note: SOPS won't be able to decrypt complex or nested values (this is a SOPS limitation). Only dotenv-compatible files or file parts with extract can be used this way._

## Pass additional flags to SOPS

By default Novops will load SOPS secrets using `sops` CLI such as `sops --decrypt [FILE]`. It's possible to pass additional flags with `additional_flags`.

**Warning:** it may break Novops loading mechanism if output is not as expected by Novops. Only use this if an equivalent feature is not already provided by a module option. Feel free to [create an issue](https://github.com/PierreBeucher/novops/issues) or [contribute](https://github.com/PierreBeucher/novops/blob/main/CONTRIBUTING.md) to add missing feature !

Example: enable SOPS verbose output

```yaml
environments:
dev:
variables:
- name: SOPS_VALUE_WITH_ADDITIONAL_FLAGS
value:
sops:
file: path/to/encrypted.yml
extract: '["nested"]["data"]["nestedKey"]'
additional_flags: [ "--verbose" ]
```

Novops `debug` logging will show `sops` stderr (stout is not shown to avoid secret leak):

```sh
RUST_LOG=novops=debug novops load
```
23 changes: 14 additions & 9 deletions src/modules/sops.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ pub struct SopsValueFromFile {
* Additional flags passed to sops
* after --decrypt --extract
*/
additional_flag: Option<Vec<String>>,
additional_flags: Option<Vec<String>>,
}

/**
Expand All @@ -52,7 +52,7 @@ pub struct SopsDotenvInput {
/**
* Additional flags passed to sops
*/
additional_flag: Option<Vec<String>>,
additional_flags: Option<Vec<String>>,

/**
* Extract a specific field via --extract flag
Expand All @@ -68,15 +68,18 @@ impl core::ResolveTo<String> for SopsValueInput {
return Ok(format!("RESULT:{:}:{:}", &self.sops.file, &self.sops.extract.clone().unwrap_or(String::from(""))));
}

let mut args = vec![
String::from("--decrypt")
];
let mut args = vec![];

// add --extract flag if specidief in input
self.sops.extract.clone().map(|e| {
args.push(String::from("--extract"));
args.push(e);
});

// Add additional flags if any
self.sops.additional_flags.clone().map(|af| {
args.extend(af);
});

let output = run_sops_decrypt(args, &self.sops.file).with_context(|| "Error running sops command.")?;

Expand All @@ -92,12 +95,11 @@ impl core::ResolveTo<Vec<VariableOutput>> for SopsDotenvInput {
if ctx.dry_run {
return Ok(vec![VariableOutput {
name: String::from("RESULT"),
value: format!("{}:{}", &self.file, &self.additional_flag.clone().unwrap_or(vec![]).join("-"))
value: format!("{}:{}", &self.file, &self.additional_flags.clone().unwrap_or(vec![]).join("-"))
}]);
}

let mut args = vec![
String::from("--decrypt"),
String::from("--output-type"),
String::from("dotenv")
];
Expand All @@ -108,7 +110,8 @@ impl core::ResolveTo<Vec<VariableOutput>> for SopsDotenvInput {
args.push(e);
});

self.additional_flag.clone().map(|af| {
// Add additional flags if any
self.additional_flags.clone().map(|af| {
args.extend(af);
});

Expand Down Expand Up @@ -145,7 +148,6 @@ pub fn run_sops_decrypt(additional_args: Vec<String>, file: &str) -> Result<Stri

debug!("Running sops command with args: {:?}", &final_args);


let output = Command::new("sops")
.args(&final_args)
.output()
Expand All @@ -157,6 +159,9 @@ pub fn run_sops_decrypt(additional_args: Vec<String>, file: &str) -> Result<Stri
let stderr = std::str::from_utf8(&output.stderr)
.with_context(|| format!("Couldn't decode stderr as UTF-8 for sops command with args: {:?}", &final_args))?;

// sops should not output any secret
debug!("sops stderr: '{:}'", &stderr);

if ! output.status.success() {
return Err(anyhow!("sops command returned non-0 exit code. args: {:?}, stderr: '{:?}'", &final_args, &stderr));
};
Expand Down

0 comments on commit 2bc749e

Please sign in to comment.