Yellow Theme

Next start · October 2026

Notes / 20

2026-09-15

SSH closed until we need break-glass

The signing host for the evidence workflow needed an admin path. Leaving port 22 open to the world was the wrong default. Empty CIDRs keep SSH closed until we intentionally open break-glass.

Thesis: A self-hosted e-sign / signing host should not advertise SSH until someone names the CIDRs. Break-glass is console browser SSH, not a standing open port.

What we shipped first

Early images opened 22 so operators could patch and debug. That felt convenient. It also meant every scan saw a login surface on a box that holds signing material and evidence workflow secrets.

We wanted a default that matched how often we actually need shell: almost never. Day-to-day work uses the app and APIs. Shell is for break-glass.

The working shape

The SSH allow-list variable defaults to an empty list. Port 22 is absent from the firewall until that list is non-empty. When we need a shell, we use Lightsail or console browser SSH — or temporarily add a CIDR and remove it after. API keys stay in secrets, not in a world-reachable sshd.

variable "signing_host_ssh_allowed_cidrs" {
  type        = list(string)
  description = "CIDRs allowed on port 22. Empty list closes SSH (use console browser SSH)."
  default     = []
}

# Port 22 exists only when the list is non-empty
dynamic "port_info" {
  for_each = length(var.signing_host_ssh_allowed_cidrs) > 0 ? [1] : []
  content {
    protocol  = "tcp"
    from_port = 22
    to_port   = 22
    cidrs     = var.signing_host_ssh_allowed_cidrs
  }
}

Checklist

Related: we put WAF on CloudFront and the Function URL stayed wide open. How we deliver: methodology.

Engineering commentary only — not audit, legal, or certification advice.