Setting up a Cloudflare Argo Tunnel on AWS Fargate.

Setting up a Cloudflare Argo Tunnel on AWS Fargate.

What is a Cloudflare Argo Tunnel?

Argo Tunnel provides a secure way to connect your origin to Cloudflare without a publicly routable IP address. With Tunnel, you don’t expose an external IP from your infrastructure to the Internet. Instead, a lightweight daemon runs in your infrastructure and creates outbound-only connections to Cloudflare’s edge. It can be used, in some cases, as an alternative to a VPN.

Argo Tunnel offers an easy way to expose web servers securely to the internet, without opening up firewall ports and configuring ACLs. Argo Tunnel also ensures requests route through Cloudflare before reaching the web server, so you can be sure attack traffic is stopped with Cloudflare’s WAF and Unmetered DDoS mitigation, and authenticated with Access if you’ve enabled those features for your account.

By combining Cloudflare Argo Tunnels with Cloudflare Access, we can achieve a great solution to give access to your internal services to people in a secure way, without exposing your services publicly and avoiding the complexity of a VPN service.

For more information, check out Cloudflare Argo Tunnel docs and How Argo Tunnel works..

Set up a Cloudflare Argo Tunnel on AWS Fargate

Argo Tunnel relies on cloudflared to create a persistent connection between your web server and the Cloudflare network.

Prerequisites

  1. Add your website to Cloudflare.
  2. Change your DNS to Cloudflare.
  3. Enable Argo Smart Routing for your account.
  4. Install cloudflared.

Generate a certificate to manage tunnels

Now, we now to generate a certificate that cloudflared will use to create tunnels and change DNS routing.

Once we have installed cloudflared, we need to run the following command:

cloudflared tunnel login

This command will open a browser and prompt you to authenticate with your Cloudflare account.

Once you're authenticated, Cloudflare will return a certificate file, cert.pem, that we will need to save to use later on Fargate to manage our tunnels.

Create a Docker image and a custom entrypoint to auto-create Argo tunnels

We are going to create a new Docker image that will contain cloudflared and awscli. We will need awscli to retrieve the certificate file we generated previously from S3.

So, we are going to use the following Dockerfile. Based on debian:stretch-slim, it installs cloudflared and awscli and adds our custom Docker entrypoint.

FROM debian:stretch-slim

RUN apt-get update && \
    apt-get dist-upgrade --yes && \
    apt-get install wget --yes && \
    wget https://bin.equinox.io/c/VdrWdbjqyF/cloudflared-stable-linux-amd64.deb && \
    dpkg -i cloudflared-stable-linux-amd64.deb && \
    rm cloudflared-stable-linux-amd64.deb && \
    apt-get install -y \
    python3 \
    python3-pip \
    python3-setuptools \
    groff \
    less \
    && pip3 install --upgrade pip \
    && apt-get clean    

RUN pip3 --no-cache-dir install --upgrade awscli

ADD entrypoint.sh /usr/local/bin/entrypoint.sh

RUN chmod +x /usr/local/bin/entrypoint.sh

ENTRYPOINT ["/usr/local/bin/entrypoint.sh"]

The entrypoint.sh file will, first, retrieve the certificate file from S3, then configure our ORIGIN and HOSTNAME for the tunnel, checks that cloudflared has connectivity to the origin and set up the tunnel using cloudflared.

#!/usr/bin/env bash

set -ueo pipefail

aws s3 cp ${S3_CERT_PEM} /etc/cloudflared/

echo -e "url: ${ORIGIN_DNS}
hostname: ${TUNNEL_HOSTNAME}" > /etc/cloudflared/config.yml 

set +ex

for i in {1..60}
do
  wget ${ORIGIN_DNS} 1>/dev/null 2>&1

  if [ $? -ne 0 ]; then
    echo "Attempt to connect to ${ORIGIN_DNS} failed."
    sleep 1
  else
    echo "Connected to origin ${ORIGIN_DNS} successfully."
    break
  fi
done

set -ex

cloudflared tunnel --no-autoupdate

S3_CERT_PEM: Path to the cert.pem file (i.e. s3://<bucket>/<cert.pem>)

ORIGIN_DNS: DNS of the origin we want cloudflared to connect to (i.e. internal-alb-13435345.us-east-1.elb.amazonaws.com)

TUNNEL_HOSTNAME: Tunnel hostname (i.e. example.com)

cloudflared tunnel is run with the option --no-autoupdate because this was causing the Fargate containers to go on a restart loop.

Start a Fargate container for cloudflared

Once we have this setup, we only need to deploy our ECS service using the Docker image we previously created. This is an example of a container definition for a cloudflared service pointing to a load balancer.

<<DEFINITION
[
  {
    "name": "cloudflare-argo-tunnel",
    "image": "<ECR_REPO>:<TAG>",
    "environment": [
      {
        "name": "S3_CERT_PEM",
        "value": "s3://<BUCKET>/<CERT_PEM>"
      },
      {
        "name": "ORIGIN_DNS",
        "value": "http://<ALB_DNS>"
      },
      {
        "name": "TUNNEL_HOSTNAME",
        "value": "https://example.com"
      }
    ]
  }
]
DEFINITION

It's worth noting that cloudflared service needs access to your origin, so make sure to permission cloudflared on the origin security group.

And this is all! If you have any doubt, feel free to reach me out using the comments or via Twitter (@kstromeiraos).

Jose López
Jose López
2020-11-08 | 4 min read
Share article

More articles