This script demonstrates how to query an AWS Athena table from a different AWS account by assuming an IAM Role. It uses the AWS SDK for JavaScript v3.
The script performs the following actions:
- Assumes a Cross-Account Role: It uses the AWS Security Token Service (STS) to obtain temporary security credentials by assuming an IAM role in a target AWS account. This is a secure way to grant temporary access to your AWS resources to users from other AWS accounts.
- Executes an Athena Query: Using the temporary credentials, it connects to Amazon Athena and executes a SQL query against a specified database and table.
- Polls for Results: It periodically checks the status of the query until it completes.
- Fetches and Displays Results: Once the query is successful, it retrieves the results from the S3 output location, parses them into a JSON format, and prints them to the console.
- Node.js and Bun (or npm/yarn) installed.
- AWS credentials (
AWS_ACCESS_KEY_ID
andAWS_SECRET_ACCESS_KEY
) for an IAM user with permission to assume the target role. - An IAM Role in the target account that this script can assume. The role must have:
- A trust relationship that allows the source IAM user to assume it.
- An
ExternalId
condition in the trust policy for added security. - Permissions to run Athena queries and read the target table.
- Permissions to write query results to the specified S3 bucket (
s3:PutObject
,s3:GetObject
).
- Clone the Gist or download the
index.js
andpackage.json
files. - Install the dependencies:
bun install
The script is configured using environment variables. You can create a .env
file in the root of the project or export them in your shell session.
# Credentials for the IAM user in the source account
AWS_ACCESS_KEY_ID="YOUR_SOURCE_ACCESS_KEY"
AWS_SECRET_ACCESS_KEY="YOUR_SOURCE_SECRET_KEY"
AWS_REGION="us-east-1"
# Configuration for the cross-account role to assume
AWS_ASSUME_ROLE_EXTERNAL_ID="YOUR_UNIQUE_EXTERNAL_ID"
CLIENT_ORG_ID="TARGET_AWS_ACCOUNT_ID"
CLIENT_ROLE_NAME="NAME_OF_THE_ROLE_TO_ASSUME"
# S3 Bucket for Athena query results in the target account
CLIENT_BUCKET="your-athena-results-bucket"
CLIENT_BUCKET_PATH="path/for/results"
# Athena configuration in the target account
CLIENT_ATHENA_DB="your_athena_database"
CLIENT_ATHENA_TABLE="your_athena_table"
Once the dependencies are installed and the environment variables are set, run the script with:
bun start
The script will then print the query results to the console in JSON format.
This asynchronous function is responsible for the role assumption.
- It initializes the
STSClient
. - It sends an
AssumeRoleCommand
with theRoleArn
, aRoleSessionName
, and theExternalId
. - The
RoleArn
is constructed dynamically using theCLIENT_ORG_ID
andCLIENT_ROLE_NAME
environment variables. - If successful, it returns the temporary
accessKeyId
,secretAccessKey
, andsessionToken
.
This is the main function that orchestrates the process.
- It calls
getTemporaryCredentials()
to get the temporary credentials. - It initializes the
AthenaClient
using these temporary credentials. This ensures all subsequent Athena API calls are made with the assumed role's permissions. - It sends a
StartQueryExecutionCommand
. The SQL query is hardcoded in this example, but it could be made dynamic. It also specifies the output location for the results in S3. - It enters a
while
loop to poll the query's status usingGetQueryExecutionCommand
every 3 seconds. - If the query state becomes
FAILED
orCANCELLED
, it throws an error. - Once the query
SUCCEEDED
, it fetches the data usingGetQueryResultsCommand
. - The results from Athena are in a specific
ResultSet
format. The script parses this format, using the first row as headers and subsequent rows as data, to build an array of JSON objects. - It includes specific error handling for
InvalidRequestException
which is common when the assumed role lackss3:PutObject
permissions on the output S3 bucket.