Skip to content

Commit

Permalink
Update trigger reconciler to create OIDC service account
Browse files Browse the repository at this point in the history
  • Loading branch information
creydr committed Sep 26, 2023
1 parent b5e3e5d commit c8f5519
Show file tree
Hide file tree
Showing 5 changed files with 83 additions and 3 deletions.
20 changes: 19 additions & 1 deletion pkg/apis/eventing/v1/trigger_lifecycle.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import (
duckv1 "knative.dev/pkg/apis/duck/v1"
)

var triggerCondSet = apis.NewLivingConditionSet(TriggerConditionBroker, TriggerConditionSubscribed, TriggerConditionDependency, TriggerConditionSubscriberResolved, TriggerConditionDeadLetterSinkResolved)
var triggerCondSet = apis.NewLivingConditionSet(TriggerConditionBroker, TriggerConditionSubscribed, TriggerConditionDependency, TriggerConditionSubscriberResolved, TriggerConditionDeadLetterSinkResolved, TriggerConditionOIDCServiceAccountResolved)

const (
// TriggerConditionReady has status True when all subconditions below have been set to True.
Expand All @@ -39,6 +39,8 @@ const (

TriggerConditionDeadLetterSinkResolved apis.ConditionType = "DeadLetterSinkResolved"

TriggerConditionOIDCServiceAccountResolved apis.ConditionType = "OIDCServiceAccountResolved"

// TriggerAnyFilter Constant to represent that we should allow anything.
TriggerAnyFilter = ""
)
Expand Down Expand Up @@ -199,3 +201,19 @@ func (ts *TriggerStatus) PropagateDependencyStatus(ks *duckv1.Source) {
ts.MarkDependencyUnknown("DependencyUnknown", "The status of Dependency is invalid: %v", kc.Status)
}
}

func (ts *TriggerStatus) MarkOIDCServiceAccountResolvedSucceeded() {
triggerCondSet.Manage(ts).MarkTrue(TriggerConditionOIDCServiceAccountResolved)
}

func (ts *TriggerStatus) MarkOIDCServiceAccountResolvedSucceededWithReason(reason, messageFormat string, messageA ...interface{}) {
triggerCondSet.Manage(ts).MarkTrueWithReason(TriggerConditionOIDCServiceAccountResolved, reason, messageFormat, messageA...)
}

func (ts *TriggerStatus) MarkOIDCServiceAccountResolvedFailed(reason, messageFormat string, messageA ...interface{}) {
triggerCondSet.Manage(ts).MarkFalse(TriggerConditionOIDCServiceAccountResolved, reason, messageFormat, messageA...)
}

func (ts *TriggerStatus) MarkOIDCServiceAccountResolvedUnknown(reason, messageFormat string, messageA ...interface{}) {
triggerCondSet.Manage(ts).MarkUnknown(TriggerConditionOIDCServiceAccountResolved, reason, messageFormat, messageA...)
}
35 changes: 34 additions & 1 deletion pkg/auth/serviceaccount.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,17 @@ limitations under the License.
package auth

import (
"context"
"fmt"
"strings"

"go.uber.org/zap"
v1 "k8s.io/api/core/v1"
apierrs "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/client-go/kubernetes"
"knative.dev/pkg/logging"
"knative.dev/pkg/ptr"
)

Expand All @@ -47,7 +52,7 @@ func GetOIDCServiceAccountForResource(gvk schema.GroupVersionKind, objectMeta me
Kind: gvk.GroupKind().Kind,
Name: objectMeta.GetName(),
UID: objectMeta.GetUID(),
Controller: ptr.Bool(false),
Controller: ptr.Bool(true),
BlockOwnerDeletion: ptr.Bool(false),
},
},
Expand All @@ -57,3 +62,31 @@ func GetOIDCServiceAccountForResource(gvk schema.GroupVersionKind, objectMeta me
},
}
}

func EnsureOIDCServiceAccountExistsForResource(ctx context.Context, kubeclient kubernetes.Interface, gvk schema.GroupVersionKind, objectMeta metav1.ObjectMeta) error {
saName := GetOIDCServiceAccountNameForResource(gvk, objectMeta)
sa, err := kubeclient.CoreV1().ServiceAccounts(objectMeta.Namespace).Get(ctx, saName, metav1.GetOptions{})

// If the resource doesn't exist, we'll create it.
if apierrs.IsNotFound(err) {
logging.FromContext(ctx).Infow("Creating OIDC service account", zap.Error(err))

expected := GetOIDCServiceAccountForResource(gvk, objectMeta)

_, err = kubeclient.CoreV1().ServiceAccounts(objectMeta.Namespace).Create(ctx, expected, metav1.CreateOptions{})
if err != nil {
return fmt.Errorf("could not create OIDC service account %s/%s for %s: %w", objectMeta.Name, objectMeta.Namespace, gvk.Kind, err)
}
return nil
} else if err != nil {
logging.FromContext(ctx).Errorw("Failed to get OIDC service account", zap.Error(err))

return fmt.Errorf("could not get OIDC service account %s/%s for %s: %w", objectMeta.Name, objectMeta.Namespace, gvk.Kind, err)
} else if !metav1.IsControlledBy(&sa.ObjectMeta, &objectMeta) {
logging.FromContext(ctx).Errorw("Service account not owned by parent resource", zap.Any("service account", sa), zap.Any("parent resource ("+gvk.Kind+")", objectMeta))

return fmt.Errorf("%s %q does not own service account %q", gvk.Kind, objectMeta.Name, sa.Name)
}

return nil
}
2 changes: 1 addition & 1 deletion pkg/auth/serviceaccount_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ func TestGetOIDCServiceAccountForResource(t *testing.T) {
Kind: "Broker",
Name: "my-broker",
UID: "my-uuid",
Controller: ptr.Bool(false),
Controller: ptr.Bool(true),
BlockOwnerDeletion: ptr.Bool(false),
},
},
Expand Down
10 changes: 10 additions & 0 deletions pkg/reconciler/broker/trigger/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import (
"k8s.io/client-go/tools/cache"
"knative.dev/pkg/client/injection/ducks/duck/v1/source"
configmapinformer "knative.dev/pkg/client/injection/kube/informers/core/v1/configmap"
serviceaccountinformer "knative.dev/pkg/client/injection/kube/informers/core/v1/serviceaccount"
"knative.dev/pkg/configmap"
"knative.dev/pkg/controller"
"knative.dev/pkg/injection/clients/dynamicclient"
Expand All @@ -43,6 +44,7 @@ import (
triggerreconciler "knative.dev/eventing/pkg/client/injection/reconciler/eventing/v1/trigger"
eventinglisters "knative.dev/eventing/pkg/client/listers/eventing/v1"
"knative.dev/eventing/pkg/duck"
kubeclient "knative.dev/pkg/client/injection/kube/client"
)

// NewController initializes the controller and is called by the generated code
Expand All @@ -57,6 +59,7 @@ func NewController(
subscriptionInformer := subscriptioninformer.Get(ctx)
configmapInformer := configmapinformer.Get(ctx)
secretInformer := secretinformer.Get(ctx)
serviceaccountInformer := serviceaccountinformer.Get(ctx)

featureStore := feature.NewStore(logging.FromContext(ctx).Named("feature-config-store"))
featureStore.WatchConfigs(cmw)
Expand All @@ -65,6 +68,7 @@ func NewController(
r := &Reconciler{
eventingClientSet: eventingclient.Get(ctx),
dynamicClientSet: dynamicclient.Get(ctx),
kubeclient: kubeclient.Get(ctx),
subscriptionLister: subscriptionInformer.Lister(),
brokerLister: brokerInformer.Lister(),
triggerLister: triggerLister,
Expand Down Expand Up @@ -106,6 +110,12 @@ func NewController(
Handler: controller.HandleAll(impl.EnqueueControllerOf),
})

// Reconciler Trigger when the OIDC service account changes
serviceaccountInformer.Informer().AddEventHandler(cache.FilteringResourceEventHandler{
FilterFunc: controller.FilterController(&eventing.Trigger{}),
Handler: controller.HandleAll(impl.EnqueueControllerOf),
})

return impl
}

Expand Down
19 changes: 19 additions & 0 deletions pkg/reconciler/broker/trigger/trigger.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import (
apierrs "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/dynamic"
"k8s.io/client-go/kubernetes"
corev1listers "k8s.io/client-go/listers/core/v1"
"k8s.io/utils/pointer"
"knative.dev/pkg/apis"
Expand All @@ -44,6 +45,7 @@ import (
eventingv1 "knative.dev/eventing/pkg/apis/eventing/v1"
"knative.dev/eventing/pkg/apis/feature"
messagingv1 "knative.dev/eventing/pkg/apis/messaging/v1"
"knative.dev/eventing/pkg/auth"
clientset "knative.dev/eventing/pkg/client/clientset/versioned"
eventinglisters "knative.dev/eventing/pkg/client/listers/eventing/v1"
messaginglisters "knative.dev/eventing/pkg/client/listers/messaging/v1"
Expand All @@ -65,6 +67,7 @@ const (
type Reconciler struct {
eventingClientSet clientset.Interface
dynamicClientSet dynamic.Interface
kubeclient kubernetes.Interface

// listers index properties about resources
subscriptionLister messaginglisters.SubscriptionLister
Expand Down Expand Up @@ -137,6 +140,22 @@ func (r *Reconciler) ReconcileKind(ctx context.Context, t *eventingv1.Trigger) p
return err
}

featureFlags := feature.FromContext(ctx)
if featureFlags.IsOIDCAuthentication() {
saName := auth.GetOIDCServiceAccountNameForResource(eventingv1.SchemeGroupVersion.WithKind("Trigger"), t.ObjectMeta)
t.Status.Auth = &duckv1.AuthStatus{
ServiceAccountName: &saName,
}

if err := auth.EnsureOIDCServiceAccountExistsForResource(ctx, r.kubeclient, eventingv1.SchemeGroupVersion.WithKind("Trigger"), t.ObjectMeta); err != nil {
t.Status.MarkOIDCServiceAccountResolvedFailed("Unable to resolve service account for OIDC authentication", "%v", err)
return err
}
t.Status.MarkOIDCServiceAccountResolvedSucceeded()
} else {
t.Status.MarkOIDCServiceAccountResolvedSucceededWithReason("OIDC authentication feature disabled", "")
}

sub, err := r.subscribeToBrokerChannel(ctx, b, t, brokerTrigger)
if err != nil {
logging.FromContext(ctx).Errorw("Unable to Subscribe", zap.Error(err))
Expand Down

0 comments on commit c8f5519

Please sign in to comment.