Secure .internal private networking endpoints

How would I secure an endpoint that accepts the incoming request, only if it connected via the private .internal address?

My first thought was to check the host http header, but this can be easily spoofed by clients connecting through the fly.dev domain.

My second thought was to check the incoming TLS servername, but then I realized my app runs behind the fly-owned SSL termination point, and only receives plaintext http

I’m not exactly sure what you’re trying to do, but…

Use ProxyProto V2 to have SNIs sent to your application by fly-proxy.

1 Like

Thanks, I’ll give that a try. For context, I have a public-facing server that also accepts connections from other apps running in same account, via the .internal addresses.

Incoming public traffic will be authenticated via authentication header, but traffic from other services/apps won’t have any auth. You could theoretically read the incoming host header, but this is not secure because it can be easily spoofed e.g.

curl -H "Host: app.internal" https://app.fly.dev/private/route

I might be terribly wrong here, but Fly 6pn is secure by design; ie, nothing outside the network namespace of your organization can send requests to the 6pn / Flycast address.

In sum, one needn’t worry about mutual auth on 6pn.

Ah right, got it. I’m running an nodejs Express server which listens on all addresses, perhaps I can figure out a way to determine the address of the .internal v6 ip and then perform auth based on that in my auth middleware. e.g. something like this (haven’t tested yet)

const app = express()
app.use((req, res, next) => {
  // currently doing this, but it's not secure as it can be spoofed from outside 
  // const isInternal = req.get('host') === 'app.internal'
  const internalAddress = dns.resolve("app.internal")
  const isInternal = req.socket.address() === internalAddress
  if (isInternal) {
    req.user = 'internal'
    return next()
  }
  const apiKey = req.get('authentication')
  // ...perform auth for public traffic
})
app.listen(3000) // listens on all interfaces by default

If I can’t get that to work, I’ll try ProxyProto V2 as a way to distinguish incoming public traffic vs internal

Gotcha. Simplest would be to use a different addr/port, say fly-local-6pn:6000, for internal requests (private services, as they refer to it in these parts; these services basically have no entry in fly.toml exposing themselves to fly-proxy / external world)?

1 Like

This topic was automatically closed 7 days after the last reply. New replies are no longer allowed.