Difference between revisions of "Apache Kerberos Authentication"
Michael.mast (talk | contribs) |
Michael.mast (talk | contribs) |
||
(10 intermediate revisions by the same user not shown) | |||
Line 16: | Line 16: | ||
*web server | *web server | ||
intranet.tld | 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.<ref>https://community.microstrategy.com/s/article/KB37602-quot-No-credentials-cache-found-while-getting-client</ref><ref>http://plosquare.blogspot.com/2013/02/solution-for-gss-api_8.html</ref> | ||
+ | <br> | ||
+ | <br> | ||
+ | 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 | ||
+ | <pre> | ||
+ | setspn -d HTTP/your.server.com@YOURDOMAIN.COM serviceaccount | ||
+ | setspn -A HTTP/your.server.com serviceaccount | ||
+ | </pre> | ||
+ | ====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. | ||
+ | <br> | ||
+ | NOTE : This is case sensitive. | ||
+ | <pre> | ||
+ | ktpass /out C:\Temp\domain1.keytab /princ HTTP/website@DOMAIN1.TLD /mapuser user /pass <password> /crypto ALL /ptype KRB5_NT_PRINCIPAL /kvno 1 | ||
+ | </pre> | ||
+ | On domain2.tld | ||
+ | <pre> | ||
+ | ktpass /out C:\Temp\domain2.keytab /princ HTTP/website@DOMAIN2.TLD /mapuser user /pass <password> /crypto ALL /ptype KRB5_NT_PRINCIPAL /kvno 1 | ||
+ | </pre> | ||
+ | ====On the web server==== | ||
+ | <pre> | ||
+ | [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 | ||
+ | </pre> | ||
+ | |||
===krb5.conf=== | ===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. | 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. | ||
<pre> | <pre> | ||
+ | # 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 = . | ||
+ | } | ||
+ | |||
+ | </pre> | ||
+ | ===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. | ||
+ | <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 Off | ||
+ | require valid-user | ||
+ | </IF> | ||
+ | </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== | ||
+ | ===Host config=== | ||
+ | In this example we are using Amazon Linux | ||
+ | <pre> | ||
+ | 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 | ||
+ | </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
Contents
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
- ↑ https://www.netiq.com/communities/cool-solutions/kerberos-authentication-against-multiple-domains
- ↑ https://community.microstrategy.com/s/article/KB37602-quot-No-credentials-cache-found-while-getting-client
- ↑ http://plosquare.blogspot.com/2013/02/solution-for-gss-api_8.html
- ↑ https://www.jeffgeerling.com/blogs/jeff-geerling/apache-kerberos-authentication
- ↑ https://wiki.apache.org/httpd/BypassAuthenticationOrAuthorizationRequirements
- ↑ https://httpd.apache.org/docs/trunk/mod/mod_access_compat.html