Tailscale Connector — subnet router for k8s service CIDR #175

Closed
opened 2026-03-26 17:14:53 +00:00 by forgejo_admin · 3 comments

Type

Infra

Lineage

project-pal-e-platform → Board item. Blocker for #174 (Mac build agent).

Repo

forgejo_admin/pal-e-platform

User Story

As an external tailnet peer (Mac build agent)
I want to reach k8s ClusterIP services directly over Tailscale
So that the Woodpecker agent can connect to gRPC port 9000 without funnels or hacks

Context

External agents can't reach k8s services (10.43.0.0/16) because those IPs are cluster-internal. Tailscale funnels don't work for gRPC (HTTP/1.1 proxy breaks HTTP/2). The Tailscale operator provides a Connector CRD with subnetRouter that advertises CIDRs to the tailnet. This creates a subnet router pod that bridges the k8s service network to the Tailscale mesh.

After this, any tailnet peer can reach any ClusterIP service. The Mac agent connects to 10.43.50.207:9000 (Woodpecker server) or any other service.

File Targets

Files to modify:

  • terraform/main.tf — add kubernetes_manifest for Tailscale Connector CRD

Files to verify:

  • terraform/main.tf — existing tailscale_acl may need a grant for subnet route approval (check if tag:k8s auto-approves)

