Skip to content

feat: tailscale-operator Workload Identity(beta) - Helm upgrade + docs#514

Open
boxp wants to merge 2 commits intomainfrom
T-20260302-009-tailscale-wif
Open

feat: tailscale-operator Workload Identity(beta) - Helm upgrade + docs#514
boxp wants to merge 2 commits intomainfrom
T-20260302-009-tailscale-wif

Conversation

@boxp
Copy link
Owner

@boxp boxp commented Mar 2, 2026

See PR commits for changes. Related: boxp/arch#7333

@github-actions
Copy link
Contributor

github-actions bot commented Mar 2, 2026

ArgoCD Diff Result

Auth path: tailscale

アプリケーション: tailscale-operator の差分

パス: argoproj/tailscale-operator

===== /ServiceAccount tailscale-operator/operator ======
1,19d0
< apiVersion: v1
< kind: ServiceAccount
< metadata:
<   annotations:
<     argocd.argoproj.io/tracking-id: tailscale-operator:/ServiceAccount:tailscale-operator/operator
<   managedFields:
<   - apiVersion: v1
<     fieldsType: FieldsV1
<     fieldsV1:
<       f:metadata:
<         f:annotations:
<           f:argocd.argoproj.io/tracking-id: {}
<     manager: argocd-controller
<     operation: Apply
<     time: "2026-02-28T10:28:08Z"
<   name: operator
<   namespace: tailscale-operator
<   resourceVersion: "543551503"
<   uid: b56e0a3e-4f99-4fb9-ab31-349c40f498f2

===== /ServiceAccount tailscale-operator/proxies ======
1,19d0
< apiVersion: v1
< kind: ServiceAccount
< metadata:
<   annotations:
<     argocd.argoproj.io/tracking-id: tailscale-operator:/ServiceAccount:tailscale-operator/proxies
<   managedFields:
<   - apiVersion: v1
<     fieldsType: FieldsV1
<     fieldsV1:
<       f:metadata:
<         f:annotations:
<           f:argocd.argoproj.io/tracking-id: {}
<     manager: argocd-controller
<     operation: Apply
<     time: "2026-02-28T10:28:08Z"
<   name: proxies
<   namespace: tailscale-operator
<   resourceVersion: "543551501"
<   uid: 458ca0b2-6ed9-41f0-ad78-44863020b6af

