]> git.apps.os.sepia.ceph.com Git - ceph-ci.git/commitdiff
auth: Kerberos authentication
authoroliveiradan <doliveirabrz@gmail.com>
Thu, 22 Nov 2018 00:10:33 +0000 (17:10 -0700)
committerDaniel Oliveira <doliveira@suse.com>
Tue, 4 Dec 2018 01:55:46 +0000 (18:55 -0700)
Signed-off-by: Daniel Oliveira <doliveira@suse.com> (github: oliveiradan)
39 files changed:
CMakeLists.txt
alpine/APKBUILD.in
ceph.spec.in
cmake/modules/FindGSSApi.cmake [new file with mode: 0644]
debian/control
doc/dev/ceph_krb_auth.rst [new file with mode: 0644]
src/CMakeLists.txt
src/auth/AuthAuthorizeHandler.cc
src/auth/AuthClientHandler.cc
src/auth/AuthMethodList.cc
src/auth/AuthServiceHandler.cc
src/auth/AuthSessionHandler.cc
src/auth/CMakeLists.txt
src/auth/krb/KrbAuthorizeHandler.cpp [new file with mode: 0644]
src/auth/krb/KrbAuthorizeHandler.hpp [new file with mode: 0644]
src/auth/krb/KrbClientHandler.cpp [new file with mode: 0644]
src/auth/krb/KrbClientHandler.hpp [new file with mode: 0644]
src/auth/krb/KrbProtocol.cpp [new file with mode: 0644]
src/auth/krb/KrbProtocol.hpp [new file with mode: 0644]
src/auth/krb/KrbServiceHandler.cpp [new file with mode: 0644]
src/auth/krb/KrbServiceHandler.hpp [new file with mode: 0644]
src/auth/krb/KrbSessionHandler.hpp [new file with mode: 0644]
src/common/options.cc
src/include/ceph_fs.h
src/librados/CMakeLists.txt
src/librbd/CMakeLists.txt
src/mds/MDSDaemon.cc
src/mds/MDSDaemon.h
src/mgr/CMakeLists.txt
src/mon/CMakeLists.txt
src/mon/MonClient.h
src/mon/Monitor.cc
src/mon/Monitor.h
src/osd/OSD.cc
src/osd/OSD.h
src/test/CMakeLists.txt
src/test/librados/CMakeLists.txt
src/test/msgr/test_msgr.cc
src/vstart.sh

index 710bc14a5881e29dee2b8c53de2bd9409a9e271c..34a7aa3821057b0f305c10cd5bc35f2303f9394f 100644 (file)
@@ -232,6 +232,12 @@ if(WITH_OPENLDAP)
   set(HAVE_OPENLDAP ${OPENLDAP_FOUND})
 endif()
 
+option(WITH_GSSAPI "GSSAPI/KRB5 is here" ON)
+if(WITH_GSSAPI)
+  find_package(GSSApi REQUIRED)
+  set(HAVE_GSSAPI ${GSSApi_FOUND})
+endif()
+
 option(WITH_FUSE "Fuse is here" ON)
 if(WITH_FUSE)
   find_package(fuse)
index 64908a3beedd78f98c73292da8b8489d95f1211b..7ddb5de452144f6ca29576af3ad1ce34e41ee50e 100644 (file)
@@ -47,6 +47,7 @@ makedepends="
        lvm2-dev
        nss-dev
        openldap-dev
+       krb5-dev
        parted
        procps
        python-dev
index 3ab90a1f7c75c293cb13dab96ea8660a2ed300aa..f5eb7bc59b5a315ee50915f5b7ab28060210c379 100644 (file)
@@ -221,6 +221,8 @@ BuildRequires:      keyutils-devel
 BuildRequires:  libopenssl-devel
 BuildRequires:  lsb-release
 BuildRequires:  openldap2-devel
+BuildRequires:  krb5
+BuildRequires:  krb5-devel
 BuildRequires:  cunit-devel
 BuildRequires: python%{_python_buildid}-base
 BuildRequires: python%{_python_buildid}-Cython
@@ -238,6 +240,7 @@ BuildRequires:      keyutils-libs-devel
 BuildRequires: libibverbs-devel
 BuildRequires:  librdmacm-devel
 BuildRequires:  openldap-devel
+BuildRequires:  krb5-devel
 BuildRequires:  openssl-devel
 BuildRequires:  CUnit-devel
 BuildRequires:  redhat-lsb-core
diff --git a/cmake/modules/FindGSSApi.cmake b/cmake/modules/FindGSSApi.cmake
new file mode 100644 (file)
index 0000000..0377180
--- /dev/null
@@ -0,0 +1,22 @@
+# - Find KRB5/GSSAPI C Libraries
+#
+# GSSAPI_FOUND - True if found.
+# GSSAPI_INCLUDE_DIR - Path to the KRB5/gssapi include directory
+# GSSAPI_LIBRARIES - Paths to the KRB5/gssapi libraries
+
+find_path(GSSAPI_INCLUDE_DIR gssapi.h PATHS
+  /usr/include
+  /opt/local/include
+  /usr/local/include)
+
+find_library(GSSAPI_KRB5_LIBRARY gssapi_krb5)
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(GSSApi DEFAULT_MSG
+       GSSAPI_INCLUDE_DIR GSSAPI_KRB5_LIBRARY)
+
+set(GSSAPI_LIBRARIES ${GSSAPI_KRB5_LIBRARY})
+
+mark_as_advanced(
+       GSSAPI_INCLUDE_DIR GSSAPI_KRB5_LIBRARY)
+
index 677c8f907ee755e5d9885e8240ecee50315fa59c..48ce3528cd854b333fb9c76d7b5c7f2e2e5ce011 100644 (file)
@@ -37,6 +37,7 @@ Build-Depends: bc,
                librdmacm-dev,
                libkeyutils-dev,
                libldap2-dev,
+               libkrb5-dev,
                libleveldb-dev,
                liblttng-ust-dev,
                liblz4-dev (>= 0.0~r131),
