Skip to content

Commit

Permalink
adding secrets manager to encrypt, edit and decrypt config
Browse files Browse the repository at this point in the history
  • Loading branch information
devdinu committed Jun 28, 2023
1 parent 4a9a214 commit 8bf5860
Show file tree
Hide file tree
Showing 10 changed files with 817 additions and 8 deletions.
1 change: 1 addition & 0 deletions .golangci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ linters:
- gochecknoglobals
- nlreturn
- godox
- wrapcheck

linters-settings:
lll:
Expand Down
4 changes: 2 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ setup:
curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s v1.46.2

install:
go install --ldflags="${LDFLAGS}" .
go install --ldflags="${LDFLAGS}" ./cmd/dolores/

lint: setup
./bin/golangci-lint run
Expand All @@ -26,4 +26,4 @@ gomod:
go mod tidy

build: gomod
go build --ldflags="${LDFLAGS}" .
go build --ldflags="${LDFLAGS}" -o ./bin ./cmd/dolores/
74 changes: 74 additions & 0 deletions client/client.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
package client

import (
"context"

"github.com/rs/zerolog/log"
"github.com/scalescape/dolores/config"
"github.com/scalescape/dolores/store/google"
)

type Client struct {
Service
bucket string
ctx context.Context //nolint:containedctx
}

type EncryptedConfig struct {
Environment string `json:"environment"`
Name string `json:"name"`
Data string `json:"data"`
}

func (c *Client) UploadSecrets(req EncryptedConfig) error {
log.Trace().Msgf("uploading to %s name: %s", c.bucket, req.Name)
return c.Service.Upload(c.ctx, req, c.bucket)
}

type FetchSecretRequest struct {
Environment string `json:"environment"`
Name string `json:"name"`
}
type FetchSecretResponse struct {
Data string `json:"data"`
}

func (c *Client) FetchSecrets(req FetchSecretRequest) ([]byte, error) {
data, err := c.Service.FetchConfig(c.ctx, c.bucket, req)
if err != nil {
return nil, err
}
return data, nil
}

type Recipient struct {
PublicKey string `json:"public_key"`
}

type OrgPublicKeys struct {
Recipients []Recipient `json:"recipients"`
}

func (c *Client) GetOrgPublicKeys(env string) (OrgPublicKeys, error) {
keys, err := c.Service.GetOrgPublicKeys(c.ctx, env, c.bucket)
if err != nil || len(keys) == 0 {
return OrgPublicKeys{}, err
}
recps := make([]Recipient, len(keys))
for i, k := range keys {
recps[i].PublicKey = k
}
return OrgPublicKeys{Recipients: recps}, nil
}

func New(ctx context.Context, cfg config.Client) (*Client, error) {
if err := cfg.Valid(); err != nil {
return nil, err
}
gcfg := google.Config{ServiceAccountFile: cfg.Google.ApplicationCredentials}
st, err := google.NewStore(ctx, gcfg)
if err != nil {
return nil, err
}
return &Client{ctx: ctx, Service: Service{store: st}, bucket: cfg.BucketName()}, nil
}
87 changes: 87 additions & 0 deletions client/service.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
package client

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

"github.com/rs/zerolog/log"
"github.com/scalescape/dolores/config"
"github.com/scalescape/dolores/store/google"
)

var ErrInvalidPublicKeys = errors.New("invalid public keys")

const metadataFile = "metadata"

type Service struct {
store google.StorageClient
}

func (s Service) Upload(ctx context.Context, req EncryptedConfig, bucket string) error {
prefix, err := s.getObjectPrefix(ctx, req.Environment, bucket)
if err != nil {
return err
}
fileName := req.Name
if prefix != "" {
fileName = fmt.Sprintf("%s/%s", prefix, fileName)
}
data, err := base64.StdEncoding.DecodeString(req.Data)
if err != nil {
return err
}
return s.store.WriteToObject(ctx, bucket, fileName, data)
}