===== apiextensions.k8s.io/CustomResourceDefinition /connectors.tailscale.com ======
1,324d0
< apiVersion: apiextensions.k8s.io/v1
< kind: CustomResourceDefinition
< metadata:
<   annotations:
<     controller-gen.kubebuilder.io/version: v0.17.0
<   generation: 1
<   managedFields:
<   - apiVersion: apiextensions.k8s.io/v1
<     fieldsType: FieldsV1
<     fieldsV1:
<       f:metadata:
<         f:annotations:
<           f:controller-gen.kubebuilder.io/version: {}
<       f:spec:
<         f:group: {}
<         f:names:
<           f:kind: {}
<           f:listKind: {}
<           f:plural: {}
<           f:shortNames: {}
<           f:singular: {}
<         f:scope: {}
<         f:versions: {}
<     manager: argocd-controller
<     operation: Apply
<     time: "2026-02-28T10:28:08Z"
<   - apiVersion: apiextensions.k8s.io/v1
<     fieldsType: FieldsV1
<     fieldsV1:
<       f:status:
<         f:acceptedNames:
<           f:kind: {}
<           f:listKind: {}
<           f:plural: {}
<           f:shortNames: {}
<           f:singular: {}
<         f:conditions:
<           k:{"type":"Established"}:
<             .: {}
<             f:lastTransitionTime: {}
<             f:message: {}
<             f:reason: {}
<             f:status: {}
<             f:type: {}
<           k:{"type":"NamesAccepted"}:
<             .: {}
<             f:lastTransitionTime: {}
<             f:message: {}
<             f:reason: {}
<             f:status: {}
<             f:type: {}
<     manager: kube-apiserver
<     operation: Update
<     subresource: status
<     time: "2026-02-28T10:28:09Z"
<   name: connectors.tailscale.com
<   resourceVersion: "543551527"
<   uid: 9466db02-1fa4-425c-aded-284d08ffbb24
< spec:
<   conversion:
<     strategy: None
<   group: tailscale.com
<   names:
<     kind: Connector
<     listKind: ConnectorList
<     plural: connectors
<     shortNames:
<     - cn
<     singular: connector
<   scope: Cluster
<   versions:
<   - additionalPrinterColumns:
<     - description: CIDR ranges exposed to tailnet by a subnet router defined via this
<         Connector instance.
<       jsonPath: .status.subnetRoutes
<       name: SubnetRoutes
<       type: string
<     - description: Whether this Connector instance defines an exit node.
<       jsonPath: .status.isExitNode
<       name: IsExitNode
<       type: string
<     - description: Whether this Connector instance is an app connector.
<       jsonPath: .status.isAppConnector
<       name: IsAppConnector
<       type: string
<     - description: Status of the deployed Connector resources.
<       jsonPath: .status.conditions[?(@.type == "ConnectorReady")].reason
<       name: Status
<       type: string
<     name: v1alpha1
<     schema:
<       openAPIV3Schema:
<         description: |-
<           Connector defines a Tailscale node that will be deployed in the cluster. The
<           node can be configured to act as a Tailscale subnet router and/or a Tailscale
<           exit node.
<           Connector is a cluster-scoped resource.
<           More info:
<           https://tailscale.com/kb/1441/kubernetes-operator-connector
<         properties:
<           apiVersion:
<             description: |-
<               APIVersion defines the versioned schema of this representation of an object.
<               Servers should convert recognized schemas to the latest internal value, and
<               may reject unrecognized values.
<               More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources
<             type: string
<           kind:
<             description: |-
<               Kind is a string value representing the REST resource this object represents.
<               Servers may infer this from the endpoint the client submits requests to.
<               Cannot be updated.
<               In CamelCase.
<               More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds
<             type: string
<           metadata:
<             type: object
<           spec:
<             description: |-
<               ConnectorSpec describes the desired Tailscale component.
<               More info:
<               https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status
<             properties:
<               appConnector:
<                 description: |-
<                   AppConnector defines whether the Connector device should act as a Tailscale app connector. A Connector that is
<                   configured as an app connector cannot be a subnet router or an exit node. If this field is unset, the
<                   Connector does not act as an app connector.
<                   Note that you will need to manually configure the permissions and the domains for the app connector via the
<                   Admin panel.
<                   Note also that the main tested and supported use case of this config option is to deploy an app connector on
<                   Kubernetes to access SaaS applications available on the public internet. Using the app connector to expose
<                   cluster workloads or other internal workloads to tailnet might work, but this is not a use case that we have
<                   tested or optimised for.
<                   If you are using the app connector to access SaaS applications because you need a predictable egress IP that
<                   can be whitelisted, it is also your responsibility to ensure that cluster traffic from the connector flows
<                   via that predictable IP, for example by enforcing that cluster egress traffic is routed via an egress NAT
<                   device with a static IP address.
<                   https://tailscale.com/kb/1281/app-connectors
<                 properties:
<                   routes:
<                     description: |-
<                       Routes are optional preconfigured routes for the domains routed via the app connector.
<                       If not set, routes for the domains will be discovered dynamically.
<                       If set, the app connector will immediately be able to route traffic using the preconfigured routes, but may
<                       also dynamically discover other routes.
<                       https://tailscale.com/kb/1332/apps-best-practices#preconfiguration
<                     items:
<                       format: cidr
<                       type: string
<                     minItems: 1
<                     type: array
<                 type: object
<               exitNode:
<                 description: |-
<                   ExitNode defines whether the Connector device should act as a Tailscale exit node. Defaults to false.
<                   This field is mutually exclusive with the appConnector field.
<                   https://tailscale.com/kb/1103/exit-nodes
<                 type: boolean
<               hostname:
<                 description: |-
<                   Hostname is the tailnet hostname that should be assigned to the
<                   Connector node. If unset, hostname defaults to <connector
<                   name>-connector. Hostname can contain lower case letters, numbers and
<                   dashes, it must not start or end with a dash and must be between 2
<                   and 63 characters long.
<                 pattern: ^[a-z0-9][a-z0-9-]{0,61}[a-z0-9]$
<                 type: string
<               proxyClass:
<                 description: |-
<                   ProxyClass is the name of the ProxyClass custom resource that
<                   contains configuration options that should be applied to the
<                   resources created for this Connector. If unset, the operator will
<                   create resources with the default configuration.
<                 type: string
<               subnetRouter:
<                 description: |-
<                   SubnetRouter defines subnet routes that the Connector device should
<                   expose to tailnet as a Tailscale subnet router.
<                   https://tailscale.com/kb/1019/subnets/
<                   If this field is unset, the device does not get configured as a Tailscale subnet router.
<                   This field is mutually exclusive with the appConnector field.
<                 properties:
<                   advertiseRoutes:
<                     description: |-
<                       AdvertiseRoutes refer to CIDRs that the subnet router should make
<                       available. Route values must be strings that represent a valid IPv4
<                       or IPv6 CIDR range. Values can be Tailscale 4via6 subnet routes.
<                       https://tailscale.com/kb/1201/4via6-subnets/
<                     items:
<                       format: cidr
<                       type: string
<                     minItems: 1
<                     type: array
<                 required:
<                 - advertiseRoutes
<                 type: object
<               tags:
<                 description: |-
<                   Tags that the Tailscale node will be tagged with.
<                   Defaults to [tag:k8s].
<                   To autoapprove the subnet routes or exit node defined by a Connector,
<                   you can configure Tailscale ACLs to give these tags the necessary
<                   permissions.
<                   See https://tailscale.com/kb/1337/acl-syntax#autoapprovers.
<                   If you specify custom tags here, you must also make the operator an owner of these tags.
<                   See  https://tailscale.com/kb/1236/kubernetes-operator/#setting-up-the-kubernetes-operator.
<                   Tags cannot be changed once a Connector node has been created.
<                   Tag values must be in form ^tag:[a-zA-Z][a-zA-Z0-9-]*$.
<                 items:
<                   pattern: ^tag:[a-zA-Z][a-zA-Z0-9-]*$
<                   type: string
<                 type: array
<             type: object
<             x-kubernetes-validations:
<             - message: A Connector needs to have at least one of exit node, subnet
<                 router or app connector configured.
<               rule: has(self.subnetRouter) || (has(self.exitNode) && self.exitNode
<                 == true) || has(self.appConnector)
<             - message: The appConnector field is mutually exclusive with exitNode
<                 and subnetRouter fields.
<               rule: '!((has(self.subnetRouter) || (has(self.exitNode)  && self.exitNode
<                 == true)) && has(self.appConnector))'
<           status:
<             description: |-
<               ConnectorStatus describes the status of the Connector. This is set
<               and managed by the Tailscale operator.
<             properties:
<               conditions:
<                 description: |-
<                   List of status conditions to indicate the status of the Connector.
<                   Known condition types are `ConnectorReady`.
<                 items:
<                   description: Condition contains details for one aspect of the current
<                     state of this API Resource.
<                   properties:
<                     lastTransitionTime:
<                       description: |-
<                         lastTransitionTime is the last time the condition transitioned from one status to another.
<                         This should be when the underlying condition changed.  If that is not known, then using the time when the API field changed is acceptable.
<                       format: date-time
<                       type: string
<                     message:
<                       description: |-
<                         message is a human readable message indicating details about the transition.
<                         This may be an empty string.
<                       maxLength: 32768
<                       type: string
<                     observedGeneration:
<                       description: |-
<                         observedGeneration represents the .metadata.generation that the condition was set based upon.
<                         For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date
<                         with respect to the current state of the instance.
<                       format: int64
<                       minimum: 0
<                       type: integer
<                     reason:
<                       description: |-
<                         reason contains a programmatic identifier indicating the reason for the condition's last transition.
<                         Producers of specific condition types may define expected values and meanings for this field,
<                         and whether the values are considered a guaranteed API.
<                         The value should be a CamelCase string.
<                         This field may not be empty.
<                       maxLength: 1024
<                       minLength: 1
<                       pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$
<                       type: string
<                     status:
<                       description: status of the condition, one of True, False, Unknown.
<                       enum:
<                       - "True"
<                       - "False"
<                       - Unknown
<                       type: string
<                     type:
<                       description: type of condition in CamelCase or in foo.example.com/CamelCase.
<                       maxLength: 316
<                       pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$
<                       type: string
<                   required:
<                   - lastTransitionTime
<                   - message
<                   - reason
<                   - status
<                   - type
<                   type: object
<                 type: array
<                 x-kubernetes-list-map-keys:
<                 - type
<                 x-kubernetes-list-type: map
<               hostname:
<                 description: |-
<                   Hostname is the fully qualified domain name of the Connector node.
<                   If MagicDNS is enabled in your tailnet, it is the MagicDNS name of the
<                   node.
<                 type: string
<               isAppConnector:
<                 description: IsAppConnector is set to true if the Connector acts as
<                   an app connector.
<                 type: boolean
<               isExitNode:
<                 description: IsExitNode is set to true if the Connector acts as an
<                   exit node.
<                 type: boolean
<               subnetRoutes:
<                 description: |-
<                   SubnetRoutes are the routes currently exposed to tailnet via this
<                   Connector instance.
<                 type: string
<               tailnetIPs:
<                 description: |-
<                   TailnetIPs is the set of tailnet IP addresses (both IPv4 and IPv6)
<                   assigned to the Connector node.
<                 items:
<                   type: string
<                 type: array
<             type: object
<         required:
<         - spec
<         type: object
<     served: true
<     storage: true
<     subresources:
<       status: {}

