[docs]@dataclasses.dataclassclassSecret:""" AWS Secret Manager secret object. - The camel case attributes are raw value from AWS API. - The snake case attributes are user-friendly accessor to the data. - only one of ``SecretBinary`` or ``SecretString`` could exist. - if you know what data type to expect in the secret, please use :meth:`Secret.binary`, :meth:`Secret.string`, :meth:`Secret.json_dict`, :meth:`Secret.json_list` to access the data. """ARN:str=dataclasses.field()Name:str=dataclasses.field()VersionId:T.Optional[str]=dataclasses.field(default=None)CreatedDate:T.Optional[datetime]=dataclasses.field(default=None)SecretBinary:T.Optional[bytes]=dataclasses.field(default=None)SecretString:T.Optional[str]=dataclasses.field(default=None)VersionStages:T.List[str]=dataclasses.field(default_factory=list)@cached_propertydeffingerprint(self)->bytes:""" The fingerprint of the content. Can be used for comparison. """ifself.SecretBinaryisnotNone:returnself.SecretBinaryelse:returnself.SecretString.encode("utf-8")
[docs]@classmethoddefload(cls,sm_client,name_or_arn:str,version_id:T.Optional[str]=None,version_stage:T.Optional[str]=None,)->T.Optional["Secret"]:""" Load secret data. Ref: - describe_secret: https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/secretsmanager.html#SecretsManager.Client.describe_secret - get_secret_value: https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/secretsmanager.html#SecretsManager.Client.get_secret_value - list_secret_version_ids: https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/secretsmanager.html#SecretsManager.Client.list_secret_version_ids """# --- resolve argumentskwargs=dict(SecretId=name_or_arn)ifversion_id:# pragma: no coverkwargs["VersionId"]=version_idifversion_id:# pragma: no coverkwargs["VersionStage"]=version_stagetry:response=sm_client.get_secret_value(**kwargs)returncls(ARN=response["ARN"],Name=response["Name"],VersionId=response["VersionId"],SecretBinary=response.get("SecretBinary"),SecretString=response.get("SecretString"),CreatedDate=response["CreatedDate"],VersionStages=response.get("VersionStages",[]),)exceptExceptionase:if"ResourceNotFoundException"instr(e):returnNoneelse:# pragma: no coverraisee
@classmethoddef_from_create_or_update_secret_response(cls,create_or_update_secret_kwargs:dict,create_or_update_secret_response:dict,):created_date=(create_or_update_secret_response.get("ResponseMetadata",{}).get("HTTPHeaders",{}).get("date"))ifcreated_dateisnotNone:created_date=datetime.strptime(created_date,"%a, %d %b %Y %H:%M:%S %Z")returnSecret(ARN=create_or_update_secret_response["ARN"],Name=create_or_update_secret_response["Name"],VersionId=create_or_update_secret_response.get("VersionId"),SecretBinary=create_or_update_secret_kwargs.get("SecretBinary"),SecretString=create_or_update_secret_kwargs.get("SecretString"),CreatedDate=created_date,)@propertydefbinary(self)->bytes:""" The binary user data. """returnself.SecretBinary@propertydefstring(self)->str:""" The string user data. """returnself.SecretString@cached_propertydefjson_dict(self)->dict:""" The python dict user data. """returnjson.loads(strip_comments(self.SecretString))@cached_propertydefjson_list(self)->list:# pragma: no cover""" The python list user data. """returnjson.loads(strip_comments(self.SecretString))@propertydefaws_account_id(self)->str:""" The aws account id of this secret. """returnself.ARN.split(":")[4]@propertydefaws_region(self)->str:""" The aws region of this secret. """returnself.ARN.split(":")[3]
[docs]defdeploy_secret(sm_client,name_or_arn:str,data:T.Union[bytes,str,list,dict,T.Any],description:T.Optional[str]=None,kms_key_id:T.Optional[str]=None,tags:T.Optional[T.Dict[str,str]]=None,add_replica_regions:T.Optional[T.List[T.Dict[str,str]]]=None,force_overwrite_replica_secret:T.Optional[bool]=None,client_request_token:T.Optional[str]=None,skip_if_duplicated:bool=True,)->T.Optional[Secret]:""" Create or Update an AWS Secret. - create_secret: https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/secretsmanager.html#SecretsManager.Client.create_secret - update_secret: https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/secretsmanager.html#SecretsManager.Client.update_secret - tag_resource: https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/secretsmanager.html#SecretsManager.Client.tag_resource - untag_resource: https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/secretsmanager.html#SecretsManager.Client.untag_resource Note: secret manager can only add tag in creation, update_secret doesn't support tagging, this function will automatically call ``tag_resource`` API when needed. :param sm_client: the boto3 secretmanager client. :param name_or_arn: name or the ARN of this secret. :param data: secret data you want to store, currently it supports bytes, string, json serializable dict or list. :param description: description of this secret. :param kms_key_id: the KMS key id you want to use for encryption, by default it uses the AWS managed KMS key. :param tags: the key value pair of the AWS resource tags. :param add_replica_regions: see official document. :param force_overwrite_replica_secret: see official document. :param client_request_token: see official document. :param skip_if_duplicated: default True, if True, will compare the secret data to the existing one before deployment. If they are the same, then no deployment happens. :return: None or an :class:`Secret` object, None means that the deployment doesn't happen. """# --------------------------------------------------------------------------# input argument pre processing# --------------------------------------------------------------------------create_or_update_secret_kwargs=dict()# dataifisinstance(data,bytes):create_or_update_secret_kwargs["SecretBinary"]=dataelifisinstance(data,str):create_or_update_secret_kwargs["SecretString"]=dataelifisinstance(data,(list,dict)):create_or_update_secret_kwargs["SecretString"]=json.dumps(data)else:# pragma: no coverraiseNotImplementedError# descriptionifdescription:create_or_update_secret_kwargs["Description"]=description# kms key idifkms_key_id:# pragma: no covercreate_or_update_secret_kwargs["KmsKeyId"]=kms_key_id# tagsiftagsisNone:tags=dict()tags_=[{"Key":k,"Value":v}fork,vintags.items()]# --------------------------------------------------------------------------# create or update# --------------------------------------------------------------------------secret=Secret.load(sm_client,name_or_arn=name_or_arn,)is_create=secretisNone# create branchifis_create:create_or_update_secret_kwargs["Name"]=name_or_arniflen(tags_):create_or_update_secret_kwargs["Tags"]=tags_ifadd_replica_regionsisnotNone:# pragma: no covercreate_or_update_secret_kwargs["AddReplicaRegions"]=add_replica_regionsifforce_overwrite_replica_secretisnotNone:# pragma: no covercreate_or_update_secret_kwargs["ForceOverwriteReplicaSecret"]=add_replica_regionsifclient_request_tokenisnotNone:# pragma: no covercreate_or_update_secret_kwargs["ClientRequestToken"]=client_request_tokenresponse=sm_client.create_secret(**create_or_update_secret_kwargs)secret=Secret._from_create_or_update_secret_response(create_or_update_secret_kwargs=create_or_update_secret_kwargs,create_or_update_secret_response=response,)returnsecret# update branch# check duplicationifskip_if_duplicated:# find existing secret's fingerprintif"SecretBinary"increate_or_update_secret_kwargs:fingerprint=create_or_update_secret_kwargs["SecretBinary"]else:fingerprint=create_or_update_secret_kwargs["SecretString"].encode("utf-8")# if the same, do nothingiffingerprint==secret.fingerprint:returnNonecreate_or_update_secret_kwargs["SecretId"]=name_or_arnresponse=sm_client.update_secret(**create_or_update_secret_kwargs)secret=Secret._from_create_or_update_secret_response(create_or_update_secret_kwargs=create_or_update_secret_kwargs,create_or_update_secret_response=response,)# do taggingiftags_isnotNone:sm_client.tag_resource(SecretId=name_or_arn,Tags=tags_)returnsecret
[docs]defdelete_secret(sm_client,name_or_arn:str,recovery_window_in_days:T.Optional[int]=None,force_delete_without_recovery:T.Optional[bool]=None,)->bool:""" Delete a Secret. Ref: - delete_secret: https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/secretsmanager.html#SecretsManager.Client.delete_secret :param sm_client: the boto3 secretmanager client. :param name_or_arn: name or the ARN of this secret. :param recovery_window_in_days: see official document. :param force_delete_without_recovery: see official document. :return: a boolean value to indicate whether a deletion happened. """kwargs=dict(SecretId=name_or_arn)ifrecovery_window_in_daysisnotNone:# pragma: no coverkwargs["RecoveryWindowInDays"]=recovery_window_in_daysifforce_delete_without_recoveryisnotNone:kwargs["ForceDeleteWithoutRecovery"]=force_delete_without_recoverytry:sm_client.delete_secret(**kwargs)returnTrueexceptExceptionase:if"ResourceNotFoundException"instr(e):returnFalseelse:# pragma: no coverraisee