Showing posts with label azure. Show all posts
Showing posts with label azure. Show all posts

Friday

Develop a Multi Agent Application and Deploy into Azure

                                                                      Azure


Let’s break this down into a clear roadmap so you can go from design to deployment smoothly.


🧩 Step 1: Define Your Multi‑Agent Architecture

  • Agents: Decide what roles your agents will play (e.g., data collector, analyzer, planner, executor).
  • Communication: Choose how agents will talk to each other — options include:
    • REST APIs
    • Azure Service Bus / Event Grid
    • Direct messaging via frameworks like LangChain or AutoGen
  • Coordination: Decide if you’ll use a central orchestrator (controller agent) or a peer‑to‑peer model.

⚙️ Step 2: Local Development

  • Frameworks: Use Python with LangChain, AutoGen, or Microsoft’s Semantic Kernel for agent orchestration.
  • Environment: Containerize each agent with Docker for portability.
  • Testing: Run locally with Docker Compose or Kubernetes (kind/minikube) to simulate multi‑agent interactions.

☁️ Step 3: Azure Infrastructure Setup

  1. Resource Group: Create a dedicated resource group for your project.
  2. Compute Options:
    • Azure Kubernetes Service (AKS) → best for scalable multi‑agent workloads.
    • Azure Container Apps → simpler, serverless container hosting.
    • Azure Functions → if agents are lightweight and event‑driven.
  3. Networking:
    • Use Azure Virtual Network for secure communication.
    • Configure Ingress Controller or Azure API Management for external access.

🔄 Step 4: Agent Deployment

  • Push Docker images to Azure Container Registry (ACR).
  • Deploy agents into AKS or Container Apps.
  • Use Helm charts or Bicep/ARM templates for repeatable deployments.

📡 Step 5: Communication & Orchestration

  • Service Bus/Event Grid → for asynchronous messaging between agents.
  • Azure Logic Apps or Durable Functions → for workflow orchestration if needed.
  • Cosmos DB / Azure Storage → for shared state or logs.

🔍 Step 6: Monitoring & Scaling

  • Azure Monitor + Application Insights → track agent performance and logs.
  • Autoscaling → configure AKS HPA (Horizontal Pod Autoscaler) or Container Apps scaling rules.
  • Security → manage secrets with Azure Key Vault.

🚀 Step 7: End‑to‑End Workflow Example

  1. User request hits API Gateway.
  2. Controller agent receives request, delegates tasks.
  3. Worker agents (e.g., data fetcher, analyzer, summarizer) process tasks.
  4. Results are aggregated and returned via API.
  5. Logs and metrics stored in Azure Monitor.

✅ Deliverables

  • Codebase: Python agents with orchestration logic.
  • Dockerfiles: For each agent.
  • Deployment scripts: Helm/Bicep/ARM templates.
  • Azure setup: Resource group, ACR, AKS/Container Apps, Service Bus, Monitor.

Perfect — let’s put this into something tangible. I’ll give you both a visual architecture diagram and a sample deployment manifest (Helm/YAML) so you can see how a multi‑agent system would be deployed end‑to‑end on Azure.


🏗️ High‑Level Architecture Diagram

                ┌───────────────────────────┐
                │       User / Client       │
                └─────────────┬─────────────┘
                              │
                      Azure API Management
                              │
                ┌─────────────┴─────────────┐
                │   Controller Agent Pod    │
                └─────────────┬─────────────┘
                              │
          ┌───────────────────┼───────────────────┐
          │                   │                   │
   Worker Agent A Pod   Worker Agent B Pod   Worker Agent C Pod
   (Data Fetcher)       (Analyzer)           (Summarizer)
          │                   │                   │
          └─────────────┬─────┴─────┬─────────────┘
                        │           │
                 Azure Service Bus / Event Grid
                        │
                 ┌──────┴───────────┐
                 │ Shared Storage   │
                 │ (Cosmos DB /     │
                 │  Blob Storage)   │
                 └──────────────────┘

Monitoring: Azure Monitor + App Insights
Secrets: Azure Key Vault
Images: Azure Container Registry
Deployment: AKS / Container Apps

📄 Sample Deployment YAML (AKS + Helm)

Here’s a simplified example of how you’d deploy controller and worker agents into AKS:

# values.yaml (Helm)
controller:
  image: myregistry.azurecr.io/controller-agent:latest
  replicas: 2
  resources:
    requests:
      cpu: "500m"
      memory: "512Mi"
    limits:
      cpu: "1"
      memory: "1Gi"

workers:
  - name: data-fetcher
    image: myregistry.azurecr.io/data-fetcher-agent:latest
    replicas: 3
  - name: analyzer
    image: myregistry.azurecr.io/analyzer-agent:latest
    replicas: 2
  - name: summarizer
    image: myregistry.azurecr.io/summarizer-agent:latest
    replicas: 2
# deployment.yaml (Helm template)
apiVersion: apps/v1
kind: Deployment
metadata:
  name: {{ .Chart.Name }}-{{ .Values.controller.name }}
spec:
  replicas: {{ .Values.controller.replicas }}
  selector:
    matchLabels:
      app: controller-agent
  template:
    metadata:
      labels:
        app: controller-agent
    spec:
      containers:
        - name: controller-agent
          image: {{ .Values.controller.image }}
          resources:
            requests:
              cpu: {{ .Values.controller.resources.requests.cpu }}
              memory: {{ .Values.controller.resources.requests.memory }}
            limits:
              cpu: {{ .Values.controller.resources.limits.cpu }}
              memory: {{ .Values.controller.resources.limits.memory }}
---
{{- range .Values.workers }}
apiVersion: apps/v1
kind: Deployment
metadata:
  name: {{ $.Chart.Name }}-{{ .name }}
spec:
  replicas: {{ .replicas }}
  selector:
    matchLabels:
      app: {{ .name }}
  template:
    metadata:
      labels:
        app: {{ .name }}
    spec:
      containers:
        - name: {{ .name }}
          image: {{ .image }}
{{- end }}

🚀 End‑to‑End Flow

  1. Build & push imagesaz acr build → Azure Container Registry.
  2. Deploy Helm charthelm install multi-agent ./chart.
  3. Agents communicate via Service Bus/Event Grid.
  4. Monitor with Application Insights.
  5. Scale automatically with AKS HPA rules.

Excellent — let’s build out the Azure Bicep template so you can provision the entire environment (ACR, AKS, Service Bus, Key Vault, Monitor) in one go. This will give you an end‑to‑end infrastructure as code setup.


📄 Sample Bicep Template (multi‑agent app infra)

targetScope = 'resourceGroup'

@description('Name of the Azure Container Registry')
param acrName string = 'multiagentacr'

@description('Name of the AKS cluster')
param aksName string = 'multiagent-aks'

@description('Name of the Service Bus namespace')
param sbNamespace string = 'multiagent-sb'

@description('Name of the Key Vault')
param kvName string = 'multiagent-kv'

@description('Name of the Log Analytics workspace')
param logAnalyticsName string = 'multiagent-law'

@description('Location for all resources')
param location string = resourceGroup().location

// Azure Container Registry
resource acr 'Microsoft.ContainerRegistry/registries@2023-01-01-preview' = {
  name: acrName
  location: location
  sku: {
    name: 'Basic'
  }
  properties: {
    adminUserEnabled: true
  }
}

// Log Analytics Workspace
resource logAnalytics 'Microsoft.OperationalInsights/workspaces@2022-10-01' = {
  name: logAnalyticsName
  location: location
  properties: {
    sku: {
      name: 'PerGB2018'
    }
    retentionInDays: 30
  }
}

// AKS Cluster
resource aks 'Microsoft.ContainerService/managedClusters@2023-01-01' = {
  name: aksName
  location: location
  properties: {
    dnsPrefix: '${aksName}-dns'
    agentPoolProfiles: [
      {
        name: 'agentpool'
        count: 3
        vmSize: 'Standard_DS2_v2'
        osType: 'Linux'
        mode: 'System'
      }
    ]
    linuxProfile: {
      adminUsername: 'azureuser'
      ssh: {
        publicKeys: [
          {
            keyData: 'ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQ...'
          }
        ]
      }
    }
    servicePrincipalProfile: {
      clientId: 'YOUR-SP-CLIENT-ID'
      secret: 'YOUR-SP-SECRET'
    }
    addonProfiles: {
      omsagent: {
        enabled: true
        config: {
          logAnalyticsWorkspaceResourceID: logAnalytics.id
        }
      }
    }
  }
}

// Service Bus Namespace
resource sb 'Microsoft.ServiceBus/namespaces@2021-06-01-preview' = {
  name: sbNamespace
  location: location
  sku: {
    name: 'Standard'
    tier: 'Standard'
  }
}

// Key Vault
resource kv 'Microsoft.KeyVault/vaults@2022-07-01' = {
  name: kvName
  location: location
  properties: {
    tenantId: subscription().tenantId
    sku: {
      name: 'standard'
      family: 'A'
    }
    accessPolicies: []
  }
}

🚀 How to Deploy

  1. Save the file as main.bicep.
  2. Run:
    az group create --name multiagent-rg --location eastus
    az deployment group create --resource-group multiagent-rg --template-file main.bicep
    
  3. This provisions:
    • ACR → for storing agent images.
    • AKS → for running multi‑agent workloads.
    • Service Bus → for agent communication.
    • Key Vault → for secrets.
    • Log Analytics + Monitor → for observability.

🔄 Next Steps

  • Push your agent Docker images into ACR.
  • Deploy Helm chart (from earlier step) into AKS.
  • Configure agents to use Service Bus for messaging.
  • Store sensitive configs in Key Vault.
  • Monitor with Application Insights linked to Log Analytics.

Perfect — let’s design a CI/CD pipeline so your multi‑agent application can be built, pushed, and deployed into Azure AKS automatically. I’ll show you a GitHub Actions workflow (you could adapt it to Azure DevOps if you prefer).


⚙️ CI/CD Pipeline Overview

  1. Trigger: On push to main or PR merge.
  2. Build: Build Docker images for each agent.
  3. Push: Push images to Azure Container Registry (ACR).
  4. Deploy: Use kubectl or Helm to deploy into AKS.
  5. Monitor: Integrate with Application Insights/Log Analytics.

📄 GitHub Actions Workflow Example

# .github/workflows/deploy.yml
name: Multi-Agent CI/CD

on:
  push:
    branches:
      - main

env:
  REGISTRY: multiagentacr.azurecr.io
  AKS_CLUSTER: multiagent-aks
  RESOURCE_GROUP: multiagent-rg

jobs:
  build-and-deploy:
    runs-on: ubuntu-latest

    steps:
    - name: Checkout code
      uses: actions/checkout@v3

    - name: Log in to Azure
      uses: azure/login@v1
      with:
        creds: ${{ secrets.AZURE_CREDENTIALS }}

    - name: Log in to ACR
      run: az acr login --name $REGISTRY

    - name: Build and push Controller Agent
      run: |
        docker build -t $REGISTRY/controller-agent:latest ./controller
        docker push $REGISTRY/controller-agent:latest

    - name: Build and push Worker Agents
      run: |
        docker build -t $REGISTRY/data-fetcher-agent:latest ./workers/data-fetcher
        docker push $REGISTRY/data-fetcher-agent:latest
        docker build -t $REGISTRY/analyzer-agent:latest ./workers/analyzer
        docker push $REGISTRY/analyzer-agent:latest
        docker build -t $REGISTRY/summarizer-agent:latest ./workers/summarizer
        docker push $REGISTRY/summarizer-agent:latest

    - name: Set AKS context
      run: |
        az aks get-credentials --resource-group $RESOURCE_GROUP --name $AKS_CLUSTER

    - name: Deploy with Helm
      run: |
        helm upgrade --install multi-agent ./helm-chart \
          --set controller.image=$REGISTRY/controller-agent:latest \
          --set workers[0].image=$REGISTRY/data-fetcher-agent:latest \
          --set workers[1].image=$REGISTRY/analyzer-agent:latest \
          --set workers[2].image=$REGISTRY/summarizer-agent:latest

🔑 Secrets Required

  • AZURE_CREDENTIALS: JSON output from az ad sp create-for-rbac (Service Principal).
  • Docker images will be tagged and pushed to ACR.
  • Helm chart values updated automatically with latest image tags.

🚀 Deployment Flow

  1. Developer pushes code → GitHub Actions triggers.
  2. Pipeline builds Docker images for all agents.
  3. Images pushed to ACR.
  4. Helm deploys/updates AKS workloads.
  5. Agents start communicating via Service Bus/Event Grid.
  6. Logs flow into Application Insights.

Great — here’s the Azure DevOps pipeline version of the CI/CD flow we built earlier. This YAML will automate building your agents, pushing them to ACR, and deploying them into AKS using Helm.


📄 Azure DevOps Pipeline (azure-pipelines.yml)

trigger:
  branches:
    include:
      - main

variables:
  REGISTRY: multiagentacr.azurecr.io
  AKS_CLUSTER: multiagent-aks
  RESOURCE_GROUP: multiagent-rg
  IMAGE_TAG: $(Build.BuildId)

stages:
- stage: Build
  displayName: Build and Push Images
  jobs:
  - job: BuildPush
    pool:
      vmImage: 'ubuntu-latest'
    steps:
    - task: AzureCLI@2
      inputs:
        azureSubscription: 'AzureServiceConnection'
        scriptType: 'bash'
        scriptLocation: 'inlineScript'
        inlineScript: |
          az acr login --name $REGISTRY
          docker build -t $REGISTRY/controller-agent:$(IMAGE_TAG) ./controller
          docker push $REGISTRY/controller-agent:$(IMAGE_TAG)

          docker build -t $REGISTRY/data-fetcher-agent:$(IMAGE_TAG) ./workers/data-fetcher
          docker push $REGISTRY/data-fetcher-agent:$(IMAGE_TAG)

          docker build -t $REGISTRY/analyzer-agent:$(IMAGE_TAG) ./workers/analyzer
          docker push $REGISTRY/analyzer-agent:$(IMAGE_TAG)

          docker build -t $REGISTRY/summarizer-agent:$(IMAGE_TAG) ./workers/summarizer
          docker push $REGISTRY/summarizer-agent:$(IMAGE_TAG)

- stage: Deploy
  displayName: Deploy to AKS
  dependsOn: Build
  jobs:
  - job: HelmDeploy
    pool:
      vmImage: 'ubuntu-latest'
    steps:
    - task: AzureCLI@2
      inputs:
        azureSubscription: 'AzureServiceConnection'
        scriptType: 'bash'
        scriptLocation: 'inlineScript'
        inlineScript: |
          az aks get-credentials --resource-group $RESOURCE_GROUP --name $AKS_CLUSTER
          helm upgrade --install multi-agent ./helm-chart \
            --set controller.image=$REGISTRY/controller-agent:$(IMAGE_TAG) \
            --set workers[0].image=$REGISTRY/data-fetcher-agent:$(IMAGE_TAG) \
            --set workers[1].image=$REGISTRY/analyzer-agent:$(IMAGE_TAG) \
            --set workers[2].image=$REGISTRY/summarizer-agent:$(IMAGE_TAG)

🔑 Setup Requirements

  • Azure Service Connection: Create a service connection in Azure DevOps pointing to your subscription (used in azureSubscription above).
  • ACR & AKS: Already provisioned via the Bicep template we built earlier.
  • Helm chart: Stored in your repo under helm-chart/.
  • Secrets: Managed via Azure DevOps Library or Key Vault integration.

🚀 Workflow

  1. Developer pushes code → Pipeline triggers.
  2. Build stage → Docker images built & pushed to ACR.
  3. Deploy stage → Helm upgrades AKS workloads with new images.
  4. Agents start running and communicating via Service Bus.
  5. Logs flow into Application Insights for monitoring.

Now we will develop a small multi‑agent application that can automatically handle the full deployment pipeline we’ve been discussing (infra provisioning, container builds, pushing to ACR, Helm deploy to AKS, monitoring setup). Let’s design this as a multi‑agent system where each agent has a clear responsibility, and together they orchestrate the end‑to‑end deployment.


🧩 Multi‑Agent Application Design

Agents & Roles

  • Infra Agent

    • Provisions Azure resources (ACR, AKS, Service Bus, Key Vault, Monitor) using Bicep/ARM.
    • Runs az deployment group create commands.
  • Build Agent

    • Builds Docker images for each micro‑agent (controller, workers).
    • Pushes images to ACR.
  • Deploy Agent

    • Applies Helm charts to AKS.
    • Updates image tags automatically.
  • Monitor Agent

    • Configures Application Insights and Log Analytics.
    • Ensures telemetry is wired up.
  • Coordinator Agent

    • Orchestrates the workflow: triggers Infra → Build → Deploy → Monitor.
    • Handles retries and error reporting.

⚙️ Implementation Approach

  • Framework: Python with AutoGen or Semantic Kernel (github.com in Bing) for agent orchestration.
  • Communication: Agents interact via async tasks or Azure Service Bus.
  • Deployment: Each agent runs as a container in AKS or locally during bootstrap.

📄 Example Python Skeleton

from autogen import AssistantAgent, UserProxyAgent

# Infra Agent
infra_agent = AssistantAgent(name="InfraAgent", system_message="Provision Azure infra with Bicep.")
# Build Agent
build_agent = AssistantAgent(name="BuildAgent", system_message="Build and push Docker images to ACR.")
# Deploy Agent
deploy_agent = AssistantAgent(name="DeployAgent", system_message="Deploy Helm charts to AKS.")
# Monitor Agent
monitor_agent = AssistantAgent(name="MonitorAgent", system_message="Configure monitoring and logging.")
# Coordinator
coordinator = UserProxyAgent(name="Coordinator", human_input_mode="NEVER")

# Define workflow
def deployment_workflow():
    coordinator.initiate_chat(infra_agent, message="Provision infra resources")
    coordinator.initiate_chat(build_agent, message="Build and push images")
    coordinator.initiate_chat(deploy_agent, message="Deploy Helm charts")
    coordinator.initiate_chat(monitor_agent, message="Setup monitoring")

if __name__ == "__main__":
    deployment_workflow()

🚀 How It Works

  1. Coordinator Agent kicks off the workflow.
  2. Infra Agent provisions infra via Azure CLI/Bicep.
  3. Build Agent builds/pushes images.
  4. Deploy Agent applies Helm charts.
  5. Monitor Agent configures observability.
  6. Workflow completes with a fully deployed multi‑agent app in AKS.

🔄 Next Step

To make this truly automatic, you can:

  • Package each agent as a container.
  • Deploy them into AKS with a controller agent orchestrating tasks.
  • Or run them locally as part of a CI/CD pipeline.

Let’s put this all together into a working prototype of a multi‑agent application that can automatically deploy the full Azure environment, build/push images, and deploy to AKS. I’ll give you a Python-based orchestration example where each agent is a class with a clear responsibility. You can extend this into containers later.


🧩 Multi‑Agent Python Prototype

import subprocess

class InfraAgent:
    def provision(self):
        print("🚀 Provisioning Azure infra...")
        subprocess.run([
            "az", "deployment", "group", "create",
            "--resource-group", "multiagent-rg",
            "--template-file", "main.bicep"
        ], check=True)

class BuildAgent:
    def build_and_push(self):
        print("🔨 Building and pushing Docker images...")
        agents = {
            "controller": "./controller",
            "data-fetcher": "./workers/data-fetcher",
            "analyzer": "./workers/analyzer",
            "summarizer": "./workers/summarizer"
        }
        registry = "multiagentacr.azurecr.io"
        for name, path in agents.items():
            image = f"{registry}/{name}-agent:latest"
            subprocess.run(["docker", "build", "-t", image, path], check=True)
            subprocess.run(["docker", "push", image], check=True)

class DeployAgent:
    def deploy(self):
        print("📦 Deploying agents to AKS...")
        registry = "multiagentacr.azurecr.io"
        subprocess.run([
            "az", "aks", "get-credentials",
            "--resource-group", "multiagent-rg",
            "--name", "multiagent-aks"
        ], check=True)
        subprocess.run([
            "helm", "upgrade", "--install", "multi-agent", "./helm-chart",
            "--set", f"controller.image={registry}/controller-agent:latest",
            "--set", f"workers[0].image={registry}/data-fetcher-agent:latest",
            "--set", f"workers[1].image={registry}/analyzer-agent:latest",
            "--set", f"workers[2].image={registry}/summarizer-agent:latest"
        ], check=True)

class MonitorAgent:
    def configure(self):
        print("📊 Configuring monitoring...")
        subprocess.run([
            "az", "monitor", "app-insights", "component", "create",
            "--app", "multiagent-app",
            "--location", "eastus",
            "--resource-group", "multiagent-rg"
        ], check=True)

class CoordinatorAgent:
    def __init__(self):
        self.infra = InfraAgent()
        self.build = BuildAgent()
        self.deploy = DeployAgent()
        self.monitor = MonitorAgent()

    def run_workflow(self):
        self.infra.provision()
        self.build.build_and_push()
        self.deploy.deploy()
        self.monitor.configure()
        print("✅ Multi-agent deployment complete!")

if __name__ == "__main__":
    CoordinatorAgent().run_workflow()

🚀 How to Use

  1. Save this as multi_agent_deploy.py.
  2. Ensure you have:
    • Azure CLI installed and logged in (az login).
    • Docker installed and running.
    • Helm installed.
    • Your main.bicep and helm-chart/ ready.
  3. Run:
    python multi_agent_deploy.py
    
  4. The workflow will:
    • Provision infra (ACR, AKS, Service Bus, Key Vault, Monitor).
    • Build/push agent images.
    • Deploy Helm chart to AKS.
    • Configure monitoring.

🔄 Next Steps

  • Wrap each agent into its own container for true distributed execution.
  • Use Azure Service Bus for inter‑agent communication instead of sequential Python calls.
  • Add error handling and retries for robustness.

Excellent — let’s extend the prototype into a containerized multi‑agent application so each agent runs independently inside AKS. This way, the deployment itself is automated and self‑contained.


🧩 Containerized Multi‑Agent Setup

1. Dockerfiles for Each Agent

Example: InfraAgent

# controller/Dockerfile
FROM python:3.10-slim

WORKDIR /app
COPY infra_agent.py .

RUN pip install azure-cli

CMD ["python", "infra_agent.py"]

Repeat similar Dockerfiles for build_agent.py, deploy_agent.py, and monitor_agent.py.
Each agent script contains its logic (Azure CLI, Docker, Helm commands).


2. Kubernetes Manifests (AKS)

infra-agent-deployment.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: infra-agent
spec:
  replicas: 1
  selector:
    matchLabels:
      app: infra-agent
  template:
    metadata:
      labels:
        app: infra-agent
    spec:
      containers:
      - name: infra-agent
        image: multiagentacr.azurecr.io/infra-agent:latest
        env:
        - name: AZURE_SUBSCRIPTION_ID
          valueFrom:
            secretKeyRef:
              name: azure-secrets
              key: subscriptionId

build-agent-deployment.yaml, deploy-agent-deployment.yaml, monitor-agent-deployment.yaml follow the same pattern, each pointing to its respective image.


3. Coordinator Agent (Orchestrator)

You can run the CoordinatorAgent as a Job in Kubernetes:

apiVersion: batch/v1
kind: Job
metadata:
  name: coordinator-agent
spec:
  template:
    spec:
      containers:
      - name: coordinator
        image: multiagentacr.azurecr.io/coordinator-agent:latest
      restartPolicy: Never

This job triggers the workflow: Infra → Build → Deploy → Monitor.
Agents can communicate via Azure Service Bus or HTTP APIs inside the cluster.


4. Secrets & Config

  • Store credentials in Azure Key Vault or Kubernetes Secrets.
  • Example secret:
apiVersion: v1
kind: Secret
metadata:
  name: azure-secrets
type: Opaque
data:
  subscriptionId: <base64-encoded-value>
  clientId: <base64-encoded-value>
  clientSecret: <base64-encoded-value>

5. Deployment Flow

  1. Build Docker images for each agent.
    docker build -t multiagentacr.azurecr.io/infra-agent:latest ./infra
    docker push multiagentacr.azurecr.io/infra-agent:latest
    
  2. Apply manifests:
    kubectl apply -f infra-agent-deployment.yaml
    kubectl apply -f build-agent-deployment.yaml
    kubectl apply -f deploy-agent-deployment.yaml
    kubectl apply -f monitor-agent-deployment.yaml
    kubectl apply -f coordinator-agent-job.yaml
    
  3. Coordinator triggers workflow → agents execute tasks → full deployment automated.

✅ With this setup, you now have a self‑deploying multi‑agent system inside AKS. Each agent is containerized, scalable, and independently responsible for its part of the pipeline.


Let’s wrap everything into a Helm chart so you can deploy the entire multi‑agent system (infra, build, deploy, monitor, coordinator) with a single helm install command.


🏗️ Helm Chart Structure

multi-agent-chart/
├── Chart.yaml
├── values.yaml
├── templates/
│   ├── infra-agent-deployment.yaml
│   ├── build-agent-deployment.yaml
│   ├── deploy-agent-deployment.yaml
│   ├── monitor-agent-deployment.yaml
│   ├── coordinator-agent-job.yaml
│   └── _helpers.tpl

📄 Chart.yaml

apiVersion: v2
name: multi-agent
description: Helm chart for multi-agent deployment automation
version: 0.1.0
appVersion: "1.0"

📄 values.yaml

registry: multiagentacr.azurecr.io

infraAgent:
  image: infra-agent:latest
  replicas: 1

buildAgent:
  image: build-agent:latest
  replicas: 1

deployAgent:
  image: deploy-agent:latest
  replicas: 1

monitorAgent:
  image: monitor-agent:latest
  replicas: 1

coordinatorAgent:
  image: coordinator-agent:latest

📄 templates/infra-agent-deployment.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: infra-agent
spec:
  replicas: {{ .Values.infraAgent.replicas }}
  selector:
    matchLabels:
      app: infra-agent
  template:
    metadata:
      labels:
        app: infra-agent
    spec:
      containers:
      - name: infra-agent
        image: "{{ .Values.registry }}/{{ .Values.infraAgent.image }}"

📄 templates/build-agent-deployment.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: build-agent
spec:
  replicas: {{ .Values.buildAgent.replicas }}
  selector:
    matchLabels:
      app: build-agent
  template:
    metadata:
      labels:
        app: build-agent
    spec:
      containers:
      - name: build-agent
        image: "{{ .Values.registry }}/{{ .Values.buildAgent.image }}"

📄 templates/deploy-agent-deployment.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: deploy-agent
spec:
  replicas: {{ .Values.deployAgent.replicas }}
  selector:
    matchLabels:
      app: deploy-agent
  template:
    metadata:
      labels:
        app: deploy-agent
    spec:
      containers:
      - name: deploy-agent
        image: "{{ .Values.registry }}/{{ .Values.deployAgent.image }}"

📄 templates/monitor-agent-deployment.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: monitor-agent
spec:
  replicas: {{ .Values.monitorAgent.replicas }}
  selector:
    matchLabels:
      app: monitor-agent
  template:
    metadata:
      labels:
        app: monitor-agent
    spec:
      containers:
      - name: monitor-agent
        image: "{{ .Values.registry }}/{{ .Values.monitorAgent.image }}"

📄 templates/coordinator-agent-job.yaml

apiVersion: batch/v1
kind: Job
metadata:
  name: coordinator-agent
spec:
  template:
    spec:
      containers:
      - name: coordinator
        image: "{{ .Values.registry }}/{{ .Values.coordinatorAgent.image }}"
      restartPolicy: Never

🚀 Deployment

  1. Package and install:
    helm install multi-agent ./multi-agent-chart
    
  2. Helm will deploy all agents (infra, build, deploy, monitor) plus the coordinator job.
  3. Coordinator triggers the workflow → agents execute tasks → full deployment automated.

Great — let’s extend the Helm chart with Azure Service Bus integration so your agents can communicate asynchronously inside AKS. This way, instead of just running sequentially, they’ll publish/subscribe to topics and queues for coordination.


🧩 Updated Helm Chart Structure

multi-agent-chart/
├── Chart.yaml
├── values.yaml
├── templates/
│   ├── infra-agent-deployment.yaml
│   ├── build-agent-deployment.yaml
│   ├── deploy-agent-deployment.yaml
│   ├── monitor-agent-deployment.yaml
│   ├── coordinator-agent-job.yaml
│   ├── servicebus-secret.yaml
│   ├── servicebus-configmap.yaml

📄 values.yaml (extended)

registry: multiagentacr.azurecr.io

serviceBus:
  namespace: multiagent-sb
  connectionString: "" # injected via secret

infraAgent:
  image: infra-agent:latest
  replicas: 1

buildAgent:
  image: build-agent:latest
  replicas: 1

deployAgent:
  image: deploy-agent:latest
  replicas: 1

monitorAgent:
  image: monitor-agent:latest
  replicas: 1

coordinatorAgent:
  image: coordinator-agent:latest

📄 templates/servicebus-secret.yaml

apiVersion: v1
kind: Secret
metadata:
  name: servicebus-secret
type: Opaque
stringData:
  connectionString: {{ .Values.serviceBus.connectionString | quote }}

📄 templates/servicebus-configmap.yaml

apiVersion: v1
kind: ConfigMap
metadata:
  name: servicebus-config
data:
  namespace: {{ .Values.serviceBus.namespace }}

📄 Example Agent Deployment with Service Bus Integration

build-agent-deployment.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: build-agent
spec:
  replicas: {{ .Values.buildAgent.replicas }}
  selector:
    matchLabels:
      app: build-agent
  template:
    metadata:
      labels:
        app: build-agent
    spec:
      containers:
      - name: build-agent
        image: "{{ .Values.registry }}/{{ .Values.buildAgent.image }}"
        env:
        - name: SERVICEBUS_CONNECTION
          valueFrom:
            secretKeyRef:
              name: servicebus-secret
              key: connectionString
        - name: SERVICEBUS_NAMESPACE
          valueFrom:
            configMapKeyRef:
              name: servicebus-config
              key: namespace

🔄 Communication Flow with Service Bus

  • Coordinator Agent publishes a message to a topic (e.g., deployment-steps).
  • Infra Agent subscribes to infra queue → provisions infra → publishes completion event.
  • Build Agent listens on build queue → builds/pushes images → publishes completion event.
  • Deploy Agent listens on deploy queue → applies Helm → publishes completion event.
  • Monitor Agent listens on monitor queue → configures monitoring → publishes completion event.

This makes the workflow event-driven and resilient.


🚀 Deployment

  1. Inject your Service Bus connection string into Helm:
    helm install multi-agent ./multi-agent-chart \
      --set serviceBus.connectionString="Endpoint=sb://multiagent-sb.servicebus.windows.net/...;SharedAccessKeyName=RootManageSharedAccessKey;SharedAccessKey=..."
    
  2. All agents will be deployed with Service Bus credentials and namespace.
  3. Agents communicate asynchronously via topics/queues.

Let’s wire up the agents’ communication logic using the Azure Service Bus SDK for Python. This will let each agent send and receive messages asynchronously via queues/topics, making the system event‑driven instead of sequential.


🧩 Install Dependencies

pip install azure-servicebus

📄 Example Agent Code

Coordinator Agent (Publisher)

from azure.servicebus import ServiceBusClient, ServiceBusMessage

CONNECTION_STR = "<your-servicebus-connection-string>"
QUEUE_NAME = "infra-queue"

def send_message():
    with ServiceBusClient.from_connection_string(CONNECTION_STR) as client:
        sender = client.get_queue_sender(queue_name=QUEUE_NAME)
        with sender:
            msg = ServiceBusMessage("Provision infra")
            sender.send_messages(msg)
            print("✅ Coordinator sent: Provision infra")

if __name__ == "__main__":
    send_message()

Infra Agent (Subscriber)

from azure.servicebus import ServiceBusClient

CONNECTION_STR = "<your-servicebus-connection-string>"
QUEUE_NAME = "infra-queue"

def receive_message():
    with ServiceBusClient.from_connection_string(CONNECTION_STR) as client:
        receiver = client.get_queue_receiver(queue_name=QUEUE_NAME)
        with receiver:
            for msg in receiver:
                print(f"📥 InfraAgent received: {msg.body}")
                # Run infra provisioning logic here (az deployment group create ...)
                receiver.complete_message(msg)

if __name__ == "__main__":
    receive_message()

Build Agent (Subscriber + Publisher)

from azure.servicebus import ServiceBusClient, ServiceBusMessage

CONNECTION_STR = "<your-servicebus-connection-string>"
QUEUE_NAME = "build-queue"

def receive_and_build():
    with ServiceBusClient.from_connection_string(CONNECTION_STR) as client:
        receiver = client.get_queue_receiver(queue_name=QUEUE_NAME)
        with receiver:
            for msg in receiver:
                print(f"📥 BuildAgent received: {msg.body}")
                # Run docker build/push logic here
                receiver.complete_message(msg)

                # Publish completion event
                sender = client.get_queue_sender(queue_name="deploy-queue")
                with sender:
                    sender.send_messages(ServiceBusMessage("Build complete"))
                    print("✅ BuildAgent published: Build complete")

if __name__ == "__main__":
    receive_and_build()

Deploy Agent (Subscriber)

from azure.servicebus import ServiceBusClient

CONNECTION_STR = "<your-servicebus-connection-string>"
QUEUE_NAME = "deploy-queue"

def receive_and_deploy():
    with ServiceBusClient.from_connection_string(CONNECTION_STR) as client:
        receiver = client.get_queue_receiver(queue_name=QUEUE_NAME)
        with receiver:
            for msg in receiver:
                print(f"📥 DeployAgent received: {msg.body}")
                # Run helm upgrade/install logic here
                receiver.complete_message(msg)

if __name__ == "__main__":
    receive_and_deploy()

Monitor Agent (Subscriber)

from azure.servicebus import ServiceBusClient

CONNECTION_STR = "<your-servicebus-connection-string>"
QUEUE_NAME = "monitor-queue"

def receive_and_monitor():
    with ServiceBusClient.from_connection_string(CONNECTION_STR) as client:
        receiver = client.get_queue_receiver(queue_name=QUEUE_NAME)
        with receiver:
            for msg in receiver:
                print(f"📥 MonitorAgent received: {msg.body}")
                # Configure Application Insights / Log Analytics here
                receiver.complete_message(msg)

if __name__ == "__main__":
    receive_and_monitor()

🔄 Workflow Example

  1. Coordinator Agent publishes "Provision infra"infra-queue.
  2. Infra Agent provisions infra → publishes "Infra complete"build-queue.
  3. Build Agent builds/pushes images → publishes "Build complete"deploy-queue.
  4. Deploy Agent applies Helm → publishes "Deploy complete"monitor-queue.
  5. Monitor Agent configures monitoring → workflow ends.

🚀 Next Step

You can containerize each agent with its own Dockerfile and deploy them via the Helm chart we built earlier. Each agent will subscribe to its queue, perform its task, and publish the next step — giving you a fully automated, event‑driven multi‑agent deployment system on Azure.


Let’s extend the automation so your Helm chart + Bicep template not only deploys the agents but also provisions Service Bus queues/topics automatically. This way, you won’t need to manually create messaging infrastructure — it’s fully declarative.


🧩 Updated Bicep Template (Service Bus Queues/Topics)

Add this to your main.bicep:

// Service Bus Namespace
resource sb 'Microsoft.ServiceBus/namespaces@2021-06-01-preview' = {
  name: sbNamespace
  location: location
  sku: {
    name: 'Standard'
    tier: 'Standard'
  }
}

// Queues for each agent
resource infraQueue 'Microsoft.ServiceBus/namespaces/queues@2021-06-01-preview' = {
  parent: sb
  name: 'infra-queue'
  properties: {
    enablePartitioning: true
  }
}

resource buildQueue 'Microsoft.ServiceBus/namespaces/queues@2021-06-01-preview' = {
  parent: sb
  name: 'build-queue'
  properties: {
    enablePartitioning: true
  }
}

resource deployQueue 'Microsoft.ServiceBus/namespaces/queues@2021-06-01-preview' = {
  parent: sb
  name: 'deploy-queue'
  properties: {
    enablePartitioning: true
  }
}

resource monitorQueue 'Microsoft.ServiceBus/namespaces/queues@2021-06-01-preview' = {
  parent: sb
  name: 'monitor-queue'
  properties: {
    enablePartitioning: true
  }
}

This provisions the namespace + queues for Infra, Build, Deploy, and Monitor agents.


📄 Helm Chart Integration

values.yaml

serviceBus:
  namespace: multiagent-sb
  connectionString: "" # injected via secret
  queues:
    infra: infra-queue
    build: build-queue
    deploy: deploy-queue
    monitor: monitor-queue

templates/servicebus-secret.yaml

apiVersion: v1
kind: Secret
metadata:
  name: servicebus-secret
type: Opaque
stringData:
  connectionString: {{ .Values.serviceBus.connectionString | quote }}

Example Agent Deployment (Build Agent)

apiVersion: apps/v1
kind: Deployment
metadata:
  name: build-agent
spec:
  replicas: {{ .Values.buildAgent.replicas }}
  selector:
    matchLabels:
      app: build-agent
  template:
    metadata:
      labels:
        app: build-agent
    spec:
      containers:
      - name: build-agent
        image: "{{ .Values.registry }}/{{ .Values.buildAgent.image }}"
        env:
        - name: SERVICEBUS_CONNECTION
          valueFrom:
            secretKeyRef:
              name: servicebus-secret
              key: connectionString
        - name: QUEUE_NAME
          value: {{ .Values.serviceBus.queues.build }}

Each agent gets its queue name injected via Helm values.


🚀 Deployment Flow

  1. Run Bicep → provisions ACR, AKS, Service Bus namespace + queues.
  2. Helm install → deploys all agents with Service Bus credentials + queue names.
  3. Agents subscribe/publish to their queues automatically.
  4. Workflow becomes event‑driven: Infra → Build → Deploy → Monitor.

✅ With this, you now have a self‑deploying, event‑driven multi‑agent system on Azure.
The infra, messaging, and agents are all provisioned declaratively.


It will help to gain more knowledge https://learn.microsoft.com/en-us/azure/devops/pipelines/?view=azure-devops


Wednesday

Integrating Authentication OAuth 2.0

Integrating authentication protocols like Azure AD (which heavily uses OAuth 2.0) and generic OAuth 2.0 into your APIs is crucial for securing your applications. Here's a breakdown of how to approach this, including key concepts and best practices:

Understanding OAuth 2.0 (the foundation)

OAuth 2.0 is an authorization framework that enables an application to obtain limited access to a user's protected resources on an HTTP service (like your API), without revealing the user's credentials to the application. Instead, the application obtains an access token from an authorization server (e.g., Azure AD) after the user grants consent.

Key Roles in OAuth 2.0:

  • Resource Owner: The user who owns the data (e.g., their profile information, documents) that the client application wants to access.

  • Client: The application (your API consumer, like a web app, mobile app, or another service) that wants to access the protected resources.

  • Authorization Server: The server that issues access tokens to the client after successfully authenticating the resource owner and obtaining their authorization. (Azure AD acts as an Authorization Server).

  • Resource Server: The API that hosts the protected resources and accepts access tokens to grant access. (Your API will be the Resource Server).

Common OAuth 2.0 Flows for APIs:

  • Authorization Code Flow (with PKCE): This is the most secure and recommended flow for web applications and mobile/native applications. It involves a redirect to the authorization server for user login and consent, then an authorization code is exchanged for an access token at the backend. PKCE (Proof Key for Code Exchange) adds an extra layer of security against interception.

  • Client Credentials Flow: Used for machine-to-machine communication where there's no user involved (e.g., a service authenticating to another service). The client uses its own credentials (Client ID and Client Secret) to obtain an access token.

  • On-Behalf-Of (OBO) Flow (Specific to Azure AD): If your API needs to call another downstream API on behalf of the user, Azure AD supports the OBO flow where your API exchanges the initial access token for another token with permissions to the downstream API.

Integrating Azure AD Authentication into APIs

Azure Active Directory (Azure AD) is Microsoft's cloud-based identity and access management service, and it heavily leverages OAuth 2.0 and OpenID Connect for authentication and authorization.

Steps to Integrate Azure AD into your API (as the Resource Server):

  1. Register your API as an Application in Azure AD:

    • Go to the Azure portal and navigate to "App registrations."

    • Register a new application that represents your API.

    • Configure its Application ID URI (also known as Audience or Identifier URI).

    • Define API permissions (scopes) that your API exposes. These scopes represent the granular access rights that clients can request (e.g., api://your-api-id/read_data, api://your-api-id/write_data).

    • For clients, you might also need to create a client secret (for confidential clients like web apps) or enable public client flows (for mobile/desktop apps).

  2. Configure your API to Validate Azure AD Tokens:

    • Your API (Resource Server) needs to be able to validate the JSON Web Tokens (JWTs) issued by Azure AD.

    • This typically involves using a JWT bearer authentication middleware or library in your API framework (e.g., Microsoft.Identity.Web for ASP.NET Core, passport-azure-ad for Node.js).

    • The middleware will:

      • Extract the access token from the Authorization: Bearer <token> header of incoming requests.

      • Validate the token's signature against Azure AD's public keys.

      • Check the token's claims:

        • iss (Issuer): Ensures the token was issued by your Azure AD tenant.

        • aud (Audience): Ensures the token is intended for your API (matches your API's Application ID URI).

        • exp (Expiration): Checks if the token is still valid.

        • nbf (Not Before): Checks if the token is active.

        • scp (Scopes) or roles: Verifies if the client has the necessary permissions to access the requested resource/operation.

      • If the token is valid, the middleware will usually populate the user's identity (claims) into the current request context, allowing your API logic to perform further authorization checks based on these claims.

  3. Implement Authorization Logic within your API:

    • Once the token is validated, your API needs to determine if the authenticated user/client has the necessary permissions (based on the scopes or roles in the token) to perform the requested action.

    • This often involves:

      • Role-based access control (RBAC): Checking if the user belongs to a specific role.

      • Scope-based authorization: Checking if the token contains the required scopes for the API endpoint.

Example (Conceptual - ASP.NET Core):

C#
// In Startup.cs or Program.cs (for minimal APIs)
public void ConfigureServices(IServiceCollection services)
{
    services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
        .AddMicrosoftIdentityWebApi(Configuration.GetSection("AzureAd")); // Binds configuration from appsettings.json

    services.AddAuthorization(options =>
    {
        options.AddPolicy("RequireReadAccess", policy => policy.RequireScope("api://your-app-id/read_data"));
        options.AddPolicy("RequireWriteAccess", policy => policy.RequireScope("api://your-app-id/write_data"));
    });

    services.AddControllers();
}

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    app.UseHttpsRedirection();
    app.UseRouting();

    app.UseAuthentication(); // Must be before UseAuthorization
    app.UseAuthorization();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapControllers();
    });
}

// In your API Controller
[Authorize] // Requires any valid token
[Authorize(Policy = "RequireReadAccess")] // Requires the "read_data" scope
[HttpGet("data")]
public IActionResult GetData()
{
    // Access user claims from HttpContext.User
    return Ok("Data accessed!");
}

Generic OAuth 2.0 Integration for APIs

If you're using a different OAuth 2.0 provider (e.g., Google, Okta, Auth0, or your own custom authorization server), the principles are similar to Azure AD, but the specific configuration details and libraries will vary.

General Steps:

  1. Register your API with the OAuth 2.0 Provider:

    • Obtain a Client ID and potentially a Client Secret for your API.

    • Define scopes that your API exposes.

    • Configure redirect URIs (if your API is part of a user-facing application).

  2. Configure your API to Validate Tokens from the Provider:

    • Your API needs to trust the specific OAuth 2.0 provider.

    • This involves configuring your API's authentication middleware to:

      • Know the provider's JWKS (JSON Web Key Set) endpoint to retrieve public keys for token signature validation.

      • Set the expected iss (Issuer) and aud (Audience) claims for tokens.

      • Implement logic to extract and validate the access token (JWT) from the Authorization header.

  3. Implement Authorization based on Claims:

    • Similar to Azure AD, extract scopes, roles, or other claims from the validated token.

    • Use these claims to enforce fine-grained access control within your API endpoints.

Best Practices for API Authentication:

  • Always use HTTPS: All communication between clients, authorization servers, and your API should be encrypted with HTTPS to prevent man-in-the-middle attacks.

  • Validate Tokens Thoroughly: Always validate the token's signature, expiration, issuer, audience, and any required scopes or claims.

  • Use the Authorization Code Flow with PKCE: This is the most secure flow for public clients (mobile/SPA) and confidential clients (web apps). Avoid the Implicit Flow.

  • Securely Store Client Secrets: If your API acts as a confidential client (e.g., in Client Credentials flow), store client secrets in secure environments (e.g., Azure Key Vault, environment variables) and never hardcode them in your codebase or commit them to public repositories.

  • Short-lived Access Tokens, Long-lived Refresh Tokens: Issue access tokens with a short expiry (e.g., 1 hour) and use refresh tokens (for user-based flows) to obtain new access tokens without requiring the user to re-authenticate. Refresh tokens should be long-lived but managed securely and revoked if compromised.

  • Implement Scope-Based Authorization: Design your API endpoints to require specific scopes, ensuring clients only have access to what they truly need.

  • Error Handling: Provide clear and informative error messages (e.g., 401 Unauthorized, 403 Forbidden) when authentication or authorization fails, but avoid revealing too much sensitive information.

  • Logging and Monitoring: Log authentication and authorization events to monitor for suspicious activity.

  • Rate Limiting: Implement rate limiting on your authentication endpoints to prevent brute-force attacks.

  • Centralized Identity Provider: Leverage a robust identity provider like Azure AD, Auth0, Okta, etc., rather than building your own from scratch.

  • Regular Security Audits: Regularly review your authentication and authorization implementation for vulnerabilities.

By following these guidelines and leveraging appropriate libraries and services, you can effectively integrate robust authentication and authorization protocols into your APIs.


Integrating OAuth with Google and Azure AD in FastAPI involves several steps, primarily centered around handling the OAuth 2.0 authorization code flow. For simplicity and best practices, we'll use libraries like Authlib (a popular choice for OAuth clients in Python) and fastapi-microsoft-identity for Azure AD specifically.

Before you start:

  • Install necessary libraries:

    Bash
    pip install fastapi uvicorn python-multipart python-jose[cryptography] authlib python-dotenv fastapi-microsoft-identity
    
  • Set up environment variables: Create a .env file in your project root to store sensitive credentials.

  • Google Cloud Console:

    • Create a new project or use an existing one.

    • Go to "APIs & Services" > "Credentials".

    • Create "OAuth client ID" (Web application).

    • Add http://localhost:8000/auth/google/callback to "Authorized redirect URIs".

    • Note down your Client ID and Client Secret.

    • Enable the "Google People API" (or other APIs relevant to the scopes you request) if you want to fetch user profile information.

  • Azure AD (Entra ID) Portal:

    • Go to "App registrations" in your Azure AD tenant.

    • Register a new application for your FastAPI API.

    • For the API application (your backend):

      • Note down Application (client) ID and Directory (tenant) ID.

      • Go to "Expose an API" and set an Application ID URI (e.g., api://your-app-id). Add a scope (e.g., access_as_user).

      • Generate a Client Secret under "Certificates & secrets".

    • For a client application (e.g., a Single-Page Application, if you plan to use Swagger UI to log in):

      • Register another application for your client.

      • Under "Authentication", add a "Redirect URI" of type "Single-page application" (SPA) to http://localhost:8000/oauth2-redirect.

      • Under "API permissions", add the permission for your backend API's scope (e.g., access_as_user) and grant admin consent.


1. Google OAuth2 Integration

This example demonstrates the Authorization Code Flow with Google, where your FastAPI application acts as the client to Google's OAuth 2.0 service.

main.py

Python
import os
from datetime import datetime, timedelta
from typing import Optional

from fastapi import FastAPI, Depends, HTTPException, status, Request
from fastapi.responses import RedirectResponse, HTMLResponse
from fastapi.security import OAuth2PasswordBearer
from starlette.middleware.sessions import SessionMiddleware
from authlib.integrations.starlette_client import OAuth
from jose import jwt, JWSAlgorithms

from dotenv import load_dotenv

load_dotenv()

# --- Configuration for Google OAuth ---
GOOGLE_CLIENT_ID = os.getenv("GOOGLE_CLIENT_ID")
GOOGLE_CLIENT_SECRET = os.getenv("GOOGLE_CLIENT_SECRET")
GOOGLE_REDIRECT_URI = "http://localhost:8000/auth/google/callback" # Must match your Google Cloud Console setting
JWT_SECRET_KEY = os.getenv("JWT_SECRET_KEY", "your-super-secret-key") # For your internal JWTs
ALGORITHM = "HS256"
ACCESS_TOKEN_EXPIRE_MINUTES = 30

# --- FastAPI App Setup ---
app = FastAPI(
    title="FastAPI OAuth Integrations",
    description="Example for Google and Azure AD authentication",
    docs_url="/docs",
    redoc_url="/redoc"
)

# Session middleware is required for Authlib's OAuth client
app.add_middleware(SessionMiddleware, secret_key=os.getenv("SESSION_SECRET_KEY", "another-secret-key"))

oauth = OAuth()
oauth.register(
    name='google',
    client_id=GOOGLE_CLIENT_ID,
    client_secret=GOOGLE_CLIENT_SECRET,
    server_metadata_url='https://accounts.google.com/.well-known/openid-configuration',
    client_kwargs={'scope': 'openid email profile'},
)

# --- Internal JWT for authenticated users (after Google login) ---
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="/token") # This tokenUrl is for your API's internal token endpoint, if you had one.
                                                      # For external OAuth, we will issue a token upon successful login.

