diff --git a/lambda/main.go b/lambda/main.go index 639d52c6..043c6612 100644 --- a/lambda/main.go +++ b/lambda/main.go @@ -159,10 +159,23 @@ func parseCreds(creds string) (string, error) { if creds == "" { return "", nil } else if (credsType == SECRET_ARN) || (credsType == SECRET_NAME) { - secret, err := GetSecret(creds) - return secret, err + secret, isJSON, err := GetSecret(creds) + if err != nil { + return "", err + } + if isJSON { + parsedSecret, err := ParseJSONSecret(secret) + if err != nil { + return "", err + } + return parsedSecret, nil + } + return secret, nil } else if credsType == SECRET_TEXT { return creds, nil + } else if credsType == SECRET_JSON { + secret, err := ParseJSONSecret(creds) + return secret, err } - return "", fmt.Errorf("unkown creds type") + return "", fmt.Errorf("unknown creds type") } diff --git a/lambda/main_test.go b/lambda/main_test.go index a28b323f..f91abdc5 100644 --- a/lambda/main_test.go +++ b/lambda/main_test.go @@ -53,3 +53,53 @@ func TestMain(t *testing.T) { }) assert.NoError(t, err) } +func TestParseCreds(t *testing.T) { + tests := []struct { + name string + creds string + want string + wantErr bool + }{ + { + name: "Empty creds", + creds: "", + want: "", + wantErr: false, + }, + // { + // name: "Secret ARN", + // creds: "arn:aws:secretsmanager:us-west-2:00000:secret:fake-secret", + // want: "{\"username\":\"privateRegistryUsername\",\"password\":\"privateRegistryPassword\"}", + // wantErr: false, + // }, + { + name: "Secret JSON", + creds: "{ \"username\" : \"privateRegistryUsername\", \"password\" : \"privateRegistryPassword\" }", + want: "privateRegistryUsername:privateRegistryPassword", + wantErr: false, + }, + { + name: "Secret Text", + creds: "username:password", + want: "username:password", + wantErr: false, + }, + { + name: "Unknown creds type", + creds: "unknown-creds", + want: "", + wantErr: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := parseCreds(tt.creds) + if (err != nil) != tt.wantErr { + t.Errorf("parseCreds() error = %v, wantErr %v", err, tt.wantErr) + return + } + assert.Equal(t, tt.want, got) + }) + } +} diff --git a/lambda/utils.go b/lambda/utils.go index 461c3807..7a365d39 100644 --- a/lambda/utils.go +++ b/lambda/utils.go @@ -154,9 +154,18 @@ const ( SECRET_ARN = "SECRET_ARN" SECRET_NAME = "SECRET_NAME" SECRET_TEXT = "SECRET_TEXT" + SECRET_JSON = "SECRET_JSON" ) func GetCredsType(s string) string { + var jsonData map[string]interface{} + if err := json.Unmarshal([]byte(s), &jsonData); err == nil { + if _, hasUsername := jsonData["username"]; hasUsername { + if _, hasPassword := jsonData["password"]; hasPassword { + return SECRET_JSON + } + } + } if strings.HasPrefix(s, "arn:aws") { return SECRET_ARN } else if strings.Contains(s, ":") { @@ -166,13 +175,13 @@ func GetCredsType(s string) string { } } -func GetSecret(secretId string) (secret string, err error) { +func GetSecret(secretId string) (secret string, isJSON bool, err error) { cfg, err := config.LoadDefaultConfig( context.TODO(), ) log.Printf("get secret id: %s of region: %s", secretId, cfg.Region) if err != nil { - return "", fmt.Errorf("api client configuration error: %v", err.Error()) + return "", false, fmt.Errorf("api client configuration error: %v", err.Error()) } client := secretsmanager.NewFromConfig(cfg) @@ -180,7 +189,31 @@ func GetSecret(secretId string) (secret string, err error) { SecretId: aws.String(secretId), }) if err != nil { - return "", fmt.Errorf("fetch secret value error: %v", err.Error()) + return "", false, fmt.Errorf("fetch secret value error: %v", err.Error()) + } + + secretString := *resp.SecretString + + var jsonData map[string]interface{} + if err := json.Unmarshal([]byte(secretString), &jsonData); err == nil { + return secretString, true, nil + } + + return secretString, false, nil +} + +func ParseJSONSecret(secretJson string) (secret string, err error) { + var jsonData map[string]interface{} + if err := json.Unmarshal([]byte(secretJson), &jsonData); err != nil { + return "", fmt.Errorf("json unmarshal error: %v", err.Error()) + } + username, ok := jsonData["username"].(string) + if !ok { + return "", fmt.Errorf("json username error") + } + password, ok := jsonData["password"].(string) + if !ok { + return "", fmt.Errorf("json password error") } - return *resp.SecretString, nil + return fmt.Sprintf("%s:%s", username, password), nil } diff --git a/lambda/utils_test.go b/lambda/utils_test.go index 4f93a37d..131ee670 100644 --- a/lambda/utils_test.go +++ b/lambda/utils_test.go @@ -30,4 +30,5 @@ func TestGetCredsType(t *testing.T) { assert.Equal(t, SECRET_NAME, GetCredsType("fake-secret")) assert.Equal(t, SECRET_TEXT, GetCredsType("username:password")) assert.Equal(t, SECRET_NAME, GetCredsType("")) + assert.Equal(t, SECRET_JSON, GetCredsType("{ \"username\" : \"privateRegistryUsername\", \"password\" : \"privateRegistryPassword\" }")) } diff --git a/src/index.ts b/src/index.ts index 9ab65116..1dcdceb3 100644 --- a/src/index.ts +++ b/src/index.ts @@ -106,6 +106,7 @@ export interface IImageName { /** * The credentials of the docker image. Format `user:password` or `AWS Secrets Manager secret arn` or `AWS Secrets Manager secret name` + * Supports JSON format returned from AWS Secrets in the format `{"username":"", "password":""}` */ creds?: string; }