Platon on Cloud

Deploying CloudFormation resource rype

AWS

Resource types are like custom resources but treated as first-class citizens within CloudFormation; you can use CloudFormation capabilities to create, provision, and manage these custom resources in a safe and repeatable manner, just as you would any AWS resource.

AWS offers CloudFormation CLI to develop, test, and deploy resource types.

During first time deployment, the CLI will create CloudFormationManagedUploadInfrastructure stack with necessary resources: S3 artifact bucket, KMS key, and logging & metrics role. The template is part of the CLI code. And this poses a problem: we need all buckets to have versioning and all roles to have PermissionBoundary and Path. I found one GitHub issue that mentions the same thing — https://github.com/aws-cloudformation/cloudformation-cli/issues/466, but there is no solution at the time of writing.

Luckily for us, we can replicate cfn submit functionality using aws cli.

The first step is to use cfn submit with --dry-run option. It will package the code but won’t do anything else. The output of this command would be zip archive located in the current directory.

Next, we need to create our own template, which can be a copy of original managed-upload-infrastructure.yaml template.

Afterward, the process is as follows:

  1. Upload zip to the S3 bucket.
  2. Call aws cloudformation register-type to register the type with code located in S3.
  3. Call aws cloudformation describe-type-registration to get the latest version ARN.
  4. Call aws cloudformation set-type-default-version to make the latest version default.

The code bellow assumed the following env vars:

  • S3_TYPE_ARTIFACT_BUCKET: artifact bucket name.
  • EXECUTION_ROLE_ARN: role ARN to allow AWS API calls; can be empty if your resource does not interact with AWS Services. This role is created by the CLI after inspecting permissions in definitions file, the template is located in resource-role.yaml file.
  • LOG_ROLE_ARN: role ARN to allow CloudWatch logging.
#for versioning purposes
resource_type_prefix=$(date '+%Y%m%d%H%M')

aws s3 cp myORG-myService-myResource.zip s3://$S3_TYPE_ARTIFACT_BUCKET/myORG-myService-myResource-$resource_type_prefix.zip

registration_token=$(aws cloudformation register-type \
    --type-name myORG::myService::myResource \
    --schema-handler-package s3://$S3_TYPE_ARTIFACT_BUCKET/myORG-myService-myResource-$resource_type_prefix.zip \
    --type RESOURCE \
    --execution-role-arn $EXECUTION_ROLE_ARN \
    --logging-config LogRoleArn=$LOG_ROLE_ARN,LogGroupName=myORG-myService-myResource \
    --output text \
    --query 'RegistrationToken')

#wait register-type to complete
sleep 60

#grab the latest version arn
type_version_arn=$(aws cloudformation describe-type-registration \
    --registration-token $registration_token \
    --output text \
    --query 'TypeVersionArn')

aws cloudformation set-type-default-version \
    --type RESOURCE \
    --type-name myORG::myService::myResource \
    --version-id "${type_version_arn: -8}"
comments powered by Disqus