Working with ARNs in AWS CDK

Roy Ben Yosef
CyberArk Engineering
4 min readJul 2, 2023
Photo by Collab Media on Unsplash

Once you start working with AWS, you will quickly learn about “Amazon Resource Names”, better known simply as “ARNs”, which uniquely identify AWS resources.

According to the AWS documentation, the format of an ARN is one of the following:

arn:<partition>:<service>:<region>:<account-id>:<resource-id>
arn:<partition>:<service>:<region>:<account-id>:<resource-type>/<resource-id>
arn:<partition>:<service>:<region>:<account-id>:<resource-type>:<resource-id>

So if, for example, we have the following ARN of an AWS ECR repository:

arn:aws:ecr:us-east-1:111111111111:repository/my-repository

Then the components are:

  • partition: aws
  • service: ecr
  • region: us-east-1
  • account-id: 111111111111
  • resource-type: repository
  • resource-id: my-repository

Often, when working with such ARNs, you might be tempted to work directly with those strings, which means you’ll try to parse or build them, which could get ugly fast.

An example could be:

arn = 'arn:aws:s3:::my_bucket'
bucket = arn.split(':')[-1]

arn = 'arn:aws:ecr:us-east-1:111111111111:repository/my-repository'
repo = arn.split('/')[-1]

And you might also be tempted to use regular expressions, but as the adage goes — “you have a problem, you chose to use regular expressions, and now you have two problems.

The problem is that these methods are not too clean as far as code goes, and could easily fall into edge cases, which are generally error-prone.

The AWS CDK Way: Using the Arn Class

AWS CDK provides us with a great solution: the Arn class. This class helps us work with ARNs by saving us the trouble of manipulating the string ourselves (splitting and concatenating ARN components).

If you are working on a CDK project, I recommend using it instead.

This class provides the following functionalities:

  1. Split the provided ARN into its components
  2. Create an ARN from given components
  3. Extract the full resource name from an ARN

Let’s explore each one and see how they help us.

1. Split the provided ARN into its components

Many times, you have an ARN string on your hand, and you want to parse it and get its components. Using the Arn class, you could do this by calling the Arn.split function.

Let’s look at an example:

components = Arn.split(arn='arn:aws:iam:us-east-1:123456789012:role/testRole', 
arn_format=ArnFormat.SLASH_RESOURCE_NAME)
print(components)

> ArnComponents(resource='role',
> service='iam',
> account='123456789012',
> partition='aws',
> region='us-east-1',
> resource_name='testRole'
> arn_format=<ArnFormat.SLASH_RESOURCE_NAME: 'SLASH_RESOURCE_NAME'>)

Using the split function, the result provides each component value (resource, account, etc.) in an easily accessible way.

Note that we needed some knowledge regarding the format of the ARN when passing the arn_format parameter. In this case, we passed SLASH_RESOURCE_NAME which represents a format where the ‘resource’ and ‘resourceName’ parts are separated with a slash.

It’s important to understand that the ArnFormat is not something formal that you find in the AWS docs, but rather something that CDK defines by examining and understanding the different ARN formats.

To learn more about the available format typed, see the CDK docs.

2. Create an ARN String From Given Components

Using the Arn.format function, we can create an ARN string from a set of given components.

Here, I specify the partition, region and account, and the format type COLON_RESOURCE_NAME which you can infer from each resource docs.

You can either pass the region, account and partition explicitly:

arn_str = Arn.format(ArnComponents(partition='aws', 
service='rds',
region='us-east-1',
account='123456789012',
resource='db',
resource_name='mysql-db',
arn_format=ArnFormat.COLON_RESOURCE_NAME))

print(arn_str)

> arn:aws:rds:us-east-1:123456789012:db:mysql-db

Or call it from your CDK stack object, which uses the stack’s region account and partition:

stack = CdkTestStack(app, "CdkTestStack")

# Option 1:
arn_str = stack.format_arn(service='rds',
resource='db',
resource_name='mysql-db',
arn_format=ArnFormat.COLON_RESOURCE_NAME)

# Option 2:
arn_str = Arn.format(stack=stack,
components=ArnComponents(
service='rds',
resource='db',
resource_name='mysql-db',
arn_format=ArnFormat.COLON_RESOURCE_NAME))

Keep in mind the following points:

  • Usually, it is preferable to use the stack instead of hard coding those values. For example, if you choose to use AWS GovCloud, you might be surprised that the partition is “aws-us-gov” instead of “aws”.
  • Some ARNs do not include a region and/or an account (e.g. IAM roles are account level, and S3 buckets are global). In which case you need to pass an empty string as the region and/or account, for example:
arn_str = self.format_arn(
region='',
service='iam',
resource='role',
resource_name='my-role')

> arn:aws:iam::111111111111:role/my-role

3. Extract the Full Resource Name

The Arn.extract_reousrce_name function allows you to get the full resource name from an ARN string that contains “/” separators. You must provide the resource type yourself (See the CDK docs for details):

arn = 'arn:aws:iam::111111111111:role/path/to/role/name'
resource_name = Arn.extract_resource_name(arn=arn, resource_type='role')
print(resource_name)

> path/to/role/name

Working Hassle-free with ARNs in AWS CDK

When working with ARN strings, you often need to parse its elements or build an ARN string from its components. Doing this by working with the string values directly could lead to errors.

CDK’s Arn utility class solves this problem and saves a lot of headaches compared with working directly with the ARN strings.

--

--

Roy Ben Yosef
CyberArk Engineering

Sr. Software architect at CyberArk’s Technology Office. Into code, architecture and problem solving. Like to build and fix stuff. Usually late at night.