-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
adding secrets manager to encrypt, edit and decrypt config
- Loading branch information
Showing
10 changed files
with
817 additions
and
8 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -98,6 +98,7 @@ linters: | |
- gochecknoglobals | ||
- nlreturn | ||
- godox | ||
- wrapcheck | ||
|
||
linters-settings: | ||
lll: | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.