8 DevSecOps Practices for Cloud Environments That Survive Production

Olivier de Turkeim
July 8, 2026

TL;DR

  • Shift policy enforcement to the orchestration layer instead of relying solely on pipeline scans. Evaluating rules against Terraform plans before API calls blocks unapproved modifications regardless of the trigger source.
  • Replace static keys with ephemeral credentials and OIDC federation for all deployment operations. Generating temporary, scoped tokens per job strictly limits the blast radius to the execution window.
  • Move security reviews to the pull request phase and set strict signal thresholds to prevent alert fatigue. Blocking merges only for high-priority exposures ensures engineers fix vulnerabilities without ignoring the output.
  • Define access controls at a central platform layer and federate them directly to individual cloud providers. This prevents permission models from fragmenting across consoles and guarantees offboarding revokes all access instantly.
  • Enforce constant drift detection against expected infrastructure states to catch manual console modifications. Using Git commit history of policy libraries replaces point-in-time annual audits with concrete, verifiable evidence.
  • Govern developer self-service by building deployment templates with strictly pre-constrained parameters. Removing free-text fields for security configurations stops users from deploying insecure defaults while keeping delivery fast.

 

Why Cloud Environments Break Standard DevSecOps Assumptions

Security practices designed for stable, perimeter-bounded environments don’t translate to cloud infrastructure, and the gap is about operational velocity, architecture, and who can change things.

On-premise DevSecOps assumed a relatively fixed deployment surface: a known set of servers, a fixed network perimeter, and a weekly change window. Cloud environments invert all of that. A developer with self-service portal access can provision a Kubernetes namespace, an S3 bucket, and a managed database in under two minutes. An auto-scaling event can modify security group rules without any human intervention. A Terraform module pulled from a public registry can introduce 40 resources, each with its own IAM surface, in a single terraform apply. By the time a manual security review runs, the infrastructure has changed again.

Gartner predicts that by 2025, 99% of cloud security failures will be the customer’s fault, primarily due to misconfigurations. The problem isn’t that cloud providers are insecure; it’s that the pace of change in cloud environments outpaces every manual enforcement mechanism. Cloud intrusions rose 37% year-over-year in 2025, accelerating from 26% growth in 2024, while 88% of organizations now operate in hybrid or multi-cloud environments.

The practices that follow are specifically designed for that context: high-velocity, self-service, multi-cloud, with teams that can’t afford a security gate on every deployment. Each one addresses a failure mode that arises specifically because cloud environments move too quickly for humans to serve as the primary enforcement mechanism. We’ll cover policy enforcement at the infrastructure layer, centralized secrets management, IaC scanning at PR time, RBAC design, drift detection, compliance-as-code, zero-trust pipeline identity, and governed self-service deployments.

 

The continuous cloud DevSecOps lifecycle

 

Top 8 DevSecOps Practices for Cloud Environments

1. Enforce Policy as Code at the Infrastructure Layer, Not the Pipeline Layer

Pipeline-level scanning solves one problem and creates a false sense of coverage for everything else. When a security scan lives only in GitHub Actions or GitLab CI, it runs only when the pipeline runs.

How InfraPolicies Differ from Pipeline-Level IaC Scanning

Tools like Checkov and tfsec run in CI and catch issues during the standard pipeline flow. That covers roughly 80% of deployments. The other 20%: a developer runs terraform apply directly from their local machine, a stack gets triggered via the platform API, or someone bypasses the pipeline entirely during an incident. Pipeline scans fail to open in those cases because they’re not in the execution path.

Cycloid’s InfraPolicies enforce policy at the orchestration layer, not the CI layer. Every Terraform plan, regardless of how or where the deployment was triggered, is evaluated against the organization’s Rego rules before any API call reaches the cloud provider. The policy engine is the gate, not the pipeline step.

InfraPolicies operate on three severity levels:

  • Critical: the changes must be blocked
  • Warning: the changes are blocked but can be overridden with a manual operation
  • Advisory: The changes can be automatically applied, but a notification must be sent

Validation with advisories, the job is green, and displays advisories as metadata:

