Microsoft Azure

Azure is supported for organizations deeply integrated with the Microsoft ecosystem, requiring Active Directory integration, or with existing Azure commitments.

When to Use Azure

RequirementWhy Azure
Microsoft ecosystemActive Directory, Office 365, Teams integration
Existing commitmentsAzure Enterprise Agreements or credits
Azure servicesAzure SQL, Blob Storage, Azure Functions
Managed KubernetesAKS with Azure-native integrations
ComplianceSOC 2, HIPAA, FedRAMP, and regional certifications

Configuration

Service Principal

Create a service principal for Teabar:

# Login to Azure CLI
az login

# Create service principal
az ad sp create-for-rbac 
  --name "teabar-provisioner" 
  --role Contributor 
  --scopes /subscriptions/<SUBSCRIPTION_ID>

This outputs:

{
  "appId": "<CLIENT_ID>",
  "displayName": "teabar-provisioner",
  "password": "<CLIENT_SECRET>",
  "tenant": "<TENANT_ID>"
}

Configure in Teabar

teactl org provider set azure 
  --subscription <AZURE_SUBSCRIPTION_ID> 
  --tenant <AZURE_TENANT_ID> 
  --client-id <AZURE_CLIENT_ID> 
  --client-secret <AZURE_CLIENT_SECRET>

Or via environment variables:

export ARM_SUBSCRIPTION_ID=<subscription-id>
export ARM_TENANT_ID=<tenant-id>
export ARM_CLIENT_ID=<client-id>
export ARM_CLIENT_SECRET=<client-secret>

Regions

Azure offers 60+ regions. Common choices:

RegionCodeLocationUse Case
East USeastusVirginia, USADefault US region
West US 2westus2Washington, USAUS West Coast
West EuropewesteuropeNetherlandsEuropean users
North EuropenortheuropeIrelandAlternative EU
Germany West CentralgermanywestcentralFrankfurtGerman data residency
Southeast AsiasoutheastasiaSingaporeAPAC users

Specifying Region

In blueprints:

spec:
  infrastructure:
    provider: azure
    region: eastus

VM Sizes

General Purpose (B-series)

Burstable VMs for variable workloads:

SizevCPURAMTemp StoragePrice/hr*Use Case
Standard_B1s11 GB4 GB~$0.01Minimal workloads
Standard_B2s24 GB8 GB~$0.04Participant VMs
Standard_B2ms28 GB16 GB~$0.08Development
Standard_B4ms416 GB32 GB~$0.17K8s control plane

*Prices are approximate and vary by region.

General Purpose (D-series)

Balanced compute for production workloads:

SizevCPURAMTemp StoragePrice/hr*
Standard_D2s_v528 GB0 GB~$0.10
Standard_D4s_v5416 GB0 GB~$0.19
Standard_D8s_v5832 GB0 GB~$0.38

Compute Optimized (F-series)

For CPU-intensive workloads:

SizevCPURAMTemp StoragePrice/hr*
Standard_F2s_v224 GB16 GB~$0.08
Standard_F4s_v248 GB32 GB~$0.17
Standard_F8s_v2816 GB64 GB~$0.34

Memory Optimized (E-series)

For memory-intensive applications:

SizevCPURAMTemp StoragePrice/hr*
Standard_E2s_v5216 GB0 GB~$0.13
Standard_E4s_v5432 GB0 GB~$0.25
Standard_E8s_v5864 GB0 GB~$0.50

Blueprint Examples

Single VM per Participant

apiVersion: teabar.dev/v1
kind: Blueprint
metadata:
  name: azure-linux-workshop
spec:
  infrastructure:
    provider: azure
    region: eastus

  resources:
    - name: participant-vm
      type: vm
      spec:
        size: Standard_B2s
        image:
          publisher: Canonical
          offer: 0001-com-ubuntu-server-jammy
          sku: 22_04-lts-gen2
          version: latest
        perParticipant: true
        customData: |
          #!/bin/bash
          apt-get update
          apt-get install -y docker.io git vim
          usermod -aG docker azureuser

AKS Cluster

apiVersion: teabar.dev/v1
kind: Blueprint
metadata:
  name: aks-workshop
spec:
  infrastructure:
    provider: azure
    region: eastus

  resources:
    - name: k8s-cluster
      type: cluster
      spec:
        distribution: aks
        version: "1.29"
        nodePools:
          - name: system
            vmSize: Standard_D2s_v5
            count: 2
            mode: System
          - name: workers
            vmSize: Standard_D4s_v5
            minCount: 1
            maxCount: 10
            enableAutoScaling: true
            mode: User
        networkPlugin: azure  # or kubenet
        networkPolicy: calico

Self-Managed Kubernetes (Talos)

apiVersion: teabar.dev/v1
kind: Blueprint
metadata:
  name: talos-on-azure
spec:
  infrastructure:
    provider: azure
    region: eastus

  resources:
    - name: k8s-cluster
      type: cluster
      spec:
        distribution: talos
        version: "1.29"
        controlPlane:
          count: 3
          size: Standard_D4s_v5
        workers:
          count: 3
          size: Standard_D2s_v5
        cni: cilium

Networking

Virtual Network Configuration

Each environment gets an isolated VNet:

spec:
  infrastructure:
    provider: azure
    region: eastus
    network:
      vnetCidr: 10.0.0.0/16
      subnets:
        - name: control-plane
          cidr: 10.0.1.0/24
        - name: workers
          cidr: 10.0.2.0/24
        - name: participants
          cidr: 10.0.10.0/24

Generated Terraform

resource "azurerm_virtual_network" "environment" {
  name                = "env-abc123-vnet"
  resource_group_name = azurerm_resource_group.environment.name
  location            = azurerm_resource_group.environment.location
  address_space       = ["10.0.0.0/16"]

  tags = {
    environment = "env-abc123"
    managed_by  = "teabar"
  }
}

