diff --git a/adapter/api/proto/wso2/discovery/api/Certificate.proto b/adapter/api/proto/wso2/discovery/api/Certificate.proto index e6421186f..34385aa31 100644 --- a/adapter/api/proto/wso2/discovery/api/Certificate.proto +++ b/adapter/api/proto/wso2/discovery/api/Certificate.proto @@ -28,6 +28,5 @@ option java_multiple_files = true; // Certificates config model message Certificate { string alias = 1; - string tier = 2; - bytes content = 3; + bytes content = 2; } diff --git a/adapter/api/proto/wso2/discovery/api/api.proto b/adapter/api/proto/wso2/discovery/api/api.proto index 887582b7b..8ce3fc9fd 100644 --- a/adapter/api/proto/wso2/discovery/api/api.proto +++ b/adapter/api/proto/wso2/discovery/api/api.proto @@ -51,6 +51,7 @@ message Api { repeated Certificate clientCertificates = 14; string mutualSSL = 15; bool applicationSecurity = 16; + bool transportSecurity = 17; /// string graphQLSchema = 22; repeated GraphqlComplexity graphqlComplexityInfo = 23; bool systemAPI = 24; diff --git a/adapter/config/default_config.go b/adapter/config/default_config.go index 6abd41fd4..3b3200b0d 100644 --- a/adapter/config/default_config.go +++ b/adapter/config/default_config.go @@ -158,7 +158,7 @@ var defaultConfig = &Config{ }, MutualSSL: mutualSSL{ CertificateHeader: "X-WSO2-CLIENT-CERTIFICATE", - EnableClientValidation: true, + EnableClientValidation: false, ClientCertificateEncode: false, EnableOutboundCertificateHeader: false, }, diff --git a/adapter/internal/oasparser/config_generator.go b/adapter/internal/oasparser/config_generator.go index 0b09afb9d..73ef25167 100644 --- a/adapter/internal/oasparser/config_generator.go +++ b/adapter/internal/oasparser/config_generator.go @@ -168,7 +168,6 @@ func GetEnforcerAPI(adapterInternalAPI model.AdapterInternalAPI, vhost string) * for _, cert := range adapterInternalAPI.GetClientCerts() { certificate := &api.Certificate{ Alias: cert.Alias, - Tier: cert.Tier, Content: cert.Content, } clientCertificates = append(clientCertificates, certificate) @@ -215,8 +214,9 @@ func GetEnforcerAPI(adapterInternalAPI model.AdapterInternalAPI, vhost string) * EndpointSecurity: generateRPCEndpointSecurity(adapterInternalAPI.EndpointSecurity), // IsMockedApi: isMockedAPI, ClientCertificates: clientCertificates, - MutualSSL: adapterInternalAPI.GetXWSO2MutualSSL(), + MutualSSL: adapterInternalAPI.GetMutualSSL(), ApplicationSecurity: adapterInternalAPI.GetXWSO2ApplicationSecurity(), + TransportSecurity: !adapterInternalAPI.GetDisableMtls(), // GraphQLSchema: adapterInternalAPI.GraphQLSchema, // GraphqlComplexityInfo: adapterInternalAPI.GraphQLComplexities.Data.List, SystemAPI: adapterInternalAPI.IsSystemAPI, diff --git a/adapter/internal/oasparser/model/adapter_internal_api.go b/adapter/internal/oasparser/model/adapter_internal_api.go index 01807d77a..80f7eb75d 100644 --- a/adapter/internal/oasparser/model/adapter_internal_api.go +++ b/adapter/internal/oasparser/model/adapter_internal_api.go @@ -58,6 +58,7 @@ type AdapterInternalAPI struct { xWso2AuthHeader string disableAuthentications bool disableScopes bool + disableMtls bool OrganizationID string IsPrototyped bool EndpointType string @@ -65,7 +66,7 @@ type AdapterInternalAPI struct { xWso2RequestBodyPass bool IsDefaultVersion bool clientCertificates []Certificate - xWso2MutualSSL string + mutualSSL string xWso2ApplicationSecurity bool EnvType string backendJWTTokenInfo *BackendJWTTokenInfo @@ -227,7 +228,6 @@ type InterceptEndpoint struct { // Certificate contains information of a client certificate type Certificate struct { Alias string - Tier string Content []byte } @@ -312,6 +312,11 @@ func (adapterInternalAPI *AdapterInternalAPI) GetDisableScopes() bool { return adapterInternalAPI.disableScopes } +// GetDisableMtls returns whether mTLS is disabled or not +func (adapterInternalAPI *AdapterInternalAPI) GetDisableMtls() bool { + return adapterInternalAPI.disableMtls +} + // GetID returns the Id of the API func (adapterInternalAPI *AdapterInternalAPI) GetID() string { return adapterInternalAPI.id @@ -335,8 +340,16 @@ func (adapterInternalAPI *AdapterInternalAPI) GetClientCerts() []Certificate { } // SetClientCerts set the client certificates of the API -func (adapterInternalAPI *AdapterInternalAPI) SetClientCerts(certs []Certificate) { - adapterInternalAPI.clientCertificates = certs +func (adapterInternalAPI *AdapterInternalAPI) SetClientCerts(apiName string, certs []string) { + var clientCerts []Certificate + for i, cert := range certs { + clientCert := Certificate{ + Alias: apiName + "-cert-" + strconv.Itoa(i), + Content: []byte(cert), + } + clientCerts = append(clientCerts, clientCert) + } + adapterInternalAPI.clientCertificates = clientCerts } // SetID set the Id of the API @@ -386,14 +399,19 @@ func (adapterInternalAPI *AdapterInternalAPI) GetXWSO2AuthHeader() string { return adapterInternalAPI.xWso2AuthHeader } -// SetXWSO2MutualSSL sets the optional or mandatory mTLS -func (adapterInternalAPI *AdapterInternalAPI) SetXWSO2MutualSSL(mutualSSl string) { - adapterInternalAPI.xWso2MutualSSL = mutualSSl +// SetMutualSSL sets the optional or mandatory mTLS +func (adapterInternalAPI *AdapterInternalAPI) SetMutualSSL(mutualSSL string) { + adapterInternalAPI.mutualSSL = mutualSSL +} + +// GetMutualSSL returns the optional or mandatory mTLS +func (adapterInternalAPI *AdapterInternalAPI) GetMutualSSL() string { + return adapterInternalAPI.mutualSSL } -// GetXWSO2MutualSSL returns the optional or mandatory mTLS -func (adapterInternalAPI *AdapterInternalAPI) GetXWSO2MutualSSL() string { - return adapterInternalAPI.xWso2MutualSSL +// SetDisableMtls returns whether mTLS is disabled or not +func (adapterInternalAPI *AdapterInternalAPI) SetDisableMtls(disableMtls bool) { + adapterInternalAPI.disableMtls = disableMtls } // SetXWSO2ApplicationSecurity sets the optional or mandatory application security @@ -451,7 +469,7 @@ func (adapterInternalAPI *AdapterInternalAPI) SetInfoHTTPRouteCR(httpRoute *gwap disableScopes := true config := config.ReadConfigs() - var authScheme *dpv1alpha1.Authentication + var authScheme *dpv1alpha2.Authentication if outputAuthScheme != nil { authScheme = *outputAuthScheme } @@ -782,7 +800,7 @@ func (adapterInternalAPI *AdapterInternalAPI) SetInfoGQLRouteCR(gqlRoute *dpv1al disableScopes := true config := config.ReadConfigs() - var authScheme *dpv1alpha1.Authentication + var authScheme *dpv1alpha2.Authentication if outputAuthScheme != nil { authScheme = *outputAuthScheme } diff --git a/adapter/internal/oasparser/model/http_route.go b/adapter/internal/oasparser/model/http_route.go index 9c18558d3..c62ededd5 100644 --- a/adapter/internal/oasparser/model/http_route.go +++ b/adapter/internal/oasparser/model/http_route.go @@ -30,8 +30,8 @@ import ( // ResourceParams contains httproute related parameters type ResourceParams struct { - AuthSchemes map[string]dpv1alpha1.Authentication - ResourceAuthSchemes map[string]dpv1alpha1.Authentication + AuthSchemes map[string]dpv1alpha2.Authentication + ResourceAuthSchemes map[string]dpv1alpha2.Authentication APIPolicies map[string]dpv1alpha2.APIPolicy ResourceAPIPolicies map[string]dpv1alpha2.APIPolicy InterceptorServiceMapping map[string]dpv1alpha1.InterceptorService @@ -207,9 +207,9 @@ func concatAPIPolicies(schemeUp *dpv1alpha2.APIPolicy, schemeDown *dpv1alpha2.AP return &apiPolicy } -func concatAuthSchemes(schemeUp *dpv1alpha1.Authentication, schemeDown *dpv1alpha1.Authentication) *dpv1alpha1.Authentication { - finalAuth := dpv1alpha1.Authentication{ - Spec: dpv1alpha1.AuthenticationSpec{}, +func concatAuthSchemes(schemeUp *dpv1alpha2.Authentication, schemeDown *dpv1alpha2.Authentication) *dpv1alpha2.Authentication { + finalAuth := dpv1alpha2.Authentication{ + Spec: dpv1alpha2.AuthenticationSpec{}, } if schemeUp != nil && schemeDown != nil { finalAuth.Spec.Override = utils.SelectPolicy(&schemeUp.Spec.Override, &schemeUp.Spec.Default, &schemeDown.Spec.Override, &schemeDown.Spec.Default) @@ -224,7 +224,7 @@ func concatAuthSchemes(schemeUp *dpv1alpha1.Authentication, schemeDown *dpv1alph // getSecurity returns security schemes and it's definitions with flag to indicate if security is disabled // make sure authscheme only has external service override values. (i.e. empty default values) // tip: use concatScheme method -func getSecurity(authScheme *dpv1alpha1.Authentication) *Authentication { +func getSecurity(authScheme *dpv1alpha2.Authentication) *Authentication { authHeader := constants.AuthorizationHeader if authScheme != nil && authScheme.Spec.Override != nil && authScheme.Spec.Override.AuthTypes != nil && len(authScheme.Spec.Override.AuthTypes.Oauth2.Header) > 0 { authHeader = authScheme.Spec.Override.AuthTypes.Oauth2.Header @@ -249,7 +249,7 @@ func getSecurity(authScheme *dpv1alpha1.Authentication) *Authentication { } else { authFound = true } - if authScheme.Spec.Override.AuthTypes.APIKey != nil { + if authScheme.Spec.Override.AuthTypes != nil && authScheme.Spec.Override.AuthTypes.APIKey != nil { authFound = authFound || len(authScheme.Spec.Override.AuthTypes.APIKey) > 0 var apiKeys []APIKey for _, apiKey := range authScheme.Spec.Override.AuthTypes.APIKey { diff --git a/adapter/internal/operator/PROJECT b/adapter/internal/operator/PROJECT index a20a3f8f3..1c9a275a4 100644 --- a/adapter/internal/operator/PROJECT +++ b/adapter/internal/operator/PROJECT @@ -129,6 +129,15 @@ resources: kind: API path: github.com/wso2/apk/adapter/internal/operator/apis/dp/v1alpha2 version: v1alpha2 +- api: + crdVersion: v1 + namespaced: true + controller: true + domain: wso2.com + group: dp + kind: Authentication + path: github.com/wso2/apk/adapter/internal/operator/apis/dp/v1alpha2 + version: v1alpha2 - api: crdVersion: v1 namespaced: true diff --git a/adapter/internal/operator/config/crd/bases/dp.wso2.com_authentications.yaml b/adapter/internal/operator/config/crd/bases/dp.wso2.com_authentications.yaml index 3a289dcb2..f1e5242cf 100644 --- a/adapter/internal/operator/config/crd/bases/dp.wso2.com_authentications.yaml +++ b/adapter/internal/operator/config/crd/bases/dp.wso2.com_authentications.yaml @@ -3,8 +3,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.9.2 - creationTimestamp: null + controller-gen.kubebuilder.io/version: v0.12.0 name: authentications.dp.wso2.com spec: group: dp.wso2.com @@ -220,6 +219,340 @@ spec: type: object type: object served: true + storage: false + subresources: + status: {} + - name: v1alpha2 + schema: + openAPIV3Schema: + description: Authentication is the Schema for the authentications API + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: AuthenticationSpec defines the desired state of Authentication + properties: + default: + description: AuthSpec specification of the authentication service + properties: + authTypes: + description: AuthTypes is to specify the authentication scheme + types and details + properties: + apiKey: + description: APIKey is to specify the APIKey authentication + scheme details + items: + description: APIKeyAuth APIKey Authentication scheme details + properties: + in: + description: In is to specify how the APIKey is passed + to the request + enum: + - Header + - Query + minLength: 1 + type: string + name: + description: Name is the name of the header or query + parameter to be used + minLength: 1 + type: string + sendTokenToUpstream: + description: SendTokenToUpstream is to specify whether + the APIKey should be sent to the upstream + type: boolean + type: object + nullable: true + type: array + mtls: + description: MutualSSL is to specify the features and certificates + for mutual SSL + properties: + certificatesInline: + description: CertificatesInline is the Inline Certificate + entry + items: + type: string + type: array + configMapRefs: + description: ConfigMapRefs denotes the reference to the + ConfigMap that contains the Certificate + items: + description: RefConfig holds a config for a secret or + a configmap + properties: + key: + description: Key of the secret or configmap + minLength: 1 + type: string + name: + description: Name of the secret or configmap + minLength: 1 + type: string + required: + - key + - name + type: object + type: array + disabled: + default: false + description: Disabled is to disable mTLS authentication + type: boolean + required: + default: optional + description: Required indicates whether mutualSSL is mandatory + or optional + enum: + - mandatory + - optional + type: string + secretRefs: + description: SecretRefs denotes the reference to the Secret + that contains the Certificate + items: + description: RefConfig holds a config for a secret or + a configmap + properties: + key: + description: Key of the secret or configmap + minLength: 1 + type: string + name: + description: Name of the secret or configmap + minLength: 1 + type: string + required: + - key + - name + type: object + type: array + type: object + oauth2: + description: Oauth2 is to specify the Oauth2 authentication + scheme details + properties: + disabled: + default: false + description: Disabled is to disable OAuth2 authentication + type: boolean + header: + default: authorization + description: Header is the header name used to pass the + OAuth2 token + type: string + sendTokenToUpstream: + description: SendTokenToUpstream is to specify whether + the OAuth2 token should be sent to the upstream + type: boolean + type: object + testConsoleKey: + description: TestConsoleKey is to specify the Test Console + Key authentication scheme details + properties: + header: + default: internal-key + description: Header is the header name used to pass the + Test Console Key + minLength: 1 + type: string + sendTokenToUpstream: + description: SendTokenToUpstream is to specify whether + the Test Console Key should be sent to the upstream + type: boolean + type: object + type: object + disabled: + description: Disabled is to disable all authentications + type: boolean + type: object + override: + description: AuthSpec specification of the authentication service + properties: + authTypes: + description: AuthTypes is to specify the authentication scheme + types and details + properties: + apiKey: + description: APIKey is to specify the APIKey authentication + scheme details + items: + description: APIKeyAuth APIKey Authentication scheme details + properties: + in: + description: In is to specify how the APIKey is passed + to the request + enum: + - Header + - Query + minLength: 1 + type: string + name: + description: Name is the name of the header or query + parameter to be used + minLength: 1 + type: string + sendTokenToUpstream: + description: SendTokenToUpstream is to specify whether + the APIKey should be sent to the upstream + type: boolean + type: object + nullable: true + type: array + mtls: + description: MutualSSL is to specify the features and certificates + for mutual SSL + properties: + certificatesInline: + description: CertificatesInline is the Inline Certificate + entry + items: + type: string + type: array + configMapRefs: + description: ConfigMapRefs denotes the reference to the + ConfigMap that contains the Certificate + items: + description: RefConfig holds a config for a secret or + a configmap + properties: + key: + description: Key of the secret or configmap + minLength: 1 + type: string + name: + description: Name of the secret or configmap + minLength: 1 + type: string + required: + - key + - name + type: object + type: array + disabled: + default: false + description: Disabled is to disable mTLS authentication + type: boolean + required: + default: optional + description: Required indicates whether mutualSSL is mandatory + or optional + enum: + - mandatory + - optional + type: string + secretRefs: + description: SecretRefs denotes the reference to the Secret + that contains the Certificate + items: + description: RefConfig holds a config for a secret or + a configmap + properties: + key: + description: Key of the secret or configmap + minLength: 1 + type: string + name: + description: Name of the secret or configmap + minLength: 1 + type: string + required: + - key + - name + type: object + type: array + type: object + oauth2: + description: Oauth2 is to specify the Oauth2 authentication + scheme details + properties: + disabled: + default: false + description: Disabled is to disable OAuth2 authentication + type: boolean + header: + default: authorization + description: Header is the header name used to pass the + OAuth2 token + type: string + sendTokenToUpstream: + description: SendTokenToUpstream is to specify whether + the OAuth2 token should be sent to the upstream + type: boolean + type: object + testConsoleKey: + description: TestConsoleKey is to specify the Test Console + Key authentication scheme details + properties: + header: + default: internal-key + description: Header is the header name used to pass the + Test Console Key + minLength: 1 + type: string + sendTokenToUpstream: + description: SendTokenToUpstream is to specify whether + the Test Console Key should be sent to the upstream + type: boolean + type: object + type: object + disabled: + description: Disabled is to disable all authentications + type: boolean + type: object + targetRef: + description: PolicyTargetReference identifies an API object to apply + policy to. This should be used as part of Policy resources that + can target Gateway API resources. For more information on how this + policy attachment model works, and a sample Policy resource, refer + to the policy attachment documentation for Gateway API. + properties: + group: + description: Group is the group of the target resource. + maxLength: 253 + pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + kind: + description: Kind is kind of the target resource. + maxLength: 63 + minLength: 1 + pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ + type: string + name: + description: Name is the name of the target resource. + maxLength: 253 + minLength: 1 + type: string + namespace: + description: Namespace is the namespace of the referent. When + unspecified, the local namespace is inferred. Even when policy + targets a resource in a different namespace, it MUST only apply + to traffic originating from the same namespace as the policy. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + required: + - group + - kind + - name + type: object + type: object + status: + description: AuthenticationStatus defines the observed state of Authentication + type: object + type: object + served: true storage: true subresources: status: {} diff --git a/adapter/internal/operator/config/webhook/manifests.yaml b/adapter/internal/operator/config/webhook/manifests.yaml index 30633a719..411ed6ee8 100644 --- a/adapter/internal/operator/config/webhook/manifests.yaml +++ b/adapter/internal/operator/config/webhook/manifests.yaml @@ -2,7 +2,6 @@ apiVersion: admissionregistration.k8s.io/v1 kind: MutatingWebhookConfiguration metadata: - creationTimestamp: null name: mutating-webhook-configuration webhooks: - admissionReviewVersions: @@ -11,14 +10,14 @@ webhooks: service: name: webhook-service namespace: system - path: /mutate-dp-wso2-com-v1alpha1-api + path: /mutate-dp-wso2-com-v1alpha2-api failurePolicy: Fail name: mapi.kb.io rules: - apiGroups: - dp.wso2.com apiVersions: - - v1alpha1 + - v1alpha2 operations: - CREATE - UPDATE @@ -35,6 +34,46 @@ webhooks: failurePolicy: Fail name: mapipolicy.kb.io rules: + - apiGroups: + - dp.wso2.com + apiVersions: + - v1alpha2 + operations: + - CREATE + - UPDATE + resources: + - apipolicies + sideEffects: None +- admissionReviewVersions: + - v1 + clientConfig: + service: + name: webhook-service + namespace: system + path: /mutate-dp-wso2-com-v1alpha2-authentication + failurePolicy: Fail + name: mauthentication.kb.io + rules: + - apiGroups: + - dp.wso2.com + apiVersions: + - v1alpha2 + operations: + - CREATE + - UPDATE + resources: + - authentications + sideEffects: None +- admissionReviewVersions: + - v1 + clientConfig: + service: + name: webhook-service + namespace: system + path: /mutate-dp-wso2-com-v1alpha1-apipolicy + failurePolicy: Fail + name: mapipolicy.kb.io + rules: - apiGroups: - dp.wso2.com apiVersions: @@ -45,6 +84,26 @@ webhooks: resources: - apipolicies sideEffects: None +- admissionReviewVersions: + - v1 + clientConfig: + service: + name: webhook-service + namespace: system + path: /mutate-dp-wso2-com-v1alpha1-authentication + failurePolicy: Fail + name: mauthentication.kb.io + rules: + - apiGroups: + - dp.wso2.com + apiVersions: + - v1alpha1 + operations: + - CREATE + - UPDATE + resources: + - authentications + sideEffects: None - admissionReviewVersions: - v1 clientConfig: @@ -129,7 +188,6 @@ webhooks: apiVersion: admissionregistration.k8s.io/v1 kind: ValidatingWebhookConfiguration metadata: - creationTimestamp: null name: validating-webhook-configuration webhooks: - admissionReviewVersions: @@ -138,14 +196,14 @@ webhooks: service: name: webhook-service namespace: system - path: /validate-dp-wso2-com-v1alpha1-api + path: /validate-dp-wso2-com-v1alpha2-api failurePolicy: Fail name: vapi.kb.io rules: - apiGroups: - dp.wso2.com apiVersions: - - v1alpha1 + - v1alpha2 operations: - CREATE - UPDATE @@ -162,6 +220,46 @@ webhooks: failurePolicy: Fail name: vapipolicy.kb.io rules: + - apiGroups: + - dp.wso2.com + apiVersions: + - v1alpha2 + operations: + - CREATE + - UPDATE + resources: + - apipolicies + sideEffects: None +- admissionReviewVersions: + - v1 + clientConfig: + service: + name: webhook-service + namespace: system + path: /validate-dp-wso2-com-v1alpha2-authentication + failurePolicy: Fail + name: vauthentication.kb.io + rules: + - apiGroups: + - dp.wso2.com + apiVersions: + - v1alpha2 + operations: + - CREATE + - UPDATE + resources: + - authentications + sideEffects: None +- admissionReviewVersions: + - v1 + clientConfig: + service: + name: webhook-service + namespace: system + path: /validate-dp-wso2-com-v1alpha1-apipolicy + failurePolicy: Fail + name: vapipolicy.kb.io + rules: - apiGroups: - dp.wso2.com apiVersions: @@ -172,6 +270,26 @@ webhooks: resources: - apipolicies sideEffects: None +- admissionReviewVersions: + - v1 + clientConfig: + service: + name: webhook-service + namespace: system + path: /validate-dp-wso2-com-v1alpha1-authentication + failurePolicy: Fail + name: vauthentication.kb.io + rules: + - apiGroups: + - dp.wso2.com + apiVersions: + - v1alpha1 + operations: + - CREATE + - UPDATE + resources: + - authentications + sideEffects: None - admissionReviewVersions: - v1 clientConfig: diff --git a/adapter/internal/operator/controllers/dp/api_controller.go b/adapter/internal/operator/controllers/dp/api_controller.go index 22f5faded..f1403f1d8 100644 --- a/adapter/internal/operator/controllers/dp/api_controller.go +++ b/adapter/internal/operator/controllers/dp/api_controller.go @@ -74,6 +74,8 @@ const ( configMapBackend = "configMapBackend" configMapAPIDefinition = "configMapAPIDefinition" secretBackend = "secretBackend" + configMapAuthentication = "configMapAuthentication" + secretAuthentication = "secretAuthentication" backendHTTPRouteIndex = "backendHTTPRouteIndex" interceptorServiceAPIPolicyIndex = "interceptorServiceAPIPolicyIndex" backendInterceptorServiceIndex = "backendInterceptorServiceIndex" @@ -150,7 +152,7 @@ func NewAPIController(mgr manager.Manager, operatorDataStore *synchronizer.Opera return err } - if err := c.Watch(source.Kind(mgr.GetCache(), &dpv1alpha1.Authentication{}), handler.EnqueueRequestsFromMapFunc(apiReconciler.getAPIsForAuthentication), + if err := c.Watch(source.Kind(mgr.GetCache(), &dpv1alpha2.Authentication{}), handler.EnqueueRequestsFromMapFunc(apiReconciler.getAPIsForAuthentication), predicates...); err != nil { loggers.LoggerAPKOperator.ErrorC(logging.PrintError(logging.Error2616, logging.BLOCKER, "Error watching Authentication resources: %v", err)) return err @@ -344,6 +346,12 @@ func (apiReconciler *APIReconciler) resolveAPIRefs(ctx context.Context, api dpv1 apiRef.String(), namespace, string(api.ObjectMeta.UID), err.Error()) } } + if len(apiState.Authentications) > 0 { + if apiState.MutualSSL, err = apiReconciler.resolveAuthentications(ctx, apiState.Authentications); err != nil { + return nil, fmt.Errorf("error while resolving authentication %v in namespace: %s was not found. %s", + apiState.Authentications, namespace, err.Error()) + } + } if len(prodRouteRefs) > 0 && apiState.APIDefinition.Spec.APIType == "REST" { apiState.ProdHTTPRoute = &synchronizer.HTTPRouteState{} @@ -663,10 +671,10 @@ func (apiReconciler *APIReconciler) concatHTTPRoutes(ctx context.Context, httpRo } func (apiReconciler *APIReconciler) getAuthenticationsForAPI(ctx context.Context, - api dpv1alpha2.API) (map[string]dpv1alpha1.Authentication, error) { + api dpv1alpha2.API) (map[string]dpv1alpha2.Authentication, error) { nameSpacedName := utils.NamespacedName(&api).String() - authentications := make(map[string]dpv1alpha1.Authentication) - authenticationList := &dpv1alpha1.AuthenticationList{} + authentications := make(map[string]dpv1alpha2.Authentication) + authenticationList := &dpv1alpha2.AuthenticationList{} if err := apiReconciler.client.List(ctx, authenticationList, &k8client.ListOptions{ FieldSelector: fields.OneTermEqualSelector(apiAuthenticationIndex, nameSpacedName), }); err != nil { @@ -745,10 +753,10 @@ func (apiReconciler *APIReconciler) getScopesForHTTPRoute(ctx context.Context, } func (apiReconciler *APIReconciler) getAuthenticationsForResources(ctx context.Context, - api dpv1alpha2.API) (map[string]dpv1alpha1.Authentication, error) { + api dpv1alpha2.API) (map[string]dpv1alpha2.Authentication, error) { nameSpacedName := utils.NamespacedName(&api).String() - authentications := make(map[string]dpv1alpha1.Authentication) - authenticationList := &dpv1alpha1.AuthenticationList{} + authentications := make(map[string]dpv1alpha2.Authentication) + authenticationList := &dpv1alpha2.AuthenticationList{} if err := apiReconciler.client.List(ctx, authenticationList, &k8client.ListOptions{ FieldSelector: fields.OneTermEqualSelector(apiAuthenticationResourceIndex, nameSpacedName), }); err != nil { @@ -903,6 +911,18 @@ func (apiReconciler *APIReconciler) getAPIPolicyChildrenRefs(ctx context.Context return interceptorServices, backendJWTs, subscriptionValidation, nil } +func (apiReconciler *APIReconciler) resolveAuthentications(ctx context.Context, + authentications map[string]dpv1alpha2.Authentication) (*dpv1alpha2.MutualSSL, error) { + resolvedMutualSSL := dpv1alpha2.MutualSSL{} + for _, authentication := range authentications { + err := utils.GetResolvedMutualSSL(ctx, apiReconciler.client, authentication, &resolvedMutualSSL) + if err != nil { + return nil, err + } + } + return &resolvedMutualSSL, nil +} + func (apiReconciler *APIReconciler) getResolvedBackendsMapping(ctx context.Context, httpRouteState *synchronizer.HTTPRouteState, interceptorServiceMapping map[string]dpv1alpha1.InterceptorService, api dpv1alpha2.API) map[string]*dpv1alpha1.ResolvedBackend { @@ -1081,7 +1101,7 @@ func (apiReconciler *APIReconciler) getAPIsForSecret(ctx context.Context, obj k8 // from Authentication objects. If the changes are done for an API stored in the Operator Data store, // a new reconcile event will be created and added to the reconcile event queue. func (apiReconciler *APIReconciler) getAPIsForAuthentication(ctx context.Context, obj k8client.Object) []reconcile.Request { - authentication, ok := obj.(*dpv1alpha1.Authentication) + authentication, ok := obj.(*dpv1alpha2.Authentication) if !ok { loggers.LoggerAPKOperator.ErrorC(logging.PrintError(logging.Error2622, logging.TRIVIAL, "Unexpected object type, bypassing reconciliation: %v", authentication)) return []reconcile.Request{} @@ -1089,13 +1109,6 @@ func (apiReconciler *APIReconciler) getAPIsForAuthentication(ctx context.Context requests := []reconcile.Request{} - // todo(amali) move this validation to validation hook - if !(authentication.Spec.TargetRef.Kind == constants.KindAPI || authentication.Spec.TargetRef.Kind == constants.KindResource) { - loggers.LoggerAPKOperator.Errorf("Unsupported target ref kind : %s was given for authentication: %s", - authentication.Spec.TargetRef.Kind, authentication.Name) - return requests - } - namespace, err := utils.ValidateAndRetrieveNamespace((*gwapiv1b1.Namespace)(authentication.Spec.TargetRef.Namespace), authentication.Namespace) if err != nil { @@ -1116,8 +1129,8 @@ func (apiReconciler *APIReconciler) getAPIsForAuthentication(ctx context.Context return requests } -// getAPIForAuthentication triggers the API controller reconcile method based on the changes detected -// from Authentication objects. If the changes are done for an API stored in the Operator Data store, +// getAPIsForAPIPolicy triggers the API controller reconcile method based on the changes detected +// from APIPolicy objects. If the changes are done for an API stored in the Operator Data store, // a new reconcile event will be created and added to the reconcile event queue. func (apiReconciler *APIReconciler) getAPIsForAPIPolicy(ctx context.Context, obj k8client.Object) []reconcile.Request { apiPolicy, ok := obj.(*dpv1alpha2.APIPolicy) @@ -1200,8 +1213,8 @@ func (apiReconciler *APIReconciler) getAPIsForBackendJWT(ctx context.Context, ob return requests } -// getAPIForAuthentication triggers the API controller reconcile method based on the changes detected -// from Authentication objects. If the changes are done for an API stored in the Operator Data store, +// getAPIsForRateLimitPolicy triggers the API controller reconcile method based on the changes detected +// from RateLimitPolicy objects. If the changes are done for an API stored in the Operator Data store, // a new reconcile event will be created and added to the reconcile event queue. func (apiReconciler *APIReconciler) getAPIsForRateLimitPolicy(ctx context.Context, obj k8client.Object) []reconcile.Request { ratelimitPolicy, ok := obj.(*dpv1alpha1.RateLimitPolicy) @@ -1342,7 +1355,7 @@ func (apiReconciler *APIReconciler) getAPIsForGateway(ctx context.Context, obj k } // addIndexes adds indexing on API, for -// - prodution and sandbox HTTPRoutes +// - production and sandbox HTTPRoutes // referenced in API objects via `.spec.prodHTTPRouteRef` and `.spec.sandHTTPRouteRef` // This helps to find APIs that are affected by a HTTPRoute CRUD operation. // - authentications @@ -1533,9 +1546,9 @@ func addIndexes(ctx context.Context, mgr manager.Manager) error { } // authentication to API indexer - if err := mgr.GetFieldIndexer().IndexField(ctx, &dpv1alpha1.Authentication{}, apiAuthenticationIndex, + if err := mgr.GetFieldIndexer().IndexField(ctx, &dpv1alpha2.Authentication{}, apiAuthenticationIndex, func(rawObj k8client.Object) []string { - authentication := rawObj.(*dpv1alpha1.Authentication) + authentication := rawObj.(*dpv1alpha2.Authentication) var apis []string if authentication.Spec.TargetRef.Kind == constants.KindAPI { @@ -1558,13 +1571,81 @@ func addIndexes(ctx context.Context, mgr manager.Manager) error { return err } + // Secret to Authentication indexer + if err := mgr.GetFieldIndexer().IndexField(ctx, &dpv1alpha2.Authentication{}, secretAuthentication, + func(rawObj k8client.Object) []string { + authentication := rawObj.(*dpv1alpha2.Authentication) + var secrets []string + if authentication.Spec.Default != nil && authentication.Spec.Default.AuthTypes != nil && authentication.Spec.Default.AuthTypes.MutualSSL != nil && authentication.Spec.Default.AuthTypes.MutualSSL.SecretRefs != nil && len(authentication.Spec.Default.AuthTypes.MutualSSL.SecretRefs) > 0 { + for _, secret := range authentication.Spec.Default.AuthTypes.MutualSSL.SecretRefs { + if len(secret.Name) > 0 { + secrets = append(secrets, + types.NamespacedName{ + Name: string(secret.Name), + Namespace: authentication.Namespace, + }.String()) + } + } + } + + if authentication.Spec.Override != nil && authentication.Spec.Override.AuthTypes != nil && authentication.Spec.Override.AuthTypes.MutualSSL != nil && authentication.Spec.Override.AuthTypes.MutualSSL.SecretRefs != nil && len(authentication.Spec.Override.AuthTypes.MutualSSL.SecretRefs) > 0 { + for _, secret := range authentication.Spec.Override.AuthTypes.MutualSSL.SecretRefs { + if len(secret.Name) > 0 { + secrets = append(secrets, + types.NamespacedName{ + Name: string(secret.Name), + Namespace: authentication.Namespace, + }.String()) + } + } + + } + return secrets + }); err != nil { + return err + } + + // ConfigMap to Authentication indexer + if err := mgr.GetFieldIndexer().IndexField(ctx, &dpv1alpha2.Authentication{}, configMapAuthentication, + func(rawObj k8client.Object) []string { + authentication := rawObj.(*dpv1alpha2.Authentication) + var configMaps []string + if authentication.Spec.Default != nil && authentication.Spec.Default.AuthTypes != nil && authentication.Spec.Default.AuthTypes.MutualSSL != nil && authentication.Spec.Default.AuthTypes.MutualSSL.ConfigMapRefs != nil && len(authentication.Spec.Default.AuthTypes.MutualSSL.ConfigMapRefs) > 0 { + for _, configMap := range authentication.Spec.Default.AuthTypes.MutualSSL.ConfigMapRefs { + if len(configMap.Name) > 0 { + configMaps = append(configMaps, + types.NamespacedName{ + Name: string(configMap.Name), + Namespace: authentication.Namespace, + }.String()) + } + } + } + + if authentication.Spec.Override != nil && authentication.Spec.Override.AuthTypes != nil && authentication.Spec.Override.AuthTypes.MutualSSL != nil && authentication.Spec.Override.AuthTypes.MutualSSL.ConfigMapRefs != nil && len(authentication.Spec.Override.AuthTypes.MutualSSL.ConfigMapRefs) > 0 { + for _, configMap := range authentication.Spec.Override.AuthTypes.MutualSSL.ConfigMapRefs { + if len(configMap.Name) > 0 { + configMaps = append(configMaps, + types.NamespacedName{ + Name: string(configMap.Name), + Namespace: authentication.Namespace, + }.String()) + } + } + + } + return configMaps + }); err != nil { + return err + } + // Till the below is httproute rule name and targetref sectionname is supported, // https://gateway-api.sigs.k8s.io/geps/gep-713/?h=multiple+targetrefs#apply-policies-to-sections-of-a-resource-future-extension // we will use a temporary kindName called Resource for policy attachments // TODO(amali) Fix after the official support is available - if err := mgr.GetFieldIndexer().IndexField(ctx, &dpv1alpha1.Authentication{}, apiAuthenticationResourceIndex, + if err := mgr.GetFieldIndexer().IndexField(ctx, &dpv1alpha2.Authentication{}, apiAuthenticationResourceIndex, func(rawObj k8client.Object) []string { - authentication := rawObj.(*dpv1alpha1.Authentication) + authentication := rawObj.(*dpv1alpha2.Authentication) var apis []string if authentication.Spec.TargetRef.Kind == constants.KindResource { @@ -1714,20 +1795,6 @@ func addIndexes(ctx context.Context, mgr manager.Manager) error { Name: string(apiPolicy.Spec.Override.BackendJWTPolicy.Name), }.String()) } - if apiPolicy.Spec.Default != nil && apiPolicy.Spec.Default.BackendJWTPolicy != nil { - backendJWTs = append(backendJWTs, - types.NamespacedName{ - Namespace: apiPolicy.Namespace, - Name: string(apiPolicy.Spec.Default.BackendJWTPolicy.Name), - }.String()) - } - if apiPolicy.Spec.Override != nil && apiPolicy.Spec.Override.BackendJWTPolicy != nil { - backendJWTs = append(backendJWTs, - types.NamespacedName{ - Namespace: apiPolicy.Namespace, - Name: string(apiPolicy.Spec.Override.BackendJWTPolicy.Name), - }.String()) - } return backendJWTs }); err != nil { return err diff --git a/adapter/internal/operator/synchronizer/api_state.go b/adapter/internal/operator/synchronizer/api_state.go index 41e5c2fe4..e15717249 100644 --- a/adapter/internal/operator/synchronizer/api_state.go +++ b/adapter/internal/operator/synchronizer/api_state.go @@ -32,9 +32,9 @@ type APIState struct { SandHTTPRoute *HTTPRouteState ProdGQLRoute *GQLRouteState SandGQLRoute *GQLRouteState - Authentications map[string]v1alpha1.Authentication + Authentications map[string]v1alpha2.Authentication RateLimitPolicies map[string]v1alpha1.RateLimitPolicy - ResourceAuthentications map[string]v1alpha1.Authentication + ResourceAuthentications map[string]v1alpha2.Authentication ResourceRateLimitPolicies map[string]v1alpha1.RateLimitPolicy ResourceAPIPolicies map[string]v1alpha2.APIPolicy APIPolicies map[string]v1alpha2.APIPolicy @@ -43,6 +43,7 @@ type APIState struct { APIDefinitionFile []byte OldOrganizationID string SubscriptionValidation bool + MutualSSL *v1alpha2.MutualSSL } // HTTPRouteState holds the state of the deployed httpRoutes. This state is compared with diff --git a/adapter/internal/operator/synchronizer/data_store.go b/adapter/internal/operator/synchronizer/data_store.go index 9f09a9ed7..80265707d 100644 --- a/adapter/internal/operator/synchronizer/data_store.go +++ b/adapter/internal/operator/synchronizer/data_store.go @@ -150,6 +150,7 @@ func (ods *OperatorDataStore) processAPIState(apiNamespacedName types.Namespaced } if len(apiState.Authentications) != len(cachedAPI.Authentications) { cachedAPI.Authentications = apiState.Authentications + cachedAPI.MutualSSL = apiState.MutualSSL updated = true events = append(events, "Authentications") } else { @@ -157,12 +158,14 @@ func (ods *OperatorDataStore) processAPIState(apiNamespacedName types.Namespaced if existingAuth, found := cachedAPI.Authentications[key]; found { if auth.UID != existingAuth.UID || auth.Generation > existingAuth.Generation { cachedAPI.Authentications = apiState.Authentications + cachedAPI.MutualSSL = apiState.MutualSSL updated = true events = append(events, "Authentications") break } } else { cachedAPI.Authentications = apiState.Authentications + cachedAPI.MutualSSL = apiState.MutualSSL updated = true events = append(events, "Authentications") break diff --git a/adapter/internal/operator/synchronizer/rest_api.go b/adapter/internal/operator/synchronizer/rest_api.go index 652e6ac7a..bb968145c 100644 --- a/adapter/internal/operator/synchronizer/rest_api.go +++ b/adapter/internal/operator/synchronizer/rest_api.go @@ -58,6 +58,13 @@ func GenerateAdapterInternalAPI(apiState APIState, httpRoute *HTTPRouteState, en adapterInternalAPI.SetAPIDefinitionFile(apiState.APIDefinitionFile) adapterInternalAPI.SetAPIDefinitionEndpoint(apiState.APIDefinition.Spec.DefinitionPath) adapterInternalAPI.SetSubscriptionValidation(apiState.SubscriptionValidation) + if apiState.MutualSSL != nil && apiState.MutualSSL.Required != "" && !adapterInternalAPI.GetDisableAuthentications() { + adapterInternalAPI.SetDisableMtls(apiState.MutualSSL.Disabled) + adapterInternalAPI.SetMutualSSL(apiState.MutualSSL.Required) + adapterInternalAPI.SetClientCerts(apiState.APIDefinition.Name, apiState.MutualSSL.ClientCertificates) + } else { + adapterInternalAPI.SetDisableMtls(true) + } adapterInternalAPI.EnvType = envType environment := apiState.APIDefinition.Spec.Environment diff --git a/adapter/internal/operator/synchronizer/zz_generated.deepcopy.go b/adapter/internal/operator/synchronizer/zz_generated.deepcopy.go index eef2fda32..f2dc5002c 100644 --- a/adapter/internal/operator/synchronizer/zz_generated.deepcopy.go +++ b/adapter/internal/operator/synchronizer/zz_generated.deepcopy.go @@ -58,7 +58,7 @@ func (in *APIState) DeepCopyInto(out *APIState) { } if in.Authentications != nil { in, out := &in.Authentications, &out.Authentications - *out = make(map[string]v1alpha1.Authentication, len(*in)) + *out = make(map[string]v1alpha2.Authentication, len(*in)) for key, val := range *in { (*out)[key] = *val.DeepCopy() } @@ -72,7 +72,7 @@ func (in *APIState) DeepCopyInto(out *APIState) { } if in.ResourceAuthentications != nil { in, out := &in.ResourceAuthentications, &out.ResourceAuthentications - *out = make(map[string]v1alpha1.Authentication, len(*in)) + *out = make(map[string]v1alpha2.Authentication, len(*in)) for key, val := range *in { (*out)[key] = *val.DeepCopy() } @@ -117,6 +117,11 @@ func (in *APIState) DeepCopyInto(out *APIState) { *out = make([]byte, len(*in)) copy(*out, *in) } + if in.MutualSSL != nil { + in, out := &in.MutualSSL, &out.MutualSSL + *out = new(v1alpha2.MutualSSL) + (*in).DeepCopyInto(*out) + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new APIState. diff --git a/adapter/internal/operator/utils/utils.go b/adapter/internal/operator/utils/utils.go index c90f88950..f9e66c596 100644 --- a/adapter/internal/operator/utils/utils.go +++ b/adapter/internal/operator/utils/utils.go @@ -455,6 +455,54 @@ func getResolvedBackendSecurity(ctx context.Context, client k8client.Client, return resolvedSecurity } +// GetResolvedMutualSSL resolves mTLS related security configurations. +func GetResolvedMutualSSL(ctx context.Context, client k8client.Client, authentication dpv1alpha2.Authentication, resolvedMutualSSL *dpv1alpha2.MutualSSL) error { + var mutualSSL *dpv1alpha2.MutualSSLConfig + authSpec := SelectPolicy(&authentication.Spec.Override, &authentication.Spec.Default, nil, nil) + if authSpec.AuthTypes != nil { + mutualSSL = authSpec.AuthTypes.MutualSSL + } + + if mutualSSL != nil { + resolvedCertificates, err := ResolveAllmTLSCertificates(ctx, mutualSSL, client, authentication.Namespace) + resolvedMutualSSL.Disabled = mutualSSL.Disabled + resolvedMutualSSL.Required = mutualSSL.Required + resolvedMutualSSL.ClientCertificates = append(resolvedMutualSSL.ClientCertificates, resolvedCertificates...) + + if err != nil { + loggers.LoggerAPKOperator.ErrorC(logging.PrintError(logging.Error2622, logging.TRIVIAL, "Error in resolving mutual SSL %v in authentication", mutualSSL)) + return err + } + } + return nil +} + +// ResolveAllmTLSCertificates resolves all mTLS certificates +func ResolveAllmTLSCertificates(ctx context.Context, mutualSSL *dpv1alpha2.MutualSSLConfig, client k8client.Client, namespace string) ([]string, error) { + var resolvedCertificates []string + var err error + var certificate string + if mutualSSL.CertificatesInline != nil { + for _, cert := range mutualSSL.CertificatesInline { + certificate, err = ResolveCertificate(ctx, client, namespace, cert, nil, nil) + resolvedCertificates = append(resolvedCertificates, certificate) + } + } + if mutualSSL.ConfigMapRefs != nil { + for _, cert := range mutualSSL.ConfigMapRefs { + certificate, err = ResolveCertificate(ctx, client, namespace, nil, ConvertRefConfigsV2ToV1(cert), nil) + resolvedCertificates = append(resolvedCertificates, certificate) + } + } + if mutualSSL.SecretRefs != nil { + for _, cert := range mutualSSL.SecretRefs { + certificate, err = ResolveCertificate(ctx, client, namespace, nil, nil, ConvertRefConfigsV2ToV1(cert)) + resolvedCertificates = append(resolvedCertificates, certificate) + } + } + return resolvedCertificates, err +} + // ResolveCertificate reads the certificate from TLSConfig, first checks the certificateInline field, // if no value then load the certificate from secretRef using util function called getSecretValue func ResolveCertificate(ctx context.Context, client k8client.Client, namespace string, certificateInline *string, diff --git a/adapter/pkg/discovery/api/wso2/discovery/api/Certificate.pb.go b/adapter/pkg/discovery/api/wso2/discovery/api/Certificate.pb.go index e0e7aae0e..e316804df 100644 --- a/adapter/pkg/discovery/api/wso2/discovery/api/Certificate.pb.go +++ b/adapter/pkg/discovery/api/wso2/discovery/api/Certificate.pb.go @@ -43,8 +43,7 @@ type Certificate struct { unknownFields protoimpl.UnknownFields Alias string `protobuf:"bytes,1,opt,name=alias,proto3" json:"alias,omitempty"` - Tier string `protobuf:"bytes,2,opt,name=tier,proto3" json:"tier,omitempty"` - Content []byte `protobuf:"bytes,3,opt,name=content,proto3" json:"content,omitempty"` + Content []byte `protobuf:"bytes,2,opt,name=content,proto3" json:"content,omitempty"` } func (x *Certificate) Reset() { @@ -86,13 +85,6 @@ func (x *Certificate) GetAlias() string { return "" } -func (x *Certificate) GetTier() string { - if x != nil { - return x.Tier - } - return "" -} - func (x *Certificate) GetContent() []byte { if x != nil { return x.Content @@ -106,20 +98,19 @@ var file_wso2_discovery_api_Certificate_proto_rawDesc = []byte{ 0x0a, 0x24, 0x77, 0x73, 0x6f, 0x32, 0x2f, 0x64, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x79, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x12, 0x77, 0x73, 0x6f, 0x32, 0x2e, 0x64, 0x69, 0x73, - 0x63, 0x6f, 0x76, 0x65, 0x72, 0x79, 0x2e, 0x61, 0x70, 0x69, 0x22, 0x51, 0x0a, 0x0b, 0x43, 0x65, + 0x63, 0x6f, 0x76, 0x65, 0x72, 0x79, 0x2e, 0x61, 0x70, 0x69, 0x22, 0x3d, 0x0a, 0x0b, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x61, 0x6c, 0x69, 0x61, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x61, 0x6c, 0x69, 0x61, 0x73, 0x12, - 0x12, 0x0a, 0x04, 0x74, 0x69, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, - 0x69, 0x65, 0x72, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x18, 0x03, - 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x42, 0x78, 0x0a, - 0x23, 0x6f, 0x72, 0x67, 0x2e, 0x77, 0x73, 0x6f, 0x32, 0x2e, 0x61, 0x70, 0x6b, 0x2e, 0x65, 0x6e, - 0x66, 0x6f, 0x72, 0x63, 0x65, 0x72, 0x2e, 0x64, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x79, - 0x2e, 0x61, 0x70, 0x69, 0x42, 0x10, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, - 0x65, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x3d, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, - 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x65, 0x6e, 0x76, 0x6f, 0x79, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2f, - 0x67, 0x6f, 0x2d, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x2d, 0x70, 0x6c, 0x61, 0x6e, 0x65, - 0x2f, 0x77, 0x73, 0x6f, 0x32, 0x2f, 0x64, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x79, 0x2f, - 0x61, 0x70, 0x69, 0x3b, 0x61, 0x70, 0x69, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x18, 0x0a, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, + 0x52, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x42, 0x78, 0x0a, 0x23, 0x6f, 0x72, 0x67, + 0x2e, 0x77, 0x73, 0x6f, 0x32, 0x2e, 0x61, 0x70, 0x6b, 0x2e, 0x65, 0x6e, 0x66, 0x6f, 0x72, 0x63, + 0x65, 0x72, 0x2e, 0x64, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x79, 0x2e, 0x61, 0x70, 0x69, + 0x42, 0x10, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x50, 0x72, 0x6f, + 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x3d, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, + 0x2f, 0x65, 0x6e, 0x76, 0x6f, 0x79, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2f, 0x67, 0x6f, 0x2d, 0x63, + 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x2d, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2f, 0x77, 0x73, 0x6f, + 0x32, 0x2f, 0x64, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x79, 0x2f, 0x61, 0x70, 0x69, 0x3b, + 0x61, 0x70, 0x69, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/adapter/pkg/discovery/api/wso2/discovery/api/api.pb.go b/adapter/pkg/discovery/api/wso2/discovery/api/api.pb.go index c306038f6..a711b1c78 100644 --- a/adapter/pkg/discovery/api/wso2/discovery/api/api.pb.go +++ b/adapter/pkg/discovery/api/wso2/discovery/api/api.pb.go @@ -59,6 +59,7 @@ type Api struct { ClientCertificates []*Certificate `protobuf:"bytes,14,rep,name=clientCertificates,proto3" json:"clientCertificates,omitempty"` MutualSSL string `protobuf:"bytes,15,opt,name=mutualSSL,proto3" json:"mutualSSL,omitempty"` ApplicationSecurity bool `protobuf:"varint,16,opt,name=applicationSecurity,proto3" json:"applicationSecurity,omitempty"` + TransportSecurity bool `protobuf:"varint,17,opt,name=transportSecurity,proto3" json:"transportSecurity,omitempty"` /// string graphQLSchema = 22; GraphqlComplexityInfo []*GraphqlComplexity `protobuf:"bytes,23,rep,name=graphqlComplexityInfo,proto3" json:"graphqlComplexityInfo,omitempty"` SystemAPI bool `protobuf:"varint,24,opt,name=systemAPI,proto3" json:"systemAPI,omitempty"` @@ -214,6 +215,13 @@ func (x *Api) GetApplicationSecurity() bool { return false } +func (x *Api) GetTransportSecurity() bool { + if x != nil { + return x.TransportSecurity + } + return false +} + func (x *Api) GetGraphqlComplexityInfo() []*GraphqlComplexity { if x != nil { return x.GraphqlComplexityInfo @@ -290,7 +298,7 @@ var file_wso2_discovery_api_api_proto_rawDesc = []byte{ 0x76, 0x65, 0x72, 0x79, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x73, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x20, 0x77, 0x73, 0x6f, 0x32, 0x2f, 0x64, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x79, 0x2f, 0x61, 0x70, 0x69, - 0x2f, 0x67, 0x72, 0x61, 0x70, 0x68, 0x71, 0x6c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xbf, + 0x2f, 0x67, 0x72, 0x61, 0x70, 0x68, 0x71, 0x6c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xed, 0x08, 0x0a, 0x03, 0x41, 0x70, 0x69, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x12, 0x18, 0x0a, 0x07, @@ -328,45 +336,48 @@ var file_wso2_discovery_api_api_proto_rawDesc = []byte{ 0x30, 0x0a, 0x13, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x18, 0x10, 0x20, 0x01, 0x28, 0x08, 0x52, 0x13, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, - 0x79, 0x12, 0x5b, 0x0a, 0x15, 0x67, 0x72, 0x61, 0x70, 0x68, 0x71, 0x6c, 0x43, 0x6f, 0x6d, 0x70, - 0x6c, 0x65, 0x78, 0x69, 0x74, 0x79, 0x49, 0x6e, 0x66, 0x6f, 0x18, 0x17, 0x20, 0x03, 0x28, 0x0b, - 0x32, 0x25, 0x2e, 0x77, 0x73, 0x6f, 0x32, 0x2e, 0x64, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, - 0x79, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x47, 0x72, 0x61, 0x70, 0x68, 0x71, 0x6c, 0x43, 0x6f, 0x6d, - 0x70, 0x6c, 0x65, 0x78, 0x69, 0x74, 0x79, 0x52, 0x15, 0x67, 0x72, 0x61, 0x70, 0x68, 0x71, 0x6c, - 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x78, 0x69, 0x74, 0x79, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x1c, - 0x0a, 0x09, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x41, 0x50, 0x49, 0x18, 0x18, 0x20, 0x01, 0x28, - 0x08, 0x52, 0x09, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x41, 0x50, 0x49, 0x12, 0x59, 0x0a, 0x13, - 0x62, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x4a, 0x57, 0x54, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x49, - 0x6e, 0x66, 0x6f, 0x18, 0x19, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x77, 0x73, 0x6f, 0x32, - 0x2e, 0x64, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x79, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x42, - 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x4a, 0x57, 0x54, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x49, 0x6e, - 0x66, 0x6f, 0x52, 0x13, 0x62, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x4a, 0x57, 0x54, 0x54, 0x6f, - 0x6b, 0x65, 0x6e, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x2c, 0x0a, 0x11, 0x61, 0x70, 0x69, 0x44, 0x65, - 0x66, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x46, 0x69, 0x6c, 0x65, 0x18, 0x1a, 0x20, 0x01, - 0x28, 0x0c, 0x52, 0x11, 0x61, 0x70, 0x69, 0x44, 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, - 0x6e, 0x46, 0x69, 0x6c, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x65, 0x6e, 0x76, 0x69, 0x72, 0x6f, 0x6e, - 0x6d, 0x65, 0x6e, 0x74, 0x18, 0x1b, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x65, 0x6e, 0x76, 0x69, - 0x72, 0x6f, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x36, 0x0a, 0x16, 0x73, 0x75, 0x62, 0x73, 0x63, - 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x18, 0x1c, 0x20, 0x01, 0x28, 0x08, 0x52, 0x16, 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, - 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, - 0x41, 0x0a, 0x09, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x73, 0x18, 0x1d, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x77, 0x73, 0x6f, 0x32, 0x2e, 0x64, 0x69, 0x73, 0x63, 0x6f, 0x76, - 0x65, 0x72, 0x79, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x45, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, - 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x52, 0x09, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, - 0x74, 0x73, 0x12, 0x4c, 0x0a, 0x10, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x53, 0x65, - 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x18, 0x1e, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x77, - 0x73, 0x6f, 0x32, 0x2e, 0x64, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x79, 0x2e, 0x61, 0x70, - 0x69, 0x2e, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x10, - 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, - 0x42, 0x70, 0x0a, 0x23, 0x6f, 0x72, 0x67, 0x2e, 0x77, 0x73, 0x6f, 0x32, 0x2e, 0x61, 0x70, 0x6b, - 0x2e, 0x65, 0x6e, 0x66, 0x6f, 0x72, 0x63, 0x65, 0x72, 0x2e, 0x64, 0x69, 0x73, 0x63, 0x6f, 0x76, - 0x65, 0x72, 0x79, 0x2e, 0x61, 0x70, 0x69, 0x42, 0x08, 0x41, 0x70, 0x69, 0x50, 0x72, 0x6f, 0x74, - 0x6f, 0x50, 0x01, 0x5a, 0x3d, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, - 0x65, 0x6e, 0x76, 0x6f, 0x79, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2f, 0x67, 0x6f, 0x2d, 0x63, 0x6f, - 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x2d, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2f, 0x77, 0x73, 0x6f, 0x32, - 0x2f, 0x64, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x79, 0x2f, 0x61, 0x70, 0x69, 0x3b, 0x61, - 0x70, 0x69, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x79, 0x12, 0x2c, 0x0a, 0x11, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x53, 0x65, + 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x18, 0x11, 0x20, 0x01, 0x28, 0x08, 0x52, 0x11, 0x74, 0x72, + 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x12, + 0x5b, 0x0a, 0x15, 0x67, 0x72, 0x61, 0x70, 0x68, 0x71, 0x6c, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, + 0x78, 0x69, 0x74, 0x79, 0x49, 0x6e, 0x66, 0x6f, 0x18, 0x17, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x25, + 0x2e, 0x77, 0x73, 0x6f, 0x32, 0x2e, 0x64, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x79, 0x2e, + 0x61, 0x70, 0x69, 0x2e, 0x47, 0x72, 0x61, 0x70, 0x68, 0x71, 0x6c, 0x43, 0x6f, 0x6d, 0x70, 0x6c, + 0x65, 0x78, 0x69, 0x74, 0x79, 0x52, 0x15, 0x67, 0x72, 0x61, 0x70, 0x68, 0x71, 0x6c, 0x43, 0x6f, + 0x6d, 0x70, 0x6c, 0x65, 0x78, 0x69, 0x74, 0x79, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x1c, 0x0a, 0x09, + 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x41, 0x50, 0x49, 0x18, 0x18, 0x20, 0x01, 0x28, 0x08, 0x52, + 0x09, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x41, 0x50, 0x49, 0x12, 0x59, 0x0a, 0x13, 0x62, 0x61, + 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x4a, 0x57, 0x54, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x49, 0x6e, 0x66, + 0x6f, 0x18, 0x19, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x77, 0x73, 0x6f, 0x32, 0x2e, 0x64, + 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x79, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x42, 0x61, 0x63, + 0x6b, 0x65, 0x6e, 0x64, 0x4a, 0x57, 0x54, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x49, 0x6e, 0x66, 0x6f, + 0x52, 0x13, 0x62, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x4a, 0x57, 0x54, 0x54, 0x6f, 0x6b, 0x65, + 0x6e, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x2c, 0x0a, 0x11, 0x61, 0x70, 0x69, 0x44, 0x65, 0x66, 0x69, + 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x46, 0x69, 0x6c, 0x65, 0x18, 0x1a, 0x20, 0x01, 0x28, 0x0c, + 0x52, 0x11, 0x61, 0x70, 0x69, 0x44, 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x46, + 0x69, 0x6c, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x65, 0x6e, 0x76, 0x69, 0x72, 0x6f, 0x6e, 0x6d, 0x65, + 0x6e, 0x74, 0x18, 0x1b, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x65, 0x6e, 0x76, 0x69, 0x72, 0x6f, + 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x36, 0x0a, 0x16, 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, + 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, + 0x1c, 0x20, 0x01, 0x28, 0x08, 0x52, 0x16, 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, + 0x69, 0x6f, 0x6e, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x41, 0x0a, + 0x09, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x73, 0x18, 0x1d, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x23, 0x2e, 0x77, 0x73, 0x6f, 0x32, 0x2e, 0x64, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, + 0x79, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x45, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x43, 0x6c, + 0x75, 0x73, 0x74, 0x65, 0x72, 0x52, 0x09, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x73, + 0x12, 0x4c, 0x0a, 0x10, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x53, 0x65, 0x63, 0x75, + 0x72, 0x69, 0x74, 0x79, 0x18, 0x1e, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x77, 0x73, 0x6f, + 0x32, 0x2e, 0x64, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x79, 0x2e, 0x61, 0x70, 0x69, 0x2e, + 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x10, 0x65, 0x6e, + 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x42, 0x70, + 0x0a, 0x23, 0x6f, 0x72, 0x67, 0x2e, 0x77, 0x73, 0x6f, 0x32, 0x2e, 0x61, 0x70, 0x6b, 0x2e, 0x65, + 0x6e, 0x66, 0x6f, 0x72, 0x63, 0x65, 0x72, 0x2e, 0x64, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, + 0x79, 0x2e, 0x61, 0x70, 0x69, 0x42, 0x08, 0x41, 0x70, 0x69, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, + 0x01, 0x5a, 0x3d, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x65, 0x6e, + 0x76, 0x6f, 0x79, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2f, 0x67, 0x6f, 0x2d, 0x63, 0x6f, 0x6e, 0x74, + 0x72, 0x6f, 0x6c, 0x2d, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2f, 0x77, 0x73, 0x6f, 0x32, 0x2f, 0x64, + 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x79, 0x2f, 0x61, 0x70, 0x69, 0x3b, 0x61, 0x70, 0x69, + 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/adapter/resources/conf/config.toml b/adapter/resources/conf/config.toml index dc0465cb1..0f2ec8f93 100644 --- a/adapter/resources/conf/config.toml +++ b/adapter/resources/conf/config.toml @@ -28,6 +28,10 @@ verifyHostName = true disableSslVerification = false +[router.downstream] +[router.downstream.tls] +mtlsAPIsEnabled = false +trustedCertPath = "/etc/ssl/certs/ca-certificates.crt" [enforcer.security] [[enforcer.security.tokenService]] diff --git a/common-controller/internal/operator/config/crd/bases/dp.wso2.com_authentications.yaml b/common-controller/internal/operator/config/crd/bases/dp.wso2.com_authentications.yaml new file mode 100644 index 000000000..f1e5242cf --- /dev/null +++ b/common-controller/internal/operator/config/crd/bases/dp.wso2.com_authentications.yaml @@ -0,0 +1,558 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.12.0 + name: authentications.dp.wso2.com +spec: + group: dp.wso2.com + names: + kind: Authentication + listKind: AuthenticationList + plural: authentications + singular: authentication + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: Authentication is the Schema for the authentications API + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: AuthenticationSpec defines the desired state of Authentication + properties: + default: + description: AuthSpec specification of the authentication service + properties: + authTypes: + description: AuthTypes is to specify the authentication scheme + types and details + properties: + apiKey: + description: APIKey is to specify the APIKey authentication + scheme details + items: + description: APIKeyAuth APIKey Authentication scheme details + properties: + in: + description: In is to specify how the APIKey is passed + to the request + enum: + - Header + - Query + minLength: 1 + type: string + name: + description: Name is the name of the header or query + parameter to be used + minLength: 1 + type: string + sendTokenToUpstream: + description: SendTokenToUpstream is to specify whether + the APIKey should be sent to the upstream + type: boolean + type: object + nullable: true + type: array + oauth2: + description: Oauth2 is to specify the Oauth2 authentication + scheme details + properties: + disabled: + default: false + description: Disabled is to disable OAuth2 authentication + type: boolean + header: + default: authorization + description: Header is the header name used to pass the + OAuth2 token + type: string + sendTokenToUpstream: + description: SendTokenToUpstream is to specify whether + the OAuth2 token should be sent to the upstream + type: boolean + type: object + testConsoleKey: + description: TestConsoleKey is to specify the Test Console + Key authentication scheme details + properties: + header: + default: internal-key + description: Header is the header name used to pass the + Test Console Key + minLength: 1 + type: string + sendTokenToUpstream: + description: SendTokenToUpstream is to specify whether + the Test Console Key should be sent to the upstream + type: boolean + type: object + type: object + disabled: + description: Disabled is to disable all authentications + type: boolean + type: object + override: + description: AuthSpec specification of the authentication service + properties: + authTypes: + description: AuthTypes is to specify the authentication scheme + types and details + properties: + apiKey: + description: APIKey is to specify the APIKey authentication + scheme details + items: + description: APIKeyAuth APIKey Authentication scheme details + properties: + in: + description: In is to specify how the APIKey is passed + to the request + enum: + - Header + - Query + minLength: 1 + type: string + name: + description: Name is the name of the header or query + parameter to be used + minLength: 1 + type: string + sendTokenToUpstream: + description: SendTokenToUpstream is to specify whether + the APIKey should be sent to the upstream + type: boolean + type: object + nullable: true + type: array + oauth2: + description: Oauth2 is to specify the Oauth2 authentication + scheme details + properties: + disabled: + default: false + description: Disabled is to disable OAuth2 authentication + type: boolean + header: + default: authorization + description: Header is the header name used to pass the + OAuth2 token + type: string + sendTokenToUpstream: + description: SendTokenToUpstream is to specify whether + the OAuth2 token should be sent to the upstream + type: boolean + type: object + testConsoleKey: + description: TestConsoleKey is to specify the Test Console + Key authentication scheme details + properties: + header: + default: internal-key + description: Header is the header name used to pass the + Test Console Key + minLength: 1 + type: string + sendTokenToUpstream: + description: SendTokenToUpstream is to specify whether + the Test Console Key should be sent to the upstream + type: boolean + type: object + type: object + disabled: + description: Disabled is to disable all authentications + type: boolean + type: object + targetRef: + description: PolicyTargetReference identifies an API object to apply + policy to. This should be used as part of Policy resources that + can target Gateway API resources. For more information on how this + policy attachment model works, and a sample Policy resource, refer + to the policy attachment documentation for Gateway API. + properties: + group: + description: Group is the group of the target resource. + maxLength: 253 + pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + kind: + description: Kind is kind of the target resource. + maxLength: 63 + minLength: 1 + pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ + type: string + name: + description: Name is the name of the target resource. + maxLength: 253 + minLength: 1 + type: string + namespace: + description: Namespace is the namespace of the referent. When + unspecified, the local namespace is inferred. Even when policy + targets a resource in a different namespace, it MUST only apply + to traffic originating from the same namespace as the policy. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + required: + - group + - kind + - name + type: object + type: object + status: + description: AuthenticationStatus defines the observed state of Authentication + type: object + type: object + served: true + storage: false + subresources: + status: {} + - name: v1alpha2 + schema: + openAPIV3Schema: + description: Authentication is the Schema for the authentications API + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: AuthenticationSpec defines the desired state of Authentication + properties: + default: + description: AuthSpec specification of the authentication service + properties: + authTypes: + description: AuthTypes is to specify the authentication scheme + types and details + properties: + apiKey: + description: APIKey is to specify the APIKey authentication + scheme details + items: + description: APIKeyAuth APIKey Authentication scheme details + properties: + in: + description: In is to specify how the APIKey is passed + to the request + enum: + - Header + - Query + minLength: 1 + type: string + name: + description: Name is the name of the header or query + parameter to be used + minLength: 1 + type: string + sendTokenToUpstream: + description: SendTokenToUpstream is to specify whether + the APIKey should be sent to the upstream + type: boolean + type: object + nullable: true + type: array + mtls: + description: MutualSSL is to specify the features and certificates + for mutual SSL + properties: + certificatesInline: + description: CertificatesInline is the Inline Certificate + entry + items: + type: string + type: array + configMapRefs: + description: ConfigMapRefs denotes the reference to the + ConfigMap that contains the Certificate + items: + description: RefConfig holds a config for a secret or + a configmap + properties: + key: + description: Key of the secret or configmap + minLength: 1 + type: string + name: + description: Name of the secret or configmap + minLength: 1 + type: string + required: + - key + - name + type: object + type: array + disabled: + default: false + description: Disabled is to disable mTLS authentication + type: boolean + required: + default: optional + description: Required indicates whether mutualSSL is mandatory + or optional + enum: + - mandatory + - optional + type: string + secretRefs: + description: SecretRefs denotes the reference to the Secret + that contains the Certificate + items: + description: RefConfig holds a config for a secret or + a configmap + properties: + key: + description: Key of the secret or configmap + minLength: 1 + type: string + name: + description: Name of the secret or configmap + minLength: 1 + type: string + required: + - key + - name + type: object + type: array + type: object + oauth2: + description: Oauth2 is to specify the Oauth2 authentication + scheme details + properties: + disabled: + default: false + description: Disabled is to disable OAuth2 authentication + type: boolean + header: + default: authorization + description: Header is the header name used to pass the + OAuth2 token + type: string + sendTokenToUpstream: + description: SendTokenToUpstream is to specify whether + the OAuth2 token should be sent to the upstream + type: boolean + type: object + testConsoleKey: + description: TestConsoleKey is to specify the Test Console + Key authentication scheme details + properties: + header: + default: internal-key + description: Header is the header name used to pass the + Test Console Key + minLength: 1 + type: string + sendTokenToUpstream: + description: SendTokenToUpstream is to specify whether + the Test Console Key should be sent to the upstream + type: boolean + type: object + type: object + disabled: + description: Disabled is to disable all authentications + type: boolean + type: object + override: + description: AuthSpec specification of the authentication service + properties: + authTypes: + description: AuthTypes is to specify the authentication scheme + types and details + properties: + apiKey: + description: APIKey is to specify the APIKey authentication + scheme details + items: + description: APIKeyAuth APIKey Authentication scheme details + properties: + in: + description: In is to specify how the APIKey is passed + to the request + enum: + - Header + - Query + minLength: 1 + type: string + name: + description: Name is the name of the header or query + parameter to be used + minLength: 1 + type: string + sendTokenToUpstream: + description: SendTokenToUpstream is to specify whether + the APIKey should be sent to the upstream + type: boolean + type: object + nullable: true + type: array + mtls: + description: MutualSSL is to specify the features and certificates + for mutual SSL + properties: + certificatesInline: + description: CertificatesInline is the Inline Certificate + entry + items: + type: string + type: array + configMapRefs: + description: ConfigMapRefs denotes the reference to the + ConfigMap that contains the Certificate + items: + description: RefConfig holds a config for a secret or + a configmap + properties: + key: + description: Key of the secret or configmap + minLength: 1 + type: string + name: + description: Name of the secret or configmap + minLength: 1 + type: string + required: + - key + - name + type: object + type: array + disabled: + default: false + description: Disabled is to disable mTLS authentication + type: boolean + required: + default: optional + description: Required indicates whether mutualSSL is mandatory + or optional + enum: + - mandatory + - optional + type: string + secretRefs: + description: SecretRefs denotes the reference to the Secret + that contains the Certificate + items: + description: RefConfig holds a config for a secret or + a configmap + properties: + key: + description: Key of the secret or configmap + minLength: 1 + type: string + name: + description: Name of the secret or configmap + minLength: 1 + type: string + required: + - key + - name + type: object + type: array + type: object + oauth2: + description: Oauth2 is to specify the Oauth2 authentication + scheme details + properties: + disabled: + default: false + description: Disabled is to disable OAuth2 authentication + type: boolean + header: + default: authorization + description: Header is the header name used to pass the + OAuth2 token + type: string + sendTokenToUpstream: + description: SendTokenToUpstream is to specify whether + the OAuth2 token should be sent to the upstream + type: boolean + type: object + testConsoleKey: + description: TestConsoleKey is to specify the Test Console + Key authentication scheme details + properties: + header: + default: internal-key + description: Header is the header name used to pass the + Test Console Key + minLength: 1 + type: string + sendTokenToUpstream: + description: SendTokenToUpstream is to specify whether + the Test Console Key should be sent to the upstream + type: boolean + type: object + type: object + disabled: + description: Disabled is to disable all authentications + type: boolean + type: object + targetRef: + description: PolicyTargetReference identifies an API object to apply + policy to. This should be used as part of Policy resources that + can target Gateway API resources. For more information on how this + policy attachment model works, and a sample Policy resource, refer + to the policy attachment documentation for Gateway API. + properties: + group: + description: Group is the group of the target resource. + maxLength: 253 + pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + kind: + description: Kind is kind of the target resource. + maxLength: 63 + minLength: 1 + pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ + type: string + name: + description: Name is the name of the target resource. + maxLength: 253 + minLength: 1 + type: string + namespace: + description: Namespace is the namespace of the referent. When + unspecified, the local namespace is inferred. Even when policy + targets a resource in a different namespace, it MUST only apply + to traffic originating from the same namespace as the policy. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + required: + - group + - kind + - name + type: object + type: object + status: + description: AuthenticationStatus defines the observed state of Authentication + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/common-controller/internal/operator/config/crd/kustomization.yaml b/common-controller/internal/operator/config/crd/kustomization.yaml index 16ac3fc02..460c451ae 100644 --- a/common-controller/internal/operator/config/crd/kustomization.yaml +++ b/common-controller/internal/operator/config/crd/kustomization.yaml @@ -7,6 +7,7 @@ resources: - bases/cp.wso2.com_applications.yaml - bases/cp.wso2.com_subscriptions.yaml - bases/cp.wso2.com_applicationmappings.yaml +- bases/dp.wso2.com_authentications.yaml #+kubebuilder:scaffold:crdkustomizeresource patches: diff --git a/common-controller/internal/operator/config/crd/patches/cainjection_in_dp_authentications.yaml b/common-controller/internal/operator/config/crd/patches/cainjection_in_dp_authentications.yaml new file mode 100644 index 000000000..680a50baf --- /dev/null +++ b/common-controller/internal/operator/config/crd/patches/cainjection_in_dp_authentications.yaml @@ -0,0 +1,7 @@ +# The following patch adds a directive for certmanager to inject CA into the CRD +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + cert-manager.io/inject-ca-from: $(CERTIFICATE_NAMESPACE)/$(CERTIFICATE_NAME) + name: authentications.dp.wso2.com diff --git a/common-controller/internal/operator/config/crd/patches/webhook_in_dp_authentications.yaml b/common-controller/internal/operator/config/crd/patches/webhook_in_dp_authentications.yaml new file mode 100644 index 000000000..a0c816328 --- /dev/null +++ b/common-controller/internal/operator/config/crd/patches/webhook_in_dp_authentications.yaml @@ -0,0 +1,16 @@ +# The following patch enables a conversion webhook for the CRD +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: authentications.dp.wso2.com +spec: + conversion: + strategy: Webhook + webhook: + clientConfig: + service: + namespace: system + name: webhook-service + path: /convert + conversionReviewVersions: + - v1 diff --git a/common-controller/internal/operator/config/rbac/dp_authentication_editor_role.yaml b/common-controller/internal/operator/config/rbac/dp_authentication_editor_role.yaml new file mode 100644 index 000000000..4d3e0f752 --- /dev/null +++ b/common-controller/internal/operator/config/rbac/dp_authentication_editor_role.yaml @@ -0,0 +1,31 @@ +# permissions for end users to edit authentications. +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + labels: + app.kubernetes.io/name: clusterrole + app.kubernetes.io/instance: authentication-editor-role + app.kubernetes.io/component: rbac + app.kubernetes.io/created-by: operator + app.kubernetes.io/part-of: operator + app.kubernetes.io/managed-by: kustomize + name: authentication-editor-role +rules: +- apiGroups: + - dp.wso2.com + resources: + - authentications + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - dp.wso2.com + resources: + - authentications/status + verbs: + - get diff --git a/common-controller/internal/operator/config/rbac/dp_authentication_viewer_role.yaml b/common-controller/internal/operator/config/rbac/dp_authentication_viewer_role.yaml new file mode 100644 index 000000000..ab69c164c --- /dev/null +++ b/common-controller/internal/operator/config/rbac/dp_authentication_viewer_role.yaml @@ -0,0 +1,27 @@ +# permissions for end users to view authentications. +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + labels: + app.kubernetes.io/name: clusterrole + app.kubernetes.io/instance: authentication-viewer-role + app.kubernetes.io/component: rbac + app.kubernetes.io/created-by: operator + app.kubernetes.io/part-of: operator + app.kubernetes.io/managed-by: kustomize + name: authentication-viewer-role +rules: +- apiGroups: + - dp.wso2.com + resources: + - authentications + verbs: + - get + - list + - watch +- apiGroups: + - dp.wso2.com + resources: + - authentications/status + verbs: + - get diff --git a/common-controller/internal/operator/config/samples/dp_v1alpha2_authentication.yaml b/common-controller/internal/operator/config/samples/dp_v1alpha2_authentication.yaml new file mode 100644 index 000000000..7c1486aeb --- /dev/null +++ b/common-controller/internal/operator/config/samples/dp_v1alpha2_authentication.yaml @@ -0,0 +1,12 @@ +apiVersion: dp.wso2.com/v1alpha2 +kind: Authentication +metadata: + labels: + app.kubernetes.io/name: authentication + app.kubernetes.io/instance: authentication-sample + app.kubernetes.io/part-of: operator + app.kubernetes.io/managed-by: kustomize + app.kubernetes.io/created-by: operator + name: authentication-sample +spec: + # TODO(user): Add fields here diff --git a/common-controller/internal/operator/config/webhook/manifests.yaml b/common-controller/internal/operator/config/webhook/manifests.yaml index c7026f4c8..411ed6ee8 100644 --- a/common-controller/internal/operator/config/webhook/manifests.yaml +++ b/common-controller/internal/operator/config/webhook/manifests.yaml @@ -44,6 +44,26 @@ webhooks: resources: - apipolicies sideEffects: None +- admissionReviewVersions: + - v1 + clientConfig: + service: + name: webhook-service + namespace: system + path: /mutate-dp-wso2-com-v1alpha2-authentication + failurePolicy: Fail + name: mauthentication.kb.io + rules: + - apiGroups: + - dp.wso2.com + apiVersions: + - v1alpha2 + operations: + - CREATE + - UPDATE + resources: + - authentications + sideEffects: None - admissionReviewVersions: - v1 clientConfig: @@ -64,6 +84,26 @@ webhooks: resources: - apipolicies sideEffects: None +- admissionReviewVersions: + - v1 + clientConfig: + service: + name: webhook-service + namespace: system + path: /mutate-dp-wso2-com-v1alpha1-authentication + failurePolicy: Fail + name: mauthentication.kb.io + rules: + - apiGroups: + - dp.wso2.com + apiVersions: + - v1alpha1 + operations: + - CREATE + - UPDATE + resources: + - authentications + sideEffects: None - admissionReviewVersions: - v1 clientConfig: @@ -190,6 +230,26 @@ webhooks: resources: - apipolicies sideEffects: None +- admissionReviewVersions: + - v1 + clientConfig: + service: + name: webhook-service + namespace: system + path: /validate-dp-wso2-com-v1alpha2-authentication + failurePolicy: Fail + name: vauthentication.kb.io + rules: + - apiGroups: + - dp.wso2.com + apiVersions: + - v1alpha2 + operations: + - CREATE + - UPDATE + resources: + - authentications + sideEffects: None - admissionReviewVersions: - v1 clientConfig: @@ -210,6 +270,26 @@ webhooks: resources: - apipolicies sideEffects: None +- admissionReviewVersions: + - v1 + clientConfig: + service: + name: webhook-service + namespace: system + path: /validate-dp-wso2-com-v1alpha1-authentication + failurePolicy: Fail + name: vauthentication.kb.io + rules: + - apiGroups: + - dp.wso2.com + apiVersions: + - v1alpha1 + operations: + - CREATE + - UPDATE + resources: + - authentications + sideEffects: None - admissionReviewVersions: - v1 clientConfig: diff --git a/common-controller/internal/operator/operator.go b/common-controller/internal/operator/operator.go index bd973ae28..73a252074 100644 --- a/common-controller/internal/operator/operator.go +++ b/common-controller/internal/operator/operator.go @@ -121,6 +121,11 @@ func InitOperator() { "Unable to create webhook for APIPolicy, error: %v", err)) } + if err = (&dpv1alpha2.Authentication{}).SetupWebhookWithManager(mgr); err != nil { + loggers.LoggerAPKOperator.ErrorC(logging.PrintError(logging.Error2638, logging.MAJOR, + "Unable to create webhook for Authentication, error: %v", err)) + } + if err = (&dpv1alpha1.InterceptorService{}).SetupWebhookWithManager(mgr); err != nil { loggers.LoggerAPKOperator.ErrorC(logging.PrintError(logging.Error2652, logging.MAJOR, "Unable to create webhook for InterceptorService, error: %v", err)) diff --git a/common-go-libs/PROJECT b/common-go-libs/PROJECT index 8f0e7f9ff..51763f3fd 100644 --- a/common-go-libs/PROJECT +++ b/common-go-libs/PROJECT @@ -31,6 +31,11 @@ resources: kind: Authentication path: github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1 version: v1alpha1 + webhooks: + conversion: true + defaulting: true + validation: true + webhookVersion: v1 - api: crdVersion: v1 namespaced: true @@ -141,4 +146,17 @@ resources: kind: TokenIssuer path: github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2 version: v1alpha2 +- api: + crdVersion: v1 + namespaced: true + domain: wso2.com + group: dp + kind: Authentication + path: github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2 + version: v1alpha2 + webhooks: + conversion: true + defaulting: true + validation: true + webhookVersion: v1 version: "3" diff --git a/common-go-libs/READ.ME b/common-go-libs/README similarity index 100% rename from common-go-libs/READ.ME rename to common-go-libs/README diff --git a/common-go-libs/apis/dp/v1alpha1/authentication_conversion.go b/common-go-libs/apis/dp/v1alpha1/authentication_conversion.go new file mode 100644 index 000000000..dd98f8ecc --- /dev/null +++ b/common-go-libs/apis/dp/v1alpha1/authentication_conversion.go @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2024, WSO2 LLC. (http://www.wso2.org) All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package v1alpha1 + +import ( + "github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2" + "sigs.k8s.io/controller-runtime/pkg/conversion" +) + +// ConvertTo converts this Authentication CR to the Hub version (v1alpha2). +// src is v1alpha1.Authentication and dst is v1alpha2.Authentication. +func (src *Authentication) ConvertTo(dstRaw conversion.Hub) error { + + dst := dstRaw.(*v1alpha2.Authentication) + dst.ObjectMeta = src.ObjectMeta + + // Spec + dst.Spec.TargetRef = src.Spec.TargetRef + + dst.Spec.Default.Disabled = src.Spec.Default.Disabled + dst.Spec.Override.Disabled = src.Spec.Override.Disabled + + // Convert Oauth2Auth to v1alpha2.Oauth2Auth + dst.Spec.Default.AuthTypes.Oauth2 = v1alpha2.Oauth2Auth(src.Spec.Default.AuthTypes.Oauth2) + dst.Spec.Override.AuthTypes.Oauth2 = v1alpha2.Oauth2Auth(src.Spec.Override.AuthTypes.Oauth2) + + for _, apiKeyAuth := range src.Spec.Default.AuthTypes.APIKey { + convertedAPIKeyAuth := v1alpha2.APIKeyAuth(apiKeyAuth) + dst.Spec.Default.AuthTypes.APIKey = append(dst.Spec.Default.AuthTypes.APIKey, convertedAPIKeyAuth) + } + + for _, apiKeyAuth := range src.Spec.Override.AuthTypes.APIKey { + convertedAPIKeyAuth := v1alpha2.APIKeyAuth(apiKeyAuth) + dst.Spec.Override.AuthTypes.APIKey = append(dst.Spec.Override.AuthTypes.APIKey, convertedAPIKeyAuth) + } + + // Status + dst.Status = v1alpha2.AuthenticationStatus(src.Status) + + return nil +} + +// ConvertFrom converts from the Hub version (v1alpha2) to this version. +// src is v1alpha1.Authentication and dst is v1alpha2.Authentication. +func (src *Authentication) ConvertFrom(srcRaw conversion.Hub) error { + + dst := srcRaw.(*v1alpha2.Authentication) + src.ObjectMeta = dst.ObjectMeta + + // Spec + src.Spec.TargetRef = dst.Spec.TargetRef + + src.Spec.Default.Disabled = dst.Spec.Default.Disabled + src.Spec.Override.Disabled = dst.Spec.Override.Disabled + src.Spec.Default.AuthTypes.Oauth2 = Oauth2Auth(dst.Spec.Default.AuthTypes.Oauth2) + src.Spec.Override.AuthTypes.Oauth2 = Oauth2Auth(dst.Spec.Override.AuthTypes.Oauth2) + + for _, apiKeyAuth := range dst.Spec.Default.AuthTypes.APIKey { + convertedAPIKeyAuth := APIKeyAuth(apiKeyAuth) + src.Spec.Default.AuthTypes.APIKey = append(src.Spec.Default.AuthTypes.APIKey, convertedAPIKeyAuth) + } + + for _, apiKeyAuth := range dst.Spec.Override.AuthTypes.APIKey { + convertedAPIKeyAuth := APIKeyAuth(apiKeyAuth) + src.Spec.Override.AuthTypes.APIKey = append(src.Spec.Override.AuthTypes.APIKey, convertedAPIKeyAuth) + } + + // Status + src.Status = AuthenticationStatus(dst.Status) + return nil +} diff --git a/common-go-libs/apis/dp/v1alpha1/authentication_webhook.go b/common-go-libs/apis/dp/v1alpha1/authentication_webhook.go new file mode 100644 index 000000000..0eefa868f --- /dev/null +++ b/common-go-libs/apis/dp/v1alpha1/authentication_webhook.go @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2023, WSO2 LLC. (http://www.wso2.org) All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package v1alpha1 + +import ( + constants "github.com/wso2/apk/common-go-libs/constants" + apierrors "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/apimachinery/pkg/util/validation/field" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/webhook" + "sigs.k8s.io/controller-runtime/pkg/webhook/admission" +) + +// SetupWebhookWithManager creates a new webhook builder for Authentication +func (r *Authentication) SetupWebhookWithManager(mgr ctrl.Manager) error { + return ctrl.NewWebhookManagedBy(mgr). + For(r). + Complete() +} + +// TODO(user): EDIT THIS FILE! THIS IS SCAFFOLDING FOR YOU TO OWN! + +//+kubebuilder:webhook:path=/mutate-dp-wso2-com-v1alpha1-authentication,mutating=true,failurePolicy=fail,sideEffects=None,groups=dp.wso2.com,resources=authentications,verbs=create;update,versions=v1alpha1,name=mauthentication.kb.io,admissionReviewVersions=v1 + +var _ webhook.Defaulter = &Authentication{} + +// Default implements webhook.Defaulter so a webhook will be registered for the type +func (r *Authentication) Default() { + // TODO(user): fill in your defaulting logic. +} + +// TODO(user): change verbs to "verbs=create;update;delete" if you want to enable deletion validation. +//+kubebuilder:webhook:path=/validate-dp-wso2-com-v1alpha1-authentication,mutating=false,failurePolicy=fail,sideEffects=None,groups=dp.wso2.com,resources=authentications,verbs=create;update,versions=v1alpha1,name=vauthentication.kb.io,admissionReviewVersions=v1 + +var _ webhook.Validator = &Authentication{} + +// ValidateCreate implements webhook.Validator so a webhook will be registered for the type +func (r *Authentication) ValidateCreate() (admission.Warnings, error) { + // TODO(user): fill in your validation logic upon object creation. + return nil, r.ValidateAuthentication() +} + +// ValidateUpdate implements webhook.Validator so a webhook will be registered for the type +func (r *Authentication) ValidateUpdate(old runtime.Object) (admission.Warnings, error) { + return nil, r.ValidateAuthentication() +} + +// ValidateAuthentication validates the Authentication +func (r *Authentication) ValidateAuthentication() error { + var allErrs field.ErrorList + + if r.Spec.TargetRef.Name == "" { + allErrs = append(allErrs, field.Required(field.NewPath("spec").Child("targetRef").Child("name"), "Name is required")) + } + if !(r.Spec.TargetRef.Kind == constants.KindAPI || r.Spec.TargetRef.Kind == constants.KindResource) { + allErrs = append(allErrs, field.Invalid(field.NewPath("spec").Child("targetRef").Child("kind"), r.Spec.TargetRef.Kind, + "Invalid Kind is provided")) + } + + if len(allErrs) > 0 { + return apierrors.NewInvalid( + schema.GroupKind{Group: "dp.wso2.com", Kind: "Authentication"}, + r.Name, allErrs) + } + return nil +} + +// ValidateDelete implements webhook.Validator so a webhook will be registered for the type +func (r *Authentication) ValidateDelete() (admission.Warnings, error) { + // TODO(user): fill in your validation logic upon object deletion. + return nil, nil +} diff --git a/common-go-libs/apis/dp/v1alpha1/webhook_suite_test.go b/common-go-libs/apis/dp/v1alpha1/webhook_suite_test.go index 5c56602ca..3dc05d4de 100644 --- a/common-go-libs/apis/dp/v1alpha1/webhook_suite_test.go +++ b/common-go-libs/apis/dp/v1alpha1/webhook_suite_test.go @@ -118,6 +118,9 @@ var _ = BeforeSuite(func() { err = (&BackendJWT{}).SetupWebhookWithManager(mgr) Expect(err).NotTo(HaveOccurred()) + err = (&Authentication{}).SetupWebhookWithManager(mgr) + Expect(err).NotTo(HaveOccurred()) + //+kubebuilder:scaffold:webhook go func() { diff --git a/common-go-libs/apis/dp/v1alpha2/authentication_conversion.go b/common-go-libs/apis/dp/v1alpha2/authentication_conversion.go new file mode 100644 index 000000000..a225d4895 --- /dev/null +++ b/common-go-libs/apis/dp/v1alpha2/authentication_conversion.go @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2024, WSO2 LLC. (http://www.wso2.org) All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package v1alpha2 + +// Hub marks this type as a conversion hub. +func (*Authentication) Hub() {} diff --git a/common-go-libs/apis/dp/v1alpha2/authentication_types.go b/common-go-libs/apis/dp/v1alpha2/authentication_types.go new file mode 100644 index 000000000..68abe7b97 --- /dev/null +++ b/common-go-libs/apis/dp/v1alpha2/authentication_types.go @@ -0,0 +1,178 @@ +/* + * Copyright (c) 2024, WSO2 LLC. (http://www.wso2.org) All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package v1alpha2 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + gwapiv1b1 "sigs.k8s.io/gateway-api/apis/v1alpha2" +) + +// EDIT THIS FILE! THIS IS SCAFFOLDING FOR YOU TO OWN! +// NOTE: json tags are required. Any new fields you add must have json tags for the fields to be serialized. + +// AuthenticationSpec defines the desired state of Authentication +type AuthenticationSpec struct { + Default *AuthSpec `json:"default,omitempty"` + Override *AuthSpec `json:"override,omitempty"` + TargetRef gwapiv1b1.PolicyTargetReference `json:"targetRef,omitempty"` +} + +// AuthSpec specification of the authentication service +type AuthSpec struct { + // Disabled is to disable all authentications + Disabled *bool `json:"disabled,omitempty"` + + // AuthTypes is to specify the authentication scheme types and details + AuthTypes *APIAuth `json:"authTypes,omitempty"` +} + +// APIAuth Authentication scheme type and details +type APIAuth struct { + // Oauth2 is to specify the Oauth2 authentication scheme details + // + // +optional + Oauth2 Oauth2Auth `json:"oauth2,omitempty"` + + // APIKey is to specify the APIKey authentication scheme details + // + // +optional + // +nullable + APIKey []APIKeyAuth `json:"apiKey,omitempty"` + + // TestConsoleKey is to specify the Test Console Key authentication scheme details + // + // +optional + TestConsoleKey TestConsoleKeyAuth `json:"testConsoleKey,omitempty"` + + // MutualSSL is to specify the features and certificates for mutual SSL + // + // +optional + MutualSSL *MutualSSLConfig `json:"mtls,omitempty"` +} + +// MutualSSLConfig scheme type and details +type MutualSSLConfig struct { + + // Disabled is to disable mTLS authentication + // + // +kubebuilder:default=false + // +optional + Disabled bool `json:"disabled,omitempty"` + + // Required indicates whether mutualSSL is mandatory or optional + // +kubebuilder:validation:Enum=mandatory;optional + // +kubebuilder:default=optional + // +optional + Required string `json:"required"` + + // CertificatesInline is the Inline Certificate entry + CertificatesInline []*string `json:"certificatesInline,omitempty"` + + // SecretRefs denotes the reference to the Secret that contains the Certificate + SecretRefs []*RefConfig `json:"secretRefs,omitempty"` + + // ConfigMapRefs denotes the reference to the ConfigMap that contains the Certificate + ConfigMapRefs []*RefConfig `json:"configMapRefs,omitempty"` +} + +// TestConsoleKeyAuth Test Console Key Authentication scheme details +type TestConsoleKeyAuth struct { + // Header is the header name used to pass the Test Console Key + // + // +kubebuilder:default:=internal-key + // +optional + // +kubebuilder:validation:MinLength=1 + Header string `json:"header,omitempty"` + + // SendTokenToUpstream is to specify whether the Test Console Key should be sent to the upstream + // + // +optional + SendTokenToUpstream bool `json:"sendTokenToUpstream,omitempty"` +} + +// Oauth2Auth OAuth2 Authentication scheme details +type Oauth2Auth struct { + + // Disabled is to disable OAuth2 authentication + // + // +kubebuilder:default=false + // +optional + Disabled bool `json:"disabled"` + + // Header is the header name used to pass the OAuth2 token + // + // +kubebuilder:default=authorization + // +optional + Header string `json:"header,omitempty"` + + // SendTokenToUpstream is to specify whether the OAuth2 token should be sent to the upstream + // + // +optional + SendTokenToUpstream bool `json:"sendTokenToUpstream,omitempty"` +} + +// APIKeyAuth APIKey Authentication scheme details +type APIKeyAuth struct { + // In is to specify how the APIKey is passed to the request + // + // +kubebuilder:validation:Enum=Header;Query + // +kubebuilder:validation:MinLength=1 + In string `json:"in,omitempty"` + + // Name is the name of the header or query parameter to be used + // +kubebuilder:validation:MinLength=1 + Name string `json:"name,omitempty"` + + // SendTokenToUpstream is to specify whether the APIKey should be sent to the upstream + // + // +optional + SendTokenToUpstream bool `json:"sendTokenToUpstream,omitempty"` +} + +// AuthenticationStatus defines the observed state of Authentication +type AuthenticationStatus struct { + // INSERT ADDITIONAL STATUS FIELD - define observed state of cluster + // Important: Run "make" to regenerate code after modifying this file +} + +// +genclient +//+kubebuilder:object:root=true +//+kubebuilder:subresource:status +//+kubebuilder:storageversion + +// Authentication is the Schema for the authentications API +type Authentication struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec AuthenticationSpec `json:"spec,omitempty"` + Status AuthenticationStatus `json:"status,omitempty"` +} + +//+kubebuilder:object:root=true + +// AuthenticationList contains a list of Authentication +type AuthenticationList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []Authentication `json:"items"` +} + +func init() { + SchemeBuilder.Register(&Authentication{}, &AuthenticationList{}) +} diff --git a/common-go-libs/apis/dp/v1alpha2/authentication_webhook.go b/common-go-libs/apis/dp/v1alpha2/authentication_webhook.go new file mode 100644 index 000000000..56fe74e0e --- /dev/null +++ b/common-go-libs/apis/dp/v1alpha2/authentication_webhook.go @@ -0,0 +1,126 @@ +/* + * Copyright (c) 2024, WSO2 LLC. (http://www.wso2.org) All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package v1alpha2 + +import ( + "strings" + + constants "github.com/wso2/apk/common-go-libs/constants" + apierrors "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/apimachinery/pkg/util/validation/field" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/webhook" + "sigs.k8s.io/controller-runtime/pkg/webhook/admission" +) + +func (r *Authentication) SetupWebhookWithManager(mgr ctrl.Manager) error { + return ctrl.NewWebhookManagedBy(mgr). + For(r). + Complete() +} + +// TODO(user): EDIT THIS FILE! THIS IS SCAFFOLDING FOR YOU TO OWN! + +//+kubebuilder:webhook:path=/mutate-dp-wso2-com-v1alpha2-authentication,mutating=true,failurePolicy=fail,sideEffects=None,groups=dp.wso2.com,resources=authentications,verbs=create;update,versions=v1alpha2,name=mauthentication.kb.io,admissionReviewVersions=v1 + +var _ webhook.Defaulter = &Authentication{} + +// Default implements webhook.Defaulter so a webhook will be registered for the type +func (r *Authentication) Default() { + // TODO(user): fill in your defaulting logic. +} + +// TODO(user): change verbs to "verbs=create;update;delete" if you want to enable deletion validation. +//+kubebuilder:webhook:path=/validate-dp-wso2-com-v1alpha2-authentication,mutating=false,failurePolicy=fail,sideEffects=None,groups=dp.wso2.com,resources=authentications,verbs=create;update,versions=v1alpha2,name=vauthentication.kb.io,admissionReviewVersions=v1 + +var _ webhook.Validator = &Authentication{} + +// ValidateCreate implements webhook.Validator so a webhook will be registered for the type +func (r *Authentication) ValidateCreate() (admission.Warnings, error) { + // TODO(user): fill in your validation logic upon object creation. + return nil, r.ValidateAuthentication() +} + +// ValidateUpdate implements webhook.Validator so a webhook will be registered for the type +func (r *Authentication) ValidateUpdate(old runtime.Object) (admission.Warnings, error) { + return nil, r.ValidateAuthentication() +} + +// ValidateAuthentication validates the Authentication +func (r *Authentication) ValidateAuthentication() error { + var allErrs field.ErrorList + isOAuthDisabled := false + isMTLSMandatory := false + isMTLSDisabled := false + + if r.Spec.TargetRef.Name == "" { + allErrs = append(allErrs, field.Required(field.NewPath("spec").Child("targetRef").Child("name"), "Name is required")) + } + if !(r.Spec.TargetRef.Kind == constants.KindAPI || r.Spec.TargetRef.Kind == constants.KindResource) { + allErrs = append(allErrs, field.Invalid(field.NewPath("spec").Child("targetRef").Child("kind"), r.Spec.TargetRef.Kind, + "Invalid Kind is provided")) + } + var mutualSSL *MutualSSLConfig + + if r.Spec.Default != nil && r.Spec.Default.AuthTypes != nil && r.Spec.Default.AuthTypes.MutualSSL != nil { + isOAuthDisabled = r.Spec.Default.AuthTypes.Oauth2.Disabled + mutualSSL = r.Spec.Default.AuthTypes.MutualSSL + + isMTLSMandatory = strings.ToLower(mutualSSL.Required) == "mandatory" + isMTLSDisabled = mutualSSL.Disabled + if isOAuthDisabled && (!isMTLSMandatory || isMTLSDisabled) { + allErrs = append(allErrs, field.Invalid(field.NewPath("spec").Child("default").Child("authTypes").Child("mtls"), r.Spec.Default.AuthTypes, + "invalid authentication configuration - one of mTLS or OAuth2 must be enabled and mandatory")) + } + if len(mutualSSL.CertificatesInline) == 0 && len(mutualSSL.ConfigMapRefs) == 0 && len(mutualSSL.SecretRefs) == 0 { + allErrs = append(allErrs, field.Invalid(field.NewPath("spec").Child("default").Child("authTypes").Child("mtls"), r.Spec.Default.AuthTypes.MutualSSL, + "invalid mTLS configuration - certificates not provided")) + } + + } else if r.Spec.Override != nil && r.Spec.Override.AuthTypes != nil && r.Spec.Override.AuthTypes.MutualSSL != nil { + isOAuthDisabled = r.Spec.Override.AuthTypes.Oauth2.Disabled + mutualSSL = r.Spec.Override.AuthTypes.MutualSSL + + isMTLSMandatory = strings.ToLower(mutualSSL.Required) == "mandatory" + isMTLSDisabled = mutualSSL.Disabled + if isOAuthDisabled && (!isMTLSMandatory || isMTLSDisabled) { + allErrs = append(allErrs, field.Invalid(field.NewPath("spec").Child("override").Child("authTypes").Child("mtls"), r.Spec.Override.AuthTypes, + "invalid authentication configuration - one of mTLS or OAuth2 must be enabled and mandatory")) + } + + if len(mutualSSL.CertificatesInline) == 0 && len(mutualSSL.ConfigMapRefs) == 0 && len(mutualSSL.SecretRefs) == 0 { + allErrs = append(allErrs, field.Invalid(field.NewPath("spec").Child("override").Child("authTypes").Child("mtls"), r.Spec.Override.AuthTypes.MutualSSL, + "invalid mTLS configuration - certificates not provided")) + } + } + + if len(allErrs) > 0 { + return apierrors.NewInvalid( + schema.GroupKind{Group: "dp.wso2.com", Kind: "Authentication"}, + r.Name, allErrs) + } + return nil +} + +// ValidateDelete implements webhook.Validator so a webhook will be registered for the type +func (r *Authentication) ValidateDelete() (admission.Warnings, error) { + // TODO(user): fill in your validation logic upon object deletion. + return nil, nil +} diff --git a/common-go-libs/apis/dp/v1alpha2/mutualSSL.go b/common-go-libs/apis/dp/v1alpha2/mutualSSL.go new file mode 100644 index 000000000..54e21c54c --- /dev/null +++ b/common-go-libs/apis/dp/v1alpha2/mutualSSL.go @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2024, WSO2 LLC. (http://www.wso2.org) All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package v1alpha2 + +// MutualSSL defines the mutual SSL configurations for an API +type MutualSSL struct { + Disabled bool + Required string + ClientCertificates []string +} diff --git a/common-go-libs/apis/dp/v1alpha2/webhook_suite_test.go b/common-go-libs/apis/dp/v1alpha2/webhook_suite_test.go index a43cff45a..d9905b38b 100644 --- a/common-go-libs/apis/dp/v1alpha2/webhook_suite_test.go +++ b/common-go-libs/apis/dp/v1alpha2/webhook_suite_test.go @@ -103,6 +103,9 @@ var _ = BeforeSuite(func() { err = (&APIPolicy{}).SetupWebhookWithManager(mgr) Expect(err).NotTo(HaveOccurred()) + err = (&Authentication{}).SetupWebhookWithManager(mgr) + Expect(err).NotTo(HaveOccurred()) + //+kubebuilder:scaffold:webhook go func() { diff --git a/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go b/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go index 4bd94c66e..9f683a179 100644 --- a/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go +++ b/common-go-libs/apis/dp/v1alpha2/zz_generated.deepcopy.go @@ -55,6 +55,48 @@ func (in *API) DeepCopyObject() runtime.Object { return nil } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *APIAuth) DeepCopyInto(out *APIAuth) { + *out = *in + out.Oauth2 = in.Oauth2 + if in.APIKey != nil { + in, out := &in.APIKey, &out.APIKey + *out = make([]APIKeyAuth, len(*in)) + copy(*out, *in) + } + out.TestConsoleKey = in.TestConsoleKey + if in.MutualSSL != nil { + in, out := &in.MutualSSL, &out.MutualSSL + *out = new(MutualSSLConfig) + (*in).DeepCopyInto(*out) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new APIAuth. +func (in *APIAuth) DeepCopy() *APIAuth { + if in == nil { + return nil + } + out := new(APIAuth) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *APIKeyAuth) DeepCopyInto(out *APIKeyAuth) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new APIKeyAuth. +func (in *APIKeyAuth) DeepCopy() *APIKeyAuth { + if in == nil { + return nil + } + out := new(APIKeyAuth) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *APIList) DeepCopyInto(out *APIList) { *out = *in @@ -237,6 +279,131 @@ func (in *APIStatus) DeepCopy() *APIStatus { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *AuthSpec) DeepCopyInto(out *AuthSpec) { + *out = *in + if in.Disabled != nil { + in, out := &in.Disabled, &out.Disabled + *out = new(bool) + **out = **in + } + if in.AuthTypes != nil { + in, out := &in.AuthTypes, &out.AuthTypes + *out = new(APIAuth) + (*in).DeepCopyInto(*out) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AuthSpec. +func (in *AuthSpec) DeepCopy() *AuthSpec { + if in == nil { + return nil + } + out := new(AuthSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Authentication) DeepCopyInto(out *Authentication) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + out.Status = in.Status +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Authentication. +func (in *Authentication) DeepCopy() *Authentication { + if in == nil { + return nil + } + out := new(Authentication) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *Authentication) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *AuthenticationList) DeepCopyInto(out *AuthenticationList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]Authentication, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AuthenticationList. +func (in *AuthenticationList) DeepCopy() *AuthenticationList { + if in == nil { + return nil + } + out := new(AuthenticationList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *AuthenticationList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *AuthenticationSpec) DeepCopyInto(out *AuthenticationSpec) { + *out = *in + if in.Default != nil { + in, out := &in.Default, &out.Default + *out = new(AuthSpec) + (*in).DeepCopyInto(*out) + } + if in.Override != nil { + in, out := &in.Override, &out.Override + *out = new(AuthSpec) + (*in).DeepCopyInto(*out) + } + in.TargetRef.DeepCopyInto(&out.TargetRef) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AuthenticationSpec. +func (in *AuthenticationSpec) DeepCopy() *AuthenticationSpec { + if in == nil { + return nil + } + out := new(AuthenticationSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *AuthenticationStatus) DeepCopyInto(out *AuthenticationStatus) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AuthenticationStatus. +func (in *AuthenticationStatus) DeepCopy() *AuthenticationStatus { + if in == nil { + return nil + } + out := new(AuthenticationStatus) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *BackendJWTToken) DeepCopyInto(out *BackendJWTToken) { *out = *in @@ -599,6 +766,89 @@ func (in *JWKS) DeepCopy() *JWKS { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *MutualSSL) DeepCopyInto(out *MutualSSL) { + *out = *in + if in.ClientCertificates != nil { + in, out := &in.ClientCertificates, &out.ClientCertificates + *out = make([]string, len(*in)) + copy(*out, *in) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MutualSSL. +func (in *MutualSSL) DeepCopy() *MutualSSL { + if in == nil { + return nil + } + out := new(MutualSSL) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *MutualSSLConfig) DeepCopyInto(out *MutualSSLConfig) { + *out = *in + if in.CertificatesInline != nil { + in, out := &in.CertificatesInline, &out.CertificatesInline + *out = make([]*string, len(*in)) + for i := range *in { + if (*in)[i] != nil { + in, out := &(*in)[i], &(*out)[i] + *out = new(string) + **out = **in + } + } + } + if in.SecretRefs != nil { + in, out := &in.SecretRefs, &out.SecretRefs + *out = make([]*RefConfig, len(*in)) + for i := range *in { + if (*in)[i] != nil { + in, out := &(*in)[i], &(*out)[i] + *out = new(RefConfig) + **out = **in + } + } + } + if in.ConfigMapRefs != nil { + in, out := &in.ConfigMapRefs, &out.ConfigMapRefs + *out = make([]*RefConfig, len(*in)) + for i := range *in { + if (*in)[i] != nil { + in, out := &(*in)[i], &(*out)[i] + *out = new(RefConfig) + **out = **in + } + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MutualSSLConfig. +func (in *MutualSSLConfig) DeepCopy() *MutualSSLConfig { + if in == nil { + return nil + } + out := new(MutualSSLConfig) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Oauth2Auth) DeepCopyInto(out *Oauth2Auth) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Oauth2Auth. +func (in *Oauth2Auth) DeepCopy() *Oauth2Auth { + if in == nil { + return nil + } + out := new(Oauth2Auth) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *PolicySpec) DeepCopyInto(out *PolicySpec) { *out = *in @@ -689,6 +939,21 @@ func (in *SignatureValidation) DeepCopy() *SignatureValidation { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TestConsoleKeyAuth) DeepCopyInto(out *TestConsoleKeyAuth) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TestConsoleKeyAuth. +func (in *TestConsoleKeyAuth) DeepCopy() *TestConsoleKeyAuth { + if in == nil { + return nil + } + out := new(TestConsoleKeyAuth) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *TokenIssuer) DeepCopyInto(out *TokenIssuer) { *out = *in diff --git a/common-go-libs/config/crd/bases/dp.wso2.com_authentications.yaml b/common-go-libs/config/crd/bases/dp.wso2.com_authentications.yaml index 24c43accb..f1e5242cf 100644 --- a/common-go-libs/config/crd/bases/dp.wso2.com_authentications.yaml +++ b/common-go-libs/config/crd/bases/dp.wso2.com_authentications.yaml @@ -219,6 +219,340 @@ spec: type: object type: object served: true + storage: false + subresources: + status: {} + - name: v1alpha2 + schema: + openAPIV3Schema: + description: Authentication is the Schema for the authentications API + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: AuthenticationSpec defines the desired state of Authentication + properties: + default: + description: AuthSpec specification of the authentication service + properties: + authTypes: + description: AuthTypes is to specify the authentication scheme + types and details + properties: + apiKey: + description: APIKey is to specify the APIKey authentication + scheme details + items: + description: APIKeyAuth APIKey Authentication scheme details + properties: + in: + description: In is to specify how the APIKey is passed + to the request + enum: + - Header + - Query + minLength: 1 + type: string + name: + description: Name is the name of the header or query + parameter to be used + minLength: 1 + type: string + sendTokenToUpstream: + description: SendTokenToUpstream is to specify whether + the APIKey should be sent to the upstream + type: boolean + type: object + nullable: true + type: array + mtls: + description: MutualSSL is to specify the features and certificates + for mutual SSL + properties: + certificatesInline: + description: CertificatesInline is the Inline Certificate + entry + items: + type: string + type: array + configMapRefs: + description: ConfigMapRefs denotes the reference to the + ConfigMap that contains the Certificate + items: + description: RefConfig holds a config for a secret or + a configmap + properties: + key: + description: Key of the secret or configmap + minLength: 1 + type: string + name: + description: Name of the secret or configmap + minLength: 1 + type: string + required: + - key + - name + type: object + type: array + disabled: + default: false + description: Disabled is to disable mTLS authentication + type: boolean + required: + default: optional + description: Required indicates whether mutualSSL is mandatory + or optional + enum: + - mandatory + - optional + type: string + secretRefs: + description: SecretRefs denotes the reference to the Secret + that contains the Certificate + items: + description: RefConfig holds a config for a secret or + a configmap + properties: + key: + description: Key of the secret or configmap + minLength: 1 + type: string + name: + description: Name of the secret or configmap + minLength: 1 + type: string + required: + - key + - name + type: object + type: array + type: object + oauth2: + description: Oauth2 is to specify the Oauth2 authentication + scheme details + properties: + disabled: + default: false + description: Disabled is to disable OAuth2 authentication + type: boolean + header: + default: authorization + description: Header is the header name used to pass the + OAuth2 token + type: string + sendTokenToUpstream: + description: SendTokenToUpstream is to specify whether + the OAuth2 token should be sent to the upstream + type: boolean + type: object + testConsoleKey: + description: TestConsoleKey is to specify the Test Console + Key authentication scheme details + properties: + header: + default: internal-key + description: Header is the header name used to pass the + Test Console Key + minLength: 1 + type: string + sendTokenToUpstream: + description: SendTokenToUpstream is to specify whether + the Test Console Key should be sent to the upstream + type: boolean + type: object + type: object + disabled: + description: Disabled is to disable all authentications + type: boolean + type: object + override: + description: AuthSpec specification of the authentication service + properties: + authTypes: + description: AuthTypes is to specify the authentication scheme + types and details + properties: + apiKey: + description: APIKey is to specify the APIKey authentication + scheme details + items: + description: APIKeyAuth APIKey Authentication scheme details + properties: + in: + description: In is to specify how the APIKey is passed + to the request + enum: + - Header + - Query + minLength: 1 + type: string + name: + description: Name is the name of the header or query + parameter to be used + minLength: 1 + type: string + sendTokenToUpstream: + description: SendTokenToUpstream is to specify whether + the APIKey should be sent to the upstream + type: boolean + type: object + nullable: true + type: array + mtls: + description: MutualSSL is to specify the features and certificates + for mutual SSL + properties: + certificatesInline: + description: CertificatesInline is the Inline Certificate + entry + items: + type: string + type: array + configMapRefs: + description: ConfigMapRefs denotes the reference to the + ConfigMap that contains the Certificate + items: + description: RefConfig holds a config for a secret or + a configmap + properties: + key: + description: Key of the secret or configmap + minLength: 1 + type: string + name: + description: Name of the secret or configmap + minLength: 1 + type: string + required: + - key + - name + type: object + type: array + disabled: + default: false + description: Disabled is to disable mTLS authentication + type: boolean + required: + default: optional + description: Required indicates whether mutualSSL is mandatory + or optional + enum: + - mandatory + - optional + type: string + secretRefs: + description: SecretRefs denotes the reference to the Secret + that contains the Certificate + items: + description: RefConfig holds a config for a secret or + a configmap + properties: + key: + description: Key of the secret or configmap + minLength: 1 + type: string + name: + description: Name of the secret or configmap + minLength: 1 + type: string + required: + - key + - name + type: object + type: array + type: object + oauth2: + description: Oauth2 is to specify the Oauth2 authentication + scheme details + properties: + disabled: + default: false + description: Disabled is to disable OAuth2 authentication + type: boolean + header: + default: authorization + description: Header is the header name used to pass the + OAuth2 token + type: string + sendTokenToUpstream: + description: SendTokenToUpstream is to specify whether + the OAuth2 token should be sent to the upstream + type: boolean + type: object + testConsoleKey: + description: TestConsoleKey is to specify the Test Console + Key authentication scheme details + properties: + header: + default: internal-key + description: Header is the header name used to pass the + Test Console Key + minLength: 1 + type: string + sendTokenToUpstream: + description: SendTokenToUpstream is to specify whether + the Test Console Key should be sent to the upstream + type: boolean + type: object + type: object + disabled: + description: Disabled is to disable all authentications + type: boolean + type: object + targetRef: + description: PolicyTargetReference identifies an API object to apply + policy to. This should be used as part of Policy resources that + can target Gateway API resources. For more information on how this + policy attachment model works, and a sample Policy resource, refer + to the policy attachment documentation for Gateway API. + properties: + group: + description: Group is the group of the target resource. + maxLength: 253 + pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + kind: + description: Kind is kind of the target resource. + maxLength: 63 + minLength: 1 + pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ + type: string + name: + description: Name is the name of the target resource. + maxLength: 253 + minLength: 1 + type: string + namespace: + description: Namespace is the namespace of the referent. When + unspecified, the local namespace is inferred. Even when policy + targets a resource in a different namespace, it MUST only apply + to traffic originating from the same namespace as the policy. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + required: + - group + - kind + - name + type: object + type: object + status: + description: AuthenticationStatus defines the observed state of Authentication + type: object + type: object + served: true storage: true subresources: status: {} diff --git a/common-go-libs/config/webhook/manifests.yaml b/common-go-libs/config/webhook/manifests.yaml index c7026f4c8..411ed6ee8 100644 --- a/common-go-libs/config/webhook/manifests.yaml +++ b/common-go-libs/config/webhook/manifests.yaml @@ -44,6 +44,26 @@ webhooks: resources: - apipolicies sideEffects: None +- admissionReviewVersions: + - v1 + clientConfig: + service: + name: webhook-service + namespace: system + path: /mutate-dp-wso2-com-v1alpha2-authentication + failurePolicy: Fail + name: mauthentication.kb.io + rules: + - apiGroups: + - dp.wso2.com + apiVersions: + - v1alpha2 + operations: + - CREATE + - UPDATE + resources: + - authentications + sideEffects: None - admissionReviewVersions: - v1 clientConfig: @@ -64,6 +84,26 @@ webhooks: resources: - apipolicies sideEffects: None +- admissionReviewVersions: + - v1 + clientConfig: + service: + name: webhook-service + namespace: system + path: /mutate-dp-wso2-com-v1alpha1-authentication + failurePolicy: Fail + name: mauthentication.kb.io + rules: + - apiGroups: + - dp.wso2.com + apiVersions: + - v1alpha1 + operations: + - CREATE + - UPDATE + resources: + - authentications + sideEffects: None - admissionReviewVersions: - v1 clientConfig: @@ -190,6 +230,26 @@ webhooks: resources: - apipolicies sideEffects: None +- admissionReviewVersions: + - v1 + clientConfig: + service: + name: webhook-service + namespace: system + path: /validate-dp-wso2-com-v1alpha2-authentication + failurePolicy: Fail + name: vauthentication.kb.io + rules: + - apiGroups: + - dp.wso2.com + apiVersions: + - v1alpha2 + operations: + - CREATE + - UPDATE + resources: + - authentications + sideEffects: None - admissionReviewVersions: - v1 clientConfig: @@ -210,6 +270,26 @@ webhooks: resources: - apipolicies sideEffects: None +- admissionReviewVersions: + - v1 + clientConfig: + service: + name: webhook-service + namespace: system + path: /validate-dp-wso2-com-v1alpha1-authentication + failurePolicy: Fail + name: vauthentication.kb.io + rules: + - apiGroups: + - dp.wso2.com + apiVersions: + - v1alpha1 + operations: + - CREATE + - UPDATE + resources: + - authentications + sideEffects: None - admissionReviewVersions: - v1 clientConfig: diff --git a/gateway/enforcer/org.wso2.apk.enforcer.commons/src/main/java/org/wso2/apk/enforcer/commons/model/APIConfig.java b/gateway/enforcer/org.wso2.apk.enforcer.commons/src/main/java/org/wso2/apk/enforcer/commons/model/APIConfig.java index 63cd27902..72aeddfc0 100644 --- a/gateway/enforcer/org.wso2.apk.enforcer.commons/src/main/java/org/wso2/apk/enforcer/commons/model/APIConfig.java +++ b/gateway/enforcer/org.wso2.apk.enforcer.commons/src/main/java/org/wso2/apk/enforcer/commons/model/APIConfig.java @@ -46,8 +46,8 @@ public class APIConfig { private List resources = new ArrayList<>(); private boolean isMockedApi; private KeyStore trustStore; - private Map mtlsCertificateTiers = new HashMap<>(); private String mutualSSL; + private boolean transportSecurity; private boolean applicationSecurity; private GraphQLSchemaDTO graphQLSchemaDTO; private JWTConfigurationDto jwtConfigurationDto; @@ -196,14 +196,6 @@ public KeyStore getTrustStore() { return trustStore; } - /** - * Returns the tier map of mutual ssl certificates for the corresponding API. - * - * @return Tier Map - */ - public Map getMtlsCertificateTiers() { - return mtlsCertificateTiers; - } /** * Returns the mTLS optionality for the corresponding API. @@ -214,6 +206,15 @@ public String getMutualSSL() { return mutualSSL; } + /** + * Returns if transport security (mTLS) is enabled or disabled for the corresponding API. + * + * @return transportSecurity enabled + */ + public boolean isTransportSecurity() { + return transportSecurity; + } + /** * Returns the application security optionality for the corresponding API. * @@ -284,7 +285,6 @@ public static class Builder { private List resources = new ArrayList<>(); private boolean isMockedApi; private KeyStore trustStore; - private Map mtlsCertificateTiers; private String mutualSSL; private boolean applicationSecurity; private GraphQLSchemaDTO graphQLSchemaDTO; @@ -293,6 +293,8 @@ public static class Builder { private boolean subscriptionValidation; private JWTConfigurationDto jwtConfigurationDto; private String environment; + private boolean transportSecurity; + public Builder(String name) { this.name = name; } @@ -372,11 +374,6 @@ public Builder trustStore(KeyStore trustStore) { return this; } - public Builder mtlsCertificateTiers(Map mtlsCertificateTiers) { - this.mtlsCertificateTiers = mtlsCertificateTiers; - return this; - } - public Builder mutualSSL(String mutualSSL) { this.mutualSSL = mutualSSL; return this; @@ -386,7 +383,8 @@ public Builder applicationSecurity(boolean applicationSecurity) { this.applicationSecurity = applicationSecurity; return this; } - public Builder systemAPI(boolean systemAPI){ + + public Builder systemAPI(boolean systemAPI) { this.systemAPI = systemAPI; return this; } @@ -411,6 +409,11 @@ public Builder subscriptionValidation(boolean subscriptionValidation) { return this; } + public Builder transportSecurity(boolean transportSecurity) { + this.transportSecurity = transportSecurity; + return this; + } + public APIConfig build() { APIConfig apiConfig = new APIConfig(); apiConfig.name = this.name; @@ -428,11 +431,11 @@ public APIConfig build() { apiConfig.uuid = this.uuid; apiConfig.isMockedApi = this.isMockedApi; apiConfig.trustStore = this.trustStore; - apiConfig.mtlsCertificateTiers = this.mtlsCertificateTiers; apiConfig.mutualSSL = this.mutualSSL; + apiConfig.transportSecurity = this.transportSecurity; apiConfig.applicationSecurity = this.applicationSecurity; apiConfig.graphQLSchemaDTO = this.graphQLSchemaDTO; - apiConfig.systemAPI = this.systemAPI; + apiConfig.systemAPI = this.systemAPI; apiConfig.jwtConfigurationDto = this.jwtConfigurationDto; apiConfig.apiDefinition = this.apiDefinition; apiConfig.environment = this.environment; diff --git a/gateway/enforcer/org.wso2.apk.enforcer/src/main/java/org/wso2/apk/enforcer/api/GraphQLAPI.java b/gateway/enforcer/org.wso2.apk.enforcer/src/main/java/org/wso2/apk/enforcer/api/GraphQLAPI.java index 4fc6ace7c..065016446 100644 --- a/gateway/enforcer/org.wso2.apk.enforcer/src/main/java/org/wso2/apk/enforcer/api/GraphQLAPI.java +++ b/gateway/enforcer/org.wso2.apk.enforcer/src/main/java/org/wso2/apk/enforcer/api/GraphQLAPI.java @@ -105,10 +105,6 @@ public String init(Api api) { throw new SecurityException(e); } - for (Certificate certificate : api.getClientCertificatesList()) { - mtlsCertificateTiers.put(certificate.getAlias(), certificate.getTier()); - } - BackendJWTTokenInfo backendJWTTokenInfo = api.getBackendJWTTokenInfo(); JWTConfigurationDto jwtConfigurationDto = new JWTConfigurationDto(); @@ -150,7 +146,7 @@ public String init(Api api) { .resources(resources).apiType(apiType).apiLifeCycleState(apiLifeCycleState).tier(api.getTier()) .envType(api.getEnvType()).disableAuthentication(api.getDisableAuthentications()) .disableScopes(api.getDisableScopes()).trustStore(trustStore).organizationId(api.getOrganizationId()) - .mtlsCertificateTiers(mtlsCertificateTiers).mutualSSL(mutualSSL) + .mutualSSL(mutualSSL) .applicationSecurity(applicationSecurity).jwtConfigurationDto(jwtConfigurationDto) .apiDefinition(apiDefinition).environment(api.getEnvironment()) .subscriptionValidation(api.getSubscriptionValidation()).graphQLSchemaDTO(graphQLSchemaDTO).build(); @@ -171,7 +167,8 @@ public ResponseObject process(RequestContext requestContext) { // This flag is used to apply CORS filter boolean isOptionCall = requestContext.getRequestMethod().contains(HttpConstants.OPTIONS); - // handle other not allowed && non option request && not yet handled error scenarios. + // handle other not allowed && non option request && not yet handled error + // scenarios. if ((!isOptionCall && !isExistsMatchedOperations) && !requestContext.getProperties() .containsKey(APIConstants.MessageFormat.ERROR_CODE)) { requestContext.getProperties() diff --git a/gateway/enforcer/org.wso2.apk.enforcer/src/main/java/org/wso2/apk/enforcer/api/RestAPI.java b/gateway/enforcer/org.wso2.apk.enforcer/src/main/java/org/wso2/apk/enforcer/api/RestAPI.java index ab6d9d578..069a2ea35 100644 --- a/gateway/enforcer/org.wso2.apk.enforcer/src/main/java/org/wso2/apk/enforcer/api/RestAPI.java +++ b/gateway/enforcer/org.wso2.apk.enforcer/src/main/java/org/wso2/apk/enforcer/api/RestAPI.java @@ -79,7 +79,6 @@ public String init(Api api) { String version = api.getVersion(); String apiType = api.getApiType(); List resources = new ArrayList<>(); - Map mtlsCertificateTiers = new HashMap<>(); String mutualSSL = api.getMutualSSL(); boolean applicationSecurity = api.getApplicationSecurity(); @@ -100,10 +99,6 @@ public String init(Api api) { throw new SecurityException(e); } - for (Certificate certificate : api.getClientCertificatesList()) { - mtlsCertificateTiers.put(certificate.getAlias(), certificate.getTier()); - } - BackendJWTTokenInfo backendJWTTokenInfo = api.getBackendJWTTokenInfo(); JWTConfigurationDto jwtConfigurationDto = new JWTConfigurationDto(); @@ -131,10 +126,11 @@ public String init(Api api) { .resources(resources).apiType(apiType).tier(api.getTier()) .envType(api.getEnvType()).disableAuthentication(api.getDisableAuthentications()) .disableScopes(api.getDisableScopes()).trustStore(trustStore).organizationId(api.getOrganizationId()) - .mtlsCertificateTiers(mtlsCertificateTiers).mutualSSL(mutualSSL).systemAPI(api.getSystemAPI()) + .mutualSSL(mutualSSL).systemAPI(api.getSystemAPI()) .applicationSecurity(applicationSecurity).jwtConfigurationDto(jwtConfigurationDto) .apiDefinition(apiDefinition).environment(api.getEnvironment()) - .subscriptionValidation(api.getSubscriptionValidation()).build(); + .subscriptionValidation(api.getSubscriptionValidation()).transportSecurity(api.getTransportSecurity()) + .build(); initFilters(); return basePath; diff --git a/gateway/enforcer/org.wso2.apk.enforcer/src/main/java/org/wso2/apk/enforcer/discovery/api/Api.java b/gateway/enforcer/org.wso2.apk.enforcer/src/main/java/org/wso2/apk/enforcer/discovery/api/Api.java index 451fd9277..d0614f392 100644 --- a/gateway/enforcer/org.wso2.apk.enforcer/src/main/java/org/wso2/apk/enforcer/discovery/api/Api.java +++ b/gateway/enforcer/org.wso2.apk.enforcer/src/main/java/org/wso2/apk/enforcer/discovery/api/Api.java @@ -169,6 +169,11 @@ private Api( applicationSecurity_ = input.readBool(); break; } + case 136: { + + transportSecurity_ = input.readBool(); + break; + } case 186: { if (!((mutable_bitField0_ & 0x00000004) != 0)) { graphqlComplexityInfo_ = new java.util.ArrayList(); @@ -829,6 +834,17 @@ public boolean getApplicationSecurity() { return applicationSecurity_; } + public static final int TRANSPORTSECURITY_FIELD_NUMBER = 17; + private boolean transportSecurity_; + /** + * bool transportSecurity = 17; + * @return The transportSecurity. + */ + @java.lang.Override + public boolean getTransportSecurity() { + return transportSecurity_; + } + public static final int GRAPHQLCOMPLEXITYINFO_FIELD_NUMBER = 23; private java.util.List graphqlComplexityInfo_; /** @@ -1114,6 +1130,9 @@ public void writeTo(com.google.protobuf.CodedOutputStream output) if (applicationSecurity_ != false) { output.writeBool(16, applicationSecurity_); } + if (transportSecurity_ != false) { + output.writeBool(17, transportSecurity_); + } for (int i = 0; i < graphqlComplexityInfo_.size(); i++) { output.writeMessage(23, graphqlComplexityInfo_.get(i)); } @@ -1200,6 +1219,10 @@ public int getSerializedSize() { size += com.google.protobuf.CodedOutputStream .computeBoolSize(16, applicationSecurity_); } + if (transportSecurity_ != false) { + size += com.google.protobuf.CodedOutputStream + .computeBoolSize(17, transportSecurity_); + } for (int i = 0; i < graphqlComplexityInfo_.size(); i++) { size += com.google.protobuf.CodedOutputStream .computeMessageSize(23, graphqlComplexityInfo_.get(i)); @@ -1278,6 +1301,8 @@ public boolean equals(final java.lang.Object obj) { .equals(other.getMutualSSL())) return false; if (getApplicationSecurity() != other.getApplicationSecurity()) return false; + if (getTransportSecurity() + != other.getTransportSecurity()) return false; if (!getGraphqlComplexityInfoList() .equals(other.getGraphqlComplexityInfoList())) return false; if (getSystemAPI() @@ -1350,6 +1375,9 @@ public int hashCode() { hash = (37 * hash) + APPLICATIONSECURITY_FIELD_NUMBER; hash = (53 * hash) + com.google.protobuf.Internal.hashBoolean( getApplicationSecurity()); + hash = (37 * hash) + TRANSPORTSECURITY_FIELD_NUMBER; + hash = (53 * hash) + com.google.protobuf.Internal.hashBoolean( + getTransportSecurity()); if (getGraphqlComplexityInfoCount() > 0) { hash = (37 * hash) + GRAPHQLCOMPLEXITYINFO_FIELD_NUMBER; hash = (53 * hash) + getGraphqlComplexityInfoList().hashCode(); @@ -1557,6 +1585,8 @@ public Builder clear() { applicationSecurity_ = false; + transportSecurity_ = false; + if (graphqlComplexityInfoBuilder_ == null) { graphqlComplexityInfo_ = java.util.Collections.emptyList(); bitField0_ = (bitField0_ & ~0x00000004); @@ -1648,6 +1678,7 @@ public org.wso2.apk.enforcer.discovery.api.Api buildPartial() { } result.mutualSSL_ = mutualSSL_; result.applicationSecurity_ = applicationSecurity_; + result.transportSecurity_ = transportSecurity_; if (graphqlComplexityInfoBuilder_ == null) { if (((bitField0_ & 0x00000004) != 0)) { graphqlComplexityInfo_ = java.util.Collections.unmodifiableList(graphqlComplexityInfo_); @@ -1833,6 +1864,9 @@ public Builder mergeFrom(org.wso2.apk.enforcer.discovery.api.Api other) { if (other.getApplicationSecurity() != false) { setApplicationSecurity(other.getApplicationSecurity()); } + if (other.getTransportSecurity() != false) { + setTransportSecurity(other.getTransportSecurity()); + } if (graphqlComplexityInfoBuilder_ == null) { if (!other.graphqlComplexityInfo_.isEmpty()) { if (graphqlComplexityInfo_.isEmpty()) { @@ -3415,6 +3449,37 @@ public Builder clearApplicationSecurity() { return this; } + private boolean transportSecurity_ ; + /** + * bool transportSecurity = 17; + * @return The transportSecurity. + */ + @java.lang.Override + public boolean getTransportSecurity() { + return transportSecurity_; + } + /** + * bool transportSecurity = 17; + * @param value The transportSecurity to set. + * @return This builder for chaining. + */ + public Builder setTransportSecurity(boolean value) { + + transportSecurity_ = value; + onChanged(); + return this; + } + /** + * bool transportSecurity = 17; + * @return This builder for chaining. + */ + public Builder clearTransportSecurity() { + + transportSecurity_ = false; + onChanged(); + return this; + } + private java.util.List graphqlComplexityInfo_ = java.util.Collections.emptyList(); private void ensureGraphqlComplexityInfoIsMutable() { diff --git a/gateway/enforcer/org.wso2.apk.enforcer/src/main/java/org/wso2/apk/enforcer/discovery/api/ApiOrBuilder.java b/gateway/enforcer/org.wso2.apk.enforcer/src/main/java/org/wso2/apk/enforcer/discovery/api/ApiOrBuilder.java index 68a84404c..9a519528d 100644 --- a/gateway/enforcer/org.wso2.apk.enforcer/src/main/java/org/wso2/apk/enforcer/discovery/api/ApiOrBuilder.java +++ b/gateway/enforcer/org.wso2.apk.enforcer/src/main/java/org/wso2/apk/enforcer/discovery/api/ApiOrBuilder.java @@ -225,6 +225,12 @@ org.wso2.apk.enforcer.discovery.api.CertificateOrBuilder getClientCertificatesOr */ boolean getApplicationSecurity(); + /** + * bool transportSecurity = 17; + * @return The transportSecurity. + */ + boolean getTransportSecurity(); + /** *
    */ string graphQLSchema = 22;