diff --git a/doc/dev/ceph_krb_auth.rst b/doc/dev/ceph_krb_auth.rst
new file mode 100644 (file)
index 0000000..dc3c739
--- /dev/null
@@ -0,0 +1,1094 @@
+===============================================================================
+A Detailed Documentation on How to Set up Ceph Kerberos Authentication
+===============================================================================
+
+This document provides details on the Kerberos authorization protocol. This is
+the 1st draft and we will try to keep it updated along with code changes that
+might take place.
+
+Several free implementations of this protocol are available (MIT, Heimdal,
+MS...), covering a wide range of operating systems. The Massachusetts
+Institute of Technology (MIT), where Kerberos was originally developed,
+continues to develop their Kerberos package and it is the implementation we
+chose to work with. `MIT Kerberos <http://web.mit.edu/Kerberos/>`_.
+
+Please, provide feedback to Daniel Oliveira (doliveira@suse.com)
+
+*Last update: Dec 3, 2018*
+
+|
+
+Background
+----------
+
+Before we get into *Kerberos details*, let us define a few terms so we can
+understand what to expect from it, *what it can and can't do*:
+
+Directory Services
+    A directory service is a customizable information store that functions as
+    a single point from which users can locate resources and services
+    distributed throughout the network. This customizable information store
+    also gives administrators a single point for managing its objects and their
+    attributes. Although this information store appears as a single point to
+    the users of the network, it is actually most often stored in a distributed
+    form. A directory service consists of at least one *Directory Server and a
+    Directory Client* and are implemented based on *X.500 standards*.
+
+    *OpenLDAP, 389 Directory Server, MS Active Directory, NetIQ eDirectory* are
+    some good examples.
+
+    A directory service is often characterized as a *write-once-read-many-times
+    service*, meaning the data that would normally be stored in an directory
+    service would not be expected to change on every access.
+
+    The database that forms a directory service *is not designed for
+    transactional data*.
+
+|
+
+LDAP (Lightweight Directory Access Protocol v3)
+    LDAP is a set of LDAP Protocol Exchanges *(not an implementation of a
+    server)* that defines the method by which data is accessed. LDAPv3 is a
+    standard defined by the IETF in RFC 2251 and describes how data is
+    represented in the Directory Service (the Data Model or DIT).
+
+    Finally, it defines how data is loaded into (imported) and saved from
+    (exported) a directory service (using LDIF). LDAP does not define how data
+    is stored or manipulated. Data Store is an 'automagic' process as far as
+    the standard is concerned and is generally handled by back-end modules.
+
+    No Directory Service implementation has all the features of LDAP v3
+    protocol implemented. All Directory Server implementations have their
+    different problems and/or anomalies, and features that may not return
+    results as another Directory Server implementation would.
+
+|
+
+Authentication
+    Authentication is about validating credentials (like User Name/ID and
+    password) to verify the identity. The system determines whether one is what
+    they say they are using their credentials.
+
+    Usually, authentication is done by a username and password, and sometimes
+    in conjunction with *(single, two, or multi) factors of authentication*,
+    which refers to the various ways to be authenticated.
+
+|
+
+Authorization
+    Authorization occurs after the identity is successfully authenticated by
+    the system, which ultimately gives one full permission to access the
+    resources such as information, files, databases, and so forth, almost
+    anything. It determines the ability to access the system and up to what
+    extent (what kind of permissions/rights are given and to where/what).
+
+|
+
+Auditing
+    Auditing takes the results from both *authentication and authorization* and
+    records them into an audit log. The audit log records records all actions
+    taking by/during the authentication and authorization for later review by
+    the administrators. While authentication and authorization are preventive
+    systems (in which unauthorized access is prevented), auditing is a reactive
+    system (in which it gives detailed log of how/when/where someone accessed
+    the environment).
+
+|
+
+Kerberos (KRB v5)
+    Kerberos is a network *authentication protocol*. It is designed to provide
+    strong authentication for client/server applications by using secret-key
+    cryptography (symmetric key). A free implementation of this protocol is
+    available from the MIT. However, Kerberos is available in many commercial
+    products as well.
+
+    It was designed to provide secure authentication to services over an
+    insecure network. Kerberos uses tickets to authenticate a user, or service
+    application and never transmits passwords over the network in the clear.
+    So both client and server can prove their identity without sending any
+    unencrypted secrets over the network.
+
+    Kerberos can be used for single sign-on (SSO). The idea behind SSO is
+    simple, we want to login just once and be able to use any service that we
+    are entitled to, without having to login on each of those services.
+
+|
+
+Simple Authentication and Security Layer (SASL)
+    SASL **(RFC 4422)** is a framework that helps developers to implement
+    different authentication mechanisms (implementing a series of challenges
+    and responses), allowing both clients and servers to negotiate a mutually
+    acceptable mechanism for each connection, instead of hard-coding them.
+
+    Examples of SASL mechanisms:
+
+        * ANONYMOUS **(RFC 4505)**
+
+            - For guest access, meaning *unauthenticated*
+
+        * CRAM-MD5 **(RFC 2195)**
+
+            - Simple challenge-response scheme based on *HMAC-MD5*.
+              It does not establish any security layer. *Less secure than
+              DIGEST-MD5 and GSSAPI.*
+
+        * DIGEST-MD5 **(RFC 2831)**
+
+            - HTTP Digest compatible *(partially)* challenge-response scheme
+              based upon MD5, offering a *data security layer*. It is preferred
+              over PLAIN text passwords, protecting against plain text attacks.
+              It is a mandatory authentication method for LDAPv3 servers.
+
+        * EXTERNAL **(RFCs 4422, 5246, 4301, 2119)**
+
+            - Where *authentication is implicit* in the context (i.e; for
+              protocols using IPsec or TLS [TLS/SSL to performing certificate-
+              based authentication] already). This method uses public keys for
+              strong authentication.
+
+        * GS2 **(RFC 5801)**
+
+            - Family of mechanisms supports arbitrary GSS-API mechanisms in
+              SASL
+
+        * NTLM (MS Proprietary)
+
+            - MS Windows NT LAN Manager authentication mechanism
+
+        * OAuth 1.0/2.0 **(RFCs 5849, 6749, 7628)**
+
+            - Authentication protocol for delegated resource access
+
+        * OTP **(RFC 2444)**
+
+            - One-time password mechanism *(obsoletes the SKEY mechanism)*
+
+        * PLAIN **(RFC 4616)**
+
+            - Simple Cleartext password mechanism **(RFC 4616)**. This is not a
+              preferred mechanism for most applications because of its relative
+              lack of strength.
+
+        * SCRAM **(RFCs 5802, 7677)**
+
+            - Modern challenge-response scheme based mechanism with channel
+              binding support
+
+|
+
+Generic Security Services Application Program Interface (GSSAPI)
+    GSSAPI **(RFCs 2078, 2743, 2744, 4121, 4752)** is widely used by protocol
+    implementers as a way to implement Kerberos v5 support in their
+    applications. It provides a generic interface and message format that can
+    encapsulate authentication exchanges from any authentication method that
+    has a GSSAPI-compliant library.
+
+    It does not define a protocol, authentication, or security mechanism
+    itself; it instead makes it easier for application programmers to support
+    multiple authentication mechanisms by providing a uniform, generic API for
+    security services. It is a set of functions that include both an API and a
+    methodology for approaching authentication, aiming to insulate application
+    protocols from the specifics of security protocols as much as possible.
+
+    *Microsoft Windows Kerberos* implementation does not include GSSAPI support
+    but instead includes a *Microsoft-specific API*, the *Security Support
+    Provider Interface (SSPI)*. In Windows, an SSPI client can communicate with
+    a *GSSAPI server*.
+
+    *Most applications that support GSSAPI also support Kerberos v5.*
+
+|
+
+Simple and Protected GSSAPI Negotiation Mechanism (SPNEGO)
+    As we can see, GSSAPI solves the problem of providing a single API to
+    different authentication mechanisms. However, it does not solve the problem
+    of negotiating which mechanism to use. In fact for GSSAPI to work, the two
+    applications communicating with each other must know in advance what
+    authentication mechanism they plan to use, which usually is not a problem
+    if only one mechanism is supported (meaning Kerberos v5).
+
+    However, if there are multiple mechanisms to choose from, a method is
+    needed to securely negotiate an authentication mechanism that is mutually
+    supported between both client and server; which is where
+    *SPNEGO (RFC 2478, 4178)* makes a difference.
+
+    *SPNEGO* provides a framework for two parties that are engaged in
+    authentication to select from a set of possible authentication mechanisms,
+    in a manner that preserves the opaque nature of the security protocols to
+    the application protocol that uses it.
+
+    It is a security protocol that uses a *GSSAPI authentication mechanism* and
+    negotiates among several available authentication mechanisms in an
+    implementation, selecting one for use to satisfy the authentication needs
+    of the application protocol.
+
+    It is a *meta protocol* that travels entirely in other application
+    protocols; it is never used directly without an application protocol.
+
+|
+
+*Why is this important and why do we care? Like, at all?*
+
+    Having this background information in mind, we can easily describe things
+    like:
+
+        1. *Ceph Kerberos authentication* is based totally on MIT *Kerberos*
+        implementation using *GSSAPI*.
+
+        2. At the moment we are still using *Kerberos default backend
+        database*, however we plan on adding LDAP as a backend which would
+        provide us with *authentication with GSSAPI (KRB5)* and *authorization
+        with LDAP (LDAPv3)*, via *SASL mechanism*.
+
+|
+
+Before We Start
+---------------
+
+We assume the environment already has some external services up and running
+properly:
+
+    * Kerberos needs to be properly configured, which also means (for both
+      every server and KDC):
+
+        - Time Synchronization (either using `NTP <http://www.ntp.org/>`_  or `chrony <https://chrony.tuxfamily.org/>`_).
+
+            + Not only Kerberos, but also Ceph depends and relies on time
+              synchronization.
+
+        - DNS resolution
+
+            + Both *(forward and reverse)* zones, with *fully qualified domain
+              name (fqdn)* ``(hostname + domain.name)``
+
+            + KDC discover can be set up to to use DNS ``(srv resources)`` as
+              service location protocol *(RFCs 2052, 2782)*, as well as *host
+              or domain* to the *appropriate realm* ``(txt record)``.
+
+            + Even though these DNS entries/settings are not required to run a
+              ``Kerberos realm``, they certainly help to eliminate the need for
+              manual configuration on all clients.
+
+            + This is extremely important, once most of the Kerberos issues are
+              usually related to name resolution. Kerberos is very picky when
+              checking on systems names and host lookups.
+
+    * Whenever possible, in order to avoid a *single point of failure*, set up
+      a *backup, secondary, or slave*, for every piece/part in the
+      infrastructure ``(ntp, dns, and kdc servers)``.
+
+
+Also, the following *Kerberos terminology* is important:
+
+    * Ticket
+
+        - Tickets or Credentials, are a set of information that can be used to
+          verify the client's identity. Kerberos tickets may be stored in a
+          file, or they may exist only in memory.
+
+        - The first ticket obtained is a ticket-granting ticket (TGT), which
+          allows the clients to obtain additional tickets. These additional
+          tickets give the client permission for specific services. The
+          requesting and granting of these additional tickets happens
+          transparently.
+
+            + The TGT, which expires at a specified time, permits the client to
+              obtain additional tickets, which give permission for specific
+              services. The requesting and granting of these additional tickets
+              is user-transparent.
+
+    * Key Distribution Center (KDC).
+
+        - The KDC creates a ticket-granting ticket (TGT) for the client,
+          encrypts it using the client's password as the key, and sends the
+          encrypted TGT back to the client. The client then attempts to decrypt
+          the TGT, using its password. If the client successfully decrypts the
+          TGT (i.e., if the client gave the correct password), it keeps the
+          decrypted TGT, which indicates proof of the client's identity.
+
+        -  The KDC is comprised of three components:
+
+            + Kerberos database, which stores all the information about the
+              principals and the realm they belong to, among other things.
+            + Authentication service (AS)
+            + Ticket-granting service (TGS)
+
+    * Client
+
+        - Either a *user, host or a service* who sends a request for a ticket.
+
+    * Principal
+
+        - It is a unique identity to which Kerberos can assign tickets.
+          Principals can have an arbitrary number of components. Each component
+          is separated by a component separator, generally ``/``. The last
+          component is the *realm*, separated from the rest of the principal by
+          the realm separator, generally ``@``.
+
+        - If there is no realm component in the principal, then it will be
+          assumed that the principal is in the default realm for the context in
+          which it is being used.
+
+        - Usually, a principal is divided into three parts:
+
+            + The ``primary``, the ``instance``, and the ``realm``
+
+            + The format of a typical Kerberos V5 principal is
+              ``primary/instance@REALM``.
+
+            + The ``primary`` is the first part of the principal. In the case
+              of a user, it's the same as the ``username``. For a host, the
+              primary is the word ``host``. For Ceph, will use ``ceph`` as a
+              primary name which makes it easier to organize and identify Ceph
+              related principals.
+
+            + The ``instance`` is an optional string that qualifies the
+              primary. The instance is separated from the primary by a slash
+              ``/``. In the case of a user, the instance is usually ``null``,
+              but a user might also have an additional principal, with an
+              instance called ``admin``, which one uses to administrate a
+              database.
+
+              The principal ``johndoe@MYDOMAIN.COM`` is completely separate
+              from the principal ``johndoe/admin@MYDOMAIN.COM``, with a
+              separate password, and separate permissions. In the case of a
+              host, the instance is the fully qualified hostname,
+              i.e., ``osd1.MYDOMAIN.COM``.
+
+            + The ``realm`` is the Kerberos realm. Usually, the Kerberos realm
+              is the domain name, in *upper-case letters*. For example, the
+              machine ``osd1.MYDOMAIN.COM`` would be in the realm
+              ``MYDOMAIN.COM``.
+
+    * Keytab
+
+        - A keytab file stores the actual encryption key that can be used in
+          lieu of a password challenge for a given principal. Creating keytab
+          files are useful for noninteractive principals, such as *Service
+          Principal Names*, which are often associated with long-running
+          processes like Ceph daemons. A keytab file does not have to be a
+          "1:1 mapping" to a single principal. Multiple different principal
+          keys can be stored in a single keytab file:
+
+            + The keytab file allows a user/service to authenticate without
+              knowledge of the password. Due to this, *keytabs should be
+              protected* with appropriate controls to prevent unauthorized
+              users from authenticating with it.
+
+            + The default client keytab file is ``/etc/krb5.keytab``
+
+|
+
+The 'Ceph side' of the things
+------------------------------
+
+In order to configure connections (from Ceph nodes) to the KDC:
+
+1. Login to the Kerberos client (Ceph server nodes) and confirm it is properly
+   configured, by checking and editing ``/etc/krb5.conf`` file properly:  ::
+
+    /etc/krb5.conf
+    [libdefaults]
+        dns_canonicalize_hostname = false
+        rdns = false
+        forwardable = true
+        dns_lookup_realm = true
+        dns_lookup_kdc = true
+        allow_weak_crypto = false
+        default_realm = MYDOMAIN.COM
+        default_ccache_name = KEYRING:persistent:%{uid}
+    [realms]
+        MYDOMAIN.COM = {
+            kdc = kerberos.mydomain.com
+            admin_server = kerberos.mydomain.com
+            ...
+        }
+    ...
+
+
+2. Login to the *KDC Server* and confirm it is properly configured to
+   authenticate to the Kerberos realm in question:
+
+    a. Kerberos related DNS RRs:  ::
+
+        /var/lib/named/master/mydomain.com
+        kerberos                IN A        192.168.10.21
+        kerberos-slave          IN A        192.168.10.22
+        _kerberos               IN TXT      "MYDOMAIN.COM"
+        _kerberos._udp          IN SRV      1 0 88 kerberos
+        _kerberos._tcp          IN SRV      1 0 88 kerberos
+        _kerberos._udp          IN SRV      20 0 88 kerberos-slave
+        _kerberos-master._udp   IN SRV      0 0 88 kerberos
+        _kerberos-adm._tcp      IN SRV      0 0 749 kerberos
+        _kpasswd._udp           IN SRV      0 0 464 kerberos
+        ...
+
+
+    b. KDC configuration file:  ::
+
+        /var/lib/kerberos/krb5kdc/kdc.conf
+        [kdcdefaults]
+                kdc_ports = 750,88
+        [realms]
+                MYDOMAIN.COM = {
+                    acl_file = /var/lib/kerberos/krb5kdc/kadm5.acl
+                    admin_keytab = FILE:/var/lib/kerberos/krb5kdc/kadm5.keytab
+                    default_principal_flags = +postdateable +forwardable +renewable +proxiable
+                                                            +dup-skey -preauth -hwauth +service
+                                                            +tgt-based +allow-tickets -pwchange
+                                                            -pwservice
+                    dict_file = /var/lib/kerberos/krb5kdc/kadm5.dict
+                    key_stash_file = /var/lib/kerberos/krb5kdc/.k5.MYDOMAIN.COM
+                    kdc_ports = 750,88
+                    max_life = 0d 10h 0m 0s
+                    max_renewable_life = 7d 0h 0m 0s
+                }
+        ...
+
+
+3. Still on the KDC Server, run the Kerberos administration utility;
+   ``kadmin.local`` so we can list all the principals already created.  ::
+
+    kadmin.local:  listprincs
+    K/M@MYDOMAIN.COM
+    krbtgt/MYDOMAIN.COM@MYDOMAIN.COM
+    kadmin/admin@MYDOMAIN.COM
+    kadmin/changepw@MYDOMAIN.COM
+    kadmin/history@MYDOMAIN.COM
+    kadmin/kerberos.mydomain.com@MYDOMAIN.COM
+    root/admin@MYDOMAIN.COM
+    ...
+
+
+4. Add a *principal for each Ceph cluster node* we want to be authenticated by
+   Kerberos:
+
+    a. Adding principals:  ::
+
+        kadmin.local:  addprinc -randkey ceph/ceph-mon1
+        Principal "ceph/ceph-mon1@MYDOMAIN.COM" created.
+        kadmin.local:  addprinc -randkey ceph/ceph-osd1
+        Principal "ceph/ceph-osd1@MYDOMAIN.COM" created.
+        kadmin.local:  addprinc -randkey ceph/ceph-osd2
+        Principal "ceph/ceph-osd2@MYDOMAIN.COM" created.
+        kadmin.local:  addprinc -randkey ceph/ceph-osd3
+        Principal "ceph/ceph-osd3@MYDOMAIN.COM" created.
+        kadmin.local:  addprinc -randkey ceph/ceph-osd4
+        Principal "ceph/ceph-osd4@MYDOMAIN.COM" created.
+        kadmin.local:  listprincs
+        K/M@MYDOMAIN.COM
+        krbtgt/MYDOMAIN.COM@MYDOMAIN.COM
+        kadmin/admin@MYDOMAIN.COM
+        kadmin/changepw@MYDOMAIN.COM
+        kadmin/history@MYDOMAIN.COM
+        kadmin/kerberos.mydomain.com@MYDOMAIN.COM
+        root/admin@MYDOMAIN.COM
+        ceph/ceph-mon1@MYDOMAIN.COM
+        ceph/ceph-osd1@MYDOMAIN.COM
+        ceph/ceph-osd2@MYDOMAIN.COM
+        ceph/ceph-osd3@MYDOMAIN.COM
+        ceph/ceph-osd4@MYDOMAIN.COM
+        ...
+
+
+    b. This follows the same idea if we are creating a *user principal*  ::
+
+        kadmin.local:  addprinc johndoe
+        WARNING: no policy specified for johndoe@MYDOMAIN.COM; defaulting to no policy
+        Enter password for principal "johndoe@MYDOMAIN.COM":
+        Re-enter password for principal "johndoe@MYDOMAIN.COM":
+        Principal "johndoe@MYDOMAIN.COM" created.
+        ...
+
+
+5. Create a *keytab file* for each Ceph cluster node:
+
+    As the default client keytab file is ``/etc/krb5.keytab``, we will want to
+    use a different file name, so we especify which *keytab file to create* and
+    which *principal to export keys* from:  ::
+
+        kadmin.local:  ktadd -k /etc/gss_client_mon1.ktab ceph/ceph-mon1
+        Entry for principal ceph/ceph-mon1 with kvno 2, encryption type aes256-cts-hmac-sha1-96 added to keytab WRFILE:/etc/gss_client_mon1.ktab.
+        Entry for principal ceph/ceph-mon1 with kvno 2, encryption type aes128-cts-hmac-sha1-96 added to keytab WRFILE:/etc/gss_client_mon1.ktab.
+        Entry for principal ceph/ceph-mon1 with kvno 2, encryption type des3-cbc-sha1 added to keytab WRFILE:/etc/gss_client_mon1.ktab.
+        Entry for principal ceph/ceph-mon1 with kvno 2, encryption type arcfour-hmac added to keytab WRFILE:/etc/gss_client_mon1.ktab.
+        kadmin.local:  ktadd -k /etc/gss_client_osd1.ktab ceph/ceph-osd1
+        Entry for principal ceph/ceph-osd1 with kvno 2, encryption type aes256-cts-hmac-sha1-96 added to keytab WRFILE:/etc/gss_client_osd1.ktab.
+        Entry for principal ceph/ceph-osd1 with kvno 2, encryption type aes128-cts-hmac-sha1-96 added to keytab WRFILE:/etc/gss_client_osd1.ktab.
+        Entry for principal ceph/ceph-osd1 with kvno 2, encryption type des3-cbc-sha1 added to keytab WRFILE:/etc/gss_client_osd1.ktab.
+        Entry for principal ceph/ceph-osd1 with kvno 2, encryption type arcfour-hmac added to keytab WRFILE:/etc/gss_client_osd1.ktab.
+        kadmin.local:  ktadd -k /etc/gss_client_osd2.ktab ceph/ceph-osd2
+        Entry for principal ceph/ceph-osd2 with kvno 2, encryption type aes256-cts-hmac-sha1-96 added to keytab WRFILE:/etc/gss_client_osd2.ktab.
+        Entry for principal ceph/ceph-osd2 with kvno 2, encryption type aes128-cts-hmac-sha1-96 added to keytab WRFILE:/etc/gss_client_osd2.ktab.
+        Entry for principal ceph/ceph-osd2 with kvno 2, encryption type des3-cbc-sha1 added to keytab WRFILE:/etc/gss_client_osd2.ktab.
+        Entry for principal ceph/ceph-osd2 with kvno 2, encryption type arcfour-hmac added to keytab WRFILE:/etc/gss_client_osd2.ktab.
+        kadmin.local:  ktadd -k /etc/gss_client_osd3.ktab ceph/ceph-osd3
+        Entry for principal ceph/ceph-osd3 with kvno 3, encryption type aes256-cts-hmac-sha1-96 added to keytab WRFILE:/etc/gss_client_osd3.ktab.
+        Entry for principal ceph/ceph-osd3 with kvno 3, encryption type aes128-cts-hmac-sha1-96 added to keytab WRFILE:/etc/gss_client_osd3.ktab.
+        Entry for principal ceph/ceph-osd3 with kvno 3, encryption type des3-cbc-sha1 added to keytab WRFILE:/etc/gss_client_osd3.ktab.
+        Entry for principal ceph/ceph-osd3 with kvno 3, encryption type arcfour-hmac added to keytab WRFILE:/etc/gss_client_osd3.ktab.
+        kadmin.local:  ktadd -k /etc/gss_client_osd4.ktab ceph/ceph-osd4
+        Entry for principal ceph/ceph-osd4 with kvno 4, encryption type aes256-cts-hmac-sha1-96 added to keytab WRFILE:/etc/gss_client_osd4.ktab.
+        Entry for principal ceph/ceph-osd4 with kvno 4, encryption type aes128-cts-hmac-sha1-96 added to keytab WRFILE:/etc/gss_client_osd4.ktab.
+        Entry for principal ceph/ceph-osd4 with kvno 4, encryption type des3-cbc-sha1 added to keytab WRFILE:/etc/gss_client_osd4.ktab.
+        Entry for principal ceph/ceph-osd4 with kvno 4, encryption type arcfour-hmac added to keytab WRFILE:/etc/gss_client_osd4.ktab.
+
+        # ls -1 /etc/gss_client_*
+        /etc/gss_client_mon1.ktab
+        /etc/gss_client_osd1.ktab
+        /etc/gss_client_osd2.ktab
+        /etc/gss_client_osd3.ktab
+        /etc/gss_client_osd4.ktab
+
+
+    We can also check these newly created keytab client files by:  ::
+
+        # klist -kte /etc/gss_client_mon1.ktab
+        Keytab name: FILE:/etc/gss_client_mon1.ktab
+        KVNO Timestamp           Principal
+        ---- ------------------- ------------------------------------------------------
+           2 10/8/2018 14:35:30 ceph/ceph-mon1@MYDOMAIN.COM (aes256-cts-hmac-sha1-96)
+           2 10/8/2018 14:35:31 ceph/ceph-mon1@MYDOMAIN.COM (aes128-cts-hmac-sha1-96)
+           2 10/8/2018 14:35:31 ceph/ceph-mon1@MYDOMAIN.COM (des3-cbc-sha1)
+           2 10/8/2018 14:35:31 ceph/ceph-mon1@MYDOMAIN.COM (arcfour-hmac)
+        ...
+
+
+6. A new *set parameter* was added in Ceph, ``gss ktab client file`` which
+   points to the keytab file related to the Ceph node *(or principal)* in
+   question.
+
+    By default it points to ``/var/lib/ceph/$name/gss_client_$name.ktab``. So,
+    in the case of a Ceph server ``osd1.mydomain.com``, the location and name
+    of the keytab file should be: ``/var/lib/ceph/osd1/gss_client_osd1.ktab``
+
+    Therefore, we need to ``scp`` each of these newly created keytab files from
+    the KDC to their respective Ceph cluster nodes (i.e):
+    ``# for node in mon1 osd1 osd2 osd3 osd4; do scp /etc/gss_client_$node*.ktab root@ceph-$node:/var/lib/ceph/$node/; done``
+
+    Or whatever other way one feels comfortable with, as long as each keytab
+    client file gets copied over to the proper location.
+
+    At this point, even *without using any keytab client file* we should be
+    already able to authenticate a *user principal*:  ::
+
+        # kdestroy -A && kinit -f johndoe && klist -f
+        Password for johndoe@MYDOMAIN.COM:
+        Ticket cache: KEYRING:persistent:0:0
+        Default principal: johndoe@MYDOMAIN.COM
+
+        Valid starting       Expires              Service principal
+        10/10/2018 15:32:01  10/11/2018 07:32:01  krbtgt/MYDOMAIN.COM@MYDOMAIN.COM
+            renew until 10/11/2018 15:32:01, Flags: FRI
+        ...
+
+
+    Given that the *keytab client file* is/should already be copied and available at the
+    Kerberos client (Ceph cluster node), we should be able to athenticate using it before
+    going forward:  ::
+
+        # kdestroy -A && kinit -k -t /etc/gss_client_mon1.ktab -f 'ceph/ceph-mon1@MYDOMAIN.COM' && klist -f
+        Ticket cache: KEYRING:persistent:0:0
+        Default principal: ceph/ceph-mon1@MYDOMAIN.COM
+
+        Valid starting       Expires              Service principal
+        10/10/2018 15:54:25  10/11/2018 07:54:25  krbtgt/MYDOMAIN.COM@MYDOMAIN.COM
+            renew until 10/11/2018 15:54:25, Flags: FRI
+        ...
+
+
+7. The default client keytab is used, if it is present and readable, to
+   automatically obtain initial credentials for GSSAPI client applications. The
+   principal name of the first entry in the client keytab is used by default
+   when obtaining initial credentials:
+
+    a. The ``KRB5_CLIENT_KTNAME environment`` variable.
+    b. The ``default_client_keytab_name`` profile variable in ``[libdefaults]``.
+    c. The hardcoded default, ``DEFCKTNAME``.
+
+    So, what we do is to internally, set the environment variable
+    ``KRB5_CLIENT_KTNAME`` to the same location as ``gss_ktab_client_file``,
+    so ``/var/lib/ceph/osd1/gss_client_osd1.ktab``, and change the ``ceph.conf``
+    file to add the new authentication method.  ::
+
+        /etc/ceph/ceph.conf
+        [global]
+            ...
+            auth cluster required = gss
+            auth service required = gss
+            auth client required = gss
+            gss ktab client file = /{$my_new_location}/{$my_new_ktab_client_file.keytab}
+            ...
+
+
+8. With that the GSSAPIs will then be able to read the keytab file and using
+   the process of name and service resolution *(provided by the DNS)*, able to
+   request a *TGT* as follows:
+
+    a. User/Client sends principal identity and credentials to the KDC Server
+       (TGT request).
+    b. KDC checks its internal database for the principal in question.
+    c. a TGT is created and wrapped by the KDC, using the principal's key
+       (TGT + Key).
+    d. The newly created TGT, is decrypted and stored in the credentials
+       cache.
+    e. At this point, Kerberos/GSSAPI aware applications (and/or services) are
+       able to check the list of active TGT in the keytab file.
+
+|
+|
+
+** *For Ceph Developers Only* **
+=================================
+
+We certainly could have used straight native ``KRB5 APIs`` (instead of
+``GSSAPIs``), but we wanted a more portable option as regards network security,
+which is the hallmark of the ``GSS`` *(Generic Security Standard)* ``-API``.
+It does not actually provide security services itself.
+
+Rather, it is a framework that provides security services to callers in a
+generic way.  ::
+
+    +---------------------------------+
+    |        Application              |
+    +---------------------------------+
+    | Protocol (RPC, Etc. [Optional]) |
+    +---------------------------------+
+    |         GSS-API                 |
+    +---------------------------------+
+    |   Security Mechs (Krb v5, Etc)  |
+    +---------------------------------+
+
+
+The GSS-API does two main things:
+
+    1. It creates a security context in which data can be passed between
+       applications. A context can be thought of as a sort of *"state of trust"*
+       between two applications.
+
+       Applications that share a context know who each other are and thus can
+       permit data transfers between them as long as the context lasts.
+
+    2. It applies one or more types of protection, known as *"security services"*,
+       to the data to be transmitted.
+
+
+GSS-API provides several types of portability for applications:
+
+    a. **Mechanism independence.** GSS-API provides a generic interface to the
+       mechanisms for which it has been implemented. By specifying a default
+       security mechanism, an application does not need to know which mechanism
+       it is using (for example, Kerberos v5), or even what type of mechanism
+       it uses. As an example, when an application forwards a user's credential
+       to a server, it does not need to know if that credential has a Kerberos
+       format or the format used by some other mechanism, nor how the
+       credentials are stored by the mechanism and accessed by the application.
+       (If necessary, an application can specify a particular mechanism to use)
+
+    b. **Protocol independence.** The GSS-API is independent of any
+       communications protocol or protocol suite. It can be used with
+       applications that use, for example, sockets, RCP, or TCP/IP.
+       RPCSEC_GSS "RPCSEC_GSS Layer" is an additional layer that smoothly
+       integrates GSS-API with RPC.
+
+    c. **Platform independence.** The GSS-API is completely oblivious to the
+       type of operating system on which an application is running.
+
+    d. **Quality of Protection independence.** Quality of Protection (QOP) is
+       the name given to the type of algorithm used in encrypting data or
+       generating cryptographic tags; the GSS-API allows a programmer to ignore
+       QOP, using a default provided by the GSS-API.
+       (On the other hand, an application can specify the QOP if necessary.)
+
+    The basic security offered by the GSS-API is authentication. Authentication
+    is the verification of an identity: *if you are authenticated, it means
+    that you are recognized to be who you say you are.*
+
+    The GSS-API provides for two additional security services, if supported by the
+    underlying mechanisms:
+
+    1. **Integrity:** It's not always sufficient to know that an application
+       sending you data is who it claims to be. The data itself could have
+       become corrupted or compromised.
+
+       The GSS-API provides for data to be accompanied by a cryptographic tag,
+       known as an ``Message Integrity Code (MIC)``, to prove that the data
+       that arrives at your doorstep is the same as the data that the sender
+       transmitted. This verification of the data's validity is known as
+       *"integrity"*.
+
+    2. **Confidentiality:** Both authentication and integrity, however, leave
+       the data itself alone, so if it's somehow intercepted, others can read
+       it.
+
+       The GSS-API therefore allows data to be encrypted, if underlying
+       mechanisms support it. This encryption of data is known as *"confidentiality"*.
+
+|
+
+Mechanisms Available With GSS-API:
+
+    The current implementation of the GSS-API works only with the Kerberos v5 security
+    mechanism.  ::
+
+        Mechanism Name          Object Identifier       Shared Library  Kernel Module
+        ----------------------  ----------------------  --------------  --------------
+        diffie_hellman_640_0    1.3.6.4.1.42.2.26.2.4   dh640-0.so.1
+        diffie_hellman_1024_0   1.3.6.4.1.42.2.26.2.5   dh1024-0.so.1
+        SPNEGO                  1.3.6.1.5.5.2
+        iakerb                  1.3.6.1.5.2.5
+        SCRAM-SHA-1             1.3.6.1.5.5.14
+        SCRAM-SHA-256           1.3.6.1.5.5.18
+        GSS-EAP (arc)           1.3.6.1.5.5.15.1.1.*
+        kerberos_v5             1.2.840.113554.1.2.2    gl/mech_krb5.so gl_kmech_krb5
+
+        Therefore:
+            Kerberos Version 5 GSS-API Mechanism
+            OID {1.2.840.113554.1.2.2}
+
+            Kerberos Version 5 GSS-API Mechanism
+            Simple and Protected GSS-API Negotiation Mechanism
+            OID {1.3.6.1.5.5.2}
+
+
+    There are two different formats:
+
+        1. The first, ``{ 1 2 3 4 }``, is officially mandated by the GSS-API
+           specs. ``gss_str_to_oid()`` expects this first format.
+
+        2. The second, ``1.2.3.4``, is more widely used but is not an official
+           standard format.
+
+    Although the GSS-API makes protecting data simple, it does not do certain
+    things, in order to maximize its generic nature. These include:
+
+        a. Provide security credentials for a user or application. These must
+           be provided by the underlying security mechanism(s). The GSS-API
+           does allow applications to acquire credentials, either automatically
+           or explicitly.
+
+        b. Transfer data between applications. It is the application's
+           responsibility to handle the transfer of all data between peers,
+           whether it is security-related or "plain" data.
+
+        c. Distinguish between different types of transmitted data (for
+           example, to know or determine that a data packet is plain data and
+           not GSS-API related).
+
+        d. Indicate status due to remote (asynchronous) errors.
+
+        e. Automatically protect information sent between processes of a
+           multiprocess program.
+
+        f. Allocate string buffers ("Strings and Similar Data") to be passed to
+           GSS-API functions.
+
+        g. Deallocate GSS-API data spaces. These must be explicitly deallocated
+           with functions such as ``gss_release_buffer()`` and
+           ``gss_delete_name()``.
+
+|
+
+These are the basic steps in using the GSS-API:
+
+    1. Each application, sender and recipient, acquires credentials explicitly,
+       if credentials have not been acquired automatically.
+
+    2. The sender initiates a security context and the recipient accepts it.
+
+    3. The sender applies security protection to the message (data) it wants to
+       transmit. This means that it either encrypts the message or stamps it
+       with an identification tag. The sender transmits the protected message.
+       (The sender can choose not to apply either security protection, in which
+       case the message has only the default GSS-API security service
+       associated with it. That is authentication, in which the recipient knows
+       that the sender is who it claims to be.)
+
+    4. The recipient decrypts the message (if needed) and verifies it
+       (if appropriate).
+
+    5. (Optional) The recipient returns an identification tag to the sender for
+       confirmation.
+
+    6. Both applications destroy the shared security context. If necessary,
+       they can also deallocate any *"leftover"* GSS-API data.
+
+    Applications that use the GSS-API should include the file ``gssapi.h``.
+
+    Good References:
+        - `rfc1964 <https://tools.ietf.org/html/rfc1964>`_.
+        - `rfc2743 <https://tools.ietf.org/html/rfc2743>`_.
+        - `rfc2744 <https://tools.ietf.org/html/rfc2744>`_.
+        - `rfc4178 <https://tools.ietf.org/html/rfc4178>`_.
+        - `rfc6649 <https://tools.ietf.org/html/rfc6649>`_.
+        - `MIT Kerberos Documentation <https://web.mit.edu/kerberos/krb5-latest/doc/appdev/gssapi.html>`_.
+
+|
+
+** *Kerberos Server Setup* **
+------------------------------
+
+First and foremost, ``this is not a recommendation for a production
+environment``. We are not covering ``Master/Slave replication cluster`` or
+anything production environment related (*ntp/chrony, dns, pam/nss, sssd, etc*).
+
+Also, on the server side there might be different dependencies and/or
+configuration steps needed, depending on which backend database will be used.
+``LDAP as a backend database`` is a good example of that.
+
+On the client side there are different steps depending on which client backend
+configuration will be used. For example ``PAM/NSS`` or ``SSSD`` (along with
+LDAP for identity service, [and Kerberos for authentication service]) which is
+the best suited option for joining ``MS Active Directory domains``, and doing
+``User Logon Management``.
+
+By no means we intend to cover every possible scenario/combination here. These
+steps are for a simple *get a (MIT) Kerberos Server up and running*.
+
+Please, note that *rpm packages might have slightly different names*, as well
+as the locations for the binaries and/or configuration files, depending on
+which Linux distro we are referring to.
+
+Finally, keep in mind that some Linux distros will have their own ``wizards``,
+which can perform the basic needed configuration:  ::
+
+    SUSE:
+        Kerberos server:
+            yast2 auth-server
+
+        Kerberos client:
+            pam/nss: yast2 ldapkrb
+            sssd: yast2 auth-client
+
+
+However, we are going through the ``manual configuration``.
+
+
+In order to get a new MIT KDC Server running:
+
+1. Install the KDC server by:
+
+    a. Install the needed packages:  ::
+
+        SUSE: zypper install krb5 krb5-server krb5-client
+            Additionally:
+                for development: krb5-devel
+                if using 'sssd': sssd-krb5 sssd-krb5-common
+
+        REDHAT: yum install krb5-server krb5-libs krb5-workstation
+            Additionally: 'Needs to be checked'
+
+
+    b. Edit the KDC Server configuration file:  ::
+
+        /var/lib/kerberos/krb5kdc/kdc.conf
+        [kdcdefaults]
+                kdc_ports = 750,88
+        [realms]
+                MYDOMAIN.COM = {
+                    acl_file = /var/lib/kerberos/krb5kdc/kadm5.acl
+                    admin_keytab = FILE:/var/lib/kerberos/krb5kdc/kadm5.keytab
+                    default_principal_flags = +postdateable +forwardable +renewable +proxiable
+                                                            +dup-skey -preauth -hwauth +service
+                                                            +tgt-based +allow-tickets -pwchange
+                                                            -pwservice
+                    dict_file = /var/lib/kerberos/krb5kdc/kadm5.dict
+                    key_stash_file = /var/lib/kerberos/krb5kdc/.k5.MYDOMAIN.COM
+                    kdc_ports = 750,88
+                    max_life = 0d 10h 0m 0s
+                    max_renewable_life = 7d 0h 0m 0s
+                }
+        ...
+
+
+    c. Edit the Kerberos Client configuration file:  ::
+
+        /etc/krb5.conf
+        [libdefaults]
+            dns_canonicalize_hostname = false
+            rdns = false
+            forwardable = true
+            dns_lookup_realm = true     //--> if using DNS/DNSMasq
+            dns_lookup_kdc = true       //--> if using DNS/DNSMasq
+            allow_weak_crypto = false
+            default_realm = MYDOMAIN.COM
+            default_ccache_name = KEYRING:persistent:%{uid}
+
+        [realms]
+            MYDOMAIN.COM = {
+                kdc = kerberos.mydomain.com
+                admin_server = kerberos.mydomain.com
+                ...
+            }
+        ...
+
+
+2. Create the Kerberos database:  ::
+
+    SUSE: kdb5_util create -s
+
+    REDHAT: kdb5_util create -s
+
+
+3. Enable and Start both 'KDC and KDC admin' servers:  ::
+
+    SUSE: systemctl enable/start krb5kdc
+          systemctl enable/start kadmind
+
+    REDHAT: systemctl enable/start krb5kdc
+            systemctl enable/start kadmin
+
+
+4. Create a Kerberos Administrator
+    Kerberos principals can be created either locally on the KDC server itself
+    or through the network, using an 'admin principal'. On the KDC server,
+    using ``kadmin.local``:
+
+    a. List the existing principals:  ::
+
+        kadmin.local:  listprincs
+        K/M@MYDOMAIN.COM
+        krbtgt/MYDOMAIN.COM@MYDOMAIN.COM
+        kadmin/admin@MYDOMAIN.COM
+        kadmin/changepw@MYDOMAIN.COM
+        kadmin/history@MYDOMAIN.COM
+        kadmin/kerberos.mydomain.com@MYDOMAIN.COM
+        root/admin@MYDOMAIN.COM
+        ...
+
+
+    b. In case we don't have a built-in 'admin principal', we then create one
+    (whatever ``principal name``, we are using ``root``, once by default
+    ``kinit`` tries to authenticate using the same system login user name,
+    unless a ``principal`` is passed as an argument ``kinit principal``):  ::
+
+        # kadmin.local -q "addprinc root/admin"
+        Authenticating as principal root/admin@MYDOMAIN.COM with password.
+        WARNING: no policy specified for root/admin@MYDOMAIN.COM; defaulting to no policy
+        Enter password for principal "root/admin@MYDOMAIN.COM":
+
+
+    c. Confirm the newly created 'admin principal' has the needed permissions
+       in the KDC ACL (if ACLs are changed, ``kadmind`` needs to be restarted):  ::
+
+        SUSE: /var/lib/kerberos/krb5kdc/kadm5.acl
+        REDHAT: /var/kerberos/krb5kdc/kadm5.acl
+
+        ###############################################################################
+        #Kerberos_principal      permissions     [target_principal]      [restrictions]
+        ###############################################################################
+        #
+        */admin@MYDOMAIN.COM     *
+
+
+    d. Create a simple 'user principal' (same steps as by *The 'Ceph side' of
+       the things*; 4a):  ::
+
+        kadmin.local:  addprinc johndoe
+        WARNING: no policy specified for johndoe@MYDOMAIN.COM; defaulting to no policy
+        Enter password for principal "johndoe@MYDOMAIN.COM":
+        Re-enter password for principal "johndoe@MYDOMAIN.COM":
+        Principal "johndoe@MYDOMAIN.COM" created.
+
+
+    e. Confirm the newly created 'user principal' is able to authenticate (same
+       steps as by *The 'Ceph side' of the things*; 6):  ::
+
+        # kdestroy -A && kinit -f johndoe && klist -f
+        Password for johndoe@MYDOMAIN.COM:
+        Ticket cache: KEYRING:persistent:0:0
+        Default principal: johndoe@MYDOMAIN.COM
+
+        Valid starting       Expires              Service principal
+        11/16/2018 13:11:16  11/16/2018 23:11:16  krbtgt/MYDOMAIN.COM@MYDOMAIN.COM
+                renew until 11/17/2018 13:11:16, Flags: FRI
+        ...
+
+
+5. At this point, we should have a *simple (MIT) Kerberos Server up and running*:
+
+     a. Considering we will want to work with keytab files, for both 'user and
+        service' principals, refer to The *'Ceph side' of the things* starting
+        at step 4.
+
+     b. Make sure you are comfortable with following and their ``manpages``:  ::
+
+            krb5.conf       -> Krb client config file
+            kdc.conf        -> KDC server config file
+
+            krb5kdc         -> KDC server daemon
+            kadmind         -> KDC administration daemon
+
+            kadmin          -> Krb administration tool
+            kdb5_util       -> Krb low-level database administration tool
+
+            kinit           -> Obtain and cache Kerberos ticket-granting ticket tool
+            klist           -> List cached Kerberos tickets tool
+            kdestroy        -> Destroy Kerberos tickets tool
+
+
+6. Name Resolution
+    As mentioned earlier, Kerberos *relies heavly on name resolution*. Most of
+    the Kerberos issues are usually related to name resolution, since Kerberos
+    is *very picky* on both *systems names* and *host lookups*.
+
+    a. As described in *The 'Ceph side' of the things*; step 2a, DNS RRs
+       greatly improves service location and host/domain resolution, by using
+       ``(srv resources)`` and ``(txt record)`` respectively (as per
+       *Before We Start*; *DNS resolution*).  ::
+
+        /var/lib/named/master/mydomain.com
+        kerberos                IN A        192.168.10.21
+        kerberos-slave          IN A        192.168.10.22
+        _kerberos               IN TXT      "MYDOMAIN.COM"
+        _kerberos._udp          IN SRV      1 0 88 kerberos
+        _kerberos._tcp          IN SRV      1 0 88 kerberos
+        _kerberos._udp          IN SRV      20 0 88 kerberos-slave
+        _kerberos-master._udp   IN SRV      0 0 88 kerberos
+        _kerberos-adm._tcp      IN SRV      0 0 749 kerberos
+        _kpasswd._udp           IN SRV      0 0 464 kerberos
+        ...
+
+
+    b. For a small network or development environment, where a *DNS server is
+       not available*, we have the option to use ``DNSMasq``, an
+       ease-to-configure lightweight DNS server (along with some other
+       capabilities).
+
+       These records can be added to ``/etc/dnsmasq.conf`` (in addition to the
+       needed 'host records'):  ::
+
+        /etc/dnsmasq.conf
+        ...
+        txt-record=_kerberos.mydomain.com,"MYDOMAIN.COM"
+        srv-host=_kerberos._udp.mydomain.com,kerberos.mydomain.com,88,1
+        srv-host=_kerberos._udp.mydomain.com,kerberos-2.mydomain.com,88,20
+        srv-host=_kerberos-master._udp.mydomain.com,kerberos.mydomain.com,88,0
+        srv-host=_kerberos-adm._tcp.mydomain.com,kerberos.mydomain.com,749,0
+        srv-host=_kpasswd._udp.mydomain.com,kerberos.mydomain.com,464,0
+        srv-host=_kerberos._tcp.mydomain.com,kerberos.mydomain.com,88,1
+        ...
+
+
+    c. After 'b)' is all set, and ``dnsmasq`` service up and running, we can
+       test it using:  ::
+
+        # nslookup kerberos
+        Server:     192.168.10.1
+        Address:    192.168.10.1#53
+
+        Name:   kerberos.mydomain.com
+        Address: 192.168.10.21
+
+        # host -t SRV _kerberos._tcp.mydomain.com
+        _kerberos._tcp.mydomain.com has SRV record 1 0 88 kerberos.mydomain.com.
+
+        # host -t SRV {each srv-host record}
+        # host -t TXT _kerberos.mydomain.com
+        _kerberos.mydomain.com descriptive text "MYDOMAIN.COM"
+        ...
+
+
+    f. As long as ``name resolution`` is working properly, either ``dnsmasq``
+       or ``named``, Kerberos should be able to find the needed service
+       records.
index f999f877a69161e59f8388ef7f6496f7809cff15..a39a025700cad6b1559a2177e75631a0c398dca9 100644 (file)
@@ -364,6 +364,7 @@ set(ceph_common_deps
   ${Backtrace_LIBRARIES}
   ${BLKIN_LIBRARIES}
   ${CRYPTO_LIBS}
+  ${GSSAPI_LIBRARIES}
   ${CMAKE_THREAD_LIBS_INIT}
   ${CMAKE_DL_LIBS})
 if(HAVE_UDEV)
