mirror of https://github.com/hashicorp/consul
commit
f664d13b10
@ -0,0 +1,3 @@
|
||||
```release-note:enhancement
|
||||
streaming: Improved performance when the server is handling many concurrent subscriptions and has a high number of CPU cores
|
||||
```
|
@ -0,0 +1,3 @@
|
||||
```release-note:bug
|
||||
xds: fix for delta xDS reconnect bug in LDS/CDS
|
||||
```
|
@ -0,0 +1,3 @@
|
||||
```release-note:enhancement
|
||||
systemd: Support starting/stopping the systemd service for linux packages when the optional EnvironmentFile does not exist.
|
||||
```
|
@ -1,34 +0,0 @@
|
||||
version: '3'
|
||||
|
||||
services:
|
||||
|
||||
consul-agent-1: &consul-agent
|
||||
image: consul:latest
|
||||
networks:
|
||||
- consul-demo
|
||||
command: "agent -retry-join consul-server-bootstrap -client 0.0.0.0"
|
||||
|
||||
consul-agent-2:
|
||||
<<: *consul-agent
|
||||
|
||||
consul-agent-3:
|
||||
<<: *consul-agent
|
||||
|
||||
consul-server-1: &consul-server
|
||||
<<: *consul-agent
|
||||
command: "agent -server -retry-join consul-server-bootstrap -client 0.0.0.0"
|
||||
|
||||
consul-server-2:
|
||||
<<: *consul-server
|
||||
|
||||
consul-server-bootstrap:
|
||||
<<: *consul-agent
|
||||
ports:
|
||||
- "8400:8400"
|
||||
- "8500:8500"
|
||||
- "8600:8600"
|
||||
- "8600:8600/udp"
|
||||
command: "agent -server -bootstrap-expect 3 -ui -client 0.0.0.0"
|
||||
|
||||
networks:
|
||||
consul-demo:
|
@ -1,57 +0,0 @@
|
||||
# Vagrant Consul Demo
|
||||
|
||||
This demo provides a very simple `Vagrantfile` that creates two Consul
|
||||
server nodes, one at *172.20.20.10* and another at *172.20.20.11*. Both are
|
||||
running a standard Debian * distribution, and *the latest version* of Consul
|
||||
is pre-installed.
|
||||
|
||||
To get started, you can start the nodes by just doing:
|
||||
|
||||
```
|
||||
vagrant up
|
||||
```
|
||||
|
||||
> NOTE: If you prefer a different Vagrant box, you can set the `DEMO_BOX_NAME`
|
||||
> environment variable before starting `vagrant` like this:
|
||||
> `DEMO_BOX_NAME="ubuntu/xenial64" vagrant up`
|
||||
|
||||
Once it is finished, you should be able to see the following:
|
||||
|
||||
```
|
||||
vagrant status
|
||||
Current machine states:
|
||||
|
||||
n1 running (virtualbox)
|
||||
n2 running (virtualbox)
|
||||
```
|
||||
|
||||
At this point the two nodes are running and you can SSH in to play with them:
|
||||
|
||||
```
|
||||
vagrant ssh n1
|
||||
consul version
|
||||
Consul v0.7.5
|
||||
Protocol 2 spoken by default, understands 2 to 3 (agent will automatically use protocol >2 when speaking to compatible agents)
|
||||
exit
|
||||
```
|
||||
|
||||
and
|
||||
|
||||
```
|
||||
vagrant ssh n2
|
||||
consul version
|
||||
Consul v0.7.5
|
||||
Protocol 2 spoken by default, understands 2 to 3 (agent will automatically use protocol >2 when speaking to compatible agents)
|
||||
exit
|
||||
```
|
||||
|
||||
> NOTE: This demo will query the HashiCorp Checkpoint service to determine
|
||||
> the latest Consul release version and install that version by default,
|
||||
> but if you need a different Consul version, set the `CONSUL_DEMO_VERSION`
|
||||
> environment variable before `vagrant up` like this:
|
||||
> `CONSUL_DEMO_VERSION=0.6.4 vagrant up`
|
||||
|
||||
## Where to Next?
|
||||
|
||||
To learn more about starting Consul, joining nodes into a cluster, and
|
||||
interacting with the agent, check out the [Getting Started guide](https://www.consul.io/intro/getting-started/install.html).
|
@ -1,56 +0,0 @@
|
||||
# -*- mode: ruby -*-
|
||||
# vi: set ft=ruby :
|
||||
|
||||
$script = <<SCRIPT
|
||||
|
||||
echo "Installing dependencies ..."
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y unzip curl jq dnsutils
|
||||
|
||||
echo "Determining Consul version to install ..."
|
||||
CHECKPOINT_URL="https://checkpoint-api.hashicorp.com/v1/check"
|
||||
if [ -z "$CONSUL_DEMO_VERSION" ]; then
|
||||
CONSUL_DEMO_VERSION=$(curl -s "${CHECKPOINT_URL}"/consul | jq .current_version | tr -d '"')
|
||||
fi
|
||||
|
||||
echo "Fetching Consul version ${CONSUL_DEMO_VERSION} ..."
|
||||
cd /tmp/
|
||||
curl -s https://releases.hashicorp.com/consul/${CONSUL_DEMO_VERSION}/consul_${CONSUL_DEMO_VERSION}_linux_amd64.zip -o consul.zip
|
||||
|
||||
echo "Installing Consul version ${CONSUL_DEMO_VERSION} ..."
|
||||
unzip consul.zip
|
||||
sudo chmod +x consul
|
||||
sudo mv consul /usr/bin/consul
|
||||
|
||||
sudo mkdir /etc/consul.d
|
||||
sudo chmod a+w /etc/consul.d
|
||||
|
||||
SCRIPT
|
||||
|
||||
# Specify a Consul version
|
||||
CONSUL_DEMO_VERSION = ENV['CONSUL_DEMO_VERSION']
|
||||
|
||||
# Specify a custom Vagrant box for the demo
|
||||
DEMO_BOX_NAME = ENV['DEMO_BOX_NAME'] || "debian/stretch64"
|
||||
|
||||
# Vagrantfile API/syntax version.
|
||||
# NB: Don't touch unless you know what you're doing!
|
||||
VAGRANTFILE_API_VERSION = "2"
|
||||
|
||||
Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
|
||||
config.vm.box = DEMO_BOX_NAME
|
||||
|
||||
config.vm.provision "shell",
|
||||
inline: $script,
|
||||
env: {'CONSUL_DEMO_VERSION' => CONSUL_DEMO_VERSION}
|
||||
|
||||
config.vm.define "n1" do |n1|
|
||||
n1.vm.hostname = "n1"
|
||||
n1.vm.network "private_network", ip: "172.20.20.10"
|
||||
end
|
||||
|
||||
config.vm.define "n2" do |n2|
|
||||
n2.vm.hostname = "n2"
|
||||
n2.vm.network "private_network", ip: "172.20.20.11"
|
||||
end
|
||||
end
|
@ -0,0 +1,114 @@
|
||||
# Certificate Authority (Connect CA)
|
||||
|
||||
The Certificate Authority Subsystem manages a CA trust chain for issuing certificates to
|
||||
services and client agents (via auto-encrypt and auto-config).
|
||||
|
||||
The code for the Certificate Authority is in the following packages:
|
||||
1. most of the core logic is in [agent/consul/leader_connect_ca.go]
|
||||
2. the providers are in [agent/connect/ca]
|
||||
3. the RPC interface is in [agent/consul/connect_ca_endpoint.go]
|
||||
|
||||
|
||||
[agent/consul/leader_connect_ca.go]: https://github.com/hashicorp/consul/blob/main/agent/consul/leader_connect_ca.go
|
||||
[agent/connect/ca]: https://github.com/hashicorp/consul/blob/main/agent/connect/ca/
|
||||
[agent/consul/connect_ca_endpoint.go]: https://github.com/hashicorp/consul/blob/main/agent/consul/connect_ca_endpoint.go
|
||||
|
||||
|
||||
## Architecture
|
||||
|
||||
### High level overview
|
||||
|
||||
In Consul the leader is responsible for handling the CA management.
|
||||
When a leader election happen, and the elected leader do not have any root CA available it will start a process of creating a set of CA certificate.
|
||||
Those certificates will be used to authenticate/encrypt communication between services (service mesh) or between `Consul client agent` (auto-encrypt/auto-config). This process is described in the following diagram:
|
||||
|
||||
![CA creation](./hl-ca-overview.svg)
|
||||
|
||||
<sup>[source](./hl-ca-overview.mmd)</sup>
|
||||
|
||||
The features that benefit from Consul CA management are:
|
||||
- [service Mesh/Connect](https://www.consul.io/docs/connect)
|
||||
- [auto encrypt](https://www.consul.io/docs/agent/options#auto_encrypt)
|
||||
|
||||
|
||||
### CA and Certificate relationship
|
||||
|
||||
This diagram shows the relationship between the CA certificates in Consul primary and
|
||||
secondary.
|
||||
|
||||
![CA relationship](./cert-relationship.svg)
|
||||
|
||||
<sup>[source](./cert-relationship.mmd)</sup>
|
||||
|
||||
|
||||
In most cases there is an external root CA that provides an intermediate CA that Consul
|
||||
uses as the Primary Root CA. The only except to this is when the Consul CA Provider is
|
||||
used without specifying a `RootCert`. In this one case Consul will generate the Root CA
|
||||
from the provided primary key, and it will be used in the primary as the top of the chain
|
||||
of trust.
|
||||
|
||||
In the primary datacenter, the Consul and AWS providers use the Primary Root CA to sign
|
||||
leaf certificates. The Vault provider uses an intermediate CA to sign leaf certificates.
|
||||
|
||||
Leaf certificates are created for two purposes:
|
||||
1. the Leaf Cert Service is used by envoy proxies in the mesh to perform mTLS with other
|
||||
services.
|
||||
2. the Leaf Cert Client Agent is created by auto-encrypt and auto-config. It is used by
|
||||
client agents for HTTP API TLS, and for mTLS for RPC requests to servers.
|
||||
|
||||
Any secondary datacenters receive an intermediate certificate, signed by the Primary Root
|
||||
CA, which is used as the CA certificate to sign leaf certificates in the secondary
|
||||
datacenter.
|
||||
|
||||
## Operations
|
||||
|
||||
When trying to learn the CA subsystem it can be helpful to understand the operations that
|
||||
it can perform. The sections below are the complete set of read, write, and periodic
|
||||
operations that provide the full behaviour of the CA subsystem.
|
||||
|
||||
### Periodic Operations
|
||||
|
||||
Periodic (or background) opeartions are started automatically by the Consul leader. They run at some interval (often 1 hour).
|
||||
|
||||
- `CAManager.InitializeCA` - attempts to initialize the CA when a leader is ellected. If the synchronous InitializeCA fails, `CAManager.backgroundCAInitialization` runs `InitializeCA` periodically in a goroutine until it succeeds.
|
||||
- `CAManager.RenewIntermediate` - (called by `CAManager.intermediateCertRenewalWatch`) runs in the primary if the provider uses a separate signing cert (the Vault provider). The operation always runs in the secondary. Renews the signing cert once half its lifetime has passed.
|
||||
- `CAManager.secondaryCARootWatch` - runs in secondary only. Performs a blocking query to the primary to retrieve any updates to the CA roots and stores them locally.
|
||||
- `Server.runCARootPruning` - removes non-active and expired roots from state.CARoots
|
||||
|
||||
### Read Operations
|
||||
|
||||
- `RPC.ConnectCA.ConfigurationGet` - returns the CA provider configuration. Only called by user, not by any internal subsystems.
|
||||
- `RPC.ConnectCA.Roots` - returns all the roots, the trust domain ID, and the ID of the active root. Each "root" also includes the signing key/cert, and any intermediate certs in the chain. It is used (via the cache) by all the connect proxy types.
|
||||
|
||||
### Write Operations
|
||||
|
||||
- `CAManager.UpdateConfiguration` - (via `RPC.ConnectCA.ConfigurationSet`) called by a user when they want to change the provider or provider configuration (ex: rotate root CA).
|
||||
- `CAManager.Provider.SignIntermediate` - (via `RPC.ConnectCA.SignIntermediate`) called from the secondary DC:
|
||||
1. by `CAManager.RenewIntermediate` to sign the new intermediate when the old intermediate is about to expire
|
||||
2. by `CAMananger.initializeSecondary` when setting up a new secondary, when the provider is changed in the secondary
|
||||
by a user action, or when the primary roots changed and the secondary needs to generate a new intermediate for the new
|
||||
primary roots.
|
||||
- `CAMananger.SignCertificate` - is used by:
|
||||
1. (via `RPC.ConnectCA.Sign`) - called by client agents to sign a leaf cert for a connect proxy (via `agent/cache-types/connect_ca_leaf.go`)
|
||||
2. (via in-process call to `RPC.ConnectCA.Sign`) - called by auto-encrypt to sign a leaf cert for a client agent
|
||||
3. called by Auto-Config to sign a leaf cert for a client agent
|
||||
|
||||
## detailed call flow
|
||||
![CA Leader Sequence](./ca-leader-sequence.svg)
|
||||
|
||||
<sup>[source](./ca-leader-sequence.mmd)</sup>
|
||||
|
||||
####TODO:
|
||||
- sequence diagram for leaf signing
|
||||
- sequence diagram for CA cert rotation
|
||||
|
||||
## CAManager states
|
||||
|
||||
This section is a work in progress
|
||||
|
||||
TODO: style the diagram to match the others, and add some narative text to describe the
|
||||
diagram.
|
||||
|
||||
![CA Mananger states](./state-machine.svg)
|
||||
|
||||
|
@ -0,0 +1,19 @@
|
||||
sequenceDiagram
|
||||
Participant Provider
|
||||
Participant PL As Primary Leader
|
||||
Participant SL As Secondary Leader
|
||||
Alt Primary don't have a valid CA
|
||||
PL->>Provider:initializeRootCA (fetch root and sign intermediate)
|
||||
Provider->>PL:root + intermediate
|
||||
PL->>PL:RPC ConnectCA.Roots (fetch primary root and store it)
|
||||
end
|
||||
SL->>PL: RPC ConnectCA.Roots (fetch primary root and store it)
|
||||
PL->>SL: Root + intermediate
|
||||
Alt Secondary needs a new intermediate (check if current intermediate is signed by primary root)
|
||||
SL->>Provider: Generate CSR
|
||||
Provider->>SL: CSR
|
||||
SL->>PL: ConnectCA.SignIntermediate (CSR)
|
||||
PL->>SL: Intermediate CA (secondary)
|
||||
SL->>Provider: Set Intermediate (secondary CA) + root (primary CA)
|
||||
SL->>SL: Store certs in RAFT (primary root + secondary intermediate)
|
||||
end
|
After Width: | Height: | Size: 12 KiB |
@ -0,0 +1,31 @@
|
||||
graph TD
|
||||
|
||||
ExternalRootCA["External RootCA (optional)"]
|
||||
|
||||
subgraph "Consul Primary"
|
||||
PrimaryRootCA["Primary Root CA"]
|
||||
PrimarySigningCA["Primary Signing CA (conditional)"]
|
||||
end
|
||||
|
||||
subgraph "Consul Secondary"
|
||||
SeconarySigningCA["Seconary Signing CA"]
|
||||
end
|
||||
|
||||
LeafCertAgentPrimary[Leaf Cert Client Agent]
|
||||
LeafCertServicePrimary[Leaf Cert Service]
|
||||
|
||||
LeafCertAgentSecondary[Leaf Cert Client Agent]
|
||||
LeafCertServiceSecondary[Leaf Cert Service]
|
||||
|
||||
|
||||
ExternalRootCA -.-> PrimaryRootCA
|
||||
PrimaryRootCA -.-> PrimarySigningCA
|
||||
|
||||
PrimaryRootCA --> SeconarySigningCA
|
||||
|
||||
PrimarySigningCA --> LeafCertAgentPrimary
|
||||
PrimarySigningCA --> LeafCertServicePrimary
|
||||
|
||||
SeconarySigningCA --> LeafCertAgentSecondary
|
||||
SeconarySigningCA --> LeafCertServiceSecondary
|
||||
|
After Width: | Height: | Size: 16 KiB |
@ -0,0 +1,43 @@
|
||||
graph TD
|
||||
subgraph "Primary DC"
|
||||
leaderP["Leader"]
|
||||
rootCAI["Root CA "]
|
||||
rootCA["Root CA "]
|
||||
Provider["Consul/AWS providers"]
|
||||
IntermediateProvider["Vault provider"]
|
||||
intermediateCAP["Intermediate CA "]
|
||||
leafP["Leaf certificates"]
|
||||
end
|
||||
|
||||
subgraph "Secondary DC"
|
||||
leaderS["Leader"]
|
||||
intermediateCAS["Intermediate CA"]
|
||||
leafS["Leaf certificates"]
|
||||
ProviderS["Consul/AWS/Vault providers"]
|
||||
end
|
||||
|
||||
consulCAS["Consul client Agents"]
|
||||
servicesS["Mesh services"]
|
||||
|
||||
consulCAP["Consul client Agents"]
|
||||
servicesP["Mesh services"]
|
||||
|
||||
leaderP -->|use|Provider
|
||||
leaderP-->|use|IntermediateProvider
|
||||
Provider--> |fetch/self sign|rootCA
|
||||
IntermediateProvider --> |fetch/self sign|rootCAI
|
||||
rootCAI -->|sign| intermediateCAP
|
||||
intermediateCAP -->|sign| leafP
|
||||
rootCA -->|sign| leafP
|
||||
|
||||
leaderS -->|use| ProviderS
|
||||
ProviderS --> |generate csr| intermediateCAS
|
||||
rootCA -->|sign| intermediateCAS
|
||||
rootCAI -->|sign| intermediateCAS
|
||||
intermediateCAS --> |sign| leafS
|
||||
|
||||
leafS -->|auth/encrypt| servicesS
|
||||
leafS -->|auth/encrypt| consulCAS
|
||||
leafP -->|auth/encrypt| servicesP
|
||||
leafP -->|auth/encrypt| consulCAP
|
||||
|
After Width: | Height: | Size: 29 KiB |
@ -0,0 +1,23 @@
|
||||
stateDiagram-v2
|
||||
|
||||
[*] --> Uninitialized
|
||||
Uninitialized --> Initializing : InitializeCA
|
||||
Uninitialized --> Reconfig : UpdateConfiguration
|
||||
Reconfig --> Uninitialized : return
|
||||
|
||||
# Initialized can transition to any state
|
||||
Initialized --> Renew : RenewIntermediate
|
||||
Initialized --> Uninitialized : Stop
|
||||
Initialized --> Reconfig : UpdateConfiguration
|
||||
Initialized --> Initializing : INVALID
|
||||
|
||||
# Initialized is set using validate=false
|
||||
Uninitialized --> Initialized : INVALID
|
||||
Reconfig --> Initialized : return
|
||||
Initializing --> Initialized : InitializeCA complete
|
||||
Renew --> Initialized : return
|
||||
|
||||
# Uninitialized is set using validate=false
|
||||
Renew --> Uninitialized : Stop
|
||||
Reconfig --> Uninitialized : Stop
|
||||
Initializing --> Uninitialized : Stop
|
After Width: | Height: | Size: 20 KiB |
@ -0,0 +1,17 @@
|
||||
import { helper } from '@ember/component/helper';
|
||||
|
||||
/**
|
||||
* Conditionally maps classInfos (classes) to a string ready for typical DOM
|
||||
* usage (i.e. space delimited)
|
||||
*
|
||||
* @typedef {([string, boolean] | [string])} classInfo
|
||||
* @param {(classInfo | string)[]} entries - An array of 'entry-like' arrays of `classInfo`s to map
|
||||
*/
|
||||
const classMap = entries => {
|
||||
const str = entries
|
||||
.filter(entry => (typeof entry === 'string' ? true : entry[entry.length - 1]))
|
||||
.map(entry => (typeof entry === 'string' ? entry : entry[0]))
|
||||
.join(' ');
|
||||
return str.length > 0 ? str : undefined;
|
||||
};
|
||||
export default helper(classMap);
|
@ -0,0 +1,45 @@
|
||||
# class-map
|
||||
|
||||
`{{class-map}}` is used to easily add a list of classes, conditionally, and
|
||||
have them all formatted nicely ready to be printed in a DOM `class` attribute.
|
||||
|
||||
For ease, as well as using entries, you can also just provide a simple string
|
||||
without the boolean and that class will always be added.
|
||||
|
||||
```hbs preview-template
|
||||
<figure>
|
||||
<figcaption>
|
||||
The correct classes added/omitted
|
||||
</figcaption>
|
||||
<div
|
||||
class={{class-map
|
||||
'component-name'
|
||||
(array 'add-this-class' true)
|
||||
(array 'dont-add-this-class' false)
|
||||
'simple-string-class'
|
||||
}}
|
||||
...attributes
|
||||
>
|
||||
<code>
|
||||
class="{{class-map
|
||||
(array 'add-this-class' true)
|
||||
(array 'dont-add-this-class' false)
|
||||
'simple-string-class'
|
||||
}}"
|
||||
</code>
|
||||
</div>
|
||||
</figure>
|
||||
```
|
||||
|
||||
## Positional Arguments
|
||||
|
||||
| Argument | Type | Default | Description |
|
||||
| --- | --- | --- | --- |
|
||||
| `entries` | `(classInfo \| string)[]` | | An array of 'entry-like' arrays of `classInfo`s to map |
|
||||
|
||||
## Types
|
||||
|
||||
| Type | Default | Description |
|
||||
| --- | --- | --- |
|
||||
| `classInfo` | `([string, boolean] \| [string])` | |
|
||||
|
@ -0,0 +1,12 @@
|
||||
import Modifier from 'ember-modifier';
|
||||
import { inject as service } from '@ember/service';
|
||||
|
||||
export default class CSSPropModifier extends Modifier {
|
||||
@service('-document') doc;
|
||||
didReceiveArguments() {
|
||||
const params = this.args.positional;
|
||||
const options = this.args.named;
|
||||
const returns = params[1] || options.returns;
|
||||
returns(this.doc.defaultView.getComputedStyle(this.element).getPropertyValue(params[0]));
|
||||
}
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
# css-prop
|
||||
|
||||
Get the value for a single specific CSS Property from the modified element.
|
||||
`returns` can be specified either as a second parameter or an option.
|
||||
|
||||
```hbs preview-template
|
||||
<div
|
||||
{{css-prop '--red-500' returns=(set this 'red')}}
|
||||
>
|
||||
<code>--red-500: {{this.red}}</code>
|
||||
</div>
|
||||
```
|
||||
|
||||
## Positional Arguments
|
||||
|
||||
| Argument | Type | Default | Description |
|
||||
| --- | --- | --- | --- |
|
||||
| `property` | `string` | | The name of the CSS property to fetch from the element |
|
||||
| `returns` | `function` | | Usually `set` or `mut` or similar |
|
||||
|
||||
## Named Arguments
|
||||
|
||||
| Argument | Type | Default | Description |
|
||||
| --- | --- | --- | --- |
|
||||
| `returns` | `function` | | See the `returns` positional argument |
|
@ -0,0 +1,147 @@
|
||||
---
|
||||
layout: docs
|
||||
page_title: AWS ECS
|
||||
description: >-
|
||||
Configuration Reference for Consul on AWS ECS (Elastic Container Service).
|
||||
Do not modify by hand! This is automatically generated documentation.
|
||||
---
|
||||
|
||||
# Configuration Reference
|
||||
|
||||
This pages details the configuration options for the JSON config format used
|
||||
by the `consul-ecs` binary. This configuration is passed to the `consul-ecs`
|
||||
binary as a string using the `CONSUL_ECS_CONFIG_JSON` environment variable.
|
||||
|
||||
This configuration format follows a [JSON schema](https://github.com/hashicorp/consul-ecs/blob/main/config/schema.json)
|
||||
that can be used for validation.
|
||||
|
||||
## Terraform Mesh Task Module Configuration
|
||||
|
||||
The `mesh-task` Terraform module provides input variables for commonly used fields.
|
||||
The following table shows which Terraform input variables correspond to each field
|
||||
of the Consul ECS configuration. Refer to the
|
||||
[Terraform registry documentation](https://registry.terraform.io/modules/hashicorp/consul-ecs/aws/latest/submodules/mesh-task?tab=inputs)
|
||||
for a complete reference of supported input variables for the `mesh-task` module.
|
||||
|
||||
| Terraform Input Variable | Consul ECS Config Field |
|
||||
| ------------------------ | ------------------------------------- |
|
||||
| `upstreams` | [`proxy.upstreams`](#proxy-upstreams) |
|
||||
| `checks` | [`service.checks`](#service-checks) |
|
||||
| `consul_service_name` | [`service.name`](#service) |
|
||||
| `consul_service_tags` | [`service.tags`](#service) |
|
||||
| `consul_service_meta` | [`service.meta`](#service) |
|
||||
| `consul_namespace` | [`service.namespace`](#service) |
|
||||
| `consul_partition` | [`service.partition`](#service) |
|
||||
|
||||
Each of these Terraform input variables follow the Consul ECS config schema.
|
||||
The remaining fields of the Consul ECS configuration not listed in this table can be passed
|
||||
using the `consul_ecs_config` input variable.
|
||||
|
||||
# Top-level fields
|
||||
|
||||
These are the top-level fields for the Consul ECS configuration format.
|
||||
|
||||
| Field | Type | Required | Description |
|
||||
| ----- | ---- | -------- | ----------- |
|
||||
| `bootstrapDir` | `string` | required | The directory at which to mount the shared volume where Envoy bootstrap configuration is written by `consul-ecs mesh-init`. |
|
||||
| `healthSyncContainers` | `array` | optional | The names of containers that will have health check status synced from ECS into Consul. Cannot be specified with `service.checks`. |
|
||||
| [`proxy`](#proxy) | `object` | optional | Configuration for the sidecar proxy registration with Consul. |
|
||||
| [`service`](#service) | `object` | required | Configuration for Consul service registration. |
|
||||
|
||||
# `service`
|
||||
|
||||
Configuration for Consul service registration.
|
||||
|
||||
| Field | Type | Required | Description |
|
||||
| ----- | ---- | -------- | ----------- |
|
||||
| [`checks`](#service-checks) | `array` | optional | The list of Consul checks for the service. Cannot be specified with `healthSyncContainers`. |
|
||||
| `enableTagOverride` | `boolean` | optional | Determines if the anti-entropy feature for the service is enabled |
|
||||
| `meta` | `object` | optional | Key-value pairs of metadata to include for the Consul service. |
|
||||
| `name` | `string` | optional | The name the service will be registered as in Consul. Defaults to the Task family name if empty or null. |
|
||||
| `namespace` | `string` | optional | The Consul namespace where the service will be registered [Consul Enterprise]. |
|
||||
| `partition` | `string` | optional | The Consul admin partition where the service will be registered [Consul Enterprise]. |
|
||||
| `port` | `integer` | required | Port the application listens on, if any. |
|
||||
| `tags` | `array` | optional | List of string values that can be used to add service-level labels. |
|
||||
| [`weights`](#service-weights) | `object` | optional | Configures the weight of the service in terms of its DNS service (SRV) response. |
|
||||
|
||||
# `service.checks`
|
||||
|
||||
Defines the Consul checks for the service. Each check may contain these fields.
|
||||
|
||||
| Field | Type | Required | Description |
|
||||
| ----- | ---- | -------- | ----------- |
|
||||
| `aliasNode` | `string` | optional | Specifies the ID of the node for an alias check. |
|
||||
| `aliasService` | `string` | optional | Specifies the ID of a service for an alias check. |
|
||||
| `args` | `array` | optional | Command arguments to run to update the status of the check. |
|
||||
| `body` | `string` | optional | Specifies a body that should be sent with `HTTP` checks. |
|
||||
| `checkId` | `string` | optional | The unique ID for this check on the node. Defaults to the check `name`. |
|
||||
| `failuresBeforeCritical` | `integer` | optional | Specifies the number of consecutive unsuccessful results required before check status transitions to critical. |
|
||||
| `grpc` | `string` | optional | Specifies a `gRPC` check. Must be an endpoint that supports the [standard gRPC health checking protocol](https://github.com/grpc/grpc/blob/master/doc/health-checking.md). The endpoint will be probed every `interval`. |
|
||||
| `grpcUseTls` | `boolean` | optional | Specifies whether to use TLS for this gRPC health check. |
|
||||
| `h2ping` | `string` | optional | Specifies this is an h2ping check. Must be an address, which will be pinged every `interval`. |
|
||||
| `h2pingUseTls` | `boolean` | optional | Specifies whether TLS is used for an h2ping check. |
|
||||
| `header` | `object` | optional | Specifies a set of headers that should be set for HTTP checks. Each header can have multiple values. |
|
||||
| `http` | `string` | optional | Specifies this is an HTTP check. Must be a URL against which request is performed every `interval`. |
|
||||
| `interval` | `string` | optional | Specifies the frequency at which to run this check. Required for HTTP and TCP checks. |
|
||||
| `method` | `string` | optional | Specifies the HTTP method to be used for an HTTP check. When no value is specified, `GET` is used. |
|
||||
| `name` | `string` | optional | The name of the check. |
|
||||
| `notes` | `string` | optional | Specifies arbitrary information for humans. This is not used by Consul internally. |
|
||||
| `status` | `string` | optional | Specifies the initial status the health check. Must be one of `passing`, `warning`, `critical`, `maintenance`, or`null`. |
|
||||
| `successBeforePassing` | `integer` | optional | Specifies the number of consecutive successful results required before check status transitions to passing. |
|
||||
| `tcp` | `string` | optional | Specifies this is a TCP check. Must be an IP/hostname plus port to which a TCP connection is made every `interval`. |
|
||||
| `timeout` | `string` | optional | Specifies a timeout for outgoing connections in the case of a Script, HTTP, TCP, or gRPC check. Must be a duration string, such as `10s` or `5m`. |
|
||||
| `tlsServerName` | `string` | optional | Specifies an optional string used to set the SNI host when connecting via TLS. |
|
||||
| `tlsSkipVerify` | `boolean` | optional | Specifies if the certificate for an HTTPS check should not be verified. |
|
||||
| `ttl` | `string` | optional | Specifies this is a TTL check. Must be a duration string, such as `10s` or `5m`. |
|
||||
|
||||
# `service.weights`
|
||||
|
||||
Configures the weight of the service in terms of its DNS service (SRV) response.
|
||||
|
||||
| Field | Type | Required | Description |
|
||||
| ----- | ---- | -------- | ----------- |
|
||||
| `passing` | `integer` | required | Weight for the service when its health checks are passing. |
|
||||
| `warning` | `integer` | required | Weight for the service when it has health checks in `warning` status. |
|
||||
|
||||
# `proxy`
|
||||
|
||||
Configuration for the sidecar proxy registration with Consul.
|
||||
|
||||
| Field | Type | Required | Description |
|
||||
| ----- | ---- | -------- | ----------- |
|
||||
| `config` | `object` | optional | Object value that specifies an opaque JSON configuration. The JSON is stored and returned along with the service instance when called from the API. |
|
||||
| [`meshGateway`](#proxy-meshgateway) | `object` | optional | Specifies the mesh gateway configuration for the proxy. |
|
||||
| [`upstreams`](#proxy-upstreams) | `array` | optional | The list of the upstream services that the proxy should create listeners for. |
|
||||
|
||||
# `proxy.upstreams`
|
||||
|
||||
The list of the upstream services that the proxy should create listeners for. Each upstream may contain these fields.
|
||||
|
||||
| Field | Type | Required | Description |
|
||||
| ----- | ---- | -------- | ----------- |
|
||||
| `config` | `object` | optional | Specifies opaque configuration options that will be provided to the proxy instance for the upstream. |
|
||||
| `datacenter` | `string` | optional | Specifies the datacenter to issue the discovery query to. |
|
||||
| `destinationName` | `string` | required | Specifies the name of the upstream service or prepared query to route the service mesh to. |
|
||||
| `destinationNamespace` | `string` | optional | Specifies the namespace containing the upstream service [Consul Enterprise]. |
|
||||
| `destinationPartition` | `string` | optional | Specifies the name of the admin partition containing the upstream service [Consul Enterprise]. |
|
||||
| `destinationType` | `string` | optional | Specifies the type of discovery query the proxy should use for finding service mesh instances. Must be one of `service`, `prepared_query`, or`null`. |
|
||||
| `localBindAddress` | `string` | optional | Specifies the address to bind a local listener to. |
|
||||
| `localBindPort` | `integer` | required | Specifies the port to bind a local listener to. The application will make outbound connections to the upstream from the local port. |
|
||||
| [`meshGateway`](#proxy-upstreams-meshgateway) | `object` | optional | Specifies the mesh gateway configuration for the proxy for this upstream. |
|
||||
|
||||
## `proxy.upstreams.meshGateway`
|
||||
|
||||
Specifies the mesh gateway configuration for the proxy for this upstream.
|
||||
|
||||
| Field | Type | Required | Description |
|
||||
| ----- | ---- | -------- | ----------- |
|
||||
| `mode` | `string` | required | Specifies how the upstream with a remote destination datacenter gets resolved. Must be one of `none`, `local`, or`remote`. |
|
||||
|
||||
# `proxy.meshGateway`
|
||||
|
||||
Specifies the mesh gateway configuration for the proxy.
|
||||
|
||||
| Field | Type | Required | Description |
|
||||
| ----- | ---- | -------- | ----------- |
|
||||
| `mode` | `string` | required | Specifies how upstreams with a remote destination datacenter get resolved. Must be one of `none`, `local`, or`remote`. |
|
||||
|
@ -1,186 +0,0 @@
|
||||
---
|
||||
layout: docs
|
||||
page_title: Installation - AWS ECS
|
||||
description: >-
|
||||
Install Consul Service Mesh on AWS ECS (Elastic Container Service).
|
||||
---
|
||||
|
||||
# Installation
|
||||
|
||||
Installing Consul on ECS is a multi-part process:
|
||||
|
||||
1. [**Task Module:**](#task-module) Define the [`mesh-task` Terraform module](https://registry.terraform.io/modules/hashicorp/consul-ecs/aws/latest/submodules/mesh-task)
|
||||
to create a task definition with the necessary sidecar containers for your application to join the service mesh.
|
||||
1. [**Routing:**](#routing) With your tasks as part of the mesh, you must specify their upstream
|
||||
services and change the URLs the tasks are using so that they're making requests through the service mesh.
|
||||
1. [**Bind Address:**](#bind-address) Now that all communication is flowing through the service mesh,
|
||||
you should change the address your application is listening on to `127.0.0.1`
|
||||
so that it only receives requests through the sidecar proxy.
|
||||
|
||||
-> **NOTE:** This page assumes you're familiar with ECS. See [What is Amazon Elastic Container Service](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/Welcome.html) for more details.
|
||||
|
||||
## Task Module
|
||||
|
||||
In order to add the necessary sidecar containers for your task to join the mesh,
|
||||
you must use the [`mesh-task` module](https://registry.terraform.io/modules/hashicorp/consul-ecs/aws/latest/submodules/mesh-task):
|
||||
|
||||
```hcl
|
||||
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"
|
||||
retry_join = ["<address of the Consul server>"]
|
||||
}
|
||||
```
|
||||
|
||||
All possible inputs are documented on the [module reference documentation](https://registry.terraform.io/modules/hashicorp/consul-ecs/aws/latest/submodules/mesh-task?tab=inputs),
|
||||
however there are some important inputs worth highlighting:
|
||||
|
||||
- `family` is used as the [task definition family](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/task_definition_parameters.html#family)
|
||||
but it's also used as the name of the service that gets registered in Consul.
|
||||
- `container_definitions` accepts an array of [container definitions](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/task_definition_parameters.html#container_definitions).
|
||||
This is where you include application containers.
|
||||
- `port` is the port that your application listens on. This should be set to a
|
||||
string, not an integer, i.e. `port = "9090"`, not `port = 9090`.
|
||||
- `retry_join` is passed to the [`-retry-join`](/docs/agent/options#_retry_join) option for the Consul agent. This tells
|
||||
the agent the location of your Consul servers so that it can join the Consul cluster.
|
||||
|
||||
-> **NOTE:** If your tasks run in a public subnet, they must have `assign_public_ip = true`
|
||||
in their [`network_configuration`](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ecs_service#network_configuration) block so that ECS can pull the Docker images.
|
||||
|
||||
## ECS Service
|
||||
|
||||
To define an ECS Service, reference the mesh-task module's `task_definition_arn` output value
|
||||
in your `aws_ecs_service` resource:
|
||||
|
||||
```hcl
|
||||
resource "aws_ecs_service" "my_task" {
|
||||
...
|
||||
task_definition = module.my_task.task_definition_arn
|
||||
}
|
||||
```
|
||||
|
||||
After running `terraform apply`, you should see your tasks registered in
|
||||
the Consul UI.
|
||||
|
||||
## Routing
|
||||
|
||||
Now that your tasks are registered in the mesh, you're able to use the service
|
||||
mesh to route between them.
|
||||
|
||||
In order to make calls through the service mesh, you must configure the sidecar
|
||||
proxy to listen on a different port for each upstream service your application
|
||||
needs to call. You then must modify your application to make requests to the sidecar
|
||||
proxy on that port.
|
||||
|
||||
For example, if your application `web` makes calls to another application called `backend`, then you would first configure the `mesh-task` module's upstream(s):
|
||||
`backend`.
|
||||
|
||||
```hcl
|
||||
module "web" {
|
||||
family = "web"
|
||||
upstreams = [
|
||||
{
|
||||
destination_name = "backend"
|
||||
local_bind_port = 8080
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
- Set the `destination_name` to the name of the upstream service (in this case `backend`)
|
||||
- Set `local_bind_port` to an unused port. This is the port that the sidecar proxy
|
||||
will listen on. Any requests to this port will be forwarded over to the `destination_name`.
|
||||
This does not have to be the port that `backend` is listening on because the service mesh
|
||||
will handle routing the request to the right port.
|
||||
|
||||
If you have multiple upstream services they each need to be listed here.
|
||||
|
||||
Next, configure your application to make requests to `localhost:8080` when
|
||||
it wants to call the `backend` service.
|
||||
|
||||
For example, if your service allows configuring the URL for `backend` via the
|
||||
`BACKEND_URL` environment variable, you would set:
|
||||
|
||||
```hcl
|
||||
module "web" {
|
||||
family = "web"
|
||||
upstreams = [
|
||||
{
|
||||
destination_name = "backend"
|
||||
local_bind_port = 8080
|
||||
}
|
||||
]
|
||||
container_definitions = [
|
||||
{
|
||||
name = "web"
|
||||
environment = [
|
||||
{
|
||||
name = "BACKEND_URL"
|
||||
value = "http://localhost:8080"
|
||||
}
|
||||
]
|
||||
...
|
||||
}
|
||||
]
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
## Bind Address
|
||||
|
||||
To ensure that your application only receives traffic through the service mesh,
|
||||
you must change the address that your application is listening on to only the loopback address
|
||||
(also known as `localhost`, `lo`, and `127.0.0.1`)
|
||||
so that only the sidecar proxy running in the same task can make requests to it.
|
||||
|
||||
If your application is listening on all interfaces, e.g. `0.0.0.0`, then other
|
||||
applications can call it directly, bypassing its sidecar proxy.
|
||||
|
||||
Changing the listening address is specific to the language and framework you're
|
||||
using in your application. Regardless of which language/framework you're using,
|
||||
it's a good practice to make the address configurable via environment variable.
|
||||
|
||||
For example in Go, you would use:
|
||||
|
||||
```go
|
||||
s := &http.Server{
|
||||
Addr: "127.0.0.1:8080",
|
||||
...
|
||||
}
|
||||
log.Fatal(s.ListenAndServe())
|
||||
```
|
||||
|
||||
In Django you'd use:
|
||||
|
||||
```bash
|
||||
python manage.py runserver "127.0.0.1:8080"
|
||||
```
|
||||
|
||||
## Next Steps
|
||||
|
||||
- Configure a secure [Production Installation](/docs/ecs/get-started/production-installation).
|
||||
- Now that your applications are running in the service mesh, read about
|
||||
other [Service Mesh features](/docs/connect).
|
||||
- View the [Architecture](/docs/ecs/architecture) documentation to understand
|
||||
what's going on under the hood.
|
@ -0,0 +1,213 @@
|
||||
---
|
||||
layout: docs
|
||||
page_title: ACL Controller - AWS ECS
|
||||
description: >-
|
||||
Manual Deployment of the ACL Controller for Consul Service Mesh on AWS ECS (Elastic Container Service).
|
||||
---
|
||||
|
||||
# Install the ACL Controller
|
||||
|
||||
This topic describes how to manually deploy the ACL controller to [automatically provision ACL tokens](/docs/ecs/architecture#automatic-acl-token-provisioning) for Consul on ECS.
|
||||
If you are using Terraform, refer to the [Terraform Secure Configuration](/docs/ecs/terraform/secure-configuration) page to deploy the ACL controller.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
* Your application tasks must include certain tags to be compatible with the ACL controller.
|
||||
Refer to the [Task Tags](/docs/ecs/manual/install#task-tags) section of the installation page.
|
||||
* You should be familiar with configuring Consul's secure features, including how to create ACL tokens and policies. Refer to the following [Learn Guides](https://learn.hashicorp.com/collections/consul/security) for an introduction and the [ACL system](/docs/security/acl) documentation for more information.
|
||||
|
||||
## Set Up Secrets
|
||||
|
||||
The ACL controller supports managing secrets in AWS Secrets Manager.
|
||||
|
||||
Before deploying the ACL controller for the first time, you must [create the following secrets](https://docs.aws.amazon.com/secretsmanager/latest/userguide/manage_create-basic-secret.html) from Consul in AWS Secrets Manager.
|
||||
|
||||
| Secret | Initial Value | Sample Secret Name |
|
||||
| --------------------- | -------------- | ------------------------------ |
|
||||
| Consul server CA cert | Set | `my-consul-ca-cert` |
|
||||
| Bootstrap ACL Token | Set | `my-consul-bootstrap-token` |
|
||||
| Consul Client ACL Token | Empty | `<PREFIX>-consul-client-token` |
|
||||
|
||||
The secret for the client token must be intially empty. The ACL controller creates the client token in Consul
|
||||
and stores the token in Secrets Manager. In the secret name, `<PREFIX>` should be replaced with the
|
||||
[secret name prefix](/docs/ecs/manual/acl-controller#secret-name-prefix) of your choice.
|
||||
|
||||
### Secret Name Prefix
|
||||
|
||||
The ACL controller requires that the secrets it reads and writes are named with a unique prefix. The name prefix is used
|
||||
in the [Task Role Policy](/docs/ecs/manual/acl-controller#task-role-policy) to limit the ACL controller's access within
|
||||
AWS Secrets Manager to only those secrets strictly needed by the ACL controller.
|
||||
|
||||
The name prefix should be unique among secrets in your AWS account. We recommend using a short (8 character) random
|
||||
string for the prefix.
|
||||
|
||||
-> **NOTE:** If you are using the ACL controller with multiple ECS clusters, each cluster requires
|
||||
its own instance of the ACL controller, and each instance of the ACL controller should have a unique
|
||||
name prefix.
|
||||
|
||||
## Task Definition
|
||||
|
||||
You must create a task definition to deploy the ACL controller in your ECS cluster.
|
||||
The ACL controller must run in the same ECS cluster hosting your service mesh application
|
||||
tasks.
|
||||
|
||||
The following example shows how the task definition should be configured for the ACL controller.
|
||||
|
||||
```json
|
||||
{
|
||||
"family": "my-consul-acl-controller",
|
||||
"networkMode": "awsvpc",
|
||||
"containerDefinitions": [
|
||||
{
|
||||
"name": "acl-controller",
|
||||
"image": "public.ecr.aws/hashicorp/consul-ecs:<CONSUL_ECS_VERSION>",
|
||||
"essential": true,
|
||||
"command": [
|
||||
"acl-controller",
|
||||
"-consul-client-secret-arn", "arn:aws:secretsmanager:us-west-2:000000000000:secret:<PREFIX>-consul-client-token",
|
||||
"-secret-name-prefix", "<PREFIX>",
|
||||
],
|
||||
"secrets": [
|
||||
{
|
||||
"name": "CONSUL_HTTP_TOKEN",
|
||||
"valueFrom": "arn:aws:secretsmanager:us-west-2:000000000000:secret:my-consul-bootstrap-token"
|
||||
},
|
||||
{
|
||||
"name": "CONSUL_CACERT_PEM",
|
||||
"valueFrom": "arn:aws:secretsmanager:us-west-2:000000000000:secret:my-consul-ca-cert"
|
||||
}
|
||||
],
|
||||
"environment": [
|
||||
{
|
||||
"name": "CONSUL_HTTP_ADDR",
|
||||
"value": "<Consul server HTTP API address>"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
You must include the following top-level fields.
|
||||
|
||||
| Field name | Type | Description |
|
||||
| ----------- | ------- | ---------------------------------------------------------------------------- |
|
||||
| `family` | string | The task family name of your choice. |
|
||||
| `networkMode` | string | Must be `awsvpc`, which is the only network mode supported by Consul on ECS. |
|
||||
|
||||
In the `containerDefinitions` list, include one container with the following fields.
|
||||
|
||||
| Field name | Type | Description |
|
||||
| ----------- | ------- | -------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `name` | string | The container name, which should be `acl-controller` |
|
||||
| `image` | string | The `consul-ecs` image. Use our public AWS registry, `public.ecr.aws/hashicorp/consul-ecs`, to avoid rate limits. |
|
||||
| `command` | list | Must be set as shown. The startup command for the ACL controller. |
|
||||
| `essential` | boolean | Must be `true` to ensure the health of your application container affects the health status of the task. |
|
||||
| `secrets` | list | Must have `CONSUL_HTTP_TOKEN` set to the ACL bootstrap token and `CONSUL_CACERT_PEM` set to the Consul server CA certificate. |
|
||||
| `environment` | string | Must set the `CONSUL_HTTP_ADDR` environment variable to the address of the HTTP API of your Consul servers. |
|
||||
|
||||
The following CLI options are required in the `command` field of the container definition.
|
||||
|
||||
| Flag | Type | Description |
|
||||
| --------------------------- | ------- | -------------------------------------------------------------------------------------------------------------------- |
|
||||
| `-consul-client-secret-arn` | string | The secret where the ACL controller will store the Consul client token. |
|
||||
| `-secret-name-prefix` | string | The [secret name prefix](/docs/ecs/manual/acl-controller#secret-name-prefix) that you chose for this ACL controller. |
|
||||
|
||||
## ECS Service
|
||||
|
||||
Once the task definition is created, define an ECS service in order to start an ACL controller task.
|
||||
|
||||
The following example contains the recommended settings for the ACL controller. Refer to
|
||||
the [ECS service](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/service_definition_parameters.html) documentation
|
||||
to complete the remaining details for your use case.
|
||||
|
||||
```json
|
||||
{
|
||||
"cluster": "<Your ECS cluster ARN>"
|
||||
"desiredCount": 1,
|
||||
"launchType": "FARGATE",
|
||||
"serviceName": "my-acl-controller",
|
||||
"taskDefinition": "<task definition ARN>",
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
| Field name | Type | Description |
|
||||
| ---------------- | ------- | ---------------------------------------------------------------------------------------------------------------- |
|
||||
| `cluster` | string | Set to your ECS cluster name or ARN. This must be the same ECS cluster where your service mesh applications run. |
|
||||
| `desiredCount` | integer | Must be `1`. Only one instance of the ACL controller should run per ECS cluster. |
|
||||
| `launchType` | string | Consul on ECS supports both the `FARGATE` and `EC2` launch types. |
|
||||
| `serviceName` | string | The service name of your choice. |
|
||||
| `taskDefinition` | string | Must be set to the ACL controller [task definition](/docs/ecs/manual/acl-controller#task-definition). |
|
||||
|
||||
## AWS IAM Roles
|
||||
|
||||
The ECS task and execution roles must be configured to allow the ACL controller access
|
||||
to the ECS API and Secrets Manager API.
|
||||
|
||||
### Task Role Policy
|
||||
|
||||
The following example shows the policy needed for the ECS task role for the ACL controller.
|
||||
This grants the ACL controller permission to list tasks, describe tasks, and read and update
|
||||
secrets.
|
||||
|
||||
```json
|
||||
{
|
||||
"Version": "2012-10-17",
|
||||
"Statement": [
|
||||
{
|
||||
"Effect": "Allow",
|
||||
"Action": [
|
||||
"ecs:ListTasks",
|
||||
"ecs:DescribeTasks"
|
||||
],
|
||||
"Resource": ["*"]
|
||||
},
|
||||
{
|
||||
"Effect": "Allow",
|
||||
"Action": [
|
||||
"secretsmanager:GetSecretValue",
|
||||
"secretsmanager:UpdateSecret"
|
||||
],
|
||||
"Resource": [
|
||||
"arn:aws:secretsmanager:us-west-2:000000000000:secret:<PREFIX>-*"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
The following are the required permissions. You will need to substitute `<PREFIX>` with your chosen [name prefix](/docs/ecs/manual/acl-controller#secret-name-prefix).
|
||||
|
||||
| Action | Resource | Description |
|
||||
| ------------------------------- | ----------------------------------------------------------------- | ---------------------------------------------------------------------------------- |
|
||||
| `ecs:ListTasks` | `*` | Allow the ACL controller to watch for new tasks. |
|
||||
| `ecs:DescribeTasks` | `*` | Allow the ACL controller to retrieve details for new tasks. |
|
||||
| `secretsmanager:GetSecretValue` | `arn:aws:secretsmanager:us-west-2:000000000000:secret:<PREFIX>-*` | Allow the ACL controller to read secrets with a name prefix. |
|
||||
| `secretsmanager:UpdateSecret` | `arn:aws:secretsmanager:us-west-2:000000000000:secret:<PREFIX>-*` | Allow the ACL controller to store Consul ACL tokens in secrets with a name prefix. |
|
||||
|
||||
### Execution Role Policy
|
||||
|
||||
The following IAM policy document allows ECS to retrieve secrets needed
|
||||
to start the ACL controller task from AWS Secrets Manager, including the ACL
|
||||
bootstrap token.
|
||||
|
||||
The following example shows the policy needed for the execution role.
|
||||
|
||||
```json
|
||||
{
|
||||
"Version": "2012-10-17",
|
||||
"Statement": [
|
||||
{
|
||||
"Effect": "Allow",
|
||||
"Action": [
|
||||
"secretsmanager:GetSecretValue"
|
||||
],
|
||||
"Resource": [
|
||||
"arn:aws:secretsmanager:us-west-2:000000000000:secret:my-consul-bootstrap-token",
|
||||
"arn:aws:secretsmanager:us-west-2:000000000000:secret:<PREFIX>-consul-client-token"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
@ -0,0 +1,552 @@
|
||||
---
|
||||
layout: docs
|
||||
page_title: Manual Installation - AWS ECS
|
||||
description: >-
|
||||
Manually Install Consul Service Mesh on AWS ECS (Elastic Container Service).
|
||||
---
|
||||
|
||||
# Manual Installation
|
||||
|
||||
The following instructions describe how to manually create the ECS task definition using the [`consul-ecs` Docker image](https://gallery.ecr.aws/hashicorp/consul-ecs) without Terraform. Refer to the [Consul ECS Terraform module](/docs/ecs/terraform/install) documentation for an alternative method for installing Consul on ECS.
|
||||
|
||||
This topic does not include instructions for creating all AWS resources necessary to install Consul, such as a VPC or the ECS cluster. Refer to the linked guides in the [Getting Started](/docs/ecs#getting-started) section for complete, runnable examples.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
You should have some familiarity with AWS ECS. See [What is Amazon Elastic Container Service](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/Welcome.html) for details.
|
||||
|
||||
## Task Definition
|
||||
|
||||
You must create a task definition, which includes the following containers:
|
||||
|
||||
* Your application container
|
||||
* An Envoy sidecar-proxy container
|
||||
* A Consul client container
|
||||
* A `consul-ecs-mesh-init` container for service mesh setup
|
||||
* Optionally, a `consul-ecs-health-sync` container to sync ECS health checks into Consul
|
||||
|
||||
## Top-level fields
|
||||
|
||||
Your task definition must include the following top-level fields.
|
||||
|
||||
The `volumes` list contains two [bind mounts](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/bind-mounts.html),
|
||||
named `consul_data` and `consul_binary`. Bind mounts are directories on the host which can be mounted into one or more containers
|
||||
in order to share files among containers. For Consul on ECS, certain binaries and configuration are shared among containers
|
||||
during task startup.
|
||||
|
||||
```json
|
||||
{
|
||||
"family": "my-example-client-app",
|
||||
"networkMode": "awsvpc",
|
||||
"volumes": [
|
||||
{
|
||||
"name": "consul_data",
|
||||
},
|
||||
{
|
||||
"name": "consul_binary",
|
||||
}
|
||||
],
|
||||
"containerDefinitions": [...]
|
||||
"tags": [
|
||||
{
|
||||
"key": "consul.hashicorp.com/mesh",
|
||||
"value": "true"
|
||||
},
|
||||
{
|
||||
"key": "consul.hashicorp.com/service-name",
|
||||
"value": "example-client-app"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
| Field name | Type | Description |
|
||||
| ---------------------- | ------ | ------------------------------------------------------------------------------------------------------------------ |
|
||||
| `family` | string | The task family name. This is used as the Consul service name by default. |
|
||||
| `networkMode` | string | Must be `awsvpc`, which is the only network mode supported by Consul on ECS. |
|
||||
| `volumes` | list | Must be defined as shown above. Volumes are used to share configuration between containers for intial task setup. |
|
||||
| `containerDefinitions` | list | The list of containers to run in this task (see [Application container](#application-container)). |
|
||||
|
||||
### Task Tags
|
||||
|
||||
The `tags` list must include the following if you are using the ACL controller in a [secure configuration](/docs/manual/secure-configuration).
|
||||
Without these tags, the ACL controller will be unable to provision a service token for the task.
|
||||
|
||||
| Tag Key | Tag Value | Description |
|
||||
| ----------------------------------- | ------------------- | -------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `consul.hashicorp.com/mesh` | `true` (string) | The ACL controller ignores tasks without this tag set to `true`. |
|
||||
| `consul.hashicorp.com/service-name` | Consul service name | Specifies the Consul service associated with this task. Required if the service name is different than the task `family`. |
|
||||
|
||||
## Application container
|
||||
|
||||
First, include your application container in the `containerDefinitions` list
|
||||
in the task definition.
|
||||
|
||||
Ensure that the `containerName` and `condition` fields in the `dependsOn` list
|
||||
are specified as described in the following example. These are container dependencies,
|
||||
which must be used to enforce a specific [startup order](/docs/ecs/architecture#task-startup).
|
||||
By using the following settings, your application container will start after `consul-ecs-mesh-init`
|
||||
has completed task setup and after `sidecar-proxy` is ready to proxy traffic between
|
||||
this task and the service mesh.
|
||||
|
||||
```json
|
||||
{
|
||||
"containerDefinitions": [
|
||||
{
|
||||
"name": "example-client-app",
|
||||
"image": "docker.io/org/my_task:v0.0.1",
|
||||
"essential": true,
|
||||
"dependsOn": [
|
||||
{
|
||||
"containerName": "consul-ecs-mesh-init",
|
||||
"condition": "SUCCESS"
|
||||
},
|
||||
{
|
||||
"containerName": "sidecar-proxy",
|
||||
"condition": "HEALTHY"
|
||||
}
|
||||
],
|
||||
...
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
| Field name | Type | Description |
|
||||
| ----------- | ------- | -------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `name` | string | The name of your application container. |
|
||||
| `image` | string | The container image used to run your application. |
|
||||
| `essential` | boolean | Must be `true` to ensure the health of your application container affects the health status of the task. |
|
||||
| `dependsOn` | list | Must be set as shown above. Container dependencies ensure your application container starts after service mesh setup is complete. |
|
||||
|
||||
See the [ECS Task Definition](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/task_definition_parameters.html) documentation for a complete reference.
|
||||
|
||||
## `sidecar-proxy` container
|
||||
|
||||
The `sidecar-proxy` container runs [Envoy proxy](/docs/connect/proxies/envoy) for Consul Connect. In most cases, the container should contain the following parameters and values.
|
||||
|
||||
The `mountPoints` list must be set as shown in the following example. This will mount the shared `consul_data` volume into the
|
||||
`sidecar-proxy` container at the path `/consul`. This volume is where the `consul-ecs-mesh-init` container copies the `envoy-bootstrap.json`
|
||||
file and the `consul-ecs` binary, which are required to start Envoy. The `dependsOn` list must also be defined as follows to ensure the
|
||||
`sidecar-proxy` container starts after `consul-ecs-mesh-init` has successfully written these files to the shared volume.
|
||||
|
||||
<CodeBlockConfig highlight="8-40">
|
||||
|
||||
```json
|
||||
{
|
||||
"containerDefinitions": [
|
||||
{
|
||||
"name": "example-client-app",
|
||||
"image": "docker.io/org/my_task:v0.0.1",
|
||||
...
|
||||
},
|
||||
{
|
||||
"name": "sidecar-proxy",
|
||||
"image": "envoyproxy/envoy-alpine:<VERSION>",
|
||||
"essential": false,
|
||||
"dependsOn": [
|
||||
{
|
||||
"containerName": "consul-ecs-mesh-init",
|
||||
"condition": "SUCCESS"
|
||||
}
|
||||
],
|
||||
"healthCheck": {
|
||||
"retries": 3,
|
||||
"command": ["nc", "-z", "127.0.0.1", "20000"],
|
||||
"timeout": 5,
|
||||
"interval": 30
|
||||
},
|
||||
"mountPoints": [
|
||||
{
|
||||
"readOnly": true,
|
||||
"containerPath": "/consul",
|
||||
"sourceVolume": "consul_data"
|
||||
}
|
||||
],
|
||||
"ulimits": [
|
||||
{
|
||||
"name": "nofile",
|
||||
"softLimit": 1048576,
|
||||
"hardLimit": 1048576
|
||||
}
|
||||
],
|
||||
"command": ["envoy", "--config-path", "/consul/envoy-bootstrap.json"],
|
||||
"entryPoint": ["/consul/consul-ecs", "envoy-entrypoint"],
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
</CodeBlockConfig>
|
||||
|
||||
The following table describes the necessary configuration settings.
|
||||
|
||||
| Field name | Type | Description |
|
||||
| ------------- | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `name` | string | The container name, which must be `sidecar-proxy`. |
|
||||
| `image` | string | The Envoy image. This must be a [supported version of Envoy](/docs/connect/proxies/envoy#supported-versions). |
|
||||
| `dependsOn` | list | Must be set as shown above to ensure Envoy starts after the `consul-ecs-mesh-init` container has written the `envoy-bootstrap.json` config file for Envoy. |
|
||||
| `healthCheck` | list | Must be set as shown above to monitor the health of Envoy's primary listener port, which ties into container dependencies and startup ordering. |
|
||||
| `mountPoints` | list | Must be set as shown above to access the files shared in the `/consul` directory, like the Envoy bootstrap configuration file and the `consul-ecs` binary. |
|
||||
| `ulimits` | list | The `nofile` ulimit must be raised to a sufficiently high value so that Envoy does not fail to open sockets. |
|
||||
| `entrypoint` | list | Must be set to the custom Envoy entrypoint, `consul-ecs envoy-entrypoint`, to facilitate graceful shutdown. |
|
||||
| `command` | list | The startup command. This passes the bootstrap configuration to Envoy. |
|
||||
|
||||
-> **NOTE**: Envoy and Consul must be compatible versions. See the [supported versions of Envoy](/docs/connect/proxies/envoy#supported-versions) in the Consul documentation.
|
||||
|
||||
## `consul-client` container
|
||||
|
||||
Each task must include a Consul client container in order for the task to join your Consul cluster.
|
||||
|
||||
<CodeBlockConfig highlight="13-31">
|
||||
|
||||
```json
|
||||
{
|
||||
"containerDefinitions": [
|
||||
{
|
||||
"name": "example-client-app",
|
||||
"image": "docker.io/org/my_task:v0.0.1",
|
||||
...
|
||||
},
|
||||
{
|
||||
"name": "sidecar-proxy",
|
||||
"image": "envoyproxy/envoy-alpine:<ENVOY_VERSION>",
|
||||
...
|
||||
}
|
||||
{
|
||||
"name": "consul-client"
|
||||
"image": "public.ecr.aws/hashicorp/consul:<CONSUL_VERSION>",
|
||||
"mountPoints": [
|
||||
{
|
||||
"readOnly": false,
|
||||
"containerPath": "/consul",
|
||||
"sourceVolume": "consul_data"
|
||||
},
|
||||
{
|
||||
"containerPath": "/bin/consul-inject",
|
||||
"sourceVolume": "consul_binary"
|
||||
}
|
||||
],
|
||||
"entryPoint": ["/bin/sh", "-ec"],
|
||||
"command": [
|
||||
"cp /bin/consul /bin/consul-inject/consul\n\nECS_IPV4=$(curl -s $ECS_CONTAINER_METADATA_URI_V4 | jq -r '.Networks[0].IPv4Addresses[0]')\n\n\ncat << EOF > /consul/agent-defaults.hcl\naddresses = {\n dns = \"127.0.0.1\"\n grpc = \"127.0.0.1\"\n http = \"127.0.0.1\"\n}\nadvertise_addr = \"$ECS_IPV4\"\nadvertise_reconnect_timeout = \"15m\"\nclient_addr = \"0.0.0.0\"\ndatacenter = \"dc1\"\nenable_central_service_config = true\nleave_on_terminate = true\nports {\n grpc = 8502\n}\nretry_join = [\n \"<Consul server location>",\n]\ntelemetry {\n disable_compat_1.9 = true\n}\n\nEOF\n\ncat << EOF > /consul/agent-extra.hcl\naddresses = {\n dns = \"0.0.0.0\"\n}\nlog_level = \"debug\"\n\nEOF\n\nexec consul agent \\\n -data-dir /consul/data \\\n -config-file /consul/agent-defaults.hcl \\\n -config-file /consul/agent-extra.hcl\n"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
</CodeBlockConfig>
|
||||
|
||||
| Field name | Type | Description |
|
||||
| ------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `name` | string | The container name, which should always be `consul-client`. |
|
||||
| `image` | string | The Consul image. Use our public AWS registry, `public.ecr.aws/hashicorp/consul`, to avoid rate limits. |
|
||||
| `mountPoints` | list | Must be set as shown above. Volumes are mounted to share information with other containers for task setup. |
|
||||
| `entrypoint` | list | Must be set to a plain shell so that the startup `command` works properly. |
|
||||
| `command` | list | Specifies the contents of the [startup script](#consul-client-startup-script). Copy the script and format it into a JSON string. |
|
||||
|
||||
### Consul client startup script
|
||||
|
||||
The following script is used to start the Consul client for Consul on ECS.
|
||||
|
||||
```shell
|
||||
# Copy the consul binary to a shared volume for `consul-ecs-mesh-init` to use to generate Envoy configuration.
|
||||
cp /bin/consul /bin/consul-inject/consul
|
||||
|
||||
# At runtime, determine the IP address assigned to this ECS Task.
|
||||
ECS_IPV4=$(curl -s $ECS_CONTAINER_METADATA_URI_V4 | jq -r '.Networks[0].IPv4Addresses[0]')
|
||||
|
||||
# Write the Consul agent configuration file.
|
||||
cat << EOF > /consul/agent-defaults.hcl
|
||||
addresses = {
|
||||
dns = "127.0.0.1"
|
||||
grpc = "127.0.0.1"
|
||||
http = "127.0.0.1"
|
||||
}
|
||||
advertise_addr = "$ECS_IPV4"
|
||||
advertise_reconnect_timeout = "15m"
|
||||
client_addr = "0.0.0.0"
|
||||
datacenter = "dc1"
|
||||
enable_central_service_config = true
|
||||
leave_on_terminate = true
|
||||
ports {
|
||||
grpc = 8502
|
||||
}
|
||||
retry_join = ["<consul server location>"]
|
||||
telemetry {
|
||||
disable_compat_1.9 = true
|
||||
}
|
||||
|
||||
EOF
|
||||
|
||||
# Start the consul agent.
|
||||
exec consul agent \
|
||||
-data-dir /consul/data \
|
||||
-config-file /consul/agent-defaults.hcl
|
||||
```
|
||||
|
||||
The following table describes the values that you should use to configure the `command` script:
|
||||
|
||||
| Field name | Type | Description |
|
||||
| -------------------- | ------- | ------------------------------------------------------------------------------------------------------------ |
|
||||
| `addresses.*` | strings | Set the DNS, GRPC, and HTTP addresses to `127.0.0.1` to ensure these are not accessible outside of the task. |
|
||||
| `advertise_addr` | string | Must be set to the task IP address so that other Consul agents know how to reach this agent. |
|
||||
| `client_addr` | string | Must be set to an interface reachable by other Consul agents. |
|
||||
| `datacenter` | string | Must be set to the Consul datacenter this task will join. |
|
||||
| `leave_on_terminate` | boolean | Must be set to `true` so that the Consul agent leaves the cluster gracefully before exiting. |
|
||||
| `retry_join` | string | Must be set to your Consul server location(s) so this agent can join the Consul cluster. |
|
||||
|
||||
-> **NOTE**: Use `exec` to start the Consul agent so that the Consul agent runs as PID 1. This ensures
|
||||
the Consul agent directly receives signals from ECS, which is important for graceful shutdown of the Consul agent.
|
||||
|
||||
Refer to the [Consul Agent documentation](/docs/agent/options#configuration_files) for a complete reference of Consul agent
|
||||
configuration options.
|
||||
|
||||
## `consul-ecs-mesh-init` container
|
||||
|
||||
The `consul-ecs-mesh-init` container runs at task startup to setup this instance for Consul service mesh.
|
||||
It registers the service and proxy for this task with Consul and writes Envoy bootstrap
|
||||
configuration to a shared volume.
|
||||
|
||||
<CodeBlockConfig highlight="18-41">
|
||||
|
||||
```json
|
||||
{
|
||||
"containerDefinitions": [
|
||||
{
|
||||
"name": "example-client-app",
|
||||
"image": "docker.io/org/my_task:v0.0.1",
|
||||
...
|
||||
},
|
||||
{
|
||||
"name": "sidecar-proxy",
|
||||
"image": "envoyproxy/envoy-alpine:<ENVOY_VERSION>",
|
||||
...
|
||||
},
|
||||
{
|
||||
"name": "consul-client"
|
||||
"image": "public.ecr.aws/hashicorp/consul:<CONSUL_VERSION>",
|
||||
...
|
||||
},
|
||||
{
|
||||
"name": "consul-ecs-mesh-init",
|
||||
"image": "public.ecr.aws/hashicorp/consul-ecs:<CONSUL_ECS_VERSION>",
|
||||
"command": ["mesh-init"],
|
||||
"essential": false,
|
||||
"environment": [
|
||||
{
|
||||
"name": "CONSUL_ECS_CONFIG_JSON",
|
||||
"value": "{\"bootstrapDir\":\"/consul\",\"healthSyncContainers\":[],\"proxy\":{\"upstreams\":[{\"destinationName\":\"example-server-app\",\"localBindPort\":1234}]},\"service\":{\"checks\":[],\"meta\":{},\"name\":\"example-client-app\",\"port\":9090,\"tags\":[]}}"
|
||||
}
|
||||
],
|
||||
"mountPoints": [
|
||||
{
|
||||
"readOnly": false,
|
||||
"containerPath": "/consul",
|
||||
"sourceVolume": "consul_data"
|
||||
},
|
||||
{
|
||||
"readOnly": true,
|
||||
"containerPath": "/bin/consul-inject",
|
||||
"sourceVolume": "consul_binary"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
</CodeBlockConfig>
|
||||
|
||||
| Field name | Type | Description |
|
||||
| ----------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `name` | string | The container name should be `consul-ecs-mesh-init`. |
|
||||
| `image` | string | The `consul-ecs` image. Use our public AWS registry, `public.ecr.aws/hashicorp/consul-ecs`, to avoid rate limits. |
|
||||
| `mountPoints` | list | Must be set as show above, so the `consul` and `consul-ecs` binaries can be shared among containers for task setup. |
|
||||
| `command` | list | Set to `["mesh-init"]` so that the container runs the `consul-ecs mesh-init` command. |
|
||||
| `environment` | list | This must include the [`CONSUL_ECS_CONFIG_JSON`](/docs/ecs/manual-installation#consul_ecs_config_json) variable. See below for details. |
|
||||
|
||||
### `CONSUL_ECS_CONFIG_JSON`
|
||||
|
||||
Configuration is passed to the `consul-ecs` binary in JSON format using the `CONSUL_ECS_CONFIG_JSON` environment variable.
|
||||
|
||||
The following is an example of the configuration that might be used for a service named `example-client-app` with one upstream
|
||||
service name `example-server-app`. The `proxy` and `service` blocks include information used by `consul-ecs-mesh-init` to perform
|
||||
[service registration](/docs/discovery/services) with Consul during task startup. The same configuration format is used for
|
||||
the `consul-ecs-health-sync` container.
|
||||
|
||||
```json
|
||||
{
|
||||
"bootstrapDir": "/consul",
|
||||
"healthSyncContainers": [],
|
||||
"proxy": {
|
||||
"upstreams": [
|
||||
{
|
||||
"destinationName": "example-server-app",
|
||||
"localBindPort": 1234
|
||||
}
|
||||
]
|
||||
},
|
||||
"service": {
|
||||
"checks": [],
|
||||
"meta": {},
|
||||
"name": "example-client-app",
|
||||
"port": 9090,
|
||||
"tags": []
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
| Field name | Type | Description |
|
||||
| ---------------------- | ------ | ----------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `bootstrapDir` | string | This is the path of a shared volume that is mounted to other containers, where `consul-ecs-mesh-init` will write out Envoy configuration. |
|
||||
| `healthSyncContainers` | list | Used for [health status syncing](/docs/ecs/manual-installation#consul-ecs-health-sync-container) from ECS to Consul. See below for details. |
|
||||
| `proxy.upstreams` | list | The upstream services that your application calls over the service mesh, if any. The `destinationName` and `localBindPort` fields are required. |
|
||||
| `service.name` | string | The name used to register this service into the Consul service catalog. |
|
||||
| `service.port` | integer | The port your application listens on. Set to `0` if your application does not listen on any port. |
|
||||
| `service.checks` | list | Consul [checks](/docs/discovery/checks) to include so that Consul can run health checks against your application. |
|
||||
|
||||
See the [Configuration Reference](/docs/ecs/configuration-reference) for a complete reference of fields.
|
||||
|
||||
## `consul-ecs-health-sync` container
|
||||
|
||||
Optionally, Consul ECS can sync health checks for this task into Consul checks.
|
||||
This allows you to configure a health check for your application in one place and
|
||||
see a consistent health status in both ECS and Consul.
|
||||
|
||||
For example, the following defines an ECS health check command that runs `curl localhost:9090/health`:
|
||||
|
||||
<CodeBlockConfig highlight="6-11">
|
||||
|
||||
```json
|
||||
{
|
||||
"containerDefinitions": [
|
||||
{
|
||||
"name": "example-client-app",
|
||||
"image": "docker.io/org/my_task:v0.0.1",
|
||||
"healthCheck": {
|
||||
"retries": 3,
|
||||
"command": ["CMD-SHELL", "curl localhost:9090/health"],
|
||||
"timeout": 5,
|
||||
"interval": 30
|
||||
},
|
||||
...
|
||||
},
|
||||
...
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
</CodeBlockConfig>
|
||||
|
||||
First, define which containers need their health status synced into Consul. To do this,
|
||||
add the container name(s) to the `healthSyncContainers` list of the `CONSUL_ECS_CONFIG_JSON` variable,
|
||||
as shown in the following example. This configuration must be passed to both the `consul-ecs-mesh-init`
|
||||
and `consul-ecs-health-sync` containers.
|
||||
|
||||
<CodeBlockConfig highlight="3-3">
|
||||
|
||||
```json
|
||||
{
|
||||
"bootstrapDir": "/consul",
|
||||
"healthSyncContainers": ["example-client-app"],
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
</CodeBlockConfig>
|
||||
|
||||
Next, set the `CONSUL_ECS_CONFIG_JSON` variable for the `consul-ecs-mesh-init` container.
|
||||
The following example shows how the `CONSUL_ECS_CONFIG_JSON` variable should be formatted.
|
||||
The JSON configuration is compacted down to a single line and escaped.
|
||||
|
||||
<CodeBlockConfig highlight="7-10">
|
||||
|
||||
```json
|
||||
{
|
||||
"containerDefinitions": [
|
||||
{
|
||||
"name": "consul-ecs-mesh-init",
|
||||
"image": "public.ecr.aws/hashicorp/consul-ecs:<VERSION>",
|
||||
"environment": [
|
||||
{
|
||||
"name": "CONSUL_ECS_CONFIG_JSON",
|
||||
"value": "{\"bootstrapDir\":\"/consul\",\"healthSyncContainers\":[\"example-client-app\"],\"proxy\":{\"upstreams\":[{\"destinationName\":\"example-server-app\",\"localBindPort\":1234}]},\"service\":{\"checks\":[],\"meta\":{},\"name\":\"example-client-app\",\"port\":9090,\"tags\":[]}}"
|
||||
}
|
||||
],
|
||||
...
|
||||
},
|
||||
...
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
</CodeBlockConfig>
|
||||
|
||||
Finally, include the `consul-ecs-health-sync` container in the `containerDefinitions` list.
|
||||
Pass the same value for `CONSUL_ECS_CONFIG_JSON` for both the `consul-ecs-health-sync`
|
||||
and `consul-ecs-mesh-init` containers.
|
||||
|
||||
<CodeBlockConfig highlight="23-40">
|
||||
|
||||
```json
|
||||
{
|
||||
"containerDefinitions": [
|
||||
{
|
||||
"name": "example-client-app",
|
||||
"image": "docker.io/org/my_task:v0.0.1",
|
||||
...
|
||||
},
|
||||
{
|
||||
"name": "sidecar-proxy",
|
||||
"image": "envoyproxy/envoy-alpine:<ENVOY_VERSION>",
|
||||
...
|
||||
},
|
||||
{
|
||||
"name": "consul-client"
|
||||
"image": "public.ecr.aws/hashicorp/consul:<CONSUL_VERSION>",
|
||||
...
|
||||
},
|
||||
{
|
||||
"name": "consul-ecs-mesh-init",
|
||||
"image": "public.ecr.aws/hashicorp/consul-ecs:<CONSUL_ECS_VERSION>",
|
||||
...
|
||||
},
|
||||
{
|
||||
"name": "consul-ecs-health-sync",
|
||||
"image": "public.ecr.aws/hashicorp/consul-ecs:<CONSUL_ECS_VERSION>",
|
||||
"command": ["health-sync"],
|
||||
"essential": false,
|
||||
"dependsOn": [
|
||||
{
|
||||
"containerName": "consul-ecs-mesh-init",
|
||||
"condition": "SUCCESS"
|
||||
}
|
||||
],
|
||||
"environment": [
|
||||
{
|
||||
"name": "CONSUL_ECS_CONFIG_JSON",
|
||||
"value": "{\"bootstrapDir\":\"/consul\",\"healthSyncContainers\":[\"example-client-app\"],\"proxy\":{\"upstreams\":[{\"destinationName\":\"example-server-app\",\"localBindPort\":1234}]},\"service\":{\"checks\":[],\"meta\":{},\"name\":\"example-client-app\",\"port\":9090,\"tags\":[]}}"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
</CodeBlockConfig>
|
||||
|
||||
| Field name | Type | Description |
|
||||
| ------------- | ------ | ----------------------------------------------------------------------------------------------------------------- |
|
||||
| `name` | string | The container name, which must be `consul-ecs-health-sync`. |
|
||||
| `image` | string | The `consul-ecs` image. Use our public AWS registry, `public.ecr.aws/hashicorp/consul-ecs`, to avoid rate limits. |
|
||||
| `command` | list | Must be set to `["health-sync"]` to run the `consul-ecs health-sync` command. |
|
||||
| `dependsOn` | list | Must be set as shown above to ensure the `health-sync` container starts after service registration has completed. |
|
||||
| `environment` | list | Must include the `CONSUL_ECS_CONFIG_JSON` variable to pass configuration to the `consul-ecs health-sync` command. |
|
||||
|
||||
# Next Steps
|
||||
|
||||
* Create the task definition using the [AWS Console](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ecs-taskdefinition.html) or the [AWS CLI](https://docs.aws.amazon.com/cli/latest/reference/ecs/register-task-definition.html), or another method of your choice.
|
||||
* Create an [ECS Service](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/ecs_services.html) to start tasks using the task definition.
|
||||
* Follow the [Secure Configration](/docs/ecs/manual/secure-configuration) to get production-ready.
|
@ -0,0 +1,215 @@
|
||||
---
|
||||
layout: docs
|
||||
page_title: Secure Configuration - AWS ECS
|
||||
description: >-
|
||||
Manual Secure Confguration of the Consul Service Mesh on AWS ECS (Elastic Container Service).
|
||||
---
|
||||
|
||||
# Secure Configuration
|
||||
|
||||
For a production-ready installation of Consul on ECS, you will need to make sure that the cluster is secured.
|
||||
A secure Consul cluster should include the following:
|
||||
|
||||
1. [TLS Encryption](/docs/security/encryption#rpc-encryption-with-tls) for RPC communication between Consul clients and servers.
|
||||
1. [Gossip Encryption](/docs/security/encryption#gossip-encryption) for encrypting gossip traffic.
|
||||
1. [Access Control (ACLs)](/docs/security/acl) for authentication and authorization for Consul clients and services on the mesh.
|
||||
|
||||
-> **NOTE:** In this topic, we assume that you have already configured your Consul server with the security-related features.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
* You should already have followed the [installation instructions](/docs/ecs/manual/install) to understand how to define
|
||||
the necessary components of the task definition for Consul on ECS.
|
||||
* You should be familiar with [specifying sensitive data](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/specifying-sensitive-data.html) on ECS.
|
||||
* You should be familiar with configuring Consul's secure features, including how to create ACL tokens and policies. Refer to the following [Learn Guides](https://learn.hashicorp.com/collections/consul/security) for an introduction and the [ACL system](/docs/security/acl) documentation for more information.
|
||||
|
||||
## ACL Tokens
|
||||
|
||||
You must create 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
|
||||
|
||||
The following sections describe the ACL polices which must be associated with these token types.
|
||||
|
||||
-> **NOTE:** This section describes how operators would create ACL tokens by hand. To ease operator
|
||||
burden, the ACL Controller can automatically create ACL tokens for Consul on ECS. Refer to the
|
||||
[ACL Controller](/docs/manual/acl-controller) page for installation details.
|
||||
|
||||
### Create Consul client token
|
||||
|
||||
You must create a token for the Consul client. This is a shared token used by the `consul-client`
|
||||
containers to join the Consul cluster.
|
||||
|
||||
The following is the ACL policy needed for the Consul client token:
|
||||
|
||||
```hcl
|
||||
node_prefix "" {
|
||||
policy = "write"
|
||||
}
|
||||
service_prefix "" {
|
||||
policy = "read"
|
||||
}
|
||||
```
|
||||
|
||||
This policy allows `node:write` for any node name, which is necessary because the Consul node
|
||||
names on ECS are not known until runtime.
|
||||
|
||||
### Create service tokens
|
||||
|
||||
Service tokens should be associated with a [service identity](https://www.consul.io/docs/security/acl/acl-system#acl-service-identities).
|
||||
The service identity includes `service:write` permissions for the service and sidecar proxy.
|
||||
|
||||
The following example shows how to use the Consul CLI to create a service token for a service named `example-client-app`:
|
||||
|
||||
```shell
|
||||
consul acl token create -service-identity=example-client-app ...
|
||||
```
|
||||
|
||||
-> **NOTE**: You will need to create one service token for each registered Consul service in ECS,
|
||||
including when new services are added to the service mesh.
|
||||
|
||||
## Secret storage
|
||||
|
||||
You should securely store the following secrets in order to make them available to ECS tasks.
|
||||
|
||||
1. Consul Server CA certificate
|
||||
2. Consul gossip encryption key
|
||||
3. Consul client ACL token
|
||||
4. Consul service ACL tokens (one per service)
|
||||
|
||||
These secrets can be securely stored and passed to ECS tasks using either of the following AWS secret services:
|
||||
|
||||
* [AWS Systems Manager Parameter Store](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/specifying-sensitive-data-parameters.html)
|
||||
* [AWS Secrets Manager](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/specifying-sensitive-data-secrets.html)
|
||||
|
||||
Once the secrets are stored they can be referenced using their ARN. The following shows
|
||||
example secret ARNs when using AWS Secrets Manager:
|
||||
|
||||
| Secret | Sample Secret ARN |
|
||||
| ---------------------- | ---------------------------------------------------------------------------------- |
|
||||
| Consul Server CA Cert | `arn:aws:secretsmanager:us-west-2:000000000000:secret:my-consul-ca-cert` |
|
||||
| Gossip encryption key | `arn:aws:secretsmanager:us-west-2:000000000000:secret:my-consul-gossip-key` |
|
||||
| Client token | `arn:aws:secretsmanager:us-west-2:000000000000:secret:my-consul-client-token` |
|
||||
| Service token | `arn:aws:secretsmanager:us-west-2:000000000000:secret:my-example-client-app-token` |
|
||||
|
||||
## Configure `consul-client`
|
||||
|
||||
The following secrets must be passed to the `consul-client` container:
|
||||
|
||||
* Consul server CA certificate
|
||||
* Gossip encryption key
|
||||
* Consul client ACL token
|
||||
|
||||
The following example shows how to include these secrets in the task definition. The `secrets`
|
||||
list specifies environment variable `name`s 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.
|
||||
|
||||
```json
|
||||
{
|
||||
"containerDefinitions": [
|
||||
{
|
||||
"name": "consul-client"
|
||||
"image": "public.ecr.aws/hashicorp/consul:<CONSUL_VERSION>",
|
||||
"secrets": [
|
||||
{
|
||||
"name": "CONSUL_CACERT",
|
||||
"valueFrom": "arn:aws:secretsmanager:us-west-2:000000000000:secret:my-consul-ca-cert"
|
||||
},
|
||||
{
|
||||
"name": "CONSUL_GOSSIP_ENCRYPTION_KEY",
|
||||
"valueFrom": "arn:aws:secretsmanager:us-west-2:000000000000:secret:my-consul-gossip-key"
|
||||
},
|
||||
{
|
||||
"name": "AGENT_TOKEN",
|
||||
"valueFrom": "arn:aws:secretsmanager:us-west-2:000000000000:secret:my-consul-client-token"
|
||||
}
|
||||
]
|
||||
},
|
||||
...
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
Next, update Consul configuration options to pass the secrets to the Consul client.
|
||||
|
||||
The following is an example of the *additional* content to include in the `consul-client` startup script. Refer to the [install
|
||||
page](/docs/ecs/manual/install#consul-client-container) for the remainder of the startup script and how to pass this
|
||||
script to the container.
|
||||
|
||||
<CodeBlockConfig highlight="3-4,10-29">
|
||||
|
||||
```shell
|
||||
...
|
||||
|
||||
# Write the CA Cert to a file
|
||||
echo "$CONSUL_CACERT" > /tmp/consul-ca-cert.pem
|
||||
|
||||
# Write the Consul agent configuration file.
|
||||
cat << EOF > /consul/agent-defaults.hcl
|
||||
...
|
||||
|
||||
# Configure gossip encryption key
|
||||
encrypt = "$CONSUL_GOSSIP_ENCRYPTION_KEY"
|
||||
|
||||
# Configure TLS settings
|
||||
auto_encrypt = {
|
||||
tls = true
|
||||
ip_san = ["$ECS_IPV4"]
|
||||
}
|
||||
ca_file = "/tmp/consul-ca-cert.pem"
|
||||
verify_outgoing = true
|
||||
|
||||
# Configure ACLs
|
||||
acl {
|
||||
enabled = true
|
||||
default_policy = "deny"
|
||||
down_policy = "async-cache"
|
||||
tokens {
|
||||
agent = "$AGENT_TOKEN"
|
||||
}
|
||||
}
|
||||
|
||||
EOF
|
||||
```
|
||||
|
||||
</CodeBlockConfig>
|
||||
|
||||
The following table describes the additional fields that must be included in the Consul client configuration file.
|
||||
|
||||
| Field name | Type | Description |
|
||||
| --------------------------------------------------------- | ------- | ------------------------------------------------------------------------------------ |
|
||||
| [`encrypt`](/docs/agent/options#_encrypt) | string | Specifies the gossip encryption key |
|
||||
| [`ca_file`](/docs/agent/options#ca_file) | string | Specifies the Consul server CA cert for TLS verification. |
|
||||
| [`acl.enabled`](/docs/agent/options#acl_enabled) | boolen | Enable ACLs for this agent. |
|
||||
| [`acl.tokens.agent`](/docs/agent/options#acl_tokens_agent) | string | Specifies the Consul client token which authorizes this agent with Consul servers. |
|
||||
|
||||
## Configure `consul-ecs-mesh-init` and `consul-ecs-health-sync`
|
||||
|
||||
Both `consul-ecs-mesh-init` and `consul-ecs-health-sync` containers need to be configured with
|
||||
the service ACL token. This allows these containers to make HTTP API requests to the local
|
||||
Consul client for service registration and health syncing.
|
||||
|
||||
The following shows how to set the `CONSUL_HTTP_TOKEN` variable to the service token for the `example-client-app` service,
|
||||
if the token is stored in AWS Secrets Manager.
|
||||
|
||||
<CodeBlockConfig highlight="5-8">
|
||||
|
||||
```json
|
||||
{
|
||||
"containerDefinitions": [
|
||||
{
|
||||
"secrets": [
|
||||
{
|
||||
"name": "CONSUL_HTTP_TOKEN",
|
||||
"valueFrom": "arn:aws:secretsmanager:us-west-2:000000000000:secret:my-example-client-app-token"
|
||||
}
|
||||
]
|
||||
},
|
||||
...
|
||||
],
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
</CodeBlockConfig>
|
@ -0,0 +1,276 @@
|
||||
---
|
||||
layout: docs
|
||||
page_title: Installing Consul on AWS ECS using Terraform
|
||||
description: >-
|
||||
Install Consul Service Mesh on AWS ECS with Terraform (Elastic Container Service).
|
||||
---
|
||||
|
||||
# Installation with Terraform
|
||||
|
||||
This topic describes how to use the [`mesh-task`](https://registry.terraform.io/modules/hashicorp/consul-ecs/aws/latest/submodules/mesh-task) Terraform module to launch your application in AWS ECS as part of Consul service mesh. If you do not use Terraform, see the [Manual Installation](/docs/ecs/manual-installation) page to install Consul on ECS without Terraform.
|
||||
|
||||
This topic does not include instructions for creating all AWS resources necessary to install Consul, such as a VPC or the ECS cluster. Refer to the linked guides in the [Getting Started](/docs/ecs#getting-started) section for complete, runnable examples.
|
||||
|
||||
## Overview
|
||||
|
||||
This topic describes the following procedure:
|
||||
|
||||
1. Create Terraform configuration files for the necessary components:
|
||||
|
||||
* [ECS task definition](#using-the-mesh-task-module): Use the `mesh-task` module to create an ECS task definition for Consul on ECS
|
||||
* [ECS service](#ecs-service): Use the `aws_ecs_service` resource to create an ECS service that schedules service mesh tasks to run on ECS
|
||||
|
||||
2. [Run Terraform](#running-terraform) to deploy the resources in AWS
|
||||
|
||||
## Prerequisites
|
||||
|
||||
* You should have some familiarity with using Terraform. Refer to the [Terraform documentation](https://www.terraform.io/docs) to learn about infrastructure as code and how to get started with Terraform.
|
||||
* You should also be familiar with AWS ECS before following these instructions. See [What is Amazon Elastic Container Service](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/Welcome.html) for details.
|
||||
|
||||
## Using the Mesh Task Module
|
||||
|
||||
To run an application in ECS with Consul service mesh, you must create an ECS task definition, which includes your application container(s)
|
||||
and additional sidecar containers, such as the Consul agent container and the Envoy sidecar proxy container.
|
||||
|
||||
The [`mesh-task` module](https://registry.terraform.io/modules/hashicorp/consul-ecs/aws/latest/submodules/mesh-task) will automatically include the necessary sidecar containers.
|
||||
|
||||
The following example shows a Terraform configuration file that creates a task definition with an application container called `example-client-app` in a file called `mesh-task.tf`:
|
||||
|
||||
<CodeBlockConfig filename="mesh-task.tf">
|
||||
|
||||
```hcl
|
||||
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
|
||||
retry_join = ["<address of the Consul server>"]
|
||||
}
|
||||
```
|
||||
|
||||
</CodeBlockConfig>
|
||||
|
||||
The following fields are required. Refer to the [module reference documentation](https://registry.terraform.io/modules/hashicorp/consul-ecs/aws/latest/submodules/mesh-task?tab=inputs) for a complete reference.
|
||||
|
||||
| Input Variable | Type | Description |
|
||||
| ----------------------- | -------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `source` | string | Must be set to the source location of the `mesh-task` module, `hashicorp/consul-ecs/aws//modules/mesh-task`. |
|
||||
| `version` | string | Must be set to the version of the `mesh-task` module. |
|
||||
| `family` | string | The [ECS task definition family](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/task_definition_parameters.html#family). The family is also used as the Consul service name by default. |
|
||||
| `container_definitions` | list | This is the list of [container definitions](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/task_definition_parameters.html#container_definitions) for the task definition. This is where you include your application containers. |
|
||||
| `essential` | boolean | Must be `true` to ensure the health of your application container affects the health status of the task. |
|
||||
| `port` | integer | The port that your application listens on, if any. If your application does not listen on a port, set `outbound_only = true`. |
|
||||
| `retry_join` | list | The is the [`retry_join`](/docs/agent/options#_retry_join) option for the Consul agent, which specifies the locations of your Consul servers. |
|
||||
|
||||
### Running Terraform
|
||||
|
||||
You will need to 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 the [AWS Terraform provider](https://registry.terraform.io/providers/hashicorp/aws/latest/docs)
|
||||
documentation for complete configuration details.
|
||||
|
||||
<CodeBlockConfig filename="provider.tf">
|
||||
|
||||
```hcl
|
||||
terraform {
|
||||
required_providers {
|
||||
aws = {
|
||||
source = "hashicorp/aws"
|
||||
version = "<latest version>"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
provider "aws" {
|
||||
region = "<AWS region>"
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
</CodeBlockConfig>
|
||||
|
||||
Additional AWS resources for your project can be included in additional Terraform configuration files
|
||||
in the same directory. The following example shows a basic project directory:
|
||||
|
||||
```shell-session
|
||||
$ ls
|
||||
mesh-task.tf
|
||||
provider.tf
|
||||
...
|
||||
```
|
||||
|
||||
Terraform should be run in your project directory as follows.
|
||||
|
||||
* Run `terraform init` first to download dependencies, such as Terraform providers
|
||||
* Run `terraform apply` to have Terraform create AWS resources, such as the task definition from the `mesh-task` module.
|
||||
|
||||
Terraform automatically reads all files in the current directory that have a `.tf` file extension.
|
||||
Refer to the [Terraform documentation](https://www.terraform.io/docs) for more information and Terraform best practices.
|
||||
|
||||
## ECS Service
|
||||
|
||||
[ECS services](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/ecs_services.html) are one of the most common
|
||||
ways to start tasks using a task definition.
|
||||
|
||||
To define an ECS service, reference the `mesh-task` module's `task_definition_arn` output value
|
||||
in your `aws_ecs_service` resource. The following example shows how to include the service in the `mesh-task.tf` file.
|
||||
|
||||
<CodeBlockConfig filename="mesh-task.tf" highlight="6-12">
|
||||
|
||||
```hcl
|
||||
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"
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
</CodeBlockConfig>
|
||||
|
||||
This is a partial configuration to highlight some important fields.
|
||||
See the [`aws_ecs_service`](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ecs_service) documentation for a complete reference.
|
||||
|
||||
| Input Variable | Type | Description |
|
||||
| ----------------- | ------- | ------------------------------------------------------------------------------------------------------------------- |
|
||||
| `name` | string | The name of the ECS service. This is required by AWS but is not used by Consul service mesh. |
|
||||
| `task_definition` | string | The task definition used to start tasks. Set this to the task definition ARN returned by the `mesh-task` module. |
|
||||
| `launch_type` | string | The launch type. Consul on ECS supports the `FARGATE` and `EC2` launch types. |
|
||||
| `propagate_tags` | string | This must be set to `TASK_DEFINITION` so that tags added by `mesh-task` to the task definition are copied to tasks. |
|
||||
|
||||
After including the ECS service in your Terraform configuration, run `terraform apply`
|
||||
from your project directory to create the ECS service resource. The ECS service will
|
||||
soon start your application in a task. The task will automatically register itself
|
||||
into the Consul service catalog during startup.
|
||||
|
||||
-> **NOTE:** If your tasks run in a public subnet, they must have `assign_public_ip = true`
|
||||
in their [`network_configuration`](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ecs_service#network_configuration) block so that ECS can pull the Docker images.
|
||||
|
||||
## Routing
|
||||
|
||||
Now that your tasks are registered in the mesh, you're able to use the service
|
||||
mesh to route between them.
|
||||
|
||||
In order to make calls through the service mesh, you must configure the sidecar
|
||||
proxy to listen on a different port for each upstream service your application
|
||||
needs to call. You then must modify your application to make requests to the sidecar
|
||||
proxy on that port.
|
||||
|
||||
For example, if your application `web` makes calls to another application called `backend`, then you would first configure the `mesh-task` module's upstream(s):
|
||||
|
||||
```hcl
|
||||
module "web" {
|
||||
family = "web"
|
||||
upstreams = [
|
||||
{
|
||||
destinationName = "backend"
|
||||
localBindPort = 8080
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
| Input Variable | Type | Description |
|
||||
| ----------------- | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `destinationName` | string | The name of the upstream service, as it is registered in the Consul service catalog. |
|
||||
| `localBindPort` | integer | Requests to this port will be forwarded by the proxy to the upstream service. This must be an unused port, but does not need to match the upstream service port. |
|
||||
|
||||
If you have multiple upstream services they each need to be listed here.
|
||||
|
||||
Next, configure your application to make requests to `localhost:8080` when
|
||||
it wants to call the `backend` service.
|
||||
|
||||
For example, if your service allows configuring the URL for `backend` via the
|
||||
`BACKEND_URL` environment variable, you would set:
|
||||
|
||||
```hcl
|
||||
module "web" {
|
||||
family = "web"
|
||||
upstreams = [
|
||||
{
|
||||
destinationName = "backend"
|
||||
localBindPort = 8080
|
||||
}
|
||||
]
|
||||
container_definitions = [
|
||||
{
|
||||
name = "web"
|
||||
environment = [
|
||||
{
|
||||
name = "BACKEND_URL"
|
||||
value = "http://localhost:8080"
|
||||
}
|
||||
]
|
||||
...
|
||||
}
|
||||
]
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
## Bind Address
|
||||
|
||||
To ensure that your application only receives traffic through the service mesh,
|
||||
you must change the address that your application is listening on to only the loopback address
|
||||
(also known as `localhost`, `lo`, and `127.0.0.1`)
|
||||
so that only the sidecar proxy running in the same task can make requests to it.
|
||||
|
||||
If your application is listening on all interfaces, e.g. `0.0.0.0`, then other
|
||||
applications can call it directly, bypassing its sidecar proxy.
|
||||
|
||||
Changing the listening address is specific to the language and framework you're
|
||||
using in your application. Regardless of which language/framework you're using,
|
||||
it's a good practice to make the address configurable via environment variable.
|
||||
|
||||
For example in Go, you would use:
|
||||
|
||||
```go
|
||||
s := &http.Server{
|
||||
Addr: "127.0.0.1:8080",
|
||||
...
|
||||
}
|
||||
log.Fatal(s.ListenAndServe())
|
||||
```
|
||||
|
||||
In Django you'd use:
|
||||
|
||||
```bash
|
||||
python manage.py runserver "127.0.0.1:8080"
|
||||
```
|
||||
|
||||
## Next Steps
|
||||
|
||||
- Follow the [Secure Configuration](/docs/ecs/secure-configuration) to get production-ready.
|
||||
- Now that your applications are running in the service mesh, read about
|
||||
other [Service Mesh features](/docs/connect).
|
||||
- View the [Architecture](/docs/ecs/architecture) documentation to understand
|
||||
what's going on under the hood.
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue