sebgamby
sebgamby

Reputation: 89

How can I get Kerberos authentication to work in a Docker Linux container hosting a .Net 6 application with a SqlConnnection?

I am experimenting in a small lab created with AutomatedLab that contains Windows Server 2022 machines running ActiveDirectory and SQLServer along with CentOS 8.5 machines running a Kubernetes cluster. My test application is a .Net 6 console application that simply connect to a SQLServer database running in the the lab over a trusted connection. It is containerized based on the official aspnet:6.0 image. The Kubernetes POD contains an InitContainer that executes kinit to generate a Kerberos token placed in a shared volume. I have made two versions of the test application: one that uses an OdbcConnection to connect to the database and the second one uses a SqlConnection. The version with the OdbcConnection successfully connects to the database but the one using the SqlConnection crashes when opening the connection to the database.

Here is the code of the application using the OdbcConnection:

using (var connection =
               new OdbcConnection(
                   "Driver={ODBC Driver 17 for SQL Server};Server=sql1.contoso.com,1433;Database=KubeDemo;Trusted_Connection=Yes;"))
        {
            Log.Information("connection created");
            var command = new OdbcCommand
                ("select * from KubeDemo.dbo.Test", connection);
            connection.Open();
            Log.Information("Connection opened");
            using (var reader = command.ExecuteReader())
            {
                Log.Information("Read");
                while (reader.Read())
                {
                    Console.WriteLine($"{reader[0]}");
                }
            }
        }

The logs of the container show that it can connect to the database and read its content

[16:24:35 INF] Starting the application
[16:24:35 INF] connection created
[16:24:35 INF] Connection opened
[16:24:35 INF] Read
1

Here is the code of the application using the SqlConnection:

using (var connection =
               new SqlConnection(
                   "Server=sql1.contoso.com,1433;Initial Catalog=KubeDemo;Integrated Security=True;"))
        {
            Log.Information("connection created");
            var command = new SqlCommand
                ("select * from KubeDemo.dbo.Test", connection);
            connection.Open();
            Log.Information("Connection opened");
            using (var reader = command.ExecuteReader())
            {
                Log.Information("Read");
                while (reader.Read())
                {
                    Console.WriteLine($"{reader[0]}");
                }
            }
        }

The container crashes, based on the log when the connection is being opened:

[16:29:58 INF] Starting the application
[16:29:58 INF] connection created

I have deployed the Kubernetes pod with a command "tail -f /dev/null" so that I could execute the application manually and I get an extra line:

[16:29:58 INF] Starting the application
[16:29:58 INF] connection created
Segmentation fault (core dumped)

According to Google, this is C++ error message that indicates an attempt to access an unauthorized memory section. Unfortunately I have no idea how to work around that. Does anyone has an idea how to get it to work?

To be complete, here is the Dockerfile for the containerized application

FROM mcr.microsoft.com/dotnet/aspnet:6.0 

ARG DEBIAN_FRONTEND=noninteractive
RUN apt-get update
RUN apt-get install curl gnupg2 -y
RUN curl https://packages.microsoft.com/keys/microsoft.asc | apt-key add -
RUN curl https://packages.microsoft.com/config/debian/11/prod.list > /etc/apt/sources.list.d/mssql-release.list
RUN apt-get update
RUN ACCEPT_EULA=Y apt-get install --assume-yes --no-install-recommends --allow-unauthenticated unixodbc msodbcsql17 mssql-tools
RUN apt-get remove curl gnupg2 -y
RUN echo 'export PATH="$PATH:/opt/mssql-tools/bin"' >> ~/.bash_profile 
RUN echo 'export PATH="$PATH:/opt/mssql-tools/bin"' >> ~/.bashrc

WORKDIR /app
EXPOSE 80
COPY ./ .
ENTRYPOINT ["dotnet", "DbTest.dll"]

And the POD Helm template:

apiVersion: v1
kind: Pod
metadata:
  name: dbtest
  labels:
    app: test
spec:    
  restartPolicy: Never
  volumes:
    - name: kbr5-cache
      emptyDir:
        medium: Memory
    - name: keytab-dir
      secret:
        secretName: back01-keytab
        defaultMode: 0444
    - name: krb5-conf
      configMap:
        name: krb5-conf
        defaultMode: 0444
  initContainers:
    - name: kerberos-init
      image: gambyseb/private:kerberos-init-0.2.0
      imagePullPolicy: {{ .Values.image.pullPolicy }}
      securityContext:
        allowPrivilegeEscalation: false
        privileged: false
        readOnlyRootFilesystem: true
      env:
        - name: KRB5_CONFIG
          value: /krb5
      volumeMounts:
        - name: kbr5-cache
          mountPath: /dev/shm
        - name: keytab-dir
          mountPath: /keytab
        - name: krb5-conf
          mountPath: /krb5
  containers:
    - name: dbtest
      image: {{ .Values.image.repository }}:DbTest-{{ .Chart.AppVersion }}
      imagePullPolicy: {{ .Values.image.pullPolicy }}          
      env:
        - name: ASPNETCORE_ENVIRONMENT
          value: "{{ .Values.environment.ASPNETCORE }}"
        - name: KRB5_CONFIG
          value: /krb5
{{/*      command:*/}}
{{/*        - "tail"*/}}
{{/*        - "-f"*/}}
{{/*        - "/dev/null"*/}}
      securityContext:
        allowPrivilegeEscalation: true
        privileged: true
      ports:
        - containerPort: 80
      volumeMounts:
        - name: kbr5-cache
          mountPath: /dev/shm
        - name: krb5-conf
          mountPath: /krb5
        - name: keytab-dir
          mountPath: /keytab
{{/*    - name: kerberos-refresh*/}}
{{/*      image: gambyseb/private:kerberos-refresh-0.1.0*/}}
{{/*      imagePullPolicy: {{ .Values.image.pullPolicy }}*/}}
{{/*      env:*/}}
{{/*        - name: KRB5_CONFIG*/}}
{{/*          value: /krb5*/}}
{{/*      volumeMounts:*/}}
{{/*        - name: kbr5-cache*/}}
{{/*          mountPath: /dev/shm*/}}
{{/*        - name: keytab-dir*/}}
{{/*          mountPath: /keytab*/}}
{{/*        - name: krb5-conf*/}}
{{/*          mountPath: /krb5*/}}
  imagePullSecrets:
    - name: {{ .Values.image.pullSecret }}

Upvotes: 4

Views: 7477

Answers (1)

Alex Sheppard-Godwin
Alex Sheppard-Godwin

Reputation: 11

This may not be Auth reated.

If you are deploying to a linux container you need to make sure you don't deploy System.Data.SqlClient as this is a Windows only library. It will just blow up your container (as you are experiencing) when it first loads the library.

I found that if I added Microsoft.Data.SqlClient it didn't get added but I think I was leaving Dapper or EF to add the dependency and it went into the release as System.Data.SqlClient. As the container blew up in AWS I had very little feedback as to the cause!

See https://devblogs.microsoft.com/dotnet/introducing-the-new-microsoftdatasqlclient/

Upvotes: 1

Related Questions