kms-vault: Encrypt and Decrypt Files with AWS KMS

A tiny bash wrapper around aws kms encrypt and aws kms decrypt, from my AWS days in 2018. I used it for stashing small secrets — config files, credentials — encrypted at rest under a KMS key alias instead of plaintext on disk. Requirements: the AWS CLI and jq.

#!/usr/bin/env bash

# License: MIT - https://opensource.org/licenses/MIT

#
# Usage:
#
# Encrypt a file:
# kms-vault encrypt My-Key-Alias some-file-i-want-encrypted.txt > topsecret.asc
#
# Decrypt a file:
# kms-vault decrypt topsecret.asc
#

#
# Requirements: AWS CLI, jq
#
# Your AWS profile / default profile needs to have access to the KMS key you want to use
# and the kms:ListAliases permission.
#

set -eu -o pipefail

command=$1

if [[ $command = "encrypt" ]]; then
    key_alias="$2"
    key_info=$(aws kms list-aliases | jq -r ".Aliases[] | select(.AliasName | contains (\"$key_alias\"))")
    echo "Using key:" 1>&2
    echo "$key_info" | jq 1>&2
    key_id=$(echo "$key_info" | jq -r .TargetKeyId)
    plaintext_path="$3"
    aws kms encrypt --key-id "$key_id" --plaintext "fileb://$plaintext_path" --query CiphertextBlob --output text
    exit 0
elif [[ $command = "decrypt" ]]; then
    ciphertext_path="$2"
    aws kms decrypt --ciphertext-blob fileb://<(cat $ciphertext_path | base64 -d) --output text --query Plaintext | base64 -d
    exit 0
else
    echo "Unknown command: $command"
    exit 1
fi

Worth knowing if you borrow this: a raw kms encrypt call caps out at 4KB of plaintext, since it’s not doing envelope encryption — no data key, no local AES step, just KMS directly. Fine for a small config file or credential; not what you want for anything larger.