Running Kerberos with Zimbra Collaboration Suite

From Zimbra :: Wiki

Jump to: navigation, search
Admin Article

Article Information

This article applies to the following ZCS versions.
  ZCS 6.0 Article  ZCS 6.0
  ZCS 5.0 Article  ZCS 5.0

This guide contains instructions for installing, configuring, running, and troubleshooting Kerberos with Zimbra Collaboration Suite. The concepts and descriptions might be not precise, just for general understanding of the mechanisms, steps and usages. For a more detailed reference of Kerberos, consult MIT's Kerberos V5 Admin Guide.

Contents

Introduction

General Knowledge of Kerberos Authentication

You may try to authenticate yourself into some service server via simply username/password login or other similar manner such as PLAIN or CRAM-MD5. In these cases you prove to the service server your identity. The server confirms this and authorize you with the requested services. However, in Kerberos protocol, a trusted third party is introduced, which generates "tickets", which hold credentials to both the user and service server. After gaining the credentials, both the user and service server can prove he is who he claims to be. Then they exchange some messages and finish the mutual authentication. This is the general steps of Kerberos authentication protocol.

In implementation, the trusted third party is the KDC (Kerberos Distribution Center) server. It holds a database (comprised of several regular files) of principals and keys.In the Kerberos world, everyone, including users, services, hosts, etc, has a principle associated with it. Principals should be global unique. Each principal has several components, which can be a username, service name, host name or realm. For example, imap/example.com@EXAMPLE.COM is a valid principal, in which "imap" is the service name, "example.com" is the host name who provides this service, and "EXAMPLE.COM" is the realm. Principal is case sensitive. Traditionally, realm is a capitalized domain name like string. Meanwhile, each principal is associated with a key.

A key is a string generated by the password. You can get a ticket contain a principal by giving that password. Also, you can write the keys into the keytab files and authenticate with them. A keytab file can contain multiple principals' keys with various encryption types. For example, if you have M principals and N encryption types, you may have M*N entries in a keytab file. Therefore you can consider keytab files and password equivalent. However, it's rather noteworthy that if a key is written into keytabfile, the password is no longer effective.

After authenticating to KDC, the corresponding credential is retrieved and cached locally. In MIT Kerberos implementation, it's cached in a regular file called /tmp/krb5cc_<uid>.Other implementations may cache it in the memory. Each credential has an expired time, commonly several hours or 1 day. Before that you can get it from cache without sending request to KDC. Note the UNIX user you used to get and use the credential. If you get it by root (e.g. sudo), and then use it with a normal user with uid 1000, it will fail because the credential you want to use is in krb5cc_0 rather than krb5cc_1000.

KDC reads the configure file "kdc.conf" to setup itself. This config tells which ports to listen, where the database files located, what encryption types should be supported and so on. KDC also reads "krb5.conf" to decide what the default realm is, how to write logs, ... The client and service server are all clients of KDC. They need to read krb5.conf to decide what the default realm is and where KDC is (address and port). Here you can set KDC for each realm. krb5.conf used by Kerberos server and client are often same.So you can config a valid krb5.conf and copy it to everywhere.

Kerberos Executives

Here are the executives of Kerberos implementation.

Name Description
krb5kdc KDC server. Default listen on 88, 750 ports
kadmin.local Manage principal database by directly manipulate database files. Only work in the machine where those files locate.
kadmin Remotely manage principal database, require kadmind.
kadmind Kerberos managment server. Default listen on 749 port.
kdb5_util Kerberos database maintainance utility. Can create, destroy, load a database.
kinit Authenticate to KDC, get the credential.
klist Show the entries in the credential cache or keytab files

There are some other executives for advanced functions, not necessary to introduce here.

Configuration Overview

Overview of ZCS with Kerberos Authentication Support

The picture in the right shows the overview of ZCS with Kerberos authentication support. There are 3 hosts in logic. "kerberos.example.com" holds KDC server, principal database and configs; "client.example.com" holds the client applications which initiates the authentication; "zcs.example.com" runs ZCS servers. Although they are in logic 3 separated hosts, you can choose to install all of them in the same host like what most developers do.In the rest of this article, I'll use these host names to illustrate the examples.

