Advanced

Strategic DevSecOps Foundations for Azure Kubernetes Service (AKS)

DevSecOps for AKS — identity, workloads, network, secrets and continuous compliance.

Level: Intermediate / Advanced Last Updated: June 2026

Table of Contents

  1. Introduction to DevSecOps
  2. Module 1 – Implementing DevSecOps with AKS
  3. Module 2 – Securing Identity and Access
  4. Module 3 – Securing AKS Workloads
  5. Module 4 – Securing the AKS Network
  6. Module 5 – Storing and Managing Secrets
  7. Module 6 – Governance and Continuous Compliance
  8. Complete Code Examples
  9. Comparative Tables
  10. Glossary

Introduction to DevSecOps

Why Traditional Security Fails in Cloud-Native Environments

For decades, application security operated on a waterfall model: development teams built the product, operations teams deployed it, and security teams conducted audits or penetration tests at the end of the cycle. This model, while effective in monolithic slow-release environments, is totally inadequate in the era of microservices, containers, and continuous deployment.

In a Kubernetes cluster, a single vulnerability in a container image can compromise the entire workload. A poorly protected secret in a YAML manifest can expose credentials to malicious actors. A missing Network Policy can allow a compromised Pod to spread laterally to all other namespaces. These risks are real, documented, and occur in production in companies of all sizes.

DevSecOps addresses this problem by integrating security at every stage of the software development lifecycle (SDLC), from the planning phase to post-deployment operations. It’s no longer the exclusive responsibility of a specialized team: it’s a shared responsibility between developers, operators, and security teams.

The “Shift Left” Philosophy

The concept of “Shift Left” is fundamental in DevSecOps. It designates moving security controls toward the initial phases of the delivery pipeline, rather than at the end of the chain.

OLD MODEL:
Plan → Dev → Build → Test → [Security] → Release → Ops

NEW MODEL (Shift Left):
[Security] → Plan → [Security] → Dev → [Security] → Build → [Security] → Test → [Security] → Release → [Security] → Ops

The economic logic is simple: fixing a vulnerability found in a developer’s IDE takes a few minutes. The same vulnerability found in production can cost days of incident, data loss, regulatory penalties, and major reputation damage.

graph LR
    A[IDE / Dev] -->|Cost: 1x| B[Build]
    B -->|Cost: 10x| C[Test QA]
    C -->|Cost: 100x| D[Staging]
    D -->|Cost: 1000x| E[Production]
    
    style A fill:#22c55e,color:#fff
    style B fill:#84cc16,color:#fff
    style C fill:#eab308,color:#000
    style D fill:#f97316,color:#fff
    style E fill:#ef4444,color:#fff

Fundamental rule: The earlier a vulnerability is discovered in the SDLC, the less expensive it is to fix. The ratio is estimated at 1:10:100:1000 between IDE, build, staging and production detection.

DevOps vs DevSecOps: Comparison

DimensionDevOpsDevSecOps
Main objectiveSpeed and delivery reliabilitySpeed + reliability + integrated security
Security responsibilitySeparate security teamShared between Dev, Ops, Sec
Control timingEnd of pipeline (pentest)Each phase (shift left)
Security testingManual and periodicAutomated and continuous
Secret managementEnvironment variables, configsVault, Managed Identities, OIDC
CompliancePeriodic auditsContinuous compliance (Azure Policy)
IncidentsReactive after the factProactive detection + rapid response

Module 1 – Implementing DevSecOps with AKS

DevSecOps Pipeline Overview for AKS

