Table of Contents for
SSH, The Secure Shell: The Definitive Guide, 2nd Edition

Version ebook / Retour

Cover image for bash Cookbook, 2nd Edition SSH, The Secure Shell: The Definitive Guide, 2nd Edition by Robert G. Byrnes Published by O'Reilly Media, Inc., 2005
  1. Cover
  2. SSH, the Secure Shell, 2nd Edition
  3. Preface
  4. Protect Your Network with SSH
  5. Intended Audience
  6. Reading This Book
  7. Our Approach
  8. Which Chapters Are for You?
  9. Supported Platforms
  10. Disclaimers
  11. Conventions Used in This Book
  12. Comments and Questions
  13. Safari Enabled
  14. Acknowledgments
  15. 1. Introduction to SSH
  16. What Is SSH?
  17. What SSH Is Not
  18. The SSH Protocol
  19. Overview of SSH Features
  20. History of SSH
  21. Related Technologies
  22. Summary
  23. 2. Basic Client Use
  24. A Running Example
  25. Remote Terminal Sessions with ssh
  26. Adding Complexity to the Example
  27. Authentication by Cryptographic Key
  28. The SSH Agent
  29. Connecting Without a Password or Passphrase
  30. Miscellaneous Clients
  31. Summary
  32. 3. Inside SSH
  33. Overview of Features
  34. A Cryptography Primer
  35. The Architecture of an SSH System
  36. Inside SSH-2
  37. Inside SSH-1
  38. Implementation Issues
  39. SSH and File Transfers (scp and sftp)
  40. Algorithms Used by SSH
  41. Threats SSH Can Counter
  42. Threats SSH Doesn’t Prevent
  43. Threats Caused by SSH
  44. Summary
  45. 4. Installation and Compile-Time Configuration
  46. Overview
  47. Installing OpenSSH
  48. Installing Tectia
  49. Software Inventory
  50. Replacing r-Commands with SSH
  51. Summary
  52. 5. Serverwide Configuration
  53. Running the Server
  54. Server Configuration: An Overview
  55. Getting Ready: Initial Setup
  56. Authentication: Verifying Identities
  57. Access Control: Letting People In
  58. User Logins and Accounts
  59. Forwarding
  60. Subsystems
  61. Logging and Debugging
  62. Compatibility Between SSH-1 and SSH-2 Servers
  63. Summary
  64. 6. Key Management and Agents
  65. What Is an Identity?
  66. Creating an Identity
  67. SSH Agents
  68. Multiple Identities
  69. PGP Authentication in Tectia
  70. Tectia External Keys
  71. Summary
  72. 7. Advanced Client Use
  73. How to Configure Clients
  74. Precedence
  75. Introduction to Verbose Mode
  76. Client Configuration in Depth
  77. Secure Copy with scp
  78. Secure, Interactive Copy with sftp
  79. Summary
  80. 8. Per-Account Server Configuration
  81. Limits of This Technique
  82. Public-Key-Based Configuration
  83. Hostbased Access Control
  84. The User rc File
  85. Summary
  86. 9. Port Forwarding and X Forwarding
  87. What Is Forwarding?
  88. Port Forwarding
  89. Dynamic Port Forwarding
  90. X Forwarding
  91. Forwarding Security: TCP-Wrappers and libwrap
  92. Summary
  93. 10. A Recommended Setup
  94. The Basics
  95. Compile-Time Configuration
  96. Serverwide Configuration
  97. Per-Account Configuration
  98. Key Management
  99. Client Configuration
  100. Remote Home Directories (NFS, AFS)
  101. Summary
  102. 11. Case Studies
  103. Unattended SSH: Batch or cron Jobs
  104. FTP and SSH
  105. Pine, IMAP, and SSH
  106. Connecting Through a Gateway Host
  107. Scalable Authentication for SSH
  108. Tectia Extensions to Server Configuration Files
  109. Tectia Plugins
  110. 12. Troubleshooting and FAQ
  111. Debug Messages: Your First Line of Defense
  112. Problems and Solutions
  113. Other SSH Resources
  114. 13. Overview of Other Implementations
  115. Common Features
  116. Covered Products
  117. Other SSH Products
  118. 14. OpenSSH for Windows
  119. Installation
  120. Using the SSH Clients
  121. Setting Up the SSH Server
  122. Public-Key Authentication
  123. Troubleshooting
  124. Summary
  125. 15. OpenSSH for Macintosh
  126. Using the SSH Clients
  127. Using the OpenSSH Server
  128. 16. Tectia for Windows
  129. Obtaining and Installing
  130. Basic Client Use
  131. Key Management
  132. Accession Lite
  133. Advanced Client Use
  134. Port Forwarding
  135. Connector
  136. File Transfers
  137. Command-Line Programs
  138. Troubleshooting
  139. Server
  140. 17. SecureCRT and SecureFX for Windows
  141. Obtaining and Installing
  142. Basic Client Use
  143. Key Management
  144. Advanced Client Use
  145. Forwarding
  146. Command-Line Client Programs
  147. File Transfer
  148. Troubleshooting
  149. VShell
  150. Summary
  151. 18. PuTTY for Windows
  152. Obtaining and Installing
  153. Basic Client Use
  154. File Transfer
  155. Key Management
  156. Advanced Client Use
  157. Forwarding
  158. Summary
  159. A. OpenSSH 4.0 New Features
  160. Server Features: sshd
  161. Client Features: ssh, scp, and sftp
  162. ssh-keygen
  163. B. Tectia Manpage for sshregex
  164. Regex Syntax: Egrep Patterns
  165. Regex Syntax: ZSH_FILEGLOB (or Traditional) Patterns
  166. Character Sets for Egrep and ZSH_FILEGLOB
  167. Regex Syntax: SSH Patterns
  168. Authors
  169. See Also
  170. C. Tectia Module Names for Debugging
  171. D. SSH-1 Features of OpenSSH and Tectia
  172. OpenSSH Features
  173. Tectia Features
  174. E. SSH Quick Reference
  175. Legend
  176. sshd Options
  177. sshd Keywords
  178. ssh Options
  179. scp Options
  180. ssh and scp Keywords
  181. ssh-keygen Options
  182. ssh-agent Options
  183. ssh-add Options
  184. Identity and Authorization Files, OpenSSH
  185. Identity and Authorization Files, Tectia
  186. Environment Variables
  187. Index
  188. Index
  189. Index
  190. Index
  191. Index
  192. Index
  193. Index
  194. Index
  195. Index
  196. Index
  197. Index
  198. Index
  199. Index
  200. Index
  201. Index
  202. Index
  203. Index
  204. Index
  205. Index
  206. Index
  207. Index
  208. Index
  209. Index
  210. Index
  211. Index
  212. Index
  213. About the Authors
  214. Colophon
  215. Copyright