@@ -455,7 +456,7 @@ endif()
 set(librados_config_srcs
   librados-config.cc)
 add_executable(librados-config ${librados_config_srcs})
-target_link_libraries(librados-config librados global ${BLKID_LIBRARIES} ${CMAKE_DL_LIBS})
+target_link_libraries(librados-config librados global ${BLKID_LIBRARIES} ${CMAKE_DL_LIBS} ${GSSAPI_LIBRARIES})
 
 install(TARGETS librados-config DESTINATION bin)
 
@@ -477,7 +478,7 @@ add_executable(ceph-mon ${ceph_mon_srcs}
 add_dependencies(ceph-mon erasure_code_plugins)
 target_link_libraries(ceph-mon mon os global-static ceph-common
   ${EXTRALIBS}
-  ${CMAKE_DL_LIBS})
+  ${CMAKE_DL_LIBS} ${GSSAPI_LIBRARIES})
 install(TARGETS ceph-mon DESTINATION bin)
 
 # OSD/ObjectStore
@@ -654,7 +655,7 @@ if(WITH_FUSE)
     client/fuse_ll.cc)
   add_executable(ceph-fuse ${ceph_fuse_srcs})
   target_link_libraries(ceph-fuse ${FUSE_LIBRARIES}
-    client ceph-common global-static)
+    ${GSSAPI_LIBRARIES} client ceph-common global-static)
   set_target_properties(ceph-fuse PROPERTIES
     COMPILE_FLAGS "-I${FUSE_INCLUDE_DIRS}"
     POSITION_INDEPENDENT_CODE ${EXE_LINKER_USE_PIE})
