New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
rgw / kmip kms #33996
rgw / kmip kms #33996
Conversation
src/rgw/rgw_kms.cc
Outdated
{ | ||
RGWKMIPTransceiver secret_req(cct, RGWKMIPTransceiver::LOCATE); | ||
|
||
secret_req.name = (char *) work.c_str(); // XXX ugh constness |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
c++17 added a non-const std::string::data()
, so this can just be secret_req.name = work.data();
protected: | ||
KmipGetTheKey(CephContext *cct) : cct(cct) {} | ||
KmipGetTheKey& keyid_to_keyname(boost::string_view key_id); | ||
KmipGetTheKey& get_uniqueid_for_keyname(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the builder pattern feels really awkward here. std::string work
has a different meaning between the steps, and each step has to check failed
instead of returning errors directly. can we refactor KmipGetTheKey into static functions that return int and take their state as arguments?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it's kind of the basic idea of the class; work is an internal state; it would be similar to object to the fact that kmip_client is basically std C, constantly allocating objects and buffers that you wouldn't in modern c++--I'm tempted, but it seems better to ask "does it work?" and then valgrind it
@@ -301,6 +304,7 @@ int radosgw_Main(int argc, const char **argv) | |||
rgw_init_resolver(); | |||
rgw::curl::setup_curl(fe_map); | |||
rgw_http_client_init(g_ceph_context); | |||
rgw_kmip_client_init(*new RGWKMIPManagerImpl(g_ceph_context)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can init() just take g_ceph_context
to hide the dependency on RGWKMIPManagerImpl
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should we be relying on g_ceph_context?
src/rgw/rgw_kmip_client_impl.cc
Outdated
} | ||
RGWKmipHandleBuilder& set_username(const std::string &v) { | ||
const char *s = v.c_str(); | ||
if (*s) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
std::string::c_str() will not return null
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's good, because if it did, "*s" would core dump. What it's actually checking is that there is at least one non-nul character, ie, not the empty string. The empty string is the default in the config logic and this code interprets that to mean "don't do password authentication", which is a required feature.
@mdw-at-linuxbox you mentioned that SKLM has new REST apis; if we're able to use those, that could simplify things quite a bit. it would also make it easier to support coroutines, since optional_yield is already built into the http client |
@cbodley I'm editing my comment here. I don't think that using libkmip is an inappropriate integration path--in fact, it's desirable because it is an OASIS standard which, we hope, will allow us to interop with other KMIP-enabled key management implementations |
@cbodley @mdw-at-linuxbox updated comment on libmip integration |
This pull request has been automatically marked as stale because it has not had any activity for 60 days. It will be closed if no further activity occurs for another 30 days. |
e8bdbf9
to
4112db2
Compare
I believe sklm's rest interface is unique to it - not likely to work with anything else. I pushed an update to this rebased against the latest master. |
@mdw-at-linuxbox can we get an update to this PR and allow it to merge upstream? |
This pull request has been automatically marked as stale because it has not had any activity for 60 days. It will be closed if no further activity occurs for another 30 days. |
e641e7c
to
afe10be
Compare
This is based on a fresher copy of master. |
afe10be
to
3df0e5b
Compare
I pushed a new version: rebased on later master, & some fixes for string handling recommended by reviewers above. I don't know if this will please "make check", - if not now I know to save the complaints before the details evaporate. |
6cd68a1
to
8de47c3
Compare
"make check" objected to the pykmip teuthology task. I've revamped that and verified it could deploy pykmip in a toy environment. |
c951d11
to
a990aae
Compare
jenkins render docs |
Doc render available at https://ceph--33996.org.readthedocs.build/en/33996/ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nice work on docs!
src/rgw/rgw_kmip_client.h
Outdated
ceph::mutex lock = ceph::make_mutex("rgw_kmip_req::lock"); | ||
ceph::condition_variable cond; | ||
|
||
int wait(optional_yield y); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if wait()
and process()
don't support yielding on the coroutine, they shouldn't take an optional_yield
src/rgw/rgw_kms.cc
Outdated
#if 0 | ||
std::string secret_engine = cct->_conf->rgw_crypt_vault_secret_engine; | ||
ldout(cct, 20) << "Vault authentication method: " << cct->_conf->rgw_crypt_vault_auth << dendl; | ||
ldout(cct, 20) << "Vault Secrets Engine: " << secret_engine << dendl; | ||
#endif |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
please don't leave dead code
src/rgw/rgw_kmip_client_impl.cc
Outdated
explicit RGWKmipHandle() : | ||
uses(0), ctx(0), ssl(0), bio(0), | ||
need_to_free_kmip(0), | ||
encoding(0) { | ||
memset(kmip_ctx, 0, sizeof kmip_ctx); | ||
memset(textstrings, 0, sizeof textstrings); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: please follow ceph's https://github.com/ceph/ceph/blob/master/CodingStyle#L76-L82 re: two-space indentation
doc/radosgw/encryption.rst
Outdated
See `OpenStack Barbican Integration`_, `HashiCorp Vault Integration`_. | ||
and `KMIP Integration`_. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
comma instead of period between HashiCorp Vault Integration. and KMIP Integration.
@mdw-at-linuxbox can you please expedite pushing an update addressing @cbodley comments from 2/11/2020? |
b4b172d
to
99aa7e0
Compare
#. `Upload object`_ | ||
|
||
Before you can use KMIP with Ceph, you will need to do three things. | ||
You will need to associate ceph with client information in KMIP, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
do we care about consistently capitalizing (or not) Ceph?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I dunno. In the doc directory, there are:
3106 Ceph
30976 ceph
8 CEPH
and there are 51 occurrence of "with Ceph". Granted, I'm not being terribly consistent even with myself. I was more worried about how to spell SKLM, especially since IBM seems to have renamed it.
doc/radosgw/kmip.rst
Outdated
using SKLM. Ceph should then be configured (see below) to | ||
use KMIP and an attempt made to use it. This will fail, | ||
but it will leave an "untrusted client device certificate" in SKLM. | ||
interface to complete the registration process. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
sentence fragment here--was it trying to say "Use the SKLM" (interface) and continuing?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What sentence fragment? "Certificates may be created using SKLM." is no fragment. I think in this case github diff formatting is making mental mush with its helpful line rapping.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
but it will leave an "untrusted client device certificate in SKLM. <-- full stop here
interface to complete the registration process. (so, is "interface to complete..." connected to certificate in SKLM?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah! Yes, that is a fragment. Will fix.
doc/radosgw/kmip.rst
Outdated
You may need to change the paths above to match where | ||
you actually want to store kmip certificate data. | ||
|
||
The kmis key template describes how ceph will modify |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
kmis?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
typo, will fix.
src/rgw/rgw_kmip_client_impl.cc
Outdated
TextString *up = 0; | ||
size_t ns; | ||
|
||
//?? OPENSSL_init_ssl(0, NULL); // XXX |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
commented code
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right, fossil, I'll remove it.
src/rgw/rgw_kmip_client_impl.cc
Outdated
} | ||
if (kmip) { | ||
} else if (!hostaddr) { | ||
// kmip = 0; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
commented code
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
well, it helped me. Evidently not helpful to others; I'll remove.
src/rgw/rgw_kmip_client_impl.cc
Outdated
if (cleaner_shutdown) { | ||
release_kmip_handle_now(kmip); | ||
} else { | ||
// kmip_easy_reset(**kmip); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
commented code
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this was meant to be a place to recycle any sticky bits in the handle once I had them, similar to how curl works. Only problem is I never had any sticky bits. I'll remove this.
RGWKMIPTransceiver &details; | ||
Request(RGWKMIPTransceiver &details) : details(details) {} | ||
}; | ||
boost::intrusive::list<Request, boost::intrusive::member_hook< Request, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
still love seeing boost::intrusive::list
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
glad you liked it.
qa/tasks/pykmip.py
Outdated
key1_json = json.dumps( | ||
{ | ||
"name": secret['name'], | ||
"expiration": "2020-12-31T19:14:44.180394", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what is this date literal (in the past) doing for us?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(does it represent an expired key?)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This code was inherited from task keystone. You'll notice the rest of this method is doing keystone things involving json & http, not kmip things. And it starts off with a try/yield/finally block which in teuthlogy land is a standard no-op. A later commit "rgw/kms/kmip - pykmip.py needs to make keys too." replaces all of this with code that actually works--and is much shorter.
A terrible way to fix this would be to go back and remove the placeholder code from the old commit. It's terrible because this placeholder code in fact has the tested behavior that it does nothing without breaking (and yet is clearly Just Wrong), and any replacement code would (should) be tested to verify the same behavior. Another way to fix this would be to squash this commit in with the earlier code - that's not bad except it loses the commit message which I think might actually be helpful but I don't think belongs inline with the code.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok
qa/tasks/pykmip.py
Outdated
""" | ||
assert config is None or isinstance(config, list) \ | ||
or isinstance(config, dict), \ | ||
"task keystone only supports a list or dictionary for configuration" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
task keystone?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, "task keystone". I dunno, think "Japanese manga?" It's exactly the same language used in 14 other teuthology tasks for about the same problem, so I think this should stay as is.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok
I pushed fixes to the issues cbodley addressed above (+rebase to latest master) - looks like there are yet more issues to resolve. |
99aa7e0
to
2f9c791
Compare
I've pushed an update that (1) addresses various nits above, and (2) is rebased on the latest master. The vault PR also contains all these commits; I plan to run that through ceph-ci + teuthology. |
Signed-off-by: Marcus Watts <mwatts@redhat.com>
Signed-off-by: Marcus Watts <mwatts@redhat.com>
Signed-off-by: Marcus Watts <mwatts@redhat.com>
First pass at configuration configuration for kmip. Signed-off-by: Marcus Watts <mwatts@redhat.com>
This implements SSE-KMS for the radosgw using kmip. This uses symmetric raw keys with a name attribute in kmip, so providing the same functionality as the "kv" key store in hashicorp vault. Signed-off-by: Marcus Watts <mwatts@redhat.com>
Configure and run a simple pykmip daemon, similar in concept to barbican | vault. Signed-off-by: Marcus Watts <mwatts@redhat.com>
Use string::data and string_view to clean up some string handling, as suggested by reviewers. Signed-off-by: Marcus Watts <mwatts@redhat.com>
The logic to deploy pykmip in teuthology was not complete. While it deployed all the code and certs to run pykmip, it didn't actually run it. This commit fixes that. Signed-off-by: Marcus Watts <mwatts@redhat.com>
The logic to deploy pykmip in teuthology was not complete. The necessary logic to add kmip keys was missing. Existing logic for other key services providers could use rest based protocols directly from the teuthology host. For kmip, it is necessary to use a special protocol, and it is more convenient to run this directly on the pykmip server. Signed-off-by: Marcus Watts <mwatts@redhat.com>
The pykmip task should be after ceph, and before rgw. kmip needs ssl certs in order to function correctly. Because the openssl_keys task has an indeterminate order of execution, it is best to create the ca as a separate task. The ca can be shared with rgw, but real life deployments of kmip are likely to have their own CA. In order to create kmip secrets, a client certificate is necessary, so must be supplied to the pykmip task. Signed-off-by: Marcus Watts <mwatts@redhat.com>
Pass endpoint configuration from pykmip to radosgw at runtime. Signed-off-by: Marcus Watts <mwatts@redhat.com>
s3tests needs to know key names in order to run kms tests. It seems desirable to have s3tests default to discovering the names that were created by the pykmip task, and that if there is more than one rgw connected to more than one pykmip, that names belonging to the appropriate pykmip instance should be used. This logic does the following: rgw task: save pykmip role name. s3tests task: set kms_key (and kms_keyid2) to these in order of priority 1 s3tests client task property ['kms_key'] (or ['kms_key2']) 2 first (second) secret created in the matching pykmip instance. 3 testkey-1 (testkey-2) For case 2, names from the secrets have an initial "token-" stripped from them. The assumption here is that rgw is being run with a setting such as rgw crypt kmip kms key template: pykmip-$keyid therefore "pykmip-" will be prefixed back onto the key before use. Signed-off-by: Marcus Watts <mwatts@redhat.com>
Actually add kmip to the kms crypt suite. This also makes some ssl certs which is required for use of kmip. Signed-off-by: Marcus Watts <mwatts@redhat.com>
I've written up a brief description of using kmip with ceph. Major features: * ceph configuration. * making keys with a "paste-in" python script. * pointers to PyKMIP and IBM SKLM. Signed-off-by: Marcus Watts <mwatts@redhat.com>
2f9c791
to
891bf1a
Compare
The "transit" PR which contains these commits and more needed to be rebased on the latest master. I've done so, and I've pushed the kmip subset patches from that PR to this PR. |
This is a preview of a set of patches to add kmip support to ceph.
Included: new submodule "libkmip", links to build that, logic to use kmip as another kms key provider in ceph, and logic to set up "pykmip" in teuthology.
Need to do,
1/ use ceph repo fo libkmip. (this is a branched version from the upstream for libkmip with significant changes (which they will hopefully adopt...))
2/ more teuthology logic to actually use pykmip...
3/ documentation.
also, apparently, 4/ update to latest master.
I'll update this PR as these things get done.