Difference between revisions of "Apache Kerberos Authentication"

From Michael's Information Zone
Jump to navigation Jump to search
Line 122: Line 122:
  
 
</pre>
 
</pre>
 +
 +
If you want to allow access regardless of authentication (i.e. If you use the apache variable as part of your own authentication, but allow manual login if this fails)
 +
<ref>https://www.jeffgeerling.com/blogs/jeff-geerling/apache-kerberos-authentication</ref>
 +
<ref>https://wiki.apache.org/httpd/BypassAuthenticationOrAuthorizationRequirements</ref>
 +
<ref>https://httpd.apache.org/docs/trunk/mod/mod_access_compat.html</ref>
 +
<pre>
 +
<IF "'%{REMOTE_ADDR}' != '<trusted IP here>' && '%{REQUEST_URI}' != '/wp-admin'">
 +
AuthType Kerberos
 +
AuthName "Kerberos authenticated site"
 +
KrbAuthRealms DOMAIN1.TLD DOMAIN2.TLD
 +
#KrbServiceName HTTP/user@DOMAIN1.TLD
 +
KrbServiceName Any
 +
Krb5KeyTab /etc/httpd/merged.keytab
 +
KrbMethodNegotiate On
 +
KrbMethodK5Passwd Off
 +
Satisfy Any
 +
</IF>
 +
</pre>
 +
 
==Docker==
 
==Docker==
 
===Host config===
 
===Host config===

Revision as of 15:07, 6 May 2019

Purpose

To allow users to authenticate using seamless SSO via kerberos.[1]

MultiRealm Authentication

In this case I want to authenticate more than one realm (two domains). After following the common instructions online I was unable to log in using the second realm. The first realm logged in without issue.

NOTE 1 : This is a messy post as I have worked on this for several days and am trying to record what I did before I forget.
NOTE 2 : I am not sure if all of this is necessary, but I wanted to track everything I did regardless

Environment

  • Domains

Domain1.tld
Domain2.tld

  • web server

intranet.tld

Keytab Creation

Please make sure that you do not have duplicate SPNs in AD. I ran into an issue where I converted a site to use dual realms, but the old one would not authenticate using the new keytab. Eventually I found the duplicate SPN.[2][3]

You can modify spns using two methods. If you like using a GUI, you can open the attribute editor for the service account and scroll down to SPNS and modify accordingly. Or you can use the CLI command setspn

setspn -d HTTP/your.server.com@YOURDOMAIN.COM serviceaccount
setspn -A HTTP/your.server.com serviceaccount

On the domain controllers

On domain1.tld, create a user object that will be used for the service. Then create the keytab and map it to the user.
NOTE : This is case sensitive.

ktpass /out C:\Temp\domain1.keytab /princ HTTP/website@DOMAIN1.TLD /mapuser user /pass <password> /crypto ALL /ptype KRB5_NT_PRINCIPAL /kvno 1

On domain2.tld

ktpass /out C:\Temp\domain2.keytab /princ HTTP/website@DOMAIN2.TLD /mapuser user /pass <password> /crypto ALL /ptype KRB5_NT_PRINCIPAL /kvno 1

On the web server

[root@web ~]# ktutil
ktutil:  read_kt domain1.keytab 
ktutil:  read_kt domain2.keytab
ktutil:  write_kt merged.keytab
ktutil:  exit
[root@web ~]# mv merged.keytab /etc/httpd
[root@web ~]# chgrp apache /etc/httpd/merged.keytab
[root@web ~]# chmod 440 /etc/httpd/merged.keytab

krb5.conf

The server I am using was enrolled in domain1 using sssd and the "realm join" command many a year ago. We will be editing the krb5.conf file that was created during this process.

# Configuration snippets may be placed in this directory as well
includedir /etc/krb5.conf.d/

includedir /var/lib/sss/pubconf/krb5.include.d/
[logging]
 default = FILE:/var/log/krb5libs.log
 kdc = FILE:/var/log/krb5kdc.log
 admin_server = FILE:/var/log/kadmind.log

[libdefaults]
 dns_lookup_realm = true
 ticket_lifetime = 24h
 renew_lifetime = 7d
 forwardable = true
 rdns = false
# default_realm = EXAMPLE.COM
 default_ccache_name = KEYRING:persistent:%{uid}

 default_realm = DOMAIN1.TLD
[realms]
# EXAMPLE.COM = {
#  kdc = kerberos.example.com
#  admin_server = kerberos.example.com
# }

 DOMAIN1.TLD = {
kdc = domain1.tld
admin_server = domain1.tld

 }

 DOIMAIN2.TLD = {
kdc = domain2.tld
admin_server = domain2.tld

 }


[domain_realm]
# .example.com = EXAMPLE.COM
# example.com = EXAMPLE.COM
 domain1.tld = DOMAIN1.TLD
 .domain1.tld = DOMAIN1.TLD
 domain2.tld = DOMAIN2.TLD
 .domain2.tld = DOMAIN2.TLD

[capaths]
	DOMAIN1.TLD = {
		DOMAIN2.TLD = .
	}
	DOMAIN2.TLD = {
		DOMAIN1.TLD = .
	}

VHOST Config

Here I tried using the principle from the keytab, but for some reason the kvno kept getting logged as 3 instead of 6. So for now I told Apache to use any service name. Need to research security risks related to this. Also I might need to keep it at ANY if I can not specify more than one principal.

<IF "'%{REMOTE_ADDR}' != '<trusted IP here>' && '%{REQUEST_URI}' != '/wp-admin'">
AuthType Kerberos
AuthName "Kerberos authenticated site"
KrbAuthRealms DOMAIN1.TLD DOMAIN2.TLD
#KrbServiceName HTTP/user@DOMAIN1.TLD
KrbServiceName Any
Krb5KeyTab /etc/httpd/merged.keytab
KrbMethodNegotiate On
KrbMethodK5Passwd Off
require valid-user
</IF>

If you want to allow access regardless of authentication (i.e. If you use the apache variable as part of your own authentication, but allow manual login if this fails) [4] [5] [6]

<IF "'%{REMOTE_ADDR}' != '<trusted IP here>' && '%{REQUEST_URI}' != '/wp-admin'">
AuthType Kerberos
AuthName "Kerberos authenticated site"
KrbAuthRealms DOMAIN1.TLD DOMAIN2.TLD
#KrbServiceName HTTP/user@DOMAIN1.TLD
KrbServiceName Any
Krb5KeyTab /etc/httpd/merged.keytab
KrbMethodNegotiate On
KrbMethodK5Passwd Off
Satisfy Any
</IF>

Docker

Host config

In this example we are using Amazon Linux

sudo yum -y upgrade
sudo yum -y install yum-cron oddjob oddjob-mkhomedir sssd samba-common-tools realmd docker amazon-efs-utils firewalld
sudo systemctl enable firewalld
sudo systemctl enable docker
sudo realm join -U <username> <fqdn>
sudo reboot

Container Config

  • First, make sure SSSD is installed in the container.
  • The container should have the environmental variable for the ticket cache set outside of kernel protected space (i.e. ENV KRB5CCNAME /tmp/ticket)
  • Then we mount the local config into the container as read only when starting the container.
docker run --name website -v /var/lib/sss:/var/lib/sss:ro -p 80:80 -p 443:443 -e TZ=America/New_York -d --restart unless-stopped