===== apiextensions.k8s.io/CustomResourceDefinition /dnsconfigs.tailscale.com ======
1,237d0
< apiVersion: apiextensions.k8s.io/v1
< kind: CustomResourceDefinition
< metadata:
<   annotations:
<     controller-gen.kubebuilder.io/version: v0.17.0
<   generation: 1
<   managedFields:
<   - apiVersion: apiextensions.k8s.io/v1
<     fieldsType: FieldsV1
<     fieldsV1:
<       f:metadata:
<         f:annotations:
<           f:controller-gen.kubebuilder.io/version: {}
<       f:spec:
<         f:group: {}
<         f:names:
<           f:kind: {}
<           f:listKind: {}
<           f:plural: {}
<           f:shortNames: {}
<           f:singular: {}
<         f:scope: {}
<         f:versions: {}
<     manager: argocd-controller
<     operation: Apply
<     time: "2026-02-28T10:28:08Z"
<   - apiVersion: apiextensions.k8s.io/v1
<     fieldsType: FieldsV1
<     fieldsV1:
<       f:status:
<         f:acceptedNames:
<           f:kind: {}
<           f:listKind: {}
<           f:plural: {}
<           f:shortNames: {}
<           f:singular: {}
<         f:conditions:
<           k:{"type":"Established"}:
<             .: {}
<             f:lastTransitionTime: {}
<             f:message: {}
<             f:reason: {}
<             f:status: {}
<             f:type: {}
<           k:{"type":"NamesAccepted"}:
<             .: {}
<             f:lastTransitionTime: {}
<             f:message: {}
<             f:reason: {}
<             f:status: {}
<             f:type: {}
<     manager: kube-apiserver
<     operation: Update
<     subresource: status
<     time: "2026-02-28T10:28:09Z"
<   name: dnsconfigs.tailscale.com
<   resourceVersion: "543551520"
<   uid: c525e4ac-e08e-4ab3-99ee-6a02b4bc34e1
< spec:
<   conversion:
<     strategy: None
<   group: tailscale.com
<   names:
<     kind: DNSConfig
<     listKind: DNSConfigList
<     plural: dnsconfigs
<     shortNames:
<     - dc
<     singular: dnsconfig
<   scope: Cluster
<   versions:
<   - additionalPrinterColumns:
<     - description: Service IP address of the nameserver
<       jsonPath: .status.nameserver.ip
<       name: NameserverIP
<       type: string
<     name: v1alpha1
<     schema:
<       openAPIV3Schema:
<         description: |-
<           DNSConfig can be deployed to cluster to make a subset of Tailscale MagicDNS
<           names resolvable by cluster workloads. Use this if: A) you need to refer to
<           tailnet services, exposed to cluster via Tailscale Kubernetes operator egress
<           proxies by the MagicDNS names of those tailnet services (usually because the
<           services run over HTTPS)
<           B) you have exposed a cluster workload to the tailnet using Tailscale Ingress
<           and you also want to refer to the workload from within the cluster over the
<           Ingress's MagicDNS name (usually because you have some callback component
<           that needs to use the same URL as that used by a non-cluster client on
<           tailnet).
<           When a DNSConfig is applied to a cluster, Tailscale Kubernetes operator will
<           deploy a nameserver for ts.net DNS names and automatically populate it with records
<           for any Tailscale egress or Ingress proxies deployed to that cluster.
<           Currently you must manually update your cluster DNS configuration to add the
<           IP address of the deployed nameserver as a ts.net stub nameserver.
<           Instructions for how to do it:
<           https://kubernetes.io/docs/tasks/administer-cluster/dns-custom-nameservers/#configuration-of-stub-domain-and-upstream-nameserver-using-coredns (for CoreDNS),
<           https://cloud.google.com/kubernetes-engine/docs/how-to/kube-dns (for kube-dns).
<           Tailscale Kubernetes operator will write the address of a Service fronting
<           the nameserver to dsnconfig.status.nameserver.ip.
<           DNSConfig is a singleton - you must not create more than one.
<           NB: if you want cluster workloads to be able to refer to Tailscale Ingress
<           using its MagicDNS name, you must also annotate the Ingress resource with
<           tailscale.com/experimental-forward-cluster-traffic-via-ingress annotation to
<           ensure that the proxy created for the Ingress listens on its Pod IP address.
<           NB: Clusters where Pods get assigned IPv6 addresses only are currently not supported.
<         properties:
<           apiVersion:
<             description: |-
<               APIVersion defines the versioned schema of this representation of an object.
<               Servers should convert recognized schemas to the latest internal value, and
<               may reject unrecognized values.
<               More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources
<             type: string
<           kind:
<             description: |-
<               Kind is a string value representing the REST resource this object represents.
<               Servers may infer this from the endpoint the client submits requests to.
<               Cannot be updated.
<               In CamelCase.
<               More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds
<             type: string
<           metadata:
<             type: object
<           spec:
<             description: |-
<               Spec describes the desired DNS configuration.
<               More info:
<               https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status
<             properties:
<               nameserver:
<                 description: |-
<                   Configuration for a nameserver that can resolve ts.net DNS names
<                   associated with in-cluster proxies for Tailscale egress Services and
<                   Tailscale Ingresses. The operator will always deploy this nameserver
<                   when a DNSConfig is applied.
<                 properties:
<                   image:
<                     description: Nameserver image. Defaults to tailscale/k8s-nameserver:unstable.
<                     properties:
<                       repo:
<                         description: Repo defaults to tailscale/k8s-nameserver.
<                         type: string
<                       tag:
<                         description: Tag defaults to unstable.
<                         type: string
<                     type: object
<                 type: object
<             required:
<             - nameserver
<             type: object
<           status:
<             description: |-
<               Status describes the status of the DNSConfig. This is set
<               and managed by the Tailscale operator.
<             properties:
<               conditions:
<                 items:
<                   description: Condition contains details for one aspect of the current
<                     state of this API Resource.
<                   properties:
<                     lastTransitionTime:
<                       description: |-
<                         lastTransitionTime is the last time the condition transitioned from one status to another.
<                         This should be when the underlying condition changed.  If that is not known, then using the time when the API field changed is acceptable.
<                       format: date-time
<                       type: string
<                     message:
<                       description: |-
<                         message is a human readable message indicating details about the transition.
<                         This may be an empty string.
<                       maxLength: 32768
<                       type: string
<                     observedGeneration:
<                       description: |-
<                         observedGeneration represents the .metadata.generation that the condition was set based upon.
<                         For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date
<                         with respect to the current state of the instance.
<                       format: int64
<                       minimum: 0
<                       type: integer
<                     reason:
<                       description: |-
<                         reason contains a programmatic identifier indicating the reason for the condition's last transition.
<                         Producers of specific condition types may define expected values and meanings for this field,
<                         and whether the values are considered a guaranteed API.
<                         The value should be a CamelCase string.
<                         This field may not be emp

