Kerberos historically presented a transparent method of authentication that found itself embraced by windows admins throughout windows enterprises. However as we migrate more services from the old world of windows servers running IIS I've found myself typically having to create IIS servers running a container that converts a modern jwt bearer token to a kerberos token. A scenario that I find brittle and unappealing as rather than migrate away from windows I'm spinning up more systems that need decommissioning.
The Dotnet Solution
That is until I discovered Kerberos.net. Kerberos.net is a small managed implementation of the kerberos protocol. So instead of spinning up new windows servers and joining them we can instead use a tiny dotnet library to integrate directly to the kerberos service. All it takes is:
var client = new KerberosClient();
var kerbCred = new KerberosPasswordCredential("user@domain.com", "userP@ssw0rd!");
await client.Authenticate(kerbCred);
var ticket = await client.GetServiceTicket("host/appservice.corp.identityintervention.com");
var header = "Negotiate " + Convert.ToBase64String(ticket.EncodeGssApi().ToArray());
With those 5 lines of code you’ve just saved yourself the cost of a windows server & the added maintenance. If you happen to be dotnet users this option is by far the easiest.
But I'm not using dotnet
But what if like myself you find yourself in the situation where you need to support a node & golang applications. Well for the moment the easiest option is to build a small transparent reverse proxy that transparently swaps out another form of authentication like your pod identity token for a kerberos token. Its not perfect, we're still introducing another hop but it still beats out spinning up more windows servers.
You can do this by building a small Yarp Proxy and adding a tiny piece of transform middleware to automatically include the kerberos negotiate header on successful authentication. For example:
using Yarp.ReverseProxy.Transforms;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddReverseProxy()
.LoadFromConfig(builder.Configuration.GetSection("ReverseProxy"))
.AddTransforms(builderContext =>
{
builderContext.AddRequestTransform(async transformContext =>
{
var client = new KerberosClient();
var kerbCred = new KerberosPasswordCredential("user@domain.com", "userP@ssw0rd!");
await client.Authenticate(kerbCred);
var ticket = await client.GetServiceTicket("host/appservice.corp.identityintervention.com");
var header = "Negotiate " + Convert.ToBase64String(ticket.EncodeGssApi().ToArray());
transformContext.ProxyRequest.Headers.Add("Authorization", header);
});
});
var app = builder.Build();
app.MapReverseProxy();
app.Run();
Chuck it in a docker container and it makes for an okay workaround and with some clever configuration you can you a single deployment to handle the traffic to all your existing kerberos protected services.
The envoy solution (coming soon)
The best solution would be a kerberos wasm filter that can be integrated directly into envoy to automatically handle windows authentication to any external services transparently. However, wasm is currently quite unstable for dotnet. But hopefully with a bit more time we’ll able to permanently remove the need to make any changes when integrating with systems using Kerberos. Stay tuned for a follow up post when wasm stabilizes.
To Conclude
Ideally we wouldn't need this stepping stone but the reality is, a progressive approach is usually the supior option. The above workarounds give straight forward ways to overcome challenges when dealing with Kerberos in a cloud world.
Top comments (0)