Manual Secure Configuration of Consul on AWS Elastic Container Service (ECS)

This topic describes how to enable Consul security features for your production workloads.

Prerequisites

The following features must be configured for your Consul server cluster:

You should already have followed the manual installation instructions to define the necessary components of the task definition for Consul on ECS.

You should be familiar with specifying sensitive data on ECS.

You should be familiar with configuring Consul’s secure features, including how to create ACL tokens and policies. Refer to the ACL system documentation and Day 1: Security tutorials for an introduction and additional information.

Auth Method

Tokens are artifacts within the ACL system that authenticate users, services, and Consul agents. Tokens are linked to policies that specify the resources the token bearer has access to when making requests in the network.

Auth Methods are a Consul server component that performs authentication against a trusted external party to authorize the creation of ACL tokens. The AWS IAM auth method is used to enable an ECS task to automatically obtain ACL tokens when the task starts up.

There are two types of ACL tokens for Consul on ECS:

  • Client tokens: used by the consul-client containers to join the Consul cluster
  • Service tokens: used by sidecar containers for service registration and health syncing

This section describes how to manually configure the AWS IAM auth method for Consul on ECS. Alternatively, you can install the ACL controller to ease the burden of creating these resources. The ACL controller can automatically configure ACL resources for Consul on ECS. For additional details, refer to ACL Controller and Architecture.

ECS Task Role Configuration

The ECS task role is an IAM role associated with an ECS task.

When an ECS task starts up, it runs a consul login command. The consul login command obtains credentials for the task role role from AWS. It uses those credentials to sign the login request to the AWS IAM auth method. This proves the ECS task’s identity to the Consul servers.

The task role must be configured with the following details to compatible with the AWS IAM auth method.

  • An iam:GetRole permission to fetch itself. See IAM Policies for details.
  • A consul.hashicorp.com.service-name tag on the task role which contains the Consul service name for the application in this task.
  • EnterpriseSecure Configuration - 图1Enterprise A consul.hashicorp.com.namespace tag on the task role indicating the Consul Enterprise namespace where this service is registering.

The following sections describe how to configure the auth method to enable task roles to successfully authenticate to the AWS IAM auth method and obtain tokens with the necessary permissions.

Auth Method for Client Tokens

The following steps configure an instance of the auth method that creates client tokens for tasks.

  1. Create the auth method instance
  2. Create the client policy and role
  3. Create the binding rule

Create Auth Method for Client Tokens

The following Consul CLI command creates an instance of the auth method for client tokens.

  1. consul acl auth-method create \
  2. -type aws-iam \
  3. -name iam-ecs-client-token \
  4. -description="AWS IAM auth method for ECS client tokens" \
  5. -config '{
  6. "BoundIAMPrincipalArns": ["arn:aws:iam::<ACCOUNT>:role/consul-ecs/*"],
  7. "EnableIAMEntityDetails": true
  8. }'

The following flags are required:

FlagTypeDescription
-typestringMust be aws-iam.
-namestringA name of your choice. Must be unique among all auth methods.
-descriptionstringA description of your choice.
-configstringA JSON string containing the configuration for the the auth method.

In the -config option, the following fields are required:

FieldTypeDescription
BoundIAMPrincipalArnslistThe list of trusted IAM roles. We recommend using a wildcard to trust IAM roles at a particular path.
EnableIAMEntityDetailsbooleanMust be true so that the auth method can retrieve IAM role details, such as the role path and role tags.

Create Client Policy and Role

Configure the following ACL policy for Consul client tokens:

Secure Configuration - 图2

client-token-policy.hcl

  1. node_prefix "" {
  2. policy = "write"
  3. }
  4. service_prefix "" {
  5. policy = "read"
  6. }

The policy allows node:write for any node name, which is necessary because the Consul node names on ECS are not known until runtime.

You can add the policy in Consul using the consul acl policy create command or the [PUT] /v1/acl/policy API endpoint.

After the policy is created, create a Consul role associated with the policy by using the consul acl role create command or the [PUT] /v1/acl/role API endpoint.

The following example shows how to use the Consul CLI to create the client policy and role.

  1. consul acl policy create -name consul-ecs-client-policy -rules @client-token-policy.hcl
  2. consul acl role create -name consul-ecs-client-role -policy-name consul-ecs-client-policy

Create Binding Rule for Client Tokens

The following creates a binding rule for the auth method for client tokens. The binding rule associates the client role with each token created by a successful login to this auth method instance.

  1. consul acl binding-rule create -method iam-ecs-client-token \
  2. -description 'Bind a role for Consul clients on ECS' \
  3. -bind-type role \
  4. -bind-name consul-ecs-client-role

Auth Method for Service Tokens

The following steps configure an instance of the auth method that creates service tokens for tasks.

  • Create the auth method instance
  • Create the binding rule

