Day 2 Challenge — Network and Data Security
Day 2 Challenge — Network and Data Security
This challenge is optional. It is meant for students who finish the labs early or want to go deeper.
All challenges build on concepts from Day 2 labs but introduce new Azure services or advanced configurations not covered in the main labs.
Challenge 1 — NSG flow logs
NSG flow logs capture information about IP traffic flowing through an NSG. Unlike diagnostic logs (which track resource-level operations), flow logs capture network-level traffic patterns. They are stored in a Storage Account and can be analyzed to detect anomalies, troubleshoot connectivity, or audit network access.
Your task:
Create a new Storage Account to store the flow logs:
- Name:
stflowlogs<random> - Performance: Standard
- Replication: LRS (cheapest option for logs)
- Region: Same as your resources
- Name:
Enable NSG flow logs for the
nsg-snet-private-endpointsNSG:- Go to: Network Watcher → Logs → Flow logs → + Create
- Select NSG:
nsg-snet-private-endpoints - Flow log version: Version 2 (includes more metadata)
- Storage account: the one created in step 1
- Retention: 7 days
- Traffic Analytics: Disabled (optional, costs extra)
Generate some traffic through the application:
curl https://<PUBLIC_BACKEND_URL>/api/data-demo curl https://<PUBLIC_BACKEND_URL>/api/trace-demoWait 10-15 minutes for logs to be written to storage.
Navigate to the Storage Account → Containers →
insights-logs-networksecuritygroupflowevent→ browse the JSON files.Download a recent JSON file and examine the flow log entries.
Sample flow log entry:
{
"time": "2026-05-28T10:30:00.000Z",
"flowLogResourceID": "/subscriptions/.../nsg-snet-private-endpoints",
"macAddress": "00-0D-3A-...",
"category": "NetworkSecurityGroupFlowEvent",
"flowRecords": [
{
"rule": "allow-bastion-inbound",
"flows": [
{
"sourceAddress": "10.0.10.5",
"destinationAddress": "10.0.2.4",
"destinationPort": "22",
"protocol": "T",
"trafficFlow": "I",
"trafficDecision": "A"
}
]
}
]
}Questions to answer:
Can you identify traffic from the App Service subnet (
10.0.1.0/24) to the private endpoints subnet (10.0.2.0/24)? Which ports are used?
What does
trafficDecision: "A"vs"D"mean? Can you find any denied traffic in the logs?
What information do NSG flow logs provide that Application Insights or storage diagnostic logs do not?
How would flow logs help you troubleshoot a connectivity issue between two subnets?
Cost reminder: Flow logs cost ~$0.10 per GB ingested. For a short lab session this is negligible. Delete the flow log configuration and storage account when done if you want to minimize costs.
Challenge 2 — Restrict database and Key Vault access to internal backend only
Currently, both the public backend and internal backend have VNet integration and can access the DB storage account and Key Vault private endpoints.
In a production architecture, only the internal backend should access the database and secrets. The public backend should call the internal backend, not the data layer directly.
Your task:
- Remove the RBAC role assignment that gives the public backend access to Key Vault secrets
- Add code to the internal backend to expose the secret via a new endpoint
/api/internal-secret-demo - Test that
/api/secret-demoon the public backend now fails (403 Forbidden) - Test that
/api/internal-secret-demoon the internal backend returns the secret
Code to add to internal backend (src/index.js):
// After existing imports, add:
const { SecretClient } = require("@azure/keyvault-secrets");
const { DefaultAzureCredential } = require("@azure/identity");
// After existing constants, add:
const keyVaultUrl = process.env.KEY_VAULT_URL;
const demoSecretName = process.env.DEMO_SECRET_NAME;
// Add this new endpoint:
app.get('/api/internal-secret-demo', async (req, res) => {
const correlationId = req.headers['x-correlation-id'] || uuidv4();
try {
const credential = new DefaultAzureCredential();
const client = new SecretClient(keyVaultUrl, credential);
const secret = await client.getSecret(demoSecretName);
res.json({
message: 'Secret retrieved from internal backend',
secret: secret.value,
correlationId,
source: 'internal-backend',
timestamp: new Date().toISOString()
});
} catch (error) {
res.status(500).json({
error: error.message,
correlationId
});
}
});Deploy the updated code:
cd src/internal-backend
zip -r ../internal-backend.zip .
az webapp deployment source config-zip \
--resource-group <rg-name> \
--name <internal-backend-name> \
--src ../internal-backend.zipQuestions to answer:
Why is it better to have only the internal backend access secrets and the database?
What happens if an attacker gains access to the public backend? Can they still read secrets or data?
How would you verify in the Azure Portal that the public backend no longer has access to Key Vault?
Challenge 3 — Table Storage diagnostic settings and monitoring
Azure Storage accounts can send diagnostic logs to Log Analytics, allowing you to monitor access patterns, performance, and security events at the data plane level.
Your task:
- Open the DB storage account (
stdb...) in the Azure Portal. - Go to Monitoring → Diagnostic settings.
- Click + Add diagnostic setting.
- Configure:
- Name:
diag-table-storage - Logs: Select
StorageReadandStorageWrite - Destination: Send to Log Analytics workspace (select the workspace from your resource group)
- Name:
- Click Save.
- Generate some table access by calling
/api/data-demoon the public backend a few times. - Wait 5-10 minutes for logs to ingest.
- Query the logs in Log Analytics:
StorageTableLogs
| where TimeGenerated > ago(1h)
| where TableName in ("messages", "audit")
| project TimeGenerated, OperationName, StatusCode, CallerIpAddress, Uri, AuthenticationType
| order by TimeGenerated desc
| take 20Questions to answer:
What is the
CallerIpAddressfor requests from the internal backend? Is it a private IP or public IP?
What
AuthenticationTypeis used? (SAS, OAuth, SharedKey, or Anonymous?)
How would these logs help you detect unauthorized access attempts to your storage account?
What information do Table Storage diagnostic logs provide that application-level logs (Application Insights) do not?
Challenge 4 — Enable HTTPS on Application Gateway
The optional Application Gateway WAF lab uses HTTP for simplicity, but production applications should use HTTPS end-to-end. In this challenge you'll configure Application Gateway to:
- Accept HTTPS traffic on the frontend (using a self-signed certificate for demo purposes)
- Keep the backend connection to the App Service as HTTPS (already configured)
Prerequisites: You must have completed the optional Application Gateway WAF lab first.
Your task:
Step 1: Create a self-signed certificate
On your laptop, generate a self-signed certificate and export it as a PFX file:
# Using OpenSSL (Linux/Mac/WSL)
openssl req -x509 -newkey rsa:2048 -keyout appgw-key.pem -out appgw-cert.pem -days 365 -nodes \
-subj "/CN=appgw.local/O=Lab/C=NL"
openssl pkcs12 -export -out appgw-cert.pfx -inkey appgw-key.pem -in appgw-cert.pem \
-passout pass:Password123!Or using PowerShell (Windows):
$cert = New-SelfSignedCertificate -DnsName "appgw.local" -CertStoreLocation "cert:\CurrentUser\My"
$pwd = ConvertTo-SecureString -String "Password123!" -Force -AsPlainText
Export-PfxCertificate -Cert $cert -FilePath "appgw-cert.pfx" -Password $pwdStep 2: Add HTTPS listener to Application Gateway
- Navigate to your Application Gateway in the Azure Portal.
- Go to Settings → Listeners.
- Click + Add listener.
- Configure:
- Listener name:
https-listener - Frontend IP: Public
- Protocol: HTTPS
- Port: 443
- Choose a certificate: Upload a certificate
- Cert name:
appgw-selfsigned - PFX certificate file: Upload the
appgw-cert.pfxfile - Password:
Password123! - Listener type: Basic
- Listener name:
- Click Add.
Step 3: Create a routing rule for HTTPS
- Go to Settings → Rules.
- Click + Request routing rule.
- Configure:
- Rule name:
https-rule - Priority: 200
- Listener:
https-listener - Backend target: Use existing backend pool (your public backend)
- Backend settings: Use existing (the HTTPS backend settings from the WAF lab)
- Rule name:
- Click Add.
Step 4: Test HTTPS access
Get your Application Gateway's public IP:
# Find the App Gateway public IP
az network public-ip show \
--resource-group <your-rg> \
--name <appgw-public-ip-name> \
--query ipAddress -o tsvTest HTTPS access (ignoring certificate validation for self-signed cert):
curl -k https://<APPGW_PUBLIC_IP>/api/healthExpected: HTTP 200 response
Step 5: Test WAF with HTTPS
Trigger a WAF block using HTTPS:
curl -kv "https://<APPGW_PUBLIC_IP>/api/health?id=1' OR '1'='1"Expected: HTTP 403 Forbidden (WAF blocks the SQL injection attempt)
Verify the WAF log in Log Analytics (same KQL query as the WAF lab):
AzureDiagnostics
| where ResourceType == "APPLICATIONGATEWAYS"
| where Category == "ApplicationGatewayFirewallLog"
| where action_s == "Blocked"
| where requestUri_s contains "api/health"
| order by TimeGenerated desc
| take 5Questions to answer:
Why is it important to use HTTPS on the Application Gateway frontend, even if the backend already uses HTTPS?
What would happen if you used an HTTP listener with an HTTPS backend? Would traffic flow work?
In a production environment, what certificate would you use instead of a self-signed certificate?
How does Application Gateway WAF protect against attacks even when using HTTPS?
Production certificate options
For production, you would use:
- Azure Key Vault integration to store and automatically rotate certificates
- Public CA-signed certificate (Let's Encrypt, DigiCert, etc.)
- Azure App Service Managed Certificate (free, auto-renewed, but limited to App Service domains)
Certificate validation
The -k flag in curl skips certificate validation. Browsers will show a security warning for self-signed certificates. This is expected in a lab environment but not acceptable in production.
Reflection
After completing any of these challenges, reflect on:
- Challenge 1 (NSG flow logs): How do flow logs differ from diagnostic logs? When would you use each?
- Challenge 2 (Restrict access): What is the principle of least privilege, and how does restricting database access to only the internal backend apply this principle?
- Challenge 3 (Storage diagnostics): How can storage-level logs help detect security incidents that application logs might miss?
- Challenge 4 (HTTPS on App Gateway): Why is end-to-end encryption important even when using a WAF?
- Cross-cutting: Which challenge gave you the most insight into network security? Which was most valuable for real-world production environments?