Install Kerberos

MIT Kerberos

Download Kerberos from Massachusetts Institute of Technology (MIT) at http://web.mit.edu/Kerberos/. Install Kerberos, following the instructions provided in MIT's Kerberos V5 Installation Guide. Normally you just run the command "./configure && make && make install". The build process might report some missing dependency such as "bison (yacc)". The Kerberos executive will be generated in /usr/local/bin and /usr/local/sbin. The most important one is /usr/local/sbin/krb5kdc. It's the KDC server.

After that, you need to copy sample krb5.conf and kdc.conf from <krb-source-root>/src/config-files by yourself. Copy krb5.conf to /etc/krb5.conf; then copy kdc.conf to /usr/local/var/krb5kdc/kdc.conf. /usr/local/var/krb5kdc is also the default location of principal database files.

MIT Kerberos Packages from Ubuntu

If using Ubuntu, you can choose to apt-get install the following packages: krb5-admin-server, krb5-kdc, krb5-config, krb5-user, krb5-clients. For Kerberos clients, no need to install admin server and KDC. In this way, the default location of kdc.conf is /etc/krb5kdc; the default location of principal database files is /var/lib/krb5kdc. Meanwhile, the KDC executive name is /etc/init.d/krb5-kdc.

Heimdal

TODO

Other Related Packages

If KDC and Kerberos clients are planed to run in different hosts, it's necessary to install NTP (Network Time Protocol) packages to make time synchronized. Kerberos protocol requires that time synchronization to improve security and convenience. But if all are going to be installed in the same host, no need to do this.

If want to do some test, you can install gsasl (GNU SASL). It contains APIs and sample client/server to use Kerberos authentication.

Configuration

Prepare Valid Host Name

One of the most important thing to configure a valid kerberos environment is to configure the correct host name. This is because ZCS will generate a request for service principal, which contains a component of host name (e.g. imap/zcs.exmaple.com@EXAMPLE.COM). Then KDC will try to find this principal in its local database. Therefore, what the client requests and what is held in KDC database have to be exactly match.

Commonly, Kerberos suggests to use the FQDN (full qualified domain name) to make the principal. However in the reality, ZCS always uses the local config "zimbra_server_hostname" for this purpose. You can see this config by typing (assuming pwd is /opt/zimbra):

$bin/zmlocalconfig | grep zimbra_server_hostname

and change this config by:

$bin/zmlocalconfig -e zimbra_server_hostname=<new host name>
$bin/zmlocalconfig -l

where "-l" is to make this change effective for ZCS.

Besides, if ZCS is built from source, this config is coming from the value of environment variable "ZIMBRA_HOSTNAME". If this variable unset, the result of command "hostname" is used. I suggest to set ZIMBRA_HOST to match the principals to be defined.

Another worthy noting is to make hostname's forward and reverse lookup is correct. This is the issue of network administrator if you are using a DNS service. Consult them to define your FQDN and static IP. If you just want to try in your host without bothering others, you can use /etc/hosts file to achieve this. Just add a line like this:

<ip> <FQDN> <hostname>

For example, in the host "zcs.example.com", you need to add this line:

179.16.143.20 zcs.example.com zcs

A common mistake is to add the FQDN to the ip "127.0.0.1" or "127.0.1.1", which might be resolved as hostname "localhost". In this case,the reverse lookup result is different with the forward one, which might incur some confusing error report.

In the following sections, 3 FQDN ("kdc.example.com","client.example.com" and "zcs.example.com") are employed.

Configure Kerberos

For the Kerberos client side, install the /etc/krb5.conf file on any client machines using Kerberos, including all of the Zimbra Mailbox servers. The content of krb5.conf should be like this:

[libdefaults]
       default_realm = EXAMPLE.COM

[realms]
       EXAMPLE.COM = {
               kdc = kdc.example.com:88
               admin_server = kdc.example.com:749
               default_domain = example.com
       }

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

The key point of this config is defining the map between realms and KDC servers. The [realms] section indicates where a request for a specified realm (here is EXAMPLE.COM) should be sent to. [domain_realm] illustrates the map between domain names and realm names.default_realm will be appended if no realm is specified. For example, if you request a credential with principal "user1" with kinit command, it will ask for "user1@EXAMPLE.COM".

