I use AWS a lot at work. The AWS CLI is powerful but verbose. Every command needs --profile to specify which account I’m targeting, and often --region too. I find myself typing things like:
aws --profile company-prod --region eu-west-1 s3 ls s3://some-bucket
aws --profile company-prod --region eu-west-1 ec2 describe-instances
aws --profile company-staging --region eu-west-1 s3 cp file.txt s3://staging-bucket/
This gets old fast. I wanted something where I could set my usual profile once and forget about it, but still be able to switch when needed.
wrapping AWS with clk
I created a clk wrapper around AWS. The idea is simple: a group command that handles the --profile and --region options, then passes them to subcommands via environment variables.
Here’s a simplified version (in real life, the subcommands would call the actual aws CLI).
First, create the group:
clk command create python aws --group --description "AWS CLI wrapper"
Then edit it to add the options. The code looks like this:
from clk.config import config
from clk.decorators import group, option
@group()
@option("--profile", "-p", default="default", help="The AWS profile to use")
@option("--region", "-r", default="us-east-1", help="The AWS region")
def aws(profile, region):
"AWS CLI wrapper with persistent configuration"
config.override_env["AWS_PROFILE"] = profile
config.override_env["AWS_REGION"] = region
config.init()
@aws.group()
def s3():
"S3 operations"
The subcommands are bash scripts that use the environment variables set by the parent group. We can declare arguments directly on the command line:
clk command create bash aws.s3.ls --description "List S3 buckets or objects" \
--argument 'path:str:S3 path to list:{"required": false}' \
--body 'echo "[${AWS_PROFILE}/${AWS_REGION}] aws s3 ls ${CLK___PATH:-}"'
clk command create bash aws.s3.cp --description "Copy files to/from S3" \
--argument 'source:str:Source path' \
--argument 'destination:str:Destination path' \
--body 'echo "[${AWS_PROFILE}/${AWS_REGION}] aws s3 cp ${CLK___SOURCE} ${CLK___DESTINATION}"'
clk command create bash aws.ec2 --description "EC2 operations" \
--argument 'args:str:EC2 command arguments:{"nargs": -1}' \
--body 'echo "[${AWS_PROFILE}/${AWS_REGION}] aws ec2 ${CLK___ARGS}"'
Now I can use it like this:
clk aws --profile company-prod --region eu-west-1 s3 ls s3://prod-bucket
[company-prod/eu-west-1] aws s3 ls s3://prod-bucket
That’s better, but I still have to type the profile every time.
setting default parameters
Here’s where clk shines. I can persist options so they become the default.
clk parameter set aws --profile company-prod --region eu-west-1
New global parameters for aws: --profile company-prod --region eu-west-1
Now I don’t need to specify them anymore:
clk aws s3 ls s3://prod-bucket
clk aws s3 cp backup.sql s3://prod-bucket/backups/
clk aws ec2 describe-instances
[company-prod/eu-west-1] aws s3 ls s3://prod-bucket
[company-prod/eu-west-1] aws s3 cp backup.sql s3://prod-bucket/backups/
[company-prod/eu-west-1] aws ec2 describe-instances
Much cleaner! And when I need to work with staging, I just override:
clk aws --profile company-staging s3 ls s3://staging-bucket
[company-staging/eu-west-1] aws s3 ls s3://staging-bucket
The region is still eu-west-1 from my persisted parameters, only the profile changed.
managing parameters
I can check what’s currently set:
clk parameter show aws
aws --profile company-prod --region eu-west-1
And remove options I no longer want persisted:
clk parameter remove aws --region eu-west-1
clk parameter show aws
Erasing aws parameters --region eu-west-1 from global settings
aws --profile company-prod
Or clear everything:
clk parameter unset aws
clk aws s3 ls
Erasing global parameters of aws (was: --profile company-prod)
[default/us-east-1] aws s3 ls
per-project configuration
Different projects often use different AWS accounts. I can set parameters at the project level so they only apply when I’m in that directory.
mkdir -p webapp-project
cd webapp-project
mkdir .clk
Note that simply creating the .clk dir make webapp-project a project in clk point of view.
clk --project . parameter set aws --profile webapp-prod --region ap-southeast-1
clk parameter show aws
New local parameters for aws: --profile webapp-prod --region ap-southeast-1
aws --profile webapp-prod --region ap-southeast-1
clk aws s3 ls s3://webapp-assets
[webapp-prod/ap-southeast-1] aws s3 ls s3://webapp-assets
When I leave the project, my global defaults (or lack thereof) take over again:
cd ..
clk aws s3 ls
[default/us-east-1] aws s3 ls
This way, I never accidentally run a command against the wrong account just because I forgot to switch profiles.