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

Send local replies from envoy #2900

Open
wants to merge 8 commits into
base: main
Choose a base branch
from
Open
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
30 changes: 27 additions & 3 deletions adapter/internal/discovery/xds/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -378,9 +378,33 @@ func GenerateEnvoyResoucesForGateway(gatewayName string) ([]types.Resource,
}
logger.LoggerAPKOperator.Debugf("JWT Requirements for API %+v is %+v", envoyInternalAPI.adapterInternalAPI.UUID, jwtRequirements)
if len(jwtRequirements) > 0 {
jwtRequirementMap[envoyInternalAPI.adapterInternalAPI.UUID] = &jwt.JwtRequirement{RequiresType: &jwt.JwtRequirement_RequiresAny{RequiresAny: &jwt.JwtRequirementOrList{Requirements: append(jwtRequirements, &jwt.JwtRequirement{
RequiresType: &jwt.JwtRequirement_AllowMissingOrFailed{},
})}}}
if envoyInternalAPI.adapterInternalAPI.GetAPIType() == "GraphQL" ||
envoyInternalAPI.adapterInternalAPI.GetAPIType() == "GRPC" ||
!envoyInternalAPI.adapterInternalAPI.GetDisableMtls() {
jwtRequirementMap[envoyInternalAPI.adapterInternalAPI.UUID] = &jwt.JwtRequirement{
RequiresType: &jwt.JwtRequirement_RequiresAny{
RequiresAny: &jwt.JwtRequirementOrList{
Requirements: append(jwtRequirements, &jwt.JwtRequirement{
RequiresType: &jwt.JwtRequirement_AllowMissingOrFailed{},
}),
},
},
}
} else {
if len(jwtRequirements) == 1 {
jwtRequirementMap[envoyInternalAPI.adapterInternalAPI.UUID] = jwtRequirements[0]
} else {
jwtRequirementMap[envoyInternalAPI.adapterInternalAPI.UUID] = &jwt.JwtRequirement{
RequiresType: &jwt.JwtRequirement_RequiresAny{
RequiresAny: &jwt.JwtRequirementOrList{
Requirements: jwtRequirements,
},
},
}
}

}

} else {
logger.LoggerAPKOperator.Debugf("No JWT Requirements for API %+v is %+v", envoyInternalAPI.adapterInternalAPI.UUID, jwtRequirements)
removeJWTRequirements = true
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,8 +81,8 @@ func TestCreateRoute(t *testing.T) {
Value: true,
},
}
clusterSpecifier := &routev3.RouteAction_ClusterHeader{
ClusterHeader: clusterHeaderName,
clusterSpecifier := &routev3.RouteAction_Cluster{
Cluster: "resource_operation_id",
}
regexRewriteWithXWso2BasePath := &envoy_type_matcherv3.RegexMatchAndSubstitute{
Pattern: &envoy_type_matcherv3.RegexMatcher{
Expand Down Expand Up @@ -150,9 +150,9 @@ func TestCreateRouteClusterSpecifier(t *testing.T) {
&resourceWithGet, clusterName, nil, false))
assert.Nil(t, err, "Error while creating route")
assert.NotNil(t, route[0], "Route should not be null")
assert.NotNil(t, route[0].GetRoute().GetClusterHeader(), "Route Cluster Header should not be null.")
assert.Empty(t, route[0].GetRoute().GetCluster(), "Route Cluster Name should be empty.")
assert.Equal(t, clusterHeaderName, route[0].GetRoute().GetClusterHeader(), "Route Cluster Name mismatch.")
// assert.NotNil(t, route[0].GetRoute().GetClusterHeader(), "Route Cluster Header should not be null.")
// assert.Empty(t, route[0].GetRoute().GetCluster(), "Route Cluster Name should be empty.")
assert.Equal(t, "cluster", route[0].GetRoute().GetCluster(), "Route Cluster Name mismatch.")
}

// func TestCreateRouteExtAuthzContext(t *testing.T) {
Expand Down
21 changes: 21 additions & 0 deletions adapter/internal/oasparser/envoyconf/response_mapper.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,27 @@ func init() {

func getErrorResponseMappers() []*hcmv3.ResponseMapper {
responseMappers := []*hcmv3.ResponseMapper{}
responseMappers = append(responseMappers, &hcmv3.ResponseMapper{
Filter: &access_logv3.AccessLogFilter{
FilterSpecifier: &access_logv3.AccessLogFilter_StatusCodeFilter{
StatusCodeFilter: &access_logv3.StatusCodeFilter{
Comparison: &access_logv3.ComparisonFilter{
Op: access_logv3.ComparisonFilter_EQ,
Value: &corev3.RuntimeUInt32{
DefaultValue: 401,
RuntimeKey: "key123",
},
},
},
},
},
StatusCode: wrapperspb.UInt32(401),
Body: &corev3.DataSource{
Specifier: &corev3.DataSource_InlineBytes{
InlineBytes: []byte("{\"error_message\":\"Invalid Credentials\",\"code\":401,\"ErrorDescription\":\"Make sure you have provided the correct security credentials\"}"),
},
},
})
conf := config.ReadConfigs()
if conf.Adapter.SoapErrorInXMLEnabled {
for flag, details := range errorResponseMap {
Expand Down
19 changes: 17 additions & 2 deletions adapter/internal/oasparser/envoyconf/routes_configs.go
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ func generateRouteMatch(routeRegex string) *routev3.RouteMatch {
return match
}

func generateRouteAction(apiType string, routeConfig *model.EndpointConfig, ratelimitCriteria *ratelimitCriteria, mirrorClusterNames []string, isBackendBasedAIRatelimitEnabled bool, descriptorValueForBackendBasedAIRatelimit string, weightedCluster *routev3.WeightedCluster_ClusterWeight, isWeighted bool) (action *routev3.Route_Route) {
func generateRouteAction(apiType string, routeConfig *model.EndpointConfig, ratelimitCriteria *ratelimitCriteria, mirrorClusterNames []string, isBackendBasedAIRatelimitEnabled bool, descriptorValueForBackendBasedAIRatelimit string, weightedCluster *routev3.WeightedCluster_ClusterWeight, isWeighted bool, aiRoundRobinEnabled bool, clusterName string) (action *routev3.Route_Route) {

if isWeighted {
// check if weightedCluster is already in the list
Expand Down Expand Up @@ -163,7 +163,7 @@ func generateRouteAction(apiType string, routeConfig *model.EndpointConfig, rate
},
},
}
} else {
} else if aiRoundRobinEnabled {
action = &routev3.Route_Route{
Route: &routev3.RouteAction{
HostRewriteSpecifier: &routev3.RouteAction_AutoHostRewrite{
Expand All @@ -178,6 +178,21 @@ func generateRouteAction(apiType string, routeConfig *model.EndpointConfig, rate
},
},
}
} else {
action = &routev3.Route_Route{
Route: &routev3.RouteAction{
HostRewriteSpecifier: &routev3.RouteAction_AutoHostRewrite{
AutoHostRewrite: &wrapperspb.BoolValue{
Value: true,
},
},
UpgradeConfigs: getUpgradeConfig(apiType),
MaxStreamDuration: getMaxStreamDuration(apiType),
ClusterSpecifier: &routev3.RouteAction_Cluster{
Cluster: clusterName,
},
},
}
}

if routeConfig != nil {
Expand Down
21 changes: 17 additions & 4 deletions adapter/internal/oasparser/envoyconf/routes_with_clusters.go
Original file line number Diff line number Diff line change
Expand Up @@ -1008,6 +1008,19 @@ func createRoutes(params *routeCreateParams) (routes []*routev3.Route, err error
LuaLocal: luaFilter,
wellknown.CORS: corsFilter,
}
if !resource.ShouldSendToEnforcer() {
perFilterConfigExtProc := extProcessorv3.ExtProcPerRoute{
Override: &extProcessorv3.ExtProcPerRoute_Disabled{
Disabled: true,
},
}
dataExtProc, _ := proto.Marshal(&perFilterConfigExtProc)
filterExtProc := &any.Any{
TypeUrl: extProcPerRouteName,
Value: dataExtProc,
}
perRouteFilterConfigs[HTTPExternalProcessor] = filterExtProc
}
// if !params.isAiAPI {
// perFilterConfigExtProc := extProcessorv3.ExtProcPerRoute{
// Override: &extProcessorv3.ExtProcPerRoute_Disabled{
Expand Down Expand Up @@ -1284,8 +1297,8 @@ func createRoutes(params *routeCreateParams) (routes []*routev3.Route, err error
metadataValue := operation.GetMethod() + "_to_" + newMethod
match2.DynamicMetadata = generateMetadataMatcherForInternalRoutes(metadataValue)

action1 := generateRouteAction(apiType, routeConfig, rateLimitPolicyCriteria, mirrorClusterNameList, resource.GetEnableBackendBasedAIRatelimit() && params.isAiAPI, resource.GetBackendBasedAIRatelimitDescriptorValue(), &weightedCluster, isWeightedClusters)
action2 := generateRouteAction(apiType, routeConfig, rateLimitPolicyCriteria, mirrorClusterNameList, resource.GetEnableBackendBasedAIRatelimit() && params.isAiAPI, resource.GetBackendBasedAIRatelimitDescriptorValue(), &weightedCluster, isWeightedClusters)
action1 := generateRouteAction(apiType, routeConfig, rateLimitPolicyCriteria, mirrorClusterNameList, resource.GetEnableBackendBasedAIRatelimit() && params.isAiAPI, resource.GetBackendBasedAIRatelimitDescriptorValue(), &weightedCluster, isWeightedClusters, resource.AIModelBasedRoundRobin != nil, clusterName)
action2 := generateRouteAction(apiType, routeConfig, rateLimitPolicyCriteria, mirrorClusterNameList, resource.GetEnableBackendBasedAIRatelimit() && params.isAiAPI, resource.GetBackendBasedAIRatelimitDescriptorValue(), &weightedCluster, isWeightedClusters, resource.AIModelBasedRoundRobin != nil, clusterName)

requestHeadersToRemove := make([]string, 0)
// Create route1 for current method.
Expand All @@ -1310,7 +1323,7 @@ func createRoutes(params *routeCreateParams) (routes []*routev3.Route, err error
} else {
var action *routev3.Route_Route
if requestRedirectAction == nil {
action = generateRouteAction(apiType, routeConfig, rateLimitPolicyCriteria, mirrorClusterNameList, resource.GetEnableBackendBasedAIRatelimit() && params.isAiAPI, resource.GetBackendBasedAIRatelimitDescriptorValue(), &weightedCluster, isWeightedClusters)
action = generateRouteAction(apiType, routeConfig, rateLimitPolicyCriteria, mirrorClusterNameList, resource.GetEnableBackendBasedAIRatelimit() && params.isAiAPI, resource.GetBackendBasedAIRatelimitDescriptorValue(), &weightedCluster, isWeightedClusters, resource.AIModelBasedRoundRobin != nil, clusterName)
}
logger.LoggerOasparser.Debug("Creating routes for resource with policies", resourcePath, operation.GetMethod())
// create route for current method. Add policies to route config. Send via enforcer
Expand All @@ -1337,7 +1350,7 @@ func createRoutes(params *routeCreateParams) (routes []*routev3.Route, err error
}
match := generateRouteMatch(routePath)
match.Headers = generateHTTPMethodMatcher(methodRegex, clusterName)
action := generateRouteAction(apiType, routeConfig, rateLimitPolicyCriteria, nil, resource.GetEnableBackendBasedAIRatelimit() && params.isAiAPI, resource.GetBackendBasedAIRatelimitDescriptorValue(), &weightedCluster, isWeightedClusters)
action := generateRouteAction(apiType, routeConfig, rateLimitPolicyCriteria, nil, resource.GetEnableBackendBasedAIRatelimit() && params.isAiAPI, resource.GetBackendBasedAIRatelimitDescriptorValue(), &weightedCluster, isWeightedClusters, resource.AIModelBasedRoundRobin != nil, clusterName)
rewritePath := generateRoutePathForReWrite(basePath, resourcePath, pathMatchType)
action.Route.RegexRewrite = generateRegexMatchAndSubstitute(rewritePath, resourcePath, pathMatchType)
requestHeadersToRemove := make([]string, 0)
Expand Down
5 changes: 3 additions & 2 deletions adapter/internal/oasparser/model/adapter_internal_api.go
Original file line number Diff line number Diff line change
Expand Up @@ -537,7 +537,7 @@ func (adapterInternalAPI *AdapterInternalAPI) Validate() error {

// SetInfoHTTPRouteCR populates resources and endpoints of adapterInternalAPI. httpRoute.Spec.Rules.Matches
// are used to create resources and httpRoute.Spec.Rules.BackendRefs are used to create EndpointClusters.
func (adapterInternalAPI *AdapterInternalAPI) SetInfoHTTPRouteCR(httpRoute *gwapiv1.HTTPRoute, resourceParams ResourceParams, ruleIdxToAiRatelimitPolicyMapping map[int]*dpv1alpha3.AIRateLimitPolicy, extractTokenFrom string) error {
func (adapterInternalAPI *AdapterInternalAPI) SetInfoHTTPRouteCR(httpRoute *gwapiv1.HTTPRoute, resourceParams ResourceParams, ruleIdxToAiRatelimitPolicyMapping map[int]*dpv1alpha3.AIRateLimitPolicy, extractTokenFrom string, sendToEnforcer bool) error {
var resources []*Resource
outputAuthScheme := utils.TieBreaker(utils.GetPtrSlice(maps.Values(resourceParams.AuthSchemes)))
outputAPIPolicy := utils.TieBreaker(utils.GetPtrSlice(maps.Values(resourceParams.APIPolicies)))
Expand Down Expand Up @@ -984,7 +984,7 @@ func (adapterInternalAPI *AdapterInternalAPI) SetInfoHTTPRouteCR(httpRoute *gwap
loggers.LoggerAPI.Debugf("ModelBasedRoundRobin extracted %v", extracted)
modelBasedRoundRobin = extracted
}

loggers.LoggerAPI.Debugf("resource path %+v methods %+v sendtoenforcer %+v", resourcePath, operations, sendToEnforcer || enableBackendBasedAIRatelimit)
resource := &Resource{
path: resourcePath,
methods: operations,
Expand All @@ -996,6 +996,7 @@ func (adapterInternalAPI *AdapterInternalAPI) SetInfoHTTPRouteCR(httpRoute *gwap
backendBasedAIRatelimitDescriptorValue: descriptorValue,
extractTokenFrom: extractTokenFrom,
AIModelBasedRoundRobin: modelBasedRoundRobin,
sendToEnforcer: sendToEnforcer || enableBackendBasedAIRatelimit,
}

resource.endpoints = &EndpointCluster{
Expand Down
6 changes: 6 additions & 0 deletions adapter/internal/oasparser/model/resource.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ type Resource struct {
enableBackendBasedAIRatelimit bool
backendBasedAIRatelimitDescriptorValue string
extractTokenFrom string
sendToEnforcer bool
}

// GetEndpointSecurity returns the endpoint security object of a given resource.
Expand Down Expand Up @@ -213,3 +214,8 @@ func (resource *Resource) GetBackendBasedAIRatelimitDescriptorValue() string {
func (resource *Resource) GetExtractTokenFromValue() string {
return resource.extractTokenFrom
}

// ShouldSendToEnforcer returns the value of sendToEnforcer
func (resource *Resource) ShouldSendToEnforcer() bool {
return resource.sendToEnforcer
}
3 changes: 3 additions & 0 deletions adapter/internal/operator/controllers/dp/api_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -978,6 +978,7 @@ func (apiReconciler *APIReconciler) getAPIPolicyChildrenRefs(ctx context.Context
aiProviderPtr := utils.GetAIProvider(ctx, apiReconciler.client, apiPolicy.Namespace,
apiPolicy.Spec.Default.AIProvider.Name, &api)
if aiProviderPtr != nil {
loggers.LoggerAPKOperator.Debugf("API Name: %s, AI Provider: %+v", api.Spec.APIName, aiProviderPtr)
aiProvider = aiProviderPtr
}
}
Expand Down Expand Up @@ -1009,6 +1010,7 @@ func (apiReconciler *APIReconciler) getAPIPolicyChildrenRefs(ctx context.Context
aiProviderPtr := utils.GetAIProvider(ctx, apiReconciler.client, apiPolicy.Namespace,
apiPolicy.Spec.Override.AIProvider.Name, &api)
if aiProviderPtr != nil {
loggers.LoggerAPKOperator.Debugf("API Name: %s, AI Provider: %+v", api.Spec.APIName, aiProviderPtr)
aiProvider = aiProviderPtr
}
}
Expand Down Expand Up @@ -1152,6 +1154,7 @@ func (apiReconciler *APIReconciler) getAPIPolicyChildrenRefs(ctx context.Context
}
}
}
loggers.LoggerAPKOperator.Debugf("API Name: %s, AI Provider: %+v", api.Spec.APIName, aiProvider)
return interceptorServices, backendJWTs, subscriptionValidation, aiProvider, resolvedModelBasedRoundRobin, nil
}

Expand Down
19 changes: 18 additions & 1 deletion adapter/internal/operator/synchronizer/rest_api.go
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,24 @@ func generateAdapterInternalAPI(apiState APIState, httpRouteState *HTTPRouteStat
RateLimitPolicies: apiState.RateLimitPolicies,
ResourceRateLimitPolicies: apiState.ResourceRateLimitPolicies,
}
if err := adapterInternalAPI.SetInfoHTTPRouteCR(httpRouteState.HTTPRouteCombined, resourceParams, httpRouteState.RuleIdxToAiRatelimitPolicyMapping, apiState.AIProvider.Spec.RateLimitFields.PromptTokens.In); err != nil {
sendToEnforcer := false
if config.ReadConfigs().Analytics.Enabled {
loggers.LoggerAPKOperator.Infof("Analytics is enabled for API: %v", apiState.APIDefinition.Name)
sendToEnforcer = true
}
if apiState.BackendJWTMapping != nil && len(apiState.BackendJWTMapping) > 0 {
sendToEnforcer = true
}
if apiState.APIDefinition.Spec.APIType == "GRPC" {
sendToEnforcer = true
}
if apiState.MutualSSL != nil {
sendToEnforcer = !apiState.MutualSSL.Disabled
}
if (apiState.AIProvider != nil && apiState.AIProvider.Name != "") || apiState.SubscriptionValidation {
sendToEnforcer = true
}
if err := adapterInternalAPI.SetInfoHTTPRouteCR(httpRouteState.HTTPRouteCombined, resourceParams, httpRouteState.RuleIdxToAiRatelimitPolicyMapping, apiState.AIProvider.Spec.RateLimitFields.PromptTokens.In, sendToEnforcer); err != nil {
loggers.LoggerAPKOperator.ErrorC(logging.PrintError(logging.Error2631, logging.MAJOR, "Error setting HttpRoute CR info to adapterInternalAPI. %v", err))
return nil, err
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ func NewAuthenticator(cfg *config.Server, subAppDataStore *datastore.Subscriptio
// Authenticate performs the authentication.
func (authenticator *Authenticator) Authenticate(rch *requestconfig.Holder) *dto.ImmediateResponse {

if rch != nil && rch.MatchedAPI != nil {
if rch != nil && rch.MatchedAPI != nil {//&& rch.MatchedAPI.IsGraphQLAPI() {
applicationSecurity := rch.MatchedAPI.ApplicationSecurity
var optionalAuthenticationResponse *AuthenticationResponse
var authenticationResponse AuthenticationResponse
Expand Down Expand Up @@ -71,11 +71,13 @@ func (authenticator *Authenticator) Authenticate(rch *requestconfig.Holder) *dto
}
if !authenticated {
if mandatoryAuthFailed || optionalAuthenticationResponse == nil {
authenticator.cfg.Logger.Sugar().Debugf("Authentication failed for the request. Responses: %+v", authenticationResponses)
errorResponse := getError(authenticationResponses)
jsonData, _ := json.MarshalIndent(errorResponse, "", " ")
return &dto.ImmediateResponse{StatusCode: 401, Message: string(jsonData)}

} else if !(optionalAuthenticationResponse.Authenticated) {
authenticator.cfg.Logger.Sugar().Debugf("Authentication failed for the request. Responses: %+v", authenticationResponses)
errorResponse := &dto.ErrorResponse{ErrorMessage: optionalAuthenticationResponse.ErrorMessage, Code: optionalAuthenticationResponse.ErrorCode, ErrorDescription: "Make sure you have provided the correct security credentials"}
jsonData, _ := json.MarshalIndent(errorResponse, "", " ")
return &dto.ImmediateResponse{StatusCode: 401, Message: string(jsonData)}
Expand Down
Loading
Loading