Files
ai-development-scaffold/.claude/skills/infrastructure/azure/SKILL.md
James Bland befb8fbaeb feat: initial Claude Code configuration scaffold
Comprehensive Claude Code guidance system with:

- 5 agents: tdd-guardian, code-reviewer, security-scanner, refactor-scan, dependency-audit
- 18 skills covering languages (Python, TypeScript, Rust, Go, Java, C#),
  infrastructure (AWS, Azure, GCP, Terraform, Ansible, Docker/K8s, Database, CI/CD),
  testing (TDD, UI, Browser), and patterns (Monorepo, API Design, Observability)
- 3 hooks: secret detection, auto-formatting, TDD git pre-commit
- Strict TDD enforcement with 80%+ coverage requirements
- Multi-model strategy: Opus for planning, Sonnet for execution (opusplan)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-20 15:47:34 -05:00

14 KiB

name, description
name description
azure-services Azure service patterns, RBAC best practices, and common architectures. Use when designing or implementing Azure infrastructure.

Azure Services Skill

Common Architecture Patterns

Web Application (App Service + Azure SQL)

┌─────────────────────────────────────────────────────────────┐
│                         VNet                                 │
│  ┌─────────────────────────────────────────────────────────┐│
│  │                   Public Subnet                          ││
│  │  ┌─────────────┐                    ┌─────────────┐     ││
│  │  │ App Gateway │                    │  NAT GW     │     ││
│  │  └──────┬──────┘                    └──────┬──────┘     ││
│  └─────────┼───────────────────────────────────┼───────────┘│
│            │                                   │             │
│  ┌─────────┼───────────────────────────────────┼───────────┐│
│  │         │       Private Subnet              │           ││
│  │  ┌──────▼──────┐                    ┌───────▼─────┐     ││
│  │  │ App Service │                    │  Azure SQL  │     ││
│  │  │  (Web App)  │───────────────────▶│  Database   │     ││
│  │  └─────────────┘                    └─────────────┘     ││
│  └─────────────────────────────────────────────────────────┘│
└─────────────────────────────────────────────────────────────┘

Serverless (Azure Functions + API Management)

┌────────────┐     ┌─────────────┐     ┌─────────────┐
│   Front    │────▶│     APIM    │────▶│  Functions  │
│   Door     │     │             │     └──────┬──────┘
└────────────┘     └─────────────┘            │
                   ┌──────────────────────────┼──────────────┐
                   │                          │              │
            ┌──────▼─────┐  ┌─────────┐  ┌────▼────┐
            │ Cosmos DB  │  │  Blob   │  │ Key     │
            └────────────┘  │ Storage │  │ Vault   │
                            └─────────┘  └─────────┘

RBAC Best Practices

Custom Role Definition

{
  "Name": "App Data Reader",
  "Description": "Read access to application data in storage",
  "Actions": [
    "Microsoft.Storage/storageAccounts/blobServices/containers/read",
    "Microsoft.Storage/storageAccounts/blobServices/containers/blobs/read"
  ],
  "NotActions": [],
  "DataActions": [
    "Microsoft.Storage/storageAccounts/blobServices/containers/blobs/read"
  ],
  "NotDataActions": [],
  "AssignableScopes": [
    "/subscriptions/{subscription-id}/resourceGroups/{resource-group}"
  ]
}

Managed Identity Usage

# Python - azure-identity
from azure.identity import DefaultAzureCredential
from azure.keyvault.secrets import SecretClient
from azure.storage.blob import BlobServiceClient

# Uses managed identity when deployed to Azure
credential = DefaultAzureCredential()

# Key Vault access
secret_client = SecretClient(
    vault_url="https://my-vault.vault.azure.net/",
    credential=credential
)
secret = secret_client.get_secret("database-password")

# Blob Storage access
blob_service = BlobServiceClient(
    account_url="https://mystorageaccount.blob.core.windows.net/",
    credential=credential
)
// TypeScript - @azure/identity
import { DefaultAzureCredential } from "@azure/identity";
import { SecretClient } from "@azure/keyvault-secrets";
import { BlobServiceClient } from "@azure/storage-blob";

const credential = new DefaultAzureCredential();

// Key Vault access
const secretClient = new SecretClient(
  "https://my-vault.vault.azure.net/",
  credential
);
const secret = await secretClient.getSecret("database-password");

// Blob Storage access
const blobService = new BlobServiceClient(
  "https://mystorageaccount.blob.core.windows.net/",
  credential
);

Key Vault Patterns

Secrets Management

from azure.identity import DefaultAzureCredential
from azure.keyvault.secrets import SecretClient

def get_secret(vault_url: str, secret_name: str) -> str:
    """Retrieve secret from Key Vault using managed identity."""
    credential = DefaultAzureCredential()
    client = SecretClient(vault_url=vault_url, credential=credential)
    return client.get_secret(secret_name).value

# Usage
db_password = get_secret(
    "https://my-vault.vault.azure.net/",
    "database-password"
)

App Service with Key Vault References

// App Service configuration
{
  "name": "DatabasePassword",
  "value": "@Microsoft.KeyVault(SecretUri=https://my-vault.vault.azure.net/secrets/db-password/)",
  "slotSetting": false
}

Blob Storage Patterns

SAS Token Generation

from datetime import datetime, timedelta
from azure.storage.blob import (
    BlobServiceClient,
    generate_blob_sas,
    BlobSasPermissions,
)

def generate_read_sas(
    account_name: str,
    account_key: str,
    container: str,
    blob_name: str,
    expiry_hours: int = 1
) -> str:
    """Generate a read-only SAS URL for a blob."""
    sas_token = generate_blob_sas(
        account_name=account_name,
        container_name=container,
        blob_name=blob_name,
        account_key=account_key,
        permission=BlobSasPermissions(read=True),
        expiry=datetime.utcnow() + timedelta(hours=expiry_hours),
    )

    return f"https://{account_name}.blob.core.windows.net/{container}/{blob_name}?{sas_token}"

User Delegation SAS (More Secure)

from azure.identity import DefaultAzureCredential
from azure.storage.blob import BlobServiceClient, UserDelegationKey

def generate_user_delegation_sas(
    account_url: str,
    container: str,
    blob_name: str,
) -> str:
    """Generate SAS using user delegation key (no storage key needed)."""
    credential = DefaultAzureCredential()
    blob_service = BlobServiceClient(account_url, credential=credential)

    # Get user delegation key
    delegation_key = blob_service.get_user_delegation_key(
        key_start_time=datetime.utcnow(),
        key_expiry_time=datetime.utcnow() + timedelta(hours=1)
    )

    sas_token = generate_blob_sas(
        account_name=blob_service.account_name,
        container_name=container,
        blob_name=blob_name,
        user_delegation_key=delegation_key,
        permission=BlobSasPermissions(read=True),
        expiry=datetime.utcnow() + timedelta(hours=1),
    )

    return f"{account_url}/{container}/{blob_name}?{sas_token}"

Cosmos DB Patterns

Async Client Usage

from azure.cosmos.aio import CosmosClient
from azure.identity.aio import DefaultAzureCredential

async def get_cosmos_client() -> CosmosClient:
    """Create async Cosmos client with managed identity."""
    credential = DefaultAzureCredential()
    return CosmosClient(
        url="https://my-cosmos.documents.azure.com:443/",
        credential=credential
    )

async def query_items(container_name: str, query: str) -> list:
    """Query items from Cosmos DB container."""
    async with await get_cosmos_client() as client:
        database = client.get_database_client("my-database")
        container = database.get_container_client(container_name)

        items = []
        async for item in container.query_items(
            query=query,
            enable_cross_partition_query=True
        ):
            items.append(item)

        return items

Partition Key Design

# Good partition key choices:
# - tenant_id for multi-tenant apps
# - user_id for user-specific data
# - category for catalog data

# Document structure
{
    "id": "order-12345",
    "partitionKey": "customer-789",  # Use customer ID for orders
    "orderDate": "2024-01-15",
    "items": [...],
    "total": 150.00
}

Azure Functions Patterns

HTTP Trigger with Input Validation

import azure.functions as func
import logging
from pydantic import BaseModel, ValidationError

class CreateOrderRequest(BaseModel):
    customer_id: str
    items: list[dict]

app = func.FunctionApp()

@app.route(route="orders", methods=["POST"])
async def create_order(req: func.HttpRequest) -> func.HttpResponse:
    """Create a new order with validation."""
    try:
        body = req.get_json()
        request = CreateOrderRequest(**body)

        # Process order...
        result = await process_order(request)

        return func.HttpResponse(
            body=result.model_dump_json(),
            status_code=201,
            mimetype="application/json"
        )

    except ValidationError as e:
        return func.HttpResponse(
            body=e.json(),
            status_code=400,
            mimetype="application/json"
        )
    except Exception as e:
        logging.exception("Error processing order")
        return func.HttpResponse(
            body='{"error": "Internal server error"}',
            status_code=500,
            mimetype="application/json"
        )

Durable Functions Orchestration

import azure.functions as func
import azure.durable_functions as df

app = func.FunctionApp()

@app.orchestration_trigger(context_name="context")
def order_orchestrator(context: df.DurableOrchestrationContext):
    """Orchestrate multi-step order processing."""
    order = context.get_input()

    # Step 1: Validate inventory
    inventory_result = yield context.call_activity(
        "validate_inventory", order["items"]
    )

    if not inventory_result["available"]:
        return {"status": "failed", "reason": "insufficient_inventory"}

    # Step 2: Process payment
    payment_result = yield context.call_activity(
        "process_payment", order["payment"]
    )

    if not payment_result["success"]:
        return {"status": "failed", "reason": "payment_failed"}

    # Step 3: Create shipment
    shipment = yield context.call_activity(
        "create_shipment", order
    )

    return {"status": "completed", "shipment_id": shipment["id"]}

Application Insights

Structured Logging

import logging
from opencensus.ext.azure.log_exporter import AzureLogHandler

# Configure logging with Application Insights
logger = logging.getLogger(__name__)
logger.addHandler(AzureLogHandler(
    connection_string="InstrumentationKey=xxx;IngestionEndpoint=xxx"
))

# Log with custom dimensions
logger.info(
    "Order processed",
    extra={
        "custom_dimensions": {
            "order_id": "12345",
            "customer_id": "cust-789",
            "total": 150.00
        }
    }
)

Custom Metrics

from opencensus.ext.azure import metrics_exporter
from opencensus.stats import aggregation, measure, stats, view

# Create measure
orders_measure = measure.MeasureInt(
    "orders_processed",
    "Number of orders processed",
    "orders"
)

# Create view
orders_view = view.View(
    "orders_processed_total",
    "Total orders processed",
    [],
    orders_measure,
    aggregation.CountAggregation()
)

# Register and export
view_manager = stats.stats.view_manager
view_manager.register_view(orders_view)

exporter = metrics_exporter.new_metrics_exporter(
    connection_string="InstrumentationKey=xxx"
)
view_manager.register_exporter(exporter)

# Record metric
mmap = stats.stats.stats_recorder.new_measurement_map()
mmap.measure_int_put(orders_measure, 1)
mmap.record()

CLI Commands

# Authentication
az login
az account set --subscription "My Subscription"
az account show

# Resource Groups
az group list --output table
az group create --name my-rg --location uksouth

# Key Vault
az keyvault secret show --vault-name my-vault --name my-secret
az keyvault secret set --vault-name my-vault --name my-secret --value "secret-value"

# Storage
az storage blob list --account-name mystorageaccount --container-name mycontainer
az storage blob upload --account-name mystorageaccount --container-name mycontainer --file local.txt --name remote.txt

# App Service
az webapp list --output table
az webapp restart --name my-app --resource-group my-rg
az webapp log tail --name my-app --resource-group my-rg

# Functions
az functionapp list --output table
az functionapp restart --name my-func --resource-group my-rg

# Cosmos DB
az cosmosdb list --output table
az cosmosdb sql database list --account-name my-cosmos --resource-group my-rg

Security Checklist

  • Use Managed Identities instead of connection strings
  • Store secrets in Key Vault, not app settings
  • Enable Azure Defender for all resources
  • Use Private Endpoints for PaaS services
  • Enable diagnostic logging to Log Analytics
  • Configure Network Security Groups
  • Use User Delegation SAS instead of account keys
  • Enable soft delete on Key Vault and Storage
  • Configure Azure Policy for compliance
  • Enable Microsoft Defender for Cloud