在现代云原生应用中,容器化技术已经成为标准做法。然而,当涉及到数据库连接时,尤其是在需要集成安全性的场景下,实现起来可能会遇到一些挑战。本文将介绍如何在Linux容器中实现通过集成安全连接到SQL Server的解决方案,该方案不需要对.NET Core应用程序代码进行任何更改,而是通过Docker镜像准备和系统级别的Kerberos认证配置来实现。
要实现这一解决方案,需要逐步构建解决方案的各个部分。这涉及到Docker主机的设置、SQL Server实例的配置、域控制器的准备,以及一个简单的.NET Core应用程序来验证数据库连接。
为了在环境重构解决方案,需要以下条件:
为了验证数据库连接,创建了一个非常简单的解决方案。该应用程序在无限循环中查询SQL Server实例中的特定表,并打印结果集。
C# using System; using System.Data.SqlClient; namespace MyApplication { class Program { static void Main(string[] args) { while (true) { try { using (var connection = new SqlConnection("Server=tcp:myDataBaseServer,46005;Initial Catalog=myDataBase;Integrated Security=true;")) { var command = new SqlCommand("SELECT TOP 10 * FROM dat.myDataTable", connection); connection.Open(); using (var reader = command.ExecuteReader()) { while (reader.Read()) { Console.WriteLine($"{reader[0]}:{reader[1]} ${reader[2]}"); } } } catch (Exception ex) { Console.Write(ex); } System.Threading.Thread.Sleep(10000); } } } }
为了使Linux容器能够与密钥分发中心(KDC)通信,需要对容器镜像和配置进行一些准备工作。
演示应用程序运行在microsoft/dotnet:aspnetcore-runtime镜像上,该镜像基于debian:stretch-slim镜像。这要求安装以下软件包:
RUN apt install -y krb5-config RUN apt-get install -y krb5-user
这些软件包使能够在容器内运行kinit命令,从KDC获取Kerberos票据。此外,ktutil工具也可用于创建上述提到的keytab文件。
为了与底层KDC通信,需要创建一个适当的krb5.conf文件,并将其存储在容器的/etc文件夹中。
[libdefaults] default_realm = MY.COMPANY.LOCAL ticket_lifetime = 25h renew_lifetime = 7d forwardable = true noaddresses = true allow_weak_crypto = true rdns = false [realms] MY.COMPANY.LOCAL = { kdc = mydomaincontroller.my.company.local default_domain = my.company.local }
krb5.conf文件必须位于容器的/etc/kerb5.conf中。
为了避免在kinit命令中传递密码(例如:执行kinit username然后输入密码),决定生成适当的keytab文件。这些文件用于获取Kerberos票据,而不需要以明文形式要求密码。为了生成这样的keytab,需要在Linux shell中运行以下命令:
ktutil add_entry -password -p myUserName@MY.COMPANY.LOCAL -k 1 -e RC4-HMAC ktutil: write_kt myUserName.keytab
收到的keytab文件可以映射或复制到容器中。在使用keytab文件请求Kerberos票据时,可以运行:
kinit myUserName -k -t myUserName.keytab
通过运行klist,可以看到已收到Kerberos票据。
现在可以看一下Dockerfile:
FROM microsoft/dotnet:sdk AS build-env WORKDIR /app COPY *.csproj . RUN dotnet restore COPY . . RUN dotnet publish -c Release -o out FROM microsoft/dotnet:aspnetcore-runtime WORKDIR /app COPY --from=build-env /app/out . RUN apt-get update RUN apt-get remove krb5-config krb5-user RUN apt install -y krb5-config RUN apt-get install -y krb5-user COPY krb5.conf /etc/krb5.conf COPY myUserName.keytab /app/myUserName.keytab COPY launch.sh /launch.sh ENTRYPOINT /launch.sh
Dockerfile的工作可以描述为:
通过kinit命令收到的每个Kerberos票据都有过期日期。为了避免在容器运行时失去认证,必须在票据过期之前再次调用kinit。换句话说,kinit必须在容器的生命周期内定期执行。
与Kerberos票据类似,keytab文件也会过期。必须定期创建并提供新的keytab文件。一个可能的选项是在容器启动过程中创建文件并将其映射到容器的文件系统中。然而,根据底层环境,可能还有其他选项。