---
⚠️ **diff出力が長すぎるため、一部内容を省略しました**



📝 **省略された内容**: 685,369文字

table prefix for written object names.
<                         type: string
<                       credentials:
<                         description: |-
<                           Configure environment variable credentials for managing objects in the
<                           configured bucket. If not set, tsrecorder will try to acquire credentials
<                           first from the file system and then the STS API.
<                         properties:
<                           secret:
<                             description: |-
<                               Use a Kubernetes Secret from the operator's namespace as the source of
<                               credentials.
<                             properties:
<                               name:
<                                 description: |-
<                                   The name of a Kubernetes Secret in the operator's namespace that contains
<                                   credentials for writing to the configured bucket. Each key-value pair
<                                   from the secret's data will be mounted as an environment variable. It
<                                   should include keys for AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY if
<                                   using a static access key.
<                                 type: string
<                             type: object
<                         type: object
<                       endpoint:
<                         description: S3-compatible endpoint, e.g. s3.us-east-1.amazonaws.com.
<                         type: string
<                     type: object
<                 type: object
<               tags:
<                 description: |-
<                   Tags that the Tailscale device will be tagged with. Defaults to [tag:k8s].
<                   If you specify custom tags here, make sure you also make the operator
<                   an owner of these tags.
<                   See  https://tailscale.com/kb/1236/kubernetes-operator/#setting-up-the-kubernetes-operator.
<                   Tags cannot be changed once a Recorder node has been created.
<                   Tag values must be in form ^tag:[a-zA-Z][a-zA-Z0-9-]*$.
<                 items:
<                   pattern: ^tag:[a-zA-Z][a-zA-Z0-9-]*$
<                   type: string
<                 type: array
<             type: object
<           status:
<             description: |-
<               RecorderStatus describes the status of the recorder. This is set
<               and managed by the Tailscale operator.
<             properties:
<               conditions:
<                 description: |-
<                   List of status conditions to indicate the status of the Recorder.
<                   Known condition types are `RecorderReady`.
<                 items:
<                   description: Condition contains details for one aspect of the current
<                     state of this API Resource.
<                   properties:
<                     lastTransitionTime:
<                       description: |-
<                         lastTransitionTime is the last time the condition transitioned from one status to another.
<                         This should be when the underlying condition changed.  If that is not known, then using the time when the API field changed is acceptable.
<                       format: date-time
<                       type: string
<                     message:
<                       description: |-
<                         message is a human readable message indicating details about the transition.
<                         This may be an empty string.
<                       maxLength: 32768
<                       type: string
<                     observedGeneration:
<                       description: |-
<                         observedGeneration represents the .metadata.generation that the condition was set based upon.
<                         For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date
<                         with respect to the current state of the instance.
<                       format: int64
<                       minimum: 0
<                       type: integer
<                     reason:
<                       description: |-
<                         reason contains a programmatic identifier indicating the reason for the condition's last transition.
<                         Producers of specific condition types may define expected values and meanings for this field,
<                         and whether the values are considered a guaranteed API.
<                         The value should be a CamelCase string.
<                         This field may not be empty.
<                       maxLength: 1024
<                       minLength: 1
<                       pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$
<                       type: string
<                     status:
<                       description: status of the condition, one of True, False, Unknown.
<                       enum:
<                       - "True"
<                       - "False"
<                       - Unknown
<                       type: string
<                     type:
<                       description: type of condition in CamelCase or in foo.example.com/CamelCase.
<                       maxLength: 316
<                       pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$
<                       type: string
<                   required:
<                   - lastTransitionTime
<                   - message
<                   - reason
<                   - status
<                   - type
<                   type: object
<                 type: array
<                 x-kubernetes-list-map-keys:
<                 - type
<                 x-kubernetes-list-type: map
<               devices:
<                 description: List of tailnet devices associated with the Recorder
<                   StatefulSet.
<                 items:
<                   properties:
<                     hostname:
<                       description: |-
<                         Hostname is the fully qualified domain name of the device.
<                         If MagicDNS is enabled in your tailnet, it is the MagicDNS name of the
<                         node.
<                       type: string
<                     tailnetIPs:
<                       description: |-
<                         TailnetIPs is the set of tailnet IP addresses (both IPv4 and IPv6)
<                         assigned to the device.
<                       items:
<                         type: string
<                       type: array
<                     url:
<                       description: |-
<                         URL where the UI is available if enabled for replaying recordings. This
<                         will be an HTTPS MagicDNS URL. You must be connected to the same tailnet
<                         as the recorder to access it.
<                       type: string
<                   required:
<                   - hostname
<                   type: object
<                 type: array
<                 x-kubernetes-list-map-keys:
<                 - hostname
<                 x-kubernetes-list-type: map
<             type: object
<         required:
<         - spec
<         type: object
<     served: true
<     storage: true
<     subresources:
<       status: {}

===== apps/Deployment tailscale-operator/operator ======
1,239d0
< apiVersion: apps/v1
< kind: Deployment
< metadata:
<   annotations:
<     argocd.argoproj.io/tracking-id: tailscale-operator:apps/Deployment:tailscale-operator/operator
<     deployment.kubernetes.io/revision: "4"
<   generation: 4
<   managedFields:
<   - apiVersion: apps/v1
<     fieldsType: FieldsV1
<     fieldsV1:
<       f:metadata:
<         f:annotations:
<           f:argocd.argoproj.io/tracking-id: {}
<       f:spec:
<         f:replicas: {}
<         f:selector: {}
<         f:strategy:
<           f:type: {}
<         f:template:
<           f:metadata:
<             f:labels:
<               f:app: {}
<           f:spec:
<             f:containers:
<               k:{"name":"operator"}:
<                 .: {}
<                 f:env:
<                   k:{"name":"APISERVER_PROXY"}:
<                     .: {}
<                     f:name: {}
<                     f:value: {}
<                   k:{"name":"CLIENT_ID_FILE"}:
<                     .: {}
<                     f:name: {}
<                     f:value: {}
<                   k:{"name":"CLIENT_SECRET_FILE"}:
<                     .: {}
<                     f:name: {}
<                     f:value: {}
<                   k:{"name":"OPERATOR_HOSTNAME"}:
<                     .: {}
<                     f:name: {}
<                     f:value: {}
<                   k:{"name":"OPERATOR_INITIAL_TAGS"}:
<                     .: {}
<                     f:name: {}
<                     f:value: {}
<                   k:{"name":"OPERATOR_LOGGING"}:
<                     .: {}
<                     f:name: {}
<                     f:value: {}
<                   k:{"name":"OPERATOR_NAMESPACE"}:
<                     .: {}
<                     f:name: {}
<                     f:valueFrom:
<                       f:fieldRef: {}
<                   k:{"name":"OPERATOR_SECRET"}:
<                     .: {}
<                     f:name: {}
<                     f:value: {}
<                   k:{"name":"POD_NAME"}:
<                     .: {}
<                     f:name: {}
<                     f:valueFrom:
<                       f:fieldRef: {}
<                   k:{"name":"POD_UID"}:
<                     .: {}
<                     f:name: {}
<                     f:valueFrom:
<                       f:fieldRef: {}
<                   k:{"name":"PROXY_FIREWALL_MODE"}:
<                     .: {}
<                     f:name: {}
<                     f:value: {}
<                   k:{"name":"PROXY_IMAGE"}:
<                     .: {}
<                     f:name: {}
<                     f:value: {}
<                   k:{"name":"PROXY_TAGS"}:
<                     .: {}
<                     f:name: {}
<                     f:value: {}
<                 f:image: {}
<                 f:imagePullPolicy: {}
<                 f:name: {}
<                 f:volumeMounts:
<                   k:{"mountPath":"/oauth"}:
<                     .: {}
<                     f:mountPath: {}
<                     f:name: {}
<                     f:readOnly: {}
<             f:nodeSelector: {}
<             f:serviceAccountName: {}
<             f:volumes:
<               k:{"name":"oauth"}:
<                 .: {}
<                 f:name: {}
<                 f:secret:
<                   f:secretName: {}
<     manager: argocd-controller
<     operation: Apply
<     time: "2026-03-01T01:19:58Z"
<   - apiVersion: apps/v1
<     fieldsType: FieldsV1
<     fieldsV1:
<       f:spec:
<         f:template:
<           f:metadata:
<             f:annotations: {}
<     manager: argocd-server
<     operation: Update
<     time: "2026-03-02T15:13:50Z"
<   - apiVersion: apps/v1
<     fieldsType: FieldsV1
<     fieldsV1:
<       f:spec:
<         f:template:
<           f:metadata:
<             f:annotations:
<               f:kubectl.kubernetes.io/restartedAt: {}
<     manager: kubectl-rollout
<     operation: Update
<     time: "2026-03-02T16:22:02Z"
<   - apiVersion: apps/v1
<     fieldsType: FieldsV1
<     fieldsV1:
<       f:metadata:
<         f:annotations:
<           f:deployment.kubernetes.io/revision: {}
<       f:status:
<         f:availableReplicas: {}
<         f:conditions:
<           .: {}
<           k:{"type":"Available"}:
<             .: {}
<             f:lastTransitionTime: {}
<             f:lastUpdateTime: {}
<             f:message: {}
<             f:reason: {}
<             f:status: {}
<             f:type: {}
<           k:{"type":"Progressing"}:
<             .: {}
<             f:lastTransitionTime: {}
<             f:lastUpdateTime: {}
<             f:message: {}
<             f:reason: {}
<             f:status: {}
<             f:type: {}
<         f:observedGeneration: {}
<         f:readyReplicas: {}
<         f:replicas: {}
<         f:updatedReplicas: {}
<     manager: kube-controller-manager
<     operation: Update
<     subresource: status
<     time: "2026-03-02T16:22:24Z"
<   name: operator
<   namespace: tailscale-operator
<   resourceVersion: "545903484"
<   uid: 1ec088cf-cddb-45b9-b6e1-85054ecf634a
< spec:
<   progressDeadlineSeconds: 600
<   replicas: 1
<   revisionHistoryLimit: 10
<   selector:
<     matchLabels:
<       app: operator
<   strategy:
<     type: Recreate
<   template:
<     metadata:
<       annotations:
<         kubectl.kubernetes.io/restartedAt: "2026-03-03T01:22:02+09:00"
<       labels:
<         app: operator
<     spec:
<       containers:
<       - env:
<         - name: OPERATOR_INITIAL_TAGS
<           value: tag:k8s-operator
<         - name: OPERATOR_HOSTNAME
<           value: tailscale-operator
<         - name: OPERATOR_SECRET
<           value: operator
<         - name: OPERATOR_LOGGING
<           value: info
<         - name: OPERATOR_NAMESPACE
<           valueFrom:
<             fieldRef:
<               apiVersion: v1
<               fieldPath: metadata.namespace
<         - name: CLIENT_ID_FILE
<           value: /oauth/client_id
<         - name: CLIENT_SECRET_FILE
<           value: /oauth/client_secret
<         - name: PROXY_IMAGE
<           value: tailscale/tailscale:v1.80.3
<         - name: PROXY_TAGS
<           value: tag:k8s-operator
<         - name: APISERVER_PROXY
<           value: "false"
<         - name: PROXY_FIREWALL_MODE
<           value: auto
<         - name: POD_NAME
<           valueFrom:
<             fieldRef:
<               apiVersion: v1
<               fieldPath: metadata.name
<         - name: POD_UID
<           valueFrom:
<             fieldRef:
<               apiVersion: v1
<               fieldPath: metadata.uid
<         image: tailscale/k8s-operator:v1.80.3
<         imagePullPolicy: Always
<         name: operator
<         resources: {}
<         terminationMessagePath: /dev/termination-log
<         terminationMessagePolicy: File
<         volumeMounts:
<         - mountPath: /oauth
<           name: oauth
<           readOnly: true
<       dnsPolicy: ClusterFirst
<       nodeSelector:
<         kubernetes.io/os: linux
<       restartPolicy: Always
<       schedulerName: default-scheduler
<       securityContext: {}
<       serviceAccount: operator
<       serviceAccountName: operator
<       terminationGracePeriodSeconds: 30
<       volumes:
<       - name: oauth
<         secret:
<           defaultMode: 420
<           secretName: tailscale-operator-oauth

