This is an example of an application protecting data in-use and in-transit (it has no persistent storage), the end user uploads a dashcam video that could contain PII like faces or license plates. The application blurs our all the PII and produces a video you can view in the app minus the PII.
It deploys a Flask-based video redaction app to Azure Container Instances (Confidential SKU), protected by a Confidential Compute Enforcement (CCE) policy and remote attestation gate.
- Serves the web app over HTTPS.
- Requires attestation validation before upload/processing can proceed.
- Accepts
.mp4uploads and processes video inside the confidential container. - Blurs sensitive content in processed output:
- Faces (cascade detection)
- License plates (direct plate detection plus vehicle-guided inference and temporal stabilization)
- Shows processing status with per-worker progress and a final playback view.
- Exposes live plate-tracking tuning controls in the UI (
holdFrames,matchIou) and applies them without redeploy.
Updated screenshot captured from the running app:
An additional copy is kept at AutomotiveVisionApp.png for convenience.
- Blurs faces and license plates.
- Draws rounded overlays around the primary lead vehicle (cars, trucks), pedestrians, and street signs to make detections legible without obscuring them.
- Uses a lead-vehicle-first strategy: per frame, only the most central, sufficiently large car/truck is selected to anchor plate inference. Tunable via
LEAD_VEHICLE_MIN_AREA_RATIO(default0.003) andLEAD_VEHICLE_MAX_CENTER_OFFSET(default0.42, fraction of frame width). - Keeps plate blur stable across short detector dropouts via temporal hold logic.
- Uses red-glare-aware carryover to avoid losing blur under brake-light glare.
app.py: Flask API, detection/redaction pipeline, job orchestration, settings APIs.templates/index.html: web UI for attestation, upload, progress, playback, and plate-tracking settings.Deploy-AutomotiveMachineVision.ps1: build/deploy script for ACR + confidential ACI deployment.deployment-template.json: ACI deployment template with CCE policy integration.deployment-params.json: deployment parameters for the template.Dockerfile,nginx.conf,supervisord.conf: runtime container stack.docs/app-screengrab.png: screenshot embedded in this README.
- Azure CLI (
az) - Azure CLI
confcomextension - PowerShell 7+
- Docker Desktop (required for CCE policy generation)
az extension add --name confcom --upgrade
az confcom --versionSet-Location automotive-machine-vision
# Build and push image to ACR
.\Deploy-AutomotiveMachineVision.ps1 -Build
# Deploy confidential ACI with CCE policy generation
.\Deploy-AutomotiveMachineVision.ps1 -DeployTo use a real certificate (including Let's Encrypt), pass your PEM files at deploy time:
.\Deploy-AutomotiveMachineVision.ps1 -Deploy \
-ImageTag amv-20260602-<suffix> \
-TlsCertPath "C:\path\to\fullchain.pem" \
-TlsKeyPath "C:\path\to\privkey.pem"For Let's Encrypt specifically, use Certbot output files:
fullchain.pemfor-TlsCertPathprivkey.pemfor-TlsKeyPath
This repo includes a helper that runs Certbot in Docker and writes local PEM artifacts under certs/live/<domain>/:
Set-Location automotive-machine-vision
# DNS challenge (manual TXT record entry)
.\Get-LetsEncryptCertificate.ps1 -Domain "your.domain.com" -Email "you@example.com" -Challenge dns-manual
# Optional: HTTP challenge (requires inbound port 80 to this machine)
.\Get-LetsEncryptCertificate.ps1 -Domain "your.domain.com" -Email "you@example.com" -Challenge http-standaloneThen deploy using generated files:
.\Deploy-AutomotiveMachineVision.ps1 -Deploy \
-TlsCertPath ".\certs\live\your.domain.com\fullchain.pem" \
-TlsKeyPath ".\certs\live\your.domain.com\privkey.pem"For deterministic deployments, use an explicit image tag:
.\Deploy-AutomotiveMachineVision.ps1 -Build -ImageTag amv-20260602-<suffix>
.\Deploy-AutomotiveMachineVision.ps1 -Deploy -ImageTag amv-20260602-<suffix>The deploy script accepts container sizing flags. Defaults are conservative; raise them for higher throughput on larger videos.
| Parameter | Default | Range | Notes |
|---|---|---|---|
-CpuCores |
4 |
1–48 (subscription quota) | Confidential ACI vCPU count |
-MemoryInGB |
6 |
up to subscription limit | RAM for the container group |
-ProcessingWorkers |
0 (auto) |
0–30 | Sets PROCESSING_WORKERS env var; 0 = max(6, min(24, CpuCores)) |
-DetectEveryNFrames |
1 |
1–12 | Detector stride; higher = faster, less precise |
The Flask processing pipeline clamps the runtime worker pool at 16 threads regardless of PROCESSING_WORKERS, so going above 16 gives diminishing returns. Verify the live worker count via:
curl https://<fqdn>/api/debug/runtime?profile=balancedExample 16 vCPU / 16 worker deployment:
.\Deploy-AutomotiveMachineVision.ps1 -Deploy -DeployAFD -CpuCores 16 -MemoryInGB 32 -ProcessingWorkers 16CCE policy gotcha: env values in the ARM template must be plain strings, not nested ARM functions like
[string(parameters('x'))].az confcom acipolicygendoes not evaluate nested functions and embeds the literal expression as the env_rules pattern; withallow_environment_variable_dropping := truethis silently drops the variable at runtime.
To simplify HTTPS access and avoid certificate management, deploy the app behind Azure Front Door with Microsoft-managed TLS:
.\Deploy-AutomotiveMachineVision.ps1 -Deploy -DeployAFDThis will:
- Deploy the confidential ACI container (with self-signed cert fallback).
- Create an Azure Front Door profile with a Microsoft-managed domain (
*.azurefd.net). - Configure Front Door to route traffic to your ACI FQDN over HTTPS.
- Return both endpoints:
- Front Door (Azure-managed HTTPS):
https://amv-endpoint-XXXXX.azurefd.net - Direct ACI (self-signed):
https://amv-XXXXX.eastus.azurecontainer.io
- Front Door (Azure-managed HTTPS):
You can access the app via the Front Door endpoint with automatic HTTPS (no self-signed cert warnings).
Why HTTP origin? AFD forwards HTTPS traffic to the origin over plain HTTP on port 80 (
forwardingProtocol: HttpOnly). The container's self-signed cert on the ephemeral*.azurecontainer.ioFQDN can't be trusted by AFD's origin TLS validation, so the edge handles HTTPS termination and the back-channel is HTTP within the Azure backbone. Note: after a redeploy that changes the container FQDN, AFD edge DNS caches can take 5–15 minutes to converge; some PoPs may briefly return 502 withDNSNameNotResolved.
Optional: Bring your own certificate
If you want to use the direct ACI endpoint with a real CA certificate (e.g., Let's Encrypt), combine both:
.\Deploy-AutomotiveMachineVision.ps1 -Deploy \
-DeployAFD \
-TlsCertPath ".\certs\live\yourdomain.com\fullchain.pem" \
-TlsKeyPath ".\certs\live\yourdomain.com\privkey.pem"This gives you both options:
- Front Door endpoint: Always available with Microsoft-managed HTTPS.
- Direct ACI endpoint: Works with your provided certificate.
- CCE policy generation enforces approved image measurement and non-interactive execution (
--disable-stdio). - The UI shows decoded claim values and explanations for attestation evidence before enabling upload.
- The container supports CA-issued certificates (including Let's Encrypt) via
-TlsCertPathand-TlsKeyPath. - If no certificate is provided, the container falls back to a self-signed certificate for demo/testing.
- Video processing is server-side within the confidential container boundary.
