Quick and dirty example of protecting a service with an authenticating nginx proxy and HTTP basic auth. The proxy passes the identity of the caller to the upstream. Key rotation is (sort-of) supported.
The easiest way to play is in a local minikube with ingress, minikube start --addons ingress,ingress-dns, and Tilt to inject the development domain (via nip.io).
Overview:
- Ingress is via the auth proxy. The auth proxy forwards to the real service.
- Users are in a htpasswd file in a ConfigMap.
- Adding new credentials is easy, e.g.
htpasswd -nbB alice p. bcrypt should mean they're safe enough but it could be stored in a vault easily enough. - Adding a "$identity/$n" prefix means credentials can be rotated without changing the caller's identity.
- The ConfigMap is a volume mount. The pod gets periodically updated. nginx reloads at runtime. No downtime or restarts.
$ curl -Ss http-apikey-demo.192.168.49.2.nip.io
<html>
<head><title>401 Authorization Required</title></head>
<body>
<center><h1>401 Authorization Required</h1></center>
<hr><center>nginx/1.23.1</center>
</body>
</html>
$ curl -Ss http-apikey-demo.192.168.49.2.nip.io -u alice:p | jq '.request.headers | { "x-auth-identity" }'
{
"x-auth-identity": "alice"
}
$ curl -Ss http-apikey-demo.192.168.49.2.nip.io -u 'alice/2:pp' | jq '.request.headers | { "x-auth-identity" }'
{
"x-auth-identity": "alice"
}
$ curl -Ss http-apikey-demo.192.168.49.2.nip.io -u 'bob:p' | jq '.request.headers | { "x-auth-identity" }'
{
"x-auth-identity": "bob"
}
It's good to be secure by default, but some endpoints are inherently public, e.g. health and status probes, public keys, etc. That would be service specific so needs to be configurable somehow.