web-dev-qa-db-fra.com

Authentification Windows dans le conteneur Docker Linux

j'essaye d'utiliser l'authentification Windows dans le conteneur de docker de linux sous kubernetes.

Je suis ces paramètres: https://docs.Microsoft.com/en-us/aspnet/core/security/authentication/windowsauth?view=aspnetcore-3.1&tabs=visual-studio#kestrel

L'application est en .net core3, avec nuget Microsoft.AspNetCore.Authentication.Negotiate et s'exécute dans Kestrel

J'ai ajouté le

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

aussi bien que

app.UseAuthentication();

et configurer mon image devbase comme

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

la construction dans le pipeline tfs crée une image docker d'application dérivée de ci-dessus et ajoute les variables d'environnement suivantes, copie également la construction dans/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

l'application est exécutée par run.sh

service syslog-ng start
kinit HTTP/[email protected] -k -t /app/is.k01.HTTP.keytab
klist
dotnet dev-certs https
dotnet /app/SampleApi.dll

klist répertorie le principal qui a attribué le SPN à la machine

dans ie et firefox, j'ai ajouté le network.negotiate-auth.trusted-uris à mon application

cependant j'obtiens la boîte de dialogue de connexion sans succès pour me connecter

donc la question est:

Comment activer le journal de débogage avec le package Microsoft.AspNetCore.Authentication.Negotiate?

Je suppose que ce paquet ne communique pas correctement avec Kerberos, peut-être qu'un paquet est manquant, ne fonctionne pas ou quelque chose.

Notez également que le conteneur et l'application .net sont connectés avec succès au domaine car j'utilise la sécurité intégrée pour la connexion à la base de données qui fonctionne.

**** Edit> Réponse à la première partie

Pour activer les journaux, il faut activer les journaux dans Kestrel: dans appsettings.json:

  "Logging": {
    "LogLevel": {
      "Default": "Debug",
    }
  },

Dans program.cs:

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

Dans Startup.cs, on peut suivre les événements de négociation:

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;
            }
        };
    }
);

**** Éditer

Pendant ce temps, selon mon objectif d'autoriser l'authentification Windows dans l'application Web Docker .net core, je parcourais le code source de .net core et corefx et je traduisais le code d'authentification vers cet exemple d'application console:

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);
}

J'ai donc découvert que la bibliothèque communique avec System.Net.NTAuthentication qui communique avec System.Net.Security.NegotiateStreamPal qui communique avec la version unix de Interop.NetSecurityNative.InitSecContext

qui devrait en quelque sorte déclencher le GSSAPI dans os

Dans dotnet runtime git, ils nous disent que gss-ntlmssp est nécessaire pour que cela fonctionne même si cela n'est de toute façon pas mentionné dans la documentation de base d'aspnet.

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

Néanmoins, j'ai compilé le gss-ntlmssp et découvert que sans cette bibliothèque, il génère une erreur " Un mécanisme non pris en charge a été demandé.". Avec ma bibliothèque, l'erreur " Aucune information d'identification n'a été fournie, ou les informations d'identification étaient indisponibles ou inaccessibles.", mais n'accédez jamais aux méthodes gss_ *.

J'ai testé l'utilisation des méthodes gss en ajoutant l'entrée de journal au fichier qui ne s'est jamais produite .. 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);
}

Ainsi .net appelle gssapi, et gssapi n'appelle pas de mécanisme.

J'ai observé le même comportement dans centos7 vm, sous-système Windows ubuntu et image docker Debian (mcr.Microsoft.com/dotnet/core/sdk:3.1-buster personnalisé)

Alors la question est maintenant, comment puis-je déboguer gssapi?

Je suppose que mon gssapi actuel est géré par cette bibliothèque:

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

jusqu'à présent, j'ai compilé le nouveau dernier gssapi à partir de la source mit, et j'ai découvert qu'il me lance l'erreur "Un mécanisme non pris en charge a été demandé." car gssapi nécessite un interpréteur gss qui n'est pas fourni. Dans centos7, j'ai eu un autre problème que la bibliothèque openssl utilisait la bibliothèque kerberos partagée qui était incompatible, donc yum a cessé de fonctionner.

*** Éditer

J'ai découvert que le gss-ntlmssp a le drapeau GSS_C_MA_NOT_DFLT_MECH donc il échouait avec le message "Aucune information d'identification n'a été fournie, ou les informations d'identification étaient indisponibles ou inaccessibles.". La solution consiste à créer un gss-ntlmssp personnalisé sans cet attribut car je souhaite l'utiliser comme mécanisme d'authentification par défaut.

