-
Notifications
You must be signed in to change notification settings - Fork 9
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Sergey Novikov
authored
Dec 16, 2018
1 parent
db15749
commit f3dbaa6
Showing
10 changed files
with
258 additions
and
14 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
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
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,96 @@ | ||
// +build awssecretsmanager | ||
|
||
package awssecretsmanager | ||
|
||
import ( | ||
"encoding/json" | ||
"errors" | ||
"fmt" | ||
"github.com/aws/aws-sdk-go-v2/aws" | ||
"github.com/aws/aws-sdk-go-v2/aws/external" | ||
"github.com/aws/aws-sdk-go-v2/service/secretsmanager" | ||
"github.com/s12v/secure-exec/provider" | ||
"regexp" | ||
"strings" | ||
) | ||
|
||
type SecretsManagerProvider struct { | ||
awsClient *secretsmanager.SecretsManager | ||
} | ||
|
||
const prefix = "{aws-sm}" | ||
|
||
var postfix = regexp.MustCompile("{[^{^}]+}$") | ||
|
||
var fetch func( | ||
awsClient *secretsmanager.SecretsManager, | ||
input *secretsmanager.GetSecretValueInput) (*secretsmanager.GetSecretValueOutput, error) | ||
|
||
func init() { | ||
cfg, err := external.LoadDefaultAWSConfig() | ||
if err != nil { | ||
panic("unable to load AWS-SDK config, " + err.Error()) | ||
} | ||
|
||
fetch = awsFetch | ||
provider.Register(&SecretsManagerProvider{secretsmanager.New(cfg)}) | ||
} | ||
|
||
func awsFetch( | ||
awsClient *secretsmanager.SecretsManager, | ||
input *secretsmanager.GetSecretValueInput) (*secretsmanager.GetSecretValueOutput, error) { | ||
if resp, err := awsClient.GetSecretValueRequest(input).Send(); err != nil { | ||
return nil, errors.New(fmt.Sprintf("AWS SecretsManager error: %v", err)) | ||
} else { | ||
return resp, nil | ||
} | ||
} | ||
|
||
func (p *SecretsManagerProvider) Match(val string) bool { | ||
return strings.HasPrefix(val, prefix) && len(val) > len(prefix) | ||
} | ||
|
||
func (p *SecretsManagerProvider) Decode(val string) (string, error) { | ||
name := val[len(prefix):] | ||
property := postfix.FindString(name) | ||
if property != "" { | ||
return p.decodeJson(name, strings.Trim(property, "{}")) | ||
} | ||
return p.fetchString(name) | ||
} | ||
|
||
func (p *SecretsManagerProvider) decodeJson(val string, property string) (string, error) { | ||
name := val[:len(val)-len(property) - 2] | ||
jsobj, err := p.fetchString(name) | ||
if err != nil { | ||
return "", err | ||
} | ||
|
||
properties, _ := unmarshal(jsobj) | ||
value, ok := properties[property] | ||
if !ok { | ||
return "", errors.New(fmt.Sprintf("property '%v' does not exist", property)) | ||
} | ||
return value, nil | ||
} | ||
|
||
func (p *SecretsManagerProvider) fetchString(name string) (string, error) { | ||
input := &secretsmanager.GetSecretValueInput{ | ||
SecretId: aws.String(name), | ||
} | ||
if err := input.Validate(); err != nil { | ||
return "", err | ||
} | ||
|
||
if output, err := fetch(p.awsClient, input); err != nil { | ||
return "", err | ||
} else { | ||
return *output.SecretString, nil | ||
} | ||
} | ||
|
||
func unmarshal(val string) (map[string]string, error) { | ||
var omap map[string]string | ||
err := json.Unmarshal([]byte(val), &omap) | ||
return omap, err | ||
} |
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,135 @@ | ||
// +build awssecretsmanager | ||
|
||
package awssecretsmanager | ||
|
||
import ( | ||
"errors" | ||
"github.com/aws/aws-sdk-go-v2/service/secretsmanager" | ||
"testing" | ||
) | ||
|
||
func TestSecretsManagerProvider_Match(t *testing.T) { | ||
provider := SecretsManagerProvider{} | ||
|
||
if provider.Match("{aws-sm}something") != true { | ||
t.Fatal("expected to match") | ||
} | ||
|
||
if provider.Match("https://example.com") != false { | ||
t.Fatal("not expected to match") | ||
} | ||
} | ||
|
||
func TestSecretsManagerProvider_Decode(t *testing.T) { | ||
provider := SecretsManagerProvider{} | ||
|
||
value := "boom" | ||
fetch = func( | ||
awsClient *secretsmanager.SecretsManager, | ||
input *secretsmanager.GetSecretValueInput) (*secretsmanager.GetSecretValueOutput, error) { | ||
if *input.SecretId != "/foo/bar" { | ||
t.Fatalf("unexpected SecretId %v", input.SecretId) | ||
} | ||
|
||
return &secretsmanager.GetSecretValueOutput{SecretString: &value}, nil | ||
} | ||
|
||
if r, _ := provider.Decode("{aws-sm}/foo/bar"); r != "boom" { | ||
t.Fatalf("unexpected value %v", r) | ||
} | ||
} | ||
|
||
func TestSecretsManagerProvider_DecodeJson(t *testing.T) { | ||
provider := SecretsManagerProvider{} | ||
|
||
value := `{"prop1": "aaa", "prop2": "bbb"}` | ||
fetch = func( | ||
awsClient *secretsmanager.SecretsManager, | ||
input *secretsmanager.GetSecretValueInput) (*secretsmanager.GetSecretValueOutput, error) { | ||
if *input.SecretId != "/foo/bar" { | ||
t.Fatalf("unexpected SecretId %v", *input.SecretId) | ||
} | ||
|
||
return &secretsmanager.GetSecretValueOutput{SecretString: &value}, nil | ||
} | ||
|
||
if r, _ := provider.Decode("{aws-sm}/foo/bar{prop2}"); r != "bbb" { | ||
t.Fatalf("unexpected value %v", r) | ||
} | ||
} | ||
|
||
func TestSecretsManagerProvider_DecodeJson_MissingProperty(t *testing.T) { | ||
provider := SecretsManagerProvider{} | ||
|
||
value := `{"prop1": "foo", "prop2": "bar"}` | ||
fetch = func( | ||
awsClient *secretsmanager.SecretsManager, | ||
input *secretsmanager.GetSecretValueInput) (*secretsmanager.GetSecretValueOutput, error) { | ||
if *input.SecretId != "/foo/bar" { | ||
t.Fatalf("unexpected SecretId %v", *input.SecretId) | ||
} | ||
|
||
return &secretsmanager.GetSecretValueOutput{SecretString: &value}, nil | ||
} | ||
|
||
if _, err := provider.Decode("{aws-sm}/foo/bar{prop3}"); err == nil { | ||
t.Fatal("expected an error") | ||
} | ||
} | ||
|
||
func TestSecretsManagerProvider_Decode_FetchError(t *testing.T) { | ||
provider := SecretsManagerProvider{} | ||
|
||
fetch = func( | ||
awsClient *secretsmanager.SecretsManager, | ||
input *secretsmanager.GetSecretValueInput) (*secretsmanager.GetSecretValueOutput, error) { | ||
|
||
return nil, errors.New("test error") | ||
} | ||
|
||
if _, err := provider.Decode("{aws-sm}/foo/bar"); err == nil { | ||
t.Fatal("expected an error") | ||
} | ||
} | ||
|
||
func TestSecretsManagerProvider_DecodeJson_FetchError(t *testing.T) { | ||
provider := SecretsManagerProvider{} | ||
|
||
fetch = func( | ||
awsClient *secretsmanager.SecretsManager, | ||
input *secretsmanager.GetSecretValueInput) (*secretsmanager.GetSecretValueOutput, error) { | ||
|
||
return nil, errors.New("test error") | ||
} | ||
|
||
if _, err := provider.Decode("{aws-sm}/foo/bar{prop1}"); err == nil { | ||
t.Fatal("expected an error") | ||
} | ||
} | ||
|
||
func TestSecretsManagerProvider_Decode_InvalidInput(t *testing.T) { | ||
provider := SecretsManagerProvider{} | ||
r, err := provider.Decode("{aws-sm}") | ||
if err == nil { | ||
t.Fatal("expected an error", r) | ||
} | ||
if r != "" { | ||
t.Fatalf("unexpected result: '%v'", r) | ||
} | ||
} | ||
|
||
func Test_Unmarshal(t *testing.T) { | ||
jsonobj, err := unmarshal(`{"prop1": "foo", "prop2": "bar"}`) | ||
|
||
if err != nil { | ||
t.Fatal("expected error: ", err) | ||
} | ||
|
||
if jsonobj["prop1"] != "foo" { | ||
t.Fatalf("unexpected value '%v'", jsonobj["prop1"]) | ||
} | ||
|
||
if jsonobj["prop2"] != "bar" { | ||
t.Fatalf("unexpected value '%v'", jsonobj["prop2"]) | ||
} | ||
} |
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,6 @@ | ||
// +build !awssecretsmanager | ||
|
||
package awssecretsmanager | ||
|
||
func init() { | ||
} |
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
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 |
---|---|---|
@@ -1,6 +1,6 @@ | ||
// +build !awsssm | ||
|
||
package awskms | ||
package awsssm | ||
|
||
func init() { | ||
} |