AWS Developer Tools Blog

Handling Credentials with AWS Tools for Windows PowerShell

The cmdlets provided in the AWS Tools for Windows PowerShell provide three ways to express credential information. Some approaches are more secure than others. Let’s take a look.

Using Credential Parameters

All cmdlets in the toolset accept -AccessKey, -SecretKey and -SessionToken parameters (-SessionToken is used when the access key and security key are part of time-limited temporary credentials obtained from the AWS Security Token Service). The intent of these parameters is to allow you to specify credentials for AWS Identity and Access Management (IAM) user accounts that you have created, optionally with restricted access to services and/or service operations. Using these parameters to pass your root account credentials can be considered the least secure (and therefore least desirable) way of passing credential information to cmdlets and we strongly recommend you investigate and use IAM user accounts.

IAM accounts can be created using the AWS Management Console or using the Visual Studio toolkit. In Visual Studio, open the AWS Explorer window and expand the AWS Identity and Access Management node. Right-click on the Users node and select Create User…. In the resulting dialog box, give the user account a name and select OK. The new user account will be added to the tree in AWS Explorer, double-click it to open a window in the IDE where we can configure what the account has access to.

The first step in configuring the IAM user is to obtain AWS access and secret keys. Select the Access Keys tab, and then click the Create button. A dialog box will appear with an option to also save the generated keys locally (and securely) in the toolkit – be sure to check this option so that we can subsequently view the secret key. Click OK and the window will update to show the generated keys, which you can now copy and paste for use with PowerShell:

The second step in configuring the IAM user is to add a policy that will give access to AWS. By default, the new policy will give access to all AWS services, service operations, and resources, but using the editor in Visual Studio (or the AWS Management Console) you can restrict this. To create the policy in Visual Studio, select the Policies tab and click Add Policy. Give the policy a name in the dialog box that appears and click OK. You can then see the policy and edit to suit; when you’ve finished, click Save on the window’s toolbar:

Now that you have obtained the keys and set up a policy governing access, you can use the IAM user account with PowerShell using the previously mentioned -AccessKey and -SecretKey parameters:

PS C:> Get-EC2Instance -AccessKey 123MYIAMUSERACCESSKEY -SecretKey 456MYIAMUSERSECRETKEY

If you want to be even more secure, we recommend that you further configure the new user account with a policy that restricts access to just the service(s), service operations, and AWS resources that you want to use with PowerShell. How to do that is beyond the scope of this blog, but see IAM Users and Groups for more information on how to set up and configure IAM user accounts.

To use session tokens, first get the token with Get-STSSessionToken and then pass it with the temporary credentials on subsequent commands:

# This example shows how to get and use temporary session credentials
PS C:> $tempcreds = Get-STSSessionToken -AccessKey 123MYIAMUSERACCESSKEY -SecretKey 456MYIAMUSERSECRETKEY -DurationSeconds 900
PS C:> Get-EC2Instance -AccessKey $tempcreds.AccessKeyId -SecretKey $tempcreds.SecretAccessKey -SessionToken $tempcreds.SessionToken
... call other cmdlets until session token expires...

The disadvantage to using the credential parameters is that you need to repeat them for every cmdlet in your script or at the shell prompt. A secure key value is a lot to type accurately even once, so you might therefore be tempted to place this information into variables at the head of your script and simply reference those; however, we’d very much like you to think twice before doing this! It’s easy to forget the values are there and share the script and…well, the credentials have then leaked. If these are your root credentials then this is, in a classic piece of understatement, a very bad idea! With IAM user accounts you can at least rotate the credentials, but it’s best not to get into this situation at all. So given that using raw credentials is inconvenient and less secure, what better ways exist?

Using the Initialize-AWSDefaults Cmdlet

After installation of the toolset, you might have noticed a new Start menu entry called Windows PowerShell for AWS. This launches a PowerShell shell with the AWSPowerShell module loaded (useful for machines that have PowerShell version 2 installed, where modules do not auto-import). This shell then runs a cmdlet named Initialize-AWSDefaults, which performs a number of checks:

  1. Have you set up a default set of credentials (which have the fixed name AWS PS Default) on the machine/EC2 instance? If so, the cmdlet reads the credentials securely into the current shell. They are then automatically available to future cmdlets that you run in that shell without needing to specify any credential data on a per-cmdlet basis (unless you want to of course).
  2. If the cmdlet is running on an EC2 instance and the default set of credentials does not exist, can we obtain credentials from the role that the instance was launched with by inspecting instance metadata? If so, the cmdlet retrieves the credential data and stores it locally on the instance (again with the name AWS PS Default) before loading the credentials into the shell ready for use.
  3. If credential data cannot be satisfied from the local encrypted store or role information in the instance metadata, the cmdlet prompts you to supply the credentials. This is where you would get to type an access key and secret key – which could be an IAM user account.

This example shows the shell after using the Windows PowerShell for AWS shortcut on the Start menu for the first time on an EC2 instance that was launched using a role:

Initialize-AWSDefaults: Credentials for this shell were set using instance profile

Specify region
Please choose one of the following regions to use or specify one by system name
[]   [] us-east-1  [] us-west-1  [] us-west-2  [] eu-west-1  [] ap-northeast-1
[] ap-southeast-1[] ap-southeast-2  [] sa-east-1  [] us-gov-west-1  [?] Help
(default is ""):