index b4efe7bfbaaa9f37547c1f44413f39fe62f521c0..dc4fcb74192947da7a1aef242ccde94b2b037a8d 100644 (file)
@@ -14,6 +14,7 @@
 
 #include "AuthAuthorizeHandler.h"
 #include "cephx/CephxAuthorizeHandler.h"
+#include "krb/KrbAuthorizeHandler.hpp"
 #include "none/AuthNoneAuthorizeHandler.h"
 
 AuthAuthorizeHandler *AuthAuthorizeHandlerRegistry::get_handler(int protocol)
@@ -35,6 +36,10 @@ AuthAuthorizeHandler *AuthAuthorizeHandlerRegistry::get_handler(int protocol)
   case CEPH_AUTH_CEPHX:
     m_authorizers[protocol] = new CephxAuthorizeHandler();
     return m_authorizers[protocol];
+
+  case CEPH_AUTH_GSS:
+    m_authorizers[protocol] = new KrbAuthorizeHandler();
+    return m_authorizers[protocol];
   }
   return NULL;
 }
index 7f6804b47ba327b0c2ca56a130b132e3680dc5c2..ef76b993f5a2f3a427e3bb4987691accc1e9fd01 100644 (file)
@@ -17,6 +17,7 @@
 
 #include "AuthClientHandler.h"
 #include "cephx/CephxClientHandler.h"
+#include "krb/KrbClientHandler.hpp"
 #include "none/AuthNoneClientHandler.h"
 
 
@@ -29,7 +30,10 @@ AuthClientHandler::create(CephContext* cct, int proto,
     return new CephxClientHandler(cct, rkeys);
   case CEPH_AUTH_NONE:
     return new AuthNoneClientHandler{cct};
+  case CEPH_AUTH_GSS: 
+    return new KrbClientHandler(cct);
   default:
     return NULL;
   }
 }