def create_access_token(data: dict, expires_delta: Optional[timedelta] = None):
    to_encode = data.copy()
    if expires_delta:
        expire = datetime.utcnow() + expires_delta
    else:
        expire = datetime.utcnow() + timedelta(minutes=15)
    to_encode.update({"exp": expire})
    encoded_jwt = jwt.encode(to_encode, JWT_SECRET_KEY, algorithm=ALGORITHM)
    return encoded_jwt

# --- Google OAuth Endpoints ---
@app.get("/auth/google/login")
async def login_google(request: Request):
    """
    Redirects to Google for authentication.
    """
    return await oauth.google.authorize_redirect(request, GOOGLE_REDIRECT_URI)

@app.get("/auth/google/callback")
async def auth_google_callback(request: Request):
    """
    Handles the callback from Google after successful authentication.
    """
    try:
        token = await oauth.google.authorize_access_token(request)
    except Exception as e:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail=f"Authentication failed: {e}"
        )

    user_info = await oauth.google.parse_id_token(request, token)

    # Here, user_info contains user details from Google (e.g., 'email', 'name', 'sub')
    # You would typically:
    # 1. Look up the user in your database based on their Google ID (user_info['sub'] or 'email').
    # 2. If the user doesn't exist, create a new user record.
    # 3. Create an internal JWT for your application's session.

    # For demonstration, we'll just create a simple JWT
    user_data = {"email": user_info['email'], "name": user_info.get('name', 'N/A'), "google_id": user_info['sub']}
    access_token = create_access_token(data=user_data, expires_delta=timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES))

    # Redirect to a frontend page or return the token directly (e.g., for SPA)
    # For a real application, you'd typically redirect to your frontend with the token
    # or set it in a secure cookie.
    response = RedirectResponse(url="/", status_code=status.HTTP_302_FOUND)
    response.set_cookie(key="access_token", value=access_token, httponly=True, max_age=ACCESS_TOKEN_EXPIRE_MINUTES * 60)
    return response

@app.get("/google-protected-data")
async def get_google_protected_data(request: Request):
    """
    An example protected endpoint.
    Checks for the internal access_token cookie.
    """
    access_token = request.cookies.get("access_token")
    if not access_token:
        raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="Not authenticated")

    try:
        payload = jwt.decode(access_token, JWT_SECRET_KEY, algorithms=[ALGORITHM])
        user_email = payload.get("email")
        user_name = payload.get("name")
        google_id = payload.get("google_id")
        if user_email is None:
            raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="Invalid token payload")
    except jwt.ExpiredSignatureError:
        raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="Token expired")
    except jwt.InvalidTokenError:
        raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="Invalid token")

    return {"message": f"Hello, {user_name} ({user_email})! This is Google-protected data.", "google_id": google_id}

@app.get("/", response_class=HTMLResponse)
async def home():
    return """
    <html>
        <head>
            <title>FastAPI OAuth</title>
        </head>
        <body>
            <h1>Welcome to FastAPI OAuth Demo</h1>
            <p><a href="/auth/google/login">Login with Google</a></p>
            <p><a href="/auth/azure/login">Login with Azure AD</a></p>
            <p><a href="/google-protected-data">Access Google Protected Data (after Google login)</a></p>
            <p><a href="/azure-protected-data">Access Azure Protected Data (after Azure login)</a></p>
        </body>
    </html>
    """

if __name__ == "__main__":
    import uvicorn
    uvicorn.run(app, host="0.0.0.0", port=8000)

.env file (create this in the same directory as main.py)

GOOGLE_CLIENT_ID="YOUR_GOOGLE_CLIENT_ID"
GOOGLE_CLIENT_SECRET="YOUR_GOOGLE_CLIENT_SECRET"
JWT_SECRET_KEY="a-very-strong-and-random-secret-key-for-your-jwt"
SESSION_SECRET_KEY="another-long-random-string-for-session-middleware"

How to run (Google OAuth):

  1. Make sure your .env file has the correct GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET, JWT_SECRET_KEY, and SESSION_SECRET_KEY.

  2. Run the FastAPI app: uvicorn main:app --reload

  3. Open your browser to http://localhost:8000.

  4. Click "Login with Google". You'll be redirected to Google for login and consent.

  5. After successful login, you'll be redirected back to http://localhost:8000, and an internal JWT will be set as a cookie.

  6. Click "Access Google Protected Data" to see if your internal JWT works.


2. Azure AD Authentication Integration

For Azure AD, fastapi-microsoft-identity is a very convenient library as it handles much of the token validation complexity for you. It's designed to validate JWTs issued by Azure AD.

main.py (continuation from above, add the Azure AD parts)

Python
import os
from datetime import datetime, timedelta
from typing import Optional

from fastapi import FastAPI, Depends, HTTPException, status, Request
from fastapi.responses import RedirectResponse, HTMLResponse
from fastapi.security import OAuth2PasswordBearer
from starlette.middleware.sessions import SessionMiddleware
from authlib.integrations.starlette_client import OAuth
from jose import jwt, JWSAlgorithms

from dotenv import load_dotenv

# --- Azure AD specific imports ---
from fastapi_microsoft_identity import initialize, requires_auth, AuthError, validate_scope

load_dotenv()

# --- Configuration for Google OAuth (already defined above) ---
GOOGLE_CLIENT_ID = os.getenv("GOOGLE_CLIENT_ID")
GOOGLE_CLIENT_SECRET = os.getenv("GOOGLE_CLIENT_SECRET")
GOOGLE_REDIRECT_URI = "http://localhost:8000/auth/google/callback"
JWT_SECRET_KEY = os.getenv("JWT_SECRET_KEY", "your-super-secret-key")
ALGORITHM = "HS256"
ACCESS_TOKEN_EXPIRE_MINUTES = 30

# --- Configuration for Azure AD ---
AZURE_TENANT_ID = os.getenv("AZURE_TENANT_ID")
AZURE_CLIENT_ID = os.getenv("AZURE_CLIENT_ID") # Client ID of your API app registration in Azure AD
AZURE_SCOPE = os.getenv("AZURE_SCOPE", "api://YOUR_AZURE_API_APP_ID/access_as_user") # This should be the scope you defined in Azure AD for your API

# Initialize fastapi-microsoft-identity
# Note: This is for validating tokens that *clients* send to your API.
# If your FastAPI app also acts as a client to Azure AD to get tokens for *itself*
# (e.g., if you were to implement a full user login flow initiated by FastAPI redirecting to Azure),
# you'd use Authlib's OAuth.register for 'microsoft' similar to 'google'.
# For now, we're focusing on FastAPI *validating* tokens issued by Azure AD.
try:
    initialize(tenant_id=AZURE_TENANT_ID, client_id=AZURE_CLIENT_ID)
except ValueError as e:
    print(f"Warning: Azure AD initialization failed. Ensure AZURE_TENANT_ID and AZURE_CLIENT_ID are set. Error: {e}")


# --- FastAPI App Setup (already defined above) ---
app = FastAPI(
    title="FastAPI OAuth Integrations",
    description="Example for Google and Azure AD authentication",
    docs_url="/docs",
    redoc_url="/redoc"
)

app.add_middleware(SessionMiddleware, secret_key=os.getenv("SESSION_SECRET_KEY", "another-secret-key"))

oauth = OAuth()
oauth.register(
    name='google',
    client_id=GOOGLE_CLIENT_ID,
    client_secret=GOOGLE_CLIENT_SECRET,
    server_metadata_url='https://accounts.google.com/.well-known/openid-configuration',
    client_kwargs={'scope': 'openid email profile'},
)

