<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Luthfi Anandra</title>
    <description>The latest articles on DEV Community by Luthfi Anandra (@lanandra).</description>
    <link>https://dev.to/lanandra</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F537224%2Fafb69bdb-bc5f-47aa-b2a9-689815db29a1.png</url>
      <title>DEV Community: Luthfi Anandra</title>
      <link>https://dev.to/lanandra</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/lanandra"/>
    <language>en</language>
    <item>
      <title>Gatekeep CodeCatalyst Workflow using Approval</title>
      <dc:creator>Luthfi Anandra</dc:creator>
      <pubDate>Wed, 15 May 2024 17:26:13 +0000</pubDate>
      <link>https://dev.to/aws-builders/gatekeep-codecatalyst-workflow-using-approval-1945</link>
      <guid>https://dev.to/aws-builders/gatekeep-codecatalyst-workflow-using-approval-1945</guid>
      <description>&lt;p&gt;In some use cases, our CI/CD pipeline or workflow may need to be validated before code can be deployed.&lt;/p&gt;

&lt;p&gt;Refer to this announcement "&lt;a href="https://aws.amazon.com/about-aws/whats-new/2024/04/workflow-approvals-amazon-codecatalyst/" rel="noopener noreferrer"&gt;Workflow approvals for Amazon CodeCatalyst&lt;/a&gt;", Amazon CodeCatalyst, now has released feature called approval gates which can be utilized so that workflow can be paused until user with privilege can validate the workflow and whether workflow is approved and can be processed or not.&lt;/p&gt;

&lt;p&gt;More details regarding Approval in CodeCatalyst can be read on this documentation: &lt;a href="https://docs.aws.amazon.com/codecatalyst/latest/userguide/workflows-approval.html" rel="noopener noreferrer"&gt;Approval Gate&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Table of Contents
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Scenario&lt;/li&gt;
&lt;li&gt;Prerequisites&lt;/li&gt;
&lt;li&gt;
Configuration Steps

&lt;ul&gt;
&lt;li&gt;Directory Structure&lt;/li&gt;
&lt;li&gt;CodeCatalyst Workflow File Configurations&lt;/li&gt;
&lt;li&gt;Example of Approval Process in CodeCatalyst Workflow&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Summary&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Scenario
&lt;/h2&gt;

&lt;p&gt;This blog is related with my previous blog "&lt;a href="https://dev.to/aws-builders/cicd-pipeline-for-terraform-workflow-using-amazon-codecatalyst-3a4c"&gt;CI/CD Pipeline for Terraform Workflow Using Amazon CodeCatalyst&lt;/a&gt;". In my previous blog, in workflow/pipeline, when terraform plan has finished and will continue to terraform apply, there is a process in between where pipeline will wait for 1 minute to check the terraform plan output and if the plan is not expected, we need to cancel the workflow manually. The difficulty that faced back then is because there was no out of the box solution provided by CodeCatalyst to restrict whether shifting between one action to other action can be cancelled if there is unexpected result.&lt;/p&gt;

&lt;p&gt;In this blog, i will make an update which between terraform plan and terraform apply action, there will be an approval action. The goal if the plan is not expected, we can cancel the workflow and terraform apply will not be processed.&lt;/p&gt;

&lt;p&gt;Here is the diagram that used in this blog:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fludesdeveloper.files.wordpress.com%2F2024%2F05%2Fdiagram.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fludesdeveloper.files.wordpress.com%2F2024%2F05%2Fdiagram.png" alt="diagram"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;Here is the prerequisite that needed to follow configurations discussed in this blog:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;CodeCatalyst space and project that has been connected with AWS account and source repository. In this blog, I use GitHub as source repository. For configuration reference, please check my other blog “&lt;a href="https://aws.plainenglish.io/build-and-release-container-image-to-amazon-elastic-container-registry-ecr-via-amazon-ae7f9f07a135" rel="noopener noreferrer"&gt;Build and Release Container Image to Amazon Elastic Container Registry (ECR) via Amazon CodeCatalyst&lt;/a&gt;”&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Configuration Steps
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Directory Structure
&lt;/h3&gt;

&lt;p&gt;Below is directory structure used in this blog:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.
├── .codecatalyst/
│   └── workflows/
│       └── tf-sandbox-sbx0-vpc.yml
└── sandbox/
    └── sbx0/
        └── vpc/
            ├── backend.tf  
            ├── main.tf
            ├── terraform.tfvars
            └── variables.tf
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  CodeCatalyst Workflow File Configurations
&lt;/h3&gt;

&lt;p&gt;Here is the configuration of CodeCatalyst workflow file that written in file &lt;strong&gt;./codecatalyst/workflows/tf-sandbox-sbx0-vpc.yml&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;Name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;tf-sandbox-sbx0-vpc&lt;/span&gt;
&lt;span class="na"&gt;SchemaVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;1.0"&lt;/span&gt;

&lt;span class="na"&gt;Triggers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;PUSH&lt;/span&gt;
    &lt;span class="na"&gt;Branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;master&lt;/span&gt;
    &lt;span class="na"&gt;FilesChanged&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;sandbox\/sbx0\/vpc\/.*&lt;/span&gt;

&lt;span class="na"&gt;Actions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;terraform-plan&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;Identifier&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;aws/build@v1&lt;/span&gt;
    &lt;span class="na"&gt;Inputs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;Sources&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;WorkflowSource&lt;/span&gt;
    &lt;span class="na"&gt;Environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;Name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;sandbox&lt;/span&gt;
      &lt;span class="na"&gt;Connections&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;Name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;lanandra-sandbox&lt;/span&gt;
          &lt;span class="na"&gt;Role&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;codecatalyst-admin&lt;/span&gt;
    &lt;span class="na"&gt;Configuration&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;Container&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;Registry&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;DockerHub&lt;/span&gt;
        &lt;span class="na"&gt;Image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;hashicorp/terraform:1.8.2&lt;/span&gt;
      &lt;span class="na"&gt;Steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;Run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;cd sandbox/sbx0/vpc&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;Run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;terraform fmt -check -no-color&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;Run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;terraform init -no-color&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;Run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;terraform validate -no-color&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;Run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;terraform plan -no-color -input=false&lt;/span&gt;
    &lt;span class="na"&gt;Compute&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;EC2&lt;/span&gt;
  &lt;span class="na"&gt;wait-for-approval&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;Identifier&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;aws/approval@v1&lt;/span&gt;
    &lt;span class="na"&gt;DependsOn&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;terraform-plan&lt;/span&gt;
    &lt;span class="na"&gt;Configuration&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;ApprovalsRequired&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
  &lt;span class="na"&gt;terraform-apply&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;DependsOn&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;wait-for-approval&lt;/span&gt;
    &lt;span class="na"&gt;Identifier&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;aws/build@v1&lt;/span&gt;
    &lt;span class="na"&gt;Inputs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;Sources&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;WorkflowSource&lt;/span&gt;
    &lt;span class="na"&gt;Environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;Name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;sandbox&lt;/span&gt;
      &lt;span class="na"&gt;Connections&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;Name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;lanandra-sandbox&lt;/span&gt;
          &lt;span class="na"&gt;Role&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;codecatalyst-admin&lt;/span&gt;
    &lt;span class="na"&gt;Configuration&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;Container&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;Registry&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;DockerHub&lt;/span&gt;
        &lt;span class="na"&gt;Image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;hashicorp/terraform:1.8.2&lt;/span&gt;
      &lt;span class="na"&gt;Steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;Run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;cd sandbox/sbx0/vpc&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;Run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;terraform init -no-color&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;Run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;terraform apply -auto-approve -no-color -input=false&lt;/span&gt;
    &lt;span class="na"&gt;Compute&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;EC2&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, I will explain more detail each sections that defined on workflow file above:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Define workflow name. Then define how workflow will be ran. Workflow will be ran automatically if there is a push to repository, specifically to directory &lt;strong&gt;sandbox/sbx0/vpc&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;Name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;tf-sandbox-sbx0-vpc&lt;/span&gt;
&lt;span class="na"&gt;SchemaVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;1.0"&lt;/span&gt;

&lt;span class="na"&gt;Triggers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;PUSH&lt;/span&gt;
    &lt;span class="na"&gt;Branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;master&lt;/span&gt;
    &lt;span class="na"&gt;FilesChanged&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;sandbox\/sbx0\/vpc\/.*&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Define action. First action will run workflow &lt;code&gt;terraform plan&lt;/code&gt;. In this section, action uses identifier &lt;code&gt;aws/build@v1&lt;/code&gt;. Then action will be ran on sandbox environment that has been connected with AWS account and also has IAM role associated with that account. In &lt;code&gt;Configuration&lt;/code&gt; section, has been defined that action will be ran on top of container using specific version of terraform public image that pulled from DockerHub. Also has defined working directory and several terraform commands which include &lt;code&gt;terraform plan&lt;/code&gt;. Lastly, define compute type which is &lt;code&gt;EC2&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;Actions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;terraform-plan&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;Identifier&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;aws/build@v1&lt;/span&gt;
    &lt;span class="na"&gt;Inputs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;Sources&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;WorkflowSource&lt;/span&gt;
    &lt;span class="na"&gt;Environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;Name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;sandbox&lt;/span&gt;
      &lt;span class="na"&gt;Connections&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;Name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;lanandra-sandbox&lt;/span&gt;
          &lt;span class="na"&gt;Role&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;codecatalyst-admin&lt;/span&gt;
    &lt;span class="na"&gt;Configuration&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;Container&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;Registry&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;DockerHub&lt;/span&gt;
        &lt;span class="na"&gt;Image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;hashicorp/terraform:1.8.2&lt;/span&gt;
      &lt;span class="na"&gt;Steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;Run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;cd sandbox/sbx0/vpc&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;Run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;terraform fmt -check -no-color&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;Run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;terraform init -no-color&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;Run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;terraform validate -no-color&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;Run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;terraform plan -no-color -input=false&lt;/span&gt;
    &lt;span class="na"&gt;Compute&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;EC2&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Next action is &lt;code&gt;wait-for-approval&lt;/code&gt;. Goal of this action is to verify workflow can be ran to next action if there is an approval from privileged user(s). This action is using identifier &lt;code&gt;aws/approval@v1&lt;/code&gt; and depends on previous action which is &lt;code&gt;terraform-plan&lt;/code&gt;. This action need at least 1 privileged user approval so that next action can be ran.&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;wait-for-approval&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;Identifier&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;aws/approval@v1&lt;/span&gt;
    &lt;span class="na"&gt;DependsOn&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;terraform-plan&lt;/span&gt;
    &lt;span class="na"&gt;Configuration&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;ApprovalsRequired&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Next action that defined is action to run &lt;code&gt;terraform apply&lt;/code&gt;. This action more or less similar with action &lt;code&gt;terraform-plan&lt;/code&gt;, the difference is just terraform command that declared on configuration. In this section, action will run commands that needed for &lt;code&gt;terraform apply&lt;/code&gt;. This action is depends on previous action which is &lt;code&gt;wait-for-approval&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;terraform-apply&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;DependsOn&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;wait-for-approval&lt;/span&gt;
    &lt;span class="na"&gt;Identifier&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;aws/build@v1&lt;/span&gt;
    &lt;span class="na"&gt;Inputs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;Sources&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;WorkflowSource&lt;/span&gt;
    &lt;span class="na"&gt;Environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;Name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;sandbox&lt;/span&gt;
      &lt;span class="na"&gt;Connections&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;Name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;lanandra-sandbox&lt;/span&gt;
          &lt;span class="na"&gt;Role&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;codecatalyst-admin&lt;/span&gt;
    &lt;span class="na"&gt;Configuration&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;Container&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;Registry&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;DockerHub&lt;/span&gt;
        &lt;span class="na"&gt;Image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;hashicorp/terraform:1.8.2&lt;/span&gt;
      &lt;span class="na"&gt;Steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;Run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;cd sandbox/sbx0/vpc&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;Run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;terraform init -no-color&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;Run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;terraform apply -auto-approve -no-color -input=false&lt;/span&gt;
    &lt;span class="na"&gt;Compute&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;EC2&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Example of Approval Process in CodeCatalyst Workflow
&lt;/h3&gt;

&lt;p&gt;I have defined Terraform codes that will be used as example in this blog. Files can be found in this GitHub path: &lt;a href="https://github.com/lanandra/mock-aws-infrastructure/tree/master/sandbox/sbx0/vpc" rel="noopener noreferrer"&gt;https://github.com/lanandra/mock-aws-infrastructure/tree/master/sandbox/sbx0/vpc&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Existing &lt;strong&gt;main.tf&lt;/strong&gt; configuration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="err"&gt;#######&lt;/span&gt;
&lt;span class="err"&gt;#&lt;/span&gt; &lt;span class="n"&gt;VPC&lt;/span&gt; &lt;span class="err"&gt;#&lt;/span&gt;
&lt;span class="err"&gt;#######&lt;/span&gt;


&lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="s"&gt;"aws_availability_zones"&lt;/span&gt; &lt;span class="s"&gt;"available"&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;

