Virtual Event
Join us for the next HashiConf Digital October 12-15, 2020 Register for Free

Service Mesh and Consul Connect

Secure Service Communication with Consul Service Mesh and Envoy

Consul service mesh secures service-to-service communication with authorization and encryption. Applications can use sidecar proxies in a service mesh configuration to automatically establish TLS connections for inbound and outbound connections without being aware of the network configuration and topology. In addition to securing your services, Consul service mesh can also intercept data about service-to-service communications and surface it to monitoring tools.

In this tutorial, you will register two services and their sidecar proxies in the Consul catalog. You will then start the services and sidecar proxies. Finally, you will demonstrate that the service-to-service communication is going through the proxies by stopping traffic with an "intention".

Flow diagram showing end user traffic being sent to the Dashboard Service at
port 9002. The dashboard service makes requests for the counting service to the
local sidecar proxy at port 5000. This traffic then traverses the service mesh
over dynamic ports. The traffic exits the service mesh from the counting
service's local proxy. The proxy sends this traffic to the counting service
itself at port 9003.

While this tutorial uses elements that are not suitable for production environments-Consul dev agents, internal proxies, and mock services—it will teach you the common process for deploying your own services using Consul service mesh. At the end of this tutorial, we also present additional information about adapting this process to more production-like environments.


  • A running Consul server with Consul service mesh enabled. For this tutorial you will use a local dev agent, which enables Consul Connect service mesh by default.

  • (Optional) Envoy binary installed on the Consul agents. Consul includes its own built-in Layer 4 (L4) proxy for testing and development but also offers first class support for Envoy as a sidecar proxy. The tutorial provides commands for both scenarios.

  • Two service applications which need to securely communicate. For this tutorial you will use two example service applications, a counter service and a dashboard. Download and unzip the executables to follow along.

»Interactive tutorial

An interactive tutorial, covering the same concepts of this tutorial, is also available. If you do not want to set up the demo environment locally, click the Show Tutorial button to launch the demo environment.

»(Optional) Install Envoy on the agent

It is possible to test Consul service mesh and follow the tutorial steps using the built-in proxy that ships with Consul. For production deployments and to enable L7 features, you should use Envoy.

You can obtain container-based builds of Envoy directly from the Envoy Website, or you can obtain a packages of Envoy binary builds from a third-party project,

Consul needs to be able to find the envoy binary in the $PATH to automatically start it without specifying the binary location.

$ curl -L | sudo bash -s -- -b /usr/local/bin
$ getenvoy run standard:1.13.0 -- --version

Copy the envoy binary in a location in your $PATH

$ sudo cp ~/.getenvoy/builds/standard/1.13.0/linux_glibc/bin/envoy /usr/local/bin/

Check that Envoy is in your $PATH by running the following command.

$ envoy --version

»Verify Consul agent health

To ensure that Consul is running and accessible from the command line, use the consul members command to verify your agent status.

$ consul members
Node            Address         Status  Type    Build  Protocol  DC   Segment
hostname.local  alive   server  1.6.2  2         dc1  <all>

If you receive an error message, verify that you have a local Consul dev agent running and try again.

»Register the services and sidecar proxies

Services have to be registered with Consul. Consul shares this information around the datacenter so that operators or other services can determine the location of a service. Consul service mesh also uses service registrations to determine where to send proxied traffic to.

There are several ways to register services in Consul:

For this tutorial, we will use the consul service register CLI command to load them into the catalog.

»Create the counting service definition

First, define the Counting service and its sidecar proxy in a file named counting.hcl. The definition should include the name of the service, the port the service listens on, and a connect block with the sidecar_service block. This block is empty so Consul will use default parameters. The definition also includes an optional service health check.

