# python/01-secret-storage.py"""Secret storage patterns and credential management"""fromtypingimportList,Dict,Any,Optional,Union,Tuplefromdataclassesimportdataclass,asdictfromenumimportEnumimportosimportjsonimportbase64importhashlibimportsecretsimporttimefromdatetimeimportdatetime,timedeltaimportloggingfrompathlibimportPathimportyamlimporttomlfromcryptography.fernetimportFernetfromcryptography.hazmat.primitivesimporthashesfromcryptography.hazmat.primitives.kdf.pbkdf2importPBKDF2HMACimportkeyringimporthvacimportboto3fromazure.keyvault.secretsimportSecretClientfromazure.identityimportDefaultAzureCredentialimportgoogle.cloud.secretmanagerassecretmanagerfromgoogle.cloudimportsecretmanager_v1# Configure logginglogging.basicConfig(level=logging.INFO)logger=logging.getLogger(__name__)classSecretType(Enum):"""Secret type enumeration"""PASSWORD="password"API_KEY="api_key"TOKEN="token"CERTIFICATE="certificate"PRIVATE_KEY="private_key"DATABASE_URL="database_url"ENCRYPTION_KEY="encryption_key"classSecretSource(Enum):"""Secret source enumeration"""ENVIRONMENT="environment"FILE="file"VAULT="vault"CLOUD="cloud"KEYRING="keyring"@dataclassclassSecret:"""Secret definition"""name:strvalue:strsecret_type:SecretTypesource:SecretSourcecreated_at:datetimeexpires_at:Optional[datetime]=Nonetags:Dict[str,str]=Noneversion:str="1"def__post_init__(self):ifself.tagsisNone:self.tags={}ifself.created_atisNone:self.created_at=datetime.utcnow()classEnvironmentSecretManager:"""Environment variable secret manager"""def__init__(self,prefix:str="SECRET_"):self.prefix=prefixself.secrets={}self.load_secrets()defload_secrets(self)->None:"""Load secrets from environment variables"""forkey,valueinos.environ.items():ifkey.startswith(self.prefix):secret_name=key[len(self.prefix):].lower()self.secrets[secret_name]=valuelogger.debug(f"Loaded secret from environment: {secret_name}")defget_secret(self,name:str,default:Optional[str]=None)->Optional[str]:"""Get secret value"""returnself.secrets.get(name,default)defset_secret(self,name:str,value:str)->None:"""Set secret value (for testing only)"""self.secrets[name]=valueos.environ[f"{self.prefix}{name.upper()}"]=valuedeflist_secrets(self)->List[str]:"""List all secret names"""returnlist(self.secrets.keys())defhas_secret(self,name:str)->bool:"""Check if secret exists"""returnnameinself.secretsclassFileSecretManager:"""File-based secret manager"""def__init__(self,secrets_file:str,encrypted:bool=True):self.secrets_file=Path(secrets_file)self.encrypted=encryptedself.encryption_key=Noneself.secrets={}ifencrypted:self.encryption_key=self._get_or_create_encryption_key()self.load_secrets()def_get_or_create_encryption_key(self)->bytes:"""Get or create encryption key"""key_file=self.secrets_file.parent/".secret_key"ifkey_file.exists():withopen(key_file,'rb')asf:returnf.read()else:key=Fernet.generate_key()withopen(key_file,'wb')asf:f.write(key)# Set restrictive permissionskey_file.chmod(0o600)returnkeydef_encrypt_value(self,value:str)->str:"""Encrypt secret value"""ifnotself.encrypted:returnvaluefernet=Fernet(self.encryption_key)encrypted_value=fernet.encrypt(value.encode())returnbase64.b64encode(encrypted_value).decode()def_decrypt_value(self,encrypted_value:str)->str:"""Decrypt secret value"""ifnotself.encrypted:returnencrypted_valuetry:encrypted_bytes=base64.b64decode(encrypted_value.encode())fernet=Fernet(self.encryption_key)decrypted_value=fernet.decrypt(encrypted_bytes)returndecrypted_value.decode()exceptExceptionase:logger.error(f"Failed to decrypt secret: {e}")raisedefload_secrets(self)->None:"""Load secrets from file"""ifnotself.secrets_file.exists():logger.warning(f"Secrets file not found: {self.secrets_file}")returntry:withopen(self.secrets_file,'r')asf:ifself.secrets_file.suffix=='.json':data=json.load(f)elifself.secrets_file.suffix=='.yaml'orself.secrets_file.suffix=='.yml':data=yaml.safe_load(f)elifself.secrets_file.suffix=='.toml':data=toml.load(f)else:# Assume plain text formatdata={}forlineinf:if'='inlineandnotline.strip().startswith('#'):key,value=line.strip().split('=',1)data[key]=valueforname,valueindata.items():ifself.encrypted:decrypted_value=self._decrypt_value(value)else:decrypted_value=valueself.secrets[name]=decrypted_valuelogger.debug(f"Loaded secret from file: {name}")exceptExceptionase:logger.error(f"Failed to load secrets from file: {e}")raisedefsave_secrets(self)->None:"""Save secrets to file"""try:data={}forname,valueinself.secrets.items():ifself.encrypted:encrypted_value=self._encrypt_value(value)else:encrypted_value=valuedata[name]=encrypted_valuewithopen(self.secrets_file,'w')asf:ifself.secrets_file.suffix=='.json':json.dump(data,f,indent=2)elifself.secrets_file.suffix=='.yaml'orself.secrets_file.suffix=='.yml':yaml.dump(data,f,default_flow_style=False)elifself.secrets_file.suffix=='.toml':toml.dump(data,f)else:# Plain text formatforname,valueindata.items():f.write(f"{name}={value}\n")# Set restrictive permissionsself.secrets_file.chmod(0o600)logger.info(f"Secrets saved to file: {self.secrets_file}")exceptExceptionase:logger.error(f"Failed to save secrets to file: {e}")raisedefget_secret(self,name:str,default:Optional[str]=None)->Optional[str]:"""Get secret value"""returnself.secrets.get(name,default)defset_secret(self,name:str,value:str)->None:"""Set secret value"""self.secrets[name]=valueself.save_secrets()defdelete_secret(self,name:str)->bool:"""Delete secret"""ifnameinself.secrets:delself.secrets[name]self.save_secrets()returnTruereturnFalsedeflist_secrets(self)->List[str]:"""List all secret names"""returnlist(self.secrets.keys())classKeyringSecretManager:"""Keyring-based secret manager"""def__init__(self,service_name:str):self.service_name=service_namedefget_secret(self,name:str,default:Optional[str]=None)->Optional[str]:"""Get secret from keyring"""try:returnkeyring.get_password(self.service_name,name)exceptExceptionase:logger.error(f"Failed to get secret from keyring: {e}")returndefaultdefset_secret(self,name:str,value:str)->None:"""Set secret in keyring"""try:keyring.set_password(self.service_name,name,value)logger.info(f"Secret set in keyring: {name}")exceptExceptionase:logger.error(f"Failed to set secret in keyring: {e}")raisedefdelete_secret(self,name:str)->bool:"""Delete secret from keyring"""try:keyring.delete_password(self.service_name,name)logger.info(f"Secret deleted from keyring: {name}")returnTrueexceptExceptionase:logger.error(f"Failed to delete secret from keyring: {e}")returnFalsedeflist_secrets(self)->List[str]:"""List secrets (keyring doesn't support listing)"""logger.warning("Keyring doesn't support listing secrets")return[]classVaultSecretManager:"""HashiCorp Vault secret manager"""def__init__(self,vault_url:str,token:str,mount_point:str="secret"):self.vault_url=vault_urlself.token=tokenself.mount_point=mount_pointself.client=hvac.Client(url=vault_url,token=token)self.client.is_authenticated()defget_secret(self,path:str,default:Optional[str]=None)->Optional[str]:"""Get secret from Vault"""try:response=self.client.secrets.kv.v2.read_secret_version(path=path,mount_point=self.mount_point)returnresponse['data']['data'].get('value')exceptExceptionase:logger.error(f"Failed to get secret from Vault: {e}")returndefaultdefset_secret(self,path:str,value:str,metadata:Optional[Dict[str,str]]=None)->None:"""Set secret in Vault"""try:secret_data={'value':value}ifmetadata:secret_data.update(metadata)self.client.secrets.kv.v2.create_or_update_secret(path=path,secret=secret_data,mount_point=self.mount_point)logger.info(f"Secret set in Vault: {path}")exceptExceptionase:logger.error(f"Failed to set secret in Vault: {e}")raisedefdelete_secret(self,path:str)->bool:"""Delete secret from Vault"""try:self.client.secrets.kv.v2.delete_metadata_and_all_versions(path=path,mount_point=self.mount_point)logger.info(f"Secret deleted from Vault: {path}")returnTrueexceptExceptionase:logger.error(f"Failed to delete secret from Vault: {e}")returnFalsedeflist_secrets(self,path:str="")->List[str]:"""List secrets in Vault"""try:response=self.client.secrets.kv.v2.list_secrets(path=path,mount_point=self.mount_point)returnresponse['data']['keys']exceptExceptionase:logger.error(f"Failed to list secrets from Vault: {e}")return[]classAWSSecretsManager:"""AWS Secrets Manager client"""def__init__(self,region_name:str="us-east-1"):self.region_name=region_nameself.client=boto3.client('secretsmanager',region_name=region_name)defget_secret(self,secret_name:str,default:Optional[str]=None)->Optional[str]:"""Get secret from AWS Secrets Manager"""try:response=self.client.get_secret_value(SecretId=secret_name)returnresponse['SecretString']exceptExceptionase:logger.error(f"Failed to get secret from AWS: {e}")returndefaultdefset_secret(self,secret_name:str,value:str,description:str="")->None:"""Set secret in AWS Secrets Manager"""try:self.client.create_secret(Name=secret_name,SecretString=value,Description=description)logger.info(f"Secret set in AWS: {secret_name}")exceptself.client.exceptions.ResourceExistsException:# Update existing secretself.client.update_secret(SecretId=secret_name,SecretString=value)logger.info(f"Secret updated in AWS: {secret_name}")exceptExceptionase:logger.error(f"Failed to set secret in AWS: {e}")raisedefdelete_secret(self,secret_name:str)->bool:"""Delete secret from AWS Secrets Manager"""try:self.client.delete_secret(SecretId=secret_name,ForceDeleteWithoutRecovery=True)logger.info(f"Secret deleted from AWS: {secret_name}")returnTrueexceptExceptionase:logger.error(f"Failed to delete secret from AWS: {e}")returnFalsedeflist_secrets(self)->List[str]:"""List secrets in AWS Secrets Manager"""try:response=self.client.list_secrets()return[secret['Name']forsecretinresponse['SecretList']]exceptExceptionase:logger.error(f"Failed to list secrets from AWS: {e}")return[]classAzureKeyVaultManager:"""Azure Key Vault secret manager"""def__init__(self,vault_url:str):self.vault_url=vault_urlself.credential=DefaultAzureCredential()self.client=SecretClient(vault_url=vault_url,credential=self.credential)defget_secret(self,name:str,default:Optional[str]=None)->Optional[str]:"""Get secret from Azure Key Vault"""try:secret=self.client.get_secret(name)returnsecret.valueexceptExceptionase:logger.error(f"Failed to get secret from Azure: {e}")returndefaultdefset_secret(self,name:str,value:str)->None:"""Set secret in Azure Key Vault"""try:self.client.set_secret(name,value)logger.info(f"Secret set in Azure: {name}")exceptExceptionase:logger.error(f"Failed to set secret in Azure: {e}")raisedefdelete_secret(self,name:str)->bool:"""Delete secret from Azure Key Vault"""try:self.client.begin_delete_secret(name)logger.info(f"Secret deleted from Azure: {name}")returnTrueexceptExceptionase:logger.error(f"Failed to delete secret from Azure: {e}")returnFalsedeflist_secrets(self)->List[str]:"""List secrets in Azure Key Vault"""try:secrets=[]forsecret_propertiesinself.client.list_properties_of_secrets():secrets.append(secret_properties.name)returnsecretsexceptExceptionase:logger.error(f"Failed to list secrets from Azure: {e}")return[]classGCPSecretManager:"""Google Cloud Secret Manager client"""def__init__(self,project_id:str):self.project_id=project_idself.client=secretmanager.SecretManagerServiceClient()defget_secret(self,secret_id:str,version:str="latest",default:Optional[str]=None)->Optional[str]:"""Get secret from GCP Secret Manager"""try:name=f"projects/{self.project_id}/secrets/{secret_id}/versions/{version}"response=self.client.access_secret_version(request={"name":name})returnresponse.payload.data.decode("UTF-8")exceptExceptionase:logger.error(f"Failed to get secret from GCP: {e}")returndefaultdefset_secret(self,secret_id:str,value:str)->None:"""Set secret in GCP Secret Manager"""try:parent=f"projects/{self.project_id}"# Create secret if it doesn't existtry:self.client.create_secret(request={"parent":parent,"secret_id":secret_id,"secret":{"replication":{"automatic":{}}},})exceptException:# Secret might already existpass# Add secret versionself.client.add_secret_version(request={"parent":f"{parent}/secrets/{secret_id}","payload":{"data":value.encode("UTF-8")},})logger.info(f"Secret set in GCP: {secret_id}")exceptExceptionase:logger.error(f"Failed to set secret in GCP: {e}")raisedefdelete_secret(self,secret_id:str)->bool:"""Delete secret from GCP Secret Manager"""try:name=f"projects/{self.project_id}/secrets/{secret_id}"self.client.delete_secret(request={"name":name})logger.info(f"Secret deleted from GCP: {secret_id}")returnTrueexceptExceptionase:logger.error(f"Failed to delete secret from GCP: {e}")returnFalsedeflist_secrets(self)->List[str]:"""List secrets in GCP Secret Manager"""try:parent=f"projects/{self.project_id}"secrets=[]forsecretinself.client.list_secrets(request={"parent":parent}):secret_id=secret.name.split("/")[-1]secrets.append(secret_id)returnsecretsexceptExceptionase:logger.error(f"Failed to list secrets from GCP: {e}")return[]classUnifiedSecretManager:"""Unified secret manager supporting multiple backends"""def__init__(self,primary_backend:Any,fallback_backends:List[Any]=None):self.primary_backend=primary_backendself.fallback_backends=fallback_backendsor[]self.all_backends=[primary_backend]+self.fallback_backendsdefget_secret(self,name:str,default:Optional[str]=None)->Optional[str]:"""Get secret from primary backend with fallback"""# Try primary backend firstvalue=self.primary_backend.get_secret(name)ifvalueisnotNone:returnvalue# Try fallback backendsforbackendinself.fallback_backends:value=backend.get_secret(name)ifvalueisnotNone:returnvaluereturndefaultdefset_secret(self,name:str,value:str)->None:"""Set secret in primary backend"""self.primary_backend.set_secret(name,value)defdelete_secret(self,name:str)->bool:"""Delete secret from all backends"""success=Trueforbackendinself.all_backends:ifhasattr(backend,'delete_secret'):ifnotbackend.delete_secret(name):success=Falsereturnsuccessdeflist_secrets(self)->List[str]:"""List secrets from primary backend"""returnself.primary_backend.list_secrets()# Usage examplesdefexample_secret_management():"""Example secret management usage"""# Environment-based secretsenv_manager=EnvironmentSecretManager("APP_")env_secret=env_manager.get_secret("database_password")print(f"Environment secret: {env_secret}")# File-based secretsfile_manager=FileSecretManager("/tmp/secrets.json",encrypted=True)file_manager.set_secret("api_key","secret-api-key")file_secret=file_manager.get_secret("api_key")print(f"File secret: {file_secret}")# Keyring secretskeyring_manager=KeyringSecretManager("my-app")keyring_manager.set_secret("database_url","postgresql://user:pass@localhost/db")keyring_secret=keyring_manager.get_secret("database_url")print(f"Keyring secret: {keyring_secret}")# AWS Secrets Manageraws_manager=AWSSecretsManager("us-east-1")aws_secret=aws_manager.get_secret("my-secret")print(f"AWS secret: {aws_secret}")# Unified secret managerunified_manager=UnifiedSecretManager(primary_backend=env_manager,fallback_backends=[file_manager,keyring_manager])unified_secret=unified_manager.get_secret("database_password")print(f"Unified secret: {unified_secret}")
# python/02-secret-rotation.py"""Secret rotation patterns and automated credential management"""fromtypingimportList,Dict,Any,Optional,Union,Tupleimporttimeimportthreadingfromdatetimeimportdatetime,timedeltaimportloggingfromdataclassesimportdataclassfromenumimportEnumimportasynciofromconcurrent.futuresimportThreadPoolExecutorimportscheduleimportcroniterlogger=logging.getLogger(__name__)classRotationStrategy(Enum):"""Rotation strategy enumeration"""TIME_BASED="time_based"USAGE_BASED="usage_based"MANUAL="manual"EVENT_BASED="event_based"@dataclassclassRotationPolicy:"""Secret rotation policy"""secret_name:strstrategy:RotationStrategyinterval_days:int=30max_usage_count:int=1000cron_schedule:str="0 0 * * *"# Daily at midnightauto_rotate:bool=Truenotify_before_days:int=7classSecretRotator:"""Secret rotation manager"""def__init__(self,secret_manager:Any):self.secret_manager=secret_managerself.rotation_policies={}self.rotation_history={}self.usage_counts={}self.rotation_lock=threading.Lock()self.is_running=Falseself.rotation_thread=Nonedefadd_rotation_policy(self,policy:RotationPolicy)->None:"""Add rotation policy for secret"""self.rotation_policies[policy.secret_name]=policylogger.info(f"Added rotation policy for secret: {policy.secret_name}")defstart_rotation_scheduler(self)->None:"""Start automatic rotation scheduler"""ifself.is_running:logger.warning("Rotation scheduler is already running")returnself.is_running=Trueself.rotation_thread=threading.Thread(target=self._rotation_loop,daemon=True)self.rotation_thread.start()logger.info("Secret rotation scheduler started")defstop_rotation_scheduler(self)->None:"""Stop automatic rotation scheduler"""self.is_running=Falseifself.rotation_thread:self.rotation_thread.join()logger.info("Secret rotation scheduler stopped")def_rotation_loop(self)->None:"""Main rotation loop"""whileself.is_running:try:self._check_rotation_requirements()time.sleep(60)# Check every minuteexceptExceptionase:logger.error(f"Error in rotation loop: {e}")time.sleep(60)def_check_rotation_requirements(self)->None:"""Check if any secrets need rotation"""forsecret_name,policyinself.rotation_policies.items():ifnotpolicy.auto_rotate:continuetry:ifself._should_rotate_secret(secret_name,policy):self._rotate_secret(secret_name,policy)exceptExceptionase:logger.error(f"Error checking rotation for {secret_name}: {e}")def_should_rotate_secret(self,secret_name:str,policy:RotationPolicy)->bool:"""Check if secret should be rotated"""ifpolicy.strategy==RotationStrategy.TIME_BASED:returnself._check_time_based_rotation(secret_name,policy)elifpolicy.strategy==RotationStrategy.USAGE_BASED:returnself._check_usage_based_rotation(secret_name,policy)elifpolicy.strategy==RotationStrategy.EVENT_BASED:returnself._check_event_based_rotation(secret_name,policy)returnFalsedef_check_time_based_rotation(self,secret_name:str,policy:RotationPolicy)->bool:"""Check time-based rotation requirements"""ifsecret_namenotinself.rotation_history:returnTrue# First rotationlast_rotation=self.rotation_history[secret_name].get('last_rotation')ifnotlast_rotation:returnTruedays_since_rotation=(datetime.utcnow()-last_rotation).daysreturndays_since_rotation>=policy.interval_daysdef_check_usage_based_rotation(self,secret_name:str,policy:RotationPolicy)->bool:"""Check usage-based rotation requirements"""usage_count=self.usage_counts.get(secret_name,0)returnusage_count>=policy.max_usage_countdef_check_event_based_rotation(self,secret_name:str,policy:RotationPolicy)->bool:"""Check event-based rotation requirements"""# This would be implemented based on specific events# For example, security breach, compromised credentials, etc.returnFalsedef_rotate_secret(self,secret_name:str,policy:RotationPolicy)->None:"""Rotate secret"""withself.rotation_lock:try:logger.info(f"Starting rotation for secret: {secret_name}")# Generate new secretnew_secret=self._generate_new_secret(secret_name)# Update secret in all backendsself._update_secret_in_backends(secret_name,new_secret)# Update rotation historyself._update_rotation_history(secret_name,new_secret)# Reset usage countself.usage_counts[secret_name]=0# Notify about rotationself._notify_rotation(secret_name,policy)logger.info(f"Successfully rotated secret: {secret_name}")exceptExceptionase:logger.error(f"Failed to rotate secret {secret_name}: {e}")raisedef_generate_new_secret(self,secret_name:str)->str:"""Generate new secret value"""# This would be implemented based on secret type# For example, generate new password, API key, etc.returnf"new_secret_{int(time.time())}"def_update_secret_in_backends(self,secret_name:str,new_secret:str)->None:"""Update secret in all backends"""ifhasattr(self.secret_manager,'set_secret'):self.secret_manager.set_secret(secret_name,new_secret)elifhasattr(self.secret_manager,'all_backends'):forbackendinself.secret_manager.all_backends:ifhasattr(backend,'set_secret'):backend.set_secret(secret_name,new_secret)def_update_rotation_history(self,secret_name:str,new_secret:str)->None:"""Update rotation history"""ifsecret_namenotinself.rotation_history:self.rotation_history[secret_name]={}self.rotation_history[secret_name].update({'last_rotation':datetime.utcnow(),'rotation_count':self.rotation_history[secret_name].get('rotation_count',0)+1,'previous_secret':self.rotation_history[secret_name].get('current_secret'),'current_secret':new_secret})def_notify_rotation(self,secret_name:str,policy:RotationPolicy)->None:"""Notify about secret rotation"""# This would implement actual notification logic# For example, send email, Slack message, etc.logger.info(f"Notification: Secret {secret_name} has been rotated")defrecord_secret_usage(self,secret_name:str)->None:"""Record secret usage for usage-based rotation"""ifsecret_nameinself.usage_counts:self.usage_counts[secret_name]+=1defget_rotation_status(self,secret_name:str)->Dict[str,Any]:"""Get rotation status for secret"""ifsecret_namenotinself.rotation_policies:return{"error":"No rotation policy found"}policy=self.rotation_policies[secret_name]history=self.rotation_history.get(secret_name,{})return{"secret_name":secret_name,"policy":{"strategy":policy.strategy.value,"interval_days":policy.interval_days,"auto_rotate":policy.auto_rotate},"history":history,"usage_count":self.usage_counts.get(secret_name,0),"next_rotation":self._calculate_next_rotation(secret_name,policy)}def_calculate_next_rotation(self,secret_name:str,policy:RotationPolicy)->Optional[datetime]:"""Calculate next rotation time"""ifnotpolicy.auto_rotate:returnNoneifpolicy.strategy==RotationStrategy.TIME_BASED:last_rotation=self.rotation_history.get(secret_name,{}).get('last_rotation')iflast_rotation:returnlast_rotation+timedelta(days=policy.interval_days)else:returndatetime.utcnow()+timedelta(days=policy.interval_days)returnNonedefmanual_rotate(self,secret_name:str)->bool:"""Manually rotate secret"""ifsecret_namenotinself.rotation_policies:logger.error(f"No rotation policy found for secret: {secret_name}")returnFalsepolicy=self.rotation_policies[secret_name]try:self._rotate_secret(secret_name,policy)returnTrueexceptExceptionase:logger.error(f"Manual rotation failed for {secret_name}: {e}")returnFalseclassSecretAuditor:"""Secret access auditor"""def__init__(self):self.access_logs=[]self.audit_lock=threading.Lock()deflog_secret_access(self,secret_name:str,user:str,action:str,success:bool,metadata:Optional[Dict[str,Any]]=None)->None:"""Log secret access"""withself.audit_lock:log_entry={"timestamp":datetime.utcnow(),"secret_name":secret_name,"user":user,"action":action,"success":success,"metadata":metadataor{}}self.access_logs.append(log_entry)logger.info(f"Secret access logged: {secret_name} by {user}")defget_access_logs(self,secret_name:Optional[str]=None,user:Optional[str]=None,start_time:Optional[datetime]=None,end_time:Optional[datetime]=None)->List[Dict[str,Any]]:"""Get access logs with optional filtering"""withself.audit_lock:logs=self.access_logs.copy()# Apply filtersifsecret_name:logs=[logforloginlogsiflog["secret_name"]==secret_name]ifuser:logs=[logforloginlogsiflog["user"]==user]ifstart_time:logs=[logforloginlogsiflog["timestamp"]>=start_time]ifend_time:logs=[logforloginlogsiflog["timestamp"]<=end_time]returnlogsdefget_secret_usage_stats(self,secret_name:str)->Dict[str,Any]:"""Get usage statistics for secret"""logs=self.get_access_logs(secret_name=secret_name)total_accesses=len(logs)successful_accesses=len([logforloginlogsiflog["success"]])failed_accesses=total_accesses-successful_accesses# Group by useruser_accesses={}forloginlogs:user=log["user"]ifusernotinuser_accesses:user_accesses[user]=0user_accesses[user]+=1return{"secret_name":secret_name,"total_accesses":total_accesses,"successful_accesses":successful_accesses,"failed_accesses":failed_accesses,"success_rate":(successful_accesses/total_accesses*100)iftotal_accesses>0else0,"user_accesses":user_accesses,"last_access":logs[-1]["timestamp"]iflogselseNone}# Usage examplesdefexample_secret_rotation():"""Example secret rotation usage"""# Create secret managersecret_manager=EnvironmentSecretManager()# Create rotatorrotator=SecretRotator(secret_manager)# Add rotation policiespolicy1=RotationPolicy(secret_name="database_password",strategy=RotationStrategy.TIME_BASED,interval_days=30,auto_rotate=True)rotator.add_rotation_policy(policy1)policy2=RotationPolicy(secret_name="api_key",strategy=RotationStrategy.USAGE_BASED,max_usage_count=1000,auto_rotate=True)rotator.add_rotation_policy(policy2)# Start rotation schedulerrotator.start_rotation_scheduler()# Record secret usagerotator.record_secret_usage("api_key")# Get rotation statusstatus=rotator.get_rotation_status("database_password")print(f"Rotation status: {status}")# Manual rotationmanual_success=rotator.manual_rotate("database_password")print(f"Manual rotation: {manual_success}")# Secret auditingauditor=SecretAuditor()auditor.log_secret_access("database_password","user1","read",True)auditor.log_secret_access("api_key","user2","write",False)# Get usage statsstats=auditor.get_secret_usage_stats("database_password")print(f"Usage stats: {stats}")# Stop rotation schedulerrotator.stop_rotation_scheduler()