Validation with criticals and/or warnings, the job fails, and displays the result as metadata:

The distinction matters operationally. Use Critical for controls with no legitimate exception (e.g., no public subnet deployment, no unencrypted storage). Use a warning for controls where a manual override with a logged justification is acceptable. Use Advisory for informational alerts where the build shouldn’t fail, but the team should be aware.

Writing Rego Rules That Map to Real Compliance Controls

Every InfraPolicy is a Rego rule evaluated against the Terraform plan JSON. The input body includes tfplan, project_canonical, and environment_canonical, so rules can be scoped to specific environments or projects. Here’s the structure directly from Cycloid’s documentation:

# Require tags on all resources (maps to ISO 27001 Annex A.8 - Asset Management)
package example
deny[reason]

For production-specific enforcement, scope the rule to the environment canonical:

# Require RDS backup on production only (maps to SOC 2 CC9 - Risk Mitigation)
package example
is_production {
input.environment_canonical \== "prod"
}
deny[reason] {
is_production
resource := input.tfplan.planned_values.root_module.resources[_]
resource.type \== "aws_db_instance"
not resource.values.backup_retention_period > 0
reason \= sprintf("Backup is required on production for %q", [resource.address])
}

When these rules live in Git, the commit history becomes auditable evidence that the control was active and enforced on every deployment since a given date. An auditor asking for ISO 27001 evidence gets a Git log, not a set of screenshots.

Local validation uses the Cycloid CLI before changes even reach the pipeline:

$ terraform plan -out\=./plan
$ terraform show -json ./plan > plan.json
$ cy infrapolicy validate --plan-path ./plan.json
ADVISORIES CRITICALS WARNINGS
1 0 0

2. Centralize Secrets Management Through the Delivery Pipeline

Credential sprawl is the silent threat in most cloud environments. In Verizon’s 2024 DBIR, “use of stolen credentials” was the most common initial action in breaches, at 24%, with ransomware close behind at 23%. A static AWS_SECRET_ACCESS_KEY pasted into a CI environment variable in January and still active in October is an incident waiting for a date.

Dynamic Credential Generation vs. Static Secret Storage

Cycloid integrates with HashiCorp Vault to manage API keys, AWS IAM/STS credentials, database credentials, X.509 certificates, and SSH keys from a central location. Secrets provide transparent, secure handling and allow you to centralize your valuable information, while giving projects secure access through HashiCorp’s managed, open-source Vault.

The operational model changes from “distribute and rotate” to “generate on demand.” Vault generates short-lived credentials per deployment: the platform requests credentials on behalf of a project, Vault authenticates the request against a role policy, and returns a time-bound token whose TTL matches the deployment window. When the job finishes, the credential expires. A compromised credential from a three-minute deployment window has a three-minute blast radius.

Compare that to the common alternative:

# What most teams actually have (don't do this)
export AWS_ACCESS_KEY_ID\="AKIAIOSFODNN7EXAMPLE"
export AWS_SECRET_ACCESS_KEY\="wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY"
# Key created 8 months ago, never rotated, used in 14 pipelines
Versus Vault dynamic credentials:
bash
# Vault generates ephemeral credentials per job
vault read aws/creds/my-role
# Key: AKIAIOSFODNN7EXAMPLE
# Secret: dynamically generated
# TTL: 15 minutes
# Automatically revoked after TTL expires

Preventing Secret Leakage at the Repository and Container Build Layer

Two structural problems cause most secret leakage before Vault even enters the picture: developers accidentally committing secrets to Git, and Docker image layers preserving deleted secrets.

Pre-commit hooks using Gitleaks or detect-secrets catch credentials before the push. Neither tool is perfect, but catching 95% of accidental commits beats catching 0%.

The Docker layer problem is less obvious. If a secret is added in a RUN layer and then deleted in a subsequent layer, the secret is still recoverable from the image history:

# Vulnerable: secret persists in layer history
FROM ubuntu:22.04
RUN echo "API_KEY=supersecret" > /app/.env
RUN rm /app/.env # too late; the secret is in layer 2
# Fixed: multi-stage build, secret never persists
FROM ubuntu:22.04 AS builder
ARG API_KEY
RUN echo "Building with key..." && build_step
FROM ubuntu:22.04
COPY --from\=builder /app/binary /app/binary
# API_KEY never written to a layer in the final image

For Kubernetes, Secret objects store data as base64, not encrypted. Base64 is encoding, not encryption. Any cluster user with kubectl get secret access can decode it in seconds. The fix is either envelope encryption at the etcd layer (AWS KMS with EKS, Azure Key Vault with AKS) or an External Secrets Operator pulling credentials from Vault at runtime rather than storing them in the cluster at all.

3. Embed IaC Scanning at Pull Request Time, Not After Deployment

A security finding that surfaces after a resource is deployed creates a different kind of problem than one caught at PR time. Post-deployment findings require changes under production conditions, are often triaged as “low priority” because the system is running fine, and pile up into security debt that eventually leads to a breach or a compliance failure.

Tuning Signal-to-Noise Ratio in IaC Security Scans

The standard tool stack for PR-time IaC scanning covers Terraform with Checkov or tfsec, Dockerfiles with Hadolint, and Kubernetes manifests with kube-score or Polaris. Each integrates into GitHub Actions, GitLab CI, or Concourse without major configuration effort.

The problem isn’t integration, but it’s running all tools with default rules against a medium-sized Terraform codebase, which produces hundreds of findings per PR, and developers learn to dismiss them as background noise within two weeks. The fix is deliberate threshold management, not scanning fewer things.

Start with a blocking ruleset covering three categories where findings have a direct path to a real attack: public exposure (S3 bucket acl \= public-read, security group 0.0.0.0/0 ingress on port 22), missing encryption (unencrypted EBS volumes, RDS without storage_encrypted \= true), and excessive IAM permissions (* actions or resources). Everything outside those categories is in informational status until the team has consistently fixed the blocking findings.

A GitHub Actions example that blocks on critical and informs on everything else:

- name: Run tfsec
uses: aquasecurity/tfsec-action@v1.0.0
with:
soft_fail: false
minimum_severity: HIGH
format: sarif
additional_args: --exclude-downloaded-modules
- name: Upload SARIF results
uses: github/codeql-action/upload-sarif@v2
with:
sarif_file: tfsec.sarif

Connecting Scan Results to Developer Workflows Without Breaking Delivery Speed

Security findings surface in developer workflows via PR comments using SARIF output (natively supported by GitHub and GitLab), Slack notifications for blocked merges, and IDE plugins to catch problems before commit. The fix rate is higher when the finding appears in the same place the developer is already working, rather than in a separate security dashboard that nobody checks, between Jira and Slack.

4. Implement RBAC That Reflects Actual Team Boundaries

Flat access models are operationally convenient and structurally dangerous. When everyone in a team has “developer” access to a cloud account, a single compromised credential or a misconfigured IAM policy can expose the entire estate. The standard response is to add more IAM policies in each cloud provider’s console, which creates a second problem: three cloud providers, three RBAC models, and access definitions that diverge over time.

Mapping Platform RBAC to Cloud-Provider IAM Roles Without Duplication

Cycloid’s RBAC model operates at three levels: organization-wide roles, team-level scoping, and resource-level enforcement. A concrete example of how this maps to real org structure:

  • Platform team: admin scope across all projects and environments
  • Product team A: deploy rights scoped to their project, staging, and production environments only
  • External contractor: read-only access to logs for their assigned project, no other access

The platform-level RBAC then maps to cloud provider IAM: Cycloid translates team permissions into scoped AWS IAM roles, Azure managed identities, and GCP service accounts. Cycloid includes multi-level RBAC with team and organizational scoping, customizable permissions, and resource-level access enforcement.

The operational benefit is a single definition of who can do what, maintained in one place and propagated to cloud providers via identity federation (OIDC or SAML), rather than managed separately in each cloud console. When a contractor’s engagement ends, their Cycloid access is revoked, which also revokes their cloud access. No separate IAM cleanup required, no access that persists because someone forgot to update the AWS console.