service {
  name = "counting"
  id = "counting-1"
  port = 9003

  connect {
    sidecar_service {}

  check {
    id       = "counting-check"
    http     = "http://localhost:9003/health"
    method   = "GET"
    interval = "1s"
    timeout  = "1s"

Services and sidecar proxies can be defined in either HCL or JSON. There is a JSON version of the service definition in the demo-consul-101 project.

»Create the dashboard service definition

Create the Dashboard service and proxy definition in the same way. First, create a file named dashboard.hcl.

service {
  name = "dashboard"
  port = 9002

  connect {
    sidecar_service {
      proxy {
        upstreams = [
            destination_name = "counting"
            local_bind_port  = 5000

  check {
    id       = "dashboard-check"
    http     = "http://localhost:9002/health"
    method   = "GET"
    interval = "1s"
    timeout  = "1s"

There is a JSON version of the service definition in the demo-consul-101 project.

Notice that the dashboard definition also includes an upstream block. Upstreams are ports on the local host that will be proxied to the destination service. The upstream block's local_bind_port value is the port your service will communicate with to reach the service you depend on. The destination name is the Consul service name that the local_bind_port will proxy to.

In our scenario, the dashboard service depends on the counting service. With this configuration, when dashboard service connects to localhost:5000 it is proxied across the service mesh to the counting service.

»Register the services and proxies

Finally, you can submit the service definitions to your Consul agent. If you are using the JSON definitions, ensure that the filenames end in ".json" instead of ".hcl".

$ consul services register counting.hcl
Registered service: counting
$ consul services register dashboard.hcl
Registered service: dashboard

»Verify the services are registered

Now that you have registered your services and sidecar proxies, run consul catalog services to verify that they are present.

$ consul catalog services

From the output you can notice that two extra services *-sidecar-proxy are automatically registered alongside the one defined in the configuration files.

»Create a Consul intention

Intentions define access control for services in the service mesh and are used to control which services may establish connections. The default intention behavior is defined by the default ACL policy.

In this tutorial, this step is not necessary since the default ACL policy for the dev agent is "allow all", so connections across the services in the service mesh are automatically allowed as well. However, you will create explicit intentions as a part of deploying service mesh enabled services.

$ consul intention create dashboard counting
Created: dashboard => counting (allow)

»Start the services and sidecar proxies

Now that you have created all the necessary configuration to describe your service's connections, it's time to start your services and their sidecar proxies. We are using the & operator to run the services as background tasks. However, because they write to the console, it's best to run them in their own shell session.

Establish the local URL and start the dashboard service.

$ PORT=9002 COUNTING_SERVICE_URL="http://localhost:5000" ./dashboard-service &

Start the counting service.

PORT=9003 ./counting-service &

Next, start the sidecar proxies that will run as sidecar processes along with the service applications.

Start the built-in sidecar proxy for the counting service.

$ consul connect proxy -sidecar-for counting-1 > counting-proxy.log &

Start the built-in sidecar proxy for the dashboard service.

$ consul connect proxy -sidecar-for dashboard > dashboard-proxy.log &

»Check the dashboard interface

Open a browser and navigate to http://localhost:9002.

You should see a screen similar to the following. There is a connection indicator in the top right that will turn green and say "Connected" when the dashboard service is in communication with the counting service.

Image of Dashboard UI. There is white text on a magenta background, with the
page title "Dashboard" at the top left. There is a green indicator in the top
right with the word connected in white.  There is a large number 19 to show
sample counting output. The node name that the counting service is running on,
host01, is in very small monospaced type underneath the large

If your application is not connected, check that the Counting service is running and healthy by viewing it in the Consul UI at http://localhost:8500.

»Test the sidecar proxy connections

To test that traffic is flowing through the sidecar proxies, you will control traffic with an intention.

First, deny the Dashboard service access to the Counting service.

$ consul intention create -deny -replace dashboard counting
Created: dashboard => counting (deny)

Refresh your browser, the connection indicator in the Dashboard ui will now say "Disconnected"

Image of Dashboard UI. There is white text on a magenta background, with the
page title "Dashboard" at the top left. There is a red indicator in the top
right with the words "Counting Service is Unreachable" in white.  There is a
large number -1 to show sample counting output. The word "Unreachable"
surrounded by square brackets is in monospaced type underneath the large

You can restore communication between the services by replacing the deny intention with an allow.

$ consul intention create -allow -replace dashboard counting

Back in the browser, verify that the dashboard reconnects to the counting service.

»Clean up

Once you are done with this tutorial, you can begin cleaning up by closing the terminal in which your counting-service, dashboard-service, and proxies are running. This should automatically stop these processes.

Delete the intention from Consul.

$ consul intention delete dashboard counting
Intention deleted.

Deregister the counting service.

$ consul services deregister counting.hcl
Deregistered service: counting

Deregister the dashboard service.

$ consul services deregister dashboard.hcl
Deregistered service: dashboard

»Extend these concepts

When you want to apply this learning to a proof-of-concept or production environment, there are some additional considerations.

»Enable Connect and gRPC

When a Consul server is started with the -dev flag, it will automatically enable Consul service mesh and provide a default port for gRPC communication. These have to be configured explicitly for regular Consul agents.

# ...

ports {
  "grpc" = 8502

connect {
  enabled = true

»Next steps

Now that you have completed this tutorial, you have familiarized yourself with a basic service mesh enabled service deployment. You created and registered Consul service definitions that describe how two services communicate with each other. After starting the application and sidecar proxies, you used Consul service mesh intentions to control traffic flow between services. Finally, you learned about additional requirements required to take the concepts to a proof-of-concept environment.