What is Inlets

"Inlets is a Cloud Native Tunnel written in Go, you can use it to connect services to other networks like the Internet through NAT, firewall and restrictive networks.

inlets creates a tunnel between two networks using a web-socket and optional TLS for encryption. The main use-case for inlets is to expose a private API or service on the Internet, or to gain incoming network access (ingress) to a private network." - docs.inlets.dev

Let's get to the setup!

What I'll be demoing today is a flavour of Inlets which is open-source and can offer a L7-tunnel for HTTP/HTTPS, but if you want to expose your local server to L4 (or raw TCP traffic) with automatic encryption with TLS, then you can use inlets-pro and opt in for a free 14-day trial license.

The web service

For demo purposes I'll be creating the standard demo react-app, so make sure you have the latest version of node and npm installed on your machine

# Install create-react-app with npm
npm install -g create-react-app

# Create and run a react app
create-react-app hello-utsav
cd hello-utsav
npm start
The react app starts up in a new window, running on port 3000 by default

Download inletsctl and inlets

In this demo we're going to use a tool called inletsctl which under the inlets umbrella and helps you to download inlets/inlets-pro, provision a instance automatically with the help of a user provided service account and gives example commands that helps you delete the instance aka the exit-node when you're done with it. To download inletsctl simply run:

# Download and install inletsctl
sudo curl -sLSf https://inletsctl.inlets.dev | sh

# Download and install inlets
sudo inletsctl download
We have inletsctl and inlets installed!

Get a service account key file from Google Cloud Platform

Now we want set up ourselves with a service account key credential which is authorized to create an exit-node on Google Compute Engine.
We can use inletsctl to provision exit-nodes on almost every major cloud platform like Google Cloud Platform, AWS, Azure, DigitalOcean, Civo, Scaleway and Packet.
But I'm going to use Google Cloud Platform today, more specifically GCE because I love GCP + I'm also the one responsible for writing the Google Compute Engine provisioner ❤️

