CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-azure-keyvault-keys

Microsoft Azure Key Vault Keys client library for Python providing cryptographic key management operations

Pending

Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

Overview
Eval results
Files

rotation-policies.mddocs/

Key Rotation and Policies

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.

Capabilities

Key Rotation Policies

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
    """

Usage Examples

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}")

Manual Key Rotation

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
    """

Usage Examples

# 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}")

Rotation Policy Configuration

Configure comprehensive rotation policies with multiple actions and conditions.

Advanced Policy Examples

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")

Rotation Monitoring and Management

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)

Rotation Best Practices

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")

Compliance and Audit

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")

Types

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/notifications

Duration Format Reference

Key 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 hours

Install with Tessl CLI

npx tessl i tessl/pypi-azure-keyvault-keys

docs

async-operations.md

backup-recovery.md

crypto-operations.md

import-export.md

index.md

key-management.md

rotation-policies.md

tile.json