kerberos - Linux Docker容器中的Windows身份验证

标签 kerberos windows-authentication gssapi http-negotiate gss

我正在尝试在kubernetes下的linux docker容器中使用Windows身份验证。

我正在执行以下设置:https://docs.microsoft.com/en-us/aspnet/core/security/authentication/windowsauth?view=aspnetcore-3.1&tabs=visual-studio#kestrel

应用程序位于.net core3中,具有nuget Microsoft.AspNetCore.Authentication.Negotiate并在kestrel中运行

我已经添加了

services.AddAuthentication(Microsoft.AspNetCore.Authentication.Negotiate.NegotiateDefaults.AuthenticationScheme).AddNegotiate();



app.UseAuthentication();

并将我的devbase镜像设置为
FROM mcr.microsoft.com/dotnet/core/sdk:3.1-buster as final
USER root
RUN whoami
RUN apt update && apt dist-upgrade -y

ADD ca/ca.crt /usr/local/share/ca-certificates/ca.crt
RUN chmod 644 /usr/local/share/ca-certificates/*
RUN update-ca-certificates


RUN DEBIAN_FRONTEND=noninteractive apt install -y krb5-config krb5-user

COPY krb5.conf /etc/krb5.conf
RUN mkdir /app

RUN echo BQIAAA..== | base64 -d > /app/is.k01.HTTP.keytab
WORKDIR /app

#RUN docker version

RUN groupadd --gid 1000 app && useradd --uid 1000 --gid app --shell /bin/bash -d /app app

RUN apt install -y mc sudo syslog-ng realmd gss-ntlmssp

tfs管道中的构建会创建从上面派生的应用docker镜像,并添加以下env变量,还将构建复制到/app
RUN chmod 0700 run.sh
ENV KRB5_KTNAME=/app/is.k01.HTTP.keytab
ENV KRB5_TRACE=/dev/stdout
ENV ASPNETCORE_URLS=http://*:80;https://+:443
RUN chown app:app /app -R
USER app

该应用程序由run.sh运行

service syslog-ng start
kinit HTTP/is.k01.mydomain.com@MYDOMAIN.COM -k -t /app/is.k01.HTTP.keytab
klist
dotnet dev-certs https
dotnet /app/SampleApi.dll

klist列出已将SPN分配给计算机的主体

在ie和firefox中,我已将network.negotiate-auth.trusted-uris添加到我的应用中

但是我得到的登录对话框没有成功登录

所以问题是:

如何使用Microsoft.AspNetCore.Authentication.Negotiate软件包启用调试日志?

我的假设是此软件包无法与kerberos正常通信,也许某些软件包丢失,无法运行或什么。

还要注意,容器和.net应用程序已成功连接到域,因为我使用集成安全性来连接有效的数据库。

****编辑>对第一部分的回答

要启用日志,应在kestrel中启用日志:
在appsettings.json中:
  "Logging": {
    "LogLevel": {
      "Default": "Debug",
    }
  },

在program.cs中:

Host.CreateDefaultBuilder(args)
.ConfigureLogging(logging =>
{
    logging.AddFilter("Microsoft", LogLevel.Debug);
    logging.AddFilter("System", LogLevel.Debug);
    logging.ClearProviders();
    logging.AddConsole();
})
.ConfigureWebHostDefaults(webBuilder =>
{

在Startup.cs中,可以跟踪协商事件:

services.AddAuthentication(NegotiateDefaults.AuthenticationScheme).AddNegotiate(

    options =>
    {
        options.PersistKerberosCredentials = true;
        options.Events = new NegotiateEvents()
        {
            OnAuthenticated = challange =>
            {
                ..
            },
            OnChallenge = challange =>
            {
                ..
            },
            OnAuthenticationFailed = context =>
            {
                // context.SkipHandler();
                Console.WriteLine($"{DateTimeOffset.Now.ToString(czechCulture)} OnAuthenticationFailed/Scheme: {context.Scheme.Str()}, Request: {context.Request.Str()}");
                Console.WriteLine("context?.HttpContext?.Features?.Select(f=>f.Key.Name.ToString())");
                var items = context?.HttpContext?.Features?.Select(f => "- " + f.Key?.Name?.ToString());
                if (items != null)
                {
                    Console.WriteLine(string.Join("\n", items));
                }
                Console.WriteLine("context.HttpContext.Features.Get<IConnectionItemsFeature>()?.Items " + context.HttpContext.Features.Get<IConnectionItemsFeature>()?.Items?.Count);
                var items2 = context.HttpContext?.Features.Get<IConnectionItemsFeature>()?.Items?.Select(f => "- " + f.Key?.ToString() + "=" + f.Value?.ToString());
                if (items2 != null) {
                    Console.WriteLine(string.Join("\n", items2));
                }
                return Task.CompletedTask;
            }
        };
    }
);

**** 编辑

同时,根据我允许在.net core docker Web应用程序中进行Windows身份验证的目标,我正在检查.net core的源代码,并使用corefx将身份验证代码截断到此示例控制台应用程序:

try
{
    var token = "MyToken==";
    var secAssembly = typeof(AuthenticationException).Assembly;
    Console.WriteLine("var ntAuthType = secAssembly.GetType(System.Net.NTAuthentication, throwOnError: true);");
    var ntAuthType = secAssembly.GetType("System.Net.NTAuthentication", throwOnError: true);
    Console.WriteLine("var _constructor = ntAuthType.GetConstructors(BindingFlags.NonPublic | BindingFlags.Instance).First();");
    var _constructor = ntAuthType.GetConstructors(BindingFlags.NonPublic | BindingFlags.Instance).First();
    Console.WriteLine("var credential = CredentialCache.DefaultCredentials;");
    var credential = CredentialCache.DefaultCredentials;
    Console.WriteLine("var _instance = _constructor.Invoke(new object[] { true, Negotiate, credential, null, 0, null });");
    var _instance = _constructor.Invoke(new object[] { true, "Negotiate", credential, null, 0, null });

    var negoStreamPalType = secAssembly.GetType("System.Net.Security.NegotiateStreamPal", throwOnError: true);
    var _getException = negoStreamPalType.GetMethods(BindingFlags.NonPublic | BindingFlags.Static).Where(info => info.Name.Equals("CreateExceptionFromError")).Single();


    Console.WriteLine("var _getOutgoingBlob = ntAuthType.GetMethods(BindingFlags.NonPublic | BindingFlags.Instance).Where(info => info.Name.Equals(GetOutgoingBlob) && info.GetParameters().Count() == 3).Single();");
    var _getOutgoingBlob = ntAuthType.GetMethods(BindingFlags.NonPublic | BindingFlags.Instance).Where(info => info.Name.Equals("GetOutgoingBlob") && info.GetParameters().Count() == 3).Single();
    Console.WriteLine("var decodedIncomingBlob = Convert.FromBase64String(token);;");
    var decodedIncomingBlob = Convert.FromBase64String(token);
    Console.WriteLine("var parameters = new object[] { decodedIncomingBlob, false, null };");
    var parameters = new object[] { decodedIncomingBlob, false, null };
    Console.WriteLine("var blob = (byte[])_getOutgoingBlob.Invoke(_instance, parameters);");
    var blob = (byte[])_getOutgoingBlob.Invoke(_instance, parameters);
    if (blob != null)
    {
        Console.WriteLine("var out1 = Convert.ToBase64String(blob);");
        var out1 = Convert.ToBase64String(blob);
        Console.WriteLine(out1);
    }
    else
    {
        Console.WriteLine("null blob value returned");


        var securityStatusType = secAssembly.GetType("System.Net.SecurityStatusPal", throwOnError: true);
        var _statusException = securityStatusType.GetField("Exception");
        var securityStatus = parameters[2];
        var error = (Exception)(_statusException.GetValue(securityStatus) ?? _getException.Invoke(null, new[] { securityStatus }));
        Console.WriteLine("Error:");
        Console.WriteLine(error);
        Console.WriteLine("securityStatus:");
        Console.WriteLine(securityStatus.ToString());
    }
}
catch(Exception exc)
{
    Console.WriteLine(exc.Message);
}

所以我发现图书馆与
System.Net.NT身份验证
与之通信
System.Net.Security.NegotiateStreamPal
与unix版本的通信
Interop.NetSecurityNative.InitSecContext

这应该以某种方式触发操作系统中的GSSAPI

在dotnet运行时git中,他们告诉我们gss-ntlmssp是运行该功能所必需的,即使在aspnet核心文档中也没有提及。

https://github.com/dotnet/runtime/issues?utf8=%E2%9C%93&q=gss-ntlmssp

尽管如此,我已经编译了gss-ntlmssp并发现,如果没有该库,它将引发错误“,请求了不受支持的机制。”。在我的库中,它引发错误“未提供凭据,或者凭据不可用或不可访问。”,但是从不访问任何gss_ *方法。

我已经通过将日志条目添加到文件中(从未发生过)来测试gss方法的用法。fe:

OM_uint32 gss_init_sec_context(OM_uint32 *minor_status,
                               gss_cred_id_t claimant_cred_handle,
                               gss_ctx_id_t *context_handle,
                               gss_name_t target_name,
                               gss_OID mech_type,
                               OM_uint32 req_flags,
                               OM_uint32 time_req,
                               gss_channel_bindings_t input_chan_bindings,
                               gss_buffer_t input_token,
                               gss_OID *actual_mech_type,
                               gss_buffer_t output_token,
                               OM_uint32 *ret_flags,
                               OM_uint32 *time_rec)
{
   FILE *fp;
   fp = fopen("/tmp/gss-debug.log", "w+");
   fprintf(fp, "gss_init_sec_context\n");
   fclose(fp);
    return gssntlm_init_sec_context(minor_status,
                                    claimant_cred_handle,
                                    context_handle,
                                    target_name,
                                    mech_type,
                                    req_flags,
                                    time_req,
                                    input_chan_bindings,
                                    input_token,
                                    actual_mech_type,
                                    output_token,
                                    ret_flags,
                                    time_rec);
}

因此,.net会调用gssapi,而gssapi不会调用机制。

我在centos7 vm,ubuntu Windows子系统和debian docker镜像中观察到了相同的行为(自定义mcr.microsoft.com/dotnet/core/sdk:3.1-buster)

因此,现在的问题是,如何调试gssapi?

我假设我当前的gssapi由此库管理:
readelf -d /usr/lib64/libgssapi_krb5.so
Dynamic section at offset 0x4aa48 contains 34 entries:
  Tag        Type                         Name/Value
 0x0000000000000001 (NEEDED)             Shared library: [libkrb5.so.3]
 0x0000000000000001 (NEEDED)             Shared library: [libk5crypto.so.3]
 0x0000000000000001 (NEEDED)             Shared library: [libcom_err.so.2]
 0x0000000000000001 (NEEDED)             Shared library: [libkrb5support.so.0]
 0x0000000000000001 (NEEDED)             Shared library: [libdl.so.2]
 0x0000000000000001 (NEEDED)             Shared library: [libkeyutils.so.1]
 0x0000000000000001 (NEEDED)             Shared library: [libresolv.so.2]
 0x0000000000000001 (NEEDED)             Shared library: [libc.so.6]
 0x000000000000000e (SONAME)             Library soname: [libgssapi_krb5.so.2]
 0x000000000000000c (INIT)               0xb1d8
 0x000000000000000d (FINI)               0x3ebcc
 0x0000000000000019 (INIT_ARRAY)         0x24a120
 0x000000000000001b (INIT_ARRAYSZ)       8 (bytes)
 0x000000000000001a (FINI_ARRAY)         0x24a128
 0x000000000000001c (FINI_ARRAYSZ)       16 (bytes)
 0x000000006ffffef5 (GNU_HASH)           0x1f0
 0x0000000000000005 (STRTAB)             0x3048
 0x0000000000000006 (SYMTAB)             0x720
 0x000000000000000a (STRSZ)              9167 (bytes)
 0x000000000000000b (SYMENT)             24 (bytes)
 0x0000000000000003 (PLTGOT)             0x24b000
 0x0000000000000002 (PLTRELSZ)           8088 (bytes)
 0x0000000000000014 (PLTREL)             RELA
 0x0000000000000017 (JMPREL)             0x9240
 0x0000000000000007 (RELA)               0x58b0
 0x0000000000000008 (RELASZ)             14736 (bytes)
 0x0000000000000009 (RELAENT)            24 (bytes)
 0x000000006ffffffc (VERDEF)             0x5788
 0x000000006ffffffd (VERDEFNUM)          3
 0x000000006ffffffe (VERNEED)            0x57e0
 0x000000006fffffff (VERNEEDNUM)         4
 0x000000006ffffff0 (VERSYM)             0x5418
 0x000000006ffffff9 (RELACOUNT)          504
 0x0000000000000000 (NULL)               0x0

到目前为止,我已经从mit来源编译了最新的最新gssapi,发现它引发了错误“请求了不受支持的机制”。因为gssapi需要未提供的gss解释器。在centos7中,我还有另一个问题,openssl库正在使用不兼容的共享kerberos库,因此yum停止工作。

*** 编辑

我发现gss-ntlmssp具有标志GSS_C_MA_NOT_DFLT_MECH,因此它失败,并显示消息“未提供凭据,或者凭据不可用或不可访问。”。解决方案是构建不带此属性的自定义gss-ntlmssp,因为我希望将其用作默认身份验证机制。

我的用于检查凭据的示例控制台应用程序现在可以正常工作,我现在尝试将其放在docker容器中。

*** 编辑

我能够在kubernetes中成功运行我的ConsoleApp:
FROM mcr.microsoft.com/dotnet/core/sdk:3.1-buster as final
USER root
RUN whoami
RUN apt update && apt dist-upgrade -y

ADD ca/ca.crt /usr/local/share/ca-certificates/ca.crt
RUN chmod 644 /usr/local/share/ca-certificates/*
RUN update-ca-certificates


RUN DEBIAN_FRONTEND=noninteractive apt install -y krb5-config krb5-user

RUN mkdir /app

RUN apt install -y mc sudo syslog-ng python3-software-properties software-properties-common packagekit git gssproxy vim
RUN apt install -y autoconf automake libxslt-dev doxygen findutils libgettextpo-dev libtool m4 make libunistring-dev libssl-dev zlib1g-dev gettext xsltproc libxml2-utils libxml2-dev xml-core docbook-xml docbook-xsl bison libkrb5-dev
RUN systemctl enable syslog-ng
RUN mkdir /src 
RUN cd /src && wget https://web.mit.edu/kerberos/dist/krb5/1.18/krb5-1.18.tar.gz
RUN cd /src && tar -xf krb5-1.18.tar.gz
RUN cd /src/krb5-1.18/src && ./configure && make && make install

RUN cd /src && git clone https://github.com/scholtz/gss-ntlmssp.git 
RUN cd /src/gss-ntlmssp/ && autoreconf -f -i && ./configure && make && make install
RUN cp /src/gss-ntlmssp/examples/mech.ntlmssp.conf /etc/gss/mech.d/mech.ntlmssp.conf

COPY testgss /testgss
RUN cd /testgss && dotnet ConsoleApp3.dll

RUN groupadd --gid 1000 app && useradd --uid 1000 --gid app --shell /bin/bash -d /app app

RUN echo BQIA..AAAB | base64 -d > /app/user.keytab
RUN echo BQIA..oQ== | base64 -d > /etc/krb5.keytab
RUN echo BQIA..oQ== | base64 -d > /app/is.k01.HTTP.keytab
RUN echo BQIA..AAA= | base64 -d > /app/is.k01.kerb.keytab

COPY krb5.conf /etc/krb5.conf
COPY krb5.conf /usr/local/etc/krb5.conf
RUN ln -s /etc/gss /usr/local/etc/gss

RUN cd /app
WORKDIR /app

enter image description here

但是,我现在收到此错误:
System.Exception: An authentication exception occured (0xD0000/0x4E540016).
 ---> Interop+NetSecurityNative+GssApiException: GSSAPI operation failed with error - Unspecified GSS failure.  Minor code may provide more information (Feature not available).
   at System.Net.Security.NegotiateStreamPal.GssAcceptSecurityContext(SafeGssContextHandle& context, Byte[] buffer, Byte[]& outputBuffer, UInt32& outFlags)
   at System.Net.Security.NegotiateStreamPal.AcceptSecurityContext(SafeFreeCredentials credentialsHandle, SafeDeleteContext& securityContext, ContextFlagsPal requestedContextFlags, Byte[] incomingBlob, ChannelBinding channelBinding, Byte[]& resultBlob, ContextFlagsPal& contextFlags)

*** 编辑
现在它在这里失败了:
gssntlm_init_sec_context ..
gssntlm_acquire_cred ..
gssntlm_acquire_cred_from ..

    if (cred_store != GSS_C_NO_CRED_STORE) {
        retmin = get_creds_from_store(name, cred, cred_store);
    } else {
        retmin = get_user_file_creds(name, cred);
        if (retmin) {
            retmin = external_get_creds(name, cred);
        }
    }

get_user_file_creds()返回错误,因为我没有特定的文件设置,因为我想从广告中验证用户

external_get_creds()在这里失败:

    wbc_status = wbcCredentialCache(&params, &result, NULL);
    if(!WBC_ERROR_IS_OK(wbc_status)) goto done;

external_get_creds尝试使用Winbind库进行身份验证,并且显然在凭据缓存中没有用户在场

我设法用samba提供的winbind库对其进行了编译

所以现在的问题是:
如何设置Winbind库以与AD通信?

*** 编辑

我曾尝试在github上使用.net 5,但有人告诉我NTLM可在.net 5中使用。但是,我得到的结果与.net 3.1相同。

我尝试过的Docker镜像:
FROM mcr.microsoft.com/dotnet/core-nightly/sdk:5.0-buster as final
USER root
RUN whoami
RUN apt update && apt dist-upgrade -y

RUN DEBIAN_FRONTEND=noninteractive apt install -y krb5-config krb5-user

RUN mkdir /app

RUN apt install -y mc sudo syslog-ng python3-software-properties software-properties-common packagekit git gssproxy vim apt-utils
RUN apt install -y autoconf automake libxslt-dev doxygen findutils libgettextpo-dev libtool m4 make libunistring-dev libssl-dev zlib1g-dev gettext xsltproc libxml2-utils libxml2-dev xml-core docbook-xml docbook-xsl bison libkrb5-dev
RUN systemctl enable syslog-ng
RUN mkdir /src 


#RUN cd /src && git clone https://github.com/scholtz/gss-ntlmssp.git 
RUN DEBIAN_FRONTEND=noninteractive apt install -y libwbclient-dev samba samba-dev
#RUN cat /usr/include/samba-4.0/wbclient.h

COPY gss-ntlmssp /usr/local/src/gss-ntlmssp
RUN cd /usr/local/src/gss-ntlmssp/ && autoreconf -f -i && ./configure && make && make install
RUN cp /usr/local/src/gss-ntlmssp/examples/mech.ntlmssp.conf /etc/gss/mech.d/mech.ntlmssp.conf
RUN groupadd --gid 1000 app && useradd --uid 1000 --gid app --shell /bin/bash -d /app app

RUN echo BQIAAABMA..ArHdoQ== | base64 -d > /etc/krb5.keytab

COPY krb5.conf /etc/krb5.conf
COPY smb.conf /etc/samba/smb.conf
COPY krb5.conf /usr/local/etc/krb5.conf

RUN DEBIAN_FRONTEND=noninteractive apt install -y winbind

ENV KRB5_TRACE=/dev/stdout

RUN mkdir /src2
WORKDIR /src2
RUN dotnet --list-runtimes
RUN dotnet new webapi --auth Windows 
RUN dotnet add package Microsoft.AspNetCore.Authentication.Negotiate


RUN sed -i '/services.AddControllers/i services.AddAuthentication(Microsoft.AspNetCore.Authentication.Negotiate.NegotiateDefaults.AuthenticationScheme).AddNegotiate();' Startup.cs 

RUN sed -i  '/app.UseAuthorization/i app.UseAuthentication();' Startup.cs
run echo a
RUN cat Startup.cs

RUN dotnet restore
RUN dotnet build


ENV ASPNETCORE_URLS="http://*:5002;https://*:5003"
EXPOSE 5002
EXPOSE 5003

RUN cd /app
WORKDIR /app
docker run -it -p 5003:5003 -it registry.k01.mydomain.com/k01-devbase:latest

在Docker容器中:
kinit HTTP/myuser@MYDOMAIN.COM -k -t /etc/krb5.keytab
klist

enter image description here
dotnet run src2.dll

enter image description here

我已将自己的调试信息放入gssntlmssp库中,并将其保存到文件中
cat /tmp/gss-debug.log

enter image description here

这与我完成.net core 3.1的目的完全相同。

wbcCredentialCache(samba lib)在找不到高速缓存的凭据时失败

这是我的krb5.conf:
[appdefaults]
    default_lifetime      = 25hrs
    krb4_convert          = false
    krb4_convert_524      = false

    ksu = {
        forwardable       = false
    }

    pam = {
        minimum_uid       = 100
        forwardable       = true
    }

    pam-afs-session = {
        minimum_uid       = 100
    }

[libdefaults]
    default_realm         = MYDOMAIN.COM

[realms]
     MYDOMAIN.COM = {
        kdc            = DC01.MYDOMAIN.COM
        default_domain = MYDOMAIN.COM
    }

[domain_realm]
    mydomain.com.    = MYDOMAIN.COM
    .mydomain.com.    = MYDOMAIN.COM

[logging]
default      = CONSOLE
default      = SYSLOG:INFO
default = FILE:/var/log/krb5-default.log
kdc = CONSOLE
kdc = SYSLOG:INFO:DAEMON
kdc = FILE:/var/log/krb5-kdc.log
admin_server = SYSLOG:INFO
admin_server = DEVICE=/dev/tty04
admin_server = FILE:/var/log/krb5-kadmin.log

以及samba文件的一部分:
[global]
  security = domain
  workgroup = mydomain.com
  password server = *
  idmap config * : range = 16777216-33554431
  template shell = /bin/bash
  winbind use default domain = yes
  winbind offline logon = false
  wins server = 10.0.0.2

在我看来,我更希望先有NTLM,然后再进行协商,因为据我所知,浏览器不支持协商。例如,在firefox中,人员必须为协商服务器设置about:config。不支持通配符,...

尽管如此,看来我将无法使用ntlm运行.net core 5 Web应用程序,因此我将尝试在不使用gssntlmssp库的情况下使用一些默认的kerberos机制对其进行设置。 知道我的krb5.conf设置有什么问题吗?

**** 编辑
所以我现在正在尝试两种不同的方法:
  • NTLM-我认为这是一种更可取的方式,因为我已经看到ntlm在iis express中对用户进行身份验证,例如没有对话框,并且不需要在firefox中或通过组策略进行任何特殊配置(如果我错了,请修复我)
  • 谈判

  • 关于谈判,我已经取得了一些进展。

    有了这个docker容器,我得以解决不受支持的机制:
    FROM mcr.microsoft.com/dotnet/core/sdk:3.1-buster as final
    USER root
    RUN whoami
    RUN apt update && apt dist-upgrade -y
    
    RUN DEBIAN_FRONTEND=noninteractive apt install -y krb5-config krb5-user
    
    RUN mkdir /app
    
    RUN apt install -y mc sudo syslog-ng python3-software-properties software-properties-common packagekit git gssproxy vim apt-utils
    RUN apt install -y autoconf automake libxslt-dev doxygen findutils libgettextpo-dev libtool m4 make libunistring-dev libssl-dev zlib1g-dev gettext xsltproc libxml2-utils libxml2-dev xml-core docbook-xml docbook-xsl bison libkrb5-dev
    RUN systemctl enable syslog-ng
    RUN mkdir /src 
    
    RUN groupadd --gid 1000 app && useradd --uid 1000 --gid app --shell /bin/bash -d /app app
    
    RUN echo BQIAAAA8..vI | base64 -d > /etc/krb5.keytab
    
    
    COPY krb5.conf /etc/krb5.conf
    COPY krb5.conf /usr/local/etc/krb5.conf
    ADD ca/is.k01.mydomain.com.p12 /etc/ssl/certs/is.k01.mydomain.com.pfx
    
    RUN cd /app
    WORKDIR /app
    

    但是现在我还有其他问题:
    在 key 表中找到请求票证服务器HTTP/is.k01.mydomain.com@MYDOMAIN.com kvno 3,但没有使用rc4-hmac编码enctype

    在我看来,keytab不是使用rc4-hmac的,这是正确的,因为keytab是使用以下命令生成的
    ktpass -princ HTTP/is.k01.mydomain.com@MYDOMAIN.COM -pass *****  -mapuser MYDOMAIN\is.k01.kerb -pType KRB5_NT_PRINCIPAL -out c:\temp\is.k01.HTTP.keytab -crypto AES256-SHA1
    

    如.net文档所述。

    我无法禁止使用rc4-hmac,而只能使用较新的编码,因此我要求基础设施部门使用旧的rc4-hmac编码生成新的 key 表。

    此步骤使我更进一步,但出现了以下错误:请求票证服务器HTTP/is.k01.mydomain.com@MYDOMAIN.COM在 key 表中找不到kvno 4; keytab可能已过期*

    这很奇怪,因为 key 表无法过期,密码没有更改,并且在一小时前生成 key 表时密码是100%有效的,并且在Web上没有信息-“在 key 表中未找到kvno 4”仅获取4结果在谷歌。

    **** 编辑

    所以最后我设法使它起作用:)

    “ktab中找不到kvno 4”的问题在krb5.conf文件中,在这里我赞成强制进行AES加密,我在其中添加了几行
    #   default_tkt_enctypes  = aes256-cts-hmac-sha1-96 aes256-cts-hmac-sha1-9
    #   default_tgs_enctypes  = aes256-cts-hmac-sha1-96 aes256-cts-hmac-sha1-9
    #   permitted_enctypes    = aes256-cts-hmac-sha1-96 aes256-cts-hmac-sha1-9
    

    在我将它们注释掉之后,使用“协商”进行的身份验证已开始起作用。我已经用.net 5测试了NTLM,但仍然无法正常工作。

    上面构建时可以在docker容器中进行协商的krb5.conf文件:
    [appdefaults]
        default_lifetime      = 25hrs
        krb4_convert          = false
        krb4_convert_524      = false
    
        ksu = {
            forwardable       = false
        }
    
        pam = {
            minimum_uid       = 100
            forwardable       = true
        }
    
        pam-afs-session = {
            minimum_uid       = 100
        }
    
    [libdefaults]
        default_realm         = MYDOMAIN.COM
    
    [realms]
         MYDOMAIN.COM = {
            kdc            = DC02.MYDOMAIN.COM
            default_domain = MYDOMAIN.COM
        }
    
    [domain_realm]
        mydomain.com.    = MYDOMAIN.COM
        .mydomain.com.    = MYDOMAIN.COM
    
    [logging]
    default      = CONSOLE
    default      = SYSLOG:INFO
    default = FILE:/var/log/krb5-default.log
    kdc = CONSOLE
    kdc = SYSLOG:INFO:DAEMON
    kdc = FILE:/var/log/krb5-kdc.log
    admin_server = SYSLOG:INFO
    admin_server = DEVICE=/dev/tty04
    admin_server = FILE:/var/log/krb5-kadmin.log
    

    因此,现在的问题是:有什么方法可以允许许多服务运行协商协议(protocol),而不用将每个服务添加到spn并手动设置浏览器?

    因此,目前每个新的Web服务都必须具有:
    setspn -S HTTP/mywebservice.mydomain.com mymachine
    setspn -S HTTP/mywebservice@MYDOMAIN.COM mymachine
    

    并且必须在Internet Explorer>设置>安全性>网站>详细信息>域中列出
    在Firefox中关于:配置> network.negotiate-auth.trusted-uris
    据我所知,chrome需要Internet Explorer设置

    我认为应该可以通过域组策略以某种方式更新Internet Explorer的设置。有人知道如何吗?

    **** 编辑
    我已经在域中测试了通配符以在浏览器中协商设置,结果如下:
  • chrome :支持* .k01.mydomain.com
  • ,即:支持* .k01.mydomain.com
  • firefox (73.0.1(64位)):不支持* .k01.mydomain.com-仅完整域,例如is.k01.mydomain.com
  • 边缘 44.18362.449.0-不知道为什么,但没有传播任何设置。..*。k01.mydomain.com或is.k01.mydomain.com都不工作

  • **** 编辑
    我已经开始将Win Auth与“协商”一起使用,但是现在.NET Core中出现了一些问题

    IIS express下的以下代码以MYDOMAIN\myuser的形式显示用户:

    var userId = string.Join(',', User?.Identities?.Select(c => c.Name)) ?? "?";
    
    

    在Linux中,它显示为myuser@mydomain.com

    IIS express下的User.Indentities.First()是WindowsIdentity,我可以列出该用户的所有组

    Linux下的User.Indentities.First()是ClaimsIdentity,没有组信息

    当我尝试通过IIS Express中的组限制它时,我得到:

    //Access granted
    [Authorize(Roles = "MYDOMAIN\\GROUP1")]
    

    //403
    [Authorize(Roles = "MYDOMAIN\\GROUP_NOT_EXISTS")]
    

    Linux红est与协商:

    //403
    [Authorize(Roles = "MYDOMAIN\\GROUP1")]
    

    因此,似乎在茶est中协商不能正确列出组。因此,我现在要研究,如何在红est 中获取WindowsIdentity。

    最佳答案

    本文是误解事物运作方式的一个很好的例子。我完全不建议遵循本文所述的方式(像我一样)。
    相反,我建议您学习Kerberos身份验证,其工作方式,所需的设置。这个article形象地很好。
    首先,
    如果您分析来自浏览器(例如,用户Fiddler)的HTTP流量,则可以在第二个请求中找到TGS token 。

  • 如果它以Negotiate TlR开头,那么您正在通过NTLM进行身份验证。
  • 如果它以Negotiate YII开头,那么您正在通过Kerberos进行身份验证。

  • 其次,
    就像David所说的那样,ASP.NET Core 3.1根本不支持Linux上的NTLM。因此,如果您具有TlR token 和ntlm-gssapi机制,则将获得“未提供凭据,或者凭据不可用或不可访问。” 错误。
    如果您具有TlR token 并使用默认的Kerberos机制,则将获得“请求了不受支持的机制”。
    接下来,
    使您的应用正常运行的唯一方法是创建SPN并正确生成 Kerberos身份验证的 key 表。 不幸的是,这没有得到很好的记录。所以,我在这里举一个例子,使事情更加清楚。
    假设您有:
  • AD域MYDOMAIN.COM
  • 具有主机webapp.webservicedomain.com的Web应用程序。这可以以mydomain.com结尾,但就我而言不是。
  • Windows计算机以mymachine的名称加入了AD。
  • 机器帐户MYDOMAIN\mymachine

  • 关于here的说明,您需要执行以下操作:
  • 将新的Web服务SPN添加到机器帐户:
  • setspn -S HTTP/webapp.webservicedomain.com mymachine
  • setspn -S HTTP/webapp@MYDOMAIN.COM mymachine
  • 使用ktpass生成 key 表文件
  • ktpass -princ HTTP/webapp.webservicedomain.com@MYDOMAIN.COM -pass myKeyTabFilePassword -mapuser MYDOMAIN\mymachine$ -pType KRB5_NT_PRINCIPAL -out c:\temp\mymachine.HTTP.keytab -crypto AES256-SHA1 *。

  • *确保MYDOMAIN\mymachine允许在AD中使用AES256-SHA1
    最后,
    完成上述所有操作,并使用keytab将应用程序部署到Linux容器后,集成Windows身份验证应该可以很好地工作。我的实验表明,您不仅可以在名称为“mymachine”的主机上使用任何地方的keytab。

    关于kerberos - Linux Docker容器中的Windows身份验证,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60296237/

    相关文章:

    hadoop - 当使用beeline连接到启用了Kerberos的EMR群集上的Hive时,为什么要使用Hive服务主体?

    asp.net-mvc - Asp.Net 3.1 使用 Windows 身份验证和角色授权

    angular - Windows 身份验证和 Angular 4 应用程序

    wcf - 具有 WCF 和 Windows 身份验证的 CORS

    java - 如何使用 keytab 在 LDAP 服务器中进行身份验证

    java - 将 Java 中获取的 TGT 用于 SSH/其他应用程序

    java - Jaspic ServerAuthModule 委托(delegate)给 JAAS Krb5LoginModule

    hadoop - Hadoop 集群交互式用户的永久 Kerberos 票证

    java - Kerberos:通过IP地址访问主机

    c# - NegotiateStream 无法通过 SASL (POP3/IMAP/SMTP) 使用 Kerberos/NTLM/GSSAPI?