Skip to content

Commit

Permalink
added chmod feature
Browse files Browse the repository at this point in the history
  • Loading branch information
mvanholsteijn committed Mar 24, 2020
1 parent cdb13ca commit 410e539
Show file tree
Hide file tree
Showing 3 changed files with 125 additions and 1 deletion.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ The utility supports the following query parameters:

- default - value if the value could not be retrieved from the parameter store.
- destination - the filename to write the value to. value replaced with file: url.
- chmod - file permissions of the destination, left to default if not specified. recommended 0600.
- template - the template to use for writing the value, defaults to '{{.}}'

If no default nor destination is specified and the parameter is not found, the utility will return an error.
Expand Down
20 changes: 19 additions & 1 deletion main.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import (
"strings"
"syscall"
"text/template"
"strconv"
)

var verbose bool
Expand All @@ -54,6 +55,7 @@ type SSMParameterRef struct {
parameter_name *string // in the parameter store
default_value *string // if one is specified
destination *string // to write the value to, otherwise ""
fileMode os.FileMode // file permissions
template *template.Template // to use, defaults to '{{.}}'
}

Expand Down Expand Up @@ -85,8 +87,17 @@ func environmentToSSMParameterReferences(environ []string) ([]SSMParameterRef, e
return nil, fmt.Errorf("environment variable %s has an invalid template syntax, %s", name, err)
}
}
var fileMode os.FileMode
chmod := values.Get("chmod")
if chmod != "" {
if mode, err := strconv.ParseUint(chmod, 8, 32); err != nil {
return nil, fmt.Errorf("chmod '%s' is not valid, %s", chmod, err)
} else {
fileMode = os.FileMode(mode)
}
}
result = append(result, SSMParameterRef{&name, &uri.Path,
&defaultValue, &destination, tpl})
&defaultValue, &destination, os.FileMode(fileMode), tpl})
}
}
return result, nil
Expand Down Expand Up @@ -180,6 +191,13 @@ func writeParameterValues(refs []SSMParameterRef, env map[string]string) error {
if err != nil {
return fmt.Errorf("failed to close file %s, %s", *ref.destination, err)
}

if ref.fileMode != 0 {
err := os.Chmod(*ref.destination, ref.fileMode)
if err != nil {
return fmt.Errorf("failed to chmod file %s to %s, %s", *ref.destination, ref.fileMode, err)
}
}
}
}
return nil
Expand Down
105 changes: 105 additions & 0 deletions test.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
#!/bin/bash

export AWS_PROFILE=integration-test
export AWS_REGION=eu-central-1

function generate_password {
head /dev/urandom | LC_ALL=C tr -dc A-Za-z0-9 | head -c 20
}

function ssm_get_parameter {
go run main.go "$@"
}
function assert_equals {
if [[ $1 == $2 ]] ; then
echo "INFO: ${FUNCNAME[1]} ok" >&2
else
echo "ERROR: ${FUNCNAME[1]} expected '$1' got '$2'" >&2
fi
}

function test_simple_get {
local result expect
expect=$(generate_password)
aws ssm put-parameter --name /mysql/root/password --value "$expect" --type SecureString --overwrite > /dev/null
result=$(ssm_get_parameter --name /mysql/root/password)
assert_equals $expect $result
}

function test_get_via_env {
local result expect
expect=$(generate_password)
aws ssm put-parameter --name /mysql/root/password --value "$expect" --type SecureString --overwrite > /dev/null
result=$(MYSQL_PASSWORD=ssm:///mysql/root/password ssm_get_parameter bash -c 'echo $MYSQL_PASSWORD')
assert_equals $expect $result
}

function test_get_via_env_default {
local result expect
expect=$(generate_password)
result=$(MYSQL_PASSWORD="ssm:///there-is-no-such-parameter-in-the-store-is-there?default=$expect" ssm_get_parameter bash -c 'echo $MYSQL_PASSWORD')
assert_equals $expect $result
}

function test_template_format {
local result expect password
password=$(generate_password)
aws ssm put-parameter --name /postgres/kong/password --value "$password" --type SecureString --overwrite > /dev/null
expect="localhost:5432:kong:kong:${password}"

result=$(TMP=/tmp \
PGPASSFILE=ssm:///postgres/kong/password?template='localhost:5432:kong:kong:{{.}}%0A&destination=$TMP/.pgpass' \
ssm_get_parameter bash -c 'cat $PGPASSFILE')
assert_equals $expect $result
}

function test_env_substitution {
local result expect
expect=$(generate_password)
aws ssm put-parameter --name /$expect/mysql/root/password --value "$expect" --type SecureString --overwrite > /dev/null
result=$(ENV=$expect \
PASSWORD='ssm:///${ENV}/mysql/root/password' \
ssm_get_parameter bash -c 'echo $PASSWORD')
assert_equals $expect $result
}

function test_destination {
local result expect filename
expect=$(generate_password)
filename=/tmp/password-$$
aws ssm put-parameter --name /postgres/kong/password --value "$expect" --type SecureString --overwrite > /dev/null

result=$(FILENAME=$filename \
PASSWORD_FILE='ssm:///postgres/kong/password?destination=$FILENAME&chmod=0600' \
ssm_get_parameter bash -c 'echo $PASSWORD_FILE')
assert_equals $filename $result
assert_equals $expect $(<$filename)
assert_equals 600 $(stat -f %A $filename)
rm $filename
}

function test_destination_default {
local result expect filename
expect=$(generate_password)
filename=/tmp/password-$$
echo -n "$expect" > $filename
result=$(FILENAME=$filename \
PASSWORD_FILE='ssm:///there-is-no-such-parameter-in-the-store-is-there?destination=$FILENAME&chmod=0600' \
ssm_get_parameter bash -c 'echo $PASSWORD_FILE')
assert_equals $filename $result
assert_equals $expect $(<$filename)
assert_equals 600 $(stat -f %A $filename)
rm $filename
}

function main {
test_simple_get
test_get_via_env
test_get_via_env_default
test_destination
test_destination_default
test_env_substitution
test_template_format
}

main

0 comments on commit 410e539

Please sign in to comment.