1
Knocknoc Integration
Dave Kempe edited this page 2026-04-26 20:12:58 +10:00

Knocknoc integration

Knocknoc is a zero-trust network access platform: it dynamically grants and revokes IP-level access to backends based on identity, MFA, and policy, instead of leaving open ports for attackers to find. We integrate with it because the rustguac login page is the kind of thing you don't want indexed by Shodan.

This page is the practical integration guide. Knocknoc's own docs are at docs.knocknoc.io.

What it does for rustguac

By default, your rustguac login page sits on the public internet. Anyone who finds the hostname can hit /, see "Sign in with...", and start probing OIDC. With Knocknoc in front of HAProxy:

  • The user authenticates to Knocknoc first (SSO + MFA, or whatever your Knocknoc policy requires).
  • Knocknoc tells HAProxy "this client IP is now allowed to see the login page."
  • HAProxy starts returning the rustguac login page to that IP.
  • When the Knocknoc session expires, HAProxy stops returning it.

To a scanner with no Knocknoc identity, the rustguac login page returns 403. There's nothing to fingerprint, nothing to probe.

What's gated, and what isn't

Only the front page (/) is gated. Everything else passes straight through to rustguac's own auth:

Path Gated by Knocknoc? Why
/ Yes The login UI; this is what we hide from scanners
/api/* No API key or OIDC session auth handles this
/auth/* No OIDC callback; the IdP needs to reach this endpoint
/ws/* No WebSocket session auth handles this
/share/* No Share-token auth handles this; needs to work for users not behind Knocknoc
/static/*, /guac/* No Static assets; cheap to serve, no value to an attacker

The reason for this split is that OIDC callbacks have to work even when the user's browser hasn't been through Knocknoc yet (they're being redirected from the IdP). Same for share links. Gating them would break the auth flow.

How HAProxy and the Knocknoc agent talk

The Knocknoc agent runs on the same host as HAProxy and uses HAProxy's admin socket to mutate a dynamic ACL:

+-------------------+     +-------------------+
|  Knocknoc agent   | --> |     HAProxy       |
+---------+---------+     |   (admin socket)  |
          |               +---------+---------+
          | mTLS                    |
          v                         | dynamic ACL #600
+-------------------+               | "is the client IP allowed?"
|  Knocknoc mgmt    |               v
|  plane (SaaS or   |        +-----------+
|  on-prem)         |        | rustguac  |
+-------------------+        +-----------+

The agent adds and removes IPs from ACL #600 (the number is a convention; both sides have to agree). HAProxy uses src -u 600 in an ACL expression to consult that runtime list.

HAProxy config sketch

This is the minimum viable Knocknoc-aware HAProxy config for rustguac. Full example is in haproxy.example.cfg in the repo root.

global
    # Admin socket for the knocknoc-agent to mutate ACLs
    stats socket /run/haproxy/admin.sock mode 0660 level admin

frontend rustguac_https
    bind :443 ssl crt /etc/haproxy/tls/console.example.com.pem alpn h2,http/1.1
    mode http

    # Knocknoc-managed dynamic ACL (id 600 must match the agent config)
    acl knoc_rustguac src -u 600
    acl is_root path /

    # The front page is gated; everything else passes
    use_backend rustguac if is_root knoc_rustguac
    use_backend denied   if is_root
    default_backend rustguac

backend rustguac
    mode http
    server rustguac 127.0.0.1:8089 ssl verify none alpn h2

backend denied
    mode http
    http-request deny status 403

use_backend rustguac if is_root knoc_rustguac reads as: send the request to rustguac if the path is / AND the source IP is in ACL #600. The fallthrough use_backend denied if is_root returns 403 for / without a Knocknoc grant. Everything else falls through to default_backend rustguac.

Verifying the ACL is working

# Show what's currently in ACL #600
echo "show acl #600" | socat stdio /run/haproxy/admin.sock

# Manually add an IP for testing (will be overwritten by knocknoc-agent)
echo "add acl #600 192.0.2.1" | socat stdio /run/haproxy/admin.sock

# Remove an IP
echo "del acl #600 192.0.2.1" | socat stdio /run/haproxy/admin.sock

If show acl #600 returns "Unknown ACL" your HAProxy config didn't load the ACL declaration. Check that the acl knoc_rustguac src -u 600 line is in the active config.

When to use this and when not to

Use Knocknoc if:

  • rustguac is reachable from the internet at large.
  • Your threat model includes "automated tools probing the login page."
  • You already have an IdP / MFA setup that Knocknoc can plug into, or you're willing to operate one.

Don't bother if:

  • rustguac only listens on a private network behind a VPN or IP-restricted load balancer.
  • You're a one-person homelab and Knocknoc is more operational complexity than the threat warrants.

In the second case, OIDC + a strong rate limiter on /auth/* (which rustguac has built in via tower_governor) is already a reasonable bar.

See also