mirror of
https://github.com/ceph/ceph
synced 2025-02-20 17:37:29 +00:00
Merge PR #23550 into master
* refs/pull/23550/head: auth: Kerberos authentication
This commit is contained in:
commit
59d0844c12
@ -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)
|
||||
|
@ -47,6 +47,7 @@ makedepends="
|
||||
lvm2-dev
|
||||
nss-dev
|
||||
openldap-dev
|
||||
krb5-dev
|
||||
parted
|
||||
procps
|
||||
python-dev
|
||||
|
@ -228,6 +228,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 < 0.29
|
||||
@ -245,6 +247,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
|
||||
|
22
cmake/modules/FindGSSApi.cmake
Normal file
22
cmake/modules/FindGSSApi.cmake
Normal file
@ -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)
|
||||
|
1
debian/control
vendored
1
debian/control
vendored
@ -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),
|
||||
|
1094
doc/dev/ceph_krb_auth.rst
Normal file
1094
doc/dev/ceph_krb_auth.rst
Normal file
File diff suppressed because it is too large
Load Diff
@ -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
|
||||
@ -656,7 +657,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})
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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"
|
||||
|
||||
@ -39,6 +40,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;
|
||||
}
|
||||
|
@ -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)
|
||||
|
||||
|
51
src/auth/krb/KrbAuthorizeHandler.cpp
Normal file
51
src/auth/krb/KrbAuthorizeHandler.cpp
Normal file
@ -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;
|
||||
}
|
||||
|
||||
|
39
src/auth/krb/KrbAuthorizeHandler.hpp
Normal file
39
src/auth/krb/KrbAuthorizeHandler.hpp
Normal file
@ -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
|
||||
|
251
src/auth/krb/KrbClientHandler.cpp
Normal file
251
src/auth/krb/KrbClientHandler.cpp
Normal file
@ -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;
|
||||
}
|
||||
|
78
src/auth/krb/KrbClientHandler.hpp
Normal file
78
src/auth/krb/KrbClientHandler.hpp
Normal file
@ -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
|
||||
|
86
src/auth/krb/KrbProtocol.cpp
Normal file
86
src/auth/krb/KrbProtocol.cpp
Normal file
@ -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;
|
||||
}
|
||||
|
159
src/auth/krb/KrbProtocol.hpp
Normal file
159
src/auth/krb/KrbProtocol.hpp
Normal file
@ -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
|
||||
|
223
src/auth/krb/KrbServiceHandler.cpp
Normal file
223
src/auth/krb/KrbServiceHandler.cpp
Normal file
@ -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));
|
||||
}
|
||||
|
60
src/auth/krb/KrbServiceHandler.hpp
Normal file
60
src/auth/krb/KrbServiceHandler.hpp
Normal file
@ -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
|
||||
|
54
src/auth/krb/KrbSessionHandler.hpp
Normal file
54
src/auth/krb/KrbSessionHandler.hpp
Normal file
@ -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
|
||||
|
||||
|
@ -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."),
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
|
||||
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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 {
|
||||
|
@ -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();
|
||||
|
@ -2049,6 +2049,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 :
|
||||
@ -2114,6 +2115,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);
|
||||
|
@ -46,6 +46,7 @@
|
||||
#include <atomic>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include "include/unordered_map.h"
|
||||
|
||||
@ -1256,6 +1257,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;
|
||||
|
@ -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
|
||||
|
@ -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})
|
||||
|
||||
|
@ -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();
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user