Automating scripts for AWS Sandbox setup - Create a new user

Automating scripts for AWS Sandbox setup - Create a new user
Photo by Diego PH / Unsplash

I decided to go back and complete an old AWS Lambda & Serverless Architecture Bootcamp Udemy course I started in 2019. I didn't finish it at the time because I only learnt what I needed to know for the company project I was working on and now I have a bit of time on my hands I want to complete it.

This article series is about how I overcame the issues I faced with an out of date course, AWS playground limitations and what I did to automate as much as possible. All the code is in GitHub.

A few things have changed since that time including AWS services and Serverless Framework but with one additional difference - this time I am using the A Cloud Guru AWS Playground as my practice account.

The two main issues with the AWS ACG playground are that:

  • It limits the regions to us-east-1 and us-west-2 only. A bit further away from the UK but I can work with it.
  • There is a set 4 hour time limit so that meant restarting the environment setup from scratch each time it ran out. I only have a certain amount of time to give to the course before have something else I need to do. I really needed some automation scripts.

I could have used my personal AWS account but I wanted to

  • save money
  • not complicate my own account
  • make my mistakes safe in isolation
  • do some learning
  • get more practice with technologies I haven't used that much

Create profile to deploy Serverless Framework

You need a profile to deploy Serverless Framework as instructed in the Udemy course. Firstly, I logged on to the A Cloud Guru website and created a new AWS sandbox.

The ACG cloud_user will be set up in the account already so all you need to do is save the credentials to the ~/.aws/credentials file. Personally, I found it useful to repeatedly set up the cloud_user to keep the file open in Notepad++ and add/update directly. You could still use the AWS CLI but no need for me to go into that here.
It might be possible to automate this using Cypress but that means logging you into ACG with your own password. Not a priority for me but one that can be looked at later.

When attempting the deployment I found a couple of issues.

User not authorised to perform on resource with explicit deny

> serverless deploy
Serverless: Packaging service...

 Serverless Error ----------------------------------------
 
 User: arn:aws:iam::123456789012:user/cloud_user is not authorized to perform:
 cloudformation:DescribeStacks on resource: arn:aws:cloudformation:us-
 east-1:123456789012:stack/sls-notes-backend-prod/* with an explicit deny
Serverless Error

Although the cloud_user is restricted to what permissions you can add, it is recommended by Serverless Framework to create a custom user for deployment anyway and with the AdministratorAccess managed policy. Yes, I know we should practice least privilege access but I am using a lab that is thrown away after the timeout and for this Udemy course there is no need for me to go into that rabbit hole. Whereas runtime access should absolutely be least privilege. This article has a list of good practice around this sort of thing.

The security token included in the request is invalid

Serverless Error ----------------------------------------

The security token included in the request is invalid.
Serverless Error

Next error - in this case this was easier to resolve, it was late in the day so by the time I realised, it was the sandbox time that had expired and the profile was no longer valid.
Also be aware of copying the wrong Access Key Id because it would still come back with that error.

How the profile needs to be created

Once I got into repeatedly recreating the sandbox setup I knew I was going to have to do this time and again so I was thinking about what to use.
To create each user the following steps need to be taken:

  • Create the user
  • Attach the AdministratorAccess managed policy
  • Create the secret access key
  • Save the AWS profile to the credentials file

The AWS CDK is a great tool but in this case you need the CloudFormation permissions but the profile required needs creating first, a chicken/egg scenario.
I then thought I would use the AWS CLI in a batch file but that gets more complicated because you need to extract the responses in batch script which didn't look straightforward plus an old technology and I need to move on.
I thought I would give PowerShell a go but even that AWS SDK didn't support adding a managed policy so the AWS CLI would be required for that step.
I then decided on Python, I've had some prior experience and as it turned out it was the right decision.

Creating the new user script

Pre-requisites:

  • You need Python installed, preferably the latest
  • The AWS SDK Python library Boto3

First we add the imports.

import boto3
import subprocess
import csv
import os
import argparse
Imports

The script needs parameters because I want the choice to use a different profile to execute the script and a different user name to create. This is where you use the Argument Parser and each argument defaults to a set value.

# Set the arguments
parser = argparse.ArgumentParser(description='Create an AWS CloudFormation user.')
parser.add_argument('-e', '--executing-profile', dest='executingprofile', 
	default='cloudguru', help='The AWS profile to use to create the new user')
parser.add_argument('-n', '--new-user', dest='newuser', default='sls-user',
                    help='The new AWS user to be created')
args = parser.parse_args()
Parse the script arguments

To execute the script with the executing profile we need to create a session. Do note I am using the args.executingprofile value.

# Use the AWS profile for this session
session = boto3.Session(profile_name=args.executingprofile)
iam = session.client('iam')
Use the profile for this session

Then you create the user.

print("Create the new user")
userCreated = iam.create_user(UserName=args.newuser)
Create the new user

Then attach the AdministratorAccess policy to the new user.

print("Attach the policy to the new user")
iam.attach_user_policy(
    UserName=args.newuser, 
    PolicyArn='arn:aws:iam::aws:policy/AdministratorAccess')
Attach the policy to the new user

Now we can get the Access Key Id and Secret Access Key.

print("Create the users' secret access key")
accessKey = iam.create_access_key(
    UserName=args.newuser,
)

# Save the values to use later
newUserId = accessKey['AccessKey']['AccessKeyId']
secretAccessKey = accessKey['AccessKey']['SecretAccessKey']
Create the users' secret access key

With that we can save AWS credentials to a temporary CSV file. Note this is a much more effective and trouble-free way of getting the new credentials into the AWS credentials file.

print("Save the AWS credentials to a CSV file")
credentials_file = "credentials.csv"

with open(credentials_file, mode='w', newline='') as csv_file:
    fieldnames = ['User name', 'Access key ID', 'Secret access key']
    writer = csv.DictWriter(csv_file, fieldnames=fieldnames)

    writer.writeheader()
    writer.writerow({'User name': args.newuser, 'Access key ID': newUserId, 'Secret access key': secretAccessKey})
Save the credentials to a temporary file

In the later versions of Python you had an issue where blank lines would appear between each row in the CSV file. To fix this you use newline='' when opening the file.

The AWS SDK does not support a way to get the credentials into the file so easiest was is execute through the AWS CLI.

subprocess.run(['aws', 'configure', 'import', '--csv',
                f'file://{credentials_file}'])
Import the credentials file

Finally, delete the temporary credentials file.

os.remove(credentials_file)
Delete the credentials file

You now have a quick and easy way to create an Admin user

> python .\create_aws_user.py

The full script is located in GitHub here.

In part 2, I go over the next issue where the Udemy course required a pipeline building.