AWS Credentials, Stored Safer

Written by mikefettis | Published 2020/03/10
Tech Story Tags: aws | security | encryption | secrets | programming | cybersecurity-skills | plain-text-credentials | hack-the-planet

TLDR AWS Credentials, Stored Safer, can be stored in plain text. There is a setting in the aws config that allows AWS to source the credentials externally. We can use this in conjunction with native openssl to give you a poor mans encrypted aws keys. The aws cli stored key id and secret in plaintext in a well known location in well-known location. We need to update `~/.aws/config` and pass the full path of the script and the encrypted blob.via the TL;DR App

By default the aws cli stored key id and secret in plaintext in a well known location. What could go wrong?!?
What if I told you that you could change this and make things at least a little bit harder?
There is a setting in the AWS config that allows AWS to source the credentials externally. This can be super handy if you don't want to store those as plain text things.
First we will take the aws credentials and dump them to a temp file this is named key.json
#key.json
{ 
"Version": 1, 
"AccessKeyId": "NOTAREALKEYID, 
"SecretAccessKey": "NOTAREALSECRET
}
Next we are going to create a script called encrypt.sh, this is going to accept the file that is passed to it and then generate an encrypted file.
#encrypt.sh
openssl aes-256-cbc -a -salt -in ${1} -out ${1}.enc -k "password"
# yes it is just "password" its a demo script! \
# Store this in an environment variable 
# or something safer than the script.
Now we need to write a quick script that will decrypt the encrypted blob and just echo it out. There is a built in on openssl that does just that. Also a proper shebang at the top of the file is crucial for aws to be able to run the script properly.
#decrypt.sh
#!/bin/bash -eu
#this will take the encrypted file passed to it decrypt it, and echo it
openssl aes-256-cbc -d -a -in $1 -k "password"
# yes it is just "password" its a demo script! \
# Store this in an environment variable 
# or something safer than the script.
Lets encrypt the file and prep it.
$ ./encrypt.sh key.json
# creates key.json.enc
Next we are going to setup our aws profile to read the creds from the external process. This means that we will need to update `~/.aws/config` and pass the full path of the script and the full path of the encrypted blob.
#~/.aws/config
[profile mine-encrypted]
credential_process = /Users/MYUSERNAME/decrypt.sh /Users/MYUSERNAME/key.json.enc
Finally we are going to tell the current session to use my new profile.
export AWS_PROFILE=mine-encrypted
Lastly we will verify the whole process worked.
aws sts get-caller-identity
We can take this in another direction as well. Let's say there is a process out there that will issue the credentials for you and then stash them in your aws profile. I would like to at least make the storing of those credentials a little bit better. So here is a whole pretty script that will handle that. You will provide the shell script with the named account profile that one would reference to use that account. This script also relies on having the decrypt.sh script we talked about earlier.
#wrap up and harden local aws keys
function _encrypt() {
    openssl aes-256-cbc -a -salt -in ${1} -out ${1}.enc -k "password"
    filestats=( $( ls -Lon "${1}" ) ) # to get size
    dd if=/dev/urandom of=${1} bs=${filestats[3]} count=1 &>/dev/null
    rm ${1}
}
function _shape(){
    id=$1
    key=$2
    session=$3
json=$(cat << DATA
{
  "Version": 1,
  "AccessKeyId": "$id",
  "SecretAccessKey": "$key",
  "SessionToken": "$session" 
}  
DATA
)
    echo "$json"
}
function _cleanup(){
    aws configure set profile.$1.aws_access_key_id "xxxx"
    aws configure set profile.$1.aws_secret_access_key "xxxx"
    aws configure set profile.$1.aws_session_token "xxxx"
}
function _set_encrypted(){
    aws configure set credential_process "/Users/$(pwd)/aws-crypt/decrypt.sh /Users/$(pwd)/aws-crypt/$1.json.enc"  --profile "$1-encrypted"
}
profile=$1
raw_aws=$(grep "\[$profile\]" ~/.aws/credentials -A 5 | awk 'NR == 1 || /^aws/'  | awk '{print $3}' | tr '\r\n' ' '|sed 's/ //')
full_json=$(_shape $raw_aws)
if [ -f "$profile.json" ]; then
 rm "$profile.json"
fi
echo "$full_json" >>"$profile.json"
_encrypt "$profile.json"
_cleanup $profile
_set_encrypted $profile
When we run this script it will look at the aws/credentials file, and pull out the id/key/token, drop those values into a new file, encrypt it, overwrite, then delete the temp file i then "xxxx" out the original values in the creds file. If the profile in question does't not uses session token then simply remove that section of the script.
I hope this helps someone out there to at least secure and lock down plain text credentials that are stored in a well known location. Every small step that we can take to better secure our systems is a small step towards a better security posture.
HACK THE PLANET!

Written by mikefettis | hacker and janitor building platforms and systems that when they work no one knows they are there.
Published by HackerNoon on 2020/03/10