When Approval Workflows Function as a Security Control, Not a Bottleneck

Cycloid supports approval workflows, environment quotas, and policy guardrails, ensuring all actions comply with internal governance. In a change management context, an approval workflow isn’t bureaucratic overhead. It’s a technical control that prevents unauthorized changes and creates an auditable record of every infrastructure modification.

The flow: a developer submits a change request through the self-service portal; the request enters an approval queue visible to the platform team; a platform engineer reviews it, approves it with a justification, or rejects it with a reason. Every action is logged with a timestamp and actor identity. The resulting audit trail satisfies SOC 2 CC8.1 (Change Management) without a separate ITSM ticketing system bolted alongside the deployment toolchain.

5. Detect and Respond to Infrastructure Drift Continuously

Infrastructure passes a security review at deployment time and then diverges from that baseline within hours. Someone runs aws ec2 authorize-security-group-ingress during a production incident and forgets to close the port. A managed service updates its default configuration. An auto-scaling group modifies its own rules. None of these changes go through the IaC pipeline; they are applied directly to the cloud API.

Automated Remediation vs. Human-in-the-Loop Drift Response

Cycloid uses Terraform state comparison via InfraView to detect divergence between the declared IaC state and the actual cloud resource state. The operational pattern: a scheduled pipeline runs Terraform plan in read-only mode (no apply), compares the output against the expected state, and triggers an alert when a divergence is detected.

Up-to-date diagram based on your Terraform file that you don’t have to maintain, and that you can share with others to accelerate your cloud and DevOps adoption.

Two response patterns apply, and choosing between them depends on what drifted:

Automatic re-apply: suitable for configuration drift on non-security-sensitive resources (tag values, instance naming conventions, cost allocation attributes). The pipeline automatically reverts to the declared state.

Human-in-the-loop: required for any drift affecting security groups, IAM policies, network topology, or encryption settings. The drift detection fires an alert, the change goes through an approval workflow, and only then does the system re-apply the declared state. Automated remediation on IAM drift without human review creates a risk of accidentally reverting a legitimate emergency change.

Using TerraCognita to Bring Legacy Infrastructure Under IaC Control

Drift detection only works on infrastructure that’s declared in IaC. Organizations with existing manually provisioned infrastructure face the brownfield problem: years of cloud resources deployed via the console with no Terraform representation.

Cycloid’s open-source TerraCognita (a reverse Terraform tool) solves the onboarding problem by scanning existing cloud resources and generating Terraform configuration from live infrastructure. No rebuilding from scratch; the existing resources get IaC representations, and drift detection can start on day one. Once resources are under IaC, InfraPolicies apply to every future change, and every modification is version-controlled.

6. Treat Compliance as Code Across the Full Infrastructure Lifecycle

Annual audits verify a point-in-time state that may have nothing to do with the other 364 days of the year. A system compliant in January’s audit can drift out of compliance by March, and nobody notices until the next audit cycle begins. Cloud environments change continuously, so point-in-time compliance is structurally insufficient.

Building a Compliance Control Library in Version Control

Policy as Code converts compliance from a periodic review into a continuous verification process. Every deployment must pass InfraPolicy rules that map to specific controls, meaning the compliance state is checked with every change, not once a year.

The control mapping is explicit and maintainable. Three examples from Cycloid’s InfraPolicy rule library:

# ISO 27001 Annex A.10 (Cryptography) - Block unencrypted RDS
package compliance.iso27001.a10
deny[reason]
# SOC 2 CC6.1 (Logical Access) - Enforce allowed regions only
package compliance.soc2.cc6
allowed_regions \= {"eu-west-1", "eu-central-1"}
deny[reason] {
provider := input.tfplan.configuration.provider_config.aws
region := provider.expressions.region.constant_value
not allowed_regions[region]
reason \= sprintf("Region %q not permitted under data residency policy (SOC 2 CC6.1)", [region])
}
# GDPR Article 32 - Require security group on all instances
package compliance.gdpr.article32
deny[reason]

Each rule lives in a Git repository, organized by compliance framework, with each rule tagged to the control it enforces. Adding a new regulatory requirement becomes a PR to the policy library, reviewed and approved like any other code change.

