Skip to content

Commit

Permalink
Merge pull request #35 from goreflect/issue-34
Browse files Browse the repository at this point in the history
start implemented vault configuring
  • Loading branch information
kubitre committed Dec 3, 2020
2 parents d9c51e0 + 2bf5075 commit 2f72a65
Show file tree
Hide file tree
Showing 8 changed files with 492 additions and 13 deletions.
21 changes: 19 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

____

## Version: v0.4.5
## Version: v0.5.1

Universal configuration library by tags

Expand All @@ -12,6 +12,7 @@ Universal configuration library by tags
- hocon values
- default values
- environment variables
- vault configs

## Current supporting types

Expand All @@ -30,7 +31,7 @@ Universal configuration library by tags
- [ ] cf_yaml - setup value for this field from yaml (version > 0.6)
- [x] cf_json - setup value for this field from json (version > 0.5)
- [ ] cf_server - setup value from configuration server like spring cloud config server or others (version>0.7)
- [ ] cf_vault - setup secret for this field from hashi corp vault (version>0.8)
- [x] cf_vault - setup secret for this field from hashi corp vault

## Running configuring by smart variant

Expand Down Expand Up @@ -87,3 +88,19 @@ func myConfigurator() {
}

```

## Fetch settings secrets from vault

For fetching secrets you should add 2 environment variables: VAULT_ADDRESS, VAULT_TOKEN. After all, you can add cf_vault tag into your structure tags.

Now vault configure support all basic types and also complex type: slice

For Example:

```go
type Test struct {
MySecretKey string `cf_vault:"my-secret-service/stage/tururu#my-key"`
MyCustomIntKey int16 `cf_vault:"my-secret-service/stage/tururur#my-key2"`
TestSda []int32 `cf_vault:"my-secret-service/stage/tururu#my-key3"`
}
```
10 changes: 4 additions & 6 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
module github.com/goreflect/gostructor

go 1.13
go 1.15

require (
github.com/go-restit/lzjson v0.0.0-20161206095556-efe3c53acc68
github.com/google/go-cmp v0.5.2 // indirect
github.com/goreflect/go_hocon v0.0.2
github.com/pkg/errors v0.9.1 // indirect
github.com/sirupsen/logrus v1.5.0
github.com/stretchr/testify v1.5.1
gotest.tools v2.2.0+incompatible
github.com/mittwald/vaultgo v0.0.6
github.com/sirupsen/logrus v1.7.0
github.com/stretchr/testify v1.6.1
)
327 changes: 327 additions & 0 deletions go.sum

Large diffs are not rendered by default.

5 changes: 2 additions & 3 deletions pipeline/pipeline.go
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ func getChainByIdentifier(
return nil, sourceFileInDisk, errors.New(notSupportedTypeError +
"yaml configurator source. Not implemented yet")
case infra.FunctionSetupVault:
return nil, sourceFielInServer, errors.New(notSupportedTypeError + "vault configurator source. Not implemented yet")
return &VaultConfig{}, sourceFielInServer, nil
case infra.FunctionSetupConfigServer:
return nil, sourceFielInServer, errors.New(notSupportedTypeError + "configure server configurator source. Not implemented yet")
default:
Expand Down Expand Up @@ -250,7 +250,6 @@ func (pipeline *Pipeline) preparedInlineStructFields(value reflect.Value, contex
StructField: value.Type().Field(i),
Prefix: pipeline.preparePrefix(context.Prefix, value.Type().Field(i)),
}); err != nil {
pipeline.addNewErrorWhileParsing(err.Error())
return pipeline.getErrorAsOne()
}
}
Expand Down Expand Up @@ -335,7 +334,7 @@ func (pipeline *Pipeline) setNextChain() error {
pipeline.curentChain = pipeline.chains
return nil
}
if pipeline.curentChain.next == nil {
if pipeline.curentChain.next == nil || pipeline.curentChain.next.stageFunction == nil {
return errors.New("can not change chain function")
}
pipeline.curentChain = pipeline.curentChain.next
Expand Down
4 changes: 2 additions & 2 deletions pipeline/pipeline_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -136,9 +136,9 @@ func Test_getChainByIdentifier(t *testing.T) {
args: args{
idFunc: infra.FunctionSetupVault,
},
want: nil,
want: &VaultConfig{},
want1: sourceFielInServer,
wantErr: true,
wantErr: false,
},
{
name: "check unknown setup function",
Expand Down
106 changes: 106 additions & 0 deletions pipeline/vault_func.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
package pipeline

import (
"errors"
"reflect"
"strings"

"github.com/goreflect/gostructor/converters"
"github.com/goreflect/gostructor/infra"
"github.com/goreflect/gostructor/properties"
"github.com/goreflect/gostructor/tags"
vault "github.com/mittwald/vaultgo"
"github.com/sirupsen/logrus"
)

/*VaultConfig - source vault configuring*/
type VaultConfig struct {
Config *properties.VaultConfiguration
connection *vault.Client
}

func (config *VaultConfig) configureVault() error {
configured, errConfigure := Configure(&properties.VaultConfiguration{}, "", []infra.FuncType{infra.FunctionSetupEnvironment}, "", true)
if errConfigure != nil {
logrus.Error("Can not initialize vault properties. Please setup VAULT_ADDRESS & VAULT_TOKEN for working with cf_vault")
return errConfigure
}
config.Config = configured.(*properties.VaultConfiguration)
return nil
}

func (config *VaultConfig) connect() error {
conn, errConnection := vault.NewClient(config.Config.VaultAddress,
vault.WithCaPath(""),
vault.WithAuthToken(config.Config.VaultToken))
if errConnection != nil {
return errConnection
}
conn.SetToken(config.Config.VaultToken)
config.connection = conn
return nil
}

func (config *VaultConfig) vaultAvailable() error {
if config.Config == nil {
if err := config.configureVault(); err != nil {
logrus.Error("Configure Vault Error: ", err)
return err
}
}

if config.connection == nil {
return config.connect()
}
return nil
}

func (config *VaultConfig) prepareLayer(context *structContext) error {
if err := config.configureVault(); err != nil {
return err
}

if errConn := config.vaultAvailable(); errConn != nil {
logrus.Error("Error while connect to vault: ", errConn)
return errConn
}
return nil
}

func (config VaultConfig) GetBaseType(context *structContext) infra.GoStructorValue {
if err := config.prepareLayer(context); err != nil {
return infra.NewGoStructorNoValue(context.Value, err)
}
nameField := context.StructField.Tag.Get(tags.TagHashiCorpVault)
path := strings.Split(nameField, "#")[0]
secretName := strings.Split(nameField, "#")[1]
secret, err := config.connection.Logical().Read(path)
secretValue := secret.Data[secretName]
logrus.Debug("Secret Vault: ", secretValue)
if err != nil {
logrus.Error("Error while reading config from vault: ", err)
return infra.NewGoStructorNoValue(context.Value, err)
}
return converters.ConvertBetweenPrimitiveTypes(reflect.ValueOf(secret.Data[secretName]), reflect.Indirect(context.Value))
}

func (config VaultConfig) GetComplexType(context *structContext) infra.GoStructorValue {
if err := config.prepareLayer(context); err != nil {
return infra.NewGoStructorNoValue(context.Value, err)
}
nameField := context.StructField.Tag.Get(tags.TagHashiCorpVault)
path := strings.Split(nameField, "#")[0]
secretName := strings.Split(nameField, "#")[1]
secret, err := config.connection.Logical().Read(path)
secretValue := secret.Data[secretName]
logrus.Debug("Secret Vault: ", secretValue)
if err != nil {
logrus.Error("Error while reading config from vault: ", err)
return infra.NewGoStructorNoValue(context.Value, err)
}
kind := reflect.Indirect(context.Value).Kind()
if kind == reflect.Slice {
return converters.ConvertBetweenComplexTypes(reflect.ValueOf(strings.Split(secret.Data[secretName].(string), ",")), reflect.Indirect(context.Value))
}
return infra.NewGoStructorNoValue(context.Value, errors.New("not supported complex type"))
}
26 changes: 26 additions & 0 deletions pipeline/vault_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package pipeline

import (
"os"
"testing"

"github.com/goreflect/gostructor/infra"
)

type TestStruct struct {
MyAPIKey string `cf_vault:"test/tururu#api-key"`
MyIntKey int64 `cf_vault:"test/tururu#kur"`
MyCustomComplexType []int32 `cf_vault:"test/tururu#kur2"`
}

func TestConnectionToVault(t *testing.T) {
os.Setenv("VAULT_URL", "http://localhost:1234")
os.Setenv("VAULT_TOKEN", "myroot")
result, err := Configure(&TestStruct{}, "", []infra.FuncType{infra.FunctionSetupVault}, "", true)
if err != nil {
t.Fail()
t.Log(err)
return
}
t.Log(result)
}
6 changes: 6 additions & 0 deletions properties/vault.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package properties

type VaultConfiguration struct {
VaultAddress string `cf_env:"VAULT_URL"`
VaultToken string `cf_env:"VAULT_TOKEN"`
}

0 comments on commit 2f72a65

Please sign in to comment.