&lt;span class="n"&gt;locals&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;azs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;aws_availability_zones&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;available&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;names&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="n"&gt;tags&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="s"&gt;"environment"&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"${var.env_name}"&lt;/span&gt;
    &lt;span class="s"&gt;"managedBy"&lt;/span&gt;   &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"terraform"&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;module&lt;/span&gt; &lt;span class="s"&gt;"sbx0_apse1"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;source&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"terraform-aws-modules/vpc/aws"&lt;/span&gt;
  &lt;span class="n"&gt;version&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"5.8.1"&lt;/span&gt;

  &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;var&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;env_name&lt;/span&gt;
  &lt;span class="n"&gt;cidr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;var&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;vpc_cidr&lt;/span&gt;

  &lt;span class="n"&gt;azs&lt;/span&gt;             &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;local&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;azs&lt;/span&gt;
  &lt;span class="n"&gt;private_subnets&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt; &lt;span class="n"&gt;local&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;azs&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;cidrsubnet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;var&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;vpc_cidr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
  &lt;span class="n"&gt;public_subnets&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt; &lt;span class="n"&gt;local&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;azs&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;cidrsubnet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;var&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;vpc_cidr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;

  &lt;span class="n"&gt;enable_nat_gateway&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;false&lt;/span&gt;
  &lt;span class="n"&gt;single_nat_gateway&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;

  &lt;span class="n"&gt;tags&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;local&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tags&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here are the configuration steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Change Terraform configuration. Enable NAT gateway in VPC&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;enable_nat_gateway&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;As defined in workflow file, all changes inside directory &lt;strong&gt;sandbox/sbx0/vpc&lt;/strong&gt; will trigger workflow run. Go to CodeCatalyst web console to verify. Go to space and project where workflow ran. Go to CI/CD menu, then choose Workflows. Verify there is new runs. Go to that runs&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fludesdeveloper.files.wordpress.com%2F2024%2F05%2F1.-find-workflows-and-run.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fludesdeveloper.files.wordpress.com%2F2024%2F05%2F1.-find-workflows-and-run.png" alt="find-workflows-and-run"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Go to run details by clicking name or run. Next, we will be redirected to overview page of that run. Click action &lt;code&gt;terraform-plan&lt;/code&gt;, on the right side will appear tray box that display all steps that configured on that action. If we want to see details of &lt;code&gt;terraform plan&lt;/code&gt;, go to tab &lt;code&gt;log&lt;/code&gt;, then click step &lt;code&gt;terraform plan -no-color -input-false&lt;/code&gt;. Verify action is succeeded&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fludesdeveloper.files.wordpress.com%2F2024%2F05%2F2.-verify-terraform-plan.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fludesdeveloper.files.wordpress.com%2F2024%2F05%2F2.-verify-terraform-plan.png" alt="verify-terraform-plan"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Next, action &lt;code&gt;wait-for-approval&lt;/code&gt; will be ran and waiting input from privileged user, whether workflow run can be approved or not&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fludesdeveloper.files.wordpress.com%2F2024%2F05%2F3.-wait-for-approval.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fludesdeveloper.files.wordpress.com%2F2024%2F05%2F3.-wait-for-approval.png" alt="wait-for-approval"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Choose approve then click submit&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fludesdeveloper.files.wordpress.com%2F2024%2F05%2F4.-approve-wait-approval.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fludesdeveloper.files.wordpress.com%2F2024%2F05%2F4.-approve-wait-approval.png" alt="approve-wait-approval"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;If pop-up approval appeared, click &lt;code&gt;Confirm&lt;/code&gt; to continue workflow&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fludesdeveloper.files.wordpress.com%2F2024%2F05%2F5.-confirm-approval.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fludesdeveloper.files.wordpress.com%2F2024%2F05%2F5.-confirm-approval.png" alt="confirm-approval"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;We also can see the status of approval, whether it has been approved or rejected&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fludesdeveloper.files.wordpress.com%2F2024%2F05%2F6.-approval-summary.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fludesdeveloper.files.wordpress.com%2F2024%2F05%2F6.-approval-summary.png" alt="approval-summary"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;After approval has been approved, next action will be ran where in this blog example is terraform apply. Verify terraform apply is succeeded&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fludesdeveloper.files.wordpress.com%2F2024%2F05%2F7.-terraform-apply-succeeded.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fludesdeveloper.files.wordpress.com%2F2024%2F05%2F7.-terraform-apply-succeeded.png" alt="terraform-apply-succeeded"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;We have reached the last section of this blog. Here are some key takeaways that can be summarized:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;In some use cases, maybe we will find condition where we will need approval before deployment in CI/CD pipeline can be done&lt;/li&gt;
&lt;li&gt;CodeCatalyst have approval feature that can gatekeep deployment in CI/CD&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Please comment if you have any suggestions, critiques, or thoughts.&lt;/p&gt;

&lt;p&gt;Hope this article will benefit you. Thank you!&lt;/p&gt;

</description>
      <category>aws</category>
      <category>codecatalyst</category>
      <category>cicd</category>
      <category>terraform</category>
    </item>
    <item>
      <title>Schedule Access Key Rotation Using CodeCatalyst</title>
      <dc:creator>Luthfi Anandra</dc:creator>
      <pubDate>Sun, 03 Mar 2024 08:16:49 +0000</pubDate>
      <link>https://dev.to/aws-builders/schedule-access-key-rotation-using-codecatalyst-4if6</link>
      <guid>https://dev.to/aws-builders/schedule-access-key-rotation-using-codecatalyst-4if6</guid>
      <description>&lt;p&gt;To interact with services/resources in Amazon Web Services (AWS), commonly We need security credentials. Security credentials are needed for authentication and authorization. There are two types of security credentials, long term and temporary. Both have its own use cases, but temporary credentials is more recommended.&lt;/p&gt;

&lt;p&gt;Despite using temporary security credentials is more recommended, maybe in some use cases We still need or have to use long term credentials such as IAM user access key and secret key. To prevent security hole, We can and encouraged to rotate access key and secret key periodically.&lt;/p&gt;

&lt;p&gt;More details about AWS security credentials: &lt;a href="https://docs.aws.amazon.com/IAM/latest/UserGuide/security-creds.html"&gt;[+]&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Table of Contents
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Scenario&lt;/li&gt;
&lt;li&gt;Prerequisites&lt;/li&gt;
&lt;li&gt;
Configuration Steps

&lt;ul&gt;
&lt;li&gt;Directory Structure&lt;/li&gt;
&lt;li&gt;Access Key Rotation Script Configurations&lt;/li&gt;
&lt;li&gt;CodeCatalyst Workflow File Configurations&lt;/li&gt;
&lt;li&gt;Example of Automate Access Key Rotation in CI/CD CodeCatalyst&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Summary&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Scenario
&lt;/h2&gt;

&lt;p&gt;In this blog, I will create CI/CD pipeline in Amazon CodeCatalyst or in CodeCatalyst also called as workflow, where this workflow will run scheduled automated IAM user access key rotation. First, CodeCatalyst will delete old access key, then it will create new access key. In the process, CodeCatalyst workflow will run shell scripts that has been configured to run aws cli commands that needed for each steps.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;Here are some prerequisites that needed to follow configurations discussed in this blog:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;CodeCatalyst space and project that has been connected with AWS account and source repository. In this blog, I use GitHub as source repository. For configuration reference, please check my other blog “&lt;a href="https://aws.plainenglish.io/build-and-release-container-image-to-amazon-elastic-container-registry-ecr-via-amazon-ae7f9f07a135"&gt;Build and Release Container Image to Amazon Elastic Container Registry (ECR) via Amazon CodeCatalyst&lt;/a&gt;”&lt;/li&gt;
&lt;li&gt;IAM user&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Configuration Steps
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Directory Structure
&lt;/h3&gt;

&lt;p&gt;Below is directory structure used in this blog:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.
├── .codecatalyst/
│   └── workflows/
│       └── rotate-access-key.yml
└── sandbox2/
    └── iam/
        ├── create-access-key.sh
        └── delete-access-key.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Access Key Rotation Script Configurations
&lt;/h3&gt;

&lt;p&gt;Configuration started with create shell scripts that will be used for automate access key rotation.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Create shell script &lt;strong&gt;delete-access-key.sh&lt;/strong&gt; that will be used to check whether IAM user has access key and if user has, script will delete that access key. In this script, We need to export environment variable value &lt;code&gt;IAM_USER&lt;/code&gt; that used to define which IAM user will be checked&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/usr/bin/env bash&lt;/span&gt;

&lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="nt"&gt;-euo&lt;/span&gt; pipefail

&lt;span class="nv"&gt;IAM_USER&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$IAM_USER&lt;/span&gt;

&lt;span class="nv"&gt;ACCESS_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;aws iam list-access-keys &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--user-name&lt;/span&gt; &lt;span class="nv"&gt;$IAM_USER&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--query&lt;/span&gt; &lt;span class="s1"&gt;'AccessKeyMetadata[].AccessKeyId'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--output&lt;/span&gt; text &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--no-cli-pager&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="nt"&gt;-z&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$ACCESS_KEY&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
  &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"No access key found on user &lt;/span&gt;&lt;span class="nv"&gt;$IAM_USER&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="k"&gt;else  
  &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Found access key &lt;/span&gt;&lt;span class="nv"&gt;$ACCESS_KEY&lt;/span&gt;&lt;span class="s2"&gt; on user &lt;/span&gt;&lt;span class="nv"&gt;$IAM_USER&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

  &lt;span class="nv"&gt;DELETE_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;aws iam delete-access-key &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--user-name&lt;/span&gt; &lt;span class="nv"&gt;$IAM_USER&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--access-key-id&lt;/span&gt; &lt;span class="nv"&gt;$ACCESS_KEY&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;

  &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Access key &lt;/span&gt;&lt;span class="nv"&gt;$ACCESS_KEY&lt;/span&gt;&lt;span class="s2"&gt; deleted"&lt;/span&gt;
&lt;span class="k"&gt;fi&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Create shell script &lt;strong&gt;create-access-key.sh&lt;/strong&gt; that will be used to create/generate new access key. Similar with &lt;strong&gt;delete-access-key.sh&lt;/strong&gt;, We need to export enviroment variable value &lt;code&gt;IAM_USER&lt;/code&gt;. Output of access key creation will be saved into file called &lt;strong&gt;access-key.csv&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/usr/bin/env bash&lt;/span&gt;

&lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="nt"&gt;-euo&lt;/span&gt; pipefail

&lt;span class="nv"&gt;IAM_USER&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$IAM_USER&lt;/span&gt;

&lt;span class="nv"&gt;CREATE_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;aws iam create-access-key &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--user-name&lt;/span&gt; &lt;span class="nv"&gt;$IAM_USER&lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--output&lt;/span&gt; text&lt;span class="si"&gt;)&lt;/span&gt;

&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Creating access key for user &lt;/span&gt;&lt;span class="nv"&gt;$IAM_USER&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$CREATE_KEY&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; ./access-key.csv
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Access key created. Please find the key values on access-key.csv"&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  CodeCatalyst Workflow File Configurations
&lt;/h3&gt;

&lt;p&gt;After created shell script for automate access key rotation, then We need to define workflow file that will be used to schedule automation of access key rotation.&lt;/p&gt;

&lt;p&gt;I configured that workflow in file &lt;strong&gt;.codecatalyst/workflows/rotate-access-key.yml&lt;/strong&gt;. Here is the full content of workflow file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;Name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;rotate-access-key&lt;/span&gt;
&lt;span class="na"&gt;SchemaVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;1.0"&lt;/span&gt;

&lt;span class="na"&gt;Triggers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;SCHEDULE&lt;/span&gt;
    &lt;span class="na"&gt;Expression&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;30&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;12&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;?&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;*&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;THU&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;*"&lt;/span&gt;
    &lt;span class="na"&gt;Branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;master&lt;/span&gt;

&lt;span class="na"&gt;Actions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;delete-access-key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;Identifier&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;aws/build@v1&lt;/span&gt;
    &lt;span class="na"&gt;Inputs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;Sources&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;WorkflowSource&lt;/span&gt;
      &lt;span class="na"&gt;Variables&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;Name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;IAM_USER&lt;/span&gt;
          &lt;span class="na"&gt;Value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;tf-admin"&lt;/span&gt;
    &lt;span class="na"&gt;Environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;Name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;sandbox&lt;/span&gt;
      &lt;span class="na"&gt;Connections&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;Name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;lanandra-sandbox&lt;/span&gt;
          &lt;span class="na"&gt;Role&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;codecatalyst-admin&lt;/span&gt;
    &lt;span class="na"&gt;Configuration&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;Steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;Run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;cd sandbox2/iam&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;Run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;./delete-access-key.sh&lt;/span&gt;
    &lt;span class="na"&gt;Compute&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;EC2&lt;/span&gt;
  &lt;span class="na"&gt;create-access-key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;DependsOn&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;delete-access-key&lt;/span&gt;
    &lt;span class="na"&gt;Identifier&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;aws/build@v1&lt;/span&gt;
    &lt;span class="na"&gt;Inputs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;Sources&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;WorkflowSource&lt;/span&gt;
      &lt;span class="na"&gt;Variables&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;Name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;IAM_USER&lt;/span&gt;
          &lt;span class="na"&gt;Value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;tf-admin"&lt;/span&gt;
    &lt;span class="na"&gt;Outputs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;Artifacts&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;Name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ACCESSKEY&lt;/span&gt;
          &lt;span class="na"&gt;Files&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;sandbox2/iam/access-key.csv&lt;/span&gt;
    &lt;span class="na"&gt;Environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;Name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;sandbox&lt;/span&gt;
      &lt;span class="na"&gt;Connections&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;Name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;lanandra-sandbox&lt;/span&gt;
          &lt;span class="na"&gt;Role&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;codecatalyst-admin&lt;/span&gt;
    &lt;span class="na"&gt;Configuration&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;Steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;Run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;cd sandbox2/iam&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;Run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;./create-access-key.sh&lt;/span&gt;
    &lt;span class="na"&gt;Compute&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;EC2&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next I will explain more details each section inside workflow file.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Define workflow name. Then define how workflow run. In this blog, as an example, workflow will be ran as scheduled on Thursday at 12:30 UTC and only will be ran on &lt;code&gt;master&lt;/code&gt; branch. Please adjust schedule following cron expression guide that used by CodeCatalyst. CodeCatalyst use six-field syntax and separated with space, more details please check this documentation: &lt;a href="https://docs.aws.amazon.com/codecatalyst/latest/userguide/workflow.top.level.html#workflow.triggers.expression"&gt;CodeCatalyst workflow triggers expression&lt;/a&gt; &amp;amp; &lt;a href="https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-cron-expressions.html"&gt;EventBridge cron expressions reference&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;Name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;rotate-access-key&lt;/span&gt;
&lt;span class="na"&gt;SchemaVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;1.0"&lt;/span&gt;

&lt;span class="na"&gt;Triggers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;SCHEDULE&lt;/span&gt;
    &lt;span class="na"&gt;Expression&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;30&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;12&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;?&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;*&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;THU&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;*"&lt;/span&gt;
    &lt;span class="na"&gt;Branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;master&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Define actions. Action will be divided into 2 sections. First section will run shell script &lt;strong&gt;delete-access-key.sh&lt;/strong&gt; in &lt;code&gt;action delete-access-key&lt;/code&gt;. As mentioned above, we need to export environment variable value &lt;code&gt;IAM_USER&lt;/code&gt;. In this blog, I will use example user called &lt;code&gt;tf-admin&lt;/code&gt;. Action will be ran in sandbox environment that has been connected with AWS account and also has IAM role associated with that account. In configuration section, I defined steps how to run shell script &lt;strong&gt;delete-access-key.sh&lt;/strong&gt; from directory where the file located&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;Actions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;delete-access-key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;Identifier&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;aws/build@v1&lt;/span&gt;
    &lt;span class="na"&gt;Inputs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;Sources&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;WorkflowSource&lt;/span&gt;
      &lt;span class="na"&gt;Variables&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;Name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;IAM_USER&lt;/span&gt;
          &lt;span class="na"&gt;Value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;tf-admin"&lt;/span&gt;
    &lt;span class="na"&gt;Environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;Name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;sandbox&lt;/span&gt;
      &lt;span class="na"&gt;Connections&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;Name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;lanandra-sandbox&lt;/span&gt;
          &lt;span class="na"&gt;Role&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;codecatalyst-admin&lt;/span&gt;
    &lt;span class="na"&gt;Configuration&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;Steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;Run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;cd sandbox2/iam&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;Run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;./delete-access-key.sh&lt;/span&gt;
    &lt;span class="na"&gt;Compute&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;EC2&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Next section will run shell script &lt;strong&gt;create-access-key.sh&lt;/strong&gt; in action &lt;code&gt;create-access-key&lt;/code&gt;. This action will depends on previous action which is &lt;code&gt;delete-access-key&lt;/code&gt; and this action will not run if previous action is failed. More or less this action will be the same with action &lt;code&gt;delete-access-key&lt;/code&gt;. We need to export environment variable value &lt;code&gt;IAM_USER&lt;/code&gt;. Similar with previous action, i will input example user called &lt;code&gt;tf-admin&lt;/code&gt;. Action will be ran in sandbox environment that has been connected with AWS account and also has IAM role associated with that account. In configuration section, there will be different steps, I defined steps to run shell script &lt;strong&gt;create-access-key.sh&lt;/strong&gt; from directory where the file located. Beside that, this action will generate output artifact called &lt;code&gt;ACCESSKEY&lt;/code&gt;, this artifact consist of file &lt;code&gt;access-key.csv&lt;/code&gt; where information releted access key and secret key stored&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;create-access-key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;DependsOn&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;delete-access-key&lt;/span&gt;
    &lt;span class="na"&gt;Identifier&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;aws/build@v1&lt;/span&gt;
    &lt;span class="na"&gt;Inputs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;Sources&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;WorkflowSource&lt;/span&gt;
      &lt;span class="na"&gt;Variables&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;Name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;IAM_USER&lt;/span&gt;
          &lt;span class="na"&gt;Value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;tf-admin"&lt;/span&gt;
    &lt;span class="na"&gt;Outputs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;Artifacts&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;Name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ACCESSKEY&lt;/span&gt;
          &lt;span class="na"&gt;Files&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;sandbox2/iam/access-key.csv&lt;/span&gt;
    &lt;span class="na"&gt;Environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;Name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;sandbox&lt;/span&gt;
      &lt;span class="na"&gt;Connections&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;Name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;lanandra-sandbox&lt;/span&gt;
          &lt;span class="na"&gt;Role&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;codecatalyst-admin&lt;/span&gt;
    &lt;span class="na"&gt;Configuration&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;Steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;Run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;cd sandbox2/iam&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;Run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;./create-access-key.sh&lt;/span&gt;
    &lt;span class="na"&gt;Compute&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;EC2&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Example of Automate Access Key Rotation in CI/CD CodeCatalyst