Audit Logging and Change Tracking as Continuous Evidence

Cycloid keeps detailed audit trails for all actions and changes, helping meet internal audit and compliance standards. Every deployment records who requested it, who approved it, what changed, and when, with timestamps and actor identity attached to every event.

At audit time, the evidence package consists of the Git history of the policy library and the Cycloid event log. No manual documentation, no screenshot collection, no “we believe we were compliant during that period” hedging.

7. Apply Zero-Trust Principles to CI/CD Pipeline Identity and Access

CI/CD pipelines are the most attractive targets in a cloud environment. They hold production credentials, deployment keys, and direct access to cloud APIs. A compromised pipeline can deploy arbitrary code or exfiltrate secrets without triggering any application-layer security control, because the pipeline is supposed to have that access.

OIDC Federation Between CI Pipelines and Cloud Providers

The zero-trust model applied to CI/CD replaces long-lived service account keys with short-lived, scoped identities generated per job. The mechanism is OIDC federation between the CI system and the cloud provider.

The flow for GitHub Actions authenticating to AWS:

jobs:
deploy:
permissions:
id-token: write # Required for OIDC token request
contents: read
steps:
- name: Configure AWS credentials via OIDC
uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: arn:aws:iam::123456789012:role/GitHubActionsDeployRole
role-session-name: GitHubActionsSession
aws-region: eu-west-1
# No static keys stored anywhere
# Credential TTL matches job duration, expires automatically

The pipeline job requests an OIDC token from GitHub’s token endpoint, presents it to AWS STS, receives a temporary credential scoped to exactly the IAM role it needs, and the credential expires when the job ends. There is no AWS_ACCESS_KEY_ID stored as a CI secret. There is nothing to rotate, nothing to accidentally commit, and no credential that persists after the job completes.

Cycloid’s pipeline model extends this further: pipeline jobs authenticate through the platform, which brokers short-lived credentials from Vault without distributing static secrets to the pipeline configuration at all.

Detecting and Blocking Unauthorized Pipeline Modifications

