# AWS Route53 Application Recovery Controller Module [Amazon Route53 Application Recovery Controller (Route 53 ARC)](https://aws.amazon.com/blogs/aws/amazon-route-53-application-recovery-controller/) is a set of Route 53 features that help you build applications with high availability. Route 53 ARC can continuously monitor your application's ability to recover from failure and control recovery across multiple AWS Availability Zones, AWS Regions, and on-premises environments. This Terraform module contains both Route 53 ARC readiness and recovery-cluster resources. You can deploy only the readiness resources, or both. For more information about creating a resilience strategy with Route 53 ARC, see [Running recovery-oriented applications with Amazon Route 53 Application Recovery Controller, AWS CI/CD tools, and Terraform](https://aws.amazon.com/blogs/networking-and-content-delivery/running-recovery-oriented-applications-with-amazon-route-53-application-recovery-controller-aws-ci-cd-tools-and-terraform/). ## Example Architecture

Example Deployment of app with R53 ARC

## Usage The primary configuration variable is `cells_definition`. With this variable, you specify the AWS resources per Region that you want Route 53 ARC to monitor. See [examples](https://github.com/aws-ia/terraform-aws-route53-recovery-controller/tree/main/examples/basic) for working examples. ### Readiness resources only The following `terraform.tfvars` values create a recovery group. The recovery group consists of Region cells `us-east-1` and `us-west-2`, each with a resource set of services `elasticloadbalancing`, `autoscaling`, `dynamodb`, and `ec2-volume` and their Amazon Resource Numbers (ARNs). Readiness checks are associated with each resource set. ```terraform name = "my-asg-elb-ddb-app" cells_definition = { us-east-1 = { elasticloadbalancing = autoscaling = dynamodb = ec2-volume = } us-west-2 = { elasticloadbalancing = autoscaling = dynamodb = ec2-volume = } } ``` ### Routing control cluster resources and Route 53 alias records To define a managed Route 53 ARC cluster for your application, add the following Terraform variables. ```terraform create_recovery_cluster = true hosted_zone = { name = "mycoolapp.com." } ``` The example shown configures the following: * A recovery cluster with a single control panel. * One routing control per Region. * Safety rules. The default is one, but you can declare more than one. * One Route 53 health check per routing control. * Route 53 alias records for each load balancer for the domain specified. Currently, this module supports active/passive for applications across Regions. The active Region is determined by your `provider` block or by `var.primary_cell_region`. (See "Inputs", later in this document.) ## Available services The R53 Readiness service supports monitoring many services, most of which have been implemented in this module or can easily be added / extended (even without a PR!). The service keys used in `var.cells_definition` must match a key in `var.resource_type_name` in [variables.tf](./variables.tf#L28) which links to the CloudFormation resource type that is accepted by Readiness service. Example: ```terraform variable "resource_type_name" { type = map(string) description = "list of all service types you can pass and their associated Resource Set Type." default = { apigateway = "AWS::ApiGatewayV2::Api" autoscaling = "AWS::AutoScaling::AutoScalingGroup" cloudwatch = "AWS::CloudWatch::Alarm" dynamodb = "AWS::DynamoDB::Table" ec2-volume = "AWS::EC2::Volume" ... } } ``` ### Adding a new service If a service does not exist in the default `var.resource_type_name` value you can include it without a PR. We also ask that you please do open a PR to include it in default value. Where you set your variables, simply define a new service key with the associated CloudFormation resource type. You must include all service keys that you plan to use in that root module. In the example below `new-service` is a new service that the Readiness can monitor. We add it to our local deployment and then use it immediately in `var.cells_definition`: ```terraform resource_type_name = { new-service = "AWS::NewService::NewAction" dynamodb = "AWS::DynamoDB::Table" ... } cells_definition = { = { new-service = } } ``` ## Requirements | Name | Version | |------|---------| | [terraform](#requirement\_terraform) | >= 0.15.0 | | [aws](#requirement\_aws) | >= 3.68 | ## Providers | Name | Version | |------|---------| | [aws.ap-northeast-1](#provider\_aws.ap-northeast-1) | >= 3.68 | | [aws.ap-northeast-2](#provider\_aws.ap-northeast-2) | >= 3.68 | | [aws.ap-northeast-3](#provider\_aws.ap-northeast-3) | >= 3.68 | | [aws.ap-south-1](#provider\_aws.ap-south-1) | >= 3.68 | | [aws.ap-southeast-1](#provider\_aws.ap-southeast-1) | >= 3.68 | | [aws.ap-southeast-2](#provider\_aws.ap-southeast-2) | >= 3.68 | | [aws.ca-central-1](#provider\_aws.ca-central-1) | >= 3.68 | | [aws.eu-central-1](#provider\_aws.eu-central-1) | >= 3.68 | | [aws.eu-north-1](#provider\_aws.eu-north-1) | >= 3.68 | | [aws.eu-west-1](#provider\_aws.eu-west-1) | >= 3.68 | | [aws.eu-west-2](#provider\_aws.eu-west-2) | >= 3.68 | | [aws.eu-west-3](#provider\_aws.eu-west-3) | >= 3.68 | | [aws.sa-east-1](#provider\_aws.sa-east-1) | >= 3.68 | | [aws.us-east-1](#provider\_aws.us-east-1) | >= 3.68 | | [aws.us-east-2](#provider\_aws.us-east-2) | >= 3.68 | | [aws.us-west-1](#provider\_aws.us-west-1) | >= 3.68 | | [aws.us-west-2](#provider\_aws.us-west-2) | >= 3.68 | ## Modules | Name | Source | Version | |------|--------|---------| | [recovery\_cluster](#module\_recovery\_cluster) | ./modules/recovery_cluster | n/a | | [recovery\_group](#module\_recovery\_group) | ./modules/readiness_recovery_group | n/a | ## Resources | Name | Type | |------|------| | [aws_lb.ap_northeast_1](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/lb) | data source | | [aws_lb.ap_northeast_2](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/lb) | data source | | [aws_lb.ap_northeast_3](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/lb) | data source | | [aws_lb.ap_south_1](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/lb) | data source | | [aws_lb.ap_southeast_1](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/lb) | data source | | [aws_lb.ap_southeast_2](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/lb) | data source | | [aws_lb.ca_central_1](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/lb) | data source | | [aws_lb.eu_central_1](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/lb) | data source | | [aws_lb.eu_north_1](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/lb) | data source | | [aws_lb.eu_west_1](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/lb) | data source | | [aws_lb.eu_west_2](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/lb) | data source | | [aws_lb.eu_west_3](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/lb) | data source | | [aws_lb.sa_east_1](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/lb) | data source | | [aws_lb.us_east_1](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/lb) | data source | | [aws_lb.us_east_2](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/lb) | data source | | [aws_lb.us_west_1](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/lb) | data source | | [aws_lb.us_west_2](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/lb) | data source | ## Inputs | Name | Description | Type | Default | Required | |------|-------------|------|---------|:--------:| | [cells\_definition](#input\_cells\_definition) | Nested map where the key is a region you want to enable and keys referring to resource arns to enable. Services enabled are defined in `var.resource_type_name`. For examples, see the variables.tf file"
/*
cells\_definition = {
us-west-2 = {
elasticloadbalancing = "arn:aws:elasticloadbalancing:us-west-2:<>:loadbalancer/app/<>"
autoscaling = "arn:aws:autoscaling:us-west-2:<>:autoScalingGroup:*:autoScalingGroupName/<>
}
}
*/ | `map(map(string))` | n/a | yes | | [name](#input\_name) | Name to prefix resources. | `string` | n/a | yes | | [create\_recovery\_cluster](#input\_create\_recovery\_cluster) | Create the Routing Control Cluster and associated resources. | `bool` | `false` | no | | [hosted\_zone](#input\_hosted\_zone) | Info about the hosted zone. If the `name` or `zone_id` is not passed, a search will be performed using the values provided. Leave null to not create Route53 Alias records (required for LB functionality). |
object({
name = optional(string)
private_zone = optional(bool)
vpc_id = optional(string)
tags = optional(map(string))
zone_id = optional(string)
})
|
{
"name": null,
"zone_id": null
}
| no | | [primary\_cell\_region](#input\_primary\_cell\_region) | (Optional) Region name of which Cell to make Route53 Primary. Defaults to default provider region if not set. | `string` | `null` | no | | [resource\_type\_name](#input\_resource\_type\_name) | list of all service types you can pass and their associated Resource Set Type. | `map(string)` |
{
"apigateway": "AWS::ApiGatewayV2::Api",
"autoscaling": "AWS::AutoScaling::AutoScalingGroup",
"cloudwatch": "AWS::CloudWatch::Alarm",
"dynamodb": "AWS::DynamoDB::Table",
"ec2-volume": "AWS::EC2::Volume",
"ec2-vpc": "AWS::EC2::VPC",
"ec2-vpn-cgw": "AWS::EC2::CustomerGateway",
"ec2-vpn-conn": "AWS::EC2::VPNConnection",
"ec2-vpn-gw": "AWS::EC2::VPNGateway",
"elasticloadbalancing": "AWS::ElasticLoadBalancingV2::LoadBalancer",
"kafka": "AWS::MSK::Cluster",
"lambda": "AWS::Lambda::Function",
"rds": "AWS::RDS::DBCluster",
"route53": "AWS::Route53::HealthCheck",
"sns": "AWS::SNS::Topic",
"sqs": "AWS::SQS::Queue"
}
| no | | [safety\_rule\_type](#input\_safety\_rule\_type) | Type of safety rules to create. Can only be "assertion" or "gating". | `string` | `"assertion"` | no | | [safety\_rules](#input\_safety\_rules) | Configuration of the Safety Rules. Key is the name applied to the rule. |
map(object({
wait_period_ms = number
inverted = bool
threshold = number
type = string
name_suffix = string
}))
|
{
"MinCellsActive": {
"inverted": false,
"name_suffix": "MinCellsActive",
"threshold": 1,
"type": "ATLEAST",
"wait_period_ms": 5000
}
}
| no | | [tags](#input\_tags) | Map of tags to be added to Readiness resources. | `map(string)` | `null` | no | ## Outputs | Name | Description | |------|-------------| | [cells](#output\_cells) | Cells per Region. | | [cluster](#output\_cluster) | Cluster information. | | [control\_panel](#output\_control\_panel) | Control Panel information. | | [health\_checks](#output\_health\_checks) | Health checks. | | [r53\_aliases](#output\_r53\_aliases) | Route53 alias records, if created. | | [readiness\_checks](#output\_readiness\_checks) | A Readiness check for each resource set. | | [recovery\_group](#output\_recovery\_group) | Recovery group resource. | | [resource\_sets](#output\_resource\_sets) | A Resource set for each service with ARN entries for each Region. | | [routing\_controls](#output\_routing\_controls) | Routing controls per cell. | | [safety\_rules](#output\_safety\_rules) | Safety rules. |