Scalable Authentication for SSH

One of the main strengths of SSH is easy setup. Install an SSH server on one host and a client on another, and you immediately have secure login via password. Generate a key pair and put the public key on the server, and you immediately have even better authentication, and single-signon. This lightweight approach is one of the main reasons for the initial popularity of SSH.

No solution fits all situations, however, and this simplicity becomes a liability as the number of users and hosts grows. In large installations, managing both server and user authentication becomes difficult. Every time you add an SSH server host, or change its name, or add an alias for it, you must update the global known-hosts list. This by itself may be a practically impossible task, because there are no standards for representing these lists. OpenSSH uses one format, Tectia another; some Windows-based clients keep them in a file, some in the registry. Even if you had a means to generate lists for all your SSH clients in their various native formats, many of the actual client machines may be unreachable for updates (remote machines, laptops, etc.).

At all too many companies, the difficulty of managing SSH server keys leads to a very lax approach to server verification. Users frequently see warning messages about missing or changed keys, and the IT staff tells them to “just accept the new key.” Very soon, these messages are completely ignored by everyone—or worse, just made to go away entirely! We’ve actually encountered an SSH installation with this configuration:

    # /etc/ssh/ssh_config
    GlobalKnownHostsFile   /dev/null
    UserKnownHostsFile     /dev/null
    StrictHostKeyChecking  no

Scary, but understandable; SSH had cried wolf one too many times. Unfortunately, effectively skipping server authentication disables a vital part of SSH security: resistance to server host spoofing and man-in-the-middle attacks! This situation also makes it impractical to replace server keys periodically, as should be done, or to revoke a key in case it is known to be compromised (i.e., tell clients to no longer trust it).

All these remarks apply to the usual modes of SSH public-key user authentication, as well. Authorizing a user for login means modifying an authorization list on every host to which the user requires access, adding his key. Revoking that access means tracking all those files down—including files he may have modified himself, perhaps to allow access to accounts other than his own, that you know nothing about. Changing keys may be essentially impossible; after a while, the user himself may have no idea where that key has gotten to! Eventually, a compromised key is almost sure to work on some machine where it’s lying forgotten in a dusty authorized_keys file (or ~/.ssh2/authorization file, or registry key, or ...).

Now, none of these issues is new or unique to SSH. The problem of large-scale, centralized authentication and authorization (AA) has been studied for a long time, and standard solutions exist. Fortunately, besides simplicity, another strength of SSH is flexibility. The common devices that we’re complaining about are not implied by the SSH protocol; they’re just widespread implementations. The protocol says nothing about how a server key should be verified or a user key authorized for access, and SSH software is free to use more sophisticated methods. Moreover, the protocol is extensible so that new elements such as key types or authentication exchanges can be defined as needed in order to support such methods.

Of course, flexibility doesn’t help much if there are no such “sophisticated methods” actually available. For years, there weren’t—but recently, maturing SSH products have incorporated support for scalable AA. We will discuss two here: X.509 public-key infrastructure (PKI) with Tectia, and Kerberos with OpenSSH.

A word before we start: both Kerberos and X.509 PKI are substantial topics on their own, and we can’t do more than scratch the surface of them here. We’ll give just a brief (incomplete!) sketch of each system, present a simple working configuration, and make some comments about other features to look at. Beyond that, you’ll need to read up on these systems yourself in order to delve into their use.

11.5.1 Tectia with X.509 Certificates

11.5.1.1 What’s a PKI?

“X.509 PKI”—a forbidding term; it sounds like part of a warp engine that needs calibration, right after you reinitialize the field coils. Let’s break it down: PKI stands for Public Key Infrastructure, and refers to a system for dealing in scalable fashion with the trust issues raised by deploying asymmetric (public-key) cryptography, including:

  • Binding public keys to identities: users, hosts, routers, etc.--these are the principals in the system

  • Indicating or controlling the use of keys (encryption, signing, email, web/SSL, etc.)

  • Replacing keys

  • Renewing or revoking previously made bindings

  • Securely communicating all these properties

