Skip to content
Snippets Groups Projects
Commit 25cdcab8 authored by Billy Griffiths's avatar Billy Griffiths
Browse files

ADHOC - Expand secrets manager to support create and delete

parent c2d128a2
Branches
Tags
1 merge request!35ADHOC - Expand secrets manager to support create and delete
...@@ -2,6 +2,7 @@ package secrets_manager ...@@ -2,6 +2,7 @@ package secrets_manager
import ( import (
"encoding/base64" "encoding/base64"
"encoding/json"
credentials2 "github.com/aws/aws-sdk-go/aws/credentials" credentials2 "github.com/aws/aws-sdk-go/aws/credentials"
"os" "os"
...@@ -55,20 +56,19 @@ func GetS3UploadCredentials(secretID string, isDebug bool) (*credentials2.Creden ...@@ -55,20 +56,19 @@ func GetS3UploadCredentials(secretID string, isDebug bool) (*credentials2.Creden
return credentials2.NewStaticCredentials(credentials.AccessKeyID, credentials.SecretKey, ""), nil return credentials2.NewStaticCredentials(credentials.AccessKeyID, credentials.SecretKey, ""), nil
} }
func GetSecret(secretID string, isDebug bool) (string, string) { // createClient Instantiates a new Secrets Manager client
cachedSecret, err := secretCache.GetSecretString(secretID) func createClient(isDebug bool) (svc *secretsmanager.SecretsManager, err error) {
awsSession, err := session.NewSession()
if err != nil { if err != nil {
logs.Info("Failed to get secret key from cache") return svc, err
}
if cachedSecret != "" {
return cachedSecret, ""
} }
awsSession := session.New()
// Get local config // Get local config
if isDebug && os.Getenv("ENVIRONMENT") != "" { if isDebug && os.Getenv("ENVIRONMENT") != "" {
logs.Info("Using access key %s", os.Getenv("AWS_ACCESS_KEY_ID")) awsAccessKey := os.Getenv("AWS_ACCESS_KEY_ID")
if len(awsAccessKey) > 0 {
logs.Info("Using access key %s", awsAccessKey)
}
awsSession, err = session.NewSessionWithOptions(session.Options{ awsSession, err = session.NewSessionWithOptions(session.Options{
Config: aws.Config{ Config: aws.Config{
Region: aws.String("af-south-1"), Region: aws.String("af-south-1"),
...@@ -76,53 +76,53 @@ func GetSecret(secretID string, isDebug bool) (string, string) { ...@@ -76,53 +76,53 @@ func GetSecret(secretID string, isDebug bool) (string, string) {
}, },
}) })
if err != nil { if err != nil {
return "", "" return svc, err
} }
} }
// Create a Secrets Manager client // Create a Secrets Manager client
svc := secretsmanager.New(awsSession, aws.NewConfig().WithRegion(secretManagerRegion)) svc = secretsmanager.New(awsSession, aws.NewConfig().WithRegion(secretManagerRegion))
input := &secretsmanager.GetSecretValueInput{ return svc, nil
SecretId: aws.String(string(secretID)),
VersionStage: aws.String("AWSCURRENT"), // VersionStage defaults to AWSCURRENT if unspecified
} }
// In this sample we only handle the specific exceptions for the 'GetSecretValue' API. // logError Logs any errors returned by the Secrets Manager client
// See https://docs.aws.amazon.com/secretsmanager/latest/apireference/API_GetSecretValue.html func logError(err error) {
result, err := svc.GetSecretValue(input)
if err != nil {
if aerr, ok := err.(awserr.Error); ok { if aerr, ok := err.(awserr.Error); ok {
switch aerr.Code() { logs.Info(aerr.Code()+" %s", aerr.Error())
case secretsmanager.ErrCodeDecryptionFailure:
// Secrets Manager can't decrypt the protected secret text using the provided KMS key.
logs.Info(secretsmanager.ErrCodeDecryptionFailure, aerr.Error())
case secretsmanager.ErrCodeInternalServiceError:
// An error occurred on the server side.
logs.Info(secretsmanager.ErrCodeInternalServiceError, aerr.Error())
case secretsmanager.ErrCodeInvalidParameterException:
// You provided an invalid value for a parameter.
logs.Info(secretsmanager.ErrCodeInvalidParameterException, aerr.Error())
case secretsmanager.ErrCodeInvalidRequestException:
// You provided a parameter value that is not valid for the current state of the resource.
logs.Info(secretsmanager.ErrCodeInvalidRequestException, aerr.Error())
case secretsmanager.ErrCodeResourceNotFoundException:
// We can't find the resource that you asked for.
logs.Info("Can't find secret with ID: ", secretID)
logs.Info(secretsmanager.ErrCodeResourceNotFoundException, aerr.Error())
default:
logs.Info(err.Error())
}
} else { } else {
// Print the error, cast err to awserr.Error to get the Code and // Print the error, cast err to awserr.Error to get the Code and
// Message from an error. // Message from an error.
logs.Info(err.Error()) logs.Info(err.Error())
} }
}
func GetSecret(secretID string, isDebug bool) (string, string) {
// Check if we have the secret in cache
cachedSecret, err := secretCache.GetSecretString(secretID)
if err != nil {
logs.Info("Failed to get secret key from cache")
}
if cachedSecret != "" {
return cachedSecret, ""
}
// Create a Secrets Manager client
svc, err := createClient(isDebug)
if err != nil {
logs.Info("Could not create client: %+v", err)
return "", ""
}
// Create a secret
input := &secretsmanager.GetSecretValueInput{
SecretId: aws.String(string(secretID)),
VersionStage: aws.String("AWSCURRENT"), // VersionStage defaults to AWSCURRENT if unspecified
}
result, err := svc.GetSecretValue(input)
if err != nil {
logError(err)
return "", "" return "", ""
} }
...@@ -135,7 +135,7 @@ func GetSecret(secretID string, isDebug bool) (string, string) { ...@@ -135,7 +135,7 @@ func GetSecret(secretID string, isDebug bool) (string, string) {
decodedBinarySecretBytes := make([]byte, base64.StdEncoding.DecodedLen(len(result.SecretBinary))) decodedBinarySecretBytes := make([]byte, base64.StdEncoding.DecodedLen(len(result.SecretBinary)))
length, err := base64.StdEncoding.Decode(decodedBinarySecretBytes, result.SecretBinary) length, err := base64.StdEncoding.Decode(decodedBinarySecretBytes, result.SecretBinary)
if err != nil { if err != nil {
logs.Info("Base64 Decode Error:", err) logs.Info("Base64 Decode Error: %+v", err)
return "", "" return "", ""
} }
decodedBinarySecret = string(decodedBinarySecretBytes[:length]) decodedBinarySecret = string(decodedBinarySecretBytes[:length])
...@@ -143,3 +143,55 @@ func GetSecret(secretID string, isDebug bool) (string, string) { ...@@ -143,3 +143,55 @@ func GetSecret(secretID string, isDebug bool) (string, string) {
return secretString, decodedBinarySecret return secretString, decodedBinarySecret
} }
// CreateSecret Creates a JSON marshaled "string secret" (can be expanded to cater for binary secrets should the need arise)
func CreateSecret(secretID string, secret any, isDebug bool) (awsSecretID string, err error) {
// Create a Secrets Manager client
svc, err := createClient(isDebug)
if err != nil {
logs.Info("Could not create client: %+v", err)
return "", err
}
// Create the secret - marshaling "any" into a JSON string
secretStr, err := json.Marshal(secret)
if err != nil {
logs.Info("Could not marshal secret: %+v", err)
return "", err
}
input := &secretsmanager.CreateSecretInput{
Name: aws.String(secretID),
SecretString: aws.String(string(secretStr)),
}
result, err := svc.CreateSecret(input)
if err != nil {
logError(err)
return "", err
}
return aws.StringValue(result.Name), nil
}
func DeleteSecret(secretID string, forceWithoutRecovery bool, isDebug bool) error {
// Create a Secrets Manager client
svc, err := createClient(isDebug)
if err != nil {
logs.Info("Could not create client: %+v", err)
return err
}
// Delete the secret
input := &secretsmanager.DeleteSecretInput{
SecretId: aws.String(secretID),
ForceDeleteWithoutRecovery: aws.Bool(forceWithoutRecovery),
}
_, err = svc.DeleteSecret(input)
if err != nil {
logError(err)
return err
}
return nil
}
package secrets_manager
import (
"gitlab.bob.co.za/bob-public-utils/bobgroup-go-utils/date_utils"
"os"
"testing"
"time"
)
var isDebug bool
var secretID = "TestSecret_" + time.Now().Format(date_utils.DateLayoutTrimmed())
func TestMain(m *testing.M) {
isDebug = true
os.Setenv("ENVIRONMENT", "dev")
os.Setenv("AWS_PROFILE", "") // <-- Use your AWS profile name here
code := m.Run()
os.Exit(code)
}
func TestAll(t *testing.T) {
testCreateSecret(t)
testGetSecret(t)
testDeleteSecret(t)
}
func testCreateSecret(t *testing.T) {
type SubStruct struct {
Arg3a string
Arg3b string
}
type Anything struct {
Arg1 string
Arg2 string
Arg3 SubStruct
}
secret := Anything{
Arg1: "lorem",
Arg2: "ipsum",
Arg3: SubStruct{
Arg3a: "dolor",
Arg3b: "sit",
},
}
secretName, err := CreateSecret(secretID, secret, isDebug)
if err != nil {
t.Errorf("Secret with name '%s' could not be created.", secretName)
}
t.Logf("Secret with name '%s' successfully created.", secretName)
}
func testGetSecret(t *testing.T) {
secret, _ := GetSecret(secretID, isDebug)
if len(secret) <= 0 {
t.Errorf("Could not get secret with name %s, or secret has not content", secretID)
}
t.Logf("Secret with name `%s` has content: %s", secretID, secret)
}
func testDeleteSecret(t *testing.T) {
err := DeleteSecret(secretID, true, isDebug)
if err != nil {
t.Errorf("Secret with name '%s' could not be deleted.", secretID)
return
}
t.Logf("Secret with name '%s' successfully deleted.", secretID)
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment