In this article, we'll see how to leverage Cloudflare's argo tunnels without publicly exposing our services. In this setup we'll use EC2 as an example, but this is works with Fargate as well.
What is an Argo Tunnel?
Argo Tunnel provides a secure way to connect your origin to Cloudflare without a publicly routable IP address. With Argo Tunnel, you do not 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.
There are tons of use cases like using exposing internal applications, replacing VPN setup with Cloudflare Access possibilities are endless!
Currently, I use this setup for developing remotely on EC2's securely.
What is Cloudflare Access?
If we want to only expose this to your team internally, we can configure a zero trust access with Cloudflare access
We'll use Terraform to define our cloud resources
Let's define the providers aws
and cloudflare
which we'll be using:
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 2.7.0"
}
cloudflare = {
source = "cloudflare/cloudflare"
version = "~> 2.26.0"
}
}
required_version = ">= 0.13"
}
provider "cloudflare" {
api_token = var.cloudflare_api_token
}
We can define our api keys and secrets as variables in variables.tf
variable "region" {
type = string
default = "us-west-2"
}
variable "cloudflare_api_token" {
type = string
description = "Cloudflare api token"
default = "<YOUR_API_TOKEN>"
}
variable "cloudflare_account_id" {
type = string
description = "Cloudflare account id"
default = "<YOUR_ACCOUNT_ID>"
}
variable "cloudflare_zone_id" {
type = string
description = "Cloudflare zone id"
default = "<YOUR_ZONE_ID>"
}
variable "subdomain" {
type = string
description = "your subdomain"
default = "pretty-cool"
}
In our main.tf
file, we'll define resources. We'll first create an argo tunnel and add a cloudflare proxied record CNAME
for it so that we can use in our user_data
init script.
resource "random_id" "argo_secret" {
byte_length = 35
}
resource "cloudflare_argo_tunnel" "argo_tunnel" {
account_id = var.cloudflare_account_id
name = "${var.subdomain}-tunnel"
secret = random_id.argo_secret.b64_std
}
resource "cloudflare_record" "http_app" {
zone_id = var.cloudflare_zone_id
name = var.subdomain
value = "${cloudflare_argo_tunnel.argo_tunnel.id}.cfargotunnel.com"
type = "CNAME"
proxied = true
}
data "template_file" "init" {
template = file("my-project/init.tpl")
vars = {
subdomain = var.subdomain
domain = var.cloudflare_zone,
account = var.cloudflare_account_id,
tunnel_id = cloudflare_argo_tunnel.argo_tunnel.id,
tunnel_name = cloudflare_argo_tunnel.argo_tunnel.name,
secret = random_id.argo_secret.b64_std
}
}
resource "aws_instance" "api" {
ami = "ami-03d5c68bab01f3496"
instance_type = "t3.large"
user_data = data.template_file.init.rendered
}
In the init.tpl
we'll simply install cloudflared
and create a config.yml
and then run it in background as our EC2 starts.
#!/bin/bash
# Logs are availabe at /var/logs/cloud-init-output.log
# Install cloudflared
wget https://bin.equinox.io/c/VdrWdbjqyF/cloudflared-stable-linux-amd64.deb
sudo dpkg -i cloudflared-stable-linux-amd64.deb
# Create required dirs
mkdir ~/.cloudflared
touch ~/.cloudflared/cert.json
touch ~/.cloudflared/config.yml
# Create cert.json
cat > ~/.cloudflared/cert.json << "EOF"
{
"AccountTag" : "${account}",
"TunnelID" : "${tunnel_id}",
"TunnelName" : "${tunnel_name}",
"TunnelSecret" : "${secret}"
}
EOF
# Add a config file
cat > ~/.cloudflared/config.yml << "EOF"
tunnel: ${tunnel_id}
credentials-file: /etc/cloudflared/cert.json
logfile: /var/log/cloudflared.log
loglevel: info
ingress:
- hostname: ${subdomain}.${domain}
service: http://localhost:80
- service: http_status:404
EOF
# Start Cloudflared service
sudo cloudflared service install
sudo cp -via ~/.cloudflared/cert.json /etc/cloudflared/
sudo service cloudflared start
Once our EC2 starts, we'll be able to access it via https://pretty-cool.your-cloudflare-domain.com
and all without allowing any ingress in the security group!
Hope this was helpful!
Top comments (0)