Note the text following the cmdlet name – this confirms that credential data was successfully obtained, securely, from the role that the EC2 instance was launched with. As this is the first run, the cmdlet then asks you to select a default region (it won’t ask for this on subsequent runs). The credential data you supply via the role, or enter manually, is stored and will be used in future shells that run Initialize-AWSDefaults, unless you override them.

The Initialize-AWSDefaults cmdlet is therefore very useful in a couple of situations. Its main job is in setting up credentials in EC2 instances launched using a role without ever needing the user to explicitly enter access and secret keys. It can also be used on your own machine, either via the Start menu shortcut or by running it when you start a new shell.

Note though that Initialize-AWSDefaults works best if you have only one AWS account. As a developer, I tend to use multiple accounts, so I prefer the third and final method, the Set-AWSCredentials cmdlet that gives me ultimate control.

Using the Set-AWSCredentials Cmdlet

As I mentioned above, Set-AWSCredentials is my preferred go-to cmdlet for both loading and saving credential data on my machine as it has the most flexibility when I need to manage multiple sets of accounts, including IAM user accounts I have created that have restricted access to services, service operations, and AWS resources.

Credential data is stored in a per-user encrypted file and is shared between PowerShell cmdlets and the AWS Toolkit for Visual Studio. If you have already registered AWS accounts in AWS Explorer inside Visual Studio, then these credentials are available right away in PowerShell. Any accounts that you register through PowerShell will also show up in Visual Studio (including the AWS PS Default account you may have set up with Initialize-AWSDefaults).

Usage of the Set-AWSCredentials cmdlet falls into two areas: storing credential data, and loading it for use. To store credentials, you use the -StoreAs parameter to assign a name to the credentials, along with the credential information. The cmdlet then saves the data into the local encrypted credential file:

PS C:> Set-AWSCredentials -AccessKey 123MYACCESSKEY -SecretKey 456SECRETKEY -StoreAs myAWScredentials

Having saved the credentials you can discard the current shell and start a new one. To load the credentials into the new shell, you run the same cmdlet, but this time pass the name you specified as the -StoredCredentials parameter:

PS C:> Set-AWSCredentials -StoredCredentials myAWScredentials

Once the credentials are loaded, the cmdlets you run in that shell do not need to have credential data supplied – it will be retrieved from the current shell instance automatically. If you need to change credentials temporarily, all cmdlets accept a -StoredCredentials parameter that looks up the credentials for the name specified and uses them for that particular cmdlet’s invocation:

PS C:> Set-AWSCredentials myAWSCredentials

# These two examples yield the same data
PS C:> Get-EC2Instance -StoredCredentials myAWScredentials 
PS C:> Get-EC2Instance 

# This invocation returns different data, as alternate credentials are specified
PS C:> Get-EC2Instance -StoredCredentials myOtherAWScredentials 

By the way, the -StoredCredentials parameter can also be used with Get-STSSessionToken (shown earlier) to avoid having to expose your keys when obtaining temporary session credentials.

Loading Credentials from a PowerShell Profile

Remembering to run Set-AWSCredentials (or Initialize-AWSDefaults) in each shell or PowerShell host that you launch can be tiresome, so I make use of my user profile to do this for me and to also set a default region for my shells. Your user profile is simply a script file named Microsoft.PowerShell_profile.ps1 that exists in a folder named WindowsPowerShell in your user documents location. See How to Create a Windows PowerShell Profile for more details on the preferred way to create this file.

Once the file is created, load it into a text editor and add the call to Set-AWSCredentials (and Set-DefaultAWSRegion if you like) to initialize all shells you load, however they are launched. For example, my profile contains these lines. The first loads my personal AWS credentials stored with the name ‘steve’.

Set-AWSCredentials -StoredCredentials steve
Set-DefaultAWSRegion us-west-2

Note that if you are using PowerShell version 2, you will need to import the AWSPowerShell module before running those cmdlets. Under PowerShell version 3, the module auto-imports whenever any of the cmdlets it contains is run.

As I routinely switch credentials and regions for AWS SDK testing, I also have a custom prompt function in my profile that shows me the current user and region for the shell – you may find this useful too:

function prompt 
{
    $realLASTEXITCODE = $LASTEXITCODE

    $prompt = "PS "
    if ($StoredAWSCredentials -ne $null)
    {
        $prompt += "$StoredAWSCredentials"
    }
    
    if ($StoredAWSRegion -ne $null) 
    { 
        $prompt += "@"
        $prompt += "$StoredAWSRegion" 
    }
    
    $prompt += " "
    $prompt += $pwd.ProviderPath
    $prompt += "> "

    $global:LASTEXITCODE = $realLASTEXITCODE
    $prompt
}

This function (which is called automatically by PowerShell) displays a custom shell prompt:

PS steve@us-west-2 C:Dev> 

In addition, as I change region/credentials, it updates automatically. Cool!

Summary

This post has shown you a number of ways in which credential data can be supplied to AWS cmdlets. Hopefully, you can now see how to pass credential data without compromising your root AWS keys by making use AWS Identity and Access Management (IAM) user accounts and the encrypted credentials file shared with the Visual Studio toolkit or using roles with EC2 instances to pass credentials without them ever appearing in plain view.