Mon exemple d'application de console pour vérifier les informations d'identification fonctionne maintenant, je vais essayer de le faire fonctionner dans le conteneur Docker maintenant.

*** Éditer

J'ai pu exécuter mon ConsoleApp avec succès dans kubernetes:

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

Cependant, j'obtiens cette erreur maintenant:

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)

*** edit Maintenant, ça échoue ici: 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 () renvoie une erreur car je n'ai pas de configuration de fichier spécifique car je veux vérifier les utilisateurs à partir de l'annonce

external_get_creds () échoue ici:

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

external_get_creds essaie de s'authentifier avec la bibliothèque winbind et, évidemment, dans le cache des informations d'identification, aucun utilisateur n'est présent

j'ai réussi à le compiler avec la bibliothèque winbind fournie par samba

donc la question est maintenant: Comment configurer la bibliothèque winbind pour communiquer avec AD?

*** Éditer

J'ai essayé d'utiliser .net 5 comme sur github, on m'a dit que NTLM fonctionne dans .net 5. Cependant, j'obtiens le même résultat qu'avec .net 3.1.

Image Docker avec laquelle j'ai essayé cela:

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

Dans le conteneur Docker:

kinit HTTP/[email protected] -k -t /etc/krb5.keytab
klist

enter image description here

dotnet run src2.dll

enter image description here

J'ai mis mes propres informations de débogage dans la bibliothèque gssntlmssp et je les ai mises dans un fichier

cat /tmp/gss-debug.log

enter image description here

C'est exactement la même fin où j'ai terminé avec .net core 3.1.

wbcCredentialCache (samba lib) échoue au point où il ne peut pas trouver les informations d'identification mises en cache

C'est mon 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

et une partie du fichier 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

À mon avis, j'aimerais plus avoir NTLM que Negotiate car Negotiate n'est pas pris en charge par les navigateurs pour autant que je sache. Par exemple, dans Firefox, la personne doit configurer le about: config pour le serveur de négociation. Les caractères génériques ne sont pas pris en charge, ...

néanmoins, il semble que je ne pourrai pas exécuter l'application Web .net core 5 avec ntlm, donc je vais essayer de la configurer sans la bibliothèque gssntlmssp maintenant avec un mécanisme kerberos par défaut. Une idée de ce qui ne va pas avec mes paramètres krb5.conf?

**** Edit J'essaye donc maintenant deux approches différentes:

  1. NTLM - à mon avis, c'est une manière préférable car j'ai vu ntlm authentifier les utilisateurs dans iis express par exemple sans la boîte de dialogue, et ne nécessite aucune configuration spéciale dans Firefox ou via la stratégie de groupe (veuillez me réparer si je me trompe)
  2. Négocier

En ce qui concerne la négociation, j'ai réussi à faire des progrès.

Avec ce conteneur docker, j'ai pu contourner le mécanisme non pris en charge:

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

Cependant, j'ai maintenant un autre problème: Demander au serveur de tickets HTTP/[email protected] kvno 3 trouvé dans keytab mais pas avec enctype rc4-hmac

Cela me semble que le keytab n'est pas avec rc4-hmac ce qui est vrai, car le keytab a été généré avec

ktpass -princ HTTP/[email protected] -pass *****  -mapuser MYDOMAIN\is.k01.kerb -pType KRB5_NT_PRINCIPAL -out c:\temp\is.k01.HTTP.keytab -crypto AES256-SHA1

comme le dit la documentation .net.

Je n'ai pas été en mesure d'interdire l'utilisation de rc4-hmac et d'autoriser uniquement le codage plus récent, j'ai donc demandé à mon service infra de générer un nouveau keytab avec l'ancien codage rc4-hmac.

Cette étape m'a déplacé plus loin et j'obtiens cette erreur à la place: Demande du serveur de tickets HTTP/[email protected] kvno 4 introuvable dans keytab; keytab est probablement obsolète *

Ce qui est très étrange car les keytabs ne peuvent pas être obsolètes, le mot de passe n'a pas été changé et était valide à 100% il y a une heure lorsque le keytab a été généré, et il n'y a aucune information sur le Web - "kvno 4 not found in keytab" chercher seulement 4 résultats dans google.

**** ÉDITER

Donc, finalement, j'ai réussi à le faire fonctionner :)

Le problème avec "kvno 4 non trouvé dans keytab" était dans le fichier krb5.conf, où je suis en faveur de forcer le cryptage aes j'ai ajouté des lignes

#   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