&lt;/h3&gt;

&lt;p&gt;After configure CodeCatalyst workflow file, next we verify scheduled automation access key rotation is working as expected.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Go to CodeCatalyst web console, choose space and project where workflow resided. Go to menu CI/CD — Workflows. Find workflow name. In section Recent runs, verify there is a successful scheduled run&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--jlClGOZX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://ludesdeveloper.files.wordpress.com/2024/02/1.-rotate-access-key-workflow.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--jlClGOZX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://ludesdeveloper.files.wordpress.com/2024/02/1.-rotate-access-key-workflow.png" alt="rotate-access-key-workflow" width="800" height="373"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Click action &lt;code&gt;delete-access-key&lt;/code&gt;. In the right will appear window to check &lt;code&gt;Logs&lt;/code&gt; related to that action. Verify shell script &lt;strong&gt;delete-access-key.sh&lt;/strong&gt; is run and successfully found existing access key in user and delete that key&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--mDWBOKgR--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://ludesdeveloper.files.wordpress.com/2024/02/2.-delete-access-key-action.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--mDWBOKgR--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://ludesdeveloper.files.wordpress.com/2024/02/2.-delete-access-key-action.png" alt="delete-access-key-action" width="800" height="386"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Click action &lt;code&gt;create-access-key&lt;/code&gt;. In the right will appear window to check &lt;code&gt;Logs&lt;/code&gt; related to that action. Verify shell script &lt;strong&gt;create-access-key.sh&lt;/strong&gt; is run and successfully create access key&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--qlbSSxcu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://ludesdeveloper.files.wordpress.com/2024/02/3.-create-access-key-action.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--qlbSSxcu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://ludesdeveloper.files.wordpress.com/2024/02/3.-create-access-key-action.png" alt="create-access-key-action" width="800" height="386"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Go to &lt;code&gt;Artifacts&lt;/code&gt; menu in related run. Verify artifact is successfully created and verify file can be downloaded&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--TPj3flNo--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://ludesdeveloper.files.wordpress.com/2024/02/4.-rotate-access-key-artifact.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--TPj3flNo--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://ludesdeveloper.files.wordpress.com/2024/02/4.-rotate-access-key-artifact.png" alt="rotate-access-key-artifact" width="800" height="221"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Open csv file inside the artifact, verify information related access and secret key. Verify user is match with what defined in workflow environment variable&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--bbvta_iG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://ludesdeveloper.files.wordpress.com/2024/02/5.-verify-access-key-in-csv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--bbvta_iG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://ludesdeveloper.files.wordpress.com/2024/02/5.-verify-access-key-in-csv.png" alt="verify-access-key-in-csv" width="800" height="96"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;For validation, go to AWS web console. Go to IAM user menu and find related user. Verify access-key is match with what defined inside csv file&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--KN35tMeP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://ludesdeveloper.files.wordpress.com/2024/02/6.-verify-access-key-in-web.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--KN35tMeP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://ludesdeveloper.files.wordpress.com/2024/02/6.-verify-access-key-in-web.png" alt="verify-access-key-in-web" width="800" height="225"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;We have reached the last section of this blog. Here are some key takeaways that can be summarized:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;There are two types of security credentials in AWS, long term and temporary&lt;/li&gt;
&lt;li&gt;Temporary credentials is more recommended. But in some cases or environments, we may need or have to use long term credentials such as access key&lt;/li&gt;
&lt;li&gt;To prevent security hole, please ensure to rotate access key periodically&lt;/li&gt;
&lt;li&gt;CodeCatalyst can be used as tool to schedule automation of access key rotation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Please check out my GitHub repository to see source code example that used in this blog:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Shell scripts used for access key rotation: &lt;a href="https://github.com/lanandra/mock-aws-infrastructure/tree/master/sandbox2/iam"&gt;rotation scripts&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Amazon CodeCatalyst workflow file: &lt;a href="https://github.com/lanandra/mock-aws-infrastructure/tree/master/.codecatalyst/workflows"&gt;codecatalyst workflow&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Please comment if you have any suggestions, critiques, or thoughts.&lt;/p&gt;

&lt;p&gt;Hope this article will benefit you. Thank you!&lt;/p&gt;

</description>
      <category>aws</category>
      <category>cicd</category>
      <category>codecatalyst</category>
      <category>iam</category>
    </item>
    <item>
      <title>CI/CD Pipeline for Terraform Workflow Using Amazon CodeCatalyst</title>
      <dc:creator>Luthfi Anandra</dc:creator>
      <pubDate>Wed, 22 Nov 2023 04:25:20 +0000</pubDate>
      <link>https://dev.to/aws-builders/cicd-pipeline-for-terraform-workflow-using-amazon-codecatalyst-3a4c</link>
      <guid>https://dev.to/aws-builders/cicd-pipeline-for-terraform-workflow-using-amazon-codecatalyst-3a4c</guid>
      <description>&lt;p&gt;&lt;a href="https://developer.hashicorp.com/terraform/intro/core-workflow"&gt;Terraform workflow&lt;/a&gt; can be ran using several methods. One of them is running Terraform workflow inside CI/CD pipeline. Running Terraform workflow inside CI/CD pipeline can have several benefits, such as: automate creation or provision resources, simplify collaboration between engineers/developers, etc.&lt;/p&gt;

&lt;h2&gt;
  
  
  Table of Contents
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Scenario&lt;/li&gt;
&lt;li&gt;Prerequisites&lt;/li&gt;
&lt;li&gt;
Configuration Steps

&lt;ul&gt;
&lt;li&gt;Directory Structure&lt;/li&gt;
&lt;li&gt;Terraform Backend Configurations&lt;/li&gt;
&lt;li&gt;CodeCatalyst Workflow File Configurations&lt;/li&gt;
&lt;li&gt;Example of Terraform Workflow Process in CodeCatalyst CI/CD&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Summary&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Scenario
&lt;/h2&gt;

&lt;p&gt;In this blog, I will explain how to run Terraform workflow inside CI/CD pipeline which in this blog is Amazon CodeCatalyst. GitHub is used as source code repository and has been connected with CodeCatalyst. Next in CodeCatalyst pipeline/workflow, We will provision resources via Terraform. In this blog, Terraform is using S3 backend. Here is the topology used in this blog:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--iFLxX4Ga--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://ludesdeveloper.files.wordpress.com/2023/10/topology.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--iFLxX4Ga--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://ludesdeveloper.files.wordpress.com/2023/10/topology.png" alt="topology" width="721" height="241"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This blog is using reference from tutorial &lt;a href="https://community.aws/tutorials/bootstrapping-terraform-automation-amazon-codecatalyst"&gt;“Bootstrapping your Terraform automation with Amazon CodeCatalyst”&lt;/a&gt; written by &lt;a href="https://github.com/cobusbernard"&gt;@Cobus Bernard&lt;/a&gt; with some adjustment in configuration.&lt;/p&gt;

&lt;p&gt;If You want to know more details about CodeCatalyst, please check &lt;a href="https://docs.aws.amazon.com/codecatalyst/latest/userguide/welcome.html"&gt;CodeCatalyst documentation&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Before starting configuration, if you have not got &lt;a href="https://docs.aws.amazon.com/signin/latest/userguide/sign-in-aws_builder_id.html"&gt;AWS Builder ID&lt;/a&gt; account, please sign up first&lt;/li&gt;
&lt;li&gt;After sign up, go to &lt;a href="https://codecatalyst.aws/explore"&gt;Amazon CodeCatalyst&lt;/a&gt; web console to start project and configuration. Apply initial configuration that needed by CodeCatalyst such as:

&lt;ul&gt;
&lt;li&gt;Creating space&lt;/li&gt;
&lt;li&gt;Connect CodeCatalyst space with AWS account&lt;/li&gt;
&lt;li&gt;Create and connect IAM role that will be used for running CodeCatalyst workflow/pipeline&lt;/li&gt;
&lt;li&gt;Connect GitHub source code repository&lt;/li&gt;
&lt;li&gt;Define environment that will be used by workflow/pipeline&lt;/li&gt;
&lt;li&gt;Please check my blog &lt;a href="https://dev.to/aws-builders/build-and-release-container-image-to-amazon-elastic-container-registry-ecr-via-amazon-codecatalyst-3a2p"&gt;“Build and Release Container Image to Amazon Elastic Container Registry (ECR) via Amazon CodeCatalyst”&lt;/a&gt; to find reference for configuration above. Please check section &lt;code&gt;Amazon CodeCatalyst Pipeline/Workflow Configuration&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;Prepare S3 bucket and DynamoDB lock table (optional) that will be used by Terraform backend&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Configuration Steps
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Directory Structure
&lt;/h3&gt;

&lt;p&gt;Below is directory structure used in this blog:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.
├── .codecatalyst/
│   └── workflows/
│       └── tf-sbx2-vpc-apse1.yml
└── sandbox2/
    ├── vpc/
    │   └── ap-southeast-1/
    │       ├── main.tf
    │       ├── resources.tf
    │       └── variables.tf
    └── tf-backend/
        ├── main.tf
        ├── resources.tf
        └── variables.tf
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Terraform Backend Configurations
&lt;/h3&gt;

&lt;p&gt;Configuration start with provisioning resources that will be needed by Terraform backend such as S3 bucket and DynamoDB table. Beside that, We also need to prepare IAM role that will be needed to provision resources from CodeCatalyst workflow/pipeline.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;At first, We haven’t had any resource for storing Terraform state in S3, so that we need to run and store terraform state on our local, for example: laptop. Later, We will move that state from local to S3. We start by defining configuration in &lt;strong&gt;sandbox2/tf-backend/main.tf&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;terraform&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;required_providers&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;aws&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;source&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"hashicorp/aws"&lt;/span&gt;
      &lt;span class="n"&gt;version&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"~&amp;gt; 5.11.0"&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="n"&gt;required_version&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"&amp;gt;= 1.3.0"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;provider&lt;/span&gt; &lt;span class="s"&gt;"aws"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;region&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;var&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;aws_region&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Define variable region in file &lt;strong&gt;sandbox2/tf-backend/variables.tf&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;variable&lt;/span&gt; &lt;span class="s"&gt;"aws_region"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;type&lt;/span&gt;        &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;
  &lt;span class="n"&gt;description&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"AWS Region"&lt;/span&gt;
  &lt;span class="k"&gt;default&lt;/span&gt;     &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"ap-southeast-1"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Define resources S3, DynamoDB and IAM that needed by CodeCatalyst in file &lt;strong&gt;sandbox2/tf-backend/resources.tf&lt;/strong&gt;. In this blog, IAM role CodeCatalyst has administrator access just for demo purposes. Please bear in mind to always use least privilege method on your production to prevent any security breaches&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="err"&gt;######&lt;/span&gt;
&lt;span class="err"&gt;#&lt;/span&gt; &lt;span class="n"&gt;S3&lt;/span&gt; &lt;span class="err"&gt;#&lt;/span&gt;
&lt;span class="err"&gt;######&lt;/span&gt;

&lt;span class="n"&gt;resource&lt;/span&gt; &lt;span class="s"&gt;"aws_s3_bucket"&lt;/span&gt; &lt;span class="s"&gt;"my_sandbox2_tfbucket"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;bucket&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"my-sandbox2-tfbucket"&lt;/span&gt;

  &lt;span class="n"&gt;lifecycle&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;prevent_destroy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;resource&lt;/span&gt; &lt;span class="s"&gt;"aws_s3_bucket_versioning"&lt;/span&gt; &lt;span class="s"&gt;"my_sandbox2_tfbucket"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;bucket&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;aws_s3_bucket&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;my_sandbox2_tfbucket&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;

  &lt;span class="n"&gt;versioning_configuration&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Enabled"&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;resource&lt;/span&gt; &lt;span class="s"&gt;"aws_s3_bucket_server_side_encryption_configuration"&lt;/span&gt; &lt;span class="s"&gt;"my_sandbox2_tfbucket"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;bucket&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;aws_s3_bucket&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;my_sandbox2_tfbucket&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;

  &lt;span class="n"&gt;rule&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;apply_server_side_encryption_by_default&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;sse_algorithm&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"AES256"&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;resource&lt;/span&gt; &lt;span class="s"&gt;"aws_s3_bucket_public_access_block"&lt;/span&gt; &lt;span class="s"&gt;"my_sandbox2_tfbucket"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;bucket&lt;/span&gt;                  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;aws_s3_bucket&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;my_sandbox2_tfbucket&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;
  &lt;span class="n"&gt;block_public_acls&lt;/span&gt;       &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;
  &lt;span class="n"&gt;block_public_policy&lt;/span&gt;     &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;
  &lt;span class="n"&gt;ignore_public_acls&lt;/span&gt;      &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;
  &lt;span class="n"&gt;restrict_public_buckets&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="err"&gt;############&lt;/span&gt;
&lt;span class="err"&gt;#&lt;/span&gt; &lt;span class="n"&gt;DynamoDB&lt;/span&gt; &lt;span class="err"&gt;#&lt;/span&gt;
&lt;span class="err"&gt;############&lt;/span&gt;

