1
0
mirror of https://github.com/raseels-repos/golang-saas-starter-kit.git synced 2025-07-05 00:58:54 +02:00

completed autocert implimentation for web-api

This commit is contained in:
Lee Brown
2019-07-13 03:03:30 -08:00
parent c757463a17
commit c5ea09d8e1
10 changed files with 164 additions and 129 deletions

View File

@ -7,26 +7,28 @@ import (
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/awserr"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/service/secretsmanager"
"github.com/pkg/errors"
"golang.org/x/crypto/acme/autocert"
"github.com/aws/aws-sdk-go/aws/session"
)
// SecretManagerAutocertCache implements the autocert.Cache interface for AWS Secrets Manager that is used by Manager
// to store and retrieve previously obtained certificates and other account data as opaque blobs.
type SecretManagerAutocertCache struct {
awsSession *session.Session
log *log.Logger
type SecretManagerAutocertCache struct {
awsSession *session.Session
log *log.Logger
secretPrefix string
cache autocert.Cache
}
// NewSecretManagerAutocertCache provides the functionality to keep config files sync'd between running tasks and across deployments.
func NewSecretManagerAutocertCache(log *log.Logger, awsSession *session.Session, secretPrefix string ) (*SecretManagerAutocertCache, error) {
func NewSecretManagerAutocertCache(log *log.Logger, awsSession *session.Session, secretPrefix string, cache autocert.Cache) (*SecretManagerAutocertCache, error) {
return &SecretManagerAutocertCache{
awsSession,
log,
secretPrefix,
cache,
}, nil
}
@ -34,6 +36,16 @@ func NewSecretManagerAutocertCache(log *log.Logger, awsSession *session.Session,
// If there's no such key, Get returns ErrCacheMiss.
func (c *SecretManagerAutocertCache) Get(ctx context.Context, key string) ([]byte, error) {
// Check short term cache.
if c.cache != nil {
v, err := c.cache.Get(ctx, key)
if err != nil && err != autocert.ErrCacheMiss {
return nil, errors.WithStack(err)
} else if len(v) > 0 {
return v, nil
}
}
svc := secretsmanager.New(c.awsSession)
secretID := filepath.Join(c.secretPrefix, key)
@ -43,7 +55,7 @@ func (c *SecretManagerAutocertCache) Get(ctx context.Context, key string) ([]byt
SecretId: aws.String(secretID),
})
if err != nil {
if aerr, ok := err.(awserr.Error); ok && aerr.Code() == secretsmanager.ErrCodeResourceNotFoundException {
if aerr, ok := err.(awserr.Error); ok && (aerr.Code() == secretsmanager.ErrCodeResourceNotFoundException || aerr.Code() == secretsmanager.ErrCodeInvalidRequestException) {
return nil, autocert.ErrCacheMiss
}
@ -52,7 +64,7 @@ func (c *SecretManagerAutocertCache) Get(ctx context.Context, key string) ([]byt
log.Printf("AWS Secrets Manager : Secret %s found", secretID)
return res.SecretBinary, nil
return []byte(*res.SecretString), nil
}
// Put stores the data in the cache under the specified key.
@ -70,28 +82,27 @@ func (c *SecretManagerAutocertCache) Put(ctx context.Context, key string, data [
SecretString: aws.String(string(data)),
})
if err != nil {
if aerr, ok := err.(awserr.Error); !ok {
aerr, ok := err.(awserr.Error)
if aerr.Code() == secretsmanager.ErrCodeInvalidRequestException {
// InvalidRequestException: You can't create this secret because a secret with this
// name is already scheduled for deletion.
if ok && aerr.Code() == secretsmanager.ErrCodeInvalidRequestException {
// InvalidRequestException: You can't create this secret because a secret with this
// name is already scheduled for deletion.
// Restore secret after it was already previously deleted.
_, err = svc.RestoreSecret(&secretsmanager.RestoreSecretInput{
SecretId: aws.String(secretID),
})
if err != nil {
return errors.Wrapf(err, "autocert failed to restore secret %s", secretID)
}
} else if aerr.Code() != secretsmanager.ErrCodeResourceExistsException {
return errors.Wrapf(err, "autocert failed to create secret %s", secretID)
// Restore secret after it was already previously deleted.
_, err = svc.RestoreSecret(&secretsmanager.RestoreSecretInput{
SecretId: aws.String(secretID),
})
if err != nil {
return errors.Wrapf(err, "autocert failed to restore secret %s", secretID)
}
} else if !ok || aerr.Code() != secretsmanager.ErrCodeResourceExistsException {
return errors.Wrapf(err, "autocert failed to create secret %s", secretID)
}
// If where was a resource exists error for create, then need to update the secret instead.
_, err = svc.UpdateSecret(&secretsmanager.UpdateSecretInput{
SecretId: aws.String(secretID),
SecretId: aws.String(secretID),
SecretString: aws.String(string(data)),
})
if err != nil {
@ -103,6 +114,13 @@ func (c *SecretManagerAutocertCache) Put(ctx context.Context, key string, data [
log.Printf("AWS Secrets Manager : Secret %s created", secretID)
}
if c.cache != nil {
err = c.cache.Put(ctx, key, data)
if err != nil {
return errors.WithStack(err)
}
}
return nil
}
@ -116,7 +134,7 @@ func (c *SecretManagerAutocertCache) Delete(ctx context.Context, key string) err
// Create the new entry in AWS Secret Manager for the file.
_, err := svc.DeleteSecret(&secretsmanager.DeleteSecretInput{
SecretId: aws.String(secretID),
SecretId: aws.String(secretID),
// (Optional) Specifies that the secret is to be deleted without any recovery
// window. You can't use both this parameter and the RecoveryWindowInDays parameter
@ -145,7 +163,14 @@ func (c *SecretManagerAutocertCache) Delete(ctx context.Context, key string) err
return errors.Wrapf(err, "autocert failed to delete secret %s", secretID)
}
log.Printf("AWS Secrets Manager : Secret %s deleted for %s", secretID)
log.Printf("AWS Secrets Manager : Secret %s deleted", secretID)
if c.cache != nil {
err = c.cache.Delete(ctx, key)
if err != nil {
return errors.WithStack(err)
}
}
return nil
}

View File

@ -22,7 +22,7 @@ func SyncCfgInit(log *log.Logger, awsSession *session.Session, secretPrefix, wat
localfiles := make(map[string]time.Time)
// Do the initial sync before starting file watch to download any existing configs.
err := SyncCfgDir(log, awsSession, secretPrefix, watchDir, localfiles)
err := SyncCfgDir(log, awsSession, secretPrefix, watchDir, localfiles)
if err != nil {
return nil, err
}
@ -41,7 +41,6 @@ func SyncCfgInit(log *log.Logger, awsSession *session.Session, secretPrefix, wat
// Init the watch to wait for sync local files to Secret Manager.
WatchCfgDir(log, awsSession, secretPrefix, watchDir, watcher, localfiles)
// Init ticker to sync remote files from Secret Manager locally at the defined interval.
if syncInterval.Seconds() > 0 {
ticker := time.NewTicker(syncInterval)
@ -52,7 +51,7 @@ func SyncCfgInit(log *log.Logger, awsSession *session.Session, secretPrefix, wat
log.Println("AWS Secrets Manager : Checking for remote updates")
// Do the initial sync before starting file watch to download any existing configs.
err := SyncCfgDir(log, awsSession, secretPrefix, watchDir, localfiles)
err := SyncCfgDir(log, awsSession, secretPrefix, watchDir, localfiles)
if err != nil {
log.Printf("AWS Secrets Manager : Remote sync error - %+v", err)
}
@ -82,7 +81,7 @@ func SyncCfgDir(log *log.Logger, awsSession *session.Session, secretPrefix, watc
for _, s := range res.SecretList {
// Skip any secret that does not have a matching prefix.
if !strings.HasPrefix(*s.Name, secretPrefix) {
if !strings.HasPrefix(*s.Name, secretPrefix) {
continue
}
@ -192,7 +191,7 @@ func handleWatchCfgEvent(log *log.Logger, awsSession *session.Session, secretPre
// Restore secret after it was already previously deleted.
_, err = svc.RestoreSecret(&secretsmanager.RestoreSecretInput{
SecretId: aws.String(secretID),
SecretId: aws.String(secretID),
})
if err != nil {
return errors.Wrapf(err, "file watcher failed to restore secret %s for %s", secretID, event.Name)
@ -205,7 +204,7 @@ func handleWatchCfgEvent(log *log.Logger, awsSession *session.Session, secretPre
// If where was a resource exists error for create, then need to update the secret instead.
_, err = svc.UpdateSecret(&secretsmanager.UpdateSecretInput{
SecretId: aws.String(secretID),
SecretId: aws.String(secretID),
SecretString: aws.String(string(dat)),
})
if err != nil {
@ -225,7 +224,7 @@ func handleWatchCfgEvent(log *log.Logger, awsSession *session.Session, secretPre
// Create the new entry in AWS Secret Manager for the file.
_, err := svc.DeleteSecret(&secretsmanager.DeleteSecretInput{
SecretId: aws.String(secretID),
SecretId: aws.String(secretID),
// (Optional) Specifies that the secret is to be deleted without any recovery
// window. You can't use both this parameter and the RecoveryWindowInDays parameter

View File

@ -3,9 +3,6 @@ package devops
import (
"encoding/base64"
"encoding/json"
"fmt"
"github.com/sethgrid/pester"
"io/ioutil"
"log"
"os"
"strconv"
@ -33,15 +30,6 @@ func EcsServiceTaskInit(log *log.Logger, awsSession *session.Session) error {
return nil
}
res, err := pester.Get("http://169.254.170.2/v2/metadata")
if err != nil {
fmt.Println("http://169.254.170.2/v2/metadata failed", err.Error())
} else {
dat, _ := ioutil.ReadAll(res.Body)
res.Body.Close()
fmt.Println("http://169.254.170.2/v2/metadata, OK", string(dat))
}
var zoneArecNames = map[string][]string{}
if v := os.Getenv("ROUTE53_ZONES"); v != "" {
dat, err := base64.RawURLEncoding.DecodeString(v)
@ -241,6 +229,15 @@ func RegisterEcsServiceTasksRoute53(log *log.Logger, awsSession *session.Session
}
/*
res, err := pester.Get("http://169.254.170.2/v2/metadata")
if err != nil {
fmt.Println("http://169.254.170.2/v2/metadata failed", err.Error())
} else {
dat, _ := ioutil.ReadAll(res.Body)
res.Body.Close()
fmt.Println("http://169.254.170.2/v2/metadata, OK", string(dat))
}
http://169.254.170.2/v2/metadata,
{

View File

@ -19,7 +19,7 @@ import (
// Headers
const (
HeaderUpgrade = "Upgrade"
HeaderUpgrade = "Upgrade"
HeaderXForwardedFor = "X-Forwarded-For"
HeaderXForwardedProto = "X-Forwarded-Proto"
HeaderXForwardedProtocol = "X-Forwarded-Protocol"