Stage 7 · Master
Cloud SDKs & Azure Automation
Key Vault from Python
Read secrets, manage certificates, and rotate credentials programmatically.
Key Vault Overview
Azure Key Vault stores secrets, keys, and certificates. It provides centralized secret management with audit logging, access control, and automatic rotation. Never store secrets in config files, environment variables on shared systems, or version control.
Secrets (passwords, connection strings), Keys (encryption keys for data at rest), and Certificates (TLS certs with auto-renewal). Most DevOps scripts interact with secrets.
Reading Secrets
from azure.identity import DefaultAzureCredential
from azure.keyvault.secrets import SecretClient
# Connect to Key Vault
credential = DefaultAzureCredential()
client = SecretClient(
vault_url="https://my-vault.vault.azure.net/",
credential=credential,
)
# Get a secret value
db_password = client.get_secret("database-password")
print(f"Password: {db_password.value}")
print(f"Version: {db_password.properties.version}")
print(f"Updated: {db_password.properties.updated_on}")
# Get a specific version
old_password = client.get_secret("database-password", version="abc123")
# List all secrets
for secret_properties in client.list_properties_of_secrets():
print(f"{secret_properties.name}: enabled={secret_properties.enabled}")DefaultAzureCredential authenticates to Key Vault. The secret client reads secret values and metadata. Always use the latest version unless you specifically need an older one.
Writing and Updating Secrets
from azure.identity import DefaultAzureCredential
from azure.keyvault.secrets import SecretClient
import secrets
import string
credential = DefaultAzureCredential()
client = SecretClient(
vault_url="https://my-vault.vault.azure.net/",
credential=credential,
)
# Create a new secret
client.set_secret("api-key", "my-api-key-value-123")
# Update an existing secret (creates a new version)
client.set_secret("api-key", "new-api-key-value-456")
# Set a secret with expiration
from datetime import datetime, timedelta
client.set_secret(
"temp-secret",
"temporary-value",
properties={
"expires_on": datetime.utcnow() + timedelta(days=90),
},
)
# Generate a random password
alphabet = string.ascii_letters + string.digits + string.punctuation
password = "".join(secrets.choice(alphabet) for _ in range(32))
client.set_secret("generated-password", password)set_secret is idempotent — it creates a new version if the secret exists. Use expiration dates to enforce rotation. secrets module generates cryptographically secure random values.
Certificate Management
from azure.identity import DefaultAzureCredential
from azure.keyvault.certificates import CertificateClient, CertificatePolicy
credential = DefaultAzureCredential()
client = CertificateClient(
vault_url="https://my-vault.vault.azure.net/",
credential=credential,
)
# Create a self-signed certificate
poller = client.begin_create_or_update_certificate(
name="my-cert",
policy=CertificatePolicy(
issuer_name="Self",
subject="CN=myapp.internal",
key_type="RSA",
key_size=2048,
validity_in_months=12,
),
)
cert = poller.result()
print(f"Certificate: {cert.name}")
print(f"Thumbprint: {cert.properties.x509_thumbprint.hex()}")
# List certificates
for cert in client.list_properties_of_certificates():
print(f"{cert.name}: {cert.enabled}")
# Get certificate details
cert_detail = client.get_certificate("my-cert")Key Vault can manage the full certificate lifecycle — creation, renewal, and revocation. For production TLS certificates, use a real issuer like Let's Encrypt or DigiCert.
Secret Rotation
from azure.identity import DefaultAzureCredential
from azure.keyvault.secrets import SecretClient
from datetime import datetime, timedelta
credential = DefaultAzureCredential()
client = SecretClient(
vault_url="https://my-vault.vault.azure.net/",
credential=credential,
)
def check_and_rotate_secret(
secret_name: str,
max_age_days: int = 90,
rotate_fn=None,
) -> bool:
"""Check if a secret is older than max_age_days and rotate it."""
try:
secret = client.get_secret(secret_name)
updated = secret.properties.updated_on
if updated and (datetime.utcnow() - updated) > timedelta(days=max_age_days):
print(f"Secret {secret_name} is {max_age_days}+ days old, rotating...")
new_value = rotate_fn() if rotate_fn else generate_password()
client.set_secret(secret_name, new_value)
print(f"Rotated {secret_name}")
return True
else:
print(f"Secret {secret_name} is still fresh")
return False
except Exception as e:
print(f"Error checking {secret_name}: {e}")
return False
def generate_password():
import secrets, string
alphabet = string.ascii_letters + string.digits
return "".join(secrets.choice(alphabet) for _ in range(32))
# Rotate secrets older than 90 days
for secret in client.list_properties_of_secrets():
if secret.enabled:
check_and_rotate_secret(secret.name)Automated rotation ensures secrets do not expire unexpectedly. Check the last update date and rotate if it exceeds your threshold. Log all rotations for audit.
Access Policies
from azure.identity import DefaultAzureCredential
from azure.mgmt.keyvault import KeyVaultManagementClient
from azure.mgmt.keyvault.models import (
VaultAccessPolicy,
AccessPolicyEntry,
Permissions,
Permission,
)
credential = DefaultAzureCredential()
client = KeyVaultManagementClient(credential, "subscription-id")
# Grant a service principal access to secrets
tenant_id = "your-tenant-id"
client_id = "service-principal-client-id"
access_policy = AccessPolicyEntry(
tenant_id=tenant_id,
object_id=client_id,
permissions=[Permissions(secrets=[Permission.GET, Permission.LIST])],
)
vault = client.vaults.get("my-rg", "my-vault")
vault.properties.access_policies.append(access_policy)
client.vaults.begin_create_or_update("my-rg", "my-vault", vault).result()Key Vault access policies control who can read, write, and delete secrets. Grant minimum required permissions. Use Managed Identity instead of service principals when possible.
Never print, log, or store secret values in plaintext. Log that a secret was accessed, not its value. Use structured logging to track access without exposing secrets.
Mark this lesson complete to store local progress and unlock a cleaner resume path the next time you visit.