Although the term sounds generic, in practice it has come to refer specifically to hierarchical systems in which so-called Certifying Authorities (CAs) vouch for the identity of principals and certify ownership of cryptographic keys. CAs can themselves be vouched for by higher CAs, arranged in a tree of trust. This reduces the trust problem to distributing the keys of a small number of well-known authorities, avoiding the combinatorial explosion of dealing individually with every pair of principals who might need to communicate securely.

X.509 is the name of a standards document of the International Telecommunications Union (ITU, formerly the CCITT). Its original intent was to describe an authentication system for another ITU standard: X.500 directories (the title is “Recommendation X.509: The Directory Authentication Framework”). However, in the process it specified a format for digital certificates: data structures which embody the key/principal binding we mentioned, and that portion of X.509 has become widely used in PKI systems.

X.509-style PKIs also use a great many other standards. To get an idea of the scope of the subject, just take a look at the home page of the IETF PKIX working group, at:

It’s a daunting list...but we’ll just sum up the essentials here. The most important components of a certificate are:

  • Issuer name

  • Subject name

  • Public key

  • Validity dates

  • Signature

The signature is a cryptographic function of the entire certificate data structure, and is made by the issuer using its private key (which does not appear here). The meaning of the certificate is: “the issuer vouches that the subject owns the private counterpart to this public key (but this affidavit is only good between the given validity dates).”

Now in reality, certificates can be much more complex, containing many more attributes. Also, the interpretation may be different: “owns” might mean “is authorized to use,” or “has access to sign with but does not actually know,” etc. And there are many unanswered questions here, such as how carefully did the issuer check the subject’s identity? But we’ll leave all that alone and concentrate on the basics.

The issuer and subject name are expressed as Distinguished Names (DNs), as defined by X.509. These are attribute/value sets, represented in text like this:

    /C=US/ST=New York/O=Mad Writer Enterprises/CN=Richard E. Silverman 
/emailAddress=res@oreilly.com

The attribute abbreviations here are Country, STate, Organization, and Common Name (and there are more).

Now, let’s see how all this helps with SSH host key verification.

11.5.1.2 Using certificates with Tectia host keys

When an SSH client connects to a server, it needs to verify that the server’s host key actually belongs to the host it intended to contact. The usual way is to compare it to a local list of already known keys, but that has many drawbacks, as we pointed out earlier. Instead of managing an unwieldy, changing set of host keys, with PKI each client needs only one public key: that of a CA shared by all hosts in the system. Each time you deploy a new Tectia host, you generate a new hostkey as usual—but you also obtain a certificate, binding the host’s name to its public key. That certificate is signed by the CA, and every client has the CA’s public key. During the key-exchange phase of the SSH protocol, the client receives the certificate along with the server’s hostkey; there are key types x509v3-sign-rsa and x509v3-sign-dss for this purpose instead of the usual ssh-rsa and ssh-dss. Instead of looking up the hostkey in a list, the Tectia client:

  1. Compares the subject name in the certificate to the server hostname and verifies that they match

  2. Verifies the server’s signature on the key-exchange transaction, proving it actually holds the corresponding private key

  3. Verifies the issuer signature on the certificate using the CA’s public key, to be sure it’s genuine (i.e., that the certificate was actually issued by the trusted CA)

If the key passes all these tests, then the client considers the key valid, and server authentication succeeds. You’ll notice this doesn’t completely remove the need for key distribution: the clients do still need to get the CA key in a trusted manner. But it’s much easier to distribute or update a single key that changes very infrequently, than to manage a constantly changing known-hosts list!

Now we’ll get down to specifics with a simple example.

11.5.1.3 A simple configuration

For our example, we’ll start with a new instance of Tectia Server installed on a Linux host; first, we need to generate a hostkey with a certificate. This is not something we can describe very comprehensively, because it relies on outside factors: what actual PKI system is in use. You might be using anything from a home-brew CA using the free OpenSSL software that comes with most Unix variants these days, to a managed PKI service outsourced to a major security vendor, involving multiple layers of hierarchy, cross-certification among organizations, separate Registration Authorities, private-key escrow, etc.

If the PKI in question uses the Certificate Management Protocols (CMP, RFC-2510), then you can use ssh-cmpclient to communicate with the PKI system: generate keys; request, receive, revoke, or update certificates; etc. You should consult your PKI vendor or managing staff as to how to proceed in this case. To keep our example simple, we’ll follow an older but still widely used process: generating a keypair and certificate request using OpenSSL, which we then supply to the CA by some simple method (email and the Web are the usual ways).

11.5.1.4 Getting a certificate

Suppose our company is Vogon Construction, Inc., and the server hostname is jeltz.vcon.com. To generate a key pair and certificate request:

    % openssl req -nodes -config -new rsa:1024 -out request.pem \
      -outform pem -keyout private.pem -days 1095 \
      -subj '/C=US/ST=New York/L=Manhattan/O=Vogon Construction, Inc./CN=jeltz.vcon.com'

This generates a new 1024-bit RSA key pair and produces two files:

private.pem

The unencrypted private key

request.pem

An X.509 certificate request

The request.pem file contains the public key and asks to bind the hostname jeltz.vcon.com to that key for a period of three years (1095 days). The DN contains other information besides the hostname, and typically the CA will require set values for some of that, e.g., that the Organization field match that of the CA.

