Writing · 2026-08-30

Platform security principles

How I expect a platform to be built: identity as the perimeter, least privilege, segmentation, secure defaults, small blast radius, tenancy isolation, auditability, and a control plane that is not the data plane.

  • Security
  • Platform
  • IAM
  • Kubernetes
  • AWS

Application secure coding is necessary and not sufficient. The platform — accounts, networks, runtimes, keys, and pipelines — decides whether a single bug is an incident or a footnote. These are the principles I use when reviewing AWS, Kubernetes, and API estates in government, banking, and insurance. They sit next to the secure coding practices write-up; that article is about the service. This one is about the ground the service stands on.

Identity is the perimeter

Do not treat “inside the VPC” as trusted. Every call has a principal: a user, a workload identity, or a break-glass role.

  • Human access to production is federated (SSO / OIDC), MFA, and time-boxed. Standing admin on a laptop is a finding.
  • Workloads assume a role, not a long-lived access key baked into a pod or Jenkins node. ECS task roles, EKS IRSA / pod identity, Lambda execution roles — one identity per function of the system.
  • Service-to-service: mTLS or signed service credentials. A user JWT copied into every hop is not a platform identity.
  • Cloud APIs (S3, SQS, RDS, Bedrock) are authorized by IAM on that principal, not by “the cluster can reach the endpoint.”

If you cannot name the principal for a request, you do not have a perimeter. You have a network.

Least privilege, split by plane

The same person or role should not be able to change production, read all case data, and approve their own access.

  • Control plane (Terraform, cluster-admin, IAM admin, pipeline that deploys) is separate from data plane (read a case, write a file, consume a queue).
  • Compute vs functions: the application runtime invokes APIs; it does not hold s3:* on the documents bucket. Processors and presign lambdas do. That is a platform principle, not an app quirk.
  • Database: instance credentials are not shared across services. Each microservice gets a user that can touch only its schema.
  • Break-glass is a different role, logged, and expires. It is not the daily deploy role.

Widen a policy only with a ticket and an expiry. “Temporarily * to unblock” becomes the permanent architecture.

Segment the blast radius

Assume a credential or a pod is lost. What else dies?

  • Accounts / subscriptions: prod ≠ non-prod. A compromised CI in dev should not assume the prod deploy role.
  • Networks: private subnets for data stores; public only for load balancers and the fronts you intend. Security groups are allow-lists, not “open 0.0.0.0/0 and we have a WAF.”
  • Namespaces and tenancy: Kubernetes RBAC so team A cannot read team B’s secrets. For multi-program platforms (SNAP / Medicaid / TANF, or multiple insurance products), isolation is a product requirement, not a naming convention.
  • Queues and topics: a consumer IAM policy names the queue, not sqs:*.
  • Blast-radius tests: if this role’s keys leak, which buckets and tables are readable? Write that down in the design.

Strangler migrations make this explicit: the new service gets a smaller identity than the monolith, not a copy of the monolith’s god-role.

Secure by default

New environments, clusters, and pipelines should ship closed. Opening a path is a change you review.

  • New API Gateway routes and Spring services default to authenticated. Public is an exception with a name and an owner.
  • New buckets: block public access, encryption on, versioning on if the data matters. Public-read is never the template default.
  • New clusters: no privileged pods by default, no hostPath for app workloads, resource quotas so one namespace cannot starve the node.
  • New accounts: CloudTrail / equivalent on, no unused access keys, default VPC tightened or unused.

“We will add security in the next sprint” is how non-prod patterns become prod.

Separate data from the path that moves it

The file platform is the example: bytes live in S3; metadata and authorization live in Postgres and the API. The compute node is not a file server.

Generalize that:

  • Large or sensitive objects do not transit application heaps when a presigned or streamed path exists.
  • Backup and ETL roles are not the online API role.
  • Analytics copies of production are masked or tokenized; a “prod replica for the data science VPC” is a second production.

Encryption and key custody are platform features

  • TLS for anything that leaves a box, including “east-west” to RDS, Kafka, and internal APIs when the data is regulated.
  • At-rest encryption with keys in KMS (or the cloud equivalent). The app uses IAM to use the key; the key material does not live in the image.
  • Key policy is as important as the bucket policy. Who may Decrypt? Who may change that list?
  • Rotate at the platform cadence. Application teams should not invent a second keystore in git.

Secrets belong to the platform

  • Inject at runtime from Secrets Manager, SSM, or a vault sidecar. Pipelines get short-lived OIDC to the cloud, not a static AKIA on the agent.
  • Kubernetes secrets are not a vault; they are a delivery mechanism. Limit who can get secrets, encrypt etcd, and prefer external secret stores.
  • Non-prod secrets are not copies of prod. If someone dumps the staging secret store, prod should still be closed.

Observe what you will need in an incident

If you cannot answer “who did what to which resource,” you do not have a platform — you have hope.

  • API and data-plane audit: who assumed which role, who called GetObject, who changed IAM.
  • Application logs: correlation ids, not PII or tokens (see the coding article).
  • Control-plane logs: Terraform apply, pipeline who, image digest that landed.
  • Alerts on the boring attacks: spike in 401/403, new public bucket, role that suddenly lists all secrets.

Retention and who may read logs are security controls. Splunk is in scope for privacy, not only for uptime.

Supply chain of the platform

The cluster runs your image and their base image.

  • Images built in CI, pinned by digest, scanned. No latest in prod manifests.
  • Admission: deny unsigned or unscanned images if you have the gate; at minimum, fail the pipeline.
  • Dependencies of the platform (ingress controller, operators, Jenkins plugins) get the same CVE treatment as application JARs.
  • Infrastructure as code is reviewed like application code. An IAM * in Terraform is a code-review block.

Fail closed, recover on purpose

  • Authz, crypto, and secret-store outages should not fail open (“let traffic through if the policy service is down”).
  • Backups are encrypted, access-controlled, and restored in a drill. An untested backup is not a control.
  • Incident roles are defined before the page: who freezes IAM, who rotates, who talks to the program owner.

Tenancy and regulated data

Public benefits, payments, and insurance data have extra rules. The platform must make the safe path the easy path.

  • Data classification labels drive which account, which encryption key, and which log index.
  • Cross-program or cross-tenant queries are explicit products, not a shared database user.
  • AI and RAG: the vector store and the model invocation use workload identity; the model still does not get the keys. Retrieval is filtered by the same tenancy you use for the OLTP API.

How this shows up in a design review

I ask:

  1. What is the principal for each hop (browser, API, Lambda, batch, human admin)?
  2. What can that principal not do if the credential leaks?
  3. Where are prod and non-prod split, and can CI in one assume the other?
  4. Where do bytes live vs where does authorization live?
  5. Who can change IAM, and is that change audited?
  6. If we lose this namespace / account / role, what is the blast radius in one sentence?

If the answers are “the VPC,” “the app role,” “same account,” “on the pod,” “whoever has the AWS login,” and “everything,” the platform is not ready for the application we are about to put on it.

Application reviews use the secure coding list. Platform reviews use this one. Ship both.

Discussion

Comments from readers and recruiters.

No comments yet. Be the first to leave a note for Subose or for other readers.