AWS Lambda environment variables → AWS SSM parameters in one (long) bash line

So, you want to use AWS SSM parameters instead of AWS Lambda environment variables? But you already have dozens of variables defined?

Keep calm (tested in production) and use this one-liner.

aws lambda list-functions --query 'Functions[?starts_with(FunctionName, `prod-`) == `true`].FunctionName' | jq '.[]' | xargs -L 1 -I {} aws lambda get-function-configuration --function-name {} --query Environment.Variables | jq -cr 'keys[] as $key | {Name: "/prod/\($key)", Value: "\(.[$key])", Type: "String"}' | xargs -d'\n' -I {} echo "aws ssm put-parameter --cli-input-json '{}'" | xargs -d'\n' -tI {} bash -c "{} || true"

Nobody in sane will run one-liners from the internet without the explanations. So here it is:

aws lambda list-functions --query 'Functions[?starts_with(FunctionName, `prod`) == `true`].FunctionName' | # Select functions
jq '.[]' | # Previous command returns an array, so expand it
xargs -L 1 -I {} aws lambda get-function-configuration --function-name {} --query Environment.Variables | # Get configuration for each function
jq -cr 'keys[] as $key | {Name: "/prod/\($key)", Value: "\(.[$key])", Type: "String"}' | # Craft a JSON for later use with aws ssm
xargs -d'\n' -I {} echo "aws ssm put-parameter --cli-input-json '{}'" | # Craft an aws ssm put-parameter command
xargs -d'\n' -tI {} bash -c "{} || true" # Finally, evaluate that command

BTW copy-pasting it in bash with all the comments will (surprisingly) work fine!:

Some notes:

  1. The whole flow assumes single AWS region is used (and defined in ~/.aws/config for used AWS_PROFILE). Add --region options where needed.

  2. You can use any valid query to get function names on the first step.

  3. JSON is used as input to aws ssm put-parameter because of automatic http:// and https:// expansion in some places! This lame behavior was fixed just a few hours prior to writing this article!

  4. Instead of hustling with jq on the final stage trying to pass arguments to xarg aws ssm put parameter, IMHO, it’s much more simpler to craft the command you need as a string and then just eval it.

What I’ve learned about bash during crafting this shitty pipeline:

  1. Damn xargs just "swallows" quotes (both single and double) in its (standard) input when passing values to commands! Use -d (or -0) flag to override this behavior. Compare echo "'test'" | xargs echo vs echo "'test'" | xargs -d'\n' echo