16/04/2023 - AWS, DOCKER, TERRAFORM
Consider this as a throw away PGP approach for Terraform. It is meant to be used for CI/CD pipeline while creating, encrypting and outputting AWS IAM user login profile password in terminal. You are going to decrypt outputted password in your local environment to get the actual password for console login. That's the whole aim here. The reason why this should be considered "throw away" is that, a passphrase is not used. Hence reason you should change decrypted password as soon as you obtain it.
We are going to use a Dockerised solution. I personally don't like installing one-off third party tools on my device, signing up to certain online accounts so on to achieve same outcome. This includes Keybase, gpg command etc. Not saying they are bad, but I find it unnecessary.
You could even create a GitHub repository for this and allow all the engineers to use it when they are being onboarded. It is up to you. Here is the simple walkthrough of this example.
aws_iam_user_login_profile.pgp_key
terraform apply
output.Create .env
out of .env.dist
file and update marked variables using your own data. Run $ make build
command to build Docker image.
Run $ make keys
command which does everything. You won't do anything with public and private keys directly but the PGP key is the one that you will use in Terraform resources where pgp_key
field is required. Having said that, you can still use public and private keys for any other work using optional steps below.
This is not specific to this post so consider it as an informative step.
tmp/plain_input.txt
file with some content.tmp/encrypted_input.txt
file that will store encrypted content.$ make encrypt
command.This is not specific to this post so consider it as an informative step.
tmp/encrypted_input.txt
file with some encrypted content.tmp/decrypted_input.txt
file that will store decrypted content.$ make decrypt
command.This is explicitly related to our post.
tmp/encrypted_input.txt
file with encrypted output from Terraform.tmp/decrypted_input.txt
file that will store decrypted content.$ make decrypt-base64
command.We are not focusing on the the most beautiful solution here. Instead we are being pragmatic. If you want, you can combine all bash scripts into one and running parameterised command. You can do all sorts of thing to improve it.
├── .env.dist
├── .gitignore
├── Dockerfile
├── Makefile
├── decrypt.sh
├── decrypt_base64.sh
├── encrypt.sh
├── keys.sh
├── pgp.cfg
└── tmp
└── .gitkeep
PGP_DIR="/root/.gnupg"
PGP_CFG="/pgp.cfg"
PUB_KEY="/tmp/public.key"
PRV_KEY="/tmp/private.key"
B64_KEY="/tmp/base64.key"
PLAIN_INPUT="/tmp/plain_input.txt"
ENCRYPTED_INPUT="/tmp/encrypted_input.txt"
DECRYPTED_INPUT="/tmp/decrypted_input.txt"
# Updated with your own data
NAME="Your name"
EMAIL="your email"
COMMENT="Key purpose"
/tmp/*
!/tmp/.gitignore
.env
FROM alpine:3.17.0
COPY .env .env
COPY pgp.cfg pgp.cfg
COPY keys.sh keys.sh
COPY encrypt.sh encrypt.sh
COPY decrypt.sh decrypt.sh
COPY decrypt_base64.sh decrypt_base64.sh
RUN apk update && \
apk fetch gnupg && \
apk add gnupg && \
chmod +x keys.sh && \
chmod +x encrypt.sh && \
chmod +x decrypt.sh && \
chmod +x decrypt_base64.sh
.PHONY: help
help: ## Display available commands
@awk 'BEGIN {FS = ":.*?## "} /^[0-9a-zA-Z_-]+:.*?## / {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}' $(MAKEFILE_LIST)
.PHONY: build
build: ## Build docker image
@DOCKER_BUILDKIT=0 docker build --no-cache --tag inanzzz/pgp:latest .
.PHONY: keys
keys: ## Generate public, private and base64 encoded public key.
docker run --rm --env ENV_FILE=".env" --volume `pwd`/tmp:/tmp:rw --name inanzzz-pgp inanzzz/pgp:latest sh -c ./keys.sh
.PHONY: encrypt
encrypt: ## Encrypt plain text.
docker run --rm --env ENV_FILE=".env" --volume `pwd`/tmp:/tmp:rw --name inanzzz-pgp inanzzz/pgp:latest sh -c ./encrypt.sh
.PHONY: decrypt
decrypt: ## Decrypt encrypt text
docker run --rm --env ENV_FILE=".env" --volume `pwd`/tmp:/tmp:rw --name inanzzz-pgp inanzzz/pgp:latest sh -c ./decrypt.sh
.PHONY: decrypt-base64
decrypt-base64: ## Decrypt base64 encrypted text
docker run --rm --env ENV_FILE=".env" --volume `pwd`/tmp:/tmp:rw --name inanzzz-pgp inanzzz/pgp:latest sh -c ./decrypt_base64.sh
#!/bin/sh
CYAN="\033[0;36m"
CLEAR="\033[0m"
printf "${CYAN}> DECRYPT INPUT -----------------------------------------------------------------------------${CLEAR}\n"
printf "${CYAN}Export all variables from dot env file into environment${CLEAR}\n"
set -o allexport
source ${ENV_FILE}
set +o allexport
echo "done"
printf "${CYAN}Create pgp directory and get into it${CLEAR}\n"
gpg2 --list-keys
cd ${PGP_DIR}
echo "done"
printf "${CYAN}Restore public and private key${CLEAR}\n"
gpg2 --import-options import-restore --import ${PUB_KEY}
gpg2 --import-options import-restore --import ${PRV_KEY}
echo "done"
printf "${CYAN}Decrypt input${CLEAR}\n"
gpg2 --decrypt ${ENCRYPTED_INPUT} > ${DECRYPTED_INPUT}
echo "done"
printf "${CYAN}> FINISHED ----------------------------------------------------------------------------------${CLEAR}\n"
#!/bin/sh
CYAN="\033[0;36m"
CLEAR="\033[0m"
printf "${CYAN}> DECRYPT INPUT -----------------------------------------------------------------------------${CLEAR}\n"
printf "${CYAN}Export all variables from dot env file into environment${CLEAR}\n"
set -o allexport
source ${ENV_FILE}
set +o allexport
echo "done"
printf "${CYAN}Create pgp directory and get into it${CLEAR}\n"
gpg2 --list-keys
cd ${PGP_DIR}
echo "done"
printf "${CYAN}Restore public and private key${CLEAR}\n"
gpg2 --import-options import-restore --import ${PUB_KEY}
gpg2 --import-options import-restore --import ${PRV_KEY}
echo "done"
printf "${CYAN}Decrypt input${CLEAR}\n"
cat ${ENCRYPTED_INPUT} | base64 -d | gpg2 --decrypt > ${DECRYPTED_INPUT}
echo "done"
printf "${CYAN}> FINISHED ----------------------------------------------------------------------------------${CLEAR}\n"
#!/bin/sh
CYAN="\033[0;36m"
CLEAR="\033[0m"
printf "${CYAN}> ENCRYPT INPUT -----------------------------------------------------------------------------${CLEAR}\n"
printf "${CYAN}Export all variables from dot env file into environment${CLEAR}\n"
set -o allexport
source ${ENV_FILE}
set +o allexport
echo "done"
printf "${CYAN}Create pgp directory and get into it${CLEAR}\n"
gpg2 --list-keys
cd ${PGP_DIR}
echo "done"
printf "${CYAN}Restore public and private key${CLEAR}\n"
gpg2 --import-options import-restore --import ${PUB_KEY}
gpg2 --import-options import-restore --import ${PRV_KEY}
echo "done"
printf "${CYAN}Auto trust and verify keys${CLEAR}\n"
echo -e "5\ny\n" | gpg2 --no-tty --command-fd 0 --expert --edit-key ${EMAIL} trust
echo "done"
printf "${CYAN}Encrypt input${CLEAR}\n"
gpg2 --batch --yes --output ${ENCRYPTED_INPUT} --encrypt --sign --armor -r ${EMAIL} ${PLAIN_INPUT}
echo "done"
printf "${CYAN}> FINISHED ----------------------------------------------------------------------------------${CLEAR}\n"
#!/bin/sh
CYAN="\033[0;36m"
CLEAR="\033[0m"
printf "${CYAN}> GENERATE KEYS -----------------------------------------------------------------------------${CLEAR}\n"
printf "${CYAN}Export all variables from dot env file into environment${CLEAR}\n"
set -o allexport
source ${ENV_FILE}
set +o allexport
echo "done"
printf "${CYAN}Prepare configuration file${CLEAR}\n"
sed -i -e 's/${NAME}/'"${NAME}"'/g' -e 's/${COMMENT}/'"${COMMENT}"'/g' -e 's/${EMAIL}/'"${EMAIL}"'/g' ${PGP_CFG}
echo "done"
printf "${CYAN}Create pgp directory and get into it${CLEAR}\n"
gpg2 --list-keys
cd ${PGP_DIR}
echo "done"
printf "${CYAN}Generate keys${CLEAR}\n"
gpg2 --verbose --batch --gen-key ${PGP_CFG}
echo "done"
printf "${CYAN}Backup public and private keys${CLEAR}\n"
gpg2 --yes --output ${PUB_KEY} --armor --export-options export-backup --export ${EMAIL}
gpg2 --yes --output ${PRV_KEY} --armor --export-options export-backup --export-secret-keys ${EMAIL}
echo "done"
printf "${CYAN}Export base64 encoded public key${CLEAR}\n"
gpg2 --export ${EMAIL} | base64 -w 0 > ${B64_KEY}
echo "done"
printf "${CYAN}> FINISHED ----------------------------------------------------------------------------------${CLEAR}\n"
Key-Type: RSA
Key-Length: 2048
Subkey-Type: RSA
Subkey-Length: 2048
Name-Real: ${NAME}
Name-Email: ${EMAIL}
Name-Comment: ${COMMENT}
Expire-Date: 0
%no-protection