Skip to content

Security Architecture

Last Updated: 2025-10-25
Architecture: 4-Layer Deployment (Foundation → Substrate → AI Models → Apps)
Identity: Single User-Assigned Managed Identity (ADR-047)
Deployment: Azure Container Instances with VNet integration (ADR-049)
Access: Azure Bastion for secure browser-based remote access (ADR-050)

Overview

The Loan Defenders platform implements a defense-in-depth security strategy aligned with the Azure Well-Architected Framework's Security pillar. This document provides a comprehensive reference for all security controls, identity management, RBAC permissions, and access patterns across the 4-layer deployment architecture.

Security Principles

1. Single Managed Identity (ADR-047)

  • ONE user-assigned managed identity used across all layers
  • Assigned to all containers for unified authentication
  • Simplifies RBAC management and eliminates timing issues
  • No service principals, API keys, or passwords anywhere

2. Defense in Depth

  • Multiple layers of security controls
  • Network isolation with Azure VNet and NSGs
  • Private endpoints for all PaaS services
  • Application-level authentication via managed identity
  • Data encryption in transit (TLS 1.2+) and at rest

3. Zero Trust Architecture

  • Verify explicitly with managed identities and RBAC
  • Assume breach with network segmentation
  • Least privileged access - each resource gets only needed roles
  • Azure Bastion for secure human access (no VPN client required)

4. RBAC Over Access Keys (ADR-047)

  • No admin user accounts or access keys enabled
  • All authentication via Azure RBAC built-in roles
  • Resource-level scope (never subscription-level)
  • Automatic credential rotation by Azure platform

Identity Architecture

Single Managed Identity Strategy (ADR-047)

The platform uses ONE user-assigned managed identity shared across all containers:

Managed Identity: {deploymentPrefix}-{environment}-identity
├── Created in: Foundation Layer (security.bicep)
├── Used by: All containers in Apps Layer (API, UI, 3× MCP servers)
├── Permissions Granted:
│   ├── ACR: AcrPull
│   ├── Storage: Storage Blob Data Contributor
│   ├── Key Vault: Key Vault Secrets Officer + Reader
│   ├── AI Services: Azure AI User + Cognitive Services User
│   ├── AI Foundry Hub: Azure AI Administrator
│   ├── AI Foundry Project: Azure AI Administrator
│   └── AI Search (optional): Search Index Data Contributor + Search Service Contributor
└── Eliminates:
    ❌ Service principals
    ❌ API keys or connection strings
    ❌ Admin user accounts
    ❌ RBAC timing issues

Why ONE User-Assigned Identity?

Per Azure Well-Architected Framework and ADR-047:

Unified permissions: All containers need same Azure resource access
Pre-authorization: RBAC assigned before containers start (no timing issues)
Simplified management: 1 identity with 8 role assignments vs 5 identities with 40 assignments
Better audit trail: Single identity for all application operations
Faster deployments: No RBAC propagation delays

Result: - Before: Multiple system-assigned identities + complex RBAC + timing issues - After: 1 user-assigned identity + clean RBAC + zero timing issues

RBAC (Role-Based Access Control)

Overview

RBAC permissions are distributed across deployment layers using a module ownership pattern - each Bicep module assigns roles for the resources it creates. This keeps security controls co-located with resource definitions.

Layer-by-Layer RBAC Breakdown

Foundation Layer (foundation.bicep)

Module: security.bicep - Identity, Storage, Key Vault
File: infrastructure/bicep/modules/security.bicep

Resources Created: - User-Assigned Managed Identity - Storage Account (with private endpoints) - Key Vault (for deployment outputs per ADR-048)

RBAC Assignments:

From Identity To Resource Role Purpose
Managed Identity Storage Account Storage Blob Data Contributor Store application data, documents, audit logs
Managed Identity Key Vault Key Vault Secrets Officer Full secret management
Managed Identity Key Vault Key Vault Reader List vaults and metadata
Current User/SP Key Vault Key Vault Secrets Officer Store deployment outputs (ADR-048)

Module: bastion-vm.bicep - Secure Remote Access
File: infrastructure/bicep/modules/bastion-vm.bicep

Resources Created: - Azure Bastion (browser-based RDP/SSH) - Windows Jump Box VM

RBAC Assignments: - ⚠️ None - VM has no managed identity by design - Jump box is for human interactive access - Users authenticate with their own Azure AD credentials - See "Human Access" section below for details


Substrate Layer (substrate.bicep)

Module: container-registry.bicep - Container Image Storage
File: infrastructure/bicep/modules/container-registry.bicep

Resources Created: - Azure Container Registry (ACR)

RBAC Assignments:

From Identity To Resource Role Purpose
Managed Identity ACR AcrPull Pull container images

Module: ai-services.bicep - AI Infrastructure
File: infrastructure/bicep/modules/ai-services.bicep

Resources Created: - Azure AI Services (multi-service Cognitive Services) - Azure AI Foundry Hub (with system-assigned identity) - Azure AI Foundry Project (with system-assigned identity) - Azure AI Search (optional, with system-assigned identity) - Log Analytics + Application Insights

RBAC Assignments - Managed Identity Access:

From Identity To Resource Role Purpose
Managed Identity AI Services Azure AI User Call OpenAI models
Managed Identity AI Services Cognitive Services User General AI services access
Managed Identity AI Foundry Hub Azure AI Administrator Manage AI Foundry Hub
Managed Identity AI Foundry Project Azure AI Administrator Manage AI Foundry Project
Managed Identity AI Search* Search Index Data Contributor Query search indexes
Managed Identity AI Search* Search Service Contributor Manage search service

*If deployAISearch = true

RBAC Assignments - AI Foundry Hub System Identity:

From Identity To Resource Role Purpose
AI Hub Identity AI Services Cognitive Services Contributor Model management
AI Hub Identity Storage Account Storage Blob Data Contributor Store artifacts
AI Hub Identity AI Search* Search Service Contributor Manage indexes
AI Hub Identity AI Search* Search Index Data Contributor Index data access

RBAC Assignments - AI Foundry Project System Identity:

From Identity To Resource Role Purpose
AI Project Identity AI Services Cognitive Services OpenAI Contributor Deploy models
AI Project Identity Storage Account Storage Blob Data Contributor Store model files
AI Project Identity AI Search* Search Index Data Contributor RAG scenarios

RBAC Assignments - Developer Users (optional via developerPrincipalIds array):

From Identity To Resource Role Purpose
Developer Users AI Foundry Hub Azure AI Developer AI Foundry portal access
Developer Users AI Foundry Project Azure AI Developer AI Foundry portal access

Apps Layer (apps.bicep)

Module: container-group-aci.bicep - Application Containers
File: infrastructure/bicep/modules/container-group-aci.bicep

Resources Created: - Azure Container Instances (ACI) container group containing: - API container - UI container - 3× MCP server containers

RBAC Assignments: - ✅ None needed - Containers use the managed identity created in Foundation layer - Container group configured with user-assigned managed identity - Inherits ALL permissions granted to the managed identity

Container Authentication Pattern:

# Containers automatically use assigned managed identity
from azure.identity import ManagedIdentityCredential
from azure.ai.inference import ChatCompletionsClient

credential = ManagedIdentityCredential()
client = ChatCompletionsClient(
    endpoint=os.environ["AZURE_AI_PROJECT_ENDPOINT"],
    credential=credential  # Uses container's managed identity
)


Complete RBAC Summary Table

Resource Identity Type Role Module Layer
Storage Account User-Assigned Managed Identity Storage Blob Data Contributor security.bicep Foundation
Key Vault User-Assigned Managed Identity Key Vault Secrets Officer + Reader security.bicep Foundation
Key Vault Current User/SP Key Vault Secrets Officer security.bicep Foundation
ACR User-Assigned Managed Identity AcrPull container-registry.bicep Substrate
AI Services User-Assigned Managed Identity Azure AI User + User ai-services.bicep Substrate
AI Foundry Hub User-Assigned Managed Identity Azure AI Administrator ai-services.bicep Substrate
AI Foundry Project User-Assigned Managed Identity Azure AI Administrator ai-services.bicep Substrate
AI Search (optional) User-Assigned Managed Identity Search Index/Service Contributor ai-services.bicep Substrate
AI Services AI Hub System Identity Cognitive Services Contributor ai-services.bicep Substrate
Storage AI Hub System Identity Storage Blob Data Contributor ai-services.bicep Substrate
AI Search (optional) AI Hub System Identity Search Service/Data Contributor ai-services.bicep Substrate
AI Services AI Project System Identity Cognitive Services OpenAI Contributor ai-services.bicep Substrate
Storage AI Project System Identity Storage Blob Data Contributor ai-services.bicep Substrate
AI Search (optional) AI Project System Identity Search Index Data Contributor ai-services.bicep Substrate
AI Hub Developer Users (optional) Azure AI Developer ai-services.bicep Substrate
AI Project Developer Users (optional) Azure AI Developer ai-services.bicep Substrate
ACI Containers User-Assigned Managed Identity (Inherits all above) container-group-aci.bicep Apps

Azure Built-in Roles Reference

All roles are Azure built-in roles maintained by Microsoft:

Role Name Permission Level
AcrPull Pull container images
Azure AI User Call OpenAI models (inference only)
Cognitive Services User General AI services access
Cognitive Services Contributor Manage AI resources
Cognitive Services OpenAI Contributor Deploy OpenAI models
Storage Blob Data Contributor Read/write/delete blobs
Key Vault Secrets Officer Manage secrets
Key Vault Reader List vaults and metadata
Azure AI Administrator Manage AI Foundry resources
Azure AI Developer Access AI Foundry portal
Search Service Contributor Manage search service
Search Index Data Contributor Read/write search data

Permission Scope Strategy

✅ All RBAC assignments use resource-level scope (not subscription-level):

// ✅ GOOD: Scoped to specific resource
resource roleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = {
  name: guid(resourceId, principalId, roleId)
  scope: specificResource  // ← Resource-level scope
  properties: {
    principalId: managedIdentity.properties.principalId
    principalType: 'ServicePrincipal'
    roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleId)
  }
}

// ❌ BAD: Subscription-level scope
resource badAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = {
  scope: subscription()  // ← Too broad! Avoid this!
}

Benefits: - Least privilege principle enforced - Blast radius limited to specific resources - Easier security audits and compliance - Follows Azure Well-Architected Framework guidance

Network Security

VNet Architecture

{deploymentPrefix}-{environment}-vnet (10.0.0.0/16)
├── compute-subnet (10.0.0.0/23)
│   ├── ACI Container Group (VNet-integrated per ADR-049)
│   │   ├── API Container (port 8000)
│   │   ├── UI Container (port 3000)
│   │   ├── MCP Application Verification (port 8010)
│   │   ├── MCP Document Processing (port 8011)
│   │   └── MCP Financial Calculations (port 8012)
│   └── Jump Box VM (for Bastion access)
├── data-subnet (10.0.3.0/24)
│   ├── AI Services Private Endpoint
│   ├── AI Foundry Hub Private Endpoint
│   ├── Storage Account Private Endpoints (blob + file)
│   └── Key Vault Private Endpoint (future)
├── apim-subnet (10.0.2.0/24)
│   └── (Reserved for future API Management)
└── AzureBastionSubnet (10.0.4.0/26)
    └── Azure Bastion (browser-based RDP/SSH)

Subnet Delegation

Compute Subnet: - Delegated to: Microsoft.ContainerInstance/containerGroups (ADR-049) - Purpose: Enables ACI VNet integration - Service endpoints: Storage, Key Vault, Cognitive Services

Network Security Groups (NSGs)

Compute Subnet NSG: - Inbound: - Internal VNet traffic allowed (10.0.0.0/16) - External access blocked (containers are private) - Outbound: - Azure services via service endpoints - Internet access for package updates (optional)

Data Subnet NSG (Private Endpoints): - Inbound: - Traffic from compute subnet only - Outbound: - Restricted to Azure backbone

APIM Subnet NSG (Reserved): - Configured when API Management is deployed

Bastion Subnet NSG: - Managed by Azure (required NSG rules auto-configured) - Allows inbound HTTPS (443) for Bastion access - Allows outbound RDP/SSH to VNet resources

Private Endpoints & DNS

Private DNS Zones (auto-configured): - privatelink.services.ai.azure.com (AI Foundry Hub) - privatelink.cognitiveservices.azure.com (AI Services) - privatelink.openai.azure.com (OpenAI API) - privatelink.api.azureml.ms (AI Foundry management API) - privatelink.notebooks.azure.net (AI Foundry UI) - privatelink.blob.core.windows.net (Storage blob) - privatelink.file.core.windows.net (Storage file)

Resolution: - VNet-linked DNS zones resolve private endpoints - Containers access Azure services via private IPs - No internet egress for PaaS service access

Container Network Access

ACI Container Group (ADR-049):

ipAddress: {
  type: 'Private'  // ✅ No public IP - VNet-only access
  ports: [
    { port: 8000, protocol: 'TCP' }  // API
    { port: 3000, protocol: 'TCP' }  // UI
    { port: 8010, protocol: 'TCP' }  // MCP App Verification
    { port: 8011, protocol: 'TCP' }  // MCP Document Processing
    { port: 8012, protocol: 'TCP' }  // MCP Financial Calculations
  ]
}

Access Patterns: - ✅ Containers → Azure Services: Via private endpoints (no internet) - ✅ Jump Box → Containers: Direct access via private IPs - ✅ Container-to-Container: Localhost (same container group) - ❌ Internet → Containers: Blocked (no public ingress)

Human Access Security

Azure Bastion + Jump Box (ADR-050)

Replaces VPN Gateway for $150/month savings and simpler developer experience.

Architecture:

Developer's Browser
    ↓ HTTPS (443)
Azure Bastion (managed PaaS)
    ↓ RDP/SSH via Private IP
Windows Jump Box VM (in compute-subnet)
    ↓ Private VNet access
Azure Resources (AI Foundry portal, containers, databases)

Jump Box Configuration: - OS: Windows Server 2022 Datacenter Azure Edition - Size: Standard_D2s_v3 (2 vCPU, 8GB RAM) - Network: Private IP in compute-subnet - Identity: ⚠️ None (by design - users authenticate as themselves) - Authentication: Azure AD credentials (no local accounts)

Why Jump Box Has NO Managed Identity

Design Decision (ADR-050): - Jump boxes are for interactive human access, not automation - Users should authenticate with their personal Azure AD credentials - Better audit trail (tracks individual user actions) - No risk of shared VM identity with excessive permissions

AI Foundry Portal Access from Jump Box

Prerequisites: 1. User must be in developerPrincipalIds array (Substrate deployment parameter) 2. User gets Azure AI Developer role on AI Foundry Hub/Project

Access Flow: 1. Navigate to Azure Portal → VM → Connect → Bastion 2. Enter Azure AD credentials (RDP into VM via browser) 3. Inside VM: Open browser (Edge/Chrome) 4. Navigate to https://ai.azure.com 5. Login with Azure AD credentials 6. Portal authenticates as the user (not the VM) 7. User sees AI Foundry resources based on their RBAC roles

What Works: - ✅ AI Foundry portal access (ai.azure.com) - ✅ Azure Portal access - ✅ Interactive Azure CLI (az login with user credentials) - ✅ Visual Studio Code with Azure extensions - ✅ Access to container private IPs for testing

What Doesn't Work (and why it's okay): - ❌ az login --identity (VM has no managed identity) - ❌ Automated scripts using VM identity (use GitHub Actions instead) - ❌ DefaultAzureCredential without user login (intentional security control)

Developer RBAC Requirements

To access AI Foundry portal from Jump Box or any machine:

# Find your Azure AD principal ID
az ad signed-in-user show --query id -o tsv

# Add to substrate deployment parameters
# File: infrastructure/bicep/environments/dev-substrate.parameters.json
{
  "developerPrincipalIds": {
    "value": [
      "your-azure-ad-principal-id-guid"
    ]
  }
}

This grants: - Azure AI Developer role on AI Foundry Hub - Azure AI Developer role on AI Foundry Project - Full portal access to manage models and deployments

Bastion Security Features

Advantages over VPN: - ✅ No client-side VPN software required - ✅ Browser-based access (works on any device) - ✅ No VPN Gateway maintenance ($150/month saved) - ✅ Azure-managed security updates - ✅ Multi-factor authentication via Azure AD - ✅ Session recording (optional for compliance)

Security Controls: - Bastion managed by Azure (auto-patched) - Public IP for Bastion only (not VMs) - RDP/SSH traffic stays on Azure backbone - No direct VM public IPs - Integration with Azure AD Conditional Access

Data Protection

Encryption in Transit

External Communication: - Azure Bastion: HTTPS/TLS 1.3 (443)

Azure Service Communication: - AI Services API: HTTPS over private endpoint - Storage Account: HTTPS over private endpoint - Key Vault: HTTPS over private endpoint - ACR: HTTPS with managed identity auth