We can get the service account key file by using the Google Cloud Console as well as by using the gcloud command line tool for Google Cloud if you have that setup already configured with your account and project (If you don't you can follow the instructions here).

Getting the service account key file from Google Cloud Console:

Step 1: Navigate to console.cloud.google.com and select the project you want to use

Step 2: Click on the Hamburger icon and go to IAM & Admin > Service Accounts and click on "+ Create Service Account"

Step 3: Put in a service account name and a description and click Create

Step 4: Assign the Service Account User role and Compute Admin role to the service account and click Continue

Step 5: Now in the Create key (optional) section click on the "+ CREATE KEY" button. A right pane will appear, choose JSON from the radio button as the key type and click CREATE to download it, then click on "DONE"


Get a service account key file from gcloud CLI

We can get the service account key file by using gcloud just as we did with the cloud console. I have documented the instructions for creating the service account file as a PR in the official inletsctl repo which you can find here, but I'm going to document the same here anyway!

# Get current projectID
export PROJECTID=$(gcloud config get-value core/project 2>/dev/null)

# Create a service account
gcloud iam service-accounts create inlets \
--description "inlets-operator service account" \
--display-name "inlets"

# Get service account email
export SERVICEACCOUNT=$(gcloud iam service-accounts list | grep inlets | awk '{print $2}')

# Assign appropriate roles to inlets service account
gcloud projects add-iam-policy-binding $PROJECTID \
--member serviceAccount:$SERVICEACCOUNT \
--role roles/compute.admin

gcloud projects add-iam-policy-binding $PROJECTID \
--member serviceAccount:$SERVICEACCOUNT \
--role roles/iam.serviceAccountUser

# Create inlets service account key file
gcloud iam service-accounts keys create key.json \
--iam-account $SERVICEACCOUNT

Now lets use inletsctl to provision our exit node!

Since we already have the service account key file from using either the Google Cloud Console or gcloud cli, now we're going to run inletsctl to provision our exit-node. Even though the exit-node should be chosen to be provisioned at the nearest geographical zone from you, I'm going to use the us-central1-a zone to provision my exit-node for demo purposes because at the time of writing this post you get 720 hrs free every month with the default machine type used by the inletsctl GCE provisioner code i.e., a f1-micro machine, making it run for almost free!

Now we can simply run:

# Running inletsctl create with gce as the provisioner

inletsctl create -p gce --project-id=$PROJECTID -f key.json

# If you want your exit-node to be something else other than the default us-central1-a zone, you can specify it with the `-f` flag as

inletsctl create -p gce --project-id=$PORJECTID -z europe-west4-a

A great thing about using GCE as the provisioner is that the exit nodes provision within seconds! Most of the times in less that 10 seconds!

Exit node got provisioned within 10 secs!

We get some output from inletsctl that we can simply copy and paste to connect to our exit node! In out case since our upstream server is running on port 3000, we would export the UPSTREAM env var with the value:

➜  ~ inletsctl create -p gce --project-id=$PROJECTID -f key.json
Using provider: gce
Requesting host: xenodochial-goldwasser4 in us-central1-a, from gce
2020/04/25 16:53:30 Creating firewall exists, updating: inlets
Host: xenodochial-goldwasser4|us-central1-a|uts-1382, status: provisioning
[1/500] Host: xenodochial-goldwasser4|us-central1-a|uts-1382, status: STAGING
[2/500] Host: xenodochial-goldwasser4|us-central1-a|uts-1382, status: STAGING
[3/500] Host: xenodochial-goldwasser4|us-central1-a|uts-1382, status: active
Inlets OSS exit-node summary:
  Auth-token: Xwq1CHYZAsRCQeI9lJL7JYAs7hsNqZiaJV572GUXbySazlBETZgU6ocSd8tX6AWI

  export UPSTREAM=
  inlets client --remote "ws://" \
	--token "Xwq1CHYZAsRCQeI9lJL7JYAs7hsNqZiaJV572GUXbySazlBETZgU6ocSd8tX6AWI" \
	--upstream $UPSTREAM

To Delete:
	inletsctl delete --provider gce --id "xenodochial-goldwasser4|us-central1-a|uts-1382"

Lets connect to our exit-node!

export UPSTREAM=
inlets client --remote "ws://" \
--token "Xwq1CHYZAsRCQeI9lJL7JYAs7hsNqZiaJV572GUXbySazlBETZgU6ocSd8tX6AWI" \
--upstream $UPSTREAM

You would get an output like this 👇🏽

Now that we're connected, if we visit the external IP address of the exit-node in our browser we get our familiar hello-world react app

The best part is editing the source code on your workstation also edits the content the external IP live! I have an upcoming feature as PR to inletsctl that will allow for creating a temporary tunnel, something valuable for say a remote web developer who might want to share his work with his clients, and automatically delete the tunnel when he's done previewing!

But now since we don't have that feature yet! Let's delete our tunnel with the output we got from inletsctl while creating our tunnel!
NOTE: Make sure to provide the -f flag with the service account key file as the output command can't know in advance what you named your service account file as

# Delete the exit-node from our Google Cloud Platform project
inletsctl delete --provider gce --id "xenodochial-goldwasser4|us-central1-a|uts-1382" -f key.json

You'll should get an output as under

My Thoughts

In my opinion inlets is a really powerful tool for developers as well as enterprises who want their edge devices exposed to the internet! We already have many use-cases of inlets being used in production!

Infact this entire blog post that you just read about inlets, is actually running on a two node Raspberry Pi 3 Kubernetes Cluster taking advantage of another umbrella project called inlets-operator. So the only time my blog will be down is when I'm out of power or if my Internet is down!

Waiting for the lockdown to be over to get this messy setup arranged with some standoffs

I'll write about how I managed to get this setup up and running in a future post!