func (s Service) GetOrgPublicKeys(ctx context.Context, env, bucketName string) ([]string, error) {
pubKey := os.Getenv("DOLORES_PUBLIC_KEY")
if pubKey != "" {
return []string{pubKey}, nil
}
return nil, ErrInvalidPublicKeys
}

func (s Service) getObjectPrefix(ctx context.Context, env, bucket string) (string, error) {
md, err := s.readMetadata(ctx, bucket, metadataFile)
if err != nil {
return "", fmt.Errorf("failed to read metadata: %w", err)
}
var meta config.Metadata
if err := json.Unmarshal(md, &meta); err != nil {
return "", fmt.Errorf("failed to parse metadata file: %w", err)
}
return meta.Locations[env], nil
}

func (s Service) FetchConfig(ctx context.Context, bucket string, req FetchSecretRequest) ([]byte, error) {
fileName := req.Name
prefix, err := s.getObjectPrefix(ctx, req.Environment, bucket)
if err != nil {
return nil, err
}
if prefix != "" {
fileName = fmt.Sprintf("%s/%s", prefix, fileName)
}
data, err := s.store.ReadObject(ctx, bucket, fileName)
if err != nil {
return nil, fmt.Errorf("failed to read config %s with error: %w", fileName, err)
}
return data, nil
}

func (s Service) readMetadata(ctx context.Context, bucket, mdf string) ([]byte, error) {
log.Trace().Msgf("reading metadata from bucket:%s file:%s", bucket, mdf)
return s.store.ReadObject(ctx, bucket, mdf)
}

func (s Service) SaveMetadata(ctx context.Context, bucket string, md config.Metadata) error {
data, err := json.Marshal(md)
if err != nil {
return err
}
return s.store.WriteToObject(ctx, bucket, metadataFile, data)
}
37 changes: 35 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,50 @@ module github.com/scalescape/dolores
go 1.19

require (
cloud.google.com/go/storage v1.30.1
filippo.io/age v1.1.1
github.com/AlecAivazis/survey/v2 v2.3.7
github.com/kelseyhightower/envconfig v1.4.0
github.com/rs/zerolog v1.29.1
github.com/stretchr/testify v1.8.4
github.com/urfave/cli/v2 v2.25.7
google.golang.org/api v0.129.0
)

require (
cloud.google.com/go v0.110.0 // indirect
cloud.google.com/go/compute v1.19.3 // indirect
cloud.google.com/go/compute/metadata v0.2.3 // indirect
cloud.google.com/go/iam v0.13.0 // indirect
github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
github.com/golang/protobuf v1.5.3 // indirect
github.com/google/go-cmp v0.5.9 // indirect
github.com/google/s2a-go v0.1.4 // indirect
github.com/google/uuid v1.3.0 // indirect
github.com/googleapis/enterprise-certificate-proxy v0.2.5 // indirect
github.com/googleapis/gax-go/v2 v2.11.0 // indirect
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect
github.com/mattn/go-colorable v0.1.12 // indirect
github.com/mattn/go-isatty v0.0.14 // indirect
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
golang.org/x/crypto v0.4.0 // indirect
golang.org/x/sys v0.3.0 // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect
go.opencensus.io v0.24.0 // indirect
golang.org/x/crypto v0.10.0 // indirect
golang.org/x/net v0.11.0 // indirect
golang.org/x/oauth2 v0.9.0 // indirect
golang.org/x/sys v0.9.0 // indirect
golang.org/x/term v0.9.0 // indirect
golang.org/x/text v0.10.0 // indirect
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect
google.golang.org/appengine v1.6.7 // indirect
google.golang.org/genproto v0.0.0-20230530153820-e85fd2cbaebc // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20230530153820-e85fd2cbaebc // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20230530153820-e85fd2cbaebc // indirect
google.golang.org/grpc v1.56.1 // indirect
google.golang.org/protobuf v1.31.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
Loading

0 comments on commit 8bf5860

Please sign in to comment.