Frontend Labs
⋯

Part 12 — Projects

Four end-to-end projects that combine everything. Each has a brief, a deliverable, a "definition of done", and a grading rubric so you can judge your own work. Do them in order — each builds on the last, and all four target SecureShop (Chapter 4). Budget a weekend each, or a week at a relaxed pace.

Set up once:

   ~/sec-lab/
     ca/          your PKI (Ch 29)
     keys/        key material (Ch 22)
     tools/       release-sign (Ch 22/26), tls-audit (Ch 32), monitors
     reports/     one markdown report per Part -- you have 7 already
     projects/
       p1-ca-mtls/  p2-harden/  p3-breakfix/  p4-pq-audit/

Everything runs locally in containers or VMs you own (Chapter 0.6).


Chapter 53 — Project 1: your own CA, plus mutual TLS

Brief

Build the certificate authority that issues every certificate SecureShop uses — public-facing server certs, internal service certs, and client certs for mTLS — with a proper offline root, an online issuing intermediate, sane profiles, a revocation mechanism, and automated renewal. Then wire three services to use it and prove the trust decisions are correct.

Architecture

                 SecureShop Dev Root CA         (offline: key encrypted,
                   ed25519, 10-year, CA:TRUE      never on a networked box)
                          | signs ONE thing: the intermediate
                          v
                 SecureShop Issuing CA           (online: does day-to-day
                   ecdsa P-256, 3-year,           issuance; pathlen:0)
                   CA:TRUE, pathlen:0
                   /              |             \
   server profile     client profile        internal-service profile
   EKU serverAuth     EKU clientAuth         EKU serverAuth+clientAuth
   90-day, SANs       30-day, CN=identity    7-day, SPIFFE-style URI SAN
        |                    |                        |
   shop.securesh.op     orders-api-client        orders-api  <-> postgres
   www.securesh.op      admin-console            (both present + verify certs)

Tasks

   1. ROOT
      - ed25519 key, encrypted at rest (openssl pkey -aes-256-cbc).
      - Self-signed cert, basicConstraints critical CA:TRUE,
        keyUsage critical keyCertSign,cRLSign. 10 years.
      - Store the passphrase in your secrets manager (Ch 49), not a file.

   2. INTERMEDIATE
      - ECDSA P-256 key. CSR -> signed by root with pathlen:0.
      - This is the only key the issuing scripts touch.

   3. PROFILES (an openssl.cnf or a small `issue` script per type)
      - server:   SAN(s) required; EKU serverAuth; 90d; CA:FALSE.
      - client:   CN = a stable identity; EKU clientAuth; 30d.
      - service:  URI SAN spiffe://securesh.op/ns/default/sa/<name>;
                  EKU serverAuth,clientAuth; 7d.
      - Reject requests that don't match the profile (e.g. server cert
        with no SAN -> refuse).

   4. REVOCATION
      - Maintain a CRL (openssl ca -gencrl) OR run a tiny OCSP responder
        (openssl ocsp -index ...). Revoke a test cert; prove clients
        reject it.

   5. WIRE IT UP
      - nginx/Caddy for shop.securesh.op with the server cert; HTTP->HTTPS
        redirect; TLS 1.3+1.2, AEAD only; HSTS.
      - /admin location: require a client cert (verify against the
        intermediate); no cert -> 403.
      - orders-api <-> postgres: mutual TLS, each verifies the other's
        service cert against your CA (Postgres: ssl=on, clientcert=verify-full).

   6. RENEWAL
      - A cron/systemd-timer script that reissues any cert < 1/3 of its
        lifetime remaining, reloads the service, and alerts on failure.
      - Bonus: stand up `step-ca` or Vault PKI and drive it via ACME so
        renewal is fully hands-off.

   7. VERIFY (write results into the report)
      - openssl verify -show_chain for each leaf.
      - curl --cacert (works), curl (fails, cert error), curl -k (works
        but note the danger).
      - testssl.sh / sslyze against shop.securesh.op -> A-equivalent.
      - mTLS: connection with/without a valid client cert.
      - Revoke -> client rejects. Expire (issue with -days 1, wait) ->
        client rejects.
      - Break the chain (omit intermediate) -> curl fails; explain why a
        browser might not.

Deliverable

~/sec-lab/projects/p1-ca-mtls/ containing: the CA scripts/config, the service configs, the renewal script, and report.md with every verification above (command + output + one-line explanation), plus a diagram of your PKI and the trust decisions.

Definition of done

  • Root is offline and its key is encrypted; you can state exactly where the passphrase lives.
  • Every leaf verifies to the root through the intermediate.
  • Each profile enforces its constraints (a wrong-shaped request is refused).
  • shop.securesh.op scores A-equivalent on testssl.sh/sslyze.
  • /admin is reachable only with a valid client cert.
  • orders-api↔Postgres is mutually authenticated.
  • Revocation works (CRL or OCSP), demonstrated.
  • Renewal is automated and alerts on failure.

Rubric (score yourself /100)

   PKI structure & key protection ........... 20
   Correct, enforced cert profiles ......... 15
   Server TLS hardening (A-grade) .......... 15
   mTLS on /admin and service-to-service ... 20
   Revocation implemented & proven ......... 10
   Automated renewal + alerting ........... 10
   Report quality (evidence + reasoning) .. 10

Further reading

  • Book (free): OpenSSL Cookbook, Ivan Ristić — the CA and CSR chapters.
  • Docs: smallstep step-ca "Run your own private CA" tutorial; HashiCorp Vault PKI secrets engine; mkcert (for the "just works locally" contrast).
  • Article: "Everything you should know about certificates and PKI" — Mike Malone (smallstep).
  • Spec: SPIFFE/SPIRE docs — the URI-SAN service-identity model.
  • Guidance: CA/Browser Forum Baseline Requirements (skim the profile sections to see what "real" cert profiles constrain).

Generated from real-life-guide.md · 8 Oct 2026 16:36