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
- Add your website to Cloudflare.
- Change your DNS to Cloudflare.
- Enable Argo Smart Routing for your account.
- 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).