-
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
Support routing to Kubernetes clusters by request path #50567
base: master
Are you sure you want to change the base?
Conversation
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
Outstanding TODOs:
|
@@ -342,6 +342,11 @@ func NewForwarder(cfg ForwarderConfig) (*Forwarder, error) { | |||
|
|||
router.GET("/api/:ver/teleport/join/:session", fwd.withAuthPassthrough(fwd.join)) | |||
|
|||
path := fmt.Sprintf("/v1/teleport/:%s/:%s/*path", paramTeleportCluster, paramKubernetesCluster) | |||
for _, method := range allHTTPMethods() { | |||
router.Handle(method, path, fwd.withAuthPassthrough(fwd.singleCertHandler, withRouteFromPath())) |
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.
As a note, compared to @tigrato's PoC I had to adapt withAuthPassthrough()
to support path routing as well, since it calls f.authenticate()
which requires the route info. I'm not sure if anything's changed since the PoC or if I missed something else, but that change seemed to be necessary.
Hopefully my route sourcing implementation is sane 😅
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.
Do we need to authenticate the request given that we will authenticate it once we rewrite the handler?
@@ -342,6 +342,11 @@ func NewForwarder(cfg ForwarderConfig) (*Forwarder, error) { | |||
|
|||
router.GET("/api/:ver/teleport/join/:session", fwd.withAuthPassthrough(fwd.join)) | |||
|
|||
path := fmt.Sprintf("/v1/teleport/:%s/:%s/*path", paramTeleportCluster, paramKubernetesCluster) |
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.
specifying the path ends up being way better in terms of readability instead of using fmt.Sprintf
@@ -342,6 +342,11 @@ func NewForwarder(cfg ForwarderConfig) (*Forwarder, error) { | |||
|
|||
router.GET("/api/:ver/teleport/join/:session", fwd.withAuthPassthrough(fwd.join)) | |||
|
|||
path := fmt.Sprintf("/v1/teleport/:%s/:%s/*path", paramTeleportCluster, paramKubernetesCluster) | |||
for _, method := range allHTTPMethods() { | |||
router.Handle(method, path, fwd.withAuthPassthrough(fwd.singleCertHandler, withRouteFromPath())) |
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.
Do we need to authenticate the request given that we will authenticate it once we rewrite the handler?
@@ -520,7 +525,7 @@ type handlerWithAuthFuncStd func(ctx *authContext, w http.ResponseWriter, r *htt | |||
const accessDeniedMsg = "[00] access denied" | |||
|
|||
// authenticate function authenticates request | |||
func (f *Forwarder) authenticate(req *http.Request) (*authContext, error) { | |||
func (f *Forwarder) authenticate(req *http.Request, params httprouter.Params, routeSourcer routeSourcer) (*authContext, error) { |
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 don't fully understand why you need to pass the params/route sourcer here.
Given that singleCertHandler
already defines the
o.Identity.RouteToCluster = teleportCluster
o.Identity.KubernetesCluster = kubeCluster
Do we ned to have a special case for route sourcer? We can always retrieve it from identity
return "", "", trace.Wrap(err) | ||
} | ||
|
||
// TODO: do we care to otherwise validate these results before casting |
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, I think it would be better anw
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.Fixes #40405