Files NOT to touch:

  • Existing funnel ingresses (they serve public web access, unchanged)
  • Woodpecker Helm chart
  • Salt states (Mac config is #174's scope)

Acceptance Criteria

  • tofu plan shows 1 new resource (Connector)
  • tofu apply creates the subnet router pod
  • tailscale status shows the subnet router advertising 10.43.0.0/16
  • From Mac: ping 10.43.50.207 succeeds (Woodpecker server ClusterIP)
  • From Mac: Woodpecker agent connects to 10.43.50.207:9000 successfully
  • Existing funnels and services unaffected

Test Expectations

  • tofu validate passes
  • kubectl get connector shows the resource
  • Mac agent logs show successful gRPC connection (no 502, no timeout, no connection refused)

Constraints

  • Use kubernetes_manifest resource in Terraform (not kubectl apply)
  • Only advertise 10.43.0.0/16 (service CIDR), NOT 10.42.0.0/16 (pod CIDR) — services are stable, pod IPs aren't
  • ACL must allow the subnet route (check autoApprovers or manual approval)
  • tofu plan -lock=false per SOP

Checklist

  • PR opened
  • tofu plan output included
  • Tests pass
  • No unrelated changes
### Type Infra ### Lineage `project-pal-e-platform` → Board item. Blocker for #174 (Mac build agent). ### Repo `forgejo_admin/pal-e-platform` ### User Story As an external tailnet peer (Mac build agent) I want to reach k8s ClusterIP services directly over Tailscale So that the Woodpecker agent can connect to gRPC port 9000 without funnels or hacks ### Context External agents can't reach k8s services (10.43.0.0/16) because those IPs are cluster-internal. Tailscale funnels don't work for gRPC (HTTP/1.1 proxy breaks HTTP/2). The Tailscale operator provides a `Connector` CRD with `subnetRouter` that advertises CIDRs to the tailnet. This creates a subnet router pod that bridges the k8s service network to the Tailscale mesh. After this, any tailnet peer can reach any ClusterIP service. The Mac agent connects to `10.43.50.207:9000` (Woodpecker server) or any other service. ### File Targets Files to modify: - `terraform/main.tf` — add `kubernetes_manifest` for Tailscale Connector CRD Files to verify: - `terraform/main.tf` — existing `tailscale_acl` may need a grant for subnet route approval (check if `tag:k8s` auto-approves) Files NOT to touch: - Existing funnel ingresses (they serve public web access, unchanged) - Woodpecker Helm chart - Salt states (Mac config is #174's scope) ### Acceptance Criteria - [ ] `tofu plan` shows 1 new resource (Connector) - [ ] `tofu apply` creates the subnet router pod - [ ] `tailscale status` shows the subnet router advertising `10.43.0.0/16` - [ ] From Mac: `ping 10.43.50.207` succeeds (Woodpecker server ClusterIP) - [ ] From Mac: Woodpecker agent connects to `10.43.50.207:9000` successfully - [ ] Existing funnels and services unaffected ### Test Expectations - [ ] `tofu validate` passes - [ ] `kubectl get connector` shows the resource - [ ] Mac agent logs show successful gRPC connection (no 502, no timeout, no connection refused) ### Constraints - Use `kubernetes_manifest` resource in Terraform (not kubectl apply) - Only advertise `10.43.0.0/16` (service CIDR), NOT `10.42.0.0/16` (pod CIDR) — services are stable, pod IPs aren't - ACL must allow the subnet route (check `autoApprovers` or manual approval) - `tofu plan -lock=false` per SOP ### Checklist - [ ] PR opened - [ ] `tofu plan` output included - [ ] Tests pass - [ ] No unrelated changes ### Related - pal-e-platform #174 — Mac build agent (blocked by this) - `project-capacitor-mobile` — consumer of the Mac build agent - Tailscale docs: https://tailscale.com/kb/1019/subnets/
Author
Owner

Ticket #175 Scope Review

TEMPLATE COMPLIANCE (template-issue)

All required sections present and well-structured:

Section Present Quality
Lineage Yes Correct -- board item with blocker reference to #174
Repo Yes forgejo_admin/pal-e-platform
User Story Yes Proper As a/I want/So that format
Context Yes Clear motivation with technical rationale
File Targets Yes Modify + verify + NOT-to-touch boundaries
Acceptance Criteria Yes 6 testable items
Test Expectations Yes 3 items
Constraints Yes 4 items, includes tofu plan -lock=false per SOP
Checklist Yes Standard 4 items
Related Yes References #174 blocker and Tailscale docs

TRACEABILITY TRIANGLE

  • story:superuser-deploy -- CONFIRMED. Documented in project-pal-e-platform user stories table: "I can deploy infrastructure changes via tofu plan/apply and see them succeed in Woodpecker CI without manual intervention."
  • arch:tailscale-funnel -- CONFIRMED. Documented in convention-architecture-ids under Deployment Components: "Ingress + TLS." However, see note below about whether a new arch ID is needed.
  • type:infra -- Appropriate for this work.

TECHNICAL REVIEW

1. Connector CRD spec is correct but underspecified in File Targets

The Tailscale Connector CRD is apiVersion: tailscale.com/v1alpha1, kind: Connector. The required field is spec.subnetRouter.advertiseRoutes (array of CIDRs, minimum 1). The issue correctly identifies 10.43.0.0/16 as the target CIDR and correctly excludes 10.42.0.0/16 (pod CIDR). Using kubernetes_manifest is the right Terraform resource for CRDs.

Optional fields the agent should know about:

  • spec.tags -- defaults to [tag:k8s] from the operator config, which matches the existing setup
  • spec.hostname or spec.hostnamePrefix -- one should be specified for a readable tailnet device name (e.g., hostnamePrefix: "k8s-subnet-router")
  • spec.replicas -- defaults to nil (single replica), fine for this use case

Recommendation: Add a note in File Targets or Constraints that the agent should set hostnamePrefix for clarity in tailscale status output.

2. ACL autoApprovers is a REQUIRED change, not just a "verify" step

The issue says to verify whether tag:k8s auto-approves subnet routes. It does NOT -- the current ACL (main.tf lines 39-98) has no autoApprovers block. Without it, the subnet route will require manual approval in the Tailscale admin console every time tofu apply runs.

The fix is to add to the tailscale_acl resource:

"autoApprovers": {
  "routes": {
    "10.43.0.0/16": ["tag:k8s"]
  }
}

This should be promoted from "Files to verify" to "Files to modify" in the File Targets section, and an acceptance criterion should cover it.

3. Existing gRPC funnel creates a scope question

main.tf lines 825-854 already define a kubernetes_ingress_v1.woodpecker_grpc_funnel resource that creates a Tailscale funnel for Woodpecker gRPC on port 9000. The issue Context says "Tailscale funnels don't work for gRPC (HTTP/1.1 proxy breaks HTTP/2)" -- but this existing funnel is live in the codebase.

Two possibilities:

  • (a) The funnel was deployed but doesn't actually work for gRPC, validating the issue's claim. If so, the issue should note this explicitly and state whether the funnel should be removed (scope) or left in place.
  • (b) The funnel does work, and subnet routing is an alternative approach. If so, the Context section's claim needs correction.

Either way, the relationship between the new Connector and the existing gRPC funnel resource must be addressed. This is not scope creep -- it is essential context for the agent to avoid confusion.

4. NetworkPolicy gap

The existing network-policies.tf allows traffic from the tailscale namespace to service namespaces. The subnet router pod will live in the tailscale namespace, so it should be able to reach ClusterIP services. However, the agent should verify that the subnet router traffic flows through the tailscale namespace (not directly from external) -- if k8s routes the traffic differently, a NetworkPolicy update may be needed. This should be mentioned in Constraints or as a test expectation.

5. Dependency verification

Issue #174 (Mac build agent) is confirmed open and is correctly identified as a downstream consumer. The blocker relationship is correct -- #174 needs subnet routing before the Mac agent can reach the Woodpecker gRPC endpoint.

ITEMS TO FIX

  1. ACL autoApprovers -- Promote from "verify" to explicit file modification target. Add autoApprovers.routes block for 10.43.0.0/16 to the tailscale_acl resource. Add an acceptance criterion: "ACL autoApprovers auto-approves the subnet route (no manual admin console step)."

  2. Existing gRPC funnel -- Address the relationship with kubernetes_ingress_v1.woodpecker_grpc_funnel (main.tf:827). Either: (a) note it doesn't work for gRPC and state whether removal is in-scope or deferred, or (b) correct the Context claim if funnels do work.

  3. hostnamePrefix -- Add to Constraints: agent should set spec.hostnamePrefix (e.g., "k8s-subnet-router") so the device is identifiable in tailscale status.

  4. arch: label fit -- arch:tailscale-funnel maps to "Ingress + TLS" in the architecture IDs convention. A subnet router is not an ingress/funnel -- it is internal network bridging. Consider whether this warrants a new arch ID (e.g., arch:tailscale-subnet) or whether arch:tailscale-funnel is intentionally broad enough to cover all Tailscale networking. Minor, but worth a conscious decision.

VERDICT: NEEDS WORK

The ticket is well-written and close to ready. Four items need addressing before an agent can execute cleanly:

  1. ACL autoApprovers must be an explicit modification target, not a "verify" footnote
  2. Existing gRPC funnel relationship must be clarified (works or doesn't, remove or keep)
  3. hostnamePrefix constraint for tailnet device naming
  4. Arch label fitness check (minor -- conscious decision either way is fine)
## Ticket #175 Scope Review ### TEMPLATE COMPLIANCE (template-issue) All required sections present and well-structured: | Section | Present | Quality | |---------|---------|---------| | Lineage | Yes | Correct -- board item with blocker reference to #174 | | Repo | Yes | `forgejo_admin/pal-e-platform` | | User Story | Yes | Proper As a/I want/So that format | | Context | Yes | Clear motivation with technical rationale | | File Targets | Yes | Modify + verify + NOT-to-touch boundaries | | Acceptance Criteria | Yes | 6 testable items | | Test Expectations | Yes | 3 items | | Constraints | Yes | 4 items, includes `tofu plan -lock=false` per SOP | | Checklist | Yes | Standard 4 items | | Related | Yes | References #174 blocker and Tailscale docs | ### TRACEABILITY TRIANGLE - **story:superuser-deploy** -- CONFIRMED. Documented in `project-pal-e-platform` user stories table: "I can deploy infrastructure changes via `tofu plan/apply` and see them succeed in Woodpecker CI without manual intervention." - **arch:tailscale-funnel** -- CONFIRMED. Documented in `convention-architecture-ids` under Deployment Components: "Ingress + TLS." However, see note below about whether a new arch ID is needed. - **type:infra** -- Appropriate for this work. ### TECHNICAL REVIEW **1. Connector CRD spec is correct but underspecified in File Targets** The Tailscale Connector CRD is `apiVersion: tailscale.com/v1alpha1`, `kind: Connector`. The required field is `spec.subnetRouter.advertiseRoutes` (array of CIDRs, minimum 1). The issue correctly identifies `10.43.0.0/16` as the target CIDR and correctly excludes `10.42.0.0/16` (pod CIDR). Using `kubernetes_manifest` is the right Terraform resource for CRDs. Optional fields the agent should know about: - `spec.tags` -- defaults to `[tag:k8s]` from the operator config, which matches the existing setup - `spec.hostname` or `spec.hostnamePrefix` -- one should be specified for a readable tailnet device name (e.g., `hostnamePrefix: "k8s-subnet-router"`) - `spec.replicas` -- defaults to nil (single replica), fine for this use case **Recommendation:** Add a note in File Targets or Constraints that the agent should set `hostnamePrefix` for clarity in `tailscale status` output. **2. ACL autoApprovers is a REQUIRED change, not just a "verify" step** The issue says to verify whether `tag:k8s` auto-approves subnet routes. It does NOT -- the current ACL (main.tf lines 39-98) has no `autoApprovers` block. Without it, the subnet route will require manual approval in the Tailscale admin console every time `tofu apply` runs. The fix is to add to the `tailscale_acl` resource: ```json "autoApprovers": { "routes": { "10.43.0.0/16": ["tag:k8s"] } } ``` This should be promoted from "Files to verify" to "Files to modify" in the File Targets section, and an acceptance criterion should cover it. **3. Existing gRPC funnel creates a scope question** `main.tf` lines 825-854 already define a `kubernetes_ingress_v1.woodpecker_grpc_funnel` resource that creates a Tailscale funnel for Woodpecker gRPC on port 9000. The issue Context says "Tailscale funnels don't work for gRPC (HTTP/1.1 proxy breaks HTTP/2)" -- but this existing funnel is live in the codebase. Two possibilities: - (a) The funnel was deployed but doesn't actually work for gRPC, validating the issue's claim. If so, the issue should note this explicitly and state whether the funnel should be removed (scope) or left in place. - (b) The funnel does work, and subnet routing is an alternative approach. If so, the Context section's claim needs correction. Either way, the relationship between the new Connector and the existing gRPC funnel resource must be addressed. This is not scope creep -- it is essential context for the agent to avoid confusion. **4. NetworkPolicy gap** The existing `network-policies.tf` allows traffic from the `tailscale` namespace to service namespaces. The subnet router pod will live in the `tailscale` namespace, so it should be able to reach ClusterIP services. However, the agent should verify that the subnet router traffic flows through the tailscale namespace (not directly from external) -- if k8s routes the traffic differently, a NetworkPolicy update may be needed. This should be mentioned in Constraints or as a test expectation. **5. Dependency verification** Issue #174 (Mac build agent) is confirmed open and is correctly identified as a downstream consumer. The blocker relationship is correct -- #174 needs subnet routing before the Mac agent can reach the Woodpecker gRPC endpoint. ### ITEMS TO FIX 1. **ACL autoApprovers** -- Promote from "verify" to explicit file modification target. Add `autoApprovers.routes` block for `10.43.0.0/16` to the `tailscale_acl` resource. Add an acceptance criterion: "ACL autoApprovers auto-approves the subnet route (no manual admin console step)." 2. **Existing gRPC funnel** -- Address the relationship with `kubernetes_ingress_v1.woodpecker_grpc_funnel` (main.tf:827). Either: (a) note it doesn't work for gRPC and state whether removal is in-scope or deferred, or (b) correct the Context claim if funnels do work. 3. **hostnamePrefix** -- Add to Constraints: agent should set `spec.hostnamePrefix` (e.g., `"k8s-subnet-router"`) so the device is identifiable in `tailscale status`. 4. **arch: label fit** -- `arch:tailscale-funnel` maps to "Ingress + TLS" in the architecture IDs convention. A subnet router is not an ingress/funnel -- it is internal network bridging. Consider whether this warrants a new arch ID (e.g., `arch:tailscale-subnet`) or whether `arch:tailscale-funnel` is intentionally broad enough to cover all Tailscale networking. Minor, but worth a conscious decision. ### VERDICT: NEEDS WORK The ticket is well-written and close to ready. Four items need addressing before an agent can execute cleanly: 1. ACL `autoApprovers` must be an explicit modification target, not a "verify" footnote 2. Existing gRPC funnel relationship must be clarified (works or doesn't, remove or keep) 3. `hostnamePrefix` constraint for tailnet device naming 4. Arch label fitness check (minor -- conscious decision either way is fine)
Author
Owner

Ticket Fix (QA review remediation)

1. ACL autoApprovers (promoted to File Targets)

terraform/main.tf line ~40 (tailscale_acl.this) needs an autoApprovers block added:

"autoApprovers": {
  "routes": {
    "10.43.0.0/16": ["tag:k8s"]
  }
}

This auto-approves subnet routes advertised by tag:k8s nodes (which the Connector gets via the operator's defaultTags). Without this, every tofu apply would require manual admin console approval.

Moved from "Files to verify" to "Files to modify."

2. gRPC funnel contradiction (clarified)

The woodpecker_grpc_funnel resource (PR #173, merged today) IS non-functional for gRPC — Tailscale funnels proxy as HTTP/1.1 which breaks gRPC's HTTP/2 framing. Confirmed by proxy logs: "http: proxy error: malformed HTTP response".

Removal of the non-functional funnel is OUT OF SCOPE for this ticket. It should be cleaned up in a follow-up. This ticket adds the working solution (subnet router). The funnel is harmless — it just doesn't serve the purpose we created it for.

3. hostnamePrefix (added to Constraints)

The Connector should specify hostname: "k8s-subnet-router" so tailscale status shows a readable name instead of a generated hash.

4. Arch label (corrected)

Changed from arch:tailscale-funnel to arch:tailscale-subnet. This is a new arch component — subnet routing is distinct from ingress/TLS. Will add arch:tailscale-subnet to the pal-e-platform architecture docs as discovered scope.

## Ticket Fix (QA review remediation) ### 1. ACL autoApprovers (promoted to File Targets) `terraform/main.tf` line ~40 (`tailscale_acl.this`) needs an `autoApprovers` block added: ```json "autoApprovers": { "routes": { "10.43.0.0/16": ["tag:k8s"] } } ``` This auto-approves subnet routes advertised by `tag:k8s` nodes (which the Connector gets via the operator's `defaultTags`). Without this, every `tofu apply` would require manual admin console approval. **Moved from "Files to verify" to "Files to modify."** ### 2. gRPC funnel contradiction (clarified) The `woodpecker_grpc_funnel` resource (PR #173, merged today) IS non-functional for gRPC — Tailscale funnels proxy as HTTP/1.1 which breaks gRPC's HTTP/2 framing. Confirmed by proxy logs: `"http: proxy error: malformed HTTP response"`. **Removal of the non-functional funnel is OUT OF SCOPE for this ticket.** It should be cleaned up in a follow-up. This ticket adds the working solution (subnet router). The funnel is harmless — it just doesn't serve the purpose we created it for. ### 3. hostnamePrefix (added to Constraints) The Connector should specify `hostname: "k8s-subnet-router"` so `tailscale status` shows a readable name instead of a generated hash. ### 4. Arch label (corrected) Changed from `arch:tailscale-funnel` to `arch:tailscale-subnet`. This is a new arch component — subnet routing is distinct from ingress/TLS. Will add `arch:tailscale-subnet` to the pal-e-platform architecture docs as discovered scope.
Author
Owner

Issue #175 Re-Review

Re-review of ticket scope after fix comment (comment #7556) addressed the 4 findings from the initial QA review (comment #7554).

FINDING 1: ACL autoApprovers -- RESOLVED

Original finding: autoApprovers block missing from tailscale_acl.this (main.tf lines 39-98). Promoted from "Files to verify" to "Files to modify."

Fix comment response: Provides the exact JSON snippet to add. Confirms tag:k8s comes from the operator's defaultTags. Notes manual admin console approval would be required without this.

Verification: Confirmed tailscale_acl.this (main.tf:39-98) has zero autoApprovers configuration. The proposed fix is correct -- "routes": { "10.43.0.0/16": ["tag:k8s"] } will auto-approve the subnet route. This is a required change, not optional.

Status: RESOLVED.

FINDING 2: gRPC Funnel Contradiction -- RESOLVED

Original finding: Issue claims "funnels don't work for gRPC" but kubernetes_ingress_v1.woodpecker_grpc_funnel (main.tf:827-854) exists in the codebase (merged in PR #173).

Fix comment response: Confirms the funnel IS non-functional for gRPC -- HTTP/1.1 proxy breaks HTTP/2 framing. Proxy logs show "http: proxy error: malformed HTTP response". Removal deferred as out-of-scope. Funnel is harmless.

Verification: Confirmed the resource exists at main.tf:827-854. The deferral is correct -- removing a non-functional but harmless resource is cleanup, not a prerequisite for the subnet router. A follow-up ticket should be created for the cleanup.

Status: RESOLVED.

FINDING 3: hostnamePrefix -- RESOLVED (with note)

Original finding: Recommended hostnamePrefix: "k8s-subnet-router" for readable tailscale status output.

Fix comment response: Says hostname: "k8s-subnet-router" (not hostnamePrefix).

Verification: Both fields are valid in the Connector CRD. hostname sets an exact name; hostnamePrefix appends a generated suffix (useful for replicas). For a single-replica connector, hostname is simpler and appropriate. The intent (readable device name in tailscale status) is preserved either way.

Status: RESOLVED.

FINDING 4: Arch Label -- RESOLVED

Original finding: arch:tailscale-funnel ("Ingress + TLS") doesn't fit subnet routing. Recommended either a new arch ID or a conscious decision.

Fix comment response: Changed to arch:tailscale-subnet. Will add to convention-architecture-ids as discovered scope.

Verification: Board item #394 confirmed updated to labels: "story:superuser-deploy,arch:tailscale-subnet,type:infra". The convention-architecture-ids note currently lists arch:tailscale-funnel under Deployment Components but does NOT yet include arch:tailscale-subnet. The fix comment correctly flags this as discovered scope -- the convention doc update should happen during /update-docs after this ticket's PR merges.

Status: RESOLVED.

TRACEABILITY VERIFICATION

  • story:superuser-deploy -- Traces to project-pal-e-platform user stories: "I can deploy infrastructure changes via tofu plan/apply and see them succeed in Woodpecker CI without manual intervention." The subnet router enables the Mac build agent to reach the Woodpecker gRPC endpoint, which is a prerequisite for the deploy pipeline to work with external agents. Traceability is correct.
  • arch:tailscale-subnet -- New arch ID, correctly differentiated from arch:tailscale-funnel. Convention doc update pending as discovered scope.
  • type:infra -- Correct for Terraform + Tailscale CRD work.
  • Blocker chain: #175 (this) blocks #174 (Mac build agent) blocks Capacitor mobile pipeline. Chain is documented and correct.

PROCESS OBSERVATION

The issue body has NOT been edited to incorporate the fixes (issue created_at and updated_at are identical: 2026-03-26T17:14:53Z). The fixes exist only in comment #7556. When the dev agent executes this ticket, it must read both the issue body AND the comments to get the complete spec. This is fine -- agents do read comments -- but for maximum clarity, consider editing the issue body to incorporate the 4 changes so the agent has a single coherent spec to execute against. This is a nit, not a blocker.

SOP COMPLIANCE

  • Issue follows template-issue format (all required sections present)
  • Lineage references project (project-pal-e-platform -- board item, not plan-driven)
  • User story in proper As a/I want/So that format
  • File Targets include modify + verify + NOT-to-touch boundaries
  • Acceptance criteria are testable (6 items)
  • Constraints include tofu plan -lock=false per SOP
  • Board item has traceability labels (story:superuser-deploy,arch:tailscale-subnet,type:infra)
  • Related references blocker (#174) and downstream consumer

VERDICT: APPROVED

All 4 findings from the initial review are resolved. The ticket is ready for agent execution. One nit: consider editing the issue body to incorporate the fix comment changes for a single coherent spec.

## Issue #175 Re-Review Re-review of ticket scope after fix comment (comment #7556) addressed the 4 findings from the initial QA review (comment #7554). ### FINDING 1: ACL autoApprovers -- RESOLVED **Original finding:** `autoApprovers` block missing from `tailscale_acl.this` (main.tf lines 39-98). Promoted from "Files to verify" to "Files to modify." **Fix comment response:** Provides the exact JSON snippet to add. Confirms `tag:k8s` comes from the operator's `defaultTags`. Notes manual admin console approval would be required without this. **Verification:** Confirmed `tailscale_acl.this` (main.tf:39-98) has zero `autoApprovers` configuration. The proposed fix is correct -- `"routes": { "10.43.0.0/16": ["tag:k8s"] }` will auto-approve the subnet route. This is a required change, not optional. **Status:** RESOLVED. ### FINDING 2: gRPC Funnel Contradiction -- RESOLVED **Original finding:** Issue claims "funnels don't work for gRPC" but `kubernetes_ingress_v1.woodpecker_grpc_funnel` (main.tf:827-854) exists in the codebase (merged in PR #173). **Fix comment response:** Confirms the funnel IS non-functional for gRPC -- HTTP/1.1 proxy breaks HTTP/2 framing. Proxy logs show `"http: proxy error: malformed HTTP response"`. Removal deferred as out-of-scope. Funnel is harmless. **Verification:** Confirmed the resource exists at main.tf:827-854. The deferral is correct -- removing a non-functional but harmless resource is cleanup, not a prerequisite for the subnet router. A follow-up ticket should be created for the cleanup. **Status:** RESOLVED. ### FINDING 3: hostnamePrefix -- RESOLVED (with note) **Original finding:** Recommended `hostnamePrefix: "k8s-subnet-router"` for readable `tailscale status` output. **Fix comment response:** Says `hostname: "k8s-subnet-router"` (not `hostnamePrefix`). **Verification:** Both fields are valid in the Connector CRD. `hostname` sets an exact name; `hostnamePrefix` appends a generated suffix (useful for replicas). For a single-replica connector, `hostname` is simpler and appropriate. The intent (readable device name in tailscale status) is preserved either way. **Status:** RESOLVED. ### FINDING 4: Arch Label -- RESOLVED **Original finding:** `arch:tailscale-funnel` ("Ingress + TLS") doesn't fit subnet routing. Recommended either a new arch ID or a conscious decision. **Fix comment response:** Changed to `arch:tailscale-subnet`. Will add to `convention-architecture-ids` as discovered scope. **Verification:** Board item #394 confirmed updated to `labels: "story:superuser-deploy,arch:tailscale-subnet,type:infra"`. The `convention-architecture-ids` note currently lists `arch:tailscale-funnel` under Deployment Components but does NOT yet include `arch:tailscale-subnet`. The fix comment correctly flags this as discovered scope -- the convention doc update should happen during `/update-docs` after this ticket's PR merges. **Status:** RESOLVED. ### TRACEABILITY VERIFICATION - **story:superuser-deploy** -- Traces to `project-pal-e-platform` user stories: "I can deploy infrastructure changes via `tofu plan/apply` and see them succeed in Woodpecker CI without manual intervention." The subnet router enables the Mac build agent to reach the Woodpecker gRPC endpoint, which is a prerequisite for the deploy pipeline to work with external agents. Traceability is correct. - **arch:tailscale-subnet** -- New arch ID, correctly differentiated from `arch:tailscale-funnel`. Convention doc update pending as discovered scope. - **type:infra** -- Correct for Terraform + Tailscale CRD work. - **Blocker chain:** #175 (this) blocks #174 (Mac build agent) blocks Capacitor mobile pipeline. Chain is documented and correct. ### PROCESS OBSERVATION The issue body has NOT been edited to incorporate the fixes (issue `created_at` and `updated_at` are identical: `2026-03-26T17:14:53Z`). The fixes exist only in comment #7556. When the dev agent executes this ticket, it must read both the issue body AND the comments to get the complete spec. This is fine -- agents do read comments -- but for maximum clarity, consider editing the issue body to incorporate the 4 changes so the agent has a single coherent spec to execute against. This is a nit, not a blocker. ### SOP COMPLIANCE - [x] Issue follows `template-issue` format (all required sections present) - [x] Lineage references project (`project-pal-e-platform` -- board item, not plan-driven) - [x] User story in proper As a/I want/So that format - [x] File Targets include modify + verify + NOT-to-touch boundaries - [x] Acceptance criteria are testable (6 items) - [x] Constraints include `tofu plan -lock=false` per SOP - [x] Board item has traceability labels (`story:superuser-deploy,arch:tailscale-subnet,type:infra`) - [x] Related references blocker (#174) and downstream consumer ### VERDICT: APPROVED All 4 findings from the initial review are resolved. The ticket is ready for agent execution. One nit: consider editing the issue body to incorporate the fix comment changes for a single coherent spec.
forgejo_admin 2026-03-26 22:18:24 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
forgejo_admin/pal-e-platform#175
No description provided.