Changes to pipeline configuration files (.github/workflows/*.yml, .gitlab-ci.yml, Concourse pipeline YAML) need the same PR review and approval process as application code. A pipeline config change can add a step that exfiltrates environment variables to an external endpoint, or remove a security scan step entirely, and neither action is detectable without a review gate.

The practical control requires at least one additional approver for changes to pipeline configuration files using CODEOWNERS or protected file rules. A pipeline change that bypasses this is a more significant security event than most application code changes.

8. Govern Self-Service Deployments with Pre-Constrained Parameters

Developer self-service is where most of the other practices get stress-tested. When developers can deploy infrastructure without ops intervention, the speed gain is real. So is the exposure. An open-text field for “security group rules” or “S3 bucket ACL” in a self-service form is a policy gap that is constantly exercised, usually by developers doing reasonable things that happen to be insecure.

Structural security inheritance - autonomous cloud deployment flow via StackForms

 

Designing StackForms That Balance Developer Autonomy with Security Constraints

Cycloid’s StackForms pre-constrain the parameters available in self-service deployment forms. Instead of free-text fields, developers select from pre-approved options defined by platform engineers. Here’s a StackForms variable definition for a database provisioning form:

use_cases:
- name: database_provisioning
sections:
- name: Database Configuration
groups:
- name: Instance Settings
technologies: [terraform]
vars:
- name: "Instance Type"
description: "Select an approved instance size"
key: db_instance_type
widget: dropdown_list
type: string
values:
- db.t3.medium
- db.t3.large
- db.r5.large
default: "db.t3.medium"
- name: "AWS Region"
description: "Deployment region (data residency policy)"
key: aws_region
widget: dropdown_list
type: string
values:
- eu-west-1
- eu-central-1
default: "eu-west-1"
# encryption is fixed, not exposed to the user

The developer provisioning a database chooses from three approved instance sizes and two approved regions. Encryption is set to true in the Terraform module and is never exposed as a configurable parameter. The developer can’t misconfigure it because the form doesn’t have a field for it.

Using Stack Templates as the Unit of Governance in Multi-Team Environments

Everything is visible in one place, and access is controlled by pre-defined roles and group mappings. If someone spins up an EC2 instance or a Kubernetes workload, it appears in the inventory, mapped to the right team and environment.

Stack templates in Git become the governed unit of infrastructure definition across a multi-team organization. When a team needs a new service type, they don’t configure it from scratch: they request a Stack template from the platform team. The template is reviewed, policy-tested against InfraPolicies, and published to the service catalog. Teams consume the template and can only modify the parameters exposed to them in the StackForm.

Security properties become inherited, not configured individually. Every new project that uses a governed Stack template receives the encryption settings, region restrictions, tagging requirements, and security group rules, with no team-level security configuration required.

Conclusion

The eight practices in this article address a single underlying problem: security enforcement that relies on humans to check the right thing at the right time fails as soon as teams scale beyond the point where a single platform engineer can review every change. Cloud environments at any meaningful scale change faster than human review cycles can keep up with.

We covered how Policy as Code at the infrastructure layer (not just the pipeline layer) closes enforcement gaps that pipeline-only scanning leaves open; how dynamic credential generation through Vault eliminates the static key sprawl that makes credential theft so consequential; how PR-time IaC scanning with tuned severity thresholds catches issues at the point of lowest remediation cost; how platform-level RBAC with cloud provider federation replaces the drift-prone pattern of managing access separately in each cloud console; how continuous drift detection with automated or human-in-the-loop remediation keeps the live state aligned with declared state; how compliance rules in version control convert annual audit snapshots into continuous verification; how OIDC-based pipeline identity eliminates long-lived service account credentials from CI/CD; and how StackForms with pre-constrained parameters make security a structural property of the deployment template rather than a review gate.

The security posture doesn’t degrade as teams scale under these controls because the controls are inherited by every project that uses the governed Stack templates and pipeline patterns, rather than renegotiated on a per-team basis.

 

Frequently Asked Questions

1. What is the practical difference between DevSecOps in cloud environments and traditional DevSecOps implementations?

Traditional DevSecOps assumed a relatively fixed deployment surface with change windows and manual approval gates. Cloud environments undergo continuous change, offer self-service provisioning, and modify their infrastructure through scaling events.

2. How does policy enforcement at the infrastructure layer actually differ from IaC scanning in a CI/CD pipeline?

Pipeline scanning runs when the pipeline runs and only when the pipeline runs. A developer who triggers a Terraform apply directly, or a platform API call that bypasses the pipeline, bypasses the scan. Infrastructure-layer enforcement (Cycloid’s InfraPolicies evaluated against every Terraform plan) runs regardless of the trigger mechanism because it’s in the path of plan execution, not CI job execution.

3. How do teams maintain compliance across multi-cloud environments without a dedicated compliance team reviewing everything?

By encoding compliance controls as InfraPolicy rules mapped to specific framework requirements (ISO 27001, SOC 2, GDPR), every deployment becomes a compliance check. The policy repository in Git serves as continuous evidence of what was enforced and when, replacing point-in-time manual reviews with an auditable automated trail.

4. When should RBAC be managed at the platform layer rather than directly in each cloud provider’s IAM console?

As soon as you’re managing more than one cloud provider, or more than one team with different access requirements. Cloud provider IAM definitions managed separately diverge over time: someone updates the AWS policy but forgets Azure, a contractor gets offboarded from Cycloid, but their GCP service account remains active.

Latest articles

Port IDP Review: Features, Pricing & Alternatives (2026)

By the Cycloid Platform Engineering team, practitioners building and operating enterprise IDPs since 2015.  ...

July 8, 2026

Service Catalog Tools: The 2026 Comparison Guide for Platform Engineering Teams

By the Cycloid Platform Engineering team, practitioners building and operating enterprise IDPs since 2015.  ...

July 8, 2026

Software Catalog: What It Is, What It Must Include, and Which Software to Choose (2026)

Direct Answer. A software catalog is the centralised registry inside an internal developer platform that...

July 8, 2026