rajanadar / VaultSharp

A comprehensive cross-platform .NET Library for HashiCorp's Vault, a secret management tool
http://rajanadar.github.io/VaultSharp
Apache License 2.0
488 stars 130 forks source link

Kerberos auth not working, not including port number in ticket request #338

Closed mfinnigan closed 5 months ago

mfinnigan commented 9 months ago

I've got Kerberos auth working from the CLI, but not from VaultSharp, using the quickstart sample program. This is against HCP Vault. See update in comment below - it's asking the KDC for a ticket without the port number of the vault SPN

VaultSharp Version 1.13.01, .NET 6.0, on Windows 10

Vault Version 1.15.2 +Ent (HCP)

Does this work with Vault CLI? Yes

Sample Code Snippet

string vaultServer = 
    "https://company-hcp-sre-dev-private-vault-dff8581e.86e0ac9c.z1.hashicorp.cloud:8200";
string authMount = "kerberos_auth_company";
// Authenticate
IAuthMethodInfo authMethod = new KerberosAuthMethodInfo(authMount, CredentialCache.DefaultCredentials, true);

VaultClientSettings vaultClientSettings = new VaultClientSettings(vaultServer, authMethod)
{
    Namespace ="admin"
};
IVaultClient vaultClient = new VaultClient(vaultClientSettings);

vaultClient.V1.Auth.PerformImmediateLogin().ConfigureAwait(true);
vaultClient.Settings.Namespace  = "admin/company";

    // Read a secret
Secret<SecretData> secret = vaultClient.V1.Secrets.KeyValue.V2.ReadSecretAsync(
    path: "/test",
    mountPoint: "farmsvc_kv-v2_release"
).Result;

Exception Details/Stack Trace/Error Message Fiddler seems to see me sending NTLM in response to a 401 Www-Authenticate: Negotiate prompt


#   Result  Protocol    Host    URL Body    Caching Content-Type    Process Comments    Custom  
29  401 HTTPS   company-hcp-sre-dev-private-vault-dff8581e.86e0ac9c.z1.hashicorp.cloud:8200 /v1/auth/kerberos_auth_company/login    39  no-store    application/json    quickstart:9980         
30  401 HTTPS   company-hcp-sre-dev-private-vault-dff8581e.86e0ac9c.z1.hashicorp.cloud:8200 /v1/auth/kerberos_auth_company/login    178 no-store    application/json    quickstart:9980         

POST https://company-hcp-sre-dev-private-vault-dff8581e.86e0ac9c.z1.hashicorp.cloud:8200/v1/auth/kerberos_auth_company/login HTTP/1.1
Host: company-hcp-sre-dev-private-vault-dff8581e.86e0ac9c.z1.hashicorp.cloud:8200
X-Vault-Request: true
X-Vault-Namespace: admin
Content-Length: 0

HTTP/1.1 401 Unauthorized
Cache-Control: no-store
Content-Type: application/json
Strict-Transport-Security: max-age=31536000; includeSubDomains
Www-Authenticate: Negotiate
X-Vault-Namespace: admin
Date: Tue, 05 Dec 2023 20:07:54 GMT
Content-Length: 39
Proxy-Support: Session-Based-Authentication

{"errors":["authentication required"]}

------------------------------------------------------------------
POST https://company-hcp-sre-dev-private-vault-dff8581e.86e0ac9c.z1.hashicorp.cloud:8200/v1/auth/kerberos_auth_company/login HTTP/1.1
Host: company-hcp-sre-dev-private-vault-dff8581e.86e0ac9c.z1.hashicorp.cloud:8200
X-Vault-Request: true
X-Vault-Namespace: admin
Authorization: Negotiate TlRMTVNTUAABAAAAl4II4gAAAAAAAAAAAAAAAAAAAAAKAGFKAAAADw==
Content-Length: 0

HTTP/1.1 401 Unauthorized
Cache-Control: no-store
Content-Type: application/json
Strict-Transport-Security: max-age=31536000; includeSubDomains
X-Vault-Namespace: admin
Date: Tue, 05 Dec 2023 20:07:54 GMT
Content-Length: 178

