Skip to content

Commit

Permalink
add pkg ansible-vault-go (#167)
Browse files Browse the repository at this point in the history
* add pkg ansible-vault-go

* implement ansible-vault (#169)

* nolint:dupl

---------

Co-authored-by: Mustafa YILDIRIM <[email protected]>
  • Loading branch information
kaplanelad and mustafayildirim authored Jun 12, 2023
1 parent e48635e commit 358cd83
Show file tree
Hide file tree
Showing 17 changed files with 648 additions and 21 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,4 @@ todo.txt
coverage.out
fixtures/sync/target.env
dist/
.idea
29 changes: 21 additions & 8 deletions .teller.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
project: teller

# Set this if you want to carry over parent process' environment variables
# carry_env: true
carry_env: true


#
Expand All @@ -12,18 +12,31 @@ project: teller
# paths.
#
opts:
region: env:AWS_REGION # you can get env variables with the 'env:' prefix
region: env:AWS_REGION # you can get env variables with the 'env:' prefix, for default values if env not found use comma. Example: env:AWS_REGION,{DEFAULT_VALUE}
stage: development


#
# Providers
#
providers:
# Configure via environment:
# CONSUL_HTTP_ADDR
cyberark_conjur:
env:
GH_USERNAME:
path: github/username

# dotenv:
## env_sync:
## path: ~/teller-env.env
# env:
# ANSIBLE_VAULT_PASSPHRASE:
# path: ~/teller-env.env

# Configure via environment variables for integration:
# ANSIBLE_VAULT_PASSPHRASE: Ansible Vault Password

ansible_vault:
env_sync:
path: ansible/vars/vault_{{stage}}.yml

env:
KEY1:
path: ansible/vars/vault_{{stage}}.yml
NONEXIST_KEY:
path: ansible/vars/vault_{{stage}}.yml
13 changes: 7 additions & 6 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ require (
go.etcd.io/etcd/api/v3 v3.5.0-alpha.0
go.etcd.io/etcd/client/v3 v3.5.0-alpha.0
go.etcd.io/etcd/pkg/v3 v3.5.0-alpha.0
golang.org/x/crypto v0.6.0
golang.org/x/crypto v0.8.0
golang.org/x/oauth2 v0.5.0
google.golang.org/api v0.40.0
google.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c
Expand Down Expand Up @@ -140,6 +140,7 @@ require (
github.com/russross/blackfriday/v2 v2.1.0 // indirect
github.com/ryanuber/go-glob v1.0.0 // indirect
github.com/sergi/go-diff v1.1.0 // indirect
github.com/sosedoff/ansible-vault-go v0.2.0 // indirect
github.com/spf13/cobra v0.0.5 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/twpayne/go-pinentry v0.2.0 // indirect
Expand All @@ -153,13 +154,13 @@ require (
go.uber.org/multierr v1.9.0 // indirect
go.uber.org/zap v1.16.0 // indirect
golang.org/x/exp v0.0.0-20230212135524-a684f29349b6 // indirect
golang.org/x/net v0.6.0 // indirect
golang.org/x/net v0.9.0 // indirect
golang.org/x/sync v0.1.0 // indirect
golang.org/x/sys v0.5.0 // indirect
golang.org/x/term v0.5.0 // indirect
golang.org/x/text v0.7.0 // indirect
golang.org/x/sys v0.7.0 // indirect
golang.org/x/term v0.7.0 // indirect
golang.org/x/text v0.9.0 // indirect
golang.org/x/time v0.0.0-20201208040808-7e3f01d25324 // indirect
golang.org/x/tools v0.3.0 // indirect
golang.org/x/tools v0.6.0 // indirect
google.golang.org/appengine v1.6.7 // indirect
google.golang.org/grpc v1.35.0 // indirect
google.golang.org/protobuf v1.28.1 // indirect
Expand Down
14 changes: 14 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -798,6 +798,8 @@ github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:s
github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s=
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
github.com/sosedoff/ansible-vault-go v0.2.0 h1:XqkBdqbXgTuFQ++NdrZvSdUTNozeb6S3V5x7FVs17vg=
github.com/sosedoff/ansible-vault-go v0.2.0/go.mod h1:wMU54HNJfY0n0KIgbpA9m15NBfaUDlJrAsaZp0FwzkI=
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk=
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
Expand Down Expand Up @@ -935,6 +937,8 @@ golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWP
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.6.0 h1:qfktjS5LUO+fFKeJXZ+ikTRijMmljikvG68fpMMruSc=
golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58=
golang.org/x/crypto v0.8.0 h1:pd9TJtTueMTVQXzk8E2XESSMQDj/U7OUu0PqJqPXQjQ=
golang.org/x/crypto v0.8.0/go.mod h1:mRqEX+O9/h5TFCrQhkgjo2yKi0yYA+9ecGkdQoHrywE=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
Expand Down Expand Up @@ -1023,6 +1027,8 @@ golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96b
golang.org/x/net v0.0.0-20210510120150-4163338589ed/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.6.0 h1:L4ZwwTvKW9gr0ZMS1yrHD9GZhIuVjOBBnaKH+SPQK0Q=
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.9.0 h1:aWJ/m6xSmxWBx+V0XRHTlrYrPG56jKsLdTFmsSsCzOM=
golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
Expand Down Expand Up @@ -1134,10 +1140,14 @@ golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.7.0 h1:3jlCCIQZPdOYu1h8BkNvLz8Kgwtae2cagcG/VamtZRU=
golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.5.0 h1:n2a8QNdAb0sZNpU9R1ALUXBbY+w51fCQDN+7EdxNBsY=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
golang.org/x/term v0.7.0 h1:BEvjmm5fURWqcfbSKTdpkDXYBrUS1c0m8agp14W48vQ=
golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
Expand All @@ -1149,6 +1159,8 @@ golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.7.0 h1:4BRB4x83lYWy72KwLD/qYDuTu7q9PjSagHvijDw7cLo=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE=
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
Expand Down Expand Up @@ -1217,6 +1229,8 @@ golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.3.0 h1:SrNbZl6ECOS1qFzgTdQfWXZM9XBkiA6tkFrH9YSTPHM=
golang.org/x/tools v0.3.0/go.mod h1:/rWhSS2+zyEVwoJf8YAX6L2f0ntZ7Kn/mGgAWcipA5k=
golang.org/x/tools v0.6.0 h1:BOw41kyTf3PuCW1pVQf8+Cyg8pMlkYB1oo9iJ6D/lKM=
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
Expand Down
133 changes: 133 additions & 0 deletions pkg/providers/ansible_vault.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
package providers

import (
"fmt"
"os"
"sort"

"github.com/joho/godotenv"
vault "github.com/sosedoff/ansible-vault-go"
"github.com/spectralops/teller/pkg/core"
"github.com/spectralops/teller/pkg/logging"
)

type AnsibleVaultClient interface {
Read(p string) (map[string]string, error)
}

type AnsibleVaultReader struct {
passPhrase string
}

func (a AnsibleVaultReader) Read(p string) (map[string]string, error) {
content, err := vault.DecryptFile(p, a.passPhrase)
if err != nil {
return nil, err
}
return godotenv.Unmarshal(content)
}

type AnsibleVault struct {
logger logging.Logger
client AnsibleVaultClient
}

//nolint
func init() {
metaInto := core.MetaInfo{
Description: "Ansible Vault",
Name: "ansible_vault",
Authentication: "ANSIBLE_VAULT_PASSPHRASE.",
ConfigTemplate: `
# Configure via environment variables for integration:
# ANSIBLE_VAULT_PASSPHRASE: Ansible Vault Password
ansible_vault:
env_sync:
path: ansible/vars/vault_{{stage}}.yml
env:
KEY1:
path: ansible/vars/vault_{{stage}}.yml
NONEXIST_KEY:
path: ansible/vars/vault_{{stage}}.yml
`,
Ops: core.OpMatrix{Get: true, GetMapping: true, Put: false, PutMapping: false},
}
RegisterProvider(metaInto, NewAnsibleVault)
}

// NewAnsibleVault creates new provider instance
func NewAnsibleVault(logger logging.Logger) (core.Provider, error) {
ansibleVaultPassphrase := os.Getenv("ANSIBLE_VAULT_PASSPHRASE")
return &AnsibleVault{
logger: logger,
client: &AnsibleVaultReader{
passPhrase: ansibleVaultPassphrase,
},
}, nil
}

// Name return the provider name
func (a *AnsibleVault) Name() string {
return "AnsibleVault"
}

// Put will create a new single entry
func (a *AnsibleVault) Put(p core.KeyPath, val string) error {
return fmt.Errorf("provider %q does not implement write yet", a.Name())
}

// PutMapping will create a multiple entries
func (a *AnsibleVault) PutMapping(p core.KeyPath, m map[string]string) error {
return fmt.Errorf("provider %q does not implement write yet", a.Name())
}

// GetMapping returns a multiple entries
func (a *AnsibleVault) GetMapping(p core.KeyPath) ([]core.EnvEntry, error) {
// Read existing secret
a.logger.WithField("path", p.Path).Debug("read secret")
kvs, err := a.client.Read(p.Path)
if err != nil {
return nil, err
}

var entries []core.EnvEntry
for k, v := range kvs {
entries = append(entries, p.FoundWithKey(k, v))
}
sort.Sort(core.EntriesByKey(entries))

return entries, nil
}

// Get returns a single entry
func (a *AnsibleVault) Get(p core.KeyPath) (*core.EnvEntry, error) { //nolint:dupl
a.logger.WithField("path", p.Path).Debug("read secret")

kvs, err := a.client.Read(p.Path)
if err != nil {
return nil, err
}

k := p.EffectiveKey()
val, ok := kvs[k]
if !ok {
a.logger.WithFields(map[string]interface{}{"path": p.Path, "key": k}).Debug("key not found")
ent := p.Missing()
return &ent, nil
}

ent := p.Found(val)
return &ent, nil
}

// Delete will delete entry
func (a *AnsibleVault) Delete(kp core.KeyPath) error {
return fmt.Errorf("provider %s does not implement delete yet", a.Name())
}

// DeleteMapping will delete the given path recessively
func (a *AnsibleVault) DeleteMapping(kp core.KeyPath) error {
return fmt.Errorf("provider %s does not implement delete yet", a.Name())
}
28 changes: 28 additions & 0 deletions pkg/providers/ansible_vault_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package providers

import (
"testing"

"github.com/golang/mock/gomock"
"github.com/spectralops/teller/pkg/providers/mock_providers"
)

func TestAnsibleVault(t *testing.T) {
ctrl := gomock.NewController(t)
defer ctrl.Finish()
client := mock_providers.NewMockAnsibleVaultClient(ctrl)
path := "settings/prod/billing-svc"
pathmap := "settings/prod/billing-svc/all"
out := map[string]string{
"MG_KEY": "shazam",
"SMTP_PASS": "mailman",
}
client.EXPECT().Read(gomock.Eq(path)).Return(out, nil).AnyTimes()
client.EXPECT().Read(gomock.Eq(pathmap)).Return(out, nil).AnyTimes()

s := AnsibleVault{
client: client,
logger: GetTestLogger(),
}
AssertProvider(t, &s, true)
}
2 changes: 1 addition & 1 deletion pkg/providers/dotenv.go
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ func (a *Dotenv) GetMapping(p core.KeyPath) ([]core.EnvEntry, error) {
return entries, nil
}

func (a *Dotenv) Get(p core.KeyPath) (*core.EnvEntry, error) {
func (a *Dotenv) Get(p core.KeyPath) (*core.EnvEntry, error) { //nolint:dupl
a.logger.WithField("path", p.Path).Debug("read secret")
kvs, err := a.client.Read(p.Path)
if err != nil {
Expand Down
49 changes: 49 additions & 0 deletions pkg/providers/mock_providers/ansible_vault_mock.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

17 changes: 17 additions & 0 deletions pkg/wizard_template.go
Original file line number Diff line number Diff line change
Expand Up @@ -266,5 +266,22 @@ providers:
ETC_DSN:
field: SOME_KEY # Optional, accesses the environment variable SOME_KEY and maps it to ETC_DSN
{{end}}
{{- if index .ProviderKeys "ansible_vault" }}
# Configure via environment variables for integration:
# ANSIBLE_VAULT_PASSPHRASE: Ansible Vault Password
ansible_vault:
env_sync:
path: ansible/vars/vault_{{stage}}.yml
env:
KEY1:
path: ansible/vars/vault_{{stage}}.yml
NONEXIST_KEY:
path: ansible/vars/vault_{{stage}}.yml
{{end}}
`
Loading

0 comments on commit 358cd83

Please sign in to comment.