Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

AWS App Config #23

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
149 changes: 149 additions & 0 deletions backend/appconfig/appconfig.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
package appconfig

import (
"errors"
"fmt"
"os"
"sync"
"time"

"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/credentials"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/service/appconfig"
"github.com/bketelsen/crypt/backend"
)

type Client struct {
client *appconfig.AppConfig
application *string
environment *string
data *data
}

type value struct {
version *string
value []byte
}

type data struct {
mu sync.RWMutex
data map[string]*value
}

func New(machines []string) (*Client, error) {
provider, err := session.NewSession(&aws.Config{
Credentials: credentials.NewEnvCredentials(),
})
if err != nil {
return nil, fmt.Errorf("creating new aws session for crypt.backend.Client: %v", err)
}
appConfig := appconfig.New(provider)
if len(machines) == 0 {
return nil, errors.New("application should be defined")
}
return &Client{
client: appConfig,
application: aws.String(machines[0]),
environment: aws.String(os.Getenv("AWS_ENV")),
data: &data{data: make(map[string]*value)},
}, nil
}

func (c *Client) Get(key string) ([]byte, error) {
// get existing data
b := c.getExistingData(key)
if b != nil {
return b, nil
}
// no existing data exists
config, err := c.getConfiguration(nil, aws.String(key))
if err != nil {
return nil, fmt.Errorf("getting configuration for %s: %v", key, err)
}
// save and return data
return c.saveAndReturnData(key, config), nil
}

func (c *Client) List(key string) (backend.KVPairs, error) {
b, err := c.Get(key)
if err != nil {
return nil, err
}
return []*backend.KVPair{{
Key: key,
Value: b,
}}, nil
}

func (c *Client) Set(string, []byte) error {
return nil
}

func (c *Client) Watch(key string, stop chan bool) <-chan *backend.Response {
ch := make(chan *backend.Response, 0)
t := time.NewTicker(time.Second)
go func() {
for {
select {
case <-t.C:
config, err := c.getConfiguration(c.getExistingVersion(key), aws.String(key))
if err == nil {
ch <- &backend.Response{
Value: c.saveAndReturnData(key, config),
Error: nil,
}
}
if err != nil {
time.Sleep(time.Second * 5)
}
case <-stop:
close(ch)
return
}
}
}()
return ch
}

func (c *Client) getExistingData(key string) []byte {
c.data.mu.RLock()
defer c.data.mu.RUnlock()
if v, ok := c.data.data[key]; ok {
b := make([]byte, len(v.value))
copy(b, v.value)
return b
}
return nil
}

func (c *Client) getExistingVersion(key string) *string {
c.data.mu.RLock()
defer c.data.mu.RUnlock()
if v, ok := c.data.data[key]; ok {
return v.version
}
return nil
}

func (c *Client) getConfiguration(version, configuration *string) (*appconfig.GetConfigurationOutput, error) {
return c.client.GetConfiguration(&appconfig.GetConfigurationInput{
Application: c.application,
ClientId: aws.String("crypt-app-config"),
Configuration: configuration,
ClientConfigurationVersion: version,
Environment: c.environment,
})
}

func (c *Client) saveAndReturnData(key string, config *appconfig.GetConfigurationOutput) []byte {
c.data.mu.Lock()
defer c.data.mu.Unlock()
c.data.data[key] = &value{
version: config.ConfigurationVersion,
value: config.Content,
}
b := make([]byte, len(config.Content))
copy(b, config.Content)
return b
}
20 changes: 20 additions & 0 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"io/ioutil"

"github.com/bketelsen/crypt/backend"
"github.com/bketelsen/crypt/backend/appconfig"
"github.com/bketelsen/crypt/backend/consul"
"github.com/bketelsen/crypt/backend/etcd"
"github.com/bketelsen/crypt/backend/firestore"
Expand Down Expand Up @@ -47,6 +48,15 @@ func NewConfigManager(client backend.Store, keystore io.Reader) (ConfigManager,
return configManager{bytes, client}, nil
}

// NewStandardAppConfigManager returns a new ConfigManager backed by AWS App Config.
func NewStandardAppConfigManager(machines []string) (ConfigManager, error) {
store, err := appconfig.New(machines)
if err != nil {
return nil, err
}
return NewStandardConfigManager(store)
}

// NewStandardFirestoreConfigManager returns a new ConfigManager backed by Firestore.
func NewStandardFirestoreConfigManager(machines []string) (ConfigManager, error) {
store, err := firestore.New(machines)
Expand Down Expand Up @@ -75,6 +85,16 @@ func NewStandardConsulConfigManager(machines []string) (ConfigManager, error) {
return NewStandardConfigManager(store)
}

// NewAppConfigManager returns a new ConfigManager backed by AWS App Config.
// Data will be encrypted.
func NewAppConfigManager(machines []string, keystore io.Reader) (ConfigManager, error) {
store, err := appconfig.New(machines)
if err != nil {
return nil, err
}
return NewConfigManager(store, keystore)
}

// NewFirestoreConfigManager returns a new ConfigManager backed by Firestore.
// Data will be encrypted.
func NewFirestoreConfigManager(machines []string, keystore io.Reader) (ConfigManager, error) {
Expand Down
13 changes: 8 additions & 5 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,13 @@ module github.com/bketelsen/crypt
go 1.12

require (
cloud.google.com/go/firestore v1.1.0
github.com/hashicorp/consul/api v1.1.0
cloud.google.com/go/firestore v1.5.0
github.com/aws/aws-sdk-go v1.40.33
github.com/google/btree v1.0.0 // indirect
github.com/hashicorp/consul/api v1.10.0
github.com/hashicorp/golang-lru v0.5.1 // indirect
go.etcd.io/etcd/client/v2 v2.305.0
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9
google.golang.org/api v0.44.0
google.golang.org/grpc v1.38.0
golang.org/x/crypto v0.0.0-20210817164053-32db794688a5
google.golang.org/api v0.55.0
google.golang.org/grpc v1.40.0
)
Loading