===== networking.k8s.io/IngressClass /tailscale ======
1,23d0
< apiVersion: networking.k8s.io/v1
< kind: IngressClass
< metadata:
<   annotations:
<     argocd.argoproj.io/tracking-id: tailscale-operator:networking.k8s.io/IngressClass:tailscale-operator/tailscale
<   generation: 1
<   managedFields:
<   - apiVersion: networking.k8s.io/v1
<     fieldsType: FieldsV1
<     fieldsV1:
<       f:metadata:
<         f:annotations:
<           f:argocd.argoproj.io/tracking-id: {}
<       f:spec:
<         f:controller: {}
<     manager: argocd-controller
<     operation: Apply
<     time: "2026-02-28T10:28:17Z"
<   name: tailscale
<   resourceVersion: "543551606"
<   uid: ea912cb2-6bd8-4b0f-94b8-68b1eb2e4001
< spec:
<   controller: tailscale.com/ts-ingress

===== rbac.authorization.k8s.io/ClusterRole /tailscale-operator ======
1,111d0
< apiVersion: rbac.authorization.k8s.io/v1
< kind: ClusterRole
< metadata:
<   annotations:
<     argocd.argoproj.io/tracking-id: tailscale-operator:rbac.authorization.k8s.io/ClusterRole:tailscale-operator/tailscale-operator
<   managedFields:
<   - apiVersion: rbac.authorization.k8s.io/v1
<     fieldsType: FieldsV1
<     fieldsV1:
<       f:metadata:
<         f:annotations:
<           f:argocd.argoproj.io/tracking-id: {}
<       f:rules: {}
<     manager: argocd-controller
<     operation: Apply
<   - apiVersion: rbac.authorization.k8s.io/v1
<     fieldsType: FieldsV1
<     fieldsV1:
<       f:metadata:
<         f:annotations:
<           .: {}
<           f:argocd.argoproj.io/tracking-id: {}
<       f:rules: {}
<     manager: argocd-application-controller
<     operation: Update
<     time: "2026-02-28T10:28:12Z"
<   name: tailscale-operator
<   resourceVersion: "543551554"
<   uid: 1cdbaf79-748a-4a87-b5ca-0937e0f6d372
< rules:
< - apiGroups:
<   - ""
<   resources:
<   - events
<   - services
<   - services/status
<   verbs:
<   - create
<   - delete
<   - deletecollection
<   - get
<   - list
<   - patch
<   - update
<   - watch
< - apiGroups:
<   - networking.k8s.io
<   resources:
<   - ingresses
<   - ingresses/status
<   verbs:
<   - create
<   - delete
<   - deletecollection
<   - get
<   - list
<   - patch
<   - update
<   - watch
< - apiGroups:
<   - networking.k8s.io
<   resources:
<   - ingressclasses
<   verbs:
<   - get
<   - list
<   - watch
< - apiGroups:
<   - tailscale.com
<   resources:
<   - connectors
<   - connectors/status
<   - proxyclasses
<   - proxyclasses/status
<   - proxygroups
<   - proxygroups/status
<   verbs:
<   - get
<   - list
<   - watch
<   - update
< - apiGroups:
<   - tailscale.com
<   resources:
<   - dnsconfigs
<   - dnsconfigs/status
<   verbs:
<   - get
<   - list
<   - watch
<   - update
< - apiGroups:
<   - tailscale.com
<   resources:
<   - recorders
<   - recorders/status
<   verbs:
<   - get
<   - list
<   - watch
<   - update
< - apiGroups:
<   - apiextensions.k8s.io
<   resourceNames:
<   - servicemonitors.monitoring.coreos.com
<   resources:
<   - customresourcedefinitions
<   verbs:
<   - get
<   - list
<   - watch