Next, send the request to the CA, and engage in whatever authentication procedures it requires: call Bob in IT, verify receipt of an email at your given address, swear an oath and sign in blood—whatever it takes. When the CA is satisfied, it will return to you a certificate, which you save in a file, certificate.blob. If it is an ASCII file looking like this:

    -----BEGIN CERTIFICATE-----
    MIIDbzCCAtigAwIBAgIDA9GvMA0GCSqGSIb3DQEBBQUAME4xCzAJBgNVBAYTAlVT
    MRAwDgYDVQQKEwdFcXVpZmF4MS0wKwYDVQQLEyRFcXVpZmF4IFNlY3VyZSBDZXJ0
    ...
    VdrJ1Z4HLT7PL+nEuvRJcpyw+A==
    -----END CERTIFICATE-----

then it is in a format called PEM; if it’s not, then it’s in another format called DER.

The two files, private.pem and certificate.blob, contain the host private key and our desired certificate; you can delete request.pem. Now, we need to convert these to Tectia’s format for host keys, in a two-step process. First:

    % openssl pkcs12 -export -out jeltz.p12 -in certificate.blob -inform {pem|der}  
-inkey private.pem

Choose “pem” or “der” depending on the format of the certificate. This stores the combined public key, private key, and certificate in a single file using yet another format, PKCS-12. You will be prompted for a passphrase to protect the file. This is a good format in which to store the keypair and certificate in case you need to rebuild the host and restore the key, so keep that file. Next:

    $ ssh-keygen -k jeltz.p12 -p ''

This will, of course, prompt you for the passphrase (twice, in fact), and finally produce the two files we want:

jeltz.p12-1_ssh2.crt

Certificate in DER format

jeltz.p12_ssh2

Unencrypted private key in SECSH format used by Tectia [6.1.2]

Now, to get Tectia sshd to use them.

11.5.1.5 Hostkey verification: configuring the server

Install the new key and certificate in the Tectia configuration directory:

    # install -o root -m 444 jeltz.p12-1_ssh2.crt /etc/ssh2/jeltz.crt
    # install -o root -m 444 jeltz.p12_ssh2 /etc/ssh2/jeltz

and add this to sshd2_config:

    HostCertificateFile jeltz.crt
    HostKeyFile jeltz

If you want to continue offering the existing plain ssh-dss host key as well as the new certificate, you may need to add or uncomment the following:

    PublicHostKeyFile hostkey.pub
    HostKeyFile hostkey

These are the defaults if no hostkey is specified, but once you add the HostCertificateFile, the defaults will not apply. For our example, though, we suggest you turn or leave off all other hostkeys so that successful server authentication by the client depends on this one key working.

Lastly, restart Tectia Server:

    # service sshd2 restart

and try to connect with ssh:

    % ssh jeltz.vcon.com
    warning: Received host certificate is not valid, error:
    search-state = { certificate-was-not-found database-method-search-failed } warning:
    Authentication failed.  Disconnected (local); key exchange or algorithm negotiation failed
    (Key exchange failed.).

This error message shows that we succeeded: the client received a certificate along with the host key. A debug trace will show more specifically that the host-key type has changed:

    % ssh -d4 jeltz.vcon.com
    ...
    debug: Ssh2Client/sshclient.c:244/ssh_client_key_check: Got key of type x509v3-sign-rsa
    debug: Ssh2Client/sshclient.c:286/ssh_client_key_check: Checking certificate validity
    ...

Now, we just need to arrange for the client to be able to verify the certificate.

11.5.1.6 Hostkey verification: configuring the Client

For this, we need the CA’s public key, itself in the form of a certificate. This should be readily available from your CA; after all, the CA isn’t much use unless everyone has it. Get it in DER format; if they provide it in PEM, convert it thus:

    $ openssl x509 -inform pem -outform der -in <certificate file> -out cacert.der

Now install the CA certificate:

    # install -o root -m 444 cacert.der /etc/ssh2

configure ssh to use it:

    # /etc/ssh2/ssh2_config
    # Note 
that this 
path must be absolute, unlike in the server config, since otherwise it is relative
    # to the user's ~/.ssh2 directory.
    HostCANoCRLs /etc/ssh2/cacert.der

...and try!

    # Tectia
    $ ssh -v jeltz.vcon.com
    ...
    debug: 
Ssh2Client/sshclient.c:984/keycheck_cert_cb: 
Host certificate valid and signed by a trusted CA, accepting
    ...

If all has gone according to plan, this works, using whatever user authentication method you have available; the debug message shown indicates that the certificate validation succeeded.

11.5.1.7 User authentication: configuring the client

We have just set up server authentication using a server-supplied certificate. In fact, the converse is possible as well: Tectia Server can authenticate users by certificate as well. As before, we need a new keypair and certificate, this time for a DN matching a user. We follow the same procedure we used earlier [11.5.1.4], but with the following subject name:

    /C=US/ST=New York/L=Manhattan/O=Vogon Construction, Inc./CN=Prostetnic V. Jeltz/ 
subjectAltName=email:pvj@vcon.com

Warning

It is critical to include a subjectAltName of type email as shown—even if the user has no email address at all, in fact, and you have to make one up. It is a very confusing and thoroughly undocumented fact that Tectia Server requires the presence of this attribute for user certificates, even if it’s not used. Otherwise, Tectia mysteriously rejects the certificate with no reason. It cost us several hours of bewilderment, culminating in an intense threesome with gdb and the Tectia source, to uncover this fact.