diff --git a/gateway/enforcer/org.wso2.apk.enforcer/src/main/java/org/wso2/apk/enforcer/discovery/api/ApiProto.java b/gateway/enforcer/org.wso2.apk.enforcer/src/main/java/org/wso2/apk/enforcer/discovery/api/ApiProto.java
index 9350f8db7..76ecc750b 100644
--- a/gateway/enforcer/org.wso2.apk.enforcer/src/main/java/org/wso2/apk/enforcer/discovery/api/ApiProto.java
+++ b/gateway/enforcer/org.wso2.apk.enforcer/src/main/java/org/wso2/apk/enforcer/discovery/api/ApiProto.java
@@ -35,7 +35,7 @@ public static void registerAllExtensions(
       "nfo.proto\032)wso2/discovery/api/endpoint_c" +
       "luster.proto\032&wso2/discovery/api/securit" +
       "y_info.proto\032 wso2/discovery/api/graphql" +
-      ".proto\"\355\005\n\003Api\022\n\n\002id\030\001 \001(\t\022\r\n\005title\030\002 \001(" +
+      ".proto\"\210\006\n\003Api\022\n\n\002id\030\001 \001(\t\022\r\n\005title\030\002 \001(" +
       "\t\022\017\n\007version\030\003 \001(\t\022\017\n\007apiType\030\004 \001(\t\022\036\n\026d" +
       "isableAuthentications\030\005 \001(\010\022\025\n\rdisableSc" +
       "opes\030\006 \001(\010\022\017\n\007envType\030\007 \001(\t\022/\n\tresources" +
@@ -45,18 +45,19 @@ public static void registerAllExtensions(
       "zationId\030\r \001(\t\022;\n\022clientCertificates\030\016 \003" +
       "(\0132\037.wso2.discovery.api.Certificate\022\021\n\tm" +
       "utualSSL\030\017 \001(\t\022\033\n\023applicationSecurity\030\020 " +
-      "\001(\010\022D\n\025graphqlComplexityInfo\030\027 \003(\0132%.wso" +
-      "2.discovery.api.GraphqlComplexity\022\021\n\tsys" +
-      "temAPI\030\030 \001(\010\022D\n\023backendJWTTokenInfo\030\031 \001(" +
-      "\0132\'.wso2.discovery.api.BackendJWTTokenIn" +
-      "fo\022\031\n\021apiDefinitionFile\030\032 \001(\014\022\023\n\013environ" +
-      "ment\030\033 \001(\t\022\036\n\026subscriptionValidation\030\034 \001" +
-      "(\010\0226\n\tendpoints\030\035 \001(\0132#.wso2.discovery.a" +
-      "pi.EndpointCluster\022:\n\020endpointSecurity\030\036" +
-      " \003(\0132 .wso2.discovery.api.SecurityInfoBp" +
-      "\n#org.wso2.apk.enforcer.discovery.apiB\010A" +
-      "piProtoP\001Z=github.com/envoyproxy/go-cont" +
-      "rol-plane/wso2/discovery/api;apib\006proto3"
+      "\001(\010\022\031\n\021transportSecurity\030\021 \001(\010\022D\n\025graphq" +
+      "lComplexityInfo\030\027 \003(\0132%.wso2.discovery.a" +
+      "pi.GraphqlComplexity\022\021\n\tsystemAPI\030\030 \001(\010\022" +
+      "D\n\023backendJWTTokenInfo\030\031 \001(\0132\'.wso2.disc" +
+      "overy.api.BackendJWTTokenInfo\022\031\n\021apiDefi" +
+      "nitionFile\030\032 \001(\014\022\023\n\013environment\030\033 \001(\t\022\036\n" +
+      "\026subscriptionValidation\030\034 \001(\010\0226\n\tendpoin" +
+      "ts\030\035 \001(\0132#.wso2.discovery.api.EndpointCl" +
+      "uster\022:\n\020endpointSecurity\030\036 \003(\0132 .wso2.d" +
+      "iscovery.api.SecurityInfoBp\n#org.wso2.ap" +
+      "k.enforcer.discovery.apiB\010ApiProtoP\001Z=gi" +
+      "thub.com/envoyproxy/go-control-plane/wso" +
+      "2/discovery/api;apib\006proto3"
     };
     descriptor = com.google.protobuf.Descriptors.FileDescriptor
       .internalBuildGeneratedFileFrom(descriptorData,
@@ -73,7 +74,7 @@ public static void registerAllExtensions(
     internal_static_wso2_discovery_api_Api_fieldAccessorTable = new
       com.google.protobuf.GeneratedMessageV3.FieldAccessorTable(
         internal_static_wso2_discovery_api_Api_descriptor,
-        new java.lang.String[] { "Id", "Title", "Version", "ApiType", "DisableAuthentications", "DisableScopes", "EnvType", "Resources", "BasePath", "Tier", "ApiLifeCycleState", "Vhost", "OrganizationId", "ClientCertificates", "MutualSSL", "ApplicationSecurity", "GraphqlComplexityInfo", "SystemAPI", "BackendJWTTokenInfo", "ApiDefinitionFile", "Environment", "SubscriptionValidation", "Endpoints", "EndpointSecurity", });
+        new java.lang.String[] { "Id", "Title", "Version", "ApiType", "DisableAuthentications", "DisableScopes", "EnvType", "Resources", "BasePath", "Tier", "ApiLifeCycleState", "Vhost", "OrganizationId", "ClientCertificates", "MutualSSL", "ApplicationSecurity", "TransportSecurity", "GraphqlComplexityInfo", "SystemAPI", "BackendJWTTokenInfo", "ApiDefinitionFile", "Environment", "SubscriptionValidation", "Endpoints", "EndpointSecurity", });
     org.wso2.apk.enforcer.discovery.api.ResourceProto.getDescriptor();
     org.wso2.apk.enforcer.discovery.api.CertificateProto.getDescriptor();
     org.wso2.apk.enforcer.discovery.api.BackendJWTTokenInfoProto.getDescriptor();
diff --git a/gateway/enforcer/org.wso2.apk.enforcer/src/main/java/org/wso2/apk/enforcer/discovery/api/Certificate.java b/gateway/enforcer/org.wso2.apk.enforcer/src/main/java/org/wso2/apk/enforcer/discovery/api/Certificate.java
index 0a4eeeb8d..f53500587 100644
--- a/gateway/enforcer/org.wso2.apk.enforcer/src/main/java/org/wso2/apk/enforcer/discovery/api/Certificate.java
+++ b/gateway/enforcer/org.wso2.apk.enforcer/src/main/java/org/wso2/apk/enforcer/discovery/api/Certificate.java
@@ -21,7 +21,6 @@ private Certificate(com.google.protobuf.GeneratedMessageV3.Builder builder) {
   }
   private Certificate() {
     alias_ = "";
-    tier_ = "";
     content_ = com.google.protobuf.ByteString.EMPTY;
   }
 
@@ -62,12 +61,6 @@ private Certificate(
             break;
           }
           case 18: {
-            java.lang.String s = input.readStringRequireUtf8();
-
-            tier_ = s;
-            break;
-          }
-          case 26: {
 
             content_ = input.readBytes();
             break;
@@ -142,48 +135,10 @@ public java.lang.String getAlias() {
     }
   }
 
-  public static final int TIER_FIELD_NUMBER = 2;
-  private volatile java.lang.Object tier_;
-  /**
-   * string tier = 2;
-   * @return The tier.
-   */
-  @java.lang.Override
-  public java.lang.String getTier() {
-    java.lang.Object ref = tier_;
-    if (ref instanceof java.lang.String) {
-      return (java.lang.String) ref;
-    } else {
-      com.google.protobuf.ByteString bs = 
-          (com.google.protobuf.ByteString) ref;
-      java.lang.String s = bs.toStringUtf8();
-      tier_ = s;
-      return s;
-    }
-  }
-  /**
-   * string tier = 2;
-   * @return The bytes for tier.
-   */
-  @java.lang.Override
-  public com.google.protobuf.ByteString
-      getTierBytes() {
-    java.lang.Object ref = tier_;
-    if (ref instanceof java.lang.String) {
-      com.google.protobuf.ByteString b = 
-          com.google.protobuf.ByteString.copyFromUtf8(
-              (java.lang.String) ref);
-      tier_ = b;
-      return b;
-    } else {
-      return (com.google.protobuf.ByteString) ref;
-    }
-  }
-
-  public static final int CONTENT_FIELD_NUMBER = 3;
+  public static final int CONTENT_FIELD_NUMBER = 2;
   private com.google.protobuf.ByteString content_;
   /**
-   * bytes content = 3;
+   * bytes content = 2;
    * @return The content.
    */
   @java.lang.Override
@@ -208,11 +163,8 @@ public void writeTo(com.google.protobuf.CodedOutputStream output)
     if (!getAliasBytes().isEmpty()) {
       com.google.protobuf.GeneratedMessageV3.writeString(output, 1, alias_);
     }
-    if (!getTierBytes().isEmpty()) {
-      com.google.protobuf.GeneratedMessageV3.writeString(output, 2, tier_);
-    }
     if (!content_.isEmpty()) {
-      output.writeBytes(3, content_);
+      output.writeBytes(2, content_);
     }
     unknownFields.writeTo(output);
   }
@@ -226,12 +178,9 @@ public int getSerializedSize() {
     if (!getAliasBytes().isEmpty()) {
       size += com.google.protobuf.GeneratedMessageV3.computeStringSize(1, alias_);
     }
-    if (!getTierBytes().isEmpty()) {
-      size += com.google.protobuf.GeneratedMessageV3.computeStringSize(2, tier_);
-    }
     if (!content_.isEmpty()) {
       size += com.google.protobuf.CodedOutputStream
-        .computeBytesSize(3, content_);
+        .computeBytesSize(2, content_);
     }
     size += unknownFields.getSerializedSize();
     memoizedSize = size;
@@ -250,8 +199,6 @@ public boolean equals(final java.lang.Object obj) {
 
     if (!getAlias()
         .equals(other.getAlias())) return false;
-    if (!getTier()
-        .equals(other.getTier())) return false;
     if (!getContent()
         .equals(other.getContent())) return false;
     if (!unknownFields.equals(other.unknownFields)) return false;
@@ -267,8 +214,6 @@ public int hashCode() {
     hash = (19 * hash) + getDescriptor().hashCode();
     hash = (37 * hash) + ALIAS_FIELD_NUMBER;
     hash = (53 * hash) + getAlias().hashCode();
-    hash = (37 * hash) + TIER_FIELD_NUMBER;
-    hash = (53 * hash) + getTier().hashCode();
     hash = (37 * hash) + CONTENT_FIELD_NUMBER;
     hash = (53 * hash) + getContent().hashCode();
     hash = (29 * hash) + unknownFields.hashCode();
@@ -410,8 +355,6 @@ public Builder clear() {
       super.clear();
       alias_ = "";
 
-      tier_ = "";
-
       content_ = com.google.protobuf.ByteString.EMPTY;
 
       return this;
@@ -441,7 +384,6 @@ public org.wso2.apk.enforcer.discovery.api.Certificate build() {
     public org.wso2.apk.enforcer.discovery.api.Certificate buildPartial() {
       org.wso2.apk.enforcer.discovery.api.Certificate result = new org.wso2.apk.enforcer.discovery.api.Certificate(this);
       result.alias_ = alias_;
-      result.tier_ = tier_;
       result.content_ = content_;
       onBuilt();
       return result;
@@ -495,10 +437,6 @@ public Builder mergeFrom(org.wso2.apk.enforcer.discovery.api.Certificate other)
         alias_ = other.alias_;
         onChanged();
       }
-      if (!other.getTier().isEmpty()) {
-        tier_ = other.tier_;
-        onChanged();
-      }
       if (other.getContent() != com.google.protobuf.ByteString.EMPTY) {
         setContent(other.getContent());
       }
@@ -607,85 +545,9 @@ public Builder setAliasBytes(
       return this;
     }
 
-    private java.lang.Object tier_ = "";
-    /**
-     * string tier = 2;
-     * @return The tier.
-     */
-    public java.lang.String getTier() {
-      java.lang.Object ref = tier_;
-      if (!(ref instanceof java.lang.String)) {
-        com.google.protobuf.ByteString bs =
-            (com.google.protobuf.ByteString) ref;
-        java.lang.String s = bs.toStringUtf8();
-        tier_ = s;
-        return s;
-      } else {
-        return (java.lang.String) ref;
-      }
-    }
-    /**
-     * string tier = 2;
-     * @return The bytes for tier.
-     */
-    public com.google.protobuf.ByteString
-        getTierBytes() {
-      java.lang.Object ref = tier_;
-      if (ref instanceof String) {
-        com.google.protobuf.ByteString b = 
-            com.google.protobuf.ByteString.copyFromUtf8(
-                (java.lang.String) ref);
-        tier_ = b;
-        return b;
-      } else {
-        return (com.google.protobuf.ByteString) ref;
-      }
-    }
-    /**
-     * string tier = 2;
-     * @param value The tier to set.
-     * @return This builder for chaining.
-     */
-    public Builder setTier(
-        java.lang.String value) {
-      if (value == null) {
-    throw new NullPointerException();
-  }
-  
-      tier_ = value;
-      onChanged();
-      return this;
-    }
-    /**
-     * string tier = 2;
-     * @return This builder for chaining.
-     */
-    public Builder clearTier() {
-      
-      tier_ = getDefaultInstance().getTier();
-      onChanged();
-      return this;
-    }
-    /**
-     * string tier = 2;
-     * @param value The bytes for tier to set.
-     * @return This builder for chaining.
-     */
-    public Builder setTierBytes(
-        com.google.protobuf.ByteString value) {
-      if (value == null) {
-    throw new NullPointerException();
-  }
-  checkByteStringIsUtf8(value);
-      
-      tier_ = value;
-      onChanged();
-      return this;
-    }
-
     private com.google.protobuf.ByteString content_ = com.google.protobuf.ByteString.EMPTY;
     /**
-     * bytes content = 3;
+     * bytes content = 2;
      * @return The content.
      */
     @java.lang.Override
@@ -693,7 +555,7 @@ public com.google.protobuf.ByteString getContent() {
       return content_;
     }
     /**
-     * bytes content = 3;
+     * bytes content = 2;
      * @param value The content to set.
      * @return This builder for chaining.
      */
@@ -707,7 +569,7 @@ public Builder setContent(com.google.protobuf.ByteString value) {
       return this;
     }
     /**
-     * bytes content = 3;
+     * bytes content = 2;
      * @return This builder for chaining.
      */
     public Builder clearContent() {
diff --git a/gateway/enforcer/org.wso2.apk.enforcer/src/main/java/org/wso2/apk/enforcer/discovery/api/CertificateOrBuilder.java b/gateway/enforcer/org.wso2.apk.enforcer/src/main/java/org/wso2/apk/enforcer/discovery/api/CertificateOrBuilder.java
index a8e92bca1..51080ae9f 100644
--- a/gateway/enforcer/org.wso2.apk.enforcer/src/main/java/org/wso2/apk/enforcer/discovery/api/CertificateOrBuilder.java
+++ b/gateway/enforcer/org.wso2.apk.enforcer/src/main/java/org/wso2/apk/enforcer/discovery/api/CertificateOrBuilder.java
@@ -20,19 +20,7 @@ public interface CertificateOrBuilder extends
       getAliasBytes();
 
   /**
-   * string tier = 2;
-   * @return The tier.
-   */
-  java.lang.String getTier();
-  /**
-   * string tier = 2;
-   * @return The bytes for tier.
-   */
-  com.google.protobuf.ByteString
-      getTierBytes();
-
-  /**
-   * bytes content = 3;
+   * bytes content = 2;
    * @return The content.
    */
   com.google.protobuf.ByteString getContent();
diff --git a/gateway/enforcer/org.wso2.apk.enforcer/src/main/java/org/wso2/apk/enforcer/discovery/api/CertificateProto.java b/gateway/enforcer/org.wso2.apk.enforcer/src/main/java/org/wso2/apk/enforcer/discovery/api/CertificateProto.java
index c0028b109..484d5794a 100644
--- a/gateway/enforcer/org.wso2.apk.enforcer/src/main/java/org/wso2/apk/enforcer/discovery/api/CertificateProto.java
+++ b/gateway/enforcer/org.wso2.apk.enforcer/src/main/java/org/wso2/apk/enforcer/discovery/api/CertificateProto.java
@@ -29,12 +29,11 @@ public static void registerAllExtensions(
   static {
     java.lang.String[] descriptorData = {
       "\n$wso2/discovery/api/Certificate.proto\022\022" +
-      "wso2.discovery.api\";\n\013Certificate\022\r\n\005ali" +
-      "as\030\001 \001(\t\022\014\n\004tier\030\002 \001(\t\022\017\n\007content\030\003 \001(\014B" +
-      "x\n#org.wso2.apk.enforcer.discovery.apiB\020" +
-      "CertificateProtoP\001Z=github.com/envoyprox" +
-      "y/go-control-plane/wso2/discovery/api;ap" +
-      "ib\006proto3"
+      "wso2.discovery.api\"-\n\013Certificate\022\r\n\005ali" +
+      "as\030\001 \001(\t\022\017\n\007content\030\002 \001(\014Bx\n#org.wso2.ap" +
+      "k.enforcer.discovery.apiB\020CertificatePro" +
+      "toP\001Z=github.com/envoyproxy/go-control-p" +
+      "lane/wso2/discovery/api;apib\006proto3"
     };
     descriptor = com.google.protobuf.Descriptors.FileDescriptor
       .internalBuildGeneratedFileFrom(descriptorData,
@@ -45,7 +44,7 @@ public static void registerAllExtensions(
     internal_static_wso2_discovery_api_Certificate_fieldAccessorTable = new
       com.google.protobuf.GeneratedMessageV3.FieldAccessorTable(
         internal_static_wso2_discovery_api_Certificate_descriptor,
-        new java.lang.String[] { "Alias", "Tier", "Content", });
+        new java.lang.String[] { "Alias", "Content", });
   }
 
   // @@protoc_insertion_point(outer_class_scope)
diff --git a/gateway/enforcer/org.wso2.apk.enforcer/src/main/java/org/wso2/apk/enforcer/security/AuthFilter.java b/gateway/enforcer/org.wso2.apk.enforcer/src/main/java/org/wso2/apk/enforcer/security/AuthFilter.java
index 0715006e4..8398b6db4 100644
--- a/gateway/enforcer/org.wso2.apk.enforcer/src/main/java/org/wso2/apk/enforcer/security/AuthFilter.java
+++ b/gateway/enforcer/org.wso2.apk.enforcer/src/main/java/org/wso2/apk/enforcer/security/AuthFilter.java
@@ -72,11 +72,15 @@ private void initializeAuthenticators(APIConfig apiConfig) {
         isOAuthBasicAuthMandatory = apiConfig.getApplicationSecurity();
 
         if (!Objects.isNull(apiConfig.getMutualSSL())) {
-            if (apiConfig.getMutualSSL().equalsIgnoreCase(APIConstants.Optionality.MANDATORY)) {
-                isMutualSSLProtected = true;
-                isMutualSSLMandatory = true;
-            } else if (apiConfig.getMutualSSL().equalsIgnoreCase(APIConstants.Optionality.OPTIONAL)) {
-                isMutualSSLProtected = true;
+            if (apiConfig.isTransportSecurity()) {
+                if (apiConfig.getMutualSSL().equalsIgnoreCase(APIConstants.Optionality.MANDATORY)) {
+                    isMutualSSLProtected = true;
+                    isMutualSSLMandatory = true;
+                } else if (apiConfig.getMutualSSL().equalsIgnoreCase(APIConstants.Optionality.OPTIONAL)) {
+                    isMutualSSLProtected = true;
+                }
+            } else {
+                isMutualSSLProtected = false;
             }
         }
 
diff --git a/gateway/enforcer/org.wso2.apk.enforcer/src/main/java/org/wso2/apk/enforcer/security/jwt/UnsecuredAPIAuthenticator.java b/gateway/enforcer/org.wso2.apk.enforcer/src/main/java/org/wso2/apk/enforcer/security/jwt/UnsecuredAPIAuthenticator.java
index 48d1d481f..5904dcaee 100644
--- a/gateway/enforcer/org.wso2.apk.enforcer/src/main/java/org/wso2/apk/enforcer/security/jwt/UnsecuredAPIAuthenticator.java
+++ b/gateway/enforcer/org.wso2.apk.enforcer/src/main/java/org/wso2/apk/enforcer/security/jwt/UnsecuredAPIAuthenticator.java
@@ -47,7 +47,7 @@ public boolean canAuthenticate(RequestContext requestContext) {
         // Retrieve the disable security value. If security is disabled for all matching resources,
         // then you can proceed directly with the authentication.
         for (ResourceConfig resourceConfig : requestContext.getMatchedResourcePaths()) {
-            if (!resourceConfig.getAuthenticationConfig().isDisabled()) {
+            if (!resourceConfig.getAuthenticationConfig().isDisabled() || requestContext.getMatchedAPI().isTransportSecurity()) {
                 return false;
             }
         }
diff --git a/gateway/enforcer/org.wso2.apk.enforcer/src/main/java/org/wso2/apk/enforcer/security/mtls/MTLSAuthenticator.java b/gateway/enforcer/org.wso2.apk.enforcer/src/main/java/org/wso2/apk/enforcer/security/mtls/MTLSAuthenticator.java
index 01ab0324f..4dfab7c43 100644
--- a/gateway/enforcer/org.wso2.apk.enforcer/src/main/java/org/wso2/apk/enforcer/security/mtls/MTLSAuthenticator.java
+++ b/gateway/enforcer/org.wso2.apk.enforcer/src/main/java/org/wso2/apk/enforcer/security/mtls/MTLSAuthenticator.java
@@ -101,14 +101,6 @@ public AuthenticationContext authenticate(RequestContext requestContext) throws
                 }
                 if (!Objects.isNull(clientCert)) {
                     authenticated = true;
-                    String clientCertificateTier = "";
-                    if (requestContext.getMatchedAPI().getMtlsCertificateTiers().containsKey(clientCertificateAlias)) {
-                        clientCertificateTier = requestContext.getMatchedAPI().getMtlsCertificateTiers()
-                                .get(clientCertificateAlias);
-                    }
-                    if (StringUtils.isNotBlank(clientCertificateTier)) {
-                        authenticationContext.setTier(clientCertificateTier);
-                    }
                     String subjectDN = clientCert.getSubjectDN().getName();
                     authenticationContext.setUsername(subjectDN);
                 }
diff --git a/helm-charts/crds/dp.wso2.com_authentications.yaml b/helm-charts/crds/dp.wso2.com_authentications.yaml
index 3a289dcb2..f1e5242cf 100644
--- a/helm-charts/crds/dp.wso2.com_authentications.yaml
+++ b/helm-charts/crds/dp.wso2.com_authentications.yaml
@@ -3,8 +3,7 @@ apiVersion: apiextensions.k8s.io/v1
 kind: CustomResourceDefinition
 metadata:
   annotations:
-    controller-gen.kubebuilder.io/version: v0.9.2
-  creationTimestamp: null
+    controller-gen.kubebuilder.io/version: v0.12.0
   name: authentications.dp.wso2.com
 spec:
   group: dp.wso2.com
@@ -220,6 +219,340 @@ spec:
             type: object
         type: object
     served: true
+    storage: false
+    subresources:
+      status: {}
+  - name: v1alpha2
+    schema:
+      openAPIV3Schema:
+        description: Authentication is the Schema for the authentications API
+        properties:
+          apiVersion:
+            description: 'APIVersion defines the versioned schema of this representation
+              of an object. Servers should convert recognized schemas to the latest
+              internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
+            type: string
+          kind:
+            description: 'Kind is a string value representing the REST resource this
+              object represents. Servers may infer this from the endpoint the client
+              submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
+            type: string
+          metadata:
+            type: object
+          spec:
+            description: AuthenticationSpec defines the desired state of Authentication
+            properties:
+              default:
+                description: AuthSpec specification of the authentication service
+                properties:
+                  authTypes:
+                    description: AuthTypes is to specify the authentication scheme
+                      types and details
+                    properties:
+                      apiKey:
+                        description: APIKey is to specify the APIKey authentication
+                          scheme details
+                        items:
+                          description: APIKeyAuth APIKey Authentication scheme details
+                          properties:
+                            in:
+                              description: In is to specify how the APIKey is passed
+                                to the request
+                              enum:
+                              - Header
+                              - Query
+                              minLength: 1
+                              type: string
+                            name:
+                              description: Name is the name of the header or query
+                                parameter to be used
+                              minLength: 1
+                              type: string
+                            sendTokenToUpstream:
+                              description: SendTokenToUpstream is to specify whether
+                                the APIKey should be sent to the upstream
+                              type: boolean
+                          type: object
+                        nullable: true
+                        type: array
+                      mtls:
+                        description: MutualSSL is to specify the features and certificates
+                          for mutual SSL
+                        properties:
+                          certificatesInline:
+                            description: CertificatesInline is the Inline Certificate
+                              entry
+                            items:
+                              type: string
+                            type: array
+                          configMapRefs:
+                            description: ConfigMapRefs denotes the reference to the
+                              ConfigMap that contains the Certificate
+                            items:
+                              description: RefConfig holds a config for a secret or
+                                a configmap
+                              properties:
+                                key:
+                                  description: Key of the secret or configmap
+                                  minLength: 1
+                                  type: string
+                                name:
+                                  description: Name of the secret or configmap
+                                  minLength: 1
+                                  type: string
+                              required:
+                              - key
+                              - name
+                              type: object
+                            type: array
+                          disabled:
+                            default: false
+                            description: Disabled is to disable mTLS authentication
+                            type: boolean
+                          required:
+                            default: optional
+                            description: Required indicates whether mutualSSL is mandatory
+                              or optional
+                            enum:
+                            - mandatory
+                            - optional
+                            type: string
+                          secretRefs:
+                            description: SecretRefs denotes the reference to the Secret
+                              that contains the Certificate
+                            items:
+                              description: RefConfig holds a config for a secret or
+                                a configmap
+                              properties:
+                                key:
+                                  description: Key of the secret or configmap
+                                  minLength: 1
+                                  type: string
+                                name:
+                                  description: Name of the secret or configmap
+                                  minLength: 1
+                                  type: string
+                              required:
+                              - key
+                              - name
+                              type: object
+                            type: array
+                        type: object
+                      oauth2:
+                        description: Oauth2 is to specify the Oauth2 authentication
+                          scheme details
+                        properties:
+                          disabled:
+                            default: false
+                            description: Disabled is to disable OAuth2 authentication
+                            type: boolean
+                          header:
+                            default: authorization
+                            description: Header is the header name used to pass the
+                              OAuth2 token
+                            type: string
+                          sendTokenToUpstream:
+                            description: SendTokenToUpstream is to specify whether
+                              the OAuth2 token should be sent to the upstream
+                            type: boolean
+                        type: object
+                      testConsoleKey:
+                        description: TestConsoleKey is to specify the Test Console
+                          Key authentication scheme details
+                        properties:
+                          header:
+                            default: internal-key
+                            description: Header is the header name used to pass the
+                              Test Console Key
+                            minLength: 1
+                            type: string
+                          sendTokenToUpstream:
+                            description: SendTokenToUpstream is to specify whether
+                              the Test Console Key should be sent to the upstream
+                            type: boolean
+                        type: object
+                    type: object
+                  disabled:
+                    description: Disabled is to disable all authentications
+                    type: boolean
+                type: object
+              override:
+                description: AuthSpec specification of the authentication service
+                properties:
+                  authTypes:
+                    description: AuthTypes is to specify the authentication scheme
+                      types and details
+                    properties:
+                      apiKey:
+                        description: APIKey is to specify the APIKey authentication
+                          scheme details
+                        items:
+                          description: APIKeyAuth APIKey Authentication scheme details
+                          properties:
+                            in:
+                              description: In is to specify how the APIKey is passed
+                                to the request
+                              enum:
+                              - Header
+                              - Query
+                              minLength: 1
+                              type: string
+                            name:
+                              description: Name is the name of the header or query
+                                parameter to be used
+                              minLength: 1
+                              type: string
+                            sendTokenToUpstream:
+                              description: SendTokenToUpstream is to specify whether
+                                the APIKey should be sent to the upstream
+                              type: boolean
+                          type: object
+                        nullable: true
+                        type: array
+                      mtls:
+                        description: MutualSSL is to specify the features and certificates
+                          for mutual SSL
+                        properties:
+                          certificatesInline:
+                            description: CertificatesInline is the Inline Certificate
+                              entry
+                            items:
+                              type: string
+                            type: array
+                          configMapRefs:
+                            description: ConfigMapRefs denotes the reference to the
+                              ConfigMap that contains the Certificate
+                            items:
+                              description: RefConfig holds a config for a secret or
+                                a configmap
+                              properties:
+                                key:
+                                  description: Key of the secret or configmap
+                                  minLength: 1
+                                  type: string
+                                name:
+                                  description: Name of the secret or configmap
+                                  minLength: 1
+                                  type: string
+                              required:
+                              - key
+                              - name
+                              type: object
+                            type: array
+                          disabled:
+                            default: false
+                            description: Disabled is to disable mTLS authentication
+                            type: boolean
+                          required:
+                            default: optional
+                            description: Required indicates whether mutualSSL is mandatory
+                              or optional
+                            enum:
+                            - mandatory
+                            - optional
+                            type: string
+                          secretRefs:
+                            description: SecretRefs denotes the reference to the Secret
+                              that contains the Certificate
+                            items:
+                              description: RefConfig holds a config for a secret or
+                                a configmap
+                              properties:
+                                key:
+                                  description: Key of the secret or configmap
+                                  minLength: 1
+                                  type: string
+                                name:
+                                  description: Name of the secret or configmap
+                                  minLength: 1
+                                  type: string
+                              required:
+                              - key
+                              - name
+                              type: object
+                            type: array
+                        type: object
+                      oauth2:
+                        description: Oauth2 is to specify the Oauth2 authentication
+                          scheme details
+                        properties:
+                          disabled:
+                            default: false
+                            description: Disabled is to disable OAuth2 authentication
+                            type: boolean
+                          header:
+                            default: authorization
+                            description: Header is the header name used to pass the
+                              OAuth2 token
+                            type: string
+                          sendTokenToUpstream:
+                            description: SendTokenToUpstream is to specify whether
+                              the OAuth2 token should be sent to the upstream
+                            type: boolean
+                        type: object
+                      testConsoleKey:
+                        description: TestConsoleKey is to specify the Test Console
+                          Key authentication scheme details
+                        properties:
+                          header:
+                            default: internal-key
+                            description: Header is the header name used to pass the
+                              Test Console Key
+                            minLength: 1
+                            type: string
+                          sendTokenToUpstream:
+                            description: SendTokenToUpstream is to specify whether
+                              the Test Console Key should be sent to the upstream
+                            type: boolean
+                        type: object
+                    type: object
+                  disabled:
+                    description: Disabled is to disable all authentications
+                    type: boolean
+                type: object
+              targetRef:
+                description: PolicyTargetReference identifies an API object to apply
+                  policy to. This should be used as part of Policy resources that
+                  can target Gateway API resources. For more information on how this
+                  policy attachment model works, and a sample Policy resource, refer
+                  to the policy attachment documentation for Gateway API.
+                properties:
+                  group:
+                    description: Group is the group of the target resource.
+                    maxLength: 253
+                    pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$
+                    type: string
+                  kind:
+                    description: Kind is kind of the target resource.
+                    maxLength: 63
+                    minLength: 1
+                    pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$
+                    type: string
+                  name:
+                    description: Name is the name of the target resource.
+                    maxLength: 253
+                    minLength: 1
+                    type: string
+                  namespace:
+                    description: Namespace is the namespace of the referent. When
+                      unspecified, the local namespace is inferred. Even when policy
+                      targets a resource in a different namespace, it MUST only apply
+                      to traffic originating from the same namespace as the policy.
+                    maxLength: 63
+                    minLength: 1
+                    pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$
+                    type: string
+                required:
+                - group
+                - kind
+                - name
+                type: object
+            type: object
+          status:
+            description: AuthenticationStatus defines the observed state of Authentication
+            type: object
+        type: object
+    served: true
     storage: true
     subresources:
       status: {}
diff --git a/helm-charts/templates/data-plane/gateway-components/common-controller/webhook/adapter-mutating-webhook-config.yaml b/helm-charts/templates/data-plane/gateway-components/common-controller/webhook/adapter-mutating-webhook-config.yaml
index 4d94ea9d8..6b30071c9 100644
--- a/helm-charts/templates/data-plane/gateway-components/common-controller/webhook/adapter-mutating-webhook-config.yaml
+++ b/helm-charts/templates/data-plane/gateway-components/common-controller/webhook/adapter-mutating-webhook-config.yaml
@@ -63,6 +63,26 @@ webhooks:
       resources:
         - apipolicies
   sideEffects: None
+- admissionReviewVersions:
+    - v1
+  clientConfig:
+    service:
+      name: {{ template "apk-helm.resource.prefix" . }}-common-controller-service
+      namespace: {{ .Release.Namespace }}
+      path: /mutate-dp-wso2-com-v1alpha2-authentication
+  failurePolicy: Fail
+  name: mauthentication.kb.io
+  rules:
+  - apiGroups:
+    - dp.wso2.com
+    apiVersions:
+    - v1alpha2
+    operations:
+    - CREATE
+    - UPDATE
+    resources:
+    - authentications
+  sideEffects: None
 - admissionReviewVersions:
     - v1
   clientConfig:
diff --git a/helm-charts/templates/data-plane/gateway-components/common-controller/webhook/adapter-validation-webhook-config.yaml b/helm-charts/templates/data-plane/gateway-components/common-controller/webhook/adapter-validation-webhook-config.yaml
index 9a81bd9cd..5edc76ec9 100644
--- a/helm-charts/templates/data-plane/gateway-components/common-controller/webhook/adapter-validation-webhook-config.yaml
+++ b/helm-charts/templates/data-plane/gateway-components/common-controller/webhook/adapter-validation-webhook-config.yaml
@@ -83,6 +83,26 @@ webhooks:
       resources:
         - apipolicies
   sideEffects: None
+- admissionReviewVersions:
+  - v1
+  clientConfig:
+    service:
+      name: {{ template "apk-helm.resource.prefix" . }}-common-controller-service
+      namespace: {{ .Release.Namespace }}
+      path: /validate-dp-wso2-com-v1alpha2-authentication
+  failurePolicy: Fail
+  name: vauthentication.kb.io
+  rules:
+  - apiGroups:
+    - dp.wso2.com
+    apiVersions:
+    - v1alpha2
+    operations:
+    - CREATE
+    - UPDATE
+    resources:
+    - authentications
+  sideEffects: None
 {{ if .Values.wso2.apk.dp.ratelimiter.enabled }}
 - admissionReviewVersions:
     - v1
diff --git a/runtime/config-deployer-service/ballerina/APIClient.bal b/runtime/config-deployer-service/ballerina/APIClient.bal
index 0a6fdb796..fb0f08bc0 100644
--- a/runtime/config-deployer-service/ballerina/APIClient.bal
+++ b/runtime/config-deployer-service/ballerina/APIClient.bal
@@ -36,11 +36,11 @@ public class APIClient {
     # + api - APKInternalAPI model
     # + return - APKConf model.
     public isolated function fromAPIModelToAPKConf(runtimeModels:API api) returns APKConf|error {
-        string generatedBasePath = api.getName() +  api.getVersion();
+        string generatedBasePath = api.getName() + api.getVersion();
         byte[] data = generatedBasePath.toBytes();
         string encodedString = "/" + data.toBase64();
         if (encodedString.endsWith("==")) {
-            encodedString = encodedString.substring(0,encodedString.length()-2);
+            encodedString = encodedString.substring(0, encodedString.length() - 2);
         }
         APKConf apkConf = {
             name: api.getName(),
@@ -102,7 +102,7 @@ public class APIClient {
             AuthenticationRequest[]? authentication = apkConf.authentication;
             if authentication is AuthenticationRequest[] {
                 if createdEndpoints != {} {
-                _ = check self.populateAuthenticationMap(apiArtifact, apkConf, authentication, createdEndpoints, organization);
+                    _ = check self.populateAuthenticationMap(apiArtifact, apkConf, authentication, createdEndpoints, organization);
                 } else {
                     // check if there are resource level endpoints
                     if resourceLevelEndpointConfigList.length() > 0 {
@@ -131,6 +131,7 @@ public class APIClient {
                     }
                 }
             }
+
             _ = check self.setHttpRoute(apiArtifact, apkConf, createdEndpoints.hasKey(PRODUCTION_TYPE) ? createdEndpoints.get(PRODUCTION_TYPE) : (), uniqueId, PRODUCTION_TYPE, organization);
             _ = check self.setHttpRoute(apiArtifact, apkConf, createdEndpoints.hasKey(SANDBOX_TYPE) ? createdEndpoints.get(SANDBOX_TYPE) : (), uniqueId, SANDBOX_TYPE, organization);
 
@@ -338,16 +339,29 @@ public class APIClient {
     private isolated function populateAuthenticationMap(model:APIArtifact apiArtifact, APKConf apkConf, AuthenticationRequest[] authentications,
             map createdEndpointMap, commons:Organization organization) returns error? {
         map authenticationMap = {};
-        model:AuthenticationExtenstionType authTypes = {};
+        model:AuthenticationExtensionType authTypes = {};
+        boolean isOAuthDisabled = false;
+        boolean isMTLSMandatory = false;
+        boolean isMTLSDisabled = false;
         foreach AuthenticationRequest authentication in authentications {
             if authentication.authType == "OAuth2" {
                 OAuth2Authentication oauth2Authentication = check authentication.cloneWithType(OAuth2Authentication);
+                isOAuthDisabled = !oauth2Authentication.enabled;
                 authTypes.oauth2 = {header: oauth2Authentication.headerName, sendTokenToUpstream: oauth2Authentication.sendTokenToUpstream, disabled: !oauth2Authentication.enabled};
             } else if authentication.authType == "APIKey" && authentication is APIKeyAuthentication {
                 APIKeyAuthentication apiKeyAuthentication = check authentication.cloneWithType(APIKeyAuthentication);
                 authTypes.apiKey = [];
                 authTypes.apiKey.push({'in: "Header", name: apiKeyAuthentication.headerName, sendTokenToUpstream: apiKeyAuthentication.sendTokenToUpstream});
                 authTypes.apiKey.push({'in: "Query", name: apiKeyAuthentication.queryParamName, sendTokenToUpstream: apiKeyAuthentication.sendTokenToUpstream});
+            } else if authentication.authType == "mTLS" {
+                MTLSAuthentication mtlsAuthentication = check authentication.cloneWithType(MTLSAuthentication);
+                isMTLSMandatory = mtlsAuthentication.required == "mandatory";
+                isMTLSDisabled = !mtlsAuthentication.enabled;
+                if isOAuthDisabled && (!isMTLSMandatory || isMTLSDisabled) {
+                    log:printError("Invalid authtypes provided: one of mTLS or OAuth2 has to be enabled and mandatory");
+                    return e909019();
+                }
+                authTypes.mtls = {disabled: !mtlsAuthentication.enabled, configMapRefs: mtlsAuthentication.certificates, required: mtlsAuthentication.required};
             }
         }
         log:printDebug("Auth Types:" + authTypes.toString());
@@ -1385,11 +1399,13 @@ public class APIClient {
     private isolated function validateAndRetrieveAPKConfiguration(json apkconfJson) returns APKConf|commons:APKError? {
         do {
             runtimeapi:APKConfValidationResponse validationResponse = check apkConfValidator.validate(apkconfJson.toJsonString());
+
             if validationResponse.isValidated() {
                 APKConf apkConf = check apkconfJson.cloneWithType(APKConf);
                 map errors = {};
                 self.validateEndpointConfigurations(apkConf, errors);
                 if (errors.length() > 0) {
+                    log:printInfo(apkconfJson.toJsonString());
                     return e909029(errors);
                 }
                 return apkConf;
@@ -1422,9 +1438,9 @@ public class APIClient {
                     operationLevelProductionEndpointAvailable = endpointConfigs.production is EndpointConfiguration;
                     operationLevelSandboxEndpointAvailable = endpointConfigs.sandbox is EndpointConfiguration;
                 }
-                    if (!operationLevelProductionEndpointAvailable && !productionEndpointAvailable) && (!operationLevelSandboxEndpointAvailable && !sandboxEndpointAvailable) {
-                        errors["endpoint"] = "production/sandbox endpoint not available for " + operation.target;
-                    }
+                if (!operationLevelProductionEndpointAvailable && !productionEndpointAvailable) && (!operationLevelSandboxEndpointAvailable && !sandboxEndpointAvailable) {
+                    errors["endpoint"] = "production/sandbox endpoint not available for " + operation.target;
+                }
 
             }
         }
@@ -1432,7 +1448,7 @@ public class APIClient {
 
     public isolated function prepareArtifact(record {|byte[] fileContent; string fileName; anydata...;|}? apkConfiguration, record {|byte[] fileContent; string fileName; anydata...;|}? definitionFile, commons:Organization organization) returns commons:APKError|model:APIArtifact {
         if apkConfiguration is () || definitionFile is () {
-            return e909018("Required apkConfiguration ,definitionFile and apiType are not provided");
+            return e909018("Required apkConfiguration, definitionFile and apiType are not provided");
         }
         do {
             APKConf? apkConf = ();
diff --git a/runtime/config-deployer-service/ballerina/DeployerClient.bal b/runtime/config-deployer-service/ballerina/DeployerClient.bal
index 4c436d118..898865996 100644
--- a/runtime/config-deployer-service/ballerina/DeployerClient.bal
+++ b/runtime/config-deployer-service/ballerina/DeployerClient.bal
@@ -6,7 +6,7 @@ import ballerina/log;
 import ballerina/lang.value;
 
 public class DeployerClient {
-    public isolated function handleAPIDeployment(http:Request request,commons:Organization organization) returns commons:APKError|http:Response {
+    public isolated function handleAPIDeployment(http:Request request, commons:Organization organization) returns commons:APKError|http:Response {
         do {
 
             DeployApiBody deployAPIBody = check self.retrieveDeployApiBody(request);
@@ -14,7 +14,7 @@ public class DeployerClient {
                 return e909017();
             }
             APIClient apiclient = new;
-            model:APIArtifact prepareArtifact = check apiclient.prepareArtifact(deployAPIBody?.apkConfiguration, deployAPIBody?.definitionFile,organization);
+            model:APIArtifact prepareArtifact = check apiclient.prepareArtifact(deployAPIBody?.apkConfiguration, deployAPIBody?.definitionFile, organization);
             model:API deployAPIToK8sResult = check self.deployAPIToK8s(prepareArtifact);
             APKConf aPKConf = check self.getAPKConf(deployAPIBody.apkConfiguration);
             aPKConf.id = deployAPIToK8sResult.metadata.name;
@@ -35,7 +35,7 @@ public class DeployerClient {
             }
         }
     }
-    public isolated function handleAPIUndeployment(string apiId,commons:Organization organization) returns AcceptedString|BadRequestError|InternalServerErrorError|commons:APKError {
+    public isolated function handleAPIUndeployment(string apiId, commons:Organization organization) returns AcceptedString|BadRequestError|InternalServerErrorError|commons:APKError {
         model:Partition|() availablePartitionForAPI = check partitionResolver.getAvailablePartitionForAPI(apiId, "");
         if availablePartitionForAPI is model:Partition {
             model:API|() api = check getK8sAPIByNameAndNamespace(apiId, availablePartitionForAPI.namespace);
@@ -116,7 +116,7 @@ public class DeployerClient {
                     }
                     check self.deployScopeCrs(apiArtifact, ownerReference);
                     check self.deployBackendServices(apiArtifact, ownerReference);
-                    check self.deployAuthneticationCRs(apiArtifact, ownerReference);
+                    check self.deployAuthenticationCRs(apiArtifact, ownerReference);
                     check self.deployRateLimitPolicyCRs(apiArtifact, ownerReference);
                     check self.deployInterceptorServiceCRs(apiArtifact, ownerReference);
                     check self.deployBackendJWTConfigs(apiArtifact, ownerReference);
@@ -276,7 +276,7 @@ public class DeployerClient {
             } else if deployScopeResult.statusCode == http:STATUS_CONFLICT {
                 log:printDebug("Scope already exists" + scope.toString());
                 model:Scope scopeFromK8s = check getScopeCR(scope.metadata.name, apiArtifact?.namespace);
-                scope.metadata.resourceVersion=scopeFromK8s.metadata.resourceVersion;
+                scope.metadata.resourceVersion = scopeFromK8s.metadata.resourceVersion;
                 http:Response scopeCR = check updateScopeCR(scope, apiArtifact?.namespace);
                 if scopeCR.statusCode != http:STATUS_OK {
                     json responsePayLoad = check scopeCR.getJsonPayload();
@@ -363,7 +363,7 @@ public class DeployerClient {
                 } else if deployHttpRouteResult.statusCode == http:STATUS_CONFLICT {
                     log:printDebug("HttpRoute already exists" + httpRoute.toString());
                     model:Httproute httpRouteFromK8s = check getHttpRoute(httpRoute.metadata.name, namespace);
-                    httpRoute.metadata.resourceVersion=httpRouteFromK8s.metadata.resourceVersion;
+                    httpRoute.metadata.resourceVersion = httpRouteFromK8s.metadata.resourceVersion;
                     http:Response httpRouteCR = check updateHttpRoute(httpRoute, namespace);
                     if httpRouteCR.statusCode != http:STATUS_OK {
                         json responsePayLoad = check httpRouteCR.getJsonPayload();
@@ -395,7 +395,7 @@ public class DeployerClient {
         }
     }
 
-    private isolated function deployAuthneticationCRs(model:APIArtifact apiArtifact, model:OwnerReference ownerReference) returns error? {
+    private isolated function deployAuthenticationCRs(model:APIArtifact apiArtifact, model:OwnerReference ownerReference) returns error? {
         string[] keys = apiArtifact.authenticationMap.keys();
         log:printDebug("Inside Deploy Authentication CRs" + keys.toString());
         foreach string authenticationCrName in keys {
@@ -408,7 +408,7 @@ public class DeployerClient {
             } else if authenticationCrDeployResponse.statusCode == http:STATUS_CONFLICT {
                 log:printDebug("Authentication CR already exists" + authenticationCr.toString());
                 model:Authentication authenticationCrFromK8s = check getAuthenticationCR(authenticationCr.metadata.name, apiArtifact?.namespace);
-                authenticationCr.metadata.resourceVersion=authenticationCrFromK8s.metadata.resourceVersion;
+                authenticationCr.metadata.resourceVersion = authenticationCrFromK8s.metadata.resourceVersion;
                 http:Response authenticationCR = check updateAuthenticationCR(authenticationCr, apiArtifact?.namespace);
                 if authenticationCR.statusCode != http:STATUS_OK {
                     json responsePayLoad = check authenticationCR.getJsonPayload();
@@ -432,7 +432,7 @@ public class DeployerClient {
             } else if deployServiceResult.statusCode == http:STATUS_CONFLICT {
                 log:printDebug("Backend already exists" + backendService.toString());
                 model:Backend backendCRFromK8s = check getBackendCR(backendService.metadata.name, apiArtifact?.namespace);
-                backendService.metadata.resourceVersion=backendCRFromK8s.metadata.resourceVersion;
+                backendService.metadata.resourceVersion = backendCRFromK8s.metadata.resourceVersion;
                 http:Response backendCR = check updateBackendCR(backendService, apiArtifact?.namespace);
                 if backendCR.statusCode != http:STATUS_OK {
                     json responsePayLoad = check backendCR.getJsonPayload();
@@ -457,7 +457,7 @@ public class DeployerClient {
         } else if deployConfigMapResult.statusCode == http:STATUS_CONFLICT {
             log:printDebug("Configmap Already Exists" + definition.toString());
             model:ConfigMap configMapFromK8s = check getConfigMap(definition.metadata.name, deployableNamespace);
-            definition.metadata.resourceVersion=configMapFromK8s.metadata.resourceVersion;
+            definition.metadata.resourceVersion = configMapFromK8s.metadata.resourceVersion;
             deployConfigMapResult = check updateConfigMap(definition, deployableNamespace);
             if deployConfigMapResult.statusCode == http:STATUS_OK {
                 log:printDebug("updated Configmap Successfully" + definition.toString());
@@ -523,7 +523,7 @@ public class DeployerClient {
             } else if deployRateLimitPolicyResult.statusCode == http:STATUS_CONFLICT {
                 log:printDebug("RateLimitPolicy already exists" + rateLimitPolicy.toString());
                 model:RateLimitPolicy rateLimitPolicyFromK8s = check getRateLimitPolicyCR(rateLimitPolicy.metadata.name, apiArtifact?.namespace);
-                rateLimitPolicy.metadata.resourceVersion=rateLimitPolicyFromK8s.metadata.resourceVersion;
+                rateLimitPolicy.metadata.resourceVersion = rateLimitPolicyFromK8s.metadata.resourceVersion;
                 http:Response rateLimitPolicyCR = check updateRateLimitPolicyCR(rateLimitPolicy, apiArtifact?.namespace);
                 if rateLimitPolicyCR.statusCode != http:STATUS_OK {
                     json responsePayLoad = check rateLimitPolicyCR.getJsonPayload();
@@ -595,7 +595,7 @@ public class DeployerClient {
             } else if deployAPIPolicyResult.statusCode == http:STATUS_CONFLICT {
                 log:printDebug("InterceptorService already exists" + interceptorService.toString());
                 model:InterceptorService interceptorServiceFromK8s = check getInterceptorServiceCR(interceptorService.metadata.name, apiArtifact?.namespace);
-                interceptorService.metadata.resourceVersion=interceptorServiceFromK8s.metadata.resourceVersion;
+                interceptorService.metadata.resourceVersion = interceptorServiceFromK8s.metadata.resourceVersion;
                 http:Response interceptorServiceCR = check updateInterceptorServiceCR(interceptorService, apiArtifact?.namespace);
                 if interceptorServiceCR.statusCode != http:STATUS_OK {
                     json responsePayLoad = check interceptorServiceCR.getJsonPayload();
@@ -620,7 +620,7 @@ public class DeployerClient {
             } else if backendJWTCrDeployResponse.statusCode == http:STATUS_CONFLICT {
                 log:printDebug("BackendJWT Config already exists" + backendJwt.toString());
                 model:BackendJWT backendJWTCrFromK8s = check getBackendJWTCr(backendJwt.metadata.name, apiArtifact?.namespace);
-                backendJwt.metadata.resourceVersion=backendJWTCrFromK8s.metadata.resourceVersion;
+                backendJwt.metadata.resourceVersion = backendJWTCrFromK8s.metadata.resourceVersion;
                 http:Response backendJWTCr = check updateBackendJWTCr(backendJwt, apiArtifact?.namespace);
                 if backendJWTCr.statusCode != http:STATUS_OK {
                     json responsePayLoad = check backendJWTCr.getJsonPayload();
diff --git a/runtime/config-deployer-service/ballerina/Errors.bal b/runtime/config-deployer-service/ballerina/Errors.bal
index b5155bf7f..a76748613 100644
--- a/runtime/config-deployer-service/ballerina/Errors.bal
+++ b/runtime/config-deployer-service/ballerina/Errors.bal
@@ -18,7 +18,6 @@
 // Before adding another function for a new error code
 // make sure there is no already existing error code for that.
 // If there is an error code for that, reuse it.
-
 import wso2/apk_common_lib as commons;
 
 public isolated function e909000(int code, string msg) returns commons:APKError {
@@ -39,7 +38,6 @@ public isolated function e909001(string id) returns commons:APKError {
     );
 }
 
-
 public isolated function e909003() returns commons:APKError {
     return error commons:APKError("apiId not found in request",
         code = 909003,
@@ -49,7 +47,6 @@ public isolated function e909003() returns commons:APKError {
     );
 }
 
-
 public isolated function e909005(string 'field) returns commons:APKError {
     string msg = 'field + " field(s) unavailable";
     return error commons:APKError(msg,
@@ -81,9 +78,9 @@ public isolated function e909007() returns commons:APKError {
 public isolated function e909008() returns commons:APKError {
     return error commons:APKError("Atleast one of the field required",
         code = 909008,
-        message = "Atleast one of the field required",
+        message = "Atleast one of the fields required",
         statusCode = 406,
-        description = "Atleast one of the field required"
+        description = "Atleast one of the fields required"
     );
 }
 
@@ -177,6 +174,15 @@ public isolated function e909018(string msg) returns commons:APKError {
     );
 }
 
+public isolated function e909019() returns commons:APKError {
+    return error commons:APKError("Invalid authtypes provided",
+        code = 909018,
+        message = "Invalid authtypes provided",
+        statusCode = 406,
+        description = "Invalid authtypes provided"
+    );
+}
+
 public isolated function e909021() returns commons:APKError {
     return error commons:APKError("Atleast one operation need to specified",
         code = 909021,
@@ -204,8 +210,8 @@ public isolated function e909022(string msg, error? e) returns commons:APKError
     }
 }
 
-public isolated function e909029(map errorItems) returns commons:APKError{ 
-return error commons:APKError("Apk-conf validation failed",
+public isolated function e909029(map errorItems) returns commons:APKError {
+    return error commons:APKError("Apk-conf validation failed",
         code = 909029,
         message = "Invalid apk-conf provided",
         statusCode = 400,
@@ -213,6 +219,7 @@ return error commons:APKError("Apk-conf validation failed",
         moreInfo = errorItems
     );
 }
+
 public isolated function e909024(string policyName) returns commons:APKError {
     return error commons:APKError("Invalid parameters provided for policy " + policyName,
         code = 909024,
@@ -249,7 +256,6 @@ public isolated function e909040() returns commons:APKError {
     );
 }
 
-
 public isolated function e909042() returns commons:APKError {
     return error commons:APKError("Unsupported API type",
         code = 909042,
@@ -259,16 +265,15 @@ public isolated function e909042() returns commons:APKError {
     );
 }
 
-
-
 public isolated function e909052(error e) returns commons:APKError {
     return error commons:APKError("Error while generating k8s artifact", e,
         code = 909052,
         message = "Error while generating k8s artifact",
         statusCode = 500,
-        description = "Error while generating k8s artifact:"+ e.message()
+        description = "Error while generating k8s artifact:" + e.message()
     );
 }
+
 public isolated function e909043() returns commons:APKError {
     return error commons:APKError("Error occured while generating openapi definition",
         code = 909043,
@@ -277,6 +282,7 @@ public isolated function e909043() returns commons:APKError {
         description = "Error occured while generating openapi definition"
     );
 }
+
 public isolated function e909044() returns commons:APKError {
     return error commons:APKError("Invalid url provided for openapi definition",
         code = 909044,
@@ -285,6 +291,7 @@ public isolated function e909044() returns commons:APKError {
         description = "Invalid url provided for openapi definition"
     );
 }
+
 public isolated function e9090445() returns commons:APKError {
     return error commons:APKError("Atleast one Vhost need per production or/and sandbox",
         code = 9090445,
@@ -293,11 +300,12 @@ public isolated function e9090445() returns commons:APKError {
         description = "Atleast one Vhost need per production or/and sandbox"
     );
 }
+
 public isolated function e909028() returns commons:APKError {
-    return error commons:APKError( "Internal error occured while deploying API",
+    return error commons:APKError("Internal error occured while deploying API",
         code = 909028,
         message = "Internal error occured while deploying API",
         statusCode = 500,
         description = "Internal error occured while deploying API"
-    ); 
-}
\ No newline at end of file
+    );
+}
diff --git a/runtime/config-deployer-service/ballerina/K8sClient.bal b/runtime/config-deployer-service/ballerina/K8sClient.bal
index e11aaefed..7dd1ff34f 100644
--- a/runtime/config-deployer-service/ballerina/K8sClient.bal
+++ b/runtime/config-deployer-service/ballerina/K8sClient.bal
@@ -61,21 +61,22 @@ isolated function deleteAPICR(string name, string namespace) returns http:Respon
 }
 
 isolated function deleteAuthenticationCR(string name, string namespace) returns http:Response|http:ClientError {
-    string endpoint = "/apis/dp.wso2.com/v1alpha1/namespaces/" + namespace + "/authentications/" + name;
+    string endpoint = "/apis/dp.wso2.com/v1alpha2/namespaces/" + namespace + "/authentications/" + name;
     return k8sApiServerEp->delete(endpoint, targetType = http:Response);
 }
+
 isolated function getAuthenticationCR(string name, string namespace) returns model:Authentication|http:ClientError {
-    string endpoint = "/apis/dp.wso2.com/v1alpha1/namespaces/" + namespace + "/authentications/" + name;
+    string endpoint = "/apis/dp.wso2.com/v1alpha2/namespaces/" + namespace + "/authentications/" + name;
     return k8sApiServerEp->get(endpoint, targetType = model:Authentication);
 }
 
 isolated function deployAuthenticationCR(model:Authentication authentication, string namespace) returns http:Response|http:ClientError {
-    string endpoint = "/apis/dp.wso2.com/v1alpha1/namespaces/" + namespace + "/authentications";
+    string endpoint = "/apis/dp.wso2.com/v1alpha2/namespaces/" + namespace + "/authentications";
     return k8sApiServerEp->post(endpoint, authentication, targetType = http:Response);
 }
 
 isolated function updateAuthenticationCR(model:Authentication authentication, string namespace) returns http:Response|http:ClientError {
-    string endpoint = "/apis/dp.wso2.com/v1alpha1/namespaces/" + namespace + "/authentications/" + authentication.metadata.name;
+    string endpoint = "/apis/dp.wso2.com/v1alpha2/namespaces/" + namespace + "/authentications/" + authentication.metadata.name;
     return k8sApiServerEp->put(endpoint, authentication, targetType = http:Response);
 }
 
@@ -93,6 +94,7 @@ isolated function getConfigMap(string name, string namespace) returns model:Conf
     string endpoint = "/api/v1/namespaces/" + namespace + "/configmaps/" + name;
     return k8sApiServerEp->get(endpoint, targetType = model:ConfigMap);
 }
+
 isolated function deleteConfigMap(string name, string namespace) returns http:Response|http:ClientError {
     string endpoint = "/api/v1/namespaces/" + namespace + "/configmaps/" + name;
     return k8sApiServerEp->delete(endpoint, targetType = http:Response);
@@ -169,6 +171,7 @@ isolated function getBackendCR(string name, string namespace) returns model:Back
     string endpoint = "/apis/dp.wso2.com/v1alpha1/namespaces/" + namespace + "/backends/" + name;
     return k8sApiServerEp->get(endpoint, targetType = model:Backend);
 }
+
 isolated function deployBackendCR(model:Backend backend, string namespace) returns http:Response|http:ClientError {
     string endpoint = "/apis/dp.wso2.com/v1alpha1/namespaces/" + namespace + "/backends";
     return k8sApiServerEp->post(endpoint, backend, targetType = http:Response);
@@ -231,6 +234,7 @@ isolated function getRateLimitPolicyCR(string name, string namespace) returns mo
     string endpoint = "/apis/dp.wso2.com/v1alpha1/namespaces/" + namespace + "/ratelimitpolicies/" + name;
     return k8sApiServerEp->get(endpoint, targetType = model:RateLimitPolicy);
 }
+
 isolated function deleteRateLimitPolicyCR(string name, string namespace) returns http:Response|http:ClientError {
     string endpoint = "/apis/dp.wso2.com/v1alpha1/namespaces/" + namespace + "/ratelimitpolicies/" + name;
     return k8sApiServerEp->delete(endpoint, targetType = http:Response);
@@ -280,6 +284,7 @@ isolated function getInterceptorServiceCR(string name, string namespace) returns
     string endpoint = "/apis/dp.wso2.com/v1alpha1/namespaces/" + namespace + "/interceptorservices/" + name;
     return k8sApiServerEp->get(endpoint, targetType = model:InterceptorService);
 }
+
 isolated function deleteInterceptorServiceCR(string name, string namespace) returns http:Response|http:ClientError {
     string endpoint = "/apis/dp.wso2.com/v1alpha1/namespaces/" + namespace + "/interceptorservices/" + name;
     return k8sApiServerEp->delete(endpoint, targetType = http:Response);
@@ -299,10 +304,12 @@ isolated function updateBackendJWTCr(model:BackendJWT backendJWT, string namespa
     string endpoint = "/apis/dp.wso2.com/v1alpha1/namespaces/" + namespace + "/backendjwts/" + backendJWT.metadata.name;
     return k8sApiServerEp->put(endpoint, backendJWT, targetType = http:Response);
 }
+
 isolated function getBackendJWTCr(string name, string namespace) returns model:BackendJWT|http:ClientError {
     string endpoint = "/apis/dp.wso2.com/v1alpha1/namespaces/" + namespace + "/backendjwts/" + name;
     return k8sApiServerEp->get(endpoint, targetType = model:BackendJWT);
 }
+
 isolated function deleteBackendJWTCr(string name, string namespace) returns http:Response|http:ClientError {
     string endpoint = "/apis/dp.wso2.com/v1alpha1/namespaces/" + namespace + "/backendjwts/" + name;
     return k8sApiServerEp->delete(endpoint, targetType = http:Response);
diff --git a/runtime/config-deployer-service/ballerina/modules/model/Authentication.bal b/runtime/config-deployer-service/ballerina/modules/model/Authentication.bal
index 9950adb94..4220e5e8d 100644
--- a/runtime/config-deployer-service/ballerina/modules/model/Authentication.bal
+++ b/runtime/config-deployer-service/ballerina/modules/model/Authentication.bal
@@ -16,7 +16,7 @@
 // under the License.
 //
 public type Authentication record {
-    string apiVersion = "dp.wso2.com/v1alpha1";
+    string apiVersion = "dp.wso2.com/v1alpha2";
     string kind = "Authentication";
     Metadata metadata;
     AuthenticationSpec spec;
@@ -30,13 +30,22 @@ public type AuthenticationSpec record {
 };
 
 public type AuthenticationData record {
-    AuthenticationExtenstionType authTypes?;
+    AuthenticationExtensionType authTypes?;
     boolean disabled?;
 };
 
-public type AuthenticationExtenstionType record {
+public type AuthenticationExtensionType record {
     OAuth2Authentication oauth2?;
     APIKey[] apiKey = [];
+    MutualSSL mtls?;
+};
+
+public type MutualSSL record {
+    string required;
+    boolean disabled;
+    RefConfig[] configMapRefs?;
+    RefConfig[] secretRefs?;
+    string[] certificatesInline?;
 };
 
 public type OAuth2Authentication record {
@@ -57,7 +66,7 @@ public type APIKey record {
 };
 
 public type AuthenticationList record {
-    string apiVersion = "dp.wso2.com/v1alpha1";
+    string apiVersion = "dp.wso2.com/v1alpha2";
     string kind = "AuthenticationList";
     Authentication[] items;
     ListMeta metadata;
diff --git a/runtime/config-deployer-service/ballerina/resources/apk-conf-schema.yaml b/runtime/config-deployer-service/ballerina/resources/apk-conf-schema.yaml
index 380cf6c4e..63904355b 100644
--- a/runtime/config-deployer-service/ballerina/resources/apk-conf-schema.yaml
+++ b/runtime/config-deployer-service/ballerina/resources/apk-conf-schema.yaml
@@ -84,11 +84,13 @@ components:
       oneOf:
         - $ref: "#/components/schemas/OAuth2Authentication"
         - $ref: "#/components/schemas/APIKeyAuthentication"
+        - $ref: "#/components/schemas/MTLSAuthentication"
       discriminator:
         propertyName: authType
         mapping:
           OAuth2: "#/components/schemas/OAuth2Authentication"
           APIKey: "#/components/schemas/APIKeyAuthentication"
+          mTLS: "#/components/schemas/MTLSAuthentication"
     Authentication:
       type: object
       discriminator:
@@ -103,43 +105,65 @@ components:
       additionalProperties: false
     OAuth2Authentication:
       allOf:
-      - $ref: '#/components/schemas/Authentication'
-      - type: object
-        properties:
-          sendTokenToUpstream:
-            type: boolean
-            default: false
-          headerName:
-            type: string
-            example: Authorization
-            default: Authorization
-          headerEnable:
-            type: boolean
-            default: true
-        additionalProperties: false
+        - $ref: "#/components/schemas/Authentication"
+        - type: object
+          properties:
+            sendTokenToUpstream:
+              type: boolean
+              default: false
+            headerName:
+              type: string
+              example: Authorization
+              default: Authorization
+            headerEnable:
+              type: boolean
+              default: true
+          additionalProperties: false
     APIKeyAuthentication:
       allOf:
-      - $ref: '#/components/schemas/Authentication'
-      - type: object
-        properties:
-          sendTokenToUpstream:
-            type: boolean
-            default: false
-          headerName:
-            type: string
-            example: Authorization
-            default: apikey
-          queryParamName:
-            type: string
-            example: apikey
-            default: apikey
-          headerEnable:
-            type: boolean
-            default: true
-          queryParamEnable:
-            type: boolean      
-            default: true
-        additionalProperties: false
+        - $ref: "#/components/schemas/Authentication"
+        - type: object
+          properties:
+            sendTokenToUpstream:
+              type: boolean
+              default: false
+            headerName:
+              type: string
+              example: Authorization
+              default: apikey
+            queryParamName:
+              type: string
+              example: apikey
+              default: apikey
+            headerEnable:
+              type: boolean
+              default: true
+            queryParamEnable:
+              type: boolean
+              default: true
+          additionalProperties: false
+    MTLSAuthentication:
+      allOf:
+        - $ref: "#/components/schemas/Authentication"
+        - type: object
+          properties:
+            required:
+              type: string
+              default: optional
+              enum:
+                - mandatory
+                - optional
+            certificates:
+              type: array
+              description: The names and keys of the config maps containing the mTLS certificates of that API
+              items:
+                type: object
+                properties:
+                  name:
+                    type: string
+                  key:
+                    type: string
+          additionalProperties: false
     CORSConfiguration:
       type: object
       description: |
@@ -224,9 +248,9 @@ components:
           type: string
           description: Unit of time
           enum:
-          - Minute
-          - Hour
-          - Day
+            - Minute
+            - Hour
+            - Day
           example: Minute
       additionalProperties: false
     EndpointConfigurations:
@@ -373,60 +397,60 @@ components:
     InterceptorPolicy:
       title: Interceptor Parameters
       allOf:
-      - $ref: "#/components/schemas/BaseOperationPolicy"
-      - type: object
-        properties:
-          parameters:
-            type: object
-            properties:
-              backendUrl:
-                type: string
-              headersEnabled:
-                type: boolean
-              bodyEnabled:
-                type: boolean
-              trailersEnabled:
-                type: boolean
-              contextEnabled:
-                type: boolean
-              tlsSecretName:
-                type: string
-              tlsSecretKey:
-                type: string
-            additionalProperties: false
+        - $ref: "#/components/schemas/BaseOperationPolicy"
+        - type: object
+          properties:
+            parameters:
+              type: object
+              properties:
+                backendUrl:
+                  type: string
+                headersEnabled:
+                  type: boolean
+                bodyEnabled:
+                  type: boolean
+                trailersEnabled:
+                  type: boolean
+                contextEnabled:
+                  type: boolean
+                tlsSecretName:
+                  type: string
+                tlsSecretKey:
+                  type: string
+              additionalProperties: false
       required:
-      - backendUrl
+        - backendUrl
       additionalProperties: false
     BackendJWTPolicy:
       title: Backend JWT Parameters
       allOf:
-      - $ref: "#/components/schemas/BaseOperationPolicy"
-      - type: object
-        properties:
-          parameters:
-            type: object
-            properties:
-              encoding:
-                type: string
-              signingAlgorithm:
-                type: string
-              header:
-                type: string
-              tokenTTL:
-                type: integer
-              customClaims:
-                type: array
-                items:
-                  "$ref": "#/components/schemas/CustomClaims"
-            additionalProperties: false
+        - $ref: "#/components/schemas/BaseOperationPolicy"
+        - type: object
+          properties:
+            parameters:
+              type: object
+              properties:
+                encoding:
+                  type: string
+                signingAlgorithm:
+                  type: string
+                header:
+                  type: string
+                tokenTTL:
+                  type: integer
+                customClaims:
+                  type: array
+                  items:
+                    "$ref": "#/components/schemas/CustomClaims"
+              additionalProperties: false
       required:
-      - enabled
+        - enabled
       additionalProperties: false
     CustomClaims:
       type: object
       required:
-      - claim
-      - value
+        - claim
+        - value
       properties:
         claim:
           type: string
diff --git a/runtime/config-deployer-service/ballerina/tests/resources/apk-schema.json b/runtime/config-deployer-service/ballerina/tests/resources/apk-schema.json
index 8cc6f4a28..f2a92cc9c 100644
--- a/runtime/config-deployer-service/ballerina/tests/resources/apk-schema.json
+++ b/runtime/config-deployer-service/ballerina/tests/resources/apk-schema.json
@@ -43,7 +43,7 @@
       "type": "boolean",
       "description": "Is this the default version of the API"
     },
-    "subscriptionValidation" : {
+    "subscriptionValidation": {
       "type": "boolean",
       "description": "Is subscription validation enabled for the API"
     },
@@ -73,7 +73,17 @@
     "authentication": {
       "type": "array",
       "items": {
-        "$ref": "#/schemas/Authentication"
+        "oneOf": [
+          {
+            "$ref": "#/schemas/OAuth2Authentication"
+          },
+          {
+            "$ref": "#/schemas/MTLSAuthentication"
+          },
+          {
+            "$ref": "#/schemas/APIKeyAuthentication"
+          }
+        ]
       }
     },
     "additionalProperties": {
@@ -98,41 +108,110 @@
   },
   "additionalProperties": false,
   "schemas": {
-    "Authentication": {
+    "OAuth2Authentication": {
       "type": "object",
       "properties": {
         "authType": {
           "type": "string",
-          "example": "OAuth2",
-          "description": "The type of authentication to be used, e.g., OAuth2, etc."
+          "enum": [
+            "OAuth2"
+          ]
         },
         "sendTokenToUpstream": {
           "type": "boolean",
-          "default": false,
-          "description": "Specifies whether to send the authentication token to the upstream service."
+          "default": false
+        },
+        "enabled": {
+          "type": "boolean"
+        },
+        "headerName": {
+          "type": "string"
+        },
+        "queryParamName": {
+          "type": "string"
+        },
+        "headerEnable": {
+          "type": "boolean"
+        },
+        "queryParamEnable": {
+          "type": "boolean"
+        }
+      },
+      "additionalProperties": false
+    },
+    "MTLSAuthentication": {
+      "type": "object",
+      "properties": {
+        "authType": {
+          "type": "string",
+          "enum": [
+            "mTLS"
+          ]
+        },
+        "required": {
+          "type": "string",
+          "default": "optional",
+          "enum": [
+            "mandatory",
+            "optional"
+          ]
         },
         "enabled": {
           "type": "boolean",
-          "example": true,
-          "description": "Specifies whether authentication is enabled for the API."
+          "default": true
+        },
+        "certificates": {
+          "type": "array",
+          "items": {
+            "type": "object",
+            "properties": {
+              "name": {
+                "type": "string"
+              },
+              "key": {
+                "type": "string"
+              }
+            }
+          }
+        }
+      },
+      "additionalProperties": false
+    },
+    "APIKeyAuthentication": {
+      "type": "object",
+      "properties": {
+        "authType": {
+          "type": "string",
+          "example": "APIKey",
+          "enum": [
+            "APIKey"
+          ],
+          "description": "The type of authentication to be used, e.g., APIKey, etc."
+        },
+        "enabled": {
+          "type": "boolean"
+        },
+        "sendTokenToUpstream": {
+          "type": "boolean",
+          "default": false
         },
         "headerName": {
           "type": "string",
           "example": "Authorization",
-          "description": "The name of the header field used to send the authentication token."
+          "default": "apikey"
         },
         "queryParamName": {
           "type": "string",
           "example": "apikey",
-          "description": "The name of the query parameter used to send the authentication token."
+          "default": "apikey"
         },
         "headerEnable": {
           "type": "boolean",
-          "description": "Specifies whether the authentication token can be sent in the header."
+          "default": true
         },
         "queryParamEnable": {
           "type": "boolean",
-          "description": "Specifies whether the authentication token can be sent as a query parameter."
+          "default": true
         }
       },
       "additionalProperties": false
diff --git a/runtime/config-deployer-service/ballerina/types.bal b/runtime/config-deployer-service/ballerina/types.bal
index 771cd105e..7981a0843 100644
--- a/runtime/config-deployer-service/ballerina/types.bal
+++ b/runtime/config-deployer-service/ballerina/types.bal
@@ -112,7 +112,7 @@ public type CircuitBreaker record {
     int maxRetries?;
 };
 
-public type AuthenticationRequest OAuth2Authentication|APIKeyAuthentication;
+public type AuthenticationRequest OAuth2Authentication|APIKeyAuthentication|MTLSAuthentication;
 
 public type EndpointConfigurations record {
     EndpointConfiguration production?;
@@ -162,8 +162,6 @@ public type DefinitionBody record {
     string apiType?;
 };
 
-
-
 # CORS Configuration of API
 #
 # + accessControlAllowOrigins - Field Description  
@@ -271,7 +269,23 @@ public type APIKeyAuthentication record {|
     boolean queryParamEnable = true;
 |};
 
+# Mutual SSL configuration of this API
+#
+# + required - If mTLS is optional or mandatory
+# + certificates - The list of config map refs referring to the client certificates
+public type MTLSAuthentication record {|
+    *Authentication;
+    string required = "optional";
+    ConfigMapRef[] certificates;
+|};
+
 public type Certificate record {
     string secretName?;
     string secretKey?;
 };
+
+public type ConfigMapRef record {
+    string name;
+    string key;
+};
+
diff --git a/runtime/config-deployer-service/docker/config-deployer/conf/apk-schema.json b/runtime/config-deployer-service/docker/config-deployer/conf/apk-schema.json
index fabed773c..4c99894ba 100644
--- a/runtime/config-deployer-service/docker/config-deployer/conf/apk-schema.json
+++ b/runtime/config-deployer-service/docker/config-deployer/conf/apk-schema.json
@@ -13,7 +13,7 @@
     },
     "basePath": {
       "type": "string",
-      "title": "basePath of the API",
+      "title": "Base Path of the API",
       "maxLength": 256,
       "minLength": 1
     },
@@ -73,7 +73,17 @@
     "authentication": {
       "type": "array",
       "items": {
-        "$ref": "#/schemas/Authentication"
+        "oneOf": [
+          {
+            "$ref": "#/schemas/OAuth2Authentication"
+          },
+          {
+            "$ref": "#/schemas/MTLSAuthentication"
+          },
+          {
+            "$ref": "#/schemas/APIKeyAuthentication"
+          }
+        ]
       }
     },
     "additionalProperties": {
@@ -98,41 +108,114 @@
   },
   "additionalProperties": false,
   "schemas": {
-    "Authentication": {
+    "OAuth2Authentication": {
       "type": "object",
       "properties": {
         "authType": {
           "type": "string",
-          "example": "OAuth2",
-          "description": "The type of authentication to be used, e.g., OAuth2, etc."
+          "enum": [
+            "OAuth2"
+          ]
         },
         "sendTokenToUpstream": {
           "type": "boolean",
-          "default": false,
-          "description": "Specifies whether to send the authentication token to the upstream service."
+          "default": false
+        },
+        "enabled": {
+          "type": "boolean"
+        },
+        "headerName": {
+          "type": "string"
+        },
+        "queryParamName": {
+          "type": "string"
+        },
+        "headerEnable": {
+          "type": "boolean"
+        },
+        "queryParamEnable": {
+          "type": "boolean"
+        }
+      },
+      "additionalProperties": false
+    },
+    "MTLSAuthentication": {
+      "type": "object",
+      "properties": {
+        "authType": {
+          "type": "string",
+          "enum": [
+            "mTLS"
+          ]
+        },
+        "required": {
+          "type": "string",
+          "default": "optional",
+          "enum": [
+            "mandatory",
+            "optional"
+          ]
         },
         "enabled": {
           "type": "boolean",
-          "example": true,
-          "description": "Specifies whether authentication is enabled for the API."
+          "default": true
+        },
+        "certificates": {
+          "type": "array",
+          "items": {
+            "type": "object",
+            "properties": {
+              "name": {
+                "type": "string"
+              },
+              "key": {
+                "type": "string"
+              }
+            }
+          }
+        }
+      },
+      "required": [
+        "authType",
+        "certificates"
+      ],
+      "additionalProperties": false
+    },
+    "APIKeyAuthentication": {
+      "type": "object",
+      "properties": {
+        "authType": {
+          "type": "string",
+          "example": "APIKey",
+          "enum": [
+            "APIKey"
+          ],
+          "description": "The type of authentication to be used, e.g., APIKey, etc."
+        },
+        "enabled": {
+          "type": "boolean"
+        },
+        "sendTokenToUpstream": {
+          "type": "boolean",
+          "default": false
         },
         "headerName": {
           "type": "string",
           "example": "Authorization",
-          "description": "The name of the header field used to send the authentication token."
+          "default": "apikey"
         },
         "queryParamName": {
           "type": "string",
           "example": "apikey",
-          "description": "The name of the query parameter used to send the authentication token."
+          "default": "apikey"
         },
         "headerEnable": {
           "type": "boolean",
-          "description": "Specifies whether the authentication token can be sent in the header."
+          "default": true
         },
         "queryParamEnable": {
           "type": "boolean",
-          "description": "Specifies whether the authentication token can be sent as a query parameter."
+          "default": true
         }
       },
       "additionalProperties": false
diff --git a/runtime/runtime-ui/schema/apk-conf.yaml b/runtime/runtime-ui/schema/apk-conf.yaml
index fe75736ab..920fef175 100644
--- a/runtime/runtime-ui/schema/apk-conf.yaml
+++ b/runtime/runtime-ui/schema/apk-conf.yaml
@@ -57,7 +57,10 @@ properties:
   authentication:
     type: array
     items:
-      "$ref": "#/schemas/Authentication"
+      oneOf:
+        - $ref: "#/schemas/OAuth2Authentication"
+        - $ref: "#/schemas/MTLSAuthentication"
+        - $ref: "#/schemas/APIKeyAuthentication"
   additionalProperties:
     type: array
     description: Map of custom properties of API
@@ -73,46 +76,93 @@ properties:
     description: Cross-Origin Resource Sharing (CORS) configuration for the API.
 additionalProperties: false
 schemas:
-  Authentication:
+  OAuth2Authentication:
     type: object
     properties:
       authType:
         type: string
-        example: OAuth2
+        enum: [OAuth2]
         description: The type of authentication to be used, e.g., OAuth2, etc.
       sendTokenToUpstream:
         type: boolean
         default: false
-        description:
-          Specifies whether to send the authentication token to the upstream
-          service.
+        description: Specifies whether to send the authentication token to the upstream service.
       enabled:
         type: boolean
         example: true
-        description: Specifies whether authentication is enabled for the API.
+        description: Specifies whether OAuth2 authentication is enabled for the API.
       headerName:
         type: string
         example: Authorization
-        description:
-          The name of the header field used to send the authentication
-          token.
+        description: The name of the header field used to send the authentication token.
       queryParamName:
         type: string
         example: apikey
-        description:
-          The name of the query parameter used to send the authentication
-          token.
+        description: The name of the query parameter used to send the authentication token.
       headerEnable:
         type: boolean
-        description:
-          Specifies whether the authentication token can be sent in the
-          header.
+        description: Specifies whether the authentication token can be sent in the header.
       queryParamEnable:
         type: boolean
-        description:
-          Specifies whether the authentication token can be sent as a query
-          parameter.
+        description: Specifies whether the authentication token can be sent as a query parameter.
     additionalProperties: false
+  MTLSAuthentication:
+    type: object
+    properties:
+      authType:
+        type: string
+        example: mTLS
+        enum: [mTLS]
+        description: The type of authentication to be used, e.g., mTLS, etc.
+      enabled:
+        type: boolean
+        example: true
+        default: true
+        description: Specifies whether mTLS authentication is enabled for the API.
+      required:
+        type: string
+        default: optional
+        enum:
+          - mandatory
+          - optional
+        description: Specifies whether mTLS is mandatory or optional
+      certificates:
+        type: array
+        description: The names and keys of the secrets containing the mTLS certificates of that API
+        items:
+          type: object
+          properties:
+            name:
+              type: string
+            key:
+              type: string
+    additionalProperties: false
+  APIKeyAuthentication:
+    - type: object
+      properties:
+        authType:
+          type: string
+          example: APIKey
+          enum: [APIKey]
+          description: The type of authentication to be used, e.g., APIKey, etc.
+        sendTokenToUpstream:
+          type: boolean
+          default: false
+        headerName:
+          type: string
+          example: Authorization
+          default: apikey
+        queryParamName:
+          type: string
+          example: apikey
+          default: apikey
+        headerEnable:
+          type: boolean
+          default: true
+        queryParamEnable:
+          type: boolean
+          default: true
+      additionalProperties: false
   CORSConfiguration:
     type: object
     description: Cross-Origin Resource Sharing (CORS) configuration for the API.
diff --git a/runtime/runtime-ui/schema/apk-schema.json b/runtime/runtime-ui/schema/apk-schema.json
index 2efeddb0c..f2a92cc9c 100644
--- a/runtime/runtime-ui/schema/apk-schema.json
+++ b/runtime/runtime-ui/schema/apk-schema.json
@@ -73,7 +73,17 @@
     "authentication": {
       "type": "array",
       "items": {
-        "$ref": "#/schemas/Authentication"
+        "oneOf": [
+          {
+            "$ref": "#/schemas/OAuth2Authentication"
+          },
+          {
+            "$ref": "#/schemas/MTLSAuthentication"
+          },
+          {
+            "$ref": "#/schemas/APIKeyAuthentication"
+          }
+        ]
       }
     },
     "additionalProperties": {
@@ -98,41 +108,110 @@
   },
   "additionalProperties": false,
   "schemas": {
-    "Authentication": {
+    "OAuth2Authentication": {
       "type": "object",
       "properties": {
         "authType": {
           "type": "string",
-          "example": "OAuth2",
-          "description": "The type of authentication to be used, e.g., OAuth2, etc."
+          "enum": [
+            "OAuth2"
+          ]
         },
         "sendTokenToUpstream": {
           "type": "boolean",
-          "default": false,
-          "description": "Specifies whether to send the authentication token to the upstream service."
+          "default": false
+        },
+        "enabled": {
+          "type": "boolean"
+        },
+        "headerName": {
+          "type": "string"
+        },
+        "queryParamName": {
+          "type": "string"
+        },
+        "headerEnable": {
+          "type": "boolean"
+        },
+        "queryParamEnable": {
+          "type": "boolean"
+        }
+      },
+      "additionalProperties": false
+    },
+    "MTLSAuthentication": {
+      "type": "object",
+      "properties": {
+        "authType": {
+          "type": "string",
+          "enum": [
+            "mTLS"
+          ]
+        },
+        "required": {
+          "type": "string",
+          "default": "optional",
+          "enum": [
+            "mandatory",
+            "optional"
+          ]
         },
         "enabled": {
           "type": "boolean",
-          "example": true,
-          "description": "Specifies whether authentication is enabled for the API."
+          "default": true
+        },
+        "certificates": {
+          "type": "array",
+          "items": {
+            "type": "object",
+            "properties": {
+              "name": {
+                "type": "string"
+              },
+              "key": {
+                "type": "string"
+              }
+            }
+          }
+        }
+      },
+      "additionalProperties": false
+    },
+    "APIKeyAuthentication": {
+      "type": "object",
+      "properties": {
+        "authType": {
+          "type": "string",
+          "example": "APIKey",
+          "enum": [
+            "APIKey"
+          ],
+          "description": "The type of authentication to be used, e.g., APIKey, etc."
+        },
+        "enabled": {
+          "type": "boolean"
+        },
+        "sendTokenToUpstream": {
+          "type": "boolean",
+          "default": false
         },
         "headerName": {
           "type": "string",
           "example": "Authorization",
-          "description": "The name of the header field used to send the authentication token."
+          "default": "apikey"
         },
         "queryParamName": {
           "type": "string",
           "example": "apikey",
-          "description": "The name of the query parameter used to send the authentication token."
+          "default": "apikey"
         },
         "headerEnable": {
           "type": "boolean",
-          "description": "Specifies whether the authentication token can be sent in the header."
+          "default": true
         },
         "queryParamEnable": {
           "type": "boolean",
-          "description": "Specifies whether the authentication token can be sent as a query parameter."
+          "default": true
         }
       },
       "additionalProperties": false
diff --git a/test/cucumber-tests/CRs/artifacts.yaml b/test/cucumber-tests/CRs/artifacts.yaml
index 3f102e158..b1292f343 100644
--- a/test/cucumber-tests/CRs/artifacts.yaml
+++ b/test/cucumber-tests/CRs/artifacts.yaml
@@ -730,4 +730,91 @@ metadata:
   namespace: apk-integration-test
 spec:
   applicationRef: 583e4146-7ef5-11ee-b962-0242ac120004
-  subscriptionRef: 583e4146-7ef6-11ee-b962-0242ac120003
\ No newline at end of file
+  subscriptionRef: 583e4146-7ef6-11ee-b962-0242ac120003
+---
+apiVersion: v1
+kind: ConfigMap
+metadata:
+  name: mtls-test-configmap
+  namespace: apk-integration-test
+data:
+  tls.crt: |
+    -----BEGIN CERTIFICATE-----
+    MIIDGTCCAgECFANIkLQBkd76qiTXzSXjBS2scPJsMA0GCSqGSIb3DQEBCwUAME0x
+    CzAJBgNVBAYTAkxLMRMwEQYDVQQIDApTb21lLVN0YXRlMQ0wCwYDVQQKDAR3c28y
+    MQwwCgYDVQQLDANhcGsxDDAKBgNVBAMMA2FwazAeFw0yMzEyMDYxMDEyNDhaFw0y
+    NTA0MTkxMDEyNDhaMEUxCzAJBgNVBAYTAkxLMRMwEQYDVQQIDApTb21lLVN0YXRl
+    MSEwHwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwggEiMA0GCSqGSIb3
+    DQEBAQUAA4IBDwAwggEKAoIBAQCdG90W/Tlk4u9awHPteD5zpVcThUKwMLvAKw9i
+    vVQBC0AG6GzPbakol5gKVm+kBUDFzzzF6eayEXKWbyaZDty66A2+7HLLcKBop5M/
+    a57Q9XtU3lRYvotgutLWuHcI7mLCScZDrjA3rnb/KjjbhZ602ZS1pp5jtyUz6DwL
+    m7w4wQ/RProqCdBj8QqoAvnDDLSPeDfsx14J5VeNJVGJV2wax65jWRjRkj6wE7z2
+    qzWAlP5vDeED6bogYYVDpC8DtgayQ+vKAQLi1uj+I9Yqb/nPUrdUh9IlxudlqiFQ
+    QxyvsXMJEzbWWmlbD0kXYkHmHzetJNPK9ayOS/fJcAcfAb01AgMBAAEwDQYJKoZI
+    hvcNAQELBQADggEBAFmUc7+cI8d0Dl4wTdq+gfyWdqjQb7AYVO9DvJi3XGxdc5Kp
+    1nCSsKzKUz9gvxXHeaYKrBNYf4SSU+Pkdf/BWePqi7UX/SIxNXby2da8zWg+W6Uh
+    xZfKlLYGMp3mCjueZpZTJ7SKOOGFA8IIgEzjJD9Ln1gl3ywMaCwlNrG9RpiD1McT
+    COKvyWNKnSRVr/RvCklLVrAMTJr50kce2czcdFl/xF4Hm66vp7cP/bYJKWAL8hBG
+    zUa9aQBKncOoAO+zQ/SGy7uJxTDUF8SverDsmjOc6AU6IhBGVUyX/JQbYyJfZinB
+    YlviYxVzIm6IaNJHx4sihw4U1/jMFWRXT470zcQ=
+    -----END CERTIFICATE-----
+---
+apiVersion: v1
+kind: ConfigMap
+metadata:
+  name: mtls-test-configmap2
+  namespace: apk-integration-test
+data:
+  tls.crt: |
+    -----BEGIN CERTIFICATE-----
+    MIIDkTCCAnmgAwIBAgIUJitjysknJ0nHeLH/mjT1JIpOz4YwDQYJKoZIhvcNAQEL
+    BQAwYDELMAkGA1UEBhMCVVMxEjAQBgNVBAgMCVlvdXJTdGF0ZTERMA8GA1UEBwwI
+    WW91ckNpdHkxGTAXBgNVBAoMEFlvdXJPcmdhbml6YXRpb24xDzANBgNVBAMMBllv
+    dXJDQTAeFw0yNDAxMDUwNDAwMjNaFw0yNTAxMDQwNDAwMjNaMGExCzAJBgNVBAYT
+    AlVTMRIwEAYDVQQIDAlZb3VyU3RhdGUxETAPBgNVBAcMCFlvdXJDaXR5MRkwFwYD
+    VQQKDBBZb3VyT3JnYW5pemF0aW9uMRAwDgYDVQQDDAdjbGllbnQxMIIBIjANBgkq
+    hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuJhFZmCVnj6N+/+HHuMvb4vyWqWcorUf
+    pAWO7a3YVsHp3BX+lbGGzh67jbPcFK6K7RqejenFw7sQK8duZlqXmik/JvZMLxY3
+    l/6e8LIAhN7PaX1zg58OU61baQ5VNBhUXkoYN77xqb87Yo7IFyyQ/tyWfRVFEzNj
+    V1+q2MpEinuscViieIQHEpB4i6fsRxomYkR+FwdfCB65MYCYveIB1z9NkmR6Pm6V
+    7zSPp+QYwc6WX4/61fbRje4BJh3j+FGYboJJg1o9O/MkD70RW6mdMV1l5bT9T98W
+    B+hJtN+5dEpSfAwXqlWWxzhDxNsEvdSwuoLz9e58gteR1LSLaJXMjQIDAQABo0Iw
+    QDAdBgNVHQ4EFgQULaoslUgyglywztd95CkL6sU5wa4wHwYDVR0jBBgwFoAUGUkK
+    +QXBjeGMy7XVnrXfrvVJUNswDQYJKoZIhvcNAQELBQADggEBABodQ1Y7zt7kvDI8
+    jQUfLLkZZAPnVpjYpG7P1dLjOzUxqDNmyZAzoBMENXy/Zu81sRQt+Bs5NKsx1pu5
+    z2TRk9ddxhszD1FKu9Hb6hqLcGHF7GnwPGVXJlHctkMp4QYvXc942VDk7c59/knC
+    PXAul7832cPTUMvFHdzRxBwJruK9xuvNLj2I24+Fji1ELPO7M/e8KZ1NrIS0Fdwn
+    DuDDw3kMkl0BlSrmvMBreSaIOU4mFhmepC97awZ/wZZ+4mpIdWIagZf01txue8o0
+    +8kdGkFsmoCpnJjNjpoQFAYLEdif00iLcRpwwW/saUuxqZC0aDnQCIeo0GSNet8t
+    HOXCkvQ=
+    -----END CERTIFICATE-----
+---
+apiVersion: v1
+kind: ConfigMap
+metadata:
+  name: mtls-test-configmap3
+  namespace: apk-integration-test
+data:
+  tls.crt: |
+    -----BEGIN CERTIFICATE-----
+    MIIDkTCCAnmgAwIBAgIUJitjysknJ0nHeLH/mjT1JIpOz4cwDQYJKoZIhvcNAQEL
+    BQAwYDELMAkGA1UEBhMCVVMxEjAQBgNVBAgMCVlvdXJTdGF0ZTERMA8GA1UEBwwI
+    WW91ckNpdHkxGTAXBgNVBAoMEFlvdXJPcmdhbml6YXRpb24xDzANBgNVBAMMBllv
+    dXJDQTAeFw0yNDAxMDUwNDE0MTlaFw0yNTAxMDQwNDE0MTlaMGExCzAJBgNVBAYT
+    AlVTMRIwEAYDVQQIDAlZb3VyU3RhdGUxETAPBgNVBAcMCFlvdXJDaXR5MRkwFwYD
+    VQQKDBBZb3VyT3JnYW5pemF0aW9uMRAwDgYDVQQDDAdjbGllbnQyMIIBIjANBgkq
+    hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2JQ8LITwayvjrrHUmFT44lH3IF3fdPhr
+    pQgKx7Z295QD9Ocka2rOFu47tuIeNcLiBTSyRLOFDRwjW9WXfWk9ALtxbedJfDyy
+    us/kLxY+SdzHW7/5dFbupGOcs58A/sxMyGTJgiCBxsgsRFfhet7ekq/ypmj5B8L3
+    5FlGg5NS0mbZlTM6aapLnkqU907RcsmzpFQBfWOHlDdWJocKEHECBXcxiTQk72C7
+    s2tndES5ltX/Wc8U/kX/M9LDXhn1Ew+roeFf0HCpdg6BlnTknhYU9S1c4aYKB2Yx
+    LNx74CsKsnxPPcePTXPqZEtZ4EsjF4PSToVFyceMBKvD6C6WPQoRNwIDAQABo0Iw
+    QDAdBgNVHQ4EFgQUWE8btMihi5eZXLJOeiNfh7XHaI0wHwYDVR0jBBgwFoAUGUkK
+    +QXBjeGMy7XVnrXfrvVJUNswDQYJKoZIhvcNAQELBQADggEBAJmXn/gefez7mq1b
+    iKpPLPeHUncIgVaru03v8YCX14pHFAsVuLgZ1lANelSrq+PR/HBJbQj8iloV938o
+    YFppe/fb96D8a2u90dnGwWipMRSDo3wgcInL38xfcH5UEPBVJVLa3IUkfwDjjEqK
+    3O0GXVSpjyv3RW+E9wfPfGSysRX66cTo5Uh3z3hTAloDc8uhCYRPcxG7S9eKD6jW
+    Z3MlFlw4U8CdO90L0nB1KFhz1Et0Sl9u/LDsUYq6mE+XhTngPs8qwR/o43s1DUID
+    y5Oi4A4+id+xO0XnHIkkqCfPtFzxl3hwytcy8EqISynzzHWNJ8bFZIYX4tgX+PLq
+    u0/ITEw=
+    -----END CERTIFICATE-----
diff --git a/test/cucumber-tests/src/test/java/org/wso2/apk/integration/api/MTLSClientCertSteps.java b/test/cucumber-tests/src/test/java/org/wso2/apk/integration/api/MTLSClientCertSteps.java
new file mode 100644
index 000000000..735e56c62
--- /dev/null
+++ b/test/cucumber-tests/src/test/java/org/wso2/apk/integration/api/MTLSClientCertSteps.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2023, WSO2 LLC (http://www.wso2.com).
+ *
+ * WSO2 LLC licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.wso2.apk.integration.api;
+
+import org.apache.http.HttpResponse;
+import org.wso2.apk.integration.utils.Constants;
+import org.wso2.apk.integration.utils.Utils;
+import org.wso2.apk.integration.utils.clients.SimpleHTTPClient;
+
+import com.google.common.io.Resources;
+
+import io.cucumber.java.Before;
+import io.cucumber.java.en.Then;
+
+import java.net.URL;
+import java.nio.charset.StandardCharsets;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * This class contains the common step definitions.
+ */
+public class MTLSClientCertSteps {
+
+        private final SharedContext sharedContext;
+        private SimpleHTTPClient httpClient;
+
+        public MTLSClientCertSteps(SharedContext sharedContext) {
+
+                this.sharedContext = sharedContext;
+        }
+
+        @Before
+        public void setup() throws Exception {
+
+                httpClient = sharedContext.getHttpClient();
+        }
+
+        @Then("I have a valid token with a client certificate {string}")
+        public void getValidClientCertificateForMTLS(String clientCertificatePath) throws Exception {
+
+                Map headers = new HashMap<>();
+                headers.put(Constants.REQUEST_HEADERS.HOST, Constants.DEFAULT_IDP_HOST);
+                headers.put(Constants.REQUEST_HEADERS.AUTHORIZATION,
+                                "Basic NDVmMWM1YzgtYTkyZS0xMWVkLWFmYTEtMDI0MmFjMTIwMDAyOjRmYmQ2MmVjLWE5MmUtMTFlZC1hZmExLTAyNDJhYzEyMDAwMg==");
+
+                HttpResponse httpResponse = httpClient.doPost(Utils.getTokenEndpointURL(), headers,
+                                "grant_type=client_credentials&scope=" + Constants.API_CREATE_SCOPE,
+                                Constants.CONTENT_TYPES.APPLICATION_X_WWW_FORM_URLENCODED);
+                sharedContext.setAccessToken(Utils.extractToken(httpResponse));
+                sharedContext.addStoreValue("accessToken", sharedContext.getAccessToken());
+
+                URL url = Resources.getResource("artifacts/certificates/" + clientCertificatePath);
+                String clientCertificate = Resources.toString(url, StandardCharsets.UTF_8);
+                sharedContext.addStoreValue("clientCertificate", clientCertificate);
+
+        }
+}
\ No newline at end of file
diff --git a/test/cucumber-tests/src/test/resources/artifacts/apk-confs/mtls/mtls_disabled_oauth2_disabled.apk-conf b/test/cucumber-tests/src/test/resources/artifacts/apk-confs/mtls/mtls_disabled_oauth2_disabled.apk-conf
new file mode 100644
index 000000000..2b434ccba
--- /dev/null
+++ b/test/cucumber-tests/src/test/resources/artifacts/apk-confs/mtls/mtls_disabled_oauth2_disabled.apk-conf
@@ -0,0 +1,34 @@
+name: "EmployeeServiceAPI"
+basePath: "/mtls"
+version: "3.14"
+type: "REST"
+id: "mtls-disabled-oauth2-disabled"
+defaultVersion: false
+endpointConfigurations:
+  production:
+    endpoint: "https://webhook.site/1e73a7f6-6187-46ff-aac9-f060d7460c93"
+operations:
+  - target: "/employee"
+    verb: "GET"
+    secured: true
+    scopes: []
+  - target: "/employee"
+    verb: "POST"
+    secured: true
+    scopes: []
+  - target: "/employee/{employeeId}"
+    verb: "PUT"
+    secured: true
+    scopes: []
+  - target: "/employee/{employeeId}"
+    verb: "DELETE"
+    secured: true
+    scopes: []
+authentication:
+  - authType: OAuth2
+    enabled: false
+  - authType: mTLS
+    enabled: false
+    certificates:
+      - name: mtls-test-configmap
+        key: tls.crt
diff --git a/test/cucumber-tests/src/test/resources/artifacts/apk-confs/mtls/mtls_disabled_oauth2_enabled.apk-conf b/test/cucumber-tests/src/test/resources/artifacts/apk-confs/mtls/mtls_disabled_oauth2_enabled.apk-conf
new file mode 100644
index 000000000..7626fb2b5
--- /dev/null
+++ b/test/cucumber-tests/src/test/resources/artifacts/apk-confs/mtls/mtls_disabled_oauth2_enabled.apk-conf
@@ -0,0 +1,32 @@
+name: "EmployeeServiceAPI"
+basePath: "/mtls"
+version: "3.14"
+type: "REST"
+id: "mtls-disabled-oauth2-enabled"
+defaultVersion: false
+endpointConfigurations:
+  production:
+    endpoint: "https://run.mocky.io/v3/0c5173b2-9d99-459c-946b-b6b67c7f0139"
+operations:
+  - target: "/employee"
+    verb: "GET"
+    secured: true
+    scopes: []
+  - target: "/employee"
+    verb: "POST"
+    secured: true
+    scopes: []
+  - target: "/employee/{employeeId}"
+    verb: "PUT"
+    secured: true
+    scopes: []
+  - target: "/employee/{employeeId}"
+    verb: "DELETE"
+    secured: true
+    scopes: []
+authentication:
+  - authType: mTLS
+    enabled: false
+    certificates:
+      - name: mtls-test-configmap
+        key: tls.crt
diff --git a/test/cucumber-tests/src/test/resources/artifacts/apk-confs/mtls/mtls_mandatory_oauth2_disabled.apk-conf b/test/cucumber-tests/src/test/resources/artifacts/apk-confs/mtls/mtls_mandatory_oauth2_disabled.apk-conf
new file mode 100644
index 000000000..05b6887fc
--- /dev/null
+++ b/test/cucumber-tests/src/test/resources/artifacts/apk-confs/mtls/mtls_mandatory_oauth2_disabled.apk-conf
@@ -0,0 +1,34 @@
+name: "EmployeeServiceAPI"
+basePath: "/mtls"
+version: "3.14"
+type: "REST"
+id: "mtls-mandatory-oauth2-disabled"
+defaultVersion: false
+endpointConfigurations:
+  production:
+    endpoint: "https://run.mocky.io/v3/0c5173b2-9d99-459c-946b-b6b67c7f0139"
+operations:
+  - target: "/employee"
+    verb: "GET"
+    secured: true
+    scopes: []
+  - target: "/employee"
+    verb: "POST"
+    secured: true
+    scopes: []
+  - target: "/employee/{employeeId}"
+    verb: "PUT"
+    secured: true
+    scopes: []
+  - target: "/employee/{employeeId}"
+    verb: "DELETE"
+    secured: true
+    scopes: []
+authentication:
+  - authType: OAuth2
+    enabled: false
+  - authType: mTLS
+    required: mandatory
+    certificates:
+      - name: mtls-test-configmap
+        key: tls.crt
diff --git a/test/cucumber-tests/src/test/resources/artifacts/apk-confs/mtls/mtls_mandatory_oauth2_enabled.apk-conf b/test/cucumber-tests/src/test/resources/artifacts/apk-confs/mtls/mtls_mandatory_oauth2_enabled.apk-conf
new file mode 100644
index 000000000..c91fcc890
--- /dev/null
+++ b/test/cucumber-tests/src/test/resources/artifacts/apk-confs/mtls/mtls_mandatory_oauth2_enabled.apk-conf
@@ -0,0 +1,32 @@
+name: "EmployeeServiceAPI"
+basePath: "/mtls"
+version: "3.14"
+type: "REST"
+id: "mtls-mandatory-oauth2-enabled"
+defaultVersion: false
+endpointConfigurations:
+  production:
+    endpoint: "https://run.mocky.io/v3/0c5173b2-9d99-459c-946b-b6b67c7f0139"
+operations:
+  - target: "/employee"
+    verb: "GET"
+    secured: true
+    scopes: []
+  - target: "/employee"
+    verb: "POST"
+    secured: true
+    scopes: []
+  - target: "/employee/{employeeId}"
+    verb: "PUT"
+    secured: true
+    scopes: []
+  - target: "/employee/{employeeId}"
+    verb: "DELETE"
+    secured: true
+    scopes: []
+authentication:
+  - authType: mTLS
+    required: mandatory
+    certificates:
+      - name: mtls-test-configmap
+        key: tls.crt
diff --git a/test/cucumber-tests/src/test/resources/artifacts/apk-confs/mtls/mtls_multiple_certs.apk-conf b/test/cucumber-tests/src/test/resources/artifacts/apk-confs/mtls/mtls_multiple_certs.apk-conf
new file mode 100644
index 000000000..3429c24b9
--- /dev/null
+++ b/test/cucumber-tests/src/test/resources/artifacts/apk-confs/mtls/mtls_multiple_certs.apk-conf
@@ -0,0 +1,34 @@
+name: "EmployeeServiceAPI"
+basePath: "/mtls"
+version: "3.14"
+type: "REST"
+id: "mtls-multiple-certs"
+defaultVersion: false
+endpointConfigurations:
+  production:
+    endpoint: "https://run.mocky.io/v3/0c5173b2-9d99-459c-946b-b6b67c7f0139"
+operations:
+  - target: "/employee"
+    verb: "GET"
+    secured: true
+    scopes: []
+  - target: "/employee"
+    verb: "POST"
+    secured: true
+    scopes: []
+  - target: "/employee/{employeeId}"
+    verb: "PUT"
+    secured: true
+    scopes: []
+  - target: "/employee/{employeeId}"
+    verb: "DELETE"
+    secured: true
+    scopes: []
+authentication:
+  - authType: mTLS
+    required: mandatory
+    certificates:
+      - name: mtls-test-configmap
+        key: tls.crt
+      - name: mtls-test-configmap2
+        key: tls.crt
diff --git a/test/cucumber-tests/src/test/resources/artifacts/apk-confs/mtls/mtls_optional_oauth2_disabled.apk-conf b/test/cucumber-tests/src/test/resources/artifacts/apk-confs/mtls/mtls_optional_oauth2_disabled.apk-conf
new file mode 100644
index 000000000..c258d686b
--- /dev/null
+++ b/test/cucumber-tests/src/test/resources/artifacts/apk-confs/mtls/mtls_optional_oauth2_disabled.apk-conf
@@ -0,0 +1,33 @@
+name: "EmployeeServiceAPI"
+basePath: "/mtls"
+version: "3.14"
+type: "REST"
+id: "mtls-optional-oauth2-disabled"
+defaultVersion: false
+endpointConfigurations:
+  production:
+    endpoint: "https://webhook.site/1e73a7f6-6187-46ff-aac9-f060d7460c93"
+operations:
+  - target: "/employee"
+    verb: "GET"
+    secured: true
+    scopes: []
+  - target: "/employee"
+    verb: "POST"
+    secured: true
+    scopes: []
+  - target: "/employee/{employeeId}"
+    verb: "PUT"
+    secured: true
+    scopes: []
+  - target: "/employee/{employeeId}"
+    verb: "DELETE"
+    secured: true
+    scopes: []
+authentication:
+  - authType: OAuth2
+    enabled: false
+  - authType: mTLS
+    certificates:
+      - name: mtls-test-configmap
+        key: tls.crt
diff --git a/test/cucumber-tests/src/test/resources/artifacts/apk-confs/mtls/mtls_optional_oauth2_enabled.apk-conf b/test/cucumber-tests/src/test/resources/artifacts/apk-confs/mtls/mtls_optional_oauth2_enabled.apk-conf
new file mode 100644
index 000000000..b2119e886
--- /dev/null
+++ b/test/cucumber-tests/src/test/resources/artifacts/apk-confs/mtls/mtls_optional_oauth2_enabled.apk-conf
@@ -0,0 +1,31 @@
+name: "EmployeeServiceAPI"
+basePath: "/mtls"
+version: "3.14"
+type: "REST"
+id: "mtls-optional-oauth2-enabled"
+defaultVersion: false
+endpointConfigurations:
+  production:
+    endpoint: "https://run.mocky.io/v3/0c5173b2-9d99-459c-946b-b6b67c7f0139"
+operations:
+  - target: "/employee"
+    verb: "GET"
+    secured: true
+    scopes: []
+  - target: "/employee"
+    verb: "POST"
+    secured: true
+    scopes: []
+  - target: "/employee/{employeeId}"
+    verb: "PUT"
+    secured: true
+    scopes: []
+  - target: "/employee/{employeeId}"
+    verb: "DELETE"
+    secured: true
+    scopes: []
+authentication:
+  - authType: mTLS
+    certificates:
+      - name: mtls-test-configmap
+        key: tls.crt
diff --git a/test/cucumber-tests/src/test/resources/artifacts/certificates/config-map-1.txt b/test/cucumber-tests/src/test/resources/artifacts/certificates/config-map-1.txt
new file mode 100644
index 000000000..5e94b0441
--- /dev/null
+++ b/test/cucumber-tests/src/test/resources/artifacts/certificates/config-map-1.txt
@@ -0,0 +1 @@
+-----BEGIN CERTIFICATE-----MIIDGTCCAgECFANIkLQBkd76qiTXzSXjBS2scPJsMA0GCSqGSIb3DQEBCwUAME0xCzAJBgNVBAYTAkxLMRMwEQYDVQQIDApTb21lLVN0YXRlMQ0wCwYDVQQKDAR3c28yMQwwCgYDVQQLDANhcGsxDDAKBgNVBAMMA2FwazAeFw0yMzEyMDYxMDEyNDhaFw0yNTA0MTkxMDEyNDhaMEUxCzAJBgNVBAYTAkxLMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCdG90W/Tlk4u9awHPteD5zpVcThUKwMLvAKw9ivVQBC0AG6GzPbakol5gKVm+kBUDFzzzF6eayEXKWbyaZDty66A2+7HLLcKBop5M/a57Q9XtU3lRYvotgutLWuHcI7mLCScZDrjA3rnb/KjjbhZ602ZS1pp5jtyUz6DwLm7w4wQ/RProqCdBj8QqoAvnDDLSPeDfsx14J5VeNJVGJV2wax65jWRjRkj6wE7z2qzWAlP5vDeED6bogYYVDpC8DtgayQ+vKAQLi1uj+I9Yqb/nPUrdUh9IlxudlqiFQQxyvsXMJEzbWWmlbD0kXYkHmHzetJNPK9ayOS/fJcAcfAb01AgMBAAEwDQYJKoZIhvcNAQELBQADggEBAFmUc7+cI8d0Dl4wTdq+gfyWdqjQb7AYVO9DvJi3XGxdc5Kp1nCSsKzKUz9gvxXHeaYKrBNYf4SSU+Pkdf/BWePqi7UX/SIxNXby2da8zWg+W6UhxZfKlLYGMp3mCjueZpZTJ7SKOOGFA8IIgEzjJD9Ln1gl3ywMaCwlNrG9RpiD1McTCOKvyWNKnSRVr/RvCklLVrAMTJr50kce2czcdFl/xF4Hm66vp7cP/bYJKWAL8hBGzUa9aQBKncOoAO+zQ/SGy7uJxTDUF8SverDsmjOc6AU6IhBGVUyX/JQbYyJfZinBYlviYxVzIm6IaNJHx4sihw4U1/jMFWRXT470zcQ=-----END CERTIFICATE-----
\ No newline at end of file
diff --git a/test/cucumber-tests/src/test/resources/artifacts/certificates/config-map-2.txt b/test/cucumber-tests/src/test/resources/artifacts/certificates/config-map-2.txt
new file mode 100644
index 000000000..9e95fa5d5
--- /dev/null
+++ b/test/cucumber-tests/src/test/resources/artifacts/certificates/config-map-2.txt
@@ -0,0 +1 @@
+-----BEGIN CERTIFICATE-----MIIDkTCCAnmgAwIBAgIUJitjysknJ0nHeLH/mjT1JIpOz4YwDQYJKoZIhvcNAQELBQAwYDELMAkGA1UEBhMCVVMxEjAQBgNVBAgMCVlvdXJTdGF0ZTERMA8GA1UEBwwIWW91ckNpdHkxGTAXBgNVBAoMEFlvdXJPcmdhbml6YXRpb24xDzANBgNVBAMMBllvdXJDQTAeFw0yNDAxMDUwNDAwMjNaFw0yNTAxMDQwNDAwMjNaMGExCzAJBgNVBAYTAlVTMRIwEAYDVQQIDAlZb3VyU3RhdGUxETAPBgNVBAcMCFlvdXJDaXR5MRkwFwYDVQQKDBBZb3VyT3JnYW5pemF0aW9uMRAwDgYDVQQDDAdjbGllbnQxMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuJhFZmCVnj6N+/+HHuMvb4vyWqWcorUfpAWO7a3YVsHp3BX+lbGGzh67jbPcFK6K7RqejenFw7sQK8duZlqXmik/JvZMLxY3l/6e8LIAhN7PaX1zg58OU61baQ5VNBhUXkoYN77xqb87Yo7IFyyQ/tyWfRVFEzNjV1+q2MpEinuscViieIQHEpB4i6fsRxomYkR+FwdfCB65MYCYveIB1z9NkmR6Pm6V7zSPp+QYwc6WX4/61fbRje4BJh3j+FGYboJJg1o9O/MkD70RW6mdMV1l5bT9T98WB+hJtN+5dEpSfAwXqlWWxzhDxNsEvdSwuoLz9e58gteR1LSLaJXMjQIDAQABo0IwQDAdBgNVHQ4EFgQULaoslUgyglywztd95CkL6sU5wa4wHwYDVR0jBBgwFoAUGUkK+QXBjeGMy7XVnrXfrvVJUNswDQYJKoZIhvcNAQELBQADggEBABodQ1Y7zt7kvDI8jQUfLLkZZAPnVpjYpG7P1dLjOzUxqDNmyZAzoBMENXy/Zu81sRQt+Bs5NKsx1pu5z2TRk9ddxhszD1FKu9Hb6hqLcGHF7GnwPGVXJlHctkMp4QYvXc942VDk7c59/knCPXAul7832cPTUMvFHdzRxBwJruK9xuvNLj2I24+Fji1ELPO7M/e8KZ1NrIS0FdwnDuDDw3kMkl0BlSrmvMBreSaIOU4mFhmepC97awZ/wZZ+4mpIdWIagZf01txue8o0+8kdGkFsmoCpnJjNjpoQFAYLEdif00iLcRpwwW/saUuxqZC0aDnQCIeo0GSNet8tHOXCkvQ=-----END CERTIFICATE-----
\ No newline at end of file
diff --git a/test/cucumber-tests/src/test/resources/artifacts/certificates/config-map-3.txt b/test/cucumber-tests/src/test/resources/artifacts/certificates/config-map-3.txt
new file mode 100644
index 000000000..a0088574c
--- /dev/null
+++ b/test/cucumber-tests/src/test/resources/artifacts/certificates/config-map-3.txt
@@ -0,0 +1 @@
+-----BEGIN CERTIFICATE-----MIIDkTCCAnmgAwIBAgIUJitjysknJ0nHeLH/mjT1JIpOz4cwDQYJKoZIhvcNAQELBQAwYDELMAkGA1UEBhMCVVMxEjAQBgNVBAgMCVlvdXJTdGF0ZTERMA8GA1UEBwwIWW91ckNpdHkxGTAXBgNVBAoMEFlvdXJPcmdhbml6YXRpb24xDzANBgNVBAMMBllvdXJDQTAeFw0yNDAxMDUwNDE0MTlaFw0yNTAxMDQwNDE0MTlaMGExCzAJBgNVBAYTAlVTMRIwEAYDVQQIDAlZb3VyU3RhdGUxETAPBgNVBAcMCFlvdXJDaXR5MRkwFwYDVQQKDBBZb3VyT3JnYW5pemF0aW9uMRAwDgYDVQQDDAdjbGllbnQyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2JQ8LITwayvjrrHUmFT44lH3IF3fdPhrpQgKx7Z295QD9Ocka2rOFu47tuIeNcLiBTSyRLOFDRwjW9WXfWk9ALtxbedJfDyyus/kLxY+SdzHW7/5dFbupGOcs58A/sxMyGTJgiCBxsgsRFfhet7ekq/ypmj5B8L35FlGg5NS0mbZlTM6aapLnkqU907RcsmzpFQBfWOHlDdWJocKEHECBXcxiTQk72C7s2tndES5ltX/Wc8U/kX/M9LDXhn1Ew+roeFf0HCpdg6BlnTknhYU9S1c4aYKB2YxLNx74CsKsnxPPcePTXPqZEtZ4EsjF4PSToVFyceMBKvD6C6WPQoRNwIDAQABo0IwQDAdBgNVHQ4EFgQUWE8btMihi5eZXLJOeiNfh7XHaI0wHwYDVR0jBBgwFoAUGUkK+QXBjeGMy7XVnrXfrvVJUNswDQYJKoZIhvcNAQELBQADggEBAJmXn/gefez7mq1biKpPLPeHUncIgVaru03v8YCX14pHFAsVuLgZ1lANelSrq+PR/HBJbQj8iloV938oYFppe/fb96D8a2u90dnGwWipMRSDo3wgcInL38xfcH5UEPBVJVLa3IUkfwDjjEqK3O0GXVSpjyv3RW+E9wfPfGSysRX66cTo5Uh3z3hTAloDc8uhCYRPcxG7S9eKD6jWZ3MlFlw4U8CdO90L0nB1KFhz1Et0Sl9u/LDsUYq6mE+XhTngPs8qwR/o43s1DUIDy5Oi4A4+id+xO0XnHIkkqCfPtFzxl3hwytcy8EqISynzzHWNJ8bFZIYX4tgX+PLqu0/ITEw=-----END CERTIFICATE-----
\ No newline at end of file
diff --git a/test/cucumber-tests/src/test/resources/artifacts/certificates/invalid-cert.txt b/test/cucumber-tests/src/test/resources/artifacts/certificates/invalid-cert.txt
new file mode 100644
index 000000000..6d1b1152d
--- /dev/null
+++ b/test/cucumber-tests/src/test/resources/artifacts/certificates/invalid-cert.txt
@@ -0,0 +1 @@
+-----BEGIN CERTIFICATE-----invalidcertificate-----END CERTIFICATE-----
\ No newline at end of file
diff --git a/test/cucumber-tests/src/test/resources/tests/api/MTLS.feature b/test/cucumber-tests/src/test/resources/tests/api/MTLS.feature
new file mode 100644
index 000000000..aba613323
--- /dev/null
+++ b/test/cucumber-tests/src/test/resources/tests/api/MTLS.feature
@@ -0,0 +1,228 @@
+Feature: Test mTLS between client and gateway with client certificate sent in header
+    Scenario: Test mandatory mTLS and enabled OAuth2 with a valid client certificate in header
+        Given The system is ready
+        And I have a valid token with a client certificate "config-map-1.txt"
+        When I use the APK Conf file "artifacts/apk-confs/mtls/mtls_mandatory_oauth2_enabled.apk-conf"
+        And the definition file "artifacts/definitions/employees_api.json"
+        And make the API deployment request
+        Then the response status code should be 200
+        Then I set headers
+            | Authorization             | bearer ${accessToken} |
+            | X-WSO2-CLIENT-CERTIFICATE | ${clientCertificate}  |
+        And I send "GET" request to "https://default.gw.wso2.com:9095/mtls/3.14/employee/" with body ""
+        And I eventually receive 200 response code, not accepting
+            | 401 |
+        When I undeploy the API whose ID is "mtls-mandatory-oauth2-enabled"
+        Then the response status code should be 202
+
+    Scenario: Test mandatory mTLS and enabled OAuth2 with an invalid client certificate in header
+        Given The system is ready
+        And I have a valid token with a client certificate "invalid-cert.txt"
+        When I use the APK Conf file "artifacts/apk-confs/mtls/mtls_mandatory_oauth2_enabled.apk-conf"
+        And the definition file "artifacts/definitions/employees_api.json"
+        And make the API deployment request
+        Then the response status code should be 200
+        Then I set headers
+            | Authorization             | bearer ${accessToken} |
+            | X-WSO2-CLIENT-CERTIFICATE | ${clientCertificate}  |
+        And I send "GET" request to "https://default.gw.wso2.com:9095/mtls/3.14/employee/" with body ""
+        And I eventually receive 401 response code, not accepting
+            | 200 |
+        When I undeploy the API whose ID is "mtls-mandatory-oauth2-enabled"
+        Then the response status code should be 202
+
+    Scenario: Test mandatory mTLS and enabled OAuth2 without a client certificate in header
+        Given The system is ready
+        And I have a valid subscription
+        When I use the APK Conf file "artifacts/apk-confs/mtls/mtls_mandatory_oauth2_enabled.apk-conf"
+        And the definition file "artifacts/definitions/employees_api.json"
+        And make the API deployment request
+        Then the response status code should be 200
+        Then I set headers
+            | Authorization | bearer ${accessToken} |
+        And I send "GET" request to "https://default.gw.wso2.com:9095/mtls/3.14/employee/" with body ""
+        And I eventually receive 401 response code, not accepting
+            | 200 |
+        When I undeploy the API whose ID is "mtls-mandatory-oauth2-enabled"
+        Then the response status code should be 202
+
+    Scenario: Test mandatory mTLS and disabled OAuth2 with a valid client certificate in header
+        Given The system is ready
+        And I have a valid token with a client certificate "config-map-1.txt"
+        When I use the APK Conf file "artifacts/apk-confs/mtls/mtls_mandatory_oauth2_disabled.apk-conf"
+        And the definition file "artifacts/definitions/employees_api.json"
+        And make the API deployment request
+        Then the response status code should be 200
+        Then I set headers
+            | X-WSO2-CLIENT-CERTIFICATE | ${clientCertificate} |
+        And I send "GET" request to "https://default.gw.wso2.com:9095/mtls/3.14/employee/" with body ""
+        And I eventually receive 200 response code, not accepting
+            | 401 |
+        When I undeploy the API whose ID is "mtls-mandatory-oauth2-disabled"
+        Then the response status code should be 202
+
+    Scenario: Test mandatory mTLS and disabled OAuth2 with an invalid client certificate in header
+        Given The system is ready
+        And I have a valid token with a client certificate "invalid-cert.txt"
+        When I use the APK Conf file "artifacts/apk-confs/mtls/mtls_mandatory_oauth2_disabled.apk-conf"
+        And the definition file "artifacts/definitions/employees_api.json"
+        And make the API deployment request
+        Then the response status code should be 200
+        Then I set headers
+            | X-WSO2-CLIENT-CERTIFICATE | ${clientCertificate} |
+        And I send "GET" request to "https://default.gw.wso2.com:9095/mtls/3.14/employee/" with body ""
+        And I eventually receive 401 response code, not accepting
+            | 200 |
+        When I undeploy the API whose ID is "mtls-mandatory-oauth2-disabled"
+        Then the response status code should be 202
+
+    Scenario: Test mandatory mTLS and disabled OAuth2 without a client certificate in header
+        Given The system is ready
+        And I have a valid subscription
+        When I use the APK Conf file "artifacts/apk-confs/mtls/mtls_mandatory_oauth2_disabled.apk-conf"
+        And the definition file "artifacts/definitions/employees_api.json"
+        And make the API deployment request
+        Then the response status code should be 200
+        And I send "GET" request to "https://default.gw.wso2.com:9095/mtls/3.14/employee/" with body ""
+        And I eventually receive 401 response code, not accepting
+            | 200 |
+        When I undeploy the API whose ID is "mtls-mandatory-oauth2-disabled"
+        Then the response status code should be 202
+
+    Scenario: Test optional mTLS and enabled OAuth2 with a valid client certificate in header
+        Given The system is ready
+        And I have a valid token with a client certificate "config-map-1.txt"
+        When I use the APK Conf file "artifacts/apk-confs/mtls/mtls_optional_oauth2_enabled.apk-conf"
+        And the definition file "artifacts/definitions/employees_api.json"
+        And make the API deployment request
+        Then the response status code should be 200
+        Then I set headers
+            | Authorization             | bearer ${accessToken} |
+            | X-WSO2-CLIENT-CERTIFICATE | ${clientCertificate}  |
+        And I send "GET" request to "https://default.gw.wso2.com:9095/mtls/3.14/employee/" with body ""
+        And I eventually receive 200 response code, not accepting
+            | 401 |
+        When I undeploy the API whose ID is "mtls-optional-oauth2-enabled"
+        Then the response status code should be 202
+
+    Scenario: Test optional mTLS and enabled OAuth2 with an invalid client certificate in header
+        Given The system is ready
+        And I have a valid token with a client certificate "invalid-cert.txt"
+        When I use the APK Conf file "artifacts/apk-confs/mtls/mtls_optional_oauth2_enabled.apk-conf"
+        And the definition file "artifacts/definitions/employees_api.json"
+        And make the API deployment request
+        Then the response status code should be 200
+        Then I set headers
+            | Authorization             | bearer ${accessToken} |
+            | X-WSO2-CLIENT-CERTIFICATE | ${clientCertificate}  |
+        And I send "GET" request to "https://default.gw.wso2.com:9095/mtls/3.14/employee/" with body ""
+        And I eventually receive 200 response code, not accepting
+            | 401 |
+        When I undeploy the API whose ID is "mtls-optional-oauth2-enabled"
+        Then the response status code should be 202
+
+    Scenario: Test optional mTLS and enabled OAuth2 without a client certificate in header
+        Given The system is ready
+        And I have a valid subscription
+        When I use the APK Conf file "artifacts/apk-confs/mtls/mtls_optional_oauth2_enabled.apk-conf"
+        And the definition file "artifacts/definitions/employees_api.json"
+        And make the API deployment request
+        Then the response status code should be 200
+        Then I set headers
+            | Authorization | bearer ${accessToken} |
+        And I send "GET" request to "https://default.gw.wso2.com:9095/mtls/3.14/employee/" with body ""
+        And I eventually receive 200 response code, not accepting
+            | 401 |
+        When I undeploy the API whose ID is "mtls-optional-oauth2-enabled"
+        Then the response status code should be 202
+
+    Scenario: Test optional mTLS and disabled OAuth2 with a valid client certificate in header
+        Given The system is ready
+        And I have a valid token with a client certificate "config-map-1.txt"
+        When I use the APK Conf file "artifacts/apk-confs/mtls/mtls_optional_oauth2_disabled.apk-conf"
+        And the definition file "artifacts/definitions/employees_api.json"
+        And make the API deployment request
+        Then the response status code should be 406
+
+    Scenario: Test an API with mTLS disabled and OAuth2 disabled
+        Given The system is ready
+        And I have a valid subscription
+        When I use the APK Conf file "artifacts/apk-confs/mtls/mtls_disabled_oauth2_disabled.apk-conf"
+        And the definition file "artifacts/definitions/employees_api.json"
+        And make the API deployment request
+        Then the response status code should be 406
+
+    Scenario: Test an API with mTLS disabled and OAuth2 enabled
+        Given The system is ready
+        And I have a valid subscription
+        When I use the APK Conf file "artifacts/apk-confs/mtls/mtls_disabled_oauth2_enabled.apk-conf"
+        And the definition file "artifacts/definitions/employees_api.json"
+        And make the API deployment request
+        Then the response status code should be 200
+        Then I set headers
+            | Authorization | bearer ${accessToken} |
+        And I send "GET" request to "https://default.gw.wso2.com:9095/mtls/3.14/employee/" with body ""
+        And I eventually receive 200 response code, not accepting
+            | 401 |
+        When I undeploy the API whose ID is "mtls-disabled-oauth2-enabled"
+        Then the response status code should be 202
+
+    Scenario: Test an API with mTLS enabled and one associated certificate with multiple certificates existing in system
+        Given The system is ready
+        And I have a valid token with a client certificate "config-map-1.txt"
+        When I use the APK Conf file "artifacts/apk-confs/mtls/mtls_mandatory_oauth2_enabled.apk-conf"
+        And the definition file "artifacts/definitions/employees_api.json"
+        And make the API deployment request
+        Then the response status code should be 200
+        Then I set headers
+            | Authorization             | bearer ${accessToken} |
+            | X-WSO2-CLIENT-CERTIFICATE | ${clientCertificate}  |
+        And I send "GET" request to "https://default.gw.wso2.com:9095/mtls/3.14/employee/" with body ""
+        And I eventually receive 200 response code, not accepting
+            | 401 |
+        And I have a valid token with a client certificate "config-map-2.txt"
+        Then I set headers
+            | Authorization             | bearer ${accessToken} |
+            | X-WSO2-CLIENT-CERTIFICATE | ${clientCertificate}  |
+        And I send "GET" request to "https://default.gw.wso2.com:9095/mtls/3.14/employee/" with body ""
+        And I eventually receive 401 response code, not accepting
+            | 200 |
+        And I have a valid token with a client certificate "config-map-3.txt"
+        Then I set headers
+            | Authorization             | bearer ${accessToken} |
+            | X-WSO2-CLIENT-CERTIFICATE | ${clientCertificate}  |
+        And I send "GET" request to "https://default.gw.wso2.com:9095/mtls/3.14/employee/" with body ""
+        And I eventually receive 401 response code, not accepting
+            | 200 |
+        When I undeploy the API whose ID is "mtls-mandatory-oauth2-enabled"
+        Then the response status code should be 202
+
+    Scenario: Test an API with mTLS enabled and multiple certificates configured
+        Given The system is ready
+        And I have a valid token with a client certificate "config-map-1.txt"
+        When I use the APK Conf file "artifacts/apk-confs/mtls/mtls_multiple_certs.apk-conf"
+        And the definition file "artifacts/definitions/employees_api.json"
+        And make the API deployment request
+        Then the response status code should be 200
+        Then I set headers
+            | Authorization             | bearer ${accessToken} |
+            | X-WSO2-CLIENT-CERTIFICATE | ${clientCertificate}  |
+        And I send "GET" request to "https://default.gw.wso2.com:9095/mtls/3.14/employee/" with body ""
+        And I eventually receive 200 response code, not accepting
+            | 401 |
+        And I have a valid token with a client certificate "config-map-2.txt"
+        Then I set headers
+            | Authorization             | bearer ${accessToken} |
+            | X-WSO2-CLIENT-CERTIFICATE | ${clientCertificate}  |
+        And I send "GET" request to "https://default.gw.wso2.com:9095/mtls/3.14/employee/" with body ""
+        And I eventually receive 200 response code, not accepting
+            | 401 |
+        And I have a valid token with a client certificate "config-map-3.txt"
+        Then I set headers
+            | Authorization             | bearer ${accessToken} |
+            | X-WSO2-CLIENT-CERTIFICATE | ${clientCertificate}  |
+        And I send "GET" request to "https://default.gw.wso2.com:9095/mtls/3.14/employee/" with body ""
+        And I eventually receive 401 response code, not accepting
+            | 200 |
+        When I undeploy the API whose ID is "mtls-multiple-certs"
+        Then the response status code should be 202