From dbe8c9299eb3b19a8bdbc715fbba6f0c0596623b Mon Sep 17 00:00:00 2001 From: Gil Bregman Date: Thu, 5 Dec 2024 14:07:45 +0200 Subject: [PATCH] mgr/cephadm/nvmeof: Add key encryption support to nvmeof configuration Signed-off-by: Gil Bregman --- src/cephadm/cephadmlib/daemons/nvmeof.py | 1 + src/pybind/mgr/cephadm/inventory.py | 4 ++++ src/pybind/mgr/cephadm/services/nvmeof.py | 3 +++ .../templates/services/nvmeof/ceph-nvmeof.conf.j2 | 1 + src/pybind/mgr/cephadm/tests/test_cephadm.py | 13 +++++++++++++ src/pybind/mgr/cephadm/tests/test_services.py | 1 + src/python-common/ceph/deployment/service_spec.py | 3 +++ 7 files changed, 26 insertions(+) diff --git a/src/cephadm/cephadmlib/daemons/nvmeof.py b/src/cephadm/cephadmlib/daemons/nvmeof.py index 06e60a49d8e4f..51b085df2a7ee 100644 --- a/src/cephadm/cephadmlib/daemons/nvmeof.py +++ b/src/cephadm/cephadmlib/daemons/nvmeof.py @@ -100,6 +100,7 @@ class CephNvmeof(ContainerDaemonForm): 'client_cert', 'client_key', 'root_ca_cert', + 'encryption_key', ]: if fn in files: mounts[ diff --git a/src/pybind/mgr/cephadm/inventory.py b/src/pybind/mgr/cephadm/inventory.py index d3681cbe60a7c..f1c56d753783b 100644 --- a/src/pybind/mgr/cephadm/inventory.py +++ b/src/pybind/mgr/cephadm/inventory.py @@ -438,6 +438,7 @@ class SpecStore(): for key_attr in [ 'server_key', 'client_key', + 'encryption_key', ]: key = getattr(nvmeof_spec, key_attr, None) if key: @@ -490,6 +491,7 @@ class SpecStore(): self.mgr.cert_key_store.rm_cert('nvmeof_root_ca_cert', service_name=spec.service_name()) self.mgr.cert_key_store.rm_key('nvmeof_server_key', service_name=spec.service_name()) self.mgr.cert_key_store.rm_key('nvmeof_client_key', service_name=spec.service_name()) + self.mgr.cert_key_store.rm_key('nvmeof_encryption_key', service_name=spec.service_name()) def get_created(self, spec: ServiceSpec) -> Optional[datetime.datetime]: return self.spec_created.get(spec.service_name()) @@ -1969,6 +1971,7 @@ class CertKeyStore(): 'ingress_ssl_key', 'nvmeof_server_key', 'nvmeof_client_key', + 'nvmeof_encryption_key', ] known_certs: Dict[str, Any] = {} @@ -2005,6 +2008,7 @@ class CertKeyStore(): 'ingress_ssl_key': {}, # service-name -> key 'nvmeof_server_key': {}, # service-name -> key 'nvmeof_client_key': {}, # service-name -> key + 'nvmeof_encryption_key': {}, # service-name -> key } def get_cert(self, entity: str, service_name: str = '', host: str = '') -> str: diff --git a/src/pybind/mgr/cephadm/services/nvmeof.py b/src/pybind/mgr/cephadm/services/nvmeof.py index 418be93b6af7a..0c9dc244c57ed 100644 --- a/src/pybind/mgr/cephadm/services/nvmeof.py +++ b/src/pybind/mgr/cephadm/services/nvmeof.py @@ -91,6 +91,9 @@ class NvmeofService(CephService): daemon_spec.extra_files['client_key'] = spec.client_key daemon_spec.extra_files['root_ca_cert'] = spec.root_ca_cert + if spec.encryption_key: + daemon_spec.extra_files['encryption_key'] = spec.encryption_key + daemon_spec.final_config, daemon_spec.deps = self.generate_config(daemon_spec) daemon_spec.deps = [] return daemon_spec diff --git a/src/pybind/mgr/cephadm/templates/services/nvmeof/ceph-nvmeof.conf.j2 b/src/pybind/mgr/cephadm/templates/services/nvmeof/ceph-nvmeof.conf.j2 index 73f36952ee78e..acc93507424d9 100644 --- a/src/pybind/mgr/cephadm/templates/services/nvmeof/ceph-nvmeof.conf.j2 +++ b/src/pybind/mgr/cephadm/templates/services/nvmeof/ceph-nvmeof.conf.j2 @@ -9,6 +9,7 @@ state_update_notify = {{ spec.state_update_notify }} state_update_interval_sec = {{ spec.state_update_interval_sec }} enable_spdk_discovery_controller = {{ spec.enable_spdk_discovery_controller }} enable_key_encryption = {{ spec.enable_key_encryption }} +encryption_key = /encryption.key enable_prometheus_exporter = {{ spec.enable_prometheus_exporter }} prometheus_exporter_ssl = False prometheus_port = 10008 diff --git a/src/pybind/mgr/cephadm/tests/test_cephadm.py b/src/pybind/mgr/cephadm/tests/test_cephadm.py index 3c647476e440a..b81510504d9ff 100644 --- a/src/pybind/mgr/cephadm/tests/test_cephadm.py +++ b/src/pybind/mgr/cephadm/tests/test_cephadm.py @@ -1797,15 +1797,18 @@ class TestCephadm(object): grafana_host1_key = 'fake-grafana-host1-key' nvmeof_client_key = 'nvmeof-client-key' nvmeof_server_key = 'nvmeof-server-key' + nvmeof_encryption_key = 'nvmeof-encryption-key' grafana_host1_key = 'fake-grafana-host1-cert' cephadm_module.cert_key_store.save_key('grafana_key', grafana_host1_key, host='host1') cephadm_module.cert_key_store.save_key('nvmeof_client_key', nvmeof_client_key, service_name='nvmeof.foo') cephadm_module.cert_key_store.save_key('nvmeof_server_key', nvmeof_server_key, service_name='nvmeof.foo') + cephadm_module.cert_key_store.save_key('nvmeof_encryption_key', nvmeof_encryption_key, service_name='nvmeof.foo') expected_calls = [ mock.call(f'{CERT_STORE_KEY_PREFIX}grafana_key', json.dumps({'host1': PrivKey(grafana_host1_key).to_json()})), mock.call(f'{CERT_STORE_KEY_PREFIX}nvmeof_client_key', json.dumps({'nvmeof.foo': PrivKey(nvmeof_client_key).to_json()})), mock.call(f'{CERT_STORE_KEY_PREFIX}nvmeof_server_key', json.dumps({'nvmeof.foo': PrivKey(nvmeof_server_key).to_json()})), + mock.call(f'{CERT_STORE_KEY_PREFIX}nvmeof_encryption_key', json.dumps({'nvmeof.foo': PrivKey(nvmeof_encryption_key).to_json()})), ] _set_store.assert_has_calls(expected_calls) @@ -1822,15 +1825,19 @@ class TestCephadm(object): 'ingress_ssl_key': False, 'nvmeof_client_key': False, 'nvmeof_server_key': False, + 'nvmeof_encryption_key': False, } assert cephadm_module.cert_key_store.key_ls() == expected_ls cephadm_module.cert_key_store.save_key('nvmeof_client_key', 'xxx', service_name='nvmeof.foo') cephadm_module.cert_key_store.save_key('nvmeof_server_key', 'xxx', service_name='nvmeof.foo') + cephadm_module.cert_key_store.save_key('nvmeof_encryption_key', 'xxx', service_name='nvmeof.foo') expected_ls['nvmeof_server_key'] = {} expected_ls['nvmeof_server_key']['nvmeof.foo'] = True expected_ls['nvmeof_client_key'] = {} expected_ls['nvmeof_client_key']['nvmeof.foo'] = True + expected_ls['nvmeof_encryption_key'] = {} + expected_ls['nvmeof_encryption_key']['nvmeof.foo'] = True assert cephadm_module.cert_key_store.key_ls() == expected_ls @mock.patch("cephadm.module.CephadmOrchestrator.get_store_prefix") @@ -1844,6 +1851,7 @@ class TestCephadm(object): nvmeof_root_ca_cert = 'nvmeof-root-ca-cert' nvmeof_server_key = 'nvmeof-server-key' nvmeof_client_key = 'nvmeof-client-key' + nvmeof_encryption_key = 'nvmeof-encryption-key' def _fake_prefix_store(key): if key == 'cert_store.cert.': @@ -1858,6 +1866,7 @@ class TestCephadm(object): f'{CERT_STORE_KEY_PREFIX}grafana_key': json.dumps({'host1': PrivKey(grafana_host1_key).to_json()}), f'{CERT_STORE_KEY_PREFIX}nvmeof_server_key': json.dumps({'nvmeof.foo': PrivKey(nvmeof_server_key).to_json()}), f'{CERT_STORE_KEY_PREFIX}nvmeof_client_key': json.dumps({'nvmeof.foo': PrivKey(nvmeof_client_key).to_json()}), + f'{CERT_STORE_KEY_PREFIX}nvmeof_encryption_key': json.dumps({'nvmeof.foo': PrivKey(nvmeof_encryption_key).to_json()}), } else: raise Exception(f'Get store with unexpected value {key}') @@ -1871,6 +1880,7 @@ class TestCephadm(object): assert cephadm_module.cert_key_store.known_keys['grafana_key']['host1'] == PrivKey(grafana_host1_key) assert cephadm_module.cert_key_store.known_keys['nvmeof_server_key']['nvmeof.foo'] == PrivKey(nvmeof_server_key) assert cephadm_module.cert_key_store.known_keys['nvmeof_client_key']['nvmeof.foo'] == PrivKey(nvmeof_client_key) + assert cephadm_module.cert_key_store.known_keys['nvmeof_encryption_key']['nvmeof.foo'] == PrivKey(nvmeof_encryption_key) def test_cert_store_get_cert_key(self, cephadm_module: CephadmOrchestrator): cephadm_module.cert_key_store._init_known_cert_key_dicts() @@ -1898,13 +1908,16 @@ class TestCephadm(object): grafana_host1_key = 'fake-grafana-host1-cert' nvmeof_server_key = 'nvmeof-server-key' + nvmeof_encryption_key = 'nvmeof-encryption-key' cephadm_module.cert_key_store.save_key('grafana_key', grafana_host1_key, host='host1') cephadm_module.cert_key_store.save_key('grafana_key', grafana_host1_key, host='host1') cephadm_module.cert_key_store.save_key('nvmeof_server_key', nvmeof_server_key, service_name='nvmeof.foo') + cephadm_module.cert_key_store.save_key('nvmeof_encryption_key', nvmeof_encryption_key, service_name='nvmeof.foo') assert cephadm_module.cert_key_store.get_key('grafana_key', host='host1') == grafana_host1_key assert cephadm_module.cert_key_store.get_key('nvmeof_server_key', service_name='nvmeof.foo') == nvmeof_server_key assert cephadm_module.cert_key_store.get_key('nvmeof_client_key', service_name='nvmeof.foo') == '' + assert cephadm_module.cert_key_store.get_key('nvmeof_encryption_key', service_name='nvmeof.foo') == nvmeof_encryption_key with pytest.raises(OrchestratorError, match='Attempted to access priv key for unknown entity'): cephadm_module.cert_key_store.get_key('unknown_entity') diff --git a/src/pybind/mgr/cephadm/tests/test_services.py b/src/pybind/mgr/cephadm/tests/test_services.py index 75c7c3c5bf79e..1b3c9bdb899da 100644 --- a/src/pybind/mgr/cephadm/tests/test_services.py +++ b/src/pybind/mgr/cephadm/tests/test_services.py @@ -399,6 +399,7 @@ state_update_notify = True state_update_interval_sec = 5 enable_spdk_discovery_controller = False enable_key_encryption = True +encryption_key = /encryption.key enable_prometheus_exporter = True prometheus_exporter_ssl = False prometheus_port = 10008 diff --git a/src/python-common/ceph/deployment/service_spec.py b/src/python-common/ceph/deployment/service_spec.py index 10e9f26794000..ebe66989cc04e 100644 --- a/src/python-common/ceph/deployment/service_spec.py +++ b/src/python-common/ceph/deployment/service_spec.py @@ -1335,6 +1335,7 @@ class NvmeofServiceSpec(ServiceSpec): state_update_interval_sec: Optional[int] = 5, enable_spdk_discovery_controller: Optional[bool] = False, enable_key_encryption: Optional[bool] = True, + encryption_key: Optional[str] = None, omap_file_lock_duration: Optional[int] = 20, omap_file_lock_retries: Optional[int] = 30, omap_file_lock_retry_sleep_interval: Optional[float] = 1.0, @@ -1422,6 +1423,8 @@ class NvmeofServiceSpec(ServiceSpec): self.enable_spdk_discovery_controller = enable_spdk_discovery_controller #: ``enable_key_encryption`` encrypt DHCHAP and PSK keys before saving in OMAP self.enable_key_encryption = enable_key_encryption + #: ``encryption_key`` gateway encryption key + self.encryption_key = encryption_key #: ``enable_prometheus_exporter`` enables Prometheus exporter self.enable_prometheus_exporter = enable_prometheus_exporter #: ``verify_nqns`` enables verification of subsystem and host NQNs for validity -- 2.39.5