<?xml version="1.0" encoding="UTF-8"?>
<!--
	Reduce section on PAM
	Show how to configure SSH and potentially other, real services
-->
<!--
  Kerberos 5 installation guide on Debian GNU, Ubuntu, and Devuan GNU+Linux

  http://techpubs.spinlocksolutions.com/dklar/kerberos.xml
  http://techpubs.spinlocksolutions.com/dklar/kerberos.html
  http://techpubs.spinlocksolutions.com/dklar/kerberos.tgz

  (C) 2006-2019 Davor Ocelic, docelic@spinlocksolutions.com

 This documentation is free; you can redistribute it and/or modify
 it under the terms of the &GNU; General Public License as published by
 the Free Software Foundation; either version 2 of the License, or
 (at your option) any later version.

 It is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.


  To build the HTML version of the article, download
  http://techpubs.spinlocksolutions.com/dklar/kerberos.tgz
  and run 'make kerberos.html'.
-->
<!DOCTYPE article PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
"docbook/docbookx.dtd" [
<!ENTITY DEB "<ulink url='https://www.debian.org/'>Debian GNU</ulink>">
<!ENTITY DEV "<ulink url='https://www.devuan.org/'>Devuan GNU+Linux</ulink>">
<!ENTITY UBU "<ulink url='https://www.ubuntu.com/'>Ubuntu</ulink>">
<!ENTITY deb "<ulink url='https://www.debian.org/'>Debian</ulink>">
<!ENTITY dev "<ulink url='https://www.devuan.org/'>Devuan</ulink>">
<!ENTITY ubu "<ulink url='https://www.ubuntu.com/'>Ubuntu</ulink>">
<!ENTITY GNU "<ulink url='https://www.gnu.org/'>GNU</ulink>">
<!ENTITY KRB "<ulink url='http://web.mit.edu/kerberos/'>MIT Kerberos</ulink>">
<!ENTITY LDA "<ulink url='http://www.openldap.org/'>OpenLDAP</ulink>">
<!ENTITY AFS "<ulink url='http://www.openafs.org/'>OpenAFS</ulink>">
<!ENTITY RAD "<ulink url='http://www.freeradius.org/'>FreeRADIUS</ulink>">
<!ENTITY DLH "<ulink url='http://colt.projectgamma.com/debian-ldap-howto/'>Debian-LDAP Howto</ulink>">
<!ENTITY PAM "<ulink url='http://www.linux-pam.org/'>Linux-PAM</ulink>">
<!ENTITY PSY "<ulink url='http://www.linux-pam.org/Linux-PAM-html/sag-configuration-file.html'>PAM Configuration File Syntax</ulink>">
<!ENTITY NSS "<ulink url='http://www.gnu.org/software/libc/manual/html_node/Name-Service-Switch.html'>NSS</ulink>">
<!ENTITY SUN "<ulink url='http://www.sun.com/'>Sun Microsystems</ulink>">
<!ENTITY HDL "<ulink url='http://www.pdc.kth.se/heimdal/'>Heimdal Kerberos</ulink>">
<!ENTITY DOCBK "<ulink url='http://www.docbook.org/'>DocBook</ulink>">
<!ENTITY SL "<ulink url='http://www.spinlocksolutions.com/'>Spinlock Solutions</ulink>">
<!ENTITY SHELL_GLOBBING "<ulink url='http://tldp.org/LDP/abs/html/globbingref.html'>shell globbing</ulink>">
<!ENTITY KRBC "<ulink url='http://www.kerberos.org/'>Kerberos consortium</ulink>">
<!ENTITY PRINCIPAL "<ulink url='http://kerberos.org/software/tutorial.html#1.3.2'>principal</ulink>">
<!ENTITY SECRET_KEY "<ulink url='http://kerberos.org/software/tutorial.html#1.3.4'>secret key</ulink>">
<!ENTITY KERBEROS_DATABASE "<ulink url='http://kerberos.org/software/tutorial.html#1.3.5.1'>Kerberos database</ulink>">
<!ENTITY REALM "<ulink url='http://kerberos.org/software/tutorial.html#1.3.1'>realm</ulink>">
<!ENTITY KERBEROS-SPECIFIC "<ulink url='http://kerberos.org/software/tutorial.html#1.3.5.1'>Kerberos-specific</ulink>">
<!ENTITY KDC "<ulink url='http://kerberos.org/software/tutorial.html#1.3.5'>KDC</ulink>">
<!ENTITY TGT "<ulink url='http://kerberos.org/software/tutorial.html#1.5.1'>TGT</ulink>">
<!ENTITY KERBEROS_RELEASE "<ulink url='http://web.mit.edu/Kerberos/dist/index.html'>Kerberos release</ulink>">
<!ENTITY DKLAR_DEB "<ulink url='http://techpubs.spinlocksolutions.com/dklar/debian.html'>Debian GNU Guide</ulink>">
<!ENTITY DKLAR_KRB "<ulink url='http://techpubs.spinlocksolutions.com/dklar/kerberos.html'>MIT Kerberos 5 Guide</ulink>">
<!ENTITY DKLAR_LDA "<ulink url='http://techpubs.spinlocksolutions.com/dklar/ldap.html'>OpenLDAP Guide</ulink>">
<!ENTITY DKLAR_AFS "<ulink url='http://techpubs.spinlocksolutions.com/dklar/afs.html'>OpenAFS Guide</ulink>">
<!ENTITY DKLAR_RAD "<ulink url='http://techpubs.spinlocksolutions.com/dklar/radius.html'>FreeRADIUS Guide</ulink>">
<!ENTITY DOC "<ulink url='http://web.mit.edu/kerberos/krb5-1.8/'>http://web.mit.edu/kerberos/krb5-1.8/</ulink>">
<!ENTITY MLS "<ulink url='http://web.mit.edu/kerberos/mail-lists.html'>http://web.mit.edu/kerberos/mail-lists.html</ulink>">
]>
<article id="debian-kerberos">
  <articleinfo>
    <!--
	<mediaobject>
		<imageobject><imagedata fileref="images/logo-debian.png"
			format="JPG" width="120px" scalefit="1" /></imageobject>
	</mediaobject>
	-->

    <title>Install MIT Kerberos 5 on Debian GNU, Ubuntu, and Devuan GNU+Linux</title>

    <titleabbrev>debian-kerberos</titleabbrev>

    <copyright>
      <year>2006-2019</year>

      <holder>Davor Ocelic</holder>
    </copyright>

    <authorgroup>
      <author>
        <firstname>Davor</firstname>

        <surname>Ocelic</surname>

        <email>docelic@spinlocksolutions.com</email>
      </author>
    </authorgroup>

    <legalnotice>
      <para>Last update: Aug 24, 2019. — Add PKINIT instructions</para>

      <para>This documentation is free; you can redistribute it and/or modify
      it under the terms of the &GNU; General Public License as published by
      the Free Software Foundation; either version 2 of the License, or (at
      your option) any later version.</para>

      <para>It is distributed in the hope that it will be useful, but WITHOUT
      ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
      FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
      more details.</para>
    </legalnotice>

    <abstract>
      <para>The purpose of this article is to give you a straightforward,
      &deb;/&ubu;/&dev;-friendly way of installing and configuring MIT Kerberos 5.</para>

      <para>By the end of this guide, you will have a functional Kerberos
      environment and one Kerberized service — the ability to login remotely
      to other machines in the network in a secure, encrypted and transparent
      way, without the need for typing in any passwords, and including
			SSH PKI authentication.</para>

      <para>This article is part of &SL;'s practical 3-piece introductory
      series to infrastructure-based Unix networks, containing
      &DKLAR_KRB;, &DKLAR_LDA; and &DKLAR_AFS;.</para>
    </abstract>
  </articleinfo>

  <section id="intro">
    <title>Introduction</title>

    <para>Kerberos is a service that has been traditionally captivating system
    administrators' and advanced users' interest, but its seemingly
    high entry barrier and infrastructure requirements have been preventing
    many from using it.</para>

    <para>Kerberos has already been the topic of numerous publications. Here,
    we will present only the necessary summary; enough information to
    establish the context and to achieve practical results.</para>

    <para>You do not need to follow any external links; however, the links
    have been provided both throughout the article and listed all together at
    the end, to serve as pointers to more precise technical treatment of
    individual topics.</para>

    <section id="intro-krb">
      <title>The role of Kerberos within a network</title>

      <para><inlinemediaobject>
          <imageobject>
            <imagedata fileref="images/logo-kerberos.jpg" format="JPG"
                       scalefit="1" width="120px" />
          </imageobject>
        </inlinemediaobject> Kerberos is intended to centrally authenticate
      users, hosts, and services on the network by verifying them against
      entries in the &KERBEROS_DATABASE;.</para>

      <para>These entries (called "&PRINCIPAL;s") consist of principal names,
      &SECRET_KEY;s, key aging (expiry) information, and &KERBEROS-SPECIFIC; data.
      They are created or modified using a Kerberos-specific administrative
      tool called <command>kadmin</command>.</para>

      <para>When users type in their principal name and password anywhere on
      the network (within a Kerberos &REALM;), their input is authenticated
      in a secure way
      against the Kerberos database. In case of a successful authentication,
      the &KDC; ("<literal>Key Distribution Center</literal>") will
      <emphasis>issue</emphasis> users a "confirmation", called the &TGT;
      ("<literal>Ticket-Granting Ticket</literal>"). From that point on, and
      until their ticket expires, users will be transparently granted access
      to all network services they'll wish to use. (The TGT will not
      grant access by itself — instead, it will be used as the
			credential to automatically create further tickets for specific services,
      once users attempt to access them.
			Hence its name, the "Ticket-granting Ticket").</para>

      <para>While the idea of a centralized network authentication is not
      unique, let's quickly identify Kerberos-specific elements in the
      authentication process:</para>

      <itemizedlist>
        <listitem>
          <para>Kerberos is not in any way related to traditional system
          usernames or other data; Kerberos identity (or tickets) are obtained
          using a separate, Kerberos-specific mechanism. Arbitrary system user
          can obtain arbitrary Kerberos identity (provided they know the
          correct password (or have the correct PKI certificate when PKINIT
					is used)).</para>

          <para>Often times, however, the Kerberos identity is obtained as part of
          log-in to the system and, for convenience, an assumption is made
          that the person's system login name matches their Kerberos principal
          name. <!-- 
	(In case
	of services, an assumption is made that the service principal matches 
	form <literal><replaceable>SERVICE-TYPE</replaceable>/<replaceable>FQDN</replaceable></literal>).
	--></para>
        </listitem>

        <listitem>
          <para>The &KERBEROS_DATABASE; only contains the information
          necessary for Kerberos authentication; it does not (and can not)
          contain any other information, such as people's real names, Unix
          user and group IDs, etc. This makes Kerberos well-defined and easy to
          fit in a network infrastructure.</para>

          <para>When a central directory is required for users' real names,
          IDs, meta information and other network information, &LDA; is often
          used in combination and installed after Kerberos as explained in
          another article from the series, the &DKLAR_LDA;.</para>
        </listitem>

        <listitem>
          <para>Thanks to the design of the protocol, users' passwords never
          travel the wire in any form; Kerberos thus allows for secure
          authentication in and over untrusted networks.</para>
        </listitem>

        <listitem>
          <para>Kerberos requires mutual authentication of users and services,
          preventing stealing of information.</para>

          <para>To achieve this, Kerberos uses its database to store host and
          service principals alongside the "real", person-owned principals.
          This is normal behavior and indeed, the host and service principals
          will account for the majority of output when you list database
          entries for the first time after installation.</para>
        </listitem>

        <listitem>
          <para>As users are only required to authenticate once
          (after which the TGT is used in place of the password to create
          further tickets), Kerberos offers a true SSO ("<literal>Single
          Sign-On</literal>") network solution.</para>
        </listitem>
      </itemizedlist>

      <para>You can find the complete Kerberos documentation at the &KRB;
      website. Their on-line documentation is, however, only generated in
      multi-page HTML format — other more convenient formats (such as
      PostScript) are available within &KERBEROS_RELEASE; tarballs.</para>
    </section>

    <section>
      <title>Glue layer: integrating Kerberos with system software</title>

      <para>On all GNU/Linux-based platforms, &PAM; is available for
      service-specific authentication configuration. &PAM; is an
      implementation of PAM ("<literal>Pluggable Authentication
      Modules</literal>") from &SUN;.</para>

      <para>Network services, instead of having hard-coded authentication
      interfaces and decision methods, invoke PAM through a standard,
      pre-defined interface. It is then up to PAM to perform any and all
      authentication-related work, and report the result back to the
      application.</para>

      <para>Exactly how PAM reaches the decision is none of the services'
      business. In traditional set-ups, that is most often done by asking and
      verifying usernames and passwords. In advanced networks, that could be
      retina scans or — Kerberos tickets.</para>

      <para>PAM will allow for inclusion of Kerberos into the authentication
      path of all services, regardless of whether they natively support
      Kerberos or not.</para>

      <para>You can find the proper introduction (and complete documentation)
      on the &PAM; website. Pay special attention to the &PSY; page. Also take
      a look at the <citerefentry>
          <refentrytitle>Linux-PAM</refentrytitle>

          <manvolnum>7</manvolnum>
        </citerefentry> and <citerefentry>
          <refentrytitle>pam</refentrytitle>

          <manvolnum>7</manvolnum>
        </citerefentry> manual pages.</para>
    </section>

<section id="conventions">
<title>Conventions</title>

<para>Let's agree on a few conventions before going down to work:</para>

<itemizedlist>
<listitem><para>
Our platform of choice, where we will demonstrate a practical setup,
will be &DEB;. The setup will also work on &UBU; and &DEV;, and if any notable
differences exist they will be noted.
</para></listitem>
<listitem><para>
Please run <command>dpkg -l sudo</command> to verify you have the package <application>sudo</application> installed.
</para><para>
<application>Sudo</application> is a program that will allow
you to carry out system administrator tasks from your normal user account.
All the examples in this article requiring root privileges use
<application>sudo</application>, so you will be able to copy-paste them
to your shell.
</para><para>
To install <application>sudo</application> if missing, run:
<programlisting>
su -c 'apt install sudo'
</programlisting>
If asked for a password, type in the root user's password.
</para><para>
If you want to run <application>sudo</application> without requiring a password, run the following
while replacing <literal>USERNAME</literal> with your login name:
<programlisting>
su -c 'echo "<replaceable>USERNAME</replaceable> ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers'
</programlisting>
</para></listitem>
<listitem><para>
Packages that we will install during the complete procedure
will ask us a series of questions through the so-called
<emphasis>debconf</emphasis> interface. To configure debconf to a 
known state, run:
<programlisting>
sudo dpkg-reconfigure debconf
</programlisting>
When asked, answer <emphasis>interface</emphasis>=<literal>Dialog</literal>
and <emphasis>priority</emphasis>=<literal>low</literal>.
</para></listitem>
<listitem>
<para>Monitoring log files is crucial in detecting problems. The
straightforward, catch-all routine to this is opening a terminal
and running: <programlisting>
sudo tail -n0 -F /var/log/{*log,dmesg,messages,kerberos/{krb5kdc,kadmin,krb5lib}.log}
</programlisting></para>

<para>The command will keep printing log messages to the screen as
they arrive.</para>
</listitem>

<listitem>
<para>For maximum convenience, the installation and configuration
procedure we will show will set everything up on a single machine. 
<!--
<literal>monarch.example.com</literal> and have an IP address of
<literal>192.168.7.12</literal>.
-->
It means that the Kerberos server, the SSH server, and the client
connecting to them will be on the same machine with an IP address of
<literal>192.168.7.12</literal>. You should use your own machine's
network address in this place.
</para><para>
To differentiate between
client and server roles, the connecting client will be named <literal>monarch.example.com</literal>,
the SSH server will be named <literal>monarch.example.com</literal> (same as the client),
and the Keberos server will be named <literal>krb1.example.com</literal>.
You can reuse these names, or even better replace them with your appropriate/existing
hostnames.
</para><para>
The following addition will be
made to <filename>/etc/hosts</filename> to completely support this single-host installation scheme.
<emphasis role="bold">Note that the client machine's hostname parts (<replaceable>monarch</replaceable> in our example) must come before "krb1" in order for things to work as expected</emphasis>: <screen>
<replaceable>192.168.7.12</replaceable>  <replaceable>monarch.example.com</replaceable> <replaceable>monarch</replaceable> krb1<replaceable>.example.com</replaceable> krb1
</screen></para>

<caution>
<para>
Note that in some installations the system's network hostname is
assigned to the localhost address <literal>127.0.0.1</literal>. This can
and will cause problems for network operations. Make sure that your
<filename>/etc/hosts</filename> looks exactly like this, except for the
actual network IP and hostnames:

<screen>
127.0.0.1  localhost
<replaceable>192.168.7.12  monarch.example.com monarch krb1.example.com krb1</replaceable>
</screen>
</para>
</caution>

<para>Finally, test that the network setup works as expected. Pinging
the hostnames should report proper FQDNs and IPs as shown: <screen>
<userinput>ping -c1 localhost</userinput>
PING localhost (127.0.0.1) 56(84) bytes of data.
....

<userinput>ping -c1 <replaceable>monarch</replaceable></userinput>
PING <replaceable>monarch.example.com</replaceable> (<replaceable>192.168.7.12</replaceable>) 56(84) bytes of data.
....

<userinput>ping -c1 krb1</userinput>
PING krb1.<replaceable>example.com</replaceable> (<replaceable>192.168.7.12</replaceable>) 56(84) bytes of data.
....
</screen></para>
</listitem>

<!--
<listitem><para>
Finally, a word on colors:
<itemizedlist>
<listitem><para>
<userinput>White-on-black</userinput> signifies the system commands
you need to run, or the answers you need to type in.
</para></listitem>
<listitem><para>
<replaceable>Italic light-blue</replaceable>,
<userinput><replaceable>on any background</replaceable></userinput>,
signifies parts of system commands
or answers that you should adjust to match your environment. For example,
you will probably want to always replace say,
<replaceable>EXAMPLE.COM</replaceable>, with your own domain name
in uppercase.
</para></listitem>
<listitem><para>
<screen>Normal text on gray background, with a teal stripe to the left
presents output of a real shell session, or the contents of
a file. Parts of the input carrying special meaning are depicted using the
rules above, such as <userinput><replaceable>EXAMPLE.COM</replaceable></userinput>.
</screen>
</para></listitem>
<listitem><para>
Text in an <literal>orange-like color</literal> signifies literal values
that are, for a reason, worth of emphasizing in the context of text flow.
</para></listitem>
<listitem><para>
Text in the <errortext>red color</errortext> signifies exact error
text as reported from applications. With the exception of
system-specific values printed in error messages,
this text could be taken verbatim and looked up on Web
search engines.
</para></listitem>
</itemizedlist>
</para></listitem>
-->
</itemizedlist>
</section>
</section>

  <section id="kerberos">
    <title>Kerberos 5</title>

    <para>Now when everything has been properly prepared, let's move
    forward.</para>

    <section id="krb-install">
      <title>Server installation</title>

      <para>Kerberos server installation basically consists of just two
      packages — the KDC (Key Distribution Center), which takes care of
      handling authentication requests and issuing Kerberos tickets, and
      kadmind (Kerberos master server), which allows <emphasis>remote
      administration access</emphasis> to the Kerberos database and carrying
      out of administrative tasks. <programlisting>
sudo apt install krb5-{admin-server,kdc}
</programlisting> Here are the Debconf answers for reference. The listing here
      includes all questions; some were asked in Kerberos 1.6 packages and
      some are asked only in Kerberos 1.7 and newer, and their order has
      changed a little as well. In any case, it's no problem — just answer the
      subset of questions you are asked: <screen>
Default Kerberos version 5 realm? <userinput><replaceable>EXAMPLE.COM</replaceable></userinput>
# (Your domain name in uppercase - a standard for naming Kerberos realms)

Add locations of default Kerberos servers to /etc/krb5.conf? <userinput>Yes</userinput>
# (Adding entries to krb.conf instead of DNS, for simplicity)

Kerberos servers for your realm: <userinput>krb1.<replaceable>example.com</replaceable></userinput>
# (Make sure your DNS resolves krb1.<replaceable>example.com</replaceable> to
# the NETWORK IP of the server, NOT 127.0.0.1!). Hint is given in
# <xref linkend="conventions" />.

Administrative server for your Kerberos realm: <userinput>krb1.<replaceable>example.com</replaceable></userinput>
# (Make sure your DNS resolves krb1.<replaceable>example.com</replaceable> to
# the NETWORK IP of the server, NOT 127.0.0.1!). Same hint as above.

Create the Kerberos KDC configuration automatically? <userinput>Yes</userinput>

Run the Kerberos V5 administration daemon (kadmind)? <userinput>Yes</userinput>
</screen>

As soon as the installation is done, the Kerberos admin server
(<command>kadmind</command>) and the KDC will try to start. Start may fail since,
initially, there are no Kerberos &REALM;s created, which is fine.</para>
</section>

<section id="krb-initial-cfg">
<title>Initial configuration</title>

<para>To create the Kerberos realm, invoke:
<screen>
<userinput>sudo krb5_newrealm</userinput>

This script should be run on the master KDC/admin server to initialize
a Kerberos realm.  It will ask you to type in a master key password.
This password will be used to generate a key that is stored in
/etc/krb5kdc/stash.  You should try to remember this password, but it
is much more important that it be a strong password than that it be
remembered.  However, if you lose the password and /etc/krb5kdc/stash,
you cannot decrypt your Kerberos database.
<emphasis role="bold">Loading random data</emphasis>
Initializing database '/var/lib/krb5kdc/principal' for realm 'EXAMPLE.COM',
master key name 'K/M@EXAMPLE.COM'
You will be prompted for the database Master Password.
It is important that you NOT FORGET this password.

Enter KDC database master key: <userinput><replaceable>PASSWORD</replaceable></userinput>

Re-enter KDC database master key to verify: <userinput><replaceable>PASSWORD</replaceable></userinput>
</screen>
</para><para>
<emphasis role='bold'>Note that the command may pause for a
significant amount of time after printing "Loading random data".</emphasis><sbr/>
To speed up the process and allow the kernel to generate enough
random data to continue, login to the machine in another terminal
and execute a couple commands, such as <userinput>find /</userinput>
and/or type random text into the terminal.<sbr/>
Once enough random data has been collected, the command execution will continue.
</para><para>
Now that the realm has been created, we need to adjust the Kerberos
config file, <filename>/etc/krb5.conf</filename>. That file should
to be the same on all Kerberos servers and clients belonging to the same
realm.</para>

<para><filename>/etc/krb5.conf</filename> is split into sections; you
should search for section "<literal>[domain_realm]</literal>"
(not "<literal>[realms]</literal>") and append
your definitions: <screen>
.<replaceable>example.com</replaceable> = <replaceable>EXAMPLE.COM</replaceable>
<replaceable>example.com</replaceable> = <replaceable>EXAMPLE.COM</replaceable>
</screen></para>

<para>At the bottom of the file, you should add the logging section:
<screen>
[logging]
	kdc = FILE:/var/log/kerberos/krb5kdc.log
	admin_server = FILE:/var/log/kerberos/kadmin.log
	default = FILE:/var/log/kerberos/krb5lib.log
</screen> To create the logging directory and set up permissions, run:
<programlisting>
sudo mkdir /var/log/kerberos
sudo touch /var/log/kerberos/{krb5kdc,kadmin,krb5lib}.log
sudo chmod -R 750  /var/log/kerberos
</programlisting></para>

<para>You do not need to restart the log monitoring command you ran
earlier (see <xref linkend="conventions" />) &mdash; the
<command>tail -F</command> command will pick up new log files from the
the <filename class="directory">kerberos/</filename> directory
automatically.</para>

<!--
<para>
It is also a good idea to disallow "weak enctypes" in Kerberos. These are the
cryptographic algorithms that are no longer considered secure (or at
least robust), and currently include all single-DES enctypes.
The option called "<literal>allow_weak_crypto</literal>" was added in Krb 1.7,
defaulting to true.  In Kerberos 1.8 and later, weak enctypes are disabled
by default and no manual setting is necessary.
</para>
<para>So, if you are using Kerberos 1.7, search for the section called
"<literal>[libdefaults]</literal>" in
<filename>/etc/krb5.conf</filename> (usually at the top of the file) and
append the following definition: <screen>
allow_weak_crypto = false
</screen>
</para>
-->

<para>To apply changes to the Kerberos server, run: <programlisting>
sudo invoke-rc.d krb5-kdc restart
sudo invoke-rc.d krb5-admin-server restart
</programlisting></para>

</section>

<section id="krb-test1">
<title>Initial test</title>

<para>It is already the time to test the installation. We assume that
both the admin server and the KDC can be restarted with no errors (which
should be no problem to determine if you're monitoring the log files as
advised).</para>

<para>
As the first test, we will run command
<command>kadmin.local</command> on the server.
The <command>kadmin</command> command ordinarily requires principal
name and password before letting anyone access the administrative
interface. However, <command>kadmin.local</command> is a variant of the
command that must be run locally on the same machine as the KDC, and
with administrator privileges. It is then able to open the Kerberos
database file directly (taking advantage of Unix file permissions),
without requiring extra privileges and without using the
<command>kadmind</command> (Kerberos master server) daemon.
</para>

<para>The purpose of our running <command>kadmin.local</command> will be
to print out the list of existing principals (user, host, and service
accounts) in the database using the command <userinput>listprincs</userinput>.
The whole session should look like this:

<screen>
<userinput>sudo kadmin.local</userinput>
Authenticating as principal root/admin@<replaceable>EXAMPLE.COM</replaceable> with password.

kadmin.local:  <userinput>listprincs</userinput>

K/M@<replaceable>EXAMPLE.COM</replaceable>
kadmin/admin@<replaceable>EXAMPLE.COM</replaceable>
kadmin/changepw@<replaceable>EXAMPLE.COM</replaceable>
kadmin/krb1.<replaceable>EXAMPLE.COM</replaceable>@<replaceable>EXAMPLE.COM</replaceable>
krbtgt/<replaceable>EXAMPLE.COM</replaceable>@<replaceable>EXAMPLE.COM</replaceable>

kadmin.local:  <userinput>quit</userinput>
</screen>

<note>
<para>If your output does not say <code>kadmin/krb1.<replaceable>EXAMPLE.COM</replaceable>@<replaceable>EXAMPLE.COM</replaceable></code> but it says <code>kadmin/<replaceable>YOUR_HOSTNAME</replaceable>.<replaceable>EXAMPLE.COM</replaceable>@<replaceable>EXAMPLE.COM</replaceable></code>, then that is fine but you need to open <filename>/etc/hosts</filename> to verify and make sure that <replaceable>YOUR_HOSTNAME</replaceable> &mdash;if it is listed there &mdash; appears associated to a real, valid network IP of the machine, and not to its local IP (127.*). 
</para><para>
In other words, if in your <filename>/etc/hosts</filename> you see something like:
<screen>
127.0.0.1       localhost
127.0.1.1       ubuntu.<replaceable>example.com</replaceable> ubuntu
192.168.7.12    krb1.<replaceable>example.com</replaceable> krb1 monarch.<replaceable>example.com</replaceable> monarch
</screen>
That would need to be adjusted to:
<screen>
127.0.0.1       localhost
192.168.7.12    ubuntu.<replaceable>example.com</replaceable> ubuntu krb1.<replaceable>example.com</replaceable> krb1 monarch.<replaceable>example.com</replaceable> monarch
</screen>
</para>
</note>

</para>
</section>

<section id="krb-princnames">
<title>Principal Names</title>

<para>In the test step above, you might have noticed &PRINCIPAL; names
similar to
<literal>kadmin/admin@<replaceable>EXAMPLE.COM</replaceable></literal>.
The general naming syntax for principals is
<literal><replaceable>SPEC</replaceable>@<replaceable>REALM</replaceable></literal>,
where <replaceable>SPEC</replaceable> by convention consists of
components separated by "<literal>/</literal>", and the default
<replaceable>REALM</replaceable> can be omitted.</para>

<para>In the case of principals related to system users, the first component identifies the user
name, and the second component (if present) identifies user role. For
regular users, there will usually be one principal with no special role,
named simply <literal><replaceable>USERNAME</replaceable></literal>. But
when administrative or other roles are required, there will be no need
to condense them all to one "<literal>admin</literal>" principal — each
user can simply be given conveniently named additional principals with
special privileges, such as
<literal><replaceable>USERNAME</replaceable>/admin</literal>.</para>

<para>In the case of principals related to system services, the components will be used to
identify service and hostname, such as
<literal>host/<replaceable>monarch.example.com</replaceable></literal>
or
<literal>ldap/<replaceable>monarch.example.com</replaceable></literal>.
("host" is somewhat of a misnomer from today's perspective — it has
nothing to do with host per-se, but is actually the service name for all
remote shell protocols, such as rsh, rlogin and ssh).</para>
</section>

<section id="krb-access">
<title>Access rights</title>

<para>Let's take a look at the
<filename>/etc/krb5kdc/kadm5.acl</filename> file; it defines user access
rights for the Kerberos database. For regular users with no special
privileges, no action will be required. For admin users, we will want to
grant all privileges, as hinted earlier in <xref
linkend="krb-princnames" />. To do this, make sure the following line is
present in the file and enabled (that is, without the comment
'<literal>#</literal>' character at the beginning): <screen>
*/admin *
</screen> (While the above syntax might remind you of &SHELL_GLOBBING;,
it does not work that way. The only matching
character supported is the asterisk ("<literal>*</literal>"), it does
not match multiple components, and it can only be used in form of
"<literal><replaceable>component</replaceable>/*</literal>" or
"<literal>*/<replaceable>component</replaceable></literal>".)</para>

<para>Make sure to restart the admin server to apply
<filename>/etc/krb5kdc/kadm5.acl</filename> changes: <programlisting>
sudo invoke-rc.d krb5-admin-server restart
</programlisting></para>
</section>

<section>
<title>Kerberos policies</title>

<para>Kerberos "policies" offer an elegant way to sort principals into a
kind of categories and to automatically apply corresponding defaults
onto newly created principals.</para>

<para>Let's create four basic policies: for admins, hosts, services and
users. In this example, each policy will define minimum password
strength (measured in number of character classes present in the
password, from 1 to 5), but a few other options can be set — run
<userinput>addpol</userinput> (the supported abbreviation of add_policy)
if you're curious. <screen>
<userinput>sudo kadmin.local</userinput>
Authenticating as principal root/admin@<replaceable>EXAMPLE.COM</replaceable> with password.

kadmin.local:  <userinput>add_policy -minlength 8 -minclasses 3 admin</userinput>
kadmin.local:  <userinput>add_policy -minlength 8 -minclasses 4 host</userinput>
kadmin.local:  <userinput>add_policy -minlength 8 -minclasses 4 service</userinput>
kadmin.local:  <userinput>add_policy -minlength 8 -minclasses 2 user</userinput>

kadmin.local:  <userinput>quit</userinput>
</screen></para>
</section>

<section id="krb-adduser-priv">
<title>Creating first privileged principal</title>

<para>As you might have noticed, the <command>kadmin.local</command>
command identified us as the principal <literal>root/admin</literal>.
Still, that principal does not actually exist in the database so we
might as well create it now. Once the principal is actually there, we'll
be able to connect to the administrative server using
<command>kadmin</command> from any machine within the Kerberos realm,
and not just by using <command>kadmin.local</command> on the Kerberos
server.</para>

<para>
Creating a principal based on your regular identity (such as
<literal><replaceable>USERNAME</replaceable>/admin</literal>) is
preferred over creating one called <literal>root/admin</literal>, 
and you are welcome to do so in your setup.
<screen>
<userinput>sudo kadmin.local</userinput>
Authenticating as principal root/admin@<replaceable>EXAMPLE.COM</replaceable> with password.

kadmin.local:  <userinput>addprinc -policy admin root/admin</userinput>

Enter password for principal "root/admin@<replaceable>EXAMPLE.COM</replaceable>": <userinput><replaceable>PASSWORD</replaceable></userinput>
Re-enter password for principal "root/admin@<replaceable>EXAMPLE.COM</replaceable>": <userinput><replaceable>PASSWORD</replaceable></userinput>
Principal "root/admin@<replaceable>EXAMPLE.COM</replaceable>" created.

kadmin.local:  <userinput>quit</userinput>
</screen></para>
</section>

<section id="krb-test2">
<title>Kadmin test</title>

<para>Now that the <literal>root/admin</literal> principal exists in the
Kerberos database, we should be able to use <command>kadmin</command>
just as we used <command>kadmin.local</command>. The only exception, of
course, is that <command>kadmin</command> will prompt for a password to
connect to the Kerberos admin server.</para>

<para>Double-check that all the permissions are granted to admin roles
in the <filename>/etc/krb5kdc/kadm5.acl</filename> (as explained in
<xref linkend="krb-access" />), and that the admin server has been
restarted to read the new configuration; then proceed to test
<command>kadmin</command> connection:</para>

<para><screen>
<userinput>kadmin -p root/admin</userinput>
Authenticating as principal root/admin@<replaceable>EXAMPLE.COM</replaceable> with password.

Password for root/admin@<replaceable>EXAMPLE.COM</replaceable>: <userinput><replaceable>PASSWORD</replaceable></userinput>

kadmin:  <userinput>listprincs</userinput>

K/M@<replaceable>EXAMPLE.COM</replaceable>
root/admin@<replaceable>EXAMPLE.COM</replaceable>
kadmin/admin@<replaceable>EXAMPLE.COM</replaceable>
kadmin/changepw@<replaceable>EXAMPLE.COM</replaceable>
kadmin/history@<replaceable>EXAMPLE.COM</replaceable>
kadmin/krb1.<replaceable>EXAMPLE.COM</replaceable>@<replaceable>EXAMPLE.COM</replaceable>
krbtgt/<replaceable>EXAMPLE.COM</replaceable>@<replaceable>EXAMPLE.COM</replaceable>

kadmin:  <userinput>quit</userinput>
</screen>

If there is a noticeable delay present before the kadmin password prompt appears, or if you
notice a "<literal>SERVER_NOT_FOUND</literal>" warning printed to
<filename>/var/log/kerberos/krb5kdc.log</filename>, look up
<xref linkend="err_server_not_found_krb5kdc" /> for a solution.
</para>
</section>

<section id="krb-adduser-ticket">
<title>Creating first unprivileged principal</title>

<para>Let's add a principal that will correspond to your regular,
unprivileged user account. In our example, the username will be called
"<literal>jirky</literal>". We've essentially performed this procedure
for the <literal>root/admin</literal> principal above, but we'll repeat
it here for your regular user account, using a different policy, and
replacing <replaceable>jirky</replaceable> with your username.
</para><para>
<screen>
<userinput>kadmin -p root/admin</userinput>
Authenticating as principal root/admin@<replaceable>EXAMPLE.COM</replaceable> with password.

Password for root/admin@<replaceable>EXAMPLE.COM</replaceable>: <userinput><replaceable>PASSWORD</replaceable></userinput>

kadmin:  <userinput>addprinc -policy user <replaceable>jirky</replaceable></userinput>

Enter password for principal "jirky@<replaceable>EXAMPLE.COM</replaceable>": <userinput><replaceable>PASSWORD</replaceable></userinput>
Re-enter password for principal "jirky@<replaceable>EXAMPLE.COM</replaceable>": <userinput><replaceable>PASSWORD</replaceable></userinput>
Principal "jirky@<replaceable>EXAMPLE.COM</replaceable>" created.

kadmin:  <userinput>quit</userinput>
</screen></para>
</section>

<section id="krb-obtain-ticket">
<title>Obtaining Kerberos ticket</title>

<para>As hinted in the introduction, each user is expected to type in
the password once, to obtain the initial TGT (Ticket-granting Ticket).
Obtained tickets are saved to a so-called <emphasis>ticket
cache</emphasis>, which is most commonly a file named
<literal>/tmp/krb5cc_*</literal>, stored on the user's
workstation.</para>

<para>Let's run the <command>klist</command> command to inspect our
ticket cache (run this command under your regular, non-privileged
username). As one might guess, since we did not obtain any tickets yet,
the cache will be empty: <screen>
<userinput>klist -f</userinput>

klist: No credentials cache found (ticket cache FILE:/tmp/krb5cc_0)
</screen> Let's use <command>kinit</command> now to obtain the ticket, and
then re-inspect the ticket cache. If the command seemingly "hangs" and
does nothing, wait a few seconds — DNS misconfiguration may be causing a
delay.
<screen>
<userinput>kinit <replaceable>jirky</replaceable></userinput>

Password for jirky@<replaceable>EXAMPLE.COM</replaceable>: <userinput><replaceable>PASSWORD</replaceable></userinput>
</screen>
</para><para>
(You do not need to specify an explicit username if it is the same as your UNIX login name.)
<screen>
<userinput>klist -f</userinput>

Ticket cache: FILE:/tmp/krb5cc_1000
Default principal: jirky@<replaceable>EXAMPLE.COM</replaceable>

Valid starting     Expires            Service principal
11/22/06 22:30:36  11/23/06 08:30:33  krbtgt/<replaceable>EXAMPLE.COM</replaceable>@<replaceable>EXAMPLE.COM</replaceable>
renew until 11/23/06 22:30:34, Flags: FPRIA
</screen> If you remember the story from the beginning, you will recognize the
"<literal>krbtgt</literal>" to be the Ticket-granting Ticket.</para>

<para>The meanings of each flag letter produced
by the <command>klist</command> switch <literal>-f</literal> are not
important at this stage, but long-term it is useful to get into the
habit of using <literal>-f</literal>, and the flag descriptions can be
looked up in the manpage <citerefentry>
<refentrytitle>klist</refentrytitle>

<manvolnum>1</manvolnum>
</citerefentry>.</para>

<para>All great. Let's run <userinput>kdestroy</userinput> to terminate
the ticket now.</para>
</section>

<section id="krb-inst-krberized">
<title>Installing kerberized services</title>

<para>To actually use Kerberos, we need to install or configure versions
of standard services that support Kerberos.</para>

<para>Each service may support Kerberos authentication either by having
native Kerberos support, or by delegating the authentication work to the
PAM subsystem (and since all relevant services support PAM, this means
it is possible to Kerberize all network services).</para>

<!-- No longer, they've been removed:

<para>In the APT repository you will find packages like
<literal>krb-ftpd</literal>, <literal>krb5-telnetd</literal> and
<literal>krb5-rsh-server</literal>. Those are replacement services for
ftp, telnet and rsh with native Kerberos (and encryption)
support.</para>

<caution>
<para>The mentioned <literal>krb-ftpd</literal>,
<literal>krb5-telnetd</literal> and <literal>krb5-rsh-server</literal>
are still part of Kerberos for traditional reasons, but they contain
known implementation flaws and their removal has been discussed a
couple of times. Do not use them in your environment.
</para>
</caution>
-->

<para>Let's install <literal>openssh-server</literal> as our first and
possibly the most important service.
<programlisting>
sudo apt install openssh-server
</programlisting></para>

<para>To successfully connect to a certain service, the service must have a
corresponding principal in the Kerberos database. This is because the
Kerberos server acts as a trusted 3rd party and performs mutual
authentication of both users and services as explained in <xref
linkend="intro-krb" />.
</para>
<para>
The generic service name for telnet, rsh, ssh
and related protocols is "<literal>host</literal>", so let's create the
necessary principal with a randomly-generated password.
</para>
<para>
Please note that since Kerberos is based on the principle of shared secrets (as opposed to e.g. public-private key),
the principal's key will need to exist in two places &mdash; one is obviously in the Kerberos database, and the
other is in a file somewhere on the host where the service is running (e.g. in /etc/ on the SSH server machine).
</para>
<para>
In our example, since we are configuring the Kerberos and SSH server on the same machine, this will be the same host.
In all other cases when these services are not on the same host, the procedure is exactly the same &mdash; you 
use kadmin on the client machine to connect to the Kerberos server, and then you call ktadd which will export the
key to the local filesystem.
<note>
<para>
Traditionally, the default behavior of <command>ktadd</command> is such that it changes the principal's key
to a random value before exporting it to a file. You can verify this by checking the principal's "kvno"
(key version number)
value, which will increase by 1 every time you call ktadd on the principal. This is done due to an assumption
that the key should always exist in only two places (in the Kerberos database and exported into a file on the client),
so whenever you call ktadd to export a key, it is a good time to change it to a fresh value for added security.
</para>
<para>
In any case, 
if you want to prevent this key randomization for some reason, use <literal>ktadd ... -norandkey</literal>.
The <literal>-norandkey</literal> option is available from the <command>kadmin.local</command> shell.
If/when you are using <command>kadmin</command> instead, the option <literal>-norandkey</literal> is available
with package <literal>krb5-user</literal> version 1.15 and above (check with <command>dpkg -l krb5-user</command>).
Also, it requires that the admin user has "extract-keys" privilege. This privilege must be granted
to principals in <filename>/etc/krb5kdc/kadm5.acl</filename> explicitly as it is not included in "<literal>*</literal>".
If you want to do this, your entry in <filename>/etc/krb5kdc/kadm5.acl</filename> should look like either of these (they are identical):
<screen>
*/admin *e

*/admin admcilspe
</screen>
</para>
</note>

<screen>
<userinput>kadmin -p <replaceable>root</replaceable>/admin</userinput>
Authenticating as principal root/admin@<replaceable>EXAMPLE.COM</replaceable> with password.

kadmin.local:  <userinput>addprinc -policy service -randkey host/<replaceable>monarch.example.com</replaceable></userinput>

Principal "host/<replaceable>monarch.example.com</replaceable>@<replaceable>EXAMPLE.COM</replaceable>" created.

kadmin.local:  <userinput>ktadd -k /etc/krb5.keytab host/<replaceable>monarch.example.com</replaceable></userinput>

Entry for principal host/<replaceable>monarch.example.com</replaceable> with kvno 2, encryption type aes256-cts-hmac-sha1-96 added to keytab WRFILE:/etc/krb5.keytab.
Entry for principal host/<replaceable>monarch.example.com</replaceable> with kvno 2, encryption type aes128-cts-hmac-sha1-96 added to keytab WRFILE:/etc/krb5.keytab.

kadmin:  <userinput>quit</userinput>
</screen>
<!--
<warning id="randkey-1.7">
<para>With Kerberos 1.7 version 1.7dfsg~beta3-1 (and possibly
others), you will see the following error when assigning -randkey
passwords to principals with minimum character classes set above
1:</para>

<para><screen>
kadmin:  <userinput>addprinc -policy service -randkey host/<replaceable>monarch.example.com</replaceable></userinput>

<errortext>
add_principal: Password does not contain enough character classes while creating "host/<replaceable>monarch.example.com</replaceable>"
</errortext>
</screen></para>

<para>This is due to a bug introduced in -randkey operation during
addition of UTF-8 support. Status report on the issue can be tracked
under <ulink
url="http://krbdev.mit.edu/rt/Ticket/Display.html?id=6568">RT Ticket
#6568</ulink>, but your immediate short term solution is to just
reduce the corresponding policy's -minclasses to 1 as follows:
<screen>
kadmin:  <userinput>modpol -minclasses 1 host</userinput>
kadmin:  <userinput>modpol -minclasses 1 service</userinput>
</screen></para>
</warning>
-->
</para>
<para>
Now let's open the file <filename>/etc/ssh/sshd_config</filename> and modify or add the following lines:
<screen>
GSSAPIAuthentication yes
GSSAPICleanupCredentials yes
GSSAPIKeyExchange yes
UsePAM yes
</screen>
</para>

<para>And to apply changes to the SSH server, run: <programlisting>
sudo invoke-rc.d ssh restart
</programlisting></para>
</section>
<!-- TODO: the above doesn't work -> kadmin doesn't have -norandkey until version 1.15 -->

<section id="PAM_configuration">
<title>PAM configuration</title>

<para>The next step in this article pertains to integrating Kerberos into
the system authentication procedure. We want Kerberos tickets to be issued
for users as they log in, without the need to run <command>kinit</command>
manually after login.</para>

<para>On GNU/Linux and derivatives, this is done by simply altering &PAM;
configuration in <filename class="directory">/etc/pam.d/</filename> on all
machines where the users are logging in.</para>

<para>As we have explained in <xref linkend="intro-krb" />, Kerberos alone
does not help replace the usual password files
(<filename>/etc/passwd</filename>, <filename>/etc/shadow</filename> or
<filename>/etc/group</filename>). For now, your "kerberized" users will
have to be present in both system password files and in Kerberos.
(For a solution to that problem, see the next article in the series,
the &DKLAR_LDA;.)
</para>

<para>Our &PAM; configuration will be defined so that
<emphasis>either</emphasis> the usual password authentication
<emphasis>or</emphasis> Kerberos authentication will need to succeed for
the user to log in. This way, both users that will have no Kerberos entry
(the system ones, such as <literal>root</literal>,
<literal>daemon</literal>, <literal>bin</literal>,
<literal>sync</literal>, <literal>sys</literal>, ...) and those that will
(regular user accounts), will be able to log in.</para>

<para>System password in <filename>/etc/shadow</filename> will be tried
first. If you want Kerberos tickets to be issued, this type of
authentication <emphasis role="bold">must fail</emphasis> for regular
users (otherwise their "system login" would succeed — resulting in the
Kerberos part being skipped altogether and no tickets issued).</para>

<para>The most common way to make regular users have only one password
(and that one being in Kerberos) is to replace their system password in
<filename>/etc/shadow</filename> with a literal "<literal>*K*</literal>",
which is not a valid password and also by spoken convention indicates that
the "real" password is stored in Kerberos. This password can be set either
by editing <filename>/etc/shadow</filename> file directly (i.e. with
<userinput>sudo vipw -s</userinput>) or by invoking <userinput>sudo
usermod -p '*K*' <replaceable>USERNAME</replaceable></userinput>.
Since maintaining this "*K*" convention is not an easy task if you don't
have custom user management scripts, you can also just forget about it and
lock out any user's system password with <userinput>sudo usermod -L <replaceable>USERNAME</replaceable></userinput>.
</para>

<para>Let's install the necessary Kerberos PAM module: <programlisting>
sudo apt install libpam-krb5
</programlisting></para>

<para>Let's configure &PAM;. PAM configuration is quite fragile, so use
the provided examples that have been verified to work. For any
modifications, you will want to look at &PSY; and pay special attention to
seemingly insignificant variations — with PAM, they often make a whole
world of difference.</para>

<para>To minimize the chance of locking yourself out of the system during
PAM configuration phase, ensure right now that you have at least one root
terminal window open and a copy of the files available
<emphasis>before</emphasis> starting on PAM configuration changes. To do
so, execute the following in a cleanly started shell and leave the
terminal open: <programlisting>
sudo su -
cd /etc
cp -a pam.d pam.d,orig
</programlisting></para>

<note>
<para>If you break logins with an invalid PAM configuration, the above
will allow you to simply revert to a known-good state by using the open
root terminal and executing: <programlisting>
cp -a pam.d,orig/* pam.d/
</programlisting></para>
</note>

The following PAM examples are complete; you should replace your existing configuration with the one shown below: 

<section>
<title>/etc/pam.d/common-account</title>

<para>
<screen>
account [success=1 new_authtok_reqd=done default=ignore]        pam_unix.so
account requisite                       pam_deny.so
account required                        pam_permit.so
account required                        pam_krb5.so minimum_uid=1000
</screen>
</para>
</section>

<section>
<title>/etc/pam.d/common-auth</title>

<para>
<screen>
auth    [success=2 default=ignore]      pam_krb5.so minimum_uid=1000
auth    [success=1 default=ignore]      pam_unix.so nullok_secure try_first_pass
auth    requisite                       pam_deny.so
auth    required                        pam_permit.so
autoh   optional                        pam_cap.so
</screen>
</para>
</section>

<section>
<title>/etc/pam.d/common-password</title>

<para>
<screen>
password        [success=2 default=ignore]      pam_krb5.so minimum_uid=1000
password        [success=1 default=ignore]      pam_unix.so obscure use_authtok try_first_pass sha512
password        requisite                       pam_deny.so
password        required                        pam_permit.so
</screen>
</para>
</section>

<section>
<title>/etc/pam.d/common-session</title>

<para>
<screen>
session [default=1]                     pam_permit.so
session requisite                       pam_deny.so
session required                        pam_permit.so
session optional                        pam_krb5.so minimum_uid=1000
session required        pam_unix.so

# If elogind and libpam-elogind are installed:
session optional                        pam_elogind.so
</screen>
</para>
</section>

<para>If you have edited PAM configuration manually, restart the services
you will
be connecting to. This isn't strictly necessary, but it will verify early that the
services can start properly as they will certainly re-read the PAM configuration.</para>
</section>

<section id="krb-service">
<title>Installing kerberized clients</title>

<para>We can install one of the most commonly used clients nowadays - SSH:
<programlisting>
sudo apt install openssh-client
</programlisting>
</para>
</section>

<section id="Testing_connection">
<title>Testing the connection</title>

<para>As we have taken care of all the pre-requisites, we can try connecting.</para>

<para>
(Just make sure that the user you will be connecting as actually exists on the machine.
If you went with our example of <replaceable>jirky</replaceable>, make sure "jirky" is a valid, existing system user.
You can do so with <userinput>sudo adduser --disabled-password <replaceable>jirky</replaceable></userinput>.)
</para>

<para>Obtain Kerberos ticket (you can do this as any user):<screen>
<userinput>kinit <replaceable>jirky</replaceable></userinput>

Password for jirky@<replaceable>EXAMPLE.COM</replaceable>: <userinput><replaceable>PASSWORD</replaceable></userinput>
</screen></para>

<para>Verify you hold the Kerberos ticket with <userinput>klist -f</userinput> and then try connecting: <screen>
<userinput>ssh <replaceable>jirky</replaceable>@<replaceable>monarch.example.com</replaceable></userinput>

Welcome to Ubuntu 14.04.2 LTS (GNU/Linux 3.13.0-55-generic x86_64)

 * Documentation:  https://help.ubuntu.com/

New release '16.04.2 LTS' available.
Run 'do-release-upgrade' to upgrade to it.

You have new mail.
<userinput>logout</userinput>
Connection closed.
</screen></para>

<para><emphasis role="bold">Congratulations! You have a working Kerberos setup</emphasis>.</para>

<para>If anything is not working, proceed immediately below to <xref
linkend="krb_troubleshooting" /> — it contains an extensive list of
possible errors and the corresponding solutions!</para>

<para>If everything is working, then you can skip that section
and head directly to <xref linkend="PKINIT" />.</para>
</section>
</section>


<section id="krb_troubleshooting">
<title>Troubleshooting Kerberos connection</title>

<!-- no ticket cache, asks for pw.
no host found in krb db (ssh -vvv)
logged in via ssh key, has no ticket/token

does it work with pam changes only after UsePAM?
note about forwarding the ticket to untrusted host
-->

<para>
(Some of the items in this section refer to old "rsh" examples that used to be documented
before the guide was updated to use SSH. Some of the errors these tools used to report are
still valid, so they are left in the list as-is along with other items.)
</para>

<section id="err_no_tickets_cached">
<title>krb_sendauth failed: You have no tickets cached</title>

<para><screen>
<userinput>ssh monarch.<replaceable>example.com</replaceable></userinput>

<errortext>
Trying krb4 rlogin...
krb_sendauth failed: You have no tickets cached
</errortext>
</screen> You have no valid Kerberos tickets, which can be verified by running
<command>klist</command> (the output will either be empty or show
expired tickets). Obtain a new ticket using <command>kinit</command>:
<screen>
<userinput>kinit <replaceable>PRINCIPAL_NAME</replaceable></userinput>
</screen></para>
</section>

<section id="err_server_not_found">
<title>Error: Server not found in Kerberos database</title>

<para><screen>
<userinput>ssh monarch.<replaceable>example.com</replaceable></userinput>

<errortext>
error getting credentials: Server not found in Kerberos database
</errortext>
</screen> As explained in <xref linkend="intro-krb" />, both the users and the
services must have an appropriate principal entry in the Kerberos
database. While users are in form of
<replaceable>NAME/ROLE</replaceable>, services are in form
<replaceable>SERVICE-NAME/HOSTNAME</replaceable>. So you need to add a
principal for service "<literal>host</literal>" (common name for all
shell services), on host where the service is provided —
<replaceable>monarch.example.com</replaceable>.
</para>

<para>As most of the errors really boil down to this step, we also take
care of re-initializing the ticket properly, to minimize the chance of a
mistake. Execute this on the machine where the SSH service is running:<screen>
<userinput>rm /etc/krb5.keytab</userinput> # &lt;-- Caution. Don't do this unless it's a test setup!

<userinput>kdestroy</userinput>

<userinput>kadmin -p root/admin</userinput>
Authenticating as principal root/admin@<replaceable>EXAMPLE.COM</replaceable> with password.

kadmin.local:  <userinput>delprinc host/<replaceable>monarch.example.com</replaceable></userinput>
Are you sure you want to delete the principal "host/<replaceable>monarch.example.com@EXAMPLE.COM</replaceable>"? (yes/no): <userinput>yes</userinput>
Principal "host/<replaceable>monarch.example.com@EXAMPLE.COM</replaceable>" deleted.
Make sure that you have removed this principal from all ACLs before reusing.

kadmin.local:  <userinput>addprinc -policy service -randkey host/<replaceable>monarch.example.com</replaceable></userinput>

Principal "host/<replaceable>monarch.example.com</replaceable>@<replaceable>EXAMPLE.COM</replaceable>" created.

kadmin.local:  <userinput>ktadd -k /etc/krb5.keytab host/<replaceable>monarch.example.com</replaceable></userinput>

kadmin.local: <userinput>quit</userinput>
</screen></para>
</section>

<section id="err_no_such_file_or_directory">
<title>Error: No such file or directory</title>

<para><screen>
<userinput>ssh monarch.<replaceable>example.com</replaceable></userinput>

<errortext>
Couldn't authenticate to server: Server rejected authentication (during sendauth exchange)
Server returned error code 60 (Generic error (see e-text))
Error text sent from server: No such file or directory
</errortext>
</screen> The above error indicates that we should pay attention to the
"e-text" (error text returned to the client). The error text tells us,
in kind of a confusing way (since — you see — there is no filename
reported), that the <filename>/etc/krb5.keytab</filename> file on the
server is missing altogether. This file needs to exist and contain
the service key. The way to obtain the file and the key is to follow the
recipe from <xref linkend="err_server_not_found" />.</para>
</section>

<section id="err_key_table_entry_not_found">
<title>Error: Key table entry not found</title>

<para><screen>
<userinput>ssh monarch.<replaceable>example.com</replaceable></userinput>

<errortext>
Couldn't authenticate to server: Server rejected authentication (during sendauth exchange)
Server returned error code 60 (Generic error (see e-text))
Error text sent from server: Key table entry not found
</errortext>
</screen> The server did accept the connection, but the e-text "Key table
entry not found" indicates that the service principal (created earlier,
<literal>host/<replaceable>monarch.example.com</replaceable></literal>)
is not listed in the keytab file on SSH server. Follow the recipe in
<xref linkend="err_server_not_found" />.</para>
</section>

<section id="err_key_version_number_incorrect">
<title>Error: Key version number for principal in key table is
incorrect</title>

<para><screen>
<userinput>ssh monarch.<replaceable>example.com</replaceable></userinput>

<errortext>
Couldn't authenticate to server: Server rejected authentication (during sendauth exchange)
Server returned error code 60 (Generic error (see e-text))
Error text sent from server: Key version number for principal in key table is incorrect
</errortext>
</screen> The service key has changed on the Kerberos server, and the service
did not succeed in proving its identity to the Kerberos server — the
file <filename>/etc/krb5.keytab</filename> on the service's machine did not
contain the correct key. (Have in mind that the key will change when you run
<literal>ktadd</literal> from within the <command>kadmin</command>
shell, and the only way to prevent that from happening is to use
<command>kadmin.local</command> interface and use <userinput>ktadd
-norandkey</userinput> in it.) If curious, read up on
<literal>ktadd</literal> behavior in <citerefentry>
<refentrytitle>kadmin</refentrytitle>

<manvolnum>8</manvolnum>
</citerefentry>. Follow the recipe in <xref
linkend="err_server_not_found" />.</para>
</section>

<section id="err_client_not_found">
<title>Error: Client not found in Kerberos database while getting
initial credentials</title>

<para><screen>
<userinput>kinit <replaceable>root/admin</replaceable></userinput>

<errortext>
kinit(v5): Client not found in Kerberos database while getting initial credentials
</errortext>
</screen> This is Kerberos way of saying "User not found". You either
misspelled the principal name ("<literal>root/admin</literal>" in this
case), or you didn't add the principal to the kerberos database in the
first place. Adding a principal is performed using the
<command>addprinc</command> command as shown in <xref
linkend="krb-adduser-priv" /> or <xref
linkend="krb-adduser-ticket" />.</para>
</section>

<section id="err_kadm_client_not_found">
<title>Error: Client not found in Kerberos database while initializing
kadmin interface</title>

<para><screen>
<userinput>kadmin -p <replaceable>root/admin</replaceable></userinput>

<errortext>
kadmin: Client not found in Kerberos database while initializing kadmin interface
</errortext>
</screen> This is Kerberos way of saying "User not found". You either
misspelled the principal name ("<literal>root/admin</literal>" in this
case), or you didn't add the principal to the kerberos database in the
first place. Adding a principal is performed using the
<command>addprinc</command> command as shown in <xref
linkend="krb-adduser-priv" /> or <xref
linkend="krb-adduser-ticket" />.</para>
</section>

<section id="err_decrypt_integrity_check_failed">
<title>Error: Decrypt integrity check failed</title>

<para><screen>
<userinput>ssh monarch.<replaceable>example.com</replaceable></userinput>

<errortext>
Couldn't authenticate to server: Server rejected authentication (during sendauth exchange)
Server returned error code 31 (Decrypt integrity check failed)
Error text sent from server: Decrypt integrity check failed
</errortext>
</screen> This is Kerberos way of saying "Password incorrect". In this case,
it means that the service key changed on the server, and your your
ticket cache no longer contains the ticket with the correct key. Running
<userinput>kdestroy; kinit</userinput> should obtain a new ticket and
solve the problem.</para>
</section>

<section id="err_unsupported_key_table_format_vno">
<title>Error: Unsupported key table format version number while
adding key to keytab</title>

<para><screen>
kadmin: <userinput>ktadd -k /etc/krb5.keytab host/<replaceable>monarch.example.com</replaceable></userinput>

<errortext>
kadmin: Unsupported key table format version number while adding key to keytab
</errortext>
</screen>
This usually happens when the local file to which you want to export the key
(<filename>/etc/krb5.keytab</filename>) is in an incorrect format.
</para><para>
The most common reason why this would happen is if you have tried to
create an empty file (using <command>touch</command> or similar commands)
beforehand, and then export the key into it.
</para><para>
To verify that this is indeed the case, try running <command>klist</command>
on the existing file to which you are attempting to export the key:
<screen>
<userinput>sudo klist -k /etc/keytab</userinput>

<errortext>
klist: Unsupported key table format version number while starting keytab scan
</errortext>
</screen>
</para><para>
The solution is to delete the incorrectly created keytab file and let the <command>ktadd</command> create it automatically, or to choose a
different keytab file to which the intended key should be exported.
</para>
</section>

<section id="err_wrong_principal">
<title>Error: Wrong principal in request</title>

<para><screen>
<userinput>ssh monarch.<replaceable>example.com</replaceable></userinput>

<errortext>
Couldn't authenticate to server: Server rejected authentication (during sendauth exchange)
Server returned error code 60 (Generic error (see e-text))
Error text sent from server: Wrong principal in request
</errortext>
</screen>
TODO
</para>
</section>

<section id="err_server_not_found_krb5kdc">
<title>Error: SERVER_NOT_FOUND</title>

<para><screen>
<userinput>kadmin -p root/admin</userinput>

==&gt; kerberos/krb5kdc.log &lt;==<errortext>
Jan 07 01:47:35 ubuntu krb5kdc[20837](info): AS_REQ (4 etypes {18 17 16 23}) 192.168.7.12: SERVER_NOT_FOUND: root/admin@<replaceable>EXAMPLE.COM</replaceable> for kadmin/krb1.<replaceable>example.com</replaceable>@<replaceable>EXAMPLE.COM</replaceable>, Server not found in Kerberos database
</errortext>
</screen>
This error is emitted in the <application>krb5kdc</application> log file when the principal reported
(<literal>kadmin/krb1.<replaceable>example.com</replaceable>@<replaceable>EXAMPLE.COM</replaceable></literal>)
is missing in the Kerberos database.<sbr/>
It usually happens when you are setting up a Kerberos server using a chosen hostname that
does not match the hostname reported by the system command <command>hostname</command>.
</para><para>
Add the missing kadmin principal as follows:
<screen>
<userinput>sudo kadmin.local</userinput>
Authenticating as principal root/admin@<replaceable>EXAMPLE.COM</replaceable> with password.

kadmin.local:  <userinput>addprinc -randkey -requires_preauth -allow_tgs_req  kadmin/krb1.<replaceable>example.com</replaceable></userinput>

WARNING: no policy specified for kadmin/krb1.<replaceable>example.com</replaceable>@<replaceable>EXAMPLE.COM</replaceable>; defaulting to no policy
Principal "kadmin/krb1.<replaceable>example.com</replaceable>@<replaceable>EXAMPLE.COM</replaceable>" created.

kadmin.local:  <userinput>quit</userinput>
</screen>
</para>
</section>

<section id="err_unknown_server_krb5kdc">
<title>Error: UNKNOWN_SERVER</title>

<para><screen>
<userinput>kadmin -p root/admin</userinput>

==&gt; kerberos/krb5kdc.log &lt;==<errortext>
Jan 07 01:47:35 ubuntu krb5kdc[20837](info): TGS_REQ (7 etypes {18 17 16 23 1 3 2}) 192.168.7.12: UNKNOWN_SERVER: authtime 1376929169, root/admin@<replaceable>EXAMPLE.COM</replaceable> for kadmin/krb1.<replaceable>example.com</replaceable>@<replaceable>EXAMPLE.COM</replaceable>, Server not found in Kerberos database
</errortext>
</screen>
TODO
</para>
</section>

<section id="err_not_authorized">
<title>Error: klogind: not authorized to login to account</title>

<para><screen>
<userinput>ssh monarch.<replaceable>example.com</replaceable></userinput>

<errortext>klogind: User root/admin@EXAMPLE.COM is not authorized to login to account root.</errortext>
</screen>
This error is emitted when the Kerberos principal name ("<literal>root/admin</literal>") does not
exactly match the name of the user account to which it wants to log in to ("<literal>root</literal>"),
and when the login allowance for that principal has not been added to
file <filename>~/.k5login</filename>.
</para><para>
To add the permission, add the principal's full name to the
file <filename>~/.k5login</filename> in the target account's home directory:
<screen>
<userinput>echo 'root/admin@<replaceable>EXAMPLE.COM</replaceable>' >> ~root/.k5login</userinput>
</screen>
</para>
</section>

<section id="err_connection_refused">
<title>Error: Connection Refused</title>

<para><screen>
<userinput>krb5-rsh -PN monarch.<replaceable>example.com</replaceable></userinput>

<errortext>
connect to address 192.168.7.12: Connection refused
Trying krb4 rlogin...
connect to address 192.168.7.12: Connection refused
trying normal rlogin (/usr/bin/netkit-rlogin)
exec: No such file or directory
</errortext>
</screen> Let's take a look at this. First of all, you can see that
<command>krb5-rsh</command> has some fallbacks built-in. It first tries
to connect using the Kerberos 5 protocol, then Kerberos 4, and then
using the normal, non-kerberized rsh. We are only interested in the krb5
result. If any of the other two methods succeed (the krb4 or plain rsh),
it's still not what we want (and you will probably want to disable them
somehow, because no one setting up a new Kerberos realm in the 21st
century should be running either krb4 or unprotected rsh).</para>

<para>So where's the problem? Assuming that you did everything right
(installed krb5-rsh-server and restarted inetd), the problem is very
simple. Namely, by default, kerberized servers in Debian do not accept
unencrypted connections! So, on next attempt, add <literal>-x</literal>
on the command line. <screen>
<userinput>krb5-rsh -PN -x monarch.<replaceable>example.com</replaceable></userinput>
</screen></para>
</section>

<section id="err_pkinit_generic">
<title>Error: Generic preauthentication failure while getting initial credentials</title>

<para><screen>
<userinput>kinit <replaceable>jirky</replaceable></userinput>

<errortext>
kinit: Generic preauthentication failure while getting initial credentials
</errortext>
</screen>If using PKINIT, make sure that package <literal>krb5-pkinit</literal> is installed:
<userinput>apt-get install krb5-pkinit</userinput>.
</para>
</section>

<section id="err_pkinit_preauth_failed">
<title>Error: Pre-authentication failed: Invalid argument while getting initial credentials</title>

<para><screen>
<userinput>kinit <replaceable>jirky</replaceable> -X pkinit_identities=FILE:<replaceable>jirky</replaceable>cert.pem,<replaceable>jirky</replaceable>key.pem</userinput>

<errortext>
kinit: Pre-authentication failed: Invalid argument while getting initial credentials
</errortext>
</screen>
Data for <literal>pkinit_identities</literal> setting was not specified or it is invalid.<sbr/>
If you are relying on settings from <filename>/etc/krb5.conf</filename>, make sure there is a line such as <literal>pkinit_identities = FILE:/path/to/cert.pem,/path/to/key.pem</literal>.
If you are relying on settings passed on command line, instead of <literal>pkinit_identities</literal> use <literal>X509_user_identity</literal>, such as <userinput>kinit -V -X X509_user_identity=FILE:/path/to/cert.pem,/path/to/key.pem</userinput>.
</para>
</section>

</section>

<section id="PKINIT">

<title>PKINIT</title>

<section id="PKINIT-intro">
<title>Introduction</title>
<para>
In proper, infrastructure-based networks, users would authenticate to Kerberos
once (at system login), and access all other services automatically and transparently from there.
</para>
<para>
However, traditionally with Kerberos this implied typing in a password, preventing use of more advanced login
methods like smartcards, etc.
</para>
<para>
Also, often times users' desktops are installed ad-hoc and are not part of
any formal infrastructure. Similarly, users might not want to bother setting up their machines
as Kerberos clients, or might not even want to care about authentication
systems used behind the scenes.<sbr/>
Such ad-hoc approaches are often characterized by users simply installing SSH private-public keys for achieving passwordless logins to remote systems.
But in SSH key-based (passwordless) logins, there are no passwords involved and
so there is nothing available for the KDC servers to verify and use as basis for
issuing TGTs.
</para>
<para>
So, while smartcards and SSH keys can be used, users who log in this way will not be able to automatically obtain Kerberos tickets. They will need to manually run <command>kinit</command>, which effectively gets them back to password-based authentication.
Additionally, this two-step approach may be even more unsuitable for hosts that rely on Kerberos for granting filesystem access, such as those using &AFS;.
</para>
<para>
To solve this problem, PKINIT was developed as a preauthentication mechanism for Kerberos 5. It uses X.509 certificates to authenticate KDCs to clients and vice versa.
Additionally, PKINIT can also be used to enable anonymity support, allowing clients to communicate securely with the KDCs or application servers without authenticating as a particular client principal.
</para>
</section>

<section id="PKINIT-server">
<title>Server configuration</title>
<para>
PKINIT configuration on the server requires package <literal>krb5-pkinit</literal>, some additional configuration files, X.509 certificate for Certificate Authority, and X.509 certificate for KDC.
</para><para>
For anonymous PKINIT, a KDC certificate is required. It is possible to use a commercially issued server certificate if that is what you have, but our example will show generating all certificates ourselves.
</para>

<section id="PKINIT-server-package">
<title>Package krb5-pkinit</title>
<para>
<screen>
<userinput>apt-get install krb5-pkinit</userinput>
</screen>
</para>
</section>

<section id="PKINIT-server-extensions-kdc">
<title>/etc/krb5kdc/extensions.kdc</title>
<para>
Create file <filename>/etc/krb5kdc/extensions.kdc</filename> with the following content:
<screen>
[kdc_cert]
basicConstraints=CA:FALSE
keyUsage=nonRepudiation,digitalSignature,keyEncipherment,keyAgreement
extendedKeyUsage=1.3.6.1.5.2.3.5
subjectKeyIdentifier=hash
authorityKeyIdentifier=keyid,issuer
issuerAltName=issuer:copy
subjectAltName=otherName:1.3.6.1.5.2.2;SEQUENCE:kdc_princ_name

[kdc_princ_name]
realm=EXP:0,GeneralString:${ENV::REALM}
principal_name=EXP:1,SEQUENCE:kdc_principal_seq

[kdc_principal_seq]
name_type=EXP:0,INTEGER:1
name_string=EXP:1,SEQUENCE:kdc_principals

[kdc_principals]
princ1=GeneralString:krbtgt
princ2=GeneralString:${ENV::REALM}
</screen>
</para>
</section>

<section id="PKINIT-server-extensions-client">
<title>/etc/krb5kdc/extensions.client</title>
<para>
Create file <filename>/etc/krb5kdc/extensions.client</filename> with the following content:
<screen>
[client_cert]
basicConstraints=CA:FALSE
keyUsage=digitalSignature,keyEncipherment,keyAgreement
extendedKeyUsage=1.3.6.1.5.2.3.4
subjectKeyIdentifier=hash
authorityKeyIdentifier=keyid,issuer
issuerAltName=issuer:copy
subjectAltName=otherName:1.3.6.1.5.2.2;SEQUENCE:princ_name

[princ_name]
realm=EXP:0,GeneralString:${ENV::REALM}
principal_name=EXP:1,SEQUENCE:principal_seq

[principal_seq]
name_type=EXP:0,INTEGER:1
name_string=EXP:1,SEQUENCE:principals

[principals]
princ1=GeneralString:${ENV::CLIENT}
</screen>
</para>
</section>

<section id="PKINIT-server-ca">
<title>Certificate Authority (CA) files</title>
<para>
Create Certificate Authority key and certificate as follows:
<screen>
<userinput>mkdir /etc/krb5</userinput>

<userinput>cd /etc/krb5kdc/</userinput>

<userinput>openssl genrsa -out cakey.pem 8192</userinput>
<userinput>openssl req -key cakey.pem -new -x509 -out ../krb5/cacert.pem -days 3650</userinput>
</screen>
All values asked during certificate creation can remain blank. Answer all fields with a dot (<literal>.</literal>) for this.
</para><para>
File <filename>/etc/krb5/cacert.pem</filename> needs to be present on all KDCs and client machines. Because of this, expiration time of 10 years (3650 days) was used in the above example.<sbr/>
File <filename>cacert.key</filename>, as all private keys, must be carefully protected, and it will be used when creating KDC and client certificates.
</para>
</section>

<section id="PKINIT-server-kdc">
<title>KDC files</title>
<para>
Create KDC key, certificate request, and signed certificate as follows:
<screen>
<userinput>cd /etc/krb5kdc/</userinput>

<userinput>openssl genrsa -out kdckey.pem 8192</userinput>
<userinput>openssl req -key kdckey.pem -new -out kdccert.req</userinput>

<userinput>env REALM=<replaceable>EXAMPLE.COM</replaceable> openssl x509 -req -in kdccert.req -CAkey cakey.pem -CA ../krb5/cacert.pem \
  -out kdccert.pem -days 3650 -extfile extensions.kdc -extensions kdc_cert -CAcreateserial</userinput>

<userinput>rm kdccert.req</userinput>
</screen>
All values asked during certificate creation can remain blank. Answer all fields with a dot (<literal>.</literal>) for this.
</para><para>
File <filename>kdccert.pem</filename> needs to be copied to all KDCs. Because of this, expiration time of 10 years (3650 days) was used in the above example.<sbr/>
File <filename>kdckey.pem</filename>, as all private keys, must be carefully protected.
</para>
<para>
At this point you can examine the CA or KDC certificates with <userinput>openssl x509 -in ../krb5/cacert.pem -text -noout</userinput>. OpenSSL will not know how to display the principal name in the Subject Alternative Name extension, so it will appear as <literal>othername:&lt;unsupported&gt;</literal>. This is fine.
</para>
</section>

<section id="PKINIT-server-kdc-config">
<title>KDC configuration</title>
<para>
After all the files above are in place, add the following to <filename>/etc/krb5kdc/kdc.conf</filename> into any section (either inside "<literal>[kdcdefaults]</literal>", or inside "<literal>[realms]</literal>" under the subsection for your realm):
<screen>
pkinit_identity = FILE:/etc/krb5kdc/kdccert.pem,/etc/krb5kdc/kdckey.pem
pkinit_anchors = FILE:/etc/krb5/cacert.pem
kdc_tcp_ports = 88
</screen>
And restart the KDC server:
<screen>
<userinput>sudo invoke-rc.d krb5-kdc restart</userinput>
</screen>
</para>
</section>
</section>

<section id="PKINIT-client-config">
<title>Client configuration</title>

<section id="PKINIT-client-certificates">
<title>Certificates</title>
<para>
Each client who wishes to authenticate against the KDC in this way will need a certificate. Certificate for our example user <replaceable>jirky</replaceable> can be created as follows:
<screen>
<userinput>cd /etc/krb5kdc/</userinput>

<userinput>openssl genrsa -out <replaceable>jirky</replaceable>key.pem 8192</userinput>
<userinput>openssl req -key <replaceable>jirky</replaceable>key.pem -new -out <replaceable>jirky</replaceable>.req</userinput>

<userinput>env REALM=<replaceable>EXAMPLE.COM</replaceable> CLIENT=<replaceable>jirky</replaceable> openssl x509 \
    -CAkey cakey.pem -CA ../krb5/cacert.pem -req -in <replaceable>jirky</replaceable>.req \
    -extensions client_cert -extfile extensions.client \
    -days 3650 -out <replaceable>jirky</replaceable>cert.pem</userinput>

<userinput>rm <replaceable>jirky</replaceable>.req</userinput>
</screen>
All values asked during certificate creation can remain blank. Answer all fields with a dot (<literal>.</literal>) for this.
</para><para>
The first two commands can be executed on any host. The third command needs to be executed on the CA machine where <filename>cakey.pem</filename> exists.
In our case this is the same machine as KDC, in the directory <filename>/etc/krb5kdc/</filename>.
</para><para>
Files <filename>jirkycert.pem</filename> and <filename>jirkykey.pem</filename> will need to be present on the machine from which the client will be authenticating.
</para><para>
As usual, you can examine the certificate with <userinput>openssl x509 -in jirkycert.pem -text -noout</userinput>. OpenSSL will not know how to display the principal name in the Subject Alternative Name extension, so it will appear as <literal>othername:&lt;unsupported&gt;</literal>. This is fine.
</para>
</section>

<section id="PKINIT-client-preauthentication">
<title>Preauthentication</title>
<para>
Since PKINIT is a preauthentication mechanism for Kerberos, preauthentication must be enabled on principals wishing to authenticate using PKINIT.
<para></para>
This may already be a default setting thanks to this line in <filename>/etc/krb5kdc/kdc.conf</filename>:

<screen>
...

[realms]
	<replaceable>EXAMPLE.COM</replaceable> = {
		...
		default_principal_flags = +preauth
		...
  }
</screen>

If this setting is not present, you can add it to the config file to serve as the default, and/oror you can check individual principals for presence of this flag:

<screen>
<userinput>sudo kadmin.local</userinput>
Authenticating as principal root/admin@<replaceable>EXAMPLE.COM</replaceable> with password.

kadmin.local:  <userinput>getprinc <replaceable>jirky</replaceable></userinput>

...
Attributes: REQUIRES_PRE_AUTH
...


kadmin.local:  <userinput>modprinc +requires_preauth <replaceable>jirky</replaceable></userinput>

kadmin.local:  <userinput>quit</userinput>
</screen>
</para>
</section>

<section id="PKINIT-client-keys">
<title>Authentication keys</title>
<para>
Sometimes it can be useful to remove all traditional authentication keys for a principal in the Kerberos database, to easier debug PKINIT-specific issues.
<para></para>
Also, if users will only ever authenticate using PKINIT, they don't need Kerberos keys at all.
<para></para>
Deleting keys for users or creating users with no keys in the first place can be done using the following commands:
<screen>
<userinput>sudo kadmin.local</userinput>
Authenticating as principal root/admin@<replaceable>EXAMPLE.COM</replaceable> with password.

kadmin.local:  <userinput>purgekeys -all <replaceable>jirky</replaceable></userinput>

kadmin.local:  <userinput>addprinc +requires_preauth -nokey <replaceable>quirky</replaceable></userinput>

kadmin.local:  <userinput>quit</userinput>
</screen>
</para>
</section>

<section id="PKINIT-client-certs">
<title>KDC and client certificates</title>
<para>
Client hosts must be configured to trust the issuing authority for the KDC certificate, and the authenticating clients need to have access to their own certificate and private key.
This can be defined in either <filename>/etc/krb5.conf</filename> which is read by all Kerberos clients, or in-place during invocation of <command>kinit</command> and similar commands.
<para></para>
Specifying the CA cert in <filename>/etc/krb5.conf</filename> may be convenient because this file can and should be world-readable, but client keys are
inherently private in nature and are best not kept or listed in a single place.
<para></para>
Thefore, for <filename>cacert.pem</filename> we will use <filename>/etc/krb5.conf</filename> and for client certificates and keys we will use in-place specification. So, we add this to <filename>/etc/krb5.conf</filename>:
<screen>
...

[realms]
	<replaceable>EXAMPLE.COM</replaceable> = {
		...
		# For own certificate:
		pkinit_anchors = FILE:/etc/krb5/cacert.pem

		# Or for commercial certificate:
		#pkinit_anchors = DIR:/etc/ssl/certs
		#pkinit_eku_checking = kpServerAuth
		#pkinit_kdc_hostname = <replaceable>hostname.of.kdc.certificate,...</replaceable>

		...
  }

</screen>
</para>
</section>
</section>

<section id="PKINIT-client-kinit">
<title>Authentication</title>
<para>
Finally, we are able to test client authentication using PKINIT!
</para><para>
As mentioned, in addition to eventual principal name, we will specify the location of the corresponding client certificate and private key:
<screen>
<userinput>kdestroy</userinput>

<userinput>kinit <replaceable>jirky</replaceable> -X X509_user_identity=FILE:jirkycert.pem,jirkykey.pem</userinput>
</screen>
If the KDC and client were properly configured, the above command has succeeded without asking for a password!
</para>

</section>

<!-- mention KRB5_TRACE, DNS lookups, anon auth, using SSH keys, and using smartcards -->

</section>

<section>
<title>Conclusion</title>

<para>At this point, you have a functional Kerberos installation!</para>

<para>You can rely on either system login or manually running
<command>kinit</command> in obtaining Kerberos tickets and accessing
Kerberized services. One of those services is the passwordless,
Kerberos-secured SSH login that we've demonstrated in this guide.</para>

<para>
<emphasis role='bold'>With a good foundation we've built, for further
information on Kerberos, please refer to other available resources:</emphasis>

<itemizedlist>
<listitem><para>
Official documentation: &DOC;
</para></listitem>
<listitem><para>
Mailing lists: &MLS;
</para></listitem>
<listitem><para>
IRC: channel #kerberos at the Libera.Chat network (irc.libera.chat)
</para></listitem>
<listitem><para>
For commercial consultation and infrastructure-based networks containing Kerberos, contact &SL;.
</para></listitem>
</itemizedlist>
</para>

<para>Remember that, as explained in this Guide, your user accounts still
need to be created locally on
all hosts the users wish to access. To solve that problem and achieve true
centralized logins, follow the next article in the series, the
&DKLAR_LDA;.</para>

<para>If you have followed the &DKLAR_LDA; first and have come here to set
up Kerberos as an afterthought, 
run <userinput>sudo dpkg-reconfigure libpam-ldap</userinput>
to choose "Unix authentication" and "Kerberos authentication"
instead of "LDAP Authentication", and re-visit the &DKLAR_LDA; to verify
that the resulting PAM configuration files have actually been re-generated
and look like the Kerberos-related examples shown there.
</para>

<para>If you have followed this &DKLAR_KRB; only as a pre-requisite for
installing OpenAFS and do not want to use LDAP in combination, proceed to
another article in the series, the &DKLAR_AFS;.</para>

</section>

<section>
<title>Links</title>

<para>Platforms:<sbr /> &GNU; <sbr /> &DEB; <sbr /><sbr />
Kerberos:<sbr /> &KRB; <sbr /> &HDL; <sbr /> &KRBC; <sbr /><sbr />
Kerberos specifics:<sbr /> &KERBEROS_RELEASE; <sbr /> &KERBEROS_DATABASE;
<sbr /> &REALM; <sbr /> &KDC; <sbr /> &PRINCIPAL; <sbr /> &SECRET_KEY;
<sbr /> &TGT; <sbr /><sbr /> Glue layer:<sbr /> &PAM; <sbr /> &PSY;
<sbr /><sbr /> Related infrastructural technologies:<sbr /> &LDA; <sbr />
&AFS; <sbr /> &RAD; <sbr /><sbr /> Commercial support:<sbr /> &SL;
<sbr /><sbr /> Misc:<sbr /> &DOCBK; <sbr /></para>
</section>
</article>
