Skip to content

Instantly share code, notes, and snippets.

@jeremypruitt
Last active October 28, 2020 15:50
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jeremypruitt/62d6beeb7a85db5f9aa9cbbc55ba81ed to your computer and use it in GitHub Desktop.
Save jeremypruitt/62d6beeb7a85db5f9aa9cbbc55ba81ed to your computer and use it in GitHub Desktop.
Shell script to help run Terraform in a Docker container
#!/usr/bin/env bash
set -e
set -o pipefail
# FORMATTING ###################################################################
DEFAULT=`tput sgr0`
BOLD=`tput bold`
RED=`tput setaf 1`
GREEN=`tput setaf 2`
YELLOW=`tput setaf 3`
CYAN=`tput setaf 6`
# FUNCTIONS ####################################################################
# log - log to console with color output
function log {
if [ $# -lt 2 ]; then
local log_msg="$1"
else
local log_type="$1"
local log_msg="$2"
fi
case "$log_type" in
info) echo -e "\n${BOLD}${CYAN}${log_msg}${DEFAULT}" ;;
error) echo -e "\n${BOLD}${RED}ERROR: ${log_msg}${DEFAULT}\n" ;;
*) echo -e "\n${log_msg}" ;;
esac
}
function usage {
echo "Usage:"
echo " $(basname $0) <role> [cmd] Run AWS command as role"
echo " $(basname $0) <role> Generate env vars for assuming role"
echo ""
echo "Examples:"
echo " \$ $(basename $0) dev-deploy aws s3 ls" # Run AWS command as dev-deploy
echo " \$ $(basename $0) operations-admin" # Print out env vars for operations-admin
echo ""
}
function lookup_account {
ar_env=$1
account=$(sed -n -e '/variable "aws_accounts"/,/}/ p' ${env_root}/variables.tf | \
sed -nE -e "s/[[:space:]]*${ar_env}[[:space:]]*=[[:space:]]*\"(.*)\"/\1/p"
)
if [[ -z $account ]]; then
log error "Failed to lookup account for ${ar_env}" 1>&2
exit 1
fi
log info $account
}
function aws_assume_role {
ar_env=$1
ar_role=$2
if [[ $ar_env == "identity" ]]; then
log info "Do not need to assume_role for the ops environment" 1>&2
return
fi
account=$(lookup_account $ar_env)
role="arn:aws:iam::${account}:role/${ar_role}"
aws_tmp=$(mktemp -t aws-XXXX.json)
aws sts assume-role --role-arn ${role} --role-session-name terraform > ${aws_tmp}
aws_key=$(cat ${aws_tmp} | jq -r ".Credentials.AccessKeyId")
aws_secret=$(cat ${aws_tmp} | jq -r ".Credentials.SecretAccessKey")
aws_session_token=$(cat ${aws_tmp} | jq -r ".Credentials.SessionToken")
aws_session_expiration=$(cat ${aws_tmp} | jq -r ".Credentials.Expiration")
}
function discover_aws_credentials {
aws_region=${AWS_DEFAULT_REGION:-$(aws configure get region)}
aws_key=${AWS_ACCESS_KEY_ID:-$(aws configure get aws_access_key_id)}
aws_secret=${AWS_SECRET_ACCESS_KEY:-$(aws configure get aws_secret_access_key)}
if [[ -z $aws_region || -z $aws_key || -z $aws_secret ]]; then
log error "Could not get AWS credentials" 1>&2
log info "Run 'aws configure' or set AWS_ACCESS_KEY_ID/AWS_SECRET_ACCESS_KEY/AWS_DEFAULT_REGION" 1>&2
exit 1
fi
}
function aws_env {
if [[ -n $aws_session_token ]]; then
export AWS_SESSION_TOKEN="$aws_session_token"
fi
export AWS_ACCESS_KEY_ID="$aws_key"
export AWS_SECRET_ACCESS_KEY="$aws_secret"
export AWS_DEFAULT_REGION="$aws_region"
export TF_VAR_aws_region="$aws_region"
}
# Get ARGS
ENV=${1}
ROLE=${2:-deployer}
ARGS=${@:3}
if [[ $# < 1 ]]; then
log error "Missing arguments"
usage && exit 1
fi
unset AWS_DEFAULT_REGION \
AWS_ACCESS_KEY_ID \
AWS_SECRET_ACCESS_KEY \
AWS_SESSION_TOKEN \
AWS_SESSION_EXPIRATION
discover_aws_credentials
aws_assume_role $ENV $ROLE
if [[ $# > 0 ]]; then
AWS_DEFAULT_REGION="$aws_region" \
AWS_ACCESS_KEY_ID="$aws_key" \
AWS_SECRET_ACCESS_KEY="$aws_secret" \
AWS_SESSION_TOKEN="$aws_session_token" \
AWS_SESSION_EXPIRATION="$aws_session_expiration" \
"$@"
else
echo export AWS_DEFAULT_REGION=\"$aws_region\"
echo export AWS_ACCESS_KEY_ID=\"$aws_key\"
echo export AWS_SECRET_ACCESS_KEY=\"$aws_secret\"
echo export AWS_SESSION_TOKEN=\"$aws_session_token\"
echo export AWS_SESSION_EXPIRATION=\"$aws_session_expiration\"
fi
#!/bin/bash
set -e
set -o pipefail
# FORMATTING ###################################################################
DEFAULT=`tput sgr0`
BOLD=`tput bold`
RED=`tput setaf 1`
GREEN=`tput setaf 2`
YELLOW=`tput setaf 3`
CYAN=`tput setaf 6`
# FUNCTIONS ####################################################################
# log - log to console with color output
function log {
if [ $# -lt 2 ]; then
local log_msg="$1"
else
local log_type="$1"
local log_msg="$2"
fi
case "$log_type" in
info) echo -e "\n${BOLD}${CYAN}${log_msg}${DEFAULT}" ;;
error) echo -e "\n${BOLD}${RED}ERROR: ${log_msg}${DEFAULT}\n" ;;
*) echo -e "\n${log_msg}" ;;
esac
}
function usage {
echo "Usage:"
echo " <env> required: <env> can be 'dev' or 'prod'"
echo ""
echo " $0 <env> ping-hosts Ping all hosts in inventory"
echo ""
echo " $0 tasks List all tasks"
echo " $0 environments List all environments"
echo ""
echo " $0 help Show this help output"
echo ""
}
# list_all_tasks - Return a space separated list of all cases in the $TASK
# case statement of this file. Used for shell autocompletion.
# 1) Grab just the $TASK case statement block from the runner.sh
# 2) Pull just the "case" lines
# 3) sed removes the trailing parentheses
function list_all_tasks() {
task_list=$( \
sed -n -e '/^case $TASK in/{' -e ':a' -e 'n' -e '/^esac$/b' -e 'p' -e 'ba' -e '}' runner.sh \
| grep '^ [-a-zA-Z0-9_]*)$' \
| sed -e 's/)//g' \
)
log info "TASKS:"
for task in $task_list; do
echo $task | grep "^help$" >/dev/null && continue
echo " $0 <ENV> $task [ARGS]"
done
}
# Return a space separated list of all environments. An environment is any
# directory that starts with `env-`.
function list_all_environments() {
log info "ENVIRONMENTS:"
for env in $(ls -1d env-*); do echo " $0 $env <TASK> [ARGS]"; done
}
# MAIN #########################################################################
# Get ARGS
ENV=${1}
TASK=${2}
ARGS=${@:3}
if [ "$ENV" = 'dev' ] || [ "$ENV" = 'prod' ]; then
pushd env-$ENV
elif [ "$ENV" = 'tasks' ]; then
list_all_tasks && exit 0
elif [ "$ENV" = 'environments' ] || [ "$ENV" = 'envs' ]; then
list_all_environments && exit 0
else
log error "Missing proper <env>: (prod or dev)"
usage && exit 1
fi
PWD=`pwd`
# Terraform
TF_IMAGE="hashicorp/terraform:latest"
MOUNT_TF_MODULES="-v $(pwd)/../modules:/modules:ro"
# AWS
ENV_VARS="-e AWS_PROFILE=${AWS_PROFILE}"
MOUNT_AWS_CREDS="-v ${HOME}/.aws/credentials:/root/.aws/credentials:ro"
MOUNT_AWS_CONFIG="-v ${HOME}/.aws/config:/root/.aws/config:ro"
# Run Docker interactively
DOCKER_CMD="docker"
DOCKER_RUN="${DOCKER_CMD} run"
DOCKER_RUN_IT="${DOCKER_RUN} -it"
MOUNT_DATA="-v $(pwd):/data -w /data"
case $TASK in
init)
TF_CMD=init
;;
plan)
TF_CMD=plan
;;
apply)
TF_CMD=apply
;;
refresh)
TF_CMD=refresh
;;
destroy)
TF_CMD=destroy
;;
import)
TF_CMD=import
;;
graph)
TF_CMD=graph
;;
console)
TF_CMD=console
;;
version)
TF_CMD=--version
;;
help)
usage
exit 0
;;
*)
usage
exit 1
;;
esac
log info " --> Running terraform $TF_CMD in $ENV"
log info " --> $DOCKER_RUN_IT $MOUNT_AWS_CREDS $MOUNT_AWS_CONFIG $MOUNT_DATA $TF_IMAGE $TF_CMD $ARGS"
$DOCKER_RUN_IT $MOUNT_AWS_CREDS \
$MOUNT_AWS_CONFIG \
$MOUNT_DATA \
$MOUNT_TF_MODULES \
$ENV_VARS \
$TF_IMAGE \
$TF_CMD $ARGS \
&& log info "DONE" \
|| log error "Problem running docker command"
# Return to original directory
popd
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment