Skip to content

Commit 4967195

Browse files
fix: resoultion of core resources and rest-mapper (#12)
* fix(handler): enhance logging for resource attributes and GVK retrieval - Improved logging structure by adding child loggers for resource attributes and cluster name. - Updated error logging to include GVR details when fetching GVK. - Changed log message for ruleless mode to clarify its purpose. - Ensured proper handling of empty resource group by defaulting to "core". * docs(contributing): add debugging instructions for telepresence with kind cluster - Included steps for installing Telepresence * feat: change mapperProvider behaviour to allow for all resource identification * fix(handler): correct group handling for resource attributes - Ensure default group is set to "core" when not specified in resource attributes. - Update object type formatting to use the correct group value. - Refactor code for clarity and maintainability. --------- Co-authored-by: aaronschweig <[email protected]>
1 parent 7591ee6 commit 4967195

File tree

6 files changed

+185
-36
lines changed

6 files changed

+185
-36
lines changed

CONTRIBUTING.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,15 @@ task mockery
2929
```
3030
P.S. If you have golang installed, it automatically installs the mockery binary in `golang-commons/bin` directory.
3131

32+
33+
## Debugging using telepresence against local kind cluster
34+
35+
- Install Telepresence as outlined in their documentation [link](https://telepresence.io/docs/quick-start)
36+
- Point your kubeconfig against the local kind cluster
37+
- Start the webhook locally using the kcp kubeconfig from the kind cluster. you may need to adjust the domain to (kcp.api.portal.dev.local:8443)
38+
- Connect telepresense to the openmfp-system namespace: `telepresence connect -n openmfp-system`
39+
- Start intercepting traffic to the webhook using: `telepresence intercept rebac-authz-webhook --port 9443:9443`
40+
3241
## Issues
3342
We use GitHub issues to track bugs. Please ensure your description is
3443
clear and includes sufficient instructions to reproduce the issue.

cmd/serve.go

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import (
1515
"k8s.io/apimachinery/pkg/runtime"
1616
"k8s.io/client-go/rest"
1717
ctrl "sigs.k8s.io/controller-runtime"
18+
"sigs.k8s.io/controller-runtime/pkg/cache"
1819
"sigs.k8s.io/controller-runtime/pkg/healthz"
1920
metricsserver "sigs.k8s.io/controller-runtime/pkg/metrics/server"
2021
"sigs.k8s.io/controller-runtime/pkg/webhook"
@@ -27,6 +28,7 @@ import (
2728
"github.com/platform-mesh/rebac-authz-webhook/pkg/client"
2829
"github.com/platform-mesh/rebac-authz-webhook/pkg/config"
2930
"github.com/platform-mesh/rebac-authz-webhook/pkg/handler"
31+
"github.com/platform-mesh/rebac-authz-webhook/pkg/mapperprovider"
3032
)
3133

3234
var (
@@ -56,7 +58,9 @@ func serve() { // coverage-ignore
5658
return otelhttp.NewTransport(rt)
5759
})
5860

59-
mgr, provider := initializeMultiClusterManager(ctx, restCfg, log, serverCfg, defaultCfg)
61+
mps := mapperprovider.New()
62+
63+
mgr, provider := initializeMultiClusterManager(ctx, restCfg, log, serverCfg, defaultCfg, mps)
6064
fga := client.MustCreateInClusterClient(serverCfg.OpenFGA.Addr)
6165

6266
kcpScheme := runtime.NewScheme()
@@ -66,7 +70,7 @@ func serve() { // coverage-ignore
6670
srv := mgr.GetWebhookServer()
6771
cmw := &ContextMiddleware{Logger: log}
6872

69-
authHandler, err := handler.NewAuthorizationHandler(fga, mgr, serverCfg.Kcp.AccountInfoName)
73+
authHandler, err := handler.NewAuthorizationHandler(fga, mgr, serverCfg.Kcp.AccountInfoName, mps)
7074
if err != nil {
7175
log.Fatal().Err(err).Msg("could not create authorization handler")
7276
}
@@ -93,7 +97,7 @@ func serve() { // coverage-ignore
9397

9498
}
9599

96-
func initializeMultiClusterManager(ctx context.Context, restCfg *rest.Config, log *logger.Logger, serviceCfg config.Config, defaultConfig *commonconfig.CommonServiceConfig) (mcmanager.Manager, *apiexport.Provider) {
100+
func initializeMultiClusterManager(ctx context.Context, restCfg *rest.Config, log *logger.Logger, serviceCfg config.Config, defaultConfig *commonconfig.CommonServiceConfig, mps *mapperprovider.MapperProviders) (mcmanager.Manager, *apiexport.Provider) {
97101
log.Info().Msg("Initializing multicluster manager")
98102
kubeconfigPath := serviceCfg.Kcp.KubeconfigPath
99103
kcpCfg, err := clientcmd.BuildConfigFromFlags("", kubeconfigPath)
@@ -108,9 +112,22 @@ func initializeMultiClusterManager(ctx context.Context, restCfg *rest.Config, lo
108112
kcpCfg.Host = serverCfg.Kcp.ClusterURL
109113
}
110114

111-
provider, err := apiexport.New(kcpCfg, apiexport.Options{
115+
wildcardCache, err := apiexport.NewWildcardCache(kcpCfg, cache.Options{
112116
Scheme: scheme,
113117
})
118+
if err != nil {
119+
log.Fatal().Err(err).Msg("unable to create wildcard cache")
120+
}
121+
122+
err = mapperprovider.Run(ctx, kcpCfg, mps, wildcardCache, log)
123+
if err != nil {
124+
log.Fatal().Err(err).Msg("unable to run mapper provider")
125+
}
126+
127+
provider, err := apiexport.New(kcpCfg, apiexport.Options{
128+
WildcardCache: wildcardCache,
129+
Scheme: scheme,
130+
})
114131
if err != nil {
115132
log.Fatal().Err(err).Msg("unable to construct cluster provider")
116133
}

pkg/handler/handler.go

Lines changed: 22 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99
"strings"
1010
"time"
1111

12+
"github.com/kcp-dev/logicalcluster/v3"
1213
openfgav1 "github.com/openfga/api/proto/openfga/v1"
1314
corev1alpha1 "github.com/platform-mesh/account-operator/api/v1alpha1"
1415
"github.com/prometheus/client_golang/prometheus"
@@ -20,13 +21,15 @@ import (
2021

2122
"github.com/platform-mesh/golang-commons/logger"
2223

24+
"github.com/platform-mesh/rebac-authz-webhook/pkg/mapperprovider"
2325
"github.com/platform-mesh/rebac-authz-webhook/pkg/util"
2426
)
2527

2628
type AuthorizationHandler struct {
2729
fga openfgav1.OpenFGAServiceClient
2830
accountInfoName string
2931
mgr mcmanager.Manager
32+
mps *mapperprovider.MapperProviders
3033
}
3134

3235
var (
@@ -37,12 +40,13 @@ var (
3740
})
3841
)
3942

40-
func NewAuthorizationHandler(fga openfgav1.OpenFGAServiceClient, mgr mcmanager.Manager, accountInfoName string) (*AuthorizationHandler, error) {
43+
func NewAuthorizationHandler(fga openfgav1.OpenFGAServiceClient, mgr mcmanager.Manager, accountInfoName string, mps *mapperprovider.MapperProviders) (*AuthorizationHandler, error) {
4144

4245
return &AuthorizationHandler{
4346
fga: fga,
4447
accountInfoName: accountInfoName,
4548
mgr: mgr,
49+
mps: mps,
4650
}, nil
4751
}
4852

@@ -116,6 +120,12 @@ func (a *AuthorizationHandler) ServeHTTP(w http.ResponseWriter, r *http.Request)
116120
return
117121
}
118122

123+
log = log.ChildLogger("resourceAttributes", sar.Spec.ResourceAttributes.String()).
124+
ChildLogger("group", sar.Spec.ResourceAttributes.Group).
125+
ChildLogger("resource", sar.Spec.ResourceAttributes.Resource).
126+
ChildLogger("subresource", sar.Spec.ResourceAttributes.Subresource).
127+
ChildLogger("verb", sar.Spec.ResourceAttributes.Verb)
128+
119129
log.Debug().Str("sar", fmt.Sprintf("%+v", sar)).Msg("Received SubjectAccessReview")
120130

121131
// For resource attributes, we need to get the store ID
@@ -126,12 +136,6 @@ func (a *AuthorizationHandler) ServeHTTP(w http.ResponseWriter, r *http.Request)
126136
return
127137
}
128138

129-
log = log.ChildLogger("resourceAttributes", sar.Spec.ResourceAttributes.String()).
130-
ChildLogger("group", sar.Spec.ResourceAttributes.Group).
131-
ChildLogger("resource", sar.Spec.ResourceAttributes.Resource).
132-
ChildLogger("subresource", sar.Spec.ResourceAttributes.Subresource).
133-
ChildLogger("verb", sar.Spec.ResourceAttributes.Verb)
134-
135139
group := util.CapGroupToRelationLength(sar, 50)
136140
group = strings.ReplaceAll(group, ".", "_")
137141
relation := sar.Spec.ResourceAttributes.Verb
@@ -142,34 +146,30 @@ func (a *AuthorizationHandler) ServeHTTP(w http.ResponseWriter, r *http.Request)
142146
clusterName = clusterNames[0]
143147
}
144148
}
149+
log = log.ChildLogger("clusterName", clusterName)
145150

146151
var namespaced bool
147152
var gvk schema.GroupVersionKind
148153

149-
cluster, err := a.mgr.GetCluster(r.Context(), clusterName)
150-
if err != nil {
151-
log.Error().Err(err).Str("cluster", clusterName).Msg("error getting cluster")
152-
noOpinion(w, sar)
153-
return
154-
}
155-
156-
restMapper := cluster.GetRESTMapper()
157-
if err != nil {
154+
restMapper, ok := a.mps.GetMapper(logicalcluster.Name(clusterName))
155+
if !ok {
158156
log.Error().Err(err).Msg("error getting provider")
159157
noOpinion(w, sar)
160158
return
161159
}
162160

163-
gvk, err = restMapper.KindFor(schema.GroupVersionResource{
161+
gvr := schema.GroupVersionResource{
164162
Group: sar.Spec.ResourceAttributes.Group,
165163
Resource: sar.Spec.ResourceAttributes.Resource,
166164
Version: sar.Spec.ResourceAttributes.Version,
167-
})
165+
}
166+
gvk, err = restMapper.KindFor(gvr)
168167
if err != nil {
169-
log.Error().Err(err).Msg("error getting GVK")
168+
log.Error().Err(err).Str("gvr", fmt.Sprintf("%+v", gvr)).Msg("error getting GVK")
170169
noOpinion(w, sar)
171170
return
172171
}
172+
log.Debug().Str("gvr", fmt.Sprintf("%+v", gvr)).Str("gvk", fmt.Sprintf("%+v", gvk)).Msg("Got GVK")
173173

174174
namespaced, err = apiutil.IsGVKNamespaced(gvk, restMapper)
175175
if err != nil {
@@ -178,15 +178,14 @@ func (a *AuthorizationHandler) ServeHTTP(w http.ResponseWriter, r *http.Request)
178178
return
179179
}
180180

181-
groupForType := strings.ReplaceAll(sar.Spec.ResourceAttributes.Group, ".", "_")
182181
resourceType := sar.Spec.ResourceAttributes.Resource
183182

184183
if singularResource, err := restMapper.ResourceSingularizer(sar.Spec.ResourceAttributes.Resource); err == nil {
185184
resourceType = singularResource
186185
log.Debug().Str("resource", sar.Spec.ResourceAttributes.Resource).Str("singular", resourceType).Msg("Converted resource to singular form")
187186
}
188187

189-
objectType := fmt.Sprintf("%s_%s", groupForType, resourceType)
188+
objectType := fmt.Sprintf("%s_%s", group, resourceType)
190189

191190
longestObjectType := fmt.Sprintf("create_%ss", objectType)
192191
if len(longestObjectType) > 50 {
@@ -233,7 +232,7 @@ func (a *AuthorizationHandler) ServeHTTP(w http.ResponseWriter, r *http.Request)
233232
}
234233
}
235234

236-
log.Debug().Str("object", object).Str("relation", relation).Any("contextualTuples", contextualTuples).Msg("ruleless mode, using contextual tuples")
235+
log.Debug().Str("object", object).Str("relation", relation).Any("contextualTuples", contextualTuples).Msg("check call elements")
237236

238237
if a.fga == nil {
239238
log.Warn().Msg("FGA client is nil, returning no opinion")
@@ -260,7 +259,7 @@ func (a *AuthorizationHandler) ServeHTTP(w http.ResponseWriter, r *http.Request)
260259
noOpinion(w, sar)
261260
return
262261
}
263-
log.Info().Bool("allowed", res.Allowed).Str("user", sar.Spec.User).Str("object", object).Str("relation", relation).Msg("sar response")
262+
log.Info().Str("allowed", fmt.Sprintf("%t", res.Allowed)).Str("user", sar.Spec.User).Str("object", object).Str("relation", relation).Msg("sar response")
264263
if !res.Allowed {
265264
noOpinion(w, sar)
266265
return

pkg/handler/handler_test.go

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,7 @@ func TestInvalidStoreOperations(t *testing.T) {
142142
assert.NoError(t, err)
143143

144144
mockManager := createSimpleMockManager()
145-
handler, err := handler.NewAuthorizationHandler(nil, mockManager, "account")
145+
handler, err := handler.NewAuthorizationHandler(nil, mockManager, "account", nil)
146146
assert.NoError(t, err)
147147

148148
recorder := httptest.NewRecorder()
@@ -208,7 +208,7 @@ func TestAuthorizationHandlerWithFGA(t *testing.T) {
208208
}
209209

210210
mockManager := createSimpleMockManager()
211-
handler, err := handler.NewAuthorizationHandler(mockFGAClient, mockManager, "account")
211+
handler, err := handler.NewAuthorizationHandler(mockFGAClient, mockManager, "account", nil)
212212
assert.NoError(t, err)
213213

214214
recorder := httptest.NewRecorder()
@@ -232,7 +232,7 @@ func TestAuthorizationHandler(t *testing.T) {
232232
assert.NoError(t, err)
233233

234234
mockManager := createSimpleMockManager()
235-
handler, err := handler.NewAuthorizationHandler(nil, mockManager, "account")
235+
handler, err := handler.NewAuthorizationHandler(nil, mockManager, "account", nil)
236236
assert.NoError(t, err)
237237

238238
recorder := httptest.NewRecorder()
@@ -245,15 +245,15 @@ func TestAuthorizationHandler(t *testing.T) {
245245
func TestNewAuthorizationHandler(t *testing.T) {
246246
t.Run("should succeed with valid parameters", func(t *testing.T) {
247247
mockManager := createSimpleMockManager()
248-
handler, err := handler.NewAuthorizationHandler(nil, mockManager, "account")
248+
handler, err := handler.NewAuthorizationHandler(nil, mockManager, "account", nil)
249249
assert.NoError(t, err)
250250
assert.NotNil(t, handler)
251251
})
252252

253253
t.Run("should succeed with FGA client", func(t *testing.T) {
254254
mockFGAClient := mocks.NewOpenFGAServiceClient(t)
255255
mockManager := createSimpleMockManager()
256-
handler, err := handler.NewAuthorizationHandler(mockFGAClient, mockManager, "account")
256+
handler, err := handler.NewAuthorizationHandler(mockFGAClient, mockManager, "account", nil)
257257
assert.NoError(t, err)
258258
assert.NotNil(t, handler)
259259
})
@@ -282,7 +282,7 @@ func TestNonResourceAttributes(t *testing.T) {
282282
assert.NoError(t, err)
283283

284284
mockManager := createSimpleMockManager()
285-
handler, err := handler.NewAuthorizationHandler(nil, mockManager, "account")
285+
handler, err := handler.NewAuthorizationHandler(nil, mockManager, "account", nil)
286286
assert.NoError(t, err)
287287

288288
recorder := httptest.NewRecorder()
@@ -319,7 +319,7 @@ func TestNonResourceAttributes(t *testing.T) {
319319
assert.NoError(t, err)
320320

321321
mockManager := createSimpleMockManager()
322-
handler, err := handler.NewAuthorizationHandler(nil, mockManager, "account")
322+
handler, err := handler.NewAuthorizationHandler(nil, mockManager, "account", nil)
323323
assert.NoError(t, err)
324324

325325
recorder := httptest.NewRecorder()
@@ -363,7 +363,7 @@ func TestMultiClusterFunctionality(t *testing.T) {
363363
assert.NoError(t, err)
364364

365365
mockManager := createSimpleMockManager()
366-
handler, err := handler.NewAuthorizationHandler(nil, mockManager, "account")
366+
handler, err := handler.NewAuthorizationHandler(nil, mockManager, "account", nil)
367367
assert.NoError(t, err)
368368

369369
recorder := httptest.NewRecorder()
@@ -406,7 +406,7 @@ func TestMultiClusterFunctionality(t *testing.T) {
406406
// Don't set up any expectations - this will test error handling
407407

408408
mockManager := createSimpleMockManager()
409-
handler, err := handler.NewAuthorizationHandler(mockFGAClient, mockManager, "account")
409+
handler, err := handler.NewAuthorizationHandler(mockFGAClient, mockManager, "account", nil)
410410
assert.NoError(t, err)
411411

412412
recorder := httptest.NewRecorder()

0 commit comments

Comments
 (0)