-
Notifications
You must be signed in to change notification settings - Fork 486
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: Add support for HCP Vault Secrets
- Loading branch information
Showing
11 changed files
with
268 additions
and
13 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
16 changes: 16 additions & 0 deletions
16
...ezmoi.io/docs/reference/templates/hcp-vault-secrets-functions/hcpVaultSecret.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
# `hcpVaultSecret` *key* [*app-name* [*project* [*organization*]]] | ||
|
||
`hcpVaultSecret` returns the plaintext secret from [HCP Vault | ||
Secrets](https://developer.hashicorp.com/hcp/docs/vault-secrets) using `vlt | ||
--plaintext`. | ||
|
||
If any of *app-name*, *project*, or *organization* are empty or omitted, then | ||
chezmoi will use the value from the `hcpVaultSecret.appName`, | ||
`hcpVaultSecret.project`, and `hcpVaultSecret.organization` config variables | ||
if they are set and not empty. | ||
|
||
!!! example | ||
|
||
``` | ||
{{ hcpVaultSecret "username" }} | ||
``` |
16 changes: 16 additions & 0 deletions
16
...i.io/docs/reference/templates/hcp-vault-secrets-functions/hcpVaultSecretJson.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
# `hcpVaultSecretJson` *key* [*app-name* [*project* [*organization*]]] | ||
|
||
`hcpVaultSecretJson` returns structured data from [HCP Vault | ||
Secrets](https://developer.hashicorp.com/hcp/docs/vault-secrets) using `vlt | ||
--format=json`. | ||
|
||
If any of *app-name*, *project*, or *organization* are empty or omitted, then | ||
chezmoi will use the value from the `hcpVaultSecret.appName`, | ||
`hcpVaultSecret.project`, and `hcpVaultSecret.organization` config variables | ||
if they are set and not empty. | ||
|
||
!!! example | ||
|
||
``` | ||
{{ (hcpVaultSecretJson "username") }} | ||
``` |
10 changes: 10 additions & 0 deletions
10
assets/chezmoi.io/docs/reference/templates/hcp-vault-secrets-functions/index.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
# HCP Vault Secrets | ||
|
||
chezmoi includes support for [HCP Vault | ||
Secrets](https://developer.hashicorp.com/hcp/docs/vault-secrets) using the `vlt` | ||
CLI to expose data through the `hcpVaultSecret` and `hcpVaultSecretJson` | ||
template functions. | ||
|
||
!!! warning | ||
|
||
HCP Vault Secrets is in beta and chezmoi's support for it may change at any time. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
10 changes: 10 additions & 0 deletions
10
assets/chezmoi.io/docs/user-guide/password-managers/hcp-vault-secrets.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
# HCP Vault Secrets | ||
|
||
chezmoi includes support for [HCP Vault | ||
Secrets](https://developer.hashicorp.com/hcp/docs/vault-secrets) using the `vlt` | ||
CLI to expose data through the `hcpVaultSecret` and `hcpVaultSecretJson` | ||
template functions. | ||
|
||
!!! warning | ||
|
||
HCP Vault Secrets is in beta and chezmoi's support for it may change at any time. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,105 @@ | ||
package cmd | ||
|
||
import ( | ||
"encoding/json" | ||
"fmt" | ||
"os" | ||
"os/exec" | ||
"strings" | ||
|
||
"golang.org/x/exp/slices" | ||
|
||
"github.com/twpayne/chezmoi/v2/pkg/chezmoilog" | ||
) | ||
|
||
type hcpVaultSecretConfig struct { | ||
Command string `json:"command" mapstructure:"command" yaml:"command"` | ||
Args []string `json:"args" mapstructure:"args" yaml:"args"` | ||
AppName string `json:"appName" mapstructure:"appName" yaml:"appName"` | ||
Organization string `json:"organization" mapstructure:"organization" yaml:"organization"` | ||
Project string `json:"project" mapstructure:"project" yaml:"project"` | ||
outputCache map[string][]byte | ||
} | ||
|
||
func (c *Config) hcpVaultSecretTemplateFunc(key string, additionalArgs ...string) string { | ||
args, err := c.appendHCPVaultSecretsAdditionalArgs( | ||
[]string{"secrets", "get", "--plaintext"}, | ||
additionalArgs, | ||
) | ||
if err != nil { | ||
panic(err) | ||
} | ||
output, err := c.vltOutput(append(args, key)) | ||
if err != nil { | ||
panic(err) | ||
} | ||
return string(output) | ||
} | ||
|
||
func (c *Config) hcpVaultSecretJSONTemplateFunc(key string, additionalArgs ...string) any { | ||
args, err := c.appendHCPVaultSecretsAdditionalArgs( | ||
[]string{"secrets", "get", "--format", "json"}, | ||
additionalArgs, | ||
) | ||
if err != nil { | ||
panic(err) | ||
} | ||
data, err := c.vltOutput(append(args, key)) | ||
if err != nil { | ||
panic(err) | ||
} | ||
var value any | ||
if err := json.Unmarshal(data, &value); err != nil { | ||
panic(err) | ||
} | ||
return value | ||
} | ||
|
||
func (c *Config) appendHCPVaultSecretsAdditionalArgs( | ||
args, additionalArgs []string, | ||
) ([]string, error) { | ||
if len(additionalArgs) > 0 && additionalArgs[0] != "" { | ||
args = append(args, "--app-name", additionalArgs[0]) | ||
} else if c.HCPVaultSecrets.AppName != "" { | ||
args = append(args, "--app-name", c.HCPVaultSecrets.AppName) | ||
} | ||
if len(additionalArgs) > 1 && additionalArgs[1] != "" { | ||
args = append(args, "--project", additionalArgs[1]) | ||
} else if c.HCPVaultSecrets.Project != "" { | ||
args = append(args, "--project", c.HCPVaultSecrets.Project) | ||
} | ||
if len(additionalArgs) > 2 && additionalArgs[2] != "" { | ||
args = append(args, "--organization", additionalArgs[2]) | ||
} else if c.HCPVaultSecrets.Organization != "" { | ||
args = append(args, "--organization", c.HCPVaultSecrets.Organization) | ||
} | ||
if len(additionalArgs) > 3 { | ||
// Add one to the number of received arguments as the hcpVaultSecret | ||
// and hcpVaultSecretJson template functions report this error and take | ||
// the key as the first argument. | ||
return nil, fmt.Errorf("expected 1 to 4 arguments, got %d", len(additionalArgs)+1) | ||
} | ||
return args, nil | ||
} | ||
|
||
func (c *Config) vltOutput(args []string) ([]byte, error) { | ||
args = append(slices.Clone(c.HCPVaultSecrets.Args), args...) | ||
key := strings.Join(args, "\x00") | ||
if data, ok := c.HCPVaultSecrets.outputCache[key]; ok { | ||
return data, nil | ||
} | ||
|
||
cmd := exec.Command(c.HCPVaultSecrets.Command, args...) //nolint:gosec | ||
cmd.Stdin = os.Stdin | ||
cmd.Stderr = os.Stderr | ||
output, err := chezmoilog.LogCmdOutput(cmd) | ||
if err != nil { | ||
return nil, newCmdOutputError(cmd, output, err) | ||
} | ||
|
||
if c.HCPVaultSecrets.outputCache == nil { | ||
c.HCPVaultSecrets.outputCache = make(map[string][]byte) | ||
} | ||
c.HCPVaultSecrets.outputCache[key] = output | ||
return output, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
[windows] skip 'UNIX only' | ||
[!windows] chmod 755 bin/vlt | ||
|
||
# test hcpVaultSecret template function | ||
exec chezmoi execute-template '{{ hcpVaultSecret "username" }}' | ||
stdout ^db-user$ | ||
|
||
# test hcpVaultSecret template function with app name, project, and organization arguments | ||
exec chezmoi execute-template '{{ hcpVaultSecret "password" "app-name" "project" "organization" }}' | ||
stdout ^password$ | ||
|
||
# test hcpVaultSecret template function with empty app name, project, and organization arguments | ||
exec chezmoi execute-template '{{ hcpVaultSecret "username" "" "" "" }}' | ||
stdout ^db-user$ | ||
|
||
# test hcpVaultSecretJson template function | ||
exec chezmoi execute-template '{{ (hcpVaultSecretJson "username").created_by.email }}' | ||
stdout ^username@example\.com$ | ||
|
||
chhome home2/user | ||
|
||
# test hcpVaultSecret template function with default app name, project, and organization arguments | ||
exec chezmoi execute-template '{{ hcpVaultSecret "password" }}' | ||
stdout ^default-password$ | ||
|
||
# test hcpVaultSecretJson template function with default project and organization arguments | ||
exec chezmoi execute-template '{{ hcpVaultSecret "password" "other-app-name" }}' | ||
stdout ^other-password$ | ||
|
||
-- bin/vlt -- | ||
#!/bin/sh | ||
|
||
case "$*" in | ||
"secrets get --format json username") | ||
cat <<EOF | ||
{ | ||
"created_at": "2023-06-09T13:14:28.140Z", | ||
"created_by": { | ||
"email": "[email protected]", | ||
"name": "example", | ||
"type": "TYPE_USER" | ||
}, | ||
"latest_version": "2", | ||
"name": "username" | ||
} | ||
EOF | ||
;; | ||
"secrets get --plaintext username") | ||
echo db-user | ||
;; | ||
"secrets get --plaintext --app-name app-name --project project --organization organization password") | ||
echo password | ||
;; | ||
"secrets get --plaintext --app-name default-app-name --project default-project --organization default-organization password") | ||
echo default-password | ||
;; | ||
"secrets get --plaintext --app-name other-app-name --project default-project --organization default-organization password") | ||
echo other-password | ||
;; | ||
*) | ||
echo "$*: unknown command" | ||
exit 1 | ||
;; | ||
esac | ||
-- home2/user/.config/chezmoi/chezmoi.toml -- | ||
[hcpVaultSecrets] | ||
appName = "default-app-name" | ||
project = "default-project" | ||
organization = "default-organization" |