Skip to content

Instantly share code, notes, and snippets.

@johnymachine
Last active July 13, 2023 07:51
Show Gist options
  • Save johnymachine/15fd9d4b7c5fdf51165258962e52488d to your computer and use it in GitHub Desktop.
Save johnymachine/15fd9d4b7c5fdf51165258962e52488d to your computer and use it in GitHub Desktop.
#!/bin/bash
# ssm_helper.sh - AWS Systems Manager Parameter Store Helper Script
echo -e "\e[1mAWS Systems Manager Parameter Store Helper Script\e[0m"
# Check if AWS CLI is installed
command -v aws >/dev/null 2>&1 || { echo >&2 "AWS CLI is required but not installed. Aborting."; exit 1; }
# Check if jq is installed
command -v jq >/dev/null 2>&1 || { echo >&2 "JQ is required but not installed. Aborting."; exit 1; }
# Set default values
dry_run=false
# Parse subcommand and named arguments
subcommand=""
while [[ $# -gt 0 ]]; do
case "$1" in
copy|save|load|toenv|delete) subcommand="$1"; shift ;;
--source_path) source_path="$2"; shift 2 ;;
--destination_path) destination_path="$2"; shift 2 ;;
--source_region) source_region="$2"; shift 2 ;;
--destination_region) destination_region="$2"; shift 2 ;;
--dryrun) dry_run=true; shift ;;
--file) file="$2"; shift 2 ;;
*) echo "Invalid argument: $1"; exit 1 ;;
esac
done
# Examples of how to use ssm_helper.sh
examples="
Examples:
- Copy parameters from source to destination:
./ssm_helper.sh copy --source_path /env/dev --destination_path /env/prod --source_region us-west-2 --destination_region us-east-1 --dryrun
- Save parameters to a file:
./ssm_helper.sh save --source_path /env/dev --source_region us-west-2 --file parameters.json
- Load parameters from a file to destination:
./ssm_helper.sh load --file parameters.json --destination_path /env/prod --destination_region us-east-1 --dryrun
- Convert parameters to .env file format:
./ssm_helper.sh toenv --file parameters.json
- Delete parameters in source path:
./ssm_helper.sh delete --source_path /env/dev --source_region us-west-2 --dryrun"
# Check if subcommand is provided
if [ -z "$subcommand" ]; then
echo "Usage: ./ssm_helper.sh [subcommand] [options]"
echo "Subcommand is required."
echo "$examples"
exit 1
fi
# Get AWS CLI identity information
identity=$(aws sts get-caller-identity --output json 2>/dev/null)
# Check if AWS CLI is logged in
if [[ -z "$identity" ]]; then
echo "AWS CLI is not logged in, please run log in."
exit 1
fi
# Extract the role and user from the identity
role=$(echo "$identity" | jq -r '.Arn' | awk -F '/' '{print $(NF-1)}')
user=$(echo "$identity" | jq -r '.Arn' | awk -F '/' '{print $(NF)}')
# Print AWS CLI identity information
echo -e "🔐 \e[34mLogged in role:\e[0m \e[1m$role\e[0m as \e[1m$user\e[0m"
# Print selcted command
echo -e "⏳ \e[34mExecuting:\e[0m \e[1m$subcommand\e[0m subcommand."
case "$subcommand" in
copy)
# Check if source path is provided
if [ -z "$source_path" ]; then
echo "Error: Source path is required for the 'delete' subcommand."
exit 1
fi
# Check if source region is provided
if [ -z "$source_region" ]; then
echo "Error: Source region is required for the 'delete' subcommand."
exit 1
fi
# Check if destination path is provided
if [ -z "$destination_path" ]; then
echo "Error: Destination path is required for the 'copy' subcommand."
exit 1
fi
# Check if destination region is provided
if [ -z "$destination_region" ]; then
echo "Error: Destination region is required for the 'copy' subcommand."
exit 1
fi
# Copy parameters from the source path to the destination path
aws_output=$(aws ssm get-parameters-by-path \
--path "$source_path" \
--with-decryption \
--recursive \
--query "Parameters[*].[Name, Type, Value]" \
--output json \
--region "$source_region")
echo "$aws_output" | jq -r '.[] | [.[0], .[1], .[2]] | @tsv' | while IFS=$'\t' read -r full_source_path type value; do
full_destination_path="${full_source_path/$source_path/$destination_path}"
if [ "$dry_run" = true ]; then
echo "[Dry run] Copying: $full_source_path -($type)-> $full_destination_path"
else
echo "[Dry run] Copying: $full_source_path -($type)-> $full_destination_path"
aws ssm put-parameter \
--name "$full_destination_path" \
--value "$value" \
--type "$type" \
--region "$destination_region"
fi
done
;;
save)
# Check if file is provided
if [ -z "$file" ]; then
file="parameters.json"
fi
# Check if source path is provided
if [ -z "$source_path" ]; then
echo "Error: Source path is required for the 'delete' subcommand."
exit 1
fi
# Check if source region is provided
if [ -z "$source_region" ]; then
echo "Error: Source region is required for the 'delete' subcommand."
exit 1
fi
# Use AWS CLI to get parameters by path and output JSON
aws_output=$(aws ssm get-parameters-by-path \
--path "$source_path" \
--with-decryption \
--recursive \
--query "Parameters[*].[Name, Type, Value]" \
--output json \
--region "$source_region")
# Strip $source_path from the parameter names
aws_output=$(echo "$aws_output" | jq -r 'map(.[0] |= gsub("'"$source_path"'/?"; ""))')
# Save to provided file
echo "$aws_output" > "$file"
echo "Parameters stored to file: $file"
;;
load)
# Check if file is provided
if [ -z "$file" ]; then
echo "No 'file' provided, setting is to: 'parameters.json'"
file="parameters.json"
fi
# Check if file exists
if [ ! -f "$file" ] || [ ! -s "$file" ]; then
echo "File '$file' does not exist or is empty."
exit 1
fi
# Check if destination path is provided
if [ -z "$destination_path" ]; then
echo "Error: Destination path is required for the 'load' subcommand."
exit 1
fi
# Check if destination region is provided
if [ -z "$destination_region" ]; then
echo "Error: Destination region is required for the 'load' subcommand."
exit 1
fi
# Read parameters from file
aws_output=$(cat "$file")
# Iterate over the AWS CLI output using jq
echo "$aws_output" | jq -r '.[] | [.[0], .[1], .[2]] | @tsv' | while IFS=$'\t' read -r name type value; do
# Create the full destination path by concatenating $destination_path and the parameter name
full_destination_path="$destination_path/$name"
# Process each parameter
if [ "$dry_run" = true ]; then
echo "[Dry run] Copying: $name -($type)-> $full_destination_path"
else
echo "Copying: $name -($type)-> $full_destination_path"
aws ssm put-parameter \
--name "$full_destination_path" \
--value "$value" \
--type "$type" \
--region "$destination_region"
fi
done
;;
toenv)
# Check if file is provided
if [ -z "$file" ]; then
echo "No 'file' provided, setting is to: 'parameters.json'"
file="parameters.json"
fi
# Check if file exists
if [ ! -f "$file" ] || [ ! -s "$file" ]; then
echo "File '$file' does not exist or is empty."
exit 1
fi
# Read parameters from file
aws_output=$(cat "$file")
# Create a new array to store .env entries
env_entries=()
# Iterate over the AWS CLI output using jq
while IFS=$'\t' read -r full_source_path type value; do
# Replace slashes with underscores in the parameter name
parameter_name="${full_source_path#\/}"
parameter_name="${parameter_name//\//_}"
# Convert the parameter name to uppercase
parameter_name="${parameter_name^^}"
# Add quotes around the parameter value
quoted_value="'$value'"
# Format the .env entry
env_entry="${parameter_name}=${quoted_value}"
# Add the .env entry to the array
env_entries+=("$env_entry")
done < <(echo "$aws_output" | jq -r '.[] | [.[0], .[1], .[2]] | @tsv')
# Store the .env entries in a file
env_file="${file}.env"
printf "%s\n" "${env_entries[@]}" > "$env_file"
echo "Parameters converted to .env format: $env_file"
;;
delete)
# Check if destination path is provided
if [ -z "$destination_path" ]; then
echo "Error: Destination path is required for the 'delete' subcommand."
exit 1
fi
# Check if destination region is provided
if [ -z "$destination_region" ]; then
echo "Error: Destination region is required for the 'delete' subcommand."
exit 1
fi
# Use AWS CLI to get a list of parameter names in the specified path and all subpaths recursively
aws_output=$(aws ssm describe-parameters \
--region "$destination_region" \
--query "Parameters[?starts_with(Name, '$destination_path')].Name" \
--output json)
parameter_names=$(echo "$aws_output" | jq -r '.[]')
if [ "$dry_run" = true ]; then
for name in $parameter_names; do
echo "[Dry run] Deleting: $name"
done
else
for name in $parameter_names; do
echo "Deleting: $name"
aws ssm delete-parameter \
--name "$name" \
--region "$source_region"
done
fi
;;
*)
echo "Invalid subcommand: $subcommand"
exit 1
;;
esac
echo -e "✅ \e[34mCompleted!\e[0m"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment