diff --git a/adapter/internal/controlplane/eventPublisher.go b/adapter/internal/controlplane/eventPublisher.go index edef827a6..044110211 100644 --- a/adapter/internal/controlplane/eventPublisher.go +++ b/adapter/internal/controlplane/eventPublisher.go @@ -76,33 +76,35 @@ type APICPEvent struct { // API holds the data that needs to be sent to agent type API struct { - APIUUID string `json:"apiUUID"` - APIName string `json:"apiName"` - APIVersion string `json:"apiVersion"` - IsDefaultVersion bool `json:"isDefaultVersion"` - Definition string `json:"definition"` - APIType string `json:"apiType"` - APISubType string `json:"apiSubType"` - BasePath string `json:"basePath"` - Organization string `json:"organization"` - SystemAPI bool `json:"systemAPI"` - APIProperties map[string]string `json:"apiProperties,omitempty"` - Environment string `json:"environment,omitempty"` - RevisionID string `json:"revisionID"` - SandEndpoint string `json:"sandEndpoint"` - ProdEndpoint string `json:"prodEndpoint"` - EndpointProtocol string `json:"endpointProtocol"` - CORSPolicy *CORSPolicy `json:"cORSPolicy,omitempty"` - Vhost string `json:"vhost"` - SandVhost string `json:"sandVhost"` - SecurityScheme []string `json:"securityScheme"` - AuthHeader string `json:"authHeader"` - APIKeyHeader string `json:"apiKeyHeader"` - Operations []Operation `json:"operations"` - AIConfiguration AIConfiguration `json:"aiConfiguration"` - APIHash string `json:"-"` - SandAIRL *AIRL `json:"sandAIRL"` - ProdAIRL *AIRL `json:"prodAIRL"` + APIUUID string `json:"apiUUID"` + APIName string `json:"apiName"` + APIVersion string `json:"apiVersion"` + IsDefaultVersion bool `json:"isDefaultVersion"` + Definition string `json:"definition"` + APIType string `json:"apiType"` + APISubType string `json:"apiSubType"` + BasePath string `json:"basePath"` + Organization string `json:"organization"` + SystemAPI bool `json:"systemAPI"` + APIProperties map[string]string `json:"apiProperties,omitempty"` + Environment string `json:"environment,omitempty"` + RevisionID string `json:"revisionID"` + SandEndpoint string `json:"sandEndpoint"` + SandEndpointSecurity EndpointSecurity `json:"sandEndpointSecurity"` + ProdEndpoint string `json:"prodEndpoint"` + ProdEndpointSecurity EndpointSecurity `json:"prodEndpointSecurity"` + EndpointProtocol string `json:"endpointProtocol"` + CORSPolicy *CORSPolicy `json:"cORSPolicy,omitempty"` + Vhost string `json:"vhost"` + SandVhost string `json:"sandVhost"` + SecurityScheme []string `json:"securityScheme"` + AuthHeader string `json:"authHeader"` + APIKeyHeader string `json:"apiKeyHeader"` + Operations []Operation `json:"operations"` + AIConfiguration AIConfiguration `json:"aiConfiguration"` + APIHash string `json:"-"` + SandAIRL *AIRL `json:"sandAIRL"` + ProdAIRL *AIRL `json:"prodAIRL"` } // AIRL holds AI ratelimit related data @@ -114,6 +116,17 @@ type AIRL struct { RequestCount *uint32 `json:"requestCount"` } +// EndpointSecurity holds the endpoint security information +type EndpointSecurity struct { + Enabled bool `json:"enabled"` + SecurityType string `json:"securityType"` + APIKeyName string `json:"apiKeyName"` + APIKeyValue string `json:"apiKeyValue"` + APIKeyIn string `json:"apiKeyIn"` + BasicUsername string `json:"basicUsername"` + BasicPassword string `json:"basicPassword"` +} + // AIConfiguration holds the AI configuration type AIConfiguration struct { LLMProviderID string `json:"llmProviderID"` diff --git a/adapter/internal/operator/controllers/dp/api_controller.go b/adapter/internal/operator/controllers/dp/api_controller.go index 7810b4c3a..283e8dd01 100644 --- a/adapter/internal/operator/controllers/dp/api_controller.go +++ b/adapter/internal/operator/controllers/dp/api_controller.go @@ -2918,7 +2918,7 @@ func (apiReconciler *APIReconciler) convertAPIStateToAPICp(ctx context.Context, for _, val := range spec.APIProperties { properties[val.Name] = val.Value } - prodEndpoint, sandEndpoint, endpointProtocol := findProdSandEndpoints(&apiState) + prodEndpoint, sandEndpoint, endpointProtocol, prodAPIKeyName, prodAPIKeyIn, prodAPIKeyValue, prodBasicUsername, prodBasicPassword, sandAPIKeyName, sandAPIKeyIn, sandAPIKeyValue, sandBasicUsername, sandBasicPassword, prodEndpointSecurityType, sandEndpointSecurityType, prodEndpointSecurityEnabled, sandEndpointSecurityEnabled := findProdSandEndpoints(&apiState) corsPolicy := pickOneCorsForCP(&apiState) vhost := getProdVhost(&apiState) sandVhost := geSandVhost(&apiState) @@ -2968,6 +2968,24 @@ func (apiReconciler *APIReconciler) convertAPIStateToAPICp(ctx context.Context, RequestCount: requestC, } } + prodEndpointSecurity := controlplane.EndpointSecurity{ + Enabled: prodEndpointSecurityEnabled, + SecurityType: prodEndpointSecurityType, + APIKeyName: prodAPIKeyName, + APIKeyIn: prodAPIKeyIn, + APIKeyValue: prodAPIKeyValue, + BasicUsername: prodBasicUsername, + BasicPassword: prodBasicPassword, + } + sandEndpointSecurity := controlplane.EndpointSecurity{ + Enabled: sandEndpointSecurityEnabled, + SecurityType: sandEndpointSecurityType, + APIKeyName: sandAPIKeyName, + APIKeyIn: sandAPIKeyIn, + APIKeyValue: sandAPIKeyValue, + BasicUsername: sandBasicUsername, + BasicPassword: sandBasicPassword, + } subType := "DEFAULT" aiConfiguration := controlplane.AIConfiguration{} loggers.LoggerAPKOperator.Debugf("AI Provider in state: %+v", apiState.AIProvider) @@ -2983,33 +3001,35 @@ func (apiReconciler *APIReconciler) convertAPIStateToAPICp(ctx context.Context, loggers.LoggerAPKOperator.Debugf("Resolved aiConfiguration: %+v", aiConfiguration) api := controlplane.API{ - APIName: spec.APIName, - APIVersion: spec.APIVersion, - IsDefaultVersion: spec.IsDefaultVersion, - APIType: spec.APIType, - APISubType: subType, - BasePath: spec.BasePath, - Organization: spec.Organization, - Environment: spec.Environment, - SystemAPI: spec.SystemAPI, - Definition: apiDef, - APIUUID: apiUUID, - RevisionID: revisionID, - APIProperties: properties, - ProdEndpoint: prodEndpoint, - SandEndpoint: sandEndpoint, - EndpointProtocol: endpointProtocol, - CORSPolicy: corsPolicy, - Vhost: vhost, - SandVhost: sandVhost, - SecurityScheme: securityScheme, - AuthHeader: authHeader, - Operations: operations, - APIHash: apiHash, - APIKeyHeader: apiKeyHeader, - SandAIRL: sandAIRLToAgent, - ProdAIRL: prodAIRLToAgent, - AIConfiguration: aiConfiguration, + APIName: spec.APIName, + APIVersion: spec.APIVersion, + IsDefaultVersion: spec.IsDefaultVersion, + APIType: spec.APIType, + APISubType: subType, + BasePath: spec.BasePath, + Organization: spec.Organization, + Environment: spec.Environment, + SystemAPI: spec.SystemAPI, + Definition: apiDef, + APIUUID: apiUUID, + RevisionID: revisionID, + APIProperties: properties, + ProdEndpoint: prodEndpoint, + SandEndpoint: sandEndpoint, + ProdEndpointSecurity: prodEndpointSecurity, + SandEndpointSecurity: sandEndpointSecurity, + EndpointProtocol: endpointProtocol, + CORSPolicy: corsPolicy, + Vhost: vhost, + SandVhost: sandVhost, + SecurityScheme: securityScheme, + AuthHeader: authHeader, + Operations: operations, + APIHash: apiHash, + APIKeyHeader: apiKeyHeader, + SandAIRL: sandAIRLToAgent, + ProdAIRL: prodAIRLToAgent, + AIConfiguration: aiConfiguration, } apiCPEvent.API = api apiCPEvent.CRName = apiState.APIDefinition.ObjectMeta.Name @@ -3193,16 +3213,44 @@ func (apiReconciler *APIReconciler) getAPIHash(apiState *synchronizer.APIState) return truncatedHash } -func findProdSandEndpoints(apiState *synchronizer.APIState) (string, string, string) { +func findProdSandEndpoints(apiState *synchronizer.APIState) (string, string, string, string, string, string, string, string, string, string, string, string, string, string, string, bool, bool) { prodEndpoint := "" sandEndpoint := "" endpointProtocol := "" + prodEndpointSecurityType := "" + prodEndpointSecurityEnabled := false + prodAPIKeyName := "" + prodAPIKeyIn := "" + prodAPIKeyValue := "" + prodBasicUsername := "" + prodBasicPassword := "" + sandEndpointSecurityType := "" + sandEndpointSecurityEnabled := false + sandAPIKeyName := "" + sandAPIKeyIn := "" + sandAPIKeyValue := "" + sandBasicUsername := "" + sandBasicPassword := "" + if apiState.ProdHTTPRoute != nil { for _, backend := range apiState.ProdHTTPRoute.BackendMapping { if len(backend.Backend.Spec.Services) > 0 { prodEndpoint = fmt.Sprintf("%s:%d", backend.Backend.Spec.Services[0].Host, backend.Backend.Spec.Services[0].Port) endpointProtocol = string(backend.Backend.Spec.Protocol) } + if backend.Security.Basic.Username != "" && backend.Security.Basic.Password != "" { + prodEndpointSecurityEnabled = true + prodEndpointSecurityType = "basic" + prodBasicUsername = backend.Security.Basic.Username + prodBasicPassword = backend.Security.Basic.Password + } + if backend.Security.APIKey.Name != "" && backend.Security.APIKey.Value != "" && backend.Security.APIKey.In != "" { + prodEndpointSecurityEnabled = true + prodEndpointSecurityType = "apikey" + prodAPIKeyName = backend.Security.APIKey.Name + prodAPIKeyIn = string(backend.Security.APIKey.In) + prodAPIKeyValue = backend.Security.APIKey.Value + } } } if apiState.SandHTTPRoute != nil { @@ -3211,6 +3259,19 @@ func findProdSandEndpoints(apiState *synchronizer.APIState) (string, string, str sandEndpoint = fmt.Sprintf("%s:%d", backend.Backend.Spec.Services[0].Host, backend.Backend.Spec.Services[0].Port) endpointProtocol = string(backend.Backend.Spec.Protocol) } + if backend.Security.Basic.Username != "" && backend.Security.Basic.Password != "" { + sandEndpointSecurityEnabled = true + sandEndpointSecurityType = "basic" + sandBasicUsername = backend.Security.Basic.Username + sandBasicPassword = backend.Security.Basic.Password + } + if backend.Security.APIKey.Name != "" && backend.Security.APIKey.Value != "" && backend.Security.APIKey.In != "" { + sandEndpointSecurityEnabled = true + sandEndpointSecurityType = "apikey" + sandAPIKeyName = backend.Security.APIKey.Name + sandAPIKeyIn = string(backend.Security.APIKey.In) + sandAPIKeyValue = backend.Security.APIKey.Value + } } } if apiState.ProdGQLRoute != nil { @@ -3219,6 +3280,19 @@ func findProdSandEndpoints(apiState *synchronizer.APIState) (string, string, str prodEndpoint = fmt.Sprintf("%s:%d", backend.Backend.Spec.Services[0].Host, backend.Backend.Spec.Services[0].Port) endpointProtocol = string(backend.Backend.Spec.Protocol) } + if backend.Security.Basic.Username != "" && backend.Security.Basic.Password != "" { + prodEndpointSecurityEnabled = true + prodEndpointSecurityType = "basic" + prodBasicUsername = backend.Security.Basic.Username + prodBasicPassword = backend.Security.Basic.Password + } + if backend.Security.APIKey.Name != "" && backend.Security.APIKey.Value != "" && backend.Security.APIKey.In != "" { + prodEndpointSecurityEnabled = true + prodEndpointSecurityType = "apikey" + prodAPIKeyName = backend.Security.APIKey.Name + prodAPIKeyIn = string(backend.Security.APIKey.In) + prodAPIKeyValue = backend.Security.APIKey.Value + } } } if apiState.SandGQLRoute != nil { @@ -3227,9 +3301,22 @@ func findProdSandEndpoints(apiState *synchronizer.APIState) (string, string, str sandEndpoint = fmt.Sprintf("%s:%d", backend.Backend.Spec.Services[0].Host, backend.Backend.Spec.Services[0].Port) endpointProtocol = string(backend.Backend.Spec.Protocol) } + if backend.Security.Basic.Username != "" && backend.Security.Basic.Password != "" { + sandEndpointSecurityEnabled = true + sandEndpointSecurityType = "basic" + sandBasicUsername = backend.Security.Basic.Username + sandBasicPassword = backend.Security.Basic.Password + } + if backend.Security.APIKey.Name != "" && backend.Security.APIKey.Value != "" && backend.Security.APIKey.In != "" { + sandEndpointSecurityEnabled = true + sandEndpointSecurityType = "apikey" + sandAPIKeyName = backend.Security.APIKey.Name + sandAPIKeyIn = string(backend.Security.APIKey.In) + sandAPIKeyValue = backend.Security.APIKey.Value + } } } - return prodEndpoint, sandEndpoint, endpointProtocol + return prodEndpoint, sandEndpoint, endpointProtocol, prodAPIKeyName, prodAPIKeyIn, prodAPIKeyValue, prodBasicUsername, prodBasicPassword, sandAPIKeyName, sandAPIKeyIn, sandAPIKeyValue, sandBasicUsername, sandBasicPassword, prodEndpointSecurityType, sandEndpointSecurityType, prodEndpointSecurityEnabled, sandEndpointSecurityEnabled } func pickOneCorsForCP(apiState *synchronizer.APIState) *controlplane.CORSPolicy {