2

I have a .NET Core application running on Linux container using AWS ECS Fargate.

How to connect from that application to SQL Server using integrated security?

1
  • 2
    This doesnt seem like a question but more like ahow to guide, you posted the questions and detailed answer in the same minute. Commented Dec 3, 2022 at 15:01

1 Answer 1

6

Step 1: ensure that SQL Server supports Kerberos authentication # Using SQL Server Management Studio (SSMS), connect to your database and execute following statement:

select auth_scheme  
from sys.dm_exec_connections 
where session_id = @@spid

If result of the query is KERBEROS, you are all set and proceed to Step 2. Otherwise, if result is NTLM, this means that Kerberos authentication failed, and SSMS silently fell back to using NTLM authentication. Since integrated security between SQL Server and clients running in Linux environments solely rely on Kerberos authentication, this issue must be addressed first.

Note: when connecting to SQL Server, it is important to use server hostname or FQDN instead of IP address, otherwise Kerberos authentication will not work.

Check SPN configuration

Ensure that SPN is properly configured for SQL Server.

Microsoft has also released several diagnostic tools that can help with SPN verification and configuration:

Last but not least, you can use following setspn command to query for a specific SPN(s):

setspn -T CONTOSO.COM -F -Q MSSQLSvc/your_sql_server.contoso.com

Query above does support * for a wildcard (replace CONTOSO.COM with your domain)

Configure encryption types allowed for Kerberos

Within Active Directory, find an account under which SQL Server is running. Under Account tab and Account options section, confirm that applicable Kerberos cyphers are selected.

Example:

enter image description here

Step 2: Configure ECS Task To use Kerberos authentication, Application Task within ECS Service will be composed of two containers:

  1. A container that will periodically (re)obtain and cache Kerberos ticket-granting tickets (TGT) using kinit command.
  2. A container that will run application, and use TGT acquired by first task to authenticate against MS SQL Server.

Both containers will mount the same volume. 1st container will cache/write TGT ticket to it, 2nd container will read cached TGT ticket from it.

TGT acquisition container (sidecar container)

There are only 3 files needed to setup TGT acquisition container:

  1. krb5.conf - a Kerberos configuration file.
  2. renew.sh - script file with commands to renew TGT.
  3. Dockerfile - packages all into a docker image.
# krb5.conf
[libdefaults]
dns_lookup_realm = true
dns_lookup_kdc = true
forwardable = true
default_ccache_name = FILE:/var/kerberos/krbcache # TGT cache location
default_realm = CONTOSO.COM
permitted_enctypes = aes256-cts aes128-cts

[realms]
CONTOSO.COM = {
  kdc = CONTOSO.COM
  admin_server = CONTOSO.COM
}

[domain_realm]
.contoso.com = CONTOSO.COM
contoso.com = CONTOSO.COM

[logging]
default = STDERR
# renew.sh
#!/bin/bash

# Refresh the token periodically.
# Set the length of time that the script will wait to refresh the token.
[[ "$DELAY_SECONDS" == "" ]] && DELAY_SECONDS=3600

# If the AWS region hasn't been set, get it from instance metadata. This will work in an instance as well as in an ECS container.
[[ "$AWS_REGION" == "" ]] && AWS_REGION=$(curl --silent http://169.254.169.254/latest/dynamic/instance-identity/document | jq -r .region)

# Use the ECS container as the source for AWS credentials. This allows the AWS CLI to use the permissions of the task role.
aws configure set credential_source EcsContainer


while true
do
    echo "Starting ticket renewal at: " + $(date)

    # Get the credentials from Secrets Manager.
    CREDENTIALS_SECRET_VALUE=$(aws secretsmanager get-secret-value --secret-id $CREDENTIALS_SECRET_ARN --region $AWS_REGION --query SecretString --output text)

    # Use `jq` to parse the credentials into username & password.
    CREDENTIALS_USERNAME=$(echo $CREDENTIALS_SECRET_VALUE | jq -r '.username')
    CREDENTIALS_PASSWORD=$(echo $CREDENTIALS_SECRET_VALUE | jq -r '.password')

    # Use the username & password to authenticate to Kerberos. The resulting token is written to the token cache, 
    # which is set up in `krb5.conf` to use the task scratch volume, shared by all containers.
    echo $CREDENTIALS_PASSWORD | kinit $CREDENTIALS_USERNAME -f -V $OPTIONS

    echo "Ticket renewal complete, waiting for $DELAY_SECONDS seconds"


    sleep $DELAY_SECONDS &
    wait
done
# Dockerfile

FROM amazonlinux:2

COPY renew.sh /
COPY krb5.conf /etc/krb5.conf

# Install the Kerberos tools -- to authenticate;
# `jq` -- to parse the credentials from the AWS Secrets Manager, which returns JSON
# `unzip` -- to install the latest version of the AWS CLI
RUN yum install -y krb5-workstation jq unzip 

# Download and install the latest version of the AWS CLI
RUN curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip"
RUN unzip awscliv2.zip
RUN ./aws/install

VOLUME ["/var/kerberos"]

ENTRYPOINT ["/renew.sh"]

Based on value specified in CREDENTIALS_SECRET_ARN , renew.sh will periodically renew TGT and cache/save it in location specified at krb5.conf file (e.g. /var/kerberos/krbcache).

To test that container successfully acquires TGT for a given principle, establish interactive session with the container and execute klist command. When successful, you should see the details of TGT ticket, containing principle name, expiration date, etc.

Application Container

Application container runs your .NET Core application. To enable Kerberos on that container add following lines in Dockerfile:

...
RUN apt update
RUN apt install -y krb5-config krb5-user  
COPY krb5.conf /etc/krb5.conf
VOLUME ["/var/kerberos"]
...

The content of krb5.conf file should be identical to one in TGT acquisition container, and it will instruct application to locate Kerberos TGT at FILE:/var/kerberos/krbcache .

Your application SQL connection string should look similar to this:

Server=yourSqlServer.contoso.com;Initial Catalog=YourDB;Integrated Security=true;

To test that container has access to cached TGT, establish interactive session with the container and execute klist . When successful, you should see same TGT ticket, as in another container.

If everything went well, you should be able to successfully connect to SQL Server using Integrated Security from your .NET Core application running on Linux.

Additional resources

Sign up to request clarification or add additional context in comments.

2 Comments

Question on how .NET understands to use Kerberos: Does it automatically call KDC (with TGT) to get the ticket to talk to SQL Server? And we have not specified the ServerSPN, is that also auto generated?
In .NET we only specify our intention to use Kerberos by specifying Integrated Security=true in SQL connection string. Server value in connection string Server=yourSqlServer.contoso.com is used for SPN value. After that, it is SQL driver responsibility perform necessary handshakes.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.