Consul
Deploy Consul to ECS using the Terraform module
This topic describes how to create a Terraform configuration that deploys Consul service mesh to your ECS cluster workloads. Consul server agents do not run on ECS and must be deployed to another runtime, such as EKS, and connected to your ECS workloads. Refer Consul on AWS Elastic Container Service overview for additional information.
Overview
Create a Terraform configuration file that includes the ECS task definition and Terraform modules that build the Consul service mesh components. The task definition is the ECS blueprint for your software services on AWS. Refer to the ECS task definitions documentation for additional information.
You can add the following modules and resources to your Terraform configuration:
mesh-task
module: Adds the Consul ECS control-plane and Consul dataplane containers to the task definition along with your application container. Envoy runs as a subprocess within the Consul dataplane container.aws_ecs_service
resource: Adds an ECS service to run and maintain your task instance.gateway-task
module: Adds mesh gateway containers to the cluster. Mesh gateways enable service-to-service communication across different types of network areas.
To enable Consul security features for your production workloads, you must also deploy the controller
module, which provisions ACL tokens for service mesh tasks.
After defining your Terraform configuration, use terraform apply
to deploy Consul to your ECS cluster.
Requirements
- You should be familiar with creating Terraform configuration files. Refer to the Terraform documentation for information about how to get started with Terraform.
- You should be familiar with AWS ECS. Refer to What is Amazon Elastic Container Service in the Amazon AWS documentation for additional information.
- If you intend to use the
gateway-task
module to deploy mesh gateways, you must enable TLS. Refer to Configure the ECS controller for additional information.
Secure configuration requirements
You must meet the following requirements and prerequisites to enable security features in Consul service mesh:
- Enable TLS encryption on your Consul servers so that they can communicate securely with Consul containers over gRPC.
- Enable access control lists (ACLs) on your Consul servers. ALCs provide authentication and authorization for access to Consul servers on the mesh.
- You should be familiar with specifying sensitive data on ECS. Refer to Passing sensitive data to a container in the AWS documentation for additional information.
Additionally, Consul requires a unique IAM role for each ECS task family. Task IAM roles cannot be shared by different task families because the task family is unique to each Consul service.
You should be familiar with configuring Consul's secure features, including how to create ACL tokens and policies. Refer to the following resources for additional information:
Create the task definition
Create a Terraform configuration file and add your ECS task definition. The task definition includes your application containers, Consul control-plane container, dataplane container, and controller container. If you intend to peer the service mesh to multiple Consul datacenters or partitions, add the gateway-task module, which deploys gateway containers that enable connectivity between network areas in your network.
Configure the mesh task module
Add a module
block to your Terraform configuration and specify the following fields:
source
: Specifies the location of themesh-task
module. This field must be set tohashicorp/consul-ecs/aws//modules/mesh-task
. Themesh-task
module automatically adds the Consul service mesh infrastructure when you apply the Terraform configuration.version
: Specifies the version of themesh-task
module to use.family
: Specifies the ECS task definition family. Consul also uses thefamily
value as the Consul service name by default.container_definitions
: Specifies a list of container definitions for the task definition. This field is where you include your application containers.
Refer to the mesh-task
module reference documentation in the Terraform registry for information about all options you can configure.
You should also configure the ACL and encryption settings if they are enabled on your Consul servers. Refer to Enable secure deployment for additional information.
In the following example, the Terraform configuration file mesh-task.tf
creates a task definition with an application container called example-client-app
:
mesh-task.tf
module "my_task" {
source = "hashicorp/consul-ecs/aws//modules/mesh-task"
version = "<latest version>"
family = "my_task"
container_definitions = [
{
name = "example-client-app"
image = "docker.io/org/my_task:v0.0.1"
essential = true
portMappings = [
{
containerPort = 9090
hostPort = 9090
protocol = "tcp"
}
]
cpu = 0
mountPoints = []
volumesFrom = []
}
]
port = 9090
}
The following fields are required. Refer to the module reference documentation for a complete reference.
Configure Consul server settings
Provide Consul server connection settings to the mesh task module so that the module can configure the control-plane and ECS controller containers to connect to the servers.
In your
variables.tf
file, define variables for the host URL and the TLS settings for gRPC and HTTP traffic. Refer to the mesh task module reference for information about the variables you can define. In the following example, the Consul server address is defined in theconsul_server_hosts
variable:variable "consul_server_hosts" { description = "Address of Consul servers." type = string }
Add an
environment
block to the control-plane and ECS controller containers definition.Set the
environment.name
field to theCONSUL_ECS_CONFIG_JSON
environment variable and the value tolocal.encoded_config
.environment = [ { name = "CONSUL_ECS_CONFIG_JSON", value = local.encoded_config } ]
When you apply the configuration, the mesh task module interpolates the server configuration variables, builds a
config.tf
file, and injects the settings into the appropriate containers. For additional information about theconfig.tf
file, refer to the JSON schema reference documentation.
Configure an ECS service to run your task instances
To start a task using the task definition, add the aws_ecs_service
resource to your configuration to create an ECS service. ECS services are one of the most common ways to start tasks using a task definition.
Reference the mesh-task
module's task_definition_arn
output value in your aws_ecs_service
resource. The following example adds an ECS service for a task definition referenced in as module.my_task.task_defintion_arn
:
mesh-task.tf
module "my_task" {
source = "hashicorp/consul-ecs/aws//modules/mesh-task"
...
}
resource "aws_ecs_service" "my_task" {
name = "my_task_service"
task_definition = module.my_task.task_definition_arn
launch_type = "FARGATE"
propagate_tags = "TASK_DEFINITION"
...
}
Refer to aws_ecs_service
in the Terraform registry for a complete configuration reference.
If you are deploying a test instance of your ECS application, you can apply your configuration in Terraform. Refer to Run your configuration for instructions. To configure your deployment for a production environment, you must also deploy the ECS controller module. Refer to Configure the ECS controller for instructions.
If you intend to leverage multi-datacenter Consul features, such as WAN federation and cluster peering, then you must add the gateway-task
module for each Consul datacenter in your network. Refer to Configure the gateway task module for instructions.
Configure the gateway task module
The gateway-task
module deploys a mesh gateway, which enables service-to-service communication across network areas. Mesh gateways detect the server name indication (SNI) header from the service mesh session and route the connection to the appropriate destination.
Refer to the following documentation for additional information:
To use mesh gateways, TLS must be enabled in your cluster. Refer to the requirements section for additional information.
- Add a
module
block to your Terraform configuration file and specify a label. The label is a unique identifier for the gateway. - Add a
source
to themodule
and specify the location of thegateway-task
. The value must behashicorp/consul-ecs/aws//modules/gateway-task
. - Specify the following required inputs:
ecs_cluster_arn
: The ARN of the ECS cluster for the gateway.family
: Specifies a name for multiple versions of the task. Refer to the AWS documentation for details.kind
: Set tomesh-gateway
subnets
: Specifies a list of subnet IDs where the gateway task should be deployed.
- If you are deploying to a production environment, you must also add the
acl
andtls
configurations. Refer to Configure the ECS controller for details. - Configure any additional parameters necessary for your environment. Refer to the module reference documentation for information about all parameters.
The following example defines a mesh gateway task called my-gateway
:
mesh-gateway.tf
module "my_mesh_gateway" {
source = "hashicorp/consul-ecs/aws//modules/gateway-task"
version = "<latest version>"
kind = "mesh-gateway"
family = "my-gateway"
ecs_cluster_arn = "<ECS cluster ARN>"
subnets = ["<subnet ID>"]
consul_server_hosts = "<address of the Consul server>"
tls = true
consul_ca_cert_arn = "<Secrets manager secret ARN>"
}
Refer to gateway-task module in the Terraform registry for a complete reference.
Refer to the gateway task configuration examples for additional example configurations.
Configure the ECS controller
Deploy the ECS controller container to its own ECS task in the cluster. Refer to ECS controller container for details about the container.
Verify that you have completed the prerequisites described in Secure configuration requirements and complete the following steps to configure the controller container.
Create a an ACL token for the controller
On the Consul server, create a policy that grants the following access for the controller:
The policy allows Consul to generate a token linked to the policy. Refer to Create a service token for instructions.
Create a token and link it to the ACL controller policy. Refer to the ACL tokens documentation for instructions.
Configure an AWS secrets manager secret
Add the aws_secretsmanager_secret
resource to your Terraform configuration and specify values for retrieving the CA and TLS certificates. The resource enables services to communicate over TLS and present ACL tokens. The ECS controller also uses the secret manager to retrieve the value of the bootstrap token.
In the following example, Terraform creates the CA certificates for gRPC and HTTPS in the secrets manager. Consul retrieves the CA certificate PEM file from the secret manager so that the mesh task can use TLS for HTTP and gRPC traffic:
secret.tf
resource "tls_private_key" "ca" {
algorithm = "ECDSA"
ecdsa_curve = "P384"
}
resource "tls_self_signed_cert" "ca" {
private_key_pem = tls_private_key.ca.private_key_pem
subject {
common_name = "Consul Agent CA"
organization = "HashiCorp Inc."
}
// 5 years.
validity_period_hours = 43800
is_ca_certificate = true
set_subject_key_id = true
allowed_uses = [
"digital_signature",
"cert_signing",
"crl_signing",
]
}
resource "aws_secretsmanager_secret" "ca_key" {
name = "${var.name}-${var.datacenter}-ca-key"
recovery_window_in_days = 0
}
resource "aws_secretsmanager_secret_version" "ca_key" {
secret_id = aws_secretsmanager_secret.ca_key.id
secret_string = tls_private_key.ca.private_key_pem
}
resource "aws_secretsmanager_secret" "ca_cert" {
name = "${var.name}-${var.datacenter}-ca-cert"
recovery_window_in_days = 0
}
resource "aws_secretsmanager_secret_version" "ca_cert" {
secret_id = aws_secretsmanager_secret.ca_cert.id
secret_string = tls_self_signed_cert.ca.cert_pem
}
Note that you could use a single CERT PEM
for both variables. The consul_ca_cert_arn
is the default ARN applicable to both the protocols. You can also use protocol-specific certificate PEMs with the consul_https_ca_cert_arn
and consul_grpc_ca_cert_arn
variables.
The following Terraform configuration passes the generated CA certificate ARN to the mesh-task
module and ensures that the CA certificate and PEM variable are set for both HTTPS and gRPC communication.
secret.tf
module "my_task" {
source = "hashicorp/consul-ecs/aws//modules/mesh-task"
version = "<version>"
...
tls = true
consul_ca_cert_arn = aws_secretsmanager_secret.ca_cert.arn
}
Enable secure deployment
To enable secure deployment, add the following configuration to the task module.
secret.tf
module "my_task" {
source = "hashicorp/consul-ecs/aws//modules/mesh-task"
version = "<version>"
...
tls = true
consul_grpc_ca_cert_arn = aws_secretsmanager_secret.ca_cert.arn
acls = true
consul_server_hosts = "https://consul-server.example.com"
consul_https_ca_cert_arn = aws_secretsmanager_secret.ca_cert.arn
}
Complete configuration examples
The terraform-aws-consul-ecs GitHub repository contains examples that you can reference to help you deploy Consul service mesh to your ECS workloads.
Apply your Terraform configuration
Run Terraform to create the task definition.
Save the Terraform configuration for the task definition to a file, such as mesh-task.tf
.
You should place this file in a directory alongside other Terraform configuration files for your project.
The mesh-task
module requires the AWS Terraform provider. The following example shows how to include
and configure the AWS provider in a file called provider.tf
. Refer to AWS provider in the Terraform registry
for additional documentation and specifications.
provider.tf
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "<latest version>"
}
}
}
provider "aws" {
region = "<AWS region>"
...
}
Specify any additional AWS resources for your project in Terraform configuration files in the same directory. The following example shows a basic project directory:
$ ls
mesh-task.tf
provider.tf
...
Issue the following commands to run the configuration:
terraform init
: This command downloads dependencies, such as Terraform providers.terraform apply
: This command directs Terraform to create the AWS resources, such as the task definition from themesh-task
module.
Terraform reads all files in the current directory that have a .tf
file extension.
Refer to the Terraform documentation for more information and Terraform best practices.
Next steps
After deploying the Consul service mesh infrastructure, you must still define routes between service instances as well as configure the bind address for your applications so that they only receive traffic through the mesh. Refer to the following topics:
Gateway task configuration examples
The following examples illustrate how to configure the gateway-task
for different use cases.
Ingress
Mesh gateways need to be reachable over the WAN to route traffic between datacenters. Configure the following options in the gateway-task
module to enable ingress through the mesh gateway.
Input variable | Type | Description |
---|---|---|
lb_enabled | Boolean | Set to true to automatically deploy and configure a network load balancer for ingress to the mesh gateway. |
lb_vpc_id | string | Specifies the VPC to launch the load balancer in. |
lb_subnets | list of strings | Specifies one or more public subnets to associate with the load balancer. |
mesh-gateway.tf
module "my_mesh_gateway" {
...
lb_enabled = true
lb_vpc_id = "<VPC ID>"
lb_subnets = ["<public subnet IDs>"]
}
Alternatively, you can manually configure ingress to the mesh gateway and provide the wan_address
and wan_port
inputs to the gateway-task
module. The wan_port
field is optional. Port 8443
is used by default.
mesh-gateway.tf
module "my_mesh_gateway" {
...
wan_address = "<public WAN address>"
wan_port = <public WAN port>
}
Mesh gateways route L4 TCP connections and do not terminate mTLS sessions. If you manually configure AWS Elastic Load Balancing for ingress to a mesh gateway, you must use an AWS Network Load Balancer or a Classic Load Balancer.
ACLs
When ACLs are enabled, configure the following options in the gateway-task
module.
Option | Type | Description |
---|---|---|
acl | Boolean | Set to true when ACLs are enabled. |
consul_server_hosts | string | Specifies the HTTP address of the Consul server. Required for the mesh gateway task to log into Consul using the IAM auth method so that it can obtain its client and service tokens. |
consul_https_ca_cert_arn | string | Specifies ARN of the Secrets Manager secret that contains the certificate for the Consul HTTPS API. |
mesh-gateway.tf
module "my_mesh_gateway" {
...
acls = true
consul_server_hosts = "<HTTP address of the Consul server>"
tls = true
consul_https_ca_cert_arn = "<Secrets Manager secret ARN>"
}
WAN federation
Configure the following options in the gateway-task
to enable WAN federation through mesh gateways.
Option | Type | Description |
---|---|---|
consul_datacenter | string | Specifies the name of the local Consul datacenter. |
consul_primary_datacenter | string | Specifies the name of the primary Consul datacenter. |
enable_mesh_gateway_wan_federation | Boolean | Set to true to enable WAN federation. |
enable_acl_token_replication | Boolean | Set to true to enable ACL token replication and allow the creation of local tokens secondary datacenters. |
The following example shows how to configure the gateway-task
module.
mesh-gateway.tf
module "my_mesh_gateway" {
...
enable_mesh_gateway_wan_federation = true
}
When federating Consul datacenters over the WAN with ACLs enabled, ACL Token replication must be enabled on all server and client agents in all datacenters.