Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ It supports various backends including:
- Conjur
- HCP Vault Secrets
- Bitwarden
- [Yandex Cloud Lockbox](https://yandex.cloud/en/docs/lockbox/)
- HTTP JSON
- Keychain

Expand Down Expand Up @@ -246,6 +247,8 @@ Please see the [relevant unit test cases](https://github.com/helmfile/vals/blob/
- [Conjur](#conjur)
- [HCP Vault Secrets](#hcp-vault-secrets)
- [Bitwarden](#bitwarden)
- [Yandex Cloud Lockbox](#yandex-cloud-lockbox)
- [Authentication](#authentication-2)
- [HTTP JSON](#http-json)
- [Fetch string value](#fetch-string-value)
- [Fetch integer value](#fetch-integer-value)
Expand Down Expand Up @@ -898,6 +901,23 @@ Examples:
- `ref+bw://4d084b01-87e7-4411-8de9-2476ab9f3f48/{username,password,uri,notes,item}` gets username, password, uri, notes or the whole item of the given item id
- `ref+bw://4d084b01-87e7-4411-8de9-2476ab9f3f48/notes#/key1` gets the *key1* from the yaml stored as note in the item

### Yandex Cloud Lockbox

Retrieve secrets from [Yandex Cloud Lockbox](https://yandex.cloud/en/docs/lockbox/). Path is used to specify secret ID. Optionally a specific secret version can be retrieved (using current version by default). If fragment is specified, retrieves a specific key from the secret.

- `ref+yclockbox://SECRET_ID[?version_id=VERSION][#KEY]`

Examples:

- `ref+yclockbox://e6qeoqvd88dcpf044n5i` - get whole secret `e6qeoqvd88dcpf044n5i` from the current version
- `ref+yclockbox://e6qeoqvd88dcpf044n5i?version_id=e6qn22seoaprg9cbe1dj` - get whole secret `e6qeoqvd88dcpf044n5i` from the `e6qn22seoaprg9cbe1dj` version
- `ref+yclockbox://e6qeoqvd88dcpf044n5i?version_id=e6qn22seoaprg9cbe1dj#oauth_secret` - get secret entry from the `oauth_secret` key of `e6qn22seoaprg9cbe1dj` version of `e6qeoqvd88dcpf044n5i` secret
- `ref+yclockbox://e6qeoqvd88dcpf044n5i#oauth_secret` - get secret entry from the `oauth_secret` key of current version of `e6qeoqvd88dcpf044n5i` secret

#### Authentication

Vals aquires Yandex Cloud IAM token from the `YC_TOKEN` environment variable. The easiest way to get it is to run `yc iam create-token`. See [Yandex Cloud Lockbox docs](https://yandex.cloud/en/docs/lockbox/api-ref/authentication) for more details on authentication

### HTTP JSON

This provider retrieves values stored in JSON hosted by a HTTP frontend.
Expand Down
3 changes: 3 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ require (
github.com/hashicorp/vault/api v1.20.0
github.com/stretchr/testify v1.10.0
github.com/tidwall/gjson v1.18.0
github.com/yandex-cloud/go-genproto v0.12.0
github.com/yandex-cloud/go-sdk v0.11.0
golang.org/x/oauth2 v0.30.0
google.golang.org/api v0.246.0
gopkg.in/yaml.v3 v3.0.1
Expand Down Expand Up @@ -53,6 +55,7 @@ require (
github.com/envoyproxy/protoc-gen-validate v1.2.1 // indirect
github.com/extism/go-sdk v1.7.0 // indirect
github.com/fxamacker/cbor/v2 v2.7.0 // indirect
github.com/ghodss/yaml v1.0.0 // indirect
github.com/go-jose/go-jose/v4 v4.0.5 // indirect
github.com/go-openapi/analysis v0.23.0 // indirect
github.com/go-openapi/errors v0.22.1 // indirect
Expand Down
8 changes: 8 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,8 @@ github.com/getsops/gopgagent v0.0.0-20241224165529-7044f28e491e h1:y/1nzrdF+RPds
github.com/getsops/gopgagent v0.0.0-20241224165529-7044f28e491e/go.mod h1:awFzISqLJoZLm+i9QQ4SgMNHDqljH6jWV0B36V5MrUM=
github.com/getsops/sops/v3 v3.10.2 h1:7t7lBXFcXJPsDMrpYoI36r8xIhjWUmEc8Qdjuwyo+WY=
github.com/getsops/sops/v3 v3.10.2/go.mod h1:Dmtg1qKzFsAl+yqvMgjtnLGTC0l7RnSM6DDtFG7TEsk=
github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/go-jose/go-jose/v4 v4.0.5 h1:M6T8+mKZl/+fNNuFHvGIzDz7BTLQPIounk/b9dw3AaE=
github.com/go-jose/go-jose/v4 v4.0.5/go.mod h1:s3P1lRrkT8igV8D9OjyL4WRyHvjB6a4JSllnOrmmBOA=
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
Expand Down Expand Up @@ -383,6 +385,8 @@ github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db h1:62I3jR2Em
github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db/go.mod h1:l0dey0ia/Uv7NcFFVbCLtqEBQbrT4OCwCSKTEv6enCw=
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJJ2JqpQmpLJOu07cU=
github.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8=
github.com/mitchellh/go-wordwrap v1.0.1 h1:TLuKupo69TCn6TQSyGxwI1EblZZEsQ0vMlAFQflz0v0=
github.com/mitchellh/go-wordwrap v1.0.1/go.mod h1:R62XHJLzvMFRBbcrT7m7WgmE1eOyTSsCt+hzestvNj0=
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
Expand Down Expand Up @@ -481,6 +485,10 @@ github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHo
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ=
github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74=
github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y=
github.com/yandex-cloud/go-genproto v0.12.0 h1:jg8UhoVs0+XpZW9cttdyOTFsCSmhyB1Qsf962UW1/Qg=
github.com/yandex-cloud/go-genproto v0.12.0/go.mod h1:0LDD/IZLIUIV4iPH+YcF+jysO3jkSvADFGm4dCAuwQo=
github.com/yandex-cloud/go-sdk v0.11.0 h1:f79LZWX3PLVXSb8QIp7efCWkja69OuGu8hcnToWURFw=
github.com/yandex-cloud/go-sdk v0.11.0/go.mod h1:n9XO+J+P1//Em9eWxOhulhU+6TZp1iCUfzVcmFn/g9U=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/zalando/go-keyring v0.2.6 h1:r7Yc3+H+Ux0+M72zacZoItR3UDxeWfKTcabvkI8ua9s=
Expand Down
109 changes: 109 additions & 0 deletions pkg/providers/yclockbox/yclockbox.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
package yclockbox

import (
"context"
"encoding/json"
"fmt"
"os"

"github.com/yandex-cloud/go-genproto/yandex/cloud/lockbox/v1"
sdk "github.com/yandex-cloud/go-sdk"

"github.com/helmfile/vals/pkg/api"
"github.com/helmfile/vals/pkg/log"
)

const (
TOKEN_ENV = "YC_TOKEN"
)

// Format: ref+yclockbox://SECRET_ID[?version_id=VERSION_ID][#KEY]
type provider struct {
logger *log.Logger
client lockbox.PayloadServiceClient
versionId string
}

func New(l *log.Logger, cfg api.StaticConfig) *provider {
token, ok := os.LookupEnv(TOKEN_ENV)
if !ok {
l.Debugf("yclockbox: Missing %s environment variable", TOKEN_ENV)
}

sdk, err := sdk.Build(
context.TODO(),
sdk.Config{
Credentials: sdk.NewIAMTokenCredentials(
token,
),
},
)

if err != nil {
l.Debugf("yclockbox: SDK initialization error: %s", err)
return nil
}

p := &provider{
logger: l,
client: sdk.LockboxPayload().Payload(),
}

if v := cfg.String("version_id"); cfg.Exists("version_id") {
p.versionId = v
}

return p
}

func (p *provider) GetString(key string) (string, error) {
if p == nil {
return "", fmt.Errorf("yclockbox: provider is nil")
}
secret, err := p.GetStringMap(key)

if err != nil {
p.logger.Debugf("yclockbox: get string failed: key=%s", key)
return "", err
}

res, err := json.Marshal(secret)

if err != nil {
p.logger.Debugf("yclockbox: marshaling failed")
return "", err
}

return string(res), nil
}

func (p *provider) GetStringMap(key string) (map[string]any, error) {
if p == nil {
return nil, fmt.Errorf("yclockbox: provider is nil")
}
secret, err := p.client.Get(
context.Background(),
&lockbox.GetPayloadRequest{
SecretId: key,
VersionId: p.versionId,
},
)
if err != nil {
p.logger.Debugf("yclockbox: %s", err)
return nil, err
}

res := map[string]interface{}{}

for _, entry := range secret.Entries {
var value string
if entry.GetTextValue() != "" {
value = entry.GetTextValue()
} else {
value = string(entry.GetBinaryValue())
}
res[entry.GetKey()] = value
}

return res, nil
}
5 changes: 5 additions & 0 deletions vals.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ import (
"github.com/helmfile/vals/pkg/providers/ssm"
"github.com/helmfile/vals/pkg/providers/tfstate"
"github.com/helmfile/vals/pkg/providers/vault"
"github.com/helmfile/vals/pkg/providers/yclockbox"
"github.com/helmfile/vals/pkg/stringmapprovider"
"github.com/helmfile/vals/pkg/stringprovider"
)
Expand Down Expand Up @@ -103,6 +104,7 @@ const (
ProviderHCPVaultSecrets = "hcpvaultsecrets"
ProviderHttpJsonManager = "httpjson"
ProviderBitwarden = "bw"
ProviderLockbox = "yclockbox"
)

var (
Expand Down Expand Up @@ -279,6 +281,9 @@ func (r *Runtime) prepare() (*expansion.ExpandRegexMatch, error) {
case ProviderBitwarden:
p := bitwarden.New(r.logger, conf)
return p, nil
case ProviderLockbox:
p := yclockbox.New(r.logger, conf)
return p, nil
}
return nil, fmt.Errorf("no provider registered for scheme %q", scheme)
}
Expand Down