Skip to content
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

OIDC - Support auto generation of PingSource identity service account and expose in AuthStatus #7344

Merged
merged 8 commits into from
Oct 19, 2023
Merged
6 changes: 6 additions & 0 deletions pkg/adapter/mtping/pingsource_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ func TestAllCases(t *testing.T) {
rtv1.WithPingSourceDeployed,
rtv1.WithPingSourceSink(sinkAddr),
rtv1.WithPingSourceCloudEventAttributes,
rtv1.WithPingSourceOIDCIdentityCreatedSucceededBecauseOIDCFeatureDisabled(),
),
},
WantErr: false,
Expand All @@ -112,6 +113,7 @@ func TestAllCases(t *testing.T) {
rtv1.WithPingSourceDeployed,
rtv1.WithPingSourceSink(sinkAddr),
rtv1.WithPingSourceCloudEventAttributes,
rtv1.WithPingSourceOIDCIdentityCreatedSucceededBecauseOIDCFeatureDisabled(),
),
},
WantErr: false,
Expand All @@ -137,6 +139,7 @@ func TestAllCases(t *testing.T) {
rtv1.WithPingSourceDeployed,
rtv1.WithPingSourceSink(sinkAddr),
rtv1.WithPingSourceCloudEventAttributes,
rtv1.WithPingSourceOIDCIdentityCreatedSucceededBecauseOIDCFeatureDisabled(),
),
},
WantErr: false,
Expand All @@ -162,6 +165,7 @@ func TestAllCases(t *testing.T) {
rtv1.WithPingSourceDeployed,
rtv1.WithPingSourceSink(sinkAddr),
rtv1.WithPingSourceCloudEventAttributes,
rtv1.WithPingSourceOIDCIdentityCreatedSucceededBecauseOIDCFeatureDisabled(),
),
},
WantErr: false,
Expand All @@ -188,6 +192,7 @@ func TestAllCases(t *testing.T) {
rtv1.WithPingSourceSink(sinkAddr),
rtv1.WithPingSourceCloudEventAttributes,
rtv1.WithPingSourceDeleted,
rtv1.WithPingSourceOIDCIdentityCreatedSucceededBecauseOIDCFeatureDisabled(),
),
},
WantErr: false,
Expand All @@ -210,6 +215,7 @@ func TestAllCases(t *testing.T) {
rtv1.WithPingSourceSink(sinkAddr),
rtv1.WithPingSourceCloudEventAttributes,
rtv1.WithPingSourceDeleted,
rtv1.WithPingSourceOIDCIdentityCreatedSucceededBecauseOIDCFeatureDisabled(),
Leo6Leo marked this conversation as resolved.
Show resolved Hide resolved
),
},
WantErr: false,
Expand Down
22 changes: 21 additions & 1 deletion pkg/apis/sources/v1/ping_lifecycle.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,15 @@ const (

// PingSourceConditionDeployed has status True when the PingSource has had it's receive adapter deployment created.
PingSourceConditionDeployed apis.ConditionType = "Deployed"

// PingSourceConditionOIDCIdentityCreated has status True when the PingSource has had it's OIDC identity created.
PingSourceConditionOIDCIdentityCreated apis.ConditionType = "OIDCIdentityCreated"
)

var PingSourceCondSet = apis.NewLivingConditionSet(
PingSourceConditionSinkProvided,
PingSourceConditionDeployed)
PingSourceConditionDeployed,
PingSourceConditionOIDCIdentityCreated)

const (
// PingSourceEventType is the default PingSource CloudEvent type.
Expand Down Expand Up @@ -122,3 +126,19 @@ func (s *PingSourceStatus) PropagateDeploymentAvailability(d *appsv1.Deployment)
PingSourceCondSet.Manage(s).MarkUnknown(PingSourceConditionDeployed, "DeploymentUnavailable", "The Deployment '%s' is unavailable.", d.Name)
}
}

func (s *PingSourceStatus) MarkOIDCIdentityCreatedSucceeded() {
PingSourceCondSet.Manage(s).MarkTrue(PingSourceConditionOIDCIdentityCreated)
}

func (s *PingSourceStatus) MarkOIDCIdentityCreatedSucceededWithReason(reason, messageFormat string, messageA ...interface{}) {
PingSourceCondSet.Manage(s).MarkTrueWithReason(PingSourceConditionOIDCIdentityCreated, reason, messageFormat, messageA...)
}

func (s *PingSourceStatus) MarkOIDCIdentityCreatedFailed(reason, messageFormat string, messageA ...interface{}) {
PingSourceCondSet.Manage(s).MarkFalse(PingSourceConditionOIDCIdentityCreated, reason, messageFormat, messageA...)
}

func (s *PingSourceStatus) MarkOIDCIdentityCreatedUnknown(reason, messageFormat string, messageA ...interface{}) {
PingSourceCondSet.Manage(s).MarkUnknown(PingSourceConditionOIDCIdentityCreated, reason, messageFormat, messageA...)
}
65 changes: 62 additions & 3 deletions pkg/apis/sources/v1/ping_lifecycle_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ func TestPingSourceStatusIsReady(t *testing.T) {
s: func() *PingSourceStatus {
s := &PingSourceStatus{}
s.InitializeConditions()
s.MarkOIDCIdentityCreatedSucceeded()
return s
}(),
wantConditionStatus: corev1.ConditionUnknown,
Expand All @@ -81,6 +82,7 @@ func TestPingSourceStatusIsReady(t *testing.T) {
s: func() *PingSourceStatus {
s := &PingSourceStatus{}
s.InitializeConditions()
s.MarkOIDCIdentityCreatedSucceeded()
s.PropagateDeploymentAvailability(availableDeployment)
return s
}(),
Expand All @@ -91,7 +93,7 @@ func TestPingSourceStatusIsReady(t *testing.T) {
s: func() *PingSourceStatus {
s := &PingSourceStatus{}
s.InitializeConditions()

s.MarkOIDCIdentityCreatedSucceeded()
s.MarkSink(exampleAddr)
return s
}(),
Expand All @@ -102,16 +104,32 @@ func TestPingSourceStatusIsReady(t *testing.T) {
s: func() *PingSourceStatus {
s := &PingSourceStatus{}
s.InitializeConditions()
s.MarkOIDCIdentityCreatedSucceeded()
s.MarkSink(exampleAddr)
s.PropagateDeploymentAvailability(availableDeployment)
return s
}(),
wantConditionStatus: corev1.ConditionTrue,
want: true,
}}
},
{
name: "oidc status false",
s: func() *PingSourceStatus {
s := &PingSourceStatus{}
s.InitializeConditions()
s.MarkOIDCIdentityCreatedFailed("Unable to create the OIDC identity", "")
s.MarkSink(exampleAddr)
s.PropagateDeploymentAvailability(availableDeployment)
return s
}(),
wantConditionStatus: corev1.ConditionFalse,
want: false,
},
}

