Debugging a GetSessionToken issue
Tags: aws, security
Published: 2022-06-30 06:39:12

When the `sts.getSessionToken()` request returns the `AccessDenied: Cannot call GetSessionToken with session credentials` error, it indicates that we are trying to use temporary credentials to obtain another set of temporary credentials.

## 1. The situation

I wanted to connect an <a href="https://aws.amazon.com/ec2/" class="link" target="_blank" rel="noopener noreferrer">EC2</a> instance to <a href="https://www.mongodb.com/atlas" class="link" target="_blank" rel="noopener noreferrer">Mongo Atlas</a> when I received the following error message:

```bash
AccessDenied: Cannot call GetSessionToken with session credentials
```

My EC2 instance had an **instance role** attached, which I added to the database users in Mongo Atlas.

What could have happened?

## 2. Explanation

The error message indicates that I wanted to get temporary credentials using another set of temporary credentials.

Mongo Atlas supports <a href="https://www.mongodb.com/docs/atlas/security/passwordless-authentication/#set-up-passwordless-authentication-with-aws-iam" class="link" target="_blank" rel="noopener noreferrer">passwordless authentication</a> using <a href="https://aws.amazon.com/iam/" class="link" target="_blank" rel="noopener noreferrer">AWS IAM</a>. The Mongo driver will read the temporary credentials (access key id, secret access key and session token) from the EC2 metadata.

My idea of using the instance role's temporary credentials was correct. But somewhere deep in the code, where the database connection gets set up, we called the `GetSessionToken` <a href="https://docs.aws.amazon.com/STS/latest/APIReference/welcome.html" class="link" target="_blank" rel="noopener noreferrer">STS</a> API endpoint to receive temporary credentials in certain situations.

## 3. The solution

The `GetSessionToken` API endpoint returns temporary credentials for **AWS accounts** or **IAM users**.

An EC2 instance role, similarly to a <a href="https://aws.amazon.com/lambda/" class="link" target="_blank" rel="noopener noreferrer">Lambda</a> execution role or an <a href="https://aws.amazon.com/ecs/" class="link" target="_blank" rel="noopener noreferrer">ECS</a> Task role, already works with temporary credentials. None of them are an AWS account or an IAM user.

When I want to test my application from my laptop, I might use my own AWS **user** credentials.

Users have long-term credentials (an access key id and a secret access key), so calling the `GetSessionToken` endpoint and adding the temporary credentials to the database connection string is a great way to reduce the attack surface.

But in the case of an EC2 instance, the temporary credentials are already present, and we can call Atlas with them straight away. We don't need to get another set of credentials.

## 4. About GetSessionToken

We must call the `GetSessionToken` operation with long-term credentials. In theory, both the root user and an IAM user can invoke the endpoint, although it's a bad practice to use the root user for everyday operations.

The endpoint returns a set of temporary credentials containing an **access key id**, **secret access key**, and **session token**. We can use these credentials in operations that require multi-factor authentication or connecting to a database in a passwordless way.

In most cases, we want to use **temporary credentials** in our applications to connect to the database or other AWS services.

The request to `GetSessionToken` can have a `DurationSeconds` parameter that specifies how long the credentials should remain valid. The length of the user sessions can vary between 15 minutes and three days, with 12 hours being the default.

But we cannot call any STS API endpoints with the credentials provided by `GetSessionToken`, except `AssumeRole` and `GetCallerIdentity`. It means that we are not allowed to invoke, for example, `GetSessionToken` again with the credentials the endpoint has already provided.

## 5. Conclusion

The `AccessDenied: Cannot call GetSessionToken with session credentials` error message shows that we invoked the STS endpoint with a set of temporary credentials. The operation doesn't allow this call.

The solution is either call `GetSessionToken` with long-term credentials (an IAM user) or remove the additional temporary credentials call from the workflow.

The application's role should be sufficient for the successful connection, given the credentials have the relevant permissions.

## 6. Further reading

<a href="https://docs.aws.amazon.com/STS/latest/APIReference/API_GetSessionToken.html" class="link" target="_blank" rel="noopener noreferrer">GetSessionToken</a> - API documentation