Click here to Skip to main content
13,828,588 members
Click here to Skip to main content
Add your own
alternative version

Stats

2.1K views
4 bookmarked
Posted 10 Jan 2019
Licenced CPOL

Authenticate .Net Core client of SQL Server with Integrated Security from Linux docker container

, 10 Jan 2019
Rate this:
Please Sign up or sign in to vote.
Illustrates the implementation of a .Net Core app, running in a linux container, connecting to an SQL Server database with integrated security.

Editorial Note

Having trouble writing or posting articles? These articles aim to gather together tips and tricks from authors and mentors to help you write great articles.

Facing the problem

In case of dockerizing .Net applications using SQL server, one has to think about the way to connect to the database.

Fortunately Microsoft provides us with a couple of opportunities to establish secure and robust connections which can be applied to windows containers as well. However, in case of connecting out of a linux container not all these concepts are available out of the box. This also affects the usage of integrated security for establishing a connection from an already authenticated client (e.g.: Single Sign On systems).

This article applies the concept of integrated security, which is build on top of a kerberos authentication process, for linux containers. The solution requires no code changes in .Net Core application. Instead it illustrates docker image preperations and configuration of kerberos authentication on system level. At the end, you can connect via integrated security to SQL Server out of a previously authenticated linux container.

Discovering the solution step by step

For this solution we have to go down a longer road and pick up pieces of a bigger puzzle, before we are able to create a solution.

Prerequisites

Things you need to reconstruct the solution in your environment:

  • Docker host (e.g.: docker on windows, docker tool box...)
  • SQL Server instance with integrated security enabled (on premise or even dockerized)
  • Domain Controller (AD acting as Key Distribution Server)

Our demo application

In order to verify the DB connection, I created a very simple solution. The application hangs in an endless loop querying a particular table dat.MyDataTable in the database myDataBase of the SQL Server instance myDataBaseServer. Retrieved result sets (im am assuming that MyDataTable contains at least three columns) are printed as console output an can be viewed by attaching to container.

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

Please consider the connection string specifying integrated security:

"Server=tcp:myDataBaseServer,46005;Initial Catalog=myDataBase;Integrated Security=true;;"

Prepare kerberos authentication in container

In order to communicate out of linux containers with a Key Distribution Center (KDC) some preparations of container image and configuration are necessary.

  1. Install packages for KDC consumption.
  2. Creating a proper krb5.conf file for accessing KDC application hosted in AD Domain controller
  3. Generate keytab file (in order to avoid exposing passwords in plain text)

Required packages for KDC consumption

The demo application is running on the microsoft/dotnet:aspnetcore-runtime image which basically derives from the debian:stretch-slim image. This requires us to install following packages (code pasted from underlying dockerfile):

...
RUN apt install -y krb5-config 
RUN apt-get install -y krb5-user
...

These pacakges enable us to run kinit command within the container for fetching kerberos tickets from the KDC. Additional also the ktutil tool is avaiable for creating above mentioned keytab files.

Creating a proper krb5.conf file

In order to communicate with the underlying KDC a proper krb5.conf file is created and stored in the containers /etc folder. For constructing a proper example assume we are in the domain my.company.local and our KDC is given by mydomaincontroller.my.company.local (in a windows AD driven environment, you can get the value of mydomaincontroller by simply running the command echo %logonserver% when you are logged in via AD). One has also keep in mind that the KDC is located in the Domain Controller as and using the AD database.

# /etc/krb5.conf -- Kerberos V5 general configuration.
# $Id: krb5.conf,v 1.43 2011/09/23 00:37:20 eagle Exp $
#
# This is my default Kerberos v5 configuration file.  The
# canonical location of this file is http://www...
#
# This configuration allows any enctypes.  Some systems with really old
# Kerberos software may have to limit to triple-DES and DES.

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

[domain_realm]
    my.company.local    = MY.COMPANY.LOCAL

[logging]
    kdc          = SYSLOG:NOTICE
    admin_server = SYSLOG:NOTICE
    default      = SYSLOG:NOTICE

The krb5.conf file has to be located in the containers at /etc/kerb5.conf.

Generating a keytab file

In order to avoid passing passwords to kinit command (e.g.: executing kinit username and subsequently entering the password), I decided to generate proper keytab files. These files are used for fetching kerberos tickets without requireing the password in plain text. In order to generate such a keytab you need to run following commands in a Linux shell:

ktutil 
ktutil: add_entry -password -p myUserName@MY.COMPANY.LOCAL -k 1 -e RC4-HMAC
# ktutil will promt for entering the password ...
ktutil: write_kt myUserName.keytab
ktuilt: extit

The received keytab file can be mapped or copied in the container. For requesting a kerberos ticket under usage of the keytab file you can run:

kinit myUserName -k -t myUserName.keytab

By running klist you can see that a kereberos ticket was received.

Dockerize the demo application

Now we are far enough to look at the docker file:

FROM microsoft/dotnet:sdk AS build-env
WORKDIR /app

# Copy csproj and restore as distinct layers
COPY *.csproj ./
RUN dotnet restore

# Copy everything else and build
COPY . ./
RUN dotnet publish -c Release -o out


# Build runtime image
FROM microsoft/dotnet:aspnetcore-runtime
WORKDIR /app
COPY --from=build-env /app/out .

# Install krb5 packages
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 kerberso configuration and keytab
COPY krb5.conf /etc/krb5.conf
COPY myUserName.keytab /app/myUserName.keytab

# copy the launch script
COPY launch.sh /launch.sh

ENTRYPOINT /launch.sh

The job of the dockerfile can be described by:

  1. Building the .Net Core application in a container based on microsoft/dotnet:sdk AS build-env image.
  2. Copy the build artefacts to a runtime image (from microsoft/dotnet:aspnetcore-runtime)
  3. Install kerberos packages for debian:stretch-slim image (is the base of microsoft/dotnet:aspnetcore-runtime)
  4. Copy the krb5.conf file and keytab.
  5. Copy a script that executes kinit and launches the .Net application
  6. Specify the launch script as entry point.

The launch script  launch.sh has to contain the keberos authentication (kinit command) and the execution of the application:

...
kinit myUserName-k -t myUserName.keytab
dotnet MyApplication.dll

Handle expiration of kerberos tickets

Each kerberos ticket, received via kinit command, has an expiration date. In order to avoid losing authentication during the container is running, one has to call kinit again before the ticket is expired. In other words, kinit has to be executed periodical over containers lifetime.

Handle expiration of keytab files

Similar to keberos tickets, keytab files will expire. You have to create and provide new keytab files also in a periodical manner. A possible option would be to create the file during containers startup process and map it into the containers file system. Nevertheless, depending on the underlying environment, there may be other options as well. 

Run it

For running the application you have to create (use dockerfile above) an image and run a container. When you attach to the docker container you can see the result of the DB query, which is written as console output.

History

  1. (10.01.2019) created 
 
   

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Andi Kleinbichler
Architect Admiral Sportwetten GmbH
Austria Austria
No Biography provided

You may also be interested in...

Comments and Discussions

 
-- There are no messages in this forum --
Permalink | Advertise | Privacy | Cookies | Terms of Use | Mobile
Web01 | 2.8.190114.1 | Last Updated 10 Jan 2019
Article Copyright 2019 by Andi Kleinbichler
Everything else Copyright © CodeProject, 1999-2019
Layout: fixed | fluid