&lt;span class="n"&gt;resource&lt;/span&gt; &lt;span class="s"&gt;"aws_dynamodb_table"&lt;/span&gt; &lt;span class="s"&gt;"my_sandbox2_tflocks"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;name&lt;/span&gt;         &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"my-sandbox2-tflocks"&lt;/span&gt;
  &lt;span class="n"&gt;billing_mode&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"PAY_PER_REQUEST"&lt;/span&gt;
  &lt;span class="n"&gt;hash_key&lt;/span&gt;     &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"LockID"&lt;/span&gt;

  &lt;span class="n"&gt;attribute&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"LockID"&lt;/span&gt;
    &lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"S"&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="err"&gt;#######&lt;/span&gt;
&lt;span class="err"&gt;#&lt;/span&gt; &lt;span class="n"&gt;IAM&lt;/span&gt; &lt;span class="err"&gt;#&lt;/span&gt;
&lt;span class="err"&gt;#######&lt;/span&gt;

&lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="s"&gt;"aws_iam_policy_document"&lt;/span&gt; &lt;span class="s"&gt;"codecatalyst_assume_role_policy"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;statement&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;actions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"sts:AssumeRole"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;principals&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Service"&lt;/span&gt;
      &lt;span class="n"&gt;identifiers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="s"&gt;"codecatalyst.amazonaws.com"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s"&gt;"codecatalyst-runner.amazonaws.com"&lt;/span&gt;
      &lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;resource&lt;/span&gt; &lt;span class="s"&gt;"aws_iam_role"&lt;/span&gt; &lt;span class="s"&gt;"codecatalyst_admin"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;name&lt;/span&gt;               &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"codecatalyst-admin"&lt;/span&gt;
  &lt;span class="n"&gt;assume_role_policy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;aws_iam_policy_document&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;codecatalyst_assume_role_policy&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;json&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;resource&lt;/span&gt; &lt;span class="s"&gt;"aws_iam_role_policy_attachment"&lt;/span&gt; &lt;span class="s"&gt;"codecatalyst_admin"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;role&lt;/span&gt;       &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;aws_iam_role&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;codecatalyst_admin&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;
  &lt;span class="n"&gt;policy_arn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"arn:aws:iam::aws:policy/AdministratorAccess"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Refer AWS keys that needed for running terraform workflow commands, for example by exporting environment variables as explained in this &lt;a href="https://registry.terraform.io/providers/hashicorp/aws/latest/docs#environment-variables"&gt;document&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Run terraform cli commands that needed for provisioning resources&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;terraform init
terraform plan
terraform apply
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Verify terraform apply is successful and resources successfully provisioned&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Back to file &lt;strong&gt;sandbox2/tf-backend/main.tf&lt;/strong&gt;, add additional configurations related to S3 backend&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="err"&gt;###########################&lt;/span&gt;
&lt;span class="err"&gt;#&lt;/span&gt; &lt;span class="n"&gt;Terraform&lt;/span&gt; &lt;span class="n"&gt;Configuration&lt;/span&gt; &lt;span class="err"&gt;#&lt;/span&gt;
&lt;span class="err"&gt;###########################&lt;/span&gt;

&lt;span class="n"&gt;terraform&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;backend&lt;/span&gt; &lt;span class="s"&gt;"s3"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;bucket&lt;/span&gt;         &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"my-sandbox2-tfbucket"&lt;/span&gt;
    &lt;span class="n"&gt;key&lt;/span&gt;            &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"path/to/terraform.tfstate"&lt;/span&gt;
    &lt;span class="n"&gt;region&lt;/span&gt;         &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"ap-southeast-1"&lt;/span&gt;
    &lt;span class="n"&gt;dynamodb_table&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"my-sandbox2-tflocks"&lt;/span&gt;
    &lt;span class="n"&gt;encrypt&lt;/span&gt;        &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Run &lt;code&gt;terraform init&lt;/code&gt; command again. Terraform will detect changes related to S3 backend and will move terraform state to S3 bucket that has been defined. Choose &lt;code&gt;yes&lt;/code&gt; if asked for input&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;terraform init

Initializing the backend...
Do you want to copy existing state to the new backend?
  Pre-existing state was found while migrating the previous "local" backend to the
  newly configured "s3" backend. No existing state was found in the newly
  configured "s3" backend. Do you want to copy this state to the new "s3"
  backend? Enter "yes" to copy and "no" to start with an empty state.

  Enter a value: yes

Releasing state lock. This may take a few moments...

Successfully configured the backend "s3"! Terraform will automatically
use this backend unless the backend configuration changes.
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Go to Amazon Web Services (AWS) web console, go to S3 service menu. Verify &lt;code&gt;terraform.tfstate&lt;/code&gt; file has been copied to defined S3 bucket/path&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  CodeCatalyst Workflow File Configurations
&lt;/h3&gt;

&lt;p&gt;After configurations for terraform backend has been finished as described above, next we continue configure CodeCatalyst workflow/pipeline.&lt;/p&gt;

&lt;p&gt;Before starting workflow configuration, please make sure to configure all configurations that needed by CodeCatalyst as mentioned in Prerequisites.&lt;/p&gt;

&lt;p&gt;As mentioned in document &lt;a href="https://docs.aws.amazon.com/codecatalyst/latest/userguide/flows.html"&gt;Build, test, and deploy with workflows in CodeCatalyst&lt;/a&gt;, CodeCatalyst use workflow definition file as reference workflow/pipeline configuration and this file is saved in directory &lt;code&gt;~/.codecatalyst/workflows/&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;In this blog, I will create basic resources that needed by VPC on AWS. As mentioned on Directory Structure above, pipeline will be ran when there is changes inside directory &lt;code&gt;sandbox2/vpc/ap-southeast-1&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Below is full content of workflow file &lt;code&gt;codecatalyst/workflows/tf-sbx2-vpc-apse1.yml&lt;/code&gt; that used as example in this blog.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;Name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;tf-sbx2-vpc-apse1&lt;/span&gt;
&lt;span class="na"&gt;SchemaVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;1.0"&lt;/span&gt;

&lt;span class="na"&gt;Triggers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;PUSH&lt;/span&gt;
    &lt;span class="na"&gt;Branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;master&lt;/span&gt;
    &lt;span class="na"&gt;FilesChanged&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;sandbox2\/vpc\/ap-southeast-1\/.*&lt;/span&gt;

&lt;span class="na"&gt;Actions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;terraform-plan&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;Identifier&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;aws/build@v1&lt;/span&gt;
    &lt;span class="na"&gt;Inputs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;Sources&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;WorkflowSource&lt;/span&gt;
    &lt;span class="na"&gt;Environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;Name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;sandbox&lt;/span&gt;
      &lt;span class="na"&gt;Connections&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;Name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;lanandra-sandbox&lt;/span&gt;
          &lt;span class="na"&gt;Role&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;codecatalyst-admin&lt;/span&gt;
    &lt;span class="na"&gt;Configuration&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;Container&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;Registry&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;DockerHub&lt;/span&gt;
        &lt;span class="na"&gt;Image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;hashicorp/terraform:1.5.7&lt;/span&gt;
      &lt;span class="na"&gt;Steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;Run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;cd sandbox2/vpc/ap-southeast-1&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;Run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;terraform fmt -check -no-color&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;Run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;terraform init -no-color&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;Run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;terraform validate -no-color&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;Run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;terraform plan -no-color -input=false&lt;/span&gt;
    &lt;span class="na"&gt;Compute&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;EC2&lt;/span&gt;
  &lt;span class="na"&gt;wait-period&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;DependsOn&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;terraform-plan&lt;/span&gt;
    &lt;span class="na"&gt;Identifier&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;aws/build@v1&lt;/span&gt;
    &lt;span class="na"&gt;Inputs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;Sources&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;WorkflowSource&lt;/span&gt;
    &lt;span class="na"&gt;Environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;Name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;sandbox&lt;/span&gt;
      &lt;span class="na"&gt;Connections&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;Name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;lanandra-sandbox&lt;/span&gt;
          &lt;span class="na"&gt;Role&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;codecatalyst-admin&lt;/span&gt;
    &lt;span class="na"&gt;Configuration&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;Steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;Run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;echo "Please wait for a while before terraform apply"&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;Run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;echo "If you wish to cancel terraform apply, please stop this run"&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;Run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;sleep &lt;/span&gt;&lt;span class="m"&gt;60&lt;/span&gt;
    &lt;span class="na"&gt;Compute&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;EC2&lt;/span&gt;
  &lt;span class="na"&gt;terraform-apply&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;DependsOn&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;wait-period&lt;/span&gt;
    &lt;span class="na"&gt;Identifier&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;aws/build@v1&lt;/span&gt;
    &lt;span class="na"&gt;Inputs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;Sources&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;WorkflowSource&lt;/span&gt;
    &lt;span class="na"&gt;Environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;Name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;sandbox&lt;/span&gt;
      &lt;span class="na"&gt;Connections&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;Name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;lanandra-sandbox&lt;/span&gt;
          &lt;span class="na"&gt;Role&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;codecatalyst-admin&lt;/span&gt;
    &lt;span class="na"&gt;Configuration&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;Container&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;Registry&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;DockerHub&lt;/span&gt;
        &lt;span class="na"&gt;Image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;hashicorp/terraform:1.5.7&lt;/span&gt;
      &lt;span class="na"&gt;Steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;Run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;cd sandbox2/vpc/ap-southeast-1&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;Run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;terraform init -no-color&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;Run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;terraform apply -auto-approve -no-color -input=false&lt;/span&gt;
    &lt;span class="na"&gt;Compute&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;EC2&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, I will explain more detail each sections that defined on workflow file above.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Define workflow name. Then define how workflow will be ran. In this blog, workflow will be ran when there is a push to master branch but only ran when changes is under directory &lt;code&gt;sandbox2/vpc/ap-southeast-1/&lt;/code&gt; (regular expression or regex is used to detect changes)&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;Triggers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;PUSH&lt;/span&gt;
    &lt;span class="na"&gt;Branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;master&lt;/span&gt;
    &lt;span class="na"&gt;FilesChanged&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;sandbox2\/vpc\/ap-southeast-1\/.*&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Define action. Action will be divided into 3 sections. The first one is used to run workflow &lt;code&gt;terraform plan&lt;/code&gt;. In this section, action uses identifier &lt;code&gt;aws/build@v1&lt;/code&gt;. Then action will be ran on sandbox environment that has been connected with AWS account and also has IAM role associated with that account. In &lt;code&gt;Configuration&lt;/code&gt; section, has been defined that action will be ran on top of container using specific version of terraform public image that pulled from DockerHub. Also has defined working directory and several terraform commands which include &lt;code&gt;terraform plan&lt;/code&gt;. Lastly, define compute type which is &lt;code&gt;EC2&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;Actions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;terraform-plan&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;Identifier&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;aws/build@v1&lt;/span&gt;
    &lt;span class="na"&gt;Inputs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;Sources&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;WorkflowSource&lt;/span&gt;
    &lt;span class="na"&gt;Environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;Name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;sandbox&lt;/span&gt;
      &lt;span class="na"&gt;Connections&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;Name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;lanandra-sandbox&lt;/span&gt;
          &lt;span class="na"&gt;Role&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;codecatalyst-admin&lt;/span&gt;
    &lt;span class="na"&gt;Configuration&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;Container&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;Registry&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;DockerHub&lt;/span&gt;
        &lt;span class="na"&gt;Image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;hashicorp/terraform:1.5.7&lt;/span&gt;
      &lt;span class="na"&gt;Steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;Run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;cd sandbox2/vpc/ap-southeast-1&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;Run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;terraform fmt -check -no-color&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;Run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;terraform init -no-color&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;Run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;terraform validate -no-color&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;Run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;terraform plan -no-color -input=false&lt;/span&gt;
    &lt;span class="na"&gt;Compute&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;EC2&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Next action that defined is called &lt;code&gt;wait-period&lt;/code&gt;. This action is defined so that there is an interlude between &lt;code&gt;terraform plan&lt;/code&gt; and &lt;code&gt;terraform apply&lt;/code&gt;. In case there is something that unwanted in terraform plan, so that we have a time to not continue to next action or process which is terraform apply. This action is workaround because by the time this blog is released, there is no out of the box solution provided by CodeCatalyst, for example manual approval. So in case there is something unwanted, we can abort the workflow. In this action, I created a logic to pause the workflow for 60 seconds and this action is depends on previous action which is &lt;code&gt;terraform plan&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;wait-period&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;DependsOn&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;terraform-plan&lt;/span&gt;
    &lt;span class="na"&gt;Identifier&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;aws/build@v1&lt;/span&gt;
    &lt;span class="na"&gt;Inputs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;Sources&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;WorkflowSource&lt;/span&gt;
    &lt;span class="na"&gt;Environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;Name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;sandbox&lt;/span&gt;
      &lt;span class="na"&gt;Connections&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;Name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;lanandra-sandbox&lt;/span&gt;
          &lt;span class="na"&gt;Role&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;codecatalyst-admin&lt;/span&gt;
    &lt;span class="na"&gt;Configuration&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;Steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;Run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;echo "Please wait for a while before terraform apply"&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;Run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;echo "If you wish to cancel terraform apply, please stop this run"&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;Run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;sleep &lt;/span&gt;&lt;span class="m"&gt;60&lt;/span&gt;
    &lt;span class="na"&gt;Compute&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;EC2&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Next action that defined is action to run &lt;code&gt;terraform apply&lt;/code&gt;. This action more or less similar with action &lt;code&gt;terraform-plan&lt;/code&gt;, the difference is just terraform command that declared on configuration. In this section, action will run commands that needed for &lt;code&gt;terraform apply&lt;/code&gt;. This action is depends on previous action which is &lt;code&gt;wait-period&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;terraform-apply&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;DependsOn&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;wait-period&lt;/span&gt;
    &lt;span class="na"&gt;Identifier&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;aws/build@v1&lt;/span&gt;
    &lt;span class="na"&gt;Inputs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;Sources&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;WorkflowSource&lt;/span&gt;
    &lt;span class="na"&gt;Environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;Name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;sandbox&lt;/span&gt;
      &lt;span class="na"&gt;Connections&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;Name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;lanandra-sandbox&lt;/span&gt;
          &lt;span class="na"&gt;Role&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;codecatalyst-admin&lt;/span&gt;
    &lt;span class="na"&gt;Configuration&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;Container&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;Registry&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;DockerHub&lt;/span&gt;
        &lt;span class="na"&gt;Image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;hashicorp/terraform:1.5.7&lt;/span&gt;
      &lt;span class="na"&gt;Steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;Run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;cd sandbox2/vpc/ap-southeast-1&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;Run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;terraform init -no-color&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;Run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;terraform apply -auto-approve -no-color -input=false&lt;/span&gt;
    &lt;span class="na"&gt;Compute&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;EC2&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Example of Terraform Workflow Process in CodeCatalyst CI/CD
&lt;/h3&gt;

&lt;p&gt;After configure CodeCatalyst workflow file, next I will create example of Terraform codes. In this blog, I will create VPC resources using public module &lt;a href="https://registry.terraform.io/modules/terraform-aws-modules/vpc/aws/latest"&gt;terraform-aws-modules/vpc/aws&lt;/a&gt; as reference. Here is the initial configuration/codes that defined:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;sandbox2/vpc/ap-souhteast-1/main.tf&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="err"&gt;###########################&lt;/span&gt;
&lt;span class="err"&gt;#&lt;/span&gt; &lt;span class="n"&gt;Terraform&lt;/span&gt; &lt;span class="n"&gt;Configuration&lt;/span&gt; &lt;span class="err"&gt;#&lt;/span&gt;
&lt;span class="err"&gt;###########################&lt;/span&gt;

