Skip to content

Instantly share code, notes, and snippets.

@rajanadar
Created September 10, 2024 12:33
Show Gist options
  • Save rajanadar/28c86d967695262bfe1f17ae82fb3d3d to your computer and use it in GitHub Desktop.
Save rajanadar/28c86d967695262bfe1f17ae82fb3d3d to your computer and use it in GitHub Desktop.
using System;
using System.Threading.Tasks;
using Kerberos.NET.Client;
using Kerberos.NET.Configuration;
using Kerberos.NET.Credentials;
using Kerberos.NET.Crypto;
// Written by Raja Nadar for users of VaultSharp dealing with Kerberos based AuthMethod
namespace VaultSharp.V1.AuthMethods.Kerberos
{
/// <summary>
/// Helper class for Kerberos based Vault Auth Method
/// Include the Nuget package Kerberos.NET before using this helper class.
/// </summary>
public static class KerberosAuthMethodHelper
{
/// <summary>
/// Creates the Kerberos Service Principal Negotiation Token header from the keytab and conf files.
/// </summary>
/// <param name="serviceAccountUsername">
/// The username for the entry within the keytab to use for logging into Kerberos.
/// This username must match a service account in LDAP.
/// </param>
/// <param name="servicePrincipalName">
/// The service principal name to use in obtaining a service ticket for gaining a SPNEGO token.
/// This service must exist in LDAP.
/// </param>
/// <param name="realmName">
/// The name of the Kerberos realm.
/// This realm must match the UPNDomain configured on the LDAP connection.
/// This check is case-sensitive.
/// </param>
/// <param name="keyTabFilePath">
/// The path to the keytab in which the entry lives for the entity authenticating to Vault.
/// Keytab files should be protected from other users on a shared server using appropriate file permissions.
/// </param>
/// <param name="krb5ConfigurationFilePath">
/// The path to a valid krb5.conf file describing how to communicate with the Kerberos environment.
/// </param>
/// <param name="disableFastNegotiation">
/// For disabling the Kerberos auth method's default of using FAST negotiation.
/// FAST is a pre-authentication framework for Kerberos.
/// It includes a mechanism for tunneling pre-authentication exchanges using armoured KDC messages.
/// FAST provides increased resistance to passive password guessing attacks.
/// Some common Kerberos implementations do not support FAST negotiation.
/// </param>
/// <returns>The "Negotiate " + ServicePrincipalNegotiationToken value.</returns>
public static async Task<string> GetServicePrincipalNegotiationTokenAsync(
string serviceAccountUsername,
string servicePrincipalName,
string realmName,
string keyTabFilePath,
string krb5ConfigurationFilePath,
bool disableFastNegotiation)
{
if (string.IsNullOrEmpty(serviceAccountUsername))
{
throw new ArgumentNullException(nameof(serviceAccountUsername));
}
if (string.IsNullOrEmpty(servicePrincipalName))
{
throw new ArgumentNullException(nameof(servicePrincipalName));
}
if (string.IsNullOrEmpty(realmName))
{
throw new ArgumentNullException(nameof(realmName));
}
if (!System.IO.File.Exists(krb5ConfigurationFilePath))
{
throw new System.IO.FileNotFoundException("Krb5Configuration file could not be found: " + krb5ConfigurationFilePath);
}
if (!System.IO.File.Exists(keyTabFilePath))
{
throw new System.IO.FileNotFoundException("KeyTabFile file could not be found: " + keyTabFilePath);
}
try
{
var krb5Config = Krb5Config.Parse(krb5ConfigurationFilePath);
var kerberosClient = new KerberosClient(krb5Config);
// Assume pre-auth
kerberosClient.AuthenticationOptions &= AuthenticationOptions.PreAuthenticate;
if (disableFastNegotiation)
{
kerberosClient.AuthenticationOptions &= ~AuthenticationOptions.PreAuthenticate;
}
var keyTable = new KeyTable(System.IO.File.ReadAllBytes(keyTabFilePath));
KerberosCredential keytabCredential =
new KeytabCredential(serviceAccountUsername,
keyTable, realmName);
await kerberosClient.Authenticate(keytabCredential);
var ticket = await kerberosClient.GetServiceTicket(servicePrincipalName);
var servicePrincipalNegotiationToken = Convert.ToBase64String(ticket.EncodeGssApi().ToArray());
var kerberosAuthHeader = "Negotiate " + servicePrincipalNegotiationToken;
return kerberosAuthHeader;
}
catch (Exception ex)
{
throw new Exception("Failed to generate Kerberos service principal negotiation token.", ex);
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment