-
Notifications
You must be signed in to change notification settings - Fork 1.8k
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
RFD0185: Kubernetes Access without Certificate-based Routing #47436
RFD0185: Kubernetes Access without Certificate-based Routing #47436
Conversation
|
||
## Security Considerations | ||
|
||
### Per-session MFA |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My outstanding concern here relates to whether or not Per-Session MFA is meant to be locked to a specific target.
Today, the KubernetesCluster
attribute seemingly has the side-effect of locking Per-Session MFA certificates to a specific target cluster. Looking back to the original Per-Session MFA RFD, the design does state that that should be the case, but says that a "TargetName" attribute should be used to enforce this - which I can't see any evidence of within the codebase today.
If locking Per-Session MFA certs to a specific cluster is intended/required, then we can retain the KubernetesCluster
attribute, but make this intention more explicit by moving the code that enforces this into the authorizer rather than as part of the router/forwarder.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To close the loop here with #50567 now merged, after some discussion we decided to keep this guarantee in place with:
- returning an error if URL routing parameters attempt to override certificate parameters, to ensure session MFA certs remain bound to the cluster for which they were issued
- explicitly requiring non-empty identity routing parameters to use the path routing endpoint if an
MFAVerified
value is present on the cert. Path routing is functionally no-op due in this case to (1), but this won't force e.g. tsh to stop using the path route inkubeconfig.yaml
encode attributes of an identity - information about which cluster you wish to | ||
connect to is not an attribute of identity! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I will approve the RFD just because of this comment
```yaml | ||
apiVersion: v1 | ||
clusters: | ||
- cluster: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's important to note that this setup requires a separate cluster entry for each Kubernetes cluster. Currently, our implementation assigns one cluster per Teleport cluster rather than per Kubernetes cluster. This approach has a significant drawback: when two different Kubernetes clusters are part of the same Teleport cluster, kubectl
caches objects in the same directory .kube/cache/discovery/teleport_proxy_port
. This can lead to major issues due to version mismatches or incompatible CRDs.
The proposed solution addresses all these problems because kubectl will start caching data in .kube/cache/discovery/teleport_proxy_port/v1/teleport/base64_teleport_cluster_name/base64_kube_cluster_name
Check #12731
Kubernetes clients: | ||
|
||
- `kubectl` | ||
- Python Kubernetes SDK |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's worth checking javascript client as we have some that also use it for automation.
It would no longer be possible to track usage of Kubernetes Access for analytics | ||
purposes via the certificate generation event. However, we have other events | ||
that indicate Kubernetes Access usage (e.g an event per request), that are | ||
better suited for this purpose - so this seems acceptable. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note that when kubectl
performs discovery, it requests a single certificate but retrieves all API resource definitions. In theory, this could generate duplicate events, but Teleport disregards discovery requests for usage purposes, so nothing will change neither the metrics will be duplicated.
As for billing, since we count Kubernetes requests, this behavior won’t affect anything.
# are provided, then the output will contain the union of the results of the | ||
# selectors. | ||
selectors: | ||
- name: my-cluster |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will this generate a separate kubeconfig for each cluster, or a single configuration that includes all clusters?
I prefer the latter, but it might be worth mentioning or offering both options. We should also pay attention to context and file naming. By default, tsh
creates context entries using the format {{TeleportCluster}}-{{KubeCluster}}
, but this can be customized by providing a template with the context override flag. It would be useful to allow users to adjust these settings to customize their outputs.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah - following discussion with [CUSTOMER] - I figure it's easier to give an option between a single kubeconfig and a kubeconfig per cluster. I'm sure one you get into the thousands of clusters range, certain implementations of the Kube SDK will probably dislike the size of the config file.
By default, tsh creates context entries using the format {{TeleportCluster}}-{{KubeCluster}}, but this can be customized by providing a template with the context override flag. It would be useful to allow users to adjust these settings to customize their outputs.
This seems reasonable - we use the same context structure in tbot as well atm fwiw.
|
||
This has the following limitations: | ||
|
||
- We've already witnessed limited support for specifying SNIs in Kubernetes |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The main challenge is that by using SNI for routing and supporting kubectl
, Teleport would need to generate certificates for *.rootCluster.kube.teleportproxy.com
, as well as for leaf clusters *.leafCluster.kube.teleportproxy.com
. Over time, this approach could introduce significant issues as the system evolves. Since we must support kubectl
, the only viable solution is to send the identification via tls-server-name
.
Teleport clients would no longer need to call `GenerateUserCerts` with a | ||
`KubernetesCluster` to produce a certificate explicitly for access to | ||
Kubernetes. When producing a kubeconfig, the client should use the user's | ||
standard identity. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Beyond just routing info (which this will be superseding) we also have a certificate usage restriction for Kubernetes, which the auth middleware currently requires for anything that touches the forwarder. Do you see the usage:kube
restriction going away with this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The usage was only configured when using KubeCSR, which was deprecated several versions ago.
Furthermore, if the identity does not have a usage specified, it will bypass any usage validation checks.
teleport/lib/auth/middleware.go
Lines 664 to 673 in b71f017
// If there is any restriction on the certificate usage | |
// reject the API server request. This is done so some classes | |
// of certificates issued for kubernetes usage by proxy, can not be used | |
// against auth server. Later on we can extend more | |
// advanced cert usage, but for now this is the safest option. | |
if len(identity.Usage) != 0 && !slices.Equal(a.AcceptedUsage, identity.Usage) { | |
log.Warningf("Restricted certificate of user %q with usage %v rejected while accessing the auth endpoint with acceptable usage %v.", | |
identity.Username, identity.Usage, a.AcceptedUsage) | |
return nil, trace.AccessDenied("access denied: invalid client certificate") | |
} |
This implements path-based routing for Kubernetes clusters as described by [RFD0185]. A new prefixed path handler is added that accepts base64-encoded Teleport and Kubernetes cluster names. The request is routed to the destination Teleport cluster using these parameters instead of those embedded in the session TLS identity, and then the preexisting handlers check authorization and complete the request as usual. This removes the need for certificates to be issued per Kubernetes cluster: so long as the incoming identity is granted access to the cluster via its roles, access can succeed, and no `KubernetesCluster` attribute or cert usage restrictions are needed. [RFD0185]: #47436
* Support routing to Kubernetes clusters by request path This implements path-based routing for Kubernetes clusters as described by [RFD0185]. A new prefixed path handler is added that accepts base64-encoded Teleport and Kubernetes cluster names. The request is routed to the destination Teleport cluster using these parameters instead of those embedded in the session TLS identity, and then the preexisting handlers check authorization and complete the request as usual. This removes the need for certificates to be issued per Kubernetes cluster: so long as the incoming identity is granted access to the cluster via its roles, access can succeed, and no `KubernetesCluster` attribute or cert usage restrictions are needed. [RFD0185]: #47436 * Remove routeSourcer in favor of identity values Also: fixes various other review comments, adds comment explaining auth strategy. * Revert more dead code * Revert more unnecessary changes; validate utf8 parameters * Build fixes after merge with slog transition * Add basic tests for Kubernetes path routing * Fix imports * Check identity parameters when per session MFA is enabled Also, don't allow path parameters to override the identity, if the contains nonempty routing params. * Fix failing TestSingleCertRouting due to improper reuse of rest config * Session MFA includes role based enforcement; added more test cases * Don't allow route params to be overwritten if MFAVerified is set * Code review feedback Deep clone the request and explicitly clear RawPath.
* Support routing to Kubernetes clusters by request path This implements path-based routing for Kubernetes clusters as described by [RFD0185]. A new prefixed path handler is added that accepts base64-encoded Teleport and Kubernetes cluster names. The request is routed to the destination Teleport cluster using these parameters instead of those embedded in the session TLS identity, and then the preexisting handlers check authorization and complete the request as usual. This removes the need for certificates to be issued per Kubernetes cluster: so long as the incoming identity is granted access to the cluster via its roles, access can succeed, and no `KubernetesCluster` attribute or cert usage restrictions are needed. [RFD0185]: #47436 * Remove routeSourcer in favor of identity values Also: fixes various other review comments, adds comment explaining auth strategy. * Revert more dead code * Revert more unnecessary changes; validate utf8 parameters * Build fixes after merge with slog transition * Add basic tests for Kubernetes path routing * Fix imports * Check identity parameters when per session MFA is enabled Also, don't allow path parameters to override the identity, if the contains nonempty routing params. * Fix failing TestSingleCertRouting due to improper reuse of rest config * Session MFA includes role based enforcement; added more test cases * Don't allow route params to be overwritten if MFAVerified is set * Code review feedback Deep clone the request and explicitly clear RawPath.
Just read this following Tim's status update and it all sounds really nice. Being able to weave this into kube APIs is *chef's kiss*. If only this was possible for TCP apps. 🥲 |
This is possible to expand to tcp apps using SNI |
…#51534) * Support routing to Kubernetes clusters by request path (#50567) * Support routing to Kubernetes clusters by request path This implements path-based routing for Kubernetes clusters as described by [RFD0185]. A new prefixed path handler is added that accepts base64-encoded Teleport and Kubernetes cluster names. The request is routed to the destination Teleport cluster using these parameters instead of those embedded in the session TLS identity, and then the preexisting handlers check authorization and complete the request as usual. This removes the need for certificates to be issued per Kubernetes cluster: so long as the incoming identity is granted access to the cluster via its roles, access can succeed, and no `KubernetesCluster` attribute or cert usage restrictions are needed. [RFD0185]: #47436 * Remove routeSourcer in favor of identity values Also: fixes various other review comments, adds comment explaining auth strategy. * Revert more dead code * Revert more unnecessary changes; validate utf8 parameters * Build fixes after merge with slog transition * Add basic tests for Kubernetes path routing * Fix imports * Check identity parameters when per session MFA is enabled Also, don't allow path parameters to override the identity, if the contains nonempty routing params. * Fix failing TestSingleCertRouting due to improper reuse of rest config * Session MFA includes role based enforcement; added more test cases * Don't allow route params to be overwritten if MFAVerified is set * Code review feedback Deep clone the request and explicitly clear RawPath. * Undo slog for v17 compatibility
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@strideynet can we merge this?
Needs one more review by the looks of it, then I'll merge. |
Part of #40405
Proposal to replace Certificate-attribute based routing in Kubernetes Access for performance and usability improvements. There's a very rough patch of what this change would look like at 47b55a8 courtesy of @tigrato