Skip to content

feat: add tailscale network ingress provisioner - #5924

Open
TristanSpeakEasy wants to merge 2 commits into
agentlink/ais-667-serving-observabilityfrom
agentlink/ais-605-tailscale-kubernetes-provisioner
Open

feat: add tailscale network ingress provisioner#5924
TristanSpeakEasy wants to merge 2 commits into
agentlink/ais-667-serving-observabilityfrom
agentlink/ais-605-tailscale-kubernetes-provisioner

Conversation

@TristanSpeakEasy

@TristanSpeakEasy TristanSpeakEasy commented Sep 1, 2026

Copy link
Copy Markdown
Member

Why

Private ingress needs a provider-neutral Kubernetes lifecycle contract before Temporal orchestration can safely create or tear down Tailscale resources. This checkpoint implements that resource boundary without adding customer APIs or workflows.

Stacked on #5923.

What changed

  • Add provider-neutral NetworkIngressProvisioner Apply/Observe/Delete contracts, UUID-derived persisted resource identities, provider registry dispatch, and bounded lifecycle telemetry.
  • Add the Tailscale adapter using typed clients for Namespace, Secret, ServiceAccount, Deployment, Service, NetworkPolicy, and Ingress, plus the dynamic client for pinned tailscale.com/v1alpha1 Tailnet, ProxyGroup, and ProxyGroupPolicy resources.
  • Reconcile in validated dependency order with policy-first isolation, projected TokenReview tokens, copied private-listener CA trust, and final MagicDNS/attestor convergence before reporting online.
  • Delete in reverse dependency order using persisted names only, continue cleanup after individual failures, and keep isolation policies until workloads are gone.
  • Gate updates and deletion on Gram ownership labels to prevent accidental adoption or deletion of colliding Kubernetes resources; immutable ProxyGroup replacement is explicitly retryable.
  • Keep OAuth credentials provider-owned and in memory except for the Kubernetes Secret; errors, logs, and metric dimensions remain redacted and bounded.

Review notes

  • AIS-611 owns Temporal orchestration, periodic health, rotation workflows, tombstones, and deletion races.
  • AIS-608 owns production operator deployment, RBAC, namespaces, config values, baseline monitoring, and infrastructure policies.
  • Focus review on ownership safety, apply/delete ordering, NetworkPolicy selectors, and observed hostname readiness.

Validation

  • mise run test:server ./internal/k8s (36 tests)
  • mise lint:server
  • mise build:server
  • git diff --check
  • Independent review completed; ownership/adoption safety, hostname convergence, immutable replacement, policy ordering, cleanup continuation, metadata egress, and metric findings addressed and retested
  • cubic review -j could not complete because local Cubic authentication is expired (cubic auth login required)

Summary by cubic

Adds the provider-neutral NetworkIngressProvisioner contract from AIS-605 with a working Tailscale adapter, so Temporal orchestration can safely create and tear down private ingress resources. No customer-facing APIs or workflows are added yet.

Provisioner contract

  • Defines Apply/Observe/Delete with UUID-derived, persisted resource names and provider registry dispatch.
  • Refuses to adopt or delete resources that lack the Gram ownership labels.
  • Wraps provisioners to record operation counts, durations, and clamped redacted error codes as metrics; OAuth credentials are written only to the operator-namespace Secret.

Tailscale adapter

  • Creates Namespace, Secret, ServiceAccount, Deployment, Service, NetworkPolicy, and Ingress with typed clients, and Tailnet, ProxyGroup, and ProxyGroupPolicy with the dynamic client.
  • Applies in dependency order with policy-first isolation, projected TokenReview tokens, and copied private-listener CA trust.
  • Reports online only after Tailnet, ProxyGroup, attestor, and MagicDNS hostname converge.
  • Deletes in reverse dependency order using persisted names only, continuing after individual failures; immutable ProxyGroup replacement is retryable.

Temporal orchestration, health, rotation, and tombstones remain in AIS-611.

Written for commit 60d5743. Summary will update on new commits.

Review in cubic

@TristanSpeakEasy
TristanSpeakEasy requested a review from a team as a code owner September 1, 2026 09:45
@linear-code

linear-code Bot commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

AIS-605

@changeset-bot

changeset-bot Bot commented Sep 1, 2026

Copy link
Copy Markdown

⚠️ No Changeset found

Latest commit: 60dbbeb

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@cubic-dev-ai

cubic-dev-ai Bot commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