flowchart TD
    subgraph PLAN["Plan Phase"]
        P1[Azure Landing Zones]
        P2[Threat Modeling]
        P3[WAF Assessment]
        P4[Governance & RBAC]
    end
    
    subgraph DEV["Develop Phase"]
        D1[SAST - SonarLint/Snyk]
        D2[Linting - ESLint/pylint]
        D3[kube-score/kube-bench]
        D4[Secret Detection IDE]
    end
    
    subgraph BUILD["Build Phase"]
        B1[Automated Tests]
        B2[Dependency Scanning - Trivy]
        B3[Image Signing - Notation]
        B4[Secret Scanning]
        B5[GitHub Dependency Review]
    end
    
    subgraph RELEASE["Release Phase"]
        R1[Protected Branches]
        R2[GitOps - Flux/ArgoCD]
        R3[DAST - OWASP ZAP]
        R4[Workload Identity]
        R5[Approval Gates]
    end
    
    subgraph OPS["Operate Phase"]
        O1[Azure Policy + Gatekeeper]
        O2[Network Policies]
        O3[Defender for Containers]
        O4[Microsoft Sentinel]
        O5[AKS Upgrades]
    end
    
    PLAN --> DEV --> BUILD --> RELEASE --> OPS
    OPS -->|Continuous feedback| PLAN
    
    style PLAN fill:#3b82f6,color:#fff
    style DEV fill:#8b5cf6,color:#fff
    style BUILD fill:#f59e0b,color:#000
    style RELEASE fill:#10b981,color:#fff
    style OPS fill:#ef4444,color:#fff

Planning Phase: Building a Secure Foundation

Azure Landing Zones

An Azure Landing Zone is a reference architecture that provides a secure, scalable and modular foundation for deploying workloads in Azure. It is not a product to install, but an architectural approach that integrates governance from the design stage.

Azure Landing Zone Structure:

graph TD
    subgraph MG["Management Group Hierarchy"]
        ROOT[Root Management Group]
        PLATFORM[Platform MG]
        APP[Application MG]
        
        ROOT --> PLATFORM
        ROOT --> APP
        
        subgraph PLAT_SUBS["Platform Subscriptions"]
            IDENT[Identity Subscription]
            CONN[Connectivity Subscription]
            MGMT[Management Subscription]
        end
        
        subgraph APP_SUBS["Application Subscriptions"]
            PROD[Production AKS Sub]
            NONPROD[Non-Prod AKS Sub]
            SAND[Sandbox Sub]
        end
        
        PLATFORM --> PLAT_SUBS
        APP --> APP_SUBS
    end
    
    style ROOT fill:#1e40af,color:#fff
    style PLATFORM fill:#3b82f6,color:#fff
    style APP fill:#10b981,color:#fff

Key Components of an AKS Landing Zone:

ComponentDescriptionAzure Service
Centralized identityAAD tenant, PIM, Conditional AccessMicrosoft Entra ID
Hub connectivityVNet peering, ExpressRoute, VPNAzure Virtual Network
Shared securityFirewall, DDoS, WAFAzure Firewall, Front Door
Centralized monitoringLogs, metrics, alertsAzure Monitor, Log Analytics
GovernancePolicies, RBAC, BlueprintsAzure Policy, RBAC
AKS workloadCluster, ACR, Key VaultAKS, ACR, Key Vault

Well-Architected Framework (WAF) Applied to AKS

mindmap
  root((WAF AKS))
    Reliability
      Multi-zone node pools
      Pod disruption budgets
      Health probes
      Auto-scaling HPA/KEDA
    Security
      Workload Identity
      Network Policies
      Private cluster
      Azure Policy Gatekeeper
    Cost Optimization
      Right-sizing nodes
      Spot node pools
      Resource quotas
      Cluster autoscaler
    Operational Excellence
      GitOps Flux
      Monitoring Prometheus
      Alerting Grafana
      Upgrade automation
    Performance Efficiency
      Node selectors
      Resource limits/requests
      Horizontal scaling
      Vertical Pod Autoscaler

Threat Modeling with STRIDE

LetterThreatAKS ExampleCountermeasure
SSpoofingPod impersonating another serviceWorkload Identity + mTLS
TTamperingMalicious modification of imagesImage signing (Notation) + Ratify
RRepudiationUntraceable actions in clusterAudit logs + Microsoft Sentinel
IInformation DisclosureSecrets exposed in manifestsAzure Key Vault + CSI Driver
DDenial of ServicePod consuming all resourcesLimitRange + ResourceQuota
EElevation of PrivilegeContainer running as rootSecurityContext + PodSecurity

Governance with Azure Policy

# Enable the Azure Policy add-on for AKS
az aks enable-addons \
    --resource-group myRG \
    --name myCluster \
    --addons azure-policy

# Assign CIS compliance policy
az policy assignment create \
    --name "aks-cis-benchmark" \
    --scope "/subscriptions/{subId}/resourceGroups/{rg}/providers/Microsoft.ContainerService/managedClusters/{cluster}" \
    --policy-set-definition "a8640138-9b0a-4a28-b8cb-1666c838647d" \
    --display-name "AKS CIS Benchmark"

Important AKS Policies:

PolicyDescriptionEffect
Kubernetes cluster pods should not use host networkPrevents Pods from using host networkDeny
Kubernetes clusters should not allow container privilege escalationPrevents privilege escalationDeny
Kubernetes cluster containers should not share the host process ID namespacePID isolationDeny
Kubernetes cluster should use authorized IP rangesRestricts API server accessAudit

Development Phase: Securing the Developer Environment

Static Application Security Testing (SAST)

SAST analyzes source code without executing it. It is the earliest form of vulnerability detection and can be integrated directly into the developer’s IDE.

Linting and static analysis tools:

ToolLanguage(s)Analysis TypeIDE Integration
ESLintJavaScript/TypeScriptSyntax, style, bugsVS Code, WebStorm
pylintPythonErrors, PEP8 styleVS Code, PyCharm
SonarLintJava, JS, Python, C#Bugs, vulnerabilities, smellsVS Code, IntelliJ
HadolintDockerfileDocker best practicesVS Code
checkovTerraform, K8s, ARMIaC misconfigurationsVS Code, CLI

Container and Kubernetes Scanning with Trivy

# Installation
brew install aquasecurity/trivy/trivy  # macOS

# Scan a Docker image
trivy image nginx:latest

# Scan with severity threshold (fail if CRITICAL or HIGH)
trivy image --exit-code 1 --severity HIGH,CRITICAL nginx:latest

# Scan Kubernetes directory
trivy config ./kubernetes/

# Scan IaC files
trivy fs --security-checks config .

Kubernetes Validation with kube-bench and kube-score

# kube-bench: CIS Kubernetes compliance
kubectl apply -f https://raw.githubusercontent.com/aquasecurity/kube-bench/main/job.yaml
kubectl logs job/kube-bench

# kube-score: Kubernetes manifest analysis
kube-score score deployment.yaml

Build Phase: Securing the Build Pipeline

GitHub Actions Pipeline for AKS

name: AKS DevSecOps Pipeline

on:
  push:
    branches: [main, develop]
  pull_request:
    branches: [main]

env:
  ACR_NAME: myacr.azurecr.io
  IMAGE_NAME: my-app
  CLUSTER_NAME: my-aks-cluster
  RESOURCE_GROUP: my-resource-group

permissions:
  id-token: write      # For OIDC with Azure
  contents: read
  security-events: write

jobs:
  security-scan:
    name: Security Scan & SAST
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v4
        with:
          fetch-depth: 0

      - name: Run Gitleaks (secret detection)
        uses: gitleaks/gitleaks-action@v2
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

      - name: Dependency Review
        uses: actions/dependency-review-action@v3
        if: github.event_name == 'pull_request'
        with:
          fail-on-severity: high

      - name: SonarCloud Scan
        uses: SonarSource/sonarcloud-github-action@master
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}

      - name: Validate K8s manifests with kube-score
        run: |
          curl -L https://github.com/zegl/kube-score/releases/download/v1.17.0/kube-score_1.17.0_linux_amd64 -o kube-score
          chmod +x kube-score
          find ./kubernetes -name "*.yaml" | xargs ./kube-score score --exit-one-on-warning

      - name: Checkov IaC Scan
        uses: bridgecrewio/checkov-action@master
        with:
          directory: .
          framework: kubernetes,dockerfile
          output_format: sarif
          output_file_path: reports/checkov.sarif

  build-and-scan:
    name: Build, Scan & Sign Image
    needs: security-scan
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v4

      - name: Azure Login (OIDC)
        uses: azure/login@v1
        with:
          client-id: ${{ secrets.AZURE_CLIENT_ID }}
          tenant-id: ${{ secrets.AZURE_TENANT_ID }}
          subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}

      - name: Login to ACR
        run: az acr login --name ${{ env.ACR_NAME }}

      - name: Build Docker image
        uses: docker/build-push-action@v5
        with:
          context: .
          push: false
          tags: ${{ env.ACR_NAME }}/${{ env.IMAGE_NAME }}:${{ github.sha }}

      - name: Trivy image vulnerability scan
        uses: aquasecurity/trivy-action@master
        with:
          image-ref: ${{ env.ACR_NAME }}/${{ env.IMAGE_NAME }}:${{ github.sha }}
          format: sarif
          output: trivy-results.sarif
          severity: CRITICAL,HIGH
          exit-code: '1'

      - name: Push image to ACR
        if: success()
        run: docker push ${{ env.ACR_NAME }}/${{ env.IMAGE_NAME }}:${{ github.sha }}

  deploy-staging:
    name: Deploy to Staging (GitOps)
    needs: build-and-scan
    runs-on: ubuntu-latest
    environment: staging
    steps:
      - name: Update GitOps repository
        run: |
          git clone https://github.com/my-org/gitops-repo.git
          cd gitops-repo
          sed -i "s|image: .*my-app:.*|image: ${{ env.ACR_NAME }}/${{ env.IMAGE_NAME }}:${{ github.sha }}|g" \
            environments/staging/deployment.yaml
          git commit -am "feat: update my-app to ${{ github.sha }}"
          git push

Module 2 – Securing Identity and Access

Workload Identity

Workload Identity allows AKS pods to access Azure resources without storing any credentials.

# ServiceAccount with Workload Identity
apiVersion: v1
kind: ServiceAccount
metadata:
  name: my-app-sa
  namespace: production
  annotations:
    azure.workload.identity/client-id: "${USER_ASSIGNED_CLIENT_ID}"
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-app
  namespace: production
spec:
  template:
    metadata:
      labels:
        azure.workload.identity/use: "true"
    spec:
      serviceAccountName: my-app-sa
      containers:
      - name: app
        image: myacr.azurecr.io/my-app:v1.0.0
# Create the User Assigned Identity
az identity create \
    --name my-app-identity \
    --resource-group myRG

# Create the Federated Credential
az identity federated-credential create \
    --name my-app-federated-credential \
    --identity-name my-app-identity \
    --resource-group myRG \
    --issuer "$(az aks show --name myCluster --resource-group myRG --query 'oidcIssuerProfile.issuerUrl' -o tsv)" \
    --subject "system:serviceaccount:production:my-app-sa"

# Assign RBAC role to the identity
az role assignment create \
    --role "Key Vault Secrets User" \
    --assignee "$(az identity show --name my-app-identity --resource-group myRG --query clientId -o tsv)" \
    --scope "$(az keyvault show --name myKeyVault --query id -o tsv)"

Azure RBAC for Kubernetes

# Grant a user Kubernetes Cluster Admin access via Azure RBAC
az role assignment create \
    --role "Azure Kubernetes Service Cluster Admin Role" \
    --assignee "user@company.com" \
    --scope "$(az aks show --name myCluster --resource-group myRG --query id -o tsv)"

# Developer access (namespace limited)
az role assignment create \
    --role "Azure Kubernetes Service Cluster User Role" \
    --assignee "dev-user@company.com" \
    --scope "$(az aks show --name myCluster --resource-group myRG --query id -o tsv)"

Module 3 – Securing AKS Workloads

Pod Security Standards

# Enforce security context on all pods
apiVersion: v1
kind: Namespace
metadata:
  name: production
  labels:
    pod-security.kubernetes.io/enforce: restricted
    pod-security.kubernetes.io/audit: restricted
    pod-security.kubernetes.io/warn: restricted
---
# Secure deployment
apiVersion: apps/v1
kind: Deployment
metadata:
  name: secure-app
  namespace: production
spec:
  template:
    spec:
      securityContext:
        runAsNonRoot: true
        runAsUser: 10001
        fsGroup: 10001
        seccompProfile:
          type: RuntimeDefault
      containers:
      - name: app
        image: myacr.azurecr.io/my-app:v1.0.0
        securityContext:
          allowPrivilegeEscalation: false
          readOnlyRootFilesystem: true
          capabilities:
            drop:
            - ALL
        resources:
          requests:
            cpu: "100m"
            memory: "128Mi"
          limits:
            cpu: "500m"
            memory: "512Mi"

ResourceQuota and LimitRange

# ResourceQuota per namespace
apiVersion: v1
kind: ResourceQuota
metadata:
  name: production-quota
  namespace: production
spec:
  hard:
    requests.cpu: "4"
    requests.memory: 8Gi
    limits.cpu: "8"
    limits.memory: 16Gi
    count/pods: "20"
---
# LimitRange to enforce defaults
apiVersion: v1
kind: LimitRange
metadata:
  name: default-limits
  namespace: production
spec:
  limits:
  - default:
      cpu: 200m
      memory: 256Mi
    defaultRequest:
      cpu: 50m
      memory: 64Mi
    type: Container

Module 4 – Securing the AKS Network

Network Policies

# Default: deny all ingress traffic
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-deny-ingress
  namespace: production
spec:
  podSelector: {}
  policyTypes:
  - Ingress
---
# Allow only specific traffic
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-api-to-db
  namespace: production
spec:
  podSelector:
    matchLabels:
      app: database
  policyTypes:
  - Ingress
  ingress:
  - from:
    - podSelector:
        matchLabels:
          app: api
    ports:
    - protocol: TCP
      port: 5432

Private AKS Cluster

# Create a private cluster
az aks create \
    --resource-group myRG \
    --name privateCluster \
    --enable-private-cluster \
    --enable-managed-identity \
    --node-count 3 \
    --enable-azure-policy \
    --enable-azure-rbac \
    --network-plugin azure \
    --generate-ssh-keys

# Verify private cluster
az aks show --name privateCluster --resource-group myRG \
    --query "apiServerAccessProfile.enablePrivateCluster"

Module 5 – Storing and Managing Secrets

Azure Key Vault with CSI Driver

# Install the Secrets Store CSI Driver
az aks enable-addons \
    --addons azure-keyvault-secrets-provider \
    --name myCluster \
    --resource-group myRG
# SecretProviderClass to access Key Vault
apiVersion: secrets-store.csi.x-k8s.io/v1
kind: SecretProviderClass
metadata:
  name: azure-kvname-workload-identity
  namespace: production
spec:
  provider: azure
  parameters:
    usePodIdentity: "false"
    clientID: "${USER_ASSIGNED_CLIENT_ID}"
    keyvaultName: "myKeyVault"
    cloudName: ""
    objects: |
      array:
        - |
          objectName: database-password
          objectType: secret
        - |
          objectName: api-key
          objectType: secret
    tenantId: "${TENANT_ID}"
  secretObjects:
  - data:
    - key: password
      objectName: database-password
    secretName: db-credentials
    type: Opaque

Module 6 – Governance and Continuous Compliance

Azure Policy Gatekeeper Constraints

# Constraint: Require container security context
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sRequireSecurityContext
metadata:
  name: require-security-context
spec:
  match:
    kinds:
    - apiGroups: [""]
      kinds: ["Pod"]
    excludedNamespaces: ["kube-system"]
  parameters:
    allowPrivilegeEscalation: false
    runAsNonRoot: true
    readOnlyRootFilesystem: true

Microsoft Defender for Containers

# Enable Defender for Containers
az security pricing create \
    --name Containers \
    --tier Standard

# View container security recommendations
az security assessment list \
    --query "[?properties.metadata.categories[0]=='Compute'].{Name:displayName,Severity:properties.metadata.severity}" \
    --output table

GitOps with Flux CD

# Install Flux CLI
curl -s https://fluxcd.io/install.sh | sudo bash

# Bootstrap Flux in AKS cluster with GitHub
flux bootstrap github \
    --owner=my-org \
    --repository=gitops-aks \
    --branch=main \
    --path=clusters/production \
    --personal \
    --token-auth
# HelmRelease via GitOps
apiVersion: helm.toolkit.fluxcd.io/v2beta1
kind: HelmRelease
metadata:
  name: my-app
  namespace: production
spec:
  interval: 5m
  chart:
    spec:
      chart: my-app
      version: ">=1.0.0"
      sourceRef:
        kind: HelmRepository
        name: my-charts
        namespace: flux-system
  values:
    image:
      repository: myacr.azurecr.io/my-app
      tag: "v1.0.0"

Comparative Tables

Security Tools for AKS

ToolCategoryPhaseCoverage
TrivyVulnerability scanningBuild + RuntimeImages, IaC, OS packages
GitleaksSecret detectionDevelop + BuildGit history
kube-scoreK8s best practicesDevelop + BuildManifests
kube-benchCIS complianceRuntimeNode + cluster
OPA GatekeeperPolicy enforcementRuntimeAll K8s resources
FalcoRuntime threat detectionRuntimeSyscalls, containers
NotationImage signingBuildContainer images
RatifyImage verificationRuntimeSigned images
Flux CDGitOpsRelease + OpsK8s configurations
Azure PolicyComplianceAll phasesAzure + K8s resources
Defender for ContainersRuntime securityRuntimeClusters, images

AKS Security Levels

LevelConfigurationToolsCompliance
BasicRBAC, Network PoliciesTrivy, kube-scoreCIS L1
Standard+ Workload Identity, Private cluster+ OPA GatekeeperCIS L2
Advanced+ Image signing, mTLS, Falco+ Ratify, NotationNIST, SOC2
Enterprise+ Landing Zone, full audit+ Sentinel, DefenderPCI-DSS, HIPAA

Glossary

TermDefinition
AKSAzure Kubernetes Service — Microsoft’s managed Kubernetes service
Cluster AutoscalerAutomatically adjusts node count based on Pod resource requirements
CSI DriverContainer Storage Interface — standardized driver for integrating storage in K8s
DevSecOpsIntegration of security in all phases of DevOps
DPoPDemonstration of Proof-of-Possession — token binding protocol
FalcoOpen-source runtime security tool based on system calls
Flux CDOpen-source GitOps operator for Kubernetes
GitOpsPractice of using Git as single source of truth for K8s configurations
HPAHorizontal Pod Autoscaler — scales Pod replicas based on metrics
KustomizeTool for K8s manifest customization without templating
LimitRangeK8s resource defining default resource constraints per namespace
NAMESPACEKubernetes virtual cluster for resource isolation
NotationCNCF tool for signing container images
OPAOpen Policy Agent — general-purpose policy engine
GatekeeperOPA-based admission controller for Kubernetes
PodSmallest deployable unit in Kubernetes (one or more containers)
Pod Security StandardsK8s security profiles (privileged, baseline, restricted)
RatifyTool that verifies image signatures and attestations in AKS
RBACRole-Based Access Control — role-based access control
ResourceQuotaK8s resource limiting total resource consumption per namespace
SecurityContextSecurity configuration applied to a Pod or container
Service AccountKubernetes identity for pods to access the K8s API
Shift LeftMoving security controls toward early phases of the SDLC
SASTStatic Application Security Testing — static code analysis
DASTDynamic Application Security Testing — tests on running application
STRIDEThreat modeling framework (Spoofing, Tampering, Repudiation, etc.)
TrivyOpen-source vulnerability scanner for images, IaC and file systems
VPAVertical Pod Autoscaler — automatically adjusts CPU/memory requests
WAFWell-Architected Framework — Microsoft’s architecture best practices framework
Workload IdentityAKS feature for granting pods access to Azure resources without secrets

Search Terms

strategic · devsecops · foundations · azure · kubernetes · service · aks · ci/cd · git · devops · securing · security · phase · pipeline · governance · identity · network · policy

Interested in this course?

Contact us to book it or get a custom training plan for your team.