diff --git a/manila/share/drivers/netapp/dataontap/client/client_cmode.py b/manila/share/drivers/netapp/dataontap/client/client_cmode.py
index d7affdbf65..3bd450b815 100644
--- a/manila/share/drivers/netapp/dataontap/client/client_cmode.py
+++ b/manila/share/drivers/netapp/dataontap/client/client_cmode.py
@@ -175,7 +175,8 @@ class NetAppCmodeClient(client_base.NetAppBaseClient):
@na_utils.trace
def create_vserver(self, vserver_name, root_volume_aggregate_name,
- root_volume_name, aggregate_names, ipspace_name):
+ root_volume_name, aggregate_names, ipspace_name,
+ security_cert_expire_days):
"""Creates new vserver and assigns aggregates."""
self._create_vserver(
vserver_name, aggregate_names, ipspace_name,
@@ -183,6 +184,7 @@ class NetAppCmodeClient(client_base.NetAppBaseClient):
root_volume_aggregate_name=root_volume_aggregate_name,
root_volume_security_style='unix',
name_server_switch='file')
+ self._modify_security_cert(vserver_name, security_cert_expire_days)
@na_utils.trace
def create_vserver_dp_destination(self, vserver_name, aggregate_names,
@@ -230,6 +232,119 @@ class NetAppCmodeClient(client_base.NetAppBaseClient):
}
self.send_request('vserver-modify', modify_args)
+ @na_utils.trace
+ def _modify_security_cert(self, vserver_name, security_cert_expire_days):
+ """Create new security certificate with given expire days."""
+
+ # Do not modify security certificate if specified expire days are
+ # equal to default security certificate expire days i.e. 365.
+ if security_cert_expire_days == 365:
+ return
+
+ api_args = {
+ 'query': {
+ 'certificate-info': {
+ 'vserver': vserver_name,
+ 'common-name': vserver_name,
+ 'certificate-authority': vserver_name,
+ 'type': 'server',
+ },
+ },
+ 'desired-attributes': {
+ 'certificate-info': {
+ 'serial-number': None,
+ },
+ },
+ }
+ result = self.send_iter_request('security-certificate-get-iter',
+ api_args)
+ try:
+ old_certificate_info_list = result.get_child_by_name(
+ 'attributes-list')
+ except AttributeError:
+ LOG.warning('Could not retrieve certificate-info for vserver '
+ '%(server)s.', {'server': vserver_name})
+ return
+
+ old_serial_nums = []
+ for certificate_info in old_certificate_info_list.get_children():
+ serial_num = certificate_info.get_child_content('serial-number')
+ old_serial_nums.append(serial_num)
+
+ try:
+ create_args = {
+ 'vserver': vserver_name,
+ 'common-name': vserver_name,
+ 'type': 'server',
+ 'expire-days': security_cert_expire_days,
+ }
+ self.send_request('security-certificate-create', create_args)
+ except netapp_api.NaApiError as e:
+ LOG.warning("Failed to create new security certificate: %s - %s",
+ e.code, e.message)
+ return
+
+ api_args = {
+ 'query': {
+ 'certificate-info': {
+ 'vserver': vserver_name,
+ 'common-name': vserver_name,
+ 'certificate-authority': vserver_name,
+ 'type': 'server',
+ },
+ },
+ 'desired-attributes': {
+ 'certificate-info': {
+ 'serial-number': None,
+ },
+ },
+ }
+
+ result = self.send_iter_request('security-certificate-get-iter',
+ api_args)
+ try:
+ new_certificate_info_list = result.get_child_by_name(
+ 'attributes-list')
+ except AttributeError:
+ LOG.warning('Could not retrieve certificate-info for vserver '
+ '%(server)s.', {'server': vserver_name})
+ return
+
+ for certificate_info in new_certificate_info_list.get_children():
+ serial_num = certificate_info.get_child_content('serial-number')
+ if serial_num not in old_serial_nums:
+ try:
+ ssl_modify_args = {
+ 'certificate-authority': vserver_name,
+ 'common-name': vserver_name,
+ 'certificate-serial-number': serial_num,
+ 'vserver': vserver_name,
+ 'client-authentication-enabled': 'false',
+ 'server-authentication-enabled': 'true',
+ }
+ self.send_request('security-ssl-modify', ssl_modify_args)
+ except netapp_api.NaApiError as e:
+ LOG.debug('Failed to modify SSL for security certificate '
+ 'with serial number %s: %s - %s', serial_num,
+ e.code, e.message)
+
+ # Delete all old security certificates
+ for certificate_info in old_certificate_info_list.get_children():
+ serial_num = certificate_info.get_child_content('serial-number')
+ delete_args = {
+ 'certificate-authority': vserver_name,
+ 'common-name': vserver_name,
+ 'serial-number': serial_num,
+ 'type': 'server',
+ 'vserver': vserver_name,
+ }
+ try:
+ self.send_request('security-certificate-delete', delete_args)
+ except netapp_api.NaApiError as e:
+ LOG.warning('Failed to delete security certificate with '
+ 'serial number %s: %s - %s', serial_num, e.code,
+ e.message)
+
@na_utils.trace
def get_vserver_info(self, vserver_name):
"""Retrieves Vserver info."""
diff --git a/manila/share/drivers/netapp/dataontap/client/client_cmode_rest.py b/manila/share/drivers/netapp/dataontap/client/client_cmode_rest.py
index b09f10e4fa..5fa6b13cb1 100644
--- a/manila/share/drivers/netapp/dataontap/client/client_cmode_rest.py
+++ b/manila/share/drivers/netapp/dataontap/client/client_cmode_rest.py
@@ -46,6 +46,7 @@ CUTOVER_ACTION_MAP = {
DEFAULT_TIMEOUT = 15
DEFAULT_TCP_MAX_XFER_SIZE = 65536
DEFAULT_UDP_MAX_XFER_SIZE = 32768
+DEFAULT_SECURITY_CERT_EXPIRE_DAYS = 365
class NetAppRestClient(object):
@@ -4120,7 +4121,8 @@ class NetAppRestClient(object):
@na_utils.trace
def create_vserver(self, vserver_name, root_volume_aggregate_name,
- root_volume_name, aggregate_names, ipspace_name):
+ root_volume_name, aggregate_names, ipspace_name,
+ security_cert_expire_days):
"""Creates new vserver and assigns aggregates."""
# NOTE(nahimsouza): root_volume_aggregate_name and root_volume_name
@@ -4129,6 +4131,7 @@ class NetAppRestClient(object):
self._create_vserver(
vserver_name, aggregate_names, ipspace_name,
name_server_switch=['files'])
+ self._modify_security_cert(vserver_name, security_cert_expire_days)
@na_utils.trace
def create_vserver_dp_destination(self, vserver_name, aggregate_names,
@@ -4161,6 +4164,77 @@ class NetAppRestClient(object):
self.send_request('/svm/svms', 'post', body=body)
+ @na_utils.trace
+ def _modify_security_cert(self, vserver_name, security_cert_expire_days):
+ """Create new security certificate with given expire days."""
+
+ # Do not modify security certificate if specified expire days are
+ # equal to default security certificate expire days i.e. 365.
+ if security_cert_expire_days == DEFAULT_SECURITY_CERT_EXPIRE_DAYS:
+ return
+
+ query = {
+ 'common-name': vserver_name,
+ 'ca': vserver_name,
+ 'type': 'server',
+ 'svm.name': vserver_name,
+ }
+ result = self.send_request('/security/certificates',
+ 'get', query=query)
+ old_certificate_info_list = result.get('records', [])
+ if not old_certificate_info_list:
+ LOG.warning("Unable to retrieve certificate-info for vserver "
+ "%(server)s'. Cannot set the certificate expiry to "
+ "%s(conf)s. ", {'server': vserver_name,
+ 'conf': security_cert_expire_days})
+ return
+
+ body = {
+ 'common-name': vserver_name,
+ 'type': 'server',
+ 'svm.name': vserver_name,
+ 'expiry_time': f'P{security_cert_expire_days}DT',
+ }
+ query = {
+ 'return_records': 'true'
+ }
+ result = self.send_request('/security/certificates',
+ 'post', body=body, query=query)
+ new_certificate_info_list = result.get('records', [])
+ if not new_certificate_info_list:
+ LOG.warning('Failed to create new security certificate for '
+ 'vserver %(server)s.', {'server': vserver_name})
+ return
+
+ for certificate_info in new_certificate_info_list:
+ cert_uuid = certificate_info.get('uuid', None)
+ svm = certificate_info.get('svm', [])
+ svm_uuid = svm.get('uuid', None)
+ if not svm_uuid or not cert_uuid:
+ continue
+
+ try:
+ body = {
+ 'certificate': {
+ 'uuid': cert_uuid,
+ },
+ 'client_enabled': 'false',
+ }
+ self.send_request(f'/svm/svms/{svm_uuid}', 'patch',
+ body=body)
+ except netapp_api.api.NaApiError:
+ LOG.debug('Failed to modify SSL for vserver '
+ '%(server)s.', {'server': vserver_name})
+
+ # Delete all old security certificates
+ for certificate_info in old_certificate_info_list:
+ uuid = certificate_info.get('uuid', None)
+ try:
+ self.send_request(f'/security/certificates/{uuid}', 'delete')
+ except netapp_api.api.NaApiError:
+ LOG.error("Failed to delete security certificate for vserver "
+ "%s.", vserver_name)
+
@na_utils.trace
def list_node_data_ports(self, node):
"""List data ports from node."""
diff --git a/manila/share/drivers/netapp/dataontap/cluster_mode/lib_multi_svm.py b/manila/share/drivers/netapp/dataontap/cluster_mode/lib_multi_svm.py
index cc6266adea..26f4875e22 100644
--- a/manila/share/drivers/netapp/dataontap/cluster_mode/lib_multi_svm.py
+++ b/manila/share/drivers/netapp/dataontap/cluster_mode/lib_multi_svm.py
@@ -343,7 +343,8 @@ class NetAppCmodeMultiSVMFileStorageLibrary(
self.configuration.netapp_root_volume_aggregate,
self.configuration.netapp_root_volume,
aggr_set,
- ipspace_name)
+ ipspace_name,
+ self.configuration.netapp_security_cert_expire_days)
vserver_client = self._get_api_client(vserver=vserver_name)
diff --git a/manila/share/drivers/netapp/options.py b/manila/share/drivers/netapp/options.py
index b90e9e296a..6eeecc1fbb 100644
--- a/manila/share/drivers/netapp/options.py
+++ b/manila/share/drivers/netapp/options.py
@@ -190,6 +190,14 @@ netapp_provisioning_opts = [
default=60, # Default to one minutes
help='Sets maximum amount of time in seconds to wait for a '
'synchronous ONTAP REST API operation to be completed.'),
+ cfg.IntOpt('netapp_security_cert_expire_days',
+ min=1,
+ max=3652,
+ default=365,
+ help='Defines the expiration time (in days) for the '
+ 'certificate created during the vserver creation. This '
+ 'option only applies when the option '
+ 'driver_handles_share_servers is set to True.'),
]
netapp_cluster_opts = [
diff --git a/manila/tests/share/drivers/netapp/dataontap/client/fakes.py b/manila/tests/share/drivers/netapp/dataontap/client/fakes.py
index c22bfe4ab8..674e478036 100644
--- a/manila/tests/share/drivers/netapp/dataontap/client/fakes.py
+++ b/manila/tests/share/drivers/netapp/dataontap/client/fakes.py
@@ -50,6 +50,8 @@ VSERVER_PEER_STATE = 'peered'
ADMIN_VSERVER_NAME = 'fake_admin_vserver'
NODE_VSERVER_NAME = 'fake_node_vserver'
NFS_VERSIONS = ['nfs3', 'nfs4.0']
+SECURITY_CERT_DEFAULT_EXPIRE_DAYS = 365
+SECURITY_CERT_LARGE_EXPIRE_DAYS = 3652
ROOT_AGGREGATE_NAMES = ('root_aggr1', 'root_aggr2')
ROOT_VOLUME_AGGREGATE_NAME = 'fake_root_aggr'
ROOT_VOLUME_NAME = 'fake_root_volume'
@@ -315,6 +317,18 @@ VSERVER_GET_RESPONSE = etree.XML("""
'aggr2': SHARE_AGGREGATE_NAMES[1],
})
+SECURITY_CERT_GET_RESPONSE = etree.XML("""
+
+
+
+ %(vserver)s
+ 12345
+
+
+ 1
+
+""" % {'vserver': VSERVER_NAME})
+
VSERVER_DATA_LIST_RESPONSE = etree.XML("""
@@ -4451,6 +4465,46 @@ SERVICE_POLICIES_REST = {
'num_records': 1,
}
+SECURITY_CERT_GET_RESPONSE_REST = {
+ 'records': [
+ {
+ 'uuid': 'fake_cert_uuid',
+ 'serial_number': 'fake_serial_number',
+ 'key_size': 0,
+ 'hash_function': "sha256",
+ 'common_name': "fake_common_name",
+ 'name': "cert1",
+ 'ca': 'fake_ca',
+ 'expiry_time': 'fake_expiry_time',
+ 'svm': {
+ 'name': VSERVER_NAME,
+ 'uuid': 'fake_uuid',
+ },
+ },
+ ],
+ 'num_records': 1,
+}
+
+SECURITY_CERT_POST_RESPONSE_REST = {
+ 'records': [
+ {
+ 'uuid': 'fake_cert_uuid',
+ 'serial_number': 'fake_serial_number',
+ 'key_size': 0,
+ 'hash_function': "sha256",
+ 'common_name': "fake_common_name",
+ 'name': "cert1",
+ 'ca': 'fake_ca',
+ 'expiry_time': 'fake_expiry_time',
+ 'svm': {
+ 'name': VSERVER_NAME,
+ 'uuid': 'fake_uuid',
+ },
+ },
+ ],
+ 'num_records': 1,
+}
+
GET_SNAPMIRROR_POLICIES_REST = {
"records": [
diff --git a/manila/tests/share/drivers/netapp/dataontap/client/test_client_cmode.py b/manila/tests/share/drivers/netapp/dataontap/client/test_client_cmode.py
index 1ebf0235df..0e6b703b6d 100644
--- a/manila/tests/share/drivers/netapp/dataontap/client/test_client_cmode.py
+++ b/manila/tests/share/drivers/netapp/dataontap/client/test_client_cmode.py
@@ -420,6 +420,9 @@ class NetAppClientCmodeTestCase(test.TestCase):
def test_create_vserver_no_ipspace(self):
self.mock_object(self.client, 'send_request')
+ self.mock_object(self.client,
+ '_modify_security_cert',
+ mock.Mock())
vserver_create_args = {
'vserver-name': fake.VSERVER_NAME,
@@ -438,16 +441,22 @@ class NetAppClientCmodeTestCase(test.TestCase):
fake.ROOT_VOLUME_AGGREGATE_NAME,
fake.ROOT_VOLUME_NAME,
fake.SHARE_AGGREGATE_NAMES,
- None)
+ None,
+ fake.SECURITY_CERT_LARGE_EXPIRE_DAYS)
self.client.send_request.assert_has_calls([
mock.call('vserver-create', vserver_create_args),
mock.call('vserver-modify', vserver_modify_args)])
+ self.client._modify_security_cert.assert_called_with(
+ fake.VSERVER_NAME, fake.SECURITY_CERT_LARGE_EXPIRE_DAYS)
def test_create_vserver_with_ipspace(self):
self.client.features.add_feature('IPSPACES')
self.mock_object(self.client, 'send_request')
+ self.mock_object(self.client,
+ '_modify_security_cert',
+ mock.Mock())
vserver_create_args = {
'vserver-name': fake.VSERVER_NAME,
@@ -467,11 +476,65 @@ class NetAppClientCmodeTestCase(test.TestCase):
fake.ROOT_VOLUME_AGGREGATE_NAME,
fake.ROOT_VOLUME_NAME,
fake.SHARE_AGGREGATE_NAMES,
- fake.IPSPACE_NAME)
+ fake.IPSPACE_NAME,
+ fake.SECURITY_CERT_LARGE_EXPIRE_DAYS)
self.client.send_request.assert_has_calls([
mock.call('vserver-create', vserver_create_args),
mock.call('vserver-modify', vserver_modify_args)])
+ self.client._modify_security_cert.assert_called_with(
+ fake.VSERVER_NAME, fake.SECURITY_CERT_LARGE_EXPIRE_DAYS)
+
+ def test__modify_security_cert(self):
+
+ certificate_create_args = {
+ 'vserver': fake.VSERVER_NAME,
+ 'common-name': fake.VSERVER_NAME,
+ 'type': 'server',
+ 'expire-days': fake.SECURITY_CERT_LARGE_EXPIRE_DAYS,
+ }
+
+ self.mock_object(self.client, 'send_request')
+ api_response = netapp_api.NaElement(fake.SECURITY_CERT_GET_RESPONSE)
+ self.mock_object(self.client,
+ 'send_iter_request',
+ mock.Mock(return_value=api_response))
+ certificate_get_args = {
+ 'query': {
+ 'certificate-info': {
+ 'vserver': fake.VSERVER_NAME,
+ 'common-name': fake.VSERVER_NAME,
+ 'certificate-authority': fake.VSERVER_NAME,
+ 'type': 'server',
+ },
+ },
+ 'desired-attributes': {
+ 'certificate-info': {
+ 'serial-number': None,
+ },
+ },
+ }
+
+ certificate_delete_args = {
+ 'certificate-authority': fake.VSERVER_NAME,
+ 'common-name': fake.VSERVER_NAME,
+ 'serial-number': '12345',
+ 'type': 'server',
+ 'vserver': fake.VSERVER_NAME,
+ }
+
+ self.client._modify_security_cert(
+ fake.VSERVER_NAME,
+ fake.SECURITY_CERT_LARGE_EXPIRE_DAYS)
+
+ self.client.send_request.assert_has_calls([
+ mock.call(
+ 'security-certificate-create', certificate_create_args),
+ mock.call(
+ 'security-certificate-delete', certificate_delete_args)])
+
+ self.client.send_iter_request.assert_has_calls([
+ mock.call('security-certificate-get-iter', certificate_get_args)])
def test_create_vserver_dp_destination(self):
@@ -506,7 +569,8 @@ class NetAppClientCmodeTestCase(test.TestCase):
fake.ROOT_VOLUME_AGGREGATE_NAME,
fake.ROOT_VOLUME_NAME,
fake.SHARE_AGGREGATE_NAMES,
- fake.IPSPACE_NAME)
+ fake.IPSPACE_NAME,
+ fake.SECURITY_CERT_LARGE_EXPIRE_DAYS)
def test_get_vserver_root_volume_name(self):
diff --git a/manila/tests/share/drivers/netapp/dataontap/client/test_client_cmode_rest.py b/manila/tests/share/drivers/netapp/dataontap/client/test_client_cmode_rest.py
index 2d4ccf8953..83ea0b7737 100644
--- a/manila/tests/share/drivers/netapp/dataontap/client/test_client_cmode_rest.py
+++ b/manila/tests/share/drivers/netapp/dataontap/client/test_client_cmode_rest.py
@@ -4808,13 +4808,69 @@ class NetAppRestCmodeClientTestCase(test.TestCase):
def test_create_vserver(self):
mock = self.mock_object(self.client, '_create_vserver')
+ self.mock_object(self.client, '_modify_security_cert',
+ mock.Mock(return_value=[]))
self.client.create_vserver(fake.VSERVER_NAME, None, None,
[fake.SHARE_AGGREGATE_NAME],
- fake.IPSPACE_NAME)
+ fake.IPSPACE_NAME,
+ fake.SECURITY_CERT_DEFAULT_EXPIRE_DAYS)
mock.assert_called_once_with(fake.VSERVER_NAME,
[fake.SHARE_AGGREGATE_NAME],
fake.IPSPACE_NAME,
name_server_switch=['files'])
+ self.client._modify_security_cert.assert_called_once_with(
+ fake.VSERVER_NAME,
+ fake.SECURITY_CERT_DEFAULT_EXPIRE_DAYS)
+
+ def test__modify_security_cert(self):
+ api_response = copy.deepcopy(fake.SECURITY_CERT_GET_RESPONSE_REST)
+ api_response2 = copy.deepcopy(fake.SECURITY_CERT_POST_RESPONSE_REST)
+ self.mock_object(
+ self.client, 'send_request',
+ mock.Mock(side_effect=[api_response, api_response2, None, None]))
+
+ query = {
+ 'common-name': fake.VSERVER_NAME,
+ 'ca': fake.VSERVER_NAME,
+ 'type': 'server',
+ 'svm.name': fake.VSERVER_NAME,
+ }
+ old_cert_info = copy.deepcopy(
+ fake.SECURITY_CERT_GET_RESPONSE_REST['records'][0])
+ old_cert_uuid = old_cert_info['uuid']
+
+ body1 = {
+ 'common-name': fake.VSERVER_NAME,
+ 'type': 'server',
+ 'svm.name': fake.VSERVER_NAME,
+ 'expiry_time': 'P' + str(
+ fake.SECURITY_CERT_LARGE_EXPIRE_DAYS) + 'DT',
+ }
+ query1 = {
+ 'return_records': 'true'
+ }
+ new_cert_info = copy.deepcopy(
+ fake.SECURITY_CERT_POST_RESPONSE_REST['records'][0])
+ new_cert_uuid = new_cert_info['uuid']
+ new_svm_uuid = new_cert_info['svm']['uuid']
+ body2 = {
+ 'certificate': {
+ 'uuid': new_cert_uuid,
+ },
+ 'client_enabled': 'false',
+ }
+
+ self.client._modify_security_cert(
+ fake.VSERVER_NAME,
+ fake.SECURITY_CERT_LARGE_EXPIRE_DAYS)
+
+ self.client.send_request.assert_has_calls([
+ mock.call('/security/certificates', 'get', query=query),
+ mock.call('/security/certificates', 'post', body=body1,
+ query=query1),
+ mock.call(f'/svm/svms/{new_svm_uuid}', 'patch', body=body2),
+ mock.call(f'/security/certificates/{old_cert_uuid}', 'delete'),
+ ])
def test__broadcast_domain_exists(self):
response = fake.FAKE_GET_BROADCAST_DOMAIN
diff --git a/manila/tests/share/drivers/netapp/dataontap/cluster_mode/test_lib_multi_svm.py b/manila/tests/share/drivers/netapp/dataontap/cluster_mode/test_lib_multi_svm.py
index 6868007952..b525443bf9 100644
--- a/manila/tests/share/drivers/netapp/dataontap/cluster_mode/test_lib_multi_svm.py
+++ b/manila/tests/share/drivers/netapp/dataontap/cluster_mode/test_lib_multi_svm.py
@@ -731,7 +731,8 @@ class NetAppFileStorageLibraryTestCase(test.TestCase):
fake.NETWORK_INFO)
self.library._client.create_vserver.assert_called_once_with(
vserver_name, fake.ROOT_VOLUME_AGGREGATE, fake.ROOT_VOLUME,
- set(fake.AGGREGATES), fake.IPSPACE)
+ set(fake.AGGREGATES), fake.IPSPACE,
+ fake.SECURITY_CERT_DEFAULT_EXPIRE_DAYS)
self.library._get_api_client.assert_called_once_with(
vserver=vserver_name)
self.library._create_vserver_lifs.assert_called_once_with(
diff --git a/manila/tests/share/drivers/netapp/dataontap/fakes.py b/manila/tests/share/drivers/netapp/dataontap/fakes.py
index cfc2c8fc21..2832fdf697 100644
--- a/manila/tests/share/drivers/netapp/dataontap/fakes.py
+++ b/manila/tests/share/drivers/netapp/dataontap/fakes.py
@@ -68,6 +68,8 @@ AGGR_POOL_NAME = 'manila_aggr_1'
FLEXGROUP_POOL_NAME = 'flexgroup_pool'
ROOT_AGGREGATES = ('root_aggr_1', 'root_aggr_2')
ROOT_VOLUME_AGGREGATE = 'manila1'
+SECURITY_CERT_DEFAULT_EXPIRE_DAYS = 365
+SECURITY_CERT_LARGE_EXPIRE_DAYS = 3652
ROOT_VOLUME = 'root'
CLUSTER_NODE = 'cluster1_01'
CLUSTER_NODES = ('cluster1_01', 'cluster1_02')
diff --git a/releasenotes/notes/netapp-add-new-security-certificate-for-vserver-aba543211ae6b811.yaml b/releasenotes/notes/netapp-add-new-security-certificate-for-vserver-aba543211ae6b811.yaml
new file mode 100644
index 0000000000..e66d9d1d9d
--- /dev/null
+++ b/releasenotes/notes/netapp-add-new-security-certificate-for-vserver-aba543211ae6b811.yaml
@@ -0,0 +1,8 @@
+---
+features:
+ - |
+ NetApp ONTAP driver now allows cloud operator to define security
+ certificate expire days for vserver. So instead of using vserver's default
+ security certificate with 365 expire days, cloud operator can ask backend
+ to create new security certificate with given expire days using config
+ option 'netapp_security_cert_expire_days'.