Description
Key Focus Areas:
Application Security Groups & Workload-Centric Segmentation
DevSecOps Pipeline Integration
Policy-as-Code Governance
Security Scanning in IaC Workflows
Managed Identity Architecture
Compliance-as-Code
Executive Summary
Architected a Security-as-Code governance platform for Azure infrastructure — embedding security controls, compliance validation, and policy enforcement directly into the infrastructure delivery lifecycle rather than applying them as post-deployment audit layers.
The architecture introduces three capabilities not covered in the existing Zero Trust and IaC studies: Application Security Groups (ASGs) for workload-centric dynamic network segmentation that scales without IP address management; DevSecOps pipeline integration embedding tfsec, Checkov, and Microsoft Defender for DevOps security scanning into Terraform CI/CD workflows; and Azure Policy-as-Code managing compliance enforcement as version-controlled infrastructure definitions rather than manually configured portal policies.
The design demonstrates that security in cloud infrastructure is not achieved at deployment time — it is built into the engineering process through automated validation, policy enforcement, and continuously tested compliance that prevents insecure configurations from ever reaching production.
Business Drivers
Cloud infrastructure security failures most commonly originate not from sophisticated attacks but from misconfiguration — publicly exposed storage accounts, overprivileged identities, missing encryption, and absent diagnostic settings deployed through ungoverned manual processes or IaC code without security validation.
This architecture was designed to address the DevSecOps governance requirements of organisations where existing infrastructure operations result in:
Security misconfigurations reaching production because IaC code is not scanned before deployment
Azure Policy compliance controls configured manually in the portal — inconsistently applied across environments and not version-controlled
NSG rules referencing IP address ranges that become stale as environments evolve — requiring manual rule updates creating operational overhead and security gaps
No automated mechanism preventing insecure resource configurations from being deployed — security review is manual and post-deployment
Compliance evidence produced through point-in-time portal exports rather than continuously enforced and automatically reportable policy state
Security controls treated as deployment artefacts rather than engineering requirements — applied after infrastructure is built rather than validated before it is deployed
Operational Constraints
The architecture was designed to operate within the following constraints typical of enterprise Azure DevOps environments:
Security scanning must integrate into existing CI/CD pipelines without requiring separate security tooling infrastructure
NSG rule management must scale with environment complexity — IP-based rules become unmanageable as workload counts grow
Azure Policy compliance enforcement must be version-controlled and deployable through the same IaC pipelines as infrastructure
Security scanning failures must block deployment — findings cannot be advisory-only for critical misconfigurations
Policy-as-Code must support both Deny effects (preventing non-compliant deployments) and DeployIfNotExists effects (remediating missing configurations)
Managed Identity must be enforced as the default authentication model — service principal credentials should not be deployable without explicit justification
Compliance reporting must be producible on demand from Azure Policy state — not from manual evidence collection
Objectives
Implement Application Security Groups providing workload-centric dynamic network segmentation that scales without IP address management overhead
Integrate tfsec and Checkov security scanning into CI/CD pipeline validation stages — blocking deployment on critical findings
Manage Azure Policy definitions, assignments, and initiatives as version-controlled Terraform code
Enforce Managed Identity as the default service authentication model through Policy-as-Code controls
Implement Azure Bastion as the secure administrative access model — eliminating public IP and management port exposure
Establish continuous compliance monitoring through Azure Policy compliance dashboards
Demonstrate DevSecOps maturity through security controls embedded at every stage of the infrastructure delivery lifecycle
Architecture Principles
Security-left — security validation occurs before deployment, not after
Policy-as-Code — compliance controls are version-controlled infrastructure definitions, not manually configured portal settings
Application-centric segmentation — network rules reference workload identity (ASGs) not IP addresses
Never trust, always verify — identity verification required for every access decision regardless of network position
Managed Identity by default — credential-based service authentication is a policy violation, not an option
Immutable compliance — Azure Policy enforces compliance state continuously, not at point-in-time audit intervals
DevSecOps integration — security is an engineering discipline embedded in delivery workflows, not a gate applied after delivery
Architecture Overview
The solution is structured as a four-layer Security-as-Code platform integrating application-centric network segmentation, DevSecOps pipeline governance, policy-as-code compliance, and secure operational access.
1. Application Security Groups — Workload-Centric Segmentation
Application Security Groups (ASGs) are the primary differentiating network segmentation capability in this study — providing workload-identity-based traffic rules that scale without IP address management.
The Problem with IP-Based NSG Rules at Scale:
Traditional NSG rules reference source and destination IP addresses or CIDR ranges:
As environments grow, IP ranges change, new subnets are added, and VM IPs evolve — NSG rules referencing specific IPs require continuous manual updates. Stale IP-based rules create security gaps (rules still permitting traffic to decommissioned IPs) and operational complexity (tracking which IPs map to which workloads across environments).
ASG-Based Rules — Workload Identity Over IP Address:
ASGs group VMs by workload role — NSG rules reference ASG membership rather than IP addresses:
hcl
VM ASG Association:
hcl
ASG Segmentation Design:
ASG | Workload Members | Permitted Inbound | Permitted Outbound |
|---|---|---|---|
asg-web-tier | Web application VMs | Load Balancer (HTTP/HTTPS) | asg-app-tier (8080) |
asg-app-tier | Application logic VMs | asg-web-tier (8080) | asg-db-tier (1433) |
asg-db-tier | Database VMs | asg-app-tier (1433) | None — deny all |
asg-management | Jumpbox/Bastion VMs | BastionSubnet (RDP/SSH) | asg-web-tier, asg-app-tier, asg-db-tier (RDP/SSH) |
asg-monitoring | Monitoring agents | asg-* (metrics ports) | Log Analytics endpoints |
Operational Benefits of ASG-Based Segmentation:
New VMs automatically inherit correct security rules by joining the appropriate ASG — no NSG rule updates required
VM migrations and IP changes require no NSG rule modifications — ASG membership is independent of IP address
Security rules remain readable and auditable — "web tier can reach app tier on port 8080" is expressed directly rather than inferred from IP ranges
Environment promotion (dev → staging → prod) uses identical NSG rule sets with different ASG memberships — no environment-specific rule rewriting
2. DevSecOps Pipeline Integration — Security Scanning in IaC Workflows
Security scanning is embedded at every stage of the infrastructure delivery lifecycle — from developer workstation through pull request validation to pre-deployment pipeline gates.
Security Scanning Toolchain:
Tool | Stage | Purpose | Blocking |
|---|---|---|---|
tfsec | Local + PR + Pipeline | Terraform security misconfiguration detection | Yes — critical findings |
Checkov | Pipeline validation | CIS Azure benchmark compliance scanning | Yes — critical findings |
Microsoft Defender for DevOps | Pipeline | Azure security posture integration | Advisory |
terraform validate | Pipeline | HCL syntax and provider schema validation | Yes |
terrascan | Pipeline | Multi-framework policy scanning | Yes — critical findings |
Pipeline Security Integration Architecture:
yaml
Security Finding Severity Treatment:
Severity | tfsec | Checkov | Pipeline Action |
|---|---|---|---|
Critical | Block deployment | Block deployment | Pipeline fails — no exceptions |
High | Block deployment | Block deployment | Pipeline fails — requires fix or suppression with justification |
Medium | Advisory warning | Advisory warning | Pipeline continues — tracked in results |
Low | Advisory | Advisory | Logged only |
Suppression Management — Handling Justified Exceptions:
Not all security scanner findings represent actual vulnerabilities — some are intentional configurations appropriate for the specific context. Suppressions must be explicit, documented, and version-controlled:
hcl
yaml
Suppressions are reviewed during pull request code review — requiring justification comment before merge approval. Suppression accumulation is monitored — growing suppression lists indicate security debt requiring remediation.
Developer Shift-Left Security:
tfsec and Checkov run locally through pre-commit hooks — developers receive security feedback before committing code:
yaml
Security findings are caught at the developer workstation — the cheapest and fastest point in the delivery lifecycle to identify and fix misconfigurations.
3. Policy-as-Code — Azure Policy Managed Through Terraform
Azure Policy definitions, initiatives, and assignments are managed as version-controlled Terraform code — ensuring compliance controls are deployed consistently across environments through the same IaC governance model as infrastructure.
Why Policy-as-Code Matters:
Manually configured Azure Policy through the portal creates the same governance problems as manually deployed infrastructure — inconsistent application across environments, no version history, no deployment audit trail, and no automated testing of policy definitions before production assignment.
Terraform-Managed Policy Architecture:
hcl
Policy Initiative — Zero Trust Security Baseline:
Policy | Effect | Enforcement Scope |
|---|---|---|
Deny public IP assignment to VMs | Deny | All resource groups |
Require diagnostic settings on all resources | DeployIfNotExists | All resource groups |
Enforce Managed Identity — deny service principal secrets in Key Vault | Audit | All resource groups |
Require TLS 1.2 minimum on storage accounts | Deny | All resource groups |
Restrict allowed Azure regions | Deny | Subscription |
Require resource tagging (environment, owner, cost-centre) | Deny | All resource groups |
Enforce NSG on all subnets | Audit | Network resource groups |
Managed Identity Enforcement Through Policy:
hcl
Policy Testing Before Production Assignment: Azure Policy definitions are tested in development subscription before assignment to production — using terraform plan to preview policy assignments and Azure Policy compliance simulation to validate policy logic against existing resources before enforcement begins.
4. Secure Administrative Access — Azure Bastion
Azure Bastion provides browser-based RDP/SSH administrative access — eliminating public IP and management port exposure as a platform-enforced architectural requirement rather than a configuration guideline.
Azure Bastion Architecture:
hcl
Bastion Standard SKU Capabilities Used:
Feature | Configuration | Purpose |
|---|---|---|
Native client support | Enabled (tunnelling) | Full RDP/SSH client capability beyond browser |
File copy | Enabled | Administrative file transfer without additional tools |
Shareable links | Disabled | Prevents session URL sharing bypassing authentication |
Session recording | Via Log Analytics | Administrative activity audit trail |
Policy Enforcement of Bastion-Only Access: Azure Policy denies public IP assignment to VMs — enforcing Bastion as the only administrative access path at the platform level rather than relying on configuration discipline:
hcl
5. Managed Identity Architecture
Managed Identity is enforced as the default authentication model through a combination of architectural pattern, Terraform module standards, and Azure Policy auditing.
System-Assigned vs User-Assigned Managed Identity:
Type | Use Case | Lifecycle | This Architecture |
|---|---|---|---|
System-Assigned | Single resource authentication | Tied to resource lifecycle | Default for VM and App Service workloads |
User-Assigned | Shared identity across multiple resources | Independent lifecycle | Used for shared service authentication (monitoring agents, backup) |
Terraform Managed Identity Pattern:
hcl
No Service Principal Credentials in Code — Enforced Through Module Standards: All Terraform modules enforce Managed Identity authentication — any module accepting service principal client secret parameters generates a Checkov finding that blocks pipeline execution.
Architecture Diagram