+
index 4caf5348157305fa961e6d02b0d0e36286383afa..429833309a008b88cf97b18da7672f51cccbc4a2 100644 (file)
@@ -34,6 +34,8 @@ AuthMethodList::AuthMethodList(CephContext *cct, std::string str)
       auth_supported.push_back(CEPH_AUTH_CEPHX);
     } else if (iter->compare("none") == 0) {
       auth_supported.push_back(CEPH_AUTH_NONE);
+    } else if (iter->compare("gss") == 0) {
+      auth_supported.push_back(CEPH_AUTH_GSS);
     } else {
       auth_supported.push_back(CEPH_AUTH_UNKNOWN);
       lderr(cct) << "WARNING: unknown auth protocol defined: " << *iter << dendl;
index bd265c4f0c962fa2fb229f8eb421f1dea25813c7..406a2ed3210751d80608eb17ebc40219f8ee6bf5 100644 (file)
@@ -14,6 +14,7 @@
 
 #include "AuthServiceHandler.h"
 #include "cephx/CephxServiceHandler.h"
+#include "krb/KrbServiceHandler.hpp"
 #include "none/AuthNoneServiceHandler.h"
 
 #define dout_subsys ceph_subsys_auth
@@ -26,6 +27,8 @@ AuthServiceHandler *get_auth_service_handler(int type, CephContext *cct, KeyServ
     return new CephxServiceHandler(cct, ks);
   case CEPH_AUTH_NONE:
     return new AuthNoneServiceHandler(cct);
+  case CEPH_AUTH_GSS: 
+    return new KrbServiceHandler(cct, ks);
   }
   return NULL;
 }
index ab46b60c57999309532569d480b17d93f01f8c48..75347b8a242ef842eb7bd639ef141d74e433b065 100644 (file)
@@ -15,6 +15,7 @@
 #include "common/debug.h"
 #include "AuthSessionHandler.h"
 #include "cephx/CephxSessionHandler.h"
+#include "krb/KrbSessionHandler.hpp"
 #include "none/AuthNoneSessionHandler.h"
 #include "unknown/AuthUnknownSessionHandler.h"
 
@@ -35,6 +36,8 @@ AuthSessionHandler *get_auth_session_handler(CephContext *cct, int protocol, Cry
     return new AuthNoneSessionHandler(cct, key);
   case CEPH_AUTH_UNKNOWN:
     return new AuthUnknownSessionHandler(cct, key);
+  case CEPH_AUTH_GSS: 
+    return new KrbSessionHandler(cct, key);
   }
   return NULL;
 }
index 5e19d8963b75515a03695f93c6204633559dd812..1e21cd6b56368be0984cfbd5a2948e888fc2c6b4 100644 (file)
@@ -10,6 +10,10 @@ set(auth_srcs
   cephx/CephxClientHandler.cc
   cephx/CephxProtocol.cc
   cephx/CephxSessionHandler.cc
+  krb/KrbAuthorizeHandler.cpp
+  krb/KrbClientHandler.cpp
+  krb/KrbProtocol.cpp
+  krb/KrbSessionHandler.hpp
   none/AuthNoneAuthorizeHandler.cc
   unknown/AuthUnknownAuthorizeHandler.cc)
 