In the Kerberos server side (where KDC located),"/etc/krb5.conf" is also necessary. For example, if you want to add or get a principal but without specifying the realm, the default_realm will be appended. Meanwhile, I suggest to add the logging section to detect errors.

[logging]
       kdc = FILE:/var/log/krb5kdc.log
       admin_server = FILE:/var/log/kadmin.log
       default = FILE:/var/log/krb5lib.log

Of course, you can write all of these in one krb5.conf and copy it to any machine you want to deploy kerberos. The kerberos commands will load the necessary config from this file and ignore they don't need.

KDC server also needs "kdc.conf", which looks like this:

[kdcdefaults]
       kdc_ports = 88,750

[realms]
       EXAMPLE.COM = {
               database_name = /usr/local/var/krb5kdc/principal
               admin_keytab = /usr/local/var/krb5kdc/kadm5.keytab
               acl_file = /usr/local/var/krb5kdc/kadm5.acl
               dict_file = /usr/local/var/krb5kdc/kadm5.dict
               key_stash_file = /usr/local/var/krb5kdc/.k5.EXAMPLE.COM
               kadmind_port = 749
               max_life = 10h 0m 0s
               max_renewable_life = 7d 0h 0m 0s
               master_key_type = des3-hmac-sha1
               supported_enctypes = des3-hmac-sha1:normal des-cbc-crc:normal
       }

It controls which ports to be listened and where the local database related files locate. Just make sure these locations are valid. These files are generated by "kdb5_util". Type this command:

$sudo kdb5_util create -s

If not specify a realm, the database files of default realm "EXAMPLE.COM" are generated. A password is required to access these files. "-s" means to generate a stash file to avoid manually input password when start KDC server. It's like the keytab file, the equivalent of password.

Finally, start KDC server:

$sudo /usr/local/sbin/krb5kdc

If nothing is output to the bash, it means KDC starts successfully. Otherwise, check the log of KDC to figure out what's wrong.

Add Principals and Keytabs

Creating Principals

For each ZCS server, create a service principal for the Zimbra services. Here IMAP is the example. This should be in the form of imap/<FQDN>@<realm> where <FQDN> is the value of ZCS local config "zimbra_server_hostname". Meanwhile, create principal for each user.

You can use the command "kadmin.local" to add these principals. This command can only be used in the host where principal database files locate (here, should be "kdc.example.com"). If want to manage the principals in remote hosts, start "kadmind" server and use command kadmin to do it. Here only shows the example of kadmin.local:

$ kadmin.local
Authenticating as principal root/admin@EXAMPLE.COM
kadmin.local: addprinc -randkey imap/zcs.example.com@EXAMPLE.COM
WARNING: no policy specified for imap/zcs.example.com@EXAMPLE.COM; defaulting to no policy
Principal "imap/zcs.example.com@EXAMPLE.COM" created.
kadmin.local: addprinc user1@EXAMPLE.COM
WARNING: no policy specified for user1@EXAMPLE.COM; defaulting to no policy
Enter password for principal "user1@EXAMPLE.COM":
Re-enter password for principal "user1@EXAMPLE.COM":
Principal "user1@EXAMPLE.COM" created.

When type "kadmin.local", the shell enters an interaction mode. Then use the sub command "addprinc" to add a new principal. The parameter "-randkey" allows generating a random key. Without it, you have to type password for the principals added. But as ZCS does the authentication with the keytab file, so the content of key is not important at all. For user principal, here we use the password to generate key.This password should match the one for its ZCS account's password. You can also generate keytab file for user principal. But remember, once keytab files are generated, the password will lose effect.

Besides "addprinc", you can use sub command "listprincs" show the list of existing principals, "getprinc" to get the detailed information of a specified princal, and "delprinc" to delete some of them.

Policy is not important here.It's useful to batch generate principals of the same kind. Just ignore it for now.

Creating a Local Keytab File for the Principal

After adding the principals, you need to generate the corresponding keytab files. This is also done by the command "kadmin.local". If users decide to authenticate with keytab, user keytab is also necessary. Here take IMAP and user1 as the example. NOTE: A keytab file can contain multiple principals. The krb5-zcs.keytab file should contain the principals for all services that Kerberos support is desired for. I.e., imap, smtp, pop, etc.

$ kadmin.local
Authenticating as principal root/admin@EXAMPLE.COM with password.
kadmin: ktadd -keytab ~/krb5-zcs.keytab imap/zcs.example.com@EXAMPLE.COM
Entry for principal imap/zcs.example.com@EXAMPLE.COM with kvno 3, encryption type Triple DES cbc mode with HMAC/sha1 added to keytab
  WRFILE:/home/jxing/krb5-zcs.keytab.
Entry for principal imap/zcs.example.com@EXAMPLE.COM with kvno 3, encryption type DES cbc mode with CRC-32 added to keytab
  WRFILE:/home/jxing/krb5-zcs.keytab
kadmin: ktadd -keytab ~/krb5-usr.keytab user1@EXAMPLE.COM
Entry for principal imap/zcs.example.com@EXAMPLE.COM with kvno 3, encryption type Triple DES cbc mode with HMAC/sha1 added to keytab
  WRFILE:/home/jxing/krb5-usr.keytab.
Entry for principal imap/zcs.example.com@EXAMPLE.COM with kvno 3, encryption type DES cbc mode with CRC-32 added to keytab
  WRFILE:/home/jxing/krb5-usr.keytab.

Copy the krb5-zcs.keytab to defaultly is "/opt/zimbra/conf/krb5.keytab" in each ZCS server. Keytab files are commonly generated by root (sudo), and has the permission 600. So use "chown" and "chmod" to change it to make sure this file can be read by ZCS. Otherwise, ZCS may report it can't find this file. In the production scenario, this keytab file's owner user and group should be zimbra:zimbra. In the dev environment, it depends on the user who starts ZCS.

Similarly, copy krb5-usr.keytab to "/etc/krb5.keytab" in each host user1 can authenticate himself, and adjust its permission as need. /etc/krb5.keytab is the default location of Kerberos client to find keytab file. If want to specify other location, use the environment variable "KRB5_KTNAME" (By the way, ZCS proxy employs this way to specify the location).

Now you can test this by the two sample utilities, sserver and sclient. In the zcs.example.com, you can start sserver in this way:

$sserver -p 12345 -s imap -S /opt/zimbra/conf/krb5.keytab

In the client.example.com, first get the user1's credential by "kinit" and take authentication to sserver by sclient:

$kinit -k user1
$sclient zcs.example.com 12345 imap
 sendauth succeeded, reply is:
 reply len 25, contents:
 You are user1@EXAMPLE.COM

"kinit -k" means to use keytab file in the default location to authenticate user1. After successful getting user1's credential, it will ask imap service to zcs.example.com:12345 as specified by sclient. If you see something errors reported, check and make sure the steps mentioned above are done correctly.

Additional Notes

The following principals might be necessary:

  • imap/zcs.example.com@EXAMPLE.COM
  • pop/zcs.example.com@EXAMPLE.COM
  • host/zcs.example.com@EXAMPLE.COM
  • smtp/zcs.example.com@EXAMPLE.COM
  • user1@EXAMPLE.COM
  • user2@EXAMPLE.COM
  • user3@EXAMPLE.COM

...

Preparing Zimbra for Kerberos Authentication

When you have installed and configured Kerberos, you must prepare a domain for Kerberos5 Authentication and then provision Zimbra accounts. Here I assume this domain is zcs.example.com. If not, please set it with "zmprov cd" command.

Configure ZCS

The authentication mechanism is set in the domain level. So first, set domain authentication mechanism to kerberos5

zmprov md zcs.example.com zimbraAuthMech kerberos5

Then set the default realm to use.

zmprov md zcs.example.com zimbraAuthKerberos5Realm EXAMPLE.COM

Finally, enable Kerberos authentication for IMAP and POP3.

zmprov ms zcs.example.com zimbraImapSaslGssapiEnabled TRUE
zmprov ms zcs.example.com zimbraPop3SaslGssapiEnabled TRUE

Provision Zimbra Accounts

When a user attempts to login to Zimbra as user/password, and when the domain's zimbraAuthMech is kerberos5, the system will authenticate to KDC instead of LDAP.