{"request_id":"84e81bda-6f39-bb5c-6a8f-a4a25dceddc1","lease_id":"","renewable":false,"lease_duration":0,"data":null,"wrap_info":null,"warnings":["Unauthorised.\n\n"],"auth":null}

Any additional info

successful CLI auth

PS C:\Users\mfinnigan\Desktop> vault login -method=kerberos -path="kerberos_auth_company" username="mfinnigan" service="HTTP/company-hcp-sre-dev-private-vault-dff8581e.86e0ac9c.z1.hashicorp.cloud:8200" realm="company.COMP.LOCAL" keytab_path=login.keytab disable_fast_negotiation="true" krb5conf_path="H:\krb5-aes.conf"
Success! You are now authenticated. The token information displayed below

setspn output

PS C:\Users\mfinnigan\Desktop> setspn -L "vault-dev-sre.svc"
Registered ServicePrincipalNames for CN=vault-dev-sre.svc,OU=Service Accounts,OU=Secure,OU=company Users,DC=company,DC=COMP,DC=local:
        HTTP/company-hcp-sre-dev-private-vault-dff8581e.86e0ac9c.z1.hashicorp.cloud:8200

lack of a ticket for this spn in klist output

PS C:\Users\mfinnigan\Desktop> klist |select-string http

        Server: HTTP/autodiscover.company.com @ company.COMP.LOCAL
        Server: HTTP/tfs.company.COMP.local @ company.COMP.LOCAL
        Server: HTTP/companypedia.company.com @ company.COMP.LOCAL
        Server: HTTP/somethingelse.company.COMP.local @ company.COMP.LOCAL

However, even if I run "klist get manually, this still fails with the same behavior.

PS C:\Users\mfinnigan\Desktop> klist get HTTP/company-hcp-sre-dev-private-vault-dff8581e.86e0ac9c.z1.hashicorp.cloud:8200@company.COMP.LOCAL

Current LogonId is 0:0x59dd667
A ticket to HTTP/company-hcp-sre-dev-private-vault-dff8581e.86e0ac9c.z1.hashicorp.cloud:8200@company.COMP.LOCAL has been retrieved successfully.

PS C:\Users\mfinnigan\Desktop> klist |select-string http

    Server: HTTP/company-hcp-sre-dev-private-vault-dff8581e.86e0ac9c.z1.hashicorp.cloud:8200 @ company.COMP.LOCAL
    Server: HTTP/company-hcp-vault-cluster-private-vault-912da0a8.6f319046.z1.hashicorp.cloud:8200 @ company.COMP.LOCAL

this is an A record, not a CNAME

PS C:\Users\mfinnigan\Desktop> Resolve-DnsName company-hcp-sre-dev-private-vault-dff8581e.86e0ac9c.z1.hashicorp.cloud -verbose |fl
VERBOSE: company-hcp-sre-dev-private-vault-dff8581e.86e0ac9c.z1.hashicorp.cloud

Name       : company-hcp-sre-dev-private-vault-dff8581e.86e0ac9c.z1.hashicorp.cloud
Type       : A
TTL        : 38
DataLength : 4
Section    : Answer
IPAddress  : 10.109.3.10
mfinnigan commented 9 months ago

Looks like the library isn't asking for the port number in the tgs-req

If I send a klist get,

PS C:\Users\mfinnigan\Desktop> klist get HTTP/company-hcp-sre-dev-private-vault-dff8581e.86e0ac9c.z1.hashicorp.cloud:8200@company.COMP.LOCAL

Current LogonId is 0:0x59dd667
A ticket to HTTP/company-hcp-sre-dev-private-vault-dff8581e.86e0ac9c.z1.hashicorp.cloud:8200@company.COMP.LOCAL has been retrieved successfully.

#2>     Client: mfinnigan @ company.COMP.LOCAL
        Server: HTTP/company-hcp-sre-dev-private-vault-dff8581e.86e0ac9c.z1.hashicorp.cloud:8200 @ company.COMP.LOCAL
        KerbTicket Encryption Type: AES-256-CTS-HMAC-SHA1-96
        Ticket Flags 0x40a10000 -> forwardable renewable pre_authent name_canonicalize
        Start Time: 12/5/2023 15:10:08 (local)
        End Time:   12/6/2023 1:10:08 (local)
        Renew Time: 12/12/2023 15:08:38 (local)
        Session Key Type: AES-256-CTS-HMAC-SHA1-96
        Cache Flags: 0
        Kdc Called: TVDC01.company.COMP.local