diff --git a/src/auth/krb/KrbAuthorizeHandler.cpp b/src/auth/krb/KrbAuthorizeHandler.cpp
new file mode 100644 (file)
index 0000000..cd84b8a
--- /dev/null
@@ -0,0 +1,51 @@
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+/*
+ * Ceph - scalable distributed file system
+ *
+ * Copyright (c) 2018 SUSE LLC.
+ * Author: Daniel Oliveira <doliveira@suse.com>
+ * 
+ * This is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software
+ * Foundation.  See file COPYING.
+ *
+ */
+
+#include "KrbAuthorizeHandler.hpp"
+
+#include "common/debug.h"
+
+#define dout_subsys ceph_subsys_auth 
+
+bool KrbAuthorizeHandler::verify_authorizer(CephContext* ceph_ctx, 
+                                            KeyStore* keys, 
+                                            bufferlist& authorizer_data,  
+                                            bufferlist& authorizer_reply, 
+                                            EntityName& entity_name, 
+                                            uint64_t& global_id,  
+                                            AuthCapsInfo& caps_info, 
+                                            CryptoKey& session_key, 
+                                            std::unique_ptr<
+                                              AuthAuthorizerChallenge>* challenge)
+{
+  auto itr(authorizer_data.cbegin());
+
+  try {
+    uint8_t value = (1);
+
+    using ceph::decode;
+    decode(value, itr);
+    decode(entity_name, itr);
+    decode(global_id, itr);
+  } catch (const buffer::error& err) {
+    ldout(ceph_ctx, 0) 
+        << "Error: KrbAuthorizeHandler::verify_authorizer() failed!" << dendl;
+    return false;
+  }
+  caps_info.allow_all = true; 
+  return true;
+}
+
+
diff --git a/src/auth/krb/KrbAuthorizeHandler.hpp b/src/auth/krb/KrbAuthorizeHandler.hpp
new file mode 100644 (file)
index 0000000..d5f16ee
--- /dev/null
@@ -0,0 +1,39 @@
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+/*
+ * Ceph - scalable distributed file system
+ *
+ * Copyright (c) 2018 SUSE LLC.
+ * Author: Daniel Oliveira <doliveira@suse.com>
+ * 
+ * This is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software
+ * Foundation.  See file COPYING.
+ *
+ */
+
+#ifndef KRB_AUTHORIZE_HANDLER_HPP
+#define KRB_AUTHORIZE_HANDLER_HPP
+
+#include "auth/AuthAuthorizeHandler.h"
+
+class KrbAuthorizeHandler : public AuthAuthorizeHandler {
+  bool verify_authorizer(CephContext*, KeyStore*, 
+                         bufferlist&, bufferlist&,
+                         EntityName&, uint64_t&, 
+                         AuthCapsInfo&, CryptoKey&, 
+                         std::unique_ptr<
+                          AuthAuthorizerChallenge>* = nullptr) override;
+
+  int authorizer_session_crypto() override { 
+    return SESSION_SYMMETRIC_AUTHENTICATE; 
+  };
+
+  ~KrbAuthorizeHandler() override = default;
+
+};
+
+
+#endif    //-- KRB_AUTHORIZE_HANDLER_HPP
+
diff --git a/src/auth/krb/KrbClientHandler.cpp b/src/auth/krb/KrbClientHandler.cpp
new file mode 100644 (file)
index 0000000..4412b7a
--- /dev/null
@@ -0,0 +1,251 @@
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+/*
+ * Ceph - scalable distributed file system
+ *
+ * Copyright (c) 2018 SUSE LLC.
+ * Author: Daniel Oliveira <doliveira@suse.com>
+ * 
+ * This is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software
+ * Foundation.  See file COPYING.
+ *
+ */
+
+#include "KrbClientHandler.hpp"
+
+#include <errno.h>
+#include <string>
+#include "KrbProtocol.hpp"
+
+#include "auth/KeyRing.h"
+#include "include/random.h"
+#include "common/ceph_context.h"
+#include "common/config.h"
+#include "common/dout.h"
+
+#define dout_subsys ceph_subsys_auth
+#undef dout_prefix
+#define dout_prefix *_dout << "krb5/gssapi client request: "
+
+struct AuthAuthorizer;
+
+AuthAuthorizer* 
+KrbClientHandler::build_authorizer(uint32_t service_id) const 
+{
+  ldout(cct, 20) 
+      << "KrbClientHandler::build_authorizer(): Service: " 
+      << ceph_entity_type_name(service_id) << dendl; 
+
+  KrbAuthorizer* krb_auth = new KrbAuthorizer();
+  if (krb_auth) {
+    krb_auth->build_authorizer(cct->_conf->name, global_id);
+  }
+  return krb_auth;
+}
+
+
+KrbClientHandler::~KrbClientHandler() 
+{
+  OM_uint32 gss_minor_status(0); 
+
+  gss_release_name(&gss_minor_status, &m_gss_client_name);
+  gss_release_name(&gss_minor_status, &m_gss_service_name);
+  gss_release_cred(&gss_minor_status, &m_gss_credentials); 
+  gss_delete_sec_context(&gss_minor_status, &m_gss_sec_ctx, GSS_C_NO_BUFFER); 
+  gss_release_buffer(&gss_minor_status, 
+                     static_cast<gss_buffer_t>(&m_gss_buffer_out)); 
+}
+
+
+int KrbClientHandler::build_request(bufferlist& buff_list) const
+{
+  ldout(cct, 20) 
+      << "KrbClientHandler::build_request() " << dendl; 
+
+  KrbTokenBlob krb_token; 
+  KrbRequest krb_request; 
+
+  krb_request.m_request_type = 
+      static_cast<int>(GSSAuthenticationRequest::GSS_TOKEN);
+
+  using ceph::encode;
+  encode(krb_request, buff_list);
+
+  if (m_gss_buffer_out.length != 0) {
+    krb_token.m_token_blob.append(buffer::create_static(
+                                    m_gss_buffer_out.length, 
+                                    reinterpret_cast<char*>
+                                      (m_gss_buffer_out.value)));
+
+    encode(krb_token, buff_list);
+    ldout(cct, 20) 
+        << "KrbClientHandler::build_request() : Token Blob: " << "\n"; 
+    krb_token.m_token_blob.hexdump(*_dout);
+    *_dout << dendl;
+  }
+  return 0;
+}
+
+
+int KrbClientHandler::handle_response(int ret, 
+                                          bufferlist::const_iterator& buff_list)
+{
+  auto result(ret);
+  gss_buffer_desc gss_buffer_in = {0, nullptr};
+  gss_OID_set_desc gss_mechs_wanted = {0, nullptr};
+  OM_uint32 gss_major_status(0); 
+  OM_uint32 gss_minor_status(0); 
+  OM_uint32 gss_wanted_flags(GSS_C_MUTUAL_FLAG | 
+                             GSS_C_INTEG_FLAG);
+  OM_uint32 gss_result_flags(0);
+
+  ldout(cct, 20) 
+      << "KrbClientHandler::handle_response() " << dendl; 
+
+  if (result < 0) {
+    return result;
+  }
+
+  gss_mechs_wanted.elements = const_cast<gss_OID>(&GSS_API_SPNEGO_OID_PTR);
+  gss_mechs_wanted.count = 1; 
+
+  KrbResponse krb_response; 
+
+  using ceph::decode;
+  decode(krb_response, buff_list);
+  if (m_gss_credentials == GSS_C_NO_CREDENTIAL) {
+    gss_buffer_desc krb_client_name_buff = {0, nullptr};
+    gss_OID krb_client_type = GSS_C_NT_USER_NAME;
+    std::string krb_client_name(cct->_conf->name.to_str());
+
+    krb_client_name_buff.length = krb_client_name.length();
+    krb_client_name_buff.value  = (const_cast<char*>(krb_client_name.c_str()));
+
+    if (cct->_conf->name.get_type() == CEPH_ENTITY_TYPE_CLIENT) {
+      gss_major_status = gss_import_name(&gss_minor_status, 
+                                         &gss_buffer_in, 
+                                         krb_client_type, 
+                                         &m_gss_client_name); 
+      if (gss_major_status != GSS_S_COMPLETE) {
+        auto status_str(gss_auth_show_status(gss_major_status, 
+                                             gss_minor_status));
+        ldout(cct, 0) 
+            << "ERROR: KrbClientHandler::handle_response() "
+               "[gss_import_name(gss_client_name)] failed! " 
+            << gss_major_status << " " 
+            << gss_minor_status << " " 
+            << status_str 
+            << dendl;
+      }
+    }
+
+    gss_major_status = gss_acquire_cred(&gss_minor_status, 
+                                        m_gss_client_name, 
+                                        0, 
+                                        &gss_mechs_wanted, 
+                                        GSS_C_INITIATE, 
+                                        &m_gss_credentials, 
+                                        nullptr, 
+                                        nullptr);
+    if (gss_major_status != GSS_S_COMPLETE) {
+      auto status_str(gss_auth_show_status(gss_major_status, 
+                                           gss_minor_status));
+      ldout(cct, 20) 
+          << "ERROR: KrbClientHandler::handle_response() "
+             "[gss_acquire_cred()] failed! " 
+          << gss_major_status << " " 
+          << gss_minor_status << " " 
+          << status_str 
+          << dendl;
+      return (-EPERM);
+    }
+
+    gss_buffer_desc krb_input_name_buff = {0, nullptr};
+    gss_OID krb_input_type = GSS_C_NT_HOSTBASED_SERVICE;
+    std::string gss_target_name(cct->_conf.get_val<std::string>
+                                            ("gss_target_name"));
+    krb_input_name_buff.length = gss_target_name.length(); 
+    krb_input_name_buff.value  = (const_cast<char*>(gss_target_name.c_str()));
+
+    gss_major_status = gss_import_name(&gss_minor_status, 
+                                       &krb_input_name_buff, 
+                                       krb_input_type, 
+                                       &m_gss_service_name); 
+    if (gss_major_status != GSS_S_COMPLETE) {
+      auto status_str(gss_auth_show_status(gss_major_status, 
+                                           gss_minor_status));
+      ldout(cct, 0) 
+          << "ERROR: KrbClientHandler::handle_response() "
+             "[gss_import_name(gss_service_name)] failed! " 
+          << gss_major_status << " " 
+          << gss_minor_status << " " 
+          << status_str 
+          << dendl;
+    }
+  } else {
+    KrbTokenBlob krb_token; 
+
+    using ceph::decode;
+    decode(krb_token, buff_list);
+    ldout(cct, 20) 
+        << "KrbClientHandler::handle_response() : Token Blob: " << "\n"; 
+    krb_token.m_token_blob.hexdump(*_dout);
+    *_dout << dendl;
+
+    gss_buffer_in.length = krb_token.m_token_blob.length();
+    gss_buffer_in.value  = krb_token.m_token_blob.c_str();
+  }
+
+  const gss_OID gss_mech_type = gss_mechs_wanted.elements; 
+  if (m_gss_buffer_out.length != 0) {
+    gss_release_buffer(&gss_minor_status, 
+                       static_cast<gss_buffer_t>(&m_gss_buffer_out)); 
+  }
+
+  gss_major_status = gss_init_sec_context(&gss_minor_status, 
+                                          m_gss_credentials, 
+                                          &m_gss_sec_ctx, 
+                                          m_gss_service_name, 
+                                          gss_mech_type, 
+                                          gss_wanted_flags, 
+                                          0, 
+                                          nullptr, 
+                                          &gss_buffer_in, 
+                                          nullptr, 
+                                          &m_gss_buffer_out, 
+                                          &gss_result_flags, 
+                                          nullptr);
+  switch (gss_major_status) {
+    case GSS_S_CONTINUE_NEEDED: 
+      ldout(cct, 20) 
+          << "KrbClientHandler::handle_response() : "
+             "[gss_init_sec_context(GSS_S_CONTINUE_NEEDED)] " << dendl; 
+      result = (-EAGAIN);
+      break;
+
+    case GSS_S_COMPLETE: 
+      ldout(cct, 20) 
+          << "KrbClientHandler::handle_response() : "
+             "[gss_init_sec_context(GSS_S_COMPLETE)] " << dendl; 
+      result = 0;
+      break;
+
+    default: 
+      auto status_str(gss_auth_show_status(gss_major_status, 
+                                           gss_minor_status));
+      ldout(cct, 0) 
+          << "ERROR: KrbClientHandler::handle_response() "
+             "[gss_init_sec_context()] failed! " 
+          << gss_major_status << " " 
+          << gss_minor_status << " " 
+          << status_str 
+          << dendl;
+      result = (-EPERM);
+      break;
+  }
+
+  return result;
+}
+
diff --git a/src/auth/krb/KrbClientHandler.hpp b/src/auth/krb/KrbClientHandler.hpp
new file mode 100644 (file)
index 0000000..66f03d0
--- /dev/null
@@ -0,0 +1,78 @@
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+/*
+ * Ceph - scalable distributed file system
+ *
+ * Copyright (c) 2018 SUSE LLC.
+ * Author: Daniel Oliveira <doliveira@suse.com>
+ * 
+ * This is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software
+ * Foundation.  See file COPYING.
+ *
+ */
+
+#ifndef KRB_CLIENT_HANDLER_HPP
+#define KRB_CLIENT_HANDLER_HPP
+
+#include "auth/AuthClientHandler.h"
+#include "auth/RotatingKeyRing.h"
+
+#include "KrbProtocol.hpp"
+
+#include <gssapi.h>
+#include <gssapi/gssapi_generic.h>
+#include <gssapi/gssapi_krb5.h>
+#include <gssapi/gssapi_ext.h>
+
+
+class CephContext;
+class Keyring;
+
+
+class KrbClientHandler : public AuthClientHandler {
+
+  public:
+    KrbClientHandler(CephContext* ceph_ctx = nullptr) 
+      : AuthClientHandler(ceph_ctx) {
+      reset();
+    }
+    ~KrbClientHandler() override;
+    
+    int get_protocol() const override { return CEPH_AUTH_GSS; }
+    void reset() override {
+      m_gss_client_name = GSS_C_NO_NAME; 
+      m_gss_service_name = GSS_C_NO_NAME; 
+      m_gss_credentials = GSS_C_NO_CREDENTIAL;
+      m_gss_sec_ctx = GSS_C_NO_CONTEXT;
+      m_gss_buffer_out = {0, 0};
+    }
+
+    void prepare_build_request() override { };
+    int build_request(bufferlist& buff_list) const override;
+    int handle_response(int ret, 
+                        bufferlist::const_iterator& buff_list) override;
+
+    bool build_rotating_request(bufferlist& buff_list) const override { 
+      return false; 
+    }
+
+    AuthAuthorizer* build_authorizer(uint32_t service_id) const override;
+    bool need_tickets() override { return false; }
+    void set_global_id(uint64_t guid) override { global_id = guid; }
+
+
+  private:
+    gss_name_t m_gss_client_name; 
+    gss_name_t m_gss_service_name; 
+    gss_cred_id_t m_gss_credentials; 
+    gss_ctx_id_t m_gss_sec_ctx; 
+    gss_buffer_desc m_gss_buffer_out; 
+
+  protected:
+    void validate_tickets() override { } 
+};
+
+#endif    //-- KRB_CLIENT_HANDLER_HPP
+
diff --git a/src/auth/krb/KrbProtocol.cpp b/src/auth/krb/KrbProtocol.cpp
new file mode 100644 (file)
index 0000000..6988d35
--- /dev/null
@@ -0,0 +1,86 @@
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+/*
+ * Ceph - scalable distributed file system
+ *
+ * Copyright (c) 2018 SUSE LLC.
+ * Author: Daniel Oliveira <doliveira@suse.com>
+ * 
+ * This is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software
+ * Foundation.  See file COPYING.
+ *
+ */
+
+#include "KrbProtocol.hpp"
+
+#include "common/Clock.h"
+#include "common/config.h"
+#include "common/debug.h"
+#include "include/buffer.h"
+
+#define dout_subsys ceph_subsys_auth
+#undef dout_prefix
+#define dout_prefix *_dout << "krb5/gssapi protocol: "
+
+
+std::string gss_auth_show_status(const OM_uint32 gss_major_status, 
+                                 const OM_uint32 gss_minor_status)
+{
+  const std::string STR_DOT(".");
+  const std::string STR_BLANK(" ");
+
+  gss_buffer_desc gss_str_status = {0, nullptr};
+  OM_uint32 gss_maj_status(0); 
+  OM_uint32 gss_min_status(0);
+  OM_uint32 gss_ctx_message(-1);
+
+  std::string str_status("");
+
+  const auto gss_complete_status_str_format = [&](const uint32_t gss_status) {
+    if (gss_status == GSS_S_COMPLETE) {
+      std::string str_tmp("");
+      str_tmp.append(reinterpret_cast<char*>(gss_str_status.value), 
+                     gss_str_status.length);
+      str_tmp += STR_DOT;
+      if (gss_ctx_message != 0) {
+        str_tmp += STR_BLANK;
+      }
+      return str_tmp;
+    }
+    return STR_BLANK;
+  };
+
+  while (gss_ctx_message != 0) {
+    gss_maj_status = gss_display_status(&gss_min_status, 
+                                        gss_major_status, 
+                                        GSS_C_GSS_CODE, 
+                                        GSS_C_NO_OID, 
+                                        &gss_ctx_message, 
+                                        &gss_str_status); 
+    
+    if (gss_maj_status == GSS_S_COMPLETE) {
+      str_status += gss_complete_status_str_format(gss_maj_status);
+      gss_release_buffer(&gss_min_status, &gss_str_status);
+    }
+  }
+
+  if (gss_major_status == GSS_S_FAILURE) {
+    gss_ctx_message = -1;
+    while (gss_ctx_message != 0) {
+      gss_maj_status = gss_display_status(&gss_min_status, 
+                                          gss_minor_status, 
+                                          GSS_C_MECH_CODE,
+                                          const_cast<gss_OID>(&GSS_API_KRB5_OID_PTR),
+                                          &gss_ctx_message, 
+                                          &gss_str_status); 
+      if (gss_maj_status == GSS_S_COMPLETE) {
+        str_status += gss_complete_status_str_format(gss_maj_status);
+        gss_release_buffer(&gss_min_status, &gss_str_status);
+      }
+    }
+  }
+  return str_status;
+}
+
diff --git a/src/auth/krb/KrbProtocol.hpp b/src/auth/krb/KrbProtocol.hpp
new file mode 100644 (file)
index 0000000..0081dfc
--- /dev/null
@@ -0,0 +1,159 @@
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+/*
+ * Ceph - scalable distributed file system
+ *
+ * Copyright (c) 2018 SUSE LLC.
+ * Author: Daniel Oliveira <doliveira@suse.com>
+ * 
+ * This is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software
+ * Foundation.  See file COPYING.
+ *
+ */
+
+#ifndef KRB_PROTOCOL_HPP
+#define KRB_PROTOCOL_HPP
+
+#include "auth/Auth.h"
+
+#include <errno.h>
+#include <gssapi.h>
+#include <gssapi/gssapi_generic.h>
+#include <gssapi/gssapi_krb5.h>
+#include <gssapi/gssapi_ext.h>
+
+#include <map>
+#include <sstream> 
+#include <string>
+
+/* 
+  Kerberos Version 5 GSS-API Mechanism
+  OID {1.2.840.113554.1.2.2}
+  RFC https://tools.ietf.org/html/rfc1964
+*/
+static const gss_OID_desc GSS_API_KRB5_OID_PTR = 
+    { 9, (void *)"\052\206\110\206\367\022\001\002\002" };
+
+/* 
+  Kerberos Version 5 GSS-API Mechanism
+  Simple and Protected GSS-API Negotiation Mechanism 
+  OID {1.3.6.1.5.5.2}
+  RFC https://tools.ietf.org/html/rfc4178
+*/
+static const gss_OID_desc GSS_API_SPNEGO_OID_PTR =
+    {6, (void *)"\x2b\x06\x01\x05\x05\x02"};
+
+static const std::string KRB_SERVICE_NAME("kerberos/gssapi");
+static const std::string GSS_API_SPNEGO_OID("{1.3.6.1.5.5.2}");
+static const std::string GSS_API_KRB5_OID("{1.2.840.113554.1.2.2}");
+
+enum class GSSAuthenticationRequest {
+  GSS_CRYPTO_ERR    = 1,
+  GSS_MUTUAL        = 0x100,
+  GSS_TOKEN         = 0x200,
+  GSS_REQUEST_MASK  = 0x0F00
+};
+
+enum class GSSKeyExchange {
+  USERAUTH_GSSAPI_RESPONSE = 70,
+  USERAUTH_GSSAPI_TOKEN,
+  USERAUTH_GSSAPI_EXCHANGE_COMPLETE,
+  USERAUTH_GSSAPI_ERROR, 
+  USERAUTH_GSSAPI_ERRTOK, 
+  USERAUTH_GSSAPI_MIC, 
+};
+static constexpr auto CEPH_GSS_OIDTYPE(0x07);
+
+struct AuthAuthorizer;
+
+
+class KrbAuthorizer : public AuthAuthorizer {
+
+  public:
+    KrbAuthorizer() : AuthAuthorizer(CEPH_AUTH_GSS) { }
+    ~KrbAuthorizer() = default; 
+    bool build_authorizer(const EntityName& entity_name, 
+                          const uint64_t guid) {
+      uint8_t value = (1);
+
+      using ceph::encode;
+      encode(value, bl, 0);
+      encode(entity_name, bl, 0); 
+      encode(guid, bl, 0);
+      return false;
+    }
+
+    bool verify_reply(bufferlist::const_iterator& buff_list) override { 
+      return true; 
+    }
+    bool add_challenge(CephContext* ceph_ctx, 
+                       bufferlist& buff_list) override { 
+      return true; 
+    }
+};
+
+class KrbRequest {
+
+  public:
+    void decode(bufferlist::const_iterator& buff_list) {
+      using ceph::decode;
+      decode(m_request_type, buff_list);
+    }
+
+    void encode(bufferlist& buff_list) const {
+      using ceph::encode;
+      encode(m_request_type, buff_list);
+    }
+
+    uint16_t m_request_type; 
+};
+WRITE_CLASS_ENCODER(KrbRequest);
+
+class KrbResponse {
+
+  public: 
+    void decode(bufferlist::const_iterator& buff_list) {
+      using ceph::decode;
+      decode(m_response_type, buff_list); 
+    }    
+
+    void encode(bufferlist& buff_list) const {
+      using ceph::encode;
+      encode(m_response_type, buff_list); 
+    }
+
+    uint16_t m_response_type;
+};
+WRITE_CLASS_ENCODER(KrbResponse);
+
+class KrbTokenBlob {
+
+  public:
+    void decode(bufferlist::const_iterator& buff_list) {
+      uint8_t value = (0); 
+     
+      using ceph::decode; 
+      decode(value, buff_list);
+      decode(m_token_blob, buff_list);
+    }
+        
+    void encode(bufferlist& buff_list) const {
+      uint8_t value = (1); 
+      
+      using ceph::encode;
+      encode(value, buff_list, 0);
+      encode(m_token_blob, buff_list, 0);
+    }
+
+    bufferlist m_token_blob;
+};
+WRITE_CLASS_ENCODER(KrbTokenBlob);
+
+
+std::string gss_auth_show_status(const OM_uint32 gss_major_status, 
+                                 const OM_uint32 gss_minor_status); 
+
+#endif    //-- KRB_PROTOCOL_HPP
+
diff --git a/src/auth/krb/KrbServiceHandler.cpp b/src/auth/krb/KrbServiceHandler.cpp
new file mode 100644 (file)
index 0000000..52ebd0a
--- /dev/null
@@ -0,0 +1,223 @@
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+/*
+ * Ceph - scalable distributed file system
+ *
+ * Copyright (c) 2018 SUSE LLC.
+ * Author: Daniel Oliveira <doliveira@suse.com>
+ * 
+ * This is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software
+ * Foundation.  See file COPYING.
+ *
+ */
+
+#include "KrbServiceHandler.hpp"
+#include "KrbProtocol.hpp"
+#include <errno.h>
+#include <sstream>
+
+#include "common/config.h"
+#include "common/debug.h"
+
+#define dout_subsys ceph_subsys_auth
+#undef dout_prefix
+#define dout_prefix *_dout << "krb5/gssapi service: " << entity_name <<  " : "
+
+
+int KrbServiceHandler::handle_request(bufferlist::const_iterator& indata, 
+                                      bufferlist& buff_list, 
+                                      uint64_t& global_id, 
+                                      AuthCapsInfo& caps) 
+{
+  auto result(0);
+  gss_buffer_desc gss_buffer_in = {0, nullptr};
+  gss_name_t gss_client_name = GSS_C_NO_NAME;
+  gss_OID gss_object_id = {0};
+  OM_uint32 gss_major_status(0); 
+  OM_uint32 gss_minor_status(0);
+  OM_uint32 gss_result_flags(0); 
+  std::string status_str(" ");
+
+  ldout(cct, 20) 
+      << "KrbServiceHandler::handle_request() " << dendl; 
+
+  KrbRequest krb_request; 
+  KrbTokenBlob krb_token; 
+
+  using ceph::decode;
+  decode(krb_request, indata); 
+  decode(krb_token, indata);
+
+  gss_buffer_in.length = krb_token.m_token_blob.length();
+  gss_buffer_in.value  = krb_token.m_token_blob.c_str();
+
+  ldout(cct, 20) 
+      << "KrbClientHandler::handle_request() : Token Blob: " 
+      << "\n"; 
+  krb_token.m_token_blob.hexdump(*_dout); 
+  *_dout << dendl;
+
+  if (m_gss_buffer_out.length != 0) {
+    gss_release_buffer(&gss_minor_status, 
+                       static_cast<gss_buffer_t>(&m_gss_buffer_out)); 
+  }
+
+  gss_major_status = gss_accept_sec_context(&gss_minor_status, 
+                                            &m_gss_sec_ctx, 
+                                            m_gss_credentials, 
+                                            &gss_buffer_in, 
+                                            GSS_C_NO_CHANNEL_BINDINGS, 
+                                            &gss_client_name, 
+                                            &gss_object_id, 
+                                            &m_gss_buffer_out, 
+                                            &gss_result_flags, 
+                                            nullptr, 
+                                            nullptr);
+  switch (gss_major_status) {
+    case GSS_S_CONTINUE_NEEDED: 
+      {
+        ldout(cct, 20) 
+            << "KrbServiceHandler::handle_response() : "
+               "[KrbServiceHandler(GSS_S_CONTINUE_NEEDED)] " << dendl;
+        result = 0;
+        break;
+      }
+
+    case GSS_S_COMPLETE: 
+      {
+        result = 0;
+        ldout(cct, 20) 
+            << "KrbServiceHandler::handle_response() : "
+               "[KrbServiceHandler(GSS_S_COMPLETE)] " << dendl; 
+        if (!m_key_server->get_service_caps(entity_name, 
+                                            CEPH_ENTITY_TYPE_MON, 
+                                            caps)) {
+          result = (-EACCES);
+          ldout(cct, 0)
+              << "KrbServiceHandler::handle_response() : "
+                 "ERROR: Could not get MONITOR CAPS : " << entity_name << dendl;
+        } else {
+          if (!caps.caps.c_str()) {
+            result = (-EACCES);
+            ldout(cct, 0)
+                << "KrbServiceHandler::handle_response() : "
+                   "ERROR: MONITOR CAPS invalid : " << entity_name << dendl;
+          }
+        }
+        break;
+      }
+            
+    default: 
+      {
+        status_str = gss_auth_show_status(gss_major_status, 
+                                          gss_minor_status);
+        ldout(cct, 0) 
+            << "ERROR: KrbServiceHandler::handle_response() "
+               "[gss_accept_sec_context()] failed! " 
+            << gss_major_status << " " 
+            << gss_minor_status << " " 
+            << status_str 
+            << dendl;
+        result = (-EPERM);
+        break;
+      }
+  }
+
+  if (m_gss_buffer_out.length != 0) {
+    KrbResponse krb_response;
+    KrbTokenBlob krb_token;
+    krb_response.m_response_type = 
+        static_cast<int>(GSSAuthenticationRequest::GSS_TOKEN);
+
+    using ceph::encode;
+    encode(krb_response, buff_list);
+
+    krb_token.m_token_blob.append(buffer::create_static(
+                                    m_gss_buffer_out.length, 
+                                    reinterpret_cast<char*>
+                                      (m_gss_buffer_out.value)));
+    encode(krb_token, buff_list);
+    ldout(cct, 20) 
+        << "KrbServiceHandler::handle_request() : Token Blob: " << "\n"; 
+    krb_token.m_token_blob.hexdump(*_dout);
+    *_dout << dendl;
+  }
+  gss_release_name(&gss_minor_status, &gss_client_name);
+  return result;
+}
+
+int KrbServiceHandler::start_session(EntityName& name, 
+                                     bufferlist::const_iterator& indata, 
+                                     bufferlist& buff_list,
+                                     AuthCapsInfo& caps)
+{
+  gss_buffer_desc gss_buffer_in = {0, nullptr};
+  gss_OID gss_object_id = GSS_C_NT_HOSTBASED_SERVICE;
+  gss_OID_set gss_mechs_wanted = GSS_C_NO_OID_SET;
+  OM_uint32 gss_major_status(0); 
+  OM_uint32 gss_minor_status(0);
+  std::string gss_service_name(cct->_conf.get_val<std::string>
+                                            ("gss_target_name"));
+
+  gss_buffer_in.length = gss_service_name.length();
+  gss_buffer_in.value  = (const_cast<char*>(gss_service_name.c_str()));
+  entity_name = name;
+
+  gss_major_status = gss_import_name(&gss_minor_status, 
+                                     &gss_buffer_in, 
+                                     gss_object_id, 
+                                     &m_gss_service_name);
+  if (gss_major_status != GSS_S_COMPLETE) {
+    auto status_str(gss_auth_show_status(gss_major_status, 
+                                         gss_minor_status));
+    ldout(cct, 0) 
+        << "ERROR: KrbServiceHandler::start_session() "
+           "[gss_import_name(gss_client_name)] failed! " 
+        << gss_major_status << " " 
+        << gss_minor_status << " " 
+        << status_str 
+        << dendl;
+  }
+
+  gss_major_status = gss_acquire_cred(&gss_minor_status, 
+                                      m_gss_service_name, 
+                                      0, 
+                                      gss_mechs_wanted, 
+                                      GSS_C_ACCEPT, 
+                                      &m_gss_credentials, 
+                                      nullptr, 
+                                      nullptr);
+  if (gss_major_status != GSS_S_COMPLETE) {
+    auto status_str(gss_auth_show_status(gss_major_status, 
+                                         gss_minor_status));
+    ldout(cct, 0) 
+        << "ERROR: KrbServiceHandler::start_session() "
+           "[gss_acquire_cred()] failed! " 
+        << gss_major_status << " " 
+        << gss_minor_status << " " 
+        << status_str 
+        << dendl;
+    return (-EPERM);
+  } else {
+    KrbResponse krb_response;
+    krb_response.m_response_type = 
+        static_cast<int>(GSSAuthenticationRequest::GSS_MUTUAL);
+
+    using ceph::encode;
+    encode(krb_response, buff_list);
+    return (CEPH_AUTH_GSS);
+  }
+}
+
+KrbServiceHandler::~KrbServiceHandler()
+{
+  OM_uint32 gss_minor_status(0); 
+
+  gss_release_name(&gss_minor_status, &m_gss_service_name);
+  gss_release_cred(&gss_minor_status, &m_gss_credentials); 
+  gss_delete_sec_context(&gss_minor_status, &m_gss_sec_ctx, GSS_C_NO_BUFFER); 
+  gss_release_buffer(&gss_minor_status, static_cast<gss_buffer_t>(&m_gss_buffer_out)); 
+}
+
diff --git a/src/auth/krb/KrbServiceHandler.hpp b/src/auth/krb/KrbServiceHandler.hpp
new file mode 100644 (file)
index 0000000..692a7eb
--- /dev/null
@@ -0,0 +1,60 @@
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+/*
+ * Ceph - scalable distributed file system
+ *
+ * Copyright (c) 2018 SUSE LLC.
+ * Author: Daniel Oliveira <doliveira@suse.com>
+ * 
+ * This is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software
+ * Foundation.  See file COPYING.
+ *
+ */
+
+#ifndef KRB_SERVICE_HANDLER_HPP
+#define KRB_SERVICE_HANDLER_HPP
+
+#include "auth/AuthServiceHandler.h"
+#include "auth/Auth.h"
+#include "auth/cephx/CephxKeyServer.h"
+
+#include <gssapi.h>
+#include <gssapi/gssapi_generic.h>
+#include <gssapi/gssapi_krb5.h>
+#include <gssapi/gssapi_ext.h>
+
+
+class KrbServiceHandler : public AuthServiceHandler {
+
+  public:
+    explicit KrbServiceHandler(CephContext* ceph_ctx, KeyServer* kserver) : 
+      AuthServiceHandler(ceph_ctx), 
+      m_gss_buffer_out({0, nullptr}), 
+      m_gss_credentials(GSS_C_NO_CREDENTIAL), 
+      m_gss_sec_ctx(GSS_C_NO_CONTEXT), 
+      m_gss_service_name(GSS_C_NO_NAME), 
+      m_key_server(kserver) { }
+    ~KrbServiceHandler();
+    int handle_request(bufferlist::const_iterator& indata, 
+                       bufferlist& buff_list, 
+                       uint64_t& global_id, 
+                       AuthCapsInfo& caps) override;
+
+    int start_session(EntityName& name, 
+                      bufferlist::const_iterator& indata, 
+                      bufferlist& buff_list, 
+                      AuthCapsInfo& caps) override;
+
+  private: 
+    gss_buffer_desc m_gss_buffer_out; 
+    gss_cred_id_t m_gss_credentials; 
+    gss_ctx_id_t m_gss_sec_ctx; 
+    gss_name_t m_gss_service_name; 
+    KeyServer* m_key_server;
+
+};
+
+#endif    //-- KRB_SERVICE_HANDLER_HPP
+
diff --git a/src/auth/krb/KrbSessionHandler.hpp b/src/auth/krb/KrbSessionHandler.hpp
new file mode 100644 (file)
index 0000000..e01b6de
--- /dev/null
@@ -0,0 +1,54 @@
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+/*
+ * Ceph - scalable distributed file system
+ *
+ * Copyright (c) 2018 SUSE LLC.
+ * Author: Daniel Oliveira <doliveira@suse.com>
+ * 
+ * This is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software
+ * Foundation.  See file COPYING.
+ *
+ */
+
+#ifndef KRB_SESSION_HANDLER_HPP
+#define KRB_SESSION_HANDLER_HPP
+
+#include "auth/AuthSessionHandler.h"
+#include "auth/Auth.h"
+
+#include "KrbProtocol.hpp"
+#include <errno.h>
+#include <sstream>
+
+#include "common/config.h"
+#include "include/ceph_features.h"
+#include "msg/Message.h"
+#define dout_subsys ceph_subsys_auth
+
+
+class CephContext;
+class Message;
+
+class KrbSessionHandler : public AuthSessionHandler {
+
+  public:
+    KrbSessionHandler(CephContext* ceph_ctx, CryptoKey session_key) : 
+        AuthSessionHandler(ceph_ctx, CEPH_AUTH_GSS, session_key) { }
+    ~KrbSessionHandler() override = default; 
+
+    bool no_security() override { return true; }
+    int sign_message(Message* msg) override { return 0; }
+    int check_message_signature(Message* msg) override { return 0; }
+    int encrypt_message(Message* msg) override { return 0; }
+    int decrypt_message(Message* msg) override { return 0; }
+
+  private:
+};
+
+#endif    //-- KRB_SESSION_HANDLER_HPP
+
+
index 2ed6e83f71b0ffcdd252b960ca4cbdc581ed473b..3d03c32b6e5d60d83b2e8631e78e381dcb9be18d 100644 (file)
@@ -5021,7 +5021,18 @@ std::vector<Option> get_global_options() {
     .set_description("Method used to predict device failures")
     .set_long_description("To disable prediction, use 'none',  'local' uses a prediction model that runs inside the mgr daemon.  'cloud' will share metrics with a cloud service and query the service for devicelife expectancy."),
 
-
+    /*  KRB Authentication. */
+    Option("gss_ktab_client_file", Option::TYPE_STR, Option::LEVEL_ADVANCED)
+    .set_default("/var/lib/ceph/$name/gss_client_$name.ktab")
+    .set_description("GSS/KRB5 Keytab file for client authentication")
+    .add_service({"mon", "osd"})
+    .set_long_description("This sets the full path for the GSS/Kerberos client keytab file location."),
+
+    Option("gss_target_name", Option::TYPE_STR, Option::LEVEL_ADVANCED)
+    .set_default("ceph")
+    .set_description("")
+    .add_service({"mon", "osd"})
+    .set_long_description("This sets the gss target service name."),
   });
 }
 