===== rbac.authorization.k8s.io/ClusterRoleBinding /tailscale-operator ======
1,39d0
< apiVersion: rbac.authorization.k8s.io/v1
< kind: ClusterRoleBinding
< metadata:
<   annotations:
<     argocd.argoproj.io/tracking-id: tailscale-operator:rbac.authorization.k8s.io/ClusterRoleBinding:tailscale-operator/tailscale-operator
<   managedFields:
<   - apiVersion: rbac.authorization.k8s.io/v1
<     fieldsType: FieldsV1
<     fieldsV1:
<       f:metadata:
<         f:annotations:
<           f:argocd.argoproj.io/tracking-id: {}
<       f:roleRef: {}
<       f:subjects: {}
<     manager: argocd-controller
<     operation: Apply
<   - apiVersion: rbac.authorization.k8s.io/v1
<     fieldsType: FieldsV1
<     fieldsV1:
<       f:metadata:
<         f:annotations:
<           .: {}
<           f:argocd.argoproj.io/tracking-id: {}
<       f:roleRef: {}
<       f:subjects: {}
<     manager: argocd-application-controller
<     operation: Update
<     time: "2026-02-28T10:28:13Z"
<   name: tailscale-operator
<   resourceVersion: "543551567"
<   uid: a6dee65a-360a-4b01-9d9a-bfa5e835a49f
< roleRef:
<   apiGroup: rbac.authorization.k8s.io
<   kind: ClusterRole
<   name: tailscale-operator
< subjects:
< - kind: ServiceAccount
<   name: operator
<   namespace: tailscale-operator

===== rbac.authorization.k8s.io/Role tailscale-operator/operator ======
1,108d0
< apiVersion: rbac.authorization.k8s.io/v1
< kind: Role
< metadata:
<   annotations:
<     argocd.argoproj.io/tracking-id: tailscale-operator:rbac.authorization.k8s.io/Role:tailscale-operator/operator
<   managedFields:
<   - apiVersion: rbac.authorization.k8s.io/v1
<     fieldsType: FieldsV1
<     fieldsV1:
<       f:metadata:
<         f:annotations:
<           f:argocd.argoproj.io/tracking-id: {}
<       f:rules: {}
<     manager: argocd-controller
<     operation: Apply
<   - apiVersion: rbac.authorization.k8s.io/v1
<     fieldsType: FieldsV1
<     fieldsV1:
<       f:metadata:
<         f:annotations:
<           .: {}
<           f:argocd.argoproj.io/tracking-id: {}
<       f:rules: {}
<     manager: argocd-application-controller
<     operation: Update
<     time: "2026-02-28T10:28:14Z"
<   name: operator
<   namespace: tailscale-operator
<   resourceVersion: "543551578"
<   uid: 50211e60-9e2a-404d-bfcd-4630557948dd
< rules:
< - apiGroups:
<   - ""
<   resources:
<   - secrets
<   - serviceaccounts
<   - configmaps
<   verbs:
<   - create
<   - delete
<   - deletecollection
<   - get
<   - list
<   - patch
<   - update
<   - watch
< - apiGroups:
<   - ""
<   resources:
<   - pods
<   verbs:
<   - get
<   - list
<   - watch
<   - update
< - apiGroups:
<   - ""
<   resources:
<   - pods/status
<   verbs:
<   - update
< - apiGroups:
<   - apps
<   resources:
<   - statefulsets
<   - deployments
<   verbs:
<   - create
<   - delete
<   - deletecollection
<   - get
<   - list
<   - patch
<   - update
<   - watch
< - apiGroups:
<   - discovery.k8s.io
<   resources:
<   - endpointslices
<   verbs:
<   - get
<   - list
<   - watch
<   - create
<   - update
<   - deletecollection
< - apiGroups:
<   - rbac.authorization.k8s.io
<   resources:
<   - roles
<   - rolebindings
<   verbs:
<   - get
<   - create
<   - patch
<   - update
<   - list
<   - watch
< - apiGroups:
<   - monitoring.coreos.com
<   resources:
<   - servicemonitors
<   verbs:
<   - get
<   - list
<   - update
<   - create
<   - delete

