A New and Standardized Way to Manage Credentials in the AWS SDKs

One of the advantages of using the AWS SDKs for programmatic access to AWS is that the SDKs handle the task of signing requests. All you have to do is provide AWS credentials (access key id and secret access key), and when you invoke a method that makes a call to AWS, the SDK translates the method call into a signed request to AWS.

The AWS SDK team has recently made some changes that make it more convenient, more consistent, and easier to specify credentials for the SDKs in a more secure way. In this post, we'll review the changes. 

Overview

In outline, all of the AWS SDKs now use a standard approach for how to manage credentials. This includes the AWS command-line interface (CLI) and the AWS Tools for Windows PowerShell. To configure credentials, you can do this:

  • Keep them in a set of environment variables that have standard names for all SDKs. The .NET SDK is an exception here, as I'll explain shortly.
  • Keep them in a central credential file that is shared by all the SDKs. And in that credentials file, now you can …
  • … use profiles. You can keep multiple sets of credentials in the same credentials files using different profile names. When you initialize a connection to AWS in code, you can specify the set of credentials you want to use.

Some of these options were available previously, but differed between SDKs. For example, different SDKs used different environment variable names, and the location and format of credentials files differed between SDKs. Now, with only one exception, you can choose any of these approaches, and whatever you do will work for all the SDKs. Once you've configured one SDK or the CLI, you can use the same credentials for any other.

Environment Variables

All the SDKs except the .NET SDK now can automatically look for credentials in the same environment variables: AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY. If you're working with temporary security credentials, you can also keep the session token in AWS_SESSION_TOKEN.

Credentials File and Profiles

Instead of keeping credentials in environment variables, you can now put credentials into a single file that's in a central location. The default location is this:

  • ~/.aws/credentials (Linux/Mac)
  • %USERPROFILE%\.aws\credentials  (Windows)

An important point is that the default location for the credentials file is a user directory. It's no longer part of a project file structure, such as an app.config file (.NET) or .properties file (Java). This can enhance security by allowing you to keep the credentials in a location that's accessible only to you, and it makes it less likely that you'll inadvertently upload credentials if you upload a project to a developer sharing site like GitHub.

The format for the credentials is the same for all the SDKs and the AWS CLI:

[default]
aws_access_key_id = ACCESS_KEY
aws_secret_access_key = SECRET_KEY
aws_session_token = TOKEN

