Skip to content

Commit

Permalink
feat(providers): first implementation of a 1password connect provider
Browse files Browse the repository at this point in the history
Signed-off-by: Fabian Jucker <[email protected]>
  • Loading branch information
juckerf committed Sep 4, 2023
1 parent 193b8a2 commit 6a31685
Show file tree
Hide file tree
Showing 7 changed files with 157 additions and 19 deletions.
23 changes: 23 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ It supports various backends including:
- [Google Sheets](#google-sheets)
- [SOPS](https://github.com/mozilla/sops)-encrypted files
- Terraform State
- 1Password Connect
- CredHub(Coming soon)

- Use `vals eval -f refs.yaml` to replace all the `ref`s in the file to actual values and secrets.
Expand Down Expand Up @@ -210,6 +211,7 @@ Please see the [relevant unit test cases](https://github.com/helmfile/vals/blob/
- [Azure Key Vault](#azure-key-vault)
- [EnvSubst](#envsubst)
- [GitLab](#gitlab)
- [1Password Connect](#1password-connect)

Please see [pkg/providers](https://github.com/helmfile/vals/tree/master/pkg/providers) for the implementations of all the providers. The package names corresponds to the URI schemes.

Expand Down Expand Up @@ -627,6 +629,27 @@ Examples:
- `ref+gitlab://gitlab.com/11111/password`
- `ref+gitlab://my-gitlab.org/11111/password?ssl_verify=true&scheme=https`
### 1Password Connect
For this provider to work you require a working and accessible [1Password connect server](https://developer.1password.com/docs/connect).
The following env vars have to be configured:
- `OP_CONNECT_HOST`
- `OP_CONNET_TOKEN`
1Password is organized in vaults and items.
An item can have multiple fields with or without a section. Labels can be set on fields and sections.
Vaults, items, sections and labels can be accessed by ID or by label/name (and IDs and labels can be mixed and matched in one URL).
If a section does not have a label the field is only accessible via the section ID. This does not hold true for some default fields which may have no section at all (e.g.username and password for a `Login` item).
*Caution: vals-expressions are parsed as URIs. For the 1Password connect provider the host component of the URI identifies the vault (by ID or name). Therefore vaults containing certain characters not allowed in the host component (e.g. whitespaces, see [RFC-3986](https://www.rfc-editor.org/rfc/rfc3986#section-3.2.2) for details) can only be accessed by ID.*
Examples:
- `ref+onepasswordconnect://VAULT_ID/ITEM_ID#/[SECTION_ID.]FIELD_ID`
- `ref+onepasswordconnect://VAULT_LABEL/ITEM_LABEL#/[SECTION_LABEL.]FIELD_LABEL`
- `ref+onepasswordconnect://VAULT_LABEL/ITEM_ID#/[SECTION_LABEL.]FIELD_ID`
## Advanced Usages
### Discriminating config and secrets
Expand Down
4 changes: 4 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ require (
cloud.google.com/go/compute v1.7.0 // indirect
cloud.google.com/go/iam v0.3.0 // indirect
filippo.io/age v1.0.0 // indirect
github.com/1Password/connect-sdk-go v1.5.3 // indirect
github.com/Azure/azure-sdk-for-go v63.3.0+incompatible // indirect
github.com/Azure/azure-sdk-for-go/sdk/internal v1.3.0 // indirect
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage v1.3.0 // indirect
Expand Down Expand Up @@ -116,12 +117,15 @@ require (
github.com/mitchellh/mapstructure v1.4.3 // indirect
github.com/mitchellh/reflectwalk v1.0.2 // indirect
github.com/oklog/run v1.1.0 // indirect
github.com/opentracing/opentracing-go v1.2.0 // indirect
github.com/pierrec/lz4 v2.6.1+incompatible // indirect
github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/ryanuber/go-glob v1.0.0 // indirect
github.com/sirupsen/logrus v1.8.1 // indirect
github.com/uber/jaeger-client-go v2.30.0+incompatible // indirect
github.com/uber/jaeger-lib v2.4.1+incompatible // indirect
go.mozilla.org/gopgagent v0.0.0-20170926210634-4d7ea76ff71a // indirect
go.opencensus.io v0.23.0 // indirect
go.uber.org/atomic v1.9.0 // indirect
Expand Down
9 changes: 9 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,8 @@ cloud.google.com/go/storage v1.23.0/go.mod h1:vOEEDNFnciUMhBeT6hsJIn3ieU5cFRmzeL
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
filippo.io/age v1.0.0 h1:V6q14n0mqYU3qKFkZ6oOaF9oXneOviS3ubXsSVBRSzc=
filippo.io/age v1.0.0/go.mod h1:PaX+Si/Sd5G8LgfCwldsSba3H1DDQZhIhFGkhbHaBq8=
github.com/1Password/connect-sdk-go v1.5.3 h1:KyjJ+kCKj6BwB2Y8tPM1Ixg5uIS6HsB0uWA8U38p/Uk=
github.com/1Password/connect-sdk-go v1.5.3/go.mod h1:5rSymY4oIYtS4G3t0oMkGAXBeoYiukV3vkqlnEjIDJs=
github.com/Azure/azure-sdk-for-go v63.3.0+incompatible h1:INepVujzUrmArRZjDLHbtER+FkvCoEwyRCXGqOlmDII=
github.com/Azure/azure-sdk-for-go v63.3.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.7.1 h1:/iHxaJhsFr0+xVFfbMr5vxz848jyiWuIEDhYq3y5odY=
Expand Down Expand Up @@ -493,6 +495,8 @@ github.com/oklog/run v1.1.0/go.mod h1:sVPdnTZT1zYwAJeCMu2Th4T21pA3FPOQRfWjQlk7DV
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
github.com/opencontainers/image-spec v1.0.2 h1:9yCKha/T5XdGtO0q9Q9a6T5NUCsTn/DrBg0D7ufOcFM=
github.com/opencontainers/runc v1.1.0 h1:O9+X96OcDjkmmZyfaG996kV7yq8HsoU2h1XRRQcefG8=
github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+1B0VhjKrZUs=
github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc=
github.com/ory/dockertest v3.3.5+incompatible h1:iLLK6SQwIhcbrG783Dghaaa3WPzGc+4Emza6EbVUUGA=
github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY=
github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
Expand Down Expand Up @@ -542,6 +546,10 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM=
github.com/uber/jaeger-client-go v2.30.0+incompatible h1:D6wyKGCecFaSRUpo8lCVbaOOb6ThwMmTEbhRwtKR97o=
github.com/uber/jaeger-client-go v2.30.0+incompatible/go.mod h1:WVhlPFC8FDjOFMMWRy2pZqQJSXxYSwNYOkTr/Z6d3Kk=
github.com/uber/jaeger-lib v2.4.1+incompatible h1:td4jdvLcExb4cBISKIpHuGoVXh+dVKhn2Um6rjCsSsg=
github.com/uber/jaeger-lib v2.4.1+incompatible/go.mod h1:ComeNDZlWwrWnDv8aPp0Ba6+uUTzImX/AauajbLI56U=
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
Expand Down Expand Up @@ -1037,6 +1045,7 @@ gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/ini.v1 v1.66.4 h1:SsAcf+mM7mRZo2nJNGt8mZCjG8ZRaNGMURJw7BsIST4=
gopkg.in/ini.v1 v1.66.4/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
Expand Down
91 changes: 91 additions & 0 deletions pkg/providers/onepasswordconnect/onepasswordconnect.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
package onepasswordconnect

import (
"errors"
"fmt"
"strings"

"github.com/1Password/connect-sdk-go/connect"
"gopkg.in/yaml.v3"

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

type provider struct {
client connect.Client
}

// New creates a new 1Password Connect provider
func New(cfg api.StaticConfig) *provider {
p := &provider{}

return p
}

// Get secret string from 1Password Connect
func (p *provider) GetString(key string) (string, error) {
var err error

splits := strings.Split(key, "/")
if len(splits) < 2 {
return "", fmt.Errorf("invalid URI: %v", errors.New("vault or item missing"))
}

client, err := connect.NewClientFromEnvironment()
if err != nil {
return "", fmt.Errorf("storage.NewClient: %v", err)
}

p.client = client

item, err := client.GetItem(splits[1], splits[0])
if err != nil {
return "", fmt.Errorf("error retrieving item: %v", err)
}

var data = make(map[string]string)
// fill map with all possible ID/Label combinations for value
for _, f := range item.Fields {
data[f.ID] = f.Value
// if no section on field (default fields on some item types) use value directly
if f.Section == nil {
data[f.Label] = f.Value
} else {
if f.Section.Label != "" {
var key = strings.Join([]string{f.Section.Label, f.Label}, ".")
data[key] = f.Value
key = strings.Join([]string{f.Section.Label, f.ID}, ".")
data[key] = f.Value
}
key = strings.Join([]string{f.Section.ID, f.Label}, ".")
data[key] = f.Value
key = strings.Join([]string{f.Section.ID, f.ID}, ".")
data[key] = f.Value

Check failure on line 64 in pkg/providers/onepasswordconnect/onepasswordconnect.go

View workflow job for this annotation

GitHub Actions / Lint

unnecessary trailing newline (whitespace)
}
}
var yamlData []byte
yamlData, err = yaml.Marshal(data)
if err != nil {
return "", fmt.Errorf("yaml.Marshal: %v", err)
}

return (string)(yamlData), nil
}

// Convert yaml to map interface and return the requested keys
func (p *provider) GetStringMap(key string) (map[string]interface{}, error) {
yamlData, err := p.GetString(key)
if err != nil {
fmt.Println(err)
return nil, err
}

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

if err := yaml.Unmarshal([]byte(yamlData), &m); err != nil {
return nil, err
}

return m, nil
}
3 changes: 3 additions & 0 deletions pkg/stringmapprovider/stringmapprovider.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"github.com/helmfile/vals/pkg/providers/awssecrets"
"github.com/helmfile/vals/pkg/providers/azurekeyvault"
"github.com/helmfile/vals/pkg/providers/gcpsecrets"
"github.com/helmfile/vals/pkg/providers/onepasswordconnect"
"github.com/helmfile/vals/pkg/providers/sops"
"github.com/helmfile/vals/pkg/providers/ssm"
"github.com/helmfile/vals/pkg/providers/vault"
Expand All @@ -34,6 +35,8 @@ func New(l *log.Logger, provider api.StaticConfig) (api.LazyLoadedStringMapProvi
return azurekeyvault.New(provider), nil
case "awskms":
return awskms.New(provider), nil
case "onepasswordconnect":
return onepasswordconnect.New(provider), nil
}

return nil, fmt.Errorf("failed initializing string-map provider from config: %v", provider)
Expand Down
3 changes: 3 additions & 0 deletions pkg/stringprovider/stringprovider.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
"github.com/helmfile/vals/pkg/providers/gcpsecrets"
"github.com/helmfile/vals/pkg/providers/gcs"
"github.com/helmfile/vals/pkg/providers/gitlab"
"github.com/helmfile/vals/pkg/providers/onepasswordconnect"
"github.com/helmfile/vals/pkg/providers/s3"
"github.com/helmfile/vals/pkg/providers/sops"
"github.com/helmfile/vals/pkg/providers/ssm"
Expand Down Expand Up @@ -52,6 +53,8 @@ func New(l *log.Logger, provider api.StaticConfig) (api.LazyLoadedStringProvider
return azurekeyvault.New(provider), nil
case "gitlab":
return gitlab.New(provider), nil
case "onepasswordconnect":
return onepasswordconnect.New(provider), nil
}

return nil, fmt.Errorf("failed initializing string provider from config: %v", provider)
Expand Down
43 changes: 24 additions & 19 deletions vals.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import (
"github.com/helmfile/vals/pkg/providers/gcs"
"github.com/helmfile/vals/pkg/providers/gitlab"
"github.com/helmfile/vals/pkg/providers/googlesheets"
"github.com/helmfile/vals/pkg/providers/onepasswordconnect"
"github.com/helmfile/vals/pkg/providers/s3"
"github.com/helmfile/vals/pkg/providers/sops"
"github.com/helmfile/vals/pkg/providers/ssm"
Expand Down Expand Up @@ -62,25 +63,26 @@ const (
// secret cache size
defaultCacheSize = 512

ProviderVault = "vault"
ProviderS3 = "s3"
ProviderGCS = "gcs"
ProviderGitLab = "gitlab"
ProviderSSM = "awsssm"
ProviderKms = "awskms"
ProviderSecretsManager = "awssecrets"
ProviderSOPS = "sops"
ProviderEcho = "echo"
ProviderFile = "file"
ProviderGCPSecretManager = "gcpsecrets"
ProviderGoogleSheets = "googlesheets"
ProviderTFState = "tfstate"
ProviderTFStateGS = "tfstategs"
ProviderTFStateS3 = "tfstates3"
ProviderTFStateAzureRM = "tfstateazurerm"
ProviderTFStateRemote = "tfstateremote"
ProviderAzureKeyVault = "azurekeyvault"
ProviderEnvSubst = "envsubst"
ProviderVault = "vault"
ProviderS3 = "s3"
ProviderGCS = "gcs"
ProviderGitLab = "gitlab"
ProviderSSM = "awsssm"
ProviderKms = "awskms"
ProviderSecretsManager = "awssecrets"
ProviderSOPS = "sops"
ProviderEcho = "echo"
ProviderFile = "file"
ProviderGCPSecretManager = "gcpsecrets"
ProviderGoogleSheets = "googlesheets"
ProviderTFState = "tfstate"
ProviderTFStateGS = "tfstategs"
ProviderTFStateS3 = "tfstates3"
ProviderTFStateAzureRM = "tfstateazurerm"
ProviderTFStateRemote = "tfstateremote"
ProviderAzureKeyVault = "azurekeyvault"
ProviderEnvSubst = "envsubst"
ProviderOnePasswordConnect = "onepasswordconnect"
)

var (
Expand Down Expand Up @@ -228,6 +230,9 @@ func (r *Runtime) prepare() (*expansion.ExpandRegexMatch, error) {
case ProviderEnvSubst:
p := envsubst.New(conf)
return p, nil
case ProviderOnePasswordConnect:
p := onepasswordconnect.New(conf)
return p, nil
}
return nil, fmt.Errorf("no provider registered for scheme %q", scheme)
}
Expand Down

0 comments on commit 6a31685

Please sign in to comment.