A sleek, production-ready FastAPI web application for uploading photos to Azure Blob Storage with enterprise-grade security using Azure RBAC (Role-Based Access Control) and managed identity.
- Sleek FastAPI Application - Modern, responsive web interface
- Drag & Drop Upload - Intuitive file upload with drag-and-drop support
- Real-time Progress - Visual upload progress and feedback
- Photo Gallery - Browse and manage uploaded photos
- Responsive Design - Works perfectly on desktop and mobile devices
This solution implements zero-trust security principles and Azure security best practices:
- ✅ Azure Managed Identity - No hardcoded keys or secrets
- ✅ Azure RBAC - Fine-grained access control using built-in roles
- ✅ Principle of Least Privilege - Minimal required permissions only
- ✅ Identity-based Authentication - Shared key access disabled
- ✅ HTTPS Only - All communications encrypted in transit (TLS 1.2+)
- ✅ Encryption at Rest - Server-side encryption with infrastructure encryption
- ✅ Private Container Access - No anonymous access allowed
- ✅ Blob Versioning - Data protection and recovery capabilities
- ✅ Configurable Network Access - Can be restricted to private endpoints
- ✅ IP Whitelisting Support - Network-level access controls
- ✅ Azure Services Bypass - Secure access for trusted Azure services
- ✅ Audit Trail - Comprehensive logging and monitoring
- ✅ Retention Policies - Automated data lifecycle management
- ✅ Change Feed - Track all blob modifications
- ✅ Soft Delete - Protection against accidental deletion
┌─────────────────┐ ┌──────────────────────┐ ┌─────────────────────┐
│ FastAPI App │ │ User-Assigned │ │ Azure Storage │
│ │───▶│ Managed Identity │───▶│ Account │
│ • Web Interface │ │ │ │ • RBAC Enabled │
│ • File Upload │ │ • No Secrets │ │ • Private Access │
│ • Photo Gallery │ │ • RBAC Permissions │ │ • Encrypted │
│ • REST API │ │ │ │ │
└─────────────────┘ └──────────────────────┘ └─────────────────────┘
│
▼
┌─────────────────┐ ┌──────────────────────┐
│ Container Apps │ │ Container Registry │
│ │───▶│ │
│ • Auto Scaling │ │ • Managed Identity │
│ • HTTPS Only │ │ • Secure Images │
│ • Health Checks │ │ │
└─────────────────┘ └──────────────────────┘
- Azure CLI installed and authenticated
- Azure Developer CLI (
azd) installed - Python 3.8+ installed
- Appropriate Azure permissions to create resources
# Initialize the project
azd init
# Set your environment variables
azd env set AZURE_LOCATION "eastus"
azd env set AZURE_ENV_NAME "photo-secure"
# Deploy to Azure
azd upFor local development:
# Run the development script (handles everything automatically)
.\run.ps1Or manually:
# Create virtual environment
python -m venv .venv
.venv\Scripts\Activate.ps1 # On Windows PowerShell
# Install dependencies
pip install -r requirements.txt
# Copy environment template and update with your values
copy .env.example .env
# Edit .env with your Azure configuration
# Start the FastAPI application
cd src
python start.pyThe web application will be available at:
- Main App: http://localhost:8000
- API Docs: http://localhost:8000/api/docs
- Gallery: http://localhost:8000/gallery
# Deploy both infrastructure and application
azd upAfter deployment, your app will be available at the generated Container App URL.
| Variable | Description | Required | Example |
|---|---|---|---|
AZURE_STORAGE_ACCOUNT_NAME |
Storage account name | Yes | st7a8b9c0d1e2f3 |
AZURE_PHOTO_CONTAINER_NAME |
Container name for photos | No | photos (default) |
AZURE_USER_ASSIGNED_IDENTITY_CLIENT_ID |
Managed identity client ID | No* | 12345678-1234-1234-1234-123456789abc |
*Required when using user-assigned managed identity. Falls back to DefaultAzureCredential if not provided.
| Parameter | Description | Default | Options |
|---|---|---|---|
environmentName |
Environment name for resources | - | dev, prod, etc. |
location |
Azure region | - | eastus, westeurope, etc. |
principalId |
User principal ID for RBAC | - | Your Azure AD user ID |
To restrict access to private endpoints only, modify the storage account in infra/main.bicep:
properties: {
publicNetworkAccess: 'Disabled' // Change from 'Enabled'
networkAcls: {
defaultAction: 'Deny' // Change from 'Allow'
// Add your IP ranges or virtual networks
ipRules: [
{
value: 'your.ip.address.range/24'
action: 'Allow'
}
]
}
}The solution uses built-in Azure roles. Available roles:
- Storage Blob Data Reader (
2a2b9908-6ea1-4ae2-8e65-a410df84e7d1) - Read only - Storage Blob Data Contributor (
ba92f5b4-2d11-453d-a403-e96b0029c9fe) - Read/Write (default) - Storage Blob Data Owner (
b7e6dc6d-f1e8-4753-8033-0f276bb0955b) - Full control
Enable Azure Monitor and set up alerts:
# Enable diagnostic settings
az monitor diagnostic-settings create \
--resource $STORAGE_ACCOUNT_ID \
--name "storage-diagnostics" \
--logs '[{"category": "StorageRead", "enabled": true}, {"category": "StorageWrite", "enabled": true}]' \
--workspace $LOG_ANALYTICS_WORKSPACE_IDFor local development, use Azure CLI authentication:
# Login to Azure
az login
# Set subscription (if needed)
az account set --subscription "your-subscription-id"
# Run the application
python src/photo_uploader.pyIn Azure environments (App Service, Container Apps, etc.), managed identity will be used automatically.
- Upload Photos: Open http://localhost:8000 and drag-drop photos or click to select
- Browse Gallery: Visit http://localhost:8000/gallery to see all uploaded photos
- API Access: Use http://localhost:8000/api/docs for API documentation
import httpx
# Upload a photo via API
with open("photo.jpg", "rb") as f:
response = httpx.post(
"http://localhost:8000/upload",
files={"file": f},
data={"album": "vacation", "description": "Beach sunset"}
)
# Get photos list
response = httpx.get("http://localhost:8000/api/photos")
photos = response.json()["photos"]from src.main import SecurePhotoUploader
# Initialize uploader
uploader = SecurePhotoUploader()
# Upload a photo with metadata
result = await uploader.upload_photo(
file=uploaded_file,
blob_name="2024/vacation/beach.jpg",
tags={
"album": "summer_vacation",
"location": "Malibu Beach",
"photographer": "John Doe"
}
)
print(f"Uploaded: {result['blob_url']}")Authentication Errors
ClientAuthenticationError: Authentication failed
- ✅ Verify you're logged into Azure CLI:
az login - ✅ Check your managed identity has the correct RBAC roles
- ✅ Ensure the storage account has shared key access disabled
Permission Errors
Access denied to container 'photos'
- ✅ Verify RBAC role assignments in the Azure portal
- ✅ Check the managed identity is assigned to the storage account
- ✅ Wait a few minutes for role assignments to propagate
Container Not Found
ResourceNotFoundError: Container 'photos' not found
- ✅ Check the container was created during deployment
- ✅ Verify the container name in environment variables
- ✅ Check storage account and container exist in the portal
-
Check Authentication:
az account show # Verify logged in user az identity show --name "id-<your-resource-token>" --resource-group "<your-rg>"
-
Verify RBAC Assignments:
az role assignment list --assignee "<managed-identity-principal-id>" --scope "<storage-account-id>"
-
Test Storage Access:
az storage blob list --container-name "photos" --account-name "<storage-account-name>" --auth-mode login
- Network Isolation: Consider using private endpoints for maximum security
- Key Rotation: While not using keys, rotate managed identity credentials regularly
- Monitoring: Set up alerts for unusual access patterns
- Backup: Implement cross-region replication for critical data
- Compliance: Review data residency and compliance requirements
- Public Data: Use public containers with appropriate access policies
- Confidential Data: Use private containers with strict RBAC
- Highly Sensitive: Consider customer-managed encryption keys (CMEK)
- Azure Storage Security Guide
- Azure RBAC Best Practices
- Managed Identity Documentation
- Azure Blob Storage Pricing
This project is licensed under the MIT License - see the LICENSE file for details.
Contributions are welcome! Please read our contributing guidelines and submit pull requests for any improvements.
⚡ Built with Azure security best practices for production workloads