Azure Storage Security & Guardrails
Azure Storage Security & Guardrails
Section titled “Azure Storage Security & Guardrails”This guide covers essential security configurations, guardrails, and request limiting strategies to protect your Azure Blob Storage and control access to your image assets.
🔐 Security Fundamentals
Section titled “🔐 Security Fundamentals”1.1 Access Control Levels
Section titled “1.1 Access Control Levels”Azure Storage provides multiple layers of access control:
- Account Level: Storage account access keys and SAS
- Container Level: Container permissions and access policies
- Blob Level: Individual blob permissions
- Network Level: Firewall rules and virtual networks
1.2 Authentication Methods
Section titled “1.2 Authentication Methods”- Storage Account Keys (Shared Key)
- Shared Access Signatures (SAS)
- Azure Active Directory (Azure AD)
- Anonymous Public Access (Limited scenarios)
🛡️ Essential Security Configurations
Section titled “🛡️ Essential Security Configurations”2.1 Disable Storage Account Keys (Recommended)
Section titled “2.1 Disable Storage Account Keys (Recommended)”# Disable shared key access for enhanced securityaz storage account update \ --name $STORAGE_ACCOUNT \ --resource-group $RESOURCE_GROUP \ --allow-shared-key-access false
# Enable Azure AD authentication onlyaz storage account update \ --name $STORAGE_ACCOUNT \ --resource-group $RESOURCE_GROUP \ --enable-azure-ad-ds false
2.2 Configure Minimum TLS Version
Section titled “2.2 Configure Minimum TLS Version”# Enforce TLS 1.2 minimumaz storage account update \ --name $STORAGE_ACCOUNT \ --resource-group $RESOURCE_GROUP \ --min-tls-version TLS1_2 \ --https-only true
2.3 Enable Blob Soft Delete
Section titled “2.3 Enable Blob Soft Delete”# Enable soft delete for containers (up to 365 days)az storage account blob-service-properties update \ --account-name $STORAGE_ACCOUNT \ --resource-group $RESOURCE_GROUP \ --enable-container-delete-retention true \ --container-delete-retention-days 7
# Enable soft delete for blobsaz storage account blob-service-properties update \ --account-name $STORAGE_ACCOUNT \ --resource-group $RESOURCE_GROUP \ --enable-delete-retention true \ --delete-retention-days 30
🔒 Shared Access Signatures (SAS) Best Practices
Section titled “🔒 Shared Access Signatures (SAS) Best Practices”3.1 Generate Account-Level SAS with Restrictions
Section titled “3.1 Generate Account-Level SAS with Restrictions”# Generate restrictive account SASaz storage account generate-sas \ --account-name $STORAGE_ACCOUNT \ --account-key $STORAGE_KEY \ --services b \ --resource-types sco \ --permissions r \ --expiry "2024-12-31T23:59:59Z" \ --https-only \ --start "2024-01-01T00:00:00Z"
3.2 Container-Level SAS for Specific Access
Section titled “3.2 Container-Level SAS for Specific Access”# Generate container SAS with read-only accessaz storage container generate-sas \ --account-name $STORAGE_ACCOUNT \ --account-key $STORAGE_KEY \ --name images \ --permissions r \ --expiry "2024-06-30T23:59:59Z" \ --https-only \ --ip "203.0.113.0/24"
3.3 Blob-Level SAS for Individual Files
Section titled “3.3 Blob-Level SAS for Individual Files”# Generate blob-specific SASaz storage blob generate-sas \ --account-name $STORAGE_ACCOUNT \ --account-key $STORAGE_KEY \ --container-name images \ --name "private-document.pdf" \ --permissions r \ --expiry "2024-03-15T23:59:59Z" \ --https-only
🔥 Network Security & Firewall Configuration
Section titled “🔥 Network Security & Firewall Configuration”4.1 Configure Storage Account Firewall
Section titled “4.1 Configure Storage Account Firewall”# Set default action to denyaz storage account update \ --name $STORAGE_ACCOUNT \ --resource-group $RESOURCE_GROUP \ --default-action Deny
# Allow specific IP ranges (your office, CI/CD systems)az storage account network-rule add \ --account-name $STORAGE_ACCOUNT \ --resource-group $RESOURCE_GROUP \ --ip-address "203.0.113.0/24"
# Allow Azure servicesaz storage account update \ --name $STORAGE_ACCOUNT \ --resource-group $RESOURCE_GROUP \ --bypass AzureServices
4.2 Virtual Network Integration
Section titled “4.2 Virtual Network Integration”# Create virtual network and subnetaz network vnet create \ --resource-group $RESOURCE_GROUP \ --name MyVNet \ --address-prefix 10.0.0.0/16 \ --subnet-name MySubnet \ --subnet-prefix 10.0.1.0/24
# Enable service endpoint for storageaz network vnet subnet update \ --resource-group $RESOURCE_GROUP \ --vnet-name MyVNet \ --name MySubnet \ --service-endpoints Microsoft.Storage
# Add VNet rule to storage accountaz storage account network-rule add \ --account-name $STORAGE_ACCOUNT \ --resource-group $RESOURCE_GROUP \ --vnet MyVNet \ --subnet MySubnet
4.3 Private Endpoints (Premium Security)
Section titled “4.3 Private Endpoints (Premium Security)”# Create private endpointaz network private-endpoint create \ --resource-group $RESOURCE_GROUP \ --name storage-private-endpoint \ --vnet-name MyVNet \ --subnet MySubnet \ --private-connection-resource-id "/subscriptions/$SUBSCRIPTION_ID/resourceGroups/$RESOURCE_GROUP/providers/Microsoft.Storage/storageAccounts/$STORAGE_ACCOUNT" \ --group-ids blob \ --connection-name storage-connection
# Create DNS zone for private endpointaz network private-dns zone create \ --resource-group $RESOURCE_GROUP \ --name "privatelink.blob.core.windows.net"
# Link DNS zone to VNetaz network private-dns link vnet create \ --resource-group $RESOURCE_GROUP \ --zone-name "privatelink.blob.core.windows.net" \ --name MyDNSLink \ --virtual-network MyVNet \ --registration-enabled false
⚡ Request Limiting & Rate Limiting
Section titled “⚡ Request Limiting & Rate Limiting”5.1 Storage Account Limits (Built-in)
Section titled “5.1 Storage Account Limits (Built-in)”Azure Storage has built-in limits per account:
- Request rate: Up to 20,000 requests/second for hot storage
- Ingress: Up to 25 Gbps (US regions)
- Egress: Up to 50 Gbps (US regions)
- IOPS: Up to 20,000 (for premium storage)
5.2 Implement Application-Level Rate Limiting
Section titled “5.2 Implement Application-Level Rate Limiting”Node.js with Express Rate Limiting:
const rateLimit = require('express-rate-limit');const { BlobServiceClient } = require('@azure/storage-blob');
// Rate limiting middlewareconst imageRequestLimiter = rateLimit({ windowMs: 15 * 60 * 1000, // 15 minutes max: 100, // Limit each IP to 100 requests per windowMs message: 'Too many image requests from this IP, please try again later.', standardHeaders: true, legacyHeaders: false,});
// Apply rate limiting to image routesapp.use('/api/images', imageRequestLimiter);
// Track and limit per-user requestsconst userRequestTracker = new Map();
app.get('/api/images/:imageName', async (req, res) => { const clientIP = req.ip; const userId = req.headers['x-user-id'] || clientIP;
// Check daily limit per user const today = new Date().toDateString(); const key = `${userId}-${today}`;
if (!userRequestTracker.has(key)) { userRequestTracker.set(key, 0); }
const currentRequests = userRequestTracker.get(key);
if (currentRequests >= 1000) { // Daily limit of 1000 requests per user return res.status(429).json({ error: 'Daily request limit exceeded', limit: 1000, resetTime: new Date(Date.now() + 24 * 60 * 60 * 1000).toISOString() }); }
userRequestTracker.set(key, currentRequests + 1);
try { // Generate SAS token for the image const sasToken = generateImageSAS(req.params.imageName); res.json({ imageUrl: `${baseImageUrl}/${req.params.imageName}?${sasToken}` }); } catch (error) { res.status(500).json({ error: 'Failed to generate image URL' }); }});
5.3 Azure CDN Rate Limiting
Section titled “5.3 Azure CDN Rate Limiting”Configure rate limiting rules in Azure CDN:
# Create CDN profile with rate limiting capabilitiesaz cdn profile create \ --resource-group $RESOURCE_GROUP \ --name cdn-with-rate-limits \ --sku Premium_Verizon # Required for advanced rules
# The rate limiting rules would be configured through Azure Portal# under CDN Profile > Rules Engine
CDN Rate Limiting Rule Example:
{ "name": "RateLimitRule", "order": 1, "conditions": [ { "name": "RequestRate", "parameters": { "requestRate": "100", "duration": "60", "operator": "GreaterThan" } } ], "actions": [ { "name": "CacheExpiration", "parameters": { "cacheBehavior": "Override", "cacheType": "All", "cacheDuration": "00:05:00" } } ]}
📊 Monitoring & Alerting
Section titled “📊 Monitoring & Alerting”6.1 Enable Storage Analytics & Metrics
Section titled “6.1 Enable Storage Analytics & Metrics”# Enable storage analytics loggingaz storage logging update \ --account-name $STORAGE_ACCOUNT \ --account-key $STORAGE_KEY \ --services b \ --log rwd \ --retention 90
# Enable metricsaz storage metrics update \ --account-name $STORAGE_ACCOUNT \ --account-key $STORAGE_KEY \ --services b \ --api true \ --hour true \ --minute false \ --retention 90
6.2 Create Security Alerts
Section titled “6.2 Create Security Alerts”# Create action group for security alertsaz monitor action-group create \ --resource-group $RESOURCE_GROUP \ --name "security-alerts" \ --action email security admin@yourdomain.com \ --action webhook https://your-security-webhook.com/alert
# Alert for unusual access patternsaz monitor metrics alert create \ --name "High Blob Request Rate" \ --resource-group $RESOURCE_GROUP \ --scopes "/subscriptions/$SUBSCRIPTION_ID/resourceGroups/$RESOURCE_GROUP/providers/Microsoft.Storage/storageAccounts/$STORAGE_ACCOUNT" \ --condition "avg Transactions > 10000" \ --action security-alerts \ --description "Alert when blob requests exceed normal patterns"
# Alert for unauthorized access attemptsaz monitor metrics alert create \ --name "Unauthorized Access" \ --resource-group $RESOURCE_GROUP \ --scopes "/subscriptions/$SUBSCRIPTION_ID/resourceGroups/$RESOURCE_GROUP/providers/Microsoft.Storage/storageAccounts/$STORAGE_ACCOUNT" \ --condition "total ClientOtherError > 50" \ --action security-alerts \ --description "Alert on multiple client authentication errors"
💰 Cost Control & Budget Alerts
Section titled “💰 Cost Control & Budget Alerts”7.1 Set Up Cost Alerts
Section titled “7.1 Set Up Cost Alerts”# Create budget for storage accountaz consumption budget create \ --resource-group $RESOURCE_GROUP \ --budget-name "storage-monthly-budget" \ --amount 100 \ --time-grain Monthly \ --start-date "2024-01-01" \ --notifications '[ { "enabled": true, "operator": "GreaterThan", "threshold": 80, "contactEmails": ["admin@yourdomain.com"] }, { "enabled": true, "operator": "GreaterThan", "threshold": 100, "contactEmails": ["admin@yourdomain.com"] } ]'
7.2 Implement Usage-Based Pricing Protection
Section titled “7.2 Implement Usage-Based Pricing Protection”// Cost tracking middlewareconst costTracker = { // Estimate cost per operation calculateRequestCost(operation, count = 1) { const costs = { 'read': 0.0004 / 10000, // $0.0004 per 10K read operations 'write': 0.05 / 10000, // $0.05 per 10K write operations 'list': 0.05 / 10000, // $0.05 per 10K list operations 'delete': 0.0004 / 10000 // $0.0004 per 10K delete operations };
return (costs[operation] || 0) * count; },
// Track daily costs per user async trackUserCost(userId, operation, count = 1) { const cost = this.calculateRequestCost(operation, count); const today = new Date().toDateString(); const key = `cost-${userId}-${today}`;
// Store in your preferred database/cache const currentCost = await redis.get(key) || 0; const newCost = parseFloat(currentCost) + cost;
await redis.set(key, newCost, 'EX', 86400); // Expire after 24 hours
return newCost; }};
// Usage in API endpointsapp.get('/api/images/:imageName', async (req, res) => { const userId = req.headers['x-user-id'] || req.ip;
// Track cost const dailyCost = await costTracker.trackUserCost(userId, 'read');
// Implement cost limit (e.g., $1 per user per day) if (dailyCost > 1.00) { return res.status(429).json({ error: 'Daily cost limit exceeded', currentCost: dailyCost, limit: 1.00 }); }
// Continue with request...});
🔍 Security Monitoring & Audit
Section titled “🔍 Security Monitoring & Audit”8.1 Enable Azure Security Center
Section titled “8.1 Enable Azure Security Center”# Enable Security Center for the subscriptionaz security auto-provisioning-setting update \ --name default \ --auto-provision on
# Enable threat detection for storage accountsaz security setting update \ --name "MCAS" \ --enabled true
8.2 Implement Custom Security Monitoring
Section titled “8.2 Implement Custom Security Monitoring”// Security monitoring serviceclass SecurityMonitor { constructor(storageAccount) { this.storageAccount = storageAccount; this.suspiciousPatterns = new Set(); }
// Monitor for suspicious access patterns async analyzeRequest(req) { const clientIP = req.ip; const userAgent = req.headers['user-agent']; const timestamp = new Date();
// Check for suspicious patterns const patterns = { rapidRequests: await this.checkRapidRequests(clientIP), unusualUserAgent: this.checkUnusualUserAgent(userAgent), geographicAnomaly: await this.checkGeographicAnomaly(clientIP), timeAnomaly: this.checkTimeAnomaly(timestamp) };
const suspiciousScore = Object.values(patterns) .filter(Boolean).length;
if (suspiciousScore >= 2) { await this.triggerSecurityAlert(clientIP, patterns); return false; // Block request }
return true; // Allow request }
async checkRapidRequests(clientIP) { const key = `requests-${clientIP}`; const count = await redis.incr(key); await redis.expire(key, 60); // 1 minute window
return count > 100; // More than 100 requests per minute }
checkUnusualUserAgent(userAgent) { const commonBots = [ 'bot', 'crawler', 'spider', 'scraper', 'wget', 'curl', 'python-requests' ];
return commonBots.some(bot => userAgent?.toLowerCase().includes(bot) ); }
async triggerSecurityAlert(clientIP, patterns) { const alert = { timestamp: new Date(), clientIP, patterns, severity: 'HIGH', action: 'BLOCKED' };
// Log to security monitoring system console.log('SECURITY ALERT:', JSON.stringify(alert));
// Send to security team await this.notifySecurityTeam(alert);
// Temporarily block IP await this.temporaryBlockIP(clientIP); }
async temporaryBlockIP(clientIP) { // Add to temporary blocklist for 1 hour await redis.set(`blocked-${clientIP}`, '1', 'EX', 3600); }}
📋 Security Checklist
Section titled “📋 Security Checklist”Essential Security Measures
Section titled “Essential Security Measures”- Disable Storage Account Keys (use Azure AD when possible)
- Enable HTTPS-only access
- Set minimum TLS version to 1.2
- Configure firewall rules to restrict access
- Enable soft delete for blobs and containers
- Implement proper CORS settings
- Use SAS tokens for controlled access
- Enable logging and monitoring
- Set up security alerts
- Regular security reviews
Advanced Security (High-Value Assets)
Section titled “Advanced Security (High-Value Assets)”- Implement Private Endpoints
- Use Customer-Managed Keys (CMK)
- Enable Azure AD authentication
- Implement network isolation
- Use Azure Security Center recommendations
- Regular penetration testing
- Implement Zero Trust architecture
Rate Limiting & Cost Control
Section titled “Rate Limiting & Cost Control”- Application-level rate limiting
- Per-user request quotas
- CDN rate limiting rules
- Cost monitoring and alerts
- Usage-based access controls
- Regular cost reviews
🔧 Advanced Security Configurations
Section titled “🔧 Advanced Security Configurations”9.1 Customer-Managed Keys (CMK)
Section titled “9.1 Customer-Managed Keys (CMK)”# Create Key Vaultaz keyvault create \ --resource-group $RESOURCE_GROUP \ --name "mykeyvault$RANDOM" \ --location $LOCATION \ --enable-purge-protection true
# Create encryption keyaz keyvault key create \ --vault-name "mykeyvault$RANDOM" \ --name "storage-encryption-key" \ --kty RSA \ --size 2048
# Configure storage account to use CMKaz storage account update \ --name $STORAGE_ACCOUNT \ --resource-group $RESOURCE_GROUP \ --encryption-key-source Microsoft.Keyvault \ --encryption-key-vault "https://mykeyvault$RANDOM.vault.azure.net/" \ --encryption-key-name "storage-encryption-key"
9.2 Immutable Blob Storage (WORM)
Section titled “9.2 Immutable Blob Storage (WORM)”# Create container with immutable policyaz storage container create \ --name immutable-images \ --account-name $STORAGE_ACCOUNT \ --account-key $STORAGE_KEY
# Set immutability policy (for compliance requirements)az storage container immutability-policy create \ --account-name $STORAGE_ACCOUNT \ --container-name immutable-images \ --period 365 \ --allow-protected-append-writes false
🚨 Incident Response Plan
Section titled “🚨 Incident Response Plan”10.1 Security Incident Checklist
Section titled “10.1 Security Incident Checklist”Immediate Response:
- Identify scope of the incident
- Temporarily block suspicious IPs
- Rotate storage account keys
- Review access logs
- Notify stakeholders
Investigation:
- Analyze logs for attack patterns
- Check for data exfiltration
- Identify compromised assets
- Document findings
Recovery:
- Remove malicious access
- Restore from backups if needed
- Update security configurations
- Monitor for additional activity
10.2 Automated Incident Response
Section titled “10.2 Automated Incident Response”// Automated incident responseclass IncidentResponse { async handleSecurityIncident(incident) { // Immediate actions await this.blockSuspiciousIPs(incident.sourceIPs); await this.rotateAccessKeys(); await this.notifySecurityTeam(incident);
// Generate incident report const report = await this.generateIncidentReport(incident); await this.logIncident(report);
return report; }
async blockSuspiciousIPs(ips) { for (const ip of ips) { await this.addFirewallRule('DENY', ip); } }
async rotateAccessKeys() { // Rotate storage account keys await this.executeAzureCLI([ 'az', 'storage', 'account', 'keys', 'renew', '--account-name', this.storageAccount, '--key', 'key1' ]); }}
🔗 Related Resources
Section titled “🔗 Related Resources”- Azure Blob Storage for Images
- GitHub Static Web Apps Integration
- Azure Storage Best Practices Documentation
📞 Support & Compliance
Section titled “📞 Support & Compliance”For critical security incidents or compliance questions:
- Azure Security Center recommendations
- Microsoft Security Response Center (MSRC)
- Azure support tickets for security issues
- Regular security audits and compliance reviews