Setting up a Cloudflare Argo Tunnel on AWS Fargate.

Jose López
November 8th, 2020 · 2 min read

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:

1cloudflared 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.

1FROM debian:stretch-slim
2
3RUN apt-get update && \
4 apt-get dist-upgrade --yes && \
5 apt-get install wget --yes && \
6 wget https://bin.equinox.io/c/VdrWdbjqyF/cloudflared-stable-linux-amd64.deb && \
7 dpkg -i cloudflared-stable-linux-amd64.deb && \
8 rm cloudflared-stable-linux-amd64.deb && \
9 apt-get install -y \
10 python3 \
11 python3-pip \
12 python3-setuptools \
13 groff \
14 less \
15 && pip3 install --upgrade pip \
16 && apt-get clean
17
18RUN pip3 --no-cache-dir install --upgrade awscli
19
20ADD entrypoint.sh /usr/local/bin/entrypoint.sh
21
22RUN chmod +x /usr/local/bin/entrypoint.sh
23
24ENTRYPOINT ["/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.

1#!/usr/bin/env bash
2
3set -ueo pipefail
4
5aws s3 cp ${S3_CERT_PEM} /etc/cloudflared/
6
7echo -e "url: ${ORIGIN_DNS}
8hostname: ${TUNNEL_HOSTNAME}" > /etc/cloudflared/config.yml
9
10set +ex
11
12for i in {1..60}
13do
14 wget ${ORIGIN_DNS} 1>/dev/null 2>&1
15
16 if [ $? -ne 0 ]; then
17 echo "Attempt to connect to ${ORIGIN_DNS} failed."
18 sleep 1
19 else
20 echo "Connected to origin ${ORIGIN_DNS} successfully."
21 break
22 fi
23done
24
25set -ex
26
27cloudflared 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.

1<<DEFINITION
2[
3 {
4 "name": "cloudflare-argo-tunnel",
5 "image": "<ECR_REPO>:<TAG>",
6 "environment": [
7 {
8 "name": "S3_CERT_PEM",
9 "value": "s3://<BUCKET>/<CERT_PEM>"
10 },
11 {
12 "name": "ORIGIN_DNS",
13 "value": "http://<ALB_DNS>"
14 },
15 {
16 "name": "TUNNEL_HOSTNAME",
17 "value": "https://example.com"
18 }
19 ]
20 }
21]
22DEFINITION

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).

More articles from Obytes

Authentication in React Native, Easy, Secure, and Reusable solution.

A guide to build a generic solution that handles most of the authentication use cases and easy to copy-paste in your next project.

August 17th, 2020 · 3 min read

Building a Full-Text Search App Using Django, Docker and Elasticsearch

In this article, I will be giving you brief information about Elasticsearch, its installation, and some examples of usage.

August 13th, 2020 · 2 min read

ABOUT US

Our mission and ambition is to challenge the status quo, by doing things differently we nurture our love for craft and technology allowing us to create the unexpected.