In a related bit of confusion, there’s a bug in OpenSSL whereby this attribute will not be automatically copied into the certificate request, like everything else next to it. You must edit the OpenSSL configuration file (often in /usr/share/ssl/openssl.cnf), and add or uncomment the following:

    [ usr_cert ]

Once you have your private key and user certificate, place them in ~/.ssh2, say:

~/.ssh2/pvj.crt

Certificate

~/.ssh2/pvj

Private key

and configure ssh to use this key:

    # ~/.ssh2/identification
    CertKey pvj

We know it won’t work, since we haven’t configured the server yet—but as a test:

    % ssh -l pvj jeltz -o AllowedAuthentications=publickey
    warning: Authentication failed.
    Disconnected (local); no more authentication methods available (No 
further authentication methods available.).

We set ssh to try only public-key authentication since that’s what we want to test; this way it doesn’t end up asking for a password. The interesting message will be in the server log, typically /var/log/secure:

    sshd2: Authorization check for user pvj's certificate rejected, reason: No 
certificate authorization configured.

And now finally, we tell the server how to authorize users based on their certificates.

11.5.1.8 User authentication: configuring the server

With the old method, there was an implicit correspondence between an account and a public key authorized to log into it: the key sat in a special file in the account’s home directory. With PKI, there is only the certificate, so we need a rule whereby Tectia can determine whether a particular certificate grants access to the requested account. In fact, Tectia allows great flexibility in expressing such rules. First, add this to the server configuration:

    # /etc/ssh2/sshd2_config
    PKI cacert.der
    PKIDisableCrls yes
    MapFile cert.users

This tells Tectia Server to trust user certificates signed by our CA, and to use the rules in /etc/ssh2/cert.users to authorize access to accounts. The rule language is described in the manpage for ssh_certd_config, section “MAPPING FILES.” We’ll give a few examples here:

    # allow a certificate issued to Prostetnic V. Jeltz in our company, access to account pvj
    #
    pvj subject C=US,ST=New York,L=Manhattan,O=Vogon Construction, Inc.,CN=Prostetnic V. Jeltz

    # allow any certificate issued to Prostetnic V. Jeltz, whether by our organization or not
    #
    pvj subject CN=Prostetnic V. Jeltz

    # allow certificate serial number 17 issued by our CA
    #
    pvj SerialAndIssuer 17 C=US,ST=New York,L=Manhattan,O=Vogon Construction, Inc.

    # allow any certificate issued by us to access account "shared"
    #
    shared Issuer C=US,ST=New York,L=Manhattan,O=Vogon Construction, Inc.

    # allow certificate with email address pvj@vcon.com
    #
    pvj email pvj@vcon.com

    # pattern rule: allow certificate with email address <foo>@vcon.com to access account <foo>
    #
    %subst% EmailRegex ([a-z]+)@vcon\.com

You would think we’d now restart sshd to have these changes take effect, but in fact Tectia has a separate daemon responsible for certificate validation: ssh-certd. So:

    # service ssh-certd restart

Now, try logging in again:

    % ssh -l pvj jeltz -o AllowedAuthentications=publickey

If all has gone well, it will work, with the following telltale message in syslog:

    sshd2: Certificate authentication for user pvj accepted.

You can have multiple PKI blocks in the server configuration, directing trust of various CAs and each with its own account mapping.

We have presented the simplest possible view of PKI; it may be much more complicated. You might interact with something called a Registration Authority for obtaining your certificate, for example, rather than directly with the CA. Verifying a certificate might involve following a chain of certificates and signatures back to a trusted “root” certificate, rather than just one—or there might be multiple trust paths, if cross-certification is available, etc.

11.5.2 OpenSSH and Tectia with Kerberos

Kerberos is an authentication system that addresses the same set of problems as PKI: providing a scalable system for mutual authentication and secure communication. Kerberos simply uses a different basic model and set of technologies. It was originally developed as part of Project Athena, a wide-ranging research and development effort carried out at MIT between 1983 and 1991, funded primarily by IBM and Digital Equipment Corporation. Project Athena contributed many other pieces of technology to the computing world, including the well-known X Window System. There is now an IETF Kerberos working group:

which coordinates work on and standardization of the current version of the Kerberos protocol, Kerberos-5.

There are two main distinctions between Kerberos and PKI:

  • Kerberos is based on symmetric encryption rather than public-key techniques.

  • Kerberos is an active third-party system.

Both the Kerberos and PKI models have trusted third parties: in PKI it is the CA, and in Kerberos it is a service called the Key Distribution Center (KDC). Both are trusted in the sense that principals depend on them to correctly identify other users, and not to reveal certain cryptographic secrets. However, Kerberos requires the real-time, online participation of the KDC when two principals wish to communicate. This is in contrast to PKI: once two principals have obtained certificates from the CA, they may communicate at any time by speaking only to each other; the CA is not involved. It may be necessary to contact the CA for related services, such as checking for certificate revocation or obtaining issuance policies—but it is not required for the basic mutual authentication procedure.

This added availability requirement would seem to be a liability over PKI—but as usual, it’s all about trade-offs. In exchange, Kerberos offers a much simpler administration and user experience, as well as some different security properties. For instance, with Kerberos, users’ long-term secrets are never stored outside the KDC, whereas in PKI each user has the secret component of his keypair, which must be stored and protected.

