Text size
On My Radar6 min read

No more static passwords between services

Workload identity and SPIFFE: letting services prove who they are.

No more static passwords between services
AI-generated editorial illustration

Think about how your services authenticate to each other and to the cloud. In many companies, the answer is static credentials. An access key in an environment variable. A shared API token in a config file. A database password copied into five places. They rarely get rotated, and when one leaks, you often don't know where else it's used.

Humans moved past this a while ago: single sign-on, MFA, short-lived sessions. Workloads deserve the same.

The problem with shared secrets

Static credentials have three big weaknesses:

  • They're long-lived. A leaked key works until someone notices and rotates it, which can be months.
  • They're copyable. Anyone or anything that gets the key can use it, from anywhere.
  • They don't say who's calling. Five services sharing one token look identical in the logs.

Zero trust is the idea that nothing should be trusted just because it's inside your network. Every request should prove who it comes from. For workloads, that means giving every service a strong, verifiable identity.

Cloud workload identity

The easiest win: let your workloads authenticate to cloud services using their platform identity instead of keys.

On Kubernetes, every pod runs with a service account. Cloud providers can trust Kubernetes service account tokens and exchange them for short-lived cloud credentials:

  • AWS: IAM Roles for Service Accounts (IRSA), or the newer EKS Pod Identity.
  • Google Cloud: Workload Identity Federation for GKE.
  • Azure: Microsoft Entra Workload ID.

The setup: link a Kubernetes service account to a cloud role. Pods using that service account automatically get temporary credentials, rotated for them, scoped to that role. No secret to store, nothing to leak for long.

apiVersion: v1
kind: ServiceAccount
metadata:
  name: orders
  namespace: shop
  annotations:
    eks.amazonaws.com/role-arn: arn:aws:iam::123456789012:role/shop-orders

The same idea works in CI: OIDC federation lets GitHub Actions, GitLab CI and others get cloud credentials without stored keys.

The safest credential is the one that's issued for a few minutes, to one workload, for one job, and then simply expires.

SPIFFE, simply

Cloud workload identity solves "my pod talking to my cloud provider". But what about service-to-service calls, across clusters, clouds and on-premises machines?

SPIFFE (Secure Production Identity Framework For Everyone) is a CNCF standard for workload identity, independent of any platform. It defines:

  • SPIFFE ID: a unique name for a workload, written as a URI, like spiffe://acme.com/ns/shop/sa/orders.
  • SVID (SPIFFE Verifiable Identity Document): a short-lived document proving that identity, either an X.509 certificate or a JWT.
  • Workload API: a local API where workloads fetch their SVIDs, without needing any secret to start with.

SPIRE is the reference implementation. A SPIRE server issues identities, and agents on each node attest workloads: they check what the workload really is (which Kubernetes service account, which node, which process) before handing out an identity. Certificates are rotated automatically, often every hour.

Many tools speak SPIFFE: service meshes like Istio and Linkerd use SPIFFE-style identities internally, and Envoy, Cilium and various databases and proxies can use SVIDs.

mTLS between services

With identities in place, services can use mutual TLS (mTLS): both sides present certificates, so each knows exactly who it's talking to, and the traffic is encrypted.

Doing mTLS by hand in every application is painful. That's why it's usually handled by:

  • A service mesh (Istio, Linkerd, Cilium), which adds mTLS between all services automatically.
  • SPIFFE libraries (go-spiffe and others) for applications that handle it themselves.

On top of mTLS, you can write authorisation policies: "only the checkout service may call payments on /charge". That's real zero trust: identity-based access, not network-based.

Where to start

You don't need SPIRE on day one. A practical path:

  1. Replace cloud access keys in Kubernetes with your provider's workload identity.
  2. Replace CI cloud keys with OIDC federation.
  3. Move remaining secrets into a secret manager with short-lived or rotated credentials.
  4. Add mTLS between services, most easily through a service mesh.
  5. Consider SPIFFE/SPIRE when you need one identity system across clusters, clouds and VMs.

So, is it worth the effort?

Yes. Removing static credentials eliminates one of the most common causes of breaches. The first steps, cloud workload identity and CI OIDC, are surprisingly easy and give immediate benefit.

My take: services should prove who they are every time, with credentials that expire before anyone can misuse them. Passwords are for humans, and even we're giving them up.

— Desly