The Kerberos credential for the user is:

  • Password. This is the user's password.
  • Principal. The Kerberos principal for a user can be resolved by either of the following methods.

Principal Resolution Method 1

One method of resolving a user's Kerberos principal is to enter the user's address in the form of <local part of Zimbra email address>@<zimbraAuthKerberos5Realm>.

For example, for user1@example.com, the Kerberos principal will be user1@EXAMPLE.COM.

Principal Resolution Method 2

Kerberos principal can also be resolved on a per account basis, instead of using the realm defined in zimbraAuthKerberos5Realm. This allows accounts in the same Zimbra domain to be mapped to different Kerberos Realms.

To use this method, set the account's zimbraForiegnPrincipal as kerberos5:<kerberos5-principal>. If the zimbraForeignPrincipal of the account starts with kerberos5:, the system will authenticate to Kerberos using as the principal the text appearing after the kerberos5: in the zimbraForeignPrincipal.

For example:

zmprov ma user1@example.com +zimbraForeignPrincipal 
kerberos5:user1@EXAMPLE.COM

In the above example, for user1@example.com, the Kerberos principal will be user1@EXAMPLE.COM.

Note: Method 2 will overwrite Method 1. If the account has a zimbraForeignPrincipal in the form of kerberos5:<kerberos5-principal>, the system will resolve the Kerberos principal using Method 2.

Now, you can authenticate to ZCS by Kerberos protocol. You can test by this way (assume ZCS IMAP port is 7143):

$gsasl --connect zcs.example.com:7143 -a user1@zcs.example.com -d

If authentication fails, try to use "kinit" to get the user credential in client.example.com and imap service credential in zcs.example.com.

Configure ZCS Proxy (Nginx)

Architecture