(The aws_session_token value is needed only if you're including temporary security credentials in the file.) 

As noted, you can keep multiple sets of credentials in the same file, identifying each set using a profile name, like the following example. I'll discuss how to use these profiles shortly.

[default]
aws_access_key_id = ACCESS_KEY
aws_secret_access_key = SECRET_KEY
aws_session_token = TOKEN
 
[Alice]
aws_access_key_id = Alice_access_key_ID
aws_secret_access_key = Alice_secret_access_key
 
[Bob]
aws_access_key_id = Bob_access_key_ID
aws_secret_access_key = Bob_secret_access_key

For additional security of the credentials file, you can set the file's permissions to make sure that only the owner is allowed to access the file. In Linux, use chmod 600 to set owner-only permissions. In Windows, use the Properties window or use the icacls command.

Using the SDK Store for .NET and Windows PowerShell

If you use the .NET SDK or the AWS Tools for Windows PowerShell, instead of using environment variables or the centralized credentials file, you store credentials in the SDK Store. This option keeps encrypted credentials in your user folder. As with the credentials file, you can store multiple sets of credentials using different profile names. You can manage the SDK Store in two ways: using a graphical interface that's part of the AWS Toolkit for Visual Studio, or using PowerShell commands.

Reading Credentials at Run Time

Once you've got the credentials configured, the SDKs can find them and use them automatically—you don't need to explicitly reference the credentials in your code at all. For example, in the following line of Java code, when you initialize the AmazonEC2Client instance, the SDK finds the access keys you've configured and uses them for subsequent method calls that you make on the client instance.

AmazonEC2Client client = new AmazonEC2Client();

If you use code like this, the SDKs look for the credentials in this order:

  1. In environment variables. (Not the .NET SDK, as noted earlier.)
  2. In the central credentials file (~/.aws/credentials or %USERPROFILE%\.aws\credentials).
  3. In an existing default, SDK-specific configuration file, if one exists. This would be the case if you had been using the SDK before these changes were made.
  4. For the .NET SDK, in the SDK Store, if it exists.
  5. If the code is running on an EC2 instance, via an IAM role for Amazon EC2. In that case, the code gets temporary security credentials from the instance metadata service; the credentials have the permissions derived from the role that is associated with the instance.

To be clear, although the .NET SDK doesn't automatically include environment variables in its lookup hierarchy, you can read environment variables using a .NET method like Environment.GetEnvironmentVariable. You might do this if you're working with multiple AWS SDKs and want to use the same credentials across SDKs.

Specifying Credentials Using a Profile Name

If you don't pass any credential information during initialization, and if the credentials are not found in the known environment variables, the SDKs look for credentials in the central credentials file. In that file, the SDKs look for a profile named [default] and use those credentials. This profile must exist in the file. As an alternative to having a [default] profile, you can point to a specific profile in these ways:

  • By setting the AWS_PROFILE environment variable to the profile you want to use.
  • In .NET, by adding an AWSProfileName key in the  appSettings element in web.config or app.config file, like this:
    <configuration>
      <appSettings>
        <add key="AWSProfileName" value="my_profile_name"/>
      </appSettings>
    </configuration>
  • In PHP, by creating the following array in the  aws-config.php file or in a custom .php config file:
    <?php return array(
        'includes' => array('_aws'),
        'services' => array(
            'default_settings' => array(
                'params' => array(
                    'profile' => 'profile_name',
                    ...
                )
            )
        )
    );

Or you can read credentials from a profile in code. To do that, you include the profile name when you initialize the connection to AWS. The exact way you do this depends on what language you're using, as shown in the following examples.

Java

AmazonEC2Client client =
    new AmazonEC2Client(new ProfileCredentialsProvider("my_profile_name"));

C#

AmazonEC2Client client =
    new AmazonEC2Client(new StoredProfileAWSCredentials("my_profile_name"));

Ruby Version 2

credentials = Aws::SharedCredentials.new(profile_name: ‘my_profile_name’)
Aws::EC2::Client.new(credentials: credentials)

Ruby Version 1

provider = AWS::Core::CredentialProviders::SharedCredentialFileProvider.new(profile_name: "my_profile_name")
client = AWS::EC2.new(credential_provider: provider)

Python

import boto
from boto import ec2
ec2 = boto.ec2.connect_to_region('us-west-2', profile_name='my_profile_name')

PHP

$client = EC2Client::factory(array(
    'profile' => 'my_profile_name'
));

Node.js

// To set globally
AWS.config.credentials =
    new AWS.SharedIniFileCredentials({ profile: 'my_profile_name' });
 
 // To set for a particular service client
var creds = new AWS.SharedIniFileCredentials({ profile: 'my_profile_name' });
var client = new AWS.EC2({ credentials: creds });

What About My Existing Code and Configuration?

For backward compatibility, the AWS SDKs continue to support the configuration options you might have used previously. For example, the SDKs will use a local configuration file if your project has one. And of course, if you've hard-coded an access key into your code, it will still work—although we strongly recommend that you remove any embedded credentials in your code or in project-specific configuration files.

If you've been using the AWS CLI, you might already have a credentials file, which is in the same location as the new credentials file, but is named config. If so, the CLI will continue to use that file. However, if you create a new credentials file, the CLI will use that one instead. (Be aware that the aws configure command that you can use to set credentials from the command line puts the credentials in the credentials file and not the config file. The preferred region and output format are written to the config file.)

Conclusion

The new credentials management scheme is both more convenient and can help make credentials more secure. After you've installed the most recent version of your favorite AWS SDK or the AWS CLI, you can begin using the new scheme immediately. And if you've got existing applications that use embedded credentials or local configuration, we strongly urge you to update those to use the new scheme.

If you have questions, please post them to the AWS Forum.

More Information

For additional information about managing credentials in the AWS SDKs, see the following:

- Mike

Comments