Appearance
Terraform
Infraetructura como código multi-plataforma
Terraform es una herramienta, con versión Open Source, para infraestructura como código que nos habilita variedad de proveedores, incluyendo AWS, GPC, OCI y más. Para definir la infraestrctura como código se utilizan archivos con formato JSON o HCL (formato propio similar a Groovy, siendo el modo más sencillo para trabajar con Terraform).
Instalación de Terraform
En Windows se puede instalar Terraform si tienes un gestor de paquetes como Chocolatey, ejecutando:
powershell
choco install terraformTambién se podría usar Scoop con el comando:
scoop install main/terraform
Para macOS podemos usar Homebrew ejecutando desde la línea de comandos lo siguiente:
bash
brew install hashicorp/tap/terraformEn Linux Ubuntu/Debian se puede instalar con los siguientes comandos:
bash
sudo apt update
sudo apt install -y gnupg software-properties-common
curl https://apt.releases.hashicorp.com/gpg | gpg --dearmor > hashicorp.gpg
sudo install -o root -g root -m 644 hashicorp.gpg /etc/apt/trusted.gpg.d/
sudo apt-add-repository "deb [arch=$(dpkg --print-architecture)] https://apt.releases.hashicorp.com $(lsb_release -cs) main"
sudo apt install terraform
terraform --versionnos permite verificar la versión instalada
Iniciando con la CLI de Terraform
Si queremos combinar Terraform con un proveedor como AWS, debemos primero configurar la CLI de AWS, siendo prerrequisito que puedes revisar en tu entorno. También podríamos utilizar LocalStack de modo que obtengamos un entorno local simulado para AWS.
Para inicializar un proyecto con Terraform, dentro de la carpeta correspondiente, ejecutaríamos:
bash
terraform init
initse usa inicializará nuestro proyecto a partir de algún archivomain.tf(que veremos a continuación).
El flujo de Terraform se basa principalmente en los comandos:init,plan,apply,destroy
Creamos entonces un archivo main.tf para y definimos el proveedor, por ejemplo:
groovy
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 4"
}
}
}
provider "aws" {
region = "us-east-1"
}Si conoces algo de Gradle o el lenguaje Groovy puede observarse su semejanza. Se definen ciertas secciones o bloques declarativos (terraform, provider, resource, variable, output, local, data) con ciertos valores necesarios, Terraform hace la magia.
Puede ser conveniente incluir bajo el bloque terraform la version requerida, por ejemplo: required_version = "1.4.6"
Para uso local de un plan es posible incorporar bajo el bloque terraform la especificación backend "local" {}, por ejemplo:
groovy
terraform {
backend "local" {}
}Se recomienda definir un archivo para las variables, por ejemplo:
groovy
variable "aws_region" {
default = "us-east-1"
}
variable "file" {
default = ["~/.aws/credentials"]
}Si tuvieramos un recurso, podemos definir este en otro archivo con un contenido como el siguiente:
groovy
resource "aws_s3_bucket" "devops" {
bucket = "x"
for_destroy = false
tags = {
responsible = "Infra"
}
}Un ejemplo sobre un recurso para Lamdas sería:
groovy
resource "aws_lambda_function" "draft" {
function_name = "workshop"
role = aws_iam_role.lambdarole.arn
runtime = "nodejs16.x"
handler = "index.handler"
filename = "index.zip"
source_code_hah = filebase64sha256 ("index.zip")
}
resource "aws_iam_role" "lambdarole" {
name = "lambda-role"
asume_role_policy = <<POLICY
{
}
POLICY
}
resource "aws_lambda_function_url" "name" {
function_name = aws_lambda_function.draft.function_name
authorization_type = "NONE"
}
output "aws_lambda_function_url" {
value = aws_lambda_function_url
}
outputes un tipo de variable que se usa, por ejemplo, para exponer un dato en otras configuraciones de Terraform.
Es posible validar el archivo ejecutando:terraform validate
A partir de lo anterior se debe establecer un plan de aprovisionamiento. Se puede lanzar un plan así:
bash
terraform plan -out=iac.tfplan
iac.tfplancorresponde al nombre asignado (IaC significa: Infraestructure as Code).
Comunmente suele usarseterraform plan -out=tfplan
Y para aplicarlo, es decir, para desplegar nuestro plan ejecutamos:
bash
terraform apply "iac.tfplan"Si el nombre fuera
tfplanno necesita especificarse enapply
Alternativa usando LocalStack
LocalStack provee un entorno local y simulado de AWS. Si se tiene LocalStack debidamente instalado y corriendo, es posible incorporar el uso del módulo tflocal (ejecutando: pip3 install terraform-local). Sin embargo, realizaremos la configuración manual siguiendo ciertas pautas. Para empezar definiendo como proveedor AWS en el bloque respectivo, logrando un código como el siguiente:
groovy
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 4"
}
}
backend "local" {}
}
provider "aws" {
region = "us-east-1"
access_key = "test"
secret_key = "test"
skip_region_validation = true
skip_credentials_validation = true
skip_requesting_account_id = true
skip_metadata_api_check = true
skip_get_ec2_platforms = true
s3_use_path_style = true
endpoints {
apigateway = "http://localhost:4566"
apigatewayv2 = "http://localhost:4566"
cloudformation = "http://localhost:4566"
cloudwatch = "http://localhost:4566"
cloudwatchlogs = "http://localhost:4566"
dynamodb = "http://localhost:4566"
iam = "http://localhost:4566"
lambda = "http://localhost:4566"
s3 = "http://s3.localhost.localstack.cloud:4566"
secretsmanager = "http://localhost:4566"
ses = "http://localhost:4566"
sns = "http://localhost:4566"
sqs = "http://localhost:4566"
sts = "http://localhost:4566"
}
}Con esta configuración habilitamos el entorno para LocalStack en buena medida. Nótese que se incluye el bloque
endpoints
Expresiones y Control de Flujo
- Las variables se pueden referenciar dentro de un dato usando el signo pesos y llaves con el objeto
var., por ejemplo:${var.my_var} - También se pueden asignar variables directamente cuando el valor es tal cual se espera, por ejemplo:
argument = var.my_var - Existen condicionales expresados con un operador ternario, semejante a Javascript, por ejemplo:
var.my_var == "" ? "true_value" : "false_value" - Se puede usar el bucle o iterador
forcon objetos, por ejemplo así:{for x in var.array : x => upper(x)}ó[for x in var.array : upper(x)] - Se puede usar el bucle o iterador
forcon tuplas, por ejemplo así:[for k, v in var.map : upper(v)]
Usando Data en Terraform
Normalmente usamos el bloque resource para definir y establecer infraestructura con Terraform. Si lo que se busca es determinar infraestructura ya disponile o previamente aprovisionada, no necesitamos establecer un recurso sino consultarlo para asociarlo o referirlo en algún otro componente.
Veamos un ejemplo consultando una VPC en AWS, para ello tendremos un archivo main.tf con un contenido como el siguiente:
groovy
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "5.0.1"
}
}
required_version = ">= 1.4.6"
}
provider "aws" {
region = local.aws_region
shared_config_files = ["~/.aws/config"]
shared_credentials_files = ["~/.aws/credentials"]
profile = local.aws_profile
}
data "aws_vpcs" "my_vpc" {
tags = {
Name = local.vpc_name
}
}
data "aws_subnets" "my_subnets" {
filter {
name = "vpc-id"
values = [data.aws_vpcs.my_vpc.ids[0]]
}
}
output "vpc_id" {
value = data.aws_vpcs.my_vpc.ids[0]
}
output "subnet_ids" {
value = data.aws_subnets.my_subnets.ids
}En el anterior código podemos identificar lo siguiente:
- Usamos
datapara obtener el identificador de la VPC a partir del nombre - Con el identificador de la VPC se pueden consultar también las subredes
- Usamos
outputpara visualizar los valores obtenidos - En este ejemplo, hemos establecido en el bloque
providervalores parashared_config_files,shared_credentials_filesyprofile - Nos faltaría agregar el archivo de variables
locals.tfa continuación...
groovy
locals {
aws_region = "us-east-1"
aws_profile = "default"
vpc_name = "my-global-vpc"
}Usando Inputs y el archivo terraform.tfvars
Podemos seguir una idea semejante al anterior ejemplo pero definiendo inputs y, en lugar de locals, y estableciendo los valores para esas variables mediente el archivo terraform.tfvars.
Veamos un ejemplo para el archivo inputs.tf:
groovy
variable "aws_region" {
type = string
description = "Specified AWS Region"
}
variable "aws_profile" {
type = string
description = "AWS Profile to use"
}
variable "vpc_name" {
type = string
description = "Name for Global VPC"
}
variable "routing_table_name" {
type = string
description = "Name for Global Routing Table"
}
variable "internet_gateway_name" {
type = string
description = "Name for Global Internet Gateway"
}
variable "public_subnet_name_a" {
type = string
description = "Name for Public Subnet A"
}
variable "public_subnet_name_b" {
type = string
description = "Name for Public Subnet B"
}
variable "private_subnet_name_a" {
type = string
description = "Name for Private Subnet A"
}
variable "private_subnet_name_b" {
type = string
description = "Name for Private Subnet B"
}En un archivo terraform.tfvars asignamos los valors así:
ini
aws_region = "us-east-1"
aws_profile = "default"
vpc_name = "global-vpc"
public_subnet_name_a = "public-net-a"
public_subnet_name_b = "public-net-b"
private_subnet_name_a = "private-net-a"
private_subnet_name_b = "private-net-b"
routing_table_name = "global-rtb"
internet_gateway_name = "global-igw"El archivo main.tf tendrá un código como el siguiente:
groovy
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "5.0.1"
}
}
required_version = ">= 1.4.6"
}
provider "aws" {
region = var.aws_region
shared_config_files = ["~/.aws/config"]
shared_credentials_files = ["~/.aws/credentials"]
profile = var.aws_profile
}
data "aws_vpcs" "existing_vpc" {
tags = {
Name = var.vpc_name
}
}
data "aws_route_tables" "existing_route_table" {
vpc_id = data.aws_vpcs.existing_vpc.ids[0]
tags = {
Name = var.routing_table_name
}
}
data "aws_internet_gateway" "existing_igw" {
tags = {
Name = var.internet_gateway_name
}
}
data "aws_subnets" "existing_public_subnets_a" {
filter {
name = "vpc-id"
values = [data.aws_vpcs.existing_vpc.ids[0]]
}
tags = {
Name = var.public_subnet_name_a
}
}
data "aws_subnets" "existing_public_subnets_b" {
filter {
name = "vpc-id"
values = [data.aws_vpcs.existing_vpc.ids[0]]
}
tags = {
Name = var.public_subnet_name_b
}
}
data "aws_subnets" "existing_private_subnets_a" {
filter {
name = "vpc-id"
values = [data.aws_vpcs.existing_vpc.ids[0]]
}
tags = {
Name = var.private_subnet_name_a
}
}
data "aws_subnets" "existing_private_subnets_b" {
filter {
name = "vpc-id"
values = [data.aws_vpcs.existing_vpc.ids[0]]
}
tags = {
Name = var.private_subnet_name_b
}
}
output "vpc_id" {
value = data.aws_vpcs.existing_vpc.ids[0]
}
output "rtb_id" {
value = data.aws_route_tables.existing_route_table.ids[0]
}
output "igw_id" {
value = data.aws_internet_gateway.existing_igw.id
}
output "public_subnet_ids" {
value = [data.aws_subnets.existing_public_subnets_a.ids[0],data.aws_subnets.existing_public_subnets_b.ids[0]]
}
output "private_subnet_ids" {
value = [data.aws_subnets.existing_private_subnets_a.ids[0],data.aws_subnets.existing_private_subnets_b.ids[0]]
}Ejemplo de Terraform con AWS AppRunner
En el siguiene ejercicio se configura en el archivo main.f un "backend" (el archivo de almacenamiento de terraform) con AWS S3. Además, usaremos AWS App Runner como servicio Serverless para una aplicación cuyos fuentes se encuentran en GitHub.
groovy
provider "aws" {
region = "us-east-1"
}
terraform {
backend "s3" {
bucket = "tfstate-demo-2023"
key = "terraform.tfstate"
region = "us-east-1"
encrypt = true
shared_credentials_file = "./iac/.secretaws"
}
}
resource "aws_iam_role" "apprunner_role" {
name = "AppRunnerRole"
assume_role_policy = jsonencode({
Version = "2012-10-17",
Statement = [
{
Action = "sts:AssumeRole",
Effect = "Allow",
Principal = {
Service = "apprunner.amazonaws.com",
},
},
],
})
}
resource "aws_apprunner_service" "my_drone_service" {
service_name = "MyDroneService"
source_configuration {
authentication_configuration {
connection_arn = "arn:aws:apprunner:us-east-1:117979987706:connection/cicd-repo/d940c059ccdd4466a82f95b50e4cdec3"
}
auto_deployments_enabled = false
code_repository {
repository_url = "https://github.com/kaesar/cicddemo"
source_code_version {
type = "BRANCH"
value = "main"
}
code_configuration {
configuration_source = "API"
code_configuration_values {
build_command = "npm install && npm run build"
start_command = "npm start"
port = "3000"
runtime = "NODEJS_16"
}
}
}
}
health_check_configuration {
path = "/health"
}
}Si usamos la imagen desde AWS ECR, nuestro ejemplo de AWS AppRunner quedaría como el siguiente código:
groovy
provider "aws" {
region = "us-east-1"
}
terraform {
required_version = "~>1.4"
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
}
backend "s3" {
bucket = "tfstate-demo-2023"
key = "terraform.tfstate"
region = "us-east-1"
encrypt = true
shared_credentials_file = "./iac/.secretaws"
}
}
data "aws_iam_policy_document" "assume_role_policy" {
statement {
actions = ["sts:AssumeRole"]
principals {
type = "Service"
identifiers = ["apprunner.amazonaws.com"]
}
}
}
resource "aws_iam_role" "apprunner_role" {
name = "AppRunnerRole"
assume_role_policy = data.aws_iam_policy_document.assume_role_policy.json
}
resource "aws_iam_role_policy_attachment" "apprunner_role_policy" {
role = aws_iam_role.apprunner_role.name
policy_arn = "arn:aws:iam::aws:policy/service-role/AWSAppRunnerServicePolicyForECRAccess"
}
resource "aws_apprunner_service" "my_drone_service" {
depends_on = [aws_iam_role.apprunner_role]
service_name = "MyDroneService"
source_configuration {
authentication_configuration {
access_role_arn = aws_iam_role.apprunner_role.arn
}
auto_deployments_enabled = false
image_repository {
image_identifier = "117979987706.dkr.ecr.us-east-1.amazonaws.com/cicd-hub:v1"
image_repository_type = "ECR"
image_configuration {
port = "3000"
}
}
}
health_check_configuration {
path = "/health"
}
}
output "service_url" {
value = aws_apprunner_service.my_drone_service.service_url
}Es posible que se requiera usar
terraform applydos (2) veces para crear el servicio
Ejemplo de Terraform con ECS/Fargate
Si queremos usar en lugar de App Runner el servicio ECS/Fargate. Dado que se requieren involucrar más componentes podríamos considerar los siguientes archivos:
main.tflocals.tfinputs.tfterraform.tfvarsecs_cluster.tfecs_task_definition.tfvpc.tfsecurity-groups.tfiam.tf
Veamos a continuación el contenido de ejemplo del archivo main.tf
groovy
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "5.0.1"
}
}
required_version = ">= 1.4.6"
}
provider "aws" {
region = var.aws_region
shared_config_files = ["~/.aws/config"]
shared_credentials_files = ["~/.aws/credentials"]
profile = var.aws_profile
default_tags {
tags = var.tags
}
}En este caso usamos
provider(AWS) conaws_profilemediante una variable.
Las varialbes de entrada las definimos en inputs.tf así:
groovy
variable "aws_account_id" {
description = "AWS Account ID"
type = string
}
variable "aws_region" {
type = string
description = "Specified AWS Region"
}
variable "aws_profile" {
type = string
description = "AWS Profile to use"
}
variable "tags" {
type = map(string)
description = "Default tags to be used in the project"
}
variable "project_name" {
type = string
description = "Specified Project Name"
}
## VPC
variable "vpc_block_cidr" {
type = string
description = "Specified CIDR Block for Global VPC"
}
variable "availability_zones" {
type = list(string)
description = "List of availability zones"
}
variable "public_subnets" {
type = list(string)
description = "List of Public Subnets"
}En locals.tf establecemos lo siguiente:
groovy
locals {
stack_name = var.project_name
container_image = "123456789012.dkr.ecr.us-east-1.amazonaws.com/myservice:v1"
}Podemos asignar los valores a las variables con el archivo terraform.tfvars así:
ini
# Default variables
aws_account_id = "123456789012"
aws_region = "us-east-1"
aws_profile = "Developer-Role"
tags = {
"Environment" = "develop"
"IaC" = "Terraform CLI"
"Owner" = "user"
"Service" = "ECS"
}
project_name = "example"
## VPC
vpc_block_cidr = "172.31.0.0/16"
availability_zones = ["us-east-1a", "us-east-1b"]
public_subnets = ["172.31.80.0/20", "172.31.16.0/20"]En ecs_cluster tendríamos un código como el siguiente:
groovy
resource "aws_ecs_cluster" "ecs_cluster" {
name = "${local.stack_name}-ecs-cluster"
depends_on = [aws_internet_gateway.igw]
setting { # Need to be Enable to get Metrics from Task Executions
name = "containerInsights"
value = "enabled"
}
}En ecs_task_definition...
groovy
resource "aws_ecs_task_definition" "ecs_task_definition" {
family = "${local.stack_name}-ecs-task-definition"
requires_compatibilities = ["FARGATE"]
network_mode = "awsvpc"
cpu = 1024
memory = 2048
task_role_arn = aws_iam_role.ecs_task_role.arn
execution_role_arn = aws_iam_role.ecs_task_execution_role.arn
container_definitions = <<TASK_DEFINITION
[
{
"name": "webcontainer",
"image": "${local.container_image}",
"cpu": 1024,
"memory": 2048,
"essential": true,
"logConfiguration": {
"logDriver": "awslogs",
"options": {
"awslogs-group": "${aws_cloudwatch_log_group.cw_log_grp_update_client_ecs.id}",
"awslogs-region": "${var.aws_region}",
"awslogs-stream-prefix": "ecs"
}
},
"portMappings": [
{
"containerPort": 8080,
"hostPort": 8080
}
]
}
]
TASK_DEFINITION
}En vpc...
groovy
# VPC
resource "aws_vpc" "main" {
cidr_block = var.vpc_block_cidr
enable_dns_support = "true"
enable_dns_hostnames = "true"
tags = {
Name = "${local.stack_name}-vpc"
}
}
# Internet Gateway
resource "aws_internet_gateway" "igw" {
vpc_id = aws_vpc.main.id
tags = {
Name = "${local.stack_name}-igw"
}
}
# Subnets
resource "aws_subnet" "main_subnet_public" {
vpc_id = aws_vpc.main.id
count = length(var.public_subnets)
cidr_block = element(var.public_subnets, count.index)
availability_zone = element(var.availability_zones, count.index)
map_public_ip_on_launch = true
depends_on = [aws_internet_gateway.igw]
tags = {
Name = "${local.stack_name}-subnet-public"
}
}
# Route Tables
resource "aws_route_table" "public" {
vpc_id = aws_vpc.main.id
tags = {
Name = "${local.stack_name}-routing-table-public"
}
}
resource "aws_route" "public" {
route_table_id = aws_route_table.public.id
destination_cidr_block = "0.0.0.0/0"
gateway_id = aws_internet_gateway.igw.id
}
resource "aws_route_table_association" "public" {
count = length(var.public_subnets)
subnet_id = element(aws_subnet.main_subnet_public.*.id, count.index)
route_table_id = aws_route_table.public.id
}En security-groups...
groovy
resource "aws_security_group" "sg" {
name = "${local.stack_name}-sg"
vpc_id = aws_vpc.main.id
ingress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
ipv6_cidr_blocks = ["::/0"]
}
}En iam...
groovy
resource "aws_iam_role" "ecs_task_execution_role" {
name = "${local.stack_name}-ecs-task-execution-role"
managed_policy_arns = ["arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy"]
assume_role_policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Action = "sts:AssumeRole"
Effect = "Allow"
Sid = ""
Principal = {
Service = "ecs-tasks.amazonaws.com"
}
},
]
})
}
resource "aws_iam_role" "ecs_task_role" {
name = "${local.stack_name}-ecs-task-role"
managed_policy_arns = [
"arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy"
]
assume_role_policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Action = "sts:AssumeRole"
Effect = "Allow"
Sid = ""
Principal = {
Service = "ecs-tasks.amazonaws.com"
}
}
]
})
}
resource "aws_iam_role" "eventbridge_invoke_ecs_role" {
name = "${local.stack_name}-eventbridge-invoke-ecs-role"
managed_policy_arns = [aws_iam_policy.eventbridge_invoke_ecs_policy.arn]
assume_role_policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Action = "sts:AssumeRole"
Effect = "Allow"
Sid = ""
Principal = {
Service = "events.amazonaws.com"
}
},
]
})
}
resource "aws_iam_policy" "eventbridge_invoke_ecs_policy" {
name = "${local.stack_name}-eventbridge-invoke-ecs-policy"
policy = jsonencode({
"Version" : "2012-10-17",
"Statement" : [
{
"Effect" : "Allow",
"Action" : [
"ecs:RunTask"
],
"Resource" : [
"${aws_ecs_task_definition.ecs_task_definition.arn}:*",
"${aws_ecs_task_definition.ecs_task_definition.arn}"
],
"Condition" : {
"ArnLike" : {
"ecs:cluster" : "${aws_ecs_cluster.ecs_cluster.arn}"
}
}
},
{
"Effect" : "Allow",
"Action" : "iam:PassRole",
"Resource" : [
"*"
],
"Condition" : {
"StringLike" : {
"iam:PassedToService" : "ecs-tasks.amazonaws.com"
}
}
}
]
})
}Ejemplo de Terraform con AWS EventBridge
En el siguiente ejercicio usaremos el archivo main.tf, acompañado de un archivo de variables inputs.tf, para definir reglas con EventBridge y API Destination. Veamos el archivo main.tf:
groovy
terraform {
#required_version = "1.4.4"
required_providers {
aws = {
source = "hashicorp/aws"
version = "4.59.0"
}
}
backend "local" {}
}
provider "aws" {
region = var.aws_region
}
resource "aws_iam_role" "eventbridge_role" {
name = "eventbridge-role"
assume_role_policy = jsonencode({
"Version" : "2012-10-17",
"Statement" : [{
"Effect" : "Allow",
"Principal" : {
"Service" : "events.amazonaws.com"
},
"Action" : "sts:AssumeRole"
}]
})
}
resource "aws_iam_policy" "eventbridge_policy" {
name = "eventbridge-policy"
policy = jsonencode({
"Version" : "2012-10-17",
"Statement" : [
{
"Effect" : "Allow",
"Action" : [
"events:PutRule",
"events:PutTargets",
"events:CreateConnection",
"events:CreateApiDestination"
],
"Resource" : "*"
},
{
"Effect" : "Allow",
"Action" : "events:InvokeApiDestination",
"Resource" : [
"arn:aws:events:us-east-1:${var.aws_id}:api-destination/${var.api_destination_name}-${var.env_name}/*"
]
}
]
})
}
resource "aws_iam_role_policy_attachment" "eventbridge_policy_attachment" {
role = aws_iam_role.eventbridge_role.name
policy_arn = aws_iam_policy.eventbridge_policy.arn
}
resource "aws_cloudwatch_event_rule" "events_put_rule" {
name = var.rule_name
description = "Regla para manejar evento"
event_bus_name = var.bus_name
event_pattern = jsonencode({
"detail-type" : [var.event_name]
})
tags = {
"Env" = var.env_name
"Owner" = "Platform"
}
}
resource "aws_cloudwatch_event_connection" "events_create_connection" {
name = "${var.connection_name}-${var.env_name}"
description = "Conexion para el API Destination evento 'cancelCard'"
authorization_type = "API_KEY"
auth_parameters {
api_key {
key = "x-api-key"
value = var.api_key
}
}
}
resource "aws_cloudwatch_event_api_destination" "events_create_api_destination" {
name = "${var.api_destination_name}-${var.env_name}"
description = "API Destination para 'cancelCard'"
connection_arn = aws_cloudwatch_event_connection.events_create_connection.arn
invocation_endpoint = var.api_destination_endpoint
http_method = "POST"
}
resource "aws_cloudwatch_event_target" "aws_events_put_targets" {
event_bus_name = var.bus_name
rule = aws_cloudwatch_event_rule.events_put_rule.name
target_id = "6c1ea055-a48c-44f0-a904-c3311512f244"
arn = aws_cloudwatch_event_api_destination.events_create_api_destination.arn
role_arn = "arn:aws:iam::${var.aws_id}:role/physicalcard-token-event-bridge-invoke-api-role-${var.env_name}"
}Y en el archivo inputs.tf tendremos un contenido como el siguiente:
groovy
variable "env_name" {
description = "Environment name"
type = string
default = "qa"
}
variable "bus_name" {
description = "Event bus name"
type = string
default = "Bus-QA"
}
variable "rule_name" {
description = "Rule name"
type = string
default = "physicalcard-token-event-message-cancelcard"
}
variable "event_name" {
description = "Event name"
type = string
default = "PHYSICALCARD.MPF0040_TOKEN_MANAGER.CANCELCARD"
}
variable "connection_name" {
description = "Connection name"
type = string
default = "conn-physicalcard-token-manager-cancelcard"
}
variable "api_destination_name" {
description = "API Destination name"
type = string
default = "api-physicalcard-token-manager-cancelcard"
}
variable "api_destination_endpoint" {
description = "API Destination endpoint"
type = string
// default = "https://subdomain.amazonaws.com/api/action"
}
variable "api_key" {
description = "API Key (de API Gateway)"
type = string
}
variable "aws_id" {
description = "AWS ID"
type = string
default = "123456789123"
}
variable "aws_region" {
description = "Region AWS"
type = string
default = "us-east-1"
}