Technologies Used
Category | Technologies |
|---|---|
Network Segmentation | Application Security Groups (ASGs), NSGs, Azure CNI |
Secure Administrative Access | Azure Bastion (Standard SKU) |
Identity & Access | Microsoft Entra ID, Managed Identity, Azure RBAC |
Security Scanning | tfsec, Checkov, terrascan, Microsoft Defender for DevOps |
Infrastructure as Code | Terraform |
Policy-as-Code | Azure Policy (Deny, Audit, DeployIfNotExists), Policy Initiatives |
CI/CD | Azure DevOps, GitHub Actions, YAML Pipelines |
Monitoring | Azure Monitor, Log Analytics |
Compliance Frameworks | CIS Azure Benchmark, NIST SP 800-53, Zero Trust Architecture (NIST SP 800-207) |
Key Challenges Addressed
NSG rule management at scale without IP address tracking overhead — addressed through ASG-based segmentation replacing IP address references with workload identity group membership — NSG rules remain correct as VMs are added, moved, or retired without rule updates.
Security misconfiguration reaching production through ungoverned IaC — addressed through multi-tool security scanning pipeline integration blocking deployment on critical findings — tfsec, Checkov, and terrascan provide overlapping coverage across different rule sets.
Azure Policy applied inconsistently across environments — addressed through Terraform-managed Policy-as-Code — policy definitions, initiatives, and assignments are version-controlled, environment-parameterised, and deployed through the same CI/CD governance as infrastructure.
Service principal credentials proliferating across workloads — addressed through Managed Identity as the default Terraform module pattern, with Azure Policy auditing detecting and flagging service principal credentials in Key Vault — reducing but not yet eliminating credential-based authentication.
Security findings treated as advisory rather than blocking — addressed through pipeline stage dependency configuration where the Plan stage depends on SecurityValidation stage success — critical security findings cause pipeline failure that prevents plan execution and deployment.
Design Decisions & Rationale
ASGs over IP-Based NSG Rules for Workload Segmentation : IP-based NSG rules create operational debt that compounds with environment complexity. As workloads scale, IPs change, and subnets are reorganised, IP-based rules require continuous maintenance to remain accurate. ASGs abstract segmentation from IP addresses — VMs join ASGs representing their role, and NSG rules govern ASG-to-ASG communication. New VMs automatically inherit correct security policy through ASG membership without any NSG rule modification.
Multi-Tool Security Scanning over Single Scanner : No single security scanning tool has complete rule coverage — tfsec, Checkov, and terrascan each identify findings that others miss. Overlapping but distinct rule sets provide more comprehensive misconfiguration detection than any single tool. The operational overhead of maintaining multiple scanner configurations is justified by the detection coverage improvement — particularly for compliance-sensitive environments where missed findings carry regulatory consequences.
Policy-as-Code over Portal-Configured Azure Policy : Manually configured Azure Policy through the portal is not version-controlled — there is no audit trail of who created a policy, when it was modified, or what it previously contained. Terraform-managed Policy-as-Code applies the same engineering discipline to compliance controls as to infrastructure — version history, code review, deployment pipeline governance, and consistent application across environments.
Deny Effect for Critical Controls, Audit for Softer Controls : Azure Policy Deny effect prevents non-compliant resources from being deployed — appropriate for controls where non-compliance represents a security risk that must never reach production (public IP on VMs, missing TLS minimum). Audit effect reports non-compliance without blocking deployment — appropriate for controls where non-compliance is a governance concern but not an immediate security risk. Using Deny excessively creates operational friction; using Audit for security-critical controls creates security gaps.
Azure Bastion Standard over Basic SKU : Bastion Basic SKU provides browser-based access only — limiting administrative workflows for engineers requiring native RDP/SSH client capabilities. Standard SKU tunnelling enables native client support, providing full RDP/SSH client functionality through the Bastion tunnel without public IP exposure. The cost premium for Standard SKU is justified by the operational capability improvement for engineering teams with native client tooling dependencies.
Trade-offs & Design Constraints
ASG Regional Limitation : ASGs are regional resources — an ASG in East US cannot be referenced in NSG rules applied to resources in West Europe. Multi-region architectures require separate ASG definitions per region with identical naming conventions to maintain rule consistency. Terraform modules must account for regional ASG replication when designing multi-region deployments.
Security Scanner False Positive Management Overhead : Running three security scanners generates significantly more findings than a single scanner — including more false positives requiring suppression management. Without systematic suppression review processes, suppression lists grow unchecked until engineers disable findings rather than address them. Suppression governance — requiring justification comments, code review approval, and periodic suppression audit — is an ongoing operational requirement for multi-scanner DevSecOps pipelines.
Policy DeployIfNotExists Remediation Timing : DeployIfNotExists policies deploy remediation resources after the primary resource is created — with a processing delay. Infrastructure deployed through Terraform may complete successfully before Policy remediation runs, creating a window where resources exist without required configurations. Terraform should explicitly configure Policy-remediable settings (diagnostic settings, tag values) rather than relying on Policy remediation for Terraform-managed resources — using Policy remediation only for resources deployed outside IaC governance.
Azure Policy Deny Effect and Terraform Plan Accuracy : Terraform plan output shows planned resource creation as successful — Azure Policy Deny effect rejection occurs at deployment time, not plan time. A Terraform plan against an environment with Deny policies may show successful resource creation that will actually fail during apply if the resource violates a policy. terraform plan does not evaluate Azure Policy — teams must understand that plan success does not guarantee apply success in Policy-governed environments.
Bastion Standard SKU Cost : Azure Bastion Standard SKU has an hourly availability charge regardless of active sessions. For environments with infrequent administrative activity, Bastion represents a significant per-hour cost for a service used occasionally. Bastion cannot currently be stopped and started — it runs continuously once deployed. Cost modelling against actual administrative session frequency should validate Bastion Standard SKU justification compared to Basic SKU or jumpbox VM alternatives.
Projected Outcomes
The architecture is designed to deliver the following security and operational outcomes in a production enterprise environment:
ASG-based network segmentation scaling with workload growth without IP address management overhead or stale rule accumulation
Security misconfiguration prevention through pipeline-blocking tfsec, Checkov, and terrascan scanning before any infrastructure reaches deployment
Consistent compliance enforcement across all environments through Terraform-managed Azure Policy deployed through the same CI/CD governance as infrastructure
Managed Identity as the default authentication model — no service principal credentials in workload configurations
Complete administrative activity audit trail through Azure Bastion session logging without public IP or management port exposure
Shift-left security feedback through pre-commit hooks providing developer-workstation security scanning before code is committed
Policy compliance state continuously reportable on demand — not requiring manual point-in-time evidence collection
Future Evolution
OPA/Conftest integration for Terraform plan-time policy validation — evaluating planned resource configurations against governance rules before apply, closing the plan-to-apply policy evaluation gap
Automated drift detection through scheduled Terraform plan runs detecting out-of-band resource modifications that bypass IaC governance
Microsoft Defender for DevOps dashboard integration providing unified security posture visibility across pipeline scan results, Azure Policy compliance, and Defender for Cloud recommendations
Continuous compliance validation pipelines running compliance scans against deployed infrastructure state rather than only pre-deployment code
AI-assisted misconfiguration detection through GitHub Copilot for Security or similar tooling providing real-time IaC security guidance during development
Multi-cloud ASG equivalent governance — extending workload-centric segmentation patterns to AWS Security Groups and GCP firewall tags through unified Terraform module standards
Automated policy exemption lifecycle management — tracking, reviewing, and expiring Azure Policy exemptions through IaC-governed workflows
Key Takeaways
Application Security Groups eliminate IP address management overhead for NSG rule governance — workload identity-based segmentation scales with environment complexity where IP-based rules create compounding maintenance debt
DevSecOps security scanning must be blocking, not advisory — advisory-only findings are systematically ignored under delivery pressure; blocking pipeline failure is the only effective enforcement model
Multi-tool security scanning provides meaningfully better coverage than single-tool approaches — tfsec, Checkov, and terrascan each identify distinct finding categories that justify managing multiple scanner configurations
Policy-as-Code through Terraform is the correct governance model for Azure Policy — portal-configured policies are ungoverned, unversioned, and inconsistently applied across environments
Azure Policy Deny effect does not surface in Terraform plan output — teams must test policy behaviour explicitly rather than assuming plan success predicts apply success
Managed Identity enforcement requires both architectural pattern and policy auditing — architecture defines the default, policy detects violations, and pipeline scanning prevents misconfigurations from reaching deployment
Security-as-code is not a tool selection — it is a cultural and process commitment to embedding security validation at every stage of the infrastructure delivery lifecycle
