Claude-code-plugins flyio-security-basics
install
source · Clone the upstream repo
git clone https://github.com/jeremylongshore/claude-code-plugins-plus-skills
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/jeremylongshore/claude-code-plugins-plus-skills "$T" && mkdir -p ~/.claude/skills && cp -r "$T/plugins/saas-packs/flyio-pack/skills/flyio-security-basics" ~/.claude/skills/jeremylongshore-claude-code-plugins-flyio-security-basics && rm -rf "$T"
manifest:
plugins/saas-packs/flyio-pack/skills/flyio-security-basics/SKILL.mdsource content
Fly.io Security Basics
Overview
Fly.io deploys applications to edge locations worldwide using Firecracker microVMs. Security concerns center on deploy token scoping (org-wide vs per-app), secrets management (encrypted at rest, injected as env vars), private networking via WireGuard mesh (6PN), and TLS certificate management. A leaked deploy token can push arbitrary code to production machines across all regions.
API Key Management
function validateFlyToken(): void { const token = process.env.FLY_API_TOKEN; if (!token) { throw new Error("Missing FLY_API_TOKEN — use `fly tokens create deploy -a <app>`"); } // Never log tokens; log only token type for debugging const isDeployToken = token.startsWith("FlyV1"); console.log("Fly.io token loaded, type:", isDeployToken ? "deploy" : "personal"); }
Webhook Signature Verification
import crypto from "crypto"; import { Request, Response, NextFunction } from "express"; function verifyFlyWebhook(req: Request, res: Response, next: NextFunction): void { const signature = req.headers["x-fly-signature"] as string; const secret = process.env.FLY_WEBHOOK_SECRET!; const expected = crypto.createHmac("sha256", secret).update(req.body).digest("hex"); if (!signature || !crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expected))) { res.status(401).send("Invalid signature"); return; } next(); }
Input Validation
import { z } from "zod"; const FlyDeploySchema = z.object({ app_name: z.string().regex(/^[a-z0-9-]+$/).max(63), region: z.enum(["iad", "ord", "lax", "sjc", "ams", "lhr", "nrt", "syd", "gru"]), image: z.string().regex(/^registry\..+\/.+:.+$/), vm_size: z.enum(["shared-cpu-1x", "shared-cpu-2x", "performance-1x", "performance-2x"]).optional(), min_machines: z.number().int().min(0).max(20).optional(), }); function validateDeployConfig(data: unknown) { return FlyDeploySchema.parse(data); }
Data Protection
const FLY_SENSITIVE_FIELDS = ["fly_api_token", "deploy_token", "db_password", "wireguard_private_key", "tls_private_key"]; function redactFlyLog(record: Record<string, unknown>): Record<string, unknown> { const redacted = { ...record }; for (const field of FLY_SENSITIVE_FIELDS) { if (field in redacted) redacted[field] = "[REDACTED]"; } return redacted; }
Security Checklist
- All sensitive values in
, never infly secrets
section of fly.toml[env] - Deploy tokens scoped per-app, not org-wide
-
set in fly.tomlforce_https = true[http_service] - Internal services use
DNS with no public ports.internal - WireGuard keys rotated and unused tunnels removed
- Secrets rotated on schedule (triggers rolling restart)
- CI/CD uses deploy-scoped tokens, not personal tokens
- Container images scanned before deployment
Error Handling
| Vulnerability | Risk | Mitigation |
|---|---|---|
| Leaked deploy token | Arbitrary code deployed to production | Per-app scoped tokens + rotation |
Secrets in fly.toml | Plaintext credentials in version control | Use exclusively |
| Open internal ports | Services exposed to public internet | DNS + NetworkPolicy |
| Org-wide token in CI | All apps in org compromised via CI breach | Deploy-scoped tokens per pipeline |
| Expired TLS certificates | MITM attacks on custom domains | Automated Let's Encrypt renewal |
Resources
Next Steps
See
flyio-prod-checklist.