All Articles

AWS Assume Role Implementation within Boomi - S3 Copy Object Script

AWS allows a user or resource to assume a role to gain access to specific resources. To authenticate to S3 and copy a file from one bucket to another, a script must be used to create an authentication header. How to implement AWS Assume Roles within an integration is reviewed in AWS Assume Role Implementation within Boomi and AWS Assume Role Instance Profile Implementation within Boomi. This article expands upon how to implement it for S3 CopyObject.

Knowledge Articles Associated with This Article

AWS S3 CopyObject

Process Overview

aws assume role process overview

Figure 1. AWS Assume Role S3 CopyObject Overview.

After the AWS Assume Role’s temporary credentials have been obtained, a Set Property shape will set required Dynamic Document Properties, a Groovy will execute, and an HTTP Connection will execute the AWS S3 CopyObject action.

Set Property Configuration

aws s3 copy set properties

Figure 2. AWS S3 Copy Set Properties.

Table 1. AWS S3 Copy Set Properties Configuration.

Dynamic Document Property Value
DDP_AWS_BUCKET <target-bucket>
DDP_FILE_NAME <target-file-name-key>
DDP_HTTP_METHOD PUT
DDP_CONTENT_TYPE i.e. text/csv
x-amz-security-token DPP_AWS_SESSION_TOKEN
x-amz-copy-source <source-bucket>/<source-file-name-key>

All properties being set are Dynamic Document Properties and will be used within the script and HTTP Connection. DDP_CONTENT_TYPE will be set to the type of content being moved. x-amz-security-token will be set using a Dynamic Process Property that was set when the AWS Assume Role temporary creates were obtained. x-amz-copy-source will look similar to bucket-name/file-name.

Data Process: Groovy Script

Next, the script below will be added to a Data Process shape.

// Groovy 2.4
// https://docs.aws.amazon.com/AmazonS3/latest/userguide/RESTAuthentication.html

/*-------------------------------------------------------
Required inputs:
DPP: DPP_AWS_ACCESS_KEY
DPP: DPP_AWS_SECRET_KEY
DPP: DPP_AWS_SESSION_TOKEN  // Only required if assuming role
DDP: DDP_AWS_BUCKET
DDP: DDP_FILE_NAME
DDP: DDP_HTTP_METHOD
DDP: DDP_CONTENT_TYPE  //Only required for PUT requests
DDP: x-amz-copy-source  // Source that is being copied. Format /bucket/key

outputs:
DDP: Authorization
DDP: Date
 ------------------------------------------------------*/

import com.boomi.execution.ExecutionUtil
import java.net.URLEncoder
import java.nio.charset.StandardCharsets
import java.text.DateFormat
import java.text.SimpleDateFormat
import javax.crypto.Mac
import javax.crypto.spec.SecretKeySpec


logger = ExecutionUtil.getBaseLogger()
// Set global variables
String accessKey = ExecutionUtil.getDynamicProcessProperty("DPP_AWS_ACCESS_KEY");
String secretKey = ExecutionUtil.getDynamicProcessProperty("DPP_AWS_SECRET_KEY");
String securityToken = ExecutionUtil.getDynamicProcessProperty("DPP_AWS_SESSION_TOKEN");

for (int i = 0; i < dataContext.getDataCount(); i++) {
    InputStream is = dataContext.getStream(i);
    Properties props = dataContext.getProperties(i);

    String bucketName = props.getProperty("document.dynamic.userdefined.DDP_AWS_BUCKET");
    String keyName = props.getProperty("document.dynamic.userdefined.DDP_FILE_NAME");
    String method = props.getProperty("document.dynamic.userdefined.DDP_HTTP_METHOD");
    String xAmzCopySource = props.getProperty("document.dynamic.userdefined.x-amz-copy-source")
    String contentType = props.getProperty("document.dynamic.userdefined.DDP_CONTENT_TYPE");
    contentType = contentType ?: "";

    // Get Current Date
    DateFormat longDateFormat = new SimpleDateFormat("E, dd MMM yyyy HH:mm:ss Z")
    Date date = new Date()
    String longDate = longDateFormat.format(date);

    // Set String to sign
    String stringToSign = method + "\n" +
            "\n" +
            contentType + "\n" +  // contentType will be blank unless it's a PUT request
            longDate + "\n" +
            "x-amz-copy-source:" + xAmzCopySource + "\n" +
            "x-amz-security-token:" + securityToken + "\n" +
            "/" + bucketName + "/" + keyName;

    logger.info(stringToSign)
    String signature = Base64.getEncoder().encodeToString(getHMAC1(secretKey.getBytes(), stringToSign));
    String authorization = "AWS " + accessKey + ":" + signature;

    // Create Authorized URL
    props.setProperty("document.dynamic.userdefined.Authorization", authorization);
    props.setProperty("document.dynamic.userdefined.Date", longDate);
    dataContext.storeStream(is, props);
}


static byte[] getHMAC1(byte[] key, String input) {
    byte[] hash;
    Mac sha1HMAC = Mac.getInstance("HmacSHA1");
    SecretKeySpec secretKey = new SecretKeySpec(key, "HmacSHA1");
    sha1HMAC.init(secretKey);
    hash = sha1HMAC.doFinal(input.getBytes(StandardCharsets.UTF_8));
    return hash;
}

HTTP Connection Configuration

http connector aws s3 copy

Figure 3. AWS S3 HTTP Connection Configuration.

The HTTP connection will be configured to send data to S3. The HTTP connection will be different than the one used to Assume Roles.

Table 2. S3 HTTP Connection Configuration.

Name Value
URL https://s3.s3-region.amazonaws.com
Authentication Type None (Being set using the Groovy Authentication header script)

http connector overview

Figure 4. AWS Assume Role S3 HTTP Connector Creation.

The Boomi HTTP Action will be a GET because the AWS S3 CopyObject action is assuming no payload. When creating a new HTTP Operation, ensure that GET is selected.

http operation aws s3 copy

Figure 5. AWS S3 HTTP Operation Configuration.

Table 3. AWS S3 HTTP Operation Configuration.

Name Value
Content Type <content-type> (can be set dynamically)
HTTP Method PUT
Request Headers: x-amz-security-token Check Is replacement variable?
Request Headers: Authorization Check Is replacement variable?
Request Headers: Date Check Is replacement variable?
Request Headers: x-amz-copy-source Check Is replacement variable?
Resource Path: DDP_AWS_BUCKET Check Is replacement variable?
Resource Path: / /
Resource Path: DDP_FILE_NAME Check Is replacement variable?

References

The article was originally posted at Boomi Community.

Published Mar 25, 2023

Developing a better world.© All rights reserved.