11.5.2.1 How Kerberos works

Since it is based on symmetric cryptography, Kerberos is perforce a shared-secret system. The basic unit of Kerberos administration is called a realm, which consists of a set of principals and single KDC database they trust. When a principal joins a Kerberos realm, it shares a secret key with the KDC; the KDC database essentially consists of a list of principals and their keys. For user principals, the key is derived from a password. Principals may also correspond to software services, such as an SSH server, IMAP server, etc.; their keys are randomly generated and stored in protected files where the services can access them. A principal name looks like 1/2/3/.../ n @REALM. There can be any (positive) number of initial parts as shown, but in practice there are usually either one or two. A plain-user principal name would be res@REALM. A user principal name for particular uses, such as a privileged administrative instance, might be res/admin@REALM. And a principal representing a service—say, an IMAP server on host mail.foo.org--would have the name imap/mail.foo.org@REALM.

When principal A wants to communicate with another—say, B—principal A first tells the KDC that it wants to talk to B. Principal A needs to do two things: prove its identity to B, and establish a shared secret with B for secure communication, called a session key. The KDC provides these things in a message called a ticket, which it sends back to A. The ticket is sealed with A’s secret key, known only to the KDC and A—hence A trusts that it is genuine, and it is protected from network snooping. Unsealing the ticket, A finds the needed session key—and yet another ticket! This one, however, is sealed with B’s secret key (known only to the KDC and B). A can’t read this at all, but that doesn’t matter; all A needs to do is send this ticket as-is to B. When B unseals its ticket, it finds A’s name and another copy of the session key. Just as before, since B’s ticket is sealed with B’s key, B trusts that the ticket is genuine. The meaning of each ticket is that the KDC has shared the session key with A and B. The two principals then execute a protocol which proves to each that the other does in fact hold that key—at which point, mutual authentication is accomplished. Further, the session key can be used for subsequent security functions, such as encrypting a conversation between them.

Now, this explanation is very basic.[152] It doesn’t exactly describe the Kerberos protocol, but rather, a simpler one. However, it gives the essential flavor of how the third-party shared-secret model works. The real Kerberos-5 protocol can be viewed as an elaboration on this basic idea, to address various possible attacks and provide more features. We won’t get any more detailed than we already have, except to list a few of the real-life differences:

  • Our model requires the user to type his password for every Kerberos transaction. Real Kerberos instead involves first issuing to a user a special ticket, called a ticket-granting ticket (TGT). Subsequent tickets for other principals involve presenting the TGT back to the KDC, proving that the requestor has been recently authenticated. TGTs (and indeed all tickets) expire after a period of time, typically 10 hours. So, the user need only type his password infrequently, and it need not be locally stored. The TGT must be stored, but it is of limited value (and can’t be used to change the user’s password).

  • The ticket expiration feature involves timestamps, which in turn require that all principals have synchronized clocks. Some skew is allowed (typically up to five minutes), but Kerberos will not function properly if hosts’ clocks drift too far from one another.

11.5.2.2 Kerberos support in SSH

Kerberos support for SSH is not defined directly; rather, there is a draft that extends SSH to use GSSAPI, as documented in “Generic Security Services/Application Programming Interface (RFC-2743).”

GSS is a sort of security meta-protocol, with a role and implementation structure similar to that of PAM or SASL. GSS allows two communicating peers to negotiate security parameters abstractly, in terms of types of protection and relative strength rather than particular protocols, ciphers, or algorithms. The GSS layers on either side will pick the strongest compatible mechanisms available to each which meet their clients’ needs, without the higher-level software needing to bother with the details. Typical GSS implementations allow adding new mechanisms in the form of system dynamic libraries, which then automatically become available to GSS clients without recompilation.

In particular, there is a GSS mechanism supporting Kerberos-5, documented in “The Kerberos Version 5 GSS-API Mechanism (RFC 1964).”

Of course, this is a bit convoluted; why not simply support Kerberos directly as its own SSH protocol extension? This was in fact done in SSH-1. The answer is that GSS is becoming a widely used standard. By defining a method for using GSS in SSH, implementers can take advantage of existing GSSAPI software libraries. And in doing so, SSH can automatically use new GSS security mechanisms as they become available, without further standards work. For example, Tectia Windows Server provides both Kerberos and NTLM user authentication via GSSAPI. The relevant SSH protocol draft is “GSSAPI Authentication and Key Exchange for the Secure Shell Protocol” (draft-ietf-secsh-gsskeyex).

Just a few years ago, this whole area was a work in progress, with only patches and experimental implementations. Now, however, it has solidified and is present in several mainstream SSH products and platforms, including OpenSSH, OS X, and Tectia on both Windows and Unix. This matches the widening adoption of Kerberos in general. And amazingly...for the most part, they all interoperate! It is now possible to have strong authentication and single-signon among various OS/SSH combinations, using Kerberos.

Note that while it has been possible for a while to get something similar using SSH public-key authentication with ssh-agent, Kerberos is a win for two different reasons. The issue of central management and scalability for larger organizations, we’ve already discussed. The other important point is that public-key authentication is SSH-specific. You go to all the trouble to teach people about generating keys, using agents, enabling agent forwarding, etc.; and after all that work, you get a solution that works only for SSH. Suppose you log into a domain account on a Windows machine, then SSH to another one. Public-key authentication may let you log in, but you’ll have to type your password again at some point to gain access to resources such as network shares—your Windows domain credentials did not follow you over SSH. With Kerberos, however, the same credentials which allowed login can also be forwarded to the remote host and used there for other purposes. And since Kerberos is a standard, the same can be true connecting from a Windows to a Unix host. This provides a much more pervasive and useful single-signon system.

