TechCart: Securing Azure Blob Storage Access with Terraform and DevSecOps
A LUIT Academy project - Upgrade

Introduction
As part of my LUIT Academy cloud and DevSecOps learning journey, I built TechCart, a secure asset management API for an e-commerce platform. The project focuses on solving a realistic cloud security problem: application assets stored in Azure Blob Storage were returning 403 Forbidden errors, and the previous access model relied on overly permissive storage account keys.
Instead of treating the issue as a simple permissions bug, I approached it as a full DevSecOps remediation project. The final solution combines secure application design, Azure Blob Storage hardening, Azure AD authentication, scoped User Delegation SAS tokens, Azure RBAC, Terraform infrastructure-as-code, and automated security checks in CI/CD.
This project demonstrates how a cloud or DevSecOps engineer can take a broken, risky storage access pattern and turn it into a secure, repeatable, production-ready solution.
Project Scenario
TechCart is an e-commerce platform that stores product images, documents, and other application assets in Azure Blob Storage. The application needed a secure way for users and services to upload and download files without exposing broad storage account keys or allowing anonymous public access.
The original environment had two major problems.
First, users were experiencing 403 Forbidden errors when attempting to access application assets.
Second, the previous design depended on storage account keys that were too powerful for normal application access. Storage account keys can provide broad access across the storage account, which creates a major security risk if they are leaked, copied, or misused.
The goal of the project was to fix the access issue while also redesigning the storage access model around least privilege, automation, and DevSecOps best practices.
Problem Statement
The TechCart application had an insecure and unreliable Azure Blob Storage access pattern.
The main problems were:
Application assets returned 403 Forbidden
Anonymous access controls were not consistently enforced
Previous access relied on overly permissive storage keys
Storage permissions were too broad
Upload and download permissions were not properly separated
Credential exposure would create a large blast radius
Infrastructure configuration was difficult to reproduce manually
Security checks were not fully integrated into the delivery pipeline
This created both an application reliability problem and a cloud security problem.
Project Objective
The objective of this LUIT Academy project was to design and implement a secure DevSecOps solution that:
Disables anonymous blob access
Removes storage account keys from the application access flow
Uses short-lived, scoped User Delegation SAS tokens
Enforces Azure RBAC based on identity and scope
Provisions Azure infrastructure with Terraform
Adds security scanning into CI/CD
Documents issues, fixes, and operational events
Demonstrates a production-style cloud security remediation workflow
Solution Overview
The final TechCart solution uses a Flask-based API as a secure gateway between users and Azure Blob Storage.
Users authenticate through Azure AD. The API validates the user’s JWT and checks the user’s application role. If the user is authorized, the API issues a short-lived SAS token for a specific blob operation.
The application no longer exposes storage account keys. Users do not receive direct Azure roles. Anonymous access is disabled. Blob containers are private. Uploads and downloads are controlled through scoped SAS tokens.
This design gives TechCart secure access without sacrificing usability.
DevSecOps Architecture
The solution includes four major layers:
1. Application Security Layer
The Flask API validates every request using Azure AD JWT authentication. Middleware checks the user’s role before allowing upload or download operations.
Application roles include:
asset_readerasset_uploaderasset_manager
Only users with the correct role can request a SAS token for the corresponding blob action.
2. Azure Storage Security Layer
Azure Blob Storage is hardened with several security controls:
Anonymous access disabled
Containers set to private
Shared key access disabled
Public network access disabled
Minimum TLS version enforced
Blob soft delete enabled
Blob versioning enabled
Change feed enabled
Diagnostics sent to Log Analytics
Access restricted through private endpoints
This protects the storage account from public exposure and reduces the risk of unauthorized access.
3. Infrastructure as Code Layer
Terraform is used to provision and manage the Azure infrastructure.
The project uses modular Terraform for:
Networking
Storage
Managed identities
RBAC
Key Vault
Monitoring
This allows the infrastructure to be version-controlled, reviewed through pull requests, and deployed consistently across environments.
The Terraform design supports both development and production environments with different settings for replication, retention, and state management.
4. DevSecOps Pipeline Layer
GitHub Actions is used to automate CI/CD and security validation.
The pipeline includes:
Code linting
Formatting checks
Unit testing
Coverage reporting
Static application security testing
Dependency vulnerability scanning
Secret detection
Infrastructure-as-code scanning
Terraform validation and planning
Security is not treated as a final step. It is built directly into the development workflow.
Secure Upload Flow
The upload workflow uses a two-step pattern.
The client sends an upload request to the Flask API.
The API validates the Azure AD JWT.
The API checks whether the user has the correct role.
The API issues a short-lived write-only SAS URL.
The client uploads the file directly to Azure Blob Storage.
The client notifies the API that the upload is complete.
The API verifies that the blob exists.
This design keeps large file uploads out of the API server while still allowing the API to control authorization and verification.
Secure Download Flow
The download workflow follows a similar least-privilege model.
The client requests access to an asset.
The API validates the user’s JWT.
The API checks the user’s role.
The API issues a short-lived read-only SAS URL.
The client downloads the asset from Azure Blob Storage.
The user receives access only to the specific asset for a limited period.
GitHub Actions are all green. This is due to checking for every error, repairing it, and rerunning.
Azure RBAC Design
The project uses Azure RBAC to separate responsibilities across identities.
| Identity | Azure Role | Scope |
|---|---|---|
| API server | Storage Blob Delegator | Storage account |
| Upload worker | Storage Blob Data Contributor | Uploads container |
| CDN service | Storage Blob Data Reader | Assets container |
| End users | No Azure role | Controlled through application JWT and role claims |
This design follows the principle of least privilege. Each identity receives only the access required to perform its job.
The API server can issue SAS tokens, but it does not become a broad privileged data conduit.
Terraform Implementation
The Terraform infrastructure is organized under an infra/ directory.
The project includes modules for:
Network Module
Creates virtual networks, subnets, network security groups, private DNS zones, and private endpoint connectivity.
Storage Module
Creates the hardened Azure Storage account, private blob containers, private endpoints, and diagnostic settings.
Identity Module
Creates user-assigned managed identities for the API server, upload worker, and CDN reader.
RBAC Module
Assigns least-privilege Azure roles to the correct identities at the correct scopes.
Key Vault Module
Creates a secure Azure Key Vault using RBAC mode, purge protection, private endpoint access, and diagnostic logging.
Monitoring Module
Creates Log Analytics and diagnostic settings for visibility across the environment.
This modular structure makes the project easier to maintain, test, and expand.
First verification of Terraform apply in GitHub Actions
Dev and Prod Environment Strategy
The project supports separate development and production environments.
| Environment | Replication | Blob Soft Delete | Key Vault Retention |
|---|---|---|---|
| Dev | LRS | 7 days | 7 days |
| Prod | GZRS | 30 days | 90 days |
This reflects a real-world environment strategy in which development remains lightweight, while production uses stronger durability and retention controls.
CI/CD and Security Tooling
The DevSecOps pipeline uses GitHub Actions.
CI Tools
Ruff for linting
Ruff format check
Pytest for unit testing
Coverage reporting
Security Tools
Bandit for Python security linting
Semgrep for secure code analysis
CodeQL for deeper static analysis
pip-audit for dependency vulnerability scanning
Trivy for filesystem, secrets, IaC, and container scanning
Gitleaks for secret detection
Checkov for Terraform and cloud misconfiguration scanning
Shift-Left Controls
The project also includes pre-commit hooks to catch common issues before code is pushed.
These include:
Ruff
Bandit
Gitleaks
Private key detection
Large file checks
Trailing whitespace checks
End-of-file fixes
This gives the project a practical DevSecOps workflow from local development through deployment.
The workflow discovered errors that had to be repaired before running Terraform apply
Issues Resolved During the Project
This project also included real troubleshooting and remediation work.
Examples of resolved or mitigated issues include:
Terraform backend initialization failure
Azure login failure in GitHub Actions
Ruff formatting failures
GitHub Actions Node version deprecation warnings
Bandit SARIF formatting issue
SARIF upload limitations in a private repository
Checkov Terraform policy findings
Trivy SARIF exit-code behavior
Semgrep authentication limitations
CodeQL limitations without GitHub Advanced Security
Azure resources remaining after the environment destroy
These issues helped make the project more realistic because DevSecOps work is not only about writing code. It also involves diagnosing pipeline failures, understanding tooling limitations, documenting fixes, and improving the delivery process.
Final Outcome
The TechCart project successfully transformed an insecure blob access pattern into a secure, automated, DevSecOps-driven solution.
The final outcome included:
Anonymous blob access disabled
Storage account keys removed from the application flow
Private containers enforced
User Delegation SAS tokens implemented
Azure RBAC applied using least privilege
Upload and download permissions separated
Terraform used for repeatable infrastructure deployment
Dev and prod environments defined
CI/CD pipeline implemented
Security scans integrated into the software delivery process
Operational issues documented and resolved
The project demonstrates how cloud security, infrastructure automation, and DevSecOps practices work together in a realistic Azure environment.
Verification of Azure resources created with Terraform
techart-dev-app-nsg verification
Verification of Terraform destroy. However, there were issues in Terraform destroy that did not remove all of the resources on the first run in the Terraform destroy. The Azure resources were destroyed on the second run.
Skills Demonstrated
This LUIT Academy project demonstrates hands-on experience with:
Azure Blob Storage
Azure AD authentication
Azure RBAC
User Delegation SAS tokens
Terraform
Infrastructure as Code
GitHub Actions
DevSecOps pipelines
Secret scanning
SAST and SCA tooling
IaC security scanning
Private endpoints
Managed identities
Key Vault
Log Analytics
Cloud security troubleshooting
Least-privilege access design
Conclusion
TechCart is a strong LUIT Academy project because it shows more than basic cloud deployment. It demonstrates how to identify an insecure access pattern, redesign the architecture, automate infrastructure, enforce least privilege, and integrate security into the software delivery lifecycle.
The project started with a common production issue: 403 Forbidden errors and risky storage key usage. It ended with a secure Azure Blob Storage access model backed by Terraform and DevSecOps automation.
This is the kind of project that shows practical readiness for cloud engineering, DevSecOps engineering, and cloud security roles. The repo can be found here: https://github.com/mdixon47/azure-techcart