resource "azurerm_subnet" "participants" {
  name                 = "participants"
  resource_group_name  = azurerm_resource_group.environment.name
  virtual_network_name = azurerm_virtual_network.environment.name
  address_prefixes     = ["10.0.10.0/24"]
}

Network Security Groups

Default NSG rules:

spec:
  infrastructure:
    firewall:
      ingress:
        - name: SSH
          priority: 100
          port: 22
          protocol: Tcp
          source: "*"
        - name: HTTPS
          priority: 110
          port: 443
          protocol: Tcp
          source: "*"
      egress:
        - name: AllOutbound
          priority: 100
          port: "*"
          protocol: "*"
          destination: "*"

Load Balancers

Azure offers multiple load balancer options:

resources:
  - name: app-lb
    type: loadbalancer
    spec:
      type: standard  # basic or standard
      sku: Standard
      frontend:
        - name: web
          publicIP: true
      backend:
        - resource: webserver
      rules:
        - name: https
          frontendPort: 443
          backendPort: 8080
          protocol: Tcp
      healthProbe:
        port: 8080
        protocol: Http
        path: /health

Storage

Managed Disks

Attach persistent storage:

resources:
  - name: data-disk
    type: volume
    spec:
      size: 100  # GB
      sku: Premium_LRS  # Standard_LRS, StandardSSD_LRS, Premium_LRS
      
  - name: database
    type: vm
    spec:
      size: Standard_D4s_v5
      volumes:
        - data-disk

Disk SKUs

SKUTypeUse CaseMax IOPS
Standard_LRSHDDArchives, backups500
StandardSSD_LRSSSDWeb servers, dev6,000
Premium_LRSPremium SSDProduction databases20,000
UltraSSD_LRSUltra diskHigh-performance160,000

AKS Integration

AKS with Azure Integrations

AKS clusters can leverage Azure-native services:

resources:
  - name: aks-cluster
    type: cluster
    spec:
      distribution: aks
      version: "1.29"
      nodePools:
        - name: system
          vmSize: Standard_D2s_v5
          count: 2
      
      # Azure integrations
      integrations:
        # Azure AD Integration
        azureAD:
          enabled: true
          adminGroupObjectIds:
            - "<AAD_GROUP_ID>"
        
        # Azure Monitor
        monitoring:
          enabled: true
          logAnalyticsWorkspaceId: "<WORKSPACE_ID>"
        
        # Azure Container Registry
        acr:
          enabled: true
          registryId: "<ACR_ID>"
        
        # Azure Key Vault
        keyVault:
          enabled: true
          secretsProvider: true

Workload Identity

Allow pods to access Azure resources:

resources:
  - name: storage-identity
    type: azure-managed-identity
    spec:
      serviceAccount: my-app
      namespace: default
      roles:
        - scope: "/subscriptions/.../storageAccounts/mystorage"
          role: "Storage Blob Data Reader"

Active Directory Integration

AAD Authentication for VMs

resources:
  - name: participant-vm
    type: vm
    spec:
      size: Standard_B2s
      image:
        publisher: Canonical
        offer: 0001-com-ubuntu-server-jammy
        sku: 22_04-lts-gen2
      perParticipant: true
      authentication:
        type: aad  # Azure AD login

AAD for AKS

resources:
  - name: aks-cluster
    type: cluster
    spec:
      distribution: aks
      version: "1.29"
      azureAD:
        enabled: true
        managed: true
        adminGroupObjectIds:
          - "00000000-0000-0000-0000-000000000000"
        tenantId: "{{ .Org.azure.tenantId }}"

DNS with Azure DNS

resources:
  - name: app-dns
    type: dns
    spec:
      provider: azure-dns
      zone: workshop.example.com
      resourceGroup: dns-rg
      records:
        - name: "app"
          type: A
          ttl: 300
          value: "{{ .Resources.app-lb.public_ip }}"
        - name: "www"
          type: CNAME
          ttl: 300
          value: "app.workshop.example.com"

Cost Management

Pricing Considerations

Cost FactorNotes
Pay-as-you-goDefault, per-minute billing
Reserved Instances1-3 year commitment for discounts
Spot VMsUp to 90% discount, can be evicted
Hybrid BenefitUse existing Windows/SQL licenses

Using Spot VMs

For cost-sensitive, interruptible workloads:

resources:
  - name: worker-vm
    type: vm
    spec:
      size: Standard_D4s_v5
      spot:
        enabled: true
        maxPrice: 0.10
        evictionPolicy: Deallocate

Cost Estimation

teactl env estimate --blueprint azure-workshop --participants 20

Resource Groups

Teabar creates a resource group for each environment:

rg-teabar-env-abc123
├── env-abc123-vnet
├── env-abc123-nsg
├── env-abc123-vm-0
├── env-abc123-vm-1
└── env-abc123-disk-0

All resources are tagged for tracking:

{
  "environment": "env-abc123",
  "organization": "acme-corp",
  "managed_by": "teabar"
}

Limitations

FeatureAzure Notes
CostSimilar to AWS, higher than Hetzner
ProvisioningSlower than Hetzner (~3-5 min)
ComplexityMany configuration options
AKS costsFree control plane + node costs

Troubleshooting

Common Issues

“AuthorizationFailed”

Service principal lacks required permissions. Check role assignments.

“QuotaExceeded”

Request a quota increase via Azure portal Support + Troubleshooting.

“SkuNotAvailable”

The VM size isn’t available in the region. Try a different size or region.

“ResourceGroupNotFound”

Ensure the subscription ID and region are correct.

View Provisioning Logs

teactl env logs my-workshop --component provisioner

Next Steps

ende