11.5.2.3 Kerberos interoperability with OpenSSH and Tectia

As an example, we will take a lone Debian GNU/Linux box, attached to a network of Windows machines in an Active Directory domain named AD.ORG. The Linux box, lonely.ad.org, is running Debian-unstable and has the following packages installed; krb5-user, krb5-doc, and ssh-krb5 (which as of this writing is based on OpenSSH 3.8.1). The Windows machines are running the Tectia Windows Server, Version 4.2 or later. Suppose you have an account, “joe,” in the Windows domain, you’re logged into the Debian machine, and you want to connect to the Windows server, “winnie,” You simply type:

    lonely% kinit -f joe@AD.ORG

Amazingly, this prompts for your Windows password, and (assuming you type it in correctly)--it works! No errors, no complaints, no “DANGER! WARNING! WINDOWS INCOMPATIBILITY DETECTED!” Disbelievingly, you type:

    lonely% klist
    Ticket cache: FILE:/tmp/krb5cc_11500

    Default principal: joe@AD.ORG

    Valid starting     Expires            Service principal
    01/30/05 02:28:35  01/30/05 10:28:41  krbtgt/AD.ORG@AD.ORG
            renew until 01/30/05 03:28:35

You have just received Kerberos credentials from a Windows Domain Controller—say, “dc1.” No local configuration was necessary, because kinit found the domain controller via the DNS, using records like this:

    $ORIGIN ad.org
    _kerberos               TXT      "AD.ORG"
    _kerberos._udp          SRV      0 0 88  dc1
    _kerberos-master._udp   SRV      0 0 88  dc1
    _kpasswd._udp           SRV      0 0 464 dc1
    _kerberos-adm._tcp      SRV      0 0 749 dc1
    _kerberos-iv._udp       SRV      0 0 750 dc1

These tell a DNS client that machines with names under ad.org belong to the AD.ORG Kerberos realm, and that a Kerberos KDC is available on dc1.ad.org via UDP to port 88 (among other Kerberos services: some of these records might be absent or unnecessary in your DNS). The Windows DNS servers for the domain will publish such records automatically. If you have an alternate or more complicated configuration—say, using non-Windows nameservers—then you may have to add these records yourself (or you could resort to local configuration; see the manpage for krb5.conf).

Trembling with technological anticipation, you forge onward:

    lonely% ssh winnie
    The authenticity of host 'winnie (10.2.17.4)' can't be established.
    DSA key fingerprint is b6:b2:09:81:f4:c7:96:43:4a:0c:cc:12:9d:61:54:1f.
    Are you sure you want to continue connecting (yes/no)?

Remember that SSH server authentication happens first, before user authentication; this shows that we’re still using the usual SSH key-based server authentication (assuming you don’t already have winnie’s key in your known-hosts list). That’s disappointing, but we’ll talk about that later. Assuming you say yes and continue, though...

    Warning: Permanently added 'winnie,10.2.17.4' (DSA) to the list of known hosts.
    Microsoft Windows XP [Version 5.1.2600]
    (C) Copyright 1985-2001 Microsoft Corp.

    C:\Documents and Settings\joe>

You have been logged into the Windows machine! Furthermore, you’ll find that you have Windows domain credentials there; you could, for example, map a network share (via the net use command) that requires the joe identity to access—without retyping your password. Repeating the ssh command with -v will show the details:

    lonely% ssh -v winnie
    OpenSSH_3.8.1p1  Debian-krb5 3.8.1p1-7, OpenSSL 0.9.7e 25 Oct 2004
    debug1: Reading configuration data /etc/ssh/ssh_config

    debug1: Connecting to winnie [10.2.17.4] port 22.
    debug1: Connection established.
    ...
    debug1: 
 Remote protocol version 2.0, remote software version 4.2.0.21 SSH 
Secure Shell Windows NT Server
    debug1: no match: 4.2.0.21 SSH 
Secure Shell Windows NT Server
    debug1: Enabling compatibility mode for protocol 2.0
    debug1: Local version string SSH-2.0-OpenSSH_3.8.1p1  Debian-krb5 3.8.1p1-7
    ...
    debug1: Authentications that can continue: gssapi-with-mic,gssapi,publickey,password
    debug1: Next authentication method: gssapi-with-mic
    debug1: Authentication succeeded (gssapi-with-mic).

The user authentication method chosen is gssapi-with-mic, an improvement which fixes a security flaw in the earlier method named simply gssapi. A subsequent klist on the client side shows the new Kerberos ticket acquired for the connection:

    lonely% klist
    Ticket cache: FILE:/tmp/krb5cc_11500
    Default principal: joe@AD.ORG

    Valid starting     Expires            Service principal
    01/30/05 02:28:35  01/30/05 10:28:41  krbtgt/AD.ORG@AD.ORG
            renew until 01/30/05 03:28:35
    01/30/05 02:45:00  01/30/05 03:45:00  host/winnie.ad.org@AD.ORG
            renew until 01/30/05 03:28:35