===== rbac.authorization.k8s.io/Role tailscale-operator/proxies ======
1,52d0
< apiVersion: rbac.authorization.k8s.io/v1
< kind: Role
< metadata:
<   annotations:
<     argocd.argoproj.io/tracking-id: tailscale-operator:rbac.authorization.k8s.io/Role:tailscale-operator/proxies
<   managedFields:
<   - apiVersion: rbac.authorization.k8s.io/v1
<     fieldsType: FieldsV1
<     fieldsV1:
<       f:metadata:
<         f:annotations:
<           f:argocd.argoproj.io/tracking-id: {}
<       f:rules: {}
<     manager: argocd-controller
<     operation: Apply
<   - apiVersion: rbac.authorization.k8s.io/v1
<     fieldsType: FieldsV1
<     fieldsV1:
<       f:metadata:
<         f:annotations:
<           .: {}
<           f:argocd.argoproj.io/tracking-id: {}
<       f:rules: {}
<     manager: argocd-application-controller
<     operation: Update
<     time: "2026-02-28T10:28:14Z"
<   name: proxies
<   namespace: tailscale-operator
<   resourceVersion: "543551577"
<   uid: 5c1659cc-deb5-4e57-840a-0a3918c2ae35
< rules:
< - apiGroups:
<   - ""
<   resources:
<   - secrets
<   verbs:
<   - create
<   - delete
<   - deletecollection
<   - get
<   - list
<   - patch
<   - update
<   - watch
< - apiGroups:
<   - ""
<   resources:
<   - events
<   verbs:
<   - create
<   - patch
<   - get

===== rbac.authorization.k8s.io/RoleBinding tailscale-operator/operator ======
1,40d0
< apiVersion: rbac.authorization.k8s.io/v1
< kind: RoleBinding
< metadata:
<   annotations:
<     argocd.argoproj.io/tracking-id: tailscale-operator:rbac.authorization.k8s.io/RoleBinding:tailscale-operator/operator
<   managedFields:
<   - apiVersion: rbac.authorization.k8s.io/v1
<     fieldsType: FieldsV1
<     fieldsV1:
<       f:metadata:
<         f:annotations:
<           f:argocd.argoproj.io/tracking-id: {}
<       f:roleRef: {}
<       f:subjects: {}
<     manager: argocd-controller
<     operation: Apply
<   - apiVersion: rbac.authorization.k8s.io/v1
<     fieldsType: FieldsV1
<     fieldsV1:
<       f:metadata:
<         f:annotations:
<           .: {}
<           f:argocd.argoproj.io/tracking-id: {}
<       f:roleRef: {}
<       f:subjects: {}
<     manager: argocd-application-controller
<     operation: Update
<     time: "2026-02-28T10:28:15Z"
<   name: operator
<   namespace: tailscale-operator
<   resourceVersion: "543551592"
<   uid: f4d86ad3-adff-42ee-b214-780aa14dd53f
< roleRef:
<   apiGroup: rbac.authorization.k8s.io
<   kind: Role
<   name: operator
< subjects:
< - kind: ServiceAccount
<   name: operator
<   namespace: tailscale-operator

===== rbac.authorization.k8s.io/RoleBinding tailscale-operator/proxies ======
1,40d0
< apiVersion: rbac.authorization.k8s.io/v1
< kind: RoleBinding
< metadata:
<   annotations:
<     argocd.argoproj.io/tracking-id: tailscale-operator:rbac.authorization.k8s.io/RoleBinding:tailscale-operator/proxies
<   managedFields:
<   - apiVersion: rbac.authorization.k8s.io/v1
<     fieldsType: FieldsV1
<     fieldsV1:
<       f:metadata:
<         f:annotations:
<           f:argocd.argoproj.io/tracking-id: {}
<       f:roleRef: {}
<       f:subjects: {}
<     manager: argocd-controller
<     operation: Apply
<   - apiVersion: rbac.authorization.k8s.io/v1
<     fieldsType: FieldsV1
<     fieldsV1:
<       f:metadata:
<         f:annotations:
<           .: {}
<           f:argocd.argoproj.io/tracking-id: {}
<       f:roleRef: {}
<       f:subjects: {}
<     manager: argocd-application-controller
<     operation: Update
<     time: "2026-02-28T10:28:15Z"
<   name: proxies
<   namespace: tailscale-operator
<   resourceVersion: "543551590"
<   uid: f6b28e25-6308-4899-bb11-b00c2822f80c
< roleRef:
<   apiGroup: rbac.authorization.k8s.io
<   kind: Role
<   name: proxies
< subjects:
< - kind: ServiceAccount
<   name: proxies
<   namespace: tailscale-operator

===== rbac.authorization.k8s.io/ClusterRoleBinding /oidc-discovery ======
0a1,14
> apiVersion: rbac.authorization.k8s.io/v1
> kind: ClusterRoleBinding
> metadata:
>   annotations:
>     argocd.argoproj.io/tracking-id: tailscale-operator:rbac.authorization.k8s.io/ClusterRoleBinding:tailscale-operator/oidc-discovery
>   name: oidc-discovery
> roleRef:
>   apiGroup: rbac.authorization.k8s.io
>   kind: ClusterRole
>   name: system:service-account-issuer-discovery
> subjects:
> - apiGroup: rbac.authorization.k8s.io
>   kind: Group
>   name: system:unauthenticated
ℹ️ 上記の差分が見つかりました

💡 完全なdiffを確認するには、ローカルで argocd app diff を実行してください。

Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: a2c5551f4b

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +80 to +84
### Step 4: lolice values.yaml のプレースホルダを更新

`argoproj/tailscale-operator/helm/values.yaml` の以下を更新:

```yaml

Choose a reason for hiding this comment

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

P2 Badge WIF切替手順にoauthSecretVolume削除を含める

この手順では oauth.clientIdoauth.audience の設定だけを案内しており、同コミットの argoproj/tailscale-operator/helm/values.yaml で必須としている oauthSecretVolume の削除が明示されていません。手順どおりに実施すると OAuth Secret のマウント設定が残ったままになり、WIF へ完全に切り替わらず(CLIENT_SECRET_FILE が残る)、移行検証やロールアウト判断を誤る原因になります。

Useful? React with 👍 / 👎.

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.

2 participants