如何让 Kerberos 身份验证在托管具有 SqlConnection 的 .Net 6 应用程序的 Docker Linux 容器中工作?

发布于 2025-01-19 09:17:38 字数 5542 浏览 1 评论 0 原文

我正在使用 AutomatedLab 创建的一个小型实验室进行实验,其中包含运行 ActiveDirectory 和 SQLServer 的 Windows Server 2022 计算机以及运行 Kubernetes 集群的 CentOS 8.5 计算机。我的测试应用程序是一个 .Net 6 控制台应用程序,它只需通过可信连接连接到在实验室中运行的 SQLServer 数据库。它是基于官方的aspnet:6.0镜像进行容器化的。 Kubernetes POD 包含一个 InitContainer,它执行 kinit 以生成放置在共享卷中的 Kerberos 令牌。我制作了两个版本的测试应用程序:第一个版本使用 OdbcConnection 连接到数据库,第二个版本使用 SqlConnection。使用 OdbcConnection 的版本成功连接到数据库,但使用 SqlConnection 的版本在打开与数据库的连接时崩溃。

以下是使用 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]}");
                }
            }
        }

容器的日志显示它可以连接到数据库并读取其内容

[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

以下是使用 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]}");
                }
            }
        }

容器崩溃,根据连接时的日志正在打开:

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

我已经使用命令“tail -f /dev/null”部署了 Kubernetes pod,以便我可以手动执行应用程序,并且我得到了额外的一行:

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

根据 Google,这是指示尝试的 C++ 错误消息访问未经授权的内存 部分。不幸的是我不知道如何解决这个问题。有谁知道如何让它发挥作用?

为了完整起见,以下是容器化应用程序的 Dockerfile

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"]

和 POD Helm 模板:

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

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(
quot;{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(
quot;{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 }}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

枫林﹌晚霞¤ 2025-01-26 09:17:38

这可能不会被重新加油。

如果要部署到Linux容器,则需要确保您不部署system.data.sqlclient,因为这是仅Windows库。当您首先加载库时,它将仅炸毁您的容器(如您所经历的)。

我发现,如果我添加了microsoft.data.sqlclient,它没有添加,但是我想我要离开dapper或ef来添加依赖关系,并且它以system.data.sqlclient为单位。随着容器在AWS中炸毁,我几乎没有关于原因的反馈!

请参阅

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/

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文