Skip to content

Commit 77d121f

Browse files
committed
Add encryption support to RBD bdev.
Signed-off-by: Gil Bregman <gbregman@il.ibm.com>
1 parent 5fb0c44 commit 77d121f

File tree

6 files changed

+245
-10
lines changed

6 files changed

+245
-10
lines changed

module/bdev/rbd/bdev_rbd.c

Lines changed: 164 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,9 @@ struct bdev_rbd {
4747
char *user_id;
4848
char *pool_name;
4949
char *namespace_name;
50+
uint32_t encryption_entries_count;
51+
uint32_t *encryption_format;
52+
char **passphrase;
5053
char **config;
5154

5255
rados_t cluster;
@@ -231,6 +234,8 @@ bdev_rbd_free(struct bdev_rbd *rbd)
231234
free(rbd->user_id);
232235
free(rbd->pool_name);
233236
free(rbd->namespace_name);
237+
free(rbd->encryption_format);
238+
bdev_rbd_free_passphrase(rbd->passphrase);
234239
bdev_rbd_free_config(rbd->config);
235240

236241
if (rbd->cluster_name) {
@@ -290,6 +295,19 @@ bdev_rbd_dup_config(const char *const *config)
290295
return copy;
291296
}
292297

298+
void
299+
bdev_rbd_free_passphrase(char **passphrase)
300+
{
301+
char **entry;
302+
303+
if (passphrase) {
304+
for (entry = passphrase; *entry; entry++) {
305+
free(*entry);
306+
}
307+
free(passphrase);
308+
}
309+
}
310+
293311
static int
294312
bdev_rados_cluster_init(const char *user_id, const char *const *config,
295313
rados_t *cluster)
@@ -461,6 +479,61 @@ bdev_rbd_get_pool_ctx(rados_t *cluster_p, const char *name, const char *namespac
461479
return -1;
462480
}
463481

482+
static void
483+
bdev_rbd_free_encryption_specs(rbd_encryption_spec_t *specs, uint32_t count)
484+
{
485+
uint32_t i;
486+
487+
if (!specs)
488+
return;
489+
490+
for (i = 0; i < count; i++) {
491+
if (specs[i].format == RBD_ENCRYPTION_FORMAT_LUKS1) {
492+
free((void *)(((rbd_encryption_luks1_format_options_t *)specs[i].opts)->passphrase));
493+
}
494+
else if (specs[i].format == RBD_ENCRYPTION_FORMAT_LUKS2) {
495+
free((void *)(((rbd_encryption_luks2_format_options_t *)specs[i].opts)->passphrase));
496+
}
497+
else if (specs[i].format == RBD_ENCRYPTION_FORMAT_LUKS) {
498+
free((void *)(((rbd_encryption_luks_format_options_t *)specs[i].opts)->passphrase));
499+
}
500+
free(specs[i].opts);
501+
}
502+
free(specs);
503+
}
504+
505+
static int
506+
bdev_rbd_set_passphrase(char **out, size_t *phrasesize, const char *phrase)
507+
{
508+
*out = strdup(phrase);
509+
if (!*out) {
510+
SPDK_ERRLOG("Cannot allocate memory for encryption pass phrase\n");
511+
return -1;
512+
}
513+
*phrasesize = strlen(phrase);
514+
return 0;
515+
}
516+
517+
#define SET_ENC_ENTRY(_specs, _rbd, _index, _fstring, _fmt, _upfmt) \
518+
if ((_rbd)->encryption_format[_index] == RBD_ENCRYPTION_FORMAT_##_upfmt ) { \
519+
rbd_encryption_##_fmt##_format_options_t *opts; \
520+
strcat(_fstring, #_upfmt " "); \
521+
opts = calloc(1, sizeof(*opts)); \
522+
if (!opts) { \
523+
SPDK_ERRLOG("Cannot allocate memory for encryption format options\n"); \
524+
bdev_rbd_free_encryption_specs(_specs, (_rbd)->encryption_entries_count); \
525+
return NULL; \
526+
} \
527+
if (bdev_rbd_set_passphrase((char **)&opts->passphrase, &opts->passphrase_size, (_rbd->passphrase[_index]))) { \
528+
free((char *)opts->passphrase); \
529+
free(opts); \
530+
bdev_rbd_free_encryption_specs(_specs, (_rbd)->encryption_entries_count); \
531+
return NULL; \
532+
} \
533+
_specs[_index].opts = (rbd_encryption_options_t)opts; \
534+
_specs[_index].opts_size = sizeof(*opts); \
535+
}
536+
464537
static void *
465538
bdev_rbd_init_context(void *arg)
466539
{
@@ -498,9 +571,52 @@ bdev_rbd_init_context(void *arg)
498571
}
499572
if (rc < 0) {
500573
SPDK_ERRLOG("Failed to open specified rbd device\n");
574+
rbd->image = NULL;
501575
return NULL;
502576
}
503577

578+
if (rbd->encryption_entries_count > 0) {
579+
uint32_t i;
580+
rbd_encryption_spec_t *specs;
581+
char *formats_string;
582+
583+
formats_string = calloc(rbd->encryption_entries_count, strlen("LUKSx") + 1);
584+
if (!formats_string) {
585+
SPDK_ERRLOG("Cannot allocate memory for encryption formats string\n");
586+
return NULL;
587+
}
588+
specs = calloc(rbd->encryption_entries_count, sizeof(*specs));
589+
if (!specs) {
590+
SPDK_ERRLOG("Cannot allocate memory for encryption specs\n");
591+
free(formats_string);
592+
return NULL;
593+
}
594+
for (i = 0; i < rbd->encryption_entries_count; i++) {
595+
specs[i].format = rbd->encryption_format[i];
596+
SET_ENC_ENTRY(specs, rbd, i, formats_string, luks1, LUKS1)
597+
SET_ENC_ENTRY(specs, rbd, i, formats_string, luks2, LUKS2)
598+
SET_ENC_ENTRY(specs, rbd, i, formats_string, luks, LUKS)
599+
if (!specs[i].opts) {
600+
SPDK_ERRLOG("Invalid encryption format %d\n", rbd->encryption_format[i]);
601+
bdev_rbd_free_encryption_specs(specs, rbd->encryption_entries_count);
602+
free(formats_string);
603+
return NULL;
604+
}
605+
}
606+
607+
SPDK_DEBUGLOG(bdev_rbd, "Will use encryption load for image %s/%s, using encryption format(s) %s\n",
608+
rbd->pool_name, rbd->rbd_name, formats_string);
609+
rc = rbd_encryption_load2(rbd->image, specs, rbd->encryption_entries_count);
610+
bdev_rbd_free_encryption_specs(specs, rbd->encryption_entries_count);
611+
if (rc != 0) {
612+
SPDK_ERRLOG("Error %d trying to encryption load image %s/%s using format(s) %s\n", rc,
613+
rbd->pool_name, rbd->rbd_name, formats_string);
614+
free(formats_string);
615+
return NULL;
616+
}
617+
free(formats_string);
618+
}
619+
504620
rc = rbd_update_watch(rbd->image, &rbd->rbd_watch_handle, rbd_update_callback, (void *)rbd);
505621
if (rc < 0) {
506622
SPDK_ERRLOG("Failed to set up watch %d\n", rc);
@@ -1061,6 +1177,27 @@ bdev_rbd_write_config_json(struct spdk_bdev *bdev, struct spdk_json_write_ctx *w
10611177
spdk_json_write_named_string(w, "user_id", rbd->user_id);
10621178
}
10631179

1180+
if (rbd->encryption_format && rbd->encryption_entries_count > 0) {
1181+
uint32_t i;
1182+
1183+
spdk_json_write_named_object_begin(w, "encryption_format");
1184+
for (i = 0; i < rbd->encryption_entries_count; i++) {
1185+
spdk_json_write_uint32(w, rbd->encryption_format[i]);
1186+
}
1187+
spdk_json_write_object_end(w);
1188+
}
1189+
1190+
if (rbd->passphrase && rbd->encryption_entries_count > 0) {
1191+
uint32_t i;
1192+
1193+
spdk_json_write_named_object_begin(w, "passphrase");
1194+
for (i = 0; i < rbd->encryption_entries_count; i++) {
1195+
/* souldn't write the real pass phrase, it's a security breach */
1196+
spdk_json_write_string(w, "*");
1197+
}
1198+
spdk_json_write_object_end(w);
1199+
}
1200+
10641201
if (rbd->config) {
10651202
char **entry = rbd->config;
10661203

@@ -1499,10 +1636,14 @@ bdev_rbd_create(struct spdk_bdev **bdev, const char *name, const char *user_id,
14991636
uint32_t block_size,
15001637
const char *cluster_name,
15011638
const struct spdk_uuid *uuid,
1502-
bool read_only)
1639+
bool read_only,
1640+
uint32_t encryption_entries_count,
1641+
const uint32_t *encryption_format,
1642+
const char **passphrase)
15031643
{
15041644
struct bdev_rbd *rbd;
15051645
int ret;
1646+
uint32_t i;
15061647

15071648
if ((pool_name == NULL) || (rbd_name == NULL) || (block_size == 0)) {
15081649
return -EINVAL;
@@ -1549,6 +1690,28 @@ bdev_rbd_create(struct spdk_bdev **bdev, const char *name, const char *user_id,
15491690
}
15501691
}
15511692

1693+
rbd->encryption_entries_count = encryption_entries_count;
1694+
if (encryption_entries_count > 0) {
1695+
rbd->encryption_format = calloc(encryption_entries_count, sizeof(uint32_t));
1696+
if (!rbd->encryption_format) {
1697+
bdev_rbd_free(rbd);
1698+
return -ENOMEM;
1699+
}
1700+
rbd->passphrase = calloc(encryption_entries_count + 1, sizeof(char *));
1701+
if (!rbd->passphrase) {
1702+
bdev_rbd_free(rbd);
1703+
return -ENOMEM;
1704+
}
1705+
for (i = 0; i < encryption_entries_count; i++) {
1706+
rbd->encryption_format[i] = encryption_format[i];
1707+
rbd->passphrase[i] = strdup(passphrase[i]);
1708+
if (!rbd->passphrase[i]) {
1709+
bdev_rbd_free(rbd);
1710+
return -ENOMEM;
1711+
}
1712+
}
1713+
}
1714+
15521715
if (config && !(rbd->config = bdev_rbd_dup_config(config))) {
15531716
bdev_rbd_free(rbd);
15541717
return -ENOMEM;

module/bdev/rbd/bdev_rbd.h

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,15 +23,17 @@ struct cluster_register_info {
2323
void dump_cluster_nonce(struct spdk_json_write_ctx *w, const char *name);
2424
void bdev_rbd_free_config(char **config);
2525
char **bdev_rbd_dup_config(const char *const *config);
26+
void bdev_rbd_free_passphrase(char **passphrase);
2627

2728
typedef void (*spdk_delete_rbd_complete)(void *cb_arg, int bdeverrno);
2829

2930
int bdev_rbd_create(struct spdk_bdev **bdev, const char *name, const char *user_id,
30-
const char *pool_name,
31-
const char *namespace_name,
31+
const char *pool_name, const char *namespace_name,
3232
const char *const *config,
3333
const char *rbd_name, uint32_t block_size, const char *cluster_name,
34-
const struct spdk_uuid *uuid, bool read_only);
34+
const struct spdk_uuid *uuid, bool read_only,
35+
uint32_t encryption_entries_count,
36+
const uint32_t *encryption_format, const char **passphrase);
3537
/**
3638
* Delete rbd bdev.
3739
*

module/bdev/rbd/bdev_rbd_rpc.c

Lines changed: 52 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@ struct rpc_create_rbd {
2020
char *cluster_name;
2121
struct spdk_uuid uuid;
2222
bool read_only;
23+
uint32_t encryption_entries_count;
24+
uint32_t *encryption_format;
25+
char **passphrase;
2326
};
2427

2528
static void
@@ -32,6 +35,8 @@ free_rpc_create_rbd(struct rpc_create_rbd *req)
3235
free(req->rbd_name);
3336
bdev_rbd_free_config(req->config);
3437
free(req->cluster_name);
38+
free(req->encryption_format);
39+
bdev_rbd_free_passphrase(req->passphrase);
3540
}
3641

3742
static int
@@ -76,6 +81,42 @@ bdev_rbd_decode_config(const struct spdk_json_val *values, void *out)
7681
return 0;
7782
}
7883

84+
static int
85+
bdev_rbd_decode_passphrase(const struct spdk_json_val *values, void *out)
86+
{
87+
char ***phrases = out;
88+
size_t out_size;
89+
90+
*phrases = calloc(values->len + 1, sizeof(**phrases));
91+
if (!*phrases) {
92+
return -1;
93+
}
94+
if (spdk_json_decode_array(values, spdk_json_decode_string, *phrases, values->len, &out_size, sizeof(char *)) != 0) {
95+
free(*phrases);
96+
*phrases = NULL;
97+
return -1;
98+
}
99+
return 0;
100+
}
101+
102+
static int
103+
bdev_rbd_decode_encryption_format(const struct spdk_json_val *values, void *out)
104+
{
105+
uint32_t **formats = out;
106+
size_t out_size;
107+
108+
*formats = calloc(values->len + 1, sizeof(**formats));
109+
if (!*formats) {
110+
return -1;
111+
}
112+
if (spdk_json_decode_array(values, spdk_json_decode_uint32, *formats, values->len, &out_size, sizeof(uint32_t)) != 0) {
113+
free(*formats);
114+
*formats = NULL;
115+
return -1;
116+
}
117+
return 0;
118+
}
119+
79120
static const struct spdk_json_object_decoder rpc_create_rbd_decoders[] = {
80121
{"name", offsetof(struct rpc_create_rbd, name), spdk_json_decode_string, true},
81122
{"user_id", offsetof(struct rpc_create_rbd, user_id), spdk_json_decode_string, true},
@@ -86,7 +127,9 @@ static const struct spdk_json_object_decoder rpc_create_rbd_decoders[] = {
86127
{"config", offsetof(struct rpc_create_rbd, config), bdev_rbd_decode_config, true},
87128
{"cluster_name", offsetof(struct rpc_create_rbd, cluster_name), spdk_json_decode_string, true},
88129
{"uuid", offsetof(struct rpc_create_rbd, uuid), spdk_json_decode_uuid, true},
89-
{"read_only", offsetof(struct rpc_create_rbd, read_only), spdk_json_decode_bool, true}
130+
{"read_only", offsetof(struct rpc_create_rbd, read_only), spdk_json_decode_bool, true},
131+
{"encryption_format", offsetof(struct rpc_create_rbd, encryption_format), bdev_rbd_decode_encryption_format, true},
132+
{"passphrase", offsetof(struct rpc_create_rbd, passphrase), bdev_rbd_decode_passphrase, true}
90133
};
91134

92135
static void
@@ -107,11 +150,16 @@ rpc_bdev_rbd_create(struct spdk_jsonrpc_request *request,
107150
goto cleanup;
108151
}
109152

110-
rc = bdev_rbd_create(&bdev, req.name, req.user_id, req.pool_name,
111-
req.namespace_name,
153+
req.encryption_entries_count = 0;
154+
while (req.passphrase[req.encryption_entries_count]) {
155+
req.encryption_entries_count++;
156+
}
157+
rc = bdev_rbd_create(&bdev, req.name, req.user_id, req.pool_name, req.namespace_name,
112158
(const char *const *)req.config,
113159
req.rbd_name,
114-
req.block_size, req.cluster_name, &req.uuid, req.read_only);
160+
req.block_size, req.cluster_name, &req.uuid, req.read_only,
161+
req.encryption_entries_count, req.encryption_format,
162+
(const char **)req.passphrase);
115163
if (rc) {
116164
spdk_jsonrpc_send_error_response(request, rc, spdk_strerror(-rc));
117165
goto cleanup;

python/spdk/cli/bdev.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -870,7 +870,9 @@ def bdev_rbd_create(args):
870870
cluster_name=args.cluster_name,
871871
namespace_name=args.namespace_name,
872872
uuid=args.uuid,
873-
read_only=args.read_only))
873+
read_only=args.read_only,
874+
encryption_format=args.encryption_format,
875+
passphrase=args.passphrase))
874876

875877
p = subparsers.add_parser('bdev_rbd_create', help='Add a bdev with ceph rbd backend')
876878
p.add_argument('-b', '--name', help="Name of the bdev")
@@ -884,6 +886,8 @@ def bdev_rbd_create(args):
884886
p.add_argument('-c', '--cluster-name', help="cluster name to identify the Rados cluster")
885887
p.add_argument('-u', '--uuid', help="UUID of the bdev")
886888
p.add_argument("-r", "--readonly", dest='read_only', action='store_true', help='Set this bdev as read-only')
889+
p.add_argument('-e', '--encryption-format', nargs='+', help="Encryption format(s) of the bdev")
890+
p.add_argument('-p', '--passphrase', nargs='+', help="Pass phrase(s) for encrypted bdevs")
887891
p.set_defaults(func=bdev_rbd_create)
888892

889893
def bdev_rbd_delete(args):

python/spdk/rpc/bdev.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1093,7 +1093,7 @@ def bdev_rbd_get_clusters_info(client, name=None):
10931093

10941094
@deprecated_method
10951095
def bdev_rbd_create(client, pool_name, rbd_name, block_size, name=None, user_id=None, config=None, cluster_name=None,
1096-
namespace_name=None, uuid=None, read_only=None):
1096+
namespace_name=None, uuid=None, read_only=None, encryption_format=None, passphrase=None):
10971097
"""Create a Ceph RBD block device.
10981098
Args:
10991099
pool_name: Ceph RBD pool name
@@ -1106,6 +1106,8 @@ def bdev_rbd_create(client, pool_name, rbd_name, block_size, name=None, user_id=
11061106
namespace_name: RBD namespace name (optional)
11071107
uuid: UUID of block device (optional)
11081108
read_only: set block device to read-only (optional)
1109+
encryption_format: encryption format to use (optional)
1110+
passphrase: pass phrase to use (optional)
11091111
Returns:
11101112
Name of created block device.
11111113
"""
@@ -1129,6 +1131,10 @@ def bdev_rbd_create(client, pool_name, rbd_name, block_size, name=None, user_id=
11291131
params['uuid'] = uuid
11301132
if read_only is not None:
11311133
params['read_only'] = read_only
1134+
if encryption_format is not None:
1135+
params['encryption_format'] = encryption_format
1136+
if passphrase is not None:
1137+
params['passphrase'] = passphrase
11321138
return client.call('bdev_rbd_create', params)
11331139

11341140

0 commit comments

Comments
 (0)