# --- Internal JWT for authenticated users (already defined above) ---
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="/token")

def create_access_token(data: dict, expires_delta: Optional[timedelta] = None):
    to_encode = data.copy()
    if expires_delta:
        expire = datetime.utcnow() + expires_delta
    else:
        expire = datetime.utcnow() + timedelta(minutes=15)
    to_encode.update({"exp": expire})
    encoded_jwt = jwt.encode(to_encode, JWT_SECRET_KEY, algorithm=ALGORITHM)
    return encoded_jwt

# --- Google OAuth Endpoints (already defined above) ---
@app.get("/auth/google/login")
async def login_google(request: Request):
    return await oauth.google.authorize_redirect(request, GOOGLE_REDIRECT_URI)

@app.get("/auth/google/callback")
async def auth_google_callback(request: Request):
    try:
        token = await oauth.google.authorize_access_token(request)
    except Exception as e:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail=f"Authentication failed: {e}"
        )

    user_info = await oauth.google.parse_id_token(request, token)
    user_data = {"email": user_info['email'], "name": user_info.get('name', 'N/A'), "google_id": user_info['sub']}
    access_token = create_access_token(data=user_data, expires_delta=timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES))
    response = RedirectResponse(url="/", status_code=status.HTTP_302_FOUND)
    response.set_cookie(key="access_token", value=access_token, httponly=True, max_age=ACCESS_TOKEN_EXPIRE_MINUTES * 60)
    return response

@app.get("/google-protected-data")
async def get_google_protected_data(request: Request):
    access_token = request.cookies.get("access_token")
    if not access_token:
        raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="Not authenticated")

    try:
        payload = jwt.decode(access_token, JWT_SECRET_KEY, algorithms=[ALGORITHM])
        user_email = payload.get("email")
        user_name = payload.get("name")
        google_id = payload.get("google_id")
        if user_email is None:
            raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="Invalid token payload")
    except jwt.ExpiredSignatureError:
        raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="Token expired")
    except jwt.InvalidTokenError:
        raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="Invalid token")

    return {"message": f"Hello, {user_name} ({user_email})! This is Google-protected data.", "google_id": google_id}


# --- Azure AD Protected Endpoint ---
@app.get("/azure-protected-data")
@requires_auth # This decorator from fastapi-microsoft-identity handles token validation
async def get_azure_protected_data(request: Request):
    """
    An example endpoint protected by Azure AD.
    Expects a Bearer token in the Authorization header issued by Azure AD.
    """
    try:
        # Optionally validate specific scopes
        validate_scope(AZURE_SCOPE, request)
        
        # Access token claims after successful validation
        # The claims are available in request.state.user
        claims = request.state.user
        user_name = claims.get("name", "N/A")
        user_email = claims.get("preferred_username", "N/A") # Or 'email'
        tenant_id = claims.get("tid", "N/A")

        return {
            "message": f"Hello, {user_name} ({user_email})! This is Azure AD-protected data.",
            "tenant_id": tenant_id,
            "claims": claims # For debugging, shows all claims
        }
    except AuthError as e:
        # fastapi-microsoft-identity raises AuthError for auth/authz issues
        raise HTTPException(
            status_code=e.status_code,
            detail=e.detail,
            headers={"WWW-Authenticate": "Bearer"}
        )
    except Exception as e:
        raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=str(e))

@app.get("/", response_class=HTMLResponse)
async def home():
    return """
    <html>
        <head>
            <title>FastAPI OAuth</title>
        </head>
        <body>
            <h1>Welcome to FastAPI OAuth Demo</h1>
            <p><a href="/auth/google/login">Login with Google</a></p>
            <p>For Azure AD, you'd typically have a client application (e.g., SPA) that acquires the token and sends it to this API.
            <br>
            If you want to test the Azure AD protected endpoint, you can use a tool like Postman or fetch an access token from Azure AD
            and include it in the 'Authorization: Bearer YOUR_AZURE_AD_TOKEN' header when calling '/azure-protected-data'.
            </p>
            <p><a href="/google-protected-data">Access Google Protected Data (after Google login)</a></p>
            <p><a href="/azure-protected-data">Access Azure Protected Data (needs Azure AD Bearer Token)</a></p>
        </body>
    </html>
    """

if __name__ == "__main__":
    import uvicorn
    uvicorn.run(app, host="0.0.0.0", port=8000)

.env file (updated)

GOOGLE_CLIENT_ID="YOUR_GOOGLE_CLIENT_ID"
GOOGLE_CLIENT_SECRET="YOUR_GOOGLE_CLIENT_SECRET"
JWT_SECRET_KEY="a-very-strong-and-random-secret-key-for-your-jwt"
SESSION_SECRET_KEY="another-long-random-string-for-session-middleware"

AZURE_TENANT_ID="YOUR_AZURE_TENANT_ID" # e.g., common or your tenant GUID
AZURE_CLIENT_ID="YOUR_AZURE_API_APP_ID" # Application (client) ID of your API app registration
AZURE_SCOPE="api://YOUR_AZURE_API_APP_ID/access_as_user" # The scope you defined in "Expose an API"

How to run (Azure AD):

  1. Make sure your .env file has the correct AZURE_TENANT_ID, AZURE_CLIENT_ID, and AZURE_SCOPE. Replace YOUR_AZURE_API_APP_ID with the actual Application (client) ID of your API app registration.

  2. Run the FastAPI app: uvicorn main:app --reload

  3. To test the Azure AD protected endpoint (/azure-protected-data):

    • Unlike Google where FastAPI initiates the login, for Azure AD token validation, your FastAPI app is the Resource Server. This means a client application needs to obtain an access token from Azure AD first and then send it to your FastAPI API.

    • Method 1: Using Postman/Insomnia/curl:

      • You'll need to manually get an access token from Azure AD. This typically involves setting up an client application (e.g., a simple SPA or a Postman setup) that performs the Azure AD login.

      • Once you have an Azure AD access token, send a request to http://localhost:8000/azure-protected-data with the Authorization header: Bearer YOUR_AZURE_AD_ACCESS_TOKEN.

    • Method 2 (For testing with Swagger UI):

      • If you registered a separate Azure AD application for your OpenAPI (Swagger) documentation and configured its redirect URI to http://localhost:8000/oauth2-redirect, then you can use the "Authorize" button in the Swagger UI (/docs).

      • You'll need to configure the security_schemes in FastAPI's OpenAPI object for this to work seamlessly in docs. This is more advanced setup and often involves fastapi-azure-auth for a comprehensive solution.

    Example of manual token acquisition for testing (simplified, often done by a frontend):

    If you were to acquire a token using a client application (e.g., a simple SPA or even a browser redirect for testing), the flow would be:

    • User clicks "Login with Azure AD" (on a frontend app).

    • Frontend redirects to Azure AD's authorization endpoint.

      https://login.microsoftonline.com/{TENANT_ID}/oauth2/v2.0/authorize?client_id={CLIENT_ID_OF_FRONTEND}&response_type=code&redirect_uri={REDIRECT_URI_OF_FRONTEND}&scope=openid profile {AZURE_SCOPE}

    • User logs in and consents.

    • Azure AD redirects back to REDIRECT_URI_OF_FRONTEND with an authorization_code.

    • Frontend exchanges this code for an access_token and id_token at Azure AD's token endpoint.

    • Frontend then calls your FastAPI API, attaching the access_token in the Authorization: Bearer header.

This setup provides a foundational understanding of how to integrate these authentication protocols. For production environments, consider:

  • Error Handling and Logging: More robust error handling and comprehensive logging.

  • Refresh Tokens: For long-lived sessions with Google and Azure AD.

  • Database Integration: Storing user information, linking Google/Azure IDs to your internal user IDs.

  • Role-Based Access Control (RBAC): Using roles/groups from ID tokens to control access to specific API endpoints beyond just authentication.

  • Custom Dependencies: Creating FastAPI dependencies to extract and validate user information from claims more cleanly.

  • CORS: If your frontend is on a different origin, you'll need CORS middleware.

@FastAPI @oauth_2 #authentication @Google @Azure demo code for you.

https://github.com/dhirajpatra/fastapi-authentication-demo

House Based Manufacturing Micro Clustering

                                 image generated by meta ai House-based manufacturing micro-clustering in China refers to the hyper-local, v...