Published
April 9, 2025

Tunnel vision: Using ngrok with your Kubernetes clusters

Sheldon Lo-A-Njoe
Sheldon Lo-A-Njoe
Senior Solutions Architect

ngrok is a popular tool for creating secure tunnels, exposing internal Kubernetes services to ops teams and developers, without complicating configurations.

This blog shows how to install the ngrok Kubernetes operator with Spectro Cloud Palette.

Common challenges in accessing Kubernetes services securely

By design, Kubernetes prioritizes internal communication, keeping its services encapsulated within the cluster for security and scalability. 

While this makes sense for production environments, it creates challenges in specific scenarios, such as debugging, testing, or granting temporary access to external users. Issues include:

  • Complex port forwarding: Setting up port-forwarding rules to expose internal services is cumbersome and often temporary, requiring constant reconfiguration.
  • Ingress configuration overhead: Deploying and managing ingress controllers, load balancers, and public IPs for secure access can be resource-intensive.
  • Risk of overexposure: Exposing services directly to the internet without proper restrictions increases the risk of unauthorized access or attacks.
  • Certificate management: Ensuring secure communication often requires handling SSL/TLS certificates, which adds complexity to the setup.

How ngrok simplifies secure access

ngrok Kubernetes operator diagram

Enter ngrok, a tool that takes the hassle out of exposing Kubernetes services. With a simple command or manifest, ngrok creates secure tunnels between your chosen endpoint and local services. It offers:

  • Instant tunnels: No need to configure ingress controllers or load balancers — ngrok provides a public URL that maps directly to your internal service.
  • Built-in security: Every ngrok tunnel is secured with HTTPS, removing the need for manual certificate handling.
  • Authentication and access control: Ngrok allows you to restrict access to your services using OAuth, SAML, OIDC with multiple identity providers, IP policies and more.
  • Ease of use: Its user-friendly CLI and dashboard make it accessible even to those unfamiliar with complex networking. 

Deploying ngrok with Palette

Here are the tools and configurations you’ll need to get started with ngrok:

  • Palette account: We will be using Palette to deploy all resources, so you will need access to a Palette account. If you don’t already have one, set up a meeting with us to get started.
  • Kubernetes cluster: A Palette-provisioned Kubernetes cluster or an imported local machine (e.g., using Minikube, Kind, or K3s) or managed EKS, AKS or GKE cluster. 
  • ngrok account: A free or paid ngrok account to securely expose Kubernetes services.

Configuring your ngrok account

Before diving into deploying the ngrok resources, we will need the following essentials prepared: 

  • ngrok API key: A unique key required to authenticate and interact with your ngrok account programmatically. 
  • Auth token: Your ngrok authentication token, used to configure the command line interface and secure your tunnels. 
  • Domain: A free random ngrok domain or a custom domain if you plan to use ngrok’s reserved or branded URLs. 

Let’s start with the API key. Go to your ngrok dashboard (https://dashboard.ngrok.com/), select API Keys under Identity & Access and then Create API Key

Ngrok dashboard API key access

Add a description for your key and select Add API Key

adding an API key from the dashboard

After selecting Add API Key, the key will be shown on screen. Make sure to copy the key and paste it into a notepad. If you lose your key, you will need to create a new one — it’s only shown once. 

How to save the generated token

Now let’s get your Auth token. Select Your Authtoken under Getting Started and copy the listed token. Store this in your notepad as well. 

Copy Authtoken

Lastly, let’s create your (free) domain. Select Domains, under Universal Gateway and select Create Domain

setting up a free domain under Universal Gateway

You can close the initial screen that pops up, as we won’t be using the ngrok CLI to set the domain. 

Closing CLI pop up

At this point, you should see a screen with a unique, randomly generated domain provided by ngrok’s free plan. This allows you to expose services at no cost but comes with limitations like randomized domains for each session, and rate limits on requests and connections. Make sure to copy and paste this into your notepad as well. 

Random domain generated

Create an addon profile for your ngrok resources

Now that you’ve gathered your API key, Authentication token and domain, let’s create a Cluster Profile in Palette for the necessary ngrok resources. In order for us to use the latest ngrok Kubernetes Ingress Controller, let’s add the ngrok Helm chart repository to Palette.

Adding Helm registries

We can add Helm registries in the Tenant Admin project -> Tenant Settings -> Registries -> Add New Helm Registry

Adding Helm registries in Palette

Fill in a name, add the https://charts.ngrok.com chart endpoint and click Confirm (everything else can stay as default). 

Helm registry name and endpoint

After adding the registry, the Last Synced status will be “Sync in progress”. Make sure to wait for that to change to a date and time. The sync will then be complete and you can create your addon profile. 

Helm registry sync

Creating macros

Before we create the Cluster Profile, let’s create three macros. Macros allow us to define key value pairs on a Project or Tenant Admin level, which can then be used with placeholder variables in our Cluster Profile layers. 

These macros make it a lot easier to update variables across multiple running clusters and allow the users to add their own custom values, which will only apply to resources deployed in their project, or inherit org level values set by an admin. 

To create the macros, go to Project Settings, open the Platform tab and select Macros. Now add the macros listed below, with your personal ngrok info. You can select Add New Macros to… add more macros. Don’t forget to select Save changes when you’re done.

  • NGROK_AUTHTOKEN
    Add your authentication token as value
  • NGROK_APIKEY
    Add your API key as value (no need to worry about mine, it will be long gone by the time you read this 🙂)
  • NGROK_DOMAIN
    Add your domain as value
creating a new macro

Creating Cluster Profiles

Now that we have our macros defined, let’s create the Cluster Profile. Cluster Profiles can be made visible from only within a project or across all projects. 

In my case, I’ve deployed a cluster in an Ngrok Demo project, so I’ll create the Cluster Profile there as well. This way, the profile will only be visible to users that have access to this project. To make your profile visible across all Projects, create it in the Tenant Admin project. 

Create your profile by making sure you’re in the right project, going to the Profiles tab and selecting Add Cluster Profile.

Adding a cluster profile

Add a name and select Add-on as the type. Full and Infrastructure will guide you through the infrastructure layers first and are infrastructure specific. Add-on Cluster Profiles can be mixed and matched with any full or infrastructure Cluster Profile, so they can be applied to any Palette provisioned or imported cluster.

Add your ngrok addon info in the cluster

We can now select the type of resource to add as a layer in the Cluster Profile. Since we added the ngrok Helm registry, we can select Add Helm chart and then Public packs

Add a helm chart

It might take a minute for all the Bitnami charts to load, so it’s faster to select your chart registry from the dropdown. After selecting the ngrok registry, select the kubernetes-ingress-controller chart, as this will contain the latest Helm chart provided by ngrok. 

Configure your ngrok pack

When adding charts this way, we download the values.yaml from the provider and they typically need some configuration before they can be deployed. In our case, we need to add the namespace, authtoken and API key

Your values.yaml might look a bit different because I’ve removed a bunch of comments, so I could fit the necessary fields in the screenshot. I’ve also set the fullnameOverride, so the deployed resources don’t get extra long names. 

For the authtoken and the API key, we need to set the variable definitions for the macros we’ve configured. After creating a macro, you can use “{{ .spectro. }}” to find all available macros (from within your project), when editing a cluster profiles layers. 

After you’ve configured the values.yaml, select Confirm & Create to save your configuration.

Confirm and create the kubernetes ingress controller

The values I’ve set: 

namespace: "ngrok-system"
fullnameOverride: "ngrok"
apiKey: "{{ .spectro.macro.NGROK_APIKEY }}"
authtoken: "{{ .spectro.macro.NGROK_AUTHTOKEN }}"

Now that we’ve created our first layer, let’s add the other manifests needed to run a test application and the services needed to connect it to ngrok and expose the test app. We’ll be adding raw YAML, so select Add Manifest to do so. 

Create a raw YAML

Add a name for the layer and then select New manifest, to add an empty YAML file where we’ll add all the necessary resources.

Add the manifest

Add a name for the manifest and select the checkmark when you want to save it and add content to the manifest. 

adding the ngrok demo app manifest

Feel free to copy the contents of the YAML below. You can find it on the ngrok Kubernetes guide as well. I’ve just replaced the tabs with spaces and I’ve added the NGROK_DOMAIN macro. If you copy YAML that’s incorrectly formatted, you will be notified in the YAML editor.

apiVersion: v1
kind: Service
metadata:
 name: game-2048
spec:
 ports:
   - name: http
     port: 80
     targetPort: 80
 selector:
   app: game-2048
 type: ClusterIP # Optional, default is ClusterIP
---
apiVersion: apps/v1
kind: Deployment
metadata:
 name: game-2048
spec:
 replicas: 1
 selector:
   matchLabels:
     app: game-2048
 template:
   metadata:  # Corrected indentation
     labels:
       app: game-2048
   spec:
     containers:
       - name: backend
         image: alexwhen/docker-2048
         ports:
           - name: http
             containerPort: 80
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
 name: game-2048
spec:
 ingressClassName: ngrok
 rules:
   - host: "{{ .spectro.macro.NGROK_DOMAIN }}"
     http:
       paths:
         - path: /
           pathType: Prefix
           backend:
             service:
               name: game-2048
               port:
                 number: 80

Make sure to also change the Install order from 0 to 1. The first layer has 0 as its order, so both layers would be deployed in parallel. However, the demo app might need ngrok-specific custom resource definitions, so it’s best to deploy that after the first layer has completed. Select Confirm Updates when you’re done with the configuration. 

ngrok-specific custom resource definitions

Now that we have our two layers configured for this Cluster Profile, select Next

two layer cluster profile build inside Palette

If all looks good, select Finish Configuration to create the profile. 

Final configuration

Deploy your Cluster Profile

Now that we have our profile configured, let’s deploy it to a cluster. For this, you will have to use a cluster you’ve provisioned or one you’ve imported.

Select your cluster, go to the Profile tab and select the + button, as seen in the screenshot. 

deploying a cluster

Select your ngrok_addons profile and select Confirm

choose you addon profile

Your profile is now listed with the other profiles, but you will need to select Save to actually apply it. You could make some last minute changes to the manifests, before applying the profile, hence the extra step of saving the shown configuration. 

Listed profiles UI

After saving the profile, you can wait for the new resources to be applied. If nothing fails, the new profile should be quick to spin up and you should see a game-2048 service, a simple web application, pop-up in the Services field.  

service selected

Accessing exposed services

You can now also go back to your ngrok dashboard and check if an Edge endpoint has been added to the Edges tab under Universal Gateway

check if an Edge endpoint has been added

Select the endpoint and check the tunnel status and backend configuration. That should look similar to the screenshot below. This tells us that our back end is correctly pointing to the game app and that the tunnel is active. 

select endpoint and backend configuration

Now let’s open our test application. You can do this by either copy-pasting the domain to your browser, or by going to Palette and selecting the exposed port 80, next to the game-2048 service. 

open the test app by selecting the exposed port 80, next to the game-2048 service. 

You might be redirected to a webpage where you need to acknowledge that you are visiting a site exposed by ngrok. Just select Visit Site to continue. 

visit site ngrok app

You should now have access to ngrok’s test game app. Now you know how simple it can be to publicly expose a Kubernetes service. 

access the ngrok test game app to publicly expose a Kubernetes service

In my case, this cluster is running locally in my homelab, meaning that I did not have to:

  • Open any ports on my firewall
  • Configure port forwarding
  • Set up reverse proxies 
  • Create any certificates

As we can see, the endpoint is secured and it has a certificate issued by Let’s Encrypt. 

endpoint is secured and it has a certificate issued by Let’s Encrypt
certificate viewer

All we had to do was deploy the ngrok ingress controller and an Ingress rule pointing to the backend we wanted to expose. 

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
 name: game-2048
spec:
 ingressClassName: ngrok
 rules:
   - host: "{{ .spectro.macro.NGROK_DOMAIN }}"
     http:
       paths:
         - path: /
           pathType: Prefix
           backend:
             service:
               name: game-2048
               port:
                 number: 80

Of course, this is the simplest thing we can do. Ngrok provides many other security features, even in its free version, so let’s set up another layer of (free) security. 

Add an extra layer of security with OAuth

Ngrok supports many different OAuth providers, like Github, Facebook, LinkedIn, Amazon, Microsoft, Google and more. Let’s add Google OAuth. To do so, we’ll create a new version of our ngrok_addons profile. 

Go to Profiles, select your ngrok_addons profile (or whichever name you’ve chosen), hover over the 1.0.0 version and select Create new version from the dropdown menu. 

Add an extra layer of security with OAuth

Choose a new version (I’ll go with 1.0.1) and select Confirm

create a new version

Now select the ngrok-demo-app layer and replace all the contents with the following. Make sure to change or remove the emailDomains field. 

apiVersion: v1
kind: Service
metadata:
 name: game-2048
spec:
 ports:
   - name: http
     port: 80
     targetPort: 80
 selector:
   app: game-2048
 type: ClusterIP # Optional, default is ClusterIP
---
apiVersion: apps/v1
kind: Deployment
metadata:
 name: game-2048
spec:
 replicas: 1
 selector:
   matchLabels:
     app: game-2048
 template:
   metadata:  # Corrected indentation
     labels:
       app: game-2048
   spec:
     containers:
       - name: backend
         image: alexwhen/docker-2048
         ports:
           - name: http
             containerPort: 80
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
 name: game-2048
 annotations:
   k8s.ngrok.com/modules: ngrok-module-set
spec:
 ingressClassName: ngrok
 rules:
   - host: "{{ .spectro.macro.NGROK_DOMAIN }}"
     http:
       paths:
         - path: /
           pathType: Prefix
           backend:
             service:
               name: game-2048
               port:
                 number: 80
---
kind: NgrokModuleSet
apiVersion: ingress.k8s.ngrok.com/v1alpha1
metadata:
 name: ngrok-module-set
modules:
 oauth:
   google:
     emailDomains: ["spectrocloud.com"]
     optionsPassthrough: false
     inactivityTimeout: 4h
     maximumDuration: 24h
     authCheckInterval: 1h  

In the manifest you can see that we’ve added an NgrokModuleSet resource and added an annotation to the Ingress definition which points to the ngrok-module-set resource. The NgrokModuleSet CRD allows us to configure resources in ngrok. 

In this case, we’re configuring Google OAuth (thus enabling OAuth as well), setting some options and in my case, configuring the spectrocloud.com email domain. This configuration will force users to login with their Google credentials and will only allow users from that email domain to view the application. 

When you’re done with the configuration, just hit Confirm Updates

NgrokModuleSet resource

Select Save Changes

save your changes

Go to your cluster’s Profile tab, hover over the 1.0.0 version and when the dropdown opens, select your new version. 

select the new version from the drop down menu

You’ll see the status icons of the layers change to grey and you’ll need to select Review & Save to review the changes and apply the new profile version. 

review and save layer changes

The change summary will open and you can select Review changes in Editor

editor review

Make sure to select the layers/manifests on the left to review all changes. If all is well and all items have a checkmark, select Apply Changes.  

select the layers/manifests on the left to review all changes

When the deployment completes, you can check your ngrok dashboard for the new config. You should see that OAuth is now enabled, that google is the selected identity provider and that an email domain is configured (or not, if you removed that).  

check your ngrok dashboard for the new config

Let’s try to visit the app again, but you might first need to open an incognito tab to avoid your browser reverting to the previously active session. 

In a new (incognito) tab, you should now get prompted to visit the ngrok exposed site again, and to sign in with Google to access the page. 

If you’ve removed the email domain, you will still have to login, but there will be no limiting factor. Anyone that logs in will be able to access the page. In my case, only a certain domain has access, so I’ll first try a gmail.com account. 

SSO sign in

After entering a @gmail.com address, my password and 2-Step Verification, I get the following error: 

errngrok 5511 when using a personal account

Now I’ll try it with an @spectrocloud.com address… and it works

That wasn’t that hard right? The “hard” part is going through the first steps to get access to your ngrok info and setting up the Cluster Profile. However, now you can reuse this Cluster Profile and make slight changes to expose any service in your clusters. 

ngrok demo app available with business account

Advanced ngrok Features for Kubernetes power users

Custom subdomains and reserved tunnels

With ngrok’s Pro or higher plans, you can assign predictable, branded URLs to your services. This is especially useful when integrating with third-party tools or APIs that require consistent endpoints. 

Advanced ngrok Features for Kubernetes power users

Enhancing security with ngrok IP Policies

Ngrok’s IP policies enhance security by restricting tunnel access to specific IP addresses or ranges. This feature lets you whitelist trusted sources or blacklist unauthorized ones, ensuring sensitive Kubernetes services remain protected.

(The IP in this example is fake, of course. 😜)

Enhancing security with ngrok IP Policies

Simply attach the IP policies to your edge endpoints and provide an immediate extra layer of security.  

 IP policies to your edge endpoints

Walkthrough video

You can watch a full video walkthrough of all the steps in this blog right here, covering:

  • A VMware cluster deployment
  • Adding a Helm registry
  • Creating Macros
  • Creating a cluster profile
  • Deploying the ngrok resources
  • Creating a new version of the cluster profile
  • Deploying the changes
  • Adding a simple Google OAuth configuration
  • Testing a public and OAuth based app deployment

Conclusion: Simplifying Kubernetes Access with ngrok

Here at Spectro we love how ngrok simplifies exposing Kubernetes services. It saves you from complex ingress configurations, certificate management and doubting if you’ve locked down your firewall correctly. 

When paired with Spectro Cloud’s Palette, the combination becomes even more impactful. Palette simplifies Kubernetes lifecycle management, while ngrok provides secure and seamless service access. A true ‘better together’ story for simplification.

Tags:
Networking
Developers
Cloud
How to
Using Palette
Subscribe to our newsletter
By signing up, you agree with our Terms of Service and our Privacy Policy