here's the tgs-req as seen in wireshark

req-body
    Padding: 0
    kdc-options: 40810000
    realm: company.COMP.LOCAL
    sname
        name-type: kRB5-NT-SRV-INST (2)
        sname-string: 2 items
            SNameString: HTTP
            SNameString: company-hcp-sre-dev-private-vault-dff8581e.86e0ac9c.z1.hashicorp.cloud:8200
    till: Sep 12, 2037 19:48:05.000000000 Pacific Daylight Time
    nonce: 843374022
    etype: 5 items
        ENCTYPE: eTYPE-AES256-CTS-HMAC-SHA1-96 (18)
        ENCTYPE: eTYPE-AES128-CTS-HMAC-SHA1-96 (17)
        ENCTYPE: eTYPE-ARCFOUR-HMAC-MD5 (23)
        ENCTYPE: eTYPE-ARCFOUR-HMAC-MD5-56 (24)
        ENCTYPE: eTYPE-ARCFOUR-HMAC-OLD-EXP (-135)
    enc-authorization-data

here's the tgs-req from running quickstart.exe

req-body
    Padding: 0
    kdc-options: 40810000
    realm: company.COMP.LOCAL
    sname
        name-type: kRB5-NT-SRV-INST (2)
        sname-string: 2 items
            SNameString: HTTP
            SNameString: company-hcp-sre-dev-private-vault-dff8581e.86e0ac9c.z1.hashicorp.cloud
    till: Sep 12, 2037 19:48:05.000000000 Pacific Daylight Time
    nonce: 544884361
    etype: 5 items
        ENCTYPE: eTYPE-AES256-CTS-HMAC-SHA1-96 (18)
        ENCTYPE: eTYPE-AES128-CTS-HMAC-SHA1-96 (17)
        ENCTYPE: eTYPE-ARCFOUR-HMAC-MD5 (23)
        ENCTYPE: eTYPE-ARCFOUR-HMAC-MD5-56 (24)
        ENCTYPE: eTYPE-ARCFOUR-HMAC-OLD-EXP (-135)
    enc-authorization-data

Note the missing port number in the snamestring. the response from the kdc is KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN

mfinnigan commented 9 months ago

I have done some debugging and found that if I set DOTNET_SYSTEM_NET_HTTP_USEPORTINSPN as an environment variable, this works properly. I don't know the proper way to set System.Net.Http.UsePortInSpn to true as a user of VaultSharp (I don't see any likely option), or if these needs to be a PR to your project.

This may also be because I'm targetting .NET 6.0, it seems this was a change in 6.0? https://stackoverflow.com/questions/74390400/net-5-to-net-6-httpclient-breaking-change-for-default-spn-port

aha - adding this line "System.Net.Http.UsePortInSpn": true to ".\quick-start\bin\Release\net6.0\quickstart.runtimeconfig.json"

takes care of the issue.

mfinnigan commented 5 months ago

I am now also running into this issue when targeting .NET framework (4.8). I'm unable to find a way to change the behavior. I did try adding this to my code

System.Net.AuthenticationManager.CustomTargetNameDictionary
    .Add("https://bng-hcp-vault1-private-vault-dda82d4a.d714d954.z1.hashicorp.cloud:8200/", "HTTP/bng-hcp-vault1-private-vault-dda82d4a.d714d954.z1.hashicorp.cloud");

or

System.Net.AuthenticationManager.CustomTargetNameDictionary
    .Add("https://bng-hcp-vault1-private-vault-dda82d4a.d714d954.z1.hashicorp.cloud:8200/", "HTTP/bng-hcp-vault1-private-vault-dda82d4a.d714d954.z1.hashicorp.cloud:8200");

with no change in behavior. (suggestion found here https://stackoverflow.com/questions/39740676/forcing-specific-spn-for-url-in-net)

mfinnigan commented 5 months ago

I ended up just asking our AD team to create an additional SPN on the service account without the port number and that works. Don't even need to regenerate the keytab, this is just to paper over a bug in the client behavior