Platform Engineering Is Security's Best Friend (If You Do It Right)
Here's a frustrating truth about enterprise security: most of the vulnerabilities I see in production aren't there because developers are careless. They're there because the path of least resistance was the insecure one. The developer needed to ship a feature, the "correct" way involved three internal tickets, two approvals, and a Confluence page nobody's updated since 2022 — so they did the thing that worked and moved on. I don't blame them.
Platform engineering changes that equation. When done well, it makes the secure option the easy option. And that's a much better security strategy than writing more policy docs that nobody reads.
Let me walk you through how security fits into the platform engineering model, and what I'd actually prioritize building.
What Platform Engineering Actually Means
Platform engineering is the practice of building internal developer platforms (IDPs) — the tooling, automation, and abstractions that let product teams self-serve their infrastructure and deployment needs without becoming ops experts. Think: "you need a Postgres database? Fill out this form and it provisions in 5 minutes with backups, monitoring, and encryption configured correctly."
The key insight is that platform engineers are building products for internal customers. The customers are developers. And just like any product, if yours is too hard to use, people will find workarounds.
From a security perspective, this is huge. If the platform team bakes security controls into the platform itself — encryption defaults, network segmentation, secret management integrations, image scanning pipelines — then every team that uses the platform inherits those controls automatically. Security scales with developer adoption, not with security headcount.
Golden Paths: Making Security the Default Route
The "golden path" is the opinionated, paved route that the platform provides. Use our CI pipeline template and you get image scanning, SAST, and dependency checking included. Use our Terraform module for RDS and you get encryption at rest, automated backups, and security group rules that follow least privilege. Step off the golden path and you're on your own.
This is security through good UX, not policy enforcement. Here's what a golden path CI template might look like in practice:
# .github/workflows/golden-path-build.yml # Platform-provided template — don't modify the security steps name: Build and Push on: push: branches: [main] jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Run SAST scan uses: internal/sast-action@v2 # platform-owned action with: fail-on: HIGH - name: Dependency audit run: npm audit --audit-level=high - name: Build image run: docker build -t ${{ env.REGISTRY }}/${{ github.repository }}:${{ github.sha }} . - name: Scan image uses: aquasecurity/trivy-action@master with: image-ref: ${{ env.REGISTRY }}/${{ github.repository }}:${{ github.sha }} exit-code: '1' severity: 'HIGH,CRITICAL' - name: Push to internal registry run: docker push ${{ env.REGISTRY }}/${{ github.repository }}:${{ github.sha }}
Teams adopt this because it handles the tedious bits for them — they get a working CI pipeline in minutes. Security comes along for the ride.
The same principle applies to IaC. Platform-owned Terraform modules handle security defaults:
# modules/rds/main.tf — platform module, security baked in resource "aws_db_instance" "this" { identifier = var.identifier engine = "postgres" instance_class = var.instance_class allocated_storage = var.allocated_storage # Security defaults — not overridable by consumers storage_encrypted = true deletion_protection = true backup_retention_period = 7 enabled_cloudwatch_logs_exports = ["postgresql", "upgrade"] publicly_accessible = false # never exposed # Consumers configure these db_name = var.db_name username = var.username password = var.password # sourced from secrets manager by convention tags = merge(var.tags, { managed-by = "platform" security-reviewed = "true" }) }
Teams get a database. They can't accidentally make it public-facing or unencrypted because those decisions aren't exposed as variables.
Developer Self-Service with Guardrails
Self-service is the point of a platform. But "self-service without guardrails" is just "developers doing whatever they want," which is a different problem. The art is in building guardrails that prevent the dangerous stuff without friction-ing the useful stuff.
A few patterns that work well:
Backstage templates with validation. Backstage (the internal developer portal from Spotify, now CNCF) lets you build software templates that scaffold new services. You can embed security decisions directly into the template — which secrets manager integration to use, which Kubernetes namespace to deploy to, what baseline security contexts to apply. Developers fill out a form and get a repo with everything configured correctly.
Service catalog with compliance visibility. If every team can see their service's security posture in one dashboard — image vulnerability count, RBAC overpermissions, missing network policies — they'll fix things without you having to chase them. Make security status visible and you make it a team priority.
Pre-approved patterns for common tasks. Need to access another service? Use the service mesh mTLS pattern we've documented. Need to call an external API? Use the egress proxy with the approved list. Need credentials? Here's the vault integration template. Pre-approving secure patterns removes the decision cost for developers.
Policy-as-Code: OPA and Kyverno
Guardrails in the pipeline catch issues early. Guardrails at the cluster level catch what slips through. This is where OPA Gatekeeper and Kyverno come in.
I've used both. Kyverno has a gentler learning curve and feels more natural for Kubernetes operators. OPA/Rego is more powerful and portable (you can use it outside Kubernetes too — API gateways, Terraform, CI pipelines). For a new platform, I'd start with Kyverno and introduce OPA when you need the cross-system policy consistency.
Here's a Kyverno policy that enforces required labels — essential for cost attribution and incident response:
apiVersion: kyverno.io/v1 kind: ClusterPolicy metadata: name: require-labels annotations: policies.kyverno.io/description: >- Require team, env, and cost-center labels on all Deployments. spec: validationFailureAction: Enforce rules: - name: check-required-labels match: any: - resources: kinds: [Deployment] validate: message: "Deployments must have 'team', 'env', and 'cost-center' labels." pattern: metadata: labels: team: "?*" env: "?*" cost-center: "?*"
And an OPA/Rego policy enforcing that Terraform resources must have specific tags (usable in CI):
# policy/require_tags.rego package terraform.analysis required_tags := {"team", "env", "cost-center"} deny[msg] { resource := input.resource_changes[_] resource.type == "aws_s3_bucket" provided := {tag | resource.change.after.tags[tag]} missing := required_tags - provided count(missing) > 0 msg := sprintf( "Resource %v is missing required tags: %v", [resource.address, missing] ) }
The important thing about policy-as-code is that the policies live in version control, go through code review, and have tests. Security policy that lives in a wiki document is fiction. Security policy enforced by code is real.
Secure Defaults Over Security Reviews
This is the mindset shift I want to leave you with. The traditional security model is: developers build things, then security reviews them and finds problems. This doesn't scale. One security team cannot review every PR across dozens of product teams.
The platform engineering model inverts this. Security team's time goes into building the platform and the policies. Developer teams inherit the controls automatically. The review burden shifts from "review everything after it's built" to "build the right defaults once and maintain them."
This means security engineers need to think like product engineers. What's the developer experience of using our secrets management integration? Is it easier than just putting the key in an environment variable? If not, developers will take the shortcut and you'll lose.
Here's a concrete example. If your secret management workflow looks like:
# The insecure path (zero friction) export DB_PASSWORD=supersecret123
versus:
# The secure path (friction) # Step 1: Get vault token vault login -method=ldap username=$USER # Step 2: Write a policy in HCL # Step 3: Submit a ticket to get the policy approved # Step 4: Wait for approval # Step 5: Read the secret vault kv get -field=password secret/my-app/db
...you've already lost. The platform's job is to make the secure path look more like this:
# Secure path with good platform tooling # In deployment manifest — platform-provided integration handles the rest envFrom: - secretRef: name: my-app-db # synced from vault by external-secrets-operator
Zero friction for the developer. Vault does the right thing under the hood.
Internal Developer Platforms: The Security Control Plane
An IDP like Backstage or Port isn't just a developer portal — it's your security control plane. From a single interface you can surface:
- Which services are using deprecated base images
- Which deployments have missing security contexts
- Which teams haven't rotated their secrets in 90 days
- DORA metrics alongside security posture metrics
When security visibility is embedded in the tools developers already use every day, it gets acted on. When it lives in a separate security dashboard that only the security team looks at, it doesn't.
Where to Start
If you're building a platform from scratch, or trying to add security to an existing one, here's the order I'd tackle it:
- Secrets management integration — this has the highest risk and most developer buy-in when you make it easy.
- Golden path CI template with image scanning and SAST baked in.
- Kyverno baseline policies — non-root, required labels, no latest image tags.
- IaC modules for common infrastructure with security defaults locked in.
- Backstage or similar for visibility and self-service with guardrails.
Don't try to do it all at once. Pick the highest-impact item, build it well, get adoption, then move to the next one.
The Takeaway
Platform engineering is the most scalable security strategy available to us right now. Security through developer experience beats security through policy enforcement every time. When the platform makes the secure path the easy path, you don't have to chase developers — they just do the right thing because it's the path of least resistance.
The security team's job in this model isn't to be the police. It's to be the architects of a system where safety is the default, not the exception. That's a better job, and it produces better outcomes.
If you're a security engineer who hasn't talked to your platform team recently, go do that this week. You probably want the same things.