Search…
Using ngrok + OAuth for private tunnels
Describes a use case to protect private services in Release with OAuth using ngrok

Introduction

A common use case for Release customers is to deploy a helper application or dashboard to ephemeral environments that may not be secret in an ephemeral environment but should be kept private from outside casual observers. For example, your application template may expose a database container with an easy-to-guess password for ease of troubleshooting or editing. Alternately, your application template may deploy a lightweight administrative tool or interface that is useful for debugging or monitoring the application in the development cycle. If anyone could gain access to the tool, they might be able to view or alter your application configuration.
The heavy-weight solution of using a Adding SSH Bastion Access to Services or a corporate VPN may be cumbersome to gain approval, setup, and use for something simple and disposable like an admin tool deployed in an ephemeral environment. Another use case is being able to share a link with an outside member of your organisation (for example, a developer, a customer, a potential client, or a vendor) without needing to setup expensive and time consuming access controls and configuration.

ngrok vs. Open Source Proxies

There are many ways to create a proxy layer in front of a private or protected application in your Release application environment. This Github document lists many you can investigate. In this document we use ngrok because it offers a simple and relatively cheap method to expose an application in a very secure, lightweight, and very safe way without adding a lot of extra configuration and maintenance infrastructure.

Prerequisites

You will need the following items to begin this setup.
  • An ngrok account (a free account might work for one-off environments. A business license can help with multiple accounts in a wildcard setup. Visit ngrok's pricing page for more details)
  • An ngrok token (preferably one that is generated specifically for this use case so it can be revoked or changed without impacting a regularly used token somewhere else)
  • A Release application running in your Release account
  • A service that you would like to expose via the proxy tunnel
  • An OAuth/SAML/OIDC service provider, like Google Workspaces (optional, may incur higher vendor charges)
  • A custom domain name for your private pages (optional, may incur higher vendor charges)

Setup

Service to expose

Let's suppose you want to expose the following service via the proxy tunnel:
1
services:
2
- name: docsbuild
3
image: mycoolrepo/mycoolapp/docsbuild
4
registry: local
5
has_repo: true
6
ports:
7
- type: node_port
8
target_port: '80'
9
port: '80'
10
build:
11
context: "."
12
dockerfile: docs/Dockerfile
Copied!
Let's say the docsbuild service is not for public consumption and we would like to view it along with our code deployments in pre-production settings. Normally, the main application is configured with authentication and auth controls, but the docs are just web pages and would be difficult to protect. If you added a regular hostnames: section to your application, the documentation would be exposed to the internet. Let's create a private tunnel for an additional layer of secrecy.

Add the ngrok Tunnel

We can expose the application via ngrok, using a simple container as follows. Add the following to your application environment variables template:
1
services:
2
docbuild-tunnel:
3
- key: NGROK_AUTH
4
value: mysecretauthtoken
5
secret: true
6
- key: NGROK_LOOK_DOMAIN
7
value: docsbuild
8
- key: NGROK_BINDTLS
9
value: "true"
Copied!
The NGROK_AUTH token is self explanatory, but the rest need to be explained. In this case, the NGROK_LOOK_DOMAIN is the service to expose via the ngrok tunnel, in this case it would be http://docsbuild from above. If you were exposing a different port or hostname, adjust as needed. You could consider adding a sidecar and pointing to http://localhost for even more privacy. The NGROK_BINDTLS option tells ngrok to only support https: traffic which is obviously correct.
Then simply instantiate this service along side your other services in the application template as follows:
1
services:
2
- name: docsbuild-tunnel
3
image: wernight/ngrok
Copied!
It's so simple it might be magic! Add both services to your setup workflow but do not add the tunnel service to your patch flow since it does not need to be restarted during deploys:
1
workflows:
2
- name: setup
3
paralellize:
4
- step: docs
5
tasks:
6
- services.docsbuild
7
- services.docsbuild-tunnel
8
wait_for_finish: false
9
- name: patch
10
paralellize:
11
- step: docs
12
tasks:
13
- services.docusaurus
14
wait_for_finish: false
Copied!

Grab the tunnel address

Exposing the tunnel service logs will reveal the one-time url in the ngrok.io similar to the following:
1
ngrok by @inconshreveable
2
3
Tunnel Status online
4
Version 2.0/2.0
5
Web Interface http://localhost:4040
6
Forwarding https://abc.ngrok.io -> docsbuild:80
7
8
Connnections ttl opn rt1 rt5 p50 p90
9
0 0 0.00 0.00 0.00 0.00
Copied!
Pointing your browser at the forwarding port will show your documentation pages!
Did you know that you could also expose the ngrok dashboard that runs on port 4040 by using a hostnames: or yet another tunnel pointed at the ngrok tunnel server? The ngrok tunnel dashboard could be used for various development or debugging services but the dashboard itself will be exposed on the internet and might need to be protected as well.

Bonus Points: use an easy subdomain

You may wish to use a well-known custom domain name for your application tunnel endpoint. This may incur additional costs and additional upgrades to your ngrok account. Please refer to the documentation and pricing pages. Simply add a subdomain directive to your environment variable template:
1
services:
2
docsbuild-tunnel:
3
- key: NGROK_SUBDOMAIN
4
value: mydocs
Copied!
Which yields something like this output:
1
ngrok by @inconshreveable
2
3
...
4
Forwarding https://mydocs.ngrok.io -> docsbuild:80
Copied!

Bonus Points: use a custom branded domain

Or even better, a fully customised hostname and make sure you follow the setup instructions:
1
services:
2
docsbuild-tunnel:
3
- key: NGROK_HOSTNAME
4
value: mydocs.example.com
Copied!
Which yields something like this output:
1
ngrok by @inconshreveable
2
3
...
4
Forwarding https://mydocs.example.com -> docsbuild:80
Copied!

Bonus Points: use password protection

Add a simple basic auth password:
1
services:
2
docsbuild-tunnel:
3
- key: NGROK_USERNAME
4
value: "myuser"
5
- key: NGROK_PASSWORD
6
value: "mypassword"
7
secret: true
Copied!

Bonus Points: use OAuth protection

Be sure to read the documentation on ngrok Link first and configure an Edge, then associate the NGROK_AUTH token with an ACL to attach to the custom Edge. You can add various Edge modules including Mutual TLS, IP restrictions, OIDC, SAML, and OAuth more and more!