Currently, ZCS employs Nginx (see http://wiki.nginx.org/Main) as the reverse proxy to take load balance and throttle control. Zimbra has extended official Nginx to complement its weak support for mail authentication, including Kerberos5.

The architecture of ZCS including Nginx with Kerberos5 support is shown in the figure on the right
Architecture of ZCS and Nginx with Kerberos5 support
. Clients and Nginx take the interaction of Kerberos5 authentication by GSSAPI. Then Nginx can confirm the identity of the client and finally authenticate to ZCS in the protocol called "X-Zimbra". It looks like SASL PLAIN but require Nginx sends authorize user name, authenticate user name and Auth Token to ZCS. The request is the base64 encoded string with form "<authz_username>\0<auth_username>\0<auth_token>. The auth token is a 3 parts string separated by underscore "_". For example,
0_5348091d5a42e658b625e3eb369966e6c96c5310_69643d33363a37343764396
363382d326435372d346633662d613162362d3839393434613532616230373b6
578703d31333a313230383239333739383337383b747970653d363a7a696d6272
613b6d61696c686f73743d32303a3139322e3136382e3135392e3132383a373037
303b

This token is given by route lookup servlet when Nginx lookup route for a client trying to log in. Only when auth_method="gssapi", the servlet will return this token.

Configuration Steps

Before setting up Nginx, you should first deploy Route Lookup Servlet and make it work correctly.

The configuration of Nginx is generated by zmproxyconfgen command. In the production environment, you should use zmproxyctl rather than directly generate the configuration. The values of nginx configuration comes from LDAP attrs or local config. Here are the attrs you need to set:

zmprov ms <server_name> zimbraReverseProxyImapSaslGssapiEnabled TRUE    # will generate "imap_auth gssapi;"
zmprov ms <server_name> zimbraReverseProxyPop3SaslGssapiEnabled TRUE    # will generate "pop3_auth gssapi;"
zmprov ms <server_name> zimbraReverseProxyDefaultRealm <REALM>     # will generate "default_realm <REALM>;" for example, EXAMPLE.COM
zmprov mcf +zimbraReverseProxyAdminIPAddress <nginx's host ip>

zimbraReverseProxyAdminIPAddress is very important. Without it, route lookup servlet will consider the requests from the nginx with that IP is invalid and directly return "login failed".

See also NGINX Interface identity with Kerberos

Configuring ZCS MTA: Postfix and Cyrus-SASL

It is possible to configure the MTA (Postfix) to use Kerberos authentication as well.

Configuration steps

Add GSSAPI to the Cyrus-SASL supported mechanisms:

zmlocalconfig -e sasl_smtpd_mech_list="GSSAPI PLAIN LOGIN"

Disable plaintext login for postfix:

 zmlocalconfig -e postfix_smtpd_sasl_security_options="noanonymous, noplaintext"

Tell postfix how and where to find the KRB5 Keytab containing the smtp/FQDN principal. If load balancing is used, it should also have an smtp/LBNAME principal as well Note: This keytab must be readable by the postfix group.

 zmlocalconfig -e postfix_import_environment="KRB5_KTNAME=/opt/zimbra/conf/krb5.keytab"

If load balancing is being used between MTAs, you need to configure the hostname value presented by the MTAs:

zmprov mcf zimbraMtaMyHostname lbname.example.com

Troubleshooting

If you find some wrong, please check the log of kdc, ZCS and nginx (if nginx is configured for kerberos authentication). These messages are valuable to detect what's the problem.

Encryption Type Unsupported

javax.security.sasl.SaslException: GSS initiate failed [Caused by GSSException:
Failure unspecified at GSS-API level (Mechanism level: AES256 CTS mode with 
HMAC SHA1- 96 encryption type not in permitted_enctypes list)]

This is because KDC use some strong encryption type that ZCS's java runtime doesn't support (such as AES256). This is related to the export restrictive policy of U.S. And JCE (Java Cryptography Extension) follows this, except you are using JCE Unlimited Strength Jurisdiction Policy Files from Sun Microsystems' Java SE Downloads page, and install JCE on your Zimbra servers. If not, just explicitly specify the supported encryption type in ZCS and client hosts' /etc/krb5.conf, for example :

 default_tgs_enctypes = des3-hmac-sha1
 default_tkt_enctypes = des3-hmac-sha1
 permitted_enctypes = des3-hmac-sha1

If your kerberos is at the latest level, and you have a DES key in your keytab, you will see errors in /var/log/zimbra.log that contain statements like:

 "SASL authentication failure: GSSAPI Error:  Miscellaneous failure (see text) (encryption type 1 not supported)"

Fix this by adding the following to the libdefaults portion of your krb5.conf file:

 allow_weak_crypto = true

No Valid Credential Found

The gsasl might report an error with an amphibolous message:

gsasl: mechanism error: GSSAPI error in client while negotiating security context in
gss_init_sec_context() in SASL library.  This is most likely due insufficient credentials
or malicious interactions.

This error normally happens when you ask for some principal but KDC can't find the one in its database. For example, if you expect "imap/zcs.example.com@EXAMPLE.COM", maybe you really send a request for "imap/localhost@EXAMPLE.COM". This is a typical error if you didn't configure the hostname lookup correctly. Check KDC's log and if you find something like:

TGS_REQ (3 etypes {16 3 1}) 176.16.143.5(88): 
UNKNOWN_SERVER: authtime 1043800211,  user1@EXAMPLE.COM for imap/localhost@EXAMPLE.COM,
Server not found in Kerberos database

That's must be the reason for this. Check #Prepare Valid Host Name and fix it.

Another possibility is the credential is not retrieved yet or the one retrieved is expired. Use "klist" to check what status of the credentials cached locally are. If confirm, just use "kinit" command to get the credential first.

No Key Found

javax.security.sasl.SaslException: Failure to initialize security context [Caused by GSSException: 
No valid credentials provided (Mechanism level: Failed to find any Kerberos Key)]

If using nginx, nginx.log will report:

GSSAPI Error:  No credentials were supplied, or the credentials were unavailable or 
inaccessible. (unknown mech-code 0 for mech unknown)

This error will happen if you didn't write the key into the keytab file, or the permission setting of keytab file reject the read access, or the key file is not the one you should access (for example, you want /opt/zimbra/conf/krb5.conf, but actually read /etc/krb5.conf, which has no that key).


Verified Against: ZCS 6.0.x Date Created: 11/15/2010
Article ID: http://wiki.zimbra.com/index.php?title=Running_Kerberos_with_Zimbra_Collaboration_Suite Date Modified: 12/6/2012
Personal tools