Skip to content

Migration v1 to v2

Minh Tu Le edited this page Jul 24, 2026 · 15 revisions

v2 of the operator drops two long-deprecated features. This guide covers what changed and the upgrade path.

What changed

Legacy Service annotations removed. The old twingate.com/resource* annotations no longer work; use the resource.twingate.com* form. The mapping is:

  • twingate.com/resource -> resource.twingate.com
  • twingate.com/resource-name -> resource.twingate.com/name
  • twingate.com/resource-alias -> resource.twingate.com/alias
  • twingate.com/resource-isVisible -> resource.twingate.com/isVisible
  • twingate.com/resource-isBrowserShortcutEnabled -> resource.twingate.com/isBrowserShortcutEnabled
  • twingate.com/resource-securityPolicyId -> resource.twingate.com/securityPolicyId
  • twingate.com/resource-syncLabels -> resource.twingate.com/syncLabels

Kubernetes proxy removed.

  • The spec.proxy field on TwingateResource is gone. Kubernetes resources now bind to a Gateway with spec.gatewayRef (see Identity Firewall).
  • type: Kubernetes can no longer be created by annotating a Service.
  • The bundled gateway subchart (which exposes in-cluster Kubernetes access) restructured its values.yaml: the annotation-based twingate.resource.extraAnnotations block is replaced by twingateOperator.gateway.* and twingateOperator.kubernetesResource.* fields (see step 4 below).

Before you upgrade

Rename any legacy annotations on your Service objects to the resource.twingate.com* form using the mapping above. Do this while still on v1 so nothing breaks during the upgrade.

For most users this is the whole migration: rename the annotations, then upgrade normally. The Upgrade path below is only needed if you use the bundled gateway subchart or created type: Kubernetes resources by hand.

Upgrade path

Follow these steps only if you use the bundled gateway subchart or hand-authored type: Kubernetes resources. Otherwise you are done after renaming the annotations above.

Warning

Twingate access to the cluster's Kubernetes API is interrupted for the duration of this migration: it goes down when you disable the gateway subchart (step 1) and returns once it is re-provisioned under the Gateway model (step 4). Plan a maintenance window. Network resources reached through a Connector are unaffected.

  1. Disable the gateway subchart. Set gateway.enabled: false and upgrade. This removes the in-cluster Kubernetes access resource so it can be recreated cleanly under the new model.
# values.yaml
twingateOperator:
  network: "<network slug>"
  apiKey: "<api key>"
  remoteNetworkId: "<remote network id>"

gateway:
  enabled: false
  1. Delete manual Kubernetes resources. Delete any TwingateResource of type: Kubernetes you created by hand. In v1 these all use the now-removed spec.proxy field, so they must be deleted before upgrading and re-created under the Gateway model (step 4).

  2. Apply the new CRDs. Helm does not upgrade CRDs, and they are not published on their own; they ship inside the chart, so you must apply them yourself or the new fields and validations will be missing. Pull the same chart you are about to install and apply the CRDs from its crds/ directory so they match the chart version:

helm pull oci://ghcr.io/twingate/helmcharts/twingate-operator --untar
kubectl apply -f twingate-operator/crds/
  1. Upgrade the operator and re-enable the gateway subchart. Set gateway.enabled: true again, but also restructure the subchart's values. The chart now renders the Gateway custom resources directly instead of annotating the Gateway Service, so the old gateway.twingate.resource.extraAnnotations block is replaced by gateway.twingateOperator.gateway.* and gateway.twingateOperator.kubernetesResource.*.

    Before (v1 subchart, annotation-based):

# values.yaml
twingateOperator:
  network: "<network slug>"
  apiKey: "<api key>"
  remoteNetworkId: "<remote network id>"

gateway:
  enabled: true
  twingate:
    network: "<network slug>"
    resource:
      enabled: true
      extraAnnotations:
        resource.twingate.com/name: "My Kubernetes Cluster"
        resource.twingate.com/alias: "my-k8s-cluster.int"

After (v2 subchart, resource fields):

# values.yaml
twingateOperator:
  network: "<network slug>"
  apiKey: "<api key>"
  remoteNetworkId: "<remote network id>"

gateway:
  enabled: true
  twingate:
    network: "<network slug>"
  twingateOperator:
    gateway:
      enabled: true
    kubernetesResource:
      enabled: true
      name: "My Kubernetes Cluster"
      alias: "my-k8s-cluster.int"

What moved:

  • gateway.twingate.resource.enabled splits into two toggles: gateway.twingateOperator.gateway.enabled renders the Gateway, and gateway.twingateOperator.kubernetesResource.enabled renders the in-cluster Kubernetes resource (which requires the Gateway toggle).
  • The resource.twingate.com/* annotations under gateway.twingate.resource.extraAnnotations become fields under gateway.twingateOperator.kubernetesResource (name, alias, securityPolicyId, and so on). Any TwingateResource spec field passes through directly.

Run the Helm upgrade. Without --version, this installs the latest published chart:

helm upgrade twop oci://ghcr.io/twingate/helmcharts/twingate-operator --install --wait -f ./values.yaml

The gateway subchart re-provisions in-cluster Kubernetes access under the new Gateway model. The in-cluster TwingateResource keeps the name <release>-gateway-resource, so existing TwingateResourceAccess references resolve again once it is recreated. Re-declare any hand-authored Kubernetes resources with gatewayRef instead of proxy.

Clone this wiki locally