Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

cmd/k8s-operator,k8s-operator: allow the operator to deploy exit nodes via Connector custom resource #10724

Merged
merged 4 commits into from
Jan 9, 2024

Conversation

irbekrm
Copy link
Contributor

@irbekrm irbekrm commented Jan 3, 2024

Context

This PR adds a new .spec.exitNode field to the Connector custom resource that allows users to configure the Tailscale node created for the Connector to act as an exit node.

It also redesigns the API:

  • there is a 1<->1 connection between a Connector and a Tailscale node
  • a Tailscale node created for a Connector can be an exit node, a subnet router or both (and in future also an app connector)
apiVersion: tailscale.com/v1alpha1
kind: Connector
metadata:
  name: prod
spec:
  tags:
  - "tag:prod"
  hostname: ts-prod
  subnetRouter:
    advertiseRoutes:
    - "10.40.0.0/14"
    - "192.168.0.0/14"
  exitNode: true

(For the above Connector the operator configures one Tailscale node that acts as an exit node and advertises routes 10.40.0.0/14, 192.168.0.0/14)

UI

  • A Connector that acts as both exit node and advertises two routes:
$ kubectl get connector
NAME   SUBNETROUTES                  ISEXITNODE   STATUS
prod   10.40.0.0/14,192.168.0.0/14   true         ConnectorCreated
  • A Connector that only advertises routes:
$ kubectl get connector
NAME   SUBNETROUTES                  ISEXITNODE   STATUS
prod   10.40.0.0/14,192.168.0.0/14   false        ConnectorCreated
  • A Connector that is only an exit node:
$ kubectl get connector
NAME   SUBNETROUTES   ISEXITNODE   STATUS
prod                  true         ConnectorCreated

Notes:

  • (same as with other resources managed by the operator) tags currently cannot be updated post-creation
  • (same as with other resources managed by the operator) multiple replicas are not supported
  • I have tested this on GKE (with ubuntu nodes) and using a linux client to reach out to internet via the exit node and access Pods via the subnet router.

See details below for how to try this out:

  • create an operator image from this PR

  • apply the CRD kubectl apply -f ./cmd/k8s-operator/deploy/crds/tailscale.com_connectors.yaml

  • install the operator with the custom image and connector functionality enabled i.e helm install operator tailscale/tailscale-dev --set enableConnector=true.... Ensure that you are using unstable-v1.57.42 or newer

  • (if using the example manifest below) update ACL tags to allow the operator to own tag:prod and to allow tag:prod to auto-approve exit nodes and the desired subnet routes

  • apply a Connector CR, such as the example one added in this PR- kubectl apply -f ./cmd/k8s-operator/deploy/examples/connector.yaml

  • verify ready Connector status and that the subnet router and exit node are functioning

Updates #10708

@irbekrm irbekrm requested review from knyar and maisem January 3, 2024 14:33
@maisem

This comment was marked as outdated.

cmd/k8s-operator/connector.go Outdated Show resolved Hide resolved
@irbekrm

This comment was marked as outdated.

@irbekrm irbekrm marked this pull request as draft January 3, 2024 15:31
@irbekrm

This comment was marked as outdated.

@irbekrm

This comment was marked as outdated.

@irbekrm irbekrm force-pushed the irbekrm/exit_node branch 5 times, most recently from deca537 to 77817ae Compare January 7, 2024 21:24
cmd/k8s-operator/sts.go Fixed Show fixed Hide fixed
cmd/k8s-operator/sts.go Fixed Show fixed Hide fixed
Comment on lines 422 to 467
} else if len(sts.Routes) > 0 {
container.Env = append(container.Env, corev1.EnvVar{
Name: "TS_ROUTES",
Value: sts.Routes,
})

}
if a.tsFirewallMode != "" {
container.Env = append(container.Env, corev1.EnvVar{
Name: "TS_DEBUG_FIREWALL_MODE",
Value: a.tsFirewallMode,
},
)
}
ss.ObjectMeta = metav1.ObjectMeta{
Name: headlessSvc.Name,
Namespace: a.operatorNamespace,
Labels: sts.ChildResourceLabels,
}
ss.Spec.ServiceName = headlessSvc.Name
ss.Spec.Selector = &metav1.LabelSelector{
MatchLabels: map[string]string{
"app": sts.ParentResourceUID,
},
}

// containerboot currently doesn't have a way to re-read the hostname/ip as
// it is passed via an environment variable. So we need to restart the
// container when the value changes. We do this by adding an annotation to
// the pod template that contains the last value we set.
ss.Spec.Template.Annotations = map[string]string{
podAnnotationLastSetHostname: sts.Hostname,
}
if sts.ClusterTargetIP != "" {
ss.Spec.Template.Annotations[podAnnotationLastSetClusterIP] = sts.ClusterTargetIP
}
if sts.TailnetTargetIP != "" {
ss.Spec.Template.Annotations[podAnnotationLastSetTailnetTargetIP] = sts.TailnetTargetIP
}
if sts.TailnetTargetFQDN != "" {
ss.Spec.Template.Annotations[podAnnotationLastSetTailnetTargetFQDN] = sts.TailnetTargetFQDN
}
ss.Spec.Template.Labels = map[string]string{
"app": sts.ParentResourceUID,
}
ss.Spec.Template.Spec.PriorityClassName = a.proxyPriorityClassName
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This change is moving existing STS configuration around so that it is ordered by type of configuration options.

@@ -0,0 +1,411 @@
// Copyright (c) Tailscale Inc & AUTHORS
Copy link
Contributor Author

@irbekrm irbekrm Jan 8, 2024

Choose a reason for hiding this comment

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

This new file contains utils shared between ingress/egress tests and connector tests, this is partially just moved from operator_test.go, connector_test.go

@irbekrm irbekrm force-pushed the irbekrm/exit_node branch 2 times, most recently from b9fa612 to 0d1e750 Compare January 8, 2024 16:29
…ine an exit node via Connector CR

Make it possible to define an exit node to be deployed to a Kubernetes cluster
via Connector Custom resource.

Also changes to Connector API so that one Connector corresponds
to one Tailnet node that can be either a subnet router or an exit
node or both.

Updates #10708

Signed-off-by: Irbe Krumina <irbe@tailscale.com>
The Kubernetes operator parses Connector custom resource and,
if .spec.isExitNode is set, configures that Tailscale node deployed
for that connector as an exit node.

Signed-off-by: Irbe Krumina <irbe@tailscale.com>
…exit node

Signed-off-by: Irbe Krumina <irbe@tailscale.com>
@irbekrm irbekrm marked this pull request as ready for review January 8, 2024 16:52
cmd/k8s-operator/connector.go Outdated Show resolved Hide resolved
cmd/k8s-operator/connector.go Outdated Show resolved Hide resolved
cmd/k8s-operator/connector.go Outdated Show resolved Hide resolved
cmd/k8s-operator/sts.go Show resolved Hide resolved
cmd/k8s-operator/sts.go Outdated Show resolved Hide resolved
k8s-operator/apis/v1alpha1/types_connector.go Outdated Show resolved Hide resolved
k8s-operator/apis/v1alpha1/types_connector.go Outdated Show resolved Hide resolved
k8s-operator/apis/v1alpha1/types_connector.go Show resolved Hide resolved
cmd/k8s-operator/connector.go Outdated Show resolved Hide resolved
cmd/k8s-operator/sts.go Outdated Show resolved Hide resolved
@irbekrm
Copy link
Contributor Author

irbekrm commented Jan 8, 2024

Thank you for the review @knyar , I have now addressed all the comments PTAL

cmd/k8s-operator/connector.go Outdated Show resolved Hide resolved
cmd/k8s-operator/connector.go Show resolved Hide resolved
cmd/k8s-operator/connector.go Outdated Show resolved Hide resolved
cmd/k8s-operator/sts.go Outdated Show resolved Hide resolved
cmd/k8s-operator/sts.go Outdated Show resolved Hide resolved
cmd/k8s-operator/sts.go Outdated Show resolved Hide resolved
cmd/k8s-operator/connector.go Outdated Show resolved Hide resolved
cmd/k8s-operator/connector.go Outdated Show resolved Hide resolved
cmd/k8s-operator/connector.go Show resolved Hide resolved
cmd/k8s-operator/connector.go Outdated Show resolved Hide resolved
cmd/k8s-operator/connector.go Outdated Show resolved Hide resolved
cmd/k8s-operator/sts.go Outdated Show resolved Hide resolved
Signed-off-by: Irbe Krumina <irbe@tailscale.com>
Co-authored-by: Anton Tolchanov <anton@tailscale.com>
Signed-off-by: Irbe Krumina <irbe@tailscale.com>
@irbekrm irbekrm merged commit 05093ea into main Jan 9, 2024
46 checks passed
@irbekrm irbekrm deleted the irbekrm/exit_node branch January 9, 2024 14:13
@btobolaski
Copy link

I'm not sure this is the appropriate place for this given that it has been merged. I'm trying to utilize this functionality as it would greatly simplify something I'm currently attempting to do. I'm on the specified unstable-v1.57.42, I tried modifying the example and eventually just deployed the example as is and I get continuous errors during reconciliation rather than the connector being configured. The error is failed to add finalizer: Connector.tailscale.com \"prod\" is invalid. The full log of a reconciliation run are here.

@irbekrm
Copy link
Contributor Author

irbekrm commented Jan 10, 2024

Hi @btobolaski thanks for trying this out!

unstable-1.57.42 tag does not yet have contents of this PR and we have changed the CRD structure since unstable-1.57.42, I suspect that the error is because you have the CRD installed from this PR, but the operator version that tries to apply a patch with contents built against a different version.

I just pushed unstable-v1.57.65 tag that has the contents of this PR if you'd like to try it. You might want to delete the old Connector resource before upgrade.

(Just for the record- the Connector CRD has not been released yet, which is why we allowed a breaking change like this. Any changes made post 1.58 release should be backwards compatible)

@btobolaski
Copy link

That was it, thank you. Everything appears to be working as expected.

kari-ts pushed a commit that referenced this pull request Jan 12, 2024
…s via Connector custom resource (#10724)

cmd/k8s-operator/deploy/crds,k8s-operator/apis/v1alpha1: allow to define an exit node via Connector CR.

Make it possible to define an exit node to be deployed to a Kubernetes cluster
via Connector Custom resource.

Also changes to Connector API so that one Connector corresponds
to one Tailnet node that can be either a subnet router or an exit
node or both.

The Kubernetes operator parses Connector custom resource and,
if .spec.isExitNode is set, configures that Tailscale node deployed
for that connector as an exit node.

Signed-off-by: Irbe Krumina <irbe@tailscale.com>
Co-authored-by: Anton Tolchanov <anton@tailscale.com>
Asutorufa pushed a commit to Asutorufa/tailscale that referenced this pull request Jan 19, 2024
…s via Connector custom resource (tailscale#10724)

cmd/k8s-operator/deploy/crds,k8s-operator/apis/v1alpha1: allow to define an exit node via Connector CR.

Make it possible to define an exit node to be deployed to a Kubernetes cluster
via Connector Custom resource.

Also changes to Connector API so that one Connector corresponds
to one Tailnet node that can be either a subnet router or an exit
node or both.

The Kubernetes operator parses Connector custom resource and,
if .spec.isExitNode is set, configures that Tailscale node deployed
for that connector as an exit node.

Signed-off-by: Irbe Krumina <irbe@tailscale.com>
Co-authored-by: Anton Tolchanov <anton@tailscale.com>
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.

None yet

4 participants