Create Auth Method for Service Tokens

The following uses the Consul CLI to create an instance of the auth method for service tokens. This configures the auth method to associate a service identity to each token created during login to this auth method instance.

  1. consul acl auth-method create \
  2. -type aws-iam \
  3. -name iam-ecs-service-token \
  4. -description="AWS IAM auth method for ECS service tokens" \
  5. -config '{
  6. "BoundIAMPrincipalArns": ["arn:aws:iam::<ACCOUNT>:role/consul-ecs/*"],
  7. "EnableIAMEntityDetails": true,
  8. "IAMEntityTags": [
  9. "consul.hashicorp.com.service-name"
  10. ]
  11. }'

The following flags are required:

FlagTypeDescription
-typestringMust be aws-iam.
-namestringA name of your choice. Must be unique among all auth methods.
-descriptionstringA description of your choice.
-configstringA JSON string containing the configuration for the the auth method.

In the -config option, the following fields are required:

FieldTypeDescription
BoundIAMPrincipalArnslistThe list of trusted IAM roles. We recommend using a wildcard to trust IAM roles at a particular path.
EnableIAMEntityDetailsbooleanMust be true so that the auth method can retrieve IAM role details, such as the role path and role tags.
IAMEntityTagslistThe list of IAM role tags to make available to binding rules. Must include the service name tag as shown.

The following binding rule is used to associate a service identity with each token created by successful login to this instance of the auth method. The service identity name is taken from the consul.hashicorp.com.service-name tag from the authenticating IAM role identity.

Create Binding Rule

  1. consul acl binding-rule create \
  2. -method iam-ecs-service-token \
  3. -description 'Bind a service identity from IAM role tags for ECS service tokens' \
  4. -bind-type service \
  5. -bind-name '${entity_tags.consul.hashicorp.com.service-name}'

Configuration for Consul EnterpriseEnterpriseSecure Configuration - 图3Enterprise

When using Consul Enterprise namespaces and admin partitions, pass the -partition <partition-name> option to the Consul CLI when creating Consul ACL roles, policies, auth methods, and binding rules, in order to create these resources in a particular partition.

The following shows how to create the ACL policy for client tokens. This ensures permissions for the client token are scoped to a particular partition.

Secure Configuration - 图4

client-token-policy-ent.hcl

  1. partition "<partition-name>" {
  2. node_prefix "" {
  3. policy = "write"
  4. }
  5. namespace_prefix "" {
  6. service_prefix "" {
  7. policy = "read"
  8. }
  9. }
  10. }

The following commands show how to use the Consul CLI to create the policy and role.

  1. consul acl policy create -partition <partition-name> \
  2. -name consul-ecs-client-policy \
  3. -rules @client-token-policy-ent.hcl
  4. consul acl role create \
  5. -partition <partition-name> \
  6. -name consul-ecs-client-role \
  7. -policy-name consul-ecs-client-policy

The auth method for service tokens requires the following additional configuration to include a namespace binding rule. This ensures the service tokens are created in the right namespace during login. (The namespace binding rule must not be configured on the instance of the auth method instance for client tokens.)

  1. consul acl auth-method create \
  2. -partition <partition-name> \
  3. -type aws-iam \
  4. -name iam-ecs-service-token \
  5. -description="AWS IAM auth method for ECS service tokens" \
  6. -namespace-rule-selector 'entity_tags["consul.hashicorp.com.namespace"] != ""' \
  7. -namespace-rule-bind-namespace '${entity_tags.consul.hashicorp.com.namespace}' \
  8. -config '{
  9. "BoundIAMPrincipalArns": ["arn:aws:iam::<ACCOUNT>:role/consul-ecs/*"],
  10. "EnableIAMEntityDetails": true,
  11. "IAMEntityTags": [
  12. "consul.hashicorp.com.service-name",
  13. "consul.hashicorp.com.namespace"
  14. ]
  15. }'
FieldTypeDescription
-partitionstringThe Consul Enterprise admin partition in which the auth method is created.
-namespace-rule-selectorstringWhen this expression evaluates to true during login, the -namespace-rule-bind-namespace is applied. As shown, it evaluates to true when the consul.hashicorp.com.namespace tag is non-empty on the task IAM role.
-namespace-rule-bind-namespacestringThis expression is evaluated to determine the namespace where the token is created during login. As shown, it uses the namespace from the consul.hashicorp.com.namespace tag on the task IAM role.
IAMEntityTagslistMust include consul.hashicorp.com.namespace to enable use of this tag in binding rules.

Secret storage

You should securely store the following secrets in order to make them available to ECS tasks.

  1. Consul Server CA certificates. More than one may be required for different Consul protocols.
  2. Consul gossip encryption key

These secrets can be securely stored and passed to ECS tasks using either of the following AWS secret services:

Once the secrets are stored they can be referenced using their ARN. The following shows example secret ARNs when using AWS Secrets Manager:

SecretSample Secret ARN
Consul Server CA Cert for RPCarn:aws:secretsmanager:us-west-2:000000000000:secret:my-consul-ca-cert
Consul Server CA Cert for HTTPSarn:aws:secretsmanager:us-west-2:000000000000:secret:my-consul-https-ca-cert
Gossip encryption keyarn:aws:secretsmanager:us-west-2:000000000000:secret:my-consul-gossip-key

Configure consul-client

The following secrets must be passed to the consul-client container:

  • Consul server CA certificates
  • Gossip encryption key

The following example shows how to include these secrets in the task definition. The secrets list specifies environment variable names that will be set to the secret values for this container. ECS automatically fetches the secret values specified in the valueFrom fields during task provisioning.

  1. {
  2. "containerDefinitions": [
  3. {
  4. "name": "consul-client"
  5. "image": "public.ecr.aws/hashicorp/consul:<CONSUL_VERSION>",
  6. "secrets": [
  7. {
  8. "name": "CONSUL_CACERT_PEM",
  9. "valueFrom": "arn:aws:secretsmanager:us-west-2:000000000000:secret:my-consul-ca-cert"
  10. },
  11. {
  12. "name": "CONSUL_HTTPS_CACERT_PEM",
  13. "valueFrom": "arn:aws:secretsmanager:us-west-2:000000000000:secret:my-consul-https-ca-cert"
  14. },
  15. {
  16. "name": "CONSUL_GOSSIP_ENCRYPTION_KEY",
  17. "valueFrom": "arn:aws:secretsmanager:us-west-2:000000000000:secret:my-consul-gossip-key"
  18. }
  19. ]
  20. },
  21. ...
  22. ]
  23. }

Next, update the Consul client startup script with the consul login command and additional Consul configuration options for a secure configuration.

The following is an example of the additional content to include in the consul-client startup script. Refer to the install page for the remainder of the startup script and how to pass this script to the container.

  1. ...
  2. # Obtain details from the task metadata
  3. ECS_TASK_META=$(curl -s $ECS_CONTAINER_METADATA_URI_V4/task)
  4. TASK_REGION=$(echo "$ECS_TASK_META" | jq --raw-output '.TaskARN / ":" | .[3]')
  5. TASK_ID=$(echo "$ECS_TASK_META" | jq --raw-output '.TaskARN / "/" | .[2]')
  6. CLUSTER_ARN=$(echo "$ECS_TASK_META" | jq --raw-output '.TaskARN | sub(":task/(?<cluster>[^/]+).*"; ":cluster/\(.cluster)")')
  7. # Write the CA certs to a files in the shared volume
  8. echo "$CONSUL_CACERT_PEM" > /consul/consul-ca-cert.pem
  9. echo "$CONSUL_HTTPS_CACERT_PEM" > /consul/consul-https-ca-cert.pem
  10. consul_login() {
  11. echo "Logging into auth method"
  12. consul login \
  13. -http-addr "<consul server address>" \
  14. -ca-file /consul/consul-https-ca-cert.pem \
  15. -partition "<partition>" \
  16. -type aws-iam \
  17. -method iam-ecs-client-token \
  18. -meta "consul.hashicorp.com/task-id=$TASK_ID" \
  19. -meta "consul.hashicorp.com/cluster=$CLUSTER_ARN" \
  20. -aws-region "$TASK_REGION" \
  21. -aws-auto-bearer-token -aws-include-entity \
  22. -token-sink-file /consul/client-token
  23. }
  24. read_token_stale() {
  25. consul acl token read -http-addr ${ consul_http_addr } \
  26. -ca-file /consul/consul-https-ca-cert.pem \
  27. -stale -self -token-file /consul/client-token \
  28. > /dev/null
  29. }
  30. # Retry in order to login successfully.
  31. while ! consul_login; do
  32. sleep 2
  33. done
  34. # Allow the health-sync container to read this token for consul logout.
  35. chmod 0644 /consul/client-token
  36. # Wait for raft replication to hopefully occur. Without this, an "ACL not found" may be cached for a while.
  37. COUNT=20
  38. while [ "$COUNT" -gt 0 ]; do
  39. echo "Checking that the ACL token exists when reading it in the stale consistency mode ($COUNT attempts remaining)"
  40. if read_token_stale; then
  41. echo "Successfully read ACL token from the server"
  42. break
  43. fi
  44. sleep 0.1
  45. COUNT=$((COUNT - 1))
  46. done
  47. if [ "$COUNT" -eq 0 ]; then
  48. echo "Unable to read ACL token from a Consul server; please check that your server cluster is healthy"
  49. exit 1
  50. fi
  51. # This is interpolated into the agent-defaults.hcl
  52. export AGENT_TOKEN=$(cat /consul/client-token)
  53. # Write the Consul agent configuration file.
  54. cat << EOF > /consul/agent-defaults.hcl
  55. ...
  56. # Configure gossip encryption key
  57. encrypt = "$CONSUL_GOSSIP_ENCRYPTION_KEY"
  58. # Configure TLS settings
  59. auto_encrypt = {
  60. tls = true
  61. ip_san = ["$ECS_IPV4"]
  62. }
  63. tls {
  64. defaults {
  65. ca_file = "/consul/consul-ca-cert.pem"
  66. verify_outgoing = true
  67. }
  68. }
  69. # Configure ACLs
  70. acl {
  71. enabled = true
  72. default_policy = "deny"
  73. down_policy = "async-cache"
  74. tokens {
  75. agent = "$AGENT_TOKEN"
  76. }
  77. }
  78. partition = "<partition>"
  79. EOF

The following describes the additional steps added to the startup script:

  • Fetch additional details from the task metadata: the AWS region, task id, and cluster arn. These details are necessary for the consul login command used to obtain a Consul client token.
  • Write CA certificates to files for Consul CLI and Consul client
  • Run the consul login command in a retry loop.
  • Wait for Raft replication to hopefully occur for this token.
  • Configure the Consul client config file with additional fields necessary for secure configuration.

The following flags are passed to the consul login command:

Field nameTypeDescription
-http-addrstringHTTP(S) address of the Consul server.
-ca-filestringPath of the CA cert for Consul’s HTTPS interface. Not required when using Consul servers on HCP.
-partitionstringEnterprise The Consul Enterprise admin partition the auth method belongs to.
-typestringThe auth method type. Must be aws-iam.
-methodstringThe auth method name. Must be the name of the auth method for ECS client tokens.
-metastringMetadata to set in description of the created token. Should include the task id and cluster as shown.
-aws-regionstringThe AWS region where the task is running.
-aws-auto-bearer-tokenMust be set to login to the AWS IAM auth method.
-aws-include-entityMust be set to enable IAM role details.

The following table describes the additional fields that must be included in the Consul client configuration file.

Field nameTypeDescription
encryptstringGossip encryption key
tls.defaults.ca_filestringConsul server CA cert for TLS verification.
acl.enabledbooleanEnable ACLs for this agent.
acl.tokens.agentstringConsul client token which authorizes this agent with Consul servers.
partitionstringEnterprise The Consul Enterprise admin partition this agent belongs to.

Configure Audit Logging EnterpriseSecure Configuration - 图7Enterprise

Audit logging is supported on clients running Consul Enterprise with ACLs enabled. To enable audit logging, update the startup script to add an audit stanza to the Consul client configuration file.

The following example modifies the consul-client startup script to configure audit logs to be written to the stdout of the consul-client container.

  1. ...
  2. # Write the Consul agent configuration file.
  3. cat << EOF > /consul/agent-defaults.hcl
  4. ...
  5. partition = "<partition>"
  6. audit {
  7. enabled = true
  8. sink "stdout" {
  9. type = "file"
  10. format = "json"
  11. path = "/dev/stdout"
  12. delivery_guarantee = "best-effort"
  13. }
  14. }
  15. EOF

The following table describes the fields that must be included to configure audit logging.

Field nameTypeDescription
audit.enabledbooleanEnable audit logging for this agent.
audit.sinkobjectThe audit logging sink for this agent.

Configure consul-ecs-mesh-init and consul-ecs-health-sync

The following additional options should be set in the CONSUL_ECS_CONFIG_JSON environment variable. When these options are specified, the consul-ecs mesh-init command will run the consul login command to obtain a service token from the Consul AWS IAM Auth method. The consul-ecs health-sync command is responsible for running a consul logout command for both the service and client tokens when the task shuts down.

  1. {
  2. "consulHTTPAddr": "<Consul server address>",
  3. "consulCACertFile": "/consul/consul-https-ca-cert.pem",
  4. "consulLogin": {
  5. "enabled": true,
  6. "method": "iam-ecs-service-token",
  7. "extraLoginFlags": ["-partition", "<partition>"]
  8. },
  9. "bootstrapDir": "/consul",
  10. "healthSyncContainers": [],
  11. ...
  12. }

The following table explains the additional fields for the CONSUL_ECS_CONFIG_JSON:

Field nameTypeDescription
consulHTTPAddrstringHTTP(S) address for the Consul server.
consulCACertFilestringPath of the CA cert file for Consul’s HTTPS interface. Not required for Consul servers in HCP.
consulLogin.enabledbooleanMust be set to true to log in to the auth method.
consulLogin.methodstringMust be set to the name of the auth method instance for service tokens.
consulLogin.extraLoginFlagslistAdditional flags passed to the consul login command. Enterprise This shows how to pass the Consul Enterprise admin partition to the consul login command.