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

Do/auth policy status #553

Merged
merged 1 commit into from
Apr 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
72 changes: 71 additions & 1 deletion controllers/authpolicy_status.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ import (
"fmt"
"slices"

kuadrantgatewayapi "github.com/kuadrant/kuadrant-operator/pkg/library/gatewayapi"
"k8s.io/utils/ptr"

"github.com/go-logr/logr"
authorinoapi "github.com/kuadrant/authorino/api/v1beta2"
apierrors "k8s.io/apimachinery/pkg/api/errors"
Expand Down Expand Up @@ -88,13 +91,18 @@ func (r *AuthPolicyReconciler) acceptedCondition(policy kuadrant.Policy, specErr
func (r *AuthPolicyReconciler) enforcedCondition(ctx context.Context, policy *api.AuthPolicy, targetNetworkObject client.Object) *metav1.Condition {
logger, _ := logr.FromContext(ctx)

t, err := r.generateTopology(ctx)
if err != nil {
logger.V(1).Info("Failed to generate topology", "error", err)
return nil
}
// Check if the policy is overridden
// Note: This logic assumes synchronous processing, where computing the desired AuthConfig, marking the AuthPolicy
// as overridden, and calculating the Enforced condition happen sequentially.
// Introducing a goroutine in this flow could break this assumption and lead to unexpected behavior.
if r.OverriddenPolicyMap.IsPolicyOverridden(policy) {
logger.V(1).Info("Gateway Policy is overridden")
return r.handleGatewayPolicyOverride(logger, policy, targetNetworkObject)
return r.handlePolicyOverride(logger, policy, targetNetworkObject, t)
}

// Check if the AuthConfig is ready
Expand Down Expand Up @@ -130,6 +138,18 @@ func (r *AuthPolicyReconciler) isAuthConfigReady(ctx context.Context, policy *ap
return authConfig.Status.Ready(), nil
}

func (r *AuthPolicyReconciler) handlePolicyOverride(logger logr.Logger, policy *api.AuthPolicy, targetNetworkObject client.Object, t *kuadrantgatewayapi.Topology) *metav1.Condition {
switch targetNetworkObject.(type) {
case *gatewayapiv1.Gateway:
return r.handleGatewayPolicyOverride(logger, policy, targetNetworkObject)
case *gatewayapiv1.HTTPRoute:
return r.handleHTTPRoutePolicyOverride(logger, policy, targetNetworkObject, t)
default:
logger.Error(errors.New("this point should never be reached"), "failed to match target network object", targetNetworkObject)
return nil
}
}

// handleGatewayPolicyOverride handles the case where the Gateway Policy is overridden by filtering policy references
// and creating a corresponding error condition.
func (r *AuthPolicyReconciler) handleGatewayPolicyOverride(logger logr.Logger, policy *api.AuthPolicy, targetNetworkObject client.Object) *metav1.Condition {
Expand All @@ -146,3 +166,53 @@ func (r *AuthPolicyReconciler) handleGatewayPolicyOverride(logger logr.Logger, p
}
return kuadrant.EnforcedCondition(policy, kuadrant.NewErrOverridden(policy.Kind(), string(jsonData)), false)
}

// handleHTTPRoutePolicyOverride handles the case where the HTTPRoute Policy is overridden by filtering policy references
// and creating a corresponding error condition.
func (r *AuthPolicyReconciler) handleHTTPRoutePolicyOverride(logger logr.Logger, policy *api.AuthPolicy, targetNetworkObject client.Object, t *kuadrantgatewayapi.Topology) *metav1.Condition {
obj := targetNetworkObject.(*gatewayapiv1.HTTPRoute)
httpRouteWrapper := kuadrant.HTTPRouteWrapper{HTTPRoute: obj, Referrer: policy}
refs := httpRouteWrapper.PolicyRefs(t)
jsonData, err := json.Marshal(refs)
if err != nil {
logger.Error(err, "Failed to marshal filtered references")
return kuadrant.EnforcedCondition(policy, kuadrant.NewErrUnknown(policy.Kind(), err), false)
}
return kuadrant.EnforcedCondition(policy, kuadrant.NewErrOverridden(policy.Kind(), string(jsonData)), false)
}

func (r *AuthPolicyReconciler) generateTopology(ctx context.Context) (*kuadrantgatewayapi.Topology, error) {
logger, _ := logr.FromContext(ctx)

gwList := &gatewayapiv1.GatewayList{}
err := r.Client().List(ctx, gwList)
logger.V(1).Info("topology: list gateways", "#Gateways", len(gwList.Items), "err", err)
if err != nil {
return nil, err
}

routeList := &gatewayapiv1.HTTPRouteList{}
err = r.Client().List(ctx, routeList)
logger.V(1).Info("topology: list httproutes", "#HTTPRoutes", len(routeList.Items), "err", err)
if err != nil {
return nil, err
}

aplist := &api.AuthPolicyList{}
err = r.Client().List(ctx, aplist)
logger.V(1).Info("topology: list rate limit policies", "#RLPS", len(aplist.Items), "err", err)
if err != nil {
return nil, err
}

policies := utils.Map(aplist.Items, func(p api.AuthPolicy) kuadrantgatewayapi.Policy {
return &p
})

return kuadrantgatewayapi.NewTopology(
kuadrantgatewayapi.WithGateways(utils.Map(gwList.Items, ptr.To[gatewayapiv1.Gateway])),
kuadrantgatewayapi.WithRoutes(utils.Map(routeList.Items, ptr.To[gatewayapiv1.HTTPRoute])),
kuadrantgatewayapi.WithPolicies(policies),
kuadrantgatewayapi.WithLogger(logger),
)
}
4 changes: 1 addition & 3 deletions pkg/library/kuadrant/apimachinery_status_conditions.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,6 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
gatewayapiv1alpha2 "sigs.k8s.io/gateway-api/apis/v1alpha2"

"github.com/kuadrant/kuadrant-operator/pkg/library/gatewayapi"
)

const (
Expand Down Expand Up @@ -55,7 +53,7 @@ func (o *OverriddenPolicyMap) RemoveOverriddenPolicy(p Policy) {

// IsPolicyOverridden checks if the provided Policy is overridden based on the tracking map maintained.
func (o *OverriddenPolicyMap) IsPolicyOverridden(p Policy) bool {
return o.policies[p.GetUID()] && gatewayapi.IsTargetRefGateway(p.GetTargetRef())
return o.policies[p.GetUID()]
}

// ConditionMarshal marshals the set of conditions as a JSON array, sorted by condition type.
Expand Down
41 changes: 41 additions & 0 deletions pkg/library/kuadrant/httproute_wrapper.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package kuadrant

import (
"github.com/kuadrant/kuadrant-operator/pkg/common"
kuadrantgatewayapi "github.com/kuadrant/kuadrant-operator/pkg/library/gatewayapi"
gatewayapiv1 "sigs.k8s.io/gateway-api/apis/v1"
)

type HTTPRouteWrapper struct {
*gatewayapiv1.HTTPRoute
Referrer
}

func (r HTTPRouteWrapper) PolicyRefs(t *kuadrantgatewayapi.Topology) []string {
if r.HTTPRoute == nil {
return make([]string, 0)
}
refs := make([]string, 0)
for _, gw := range t.Gateways() {
authPolicyRefs, ok := gw.GetAnnotations()[common.AuthPolicyBackRefAnnotation]
if !ok {
continue
}
refs = append(refs, authPolicyRefs)
}
return refs
}

// HTTPRouteWrapperList is a list of HTTPRouteWrapper that implements sort.interface
// impl: sort.interface
type HTTPRouteWrapperList []HTTPRouteWrapper

func (l HTTPRouteWrapperList) Len() int { return len(l) }

func (l HTTPRouteWrapperList) Less(i, j int) bool {
return l[i].CreationTimestamp.Before(&l[j].CreationTimestamp)
}

func (l HTTPRouteWrapperList) Swap(i, j int) {
l[i], l[j] = l[j], l[i]
}
Loading