&lt;span class="n"&gt;terraform&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;backend&lt;/span&gt; &lt;span class="s"&gt;"s3"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;bucket&lt;/span&gt;         &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"my-sandbox-tfbucket"&lt;/span&gt;
    &lt;span class="n"&gt;key&lt;/span&gt;            &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"path/to/terraform.tfstate"&lt;/span&gt;
    &lt;span class="n"&gt;region&lt;/span&gt;         &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"ap-southeast-1"&lt;/span&gt;
    &lt;span class="n"&gt;dynamodb_table&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"my-sandbox-tflocks"&lt;/span&gt;
    &lt;span class="n"&gt;encrypt&lt;/span&gt;        &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;terraform&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;required_providers&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;aws&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;source&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"hashicorp/aws"&lt;/span&gt;
      &lt;span class="n"&gt;version&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"~&amp;gt; 5.11.0"&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="n"&gt;required_version&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"&amp;gt;= 1.3.0"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;provider&lt;/span&gt; &lt;span class="s"&gt;"aws"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;region&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;var&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;aws_region&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;sandbox2/vpc/ap-souhteast-1/variables.tf&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;variable&lt;/span&gt; &lt;span class="s"&gt;"aws_region"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;type&lt;/span&gt;        &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;
  &lt;span class="n"&gt;description&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"AWS Region"&lt;/span&gt;
  &lt;span class="k"&gt;default&lt;/span&gt;     &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"ap-southeast-1"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;variable&lt;/span&gt; &lt;span class="s"&gt;"env_name"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;type&lt;/span&gt;    &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;
  &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"sbx2"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;sandbox2/vpc/ap-souhteast-1/resources.tf&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="err"&gt;#######&lt;/span&gt;
&lt;span class="err"&gt;#&lt;/span&gt; &lt;span class="n"&gt;VPC&lt;/span&gt; &lt;span class="err"&gt;#&lt;/span&gt;
&lt;span class="err"&gt;#######&lt;/span&gt;


&lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="s"&gt;"aws_availability_zones"&lt;/span&gt; &lt;span class="s"&gt;"available"&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;

&lt;span class="n"&gt;locals&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;azs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;aws_availability_zones&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;available&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;names&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="n"&gt;tags&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="s"&gt;"myTag:environment"&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"sbx2"&lt;/span&gt;
    &lt;span class="s"&gt;"myTag:managedBy"&lt;/span&gt;   &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"terraform"&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;module&lt;/span&gt; &lt;span class="s"&gt;"vpc"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;source&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"terraform-aws-modules/vpc/aws"&lt;/span&gt;
  &lt;span class="n"&gt;version&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"5.1.2"&lt;/span&gt;

  &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;var&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;env_name&lt;/span&gt;
  &lt;span class="n"&gt;cidr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"10.255.8.0/21"&lt;/span&gt;

  &lt;span class="n"&gt;azs&lt;/span&gt;             &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;local&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;azs&lt;/span&gt;
  &lt;span class="n"&gt;private_subnets&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"10.255.8.0/24"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"10.255.9.0/24"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"10.255.10.0/24"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="n"&gt;public_subnets&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"10.255.15.0/24"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"10.255.14.0/24"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"10.255.13.0/24"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

  &lt;span class="n"&gt;enable_nat_gateway&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;false&lt;/span&gt;
  &lt;span class="n"&gt;single_nat_gateway&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;

  &lt;span class="n"&gt;tags&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;local&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tags&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;To conduct testing of Terraform workflow in CI/CD, I will change 1 line of code inside file &lt;strong&gt;sandbox2/vpc/ap-souhteast-1/resources.tf&lt;/strong&gt;. I will activate NAT gateway with changing this line of code that current value is &lt;code&gt;false&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;enable_nat_gateway&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;As defined in workflow file, all changes inside directory &lt;strong&gt;sandbox/vpc/ap-southeast-1&lt;/strong&gt; will trigger workflow run. To verify, go to CodeCatalyst web console, go to space and project where codes resided. Then go to CI/CD menu, choose Workflows. Go to tab Runs, verify there is new run that currently running.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--iTB8VK1M--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://ludesdeveloper.files.wordpress.com/2023/10/1.-new-run.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--iTB8VK1M--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://ludesdeveloper.files.wordpress.com/2023/10/1.-new-run.png" alt="new-run" width="800" height="383"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Go to run details by clicking name/id of run. Then We will be redirected to overview page of run. Click action name &lt;code&gt;terraform-plan&lt;/code&gt;, on the right will be showed tray box that display details configuration/steps of action. For example We want to see details of &lt;code&gt;terraform plan&lt;/code&gt;, go to tab &lt;code&gt;log&lt;/code&gt;, then click step &lt;code&gt;terraform plan -no-color -input-false&lt;/code&gt;. Verify action succeeded&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--G3ninX7_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://ludesdeveloper.files.wordpress.com/2023/10/2.-tf-plan-overview.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--G3ninX7_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://ludesdeveloper.files.wordpress.com/2023/10/2.-tf-plan-overview.png" alt="tf-plan-overview" width="800" height="379"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Verify terraform plan show expected result. Terraform will create resources releated to NAT gateway as mentioned in point number 1&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--n92VIyMv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://ludesdeveloper.files.wordpress.com/2023/10/3.-tf-plan-details.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--n92VIyMv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://ludesdeveloper.files.wordpress.com/2023/10/3.-tf-plan-details.png" alt="tf-plan-details" width="800" height="380"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;As defined in workflow file, after &lt;code&gt;terraform-plan&lt;/code&gt; action ran successfully, next workflow will proceed next action which is &lt;code&gt;wait-period&lt;/code&gt; to give some interlude whether terraform plan will be executed to next action which is &lt;code&gt;terraform-apply&lt;/code&gt; or apply will be aborted. If plan has met expectation and We want to proceed to &lt;code&gt;terraform apply&lt;/code&gt;, no action needed, just wait 60 seconds and then verify action succeeded&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--5rU2B_g8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://ludesdeveloper.files.wordpress.com/2023/10/4a.-wait-period-successful.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--5rU2B_g8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://ludesdeveloper.files.wordpress.com/2023/10/4a.-wait-period-successful.png" alt="wait-period-successful" width="800" height="380"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;But, if want to abort workflow and don’t want continue to &lt;code&gt;terraform apply&lt;/code&gt;, click stop button when action still in progress&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--mxpldbdL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://ludesdeveloper.files.wordpress.com/2023/10/4b.-stop-wait-period.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--mxpldbdL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://ludesdeveloper.files.wordpress.com/2023/10/4b.-stop-wait-period.png" alt="stop-wait-period" width="800" height="380"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Let’s say We want to continue to &lt;code&gt;terraform apply&lt;/code&gt; process, then &lt;code&gt;terraform-apply&lt;/code&gt; action will be ran. We can see the details of the action inside tray box similar with previous actions. To verify resources has been provisioned via &lt;code&gt;terraform apply&lt;/code&gt;, click step &lt;code&gt;terraform apply -auto-approve -no-color -input=false&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--_JxwC2th--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://ludesdeveloper.files.wordpress.com/2023/10/5.-tf-apply-overview.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--_JxwC2th--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://ludesdeveloper.files.wordpress.com/2023/10/5.-tf-apply-overview.png" alt="tf-apply-overview" width="800" height="380"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Verify terraform apply has been expected and action is succeeded&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--0rkxGBWy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://ludesdeveloper.files.wordpress.com/2023/10/6.-tf-apply-details.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--0rkxGBWy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://ludesdeveloper.files.wordpress.com/2023/10/6.-tf-apply-details.png" alt="tf-apply-details" width="800" height="380"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Go to VPC service page in AWS web console to verify NAT gateway has been provisioned successfully&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--1X9pOJN5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://ludesdeveloper.files.wordpress.com/2023/10/7.-verify-nat-gw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--1X9pOJN5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://ludesdeveloper.files.wordpress.com/2023/10/7.-verify-nat-gw.png" alt="verify-nat-gw" width="800" height="695"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;We have reached the last section of this blog. Here are some key takeaways that can be summarized:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Amazon CodeCatalyst can act as alternative for CI/CD engine/tools that can be used to run Terraform workflow&lt;/li&gt;
&lt;li&gt;Amazon CodeCatalyst use IAM role to interact with AWS services. By using this method, Terraform doesn’t need to inject static credentials such as AWS Access Key and AWS Secret Key into the pipeline. This can’t help prevent security breaches&lt;/li&gt;
&lt;li&gt;Amazon CodeCatalyst can give seamless experience if We want to deploy application to AWS environments&lt;/li&gt;
&lt;li&gt;But some workflow or logic haven’t been provided by CodeCatalyst by the time this blog is released. Maybe there will be some improvement in the future&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Please check out my GitHub repository to see source code example that used in this blog:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Terraform backend configuration: &lt;a href="https://github.com/lanandra/mock-aws-infrastructure/tree/master/sandbox2/tf-backend"&gt;tf backend&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Amazon CodeCatalyst workflow file: &lt;a href="https://github.com/lanandra/mock-aws-infrastructure/tree/master/.codecatalyst/workflows"&gt;codecatalyst workflow&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Example of Terraform AWS VPC configuration: &lt;a href="https://github.com/lanandra/mock-aws-infrastructure/tree/master/sandbox2/vpc/ap-southeast-1"&gt;tf aws vpc&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Please comment if you have any suggestions, critiques, or thoughts.&lt;/p&gt;

&lt;p&gt;Hope this article will benefit you. Thank you!&lt;/p&gt;

</description>
      <category>aws</category>
      <category>cicd</category>
      <category>codecatalyst</category>
      <category>terraform</category>
    </item>
    <item>
      <title>Build and Release Container Image to Amazon Elastic Container Registry (ECR) via Amazon CodeCatalyst</title>
      <dc:creator>Luthfi Anandra</dc:creator>
      <pubDate>Sat, 16 Sep 2023 05:20:25 +0000</pubDate>
      <link>https://dev.to/aws-builders/build-and-release-container-image-to-amazon-elastic-container-registry-ecr-via-amazon-codecatalyst-3a2p</link>
      <guid>https://dev.to/aws-builders/build-and-release-container-image-to-amazon-elastic-container-registry-ecr-via-amazon-codecatalyst-3a2p</guid>
      <description>&lt;p&gt;In this blog, I will discuss how to build and release container image to Amazon Elastic Container Registry (ECR) using service that by the time this blog is released, the service is quite new which is Amazon CodeCatalyst.&lt;/p&gt;

&lt;p&gt;Before continue further, I would like to explain briefly about Amazon CodeCatalyst. As referred from Amazon CodeCatalyst &lt;a href="https://docs.aws.amazon.com/codecatalyst/latest/userguide/welcome.html"&gt;documentation&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Amazon CodeCatalyst is an integrated service for software development teams adopting continuous integration and deployment practices into their software development process. CodeCatalyst puts the tools you need all in one place. You can plan work, collaborate on code, and build, test, and deploy applications with continuous integration/continuous delivery (CI/CD) tools.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Scenario
&lt;/h2&gt;

&lt;p&gt;In this blog, I will discuss how to build and release container image with GitHub as source code repository. Then Amazon CodeCatalyst will run pipeline/workflow used for build and release container image, then later container image will be sent to ECR. The topology would be like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--WfBGBVgp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://ludesdeveloper.files.wordpress.com/2023/08/codecatalyst-push-to-ecr-workflow.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--WfBGBVgp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://ludesdeveloper.files.wordpress.com/2023/08/codecatalyst-push-to-ecr-workflow.png" alt="codecatalyst push to ecr workflow" width="721" height="241"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Before starting configuration, if you have not got AWS Builder ID account, please sign up first&lt;/li&gt;
&lt;li&gt;After sign up, go to Amazon CodeCatalyst web console to start project and configuration&lt;/li&gt;
&lt;li&gt;Create repository for container image in Amazon ECR&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Configuration Steps
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Amazon ECR Repository Configuration
&lt;/h3&gt;

&lt;p&gt;In this blog, I created ECR repository using Terraform with remote backend (Terraform Cloud). ECR repository created with reference from terraform public module &lt;a href="https://registry.terraform.io/modules/terraform-aws-modules/ecr/aws/latest"&gt;terraform-aws-modules/terraform-aws-ecr&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Below is file or directory structure used by Terraform codes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;└── ecr/
    └── region-name/
        ├── files/
        │   └── policies/
        │       └── expire-untagged-images.json
        ├── main.tf
        ├── resources.tf
        └── variables.tf
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here are the configuration steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Define Terraform configuration inside file &lt;strong&gt;main.tf&lt;/strong&gt;. In this configuration, I declared remote backend (Terraform Cloud), workspace used by Terraform, provider and its version and also AWS region that declared from variable&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;###########################
# Terraform Configuration #
###########################

terraform {
  backend "remote" {
    hostname     = "app.terraform.io"
    organization = "my-organization"

    workspaces {
      name = "my-ecr-workspace"
    }
  }
}

terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~&amp;gt; 5.11.0"
    }
  }

  required_version = "&amp;gt;= 1.3.0"
}