Now, of course, there are many possible combinations of client, server, and Kerberos systems, and some of them will require more work. For example, going the other way in this scenario (Windows to Linux) would mean joining the Debian box to the Windows Kerberos realm. You could do this using Resource Kit utilities to add its host principal, , to the domain controller; extract a Unix-compatible keytab file from it; and copy it to /etc/krb5.keytab on the Linux machine. Or, you might solve the problem a different way by placing the non-Windows hosts in a separate realm, perhaps with Linux-based KDCs, and establishing inter-realm trust between them. These issues are more specific to Kerberos administration than to SSH proper, and are beyond our scope here.

Before leaving this case study, let’s discuss some final details of SSH configuration, server authentication, and network address translation (NAT).

SSH configuration. The Debian ssh-krb5 package is built with Kerberos authentication turned on by default; that’s not normally true. In other situations you would have to set some configuration options:

    # ~/.ssh/config
    GSSAPIAuthentication       yes
    GSSAPIDelegateCredentials  yes

You might not want to delegate credentials automatically for all connections, though, just as you might not set X forwarding on by default: it could give access to an attacker if the remote host has been compromised.

Server authentication. The secsh-keyex draft defines Kerberos server authentication as well, in the form of new SSH-TRANS key exchange methods using GSSAPI. This part of the draft is not as widely implemented as user authentication, however; for example, the Debian and OS X versions of OpenSSH support it, whereas the main OpenSSH and Tectia do not. Its use is controlled with the GSSAPIKeyExchange server keyword. To see that the client supports it, look in the -v trace for lines like this:

    debug1: Mechanism encoded as toWM5Slw5Ew8Mqkay+al2g==
    debug1: Mechanism encoded as A/vxljAEU54gt9a48EiANQ==

The “mechanisms” here are GSSAPI mechanisms, and these messages occur during the key-exchange phase.

Kerberos server authentication, when available, has several advantages:

It relieves you of managing known-hosts lists

The client doesn’t consult these files at all; instead, it relies on Kerberos to validate the server’s identity. In fact, depending on the server implementation, you may be able to dispense with even generating host keys at all; the draft defines a “null” host key type for just this situation, where none is required. Of course, this would keep non-Kerberized clients from connecting at all, so you might want to keep host keys anyway for compatibility’s sake.

It automatically deals with host aliases

With known-host lists, every possible name a host might be called must be listed with that host’s key in the file. Kerberos, though, uses the server’s canonical name from the DNS, obtained by mapping the given name to an address and then mapping that address back to a name. As long as you maintain your hosts’ canonical names properly and use them for corresponding Kerberos service principals, aliases will be handled automatically.

Note that this does entail some security trade-off: an attacker who can subvert the DNS can cause an SSH client to authenticate the server against the wrong name. Of course, the server it contacts must still actually validate against Kerberos with this name, so it can’t be just any machine—but it might have credentials from a host the attacker previously compromised. This level of risk may be acceptable, but should be considered. This isn’t really a Kerberos-specific problem; the same feature could be used with hostkey authentication, with the same usability/security trade-off.

It’s much faster

Since Kerberos uses symmetric cryptography, it is noticeably faster than public-key methods. If both server and user authentication happen via Kerberos, new SSH connections can be very fast. In fact, the Kerberos exchange that affects server authentication does client authentication as well, and some implementations support a userauth method named external-keyx that takes advantage of this fact. external-keyx says to the server, “Look back at the key exchange—you’ll find it already authenticated me, so please let me in!”

There are some limitations, though. One is name uniqueness: hosts must have unique names known beforehand in order to be joined to the Kerberos realm. This shows up most immediately with the “localhost” problem: ssh localhost doesn’t usually work with Kerberos server authentication, even when it works for connecting to the same machine using its hostname. This is because the name “localhost” means a different host on every machine—so there can’t be an entry in the Kerberos database for “localhost,” because it can only have one key. You can make it work by arranging /etc/hosts files so that on each host, 127.0.0.1 maps back to that host’s canonical name—but the way that hosts files work, this means the name must also forward-map to the loopback address, not the host’s “real” address. This has some advantages, actually, but is likely to break some things also; it may not be worth it.

The problem can also show up with more complicated network situations such as proxies, tunnels, or clusters of machines with dynamically assigned and shared addresses—anything in which the simple server/hostname/address correspondence Kerberos needs is violated. Furthermore, it won’t work for batch jobs if those don’t also use Kerberos for authentication, which is often not the best choice. The bottom line is that while Kerberos server authentication can be useful, hostkey-based authentication usually needs to be available as well for exceptional situations.

Network address translation (NAT). Kerberos originally bound credentials to the address of the machine to which they were issued, to make attacks harder: if someone managed to steal a ticket, it would be harder to (mis)use it. However, in today’s sad world of ubiquitous NAT, this can cause more trouble than it’s worth. Most recent Kerberos deployments have this address-matching feature turned off, but you may need to do it yourself if not, e.g., with a statement like:

    # /etc/krb5.conf
    [libdefaults]
    noaddresses = true

This actually controls whether clients include addresses in ticket requests, so when you change it you will need to run kinit again. Situations involving multiple credential-forwarding connections may have addresses creep back in anyway, due to forwarding code which requests them anyway even if the original ticket had none; again, most recent Kerberos code has eliminated this problem, but you may still see it.



[152] And in fact, in some ways an outright lie.