We use analytics cookies.We use cookies to analyze site traffic and improve your experience.
Loading...
System Design Masterclass · Security Architecture
Free preview: the first 2 parts of this 5-part lesson.
Already bought the course? Sign in to read the whole lesson.
this lesson is part of
System Design Masterclass
Unlock this lesson and the 751 other paid lessons
$25 once, by PayPal
See the System Design courseread the rest of this lesson in
System Design Masterclass
Unlock this lesson and the 751 other paid lessons
$25 once, by PayPal
See the System Design coursein Security Architecture
This lesson is part of the full System Design Masterclass. Unlock it along with 769 other lessons for a one-time payment.
One-time payment by card or PayPal
Get Lifetime AccessOne-time payment: UPI, card or netbanking
Get Lifetime Access18 Foundation lessons are free, no payment needed. Try them now
It is easy and good
“It is really nice and good Please join the course”
A payment service accepted requests from any service on the internal network without authentication. The reasoning was "it's behind the firewall, so only our services can reach it." Then an attacker compromised a low-priority logging service through a dependency vulnerability. From that foothold, they called the payment service directly, because the payment service trusted any internal caller, and initiated unauthorized refunds. The logging service had no business talking to the payment service, but nothing enforced that boundary.
This is not hypothetical. Capital One's 2019 breach followed this pattern. An attacker exploited a misconfigured WAF to gain credentials that could call internal AWS services. The services did not verify whether the caller should have access to the data it requested. 106 million records were exposed.
Service-to-service authentication answers the question: "Is the service calling me actually who it claims to be?" In a architecture with dozens or hundreds of services, every inter-service call should be authenticated. Network location is not identity.
Five approaches dominate, each with different security and complexity trade-offs.
API keys are the simplest approach. Each service pair shares a unique key. The caller includes it in an header. The problem: keys are long-lived bearer tokens. They sit in environment variables, get logged by proxies, and rotating them requires coordinated deployments across every consumer. At 5 services, this is manageable. At 200, it is a full-time job.
2.0 client credentials improve on API keys. Services request short-lived access tokens from an authorization server. Tokens expire in minutes, limiting the damage window. But the client secret is still a shared secret stored on the service.
with service identity works well when you have an identity provider issuing JWTs to each service. The JWT carries the service identity as a claim and is signed by the IdP's key. Recipients verify the signature without calling the IdP. Short expiration limits replay risk.
mTLS provides the strongest authentication. Identity is proven cryptographically per-connection. The private key never leaves the service. Service meshes (Istio, Linkerd) automate certificate lifecycle entirely.
SPIFFE/SPIRE standardizes identity across heterogeneous environments. Each workload gets a SPIFFE ID like spiffe://company.com/payment-service. SPIRE issues short-lived X.509 certificates or JWTs automatically, rotating them every few hours. It works across , bare-metal VMs, and multi-cloud.