Skip to content

Commit f0aa298

Browse files
committed
feat(kubernetes): access control round tripper
Signed-off-by: Marc Nuri <[email protected]>
1 parent 87351bb commit f0aa298

File tree

9 files changed

+378
-189
lines changed

9 files changed

+378
-189
lines changed

pkg/kubernetes/accesscontrol_restclient.go

Lines changed: 0 additions & 61 deletions
This file was deleted.

pkg/kubernetes/accesscontrol_restmapper.go

Lines changed: 0 additions & 80 deletions
This file was deleted.
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
package kubernetes
2+
3+
import (
4+
"fmt"
5+
"net/http"
6+
"strings"
7+
8+
"github.com/containers/kubernetes-mcp-server/pkg/config"
9+
"k8s.io/apimachinery/pkg/api/meta"
10+
"k8s.io/apimachinery/pkg/runtime/schema"
11+
)
12+
13+
type AccessControlRoundTripper struct {
14+
delegate http.RoundTripper
15+
staticConfig *config.StaticConfig
16+
restMapper meta.RESTMapper
17+
}
18+
19+
func (rt *AccessControlRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) {
20+
gvr, ok := parseURLToGVR(req.URL.Path)
21+
// Not an API resource request, just pass through
22+
if !ok {
23+
return rt.delegate.RoundTrip(req)
24+
}
25+
26+
gvk, err := rt.restMapper.KindFor(gvr)
27+
if err != nil {
28+
return nil, fmt.Errorf("failed to make request: AccessControlRoundTripper failed to get kind for gvr %v: %w", gvr, err)
29+
}
30+
if !isAllowed(rt.staticConfig, &gvk) {
31+
return nil, isNotAllowedError(&gvk)
32+
}
33+
34+
return rt.delegate.RoundTrip(req)
35+
}
36+
37+
func parseURLToGVR(path string) (gvr schema.GroupVersionResource, ok bool) {
38+
parts := strings.Split(strings.Trim(path, "/"), "/")
39+
40+
gvr = schema.GroupVersionResource{}
41+
switch parts[0] {
42+
case "api":
43+
// /api or /api/v1 are discovery endpoints
44+
if len(parts) < 3 {
45+
return
46+
}
47+
gvr.Group = ""
48+
gvr.Version = parts[1]
49+
if parts[2] == "namespaces" && len(parts) > 4 {
50+
gvr.Resource = parts[4]
51+
} else {
52+
gvr.Resource = parts[2]
53+
}
54+
case "apis":
55+
// /apis, /apis/apps, or /apis/apps/v1 are discovery endpoints
56+
if len(parts) < 4 {
57+
return
58+
}
59+
gvr.Group = parts[1]
60+
gvr.Version = parts[2]
61+
if parts[3] == "namespaces" && len(parts) > 5 {
62+
gvr.Resource = parts[5]
63+
} else {
64+
gvr.Resource = parts[3]
65+
}
66+
default:
67+
return
68+
}
69+
return gvr, true
70+
}

0 commit comments

Comments
 (0)