Après les avoir commentés, l'authentification à l'aide de Negotiate a commencé à fonctionner. J'ai testé le NTLM avec .net 5 et cela ne fonctionne toujours pas.

Le fichier krb5.conf avec lequel négocier dans le conteneur docker comme build ci-dessus fonctionne:

[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

Donc la question maintenant: Y a-t-il un moyen de permettre à de nombreux services d'exécuter le protocole de négociation sans ajouter chacun à spn par un, et de configurer manuellement les navigateurs?

Donc, pour le moment, chaque nouveau service Web doit avoir:

setspn -S HTTP/mywebservice.mydomain.com mymachine
setspn -S HTTP/[email protected] mymachine

et doit être autorisé dans Internet Explorer> paramètres> sécurité> sites Web> Détails> le domaine doit y figurer dans Firefox à propos de: config> network.negotiate-auth.trusted-uris chrome en ce qui concerne i know prend les paramètres d'Internet Explorer

je suppose que les paramètres d'Internet Explorer devraient être mis à jour d'une manière ou d'une autre par la stratégie de groupe de domaine .. quelqu'un a une idée de comment?

**** EDIT J'ai testé le caractère générique dans le domaine pour négocier les paramètres dans les navigateurs et voici les résultats:

  • chrome: SUPPORTS * .k01.mydomain.com
  • ie: SUPPORTS * .k01.mydomain.com
  • firefox (73.0.1 (64 bits)): NE SUPPORTE PAS * .k01.mydomain.com - uniquement domaine complet, par exemple is.k01.mydomain.com
  • Edge 44.18362.449.0 - je ne sais pas pourquoi mais aucun des paramètres ie n'a été propagé .. ne fonctionne pas avec * .k01.mydomain.com ni is.k01.mydomain.com

**** EDIT J'ai commencé à utiliser l'authentification win avec negocier, mais j'obtiens maintenant des problèmes dans .net core

Ce code sous IIS express montre l'utilisateur sous la forme MYDOMAIN\myuser:

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

Sous Linux, il s'affiche sous la forme [email protected]

User.Indentities.First () under IIS express est WindowsIdentity et je peux lister tous les groupes de l'utilisateur

User.Indentities.First () sous Linux est ClaimsIdentity sans informations de groupe

Quand j'essaye de le restreindre avec le groupe dans IIS Express j'obtiens:

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

Kestrel Linux avec negocier:

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

Il semble donc que la négociation dans Kestrel ne répertorie pas correctement les groupes. Je vais donc étudier maintenant, comment obtenir WindowsIdentity dans Kestrel.

5
Scholtz

Dans dotnet runtime git, ils nous disent que gss-ntlmssp est nécessaire pour que cela fonctionne même si cela n'est de toute façon pas mentionné dans la documentation de base d'aspnet.

Le paquet 'gss-ntlmssp' est un plug-in pour prendre en charge le protocole NTLM pour l'API GSS. Il prend en charge le protocole NTLM brut ainsi que NTLM utilisé comme solution de secours de Kerberos vers NTLM lorsque "Negotiate" (protocole SPNEGO) est utilisé. Réf: https://docs.Microsoft.com/en-us/openspecs/windows_protocols/MS-SPNG/f377a379-c24f-4a0f-a3eb-0d835389e28a

À la lecture de la discussion ci-dessus et de l'image que vous avez publiée, il semble que l'application essaie réellement d'utiliser NTLM au lieu de Kerberos. Vous pouvez le dire car le jeton encodé based64 commence par "T" au lieu de "Y".

Le serveur ASP.NET Core (Kestrel) ne prend PAS du tout en charge NTLM côté serveur sous Linux. Il prévoit uniquement le renvoi de "Www-Authenticate: Negotiate" aux clients. Et cela signifie généralement que Kerberos serait utilisé. Negotiate peut revenir à l'utilisation de NTLM. Cependant, cela ne fonctionne pas dans ASP.NET Core, sauf dans .NET 5 qui n'a pas encore été livré.

Vous attendez-vous à ce que votre application revienne à NTLM? Sinon, l'environnement Kerberos n'est peut-être pas complètement configuré. Cela peut être dû à divers problèmes, notamment les SPN et les fichiers keytab Linux qui ne sont pas corrects. Cela peut également être dû au fait que le client essaie d'utiliser un nom d'utilisateur/mot de passe qui ne fait pas partie du domaine Kerberos.

Ce problème est discuté ici: https://github.com/dotnet/aspnetcore/issues/19397

Je recommande que la conversation se poursuive dans la discussion sur la question du repo core aspnet.

1
David - MSFT