Security in Distributed Systems
Security in Distributed Systems#
TL;DR#
Security in a distributed system starts from a threat model that a single machine never has to consider: the network itself is untrusted, and there is no shared trust anchor by default - every node must be explicitly convinced of every other node's identity and authorization, over a channel an attacker might control. This lesson covers authentication across nodes, securing channels, distributed access control, and the attack shapes unique to distribution - replay, man-in-the-middle, and (specific to peer-to-peer/gossip systems, Lesson 07) Sybil attacks - each a direct consequence of removing the assumptions a single trusted machine takes for granted.
The idea#
A single machine's security model can often lean on physical or OS-level trust: a process on the same machine as another process can (with appropriate permissions) trust the kernel to correctly identify who's calling. A distributed system has none of that for free. Fallacy 4 from Lesson 01's "eight fallacies" - "the network is secure" - is false by default, and the consequence cascades through everything: a message arriving over the network could have been sent by exactly who it claims, or by an attacker who has compromised a link, is impersonating a legitimate node, or is replaying an old, previously-valid message. Fallacy 6 - "there is one administrator" - compounds this: large distributed systems frequently cross organizational boundaries where there is no single party everyone implicitly trusts.
This lesson's job is to make that threat model explicit and walk through the mechanisms distributed systems use to establish trust despite it: authentication (proving identity across an untrusted network), secure channels (protecting messages in transit), access control (deciding what an authenticated identity is allowed to do), and the specific attack shapes that these mechanisms exist to defend against.
How it works#
1. The threat model: what's different about a distributed system#
Before any mechanism makes sense, the threat model needs to be stated precisely - echoing Lesson 09's insistence that "fault tolerant" is meaningless without naming the failure model, "secure" is meaningless without naming the threat model:
- The network is not trusted. Any message could be intercepted, read, modified, dropped, delayed, duplicated, or forged by an adversary with access to any link the message traverses (a compromised router, a malicious Wi-Fi access point, an ISP, a state actor - the specific adversary varies, but the assumption "the wire is safe" cannot be made by default).
- There is no shared trust anchor by default. On a single machine, the OS kernel is an implicit trust anchor everyone relies on. Across a distributed system - especially one crossing organizational boundaries (Lesson 01's administrative-scalability dimension) - no single component is automatically trusted by every participant; trust has to be explicitly established (via cryptographic credentials, certificate authorities, or a shared secret) rather than assumed.
- Nodes themselves might not be who or what they claim. Especially in decentralized/P2P architectures (Lesson 02), where any node can claim any identity with no central authority vetting it, the system must defend against nodes lying about their own identity or capabilities.
The practical consequence: every distributed-systems security mechanism is ultimately answering one of three questions - who are you (authentication), can I trust what you're sending me hasn't been tampered with or overheard (secure channels), and are you allowed to do this (access control) - and all three must be re-established, not assumed, at essentially every network boundary.
2. Authentication across nodes#
Authentication proves identity - that a message or connection genuinely originates from the party it claims to. Across a network, this cannot rely on physical proximity or OS-level process identity; it must rely on cryptography.
- Shared-secret (symmetric) authentication. Two parties who already share a secret key can prove their identity to each other by demonstrating knowledge of that secret (e.g., via a challenge-response protocol, where one side sends a random challenge and the other proves it can correctly encrypt/sign it using the shared key, without ever transmitting the key itself). Simple and fast, but requires securely distributing the shared secret in advance, and doesn't scale well to large groups (every pair needing a distinct shared secret, or a shared group secret that, if compromised on any one member, compromises everyone's authentication).
- Public-key (asymmetric) authentication. Each party has a private key (kept secret) and a corresponding public key (freely shared). A party proves its identity by signing a challenge with its private key; anyone holding the corresponding public key can verify the signature without ever needing the private key itself. This scales far better than shared secrets (no need for every pair to share a distinct secret) but requires a way to trust that a given public key really belongs to the party claiming it - which is exactly what certificates and certificate authorities (CAs) provide: a CA (or a chain of them) vouches, via its own signature, that "this public key belongs to this identity," and participants trust the CA's signature because they've pre-configured trust in that CA (the actual trust anchor, ultimately still established out-of-band, e.g., via CA root certificates shipped with an OS or browser).
Worked example. Two microservices, orders-api and payments-api, operated by the same company but running on different hosts, need to authenticate each other before exchanging sensitive data. Using mutual TLS (mTLS), each service holds a private key and a certificate (signed by the company's internal CA) asserting its identity. When orders-api connects to payments-api, both sides present their certificates during the TLS handshake; each verifies the other's certificate chain up to the shared, pre-trusted internal CA root, and each proves possession of the corresponding private key as part of the handshake protocol. Neither service ever needed to pre-share a secret directly with the other - both independently trust the CA, and the CA's signature transitively establishes trust between them. This is exactly the pattern service meshes (Lesson 02's hybrid architectures) automate: issuing and rotating short-lived certificates for every service automatically, so mutual authentication happens transparently on every internal connection without each service team manually managing key distribution.
3. Secure channels: protecting messages in transit#
Once identity is established, messages exchanged over the (still untrusted) network need protection against two distinct threats: eavesdropping (an attacker reading the content) and tampering (an attacker modifying the content in transit, or injecting forged messages). A secure channel provides: - Confidentiality - encrypting message content so an eavesdropper on the wire cannot read it, even if they can intercept every byte. - Integrity - a cryptographic mechanism (a MAC, or a digital signature) that lets the receiver detect if a message was altered in transit, even by a single bit. - Authenticity (tying back to the previous section) - assurance that the message genuinely originates from the claimed sender, not an impersonator.
TLS (Transport Layer Security) is the dominant real-world implementation, bundling all three properties together for a connection: after an initial handshake (which performs authentication, typically of the server and optionally of the client as in mTLS above, and negotiates shared session keys), all subsequent traffic on the connection is encrypted and integrity-protected using those session keys.
Worked example. Without a secure channel, a payment amount sent as plain-text JSON over the network ({"amount": 100}) could be read by anyone with access to any link along the path (violating confidentiality - a serious problem even for "internal" traffic, since Lesson 01's fallacies remind us the network cannot be assumed uniformly safe just because it's "inside" a data center), or modified in transit to {"amount": 100000} before reaching the payment processor (violating integrity, with obviously severe consequences). TLS closes both gaps: the encrypted channel prevents the eavesdropping read, and the integrity check (built into TLS's record protocol) means any in-transit modification is detected and the connection is torn down rather than silently accepting corrupted data.
4. Access control in a distributed setting#
Once a party is authenticated, access control decides what it's actually permitted to do - and in a distributed system, this decision itself often can't be made locally by a single node, because the resource being accessed, the policy governing it, and the identity requesting it may all live on different machines.
- Centralized access control - a single policy service (or a small, replicated cluster of one, per Lesson 08's replication techniques) holds the authoritative access-control policy, and every request is checked against it, either by calling the service directly on each request or by issuing short-lived, cryptographically signed tokens (e.g., a signed JWT or a Kerberos-style ticket) that encode "this identity has been granted this permission until this expiry" - so downstream services can verify the token's signature locally without a round trip to the policy service on every single request.
- Decentralized/capability-based access control - rather than checking identity against a central policy on every access, a requester holds an unforgeable "capability" (a cryptographic token proving it was granted specific access to a specific resource) and simply presents it; possession of the capability is the authorization, with no centralized lookup needed at request time. This fits decentralized architectures (Lesson 02) well, since it avoids reintroducing a centralized bottleneck purely for authorization checks, at the cost of needing careful capability-revocation mechanisms (since there's no central point to instantly "turn off" access - a capability is valid until it expires or is explicitly revoked via whatever out-of-band mechanism the system provides).
Worked example. A microservices platform issues short-lived (5-minute) signed access tokens after a user authenticates once at a central identity provider. Each downstream service (orders, payments, shipping) verifies the token's signature locally (using the identity provider's public key, distributed in advance - the same public-key trust pattern as the authentication section above) and checks the permissions encoded in the token, without calling back to the identity provider on every single request. This avoids the "hidden centralization" pitfall from Lesson 01 (every request funneling through one authorization service, which would be both a latency and availability bottleneck) while still deriving from a single, centrally-managed source of truth for who's allowed to do what - the token's short expiry bounds how long a compromised or over-broadly-scoped token remains dangerous, which is the direct trade-off against the convenience of not re-authenticating constantly.
5. Attack shapes unique to distributed systems#
- Replay attacks. An attacker captures a legitimate, validly-authenticated message (e.g., a signed "transfer $100" request) and re-sends it later, hoping the receiver processes it again as if it were a new, legitimate request. Because the message's signature is genuinely valid (it really was signed by the legitimate sender, just not now), signature verification alone does not catch a replay - defenses require adding freshness: a timestamp (rejecting messages older than some window), a nonce (a unique, single-use value the receiver tracks and rejects if seen again), or a sequence number (rejecting anything not strictly greater than the last accepted number from that sender). This connects directly to Lesson 04's idempotency discussion: a well-designed idempotent API is also naturally replay-resistant for its side effects (a replayed "charge $100 with idempotency key X" simply returns the already-computed result rather than charging again) - though idempotency and replay-defense solve related but distinct problems (idempotency protects against duplicate effects from legitimate retries; replay-defense protects against an attacker deliberately resending a captured legitimate message).
- Man-in-the-middle (MITM) attacks. An attacker positions itself between two communicating parties, intercepting and potentially altering traffic while each party believes it's talking directly to the other. Without mutual authentication (verifying both directions of a connection, not just one), an attacker can impersonate the server to the client, the client to the server, or both simultaneously, relaying (and manipulating) traffic between them. This is exactly why the certificate-chain verification in TLS matters so much: skipping certificate validation (a distressingly common mistake, e.g., disabling verification "just for testing" and shipping it) reopens the door to exactly this attack, because the client no longer has any cryptographic assurance it's really talking to the legitimate server rather than an attacker's proxy.
- Sybil attacks. Specific to decentralized/P2P systems (Lesson 02) and gossip-based protocols (Lesson 07) that have no central authority vouching for identity: an attacker creates a large number of fake identities (nodes) to gain disproportionate influence over the system - e.g., in a gossip-based reputation or voting system, controlling enough fake "peers" to outvote or drown out legitimate participants, or in a DHT (Lesson 05), controlling enough of the address space to intercept or censor lookups for specific keys. Because there's no central authority to check "is this a real, distinct participant," defending against Sybil attacks requires making identity creation costly or externally verifiable in some way - proof-of-work (making each identity computationally expensive to create, as in Bitcoin), proof-of-stake (requiring identities to have an economic stake that can be slashed for misbehavior), or tying digital identities to a scarcer, harder-to-fake external resource (real-world identity verification, invitation-only bootstrapping from already-trusted nodes).
Worked example: Sybil attack on a gossip-based reputation system. A decentralized marketplace uses gossip (Lesson 07) to disseminate seller reputation scores, with each peer's vote on another peer's trustworthiness weighted equally. An attacker spins up 10,000 fake peer identities (cheap to do with no identity-creation cost) and has them all gossip artificially high reputation scores for a single, actually-malicious seller identity the attacker also controls. Because reputation is computed by counting/aggregating peer votes with no way to distinguish the 10,000 fake peers from genuine ones, the malicious seller's reputation is inflated far beyond what real peer opinion would support - a textbook Sybil attack exploiting the system's lack of a trust anchor for "one identity, one vote." A proof-of-work requirement (each new identity must solve a computationally expensive puzzle before its votes count) would make creating 10,000 identities prohibitively expensive, directly closing this attack vector at the cost of a real computational (and thus environmental/economic) overhead for every legitimate participant too.
Pros#
- Explicit authentication, secure channels, and access control let mutually untrusting (or simply unfamiliar) parties cooperate safely across an inherently untrusted network - the foundation that makes cross-organizational and internet-scale distributed systems possible at all.
- Public-key infrastructure (certificates, CAs) scales trust establishment far better than pairwise shared secrets, enabling secure communication between parties that have never directly exchanged keys.
- Short-lived, signed tokens for access control avoid the "hidden centralization" bottleneck of checking every request against a central authority, while still deriving from a single manageable source of truth.
Cons#
- Every security mechanism here adds real overhead - cryptographic operations cost CPU, certificate/token verification adds latency, and key/certificate lifecycle management (issuance, rotation, revocation) is genuine, ongoing operational work that's easy to under-invest in.
- Centralized access control models reintroduce a bottleneck/single-point-of-failure risk if not carefully designed (mitigated, but not eliminated, by short-lived cached tokens); decentralized/capability-based models push complexity into revocation, which is inherently harder without a central point of control.
- Defenses against specific attacks (replay, Sybil) add design and operational complexity (nonce tracking, proof-of-work tuning) that must be weighed against the actual likelihood and cost of the attack in a given system's real threat model.
Alternatives#
- Network-level isolation (VPNs, private networks, firewalls) as the primary defense - rather than (or in addition to) cryptographic authentication at the application layer, restrict which parties can even reach a service over the network. Useful as defense-in-depth, but insufficient alone in any system crossing trust boundaries or where an attacker might gain a foothold inside the "trusted" network perimeter (the well-known weakness of purely perimeter-based security models, which is why "zero trust" architectures - authenticating every connection regardless of network origin - have become the more robust default).
- Blockchain/distributed-ledger consensus for Sybil resistance - proof-of-work or proof-of-stake consensus (an application of Lesson 10's consensus machinery to a specifically adversarial, Byzantine threat model per Lesson 09) as a more elaborate answer to "how do we agree on shared state with no trusted central authority and Sybil-resistant participation" - appropriate for genuinely trustless, adversarial, multi-party settings, and significant overkill for a single organization's internal systems.
- Federated identity (OAuth2/OIDC) - rather than every service managing its own authentication directly, delegate identity verification to a trusted external identity provider, which issues tokens that downstream services trust based on the provider's signature - a practical, widely-adopted middle ground between fully centralized and fully decentralized identity management.
When to use it#
- Use mutual authentication and encrypted channels (mTLS or equivalent) for any communication crossing a trust boundary - between organizations always, and, given zero-trust principles, increasingly for internal service-to-service traffic too, since "inside the data center" is not automatically safe (Lesson 01's fallacy 4 again).
- Use short-lived signed tokens for access control in systems where centralizing every authorization check would create an unacceptable bottleneck, while still wanting a single, centrally-manageable source of policy truth.
- Use replay defenses (nonces, timestamps, sequence numbers) for any endpoint accepting state-changing requests over a network an attacker might observe and capture traffic on.
- Use Sybil-resistance mechanisms (proof-of-work/stake, invitation-based bootstrapping) specifically in decentralized/P2P or gossip-based systems where identity creation is otherwise free and influence is proportional to identity count.
When NOT to use it#
- Don't rely on network perimeter security (VPN/firewall) alone as your only defense for anything crossing an organizational or even internal-team trust boundary - it fails completely the moment an attacker gains any foothold inside the perimeter, and doesn't defend against a compromised or malicious insider at all.
- Don't disable certificate validation "temporarily" for convenience in any environment that could plausibly see production-adjacent traffic - this is one of the most common, most severe real-world MITM-enabling mistakes, and configuration meant to be temporary routinely ships to production.
- Don't build Sybil-resistance machinery (proof-of-work, elaborate identity-cost schemes) for a centralized or permissioned system where identity is already vetted by a trusted authority - it's solving a problem (unlimited free fake identities) that a centralized system with an actual identity provider doesn't have.
Key takeaways / mental model#
Distributed-systems security starts from refusing to assume anything Fallacy 4 ("the network is secure") or Fallacy 6 ("there is one administrator") would otherwise let you assume - the network is hostile territory, and trust must be established explicitly, cryptographically, and continually re-verified rather than assumed from network location or prior handshakes alone. Authentication answers "who are you" (via shared secrets or, more scalably, public-key certificates chaining to a trusted CA); secure channels answer "can this message be read or altered in transit" (TLS bundles confidentiality, integrity, and authenticity together); access control answers "are you allowed to do this" (centralized policy with cached short-lived tokens is the common, scalable pattern). The named attack shapes - replay, MITM, Sybil - are each a precise description of what happens when one of these mechanisms is missing or incomplete, which is why naming the threat model precisely (mirroring Lesson 09's insistence on naming the failure model precisely) is the first and most important step, not an afterthought.
Self-check questions#
- Explain why "the network is secure" being false (Lesson 01's fourth fallacy) has security implications beyond just "use HTTPS" - trace through what specifically breaks (confidentiality, integrity, authenticity) if a distributed system assumes internal network traffic is inherently safe.
- Why does public-key authentication scale better than shared-secret authentication for a system with many participants, and what role does a certificate authority play in making public-key authentication practically trustworthy rather than just theoretically possible?
- A service verifies that an incoming request's digital signature is valid and concludes the request is safe to process. What attack does this alone fail to prevent, and what additional mechanism is needed to close the gap?
- Explain why Sybil attacks are a problem specifically for decentralized/gossip-based systems (Lesson 02, Lesson 07) but not really a concern for a centralized system with a vetted identity provider. What are two different classes of defense against Sybil attacks?
- A team disables TLS certificate validation in their staging environment "to make local testing easier" and the same code path accidentally ships to production. Walk through exactly what attack this exposes the system to, and why signature/encryption alone (without validating the certificate chain) doesn't protect against it.
References#
- Distributed Systems, 3rd ed. (van Steen & Tanenbaum), Chapter 9: Security
system-design/13(Security: Authentication and Authorization) - the applied treatment of authn/authz, sessions, OAuth2/OIDC, TLS/mTLS- distributed-systems.net (free companion site for the source book)