In early 2026 I decided to do a better job documenting my work. The infrastructure decisions, the security observations, the things I was noticing about how AI was changing how technical work gets done. The problem was scope. I have a fiduciary duty to protect the systems I manage professionally. Writing publicly about those systems, their architecture, and their failure modes is not compatible with that duty. So I built my own.
That decision forced a second one: if I was going to run infrastructure for this purpose, I was going to run it correctly. Cloud Run behind Identity-Aware Proxy. Cloudflare at the edge. Infrastructure as code. GitHub Actions with Workload Identity Federation. Secrets in Secret Manager. The same stack I advocate professionally, running on systems I own, for work I can document honestly.
The current system is documented in About this site.
This series is the output of that decision.
What atrophies when you stop being hands-on
There is a specific thing that degrades when you move into senior leadership and stop doing the technical work directly. It is not knowledge exactly. You still know what IAP is, what Terraform does, what WIF solves. What degrades is the ability to give technically credible guidance on how these things behave in practice.
The manpage describes the system. What it does not describe is the 302 redirect behavior when you put a Cloud Run health check behind IAP. It does not describe the token exchange failures that surface in WIF when your GitHub Actions workflow has subtly wrong permission scoping. You only know those things if you have hit them. And you only hit them if you are still doing the work.
At a certain level, your job is to set direction and standards on deeply technical topics. That job requires more than familiarity. It requires current, practical knowledge of the gap between how something is documented and how it actually behaves. The personal infrastructure is how I keep that gap visible. Not by reading about it. By running into it.
The AI angle
The second reason is more forward-looking. I am actively developing a POV on AI-assisted development and deployment at knowledge-worker scale. How it actually changes the work, what governance it requires, where it breaks down without structure. That POV has to come from practice.
Running AI-assisted development on my own systems, against my own infrastructure, with my own CI/CD pipeline, produces observations that reading analyst reports does not. What I have found is that the workflow produces excellent results when it is disciplined and ungoverned chaos when it is not. The discipline required is not individual, it is organizational. GitHub governance, centrally managed standards that encode into the AI's behavior, engineering review gates. That argument deserves its own piece, and it will get one.
The point here is simpler: I can translate from deep technical to business logic credibly only if the technical end of that bridge is still load-bearing. The personal lab is what keeps it load-bearing.
What it actually costs
Money is not the real cost. Both projects run for roughly $25-40 a month combined. Cloud Run scales to zero. Cloud SQL is the largest line item.
Time is the real cost. Setting up IAP on Cloud Run correctly takes hours the first time. The health check behavior and CORS configuration are underdocumented, and you learn by debugging, not by reading. Getting WIF working in GitHub Actions requires understanding the token exchange model well enough to diagnose failures that surface as cryptic permission errors. These are not quick tasks.
I count this as learning spend, not overhead. The hours I spent debugging WIF on a personal project saved days when deploying the same pattern at organizational scale, because I already knew where it breaks. The IAP configuration issues I hit on my private app were solved before I ever had to solve them under pressure in a production context.
The feedback loop runs consistently: hit the problem personally at low stakes, understand it fully, transfer the solution to professional work where the stakes are higher and the time pressure is real.
The technical details below describe the stack, the controls, and the specific patterns that make this work.
The Stack: What Runs and Why
Two projects, different purposes, shared operational patterns.
Table 1. Project comparison.
| Attribute | Private App (IAP-only) | Public Site + Honeypot |
|---|---|---|
| Purpose | Private personal application behind IAP | Personal site + honeypot/deception platform |
| Frontend | React, Vite, TypeScript, shadcn/ui, Tailwind | Static site with embedded trap endpoints |
| Backend | Express (Node.js) | Cloud Run service (Go + Node.js) |
| Compute | Cloud Run | Cloud Run |
| Data | Cloud SQL (PostgreSQL) | BigQuery + Pub/Sub |
| Auth / Access | IAP (no public endpoints) | IAP for admin; public ingress for honeypot paths |
| Deception | None | Galah LLM honeypot [^1], canary tokens, trap paths |
| Alerting | Metric-freshness and error alerts, added later in 2026 | SMS alerts, daily email digests |
| IaC | gcloud + Cloud Run service YAML | Terraform (three layers: platform/services/site) |
| CI/CD | GitHub Actions + WIF | GitHub Actions + WIF |
| Secrets | Secret Manager | Secret Manager |
| Artifact Registry | Yes | Yes |
| Edge / DNS | Cloudflare (WAF, DDoS, DNS) | Cloudflare (WAF, DDoS, DNS) |
The honeypot was my first personal Terraform project. It uses three Terraform state layers (platform, services, site) with isolated state files. The private app takes a simpler approach: a Cloud Run service YAML deployed through GitHub Actions, no Terraform. That state isolation pattern on the honeypot came directly from reading about blast radius problems at organizational scale and deciding to practice it at personal scale, where the stakes are low enough to learn on.
Both projects sit behind Cloudflare. DNS, WAF rules, and DDoS protection at the edge, with GCP Cloud Run as the origin. For the honeypot, the Cloudflare configuration lives in the same Terraform repo as the GCP resources. Cloudflare also provides visibility into scanner traffic before it reaches the application layer.
What Production-Grade Means at Personal Scale
Production-grade does not mean enterprise-scale; it means applying the controls that matter regardless of scale. Table 2 lists the specific controls running on both projects.
Table 2. Production-grade controls applied to personal projects.
| Control | Implementation | Why It Matters at Any Scale |
|---|---|---|
| IAP on every service | Cloud Run services behind Identity-Aware Proxy; no public endpoints (except honeypot ingress) | Zero-trust access is a habit, not a headcount threshold |
| Infrastructure as code | Terraform for the honeypot; gcloud + service YAML for the private app | Reproducibility. If I lose the project, I can rebuild it from code |
| CI/CD for all deployments | GitHub Actions triggered on push to default branch | No manual deploys means no deployment drift |
| Workload Identity Federation | GitHub Actions authenticates via OIDC; no static service account keys | Eliminates the credential that leaks most often |
| Secret Manager for all credentials | API keys, database passwords, alerting tokens, all in Secret Manager | No credentials in code, environment variables, or container images |
| Structured logging | Honeypot logs to BigQuery via Cloud Logging sinks | Queryable audit trail, not console.log |
| Budget alerts and scaling limits | GCP budget alerts on both projects; Cloud Run concurrency caps | Cost control. A denial-of-wallet attack on the honeypot is a real risk |
| Cloudflare edge protection | WAF, DDoS mitigation, managed DNS on both projects | Defense in depth. GCP handles compute; Cloudflare handles the edge |
| Automated security testing | DAST regression testing against both projects | Catches regressions before they reach production |
None of these controls require a team. They require discipline and the willingness to invest setup time that a personal project does not demand. Simpler stacks exist, and at personal scale they would be defensible. Simplicity was not the only optimization target here: the operational learning was.
Shared Patterns
Both projects converge on five patterns that also define the stack I advocate professionally.
Identity-Aware Proxy (IAP). Every Cloud Run service that is not intentionally public sits behind IAP. The honeypot ingress is the single exception: it must be publicly reachable to attract scanner traffic. The private app has no public endpoints at all. IAP handles authentication at the infrastructure layer, not the application layer. The application never sees unauthenticated traffic.
Terraform with state isolation. The honeypot site uses three Terraform state layers (platform/services/site) with state stored in GCS buckets with versioning enabled. The private app does not use Terraform: it deploys via gcloud and a Cloud Run service YAML, which keeps the deployment simple but trades away the reproducibility that Terraform provides. The state isolation on the honeypot came from learning that a monolithic state file creates blast radius problems when any terraform apply touches shared resources. That lesson transferred directly to the project factory pattern I later built at work.
Workload Identity Federation (WIF). Neither project uses a static service account key in its deploy path, and no long-lived credential is involved in CI. The one exception, a key another system uses to read BigQuery, is covered in Layered Terraform on GCP. The GitHub Actions workflow holds an id-token: write permission, exchanges a short-lived OIDC token for short-lived GCP credentials through WIF, and that is the entire credential surface. I enforce this same pattern for CI/CD pipelines at the organization I work for. I enforce it with more confidence because I have run it on my own projects for months.
Cloudflare as the edge layer. Both projects route through Cloudflare for DNS, WAF, and DDoS protection. Cloudflare sits in front of GCP Cloud Run origins. The Cloudflare configuration lives in the same Terraform repos as the GCP infrastructure, managed through the Cloudflare Terraform provider. For the honeypot, this creates a useful dual-layer view: Cloudflare logs show what arrives at the edge, BigQuery shows what reaches the application. The gap between those two tells you what Cloudflare filtered.
Secret Manager. API keys (OpenAI for Galah, SMS alerting tokens), database credentials, and integration tokens all live in Secret Manager. Cloud Run services reference secrets at deploy time. No secret appears in a Terraform variable file, an environment variable baked into a container image, or a GitHub Actions log.
Where Personal Scale Differs from Organizational Scale
Not everything translates. Table 3 lists the gaps between personal and organizational infrastructure and why those gaps matter.
Table 3. Where personal-scale infrastructure diverges from organizational-scale.
| Dimension | Personal Scale | Organizational Scale | Why the Gap Matters |
|---|---|---|---|
| Documentation | For future-me | For the team | I skip writing runbooks. At work, that would be negligent |
| Compliance audit trail | Self-imposed discipline only | External auditors, SOC 2, PCI | No one checks my work. The discipline is internal |
| SLA obligation | Availability is nice, not contractual | Uptime commitments with financial penalties | I tolerate downtime I would never accept professionally |
| Multi-tenancy | Single-tenant by definition | Teams, customers, data isolation | I never encounter the hardest IAM problems |
| Incident response | Alerts fire; response is whenever I am next at a keyboard | On-call rotation, runbooks, war rooms | Detection is automated now. Response still has no SLA |
| Change management | Push to main, it deploys |
PR reviews, approval gates, change advisory boards | I am reviewer and approver. The review is weaker |
The gaps matter because what I skip here, I might underweight at work. Running personal infrastructure does not replace organizational governance. It supplements it. The places where I take shortcuts on personal projects are useful signals for where I might underestimate friction at organizational scale.
The Feedback Loop
Every article in this series originated from a personal infrastructure problem. Running the stack personally means encountering GCP edge cases firsthand, in an environment where the cost of failure is low and the learning is high.
Table 4. Feedback loop: personal infrastructure problems that became articles.
| Topic | Problem Origin | What I Found |
|---|---|---|
| Website Tracking | The honeypot | Understanding what tracking scripts reveal about visitors, and what your own site leaks |
| GCP Sprawl and Golden Path | Both projects | The personal projects were my first brownfield governance exercise. Organizing two GCP projects taught patterns I later applied to an org with a decade of sprawl |
| IAP on Cloud Run | The private app | Discovered the health check 302 redirect issue and IAP CORS behavior on Cloud Run. Problems that do not appear in documentation but appear immediately in practice |
| Pentest Regression | The honeypot | Built automated DAST regression for the honeypot, then applied it to the private app. The patterns generalized |
| Cloud SQL Auth Proxy | The private app | Running Cloud SQL for a private personal app surfaced Auth Proxy configuration and connection-management issues that are well-documented in theory but poorly documented in practice |
The pattern is consistent: personal infrastructure surfaces problems at low cost, and the solutions transfer to professional work at high value. The feedback loop runs in both directions. Professional standards set the bar for personal projects, and personal projects stress-test those standards in practice.
What Comes Next
The remaining articles each pick up a thread from one of these two projects:
- Explore the Site Data - the colophon for the stack underneath /explore.
- A Decade of GCP Sprawl, Part 1: The Inventory - what the opposite of personal infrastructure discipline looks like at organization scale.
- What's Running at jon.rehagen.net/explore - the legend for the data /explore shows.
- Layered Terraform on GCP - the IaC layer.
- IAP on Cloud Run: The Single-User Deployment Model - the auth layer.
- Putting Cloud Run Behind Cloudflare Pro - the edge layer.
References
[^1]: Karimi, A. (2024). Galah: An LLM-powered web honeypot. GitHub. https://github.com/0x4D31/galah
[^2]: Google Cloud. Workload Identity Federation. IAM Documentation. https://cloud.google.com/iam/docs/workload-identity-federation
[^3]: Google Cloud. Secret Manager - Best practices. Google Cloud Documentation. https://cloud.google.com/secret-manager/docs/best-practices
[^4]: Cloudflare. Terraform Cloudflare Provider. Cloudflare Documentation. https://developers.cloudflare.com/terraform/