Running ultrareview automatically — Adds a 1,500-line Kubernetes lifecycle provisioner with Tailscale integration, handling credentials, NetworkPolicies, and ownership-sensitive apply/delete ordering — a subtle bug could orphan resources or break network security.. I'll post findings when complete.

@blacksmith-sh

This comment has been minimized.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ultrareview completed in 12m 49s

All reported issues were addressed across 6 files

Linked issue analysis

Linked issue: AIS-605: Tailscale Kubernetes resource provisioner

Status Acceptance criteria Notes
Provide a provider-neutral NetworkIngressProvisioner with Apply, Observe, and Delete, plus provider registry dispatch. The shared interface, desired state, persisted resource identities, registry, and Tailscale adapter are implemented.
Generate stable resource names solely from the ingress UUID and persist/validate all resource identities. Names are deterministically derived from the UUID, contain no organization/customer data, and are round-tripped through JSON persistence.
Use typed Kubernetes clients for core resources and a dynamic client with pinned tailscale.com/v1alpha1 resources for Tailnet, ProxyGroup, and ProxyGroupPolicy. The adapter uses typed clients for the listed Kubernetes resources and pinned dynamic GVRs without vendor Go types.
⚠️ Apply resources in the specified dependency order: OAuth Secret, Tailnet, ProxyGroup, attestor workload/Service, policies, then Ingress. The implementation applies the OAuth Secret after namespace and NetworkPolicies, so it does not follow the issue's stated ordering exactly, although the remaining major dependencies and final Ingress ordering are implemented.
Observe Tailnet, ProxyGroup, attestor, and Ingress readiness and report the final HTTPS hostname. Observe checks Tailnet and ProxyGroup conditions, Deployment availability, Ingress hostname, and expected-host convergence before reporting online.
Delete using persisted names in reverse dependency order, tolerate absent resources, and protect against unowned resources. Deletion uses NetworkIngressResourceNames verbatim, ignores not-found responses, continues after individual failures, and verifies ownership before cleanup.
Handle immutable ProxyGroup replacement, partial apply, redacted errors, and the required fake-client test coverage. Immutable replacement is retryable, partial failures return bounded status codes, credentials are parsed only by the adapter, and tests cover idempotency, partial failure, observe, replacement, deletion, absent resources, and redaction.
Enforce cross-namespace policy and per-ProxyGroup isolation consistent with the Phase 0 contract. NetworkPolicies constrain attestor ingress to the selected ProxyGroup and isolate proxy egress to the corresponding attestor and allowed destinations; tests verify the key selectors.

Tip: instead of fixing issues one by one fix them all with cubic

Re-trigger cubic

Comment thread server/internal/k8s/tailscale_network_ingress_provisioner.go Outdated
Comment thread server/internal/k8s/tailscale_network_ingress_provisioner.go
Comment thread server/internal/k8s/network_ingress_provisioner.go
Comment thread server/internal/k8s/network_ingress_provisioner.go Outdated
Comment thread server/internal/k8s/tailscale_network_ingress_provisioner.go Outdated
Comment thread server/internal/k8s/network_ingress_provisioner.go Outdated
Comment thread server/internal/k8s/network_ingress_provisioner.go Outdated
Comment thread server/internal/k8s/tailscale_network_ingress_provisioner.go
Comment thread server/internal/k8s/tailscale_network_ingress_provisioner.go Outdated
Comment thread server/internal/k8s/tailscale_network_ingress_provisioner_test.go Outdated
@TristanSpeakEasy

Copy link
Copy Markdown
Member Author

Addressed all 15 actionable findings from @cubic-dev-ai’s review in commit 30dbba90c2, including per-resource ownership/UID deletion safety, teardown ordering, canonical identities, credential serialization/validation, metadata preservation, immutable replacement, readiness convergence, and telemetry wiring/noise. Original review: #5924 (review)

@TristanSpeakEasy
TristanSpeakEasy force-pushed the agentlink/ais-605-tailscale-kubernetes-provisioner branch from 30dbba9 to bc195c6 Compare September 2, 2026 00:10
@TristanSpeakEasy
TristanSpeakEasy force-pushed the agentlink/ais-605-tailscale-kubernetes-provisioner branch from bc195c6 to 60dbbeb Compare September 2, 2026 01:20
@TristanSpeakEasy
TristanSpeakEasy force-pushed the agentlink/ais-605-tailscale-kubernetes-provisioner branch from 60dbbeb to 60d5743 Compare September 2, 2026 11:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant