Skip to content
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

Support to recover/purge delete secret #1489

Merged
merged 3 commits into from
Mar 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion plugins/modules/azure_rm_keyvaultkey.py
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@

try:
from azure.keyvault.keys import KeyClient
from azure.core.exceptions import ResourceNotFoundError
from datetime import datetime
except ImportError:
# This is handled in azure_rm_common
Expand Down Expand Up @@ -191,10 +192,12 @@ def exec_module(self, **kwargs):
if self.state == 'absent':
changed = True

except Exception:
except ResourceNotFoundError as ec:
# Key doesn't exist
if self.state == 'present':
changed = True
except Exception as ec:
self.fail("Find the key vault secret got exception, exception as {0}".format(ec))

self.results['changed'] = changed
self.results['state'] = results
Expand Down
19 changes: 12 additions & 7 deletions plugins/modules/azure_rm_keyvaultkey_info.py
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,7 @@
from ansible_collections.azure.azcollection.plugins.module_utils.azure_rm_common import AzureRMModuleBase

try:
from azure.core.exceptions import ResourceNotFoundError
from azure.keyvault.keys import KeyClient
except ImportError:
# This is handled in azure_rm_common
Expand Down Expand Up @@ -398,9 +399,10 @@ def get_key(self):
self.log("Response : {0}".format(response))
results.append(response)

except Exception as e:
self.fail(e)
except ResourceNotFoundError as e:
self.log("Did not find the key vault key {0}: {1}".format(self.name, str(e)))
except Exception as ec:
self.fail("Find the key vault key got a exception as {0}".format(ec))
return results

def get_key_versions(self):
Expand All @@ -422,7 +424,7 @@ def get_key_versions(self):
if self.has_tags(item['tags'], self.tags):
results.append(item)
except Exception as e:
self.log("Did not find key versions {0} : {1}.".format(self.name, str(e)))
self.fail("Did not find key versions {0} : {1}.".format(self.name, str(e)))
return results

def list_keys(self):
Expand All @@ -444,7 +446,7 @@ def list_keys(self):
if self.has_tags(item['tags'], self.tags):
results.append(item)
except Exception as e:
self.log("Did not find key vault in current subscription {0}.".format(str(e)))
self.fail("Did not find key vault in current subscription {0}.".format(str(e)))
return results

def get_deleted_key(self):
Expand All @@ -465,8 +467,11 @@ def get_deleted_key(self):
self.log("Response : {0}".format(response))
results.append(response)

except Exception as e:
self.log("Did not find the key vault key {0}: {1}".format(self.name, str(e)))
except ResourceNotFoundError as ec:
self.log("Did not find the key vault key {0}: {1}".format(self.name, str(ec)))
except Exception as ec:
self.fail("Find the key vault key got a exception {0}".format(str(ec)))

return results

def list_deleted_keys(self):
Expand All @@ -488,7 +493,7 @@ def list_deleted_keys(self):
if self.has_tags(item['tags'], self.tags):
results.append(item)
except Exception as e:
self.log("Did not find key vault in current subscription {0}.".format(str(e)))
self.fail("Did not find key vault in current subscription {0}.".format(str(e)))
return results


Expand Down
71 changes: 68 additions & 3 deletions plugins/modules/azure_rm_keyvaultsecret.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,14 @@
description:
- Optional valid-from datetime for secret
type: str
recover_if_need:
description:
- Whether to permanently recover delete secrets.
type: bool
purge_if_need:
description:
- Whether to permanently delete secrets.
type: bool
state:
description:
- Assert the state of the subnet. Use C(present) to create or update a secret and C(absent) to delete a secret .
Expand Down Expand Up @@ -76,6 +84,18 @@
secret_name: MySecret
keyvault_uri: https://contoso.vault.azure.net/
state: absent

- name: Recover a delete secret
azure_rm_keyvaultsecret:
secret_name: MySecret
keyvault_uri: https://contoso.vault.azure.net/
recover_if_need: true

- name: Purge a delete secret
azure_rm_keyvaultsecret:
secret_name: MySecret
keyvault_uri: https://contoso.vault.azure.net/
purge_if_need: true
'''

RETURN = '''
Expand All @@ -96,6 +116,8 @@

try:
from azure.keyvault.secrets import SecretClient
from azure.core.exceptions import ResourceNotFoundError
from azure.core.exceptions import HttpResponseError
import dateutil.parser
except ImportError:
# This is handled in azure_rm_common
Expand All @@ -114,6 +136,8 @@ def __init__(self):
secret_expiry=dict(type='str', no_log=True),
keyvault_uri=dict(type='str', no_log=True, required=True),
state=dict(type='str', default='present', choices=['present', 'absent']),
recover_if_need=dict(type='bool'),
purge_if_need=dict(type='bool'),
content_type=dict(type='str')
)

Expand All @@ -135,6 +159,8 @@ def __init__(self):
self.data_creds = None
self.client = None
self.tags = None
self.recover_if_need = None
self.purge_if_need = None
self.content_type = None

super(AzureRMKeyVaultSecret, self).__init__(self.module_arg_spec,
Expand Down Expand Up @@ -162,10 +188,12 @@ def exec_module(self, **kwargs):
elif self.secret_value and results['secret_value'] != self.secret_value:
changed = True

except Exception as ec:
except ResourceNotFoundError as ec:
# Secret doesn't exist
if self.state == 'present':
changed = True
except Exception as ec2:
self.fail("Find the key vault secret got exception, exception as {0}".format(str(ec2)))

self.results['changed'] = changed
self.results['state'] = results
Expand All @@ -181,9 +209,21 @@ def exec_module(self, **kwargs):
if not self.check_mode:
# Create secret
if self.state == 'present' and changed:
results['secret_id'] = self.create_update_secret(self.secret_name, self.secret_value, self.tags, self.content_type, valid_from, expiry)
if self.get_delete_secret(self.secret_name):
if self.recover_if_need:
results['secret_id'] = self.recover_delete_secret(self.secret_name)
status = 'Recover'
elif self.purge_if_need:
self.purge_deleted_secret(self.secret_name)
status = 'Purged'
else:
self.fail("Secret {0} is currently in a deleted but recoverable state, and its name cannot be reused; in this state,\
the secret can only be recovered or purged.".format(self.secret_name))
else:
results['secret_id'] = self.create_update_secret(self.secret_name, self.secret_value, self.tags, self.content_type, valid_from, expiry)
status = 'Created'
self.results['state'] = results
self.results['state']['status'] = 'Created'
self.results['state']['status'] = status
# Delete secret
elif self.state == 'absent' and changed:
results['secret_id'] = self.delete_secret(self.secret_name)
Expand Down Expand Up @@ -225,6 +265,31 @@ def delete_secret(self, name):
result = self.get_poller_result(deleted_secret)
return result.properties._id

def recover_delete_secret(self, name):
''' Recover a delete secret '''
try:
recover_delete_secret = self.client.begin_recover_deleted_secret(name)
result = self.get_poller_result(recover_delete_secret)
return result._id
except HttpResponseError as ec:
self.fail("Recover the delete secret fail, detail info {0}".format(ec))

def purge_deleted_secret(self, name):
''' Purge delete secret '''
try:
purge_deleted_secret = self.client.purge_deleted_secret(name)
return purge_deleted_secret
except HttpResponseError as ec:
self.fail("Purge delete secret fail, detail info {0}".format(ec))

def get_delete_secret(self, name):
''' Get delete secret '''
try:
self.client.get_deleted_secret(name=name)
except ResourceNotFoundError:
return False
return True


def main():
AzureRMKeyVaultSecret()
Expand Down
21 changes: 14 additions & 7 deletions plugins/modules/azure_rm_keyvaultsecret_info.py
Original file line number Diff line number Diff line change
Expand Up @@ -163,12 +163,14 @@

try:
from azure.keyvault.secrets import SecretClient
from azure.core.exceptions import ResourceNotFoundError
except ImportError:
# This is handled in azure_rm_common
pass


def secretbundle_to_dict(bundle):

return dict(tags=bundle._properties._tags,
attributes=dict(
enabled=bundle._properties._attributes.enabled,
Expand Down Expand Up @@ -302,9 +304,11 @@ def get_secret(self):
self.log("Response : {0}".format(response))
results.append(response)

except Exception as e:
except ResourceNotFoundError as ec:
self.log("Did not find the key vault secret {0}: {1}".format(
self.name, str(e)))
self.name, str(ec)))
except Exception as ec2:
self.fail("Find the key vault secret got exception, exception as {0}".format(str(ec2)))
return results

def get_secret_versions(self):
Expand All @@ -326,7 +330,7 @@ def get_secret_versions(self):
if self.has_tags(item['tags'], self.tags):
results.append(item)
except Exception as e:
self.log("Did not find secret versions {0} : {1}.".format(
self.fail("Did not find secret versions {0} : {1}.".format(
self.name, str(e)))
return results

Expand All @@ -349,7 +353,7 @@ def list_secrets(self):
if self.has_tags(item['tags'], self.tags):
results.append(item)
except Exception as e:
self.log(
self.fail(
"Did not find key vault in current subscription {0}.".format(
str(e)))
return results
Expand All @@ -372,9 +376,12 @@ def get_deleted_secret(self):
self.log("Response : {0}".format(response))
results.append(response)

except Exception as e:
except ResourceNotFoundError as ec:
self.log("Did not find the key vault secret {0}: {1}".format(
self.name, str(e)))
self.name, str(ec)))
except Exception as ec2:
self.fail("Did not find the key vault secret {0}: {1}".format(
self.name, str(ec2)))
return results

def list_deleted_secrets(self):
Expand All @@ -396,7 +403,7 @@ def list_deleted_secrets(self):
if self.has_tags(item['tags'], self.tags):
results.append(item)
except Exception as e:
self.log(
self.fail(
"Did not find key vault in current subscription {0}.".format(
str(e)))
return results
Expand Down