provider "aws" {
  region = var.aws_region
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Define variable inside file &lt;strong&gt;variables.tf&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;variable "aws_region" {
  type        = string
  description = "AWS Region"
  default     = "ap-southeast-1"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Define ECR repository creation using public module reference as mentioned above. I also defined repository lifecycle policy so that untagged image will be expired after period amount of time. This configuration is defined in file &lt;strong&gt;resources.tf&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;####################
# ECR Repositories #
####################

module "my_repository" {
  source  = "terraform-aws-modules/ecr/aws"
  version = "1.6.0"

  repository_name             = "my-repository"
  repository_lifecycle_policy = file("${path.module}/files/policies/expire-untagged-images.json")

  tags = {
    Name             = "my-repository"
    "my:environment" = "my-environment"
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Policy file reference expire-untagged-images.json is contain this instruction&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
    "rules": [
        {
            "rulePriority": 1,
            "description": "Expire images older than 14 days",
            "selection": {
                "tagStatus": "untagged",
                "countType": "sinceImagePushed",
                "countUnit": "days",
                "countNumber": 14
            },
            "action": {
                "type": "expire"
            }
        }
    ]
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Next commit and push terraform codes to the repository. After that run Terraform plan and Terraform apply from Terraform Cloud workspace so that infrastructures or resources can be provisioned. This activity will not be explained in detail and I will only show the simulation. If you are interested in how to configure Terraform Cloud workspace and how to run Terraform plans and apply for the provision of AWS resources, please check out my other blog post &lt;a href="https://aws.plainenglish.io/basic-configuration-how-to-provision-amazon-web-services-aws-resources-via-terraform-cl-5e1d6db8b22f"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--50QlKpFo--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://ludesdeveloper.files.wordpress.com/2023/08/tfc-plan-and-apply.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--50QlKpFo--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://ludesdeveloper.files.wordpress.com/2023/08/tfc-plan-and-apply.png" alt="tfc plan and apply" width="800" height="363"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Amazon CodeCatalyst Pipeline/Workflow Configuration
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Before starting configuration, please make sure space on Amazon CodeCatalyst has been created. More details on space, please check &lt;a href="https://docs.aws.amazon.com/codecatalyst/latest/userguide/spaces.html"&gt;Spaces in CodeCatalyst&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Connect Amazon CodeCatalyst space with AWS account. In space page, go to menu Settings &amp;gt; AWS accounts. Click Add an AWS account button&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--fiwQZ-T9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://ludesdeveloper.files.wordpress.com/2023/08/1.-add-aws-account.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--fiwQZ-T9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://ludesdeveloper.files.wordpress.com/2023/08/1.-add-aws-account.png" alt="add aws account" width="800" height="125"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Input required values such as AWS account ID, then display name. Next click Associate AWS account button&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--IJVUoVcY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://ludesdeveloper.files.wordpress.com/2023/08/2.-associate-aws-account.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--IJVUoVcY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://ludesdeveloper.files.wordpress.com/2023/08/2.-associate-aws-account.png" alt="associate aws account" width="800" height="506"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Next We will be redirected to Amazon CodeCatalyst page in AWS web console. Insert token that has been generated by CodeCatalyst (image for this is not displayed in this blog). Verify space has been connected&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Back to AWS account page in CodeCatalyst web console, verify account has been connected as well&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s---X2wnoX0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://ludesdeveloper.files.wordpress.com/2023/08/4.-verify-aws-account.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s---X2wnoX0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://ludesdeveloper.files.wordpress.com/2023/08/4.-verify-aws-account.png" alt="verify aws account" width="800" height="131"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Add IAM role that will be used to run workflow. Go to account details page by clicking account name in previous point. Then click Manage roles from AWS Management Console button&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s---kH1_jQc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://ludesdeveloper.files.wordpress.com/2023/08/5.-add-iam-role.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s---kH1_jQc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://ludesdeveloper.files.wordpress.com/2023/08/5.-add-iam-role.png" alt="add iam role" width="800" height="190"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;In this blog, I created administrator IAM role because I just need for development only. On production environment, please bear in mind to always use least privileged method for security concern. Next, set role name and click Create development role button&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ege-SRE9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://ludesdeveloper.files.wordpress.com/2023/08/6.-create-iam-role-for-codecatalyst.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ege-SRE9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://ludesdeveloper.files.wordpress.com/2023/08/6.-create-iam-role-for-codecatalyst.png" alt="create iam role for codecatalyst" width="800" height="272"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Verify IAM role has been created&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--_k19aa2L--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://ludesdeveloper.files.wordpress.com/2023/08/7.-verify-iam-role.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--_k19aa2L--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://ludesdeveloper.files.wordpress.com/2023/08/7.-verify-iam-role.png" alt="verify iam role" width="800" height="235"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Go back to CodeCatalyst space page and create project by clicking Create project button&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--TYK9P-Jc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://ludesdeveloper.files.wordpress.com/2023/08/8.-create-project.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--TYK9P-Jc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://ludesdeveloper.files.wordpress.com/2023/08/8.-create-project.png" alt="create project" width="800" height="158"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;In this blog, I created project with bring your own code method. The codes has been stored in GitHub. Choose GitHub account that will be connected, then choose GitHub repository name. After that, set project name used by CodeCatalyst. If all set, click Create project button&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Ahspi_rs--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://ludesdeveloper.files.wordpress.com/2023/08/9.-create-project-bring-your-own-code.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Ahspi_rs--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://ludesdeveloper.files.wordpress.com/2023/08/9.-create-project-bring-your-own-code.png" alt="create project bring your own code" width="800" height="346"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Verify GitHub repository has been connected. In project page, go to menu Code &amp;gt; Source repositories.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--gx9Lh6ac--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://ludesdeveloper.files.wordpress.com/2023/08/10.-verify-source-repositories.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--gx9Lh6ac--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://ludesdeveloper.files.wordpress.com/2023/08/10.-verify-source-repositories.png" alt="verify source repositories" width="800" height="203"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Create environment that will be used by CI/CD workflow/pipeline. Go to menu CI/CD &amp;gt; Environment. Then click Create environment button&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Nq6BJEfM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://ludesdeveloper.files.wordpress.com/2023/08/11.-create-environment.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Nq6BJEfM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://ludesdeveloper.files.wordpress.com/2023/08/11.-create-environment.png" alt="create environment" width="800" height="231"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;In Create environment page, input environment name, environment type and AWS account connection (optional). If all set, click Create environment button&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--OR4fXv3K--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://ludesdeveloper.files.wordpress.com/2023/08/12.-create-environment-details.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--OR4fXv3K--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://ludesdeveloper.files.wordpress.com/2023/08/12.-create-environment-details.png" alt="create environment details" width="800" height="420"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Define CI/CD workflow/pipeline. CodeCatalyst need workflow definition file for pipeline creation. This file can be created by several methods, for example create via CodeCatalyst web console or using code/text editor. Further details about workflow in CodeCatalyst, please check CodeCatalyst documentation &lt;a href="https://docs.aws.amazon.com/codecatalyst/latest/userguide/workflows-concepts.html"&gt;Workflows concepts&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--kyV6MgZm--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://ludesdeveloper.files.wordpress.com/2023/08/13.-create-workflow-menu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--kyV6MgZm--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://ludesdeveloper.files.wordpress.com/2023/08/13.-create-workflow-menu.png" alt="create workflow menu" width="800" height="171"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Before creating workflow file, I would like to inform that there are several pre-defined workflow definition files that has been provided. To check those files, go to menu Create workflow &amp;gt; in Actions section, find template file that suitable with your needs. In this blog, for example I will use pre-defined template for workflow push to Amazon ECR. This pre-defined template will help me to simplify build and push container image to Amazon ECR&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--V1af2iw9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://ludesdeveloper.files.wordpress.com/2023/08/14.-find-workflow-push-to-amazon-ecr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--V1af2iw9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://ludesdeveloper.files.wordpress.com/2023/08/14.-find-workflow-push-to-amazon-ecr.png" alt="find workflow push to amazon ecr" width="800" height="755"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;We can see the details of each pre-defined template file. For example documentation about how to use, YAML preview etc. To see the details, click pre-defined template name and next will be redirected to detail page&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--rYUZo3R8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://ludesdeveloper.files.wordpress.com/2023/08/15.-action-push-to-amazon-ecr-documentation.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--rYUZo3R8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://ludesdeveloper.files.wordpress.com/2023/08/15.-action-push-to-amazon-ecr-documentation.png" alt="action push to amazon ecr documentation" width="800" height="408"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;We also can see the preview of YAML and also the details for example variables used by the template&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--qbU1VPQD--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://ludesdeveloper.files.wordpress.com/2023/08/16.-action-push-to-amazon-ecr-yaml-preview.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--qbU1VPQD--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://ludesdeveloper.files.wordpress.com/2023/08/16.-action-push-to-amazon-ecr-yaml-preview.png" alt="action push to amazon ecr yaml preview" width="800" height="383"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Next You can adjust with your preference, whether you want to create configuration using visual editor on web console or using code/text editor&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;In this blog, I created configuration using code/text editor and I will explain the details of workflow file&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# - I created workflow name build-container
# - Workflow created using reference from pre-defined template `codecatalyst-labs/push-to-ecr@v1.0.1` with source from WorkflowSource which in this blog is GitHub repository
# - Workflow will run in sandbox environment with AWS account reference as explained above and IAM role that associated within that account
# - Define ECR repository name, image tag and AWS region

Name: build-container
SchemaVersion: "1.0"

Actions:
  build-and-push-to-ecr:
    # Identifies the action. Do not modify this value.
    Identifier: codecatalyst-labs/push-to-ecr@v1.0.1

    # Specifies the source and/or artifacts to pass to the action as input.
    Inputs:
      # Required
      Sources:
        - WorkflowSource # This specifies that the action requires this Workflow as a source

    # Required; You can use an environment, AWS account connection, and role to access AWS resources.
    Environment:
      Name: sandbox
      Connections:
        - Name: lanandra-sandbox
          Role: CodeCatalystWorkflowDevelopmentRole-lanandra-sandbox

    # Defines the action's properties.
    Configuration:
      # Required; type: string; description: The name to use for the repository. 
      # The repository name may be specified on its own (such as nginx-web-app) 
      # or it can be prepended with a namespace to group the repository into a category (such as project-a/nginx-web-app)
      RepositoryName: steampipe-container-agent
      ImageTag: v0.1.0
      AWSRegion: ap-southeast-1
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Run workflow. In this blog, I did not configured trigger event for workflow that can make workflow run automatically. Thus, I need to run the workflow manually. Go to menu CI/CD &amp;gt; Workflows. In tab Workflows, choose GitHub repository name, branch name and workflow name. Then in Action drop down list, choose Run&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--QB4Gb_hN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://ludesdeveloper.files.wordpress.com/2023/08/17.-run-workflow.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--QB4Gb_hN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://ludesdeveloper.files.wordpress.com/2023/08/17.-run-workflow.png" alt="run workflow" width="800" height="305"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Next workflow will be running. Verify it by choosing workflow name as mentioned in previous point, then choose tab Runs&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--1mvzqyUw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://ludesdeveloper.files.wordpress.com/2023/08/18.-workflow-run-menu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--1mvzqyUw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://ludesdeveloper.files.wordpress.com/2023/08/18.-workflow-run-menu.png" alt="workflow run menu" width="800" height="289"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Go to workflow run. Verify run has been running and succeeded. Details of run can be seen inside tab Logs&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Ku-EVhL4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://ludesdeveloper.files.wordpress.com/2023/08/19.-verify-run.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Ku-EVhL4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://ludesdeveloper.files.wordpress.com/2023/08/19.-verify-run.png" alt="verify run" width="800" height="347"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Verify container image has been created and uploaded to Amazon ECR. Go to ECR service page, then go to repository used or defined in workflow&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--0PD7V5Fb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://ludesdeveloper.files.wordpress.com/2023/08/20.-verify-container-image.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--0PD7V5Fb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://ludesdeveloper.files.wordpress.com/2023/08/20.-verify-container-image.png" alt="verify container image" width="800" height="335"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;We have reached the last section of this blog. Here are some key takeaways that can be summarized:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Amazon CodeCatalyst is service by AWS that provide Continues Integration/Continues Delivery or Deployment (CI/CD) in one place&lt;/li&gt;
&lt;li&gt;CodeCatalyst can be used as alternative for CI/CD engine/tools that have seamless experience if we want to deploy our application to AWS environment&lt;/li&gt;
&lt;li&gt;Currently there are some integration or template that can simplify user for creating CI/CD pipeline&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Please check out my GitHub repository to see source code example that used in this blog:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Terraform code for ECR creation: &lt;a href="https://github.com/lanandra/mock-aws-infrastructure/tree/master/environment-name/ecr/region-name"&gt;ecr&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Amazon CodeCatalyst workflow: &lt;a href="https://github.com/lanandra/steampipe-container-agent/blob/main/.codecatalyst/workflows/build-container.yaml"&gt;codecatalyst&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Please comment if you have any suggestions, critiques, or thoughts.&lt;/p&gt;

&lt;p&gt;Hope this article will benefit you. Thank you!&lt;/p&gt;

</description>
      <category>aws</category>
      <category>codecatalyst</category>
      <category>ecr</category>
      <category>cicd</category>
    </item>
    <item>
      <title>Alternative Way Provision AWS Resource via Terraform (Using IAM Assume Role Reference)</title>
      <dc:creator>Luthfi Anandra</dc:creator>
      <pubDate>Wed, 01 Mar 2023 14:55:43 +0000</pubDate>
      <link>https://dev.to/aws-builders/alternative-way-provision-aws-resource-via-terraform-using-iam-assume-role-reference-4lni</link>
      <guid>https://dev.to/aws-builders/alternative-way-provision-aws-resource-via-terraform-using-iam-assume-role-reference-4lni</guid>
      <description>&lt;p&gt;When provisioning or creating Amazon Web Services (AWS) resources via Terraform, maybe the most common method used is using AWS credentials reference that includes AWS Access Key ID and AWS Secret Access Key.&lt;/p&gt;

&lt;p&gt;In this blogpost, I will explain one of the alternative for provisioning AWS resource via Terraform. I reference IAM assumed role during provision.&lt;/p&gt;

&lt;p&gt;For context, before we discussed the configuration in detail, below is the scenario or architecture that I used in this blogpost:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fludesdeveloper.files.wordpress.com%2F2023%2F02%2Ftopology-tf-with-iam-assumed-role.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fludesdeveloper.files.wordpress.com%2F2023%2F02%2Ftopology-tf-with-iam-assumed-role.png" alt="topology"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;In this blogpost, I used Terraform with backend remote or Terraform Cloud&lt;/li&gt;
&lt;li&gt;In most common usage of Terraform, we reference AWS Access Key ID and AWS Secret Access Key for communication or interaction to AWS API. In this blogpost, I used IAM role that associated with IAM policy that needed for provision AWS resource&lt;/li&gt;
&lt;li&gt;But in this case, We still need IAM user or if I may call that intermediary user that act as middle man when Terraform interact with AWS API. And this IAM user still need AWS Access Key ID and AWS Secret Access Key, although this IAM user does not associated with IAM policy at all.&lt;/li&gt;
&lt;li&gt;IAM role will run assume role to IAM intermediary user before it can send API call that used for provision AWS resource&lt;/li&gt;
&lt;li&gt;The idea is we only concern about AWS keys that used by IAM intermediary user. And after that, We only need to create IAM role with privilege or IAM policy that needed, then IAM role will assume role to IAM intermediary user&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;As mentioned on scenario above, to provision from terraform via IAM assume role, we need some IAM resource. Here are some of them:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;IAM user that act as intermediary user&lt;/li&gt;
&lt;li&gt;IAM role&lt;/li&gt;
&lt;li&gt;Associate IAM policy to IAM role&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In this blogpost, I will create IAM resource using terraform code. Here are the steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Create IAM user that act as intermediary user. This IAM user will be associated to IAM group. IAM user and IAM group will be provisioned using &lt;a href="https://registry.terraform.io/modules/terraform-aws-modules/iam/aws/latest" rel="noopener noreferrer"&gt;public terraform aws module iam&lt;/a&gt;. Here is example of code:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#############
# IAM Users #
#############

module "tf_assume_user" {
  source  = "terraform-aws-modules/iam/aws//modules/iam-user"
  version = "5.9.2"

  name                          = "tf-assume-user"
  force_destroy                 = true
  create_iam_access_key         = false
  create_iam_user_login_profile = false

  tags = {
    Name             = "tf-assume-user"
    "my:environment" = "my-environment"
  }
}

##############
# IAM Groups #
##############

module "tf_assume_group" {
  source  = "terraform-aws-modules/iam/aws//modules/iam-group-with-policies"
  version = "5.9.2"

  name                              = "tf-assume-group"
  attach_iam_self_management_policy = false

  group_users = [
    module.tf_assume_user.iam_user_name
  ]

  custom_group_policy_arns = [
  ]

  tags = {
    Name             = "tf-assume-group"
    "my:environment" = "my-environment"
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Here is the example of IAM group and IAM user when verified from AWS Web Console. Create new AWS credentials (AWS Access Key ID and AWS Secret Acces Key) that will be used by IAM intermediary user.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fludesdeveloper.files.wordpress.com%2F2023%2F02%2F1.-tf-assume-group-1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fludesdeveloper.files.wordpress.com%2F2023%2F02%2F1.-tf-assume-group-1.png" alt="tf-assume-group"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fludesdeveloper.files.wordpress.com%2F2023%2F02%2F2.-tf-assume-user-1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fludesdeveloper.files.wordpress.com%2F2023%2F02%2F2.-tf-assume-user-1.png" alt="tf-assume-user"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Create IAM role that will assign IAM intermediary user above as trusted entity and will run sts:AssumeRole. Then in this blgpost, I will associate that IAM role with customer managed policy that can provision Amazon Lightsail. Policy that used for provision Lightsail is just for demo purpose so that it is not least privileged, please consider to use least privileged policy in production environment. IAM role and IAM policy will be provisioned using public terraform module as well. Here is the example of code:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#############
# IAM Roles #
#############

module "compute_admin_role" {
  source  = "terraform-aws-modules/iam/aws//modules/iam-assumable-role"
  version = "5.11.1"

  trusted_role_arns = [
    "arn:aws:iam::12digitsawsid:user/tf-assume-user",
  ]

  trusted_role_services = [
    "lightsail.amazonaws.com"
  ]

  create_role       = true
  role_name_prefix  = "compute-admin-sbx"
  role_requires_mfa = false

  custom_role_policy_arns = [
    module.lightsail_full_access.arn
  ]
}

################
# IAM Policies #
################

module "lightsail_full_access" {
  source  = "terraform-aws-modules/iam/aws//modules/iam-policy"
  version = "5.11.1"

  name        = "lightsail-full-access"
  path        = "/"
  description = "Provides full access to Amazon Lightsail"
  policy      = file("${path.module}/files/policies/lightsail/lightsail-full-access.json")

  tags = {
    Name             = "lightsail-full-access"
    "my:environment" = "my-environment"
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Here is the example of IAM role when verified from AWS Web Console.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fludesdeveloper.files.wordpress.com%2F2023%2F02%2F3.-tf-iam-assume-role.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fludesdeveloper.files.wordpress.com%2F2023%2F02%2F3.-tf-iam-assume-role.png" alt="iam-role-summary"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fludesdeveloper.files.wordpress.com%2F2023%2F02%2F3.1-tf-iam-assume-role-trust-relationship.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fludesdeveloper.files.wordpress.com%2F2023%2F02%2F3.1-tf-iam-assume-role-trust-relationship.png" alt="iam-role-trusted-entity"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Configuration Steps
&lt;/h2&gt;

&lt;p&gt;In this section, I will explain configuration steps that needed for provisioning AWS resource. As mentioned above, I used remote backend or Terraform Cloud. So I will explained a little bit about configuration on Terraform Cloud as well. In this blogpost, I provisioned Amazon Lightsail Instance as example.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;In Terraform Cloud workspace that used for provision AWS resource, on variables section I associated AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY that used by IAM intermediary user. I referenced those variables using variable sets. Variable sets configuration will not be explained more detail in this blogpost, please visit this &lt;a href="https://developer.hashicorp.com/terraform/cloud-docs/workspaces/variables/managing-variables#variable-sets" rel="noopener noreferrer"&gt;HashiCorp blog&lt;/a&gt; for more details.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fludesdeveloper.files.wordpress.com%2F2023%2F02%2F4.-set-tfc-workspace-varsets.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fludesdeveloper.files.wordpress.com%2F2023%2F02%2F4.-set-tfc-workspace-varsets.png" alt="tfc-variables"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Next in Terraform Code, I created file &lt;strong&gt;main.tf&lt;/strong&gt;. In this file, I declared terraform configuration that refers to terraform cloud (app.terraform.io) as a remote backend. I also declared the organization and workspace used by Terraform code. Next in this file, I declared the provider used by Terraform code which is Hashicorp/AWS, and versions related to it. Last, I declared the AWS region refer to the variable aws_region and IAM role arn refer to variable role_arn , which both are configured in file variables.tf which I will explain later.&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;###########################
# Terraform Configuration #
###########################

terraform {
  backend "remote" {
    hostname     = "app.terraform.io"
    organization = "my-organization"

    workspaces {
      name = "my-workspace"
    }
  }
}

terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~&amp;gt; 4.53.0"
    }
  }

  required_version = "&amp;gt;= 1.3.0"
}

provider "aws" {
  region = var.aws_region

  assume_role {
    role_arn = var.role_arn
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Next, I defined variables used by the Terraform in file &lt;strong&gt;variables.tf&lt;/strong&gt;.&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;variable "aws_region" {
  type        = string
  description = "AWS Region"
  default     = "ap-southeast-1"
}

variable "role_arn" {
  type        = string
  description = "IAM role ARN"
  default     = "arn:aws:iam::12digitsawsid:role/compute-admin-sbx"
}

variable "az" {
  type        = list(string)
  description = "AWS Availability Zone"
  default     = ["ap-southeast-1a", "ap-southeast-1b", "ap-southeast-1c"]
}

variable "key_pair_name" {
  type        = string
  description = "Name of Lightsail key pair"
  default     = "my-key-pair"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Next I created example code for provisioning Amazon Lightsail Instance.&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;######################
# Lightsail Instance #
######################

resource "aws_lightsail_instance" "my_instance" {
  name              = "my-instance"
  availability_zone = var.az[0]
  blueprint_id      = "ubuntu_20_04"
  bundle_id         = "micro_2_0"
  key_pair_name     = var.key_pair_name

  tags = {
    "Name"           = "my-instance"
    "my:environment" = "my-environment"
    "my:owner"       = "my-owner"
  }
}

resource "aws_lightsail_instance_public_ports" "my_instance_ports" {
  instance_name = aws_lightsail_instance.my_instance.name

  port_info {
    protocol  = "tcp"
    from_port = 22
    to_port   = 22
  }

  port_info {
    protocol  = "tcp"
    from_port = 443
    to_port   = 443
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Next commit and push terraform codes to the repository. After that run Terraform plan and Terraform apply from Terraform Cloud workspace so that infrastructures or resources can be provisioned. This activity will not be explained in detail and I will only show the simulation. If you are interested in how to configure Terraform Cloud workspace and how to run Terraform plans and apply for the provision of AWS resources, please check out my other blog post &lt;a href="https://aws.plainenglish.io/basic-configuration-how-to-provision-amazon-web-services-aws-resources-via-terraform-cl-5e1d6db8b22f" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fludesdeveloper.files.wordpress.com%2F2023%2F02%2F5.-tfc-appy-and-run.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fludesdeveloper.files.wordpress.com%2F2023%2F02%2F5.-tfc-appy-and-run.png" alt="tfc-plan-apply"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;After resource provisioning via Terraform Cloud has been finished, then we can verify resources have been successfully created via the AWS web console. I switched to Lightsail service page and verified that instance has been provisioned.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fludesdeveloper.files.wordpress.com%2F2023%2F02%2F6.-verify-lightsail-instance.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fludesdeveloper.files.wordpress.com%2F2023%2F02%2F6.-verify-lightsail-instance.png" alt="verify-lightsail-instance"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;So We have reached the last section of this article. There are some key takeaways that I want to point out:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Beside using most common method which is using IAM user that associated with AWS Credentials (AWS Access Key ID and AWS Secret Access Key) and IAM policy, we can provision AWS resource via Terraform using IAM role reference (IAM assume role)&lt;/li&gt;
&lt;li&gt;The idea is We only need to create IAM role with certain privilege and We don’t need create multiple IAM user that need AWS Credentials (AWS Access Key ID and AWS Secret Access Key)&lt;/li&gt;
&lt;li&gt;But by the time this blogpost is released, I found that there is still some limitation with this IAM assume role method. Because We still need IAM user that act as intermediary user and this IAM user need AWS Credentials (AWS Access Key ID and AWS Secret Access Key). Although this IAM user is not associated with any IAM policy at all and just IAM role that associated with IAM policy&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Please check my GitHub repository to see source code example used in this blogpost. For IAM resource configuration, please check this &lt;a href="https://github.com/lanandra/mock-aws-infrastructure/tree/master/environment-name/iam" rel="noopener noreferrer"&gt;iam&lt;/a&gt; directory and for example how to apply this Terraform assume role configuration, please refer to this &lt;a href="https://github.com/lanandra/mock-aws-infrastructure/tree/master/environment-name/lightsail/region-name" rel="noopener noreferrer"&gt;lightsail directory&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Please comment if you have any suggestions, critiques, or thoughts.&lt;/p&gt;

&lt;p&gt;Hope this article will benefit you. Thank you!&lt;/p&gt;

</description>
      <category>aws</category>
      <category>terraform</category>
      <category>iam</category>
    </item>
    <item>
      <title>Centralizing IAM Access Key Used by IAM Machine User Using AWS Secrets Manager</title>
      <dc:creator>Luthfi Anandra</dc:creator>
      <pubDate>Thu, 19 Jan 2023 15:08:41 +0000</pubDate>
      <link>https://dev.to/aws-builders/centralizing-iam-access-key-used-by-iam-machine-user-using-aws-secrets-manager-a89</link>
      <guid>https://dev.to/aws-builders/centralizing-iam-access-key-used-by-iam-machine-user-using-aws-secrets-manager-a89</guid>
      <description>&lt;p&gt;In Amazon Web Services (AWS) environment, if We want to interact with AWS API, we can use AWS API key/AWS credentials for programmatic access which usually consist of AWS Access Key ID and AWS Secret Access Key. Usually this API key associated with AWS Identity and Access Management (IAM) such as IAM user. IAM user also can be classified to IAM user for human-to-machine interaction and IAM user for machine-to-machine interaction. Example usage of machine-to-machine interaction is when We created IAM machine user for CI/CD integration, then We save API key credential of IAM machine user in CI/CD engine environment variable so that the engine can interact with AWS. For example when it is used to push container image from CI/CD to AWS.&lt;/p&gt;

&lt;p&gt;Sometimes it is common that those API key need to share with developers/engineers that in need and has privileged to access the key. For example Infrastructure Team want to share API key information with one of developer in service product team A. If the API key just shared or sent via csv file, probably there will be a problem in the future. For example that developer forgot where the API key is saved, or if the developer/engineer has resigned and forgot to share that API key with other team member or that API key might be shared or leaked to unprivileged user or bad actor and will open a security hole.&lt;/p&gt;

&lt;p&gt;In this blogpost, I want to share some idea or solution regarding problem that mentioned above. The solution is We keep the API key used by IAM machine user in centralized way using AWS service called &lt;a href="https://docs.aws.amazon.com/secretsmanager/latest/userguide/intro.html" rel="noopener noreferrer"&gt;AWS Secrets Manager&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Scenario
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa4u3x3clgthmljtjjkq7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa4u3x3clgthmljtjjkq7.png" alt="topology" width="401" height="241"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Configuration of storing API key will be initialized with Infrastructure as Code (IaC) method using Terraform&lt;/li&gt;
&lt;li&gt;Terraform configuration is using remote backend via Terraform Cloud&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Directory Structure
&lt;/h2&gt;

&lt;p&gt;In this article, the file structure used by Terraform codes is described below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.
└── environment-name/
    └── secrets-manager/
        └── region-name/
            ├── main.tf
            ├── resources.tf
            └── variables.tf
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Configuration
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;I started with creating file &lt;strong&gt;main.tf&lt;/strong&gt;. In this file, I declared terraform configuration that refers to terraform cloud (app.terraform.io) as a remote backend. I also declared the organization and workspace used by Terraform code. Next in this file, I declared the provider used by Terraform code which is Hashicorp/AWS, and versions related to it. Last, I declared the AWS region used by Terraform code to refer to the variable aws_region that is configured in file &lt;strong&gt;variables.tf&lt;/strong&gt; which I will explain later.&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;###########################
# Terraform Configuration #
###########################

terraform {
  backend "remote" {
    hostname     = "app.terraform.io"
    organization = "my-organization"

    workspaces {
      name = "my-secretsmanager-workspace"
    }
  }
}

terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~&amp;gt; 4.48.0"
    }
  }

  required_version = "&amp;gt;= 1.3.0"
}

provider "aws" {
  region = var.aws_region
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Next, I defined variables used by the Terraform in file &lt;strong&gt;variables.tf&lt;/strong&gt;.&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;variable "aws_region" {
  type        = string
  description = "AWS Region"
  default     = "ap-southeast-1"
}

variable "waiting_deletion_period" {
  type        = number
  description = "Waiting period in days before secret deleted. Set to 0 for force destroy"
  default     = 0
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Refer to Terraform AWS provider document regarding resource &lt;a href="https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/secretsmanager_secret_version" rel="noopener noreferrer"&gt;aws_secretsmanager_secret_version&lt;/a&gt;. If We want to create secret with key-value pairs, we can get those value with several methods and one in common is from variable. So that, still in file &lt;strong&gt;variables.tf&lt;/strong&gt;, I created variable that consist key-value pairs used by IAM machine user. And because AWS_SECRET_ACCESS_KEY contain sensitive value, I did not type the real value in the code but I changed manually from AWS Web Console to prevent repository contain any sensitive value. Example:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;variable "my_machine_credentials" {
  type        = map(string)
  description = "Key value pairs consist of AWS credentials used by my machine user"
  default = {
    "AWS_ACCESS_KEY_ID"     = "AKIAWE1AB2CD34FG5I767"
    "AWS_SECRET_ACCESS_KEY" = "change_me"
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Next in file &lt;strong&gt;resources.tf&lt;/strong&gt;, I declared secret with value, which value is referred from variable that described in point number 3.&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;###########
# Secrets #
###########

resource "aws_secretsmanager_secret" "dummy_machine_sbx" {
  name                    = "dummy-machine-sbx"
  recovery_window_in_days = var.waiting_deletion_period

  tags = {
    "Name"                 = "dummy-machine-sbx"
    "my:environment"       = "sandbox"
    "my:owner"             = "Luthfi"
  }
}

resource "aws_secretsmanager_secret_version" "dummy_machine_sbx" {
  secret_id     = aws_secretsmanager_secret.dummy_machine_sbx.id
  secret_string = jsonencode(var.dummy_machine_user_sbx_credentials)
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Next commit and push terraform codes to the repository. After that run Terraform plan and Terraform apply from Terraform Cloud workspace so that infrastructures or resources can be provisioned. This activity will not be explained in detail and I will only show the simulation. If you are interested in how to configure Terraform Cloud workspace and how to run Terraform plans and apply for the provision of AWS resources, please check out my other blog post &lt;a href="https://aws.plainenglish.io/basic-configuration-how-to-provision-amazon-web-services-aws-resources-via-terraform-cl-5e1d6db8b22f" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl2stju6kchlntgt6bjo4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl2stju6kchlntgt6bjo4.png" alt="tfc-plan-apply" width="800" height="461"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;After resource provisioning via terraform has been finished, then we can verify resources have been successfully created via the AWS web console. Go to Secrets Manager service page, then go to menu Secrets. Verify secret that defined in Terraform has been successfully created.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fivge0t6hg2my6vsp8tjg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fivge0t6hg2my6vsp8tjg.png" alt="get-secret" width="800" height="220"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Next go to details configuration of the secret by clicking secret name mentioned in previous step. In this page, We can see details configuration of secret such as: secret name, secret ARN, encryption key used by secret and secret tags.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fr1avu48o0jr8hj3upfsi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fr1avu48o0jr8hj3upfsi.png" alt="get-secret-details" width="800" height="234"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp8cskpk1ueyi8x3d5yy7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp8cskpk1ueyi8x3d5yy7.png" alt="get-secret-tags" width="800" height="250"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;In this blogpost, I don’t use automatic rotation for the secret.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4cb4tvzr1o6wjmxzbn94.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4cb4tvzr1o6wjmxzbn94.png" alt="get-secret-rotation" width="800" height="350"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;To verify the value of sercet, click &lt;strong&gt;Retrieve secret value&lt;/strong&gt; button as seen in point number 7. Then click Edit button to change the value of &lt;strong&gt;AWS_SECRET_ACCESS_KEY&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fw0inw9as14xvd8ya0dm5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fw0inw9as14xvd8ya0dm5.png" alt="get-secret-value" width="800" height="196"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Change the value of &lt;strong&gt;AWS_SECRET_ACCESS_KEY&lt;/strong&gt; then click Save.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fg3ey2tp0s545xyylmzeq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fg3ey2tp0s545xyylmzeq.png" alt="edit-secret-value" width="800" height="208"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Verify value has been updated.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1zxhxmh94p6q3ph4npn6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1zxhxmh94p6q3ph4npn6.png" alt="verify-secret-after-edited" width="800" height="190"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Next please always make sure that only privileged user that can access the secret.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5h80ofjlnp8b2cpipuvn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5h80ofjlnp8b2cpipuvn.png" alt="unpriveleged-user-cannot-access" width="800" height="251"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;So We have reached the last section of this article. There are some key takeaways that I want to point out:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;To prevent some potential issue regarding security hole and shared secret of API key used by IAM machine, We can keep the API key in centralized way using AWS Secrets Manager.&lt;/li&gt;
&lt;li&gt;Secret configuration in AWS Secrets Manager can be declared using the Infrastructure as Code (IaC) method. So that We can have a state file of infrastructure that has been created.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Please check my &lt;a href="https://github.com/lanandra/mock-aws-infrastructure/tree/master/environment-name/secrets-manager/region-name" rel="noopener noreferrer"&gt;GitHub repository&lt;/a&gt; to see source code example used in this blogpost.&lt;/p&gt;

&lt;p&gt;Please comment if you have any suggestions, critiques, or thoughts.&lt;/p&gt;

&lt;p&gt;Hope this article will benefit you. Thank you!&lt;/p&gt;

</description>
      <category>productivity</category>
      <category>tooling</category>
      <category>softwaredevelopment</category>
      <category>development</category>
    </item>
    <item>
      <title>What’s Alternative Way to Find AWS IAM Key that has not been rotated for ages? Let’s Check Out This Tool</title>
      <dc:creator>Luthfi Anandra</dc:creator>
      <pubDate>Sat, 24 Dec 2022 09:27:52 +0000</pubDate>
      <link>https://dev.to/aws-builders/whats-alternative-way-to-find-aws-iam-key-that-has-not-been-rotated-for-ages-lets-check-out-this-tool-13of</link>
      <guid>https://dev.to/aws-builders/whats-alternative-way-to-find-aws-iam-key-that-has-not-been-rotated-for-ages-lets-check-out-this-tool-13of</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzjujpl6qi48fivpa2ai5.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzjujpl6qi48fivpa2ai5.jpeg" alt="meme-iam" width="710" height="957"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;AWS IAM Key is one of tool that used to interact with AWS API. In AWS, it’s common for user that used for human-to-machine interaction or machine-to-machine interaction to have AWS Key that consists of AWS Access Key and AWS Secret Key.&lt;/p&gt;

&lt;p&gt;For security reason, IAM key should be rotated for example every 90 days. The goal is to prevent security holes/leaks, for example we accidentally expose our IAM key. Because with this IAM key, every person that has access to the key can access AWS API in accordance with privilege given to that key and we don’t want any bad actor have access to our AWS environment.&lt;/p&gt;

&lt;p&gt;In this blogpost, I want to introduce a tool that can be used to check or notify if any our AWS IAM key has exceeded the threshold. This tool name &lt;a href="https://github.com/lanandra/kuncen-aws-iam" rel="noopener noreferrer"&gt;kuncen-aws-iam&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;To run kuncen-aws-iam, you must follow these prerequisites:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Have &lt;a href="https://docs.docker.com/engine/install/" rel="noopener noreferrer"&gt;Docker Engine&lt;/a&gt; installed or run on your environment&lt;/li&gt;
&lt;li&gt;Pull &lt;a href="https://hub.docker.com/r/lanandra/steampipe-container-agent" rel="noopener noreferrer"&gt;lanandra/steampipe-container-agent&lt;/a&gt; container image. This container will utilize &lt;a href="https://steampipe.io/" rel="noopener noreferrer"&gt;Steampipe&lt;/a&gt; for querying AWS IAM API&lt;/li&gt;
&lt;li&gt;Have AWS API credentials (such as: AWS Access Key and AWS Secret Key) that have privilege to AWS IAM service&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How to Use
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Clone &lt;a href="https://github.com/lanandra/kuncen-aws-iam" rel="noopener noreferrer"&gt;kuncen-aws-iam&lt;/a&gt; source code&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;From your terminal, export AWS credentials (AWS_ACCESS_KEY_ID &amp;amp; AWS_SECRET_ACCESS_KEY)&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export AWS_ACCESS_KEY_ID="AWS_ACCESS_KEY_ID"
export AWS_SECRET_ACCESS_KEY="AWS_SECRET_ACCESS_KEY"
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Go to directory where kuncen-aws-iam resided. Then run the script&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cd path/to/kuncen-aws-iam/

./kuncen-aws-iam.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Or if you want to run kuncen-aws-iam anywhere in your terminal, please create symlink to this script. Example:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo ln -s path/to/kuncen-aws-iam/kuncen-aws-iam.sh 
/usr/local/bin/kuncen-aws-iam
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Example output of kuncen-aws-iam&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffpo1itktp2nf5h1lhqac.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffpo1itktp2nf5h1lhqac.png" alt="output-table" width="800" height="358"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Notes
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;As mentioned above, kuncen-aws-iam will check and send output of IAM key that age has exceed 90 days. But if you need to adjust the interval days, you can set it by set this environment variable below:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export KUNCEN_AWS_IAM_INTERVAL=int

example:
export KUNCEN_AWS_IAM_INTERVAL=180
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;As mentioned above, kuncen-aws-iam utilize Steampipe for querying AWS IAM API. By default Steampipe will output a query with table format. But Steampipe offers some output format such as: line, csv, json or table. If you need kuncen-aws-iam send output with different output other than table, you can set it by set this environment variable below:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export KUNCEN_AWS_IAM_OUTPUT=string

example:
export KUNCEN_AWS_IAM_OUTPUT=json
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;example output:&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0rj58xhalqo1w3v3ujgn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0rj58xhalqo1w3v3ujgn.png" alt="output-json" width="800" height="670"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Please comment if you have any suggestions, critiques, or thoughts.&lt;/p&gt;

&lt;p&gt;Hope this article will benefit you. Thank you.&lt;/p&gt;

</description>
      <category>nocode</category>
      <category>lowcode</category>
    </item>
    <item>
      <title>Backup MySQL Database That Running on Docker Container</title>
      <dc:creator>Luthfi Anandra</dc:creator>
      <pubDate>Fri, 15 Jan 2021 13:36:14 +0000</pubDate>
      <link>https://dev.to/lanandra/backup-mysql-database-that-running-on-docker-container-1k8h</link>
      <guid>https://dev.to/lanandra/backup-mysql-database-that-running-on-docker-container-1k8h</guid>
      <description>&lt;p&gt;In this article, i want to share some information how to backup MySQL database that running on Docker Container.&lt;/p&gt;

&lt;p&gt;The environment that i use is Ubuntu Linux running Docker container. MySQL is running on top of Docker container and mysql backup is using mysqldump.&lt;/p&gt;

&lt;p&gt;Here are few steps, how to backup MySQL that running on Docker container:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Check your MySQL container name&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fguz8r1txd4o31a9vwfy2.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fguz8r1txd4o31a9vwfy2.jpg" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Backup your database using this command:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;docker exec [mysql_container_name] /usr/bin/mysqldump -u [mysql_username] --password=[mysql_password] [database_name] &amp;gt; [destination_path]&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F46twzqu5v9t37h1zxn0o.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F46twzqu5v9t37h1zxn0o.jpg" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Verify your backup destination path. Make sure backup sql file has been added to destination&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fqllfoltxqxyso2u8g8pq.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fqllfoltxqxyso2u8g8pq.jpg" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>mysql</category>
      <category>database</category>
      <category>docker</category>
    </item>
    <item>
      <title>Extend EBS Volume</title>
      <dc:creator>Luthfi Anandra</dc:creator>
      <pubDate>Mon, 14 Dec 2020 17:28:51 +0000</pubDate>
      <link>https://dev.to/lanandra/extend-elb-volume-bhb</link>
      <guid>https://dev.to/lanandra/extend-elb-volume-bhb</guid>
      <description>&lt;p&gt;In this article, i want to share some information how to extend your aws ebs volume. In this example, i use ec2 instance with ubuntu operating system and mount gp2 ebs volume to that ec2.&lt;/p&gt;

&lt;p&gt;EC2 instance is using non Nitro System or non NVMe volume&lt;/p&gt;

&lt;p&gt;The scenario is, i have existing ebs volume with size 10 GB then i want to extend the volume to 20 GB&lt;/p&gt;

&lt;p&gt;Here are few configuration steps to extend linux ebs volume:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Verify existing disk usage. Type &lt;code&gt;df -hT&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--jXsFDlSq--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/d00f1hqkh5fag886tay5.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--jXsFDlSq--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/d00f1hqkh5fag886tay5.jpg" alt="Alt Text" width="611" height="263"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Verify existing block device. Type &lt;code&gt;lsblk&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--oGgbDQQR--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/m5mjyrdmuvl8uth5pbmh.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--oGgbDQQR--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/m5mjyrdmuvl8uth5pbmh.jpg" alt="Alt Text" width="497" height="199"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Based on example existing configuration, disk space is configured with 10 GB in size.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Go to aws console. Go to menu EC2 &amp;gt; Elastic Block Store &amp;gt; Volumes. Click on the block store that want to be extended&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--73IdLrNr--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/drmzwns12lh7g8ke42q1.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--73IdLrNr--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/drmzwns12lh7g8ke42q1.jpg" alt="Alt Text" width="800" height="336"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;To prevent any unwanted issues, you can optionally create a snapshot for that ebs. Go to menu Actions &amp;gt; Create Snapshot&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--QLrL0mbS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/6kamuw7onfput4maays3.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--QLrL0mbS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/6kamuw7onfput4maays3.jpg" alt="Alt Text" width="545" height="319"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Configure snapshot description and tag (optional). After that, click Create Snapshot&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--iYRDuyrl--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/q2o74n1ftbpzu6ki40w8.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--iYRDuyrl--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/q2o74n1ftbpzu6ki40w8.jpg" alt="Alt Text" width="800" height="344"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Wait until create snapshot request succeeded, then click Close&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--snKJubEW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/9hiuh0ghz2uubr4o7k1f.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--snKJubEW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/9hiuh0ghz2uubr4o7k1f.jpg" alt="Alt Text" width="800" height="289"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Verify snapshot has been successfully created. Go to menu Elastic Block Store &amp;gt; Snapshot. Then verify&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--QPdAZxET--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/w48v1856sipkcv979hbt.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--QPdAZxET--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/w48v1856sipkcv979hbt.jpg" alt="Alt Text" width="800" height="341"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Then, you can modify your EBS volume. Go to menu Elastic Block Store &amp;gt; Volumes. Click on the volume you want to extend. Then click Actions &amp;gt; Modify Volume&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--dGIbXwTt--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/gqtrndf1k1vtysriq1p0.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--dGIbXwTt--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/gqtrndf1k1vtysriq1p0.jpg" alt="Alt Text" width="800" height="471"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Modify volume size, after that click Modify&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--rtkK6DGC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/p7mltlxqap6w2n800ghm.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--rtkK6DGC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/p7mltlxqap6w2n800ghm.jpg" alt="Alt Text" width="700" height="434"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Modify volume confirmation page will be prompted. Click Yes to continue&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--FFY8RJ3s--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/gw1ctgxhb1q4d7ybd12t.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--FFY8RJ3s--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/gw1ctgxhb1q4d7ybd12t.jpg" alt="Alt Text" width="685" height="309"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Wait until modify volume request succeeded&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--PhBMBNl0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/f9jyqnrr05o6fxmv0u6g.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--PhBMBNl0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/f9jyqnrr05o6fxmv0u6g.jpg" alt="Alt Text" width="695" height="223"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Verify volume has been modified&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--7sdQuSld--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/pq0tdslzqrv07ccl4h7p.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--7sdQuSld--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/pq0tdslzqrv07ccl4h7p.jpg" alt="Alt Text" width="578" height="311"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;SSH to your EC2 instance. Type this command:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;sudo growpart [block_number]&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;in this example, the command should be:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;sudo growpart /dev/xvda 1&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--z8vpBV3n--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/g6qzql31n53z4lqny7ct.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--z8vpBV3n--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/g6qzql31n53z4lqny7ct.jpg" alt="Alt Text" width="774" height="37"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Verify block device size has been extended&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--mfgl8wug--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/xh0qxltxph94dq63rbi0.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--mfgl8wug--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/xh0qxltxph94dq63rbi0.jpg" alt="Alt Text" width="498" height="198"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Resize your block device to new size. Type this command:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;sudo resize2fs [block_number]&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;in this example, the command should be:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;sudo resize2fs /dev/xvda1&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--LnE408Nv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/cwi00c306wv2ryb2gs5a.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--LnE408Nv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/cwi00c306wv2ryb2gs5a.jpg" alt="Alt Text" width="553" height="90"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Verify your disk space has been extended&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--7MjwqLvp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/vjxa5t12rgwwnyzqlac0.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--7MjwqLvp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/vjxa5t12rgwwnyzqlac0.jpg" alt="Alt Text" width="607" height="263"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;For further reference you can also check aws documentation on this link:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/recognize-expanded-volume-linux.html"&gt;Link&lt;/a&gt;&lt;/p&gt;

</description>
      <category>aws</category>
      <category>ebs</category>
      <category>volume</category>
      <category>linux</category>
    </item>
  </channel>
</rss>
