Difference between revisions of "Apache Kerberos Authentication"

From Michael's Information Zone
Jump to navigation Jump to search
 
(3 intermediate revisions by the same user not shown)
Line 109: Line 109:
 
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.
 
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.
 
<pre>
 
<pre>
<IF "'%{REMOTE_ADDR}' != '<trusted IP here>' && '%{REQUEST_URI}' != '/wp-admin'">
+
<IF "'%{REQUEST_URI}' != '/wp-admin'">
 
AuthType Kerberos
 
AuthType Kerberos
 
AuthName "Kerberos authenticated site"
 
AuthName "Kerberos authenticated site"
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) you are limited in options. In my case I ended up allowing a subnet and a single IP to access without kerberos authentication, but all others would be required to use it.
 +
<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 "'%{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 On
 +
Require valid-user
 +
Satisfy any
 +
Deny from all
 +
Allow from xxx.xxx.xxx.xxx xxx.xxx.xxx.xxx/xx
 +
</IF>
 +
</pre>
 +
 
==Docker==
 
==Docker==
 
===Host config===
 
===Host config===
Line 127: Line 149:
 
<pre>
 
<pre>
 
sudo yum -y upgrade
 
sudo yum -y upgrade
sudo yum -y install yum-cron oddjob oddjob-mkhomedir sssd samba-common-tools realmd docker amazon-efs-utils docker firewalld
+
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 firewalld
 
sudo systemctl enable docker
 
sudo systemctl enable docker
 
sudo realm join -U <username> <fqdn>
 
sudo realm join -U <username> <fqdn>
 
sudo reboot
 
sudo reboot
 +
</pre>
 +
===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.
 +
<pre>
 +
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
 
</pre>
 
</pre>

Latest revision as of 19:00, 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 "'%{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) you are limited in options. In my case I ended up allowing a subnet and a single IP to access without kerberos authentication, but all others would be required to use it. [4] [5] [6]

<IF "'%{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 On
Require valid-user
Satisfy any
Deny from all
Allow from xxx.xxx.xxx.xxx xxx.xxx.xxx.xxx/xx
</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