for _, test := range tests {
t.Run(test.name, func(t *testing.T) {

if test.wantConditionStatus != "" {
gotConditionStatus := test.s.GetTopLevelCondition().Status
if gotConditionStatus != test.wantConditionStatus {
Expand All @@ -122,6 +140,7 @@ func TestPingSourceStatusIsReady(t *testing.T) {
if got != test.want {
t.Errorf("unexpected readiness: want %v, got %v", test.want, got)
}

})
}
}
Expand All @@ -145,6 +164,7 @@ func TestPingSourceStatusGetTopLevelCondition(t *testing.T) {
s: func() *PingSourceStatus {
s := &PingSourceStatus{}
s.InitializeConditions()
s.MarkOIDCIdentityCreatedSucceeded()
return s
}(),
want: &apis.Condition{
Expand All @@ -156,6 +176,7 @@ func TestPingSourceStatusGetTopLevelCondition(t *testing.T) {
s: func() *PingSourceStatus {
s := &PingSourceStatus{}
s.InitializeConditions()
s.MarkOIDCIdentityCreatedSucceeded()
s.PropagateDeploymentAvailability(availableDeployment)
return s
}(),
Expand All @@ -168,6 +189,7 @@ func TestPingSourceStatusGetTopLevelCondition(t *testing.T) {
s: func() *PingSourceStatus {
s := &PingSourceStatus{}
s.InitializeConditions()
s.MarkOIDCIdentityCreatedSucceeded()
s.MarkSink(exampleAddr)
return s
}(),
Expand All @@ -180,6 +202,7 @@ func TestPingSourceStatusGetTopLevelCondition(t *testing.T) {
s: func() *PingSourceStatus {
s := &PingSourceStatus{}
s.InitializeConditions()
s.MarkOIDCIdentityCreatedSucceeded()
s.MarkSink(exampleAddr)
s.PropagateDeploymentAvailability(availableDeployment)
return s
Expand All @@ -188,10 +211,28 @@ func TestPingSourceStatusGetTopLevelCondition(t *testing.T) {
Type: PingSourceConditionReady,
Status: corev1.ConditionTrue,
},
}}
},
{
name: "oidc fail",
s: func() *PingSourceStatus {
s := &PingSourceStatus{}
s.InitializeConditions()
s.MarkOIDCIdentityCreatedFailed("Unable to create the OIDC identity", "")
s.MarkSink(exampleAddr)
s.PropagateDeploymentAvailability(availableDeployment)
return s
}(),
want: &apis.Condition{
Type: PingSourceConditionReady,
Status: corev1.ConditionFalse,
Reason: "Unable to create the OIDC identity",
},
},
}

for _, test := range tests {
t.Run(test.name, func(t *testing.T) {

got := test.s.GetTopLevelCondition()
ignoreTime := cmpopts.IgnoreFields(apis.Condition{},
"LastTransitionTime", "Severity")
Expand Down Expand Up @@ -223,6 +264,7 @@ func TestPingSourceStatusGetCondition(t *testing.T) {
s: func() *PingSourceStatus {
s := &PingSourceStatus{}
s.InitializeConditions()
s.MarkOIDCIdentityCreatedSucceeded()
return s
}(),
condQuery: PingSourceConditionReady,
Expand All @@ -235,6 +277,7 @@ func TestPingSourceStatusGetCondition(t *testing.T) {
s: func() *PingSourceStatus {
s := &PingSourceStatus{}
s.InitializeConditions()
s.MarkOIDCIdentityCreatedSucceeded()
s.PropagateDeploymentAvailability(availableDeployment)
return s
}(),
Expand All @@ -248,6 +291,7 @@ func TestPingSourceStatusGetCondition(t *testing.T) {
s: func() *PingSourceStatus {
s := &PingSourceStatus{}
s.InitializeConditions()
s.MarkOIDCIdentityCreatedSucceeded()
s.MarkSink(exampleAddr)
return s
}(),
Expand All @@ -256,6 +300,21 @@ func TestPingSourceStatusGetCondition(t *testing.T) {
Type: PingSourceConditionReady,
Status: corev1.ConditionUnknown,
},
}, {
name: "oidc failed",
s: func() *PingSourceStatus {
s := &PingSourceStatus{}
s.InitializeConditions()
s.MarkOIDCIdentityCreatedFailed("Unable to create the OIDC identity", "")
s.MarkSink(exampleAddr)
return s
}(),
condQuery: PingSourceConditionReady,
want: &apis.Condition{
Type: PingSourceConditionReady,
Status: corev1.ConditionFalse,
Reason: "Unable to create the OIDC identity",
},
}}

for _, test := range tests {
Expand Down
27 changes: 23 additions & 4 deletions pkg/reconciler/pingsource/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ package pingsource
import (
"context"

serviceaccountinformer "knative.dev/pkg/client/injection/kube/informers/core/v1/serviceaccount"

"go.uber.org/zap"

appsv1 "k8s.io/api/apps/v1"
Expand Down Expand Up @@ -60,18 +62,26 @@ func NewController(
logger.Fatalw("Error converting leader election configuration to JSON", zap.Error(err))
}

featureStore := feature.NewStore(logging.FromContext(ctx).Named("feature-config-store"))
var globalResync func(obj interface{})

featureStore := feature.NewStore(logging.FromContext(ctx).Named("feature-config-store"), func(name string, value interface{}) {
if globalResync != nil {
globalResync(nil)
}
})
featureStore.WatchConfigs(cmw)

// Configure the reconciler

deploymentInformer := deploymentinformer.Get(ctx)
pingSourceInformer := pingsourceinformer.Get(ctx)
serviceaccountInformer := serviceaccountinformer.Get(ctx)

r := &Reconciler{
kubeClientSet: kubeclient.Get(ctx),
leConfig: leConfig,
configAcc: reconcilersource.WatchConfigurations(ctx, component, cmw),
kubeClientSet: kubeclient.Get(ctx),
leConfig: leConfig,
configAcc: reconcilersource.WatchConfigurations(ctx, component, cmw),
serviceAccountLister: serviceaccountInformer.Lister(),
}

impl := pingsourcereconciler.NewImpl(ctx, r, func(impl *controller.Impl) controller.Options {
Expand All @@ -80,6 +90,10 @@ func NewController(
}
})

globalResync = func(interface{}) {
impl.GlobalResync(pingSourceInformer.Informer())
}

r.sinkResolver = resolver.NewURIResolver(ctx, cmw, impl.Tracker)

pingSourceInformer.Informer().AddEventHandler(controller.HandleAll(impl.Enqueue))
Expand All @@ -97,5 +111,10 @@ func NewController(
)),
})

serviceaccountInformer.Informer().AddEventHandler(cache.FilteringResourceEventHandler{
Cali0707 marked this conversation as resolved.
Show resolved Hide resolved
FilterFunc: controller.FilterWithNameAndNamespace(system.Namespace(), mtadapterName),
creydr marked this conversation as resolved.
Show resolved Hide resolved
Handler: controller.HandleAll(impl.EnqueueControllerOf),
})

return impl
}
24 changes: 24 additions & 0 deletions pkg/reconciler/pingsource/pingsource.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@ import (
"encoding/json"
"fmt"

v1 "k8s.io/client-go/listers/core/v1"
"knative.dev/eventing/pkg/apis/feature"
"knative.dev/eventing/pkg/auth"

"go.uber.org/zap"

appsv1 "k8s.io/api/apps/v1"
Expand Down Expand Up @@ -74,6 +78,8 @@ type Reconciler struct {

// Leader election configuration for the mt receive adapter
leConfig string

serviceAccountLister v1.ServiceAccountLister
}

// Check that our Reconciler implements ReconcileKind
Expand All @@ -99,6 +105,24 @@ func (r *Reconciler) ReconcileKind(ctx context.Context, source *sourcesv1.PingSo
}
}

// OIDC authentication
featureFlags := feature.FromContext(ctx)
if featureFlags.IsOIDCAuthentication() {
saName := auth.GetOIDCServiceAccountNameForResource(sourcesv1.SchemeGroupVersion.WithKind("PingSource"), source.ObjectMeta)
source.Status.Auth = &duckv1.AuthStatus{
ServiceAccountName: &saName,
}

if err := auth.EnsureOIDCServiceAccountExistsForResource(ctx, r.serviceAccountLister, r.kubeClientSet, sourcesv1.SchemeGroupVersion.WithKind("PingSource"), source.ObjectMeta); err != nil {
source.Status.MarkOIDCIdentityCreatedFailed("Unable to resolve service account for OIDC authentication", "%v", err)
return err
}
source.Status.MarkOIDCIdentityCreatedSucceeded()
} else {
source.Status.Auth = nil
source.Status.MarkOIDCIdentityCreatedSucceededWithReason(fmt.Sprintf("%s feature disabled", feature.OIDCAuthentication), "")
Leo6Leo marked this conversation as resolved.
Show resolved Hide resolved
}

sinkAddr, err := r.sinkResolver.AddressableFromDestinationV1(ctx, *dest, source)
if err != nil {
source.Status.MarkNoSink("NotFound", "")
Expand Down
Loading