Administering Oracle Linux 7.2: Part 1 — Configuring a Time Server and Kerberos

Version 3

    by Alexandre Borges

     

    This article is Part 1 of a series that explains how to administer Oracle Linux 7.2. This article focuses on how to configure a Network Time Protocol (NTP) client/server and Kerberos on Oracle Linux 7.2.

     

    Introduction

     

    This article explains how to configure a Kerberos server. Kerberos is a frequently used authentication framework, and it is almost omnipresent in the Microsoft world through the Microsoft Active Directory service. We will have a nice journey, because we will have a chance to manage and keep in touch with details about how Kerberos is working and explore a few respective concepts, most of which are related to cryptography (symmetric keys).

     

    Kerberos, as a network authentication protocol and framework, brings us excellent advantages and features when handling authentication. For example, at beginning of the day, users can log into a Kerberos server to get credentials that will be used to access applications all day long, without any of these applications asking users to enter a username and password. This is known as single sign-on (SSO).

     

    During the process mentioned above, Kerberos helps us by providing authentication without passing any passwords through the network, thus preventing hackers from stealing passwords by monitoring the network. It's also possible to get remote authentication without incurring any unnecessary risks.

     

    One of main support services of Kerberos is a time server, which provides the clock time that is indirectly inserted into a packet for checking the packet's authentication and to prevent replay attacks. So we will review Network Time Protocol (NTP)l concepts and chronyd server configuration procedures before delving into the Kerberos setup.

     

    Note: Before starting, note the following very important information:

     

    • The myoracle4.example.com host (192.168.1.91) will be our Kerberos and DNS server.
    • The myoracle5.example.com host (192.168.1.92) will be our client.
    • The myoracle6.example.com host (192.168.1.93) will be our second SSH server.

     

    Configuring a Time Server

     

    On a system, and even in our daily life, there are several areas where time is fundamental. For example, every time that we make a bank transaction, the bank system registers our operation into their database together the time when the transaction happens. Another similar example occurs during the administration of a system where important tasks are logged by a central daemon and all registers are entered into either a database or a file followed by their respective time of occurrence. Other examples where time is fundamental include encryption and services.

     

    Kerberos is a service that uses time as a reference to authenticate users, and if the client system is not synchronized with the time server, the user is not able to accomplish the authentication. Later, we will see a clever technique that helps the system to prevent passing a password over the network.

     

    NTP is a client/server service in which there are hosts (clients systems) that need accurate time (client systems use the time in databases, logging systems, encryption, and so on) and a server that provides the time. Usually, client systems use the NTP protocol (port 123/UDP) to get accurate time information from either a private NTP server (deployed inside a company and less reliable) or a public NTP server (offered by very reliable organizations through which the time is provided from either a GPS or atomic source, for example).

     

    Usually, system administrators install some private NTP servers inside their company, which provide time to their client systems and services, but these private servers fetch a precise and accurate time from a public pool (group) of NTP servers. (For North America, this pool is found at http://www.pool.ntp.org/zone/north-america, and for United States the pool is described at http://www.pool.ntp.org/zone/us.) It is interesting to note that if your company has stable and not-overloaded bandwidth, your servers can become part of the public NTP pool (more information can be found on http://www.pool.ntp.org/en/join.html).

     

    Thus, the final NTP schema for a company could be the following:

     

    NTP clients -> Private NTP servers -> Public NTP server pool

     

    NTP concepts are sophisticated and you should know that NTP servers are classified by "stratum" levels (0 to 15) according to various criteria that indicate their time accuracy and reliability (more information is available at http://www.ntp.org/ntpfaq/NTP-s-algo.htm). Lower stratum levels offer more-accurate time; stratum 0 is known as the reference clock.

     

    Before configuring Kerberos, we will configure a local NTP service, and we will be use two systems (myoracle4 and myoracle5) as the server and client, respectively. A simple schema will be shown here, because the main purpose is to explain the concepts and show how to configure an NTP environment.

     

    The first step for configuring an NTP service is to get the current time information on either system, as shown in Listing 1:

     

    [root@myoracle5 ~]# timedatectl

     

          Local time: Mon 2015-04-20 18:50:12 BRT

      Universal time: Mon 2015-04-20 21:50:12 UTC

            RTC time: Mon 2015-04-20 21:50:12

            Timezone: America/Sao_Paulo (BRT, -0300)

         NTP enabled: yes

    NTP synchronized: yes

    RTC in local TZ: no

          DST active: no

    Last DST change: DST ended at

                      Sat 2015-02-21 23:59:59 BRST

                      Sat 2015-02-21 23:00:00 BRT

    Next DST change: DST begins (the clock jumps one hour forward) at

                      Sat 2015-10-17 23:59:59 BRT

                      Sun 2015-10-18 01:00:00 BRST

    Listing 1

     

    Listing 1 shows the following information:

     

    • Local time is BRT (Brasilia Summer Time) in my location; all abbreviations are available at https://en.wikipedia.org/wiki/List_of_time_zone_abbreviations.
    • Universal time is the primary time standard by which the world regulates clocks and time (Coordinated Universal Time [UTC]).
    • RTC time is the RTC (real-time clock) provided by an internal circuit on the computer, which includes a battery that keeps track of the time even when the machine is turned off.
    • Timezone is the region that observes the time for commercial, social, and legal purposes. A list is available at https://en.wikipedia.org/wiki/List_of_tz_database_time_zones).
    • NTP enabled indicates whether this host is fetching time from an NTP server.
    • NTP synchronized indicates whether the local time is synchronized with an NTP server.
    • RTC in local TZ indicates whether the RTC time is maintained in local time. If the value of this field is no, the RTC time is maintained in UTC.
    • DST active indicates whether Daylight Saving Time (DST) is active in the current location.
    • Last DST change is the last time when DST was in effect.
    • Next DST change indicates the next period when DST will be in effect.

     

    In this case, the time zone is Sao Paulo, but you can list all time zones by running the command in Listing 2:

     

    [root@myoracle5 ~]# timedatectl list-timezones

     

    Africa/Abidjan

    Africa/Accra

    Africa/Addis_Ababa

    Africa/Algiers

    Africa/Asmara

    ...

    Listing 2

     

    For example, if you have to change the time zone to America/New_York, execute these commands:

     

    [root@myoracle5 ~]# timedatectl set-timezone America/New_York

     

    [root@myoracle5 ~]# timedatectl

     

          Local time: Mon 2015-04-20 18:04:37 EDT

      Universal time: Mon 2015-04-20 22:04:37 UTC

            RTC time: Mon 2015-04-20 22:04:37

            Timezone: America/New_York (EDT, -0400)

         NTP enabled: yes

    NTP synchronized: yes

    RTC in local TZ: no

          DST active: yes

    Last DST change: DST began at

                      Sun 2015-03-08 01:59:59 EST

                      Sun 2015-03-08 03:00:00 EDT

    Next DST change: DST ends (the clock jumps one hour backwards) at

                      Sun 2015-11-01 01:59:59 EDT

                      Sun 2015-11-01 01:00:00 EST

     

    Two Linux services that are able to provide time services are ntpd (from Oracle Linux 6) and chronyd (from Oracle Linux 7). Because chronyd is installed by default on Oracle Linux 7 and it is the recommended clock service to be use, I am using it in this article.

     

    The first step is to check whether the public pools of NTP servers are available and reachable (there is a good NTP server list at http://www.pool.ntp.org/zone/@). We need these pools of NTP servers to provide time to our local NTP server to make the time more accurate.

     

    Therefore, having the list of the public NTP server pools (for example, we can use a pool for Brazil; see http://www.pool.ntp.org/zone/br), we are able to verify the availability of the servers by running the command shown in Listing 3:

     

    [root@myoracle4 ~]# ntpdate -q 1.br.pool.ntp.org

     

    server 200.129.0.46, stratum 2, offset -0.005986, delay 0.08086

    server 200.189.40.8, stratum 2, offset -0.004017, delay 0.04520

    server 200.160.0.8, stratum 2, offset -0.008282, delay 0.04192

    server 200.192.232.8, stratum 2, offset -0.003690, delay 0.06099

    20 Apr 19:53:34 ntpdate[6220]: adjust time server 200.160.0.8 offset -0.008282 sec

    Listing 3

     

    In Listing 3, the option -q means "query only" so the time has not been set. Another interesting fact is that different servers from the pool answered our request, and they informed us of their IP addresses, stratum level, and eventual delay.

     

    Each pool is back-ended by several NTP servers (as shown in Listing 3) and the recommendation is to use at least three aliases from the same pool. In fact, it is preferable to configure four servers closest your country, as mentioned in this reference, for example:

     

    0.br.pool.ntp.org

    1.br.pool.ntp.org

    2.br.pool.ntp.org

    3.br.pool.ntp.org

     

    We could repeat the procedure using similar commands with continental NTP pools (for example, the South America pools) by running the command below:

     

    [root@myoracle4 ~]# ntpdate -q 0.south-america.pool.ntp.org

     

    server 190.181.129.115, stratum 2, offset -0.000690, delay 0.19424

    server 200.160.7.186, stratum 1, offset -0.007801, delay 0.04253

    server 66.60.22.202, stratum 4, offset -0.006213, delay 0.29182

    server 190.139.102.146, stratum 3, offset 0.046463, delay 0.18404

    20 Apr 19:54:23 ntpdate[6235]: adjust time server 200.160.7.186 offset -0.007801 sec

     

    In this case, when using continental servers, we also need to point to at least three servers aliases (preferable four) from the same pool, as shown below:

     

    0.south-america.pool.ntp.org

    1.south-america.pool.ntp.org

    2.south-america.pool.ntp.org

    3.south-america.pool.ntp.org

     

    Instead of using the old NTP service (ntpd), which it still present in Oracle Linux 7, we must use the new chronyd service to keep updated time on the system. As mentioned earlier, the chronyd service is the recommend method for providing accurate time for applications and other services on Oracle Linux 7.We should use the ntpd service only when there is no chronyd service installed on the host. A few advantages of chronyd are that it supports intermittent internet connections and it keeps track of the computer's local clock offset compared to the remote public NTP servers to fix its time while the computer is not connected to the internet. chronyd is very accurate (down to about microseconds).

     

    To configure the chronyd server, the first step is to change the /etc/chronyd.conf file to include the chosen NTP servers, according our previous discussion and as shown below:

     

    [root@myoracle4 ~]# cat /etc/chrony.conf| grep '^server'

    server 0.br.pool.ntp.org

    server 1.br.pool.ntp.org

    server 2.br.pool.ntp.org

    server 3.br.pool.ntp.org

     

    Once more, we should remember that is recommended to include at least three aliases to the same pool.

     

    Before proceeding, it would be nice to check whether the chrony package is installed (it should be) by running the following command:

     

    [root@myoracle4 ~]# rpm -qa | grep chrony

    chrony-2.1.1-1.el7.x86_64

     

    Now, enable and start the chronyd service by running these commands:

     

    [root@myoracle4 ~]# systemctl enable chronyd.service

    ln -s '/usr/lib/systemd/system/chronyd.service' '/etc/systemd/system/multi-user.target.wants/chronyd.service'

     

    [root@myoracle4 ~]# systemctl start chronyd

     

    Sometimes, it takes times for the initial synchronization to occur.  We can accelerate the process by executing the ntpdate command with one of sources, as shown below:

     

    [root@myoracle4 ~]# ntpdate -q 0.br.pool.ntp.org

    server 192.99.2.8, stratum 2, offset -0.001648, delay 0.19318

    server 201.49.148.135, stratum 1, offset -0.003443, delay 0.05640

    server 200.160.7.193, stratum 1, offset -0.001256, delay 0.03940

    3 Feb 04:14:46 ntpdate[3661]: adjust time server 200.160.7.193 offset -0.001256 sec

     

    To verify that our local clock server is synchronizing to the public NTP pool of servers, execute the command shown in Listing 4:

     

    [root@myoracle4 ~]# chronyc sources

     

    210 Number of sources = 4

    MS Name/IP address         Stratum Poll Reach LastRx Last sample

    ===============================================================================

    ^+ c.ntp.br                      2   6    77    10  -5913us[-6964us] +/-   38ms

    ^- time100.stupi.se              1   6    77     7  -9494us[-9494us] +/-  123ms

    ^* b.st1.ntp.br                  1   6    77     9  +1033us[  -19us] +/-   17ms

    ^- aprihop.cdknnjln.sodtech.     2   6    37    74  +1535us[+1909us] +/-   98ms

    Listing 4

     

    The meaning of each column in Listing 4 is as follows:

     

    • M: Tells us the mode of the remote server (source), where ^ means a server, = means a peer, and # means a locally connected reference clock.
    • S: Indicates the source of the remote servers, where:

      * means the source to which chronyd is currently synchronized.

      + indicates another acceptable source.

      - indicates an acceptable source that was excluded by the algorithm.

      ? indicates that connectivity was lost.

      x means that the clock is a false clock when compared to the majority of other sources.

      ~ means that the source appears to be volatile (too much variability and changing its time very often).

    • Name/IP address: Shows the IP address or name of the remote clock server (source).
    • Stratum: Shows the stratum level of the source. When analyzing the output in Listing 4, here is a very interesting point: if the stratum level of the remote server (source) is 2, our stratum level must be 3 (it's always the source stratum level + 1).
    • Poll: Means the rate at which the remote server (source) is being polled. In this case, 10 means 2^10 (1024) seconds.
    • Reach: An octal number that shows the reach register (8 bits) of the remote server. It is updated on every received or missed packet from the remote server. For example, 377 means that a valid reply was received for all of the last eight transmissions.
    • LastRx:  Indicates how long ago the last update was received from the remote server.
    • Last sample: Shows the offset time between the local clock server and the remote clock server (source).

     

    To gather statistics from the remote clock servers (sources), execute the command shown in Listing 5:

     

    [root@myoracle4 ~]# chronyc sourcestats -v

     

    210 Number of sources = 4

                                 .- Number of sample points in measurement set.

                                /      .- Number of residual runs with same sign.

                               |     /      .- Length of measurement set (time).

                               |    |     /      .- Est. clock freq error (ppm).

                               |    |    |      /           .- Est. error in freq.

                               |    |    |     |           /         .- Est. offset.

                               |    |    |     |           |         |   On the -.

                               |    |    |     |           |         |   samples. \

                               |    |    |     |           |         |            /

    Name/IP Address            NP  NR  Span  Frequency  Freq Skew  Offset  Std Dev

    ==============================================================================

    c.ntp.br                    6   5   323     -3.107     31.736  -4039us   730us

    time100.stupi.se            6   3   326     -8.187     81.559  -7596us  2029us

    b.st1.ntp.br                6   5   324     +2.834     62.155  +1918us  1848us

    aprihop.cdknnjln.sodtech.   5   4   259     +7.888     64.905  +2387us   983us

    Listing 5

     

    The following explains each column shown in Listing 5:

     

    • Name/IP Address: Indicates the name or IP address of the remote clock server.
    • NP: Indicates the number of runs of residuals having the same sign following the last regression. If this number becomes too low, chronyd discards old samples and run the regression again until the number of runs becomes acceptable.
    • NR: Indicates the number of runs of residuals having the same sign following the last regression. We should concern with this number only if it becomes too small when compared to the number of samples, because that would be an indication that the server is not so good for providing the time.
    • Span: Indicates the interval between the oldest and newest sample.
    • Frequency: Indicates the estimated residual frequency for the server.
    • Freq Skew: Indicates a limit for the expected and tolerable frequency errors (in parts per million).
    • Offset: Indicates the estimated offset from our local clock server compared to the remote clock server (source).
    • Std Dev: Indicates the estimated standard deviation of the sample.

     

    Finally, collect information about the main time reference by running the command shown in Listing 6:

     

    [root@myoracle4 ~]# chronyc tracking

     

    Reference ID    : 201.49.148.135 (b.st1.ntp.br)

    Stratum         : 2

    Ref time (UTC)  : Wed Feb  3 06:17:33 2016

    System time     : 0.001213228 seconds slow of NTP time

    Last offset     : -0.000584088 seconds

    RMS offset      : 0.000635298 seconds

    Frequency       : 8.662 ppm slow

    Residual freq   : -0.557 ppm

    Skew            : 24.767 ppm

    Root delay      : 0.034529 seconds

    Root dispersion : 0.002150 seconds

    Update interval : 65.2 seconds

    Leap status     : Normal

    Listing 6

     

    The meaning of each row in Listing 6 is as follows:

     

    • Reference ID: The IP address/name of the remote clock server (source).
    • Stratum: Indicates how many hops our local clock server is away from the reference clock that provides time to the remote clock server. This is interesting because, as explained previously, the remote NTP server was at stratum level 2, so our local clock server is at stratum level 3.
    • Ref time (UTC): The UTC time at which the last measurement from the reference source was processed.
    • System time: Indicates a potential difference between the time provided by chronyd and the local system clock fetched by a system call. Usually, it is not relevant.
    • Last offset: Indicates the estimated local offset measured on the last clock update.
    • RMS offset: Indicates an average of offsets over the clock time.
    • Frequency: Indicates (in parts per million) the rate at which the local clock would be wrong if chronyd was not correcting it.
    • Residual freq: Reflects any difference between the frequency that should be used and the frequency currently being used.
    • Skew: Indicates a limit for the expected and tolerable frequency errors.
    • Root delay: Indicates the total difference between the time of the local clock server and the time of the reference clock that provides time to the remote clock server.
    • Root dispersion: Indicates the total dispersion (a concept related to statistical measurement variations) of the clock that was accumulated from the stratum-1 servers up to the local clock server.
    • Update interval: Indicates how long ago the last update happened.
    • Leap status: Indicates the leap (offset) status, which can be Normal, Insert Second, Delete Second, or Not Synchronized.

     

    To begin configuring our local client, let's alter the /etc/chrony.conf file on the client system (the following command is executed on myoracle5) to point the same four NTP pools we used for the myoracle4 system, as shown in Listing 7:

     

    [root@myoracle5 ~]# cat /etc/chrony.conf | grep '^server'

    server 0.br.pool.ntp.org

    server 1.br.pool.ntp.org

    server 2.br.pool.ntp.org

    server 3.br.pool.ntp.org

    Listing 7

     

    The configuration in Listing 7 is the recommended configuration (as explained previously) and we could use it. However, if you want either to prevent each client from accessing the internet to get the correct clock or if some clients do not have internet access, you can cause your client host (myoracle5) to get the clock from myoracle4 by changing the chrony.conf file, as shown below:

     

    [root@myoracle5 ~]# cat /etc/chrony.conf | grep '^server'

    server 192.168.1.91

     

    If we stopped here, our configuration (with myoracle5 fetching its time from myoracle4) would not work because the chronyd server (on the myoracle4 host) does not accept queries from any client. Therefore, change the /etc/chrony.conf file on the chronyd server (on myoracle4) to accept queries from local systems (in this case, the myoracle5 client):

     

    [root@myoracle4 ~]# cat /etc/chrony.conf | grep '^allow'

    allow 192.168.1/24

     

    For our changes to take effect, restart the chronyd server by executing this:

     

    [root@myoracle4 ~]# systemctl restart chronyd.service

     

    There are some additional tasks to do now. We must remember to open the NTP port (123/UDP) in the firewall on the chronyd server (myoracle4) by running the following commands:

     

    [root@myoracle4 ~]# firewall-cmd --permanent --zone=public --add-port=123/udp

    [root@myoracle4 ~]# firewall-cmd --reload

     

    Update the client time (the reasons are the same as explained previously for the ntpd service) from the chronyd server by running the next command:

     

    [root@myoracle5 ~]# ntpdate 192.168.1.91

     

    3 Feb 04:35:46 ntpdate[3501]: adjust time server 192.168.1.91 offset 0.001157 sec

     

    Then, restart the chronyd service on the client by executing the commands shown in Listing 8:

     

    [root@myoracle5 ~]# systemctl restart chronyd.service

    [root@myoracle5 ~]# systemctl status chronyd.service

     

    chronyd.service - NTP client/server

       Loaded: loaded (/usr/lib/systemd/system/chronyd.service; disabled; vendor preset: enabled)

       Active: active (running) since Wed 2016-02-03 04:35:15 BRST; 1min 7s ago

      Process: 3492 ExecStartPost=/usr/libexec/chrony-helper update-daemon (code=exited, status=0/SUCCESS)

      Process: 3489 ExecStart=/usr/sbin/chronyd $OPTIONS (code=exited, status=0/SUCCESS)

    Main PID: 3491 (chronyd)

       CGroup: /system.slice/chronyd.service

               └─3491 /usr/sbin/chronyd

     

    Feb 03 04:35:15 myoracle5.example.com systemd[1]: Starting NTP client/server...

    Feb 03 04:35:15 myoracle5.example.com chronyd[3491]: chronyd version 2.1.1 starting (+CMDMON +NTP +REFCLOCK +RTC +PRIVDROP +DEBUG +...CHASH)

    Feb 03 04:35:15 myoracle5.example.com chronyd[3491]: Generated key 1

    Feb 03 04:35:15 myoracle5.example.com systemd[1]: Started NTP client/server.

    Hint: Some lines were ellipsized, use -l to show in full.

    Listing 8

     

    As we can see in Listing 8, the chronyd client started its synchronism operation. To track this operation, execute the command shown in Listing 9:

     

    [root@myoracle5 ~]# chronyc tracking

     

    Reference ID    : 192.168.1.91 (192.168.1.91)

    Stratum         : 3

    Ref time (UTC)  : Wed Feb  3 06:37:24 2016

    System time     : 0.000000000 seconds slow of NTP time

    Last offset     : +0.001040759 seconds

    RMS offset      : 0.001040759 seconds

    Frequency       : 0.000 ppm fast

    Residual freq   : +13.658 ppm

    Skew            : 1000000.000 ppm

    Root delay      : 0.016670 seconds

    Root dispersion : 32.407433 seconds

    Update interval : 0.0 seconds

    Leap status     : Normal

    Listing 9

     

    According to Listing 9, everything is OK. Verify the source clock server, which, in this case, is our local clock server (myoracle4, which has the IP address 192.168.1.91), as shown below:

     

    [root@myoracle5 ~]# chronyc sources

     

    210 Number of sources = 1

    MS Name/IP address         Stratum Poll Reach LastRx Last sample

    ===============================================================================

    ^* 192.168.1.91                  2   6    17     2   -860us[-1171us] +/-   10ms

     

    This is great! Everything is working as expected.

     

    Now, we can proceed to configure the DNS server.

     

    Configuring the DNS Server

     

    To succeed with our Kerberos configuration, the name resolution of our system must be correct and it is extremely important to know that using a DNS service is recommended, because Kerberos requires fully qualified domain names and not short host names.

     

    In a common DNS configuration in the real world, we would have both master and slave DNS servers, but we will keep things simple here. So we will review only how to configure a master DNS server.

     

    Once more, we should remember the system names and their respective IP addresses:

     

    • myoracle4.example.com: 192.168.1.91 (our DNS master server)
    • myoracle5.example.com: 192.168.1.92
    • myoracle6.example.com: 192.168.1.93

     

    To begin, we must install the bind package in our server:

     

    [root@myoracle4 ~]# yum install -y bind

     

    Edit the /etc/named.conf file and make the changes (shown in bold) in Listing 10:

     

    [root@myoracle4 ~]# more /etc/named.conf | grep -v '^//'

     

    options {

       listen-on port 53 { any; };

       listen-on-v6 port 53 { ::1; };

       directory    "/var/named";

       dump-file    "/var/named/data/cache_dump.db";

       statistics-file "/var/named/data/named_stats.txt";

       memstatistics-file "/var/named/data/named_mem_stats.txt";

       allow-query     { localhost;192.168.1.0/24; };

     

       /*

        - If you are building an AUTHORITATIVE DNS server, do NOT enable recursion.

        - If you are building a RECURSIVE (caching) DNS server, you need to enable

          recursion.

        - If your recursive DNS server has a public IP address, you MUST enable access

          control to limit queries to your legitimate users. Failing to do so will

          cause your server to become part of large scale DNS amplification

          attacks. Implementing BCP38 within your network would greatly

          reduce such attack surface

       */

       recursion yes;

     

      

       forwarders { 8.8.8.8; 8.8.4.4; };

     

       dnssec-enable yes;

       dnssec-validation yes;

       dnssec-lookaside auto;

     

       /* Path to ISC DLV key */

       bindkeys-file "/etc/named.iscdlv.key";

     

       managed-keys-directory "/var/named/dynamic";

     

       pid-file "/run/named/named.pid";

       session-keyfile "/run/named/session.key";

    };

     

    logging {

            channel default_debug {

                    file "data/named.run";

                    severity dynamic;

            };

    };

     

    zone "." IN {

       type hint;

       file "named.ca";

    };

     

    zone "example.com" IN {

       type master;

       file "forward.example.com.db";

       allow-update { none; };

    };

     

    zone "1.168.192.in-addr.arpa" IN {

       type master;

       file "reverse.1.168.192.db";

       allow-update { none; };

    };

     

     

    include "/etc/named.rfc1912.zones";

    include "/etc/named.root.key";

    Listing 10

     

    Here's a summarized explanation about each bold configuration change shown in Listing 10:

     

    • listen-on port 53 { any; };  allows the DNS service (BIND) to listen to port 53 for requests on any network interface.
    • allow-query { localhost;192.168.1.0/24; };  allows only the client from this address and the network address to query the DNS server for IP address translation.
    • forwarders { 8.8.8.8; 8.8.4.4; };   configures this DNS master server to forward any request not related to domain example.com to external DNS servers.
    • zone "example.com"  block specifies that any request for translating from a name to an IP address must be searched for in the forward.example.com.db file in the  /var/named directory. Additionally, the parameter allow-update { none; } disables DHCP updates to the forward.example.com.db file.
    • zone "1.168.192.in-addr.arpa" block specifies that any request for translating from an IP address to a name must be searched for in the reverse.1.168.192.db file. Additionally, the parameter allow-update { none; } disables DHCP updates to the reverse.1.168.192.db file.

     

    Now, we have to create the /var/named/forward.example.com.db file as shown in Listing 11:

     

    [root@myoracle4 ~]# more /var/named/forward.example.com.db

     

    $TTL 86400

     

    @    IN  SOA     myoracle4.example.com. root.example.com. (

    20160201  ;Serial

    3600        ;Refresh

    1800        ;Retry

    604800      ;Expire

    86400       ;Minimum TTL

    )

    ;The name server information

    @    IN  NS      myoracle4.example.com.

     

    ;The IP address of the name server

    myoracle4    IN  A       192.168.1.91

     

    ;Remaining records

    myoracle5    IN  A       192.168.1.92

    myoracle6    IN  A       192.168.1.93

    Listing 11

     

    Here are a few quick explanations for Listing 11:

     

    • The first line configures the SOA (Start of Authority), that is, it specifies which host is the master server (myoracle4) and the contact email address (root.example.com means root@example.com).
    • The second line is the serial number that represents the version of this configuration file. This is very important when there is a slave server. In such a case, I use the date in reverse.
    • The line beginning with @ represents the domain (in this case, example.com) and it configures myoracle4.example.com as its name server.
    • The last three lines configure address (A) records to resolve from a name to an IP address.

     

    Create the /var/named/reverse.1.168.192.db file, as shown in Listing 12:

     

    [root@myoracle4 ~]# more /var/named/reverse.1.168.192.db

     

    $TTL 86400

    @   IN  SOA     myoracle4.example.com. root.example.com. (

    20160202  ;Serial

    3600        ;Refresh

    1800        ;Retry

    604800      ;Expire

    86400       ;Minimum TTL

    )

     

    ;The name server information

    @ IN  NS      myoracle4.example.com.

     

    ;The pointer records

    91   IN   PTR     myoracle4.example.com.

    92   IN   PTR     myoracle5.example.com.

    93   IN   PTR     myoracle6.example.com.

    Listing 12

     

    This file is very similar to the previous one, but in Listing 12, the last three lines are using PTR records, which translate from an IP address to a name.

     

    Now, it's appropriate to check the syntax of the configuration files by running the next command:

     

    [root@myoracle4 ~]# named-checkconf

     

    An empty output means that everything is OK.

     

    Change the DNS client configuration of each host to point to our master server. First, list the available network interfaces and network connections as shown in Listing 13:

     

    [root@myoracle4 ~]# ip link

     

    1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT

        link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00

    2: eno16777736: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP mode DEFAULT qlen 1000

        link/ether 00:0c:29:a1:ff:84 brd ff:ff:ff:ff:ff:ff

    3: virbr0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN mode DEFAULT

        link/ether 52:54:00:53:a8:f6 brd ff:ff:ff:ff:ff:ff

    4: virbr0-nic: <BROADCAST,MULTICAST> mtu 1500 qdisc pfifo_fast master virbr0 state DOWN mode DEFAULT qlen 500

        link/ether 52:54:00:53:a8:f6 brd ff:ff:ff:ff:ff:ff

     

    [root@myoracle4 ~]# nmcli con show

    NAME         UUID                                  TYPE            DEVICE     

    eno16777736  e4f26d9f-2d70-4d3a-9feb-6d943b88ed36  802-3-ethernet  eno16777736

    Listing 13

     

    According to the output in Listing 13, the connection and the network interface have the same name (eno16777736).

     

    Modify the DNS server setting for the eno16777736 connection, as shown below:

     

    [root@myoracle4 ~]# nmcli con mod "eno16777736" ipv4.dns 192.168.1.91

     

    Modify the domain search domain parameter for the eno16777736 connection by executing the following command:

     

    [root@myoracle4 ~]# nmcli con mod "eno16777736" ipv4.dns-search example.com

     

    To make the changes take effect, execute the following commands to bring the eno16777736 connection down and up:

     

    [root@myoracle4 ~]# nmcli con down "eno16777736"

    Connection 'eno16777736' successfully deactivated (D-Bus active path: /org/freedesktop/NetworkManager/ActiveConnection/0)

     

    [root@myoracle4 ~]# nmcli con up "eno16777736"

    Connection successfully activated (D-Bus active path: /org/freedesktop/NetworkManager/ActiveConnection/1)

     

    Verify whether all configurations were accomplished successfully by running the next command:

     

    [root@myoracle4 ~]# nmcli con show "eno16777736" | grep ipv4.dns

    ipv4.dns:                               192.168.1.91

    ipv4.dns-search:                        example.com

     

    Open the necessary firewall ports by changing permanently the firewall configuration file, as shown below:

     

    [root@myoracle4 ~]# firewall-cmd --permanent --add-service=dns

     

    Now, reload this configuration into memory:

     

    [root@myoracle4 ~]# firewall-cmd -reload

     

    Manage the permission (chgrp command), ownership (chown command), and the Security Enhanced Linux (SELinux) configuration (restorecon command), as shown below:

     

    [root@myoracle4 ~]# chgrp named -R /var/named
    [root@myoracle4 ~]# chown -v root:named /etc/named.conf
    [root@myoracle4 ~]# restorecon /etc/named.conf
    [root@myoracle4 ~]# restorecon -rv /var/named

     

    Enable the DNS service to run upon the next boot by executing the following command:

     

    [root@myoracle4 ~]# systemctl enable named
    Created symlink from /etc/systemd/system/multi-user.target.wants/named.service to /usr/lib/systemd/system/named.service.

     

    Start the DNS service by running the following command:

     

    [root@myoracle4 ~]# systemctl start named

     

    Check if the DNS service is running by running the next command:

     

    [root@myoracle4 ~]# systemctl status named

    named.service - Berkeley Internet Name Domain (DNS)

       Loaded: loaded (/usr/lib/systemd/system/named.service; enabled; vendor preset: disabled)

       Active: active (running) since Wed 2016-02-03 07:22:03 BRST; 51s ago

      Process: 38265 ExecStart=/usr/sbin/named -u named $OPTIONS (code=exited, status=0/SUCCESS)

      Process: 38263 ExecStartPre=/bin/bash -c if [ ! "$DISABLE_ZONE_CHECKING" == "yes" ]; then /usr/sbin/named-checkconf -z /etc/named.conf; else echo "Checking of zone files is disabled"; fi (code=exited, status=0/SUCCESS)

    Main PID: 38268 (named)

       CGroup: /system.slice/named.service

               └─38268 /usr/sbin/named -u named

     

    Feb 03 07:22:02 myoracle4.example.com named[38268]: zone 0.in-addr.arpa/IN: loaded serial 0

    Feb 03 07:22:02 myoracle4.example.com named[38268]: zone 1.0.0.127.in-addr.arpa/IN: loaded serial 0

    Feb 03 07:22:02 myoracle4.example.com named[38268]: zone 1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa/I...rial 0

    Feb 03 07:22:02 myoracle4.example.com named[38268]: zone 1.168.192.in-addr.arpa/IN: loaded serial 20160202

    Feb 03 07:22:02 myoracle4.example.com named[38268]: zone localhost.localdomain/IN: loaded serial 0

    Feb 03 07:22:02 myoracle4.example.com named[38268]: zone localhost/IN: loaded serial 0

    Feb 03 07:22:02 myoracle4.example.com named[38268]: zone example.com/IN: loaded serial 20160201

    Feb 03 07:22:02 myoracle4.example.com named[38268]: all zones loaded

    Feb 03 07:22:02 myoracle4.example.com named[38268]: running

    Feb 03 07:22:03 myoracle4.example.com systemd[1]: Started Berkeley Internet Name Domain (DNS).

    Hint: Some lines were ellipsized, use -l to show in full.

     

    Finally, we could test the DNS configuration either by running the nslookup command or the dig command. If you have performed a minimal installation of Oracle Linux 7.x, first install these commands because they are not installed by default. To do that, execute the following commands to update the current installation, list the necessary packages, and install them:

     

    [root@myoracle4 ~]# yum -y update
    [root@myoracle4 ~]# yum provides nslookup
    [root@myoracle4 ~]# yum provides dig
    [root@myoracle4 ~]# yum install 32:bind-utils-9.9.4-29.el7_2.3.x86_64

     

    Continuing, let's use the nslookup command, as shown below:

     

    [root@myoracle4 ~]# nslookup

    > server

    Default server: 192.168.1.91

    Address: 192.168.1.91#53

     

    > myoracle4.example.com

    Server:      192.168.1.91

    Address:     192.168.1.91#53

    Name:        myoracle4.example.com

    Address:     192.168.1.91

     

    > myoracle5.example.com

    Server:      192.168.1.91

    Address:     192.168.1.91#53

    Name:        myoracle5.example.com

    Address:     192.168.1.92

     

    > myoracle6.example.com

    Server:      192.168.1.91

    Address:     192.168.1.91#53

    Name:        myoracle6.example.com

    Address:     192.168.1.93

     

    > 192.168.1.91

    Server:      192.168.1.91

    Address:     192.168.1.91#53

    91.1.168.192.in-addr.arpa   name = myoracle4.example.com.

     

    > 192.168.1.92

    Server:      192.168.1.91

    Address:     192.168.1.91#53

    92.1.168.192.in-addr.arpa   name = myoracle5.example.com.

     

    > 192.168.1.93

    Server:      192.168.1.91

    Address:     192.168.1.91#53

    93.1.168.192.in-addr.arpa   name = myoracle6.example.com.

     

    > exit

     

    It's nice! The DNS server is working. Let's proceed to the Kerberos server configuration.

     

    Introduction to Kerberos

     

    Around the world, there are many mechanisms available for implementing SSO (single sign-on), which allows a single identity to be shared across many applications. Kerberos (defined and described in RFC 1510) is one of these mechanisms. The components of the Kerberos service are the Key Distribution Center (KDC), the Authentication Service (AS), and the Ticket Granting Service (TGS). In a few words, Kerberos provides strong authentication using symmetric encryption and supports the basic principles of security: authentication, authorization, confidentiality, integrity, and nonrepudiation. There are several applications in UNIX/Linux and Windows environments that could use Kerberos such as SSH, Apache Tomcat, and IIS (Internet Information Server).

     

    As many people know, the name "Kerberos" comes from Greek mythology and refers to a three-headed guard dog from Hades (https://en.wikipedia.org/wiki/Cerberus). This is interesting because in the Kerberos scheme, the third head would be the KDC, which accomplishes the authentication between the client and the target application server.

     

    Another fundamental fact is that usually the KDC is composed of the AS and the TGS (as shown in Figure 1), although we are describing the KDC as a separate component.

     

    f1.png

    Figure 1

     

    The final goal of users is to authenticate themselves (which will be done by Kerberos) and to access the target application server. Therefore, the simplified process by which Kerberos accomplishes this authentication scheme is as follows:

     

    1. Before starting, it is necessary to know that a user requesting access must obtain a ticket (that will be taken as a proof of identity) from the AS and used for a later conversation with the TGS. This request is composed of a message containing the username and the name of the TGS. Therefore, the username (and the user's password) must have been registered in the KDC database previously.

     

    f2.png

    Figure 2

     

    2. The AS looks up (but does not authenticate) the user in the KDC database and, if the user was registered previously (that is, the user exists), the AS creates a random session key (called the TGS session key) to be used to encrypt the communication during the conversation between the user and the TGS. Additionally, the AS also creates a ticket-granting ticket (TGT) to allow the user to access the TGS. Therefore, two messages are sent to the user. The first one (the TGT), which is encrypted by the TGS secret key, is composed of the username, the TGS name, a time stamp, the IP address of the client, the lifetime of the TGT, and the TGS session key. The second message, which is encrypted with the client secret key, is composed of the username, the time stamp, the lifetime, and the TGS session key.

     

    It is interesting to note that the TGT is encrypted using the secret key of the TGS (remember, it is a symmetric algorithm such as AES, 3DES,Blowfish, and so on, by which the message is encrypted and decrypted using the same key). At the end, both the session key and the TGT are sent inside an encrypted message (using the previously registered password as a key) back to the user (client system).

     

    f3.png

    Figure 3

     

    3. From step 2, we can observe a pattern that will be repeated. For each interaction, the client system always receives two messages, one of which it can decrypt and another that it cannot decrypt. Another important fact is that the user never directly talks to the KDC, because the role of the KDC is to store all secret keys (password plus a salt that are hashed) for user hosts and services (or the target application server) in its database. Moreover, all these secret keys are protected with another encryption using the master key from KDC itself to make it difficult for hackers to steal keys from the database.

     

    f4.png

    Figure 4

     

    4. The client host decrypts its message (containing its session key) and uses it to create an authenticator that contains the username, IP address of the client, and time stamp (therefore, there is no password).

     

    5. The client host sends two messages to the TGS to get a ticket to a particular application server. The first message is the authenticator (encrypted by TGS session key) and the second message is composed of the name of the application server, the lifetime, and both the encrypted authenticator and the TGT session key (that was gotten previously and is already encrypted).

     

    f5.png

    Figure 5

     

    6. When the TGS receives the request, it decrypts the TGT by using its secret key and it decrypts the authenticator by using the session key created by the AS in the step 2.  Having both the TGT and the authentication decrypted by the TGS, a sequence of verifications is accomplished. First, the TGS checks the KDC database to see if the target application server exists. Afterwards, it checks to see if the TGT has expired. If the TGT has not expired, the information inside the authenticator is compared to the information in the ticket, the IP address from the client is compared to the address from which the request was sent, and the time stamp is compared with the local time (now you know why we have configured a clock service using chronyd!). If everything is OK, the request is allowed to proceed.

     

    f6.png

    Figure 6

     

    7. The TGS creates a second random session key (the service session key) to be used to encrypt the conversation between the user and the target application server. This new service session key will be incorporated into a new ticket, which also contains the username, the user's IP address, the lifetime, a time stamp, and an expiration time. All these components are encrypted using the application server's secret key and, finally, the application server's name is appended to the new ticket. Therefore, this ticket (the service ticket) is the first message. Additionally, a second message containing the service session key (which will be used to encrypt the communication between the user and the target application server), the target application server name, the time stamp, and the lifetime are also encrypted by using the previously shared (or secret) TGS session key. Both messages are sent to client system (the user). The second message the client can decrypt, because it was encrypted using the TGS session key (shared by the TGS and the user), but the first message for the client system (the user) cannot be decrypted, because it was encrypted using the application server secret key (which is stored inside the KDC database).

     

    f7.png

    Figure 7

     

    8. The client system decrypts the second message. The service session key (created in step 7) will be used to keep an encrypted conversation with the target application server and, through this encrypted conversation, the user can authenticate to the target application server. To accomplish this task, a new authenticator will be created by the client system and it will be encrypted using the service session key created during the step 7. Therefore, a new message containing the username (or user ID), a time stamp, this new authenticator (service authenticator), and the still-encrypted service ticket (remember that it couldn't be decrypted by the user previously because it was encrypted using the service session key) is created.

     

    f8.png

    Figure 8

     

    f9.png

    Figure 9

     

    9. The client's system sends the message to the target application server, which decrypts the service ticket by using its service secret key. Inside this service ticket, the target application server finds its service session key, so it uses this service session key to decrypt the service authenticator (created during step 8). With the decrypted service authenticator and the service ticket information, the target application server will check the username (or user ID), the time stamp, the lifetime, and the IP address from the client. This time, an implicit confirmation happens because the user proves to be who she claims to be because she knows the key. Additionally, the time stamp that was included in the service ticket will also help to prevent any replay attack later.

     

    f10.png

    Figure 10

     

    10. The target application server then sends an authenticator message containing its name/ID and time stamp to confirm its identity to the client. This message is encrypted using the service session key.

     

    f11.png

    Figure 11

     

    11. The client system (the user) decrypts the authenticator message with the service session key and confirms the service name/ID and time stamp. From now on, both the user and the application server are able to exchange encrypted messages.

     

    f12.png

    Figure 12

     

    Here are a few related comments:

     

    • The clock (time) is essential. Authentication is possible only when all systems are synchronized in time.
    • The KDC must be physically secured because it keeps all the secret keys.
    • Because the AS (which is commonly built into the KDC) is one point of failure, it is strongly recommended to create a second AS for tolerance against failure.
    • Applications should be prepared to use Kerberos authentication.
    • Some Kerberos implementations save a ticket in the /tmp directory. That might be a problem if more than one user uses the machine.

     

    Configuring the Kerberos Server

     

    Now that we've had a short introduction about Kerberos, let's configure the Kerberos environment. To accomplish the Kerberos configuration, we are using two systems: the first one will be the KDC (myoracle4) and the second one will be the client (myoracle5). As explained previously, a time server is required by using either ntpd or chronyd (the latter is by far our preferred choice).

     

    Kerberos packages are not installed by default on Oracle Linux 7, so we should install them:

     

    [root@myoracle4 ~]# yum install -y krb5-server pam_krb5 krb5-workstation

     

    In the Kerberos environment, the realm is the equivalent to the domain. Because the DNS domain name is example.com (the output from the first command in Listing 14 below shows this information), change the realm to EXAMPLE.COM in the /var/kerberos/krb5kdc/kdc.conf file (the Kerberos configuration file) on the KDC system, as shown in Listing 14:

     

    [root@myoracle4 ~]# domainname

    example.com

     

    [root@myoracle4 ~]# more /var/kerberos/krb5kdc/kdc.conf

     

    [kdcdefaults]

    kdc_ports = 88

    kdc_tcp_ports = 88

     

    [realms]

    EXAMPLE.COM = {

      #master_key_type = aes256-cts

      acl_file = /var/kerberos/krb5kdc/kadm5.acl

      dict_file = /usr/share/dict/words

      admin_keytab = /var/kerberos/krb5kdc/kadm5.keytab

      supported_enctypes = aes256-cts:normal aes128-cts:normal des3-hmac-sha1:normal

    arcfour-hmac:normal camellia256-cts:normal camellia128-cts:normal

    des-hmac-sha1:normal des-cbc-md5:normal des-cbc-crc:normal

      #default_principal_flags = +preauth

    }

    Listing 14

     

    Although we will not enter further details in this file, the meaning of the information shown in Listing 14 is as follows:

     

    • kdc_ports: Ports on which the Kerberos server should listen.
    • kdc_tcp_ports: Ports on which the Kerberos server should listen for TCP connections.
    • master_key_type: Key type string that represents the key type of the master key.
    • acl_file: Location of the access control list (ACL) file that is used by the kadmind daemon to control which users are allowed in the database.
    • dict_file: Location of the dictionary files containing strings that are not allowed as a password.
    • admin_keytab: Location of the keytab file that is used by kadmind to authenticate users against the database.
    • supported_enctypes: List of keys/salts that specify the key/salt pair of principals (users) in this realm.
    • default_principal_flags: Specifies default attributes of principals; + enables a flag and - disables a flag.

     

    Additionally, note that to implement a more-secure configuration, the master_key_type line should not be commented out; so remove the # character, which is there by default. And the line default_principal_flags = +preauth should be inserted at end of the file (service tickets will be issued only to clients with a TGT that has the preauthenticated bit set) and comment it out. This line is commented out only for now.

     

    The master_key_type specifies the key type of the master key to be entered manually as a password when the -m option is given, and its default value is des-cbc-crc, which is an unsafe value because it uses the very weak symmetric DES algorithm with CRC-32 when the line is commented out. There are some interesting symmetric algorithms that can be used such as aes256-cts (AES 256-bit algorithm in CTS mode), aes256-cts-hmac-sha1-96 (AES 256-bit algorithm with 96 bits SHA1-MAC), des3-hmac-sha1 (Triple DES algorithm in CBC mode with HMAC/sha1), and so on. "CTS" stands for "Ciphertext Stealing," which is a technique for encrypting data by using a block cipher, without padding the message to a multiple of the block size. The final result is that the cyphertext has the same size as the plain text (original text).

     

    AES is a block symmetric algorithm (once more, we should remember that symmetric means that the same key is used to encrypt and decrypt the data) with a block option of 128 bits (different from Rijndael, which offers 128-, 192-, and 256-bit options), with key options of 128, 192, and 256 bits (we are using 256 bits in our description above) and rounds (how many times the data is encrypted) of 10, 12, and 14. There are six modes of symmetric ciphers: as Electronic Code Book (ECB), Cipher Block Chaining (CBC), Cipher Feed Back (CFB), Output Feed Back (OFB), Counter (CTR), and Counter with CBC-MAC (CCM).

     

    Another key concept is that the Kerberos principal is a unique identity to which the Kerberos server can assign a ticket. Therefore, a principal can be either a user, a host (client/server), or a service.

     

    When using this flag on the service server, this flag means that service tickets will be issued only to clients with a TGT that have a prior preauthenticated ticket set. When using this flag on the clients, it means that the user should be preauthenticated to the KDC before receiving any ticket. Therefore, the server's /var/kerberos/krb5kdc/kdc.conf file should appear as shown in Listing 15. Note that the first and last lines should not be commented out, as was shown previously in Listing 14:

     

    [root@myoracle4 ~]# more /var/kerberos/krb5kdc/kdc.conf

     

    [kdcdefaults]

    kdc_ports = 88

    kdc_tcp_ports = 88

     

    [realms]

    EXAMPLE.COM = {

      master_key_type = aes256-cts

      acl_file = /var/kerberos/krb5kdc/kadm5.acl

      dict_file = /usr/share/dict/words

      admin_keytab = /var/kerberos/krb5kdc/kadm5.keytab

      supported_enctypes = aes256-cts:normal aes128-cts:normal des3-hmac-sha1:normal

    arcfour-hmac:normal camellia256-cts:normal camellia128-cts:

    normal des-hmac-sha1:normal des-cbc-md5:normal des-cbc-crc:normal

      default_principal_flags = +preauth

    }

    Listing 15

     

    Change the /etc/krb5.conf file on the server, which contains configuration information needed by the Kerberos v5 library, by uncommenting all lines that begin with # to make the configuration appropriate to our environment and according to the kdc.conf configuration in Listing 15. Thus, for an original /etc/krb5.conf file that looks like Listing 16:

     

    [root@myoracle4 ~]# more /etc/krb5.conf

     

    [logging]

    default = FILE:/var/log/krb5libs.log

    kdc = FILE:/var/log/krb5kdc.log

    admin_server = FILE:/var/log/kadmind.log

     

    [libdefaults]

    dns_lookup_realm = false

    ticket_lifetime = 24h

    renew_lifetime = 7d

    forwardable = true

    rdns = false

    # default_realm = EXAMPLE.COM

    default_ccache_name = KEYRING:persistent:%{uid}

     

    [realms]

    # EXAMPLE.COM = {

    #  kdc = kerberos.example.com

    #  admin_server = kerberos.example.com

    # }

     

    [domain_realm]

    # .example.com = EXAMPLE.COM

    # example.com = EXAMPLE.COM

    Listing 16

     

    The file should now look like Listing 17:

     

    [root@myoracle4 ~]# more /etc/krb5.conf

     

    [logging]

    default = FILE:/var/log/krb5libs.log

    kdc = FILE:/var/log/krb5kdc.log

    admin_server = FILE:/var/log/kadmind.log

     

    [libdefaults]

    dns_lookup_realm = false

    ticket_lifetime = 24h

    renew_lifetime = 7d

    forwardable = true

    rdns = false

    default_realm = EXAMPLE.COM

    # default_ccache_name = KEYRING:persistent:%{uid}

     

    [realms]

    EXAMPLE.COM = {

      kdc = myoracle4.example.com

      admin_server = myoracle4.example.com

    }

     

    [domain_realm]

    .example.com = EXAMPLE.COM

    example.com = EXAMPLE.COM

    Listing 17

     

    Before proceeding, here is an explanation of the options in the krb5.conf file shown in Listing 17:

     

    • default, kdc and admin_server attributes (under the logging section):  Specify the default log location to the Kerberos engine, KDC, and kadmind, respectively.
    • dns_lookup_realm: Indicates whether DNS TXT records should be used to determine the Kerberos realm host.
    • ticket_lifetime: Indicates the default lifetime for initial tickets.
    • forwardable: When true, indicates that initial tickets will be forwardable.
    • rdns: Controls reverse DNS resolution when translating client host names.
    • default_realm: Identifies the default realm to be used by the client host's activity.
    • default_ccache_name: Specifies the credential cache, which holds Kerberos credentials while they remain valid; this parameter tells the type of credential cache and any associated naming data to use. There are several types of supported caches such as API (usually implemented in Windows), DIR, FILE, KEYRING, MEMORY, and MSLSA.
    • kdc and admin_server attributes (under the realms section): Specifies the realm for each component, respectively.
    • [.]example.com = EXAMPLE.COM: Indicates the mapping between the DNS domain and the Kerberos realm.

     

    Confirm that the /var/kerberos/krb5kdc/kadm5.acl file on the server, which contains ACLs to manage access rights to the Kerberos server, has either the EXAMPLE.COM realm or whatever other realm you have chosen:

     

    [root@myoracle4 ~]# more /var/kerberos/krb5kdc/kadm5.acl
    */admin@EXAMPLE.COM   *

     

    Using the kdb5_util command, which allows an administrator to perform several maintenance operations (such as create, destroy, dump, and load) on the KDC database, create a Kerberos database in which to store the key from each user, as shown in Listing 18:

     

    [root@myoracle4 ~]# kdb5_util create -s -r EXAMPLE.COM

     

    Loading random data

    Initializing database '/var/kerberos/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: Otn2015$

    Re-enter KDC database master key to verify: Otn2015$

    Listing 18

     

    The create argument in Listing 18 is used to create a KDC database. The -s option is used to create a new stash to store the master's principal key, and the -r option specifies the realm for this database.

     

    The function of the kdb5_util command is important, because this master key will be used to encrypt the whole database containing all remaining keys and to prevent hackers from stealing stored users' key. Therefore, every time that the kdb5_util command is executed, it attempts to acquire the master key (which we should memorize) and open the database to access keys from users.

     

    Enable and start the Kerberos services (for reading the Kerberos' configuration files again) by executing the following commands:

     

    [root@myoracle4 ~]# systemctl enable krb5kdc

    ln -s '/usr/lib/systemd/system/krb5kdc.service' '/etc/systemd/system/multi-user.target.wants/krb5kdc.service'

     

    [root@myoracle4 ~]# systemctl enable kadmin

    ln -s '/usr/lib/systemd/system/kadmin.service' '/etc/systemd/system/multi-user.target.wants/kadmin.service'

     

    [root@myoracle4 ~]# systemctl start krb5kdc

    [root@myoracle4 ~]# systemctl start kadmin

    [root@myoracle4 ~]# systemctl status krb5kdc

    krb5kdc.service - Kerberos 5 KDC

       Loaded: loaded (/usr/lib/systemd/system/krb5kdc.service; enabled)

       Active: active (running) since Tue 2015-04-21 19:12:18 BRT; 10s ago

      Process: 14339 ExecStart=/usr/sbin/krb5kdc -P /var/run/krb5kdc.pid $KRB5KDC_ARGS (code=exited, status=0/SUCCESS)

    Main PID: 14340 (krb5kdc)

       CGroup: /system.slice/krb5kdc.service

               └─14340 /usr/sbin/krb5kdc -P /var/run/krb5kdc.pid

     

    Apr 21 19:12:18 myoracle4 systemd[1]: PID file /var/run/krb5kdc.pid not readable (yet?) after start.

    Apr 21 19:12:18 myoracle4 systemd[1]: Started Kerberos 5 KDC.

     

    Verify the status of the kadmin administration tool's daemon (kadmind), which controls the Kerberos administration server, by running the following command:

     

    [root@myoracle4 ~]# systemctl status kadmin

    kadmin.service - Kerberos 5 Password-changing and Administration

       Loaded: loaded (/usr/lib/systemd/system/kadmin.service; enabled)

       Active: active (running) since Tue 2015-04-21 19:12:22 BRT; 11s ago

      Process: 14346 ExecStart=/usr/sbin/_kadmind -P /var/run/kadmind.pid $KADMIND_ARGS (code=exited, status=0/SUCCESS)

    Main PID: 14347 (kadmind)

       CGroup: /system.slice/kadmin.service

               └─14347 /usr/sbin/kadmind -P /var/run/kadmind.pid

     

    Apr 21 19:12:22 myoracle4 systemd[1]: PID file /var/run/kadmind.pid not readable (yet?) after start.

    Apr 21 19:12:22 myoracle4 systemd[1]: Started Kerberos 5 Password-changing and Administration.

     

    Kerberos is working, so create a new user on the operating system, as shown below:

     

    [root@myoracle4 ~]# useradd -m -d /home/aborges -s /bin/bash aborges

    [root@myoracle4 ~]# passwd aborges

    Changing password for user aborges.

    New password: otn@@2015

    Retype new password: otn@@2015

    passwd: all authentication tokens updated successfully.

     

    Now, to help us test the Kerberos authentication, let's use the addprinc command to add a Kerberos principal. Therefore, create an admin user, a root user, and a regular user named aborges in Kerberos, as shown below, by using the Kerberos kadmin administration tool, which performs operations using kadmind:

     

    [root@myoracle4 ~]# kadmin.local

    Authenticating as principal root/admin@EXAMPLE.COM with password.

     

    kadmin.local:  addprinc root/admin

    WARNING: no policy specified for root/admin@EXAMPLE.COM; defaulting to no policy

    Enter password for principal "root/admin@EXAMPLE.COM": Oracle%%33

    Re-enter password for principal "root/admin@EXAMPLE.COM": Oracle%%33

    Principal "root/admin@EXAMPLE.COM" created.

     

    kadmin.local:  addprinc root

    WARNING: no policy specified for root@EXAMPLE.COM; defaulting to no policy

    Enter password for principal "root@EXAMPLE.COM": Hacker145#@

    Re-enter password for principal "root@EXAMPLE.COM": Hacker145#@

    Principal "root@EXAMPLE.COM" created.

     

    kadmin.local:  addprinc aborges

    WARNING: no policy specified for aborges@EXAMPLE.COM; defaulting to no policy

    Enter password for principal "aborges@EXAMPLE.COM": OtN9753!&

    Re-enter password for principal "aborges@EXAMPLE.COM": OtN9753!&

    Principal "aborges@EXAMPLE.COM" created.

    kadmin.local: 

     

    The next step is to add the KDC host name (myoracle4), which is also a principal, to the Kerberos database, as shown in Listing 19:

     

    kadmin.local:  addprinc -randkey host/myoracle4.example.com

    WARNING: no policy specified for host/myoracle4.example.com@EXAMPLE.COM; defaulting to no policy

    Principal "host/myoracle4.example.com@EXAMPLE.COM" created.

    kadmin.local:

    Listing 19

     

    It is relevant to mention that as the users and hosts are principals, so both can be authenticated by Kerberos.

     

    The randkey parameter in Listing 19 makes the secret key random and unknown even to us. This is a good security measure.

     

    Finally, execute the following commands to create a local copy of the previously entered information in a file called /etc/krb5.keytab (a raw data file) and quit the Kerberos administration tool:

     

    kadmin.local:  ktadd host/myoracle4.example.com

    Entry for principal host/myoracle4.example.com with kvno 2, encryption type

    aes256-cts-hmac-sha1-96 added to keytab FILE:/etc/krb5.keytab.

    Entry for principal host/myoracle4.example.com with kvno 2, encryption type

    aes128-cts-hmac-sha1-96 added to keytab FILE:/etc/krb5.keytab.

    Entry for principal host/myoracle4.example.com with kvno 2, encryption type des3-

    cbc-sha1 added to keytab FILE:/etc/krb5.keytab.

    Entry for principal host/myoracle4.example.com with kvno 2, encryption type

    arcfour-hmac added to keytab FILE:/etc/krb5.keytab.

    Entry for principal host/myoracle4.example.com with kvno 2, encryption type

    camellia256-cts-cmac added to keytab FILE:/etc/krb5.keytab.

    Entry for principal host/myoracle4.example.com with kvno 2, encryption type

    camellia128-cts-cmac added to keytab FILE:/etc/krb5.keytab.

    Entry for principal host/myoracle4.example.com with kvno 2, encryption type des-

    hmac-sha1 added to keytab FILE:/etc/krb5.keytab.

    Entry for principal host/myoracle4.example.com with kvno 2, encryption type des-

    cbc-md5 added to keytab FILE:/etc/krb5.keytab.

     

    To list the principals (host and users), execute the following:

     

    kadmin.local:  list_principals

    K/M@EXAMPLE.COM

    aborges@EXAMPLE.COM

    host/myoracle4.example.com@EXAMPLE.COM

    kadmin/admin@EXAMPLE.COM

    kadmin/changepw@EXAMPLE.COM

    kadmin/myoracle4.example.com@EXAMPLE.COM

    kiprop/myoracle4.example.com@EXAMPLE.COM

    krbtgt/EXAMPLE.COM@EXAMPLE.COM

    root/admin@EXAMPLE.COM

    root@EXAMPLE.COM

     

    If you want to change a principal's password, execute the following command:

     

    kadmin.local:  cpw aborges

    Enter password for principal "aborges@EXAMPLE.COM":

    Re-enter password for principal "aborges@EXAMPLE.COM":

    Password for "aborges@EXAMPLE.COM" changed.

     

    To quit from the kadmin.local environment, type the following:

     

    kadmin.local:  quit

     

    A smart way to list the /etc/krb5.keytab file is by running the command shown in Listing 20:

     

    [root@myoracle4 ~]# klist -k

    Keytab name: FILE:/etc/krb5.keytab

    KVNO Principal

    ---- --------------------------------------------------------------------------

       2 host/myoracle4.example.com@EXAMPLE.COM

       2 host/myoracle4.example.com@EXAMPLE.COM

       2 host/myoracle4.example.com@EXAMPLE.COM

       2 host/myoracle4.example.com@EXAMPLE.COM

       2 host/myoracle4.example.com@EXAMPLE.COM

       2 host/myoracle4.example.com@EXAMPLE.COM

       2 host/myoracle4.example.com@EXAMPLE.COM

       2 host/myoracle4.example.com@EXAMPLE.COM

    Listing 20

     

    In the output of Listing 20, we can see that only myoracle4.example.com is currently listed as a principal.

     

    Another method for examining the /etc/krb5.keytab file is by executing the following commands (quit by using CTRL+D):

     

    [root@myoracle4 ~]# ktutil

    ktutil:  rkt /etc/krb5.keytab

    ktutil:  list -e

    slot KVNO Principal

    ---- ---- ---------------------------------------------------------------------

       1    2   host/myoracle4.example.com@EXAMPLE.COM (aes256-cts-hmac-sha1-96)

       2    2   host/myoracle4.example.com@EXAMPLE.COM (aes128-cts-hmac-sha1-96)

       3    2   host/myoracle4.example.com@EXAMPLE.COM (des3-cbc-sha1)

       4    2   host/myoracle4.example.com@EXAMPLE.COM (arcfour-hmac)

       5    2   host/myoracle4.example.com@EXAMPLE.COM (camellia256-cts-cmac)

       6    2   host/myoracle4.example.com@EXAMPLE.COM (camellia128-cts-cmac)

       7    2   host/myoracle4.example.com@EXAMPLE.COM (des-hmac-sha1)

       8    2   host/myoracle4.example.com@EXAMPLE.COM (des-cbc-md5)

     

    To keep the authentication service working and accessible by the network, we need to open a few necessary Kerberos ports and other ports to support the service. First, enable the firewall if it is not enabled:

     

    [root@myoracle4 ~]# systemctl enable firewalld.service

     

    Open the following ports and their respective protocols:

     

    [root@myoracle4 ~]# firewall-cmd --permanent --zone=public --add-port={88/tcp,464/tcp,88/udp,464/udp,749/tcp,749/udp}

    success

     

    The role of each port related to Kerberos is as follows:

     

    • Port 88: Used for the Kerberos service to be able to reach its KDC.
    • Port 464: Allows password changes.
    • Port 749: Enables getting remote KDCs from other realms.

     

    Reload the firewall service to read the firewall configuration file again and then list the result:

     

    [root@myoracle4 ~]# firewall-cmd --reload

    success

     

    [root@myoracle4 ~]# firewall-cmd --list-all

    public (default, active)

      interfaces: ens33 virbr0 virbr0-nic

      sources:

      services: dhcpv6-client ssh

      ports: 443/tcp 80/tcp 464/tcp 88/udp 464/udp 88/tcp 123/udp 389/tcp 53/tcp 53/udp 636/tcp

      masquerade: no

      forward-ports:

      icmp-blocks:

      rich rules:

     

    Configuring Kerberos Clients

     

    To configure the client systems (myoracle5 and myoracle6) to use the Kerberos authentication configured previously, execute the following commands to install the required packages on each system:

     

    [root@myoracle5 ~]# yum -y install krb5-workstation pam_krb5
    [root@myoracle6 ~]# yum -y install krb5-workstation pam_krb5

     

    Before proceeding, verify the contents of the /etc/pam.d/system-auth file on the client side (myoracle5 or myoracle6), as shown below:

     

    [root@myoracle5 ~]# more /etc/pam.d/system-auth

    #%PAM-1.0

    # This file is auto-generated.

    # User changes will be destroyed the next time authconfig is run.

    auth        required      pam_env.so

    auth        sufficient    pam_fprintd.so

    auth        sufficient    pam_unix.so nullok try_first_pass

    auth        requisite     pam_succeed_if.so uid >= 1000 quiet_success

    auth        required      pam_deny.so

     

    account     required      pam_unix.so

    account     sufficient    pam_localuser.so

    account     sufficient    pam_succeed_if.so uid < 1000 quiet

    account     required      pam_permit.so

     

    password    requisite     pam_pwquality.so try_first_pass local_users_only retry=3 authtok_type=

    password    sufficient    pam_unix.so sha512 shadow nullok try_first_pass use_authtok

    password    required      pam_deny.so

     

    session     optional      pam_keyinit.so revoke

    session     required      pam_limits.so

    -session    optional      pam_systemd.so

    session     [success=1 default=ignore] pam_succeed_if.so service in crond quiet use_uid

    session     required      pam_unix.so

     

    As shown below, make a backup of all pluggable authentication module (PAM) files for restoring them later just in case you decide you don't want to use Kerberos anymore:

     

    [root@myoracle5 ~]# mkdir -p /backup/pam

    [root@myoracle5 ~]# cp /etc/pam.d/* /backup/

     

    [root@myoracle6 ~]# mkdir -p /backup/pam

    [root@myoracle6 ~]# cp /etc/pam.d/* /backup/

     

    On the client system, execute the commands shown in Listing 21 to update the PAM configuration to enable Kerberos authentication on each client system:

     

    [root@myoracle5 ~]# authconfig --enablekrb5 --update \

    --krb5kdc=myoracle4.example.com --krb5adminserver=myoracle4.example.com \

    --krb5realm=EXAMPLE.COM

     

    [root@myoracle6 ~]# authconfig --enablekrb5 --update \

    --krb5kdc=myoracle4.example.com --krb5adminserver=myoracle4.example.com \

    --krb5realm=EXAMPLE.COM

    Listing 21

     

    The authconfig command in Listing 21 makes several changes that we would need to make manually if we didn't know about this command.

     

    The /etc/pam.d/system-auth file has been modified and its contents are similar to what's shown below:

     

    [root@myoracle5 pam.d]# more /etc/pam.d/system-auth

     

    #%PAM-1.0

    # This file is auto-generated.

    # User changes will be destroyed the next time authconfig is run.

    auth        required      pam_env.so

    auth        sufficient    pam_fprintd.so

    auth        sufficient    pam_unix.so nullok try_first_pass

    auth        requisite     pam_succeed_if.so uid >= 1000 quiet_success

    auth        sufficient    pam_krb5.so use_first_pass

    auth        required      pam_deny.so

     

    account     required      pam_unix.so broken_shadow

    account     sufficient    pam_localuser.so

    account     sufficient    pam_succeed_if.so uid < 1000 quiet

    account     [default=bad success=ok user_unknown=ignore] pam_krb5.so

    account     required      pam_permit.so

     

    password    requisite     pam_pwquality.so try_first_pass local_users_only retry=3 authtok_type=

    password    sufficient    pam_unix.so sha512 shadow nullok try_first_pass use_authtok

    password    sufficient    pam_krb5.so use_authtok

    password    required      pam_deny.so

     

    session     optional      pam_keyinit.so revoke

    session     required      pam_limits.so

    -session    optional      pam_systemd.so

    session     [success=1 default=ignore] pam_succeed_if.so service in crond quiet use_uid

    session     required      pam_unix.so

    session     optional      pam_krb5.so

     

     

    Run the following commands to create the same user (aborges) that we created previously on the Kerberos server (myoracle4) and to create the user's respective password on the client systems (myoracle5 and myoracle6):

     

    [root@myoracle5 ~]# useradd -m -d /home/aborges -s /bin/bash aborges

    [root@myoracle5 ~]# passwd aborges

    New password: hacker@999

    Retype new password: hacker@999

    passwd: all authentication tokens updated successfully.

     

    [root@myoracle6 ~]# useradd -m -d /home/aborges -s /bin/bash aborges

    [root@myoracle6 ~]# passwd aborges

    Changing password for user aborges.

    New password: hacker@888

    Retype new password: hacker@888

    passwd: all authentication tokens updated successfully.

     

    To verify that the client configuration is working, execute the commands shown in Listing 22:

     

    [root@myoracle5 ~]# su - aborges

     

    [aborges@myoracle5 ~]$ kinit

    Password for aborges@EXAMPLE.COM: OtN9753!&

    Listing 22

     

    The kinit command in Listing 22 obtains and caches an initial TGT for the user.

     

    To list the session ticket, run the klist command:

     

    [aborges@myoracle5 ~]$ klist

     

    Ticket cache: FILE:/tmp/krb5cc_1002

    Default principal: aborges@EXAMPLE.COM

     

    Valid starting       Expires              Service principal

    02/03/2016 18:44:28  02/04/2016 18:44:25  krbtgt/EXAMPLE.COM@EXAMPLE.COM

     

    The same steps should be done for myoracle6, as shown below:

     

    [root@myoracle6 ~]# su - aborges

     

    [aborges@myoracle6 ~]$ kinit

    Password for aborges@EXAMPLE.COM: OtN9753!&

     

    [aborges@myoracle6 ~]$ klist

    Ticket cache: FILE:/tmp/krb5cc_1002

    Default principal: aborges@EXAMPLE.COM

     

    Valid starting       Expires              Service principal

    02/03/2016 18:49:02  02/04/2016 18:48:59  krbtgt/EXAMPLE.COM@EXAMPLE.COM

     

    Eventually, we see a strange error while executing the kinit command:

    [aborges@myoracle6 ~]$ kinit
    kinit: Invalid UID in persistent keyring name while getting default ccache

     

    If this issue comes up, comment out the cache line in the /etc/krb5.conf file on each system (myoracle4, myoracle5, and myoracle6). Thus, that line should be changed from this:

     

    [root@myoracle6 ~]# grep ccache /etc/krb5.conf 
    default_ccache_name = KEYRING:persistent:%{uid}

     

    To this:

     

    [root@myoracle6 ~]# grep ccache /etc/krb5.conf
    # default_ccache_name = KEYRING:persistent:%{uid}

     

    We should remember that when changing this setting on the Kerberos server (myoracle4), we must restart both Kerberos services by executing the following commands:

     

    [root@myoracle4 ~]# systemctl start krb5kdc
    [root@myoracle4 ~]# systemctl start kadmin

     

    Finally, if you want to invalidate the session ticket before its ticket_lifetime, execute the following commands:

     

    [aborges@myoracle5 ~]$ kdestroy

     

    [aborges@myoracle5 ~]$ klist

    klist: Credentials cache file '/tmp/krb5cc_1001' not found

     

    [aborges@myoracle6 ~]$ kdestroy

     

    [aborges@myoracle6 ~]$ klist

    klist: Credentials cache file '/tmp/krb5cc_1002' not found

     

    Examples of Applications Using Kerberos

     

    Until now, we have learned the concepts of Kerberos and how to use it. This section shows two cases where an application uses Kerberos.

     

    Implementing Kerberos Authentication for SSH: A First Example

     

    As a first test of an application using Kerberos, enable the SSH service to use Kerberos authentication by changing the SSH configuration file (/etc/ssh/sshd_config) on the Kerberos server (myoracle4), as shown in Listing 23:

     

    [root@myoracle4 ~]# more /etc/ssh/sshd_config

    ...

    # Kerberos options

    KerberosAuthentication yes

    KerberosOrLocalPasswd no

    KerberosTicketCleanup yes

    #KerberosGetAFSToken no

    KerberosUseKuserok no

    ...

    # GSSAPI options

    GSSAPIAuthentication yes

    GSSAPICleanupCredentials yes

    #GSSAPIStrictAcceptorCheck yes

    GSSAPIKeyExchange yes

    #GSSAPIEnablek5users no

    Listing 23

     

    These Kerberos options from sshd_config file shown in Listing 23 have the following meaning:

     

    • KerberosAuthentication: Determines whether the password provided by the user will be validated through the KDC.
    • KerberosOrLocalPasswd: Specifies that when Kerberos authentication fails the same password is used to authenticate against the /etc/passwd file.
    • KerberosTicketCleanup: Specifies whether the Kerberos framework automatically destroys the user's ticket cache file during the logout process.
    • KerberosGetAFSToken: Specifies that if an AFS (Andrew File System) is active, the system will attempt to acquire an AFS Token before proceeding and accessing the user's home directory.
    • KerberosUseKuserok: Specifies whether the .k5login file is checked for the user's aliases.
    • GSSAPIAuthentication: Specifies whether the user authentication based on GSSAPI is allowed.
    • GSSAPICleanupCredentials: Specifies whether the credential cache of the user is automatically destroyed on logout.
    • GSSAPIStrictAcceptorCheck: Specifies whether the client must authenticate against the host service on the current system.
    • GSSAPIKeyExchange: Specifies whether key exchange based on GSSAPI is allowed. Note that GSSAPI key exchange doesn't rely on SSH keys to verify the host identity.
    • GSSAPIEnablek5users: Specifies whether to look at the .k5users file for GSSAPI authentication access control.

     

    Then restart the SSH service on both systems:

     

    [root@myoracle4 ~]# systemctl restart sshd
    [root@myoracle5 ~]# systemctl restart sshd

     

    To confirm that the SSH configuration is working together with Kerberos, create an SSH session using the aborges user that was created previously. It's interesting to note that once we have a valid ticket, it is not necessary to enter the password again, as shown below:

     

    [root@myoracle5 ~]# su - aborges

    Last login: Wed Feb  3 18:44:19 BRST 2016 on pts/0

     

    [aborges@myoracle5 ~]$ klist

    klist: Credentials cache file '/tmp/krb5cc_1002' not found

     

    [aborges@myoracle5 ~]$ kinit

    Password for aborges@EXAMPLE.COM: OtN9753!&

     

    [aborges@myoracle5 ~]$ ssh myoracle4.example.com

    The authenticity of host 'myoracle4.example.com (192.168.1.91)' can't be established.

    ECDSA key fingerprint is 43:1a:e9:9c:4f:bf:0a:c1:0f:22:32:7e:e4:2b:f3:6c.

    Are you sure you want to continue connecting (yes/no)? yes

    Warning: Permanently added 'myoracle4.example.com,192.168.1.91' (ECDSA) to the list of known hosts.

    Last login: Wed Feb  3 18:34:58 2016

     

    [aborges@myoracle4 ~]$ uname -a

    Linux myoracle4.example.com 3.8.13-118.2.5.el7uek.x86_64 #2 SMP Tue Jan 19 15:42:26 PST 2016 x86_64 x86_64 x86_64 GNU/Linux

     

    Once we are logged on, open a new terminal on myoracle5 and run the following command to confirm that we have two tickets being cached (the TGT and another one related to the SSH service running on the myoracle4 system), as shown below:

     

    [aborges@myoracle5 ~]$ klist

    Ticket cache: FILE:/tmp/krb5cc_1002

    Default principal: aborges@EXAMPLE.COM

     

    Valid starting       Expires              Service principal

    02/03/2016 19:29:16  02/04/2016 19:29:12  krbtgt/EXAMPLE.COM@EXAMPLE.COM

    02/03/2016 19:29:19  02/04/2016 19:29:12  host/myoracle4.example.com@EXAMPLE.COM

     

    Implementing Kerberos Authentication for SSH: A Second Example

     

    In first SSH example, the SSH server was in the same system as the Kerberos server and we didn't need to perform any different configuration. Nonetheless, it is much more interesting when we configure the SSH server in another host (for example, myoracle6) and try to confirm, once more, that the SSO using Kerberos really works. Let's perform this experiment.

     

    First, we have to add the myoracle6 host to the Kerberos database and update the local copy this database (krb5.keytab file) with this new information by executing the following commands on the myoracle4 system:

     

    [root@myoracle4 ~]# kadmin.local

    Authenticating as principal root/admin@EXAMPLE.COM with password.

     

    kadmin.local:  addprinc -randkey host/myoracle6.example.com

     

    WARNING: no policy specified for host/myoracle6.example.com@EXAMPLE.COM; defaulting to no policy

    Principal "host/myoracle6.example.com@EXAMPLE.COM" created.

     

    kadmin.local:  ktadd host/myoracle6.example.com

     

    Entry for principal host/myoracle6.example.com with kvno 2, encryption type aes256-cts-hmac-sha1-96 added to keytab FILE:/etc/krb5.keytab.

    Entry for principal host/myoracle6.example.com with kvno 2, encryption type aes128-cts-hmac-sha1-96 added to keytab FILE:/etc/krb5.keytab.

    Entry for principal host/myoracle6.example.com with kvno 2, encryption type des3-cbc-sha1 added to keytab FILE:/etc/krb5.keytab.

    Entry for principal host/myoracle6.example.com with kvno 2, encryption type arcfour-hmac added to keytab FILE:/etc/krb5.keytab.

    Entry for principal host/myoracle6.example.com with kvno 2, encryption type camellia256-cts-cmac added to keytab FILE:/etc/krb5.keytab.

    Entry for principal host/myoracle6.example.com with kvno 2, encryption type camellia128-cts-cmac added to keytab FILE:/etc/krb5.keytab.

    Entry for principal host/myoracle6.example.com with kvno 2, encryption type des-hmac-sha1 added to keytab FILE:/etc/krb5.keytab.

    Entry for principal host/myoracle6.example.com with kvno 2, encryption type des-cbc-md5 added to keytab FILE:/etc/krb5.keytab.

     

    kadmin.local:  quit

     

    We can check whether those commands successfully updated the krb5.keytab file by running the following command:

     

    [root@myoracle4 ~]# klist -k

    Keytab name: FILE:/etc/krb5.keytab

    KVNO Principal

    ---- --------------------------------------------------------------------------

       2 host/myoracle4.example.com@EXAMPLE.COM

       2 host/myoracle4.example.com@EXAMPLE.COM

       2 host/myoracle4.example.com@EXAMPLE.COM

       2 host/myoracle4.example.com@EXAMPLE.COM

       2 host/myoracle4.example.com@EXAMPLE.COM

       2 host/myoracle4.example.com@EXAMPLE.COM

       2 host/myoracle4.example.com@EXAMPLE.COM

       2 host/myoracle4.example.com@EXAMPLE.COM

       2 host/myoracle6.example.com@EXAMPLE.COM

       2 host/myoracle6.example.com@EXAMPLE.COM

       2 host/myoracle6.example.com@EXAMPLE.COM

       2 host/myoracle6.example.com@EXAMPLE.COM

       2 host/myoracle6.example.com@EXAMPLE.COM

       2 host/myoracle6.example.com@EXAMPLE.COM

       2 host/myoracle6.example.com@EXAMPLE.COM

       2 host/myoracle6.example.com@EXAMPLE.COM

     

    On the client system (myoracle5), we don't need to make any change, but we should confirm that the /etc/ssh/ssh_config file has the following Kerberos options (shown in bold) enabled:

     

    [root@myoracle5 ~]# more /etc/ssh/ssh_config

    ...

    Host *

    #   ForwardAgent no

    #   ForwardX11 no

    #   RhostsRSAAuthentication no

    #   RSAAuthentication yes

    #   PasswordAuthentication yes

    #   HostbasedAuthentication no

       GSSAPIAuthentication yes

       GSSAPIDelegateCredentials yes

    #   GSSAPIKeyExchange yes

    #   GSSAPITrustDNS no

     

    The next step is to configure the SSH server on the myoracle6 host. The steps are exactly identical to the previous steps for configuring the SSH server on myoracle5, so I will not repeat them again.

     

    In the same myoracle6 host (our SSH server), we have to run the following commands to create a local krb5.keytab file containing itself as a principal:

     

    [root@myoracle6 ~]# kadmin -p root/admin

    Authenticating as principal root/admin with password.

    Password for root/admin@EXAMPLE.COM: Oracle%%33

     

    kadmin:  addprinc -randkey host/myoracle6.example.com

    WARNING: no policy specified for host/myoracle6.example.com@EXAMPLE.COM; defaulting to no policy

    add_principal: Principal or policy already exists while creating "host/myoracle6.example.com@EXAMPLE.COM".

     

    kadmin:  ktadd host/myoracle6.example.com

    Entry for principal host/myoracle6.example.com with kvno 3, encryption type aes256-cts-hmac-sha1-96 added to keytab FILE:/etc/krb5.keytab.

    Entry for principal host/myoracle6.example.com with kvno 3, encryption type aes128-cts-hmac-sha1-96 added to keytab FILE:/etc/krb5.keytab.

    Entry for principal host/myoracle6.example.com with kvno 3, encryption type des3-cbc-sha1 added to keytab FILE:/etc/krb5.keytab.

    Entry for principal host/myoracle6.example.com with kvno 3, encryption type arcfour-hmac added to keytab FILE:/etc/krb5.keytab.

    Entry for principal host/myoracle6.example.com with kvno 3, encryption type camellia256-cts-cmac added to keytab FILE:/etc/krb5.keytab.

    Entry for principal host/myoracle6.example.com with kvno 3, encryption type camellia128-cts-cmac added to keytab FILE:/etc/krb5.keytab.

    Entry for principal host/myoracle6.example.com with kvno 3, encryption type des-hmac-sha1 added to keytab FILE:/etc/krb5.keytab.

    Entry for principal host/myoracle6.example.com with kvno 3, encryption type des-cbc-md5 added to keytab FILE:/etc/krb5.keytab.

     

    kadmin:  quit

     

    Finally, on the myoracle5 system (our client), we can open a SSH connection to the SSH server (myoracle6). If the host still does not have a ticket (use the klist command to check that), get a ticket and open the SSH connection, as shown below:

     

    [root@myoracle5 ~]# su - aborges

    Last login: Wed Feb  3 22:01:45 BRST 2016 on pts/1

     

    [aborges@myoracle5 ~]$ klist

    klist: Credentials cache file '/tmp/krb5cc_1002' not found

     

    [aborges@myoracle5 ~]$ kinit

    Password for aborges@EXAMPLE.COM: OtN9753!&

     

    [aborges@myoracle5 ~]$ klist

    Ticket cache: FILE:/tmp/krb5cc_1002

    Default principal: aborges@EXAMPLE.COM

     

    Valid starting       Expires              Service principal

    02/03/2016 22:02:58  02/04/2016 22:02:54  krbtgt/EXAMPLE.COM@EXAMPLE.COM

     

    [aborges@myoracle5 ~]$ ssh aborges@myoracle6.example.com

    The authenticity of host 'myoracle6.example.com (192.168.1.93)' can't be established.

    ECDSA key fingerprint is 43:1a:e9:9c:4f:bf:0a:c1:0f:22:32:7e:e4:2b:f3:6c.

    Are you sure you want to continue connecting (yes/no)? yes

    Warning: Permanently added 'myoracle6.example.com,192.168.1.93' (ECDSA) to the list of known hosts.

    Last login: Wed Feb  3 22:01:12 2016

     

    [aborges@myoracle6 ~]$ uname -a

    Linux myoracle6.example.com 3.8.13-118.2.5.el7uek.x86_64 #2 SMP Tue Jan 19 15:42:26 PST 2016 x86_64 x86_64 x86_64 GNU/Linux

     

    It is perfect! We opened a connection to our second SSH server and we didn't enter any password. This fact proves that our SSO environment is using Kerberos. To complete this test, open a new terminal and make a new connection to our first SSH server (myoracle4), as shown below:

     

    [root@myoracle5 ~]# su - aborges

    Last login: Wed Feb  3 22:02:01 BRST 2016 on pts/1

     

    [aborges@myoracle5 ~]$ ssh aborges@myoracle4.example.com

    Last login: Wed Feb  3 19:43:37 2016 from myoracle5.example.com

     

    [aborges@myoracle4 ~]$ uname -a

    Linux myoracle4.example.com 3.8.13-118.2.5.el7uek.x86_64 #2 SMP Tue Jan 19 15:42:26 PST 2016 x86_64 x86_64 x86_64 GNU/Linux

     

    On the myoracle5 system, open a new terminal (as the aborges user) and confirm that we have three tickets now (the TGT, a ticket for the SSH service on myoracle6, and another one for the SSH service on myoracle4), as shown below:

     

    [root@myoracle5 ~]# su - aborges

    Last login: Wed Feb  3 22:10:57 BRST 2016 on pts/2

    [aborges@myoracle5 ~]$ klist

    Ticket cache: FILE:/tmp/krb5cc_1002

    Default principal: aborges@EXAMPLE.COM

     

    Valid starting       Expires              Service principal

    02/03/2016 22:02:58  02/04/2016 22:02:54  krbtgt/EXAMPLE.COM@EXAMPLE.COM

    02/03/2016 22:04:49  02/04/2016 22:02:54  host/myoracle6.example.com@EXAMPLE.COM

    02/03/2016 22:11:27  02/04/2016 22:02:54  host/myoracle4.example.com@EXAMPLE.COM

     

     

    It is interesting to check logs to try to understand what is happening. Thus, on myoracle4 (the Kerberos system), execute the command shown in Listing 24:

     

    [root@myoracle4 ~]# tail -f /var/log/krb5kdc.log

    ...

    Feb 03 21:48:38 myoracle4.example.com krb5kdc[12560](info): AS_REQ (6 etypes {18

    17 16 23 25 26}) 192.168.1.93: NEEDED_PREAUTH: root/admin@EXAMPLE.COM for

    kadmin/myoracle4.example.com@EXAMPLE.COM, Additional pre-authentication required

     

    Feb 03 21:48:40 myoracle4.example.com krb5kdc[12560](info): AS_REQ (6 etypes {18

    17 16 23 25 26}) 192.168.1.93: ISSUE: authtime 1454543320, etypes {rep=18 tkt=18

    ses=18}, root/admin@EXAMPLE.COM for kadmin/myoracle4.example.com@EXAMPLE.COM

     

    Feb 03 22:00:51 myoracle4.example.com krb5kdc[12560](info): AS_REQ (6 etypes {18

    17 16 23 25 26}) 192.168.1.93: NEEDED_PREAUTH: aborges@EXAMPLE.COM for

    krbtgt/EXAMPLE.COM@EXAMPLE.COM, Additional pre-authentication required

     

    Feb 03 22:00:57 myoracle4.example.com krb5kdc[12560](info): AS_REQ (6 etypes {18

    17 16 23 25 26}) 192.168.1.93: ISSUE: authtime 1454544057, etypes {rep=18 tkt=18

    ses=18}, aborges@EXAMPLE.COM for krbtgt/EXAMPLE.COM@EXAMPLE.COM

     

    Feb 03 22:02:54 myoracle4.example.com krb5kdc[12560](info): AS_REQ (6 etypes {18

    17 16 23 25 26}) 192.168.1.92: NEEDED_PREAUTH: aborges@EXAMPLE.COM for

    krbtgt/EXAMPLE.COM@EXAMPLE.COM, Additional pre-authentication required

     

    Feb 03 22:02:58 myoracle4.example.com krb5kdc[12560](info): AS_REQ (6 etypes {18

    17 16 23 25 26}) 192.168.1.92: ISSUE: authtime 1454544178, etypes {rep=18 tkt=18

    ses=18}, aborges@EXAMPLE.COM for krbtgt/EXAMPLE.COM@EXAMPLE.COM

     

    Feb 03 22:04:49 myoracle4.example.com krb5kdc[12560](info): TGS_REQ (6 etypes {18

    17 16 23 25 26}) 192.168.1.92: ISSUE: authtime 1454544178, etypes {rep=18 tkt=18

    ses=18}, aborges@EXAMPLE.COM for host/myoracle6.example.com@EXAMPLE.COM

     

    Feb 03 22:04:49 myoracle4.example.com krb5kdc[12560](info): TGS_REQ (1 etypes

    {18}) 192.168.1.92: ISSUE: authtime 1454544178, etypes {rep=18 tkt=18 ses=18},

    aborges@EXAMPLE.COM for krbtgt/EXAMPLE.COM@EXAMPLE.COM

     

    Feb 03 22:11:27 myoracle4.example.com krb5kdc[12560](info): TGS_REQ (6 etypes {18

    17 16 23 25 26}) 192.168.1.92: ISSUE: authtime 1454544178, etypes {rep=18 tkt=18

    ses=18}, aborges@EXAMPLE.COM for host/myoracle4.example.com@EXAMPLE.COM

     

    Feb 03 22:11:27 myoracle4.example.com krb5kdc[12560](info): TGS_REQ (1 etypes {18

    }) 192.168.1.92: ISSUE: authtime 1454544178, etypes {rep=18 tkt=18 ses=18},

    aborges@EXAMPLE.COM for krbtgt/EXAMPLE.COM@EXAMPLE.COM

    Listing 24

     

    In Listing 24, we can see all the last authentications (shown in bold).

     

    Furthermore, it is interesting to examine one of the SSH servers (for example, myoracle6) to check that the login operation has happened successfully, as shown below (in bold):

     

    [root@myoracle6 ~]# tail -f /var/log/secure

     

    Feb  3 20:59:04 myoracle6 sshd[14595]: Server listening on 0.0.0.0 port 22.

    Feb  3 20:59:04 myoracle6 sshd[14595]: Server listening on :: port 22.

    Feb  3 22:00:36 myoracle6 su: pam_unix(su-l:session): session closed for user aborges

    Feb  3 22:00:39 myoracle6 su: pam_unix(su-l:session): session opened for user aborges by root(uid=0)

    Feb  3 22:01:12 myoracle6 su: pam_unix(su-l:session): session opened for user aborges by root(uid=0)

    Feb  3 22:01:35 myoracle6 su: pam_unix(su-l:session): session closed for user aborges

    Feb  3 22:04:44 myoracle6 sshd[15391]: Authorized to aborges, krb5 principal aborges@EXAMPLE.COM (ssh_gssapi_krb5_cmdok)

    Feb  3 22:04:44 myoracle6 sshd[15391]: Accepted gssapi-with-mic for aborges from 192.168.1.92 port 44327 ssh2

    Feb  3 22:04:45 myoracle6 sshd[15391]: pam_unix(sshd:session): session opened for user aborges by (uid=0)

     

    To confirm that the authentication process is going through the Kerberos server (myoracle4), we can follow the connection by using the tcpdump tool on the Kerberos server, as shown in Listing 25:

     

    [root@myoracle4 ~]# tcpdump -i eno16777736 port 88

    tcpdump: verbose output suppressed, use -v or -vv for full protocol decode

    listening on eno16777736, link-type EN10MB (Ethernet), capture size 65535 bytes

     

    22:31:10.500524 IP myoracle5.example.com.40972 > myoracle4.example.com.kerberos:

    22:31:10.502678 IP myoracle4.example.com.kerberos > myoracle5.example.com.40972:

    ...

    Listing 25

     

    The -i option used in Listing 25 means "network interface" and port 88 is bound to the Kerberos server.

     

    During daily operations, if you need to change the Kerberos password, there are two methods to accomplish that: changing your own password using the kpasswd command or—as the Kerberos administrator—using the cpw command (as we learned previously). For example, once we've logged in as the aborges user, we can change the password, as shown below:

     

    [aborges@myoracle5 ~]$ id

    uid=1002(aborges) gid=1002(aborges) groups=1002(aborges) context=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023

     

    [aborges@myoracle5 ~]$ klist

    Ticket cache: FILE:/tmp/krb5cc_1002

    Default principal: aborges@EXAMPLE.COM

     

    Valid starting       Expires              Service principal

    02/03/2016 22:02:58  02/04/2016 22:02:54  krbtgt/EXAMPLE.COM@EXAMPLE.COM

    02/03/2016 22:04:49  02/04/2016 22:02:54  host/myoracle6.example.com@EXAMPLE.COM

    02/03/2016 22:11:27  02/04/2016 22:02:54  host/myoracle4.example.com@EXAMPLE.COM

     

    [aborges@myoracle5 ~]$ kpasswd

    Password for aborges@EXAMPLE.COM: OtN9753!&

    Enter new password: Oracle@@@1

    Enter it again: Oracle@@@1

    Password changed.

     

    Conclusion

     

    Certainly, it is unnecessary to highlight the importance of the Kerberos service as an authentication server and an additional layer of security. Kerberos offers outstanding advantages as a single sign-on (SSO) technology, and the password is not transmitted over the network during the authentication, which is an efficient way to protect against hackers.

     

    Additionally, we could learn useful concepts about encryption by understanding the Kerberos service. We used SSH as example during our demonstration, but there are several other very interesting opportunities to use Kerberos such as for identity management (IdM) and with Microsoft Active Directory. You should look around and stay tuned!

     

    See Also

     

    Here are some links to other things I've written:

     

     

    Also see:

     

     

    About the Author

     

    Alexandre Borges is a malware and security researcher. He teaches courses on malware analysis, digital forensic analysis, and reverse engineering. He is also an Oracle instructor, (ISC)2 CISSP instructor, EC-Council instructor, and he has been writing articles for the Oracle Technical Network on a regular basis since 2013. He was awarded the title of Instructor of the Year twice for his performance teaching Sun Microsystems courses.

     

    Additionally, Borges is an Oracle ACE and he has spoken at several conferences, universities, and universities about malware analysis.

     


    Note: This article represents the expertise, findings, and opinion of the author. It has been published by Oracle in this space as part of a larger effort to encourage the exchange of such information within this Community, and to promote evaluation and commentary by peers. This article has not been reviewed by the relevant Oracle product team for compliance with Oracle's standards and practices, and its publication should not be interpreted as an endorsement by Oracle of the statements expressed therein.

     

    Follow us:
    Blog | Facebook | Twitter | YouTube