Security#
Security architecture is the operator designing systems that survive contact. The job is to make the right thing easy and the wrong thing hard, so that the next intruder, insider, or misconfiguration meets a layer that holds. Most breaches do not come from clever attacks; they come from known categories the architecture did not address.
The sections below are the categories: defense in depth, authentication, authorization, secrets, crypto, supply chain, audit. Each is a control the operator adds at design time so the blue-team operator on shift later does not have to invent it under fire.
Defense in Depth#
No single control is sufficient. Layer them so that compromise of any one control doesn’t ruin the day. The model below is the standard six-layer breakdown (edge, network, identity, application, data, audit) with each layer expected to fail gracefully into the next.
Edge, WAF, rate limiting, DDoS protection.
Network, VPC isolation, security groups, NetworkPolicy.
Identity, SSO, MFA, short-lived tokens.
Application, input validation, output encoding, authz on every route.
Data, encryption at rest and in transit, field-level encryption for the most sensitive.
Audit, immutable logs, anomaly detection, tested IR runbooks.
Authentication#
Three different audiences with three different authentication stories. Workforce auth optimizes for federation and MFA; customer-facing auth optimizes for usability and recovery flows; service-to-service auth optimizes for short-lived credentials and no human in the loop.
Workforce, SSO via OIDC / SAML; enforce MFA.
Customer-facing, proven libraries; never roll your own. Passwordless or password + MFA. Argon2id for hashes.
Service-to-service, short-lived workload identity (SPIFFE / IAM roles / managed identity). No long-lived secrets in code.
Common pitfalls.
Custom session tokens. Use signed cookies or JWTs from a trusted library.
Comparing tokens with
==(timing attack). Use a constant-time compare.Reusing passwords across users for testing in production environments.
Threat Modeling#
Before shipping a new system, spend an hour with STRIDE, the six-category Microsoft framework for “what could go wrong.” Write the assumptions and trust boundaries down somewhere durable, name a mitigation per category, and revisit before significant changes.
Spoofing, can someone pretend to be someone else?
Tampering, can data be modified in transit or at rest?
Repudiation, can an actor deny they did something?
Information disclosure, what leaks?
Denial of service, what overwhelms us?
Elevation of privilege, can a low-priv actor get higher privileges?
Write down the assumptions, the trust boundaries, and the mitigations. Revisit before significant changes.
Zero Trust#
Don’t grant trust based on network location. The “perimeter” went away when remote work, multi-cloud, and SaaS arrived; treat every network as hostile and authenticate and authorize every request, including internal traffic.
mTLS between services (or signed JWTs at minimum).
Per-service identity, not “everyone in the VPC is a friend”.
Short-lived credentials by default; rotate on a schedule.
Least Privilege#
Every principal, human or service, should have only the permissions it needs to do its job. Permissions accumulate naturally over time as people change roles and one-time exceptions become permanent; the discipline below pushes back against the accretion.
Use roles scoped to the smallest reasonable resource set.
Time-bound elevated access; never hand out permanent admin.
Audit periodically; permissions accumulate.
Input Validation and Output Encoding#
Most injection vulnerabilities boil down to mixing validation and encoding, validating inputs at the boundary and encoding outputs for the destination. Get either side wrong and SQL injection, XSS, command injection, and path traversal all become possible.
Validate at the boundary; types, ranges, length, format. Fail closed.
Encode for the destination; HTML encoding for HTML, parameterized queries for SQL, escaping for shell.
Treat all user input as hostile, including from logged-in users.
Cryptography#
The discipline is mostly negative: don’t roll your own, don’t reach for old algorithms, don’t store keys in source. Use what the platform provides, in the modes the spec recommends, with keys managed in a KMS. The list below is the operator’s short version.
Use modern, well-tested libraries (libsodium, the platform’s KMS, the language’s standard library).
Never roll your own primitives.
Modern algorithms only: AES-GCM / ChaCha20-Poly1305 for symmetric, X25519 / ECDSA P-256 for asymmetric, Argon2id / scrypt for passwords, HMAC-SHA-256 for MACs.
Manage keys in a KMS; rotate them; audit access.
Secret Management#
Tokens, certificates, database credentials, API keys, treat them as ephemeral data the system fetches at runtime, not as config bundled with the build. The discipline below limits blast radius when something does leak.
Centralize: AWS Secrets Manager, GCP Secret Manager, Azure Key Vault, Vault, Doppler.
Never bake secrets into images.
Rotate, with grace periods.
Limit blast radius, per-service, per-environment.
Supply Chain#
Most modern code is mostly other people’s code. The supply chain becomes the attack surface; a single compromised dependency or upstream image takes the entire dependent tree with it. The discipline below builds in attestation and pinning so the provenance of every artifact is checkable.
Lockfiles + dependency scanning.
Pin base images by digest.
Sign artifacts (cosign / Sigstore).
SBOMs and provenance attestations.
Be careful what you
npm install.
Privacy by Design#
The same instinct as least-privilege, applied to user data. Don’t collect what you don’t need, retain it as briefly as the business allows, and design schemas where deletion is actually possible, including from backups, on a documented schedule.
Minimize collected data.
Document retention; delete on schedule.
Pseudonymize where you can; encrypt where you must.
Make user-visible deletion actually delete (including from backups, on a schedule).