Modifying AWS Route53 Records in vRealize Automation – Part 1

20161114-1I recently built a vRealize Automation blueprint in the lab that provisions a vSphere machine into the DMZ which could be accessed externally. For users to be able to connect to this machine it will need a DNS record to be created in my external DNS domain, which is hosted with Amazon Web Services.

In order for my solution to be provisioned without manual intervention, this last step – the DNS record creation – also needs to be automated. How can we do this all from a vRA blueprint?

Actually, using an XaaS workflow built in vRealize Orchestrator, it’s quite easy.

Whilst AWS offers an API for automation operations such as this, it is far from straightforward to use. The documentation for connecting is pretty thorough and explains how to construct the API request and execute it.

Once a catalog item has been requested in vRealize Automation, it will begin a deployment which will as one of the final steps invoke a vRO workflow. This workflow will connect to AWS Route53 and create the necessary DNS record for our hosted zone.

Mapping out some technical thoughts, the potential solution seemed straightforward:

Easy, right?

Unfortunately, making REST calls to AWS is far from simple – even more so when coding it in vRO.

Other posts in this series:

  1. Part 1
  2. Part 2

Consulting the Documentation

To begin crafting the solution I needed to consult the documentation. Making REST API calls to Route53 requires the use of the AWS Signature Version 4, the documentation for which can be found at https://docs.aws.amazon.com/general/latest/gr/signature-version-4.html.

To sign a request, you first calculate a hash (digest). Then you use the hash value, some other information from the request, and your secret access key to calculate another hash known as the signature. Then you add the signature to the request as part of the Authorization header.

To reach our desired outcome of producing an authentication signature for our REST API call we have to complete four tasks. They break down as follows:

Task 1: Create a Canonical Request

This requires us to create our request, consisting of the payload, the URI, the headers, and the signed header. When this is all put together, it forms the “canonical request”. This will then be hashed giving us our output, which will be used in the next task.

Reference: https://docs.aws.amazon.com/general/latest/gr/sigv4-create-canonical-request.html.

Task 2: Create a String to Sign

The string to sign includes meta-information about the request and about the canonical request that created in task 1.

The output of this will be a string and a signing key, both of which will be used in the following task.

Reference: https://docs.aws.amazon.com/general/latest/gr/sigv4-create-string-to-sign.html

Task 3: Calculate the signature

To calculate the signature, we must first derive the signing key. We start off with our AWS secret key, and then use that to create a series of hash-based message authentication codes (HMACs). As we create each one, it becomes the input for the next one.

One we have the signing key, we hash that and the string to sign from task 2. The output of this is then encoded from binary to hex. What we are left with is then our signature.

Reference: https://docs.aws.amazon.com/general/latest/gr/sigv4-calculate-signature.html

Task 4: Add the signature to the HTTP request

The last step in the process is to creature the authorization header (string). This is simply a matter of concatenating our series of known inputs, such as our AWS access key, service, signed headers and signature.

Once we have our authorization header to append it to our HTTP REST request as we would any normal header.

The process should look something like this:

Image courtesy of Amazon Web Services

Getting Started

Please note: the following isn’t the best use of re-usable code, as it would need re-engineering for using with other AWS services. Hopefully, I’ll get the chance to do that when I have more time.

Create the following XML file:

<?xml version="1.0" encoding="UTF-8"?>
<ChangeResourceRecordSetsRequest xmlns="https://route53.amazonaws.com/doc/2013-04-01/">
<ChangeBatch>
<Changes>
<Change>
<Action>{attXmlConfigAction}</Action>
<ResourceRecordSet>
<Name>{attXmlConfigRecord}</Name>
<Type>{attXmlConfigType}</Type>
<TTL>{attXmlConfigTtl}</TTL>
<ResourceRecords>
<ResourceRecord>
<Value>{attXmlConfigValue}</Value>
</ResourceRecord>
</ResourceRecords>
</ResourceRecordSet>
</Change>
</Changes>
</ChangeBatch>
</ChangeResourceRecordSetsRequest>

view raw
route53.xml
hosted with ❤ by GitHub

Log in to vRealize Orchestrator, click on the Resources tab and create a new folder then upload the XML file.

Click on the Configurations tab and create a new folder for AWS. Create a new element called login with two attributes, both of type string:

  • attAccessKey
  • attSecretKey

Enter your AWS keys into the attributes.

Create a new folder for Route53 followed by a new element for your hosted zone. Create four attributes, all of type string:

  • attHostedZone
  • attRegion
  • attService
  • attUrl

Enter your hosted zone ID in the first attribute. Set the region to “us-east-1”, the service to “route53” and the URL to “route53.amazonaws.com”.

Please note: The region must be set to “us-east-1”, regardless of where you are located, for this to work.

Your configuration structure should look something like this:

Click on the Actions tab and create two new modules (substitute accordingly):

  • com.hobbitcloud.aws.date
  • com.hobbitcloud.aws.signing

Under com.hobbitcloud.aws.date create an action called getAmzDate. Create an input called inDate of type string, set the return type as string, and paste in the following code:

var dateStr;
var chars = [":","-"];
for (var i = 0; i < chars.length;i++) {
while (inDate.indexOf(chars[i]) !== 1) {
inDate = inDate.replace(chars[i],"");
}
}
dateStr = inDate.split(".")[0] + "Z";
return dateStr;

view raw
getAmzDate.js
hosted with ❤ by GitHub

Under com.hobbitcloud.aws.signing create an action called getSigningKey with a return type set to string. Create the following inputs all of type string, except for inSecretKey, which is of type SecureString:

  • inAmzAuthDate
  • inRegion
  • inSecretKey
  • inService

Paste in the following code:

var kDate = CryptoDigest.hmacSha256(CryptoEncoding.base64Encode("AWS4" + inSecretKey), CryptoEncoding.base64Encode(inAmzAuthDate));
var kRegion = CryptoDigest.hmacSha256(kDate, CryptoEncoding.base64Encode(inRegion));
var kService = CryptoDigest.hmacSha256(kRegion, CryptoEncoding.base64Encode(inService));
var kSigning = CryptoDigest.hmacSha256(kService, CryptoEncoding.base64Encode("aws4_request"));
var keySigning = CryptoEncoding.base64toHex(kSigning);
return keySigning;

view raw
getSigningkey.js
hosted with ❤ by GitHub

That’s it for resources, configurations and actions. In part 2 we will construct the main workflow.

2 thoughts on “Modifying AWS Route53 Records in vRealize Automation – Part 1

  1. Pingback: Modifying AWS Route53 Records in vRealize Automation – Part 2 | virtualhobbit

  2. Pingback: vExpert Cloud Management July 2020 Blog Digest - VMware Cloud Management

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.