index b4f4cbea6e78bfc8bd4cbf700eec332b5756efaa..84708338c2c7a14428a6a5530581798d5d4f10d6 100644 (file)
@@ -73,6 +73,16 @@ struct ceph_dir_layout {
 #define CEPH_AUTH_NONE         0x1
 #define CEPH_AUTH_CEPHX                0x2
 
+/*  For options with "_", like: GSS_GSS
+    which means: Mode/Protocol to validate "authentication_authorization",
+    where:
+      - Authentication: Verifying the identity of an entity.
+      - Authorization:  Verifying that an authenticated entity has
+                        the right to access a particular resource.
+*/ 
+#define CEPH_AUTH_GSS     0x4
+#define CEPH_AUTH_GSS_GSS CEPH_AUTH_GSS
+
 #define CEPH_AUTH_UID_DEFAULT ((__u64) -1)
 
 
index 4985e824baadf8f0e7c0a234c9798cd7bc26b062..c2f68f648c1ef228ee9f50e5076e49a7ae720029 100644 (file)
@@ -41,7 +41,8 @@ endif()
 target_link_libraries(librados PRIVATE
   rados_cxx librados_impl
   osdc ceph-common cls_lock_client
-  ${BLKID_LIBRARIES} ${CRYPTO_LIBS} ${EXTRALIBS})
+  ${BLKID_LIBRARIES} ${CRYPTO_LIBS} ${EXTRALIBS} ${GSSAPI_LIBRARIES})
+target_link_libraries(librados ${rados_libs})
 install(TARGETS librados DESTINATION ${CMAKE_INSTALL_LIBDIR})
 
 # C++ API
index 38d625f10d316b7a92e3f1fd60e03bea0680dd27..1969abeb034c7d358acb50b1b54ed9352515539b 100644 (file)
@@ -161,7 +161,7 @@ target_link_libraries(librbd PRIVATE
   ceph-common
   pthread
   ${CMAKE_DL_LIBS}
-  ${EXTRALIBS})
+  ${EXTRALIBS} ${GSSAPI_LIBRARIES})
 if(HAVE_UDEV)
   target_link_libraries(librbd PRIVATE
     udev)
index 079227cb63ecfdab020ef4004306fdf77d623cbf..56ea3324b2b692d494f4ea70cabbd7d968d07e5a 100644 (file)
@@ -66,6 +66,7 @@ MDSDaemon::MDSDaemon(std::string_view n, Messenger *m, MonClient *mc) :
   mds_lock("MDSDaemon::mds_lock"),
   stopping(false),
   timer(m->cct, mds_lock),
