{"id":3265,"date":"2026-11-06T18:15:35","date_gmt":"2026-11-06T18:15:35","guid":{"rendered":"https:\/\/devsecopsschool.com\/blog\/?p=3265"},"modified":"2026-11-06T18:15:37","modified_gmt":"2026-11-06T18:15:37","slug":"securing-ci-cd-pipelines-with-policy-as-code","status":"publish","type":"post","link":"https:\/\/devsecopsschool.com\/blog\/securing-ci-cd-pipelines-with-policy-as-code\/","title":{"rendered":"Securing CI\/CD Pipelines with Policy as Code"},"content":{"rendered":"\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"572\" src=\"https:\/\/devsecopsschool.com\/blog\/wp-content\/uploads\/2026\/11\/image-10.png\" alt=\"\" class=\"wp-image-3266\" srcset=\"https:\/\/devsecopsschool.com\/blog\/wp-content\/uploads\/2026\/11\/image-10.png 1024w, https:\/\/devsecopsschool.com\/blog\/wp-content\/uploads\/2026\/11\/image-10-300x168.png 300w, https:\/\/devsecopsschool.com\/blog\/wp-content\/uploads\/2026\/11\/image-10-768x429.png 768w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">A release can pass every unit, integration, and performance test, yet still harbor critical misconfigurations\u2014such as an unencrypted S3 bucket, exposed service ports, or a container running with privileged root access. In modern, high-velocity CI\/CD environments where teams push updates dozens of times a day, traditional manual security reviews and static checklists quickly become unworkable operational bottlenecks that let vulnerabilities slip into production. Implementing <strong>Policy as Code for Deployment Security<\/strong> eliminates this blind spot by translating security, compliance, and governance requirements into version-controlled, machine-readable rules. For engineers looking to master these modern delivery guardrails, <strong>DevOpsSchool<\/strong> provides hands-on learning resources in DevOps and DevSecOps, helping teams automate guardrails directly within their pipelines and stop misconfigurations before they ever reach a cluster.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">1. Understanding Policy as Code Beyond the Definition<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Policy as Code (PaC) is the practice of defining, managing, and enforcing security, compliance, and operational governance rules using machine-readable code stored in version control.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Instead of writing security baselines into a static wiki or compliance handbook, engineers express policies in specialized languages (such as Rego, Sentinel, or declarative YAML). These policies run automatically against infrastructure plans, Kubernetes manifests, configuration baselines, and deployment artifacts.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Traditional Governance vs. Policy as Code\n\u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510       \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502     Traditional Governance      \u2502       \u2502         Policy as Code          \u2502\n\u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524       \u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n\u2502 \u2022 Security manuals in wikis     \u2502  vs.  \u2502 \u2022 Version-controlled code repos \u2502\n\u2502 \u2022 Manual checklist sign-offs    \u2502       \u2502 \u2022 Automated pipeline evaluation \u2502\n\u2502 \u2022 Late-stage security reviews   \u2502       \u2502 \u2022 Shift-left CI\/CD guardrails   \u2502\n\u2502 \u2022 Inconsistent human decisions  \u2502       \u2502 \u2022 Deterministic, audited logic  \u2502\n\u2502 \u2022 Periodic, stressful audits    \u2502       \u2502 \u2022 Continuous compliance proofs  \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518       \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Core Characteristics of Policy as Code<\/h3>\n\n\n\n<ol start=\"1\" class=\"wp-block-list\">\n<li><strong>Machine-Readable Rules:<\/strong> Policies are written in programmatic, deterministic formats that parse structured configurations (JSON, YAML, plan files) directly.<\/li>\n\n\n\n<li><strong>Automated Policy Evaluation:<\/strong> Verification occurs automatically within continuous integration pipelines, pre-commit hooks, or admission webhooks without manual human intervention.<\/li>\n\n\n\n<li><strong>Consistent Enforcement:<\/strong> The same policy produces an identical verdict whether executed on an engineer\u2019s laptop, inside a GitHub Actions runner, or at the ingress of a Kubernetes production cluster.<\/li>\n\n\n\n<li><strong>Version-Controlled Definitions:<\/strong> Policies follow standard software development lifecycles. They are committed to Git, reviewed via pull requests, branched, and tagged.<\/li>\n\n\n\n<li><strong>Repeatable Compliance Checks:<\/strong> Compliance is measured continuously on every single commit, generating programmatic records rather than point-in-time audit snapshots.<\/li>\n\n\n\n<li><strong>Auditable Decision Trails:<\/strong> Modern policy engines produce structured evaluation logs that record exactly which inputs were evaluated, which rules fired, and why a change passed or failed.<\/li>\n\n\n\n<li><strong>Native Workflow Integration:<\/strong> Policies operate alongside existing Infrastructure as Code (IaC) and container delivery tooling, functioning as automated tests rather than separate external processes.<\/li>\n<\/ol>\n\n\n\n<h3 class=\"wp-block-heading\">The Ecosystem: How PaC, IaC, and DevSecOps Align<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Policy as Code is not a replacement for Infrastructure as Code (IaC); it is its quality and security control layer. IaC tools such as Terraform, OpenTofu, Pulumi, and CloudFormation define <em>what infrastructure should exist<\/em>. Policy as Code defines <em>what constraints that infrastructure must satisfy<\/em>.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>DevSecOps Lifecycle\n&#091;Code &amp; Commit] \u2500\u2500\u25ba &#091;Build &amp; Scan] \u2500\u2500\u25ba &#091;IaC \/ Manifest Gen] \u2500\u2500\u25ba &#091;Policy as Code Gate] \u2500\u2500\u25ba &#091;Deploy] \u2500\u2500\u25ba &#091;Runtime Admission]\n                                                                        \u2502                                      \u2502\n                                                                 (Blocks Non-Compliant                  (Guards Cluster\n                                                                   Terraform\/K8s)                         State)\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Within a DevSecOps framework, PaC bridges the gap between development agility and information security:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Developers<\/strong> receive immediate, clear feedback directly in their pull requests explaining why a configuration failed and how to remediate it.<\/li>\n\n\n\n<li><strong>Security Teams<\/strong> encode their requirements once as code instead of reviewing thousands of individual infrastructure pull requests manually.<\/li>\n\n\n\n<li><strong>Compliance Teams<\/strong> query Git history and pipeline logs to mathematically prove that deployed infrastructure matches designated regulatory benchmarks (e.g., CIS Benchmarks, SOC 2, HIPAA, PCI-DSS).<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">2. Common Deployment Risks Prevented by Automated Policies<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">When deployment pipelines lack programmatic guardrails, subtle configuration drift and human oversights introduce critical attack vectors. Automated deployment policies target specific, recurring configuration failures:<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><thead><tr><td><strong>Deployment Risk<\/strong><\/td><td><strong>Manifest \/ Infrastructure Target<\/strong><\/td><td><strong>What the Policy Inspects<\/strong><\/td><td><strong>Enforced Action on Violation<\/strong><\/td><\/tr><\/thead><tbody><tr><td><strong>Publicly Exposed Cloud Storage<\/strong><\/td><td>Terraform (<code>aws_s3_bucket<\/code>, <code>google_storage_bucket<\/code>)<\/td><td>Checks public access block settings, ACLs, and bucket policies for open read\/write access.<\/td><td><strong>Block deployment<\/strong>: Reject the plan before cloud provisioning begins.<\/td><\/tr><tr><td><strong>Overly Permissive IAM Roles<\/strong><\/td><td>Terraform, CloudFormation (<code>iam_policy<\/code>)<\/td><td>Scans statements for wildcard actions (<code>Action: \"*\"<\/code>) or wildcard resources (<code>Resource: \"*\"<\/code>).<\/td><td><strong>Block deployment<\/strong>: Enforce principle of least privilege.<\/td><\/tr><tr><td><strong>Privileged Containers<\/strong><\/td><td>Kubernetes (<code>Deployment<\/code>, <code>PodSpec<\/code>)<\/td><td>Evaluates <code>securityContext.privileged<\/code>, requiring it to be explicitly <code>false<\/code> or absent.<\/td><td><strong>Reject Admission \/ Fail CI<\/strong>: Prevent pod execution with kernel-level access.<\/td><\/tr><tr><td><strong>Untrusted Container Images<\/strong><\/td><td>Kubernetes, Dockerfiles<\/td><td>Verifies that image URLs match authorized enterprise registries (e.g., <code>ecr.myorg.internal\/*<\/code>) and prohibit the <code>:latest<\/code> tag.<\/td><td><strong>Block pipeline<\/strong>: Halt artifact building and reject deployment manifests.<\/td><\/tr><tr><td><strong>Missing Resource Limits<\/strong><\/td><td>Kubernetes (<code>PodSpec.containers.resources<\/code>)<\/td><td>Verifies that both CPU and memory <code>requests<\/code> and <code>limits<\/code> are specified.<\/td><td><strong>Warn or Block<\/strong>: Protect cluster nodes against noisy neighbors and memory exhaustion (OOM kills).<\/td><\/tr><tr><td><strong>Unencrypted Data at Rest<\/strong><\/td><td>Terraform (<code>aws_ebs_volume<\/code>, <code>aws_rds_cluster<\/code>)<\/td><td>Validates <code>encrypted = true<\/code> and checks for valid customer-managed KMS key identifiers.<\/td><td><strong>Block deployment<\/strong>: Prevent unencrypted data stores from provisioning.<\/td><\/tr><tr><td><strong>Non-Compliant Cloud Regions<\/strong><\/td><td>Terraform provider configuration and resource attributes<\/td><td>Validates that resources are pinned to legally compliant geographic regions (e.g., <code>eu-west-1<\/code>, <code>us-east-1<\/code>).<\/td><td><strong>Block deployment<\/strong>: Prevent data sovereignty and latency violations.<\/td><\/tr><tr><td><strong>Insecure Network Configurations<\/strong><\/td><td>Terraform security groups, Kubernetes <code>NetworkPolicy<\/code><\/td><td>Identifies inbound rules allowing <code>0.0.0.0\/0<\/code> across management ports (22, 3389, 5432).<\/td><td><strong>Block deployment<\/strong>: Ensure zero public ingress on internal services.<\/td><\/tr><tr><td><strong>Missing Observability &amp; Ownership Metadata<\/strong><\/td><td>Kubernetes manifests, Cloud resources<\/td><td>Verifies required tags\/labels: <code>environment<\/code>, <code>owner<\/code>, <code>service<\/code>, <code>cost-center<\/code>.<\/td><td><strong>Warn or Block<\/strong>: Prevent orphaned, untracked, and unmonitored infrastructure.<\/td><\/tr><tr><td><strong>Root User Execution<\/strong><\/td><td>Kubernetes <code>securityContext<\/code><\/td><td>Enforces <code>runAsNonRoot: true<\/code> and an explicit <code>runAsUser<\/code> ID greater than 0.<\/td><td><strong>Reject Admission<\/strong>: Prevent arbitrary user escalation inside running pods.<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">3. Selecting the Right Policy Engine<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Choosing a Policy as Code engine requires matching the tool&#8217;s evaluation model with your deployment targets and engineering stack.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Policy Engines by Deployment Focus\n\u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502                        General-Purpose &amp; Multi-Target                  \u2502\n\u2502                     Open Policy Agent (OPA) \/ Rego                     \u2502\n\u2502               &#091;Terraform Plans, Kubernetes, Custom JSON, APIs]          \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n                                                 \u2502\n          \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n          \u25bc                                                                             \u25bc\n\u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510                                          \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502  Kubernetes-Native Engines   \u2502                                          \u2502      IaC-Focused Engines     \u2502\n\u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524                                          \u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n\u2502 \u2022 Kyverno (Declarative YAML) \u2502                                          \u2502 \u2022 Checkov (Python \/ Prebuilt)\u2502\n\u2502 \u2022 Gatekeeper (OPA K8s CRDs)  \u2502                                          \u2502 \u2022 HashiCorp Sentinel (HCL)   \u2502\n\u2502                              \u2502                                          \u2502 \u2022 Conftest (OPA Wrapper)     \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518                                          \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">1. Open Policy Agent (OPA) &amp; Rego<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Primary Focus:<\/strong> General-purpose, domain-agnostic policy engine.<\/li>\n\n\n\n<li><strong>Language:<\/strong> Rego (a declarative query language based on Datalog).<\/li>\n\n\n\n<li><strong>Strengths:<\/strong> OPA evaluates any structured data formatted as JSON or YAML. It runs anywhere: as a standalone daemon, a Go library, a CLI utility, or a WebAssembly binary.<\/li>\n\n\n\n<li><strong>Typical Use Cases:<\/strong> Unified policy management across diverse toolchains\u2014microservice authorization, CI\/CD artifact validation, and cloud configuration checks.<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">2. Kyverno<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Primary Focus:<\/strong> Kubernetes-native policy management.<\/li>\n\n\n\n<li><strong>Language:<\/strong> Native Kubernetes Custom Resource Definitions (CRDs) written in standard YAML.<\/li>\n\n\n\n<li><strong>Strengths:<\/strong> Zero requirement to learn a specialized policy language like Rego. Kyverno operates directly as an admission controller inside Kubernetes, offering not only policy validation but also resource mutation (altering manifests on the fly) and generation (auto-creating resources like NetworkPolicies for new namespaces).<\/li>\n\n\n\n<li><strong>Typical Use Cases:<\/strong> Kubernetes platform engineering teams wanting fast adoption using standard Kubernetes tooling.<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">3. HashiCorp Sentinel<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Primary Focus:<\/strong> Native policy framework for the HashiCorp enterprise ecosystem.<\/li>\n\n\n\n<li><strong>Language:<\/strong> Sentinel policy language (imperative\/procedural with declarative logic).<\/li>\n\n\n\n<li><strong>Strengths:<\/strong> Deep, turnkey integration with Terraform Enterprise\/Cloud, Nomad, Consul, and Vault. Features fine-grained enforcement levels (<code>advisory<\/code>, <code>soft-mandatory<\/code>, <code>hard-mandatory<\/code>).<\/li>\n\n\n\n<li><strong>Typical Use Cases:<\/strong> Organizations standardizing strictly on HashiCorp cloud infrastructure platforms.<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">4. Checkov<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Primary Focus:<\/strong> Static analysis for Infrastructure as Code (IaC).<\/li>\n\n\n\n<li><strong>Language:<\/strong> Python or declarative YAML.<\/li>\n\n\n\n<li><strong>Strengths:<\/strong> Comes out of the box with thousands of pre-configured policies mapped to industry compliance frameworks (CIS, NIST, HIPAA, PCI-DSS). Analyzes Terraform, CloudFormation, Helm charts, Dockerfiles, and GitHub Actions workflows directly.<\/li>\n\n\n\n<li><strong>Typical Use Cases:<\/strong> Fast-tracking IaC security scanning in CI\/CD without writing every security rule from scratch.<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">5. Conftest<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Primary Focus:<\/strong> Testing tool using OPA to evaluate configuration files.<\/li>\n\n\n\n<li><strong>Language:<\/strong> Rego.<\/li>\n\n\n\n<li><strong>Strengths:<\/strong> Provides a simple, developer-friendly CLI interface (<code>conftest test<\/code>) tailored for CI\/CD pipelines. It makes validating Kubernetes manifests, Terraform plan outputs, and Dockerfiles straightforward with OPA logic.<\/li>\n\n\n\n<li><strong>Typical Use Cases:<\/strong> Developer workstation checks and CI\/CD validation gates running alongside automated unit tests.<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">Selection Matrix<\/h3>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><thead><tr><td><strong>Criterion<\/strong><\/td><td><strong>Open Policy Agent (OPA)<\/strong><\/td><td><strong>Kyverno<\/strong><\/td><td><strong>HashiCorp Sentinel<\/strong><\/td><td><strong>Checkov<\/strong><\/td><td><strong>Conftest<\/strong><\/td><\/tr><\/thead><tbody><tr><td><strong>Ecosystem Target<\/strong><\/td><td>Agnostic (JSON\/YAML)<\/td><td>Kubernetes Only<\/td><td>HashiCorp Cloud\/Enterprise<\/td><td>Cloud IaC &amp; Containers<\/td><td>Agnostic Files<\/td><\/tr><tr><td><strong>Language<\/strong><\/td><td>Rego<\/td><td>Kubernetes YAML<\/td><td>Sentinel Language<\/td><td>Python \/ YAML<\/td><td>Rego<\/td><\/tr><tr><td><strong>Learning Curve<\/strong><\/td><td>Moderate to High<\/td><td>Low (Native YAML)<\/td><td>Moderate<\/td><td>Low<\/td><td>Moderate<\/td><\/tr><tr><td><strong>Mutation Capabilities<\/strong><\/td><td>Yes (via Gatekeeper)<\/td><td>Yes (Excellent)<\/td><td>No<\/td><td>No<\/td><td>No<\/td><\/tr><tr><td><strong>Out-of-the-Box Rules<\/strong><\/td><td>Minimal (Framework)<\/td><td>Strong Library<\/td><td>Medium<\/td><td>Thousands Prebuilt<\/td><td>Minimal (Framework)<\/td><\/tr><tr><td><strong>Best Stage<\/strong><\/td><td>CI\/CD &amp; Admission<\/td><td>Admission &amp; Runtime<\/td><td>Plan Execution Gate<\/td><td>Pre-commit &amp; CI<\/td><td>Pre-commit &amp; CI<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">4. Designing a Policy-Driven Deployment Security Architecture<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">A complete deployment security architecture enforces policies at multiple, defense-in-depth stages: within the developer environment, during pipeline continuous integration, and finally at admission or runtime.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"> <code>                   POLICY-DRIVEN DEPLOYMENT ARCHITECTURE\n\n Developer Workstation                    CI\/CD Pipeline (Build \/ Release)\n\u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510                \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502 \u2022 Git Pre-Commit Hook \u2502                \u2502 1. Git Push \/ PR Created              \u2502\n\u2502 \u2022 Local Conftest Run  \u2502 \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u25ba \u2502 2. SAST &amp; Container Vulnerability Scan\u2502\n\u2502 \u2022 IDE Linter \/ Policy \u2502                \u2502 3. Policy Gate: Checkov \/ Conftest    \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518                \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n                                                             \u2502\n                                                  Compliant? \u2502\n                                           \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n                                      No   \u2502                   \u2502  Yes\n                                 \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2510      \u250c\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n                                 \u2502 Block Pipeline \u2502      \u2502 Generate Deployment   \u2502\n                                 \u2502 Notify Dev PR  \u2502      \u2502 Artifacts &amp; Plans     \u2502\n                                 \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518      \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n                                                                     \u2502\n                                                                     \u25bc\n                                                         Production Infrastructure\n                                                \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n                                                \u2502 Kubernetes API Server                   \u2502\n                                                \u2502  \u2514\u2500\u25ba Validating Admission Webhook       \u2502\n                                                \u2502       (Gatekeeper \/ Kyverno)            \u2502\n                                                \u2502          \u2502 Validated?                   \u2502\n                                                \u2502          \u251c\u2500\u25ba Pass: Apply to Cluster     \u2502\n                                                \u2502          \u2514\u2500\u25ba Fail: Reject API Request   \u2502\n                                                \u2502                                         \u2502\n                                                \u2502 Cloud Platform (AWS \/ Azure \/ GCP)      \u2502\n                                                \u2502  \u2514\u2500\u25ba Audit Logs &amp; Compliance Engine     \u2502\n                                                \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Architecture Components and Responsibilities<\/h3>\n\n\n\n<ol start=\"1\" class=\"wp-block-list\">\n<li><strong>Policy Repository:<\/strong> A dedicated, version-controlled repository storing organizational policies. Managed primarily by platform and security engineers, updated through pull requests with automated regression tests.<\/li>\n\n\n\n<li><strong>CI\/CD System (e.g., GitHub Actions, Jenkins, GitLab CI):<\/strong> Checks out application code, runs linters, compiles artifacts, generates Terraform execution plans or renders Kubernetes manifests, and invokes policy runners.<\/li>\n\n\n\n<li><strong>Static Policy Engine (e.g., Conftest, Checkov):<\/strong> Parses generated configurations in the CI runner. If violations occur, it halts execution and returns exit code <code>1<\/code>, printing descriptive errors directly to the pipeline logs.<\/li>\n\n\n\n<li><strong>Target Cloud Platform (e.g., AWS, Azure, GCP):<\/strong> Receives approved infrastructure changes, enforcing baseline boundaries through cloud organization policies (e.g., AWS Service Control Policies).<\/li>\n\n\n\n<li><strong>Kubernetes Admission Controller (e.g., Gatekeeper, Kyverno):<\/strong> Intercepts API requests to the Kubernetes cluster (<code>kubectl apply<\/code>, Helm releases, GitOps operators) before resources are persisted to <code>etcd<\/code>. It acts as the final gatekeeper in case non-compliant manifests bypass CI.<\/li>\n\n\n\n<li><strong>Audit and Telemetry Systems:<\/strong> Aggregates policy decisions, passes, and violations into centralized logging and monitoring dashboards (e.g., Elasticsearch, Prometheus, SIEM) for security auditing.<\/li>\n<\/ol>\n\n\n\n<h2 class=\"wp-block-heading\">5. Practical Implementation: Writing Your First Deployment Policy<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">In this hands-on lab, we will build a security policy using <strong>Open Policy Agent (OPA)<\/strong> and evaluate it against a Kubernetes manifest.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Lab Objective<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Write an OPA Rego policy that prevents any container within a Kubernetes <code>Deployment<\/code> from running in <strong>privileged mode<\/strong> (<code>securityContext.privileged: true<\/code>).<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Prerequisites<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Install Open Policy Agent (<code>opa<\/code> executable) locally:Bash<code># Linux\/macOS via curl curl -L -o opa https:\/\/openpolicyagent.org\/downloads\/v0.68.0\/opa_linux_amd64_download chmod +x .\/opa sudo mv .\/opa \/usr\/local\/bin\/opa<\/code><\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">Project Directory Structure<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Create a dedicated working directory:<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Plaintext<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>opa-deployment-security\/\n\u251c\u2500\u2500 policy\/\n\u2502   \u2514\u2500\u2500 secure_pod.rego\n\u2514\u2500\u2500 manifests\/\n    \u251c\u2500\u2500 bad_deployment.yaml\n    \u2514\u2500\u2500 good_deployment.yaml\n<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Step 1: The Deployment Configurations<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Create <code>manifests\/bad_deployment.yaml<\/code>. This manifest violates security best practices by requesting host kernel privileges:<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">YAML<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>apiVersion: apps\/v1\nkind: Deployment\nmetadata:\n  name: payment-processor\n  namespace: finance\n  labels:\n    app: payment-processor\nspec:\n  replicas: 2\n  selector:\n    matchLabels:\n      app: payment-processor\n  template:\n    metadata:\n      labels:\n        app: payment-processor\n    spec:\n      containers:\n        - name: processor\n          image: internal-registry.company.com\/finance\/processor:v1.2.0\n          securityContext:\n            privileged: true\n          ports:\n            - containerPort: 8080\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Next, create <code>manifests\/good_deployment.yaml<\/code>. This compliant manifest explicitly sets privileged mode to <code>false<\/code> and enforces non-root execution:<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">YAML<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>apiVersion: apps\/v1\nkind: Deployment\nmetadata:\n  name: payment-processor\n  namespace: finance\n  labels:\n    app: payment-processor\nspec:\n  replicas: 2\n  selector:\n    matchLabels:\n      app: payment-processor\n  template:\n    metadata:\n      labels:\n        app: payment-processor\n    spec:\n      containers:\n        - name: processor\n          image: internal-registry.company.com\/finance\/processor:v1.2.0\n          securityContext:\n            privileged: false\n            runAsNonRoot: true\n            readOnlyRootFilesystem: true\n          ports:\n            - containerPort: 8080\n<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Step 2: Writing the Policy in Rego<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Create <code>policy\/secure_pod.rego<\/code>:<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Code snippet<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>package deployment.security\n\nimport future.keywords.in\n\n# Default state: allow is false until evaluated rules verify compliance\ndefault allow := false\n\n# The deployment is allowed only if there are zero violations reported\nallow {\n    count(violations) == 0\n}\n\n# Rule: Detect containers running with privileged security context\nviolations&#091;msg] {\n    # Check if the resource is a Kubernetes Deployment\n    input.kind == \"Deployment\"\n    \n    # Navigate through the pod template specification to inspect each container\n    container := input.spec.template.spec.containers&#091;_]\n    \n    # Identify containers where privileged mode is explicitly enabled\n    container.securityContext.privileged == true\n    \n    # Generate an actionable diagnostic message\n    msg := sprintf(\n        \"CONTAINER SECURITY VIOLATION: Container '%v' in Deployment '%v' is running in privileged mode. Privileged containers grant root access to the host kernel and are prohibited.\",<\/code><\/pre>\n\n\n<p>[container.name, input.metadata.name]<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">) } # Rule: Flag containers that lack a defined security context entirely violations[msg] { input.kind == &#8220;Deployment&#8221; container := input.spec.template.spec.containers[_] not container.securityContext msg := sprintf( &#8220;CONTAINER SECURITY VIOLATION: Container &#8216;%v&#8217; in Deployment &#8216;%v&#8217; does not define a securityContext. You must explicitly configure secure runtime privileges.&#8221;,<\/p>\n\n\n<p>[container.name, input.metadata.name]<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">) }<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Understanding the Rego Code Logic<\/h3>\n\n\n\n<ol start=\"1\" class=\"wp-block-list\">\n<li><code>package deployment.security<\/code>: Defines the logical namespace for our policy, allowing modular composition.<\/li>\n\n\n\n<li><code>default allow := false<\/code>: Enforces a secure baseline. Unless our allow conditions are met, the configuration is considered non-compliant.<\/li>\n\n\n\n<li><code>violations[msg]<\/code>: Rego uses set rules. If any condition inside this block resolves to true, the generated string <code>msg<\/code> is added to the <code>violations<\/code> set.<\/li>\n\n\n\n<li><code>container := input.spec.template.spec.containers[_]<\/code>: The <code>[_]<\/code> syntax acts as an iterator. OPA iterates through every container listed inside the pod specification array automatically.<\/li>\n\n\n\n<li><code>container.securityContext.privileged == true<\/code>: This line acts as a filter assertion. If true, the evaluation proceeds to format the violation string.<\/li>\n<\/ol>\n\n\n\n<h3 class=\"wp-block-heading\">Step 3: Evaluating the Policy<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Execute OPA against the insecure configuration:<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Bash<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>opa eval --data policy\/secure_pod.rego \\\n         --input manifests\/bad_deployment.yaml \\\n         \"data.deployment.security\"\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Output:<\/strong><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">JSON<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>{\n  \"result\": &#091;\n    {\n      \"expressions\": &#091;\n        {\n          \"value\": {\n            \"allow\": false,\n            \"violations\": &#091;\n              \"CONTAINER SECURITY VIOLATION: Container 'processor' in Deployment 'payment-processor' is running in privileged mode. Privileged containers grant root access to the host kernel and are prohibited.\"\n            ]\n          },\n          \"text\": \"data.deployment.security\",\n          \"location\": {\n            \"row\": 1,\n            \"col\": 1\n          }\n        }\n      ]\n    }\n  ]\n}\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Now, evaluate the policy against the compliant manifest:<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Bash<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>opa eval --data policy\/secure_pod.rego \\\n         --input manifests\/good_deployment.yaml \\\n         \"data.deployment.security\"\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Output:<\/strong><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">JSON<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>{\n  \"result\": &#091;\n    {\n      \"expressions\": &#091;\n        {\n          \"value\": {\n            \"allow\": true\n          },\n          \"text\": \"data.deployment.security\",\n          \"location\": {\n            \"row\": 1,\n            \"col\": 1\n          }\n        }\n      ]\n    }\n  ]\n}\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The insecure manifest is successfully flagged with an explicit, educational error message, while the compliant manifest is approved for deployment.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">6. Integrating Policy Checks Into a CI\/CD Pipeline<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">To make policy checks effective, they must run as an automated security gate within the continuous integration and delivery pipeline. Below is an enterprise-grade GitHub Actions pipeline demonstrating automated policy validation using <code>conftest<\/code>.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Recommended Repository Organization<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Store policies either in a centralized repository or alongside the application manifest repository:<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Plaintext<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>service-repository\/\n\u251c\u2500\u2500 .github\/\n\u2502   \u2514\u2500\u2500 workflows\/\n\u2502       \u2514\u2500\u2500 deployment-security.yaml\n\u251c\u2500\u2500 policy\/\n\u2502   \u251c\u2500\u2500 k8s\/\n\u2502   \u2502   \u251c\u2500\u2500 privileged.rego\n\u2502   \u2502   \u251c\u2500\u2500 privileged_test.rego\n\u2502   \u2502   \u2514\u2500\u2500 registries.rego\n\u2502   \u2514\u2500\u2500 terraform\/\n\u2502       \u2514\u2500\u2500 s3_encryption.rego\n\u251c\u2500\u2500 k8s\/\n\u2502   \u2514\u2500\u2500 release-manifest.yaml\n\u2514\u2500\u2500 terraform\/\n    \u2514\u2500\u2500 main.tf\n<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">GitHub Actions Workflow<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Create <code>.github\/workflows\/deployment-security.yaml<\/code>:<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">YAML<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>name: \"Continuous Deployment Security &amp; Policy Validation\"\n\non:\n  pull_request:\n    branches:\n      - main\n  push:\n    branches:\n      - main\n\njobs:\n  policy-enforcement:\n    name: \"Enforce Deployment Policies\"\n    runs-on: ubuntu-latest\n\n    steps:\n      - name: \"Checkout Application &amp; Manifests\"\n        uses: actions\/checkout@v4\n\n      - name: \"Install Conftest (OPA CLI Wrapper)\"\n        run: |\n          CONFTEST_VERSION=\"0.51.0\"\n          curl -LO \"https:\/\/github.com\/open-policy-agent\/conftest\/releases\/download\/v${CONFTEST_VERSION}\/conftest_${CONFTEST_VERSION}_Linux_x86_64.tar.gz\"\n          tar xzf \"conftest_${CONFTEST_VERSION}_Linux_x86_64.tar.gz\"\n          sudo mv conftest \/usr\/local\/bin\/\n          conftest --version\n\n      - name: \"Unit Test Policies\"\n        run: |\n          echo \"Executing internal unit tests for policy files...\"\n          conftest verify --policy policy\/\n\n      - name: \"Evaluate Kubernetes Manifests\"\n        run: |\n          echo \"Scanning rendered deployment manifests against security policies...\"\n          # Evaluates files in k8s\/ using policies in policy\/k8s\/\n          conftest test k8s\/release-manifest.yaml \\\n            --policy policy\/k8s\/ \\\n            --namespace k8s.security \\\n            --output table\n\n      - name: \"Generate Policy Audit Summary\"\n        if: always()\n        run: |\n          echo \"Exporting structured JSON audit log for security compliance...\"\n          conftest test k8s\/release-manifest.yaml \\\n            --policy policy\/k8s\/ \\\n            --output json &gt; policy-audit-report.json || true\n\n      - name: \"Archive Policy Audit Artifact\"\n        if: always()\n        uses: actions\/upload-artifact@v4\n        with:\n          name: policy-audit-report\n          path: policy-audit-report.json\n<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Writing Actionable Policy Error Messages<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">When policy gates fail, developers should not have to reverse-engineer obscure Rego queries. A high-quality policy failure message contains three distinct elements:<\/p>\n\n\n\n<ol start=\"1\" class=\"wp-block-list\">\n<li><strong>The exact resource identified:<\/strong> Name, kind, namespace, and field.<\/li>\n\n\n\n<li><strong>The specific security requirement violated:<\/strong> Explain the risk clearly.<\/li>\n\n\n\n<li><strong>The required remediation:<\/strong> Concrete instructions or code snippets showing how to fix it.<\/li>\n<\/ol>\n\n\n\n<p class=\"wp-block-paragraph\">Plaintext<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\u274c POLICY FAILURE: &#091;k8s.security.privileged_container]\n   Resource: apps\/v1 Deployment 'order-service' in namespace 'ecommerce'\n   Field:    spec.template.spec.containers&#091;0].securityContext.privileged\n   Issue:    Container 'backend' explicitly requests privileged kernel access.\n   Fix:      Remove 'privileged: true' from securityContext and set:\n             securityContext:\n               runAsNonRoot: true\n               allowPrivilegeEscalation: false\n               readOnlyRootFilesystem: true\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">7. Applying Policy as Code to Kubernetes Deployments<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">While CI\/CD pipelines check configurations early, a comprehensive deployment security posture requires admission control directly inside the Kubernetes cluster. If a developer runs <code>kubectl apply<\/code> directly, or an automated GitOps operator pulls an unverified commit, <strong>Kubernetes Admission Controllers<\/strong> act as the authoritative gate.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"> <code>                 KUBERNETES ADMISSION POLICY WORKFLOW\n\n API Request: \"kubectl apply -f manifest.yaml\"\n                     \u2502\n                     \u25bc\n       \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n       \u2502   Kubernetes API Server   \u2502\n       \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n                     \u2502\n         Mutating Admission Phase\n                     \u2502 (Injects default labels, sidecars, etc.)\n                     \u25bc\n        Validating Admission Phase \u25c4\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n                     \u2502                         \u2502 Evaluates against\n                     \u25bc                         \u2502 registered policies\n       \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510           \u2502\n       \u2502   Admission Controller    \u2502 \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n       \u2502  (OPA Gatekeeper\/Kyverno) \u2502\n       \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n                     \u2502\n           Passed?   \u2502\n       \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n  Yes  \u2502                           \u2502  No\n       \u25bc                           \u25bc\n[Persist to etcd]          [Reject API Request]\n(Object Created)           (Error returned to client)\n<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">CI-Time Validation vs. Admission-Time Enforcement<\/h3>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><thead><tr><td><strong>Feature<\/strong><\/td><td><strong>CI\/CD Pipeline Policy Check<\/strong><\/td><td><strong>Kubernetes Admission Controller<\/strong><\/td><\/tr><\/thead><tbody><tr><td><strong>Location<\/strong><\/td><td>Runner \/ Build Server<\/td><td>Inside Kubernetes Control Plane<\/td><\/tr><tr><td><strong>Execution Trigger<\/strong><\/td><td>Code commit \/ Pull Request<\/td><td><code>kubectl<\/code>, Helm, ArgoCD, or Flux API call<\/td><\/tr><tr><td><strong>Speed \/ Feedback<\/strong><\/td><td>Fast; immediate developer feedback<\/td><td>Late; triggers at deployment stage<\/td><\/tr><tr><td><strong>Bypass Vulnerability<\/strong><\/td><td>Can be bypassed if cluster APIs are directly accessible<\/td><td>Cannot be bypassed; intercepts the API request before <code>etcd<\/code> persistence<\/td><\/tr><tr><td><strong>Scope of Context<\/strong><\/td><td>Evaluates static files in the repository<\/td><td>Can evaluate dynamic cluster state (e.g., existing namespaces, node count)<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\">Practical Example: Kyverno Policy<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Kyverno simplifies Kubernetes admission security because policies are written as native Kubernetes resources.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Save this policy as <code class=\"\">disallow-privileged-containers.yaml<\/code>:<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">YAML<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>apiVersion: kyverno.io\/v1\nkind: ClusterPolicy\nmetadata:\n  name: disallow-privileged-containers\n  annotations:\n    policies.kyverno.io\/title: Disallow Privileged Containers\n    policies.kyverno.io\/category: Pod Security Standards (Restricted)\n    policies.kyverno.io\/severity: high\n    policies.kyverno.io\/description: &gt;-\n      Privileged containers can access host devices, bypass container isolation,\n      and elevate node-level privileges. Containers must not set securityContext.privileged to true.\nspec:\n  # 'Enforce' blocks the creation. Use 'Audit' to test without blocking.\n  validationFailureAction: Enforce\n  background: true\n  rules:\n    - name: validate-privileged\n      match:\n        any:\n          - resources:\n              kinds:\n                - Pod\n      validate:\n        message: \"Running a container in privileged mode is forbidden in this cluster.\"\n        pattern:\n          spec:\n            containers:\n              - =(securityContext):\n                  =(privileged): \"false\"\n<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Testing the Policy Safely<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Before applying a policy in <code>Enforce<\/code> mode across a production cluster, deploy it with <code>validationFailureAction: Audit<\/code>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">In Audit mode:<\/p>\n\n\n\n<ol start=\"1\" class=\"wp-block-list\">\n<li>The admission controller permits existing and incoming workloads to proceed.<\/li>\n\n\n\n<li>Violations are tracked in the cluster policy reports (<code>kubectl get clusterpolicyreport<\/code>).<\/li>\n\n\n\n<li>Platform teams review the report to identify workloads needing remediation without causing unplanned production outages.<\/li>\n\n\n\n<li>Once verified, flip the setting to <code>Enforce<\/code>.<\/li>\n<\/ol>\n\n\n\n<h2 class=\"wp-block-heading\">8. Securing Cloud Infrastructure Before Deployment (IaC Policy Checks)<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Cloud configurations provisioned through Terraform, OpenTofu, or Pulumi can introduce critical infrastructure vulnerabilities before any software runs. Policy as Code allows teams to inspect declarative execution plans before calling <code>terraform apply<\/code>.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"> <code>                       TERRAFORM POLICY GATE\n\n[ main.tf ] \u2500\u2500\u25ba [ terraform plan -out=tfplan.binary ]\n                               \u2502\n                               \u25bc\n        [ terraform show -json tfplan.binary &gt; tfplan.json ]\n                               \u2502\n                               \u25bc\n                    [ Policy Engine: Checkov \/ OPA ]\n                               \u2502\n                Passes Baseline Security Rules?\n                               \u2502\n                 \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n            Yes  \u2502                           \u2502  No\n                 \u25bc                           \u25bc\n        [ terraform apply ]          [ Terminate Pipeline ]\n                                     [ Return Exit Code 1 ]\n<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Practical Terraform Policy: Enforce S3 Bucket Encryption<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Below is a Rego policy (<code>policy\/terraform\/s3_encryption.rego<\/code>) designed to evaluate a rendered <code>tfplan.json<\/code> output and ensure all provisioned AWS S3 buckets enable server-side encryption with an approved KMS key.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Code snippet<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>package terraform.security\n\nimport future.keywords.in\n\ndefault allow := false\n\n# Allow deployment if zero violations are found\nallow {\n    count(violations) == 0\n}\n\n# Inspect all resource changes within the Terraform execution plan\nviolations&#091;msg] {\n    # Find all resources scheduled for creation or update\n    resource := input.resource_changes&#091;_]\n    resource.type == \"aws_s3_bucket\"\n    \n    # Check if encryption configuration is missing entirely\n    actions := resource.change.actions\n    actions&#091;_] in &#091;\"create\", \"update\"]\n    \n    not bucket_has_encryption(resource.address)\n    \n    msg := sprintf(\n        \"TERRAFORM POLICY VIOLATION: The S3 bucket '%v' does not configure server-side encryption. All buckets must declare an aws_s3_bucket_server_side_encryption_configuration resource.\",<\/code><\/pre>\n\n\n<p>[resource.address]<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">) } # Helper rule to verify companion encryption configuration resource bucket_has_encryption(bucket_address) { encryption_resource := input.resource_changes[_] encryption_resource.type == &#8220;aws_s3_bucket_server_side_encryption_configuration&#8221; # Ensure the encryption configuration points to our target bucket startswith(encryption_resource.address, bucket_address) # Verify SSE algorithm uses AWS KMS rule := encryption_resource.change.after.rule[_] apply := rule.apply_server_side_encryption_by_default[_] apply.sse_algorithm == &#8220;aws:kms&#8221; }<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Executing the Validation in CI<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Bash<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code># 1. Generate binary plan\nterraform plan -out=tfplan.binary\n\n# 2. Convert binary plan to standardized JSON format\nterraform show -json tfplan.binary &gt; tfplan.json\n\n# 3. Evaluate plan using OPA\nopa eval --data policy\/terraform\/s3_encryption.rego \\\n         --input tfplan.json \\\n         --fail-defined \"data.terraform.security.violations&#091;msg]\"\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">If an unencrypted bucket exists in the plan, the command exits with an error and prints the diagnostic message, preventing the pipeline from advancing to <code>terraform apply<\/code>.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">9. Managing Policy Exceptions Without Weakening Security<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Zero-tolerance security enforcement without an exception management path causes friction. When a legitimate operational requirement arises\u2014such as a storage utility daemon requiring host access or a temporary migration bucket\u2014teams must have a formal, auditable process. Informal workarounds (such as granting developers admin access to bypass CI) compromise the entire security baseline.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"> <code>                     EXCEPTION MANAGEMENT WORKFLOW\n\n\u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502  Developer Exception   \u2502  Requirements:\n\u2502        Request         \u2502  \u2022 Reason &amp; Risk Assessment\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518  \u2022 Target Resource Name &amp; Hash\n            \u2502               \u2022 Expiration Date (e.g., 14 Days)\n            \u25bc\n\u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502 Authorized Security \/  \u2502  Reviews via PR to Policy Repo\n\u2502 Platform Team Approval \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n            \u2502\n            \u251c\u2500\u25ba Approved: Exception entry added to exceptions.json\n            \u2502             Policy engine permits resource until TTL expires.\n            \u2502\n            \u2514\u2500\u25ba Rejected: Engineering team must fix configuration.\n<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Implementing Code-Based Exceptions<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Never delete or disable a security rule to grant an exception. Instead, configure policies to ingest an <strong>audited exception dataset<\/strong> that requires an explicit expiration date and signed approval ticket.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Create <code>policy\/exceptions.json<\/code>:<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">JSON<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>{\n  \"privileged_container_exceptions\": &#091;\n    {\n      \"resource_name\": \"node-exporter-daemonset\",\n      \"namespace\": \"monitoring\",\n      \"approved_by\": \"secops-lead@company.com\",\n      \"ticket\": \"SEC-8492\",\n      \"expires_at\": \"2026-12-31T23:59:59Z\"\n    }\n  ]\n}\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Update your Rego policy to evaluate exceptions:<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Code snippet<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>package deployment.security\n\nimport future.keywords.in\n\n# Check if the resource has an active, unexpired exception\nis_exception(resource_name, namespace) {\n    some exception in data.privileged_container_exceptions\n    exception.resource_name == resource_name\n    exception.namespace == namespace\n    time.now_ns() &lt; time.parse_rfc3339_ns(exception.expires_at)\n}\n\n# The policy only triggers a violation if NO valid exception exists\nviolations&#091;msg] {\n    input.kind == \"Deployment\"\n    container := input.spec.template.spec.containers&#091;_]\n    container.securityContext.privileged == true\n    \n    # Halt violation if verified exception exists\n    not is_exception(input.metadata.name, input.metadata.namespace)\n    \n    msg := sprintf(\"UNAUTHORIZED PRIVILEGED CONTAINER: Deployment '%v' is not permitted to run privileged containers.\", &#091;input.metadata.name])\n}\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">This approach ensures that exceptions are:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Explicit and discoverable<\/strong> within version control.<\/li>\n\n\n\n<li><strong>Time-bound:<\/strong> Once the <code>expires_at<\/code> timestamp passes, pipelines automatically fail until the exception is renewed or the workload is remediated.<\/li>\n\n\n\n<li><strong>Completely auditable<\/strong> through git commit history and pull request approvals.<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">10. Troubleshooting Policy Enforcement Problems<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">When deploying Policy as Code at scale, teams encounter practical hurdles across tooling boundaries. Below are root causes, debugging steps, and solutions for common implementation issues.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">1. A Valid Deployment Is Blocked by an Inaccurate Policy<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Symptom:<\/strong> A developer creates a compliant manifest, but the policy engine flags it as non-compliant.<\/li>\n\n\n\n<li><strong>Root Cause:<\/strong> Overly broad match conditions, unhandled optional fields, or naive regex expressions in the policy logic.<\/li>\n\n\n\n<li><strong>Debugging:<\/strong> Run the policy locally with raw input data printing:Bash<code>opa eval --data policy\/ --input input.json \"data\"<\/code><\/li>\n\n\n\n<li><strong>Correction:<\/strong> Add unit tests (<code>_test.rego<\/code> files) covering positive, negative, and edge cases (such as omitted optional fields). Never deploy policies without unit tests.<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">2. Missing Input Data Causes Policy Evaluation Errors<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Symptom:<\/strong> Policy engine throws runtime null-pointer or undefined errors during pipeline evaluation (e.g., <code>input.spec.template.spec.containers undefined<\/code>).<\/li>\n\n\n\n<li><strong>Root Cause:<\/strong> The policy assumes a nested JSON\/YAML structure exists without verifying that intermediate nodes are defined (e.g., evaluating a ConfigMap using Pod inspection rules).<\/li>\n\n\n\n<li><strong>Correction:<\/strong> Use explicit path verification or optional indexing in Rego:Code snippet<code># Ensure the object kind is verified before querying nested fields input.kind == \"Deployment\" containers := object.get(input.spec.template.spec, \"containers\", [])<\/code><\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">3. Divergent Results Across Different Environments<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Symptom:<\/strong> A manifest passes policy evaluation on a developer workstation via <code>conftest<\/code> but fails inside the Kubernetes admission controller.<\/li>\n\n\n\n<li><strong>Root Cause:<\/strong> Version mismatches between the local policy engine binary and the cluster admission controller, or differing input contexts (e.g., rendered Helm manifests vs. raw source manifests).<\/li>\n\n\n\n<li><strong>Correction:<\/strong> Pin policy engine versions across pre-commit hooks, CI container images, and cluster webhooks. Standardize evaluation on the final, rendered manifest artifact (e.g., output of <code>helm template<\/code>).<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">4. Policy Checks Introduce Significant Pipeline Latency<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Symptom:<\/strong> Pipeline execution times increase significantly during policy phases.<\/li>\n\n\n\n<li><strong>Root Cause:<\/strong> External HTTP network lookups inside policy rules, inefficient recursion over large JSON structures, or re-downloading large policy bundles on every step.<\/li>\n\n\n\n<li><strong>Correction:<\/strong> Eliminate external network requests inside Rego rules during CI; pass necessary metadata as local JSON mock bundles (<code>--data<\/code>). Cache engine binaries and pre-compile policy bundles using <code>opa build<\/code>.<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">5. Admission Controllers Reject Existing, Running Workloads<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Symptom:<\/strong> Applying a new admission policy breaks existing pods when they restart or when nodes roll over.<\/li>\n\n\n\n<li><strong>Root Cause:<\/strong> Enforcing a new policy on a live cluster without first auditing existing workloads.<\/li>\n\n\n\n<li><strong>Correction:<\/strong> Always apply new policies in <code>Audit<\/code> mode first. Query policy reports (<code>kubectl get clusterpolicyreports<\/code>) to identify and fix non-compliant workloads before switching to <code>Enforce<\/code> mode.<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">11. Building a Sustainable Policy Management Process<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Treating policies with the same engineering rigor as application source code prevents policy bloat, technical debt, and pipeline breakage.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"> <code>                 POLICY AS CODE LIFECYCLE MANAGEMENT\n\n  Draft &amp; Author          Unit &amp; Integration Tests        Gradual Rollout           Monitor &amp; Refine\n\u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510       \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510    \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510    \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502 \u2022 Write Rego\/   \u2502 \u2500\u2500\u2500\u2500\u25ba \u2502 \u2022 Test against mock   \u2502\u2500\u2500\u25ba \u2502 \u2022 Phase 1: Warn    \u2502\u2500\u2500\u25ba \u2502 \u2022 Audit logs       \u2502\n\u2502   Kyverno rules \u2502       \u2502   good\/bad inputs     \u2502    \u2502 \u2022 Phase 2: Audit   \u2502    \u2502 \u2022 Clean unused     \u2502\n\u2502 \u2022 Code reviews  \u2502       \u2502 \u2022 Regression suites   \u2502    \u2502 \u2022 Phase 3: Enforce \u2502    \u2502   policies         \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518       \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518    \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518    \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Policy Lifecycle Best Practices<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Version Control and Code Reviews:<\/strong> Host policies in a centralized repository (<code>git@org\/security-policies.git<\/code>). Every policy update must undergo peer review involving both security engineers and application platform leads.<\/li>\n\n\n\n<li><strong>Mandatory Unit Testing:<\/strong> Every policy must include companion unit test files (<code>*_test.rego<\/code>). Test suites must validate:\n<ul class=\"wp-block-list\">\n<li>Valid configurations pass with zero errors.<\/li>\n\n\n\n<li>Known invalid configurations fail with the expected error message.<\/li>\n\n\n\n<li>Partial or malformed configurations fail gracefully without crashing the engine.<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><strong>Modular Policy Architecture:<\/strong> Separate shared utility libraries (e.g., extracting namespaces, parsing container image tags) from concrete enforcement rules.<\/li>\n\n\n\n<li><strong>Gradual Rollout (The Three-Phase Model):<\/strong>\n<ol start=\"1\" class=\"wp-block-list\">\n<li><strong>Phase 1: Warning \/ Advisory Mode:<\/strong> Violations log clear warning messages in CI\/CD pipeline outputs without breaking builds.<\/li>\n\n\n\n<li><strong>Phase 2: Audit Mode (Admission Control):<\/strong> In-cluster controllers allow deployments but populate compliance audit logs.<\/li>\n\n\n\n<li><strong>Phase 3: Blocking \/ Enforcement Mode:<\/strong> Builds fail on violation; admission controllers reject non-compliant API calls.<\/li>\n<\/ol>\n<\/li>\n\n\n\n<li><strong>Periodic Policy Cleanup:<\/strong> Conduct quarterly audits to deprecate unused rules, clean up expired exceptions, and tune thresholds as cloud and Kubernetes platform capabilities evolve.<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">12. Hands-On Project: Build a Secure Deployment Pipeline with PaC<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">To consolidate your practical understanding, build this end-to-end deployment security project. This project forms a production-grade portfolio piece demonstrating modern DevSecOps engineering skills.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Project Architecture Overview<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">You will construct an end-to-end automated deployment workflow where code changes trigger automated policy validation against both cloud infrastructure (Terraform) and container workloads (Kubernetes) before any resource is provisioned.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"> <code>                             HANDS-ON PROJECT WORKFLOW\n                              \n   [ Developer Git Push ]\n              \u2502\n              \u25bc\n    GitHub Actions Runner\n      \u251c\u2500\u25ba Step 1: Lint &amp; Verify Policy Rego Unit Tests (`opa test`)\n      \u251c\u2500\u25ba Step 2: Render Terraform Plan &amp; Scan via Checkov\n      \u251c\u2500\u25ba Step 3: Render Kubernetes Manifests &amp; Scan via Conftest \/ OPA\n      \u251c\u2500\u25ba Step 4: Security Approval Gate (Manual approval required for non-prod warnings)\n      \u2514\u2500\u25ba Step 5: Mock Deploy to Staging Namespace (Protected by Kyverno Admission Controller)\n<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Required Project Deliverables<\/h3>\n\n\n\n<ol start=\"1\" class=\"wp-block-list\">\n<li><strong>Source Repositories:<\/strong>\n<ul class=\"wp-block-list\">\n<li><code>policy-base<\/code>: Central repository holding Rego rules and Kyverno policies with complete unit test coverage.<\/li>\n\n\n\n<li><code>demo-workload<\/code>: Application repository containing a simple microservice, Dockerfile, Helm chart, and Terraform plan for an S3 storage bucket.<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><strong>Defined Policies:<\/strong>\n<ul class=\"wp-block-list\">\n<li><strong>Policy A (Terraform):<\/strong> Reject any S3 bucket or RDS instance lacking encryption at rest.<\/li>\n\n\n\n<li><strong>Policy B (Kubernetes):<\/strong> Enforce that all container images originate from <code>ghcr.io\/yourorg\/*<\/code> and block images using the <code>:latest<\/code> tag.<\/li>\n\n\n\n<li><strong>Policy C (Kubernetes):<\/strong> Enforce CPU and Memory requests and limits on every container.<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><strong>CI\/CD Pipeline File:<\/strong>\n<ul class=\"wp-block-list\">\n<li>A fully functional GitHub Actions or GitLab CI configuration executing unit tests, linting, and policy checks before triggering the deployment step.<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><strong>Exception Demonstration:<\/strong>\n<ul class=\"wp-block-list\">\n<li>A documented, code-based exception for a specific debugging utility workload, demonstrating clean use of automated expiration dates.<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><strong>Interview \/ Portfolio Presentation Tip:<\/strong>\n<ul class=\"wp-block-list\">\n<li>When presenting this project in a technical interview, demonstrate the exact failure mode: submit a pull request introducing a non-compliant container, show the pipeline failing with clear diagnostic messaging, and explain how this approach replaces manual pre-deployment security reviews.<\/li>\n<\/ul>\n<\/li>\n<\/ol>\n\n\n\n<h2 class=\"wp-block-heading\">13. Frequently Asked Questions (FAQ)<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">What is Policy as Code in DevOps?<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Policy as Code is the practice of writing security, compliance, and operational requirements in programmatic code. This code is stored in version control and evaluated automatically across CI\/CD pipelines, cloud provisioning workflows, and runtime environments to prevent misconfigurations without slowing delivery velocity.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">How does Policy as Code improve deployment security?<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Traditional security models rely on periodic human reviews, spreadsheets, or post-deployment vulnerability scans that catch issues after systems are exposed. Policy as Code shifts security left: it evaluates deployment artifacts and infrastructure plans <em>before<\/em> provisioning occurs, automatically blocking insecure configurations at the pipeline level.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">What is the difference between OPA and Gatekeeper?<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Open Policy Agent (OPA) is a general-purpose, host-level policy engine that parses any JSON or YAML input using the Rego language. Gatekeeper is a Kubernetes-specific project that integrates OPA directly into Kubernetes as an admission controller, translating policies into Kubernetes Custom Resource Definitions (ConstraintTemplates and Constraints).<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Can Policy as Code be integrated with Jenkins?<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Yes. Policy as Code CLI tools such as Conftest, Checkov, and OPA run anywhere a shell or container command can execute. In a Jenkins pipeline (<code>Jenkinsfile<\/code>), policy checks run as explicit pipeline stages executing shell steps (e.g., <code>sh 'conftest test manifests\/'<\/code>), failing the build stage if violations are detected.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">How is Rego used in deployment security?<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Rego is the declarative query language used by Open Policy Agent. In deployment security, Rego queries represent structural assertions about infrastructure files (e.g., &#8220;are all security groups restricted?&#8221;). When an input file violates these assertions, Rego constructs a diagnostic error message and reports a non-zero exit code to the pipeline.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Can Kubernetes policies block insecure deployments?<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Yes. Through Validating Admission Controllers (such as OPA Gatekeeper or Kyverno), Kubernetes evaluates incoming API requests before saving objects to its state store (<code>etcd<\/code>). If a manifest violates a cluster policy\u2014such as attempting to run a pod with host network access or root permissions\u2014the API server rejects the request immediately.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">How does Policy as Code work with Terraform?<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Terraform generates an execution plan before provisioning real resources (<code>terraform plan -out=tfplan.binary<\/code>). Engineers convert this plan into JSON (<code>terraform show -json tfplan.binary &gt; tfplan.json<\/code>) and pass it to a policy engine like OPA, Conftest, or Checkov. The engine inspects planned changes and blocks the pipeline if unencrypted, public, or non-compliant infrastructure is detected.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">What happens when a deployment violates a policy?<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">In a CI\/CD pipeline, the policy engine returns a non-zero exit code (typically <code>1<\/code>), causing the automated build job to halt. The pipeline blocks deployment artifacts from advancing and prints an actionable error message into the build log, directing the developer on how to fix the configuration.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">How should organizations manage policy exceptions?<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Exceptions should never be handled by giving engineers permissions to bypass pipelines. Instead, maintain an auditable, version-controlled exception data file that defines the exempt resource, the specific policy bypassed, an authorized security ticket reference, and a strict expiration date. Policies evaluate this file and automatically revoke access once the exception expires.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Is Policy as Code part of DevSecOps?<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Yes. Policy as Code is one of the foundational technical pillars of DevSecOps. It enables the practical shifting of security responsibilities to the left by turning abstract security guidelines into actionable, automated test gates integrated into standard developer delivery workflows.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Conclusion: Making Security an Automated Part of Every Deployment<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">The speed of modern software delivery makes manual security gatekeeping obsolete. When microservices deploy continuously across distributed cloud and container environments, security cannot function as an afterthought or a manual checkpoint. Policy as Code bridges the gap between rapid delivery and strict security standards. By codifying infrastructure requirements, container privileges, network rules, and compliance benchmarks into machine-readable policies, organizations establish reliable, automated guardrails across their delivery lifecycles. Security shifts from an adversarial, late-stage bottleneck to an automated, continuous, and transparent engineering feedback loop. Building and maintaining these systems requires a solid grounding in automation, declarative tooling, and cloud architectures. For engineers, platform architects, and technology leaders looking to build production-grade expertise across these domains, <strong>DevOpsSchool<\/strong> provides comprehensive, real-world training programs covering DevOps, DevSecOps, continuous deployment automation, and modern infrastructure security practices. Adopting Policy as Code begins with small, high-impact rules: identify your top three recurring configuration issues\u2014whether public cloud storage, unencrypted disks, or privileged containers\u2014codify them into your pipeline today, and build an automated delivery process that is secure by default.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>A release can pass every unit, integration, and performance test, yet still harbor critical misconfigurations\u2014such as an unencrypted S3 bucket,&#8230; <\/p>\n","protected":false},"author":5,"featured_media":3266,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"series":[],"class_list":["post-3265","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-uncategorized"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v28.5 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Securing CI\/CD Pipelines with Policy as Code - DevSecOps School<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/devsecopsschool.com\/blog\/securing-ci-cd-pipelines-with-policy-as-code\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Securing CI\/CD Pipelines with Policy as Code - DevSecOps School\" \/>\n<meta property=\"og:description\" content=\"A release can pass every unit, integration, and performance test, yet still harbor critical misconfigurations\u2014such as an unencrypted S3 bucket,...\" \/>\n<meta property=\"og:url\" content=\"https:\/\/devsecopsschool.com\/blog\/securing-ci-cd-pipelines-with-policy-as-code\/\" \/>\n<meta property=\"og:site_name\" content=\"DevSecOps School\" \/>\n<meta property=\"article:published_time\" content=\"2026-11-06T18:15:35+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2026-11-06T18:15:37+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/devsecopsschool.com\/blog\/wp-content\/uploads\/2026\/11\/image-10.png\" \/>\n\t<meta property=\"og:image:width\" content=\"1024\" \/>\n\t<meta property=\"og:image:height\" content=\"572\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/png\" \/>\n<meta name=\"author\" content=\"Amelia Olivia\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Amelia Olivia\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"17 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/devsecopsschool.com\\\/blog\\\/securing-ci-cd-pipelines-with-policy-as-code\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/devsecopsschool.com\\\/blog\\\/securing-ci-cd-pipelines-with-policy-as-code\\\/\"},\"author\":{\"name\":\"Amelia Olivia\",\"@id\":\"https:\\\/\\\/devsecopsschool.com\\\/blog\\\/#\\\/schema\\\/person\\\/5ff4d5d2ff886aa29536db0d8a0787d1\"},\"headline\":\"Securing CI\\\/CD Pipelines with Policy as Code\",\"datePublished\":\"2026-11-06T18:15:35+00:00\",\"dateModified\":\"2026-11-06T18:15:37+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/devsecopsschool.com\\\/blog\\\/securing-ci-cd-pipelines-with-policy-as-code\\\/\"},\"wordCount\":3851,\"commentCount\":0,\"image\":{\"@id\":\"https:\\\/\\\/devsecopsschool.com\\\/blog\\\/securing-ci-cd-pipelines-with-policy-as-code\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/devsecopsschool.com\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/11\\\/image-10.png\",\"inLanguage\":\"en\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\\\/\\\/devsecopsschool.com\\\/blog\\\/securing-ci-cd-pipelines-with-policy-as-code\\\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/devsecopsschool.com\\\/blog\\\/securing-ci-cd-pipelines-with-policy-as-code\\\/\",\"url\":\"https:\\\/\\\/devsecopsschool.com\\\/blog\\\/securing-ci-cd-pipelines-with-policy-as-code\\\/\",\"name\":\"Securing CI\\\/CD Pipelines with Policy as Code - DevSecOps School\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/devsecopsschool.com\\\/blog\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/devsecopsschool.com\\\/blog\\\/securing-ci-cd-pipelines-with-policy-as-code\\\/#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/devsecopsschool.com\\\/blog\\\/securing-ci-cd-pipelines-with-policy-as-code\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/devsecopsschool.com\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/11\\\/image-10.png\",\"datePublished\":\"2026-11-06T18:15:35+00:00\",\"dateModified\":\"2026-11-06T18:15:37+00:00\",\"author\":{\"@id\":\"https:\\\/\\\/devsecopsschool.com\\\/blog\\\/#\\\/schema\\\/person\\\/5ff4d5d2ff886aa29536db0d8a0787d1\"},\"breadcrumb\":{\"@id\":\"https:\\\/\\\/devsecopsschool.com\\\/blog\\\/securing-ci-cd-pipelines-with-policy-as-code\\\/#breadcrumb\"},\"inLanguage\":\"en\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/devsecopsschool.com\\\/blog\\\/securing-ci-cd-pipelines-with-policy-as-code\\\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en\",\"@id\":\"https:\\\/\\\/devsecopsschool.com\\\/blog\\\/securing-ci-cd-pipelines-with-policy-as-code\\\/#primaryimage\",\"url\":\"https:\\\/\\\/devsecopsschool.com\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/11\\\/image-10.png\",\"contentUrl\":\"https:\\\/\\\/devsecopsschool.com\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/11\\\/image-10.png\",\"width\":1024,\"height\":572},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/devsecopsschool.com\\\/blog\\\/securing-ci-cd-pipelines-with-policy-as-code\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/devsecopsschool.com\\\/blog\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Securing CI\\\/CD Pipelines with Policy as Code\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/devsecopsschool.com\\\/blog\\\/#website\",\"url\":\"https:\\\/\\\/devsecopsschool.com\\\/blog\\\/\",\"name\":\"DevSecOps School\",\"description\":\"DevSecOps Redefined\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/devsecopsschool.com\\\/blog\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en\"},{\"@type\":\"Person\",\"@id\":\"https:\\\/\\\/devsecopsschool.com\\\/blog\\\/#\\\/schema\\\/person\\\/5ff4d5d2ff886aa29536db0d8a0787d1\",\"name\":\"Amelia Olivia\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en\",\"@id\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/86aec18083c8b8a8ca5aec5530fef69a4a2fe9d706774cf20e99fbaccf741608?s=96&d=mm&r=g\",\"url\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/86aec18083c8b8a8ca5aec5530fef69a4a2fe9d706774cf20e99fbaccf741608?s=96&d=mm&r=g\",\"contentUrl\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/86aec18083c8b8a8ca5aec5530fef69a4a2fe9d706774cf20e99fbaccf741608?s=96&d=mm&r=g\",\"caption\":\"Amelia Olivia\"},\"url\":\"https:\\\/\\\/devsecopsschool.com\\\/blog\\\/author\\\/amelia\\\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Securing CI\/CD Pipelines with Policy as Code - DevSecOps School","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/devsecopsschool.com\/blog\/securing-ci-cd-pipelines-with-policy-as-code\/","og_locale":"en_US","og_type":"article","og_title":"Securing CI\/CD Pipelines with Policy as Code - DevSecOps School","og_description":"A release can pass every unit, integration, and performance test, yet still harbor critical misconfigurations\u2014such as an unencrypted S3 bucket,...","og_url":"https:\/\/devsecopsschool.com\/blog\/securing-ci-cd-pipelines-with-policy-as-code\/","og_site_name":"DevSecOps School","article_published_time":"2026-11-06T18:15:35+00:00","article_modified_time":"2026-11-06T18:15:37+00:00","og_image":[{"width":1024,"height":572,"url":"https:\/\/devsecopsschool.com\/blog\/wp-content\/uploads\/2026\/11\/image-10.png","type":"image\/png"}],"author":"Amelia Olivia","twitter_card":"summary_large_image","twitter_misc":{"Written by":"Amelia Olivia","Est. reading time":"17 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/devsecopsschool.com\/blog\/securing-ci-cd-pipelines-with-policy-as-code\/#article","isPartOf":{"@id":"https:\/\/devsecopsschool.com\/blog\/securing-ci-cd-pipelines-with-policy-as-code\/"},"author":{"name":"Amelia Olivia","@id":"https:\/\/devsecopsschool.com\/blog\/#\/schema\/person\/5ff4d5d2ff886aa29536db0d8a0787d1"},"headline":"Securing CI\/CD Pipelines with Policy as Code","datePublished":"2026-11-06T18:15:35+00:00","dateModified":"2026-11-06T18:15:37+00:00","mainEntityOfPage":{"@id":"https:\/\/devsecopsschool.com\/blog\/securing-ci-cd-pipelines-with-policy-as-code\/"},"wordCount":3851,"commentCount":0,"image":{"@id":"https:\/\/devsecopsschool.com\/blog\/securing-ci-cd-pipelines-with-policy-as-code\/#primaryimage"},"thumbnailUrl":"https:\/\/devsecopsschool.com\/blog\/wp-content\/uploads\/2026\/11\/image-10.png","inLanguage":"en","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/devsecopsschool.com\/blog\/securing-ci-cd-pipelines-with-policy-as-code\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/devsecopsschool.com\/blog\/securing-ci-cd-pipelines-with-policy-as-code\/","url":"https:\/\/devsecopsschool.com\/blog\/securing-ci-cd-pipelines-with-policy-as-code\/","name":"Securing CI\/CD Pipelines with Policy as Code - DevSecOps School","isPartOf":{"@id":"https:\/\/devsecopsschool.com\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/devsecopsschool.com\/blog\/securing-ci-cd-pipelines-with-policy-as-code\/#primaryimage"},"image":{"@id":"https:\/\/devsecopsschool.com\/blog\/securing-ci-cd-pipelines-with-policy-as-code\/#primaryimage"},"thumbnailUrl":"https:\/\/devsecopsschool.com\/blog\/wp-content\/uploads\/2026\/11\/image-10.png","datePublished":"2026-11-06T18:15:35+00:00","dateModified":"2026-11-06T18:15:37+00:00","author":{"@id":"https:\/\/devsecopsschool.com\/blog\/#\/schema\/person\/5ff4d5d2ff886aa29536db0d8a0787d1"},"breadcrumb":{"@id":"https:\/\/devsecopsschool.com\/blog\/securing-ci-cd-pipelines-with-policy-as-code\/#breadcrumb"},"inLanguage":"en","potentialAction":[{"@type":"ReadAction","target":["https:\/\/devsecopsschool.com\/blog\/securing-ci-cd-pipelines-with-policy-as-code\/"]}]},{"@type":"ImageObject","inLanguage":"en","@id":"https:\/\/devsecopsschool.com\/blog\/securing-ci-cd-pipelines-with-policy-as-code\/#primaryimage","url":"https:\/\/devsecopsschool.com\/blog\/wp-content\/uploads\/2026\/11\/image-10.png","contentUrl":"https:\/\/devsecopsschool.com\/blog\/wp-content\/uploads\/2026\/11\/image-10.png","width":1024,"height":572},{"@type":"BreadcrumbList","@id":"https:\/\/devsecopsschool.com\/blog\/securing-ci-cd-pipelines-with-policy-as-code\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/devsecopsschool.com\/blog\/"},{"@type":"ListItem","position":2,"name":"Securing CI\/CD Pipelines with Policy as Code"}]},{"@type":"WebSite","@id":"https:\/\/devsecopsschool.com\/blog\/#website","url":"https:\/\/devsecopsschool.com\/blog\/","name":"DevSecOps School","description":"DevSecOps Redefined","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/devsecopsschool.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en"},{"@type":"Person","@id":"https:\/\/devsecopsschool.com\/blog\/#\/schema\/person\/5ff4d5d2ff886aa29536db0d8a0787d1","name":"Amelia Olivia","image":{"@type":"ImageObject","inLanguage":"en","@id":"https:\/\/secure.gravatar.com\/avatar\/86aec18083c8b8a8ca5aec5530fef69a4a2fe9d706774cf20e99fbaccf741608?s=96&d=mm&r=g","url":"https:\/\/secure.gravatar.com\/avatar\/86aec18083c8b8a8ca5aec5530fef69a4a2fe9d706774cf20e99fbaccf741608?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/86aec18083c8b8a8ca5aec5530fef69a4a2fe9d706774cf20e99fbaccf741608?s=96&d=mm&r=g","caption":"Amelia Olivia"},"url":"https:\/\/devsecopsschool.com\/blog\/author\/amelia\/"}]}},"_links":{"self":[{"href":"https:\/\/devsecopsschool.com\/blog\/wp-json\/wp\/v2\/posts\/3265","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devsecopsschool.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devsecopsschool.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devsecopsschool.com\/blog\/wp-json\/wp\/v2\/users\/5"}],"replies":[{"embeddable":true,"href":"https:\/\/devsecopsschool.com\/blog\/wp-json\/wp\/v2\/comments?post=3265"}],"version-history":[{"count":1,"href":"https:\/\/devsecopsschool.com\/blog\/wp-json\/wp\/v2\/posts\/3265\/revisions"}],"predecessor-version":[{"id":3267,"href":"https:\/\/devsecopsschool.com\/blog\/wp-json\/wp\/v2\/posts\/3265\/revisions\/3267"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devsecopsschool.com\/blog\/wp-json\/wp\/v2\/media\/3266"}],"wp:attachment":[{"href":"https:\/\/devsecopsschool.com\/blog\/wp-json\/wp\/v2\/media?parent=3265"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devsecopsschool.com\/blog\/wp-json\/wp\/v2\/categories?post=3265"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devsecopsschool.com\/blog\/wp-json\/wp\/v2\/tags?post=3265"},{"taxonomy":"series","embeddable":true,"href":"https:\/\/devsecopsschool.com\/blog\/wp-json\/wp\/v2\/series?post=3265"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}