Skip to content

Commit c105e6a

Browse files
feat: add OIDC and RBAC support to EventTransform auth-proxy
Signed-off-by: arpit529srivastava <arpitsrivastava529@gmail.com>
1 parent cb2b426 commit c105e6a

File tree

2 files changed

+87
-139
lines changed

2 files changed

+87
-139
lines changed

pkg/reconciler/eventtransform/eventtransform.go

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -413,6 +413,9 @@ func (r *Reconciler) jsonataCaCerts(_ context.Context, transform *eventing.Event
413413
return ptr.String(string(ca))
414414
}
415415

416+
// reconcileAuthProxyRBAC reconciles the RBAC resources required by the auth-proxy sidecar:
417+
// a namespace-scoped RoleBinding for EventPolicy access and an aggregated RoleBinding in the
418+
// knative-eventing namespace for ConfigMap access. Both are only created when OIDC is enabled.
416419
func (r *Reconciler) reconcileAuthProxyRBAC(ctx context.Context, transform *eventing.EventTransform) error {
417420
features := feature.FromContext(ctx)
418421

@@ -427,6 +430,9 @@ func (r *Reconciler) reconcileAuthProxyRBAC(ctx context.Context, transform *even
427430
return nil
428431
}
429432

433+
// reconcileEventPolicyRBAC reconciles a namespace-scoped RoleBinding that grants the auth-proxy
434+
// read access to EventPolicies in the EventTransform's namespace, enabling authorization checks.
435+
// The RoleBinding is deleted when OIDC authentication is disabled.
430436
func (r *Reconciler) reconcileEventPolicyRBAC(ctx context.Context, transform *eventing.EventTransform, features feature.Flags) error {
431437
expected := jsonataEventPolicyRoleBinding(transform)
432438

@@ -454,6 +460,10 @@ func (r *Reconciler) reconcileEventPolicyRBAC(ctx context.Context, transform *ev
454460
return nil
455461
}
456462

463+
// reconcileConfigMapAccessRBAC reconciles an aggregated RoleBinding in the knative-eventing
464+
// namespace that grants the auth-proxy read access to the config-features and config-logging
465+
// ConfigMaps. All EventTransform service accounts are aggregated into a single RoleBinding to
466+
// avoid creating one per EventTransform. The RoleBinding is deleted when OIDC is disabled.
457467
func (r *Reconciler) reconcileConfigMapAccessRBAC(ctx context.Context, transform *eventing.EventTransform, features feature.Flags) error {
458468
allTransforms, err := r.eventTransformLister.List(labels.Everything())
459469
if err != nil {
@@ -484,16 +494,13 @@ func (r *Reconciler) reconcileConfigMapAccessRBAC(ctx context.Context, transform
484494
return err
485495
}
486496

497+
// deleteRoleBinding deletes the given RoleBinding if it exists, using the lister cache to
498+
// avoid unnecessary API calls when the RoleBinding is already absent.
487499
func (r *Reconciler) deleteRoleBinding(ctx context.Context, rb *rbacv1.RoleBinding) error {
488-
_, err := r.rolebindingLister.RoleBindings(rb.Namespace).Get(rb.Name)
489-
if apierrors.IsNotFound(err) {
500+
if _, err := r.rolebindingLister.RoleBindings(rb.Namespace).Get(rb.Name); apierrors.IsNotFound(err) {
490501
return nil
491502
}
492-
if err != nil {
493-
return fmt.Errorf("failed to get rolebinding %s/%s: %w", rb.Namespace, rb.Name, err)
494-
}
495-
496-
err = r.k8s.RbacV1().RoleBindings(rb.Namespace).Delete(ctx, rb.Name, metav1.DeleteOptions{})
503+
err := r.k8s.RbacV1().RoleBindings(rb.Namespace).Delete(ctx, rb.Name, metav1.DeleteOptions{})
497504
if apierrors.IsNotFound(err) {
498505
return nil
499506
}

pkg/reconciler/eventtransform/eventtransform_test.go

Lines changed: 73 additions & 132 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ package eventtransform
1919
import (
2020
"context"
2121
"fmt"
22+
"os"
2223
"sync/atomic"
2324
"testing"
2425

@@ -72,6 +73,8 @@ var (
7273

7374
func TestReconcile(t *testing.T) {
7475
t.Setenv("EVENT_TRANSFORM_JSONATA_IMAGE", "quay.io/event-transform")
76+
t.Setenv("AUTH_PROXY_IMAGE", testAuthProxyImage)
77+
t.Setenv("SYSTEM_NAMESPACE", "knative-testing")
7578

7679
ctx := context.Background()
7780
logger := logtesting.TestLogger(t)
@@ -2030,6 +2033,75 @@ func TestReconcile(t *testing.T) {
20302033
},
20312034
WantErr: true, // skip key, waiting for endpoints
20322035
},
2036+
{
2037+
Name: "creates auth-proxy RoleBindings and deployment with auth-proxy when OIDC is enabled",
2038+
Key: testKey,
2039+
Objects: []runtime.Object{
2040+
NewEventTransform(testName, testNS,
2041+
WithEventTransformJsonataExpression(),
2042+
),
2043+
jsonataTestDeploymentWithAuthProxy(ctx, cw, func(d *appsv1.Deployment) {
2044+
d.Status = appsv1.DeploymentStatus{
2045+
ObservedGeneration: 1,
2046+
Replicas: 1,
2047+
UpdatedReplicas: 1,
2048+
ReadyReplicas: 1,
2049+
AvailableReplicas: 1,
2050+
UnavailableReplicas: 0,
2051+
}
2052+
}),
2053+
&corev1.Endpoints{
2054+
ObjectMeta: metav1.ObjectMeta{
2055+
Namespace: testNS,
2056+
Name: fmt.Sprintf("%s-%s", testName, "jsonata"),
2057+
},
2058+
Subsets: []corev1.EndpointSubset{
2059+
{
2060+
Ports: []corev1.EndpointPort{{Port: 3128}},
2061+
Addresses: []corev1.EndpointAddress{{IP: "192.168.0.1"}},
2062+
},
2063+
},
2064+
},
2065+
jsonataExpressionTestConfigMap(ctx),
2066+
&corev1.ConfigMap{
2067+
ObjectMeta: metav1.ObjectMeta{Namespace: testNS, Name: "config-features"},
2068+
Data: map[string]string{
2069+
"authentication-oidc": "enabled",
2070+
},
2071+
},
2072+
},
2073+
WantCreates: []runtime.Object{
2074+
jsonataTestServiceWithAuthProxy(ctx),
2075+
jsonataTestEventPolicyRoleBinding(),
2076+
jsonataTestAuthProxyRoleBinding(),
2077+
},
2078+
WantEvents: []string{
2079+
eventJsonataServiceCreated(),
2080+
},
2081+
WantStatusUpdates: []clientgotesting.UpdateActionImpl{
2082+
{Object: NewEventTransform(testName, testNS,
2083+
WithEventTransformJsonataExpression(),
2084+
WithJsonataEventTransformInitializeStatus(),
2085+
WithJsonataDeploymentStatus(appsv1.DeploymentStatus{
2086+
ObservedGeneration: 1,
2087+
Replicas: 1,
2088+
UpdatedReplicas: 1,
2089+
ReadyReplicas: 1,
2090+
AvailableReplicas: 1,
2091+
UnavailableReplicas: 0,
2092+
}),
2093+
WithEventTransformAddresses(
2094+
duckv1.Addressable{
2095+
Name: ptr.String("http"),
2096+
URL: apis.HTTP(network.GetServiceHostname(fmt.Sprintf("%s-%s", testName, "jsonata"), testNS)),
2097+
Audience: ptr.String(v1alpha1.SchemeGroupVersion.Group + "/eventtransform/" + testNS + "/" + testName),
2098+
},
2099+
),
2100+
WithEventTransformEventPoliciesReady("DefaultAuthorizationMode", `Default authz mode is "Allow-Same-Namespace"`),
2101+
)},
2102+
},
2103+
SkipNamespaceValidation: true,
2104+
},
20332105
}
20342106

20352107
table.Test(t, MakeFactory(func(ctx context.Context, listers *Listers, watcher configmap.Watcher) controller.Reconciler {
@@ -2053,7 +2125,7 @@ func TestReconcile(t *testing.T) {
20532125
eventPolicyLister: listers.GetEventPolicyLister(),
20542126
rolebindingLister: listers.GetRoleBindingLister(),
20552127
eventTransformLister: listers.GetEventTransformLister(),
2056-
authProxyImage: "",
2128+
authProxyImage: os.Getenv("AUTH_PROXY_IMAGE"),
20572129
configWatcher: cw,
20582130
}
20592131

@@ -2227,137 +2299,6 @@ func eventJsonataCertificateDeleted() string {
22272299

22282300
const testAuthProxyImage = "quay.io/fake-auth-proxy"
22292301

2230-
func TestReconcileOIDC(t *testing.T) {
2231-
t.Setenv("EVENT_TRANSFORM_JSONATA_IMAGE", "quay.io/event-transform")
2232-
t.Setenv("SYSTEM_NAMESPACE", "knative-testing")
2233-
2234-
ctx := context.Background()
2235-
logger := logtesting.TestLogger(t)
2236-
ctx = logging.WithLogger(ctx, logger)
2237-
2238-
cw := reconcilersource.WatchConfigurations(
2239-
ctx,
2240-
"eventtransform",
2241-
configmap.NewStaticWatcher(
2242-
&corev1.ConfigMap{
2243-
ObjectMeta: metav1.ObjectMeta{Name: "config-logging"},
2244-
},
2245-
&corev1.ConfigMap{
2246-
ObjectMeta: metav1.ObjectMeta{Name: "config-observability"},
2247-
},
2248-
&corev1.ConfigMap{
2249-
ObjectMeta: metav1.ObjectMeta{Name: "config-tracing"},
2250-
},
2251-
),
2252-
)
2253-
2254-
serviceName := fmt.Sprintf("%s-%s", testName, "jsonata")
2255-
2256-
table := TableTest{
2257-
{
2258-
Name: "creates auth-proxy RoleBindings and deployment with auth-proxy when OIDC is enabled",
2259-
Key: testKey,
2260-
Ctx: feature.ToContext(context.Background(), feature.Flags{
2261-
feature.OIDCAuthentication: feature.Enabled,
2262-
}),
2263-
Objects: []runtime.Object{
2264-
NewEventTransform(testName, testNS,
2265-
WithEventTransformJsonataExpression(),
2266-
),
2267-
jsonataTestDeploymentWithAuthProxy(ctx, cw, func(d *appsv1.Deployment) {
2268-
d.Status = appsv1.DeploymentStatus{
2269-
ObservedGeneration: 1,
2270-
Replicas: 1,
2271-
UpdatedReplicas: 1,
2272-
ReadyReplicas: 1,
2273-
AvailableReplicas: 1,
2274-
UnavailableReplicas: 0,
2275-
}
2276-
}),
2277-
&corev1.Endpoints{
2278-
ObjectMeta: metav1.ObjectMeta{
2279-
Namespace: testNS,
2280-
Name: serviceName,
2281-
},
2282-
Subsets: []corev1.EndpointSubset{
2283-
{
2284-
Ports: []corev1.EndpointPort{{Port: 3128}},
2285-
Addresses: []corev1.EndpointAddress{{IP: "192.168.0.1"}},
2286-
},
2287-
},
2288-
},
2289-
jsonataExpressionTestConfigMap(ctx),
2290-
&corev1.ConfigMap{ObjectMeta: metav1.ObjectMeta{Namespace: testNS, Name: "config-features"}},
2291-
},
2292-
WantCreates: []runtime.Object{
2293-
jsonataTestServiceWithAuthProxy(ctx),
2294-
jsonataTestEventPolicyRoleBinding(),
2295-
jsonataTestAuthProxyRoleBinding(),
2296-
},
2297-
WantEvents: []string{
2298-
eventJsonataServiceCreated(),
2299-
},
2300-
WantStatusUpdates: []clientgotesting.UpdateActionImpl{
2301-
{Object: NewEventTransform(testName, testNS,
2302-
WithEventTransformJsonataExpression(),
2303-
WithJsonataEventTransformInitializeStatus(),
2304-
WithJsonataDeploymentStatus(appsv1.DeploymentStatus{
2305-
ObservedGeneration: 1,
2306-
Replicas: 1,
2307-
UpdatedReplicas: 1,
2308-
ReadyReplicas: 1,
2309-
AvailableReplicas: 1,
2310-
UnavailableReplicas: 0,
2311-
}),
2312-
WithEventTransformAddresses(
2313-
duckv1.Addressable{
2314-
Name: ptr.String("http"),
2315-
URL: apis.HTTP(network.GetServiceHostname(serviceName, testNS)),
2316-
Audience: ptr.String(v1alpha1.SchemeGroupVersion.Group + "/eventtransform/" + testNS + "/" + testName),
2317-
},
2318-
),
2319-
WithEventTransformEventPoliciesReady("DefaultAuthorizationMode", `Default authz mode is ""`),
2320-
)},
2321-
},
2322-
SkipNamespaceValidation: true,
2323-
},
2324-
}
2325-
2326-
table.Test(t, MakeFactory(func(ctx context.Context, listers *Listers, watcher configmap.Watcher) controller.Reconciler {
2327-
2328-
cmCertificatesListerAtomic := &atomic.Pointer[cmlisters.CertificateLister]{}
2329-
cmCertificatesLister := listers.GetCertificateLister()
2330-
cmCertificatesListerAtomic.Store(&cmCertificatesLister)
2331-
2332-
r := &Reconciler{
2333-
k8s: kubeclient.Get(ctx),
2334-
client: eventingclient.Get(ctx),
2335-
cmClient: cmclient.Get(ctx),
2336-
jsonataConfigMapLister: listers.GetConfigMapLister(),
2337-
jsonataDeploymentsLister: listers.GetDeploymentLister(),
2338-
jsonataServiceLister: listers.GetServiceLister(),
2339-
jsonataEndpointLister: listers.GetEndpointsLister(),
2340-
jsonataSinkBindingLister: listers.GetSinkBindingLister(),
2341-
cmCertificateLister: cmCertificatesListerAtomic,
2342-
certificatesSecretLister: listers.GetSecretLister(),
2343-
trustBundleConfigMapLister: listers.GetConfigMapLister(),
2344-
eventPolicyLister: listers.GetEventPolicyLister(),
2345-
rolebindingLister: listers.GetRoleBindingLister(),
2346-
eventTransformLister: listers.GetEventTransformLister(),
2347-
authProxyImage: testAuthProxyImage,
2348-
configWatcher: cw,
2349-
}
2350-
2351-
return eventtransform.NewReconciler(ctx,
2352-
logger,
2353-
fakeeventingclient.Get(ctx),
2354-
listers.GetEventTransformLister(),
2355-
controller.GetEventRecorder(ctx),
2356-
r,
2357-
)
2358-
}, false, logger))
2359-
}
2360-
23612302
func jsonataTestDeploymentWithAuthProxy(ctx context.Context, cw *reconcilersource.ConfigWatcher, opts ...DeploymentOption) *appsv1.Deployment {
23622303
oidcCtx := feature.ToContext(ctx, feature.Flags{
23632304
feature.OIDCAuthentication: feature.Enabled,

0 commit comments

Comments
 (0)