+  gss_ktfile_client(m->cct->_conf.get_val<std::string>("gss_ktab_client_file")),
   beacon(m->cct, mc, n),
   authorize_handler_cluster_registry(new AuthAuthorizeHandlerRegistry(m->cct,
                                                                      m->cct->_conf->auth_supported.empty() ?
@@ -88,6 +89,21 @@ MDSDaemon::MDSDaemon(std::string_view n, Messenger *m, MonClient *mc) :
   orig_argv = NULL;
 
   clog = log_client.create_channel();
+  if (!gss_ktfile_client.empty()) {
+    // Assert we can export environment variable 
+    /* 
+        The default client keytab is used, if it is present and readable,
+        to automatically obtain initial credentials for GSSAPI client
+        applications. The principal name of the first entry in the client
+        keytab is used by default when obtaining initial credentials.
+        1. The KRB5_CLIENT_KTNAME environment variable.
+        2. The default_client_keytab_name profile variable in [libdefaults].
+        3. The hardcoded default, DEFCKTNAME.
+    */
+    const int32_t set_result(setenv("KRB5_CLIENT_KTNAME", 
+                                    gss_ktfile_client.c_str(), 1));
+    ceph_assert(set_result == 0);
+  }
 
   monc->set_messenger(messenger);
 
index 83a9240fb3a4c53f994bcda405fb9db98e07b228..41b36cb99616dbc85f0a8199b83e996ec3139163 100644 (file)
@@ -51,7 +51,7 @@ class MDSDaemon : public Dispatcher, public md_config_obs_t {
   bool         stopping;
 
   SafeTimer    timer;
-
+  std::string gss_ktfile_client{};
 
   mono_time get_starttime() const {
     return starttime;
index f8b12747c6032af47594018f581d81fcfc0cfd8c..252fb3e5e317f25f9119813e31ffbc2a22d1b438 100644 (file)
@@ -27,7 +27,7 @@ target_link_libraries(ceph-mgr
   osdc client heap_profiler
   global-static ceph-common
   Boost::python${MGR_PYTHON_VERSION_MAJOR}${MGR_PYTHON_VERSION_MINOR}
-  ${MGR_PYTHON_LIBRARIES} ${CMAKE_DL_LIBS})
+  ${MGR_PYTHON_LIBRARIES} ${CMAKE_DL_LIBS} ${GSSAPI_LIBRARIES})
 set_target_properties(ceph-mgr PROPERTIES
   POSITION_INDEPENDENT_CODE ${EXE_LINKER_USE_PIE})
 install(TARGETS ceph-mgr DESTINATION bin)
index ca73bc04746b1912be8fc5e95fbcc8f94aca06aa..d0dde1fcd4cb31dcea331baa846565042e9d114f 100644 (file)
@@ -2,6 +2,7 @@ set(lib_mon_srcs
   ${CMAKE_SOURCE_DIR}/src/auth/cephx/CephxKeyServer.cc
   ${CMAKE_SOURCE_DIR}/src/auth/cephx/CephxServiceHandler.cc
   ${CMAKE_SOURCE_DIR}/src/auth/AuthServiceHandler.cc
+  ${CMAKE_SOURCE_DIR}/src/auth/krb/KrbServiceHandler.cpp
   ${osd_mon_files}
   Paxos.cc
   PaxosService.cc
index 9194cabb95fbc4d8ed9f828c8d79707a6390146f..83561803e3b38b21f8f620dc44f37725efbf79e9 100644 (file)
@@ -165,6 +165,7 @@ private:
   bool initialized;
   bool stopping = false;
   bool no_keyring_disabled_cephx;
+  bool no_ktfile_disabled_krb;
 
   LogClient *log_client;
   bool more_log_pending;
index 01c1cc877a08dca49f815988126d60227e5292fa..98dd216bfa160612ad89eab108d5c3bc16426953 100644 (file)
@@ -146,9 +146,10 @@ Monitor::Monitor(CephContext* cct_, string nm, MonitorDBStore *s,
                        cct->_conf->auth_cluster_required : cct->_conf->auth_supported),
   auth_service_required(cct,
                        cct->_conf->auth_supported.empty() ?
-                       cct->_conf->auth_service_required : cct->_conf->auth_supported ),
+                       cct->_conf->auth_service_required : cct->_conf->auth_supported),
   mgr_messenger(mgr_m),
   mgr_client(cct_, mgr_m),
+  gss_ktfile_client(cct->_conf.get_val<std::string>("gss_ktab_client_file")),
   store(s),
   
   state(STATE_PROBING),
@@ -185,6 +186,22 @@ Monitor::Monitor(CephContext* cct_, string nm, MonitorDBStore *s,
 
   update_log_clients();
 
+  if (!gss_ktfile_client.empty()) {
+    // Assert we can export environment variable 
+    /* 
+        The default client keytab is used, if it is present and readable,
+        to automatically obtain initial credentials for GSSAPI client
+        applications. The principal name of the first entry in the client
+        keytab is used by default when obtaining initial credentials.
+        1. The KRB5_CLIENT_KTNAME environment variable.
+        2. The default_client_keytab_name profile variable in [libdefaults].
+        3. The hardcoded default, DEFCKTNAME.
+    */
+    const int32_t set_result(setenv("KRB5_CLIENT_KTNAME", 
+                                    gss_ktfile_client.c_str(), 1));
+    ceph_assert(set_result == 0);
+  }
+
   op_tracker.set_complaint_and_threshold(
       g_conf().get_val<std::chrono::seconds>("mon_op_complaint_time").count(),
       g_conf().get_val<int64_t>("mon_op_log_threshold"));
@@ -2890,8 +2907,10 @@ void Monitor::format_command_descriptions(const std::vector<MonCommand> &command
 
 bool Monitor::is_keyring_required()
 {
-  return auth_cluster_required.is_supported_auth(CEPH_AUTH_CEPHX) ||
-    auth_service_required.is_supported_auth(CEPH_AUTH_CEPHX);
+  return auth_cluster_required.is_supported_auth(CEPH_AUTH_CEPHX) || 
+         auth_service_required.is_supported_auth(CEPH_AUTH_CEPHX) || 
+         auth_cluster_required.is_supported_auth(CEPH_AUTH_GSS)   || 
+         auth_service_required.is_supported_auth(CEPH_AUTH_GSS);
 }
 
 struct C_MgrProxyCommand : public Context {
index 3c2685ae45f4774cf0d11187fe343eddcc828903..177102e6768d7aa0ca383016f810cf87b48f7136 100644 (file)
@@ -25,6 +25,7 @@
 
 #include <errno.h>
 #include <cmath>
+#include <string>
 
 #include "include/types.h"
 #include "include/health.h"
@@ -168,6 +169,7 @@ public:
   Messenger *mgr_messenger;
   MgrClient mgr_client;
   uint64_t mgr_proxy_bytes = 0;  // in-flight proxied mgr command message bytes
+  std::string gss_ktfile_client{};
 
 private:
   void new_tick();
index 8f3bd8e6afc80faf168ef6db023f609f1ea93a33..093d430e7502d814d372dcaff15ba0e6f7c25703 100644 (file)
@@ -2046,6 +2046,7 @@ OSD::OSD(CephContext *cct_, ObjectStore *store_,
   tick_timer(cct, osd_lock),
   tick_timer_lock("OSD::tick_timer_lock"),
   tick_timer_without_osd_lock(cct, tick_timer_lock),
+  gss_ktfile_client(cct->_conf.get_val<std::string>("gss_ktab_client_file")),
   authorize_handler_cluster_registry(new AuthAuthorizeHandlerRegistry(cct,
                                                                      cct->_conf->auth_supported.empty() ?
                                                                      cct->_conf->auth_cluster_required :
@@ -2111,6 +2112,23 @@ OSD::OSD(CephContext *cct_, ObjectStore *store_,
     &command_tp),
   service(this)
 {
+
+  if (!gss_ktfile_client.empty()) {
+    // Assert we can export environment variable 
+    /* 
+        The default client keytab is used, if it is present and readable,
+        to automatically obtain initial credentials for GSSAPI client
+        applications. The principal name of the first entry in the client
+        keytab is used by default when obtaining initial credentials.
+        1. The KRB5_CLIENT_KTNAME environment variable.
+        2. The default_client_keytab_name profile variable in [libdefaults].
+        3. The hardcoded default, DEFCKTNAME.
+    */
+    const int32_t set_result(setenv("KRB5_CLIENT_KTNAME", 
+                                    gss_ktfile_client.c_str(), 1));
+    ceph_assert(set_result == 0);
+  }
+
   monc->set_messenger(client_messenger);
   op_tracker.set_complaint_and_threshold(cct->_conf->osd_op_complaint_time,
                                          cct->_conf->osd_op_log_threshold);
index c8e0cea6a81d18f101d271ec908cb9cbfbb7bd90..c0977cb5eff8cc659570b407de610a0d770e7c7f 100644 (file)
@@ -46,6 +46,7 @@
 #include <atomic>
 #include <map>
 #include <memory>
+#include <string>
 
 #include "include/unordered_map.h"
 
@@ -1259,6 +1260,8 @@ class OSD : public Dispatcher,
   // Tick timer for those stuff that do not need osd_lock
   Mutex tick_timer_lock;
   SafeTimer tick_timer_without_osd_lock;
+  std::string gss_ktfile_client{};
+
 public:
   // config observer bits
   const char** get_tracked_conf_keys() const override;
index f9eb45b5bd8c7071a729c893dd844ed3bc7eaf28..9d58ab48655b840d7134532f5b6d5bd2b650ee9b 100644 (file)
@@ -1,6 +1,7 @@
 include(AddCephTest)
 
-set(UNITTEST_LIBS GMock::Main GMock::GMock GTest::GTest ${CMAKE_THREAD_LIBS_INIT} ${CMAKE_DL_LIBS})
+set(UNITTEST_LIBS GMock::Main GMock::GMock GTest::GTest ${CMAKE_THREAD_LIBS_INIT} 
+    ${GSSAPI_LIBRARIES} ${OPENLDAP_LIBRARIES} ${CMAKE_DL_LIBS})
 
 add_library(unit-main OBJECT unit.cc)
 target_include_directories(unit-main PRIVATE
index 1e7ccff92f1c41df4876426d4f39420155f0aa10..e4b3011d3ff2aa0bb8b7b206beb01bfe91e4e1eb 100644 (file)
@@ -12,7 +12,7 @@ target_link_libraries(radostest PUBLIC
   GTest::GTest
   ceph-common
   json_spirit
-  ${EXTRALIBS})
+  ${GSSAPI_LIBRARIES} ${OPENLDAP_LIBRARIES} ${EXTRALIBS})
 add_library(radostest-cxx STATIC
   testcase_cxx.cc
   test_cxx.cc
@@ -175,7 +175,8 @@ add_executable(unittest_librados
   librados.cc
   )
 add_ceph_unittest(unittest_librados)
-target_link_libraries(unittest_librados librados ${BLKID_LIBRARIES})
+target_link_libraries(unittest_librados librados ${BLKID_LIBRARIES}
+       ${GSSAPI_LIBRARIES} ${OPENLDAP_LIBRARIES})
 
 # unittest_librados_config
 add_executable(unittest_librados_config
@@ -184,6 +185,5 @@ add_executable(unittest_librados_config
 add_ceph_unittest(unittest_librados_config)
 target_link_libraries(unittest_librados_config
   librados
-  ${BLKID_LIBRARIES}
-  )
+  ${BLKID_LIBRARIES} ${GSSAPI_LIBRARIES} ${OPENLDAP_LIBRARIES})
 
index 6977269cde3ba966223e62909931282bcf8efabc..6d9a3c540b8806b8a32ec070fab48800d2d02e2c 100644 (file)
@@ -721,7 +721,6 @@ TEST_P(MessengerTest, AuthTest) {
   }
   ASSERT_TRUE(conn->is_connected());
   ASSERT_EQ(1U, static_cast<Session*>(conn->get_priv().get())->get_count());
-
   server_msgr->shutdown();
   client_msgr->shutdown();
   server_msgr->wait();
index 2f6d2608005b7e3630f5f9d551676bfd254d1e04..15ca56eedcc3e8743a9345401cdc79c9312d62ed 100755 (executable)
@@ -121,6 +121,7 @@ ec=0
 hitset=""
 overwrite_conf=1
 cephx=1 #turn cephx on by default
+gssapi_authx=0
 cache=""
 if [ `uname` = FreeBSD ]; then
     objectstore="filestore"
@@ -169,6 +170,8 @@ usage=$usage"\t-m ip:port\t\tspecify monitor address\n"
 usage=$usage"\t-k keep old configuration files\n"
 usage=$usage"\t-x enable cephx (on by default)\n"
 usage=$usage"\t-X disable cephx\n"
+usage=$usage"\t-g --gssapi enable Kerberos/GSSApi authentication\n"
+usage=$usage"\t-G disable Kerberos/GSSApi authentication\n"
 usage=$usage"\t--hitset <pool> <hit_set_type>: enable hitset tracking\n"
 usage=$usage"\t-e : create an erasure pool\n";
 usage=$usage"\t-o config\t\t add extra config parameters to all sections\n"
@@ -290,6 +293,14 @@ case $1 in
     -X )
            cephx=0
            ;;
+    
+    -g | --gssapi)
+           gssapi_authx=1 
+           ;;
+    -G)
+           gssapi_authx=0 
+           ;;
+
     -k )
            if [ ! -r $conf_fn ]; then
                echo "cannot use old configuration: $conf_fn not readable." >&2
@@ -483,7 +494,20 @@ EOF
         lockdep = true
 EOF
        fi
-       if [ "$cephx" -ne 1 ] ; then
+       if [ "$cephx" -eq 1 ] ; then
+               wconf <<EOF
+       auth cluster required = cephx
+       auth service required = cephx
+       auth client required = cephx
+EOF
+       elif [ "$gssapi_authx" -eq 1 ] ; then
+               wconf <<EOF
+       auth cluster required = gss
+       auth service required = gss
+       auth client required = gss
+       gss ktab client file = $CEPH_DEV_DIR/gss_\$name.keytab
+EOF
+       else 
                wconf <<EOF
        auth cluster required = none
        auth service required = none