diff --git a/README.md b/README.md index 5e40306..c4ef5c4 100644 --- a/README.md +++ b/README.md @@ -136,7 +136,7 @@ or domain within the resource e.g -cn=secret:secrets/myservice/${ENV}/config:fmt ## Output Formatting -The following output formats are supported: json, yaml, ini, txt, cert, csv, bundle, env, credential +The following output formats are supported: json, yaml, ini, txt, cert, csv, bundle, env, credential, aws Using the following at the demo secrets @@ -163,7 +163,7 @@ In order to change the output format: Format: 'cert' is less of a format of more file scheme i.e. is just extracts the 'certificate', 'issuing_ca' and 'private_key' and creates the three files FILE.{ca,key,crt}. The bundle format is very similar in the sense it similar takes the private key and certificate and places into a single file. -'credential' will attempt to decode a GCP credential file. +'credential' will attempt to decode a GCP credential file and 'aws' will write an AWS credentials file. ## Resource Options diff --git a/formats.go b/formats.go index 40d76df..9606cbc 100644 --- a/formats.go +++ b/formats.go @@ -142,6 +142,33 @@ func writeCredentialFile(filename string, data map[string]interface{}, mode os.F return nil } +func writeAwsCredentialFile(filename string, data map[string]interface{}, mode os.FileMode) error { + if err := writeFile(filename, generateAwsCredentialFile(data), mode); err != nil { + glog.Errorf("failed to write aws credentials file, error: %s", err) + return err + } + return nil +} + +func generateAwsCredentialFile(data map[string]interface{}) []byte { + const profileName = "[default]" + accessKey := fmt.Sprintf("aws_access_key_id=%s", data["access_key"]) + secretKey := fmt.Sprintf("aws_secret_access_key=%s", data["secret_key"]) + + // Credentials of type IAM User do not have a security token, and are returned as nil + if data["security_token"] != nil { + sessionToken := fmt.Sprintf("aws_session_token=%s", data["security_token"]) + + // Support clients that are using boto + securityToken := fmt.Sprintf("aws_security_token=%s", data["security_token"]) + + return []byte(fmt.Sprintf("%s\n%s\n%s\n%s\n%s\n", + profileName, accessKey, secretKey, securityToken, sessionToken)) + } + + return []byte(fmt.Sprintf("%s\n%s\n%s\n", profileName, accessKey, secretKey)) +} + func writeTxtFile(filename string, data map[string]interface{}, mode os.FileMode) error { keys := getKeys(data) if len(keys) > 1 { diff --git a/formats_test.go b/formats_test.go new file mode 100644 index 0000000..2a7ca2c --- /dev/null +++ b/formats_test.go @@ -0,0 +1,37 @@ +package main + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestWriteAwsCredentialFileIAMUser(t *testing.T) { + data := map[string]interface{}{ + "access_key": "AKIAJIVWU52VCBFROFFA", + "secret_key": "oocha7Wahma3bahmaitoo8ufae6Yahzouphooy2p", + "security_token": nil, + } + expected := `[default] +aws_access_key_id=AKIAJIVWU52VCBFROFFA +aws_secret_access_key=oocha7Wahma3bahmaitoo8ufae6Yahzouphooy2p +` + assert.Equal(t, expected, string(generateAwsCredentialFile(data))) +} + +func TestWriteAwsCredentialFileAssumedRole(t *testing.T) { + data := map[string]interface{}{ + "access_key": "AKIAJIVWN52VCBFROAFA", + "secret_key": "oocha7Wahma3bahmaitoo8ufae6Yahzouphooy2p", + "security_token": "phe2lahD7oofoo8eibohpu1kuwohn0eir7wieH7E", + "session_token": "phe2lahD7oofoo8eibohpu1kuwohn0eir7wieH7E", + } + + expected := `[default] +aws_access_key_id=AKIAJIVWN52VCBFROAFA +aws_secret_access_key=oocha7Wahma3bahmaitoo8ufae6Yahzouphooy2p +aws_security_token=phe2lahD7oofoo8eibohpu1kuwohn0eir7wieH7E +aws_session_token=phe2lahD7oofoo8eibohpu1kuwohn0eir7wieH7E +` + assert.Equal(t, expected, string(generateAwsCredentialFile(data))) +} diff --git a/utils.go b/utils.go index fef3814..bc5722e 100644 --- a/utils.go +++ b/utils.go @@ -195,6 +195,8 @@ func processResource(rn *VaultResource, data map[string]interface{}) (err error) err = writeCredentialFile(filename, data, rn.fileMode) case "template": err = writeTemplateFile(filename, data, rn.fileMode, rn.templateFile) + case "aws": + err = writeAwsCredentialFile(filename, data, rn.fileMode) default: return fmt.Errorf("unknown output format: %s", rn.format) } diff --git a/vault_resource.go b/vault_resource.go index daa139a..b2871e5 100644 --- a/vault_resource.go +++ b/vault_resource.go @@ -57,7 +57,7 @@ const ( ) var ( - resourceFormatRegex = regexp.MustCompile("^(yaml|yml|json|env|ini|txt|cert|bundle|csv|template|credential)$") + resourceFormatRegex = regexp.MustCompile("^(yaml|yml|json|env|ini|txt|cert|bundle|csv|template|credential|aws)$") // a map of valid resource to retrieve from vault validResources = map[string]bool{