AWS STS (Security Token Service) is a service that allows you to create temporary credentials for AWS resources without having to create an IAM user.
Using STS in AWS
Because credentials are produced on-demand, you don’t need to inject any access keys or environment variables into your application.
You do not have to replace them or remember to remove them when they are not needed anymore because they’re temporary credentials. How does this, however, grant the contractor access to your buckets? IAM (Identity and Access Management) roles play a major part in this.
In most cases, a user from another AWS account cannot assume one of your roles. You can, instead, change the role’s trust policy to trust the external user account and allow it to take on the role. Assuming the role, the user will gain access to the necessary resources.
Creating IAM Role
First, we must create an IAM role that could allow the appropriate access to the S3 buckets once it is assumed. Now let’s begin the process of creating the IAM role:
Then we create a new role:
We chose the option of allowing users from other accounts to assume the job because your contractor does not have a user account in your AWS environment. You’ll need to obtain your contractor’s AWS Account ID in order to enter it here. The Account ID isn’t deemed confidential in and of itself. You can use your own Account ID for testing:
The permissions that the role will grant to an entity must then be defined. Please note that using AWS Managed Policies (the one having the orange box logo) rather than custom policies is one of AWS IAM’s security best practices aimed at preventing the creation of a large number of policies that no one checks or maintains:
However, we do not utilize one of the default S3 rules in this example since we want to offer highly particular access privileges. As a result, we adhere to the following policy:
We’ll use S3 as a service in this example, and the resource in question is the bucket “importantprojectbucket.” The name of your bucket will be different because buckets must be globally unique. For this example, you can create a new bucket (it can be private, with all default settings) if you want.
We just need the contractor to be able to place objects in the bucket and nothing else, thus the overview should now look like this:
Simply give it a sensible name and description (for example, “importantproject-put-bucket”).
Our policy was created successfully. That name (in this case, “importantproject-put-bucket”) should be copied.
Let’s reload the list of policies in our previous browser tab and paste the name of the one we just created:
We won’t need any tags, so we can jump forward to the next step and name our role. It could be something like “importantproject-contractorA-bucket-put”:
Also, make a note of the new role’s ARN, which can be seen on the overview page – we’ll need it later to deliver it to the contractor:
Limiting the number of people with whom you can have a trust relationship
So now we know what we’re supposed to do. However, in terms of offering the least privilege, it is not ideal because it allows anyone with access to your contractor’s AWS account to assume that role. This is something we can check and change. Open the newly – created role, navigate to the “Trust Relationships” page, and select “Edit trust relationship”:
We’ll see something along these lines:
As you’ve seen, our role trusts the contractor’s account’s “root.” This does not refer to your contractor’s most privileged AWS superuser, but rather to any authorized and authenticated principal in the provided account. Anybody who logs into the contractor’s AWS environment, in other words.
We’d like to amend this so that only “Richard,” a contractor’s employee, should assume the role. In a practical case, you’d ask him for his AWS username; however, if you’re working in your own AWS environment and don’t have another account, you can simply establish one. Return to the IAM console and click “Add user”:
Let’s continue with the permissions by granting Richard Programmatic Access. Richard doesn’t need any rights, especially when it comes to writing to S3 buckets!
Let’s go straight to the last overview page and click create a user without making any changes. It will alert us that the user has no permissions, but that’s fine since we’ll take care of that with our newly formed role.
Remember to note down your programmatic access credentials so you may test out our setup later:
These credentials can be saved locally in your AWS credentials file: /.aws/.credentials. You can call the profile “importantproject,” for example, and the file will look like this:
Of course, in a live environment, this file would be your contractor’s standard AWS credentials file on his or her own machine. In this case, we’re being a little schizophrenic by playing both contractor and customer at the same time.
We will now go back to the AWS console
We can return to our role’s trust relationship and change the JSON properly now that we know the username – “Richard.” In a real-world scenario, you’d enter the following user name for your contractor’s employee:
Only our contractor’s employee Richard (or, in our example, our local user Richard) will be able to assume that role when we “Update Trust Policy.” You can fine-tune the trust policy such that Richard could only assume the role if he applied Multi-Factor Authentication, arrives at the agreed-upon time and date, and comes from a certain IP address, just to mention a few.
Assuming a Role
We use the Security Token Service (STS) to assume a role, which provides us with temporary credentials to use the role. Why do we need two sets of credentials? You acquire credentials when you assume a role, which you may use to make API calls.
You can use these credentials to use the role until they expire. They’re distinct from your original credentials, so you can use them for different API calls at the same time. Temporary credentials differ from long-term credentials in appearance.
The sts:AssumeRole action is the API request we need to execute to assume the role. The ARN of the role we want to assume, as well as a session name, must be specified here.
The session name will be displayed in CloudTrail, and it is one of the ways to see who has assumed a role. We can additionally indicate how long the credentials should be valid if desired. In IAM, the highest limit is 72 hours, but you can set a lower restriction for each position.
In order to be successful, the principal who assumes the position must have the following: In its identity policy, the role must have AssumeRole permission for said position, and the principal must be included in the role’s trust relationship.
If either of them is absent, the call will be terminated. The response coming from the STS contains the credential objects with four bits of information when every permission has been correctly set up:
- Security Token
- Secret Access Key
- Access Key Id
- Expiration – a timestamp indicating when the credentials will expire
The first three pieces of information above can then be used to create an API client and at the same time, make calls to the API using the role’s permission.
Possible Errors Faced During the Process
Access Denied when assuming a role
This is the most common error you’ll bump into, and there are a few things to look for:
- Check that the role’s ARN is valid.
- Ensure that the caller’s identity is such a way that the authorization is granted under sts:AssumeRole’s policies.
- Ascertain that the role’s trust relationship refers to the entity that calls the assumed role.
- Make sure neither of the two policies has an explicit “deny” for the operation.
Whenever you assume a role, you are given temporary credentials that will expire after a certain amount of time has passed. Here’s how it seems. The solution is simple: simply re-assume the role and log in using the new temporary credentials.
Access Denied when using a role
When making use of a role, you may get Access Denied errors that aren’t supposed to be there. There are two major causes of errors in this situation:
- The permissions are really not there, as you can see by looking at the policies connected to the position.
- You’re not certainly using the role, as determined by the aws sts get-caller-identity API call, which returns the ARN of the entity performing the API call. This API Docs doesn’t need any specific permissions.