andrey
10 months ago
7 changed files with 433 additions and 4 deletions
@ -0,0 +1,29 @@ |
|||||
|
module gitoa.ru/go-4devs/config/provider/vault |
||||
|
|
||||
|
go 1.21 |
||||
|
|
||||
|
require ( |
||||
|
github.com/hashicorp/vault/api v1.11.0 |
||||
|
gitoa.ru/go-4devs/config v0.0.2 |
||||
|
) |
||||
|
|
||||
|
require ( |
||||
|
github.com/cenkalti/backoff/v3 v3.0.0 // indirect |
||||
|
github.com/go-jose/go-jose/v3 v3.0.1 // indirect |
||||
|
github.com/hashicorp/errwrap v1.1.0 // indirect |
||||
|
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect |
||||
|
github.com/hashicorp/go-multierror v1.1.1 // indirect |
||||
|
github.com/hashicorp/go-retryablehttp v0.6.6 // indirect |
||||
|
github.com/hashicorp/go-rootcerts v1.0.2 // indirect |
||||
|
github.com/hashicorp/go-secure-stdlib/parseutil v0.1.6 // indirect |
||||
|
github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 // indirect |
||||
|
github.com/hashicorp/go-sockaddr v1.0.2 // indirect |
||||
|
github.com/hashicorp/hcl v1.0.0 // indirect |
||||
|
github.com/mitchellh/go-homedir v1.1.0 // indirect |
||||
|
github.com/mitchellh/mapstructure v1.5.0 // indirect |
||||
|
github.com/ryanuber/go-glob v1.0.0 // indirect |
||||
|
golang.org/x/crypto v0.17.0 // indirect |
||||
|
golang.org/x/net v0.17.0 // indirect |
||||
|
golang.org/x/text v0.14.0 // indirect |
||||
|
golang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1 // indirect |
||||
|
) |
@ -0,0 +1,92 @@ |
|||||
|
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= |
||||
|
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= |
||||
|
github.com/cenkalti/backoff/v3 v3.0.0 h1:ske+9nBpD9qZsTBoF41nW5L+AIuFBKMeze18XQ3eG1c= |
||||
|
github.com/cenkalti/backoff/v3 v3.0.0/go.mod h1:cIeZDE3IrqwwJl6VUwCN6trj1oXrTS4rc0ij+ULvLYs= |
||||
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= |
||||
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= |
||||
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= |
||||
|
github.com/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys= |
||||
|
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= |
||||
|
github.com/go-jose/go-jose/v3 v3.0.1 h1:pWmKFVtt+Jl0vBZTIpz/eAKwsm6LkIxDVVbFHKkchhA= |
||||
|
github.com/go-jose/go-jose/v3 v3.0.1/go.mod h1:RNkWWRld676jZEYoV3+XK8L2ZnNSvIsxFMht0mSX+u8= |
||||
|
github.com/go-test/deep v1.0.2 h1:onZX1rnHT3Wv6cqNgYyFOOlgVKJrksuCMCRvJStbMYw= |
||||
|
github.com/go-test/deep v1.0.2/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA= |
||||
|
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= |
||||
|
github.com/google/go-cmp v0.5.7 h1:81/ik6ipDQS2aGcBfIN5dHDB36BwrStyeAQquSYCV4o= |
||||
|
github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= |
||||
|
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= |
||||
|
github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= |
||||
|
github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= |
||||
|
github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= |
||||
|
github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= |
||||
|
github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= |
||||
|
github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= |
||||
|
github.com/hashicorp/go-hclog v0.16.2 h1:K4ev2ib4LdQETX5cSZBG0DVLk1jwGqSPXBjdah3veNs= |
||||
|
github.com/hashicorp/go-hclog v0.16.2/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= |
||||
|
github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= |
||||
|
github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= |
||||
|
github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= |
||||
|
github.com/hashicorp/go-retryablehttp v0.6.6 h1:HJunrbHTDDbBb/ay4kxa1n+dLmttUlnP3V9oNE4hmsM= |
||||
|
github.com/hashicorp/go-retryablehttp v0.6.6/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY= |
||||
|
github.com/hashicorp/go-rootcerts v1.0.2 h1:jzhAVGtqPKbwpyCPELlgNWhE1znq+qwJtW5Oi2viEzc= |
||||
|
github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= |
||||
|
github.com/hashicorp/go-secure-stdlib/parseutil v0.1.6 h1:om4Al8Oy7kCm/B86rLCLah4Dt5Aa0Fr5rYBG60OzwHQ= |
||||
|
github.com/hashicorp/go-secure-stdlib/parseutil v0.1.6/go.mod h1:QmrqtbKuxxSWTN3ETMPuB+VtEiBJ/A9XhoYGv8E1uD8= |
||||
|
github.com/hashicorp/go-secure-stdlib/strutil v0.1.1/go.mod h1:gKOamz3EwoIoJq7mlMIRBpVTAUn8qPCrEclOKKWhD3U= |
||||
|
github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 h1:kes8mmyCpxJsI7FTwtzRqEy9CdjCtrXrXGuOpxEA7Ts= |
||||
|
github.com/hashicorp/go-secure-stdlib/strutil v0.1.2/go.mod h1:Gou2R9+il93BqX25LAKCLuM+y9U2T4hlwvT1yprcna4= |
||||
|
github.com/hashicorp/go-sockaddr v1.0.2 h1:ztczhD1jLxIRjVejw8gFomI1BQZOe2WoVOu0SyteCQc= |
||||
|
github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A= |
||||
|
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= |
||||
|
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= |
||||
|
github.com/hashicorp/vault/api v1.11.0 h1:AChWByeHf4/P9sX3Y1B7vFsQhZO2BgQiCMQ2SA1P1UY= |
||||
|
github.com/hashicorp/vault/api v1.11.0/go.mod h1:si+lJCYO7oGkIoNPAN8j3azBLTn9SjMGS+jFaHd1Cck= |
||||
|
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= |
||||
|
github.com/mattn/go-colorable v0.1.6 h1:6Su7aK7lXmJ/U79bYtBjLNaha4Fs1Rg9plHpcH+vvnE= |
||||
|
github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= |
||||
|
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= |
||||
|
github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY= |
||||
|
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= |
||||
|
github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= |
||||
|
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-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= |
||||
|
github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= |
||||
|
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= |
||||
|
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= |
||||
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= |
||||
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= |
||||
|
github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= |
||||
|
github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= |
||||
|
github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk= |
||||
|
github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= |
||||
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= |
||||
|
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= |
||||
|
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= |
||||
|
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= |
||||
|
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= |
||||
|
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= |
||||
|
gitoa.ru/go-4devs/config v0.0.2 h1:bkTxW57kDDMf4cj/8W7fxPSN7JCPWEqlhCmL6LP3Vzg= |
||||
|
gitoa.ru/go-4devs/config v0.0.2/go.mod h1:xfEC2Al9xnMLJUuekYs3KhJ5BIzWAseNwkMwbN6/xss= |
||||
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= |
||||
|
golang.org/x/crypto v0.0.0-20190911031432-227b76d455e7/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= |
||||
|
golang.org/x/crypto v0.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k= |
||||
|
golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= |
||||
|
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= |
||||
|
golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= |
||||
|
golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= |
||||
|
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= |
||||
|
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= |
||||
|
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= |
||||
|
golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc= |
||||
|
golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= |
||||
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= |
||||
|
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= |
||||
|
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= |
||||
|
golang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1 h1:NusfzzA6yGQ+ua51ck7E3omNUX/JuqbFSaRGqU8CcLI= |
||||
|
golang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= |
||||
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= |
||||
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= |
||||
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= |
||||
|
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= |
||||
|
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= |
@ -0,0 +1,120 @@ |
|||||
|
package vault |
||||
|
|
||||
|
import ( |
||||
|
"context" |
||||
|
"encoding/json" |
||||
|
"fmt" |
||||
|
"strings" |
||||
|
|
||||
|
"github.com/hashicorp/vault/api" |
||||
|
"gitoa.ru/go-4devs/config" |
||||
|
"gitoa.ru/go-4devs/config/value" |
||||
|
) |
||||
|
|
||||
|
const ( |
||||
|
Name = "vault" |
||||
|
Separator = "/" |
||||
|
Prefix = "secret/data/" |
||||
|
ValueName = "value" |
||||
|
) |
||||
|
|
||||
|
var _ config.Provider = (*Provider)(nil) |
||||
|
|
||||
|
type SecretOption func(*Provider) |
||||
|
|
||||
|
func WithSecretResolve(f func(key []string) (string, string)) SecretOption { |
||||
|
return func(s *Provider) { s.resolve = f } |
||||
|
} |
||||
|
|
||||
|
func New(namespace, appName string, client *api.Client, opts ...SecretOption) *Provider { |
||||
|
prov := Provider{ |
||||
|
client: client, |
||||
|
resolve: func(key []string) (string, string) { |
||||
|
keysLen := len(key) |
||||
|
if keysLen == 1 { |
||||
|
return "", key[0] |
||||
|
} |
||||
|
|
||||
|
return strings.Join(key[:keysLen-1], Separator), key[keysLen-1] |
||||
|
}, |
||||
|
name: Name, |
||||
|
prefix: Prefix + namespace + Separator + appName, |
||||
|
} |
||||
|
|
||||
|
for _, opt := range opts { |
||||
|
opt(&prov) |
||||
|
} |
||||
|
|
||||
|
return &prov |
||||
|
} |
||||
|
|
||||
|
type Provider struct { |
||||
|
client *api.Client |
||||
|
resolve func(key []string) (string, string) |
||||
|
name string |
||||
|
prefix string |
||||
|
} |
||||
|
|
||||
|
func (p *Provider) Name() string { |
||||
|
return p.name |
||||
|
} |
||||
|
|
||||
|
func (p *Provider) Key(in []string) (string, string) { |
||||
|
path, val := p.resolve(in) |
||||
|
if path == "" { |
||||
|
return p.prefix, val |
||||
|
} |
||||
|
|
||||
|
return p.prefix + Separator + path, val |
||||
|
} |
||||
|
|
||||
|
func (p *Provider) read(path, key string) (*api.Secret, error) { |
||||
|
secret, err := p.client.Logical().Read(path) |
||||
|
if err != nil { |
||||
|
return nil, fmt.Errorf("read[%s:%s]:%w", path, key, err) |
||||
|
} |
||||
|
|
||||
|
if secret == nil && key != ValueName { |
||||
|
return p.read(path+Separator+key, ValueName) |
||||
|
} |
||||
|
|
||||
|
return secret, nil |
||||
|
} |
||||
|
|
||||
|
func (p *Provider) Value(_ context.Context, key ...string) (config.Value, error) { |
||||
|
path, field := p.Key(key) |
||||
|
|
||||
|
secret, err := p.read(path, field) |
||||
|
if err != nil { |
||||
|
return nil, fmt.Errorf("%w: path:%s, field:%s, provider:%s", err, path, field, p.Name()) |
||||
|
} |
||||
|
|
||||
|
if secret == nil || len(secret.Data) == 0 { |
||||
|
return nil, fmt.Errorf("%w: path:%s, field:%s, provider:%s", config.ErrValueNotFound, path, field, p.Name()) |
||||
|
} |
||||
|
|
||||
|
if len(secret.Warnings) > 0 { |
||||
|
return nil, |
||||
|
fmt.Errorf("%w: warn: %s, path:%s, field:%s, provider:%s", config.ErrValueNotFound, secret.Warnings, path, field, p.Name()) |
||||
|
} |
||||
|
|
||||
|
data, ok := secret.Data["data"].(map[string]interface{}) |
||||
|
if !ok { |
||||
|
return nil, fmt.Errorf("%w: path:%s, field:%s, provider:%s", config.ErrValueNotFound, path, field, p.Name()) |
||||
|
} |
||||
|
|
||||
|
if val, ok := data[field]; ok { |
||||
|
return value.JString(fmt.Sprint(val)), nil |
||||
|
} |
||||
|
|
||||
|
if val, ok := data[ValueName]; ok { |
||||
|
return value.JString(fmt.Sprint(val)), nil |
||||
|
} |
||||
|
|
||||
|
md, err := json.Marshal(data) |
||||
|
if err != nil { |
||||
|
return nil, fmt.Errorf("%w: %w", config.ErrInvalidValue, err) |
||||
|
} |
||||
|
|
||||
|
return value.JBytes(md), nil |
||||
|
} |
@ -0,0 +1,47 @@ |
|||||
|
package vault_test |
||||
|
|
||||
|
import ( |
||||
|
"context" |
||||
|
"fmt" |
||||
|
"log" |
||||
|
|
||||
|
"gitoa.ru/go-4devs/config" |
||||
|
"gitoa.ru/go-4devs/config/provider/vault" |
||||
|
) |
||||
|
|
||||
|
func ExampleClient_Value() { |
||||
|
const ( |
||||
|
namespace = "fdevs" |
||||
|
appName = "config" |
||||
|
) |
||||
|
|
||||
|
ctx := context.Background() |
||||
|
|
||||
|
// configure vault client
|
||||
|
vaultClient, err := NewVault() |
||||
|
if err != nil { |
||||
|
log.Print(err) |
||||
|
|
||||
|
return |
||||
|
} |
||||
|
|
||||
|
config, err := config.New( |
||||
|
vault.New(namespace, appName, vaultClient), |
||||
|
) |
||||
|
if err != nil { |
||||
|
log.Print(err) |
||||
|
|
||||
|
return |
||||
|
} |
||||
|
|
||||
|
dsn, err := config.Value(ctx, "example", "dsn") |
||||
|
if err != nil { |
||||
|
log.Print("example:dsn ", err) |
||||
|
|
||||
|
return |
||||
|
} |
||||
|
|
||||
|
fmt.Printf("dsn from vault: %s\n", dsn.String()) |
||||
|
// Output:
|
||||
|
// dsn from vault: pgsql://user@pass:127.0.0.1:5432
|
||||
|
} |
@ -0,0 +1,26 @@ |
|||||
|
package vault_test |
||||
|
|
||||
|
import ( |
||||
|
"testing" |
||||
|
"time" |
||||
|
|
||||
|
"gitoa.ru/go-4devs/config/provider/vault" |
||||
|
"gitoa.ru/go-4devs/config/test" |
||||
|
"gitoa.ru/go-4devs/config/test/require" |
||||
|
) |
||||
|
|
||||
|
func TestProvider(t *testing.T) { |
||||
|
t.Parallel() |
||||
|
|
||||
|
cl, err := NewVault() |
||||
|
require.NoError(t, err) |
||||
|
|
||||
|
provider := vault.New("fdevs", "config", cl) |
||||
|
|
||||
|
read := []test.Read{ |
||||
|
test.NewReadConfig("database"), |
||||
|
test.NewRead(test.DSN, "db", "dsn"), |
||||
|
test.NewRead(time.Minute, "db", "timeout"), |
||||
|
} |
||||
|
test.Run(t, provider, read) |
||||
|
} |
@ -0,0 +1,90 @@ |
|||||
|
package vault_test |
||||
|
|
||||
|
import ( |
||||
|
"bytes" |
||||
|
"context" |
||||
|
"encoding/json" |
||||
|
"net/http" |
||||
|
"os" |
||||
|
|
||||
|
"github.com/hashicorp/vault/api" |
||||
|
"gitoa.ru/go-4devs/config/test" |
||||
|
) |
||||
|
|
||||
|
const token = "dev" |
||||
|
|
||||
|
func NewVault() (*api.Client, error) { |
||||
|
address, ok := os.LookupEnv("VAULT_DEV_LISTEN_ADDRESS") |
||||
|
if !ok { |
||||
|
address = "http://127.0.0.1:8200" |
||||
|
} |
||||
|
|
||||
|
tokenID, ok := os.LookupEnv("VAULT_DEV_ROOT_TOKEN_ID") |
||||
|
if !ok { |
||||
|
tokenID = token |
||||
|
} |
||||
|
|
||||
|
cl, err := api.NewClient(&api.Config{ |
||||
|
Address: address, |
||||
|
}) |
||||
|
if err != nil { |
||||
|
return nil, err |
||||
|
} |
||||
|
|
||||
|
cl.SetToken(tokenID) |
||||
|
|
||||
|
values := map[string]map[string]interface{}{ |
||||
|
"database": { |
||||
|
"duration": 1260000000000, |
||||
|
"enabled": true, |
||||
|
}, |
||||
|
"db": { |
||||
|
"dsn": test.DSN, |
||||
|
"timeout": "60s", |
||||
|
}, |
||||
|
"example": { |
||||
|
"dsn": test.DSN, |
||||
|
"timeout": "60s", |
||||
|
}, |
||||
|
} |
||||
|
|
||||
|
for name, val := range values { |
||||
|
if err := create(address, tokenID, name, val); err != nil { |
||||
|
return nil, err |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
return cl, nil |
||||
|
} |
||||
|
|
||||
|
func create(host, token, path string, data map[string]interface{}) error { |
||||
|
type Req struct { |
||||
|
Data interface{} `json:"data"` |
||||
|
} |
||||
|
|
||||
|
b, err := json.Marshal(Req{Data: data}) |
||||
|
if err != nil { |
||||
|
return err |
||||
|
} |
||||
|
|
||||
|
body := bytes.NewBuffer(b) |
||||
|
|
||||
|
req, err := http.NewRequestWithContext( |
||||
|
context.Background(), |
||||
|
http.MethodPost, |
||||
|
host+"/v1/secret/data/fdevs/config/"+path, |
||||
|
body, |
||||
|
) |
||||
|
if err != nil { |
||||
|
return err |
||||
|
} |
||||
|
|
||||
|
req.Header.Set("X-Vault-Token", token) |
||||
|
|
||||
|
res, err := http.DefaultClient.Do(req) |
||||
|
if err != nil { |
||||
|
return err |
||||
|
} |
||||
|
|
||||
|
return res.Body.Close() |
||||
|
} |
Loading…
Reference in new issue