Microsoft Azure Key Vault Keys client library for Python providing cryptographic key management operations
—
Quality
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Automated key rotation management with configurable policies, lifetime actions, and rotation triggers. Azure Key Vault enables compliance with security policies requiring regular key rotation through automated policy-driven key lifecycle management with configurable actions and notifications.
Define and manage automated key rotation policies with customizable lifetime actions.
def get_key_rotation_policy(key_name: str, **kwargs) -> KeyRotationPolicy:
"""
Get the rotation policy for a key.
Parameters:
- key_name: The name of the key
Returns:
KeyRotationPolicy: The current rotation policy for the key
Raises:
- ResourceNotFoundError: If the key doesn't exist
- ForbiddenError: If insufficient permissions
"""
def update_key_rotation_policy(
key_name: str,
policy: KeyRotationPolicy,
*,
lifetime_actions: List[KeyRotationLifetimeAction] = None,
expires_in: str = None,
**kwargs
) -> KeyRotationPolicy:
"""
Update the rotation policy for a key.
Parameters:
- key_name: The name of the key
- policy: The new rotation policy
- lifetime_actions: List of lifetime actions to perform
- expires_in: ISO 8601 duration when key expires (e.g., "P90D" for 90 days)
Returns:
KeyRotationPolicy: The updated rotation policy
Raises:
- ResourceNotFoundError: If the key doesn't exist
- InvalidArgumentError: If policy format is invalid
- ForbiddenError: If insufficient permissions
"""from azure.keyvault.keys import KeyClient, KeyRotationPolicy, KeyRotationLifetimeAction, KeyRotationPolicyAction
from azure.identity import DefaultAzureCredential
client = KeyClient("https://vault.vault.azure.net/", DefaultAzureCredential())
# Get current rotation policy
current_policy = client.get_key_rotation_policy("my-key")
print(f"Current policy expires in: {current_policy.expires_in}")
print(f"Created on: {current_policy.created_on}")
# Create a new rotation policy
lifetime_actions = [
KeyRotationLifetimeAction(
action=KeyRotationPolicyAction.rotate,
time_before_expiry="P30D" # Rotate 30 days before expiry
),
KeyRotationLifetimeAction(
action=KeyRotationPolicyAction.notify,
time_before_expiry="P7D" # Notify 7 days before expiry
)
]
new_policy = client.update_key_rotation_policy(
"my-key",
KeyRotationPolicy(),
lifetime_actions=lifetime_actions,
expires_in="P365D" # Key expires in 365 days
)
print(f"Updated policy ID: {new_policy.id}")Manually trigger key rotation outside of automated policies.
def rotate_key(name: str, **kwargs) -> KeyVaultKey:
"""
Manually rotate a key, creating a new version.
Parameters:
- name: The name of the key to rotate
Returns:
KeyVaultKey: The new version of the rotated key
Raises:
- ResourceNotFoundError: If the key doesn't exist
- ForbiddenError: If rotation permission is not granted
"""# Manually rotate a key
rotated_key = client.rotate_key("my-key")
print(f"Rotated key version: {rotated_key.properties.version}")
print(f"New key ID: {rotated_key.id}")
# Compare with previous version
previous_key = client.get_key("my-key", version="previous-version-id")
print(f"Previous version: {previous_key.properties.version}")
print(f"Current version: {rotated_key.properties.version}")Configure comprehensive rotation policies with multiple actions and conditions.
from datetime import timedelta
def setup_quarterly_rotation_policy(client: KeyClient, key_name: str):
"""Set up a policy for quarterly key rotation with notifications."""
lifetime_actions = [
# Rotate every 90 days
KeyRotationLifetimeAction(
action=KeyRotationPolicyAction.rotate,
time_after_create="P90D"
),
# Notify 14 days before rotation
KeyRotationLifetimeAction(
action=KeyRotationPolicyAction.notify,
time_after_create="P76D" # 90 - 14 = 76 days
),
# Final notification 3 days before rotation
KeyRotationLifetimeAction(
action=KeyRotationPolicyAction.notify,
time_after_create="P87D" # 90 - 3 = 87 days
)
]
policy = client.update_key_rotation_policy(
key_name,
KeyRotationPolicy(),
lifetime_actions=lifetime_actions,
expires_in="P2Y" # Key valid for 2 years
)
return policy
def setup_annual_rotation_policy(client: KeyClient, key_name: str):
"""Set up a policy for annual key rotation."""
lifetime_actions = [
# Rotate annually
KeyRotationLifetimeAction(
action=KeyRotationPolicyAction.rotate,
time_after_create="P365D"
),
# Notify 30 days before rotation
KeyRotationLifetimeAction(
action=KeyRotationPolicyAction.notify,
time_after_create="P335D" # 365 - 30 = 335 days
)
]
policy = client.update_key_rotation_policy(
key_name,
KeyRotationPolicy(),
lifetime_actions=lifetime_actions,
expires_in="P3Y" # Key valid for 3 years
)
return policy
# Usage
quarterly_policy = setup_quarterly_rotation_policy(client, "quarterly-key")
annual_policy = setup_annual_rotation_policy(client, "annual-key")Monitor rotation policies and handle rotation events.
def monitor_key_rotation_status(client: KeyClient, key_names: List[str]):
"""Monitor rotation status for multiple keys."""
for key_name in key_names:
try:
# Get key properties
key = client.get_key(key_name)
policy = client.get_key_rotation_policy(key_name)
print(f"\nKey: {key_name}")
print(f"Current Version: {key.properties.version}")
print(f"Created: {key.properties.created_on}")
print(f"Updated: {key.properties.updated_on}")
if policy.expires_in:
print(f"Policy Expires In: {policy.expires_in}")
if policy.lifetime_actions:
print("Lifetime Actions:")
for action in policy.lifetime_actions:
print(f" - {action.action}: {action.time_after_create or action.time_before_expiry}")
except Exception as e:
print(f"Error monitoring {key_name}: {e}")
def handle_rotation_notification(key_name: str, action: str):
"""Handle rotation notifications (would be called by event handler)."""
if action == "notify":
print(f"NOTIFICATION: Key '{key_name}' is approaching rotation time")
# Send alert, create ticket, etc.
elif action == "rotate":
print(f"ROTATION: Key '{key_name}' has been rotated")
# Update applications, restart services, etc.
# Example usage
key_list = ["app-signing-key", "data-encryption-key", "api-key"]
monitor_key_rotation_status(client, key_list)Implement rotation policies that align with security and operational requirements.
def implement_secure_rotation_strategy(client: KeyClient, key_name: str, key_type: str):
"""Implement rotation strategy based on key type and usage."""
if key_type == "signing":
# Signing keys: longer rotation period, more notifications
lifetime_actions = [
KeyRotationLifetimeAction(
action=KeyRotationPolicyAction.rotate,
time_after_create="P180D" # 6 months
),
KeyRotationLifetimeAction(
action=KeyRotationPolicyAction.notify,
time_after_create="P150D" # 30 days before
),
KeyRotationLifetimeAction(
action=KeyRotationPolicyAction.notify,
time_after_create="P173D" # 7 days before
)
]
expires_in = "P2Y"
elif key_type == "encryption":
# Encryption keys: more frequent rotation
lifetime_actions = [
KeyRotationLifetimeAction(
action=KeyRotationPolicyAction.rotate,
time_after_create="P90D" # 3 months
),
KeyRotationLifetimeAction(
action=KeyRotationPolicyAction.notify,
time_after_create="P76D" # 14 days before
)
]
expires_in = "P1Y"
elif key_type == "master":
# Master keys: less frequent rotation, more notifications
lifetime_actions = [
KeyRotationLifetimeAction(
action=KeyRotationPolicyAction.rotate,
time_after_create="P365D" # 1 year
),
KeyRotationLifetimeAction(
action=KeyRotationPolicyAction.notify,
time_after_create="P335D" # 30 days before
),
KeyRotationLifetimeAction(
action=KeyRotationPolicyAction.notify,
time_after_create="P358D" # 7 days before
),
KeyRotationLifetimeAction(
action=KeyRotationPolicyAction.notify,
time_after_create="P364D" # 1 day before
)
]
expires_in = "P5Y"
else:
raise ValueError(f"Unknown key type: {key_type}")
policy = client.update_key_rotation_policy(
key_name,
KeyRotationPolicy(),
lifetime_actions=lifetime_actions,
expires_in=expires_in
)
print(f"Applied {key_type} rotation strategy to {key_name}")
return policy
# Apply strategies to different key types
implement_secure_rotation_strategy(client, "app-signing-key", "signing")
implement_secure_rotation_strategy(client, "data-key", "encryption")
implement_secure_rotation_strategy(client, "master-key", "master")Implement rotation policies that meet compliance requirements.
def create_compliance_rotation_policy(client: KeyClient, key_name: str, compliance_standard: str):
"""Create rotation policies for specific compliance standards."""
if compliance_standard == "PCI-DSS":
# PCI-DSS typically requires annual key rotation
lifetime_actions = [
KeyRotationLifetimeAction(
action=KeyRotationPolicyAction.rotate,
time_after_create="P365D"
),
KeyRotationLifetimeAction(
action=KeyRotationPolicyAction.notify,
time_after_create="P335D" # 30 days notice
)
]
expires_in = "P1Y"
elif compliance_standard == "FIPS-140-2":
# FIPS may require more frequent rotation
lifetime_actions = [
KeyRotationLifetimeAction(
action=KeyRotationPolicyAction.rotate,
time_after_create="P180D" # 6 months
),
KeyRotationLifetimeAction(
action=KeyRotationPolicyAction.notify,
time_after_create="P165D" # 15 days notice
)
]
expires_in = "P1Y"
elif compliance_standard == "HIPAA":
# HIPAA may require specific rotation schedules
lifetime_actions = [
KeyRotationLifetimeAction(
action=KeyRotationPolicyAction.rotate,
time_after_create="P90D" # Quarterly
),
KeyRotationLifetimeAction(
action=KeyRotationPolicyAction.notify,
time_after_create="P76D" # 14 days notice
)
]
expires_in = "P2Y"
else:
raise ValueError(f"Unknown compliance standard: {compliance_standard}")
policy = client.update_key_rotation_policy(
key_name,
KeyRotationPolicy(),
lifetime_actions=lifetime_actions,
expires_in=expires_in
)
# Add compliance tags
key = client.get_key(key_name)
updated_key = client.update_key_properties(
key_name,
tags={
**key.properties.tags,
"compliance": compliance_standard,
"rotation_policy": "automated",
"last_policy_update": datetime.utcnow().isoformat()
}
)
return policy, updated_key
# Apply compliance policies
pci_policy, pci_key = create_compliance_rotation_policy(client, "payment-key", "PCI-DSS")
fips_policy, fips_key = create_compliance_rotation_policy(client, "crypto-key", "FIPS-140-2")class KeyRotationPolicy:
"""Key rotation policy configuration."""
id: str # Policy identifier
lifetime_actions: List[KeyRotationLifetimeAction] # Actions to perform during key lifetime
expires_in: str # ISO 8601 duration (e.g., "P90D")
created_on: datetime # Policy creation date
updated_on: datetime # Policy last update date
class KeyRotationLifetimeAction:
"""An action and its trigger for key lifetime management."""
action: KeyRotationPolicyAction # Action to perform
time_after_create: str # ISO 8601 duration after creation
time_before_expiry: str # ISO 8601 duration before expiry
class KeyRotationPolicyAction(str, Enum):
"""Actions for key rotation policy."""
rotate = "Rotate" # Rotate the key based on policy
notify = "Notify" # Trigger Event Grid events/notificationsKey rotation policies use ISO 8601 duration format for specifying time periods:
# Duration Format Examples
"P1D" # 1 day
"P7D" # 7 days (1 week)
"P30D" # 30 days
"P90D" # 90 days (3 months)
"P180D" # 180 days (6 months)
"P365D" # 365 days (1 year)
"P1Y" # 1 year
"P2Y" # 2 years
"PT1H" # 1 hour
"PT24H" # 24 hours
"P1M" # 1 month (calendar month)
"P6M" # 6 months (calendar months)
# Complex durations
"P1Y6M" # 1 year and 6 months
"P90DT12H" # 90 days and 12 hoursInstall with Tessl CLI
npx tessl i tessl/pypi-azure-keyvault-keys