QIAOPANG.COM · SELECTED ESSAYS (2013–2026) · 260 ESSAYSBrowse Chronologically (2013 → 2026) ↗
QiaoPang · Programmers LifeSelected Essays · Systems, Craft & Agentic Era
Timeline ↗

AWS Best Practices

AWS Best Practices

I’m a heavy AWS user — so heavy that, as the saying goes, “a day without food is fine; a day without AWS is not.” My daily routine amounts to “eat, sleep, use AWS.” Looking back over the past few years at Juniper and Tubi, and over my first month at Arcblock, I’ve gradually worked out some best practices for using AWS — and although these practices are aimed at AWS, they may hold some lessons for the way you approach other clouds too.

Principles

First, when using cloud services, we need to define a few basic principles:

  • R1. Security and ease of use are irreconcilably at odds. We cannot sacrifice security to gain usability. So the only path is to build the simplest possible tools, preserving some ease of use while guaranteeing security.
  • R2. No resource should have external access unless it is truly necessary.
  • R2. Test accounts and production accounts must be completely isolated. The test account serves as a sandbox where engineers can attempt all sorts of high-risk experiments. The production account is reachable only through scripts with specific permissions, minimizing the risk of human error.
  • R3. Continuously train the whole team to reduce its dependence on the Console until, eventually, no one uses the Console at all.

Practices

MFA

Multi-Factor Authentication must be enabled at the earliest possible moment. Every IAM user we create carries one precondition on any service it can access: MFA must be enabled. You can add a condition like this to an IAM policy:

{
  "Condition": {
    "Effect": "Allow",
    "Action": [
      "ec2:*",
      "s3:*"
    ],
    "Bool": {
      "aws:MultiFactorAuthPresent": true
      }
  }
}

This way, engineers must present MFA credentials when accessing EC2 / S3. Of course, you also need to allow users to register an MFA device while MFA is not yet enabled — otherwise you’ve checkmated yourself.

The trouble is that this makes life miserable for engineers, especially when accessing APIs with access keys — the nuisance never ends. To fix that, we can wrap STS, so that every other day you run something like this to obtain temporary session-level credentials:

AWS Best Practices

Bastion / VPN server

In the martial world, everything comes down to one word: concealment. The fewer points you expose, the safer you are.

Bastion and VPN servers both exist to grant access to internal resources. For internal servers you don’t want to expose certain interfaces — SSH, RPC, and so on — yet whether for internal testing or for ad-hoc administrative access, you need some way in. That’s where a dedicated jump host or VPN server strikes a balance between security and usability.

For extra safety, the bastion / VPN server can also move well-known ports elsewhere — so a scanner can’t discover your bastion / VPN server simply by port scanning. For example, SSH listens not on port 22 but on port 9527.

SSH

Accessing a server over SSH to get things done is often necessary, but as the number of machines grows, managing SSH keys becomes a headache — using one or a handful of SSH keys and sharing the private key with the whole team is clearly not safe. What happens when an engineer leaves? Should the key you shared with them be revoked? If you revoke it, what about all those servers already using it? If you don’t, how do you guarantee security?

So the best approach is for every engineer to use their own key; there is never a situation where everyone shares one. When a machine is provisioned, create an account for each engineer and enable their SSH public key. But then problems arise: 1) Where do you find each engineer’s SSH public key? 2) What happens when a new engineer joins — or when one leaves?

For 1), if we tie users to IAM, we can pull the SSH key each user has uploaded to IAM; for 2), when people come and go, we simply add or remove users on each machine, without affecting anyone else.

Many companies deploy a bastion server to protect internal resources, yet the bastion server and the other servers use the same key. It’s like building a security architecture as bewildering as a set of Russian nesting dolls, only to find that every nested lock opens with the same key. That is not security.

MORE IN Systems & Architecture

Further Reading in This Column

View all essays in “Systems & Architecture” →

The Future of Logs: Rectifying Names

For a decade we built observability into a beautiful tower on a foundation of drifting strings—field names by convention, cardinality by luck, bills by endurance. This essay proposes a radical fix: use protobuf to give every observed event a proper name, unify logs, metrics, and audit into one versioned, owner-tagged, retention-aware event catalog, and keep an escape hatch called ForensicEvent for the unknown unknowns.

New Hope (2025–2026)10,772 chars · 24 min read

Abandoning Multi-Environment Entirely: Reshaping the Next-Generation Serverless Architecture with Rust and Pingora

When we return to first principles and reconsider what "compute" really is, we find that multi-environment setups are an illusion, Kubernetes is an over-abstraction, and Serverless cold starts and connection-pool storms are self-inflicted. This essay dissects an environment-less architecture built on Baggage Header routing, a Pingora smart gateway, Firecracker microVMs, and a Rust Data Bus — an attempt to answer: what should compute look like in the post-Kubernetes era?

New Hope (2025–2026)23,788 chars · 53 min read