Provision EC2 instance with Terraform
This Workflow allows you to gather information about the resources, scaffold a new repository, create a new Terraform workspace, create an entity in your Cortex workspace, then send a message to Slack to confirm that the EC2 instance has been created.
How to use a Cortex Workflow to provision an EC2 instance with Terraform
Considerations
This Workflow makes HTTP calls to Terraform Cloud, but it is possible to call other Terraform orchestrators, such as Spacelift.
This Workflow demonstrates how to create a PR, but if you are using PR automation such as Atlantis, then you do not need to include the Async HTTP call to Plan and Apply.
Step 1: Register the Scaffolder template in Cortex
Follow the instructions to register the Scaffolder template in Cortex. Use the following template:
Cookiecutter template
Save the JSON template below to register in Cortex:
{
"project_name" :"new-vm",
"resource_name": "my-ec2-instance",
"region": [ "us-east-1","us-east-2", "us-west-1","us-west-2"],
"instance_type": [ "t2.micro", "t2.medium","t2.large"],
"version": "0.2"
}Step 2: Start creating the Workflow
Follow the steps in the documentation to create a Workflow and configure its basic settings.
Step 3: Add blocks to the Workflow
The instructions on this page describe how to create this Workflow in the Cortex UI, but it is also possible to copy the Workflow YAML and add it to your workspace via the Cortex CLI. This allows you to quickly set up the example configuration then iterate on it for your own use case. Expand the tile below to learn more.
Workflow YAML instructions
To upload the Workflow example YAML into your workspace:
Save the Workflow example YAML file below:
Use the Cortex CLI to run this command, using the path to your Workflow YAML file:
cortex workflows create -f <path-to-your-workflow.yaml>
Expand the tiles below to learn about each block in this Workflow and how to configure them in the Cortex UI:
User input
In this example, we add a User Input block to gather resource details from the user. For the resource size and region, the user can select from the options configured here.
Click + in the center of the page. In the block library modal, choose User input.
In the block configuration side panel, enter a name and unique slug for this block.
In this example, we use the name
Resource detailsand the slugresource-details.
Click +Add user input. Add the following:
Name: Resource Name
Key: resource-name
Type: Text
Placeholder: my-ec2-instance
Click Add input.
Click +Add user input. Add the following:
Name: Resource Size
Key: resource-size
Type: Select
Data source: Manual
Placeholder: In this example, the resource size options are t2.micro, t2.medium, and t2.large.
Click Add input.
Click +Add user input. Add the following:
Name: Resource Region
Key: resource-region
Type: Select
Data source: Manual
Placeholder: In this example, the region options are us-east-1, us-east-2, us-west-1, and us-west-2.
Click Add input.
At the bottom of the side panel, click Save.
Data transformations
In this Workflow, we use two Data transformation blocks to reshape the data before scaffolding:
Create a data transformation to lowercase the resource name:
Click + in the center of the page. In the block library modal, choose Data transformation.
In the block configuration side panel, enter a name and unique slug for this block.
In this example, we use the name
Slugify Resource Nameand the slugslugify-resource-name.
Add a jq expression to take the output of the previous action, then downcase its characters:
At the bottom of the side panel, click Save.
Create a second data transformation to get GitHub details:
Click + in the center of the page. In the block library modal, choose Data transformation.
In the block configuration side panel, enter a name and unique slug for this block.
In this example, we use the name
Getting GitHub detailsand the sluggetting-github-details.
Add a jq expression to take the output of the previous action, and use that to create a PR name and branch name:
At the bottom of the side panel, click Save.
Scaffolder
This block creates a new repository in your connected Git integration, using templating to apply the outputs of previous blocks to the Scaffolder configuration.
Click + in the center of the page. In the block library modal, select the Scaffolder block.
In the side panel, enter a name and unique slug for the block.
In this example, we use the name
Scaffold Git Repoand the slugscaffold-git-repo.
Under Scaffolder template, select your template. In this example, we use the
New EC2 Instancetemplate.Select the option to Create a new repo.
Add override variables. The Variable dropdown pulls in all the variables that are able to be overridden in the Git provider and in the Scaffolder template. In this example, we apply the following overrides:
resource_name:
actions.slugify-resource-name.outputs.resultThis overrides it with the output of the "Slugify resource name" block earlier in the Workflow.
region:
actions.resource-details.outputs.resource-regionThis overrides it with the output of the resource region chosen during the "Resource details" block earlier in the Workflow.
instance_type:
actions.resource-details.outputs.resource-sizeThis overrides it with the output of the resource size chosen during the "Resource details" block earlier in the Workflow.
publisherRepoName:
actions.slugify-resource-name.outputs.resultThis overrides it with the output of the "Slugify resource name" earlier in the Workflow.
publisherPullRequestTitle:
actions.getting-github-details.outputs.result.pr_nameThis overrides it with the pr_name output from the "Getting GitHub details" block earlier in the Workflow.
publisherBranch:
actions.getting-github-details.outputs.result.branch_nameThis overrides it with the branch_name output from the "Getting GitHub details" block earlier in the Workflow.
publisherRepoFullName:
actions.getting-github-details.outputs.result.repo_nameThis overrides it with the repo_name output from the "Getting GitHub details" block earlier in the Workflow.
publisherCommitMessage:
actions.getting-github-details.outputs.result.commit_msgThis overrides it with the commit_msg output from the "Getting GitHub details" block earlier in the Workflow.
project_name:
actions.slugify-resource-name.outputs.resultThis overrides it with the output from the "Slugify resource name" block earlier in the Workflow.
publisherPullRequestBody:
actions.getting-github-details.outputs.result.pr_nameThis overrides it with the pr_name output from the "Getting GitHub details" block earlier in the Workflow.
At the bottom of the side panel, click Save.
GitHub merge branch
This block sets the head branch name and merges it.
Click + in the center of the page. In the block library modal, select the GitHub > Merge a branch block.
In the side panel, enter a name and unique slug for the block.
In this example, we use the name
Merge a branchand the slugmerge-a-branch.
Configure the block:
Repository: Enter your repository name
Base branch: Enter the name of the branch into which changes will be merged, e.g.
main.Head branch: Enter the name of the head branch containing the changes to merge.
In our example, we use the following template to pull the "branch name" output from the earlier Data transformation step whose slug is
getting-github-details:{{actions.getting-github-details.outputs.result.branch_name}}
Commit message: Optionally enter a commit message.
At the bottom of the side panel, click Save.
HTTP requests
There are three HTTP requests that perform the following actions: Create a workspace in Terraform, add the AWS access key environment variable, and add the AWS secret key environment variable.
Create a workspace in Terraform
Click + in the center of the page. In the block library modal, select the HTTP request block.
In the side panel, enter a name and unique slug for the block.
In this example, we use the name
Create workspaceand the slugcreate-workspace.
Configure the block:
HTTP method: POST
URL: In our example, we set this to:
https://app.terraform.io/api/v2/organizations/{{context.secrets.tf_organization}}/workspaces/Headers: Set the following headers:
Content-Type:application/vnd.api+jsonAuthorization:Bearer {{ context.secrets.tf_token }}
Payload: In our example, we enter the following:
Save the block.
Add the AWS access key environment variable
Click + in the center of the page. In the block library modal, select the HTTP request block.
In the side panel, enter a name and unique slug for the block.
In this example we use the name
Add AWS Access Key environment variableand the slugadd-aws-access-key-environment-variable.
Configure the block:
HTTP method: POST
URL: In our example, we set this to:
https://app.terraform.io/api/v2/workspaces/{{ actions.create-workspace.outputs.body.data.id }}/varsHeaders: Set the following headers:
Content-Type:application/vnd.api+jsonAuthorization:Bearer {{ context.secrets.tf_token }}
Payload: In our example, we enter the following:
Save the block.
Add the AWS secret key environment variable
Click + in the center of the page. In the block library modal, select the HTTP request block.
In the side panel, enter a name and unique slug for the block.
In this example we use the name
Add AWS Secret Key environment variableand the slugadd-aws-secret-key-environment-variable.
Configure the block:
HTTP method: POST
URL: In our example, we set this to:
https://app.terraform.io/api/v2/workspaces/{{ actions.create-workspace.outputs.body.data.id }}/varsHeaders: Set the following headers:
Content-Type:application/vnd.api+jsonAuthorization:Bearer {{ context.secrets.tf_token }}
Payload: In our example, we enter the following:
Save the block.
Async HTTP request
Note: If you are using PR automation such as Atlantis, then you do not need to include this HTTP call to Plan and Apply.
Click + in the center of the page. In the block library modal, select the Async HTTP request block.
In the side panel, enter a name and unique slug for the block.
In this example we use the name
Plan and Applyand the slugplan-and-apply.
Configure the block:
HTTP method: POST
URL: In our example, we set this to:
https://app.terraform.io/api/v2/runsHeaders: Set the following headers:
Content-Type:application/vnd.api+jsonAuthorization:Bearer {{ context.secrets.tf_token }}
Timeout: 5 minutes
Payload: In our example, we enter the following:
Save the block.
Data transformations
This four data transformations take output from previous blocks then parse the ARN, get the EC2 ID, get the AWS region, and get the AWS account.
Parse the ARN
Click + in the center of the page. In the block library modal, select the Data transformation block.
In the side panel, enter a name and unique slug for the block.
In this example we use the name
Parse arnand the slugparse-arn.
Enter a jq expression:
Save the block.
Get EC2 ID
Click + in the center of the page. In the block library modal, select the Data transformation block.
In the side panel, enter a name and unique slug for the block.
In this example we use the name
Get EC2 IDand the slugget-ec2-id.
Enter a jq expression:
Save the block.
Get region
Click + in the center of the page. In the block library modal, select the Data transformation block.
In the side panel, enter a name and unique slug for the block.
In this example we use the name
Get regionand the slugget-region.
Enter a jq expression:
Save the block.
Get AWS account
Click + in the center of the page. In the block library modal, select the Data transformation block.
In the side panel, enter a name and unique slug for the block.
In this example we use the name
Get AWS accountand the slugget-aws-account.
Enter a jq expression:
Save the block.
Create or patch entity
In this step, we use the output of previous blocks to create a new entity in Cortex.
Click + in the center of the page. In the block library modal, select the Create or patch entity block.
In the side panel, enter a name and unique slug for the block.
In this example we use the name
Add entity to catalogand the slugadd-entity-to-catalog.
Under descriptor, enter the following:
Send Slack message
In this step, we use the output of previous steps to send a templated message via Slack informing the user that their EC2 instance has been created..
Click + in the center of the page. In the block library modal, select the Slack block.
In the side panel, enter a name and unique slug for the block.
In this example we use the name
Send messageand the slugsend-message.
Select a Slack channel name.
Enter text for the message that will be sent via Slack. In our example, we use the following:
Save the block.
Step 4: Run the Workflow
When you run the Workflow, the following events happen:
The Workflow pauses to collect responses from the user during the User Input step.
The Data transformation steps reshape the responses, then that reformatted data is used to create a repository during the Scaffolder step.
A new Terraform workspace is created, and the AWS access key and secret key variables are included. The async HTTP request block triggers the planning and applying process in Terraform.
The data is transformed, and the reformatted data is used to create an entity in Cortex.
A message is sent in Slack to confirm that the EC2 instance has been provisioned. It includes a link to the EC2 instance and a link to the newly-created entity in Cortex:

The entity in Cortex is connected to the repository and to the Terraform workspace.
Last updated
Was this helpful?