Agent skill
ingress-factory-migration
Migrate raw kubernetes_ingress_v1 resources to the centralized ingress_factory module. Use when: (1) a service defines a raw kubernetes_ingress_v1 with hand-rolled Traefik middleware annotations, (2) adding a new service that needs standard ingress with rate limiting, CrowdSec, CSP headers, rybbit analytics, or authentik auth, (3) refactoring existing ingresses for consistency. Covers single-path, multi-path, split UI/API, full_host overrides, custom rate limits, and extra middleware injection.
Install this agent skill to your Project
npx add-skill https://github.com/majiayu000/claude-skill-registry/tree/main/skills/other/other/ingress-factory-migration
SKILL.md
Ingress Factory Migration
Problem
Services define raw kubernetes_ingress_v1 resources with hand-rolled Traefik middleware
chains. This creates inconsistency - middleware chains are copy-pasted per service, making
it easy to miss security middleware (CrowdSec, rate limiting) or analytics (rybbit). The
ingress_factory module at modules/kubernetes/ingress_factory/main.tf provides a single
point of control.
Context / Trigger Conditions
- Service has a raw
kubernetes_ingress_v1resource instead of usingmodule "ingress" - Service has a manually defined
kubernetes_manifestfor rybbit analytics middleware - New service needs standard ingress configuration
- Middleware chain needs to be updated across many services
Solution
Standard single-path ingress
Replace the raw resource with:
module "ingress" {
source = "../ingress_factory"
namespace = kubernetes_namespace.<service>.metadata[0].name
name = "<service-name>" # becomes the ingress name AND default hostname
host = "<subdomain>" # optional: override hostname (if different from name)
service_name = "<k8s-service-name>" # optional: defaults to name
port = 80 # optional: defaults to 80
tls_secret_name = var.tls_secret_name
protected = false # set true for authentik forward auth
}
Multi-path / split UI+API
Use two module calls with different names but same host:
module "ingress" {
source = "../ingress_factory"
namespace = kubernetes_namespace.<service>.metadata[0].name
name = "<service>"
host = "<subdomain>"
service_name = "<ui-service>"
tls_secret_name = var.tls_secret_name
rybbit_site_id = "<id>" # optional: adds rybbit analytics
}
module "ingress-api" {
source = "../ingress_factory"
namespace = kubernetes_namespace.<service>.metadata[0].name
name = "<service>-api"
host = "<subdomain>" # same host as UI
service_name = "<api-service>"
ingress_path = ["/api"]
tls_secret_name = var.tls_secret_name
# No rybbit_site_id - API returns JSON, not HTML
}
Full host override (for root domain like viktorbarzin.me)
module "ingress" {
source = "../ingress_factory"
namespace = kubernetes_namespace.<service>.metadata[0].name
name = "<service>"
service_name = "<k8s-service>"
full_host = "viktorbarzin.me" # bypasses name.root_domain construction
tls_secret_name = var.tls_secret_name
}
Custom rate limiting (e.g., immich)
module "ingress" {
source = "../ingress_factory"
namespace = kubernetes_namespace.<service>.metadata[0].name
name = "<service>"
skip_default_rate_limit = true
extra_middlewares = ["traefik-<custom>-rate-limit@kubernetescrd"]
tls_secret_name = var.tls_secret_name
}
Key variables reference
| Variable | Default | Purpose |
|---|---|---|
name |
required | Ingress resource name + default hostname |
host |
null | Override hostname prefix (name used if null) |
full_host |
null | Override entire hostname (bypasses root_domain) |
service_name |
null | K8s service name (name used if null) |
port |
80 | Backend service port |
ingress_path |
["/"] | URL paths to match |
protected |
false | Adds authentik forward auth middleware |
rybbit_site_id |
null | Adds rybbit analytics script injection |
skip_default_rate_limit |
false | Omits default rate limiter |
extra_middlewares |
[] | Additional middleware references to append |
extra_annotations |
{} | Additional ingress annotations |
allow_local_access_only |
false | Restricts to LAN/VPN |
exclude_crowdsec |
false | Skips CrowdSec middleware |
custom_content_security_policy |
null | Custom CSP header |
After migration, delete:
- The raw
kubernetes_ingress_v1resource - Any manually defined
kubernetes_manifest "rybbit_analytics"(the factory creates this automatically whenrybbit_site_idis set)
Gotchas
Duplicate module names
If the service directory has multiple .tf files (e.g., main.tf and frame.tf), check
for existing module "ingress" blocks. Module names must be unique within a directory.
Use a descriptive name like module "ingress-immich" instead.
Terraform target module names with hyphens
Module names in terraform state list may use hyphens (e.g., module.real-estate-crawler).
When using -target, you must match the exact name including hyphens:
# Wrong - underscores:
terraform apply -target=module.kubernetes_cluster.module.real_estate_crawler
# Correct - hyphens (quote to prevent shell interpretation):
terraform apply '-target=module.kubernetes_cluster.module.real-estate-crawler'
Service name defaults
The factory defaults service_name to name. If the K8s service has a different name
than the ingress, you must explicitly set service_name. Common case: headscale has one
K8s service named headscale with multiple ports, so the UI ingress needs
service_name = "headscale" even though name = "headscale-ui".
Servarr subdirectory source path
Services under servarr/ need ../../ingress_factory as the source path instead of
../ingress_factory.
Verification
terraform validate- check for syntax errorsterraform plan -target=module.kubernetes_cluster.module.<service>- verify old ingress destroyed, new createdkubectl get ingress -n <namespace>- verify ingress exists with correct host/paths- Browse the service URL to confirm accessibility
Notes
- Services using special protocols (gRPC, mTLS, WebSocket with custom headers) should NOT
be migrated - keep raw
kubernetes_ingress_v1for those - The factory automatically includes: rate-limit, CSP headers, CrowdSec, and entrypoint=websecure
- When
rybbit_site_idis set, the factory creates akubernetes_manifestfor the rewrite-body middleware that injects the analytics script into HTML responses
Recommended Agent Skills
Expand your agent's capabilities with these related and highly-rated skills.
agent-ops-spec
Manage specification documents in .agent/specs/. Use when user provides requirements, acceptance criteria, or feature descriptions that need to be tracked and validated against implementation.
agent-ops-state
Maintain .agent state files. Use at session start, after meaningful steps, and before concluding: read/update constitution/memory/focus/issues/baseline consistently.
agent-ops-spec
Manage specification documents in .agent/specs/. Use when user provides requirements, acceptance criteria, or feature descriptions that need to be tracked and validated against implementation.
agent-ops-testing
Test strategy, execution, and coverage analysis. Use when designing tests, running test suites, or analyzing test results beyond baseline checks.
agent-ops-testing
Test strategy, execution, and coverage analysis. Use when designing tests, running test suites, or analyzing test results beyond baseline checks.
agent-ops-state
Maintain .agent state files. Use at session start, after meaningful steps, and before concluding: read/update constitution/memory/focus/issues/baseline consistently.
Didn't find tool you were looking for?