Internal VNet Communication: - Container-to-container: HTTP over localhost (same pod) - Jump Box to containers: HTTP over private VNet (isolated network) - Rationale: TLS overhead unnecessary within isolated VNet

Encryption at Rest

All Azure PaaS services use encryption at rest by default:

Service Encryption Key Management
Storage Account AES-256 Microsoft-managed keys
ACR (images) AES-256 Microsoft-managed keys
AI Services AES-256 Microsoft-managed keys
AI Foundry AES-256 Microsoft-managed keys
Key Vault FIPS 140-2 Level 2 Azure Key Vault HSM
VM OS Disk AES-256 Microsoft-managed keys

Sensitive Data Handling

PII Protection Rules:

✅ DO:
- Use applicant_id (UUID) in all MCP tool calls
- Encrypt loan application documents in storage
- Log access events without PII values
- Use private endpoints for all data transmission

❌ DON'T:
- Pass SSN to MCP servers (use applicant_id instead)
- Log full loan application JSON with PII
- Store plaintext sensitive data in environment variables
- Transmit PII over public internet

SSN Handling Example:

# ✅ CORRECT: Use UUID for tool calls
mcp_tool.verify_credit(applicant_id="550e8400-e29b-41d4-a716-446655440000")

# ❌ WRONG: Never pass SSN to tools
mcp_tool.verify_credit(ssn="123-45-6789")  # DON'T DO THIS!

Audit Trail: - Application Insights logs all requests (without PII) - Storage access logs enabled (who/when, not what) - AI model calls logged (prompts redacted if containing PII) - Agent decisions logged with reasoning (for fair lending compliance)

Application Security

Container Security

Base Images: - Official Python 3.11+ images from Docker Hub - Regular security updates via automated builds - Minimal attack surface (no unnecessary packages)

Runtime Security:

# ✅ Run as non-root user
USER appuser

# ✅ Resource limits enforced by ACI
resources:
  requests:
    cpu: 1
    memoryInGB: 2
  limits:
    cpu: 2
    memoryInGB: 4

Image Pull Security (ADR-047): - ✅ Managed identity for ACR authentication - ✅ No registry credentials in config - ✅ Private ACR (publicNetworkAccess: Disabled for production) - ✅ AcrPull role scoped to specific registry

API Security

Authentication: - ✅ Service-to-Service: Managed identity with RBAC - ✅ Internal APIs: Network isolation (VNet-only access)

Authorization: - ✅ Network-level isolation (containers in private subnet) - ✅ RBAC for Azure resource access

Secrets Management

Current State: - ✅ NO secrets in environment variables - ✅ NO connection strings (managed identity for everything) - ✅ NO API keys (RBAC-based authentication) - ✅ Deployment outputs stored in Key Vault (ADR-048)

Key Vault Integration (when needed):

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

credential = ManagedIdentityCredential()
client = SecretClient(
    vault_url=os.environ["KEY_VAULT_URI"],
    credential=credential
)

# Retrieve secrets at runtime (never in env vars)
secret = client.get_secret("third-party-api-key")

Dependency Security

Supply Chain Security: - uv.lock for Python dependency pinning - package-lock.json for Node.js dependency pinning - Automated Dependabot alerts via GitHub

Validation:

# Check for known vulnerabilities
uv pip check
npm audit

# Update dependencies
uv pip install --upgrade
npm update

Security Monitoring & Auditing

Current Monitoring (Implemented)

Application Insights: - ✅ Request tracking and performance monitoring - ✅ Error logging and exception tracking - ✅ Dependency call tracing (AI Services, Storage) - ✅ Custom event logging for loan processing workflow

Azure Monitor Logs: - ✅ Resource activity logs (RBAC changes, network events) - ✅ Storage access logs (blob operations) - ✅ AI Services request logs (model calls, token usage)

Log Analytics Workspace: - ✅ Centralized log aggregation - ✅ 30-day retention (configurable) - ✅ Kusto queries for security investigation

Audit Trail Requirements

For Fair Lending Compliance:

Tracked Events:
├── Loan application submission
├── Agent assessment decisions
│   ├── Credit agent reasoning
│   ├── Income agent verification
│   └── Risk agent final decision
├── LoanDecision with audit trail
├── Model deployment changes
└── RBAC permission modifications

NOT Logged (PII Protection):
├── Full SSN values
├── Bank account numbers
└── Detailed financial documents

Audit Log Format:

{
  "timestamp": "2025-10-25T14:17:00Z",
  "event": "loan_application_processed",
  "application_id": "550e8400-e29b-41d4-a716-446655440000",
  "decision": "approved",
  "agents": ["intake", "credit", "income", "risk"],
  "reasoning": "Strong credit profile, stable income, low DTI",
  "model_version": "gpt-4o-2024-11-20",
  "user_identity": "loan-officers-managed-identity",
  "compliance_flags": []
}

Security Alerts

Azure Monitor Alerts (configured as needed): - Unauthorized ACR access attempts - Excessive failed AI Service calls - Storage account access anomalies - RBAC permission changes - Key Vault secret access spikes - Container restart failures

Microsoft Defender for Cloud (enabled per compliance requirements): - Container vulnerability alerts - Storage threat detection - Network anomaly detection - Security recommendations

Kusto Query Examples

Find all loan decisions for regulatory review:

traces
| where customDimensions.event == "loan_decision_final"
| where timestamp > ago(90d)
| project timestamp, application_id, decision, reasoning
| order by timestamp desc

Detect suspicious RBAC changes:

AzureActivity
| where OperationNameValue contains "roleAssignments/write"
| where ActivityStatusValue != "Success"
| project TimeGenerated, Caller, ResourceId, ActivityStatusValue

Monitor AI Service usage:

dependencies
| where target contains "openai.azure.com"
| summarize TotalCalls=count(), AvgDuration=avg(duration) by bin(timestamp, 1h)
| render timechart

Security Testing & Validation

Pre-Deployment Validation

Bicep Linting:

# Security misconfigurations check
az bicep lint --file infrastructure/bicep/foundation.bicep
az bicep lint --file infrastructure/bicep/substrate.bicep
az bicep lint --file infrastructure/bicep/apps.bicep

# Check for security warnings
grep -i "security\|rbac\|identity" bicep-lint-output.txt

RBAC Validation:

# Verify no subscription-level role assignments
az role assignment list --scope /subscriptions/<sub-id> --query "[?scope == '/subscriptions/<sub-id>']"

# Verify resource-level scoping
az role assignment list -g <rg-name> --query "[].{Principal:principalName, Role:roleDefinitionName, Scope:scope}"

Post-Deployment Security Checks

Identity Verification:

# Verify managed identity created
az identity show -n <identity-name> -g <rg-name> -o table

# Check identity assignments on containers
az container show -n <container-group-name> -g <rg-name> --query "identity"

RBAC Verification:

# List all RBAC assignments in resource group
az role assignment list -g <rg-name> -o table

# Verify specific role assignment
az role assignment list \
  --assignee <identity-principal-id> \
  --scope <resource-id> \
  --query "[].roleDefinitionName"

Network Security Checks:

# Verify private endpoints created
az network private-endpoint list -g <rg-name> -o table

# Check NSG rules
az network nsg rule list -g <rg-name> --nsg-name <nsg-name> -o table

# Verify ACR public access disabled (production)
az acr show -n <acr-name> --query "publicNetworkAccess" -o tsv
# Should return: Disabled

Container Security:

# Verify containers using managed identity
az container show -n <container-group-name> -g <rg-name> \
  --query "identity.type" -o tsv
# Should return: UserAssigned

# Check no public IP assigned
az container show -n <container-group-name> -g <rg-name> \
  --query "ipAddress.type" -o tsv
# Should return: Private

Automated Security Validation Script

File: scripts/validate-security.sh (to be created)

#!/bin/bash
# Security validation checklist

echo "=== Security Validation ==="

# 1. Verify managed identity
echo "✓ Checking managed identity..."
az identity show -n $IDENTITY_NAME -g $RG_NAME > /dev/null
if [ $? -eq 0 ]; then
  echo "  ✅ Managed identity exists"
else
  echo "  ❌ Managed identity missing"
  exit 1
fi

# 2. Verify RBAC assignments
echo "✓ Checking RBAC assignments..."
ROLE_COUNT=$(az role assignment list -g $RG_NAME --query "length([])")
if [ $ROLE_COUNT -gt 0 ]; then
  echo "  ✅ RBAC assignments configured ($ROLE_COUNT roles)"
else
  echo "  ❌ No RBAC assignments found"
  exit 1
fi

# 3. Verify private endpoints
echo "✓ Checking private endpoints..."
PE_COUNT=$(az network private-endpoint list -g $RG_NAME --query "length([])")
if [ $PE_COUNT -gt 0 ]; then
  echo "  ✅ Private endpoints configured ($PE_COUNT endpoints)"
else
  echo "  ⚠️ No private endpoints found"
fi

# 4. Verify container security
echo "✓ Checking container security..."
IP_TYPE=$(az container show -n $CONTAINER_GROUP -g $RG_NAME --query "ipAddress.type" -o tsv)
if [ "$IP_TYPE" == "Private" ]; then
  echo "  ✅ Containers use private IP"
else
  echo "  ❌ Containers exposed publicly"
  exit 1
fi

echo "=== All security checks passed ==="

Incident Response

Standard incident response procedures follow Azure security best practices:

  1. Detection: Azure Monitor alerts + Application Insights anomaly detection
  2. Isolation: Disable compromised identity via Azure Portal or Azure CLI
  3. Investigation: Review audit logs in Log Analytics, trace request flows
  4. Remediation: Rotate credentials (automatic for managed identities), patch vulnerabilities
  5. Post-mortem: Update security controls, document learnings in ADRs

Key Contacts: - Azure Support: Via Azure Portal (support.azure.com) - Security Team: Defined per organization

Compliance and Regulations

Fair Lending Compliance

ECOA (Equal Credit Opportunity Act): - ✅ Complete audit trails for all loan decisions - ✅ Agent reasoning stored in LoanDecision model - ✅ No discriminatory data (race, religion) in processing - ✅ Explainable AI with transparent decision logic

FCRA (Fair Credit Reporting Act): - ✅ Credit report access logged with applicant_id - ✅ Adverse action notices trackable - ✅ Consumer dispute handling via audit trail - ✅ Credit data retention policy (7 years)

GLBA (Gramm-Leach-Bliley Act): - ✅ PII encryption in transit (TLS 1.2+) and at rest (AES-256) - ✅ Access controls via RBAC (least privilege) - ✅ Audit logging for all data access

Data Retention Policies

Data Type Retention Period Storage Location Encryption
Loan Applications 7 years Azure Storage (blob) AES-256
Audit Logs 7 years Log Analytics Microsoft-managed
AI Model Decisions 7 years Storage (JSON) AES-256
AI Model Versions Indefinite AI Foundry AES-256
Container Logs 30 days Application Insights Microsoft-managed
RBAC Changes 90 days Azure Activity Log Microsoft-managed

Security Compliance Matrix

Control Requirement Implementation Status
Identity Management Managed identities only User-assigned managed identity ✅ Implemented
Access Control RBAC with least privilege Resource-level RBAC ✅ Implemented
Network Security Private network isolation VNet + Private Endpoints ✅ Implemented
Data Encryption TLS 1.2+ in transit HTTPS/TLS 1.3 ✅ Implemented
Data Encryption AES-256 at rest Azure platform default ✅ Implemented
Audit Logging All access tracked Application Insights + Azure Monitor ✅ Implemented
Secret Management No plaintext secrets Managed identity + Key Vault ✅ Implemented
PII Protection SSN never in logs applicant_id UUID pattern ✅ Implemented

Future Security Enhancements

Authentication & Authorization

  • Azure AD B2C for end-user authentication
  • API-level RBAC (role-based loan officer permissions)
  • Customer-managed encryption keys (CMK)

Network & Infrastructure

  • Azure Application Gateway or API Management for public ingress
  • Web Application Firewall (WAF)
  • Azure Front Door with DDoS protection
  • Azure Sentinel for SIEM

Monitoring & Threat Detection

  • Microsoft Defender for Containers (vulnerability scanning)
  • Automated security alerts (ACR access, RBAC changes, anomalies)
  • Third-party penetration testing (annual)
  • OWASP Top 10 validation

Compliance & Auditing

  • Customer privacy notices (GLBA)
  • Just-in-time (JIT) VM access
  • Bastion session recording
  • Automated compliance reporting

References

Architecture Decision Records (ADRs)

Microsoft Documentation


Last Updated: 2025-10-25
Review Cycle: Quarterly
Maintained By: Infrastructure Team + Security Team