# Setting up a Cloudflare Argo Tunnel on AWS Fargate.

- URL: https://www.obytes.com/blog/cloudflare-argo-tunnel
- Published: 2020-11-08
- Author: Jose López
- Topics: DevOps
- Summary: Run a Cloudflare Argo Tunnel on AWS Fargate. Build a Docker image with a custom entrypoint that auto-creates tunnels and start the cloudflared container.

## 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](https://developers.cloudflare.com/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](https://developers.cloudflare.com/argo-tunnel/) and [How Argo Tunnel works.](https://developers.cloudflare.com/argo-tunnel/learning/how-tunnel-works).

## Set up a Cloudflare Argo Tunnel on AWS Fargate

Argo Tunnel relies on [cloudflared](https://github.com/cloudflare/cloudflared) to create a persistent connection between your web server and the Cloudflare network.

### Prerequisites

1. [Add your website to Cloudflare.](https://support.cloudflare.com/hc/en-us/articles/201720164-Creating-a-Cloudflare-account-and-adding-a-website)
2. [Change your DNS to Cloudflare.](https://support.cloudflare.com/hc/en-us/articles/205195708)
3. [Enable Argo Smart Routing for your account.](https://support.cloudflare.com/hc/en-us/articles/115000224552-Configuring-Argo-through-the-UI)
4. [Install cloudflared.](https://developers.cloudflare.com/argo-tunnel/getting-started/installation/)

### 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](https://twitter.com/kstromeiraos)).
