0

I am running a webserver (in this case airflow) on an Ubuntu 18.04 machine which needs to access a SQL Server database which is on the domain/AD.

Q: How can I use Kerberos authentication in a systemd service to access a MSSQL database on the domain?

Subqestion: How might I automate renewal of tickets? I toiled with k5start for some time with no success, is there a standardized way of doing this?

Running from shell:

airflow@airflow:~$ kinit airflow@EXAMPLE.COM
Password for airflow@EXAMPLE.COM:
airflow@airflow:~$ klist -A
Ticket cache: KEYRING:persistent:478604841:478604841
Default principal: airflow@EXAMPLE.COM

Valid starting       Expires              Service principal
11/08/2019 22:34:41  11/09/2019 08:34:41  krbtgt/EXAMPLE.COM@EXAMPLE.COM
        renew until 11/09/2019 08:34:41
airflow@airflow:~$ airflow webserver

Result: webserver successfully connects to SQL Server through Kerberos

Side note: after running web server as above, klist shows the SPN of the SQL Server:

airflow@airflow:~$ klist
Ticket cache: KEYRING:persistent:478604841:478604841
Default principal: airflow@EXAMPLE.COM

Valid starting       Expires              Service principal
11/08/2019 23:00:22  11/09/2019 09:00:18  MSSQLSvc/dbserver.example.com:1433@EXAMPLE.COM
        renew until 11/15/2019 23:00:14
11/08/2019 23:00:18  11/09/2019 09:00:18  krbtgt/EXAMPLE.COM@EXAMPLE.COM
        renew until 11/15/2019 23:00:14

Kinit then start service

airflow@airflow:~$ kinit airflow@EXAMPLE.COM
airflow@airflow:~$ sudo service airflow-webserver start
airflow@airflow:~$ journalctl -u airflow-webserver.service -xe

Output

Nov 08 18:12:11 airflow airflow[54723]:   File "/home/EXAMPLE.COM/airflow/.pyenv/versions/3.7.4/lib/python3.7/site-packages/sqlalchemy/engine/default.py", line 481, in connect
Nov 08 18:12:11 airflow airflow[54723]:     return self.dbapi.connect(*cargs, **cparams)
Nov 08 18:12:11 airflow airflow[54723]: sqlalchemy.exc.DBAPIError: (pyodbc.Error) ('HY000', '[HY000] [Microsoft][ODBC Driver 17 for SQL Server]SSPI Provider: No Kerberos credentials available (default cache: FILE:/tmp/krb5cc_478604841) (851968) (SQLDriverConnect)')
Nov 08 18:12:11 airflow airflow[54723]: (Background on this error at: http://sqlalche.me/e/dbapi)

/etc/krb5.conf

[libdefaults]
        default_realm = EXAMPLE.COM
        dns_lookup_realm = true
        dns_lookup_kdc = true
        ticket_lifetime = 24h
        renew_lifetime = 7d
        forwardable = true
        ccache_type = 5
        default_ccache_name = KEYRING:persistent:%{uid}
        default_client_keytab_name = /home/%d/%u.keytab
[realms]
        EXAMPLE.COM = {
                kdc = exampledc1.example.com
                kdc = exampledc2.example.com
        }

[domain_realm]
        .example.com = EXAMPLE.COM
        example.com = EXAMPLE.COM

/etc/systemd/system/airflow-webserver.service

[Unit]
Description=Airflow web server daemon
After=network.target

[Service]
EnvironmentFile=/etc/sysconfig/airflow
User=airflow
Group=airflow
Type=simple
ExecStart = /home/EXAMPLE.COM/airflow/.pyenv/versions/3.7.4/bin/airflow webserver
Restart=on-failure
RestartSec=5s

[Install]
WantedBy=multi-user.target
telemark
  • 3
  • 1
  • 3

2 Answers2

1

The usual way to do this is to have a separate service that keeps your Kerberos ticket refreshed, and in the MS SQL service set the KRB5CCNAME environment variable to the path of the credentials cache that the other service is keeping refreshed.

In the MS SQL service:

# systemd service file
...
[Service]
Environment="KRB5CCNAME=FILE:/tmp/cache.tkt"
...

Here is the "refresher" service:

[Unit]
Description=My Kerberos Ticket Service
Wants=network-online.target
After=network-online.target

[Service]
Type=simple
ExecStart=/usr/bin/k5start -U -f /path/to/keytab \
         -k /tmp/cache.tkt -l 10h -K 30 \
         -m 600 -o root -g root

# Restart on any failure after 5 seconds
Restart=on-failure
RestartSec=5s

You may need to adjust the credentials cache file permissions to be sure that the MS SQL service can read the file. You will, of course, need to have a keytab file with the proper credentials.

user35042
  • 2,601
  • 10
  • 32
  • 57
  • Thanks for this. A point of clarification: Is the keytab needed in the refresher service the client keytab or the one located in /etc/krb5.keytab? Does the latter serve any purpose on a client machine? – telemark Nov 09 '19 at 16:06
  • The keytab used by the refresher service needs to be the one that contains the credentials your other service needs. In your case, you need to point at the keytab file containing the credentials for `airflow@EXAMPLE.COM`. – user35042 Nov 09 '19 at 23:42
0

In recent MIT Kerberos versions client keytabs were introduced. They are used by the GSS-API to obtain a credential cache if it is missing. You just have to find the default location:

krb5-config --defcktname

and create the keytab using kadmin:

ktadd -k <location> airflow@EXAMPLE.COM
Piotr P. Karwasz
  • 5,292
  • 2
  • 9
  • 20