diff --git a/README.md b/README.md index 9ec93f82e..c8dd8694b 100644 --- a/README.md +++ b/README.md @@ -62,17 +62,17 @@ to operate the cluster (Istio's) ingress gateway to provide API management with The kuadrant control plane owns the following [Custom Resource Definitions, CRDs](https://kubernetes.io/docs/tasks/extend-kubernetes/custom-resources/custom-resource-definitions/): -| CRD | Description | Example | -|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|----------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------| -| RateLimitPolicy CRD [\[doc\]](https://github.com/Kuadrant/kuadrant-operator/blob/main/doc/rate-limiting.md) [[reference]](https://github.com/Kuadrant/kuadrant-operator/blob/main/doc/ratelimitpolicy-reference.md) | Enable access control on workloads based on HTTP rate limiting | [RateLimitPolicy CR](https://raw.githubusercontent.com/Kuadrant/kuadrant-operator/main/config/samples/kuadrant_v1beta1_kuadrant.yaml) | -| [AuthPolicy CRD](https://github.com/Kuadrant/kuadrant-operator/blob/main/apis/apim/v1alpha1/authpolicy_types.go) | Enable AuthN and AuthZ based access control on workloads | [AuthPolicy CR](https://github.com/Kuadrant/kuadrant-operator/blob/main/config/samples/kuadrant_v1beta1_ratelimitpolicy.yaml) | +| CRD | Description | Example | +|-----------------------------------------------------------------------------------------------------|----------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------| +| AuthPolicy CRD [\[doc\]](doc/auth.md) [[reference]](doc/reference/authpolicy.md) | Enable AuthN and AuthZ based access control on workloads | [AuthPolicy CR](https://github.com/Kuadrant/kuadrant-operator/blob/main/examples/toystore/authpolicy.yaml) | +| RateLimitPolicy CRD [\[doc\]](doc/rate-limiting.md) [[reference]](doc/reference/ratelimitpolicy.md) | Enable access control on workloads based on HTTP rate limiting | [RateLimitPolicy CR](https://raw.githubusercontent.com/Kuadrant/kuadrant-operator/main/examples/toystore/ratelimitpolicy_httproute.yaml) | Additionally, Kuadrant provides the following CRDs | CRD | Owner | Description | Example | |--------------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------|-------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------| | [Kuadrant CRD](https://github.com/Kuadrant/kuadrant-operator/blob/main/api/v1beta1/kuadrant_types.go) | [Kuadrant Operator](https://github.com/Kuadrant/kuadrant-operator) | Represents an instance of kuadrant | [Kuadrant CR](https://github.com/Kuadrant/kuadrant-operator/blob/main/config/samples/kuadrant_v1beta1_kuadrant.yaml) | -| [Limitador CRD](doc/ratelimitpolicy-reference.md) | [Limitador Operator](https://github.com/Kuadrant/limitador-operator) | Represents an instance of Limitador | [Limitador CR](https://github.com/Kuadrant/limitador-operator/blob/main/config/samples/limitador_v1alpha1_limitador.yaml) | +| [Limitador CRD](https://github.com/Kuadrant/limitador-operator/blob/main/api/v1alpha1/limitador_types.go) | [Limitador Operator](https://github.com/Kuadrant/limitador-operator) | Represents an instance of Limitador | [Limitador CR](https://github.com/Kuadrant/limitador-operator/blob/main/config/samples/limitador_v1alpha1_limitador.yaml) | | [Authorino CRD](https://github.com/Kuadrant/authorino-operator#the-authorino-custom-resource-definition-crd) | [Authorino Operator](https://github.com/Kuadrant/authorino-operator) | Represents an instance of Authorino | [Authorino CR](https://github.com/Kuadrant/authorino-operator/blob/main/config/samples/authorino-operator_v1beta1_authorino.yaml) | Kuadrant Architecture @@ -146,7 +146,7 @@ EOF * Expose the service/API using the kubernetes Gateway API, ie [HTTPRoute](https://gateway-api.sigs.k8s.io/v1alpha2/references/spec/#gateway.networking.k8s.io/v1beta1.HTTPRoute) object. * Write and apply the Kuadrant's [RateLimitPolicy](doc/rate-limiting.md) and/or - [AuthPolicy](api/v1beta1/authpolicy_types.go) custom resources targeting the HTTPRoute resource + [AuthPolicy](doc/auth.md) custom resources targeting the HTTPRoute resource to have your API protected. #### If you are a *Cluster Operator* @@ -154,7 +154,7 @@ EOF * (Optionally) deploy istio ingress gateway using the [Gateway](https://gateway-api.sigs.k8s.io/v1alpha2/references/spec/#gateway.networking.k8s.io/v1beta1.Gateway) resource. * Write and apply the Kuadrant's [RateLimitPolicy](doc/rate-limiting.md) and/or - [AuthPolicy](api/v1beta1/authpolicy_types.go) custom resources targeting the Gateway resource + [AuthPolicy](doc/auth.md) custom resources targeting the Gateway resource to have your gateway traffic protected. ## User guides @@ -177,7 +177,7 @@ Docs can be found on the [Kuadrant website](https://kuadrant.io/). The [Development guide](doc/development.md) describes how to build the kuadrant operator and how to test your changes before submitting a patch or opening a PR. -Join us on the [#kuadrant](https://kubernetes.slack.com/archives/C05J0D0V525) channel in the Kubernetes Slack workspace, +Join us on the [#kuadrant](https://kubernetes.slack.com/archives/C05J0D0V525) channel in the Kubernetes Slack workspace, for live discussions about the roadmap and more. ## Licensing diff --git a/doc/auth.md b/doc/auth.md new file mode 100644 index 000000000..73057723b --- /dev/null +++ b/doc/auth.md @@ -0,0 +1,323 @@ +# Kuadrant Auth + +A Kuadrant AuthPolicy custom resource: + +1. Targets Gateway API networking resources such as [HTTPRoutes](https://gateway-api.sigs.k8s.io/references/spec/#gateway.networking.k8s.io/v1beta1.HTTPRoute) and [Gateways](https://gateway-api.sigs.k8s.io/references/spec/#gateway.networking.k8s.io/v1beta1.Gateway), using these resources to obtain additional context, i.e., which traffic workload (HTTP attributes, hostnames, user attributes, etc) to enforce auth. +2. Supports targeting subsets (sections) of a network resource to apply the auth rules to. +3. Abstracts the details of the underlying external authorization protocol and configuration resources, that have a much broader remit and surface area. +4. Enables cluster operators to set defaults that govern behavior at the lower levels of the network, until a more specific policy is applied. + +## How it works + +### Envoy's External Authorization Protocol + +Kuadrant's Auth implementation relies on the Envoy's [External Authorization](https://www.envoyproxy.io/docs/envoy/latest/configuration/http/http_filters/ext_authz_filter) protocol. The workflow per request goes: +1. On incoming request, the gateway checks the matching rules for enforcing the auth rules, as stated in the AuthPolicy custom resources and targeted Gateway API networking objects +2. If the request matches, the gateway sends one [CheckRequest](https://www.envoyproxy.io/docs/envoy/latest/api-v3/service/auth/v3/external_auth.proto#envoy-v3-api-msg-service-auth-v3-checkrequest) to the external auth service ("Authorino"). +3. The external auth service responds with a [CheckResponse](https://www.envoyproxy.io/docs/envoy/latest/api-v3/service/auth/v3/external_auth.proto#service-auth-v3-checkresponse) back to the gateway with either an `OK` or `DENIED` response code. + +An AuthPolicy and its targeted Gateway API networking resource contain all the statements to configure both the ingress gateway and the external auth service. + +### The AuthPolicy custom resource + +#### Overview + +The `AuthPolicy` spec includes the following parts: + +* A reference to an existing Gateway API resource (`spec.targetRef`) +* Authentication/authorization scheme (`spec.rules`) +* Top-level route selectors (`spec.routeSelectors`) +* Top-level additional conditions (`spec.when`) +* List of named patterns (`spec.patterns`) + +The auth scheme specify rules for: +* Authentication (`spec.rules.authentication`) +* External auth metadata fetching (`spec.rules.metadata`) +* Authorization (`spec.rules.authorization`) +* Custom response items (`spec.rules.response`) +* Callbacks (`spec.rules.callbacks`) + +Each auth rule can declare specific `routeSelectors` and `when` conditions for the rule to apply. + +#### High-level example and field definition + +```yaml +apiVersion: kuadrant.io/v1beta2 +kind: AuthPolicy +metadata: + name: my-auth-policy +spec: + # Reference to an existing networking resource to attach the policy to. + # It can be a Gateway API HTTPRoute or Gateway resource. + # It can only refer to objects in the same namespace as the AuthPolicy. + targetRef: + group: gateway.networking.k8s.io + kind: HTTPRoute / Gateway + name: myroute / mygateway + + # Selectors of HTTPRouteRules within the targeted HTTPRoute that activate the AuthPolicy. + # Each element contains a HTTPRouteMatch object that will be used to select HTTPRouteRules that include at least + # one identical HTTPRouteMatch. + # The HTTPRouteMatch part does not have to be fully identical, but the what's stated in the selector must be + # identically stated in the HTTPRouteRule. + # Do not use it on AuthPolicies that target a Gateway. + routeSelectors: + - matches: + - path: + type: PathPrefix + value: "/admin" + + # Additional dynamic conditions to trigger the AuthPolicy. + # Use it for filterring attributes not supported by HTTPRouteRule or with AuthPolicies that target a Gateway. + # Check out https://github.com/Kuadrant/architecture/blob/main/rfcs/0002-well-known-attributes.md to learn more + # about the Well-known Attributes that can be used in this field. + when: […] + + # The auth rules to apply to the network traffic routed through the targeted resource + rules: + # Authentication rules to enforce. + # At least one config must evaluate to a valid identity object for the auth request to be successful. + # If omitted or empty, anonymous access is assumed. + authentication: + "my-authn-rule": + # The authentication method of this rule. + # One-of: apiKey, jwt, oauth2Introspection, kubernetesTokenReview, x509, plain, anonymous. + apiKey: {…} + + # Where credentials are required to be passed in the request for authentication based on this rule. + # One-of: authorizationHeader, customHeader, queryString, cookie. + credentials: + authorizationHeader: + prefix: APIKEY + + # Rule-level route selectors. + routeSelectors: […] + + # Rule-level additional conditions. + when: […] + + # Configs for caching the resolved object returned out of evaluating this auth rule. + cache: {…} + + # Rules for fetching auth metadata from external sources. + metadata: + "my-external-source": + # The method for fetching metadata from the external source. + # One-of: http: userInfo, uma. + http: {…} + + # Authorization rules to enforce. + # All policies must allow access for the auth request be successful. + authorization: + "my-authz-rule": + # The authorization method of this rule. + # One-of: patternMatching, opa, kubernetesSubjectAccessReview, spicedb. + opa: {…} + + # Customizations to the authorization response. + response: + # Custom denial status and other HTTP attributes for unauthenticated requests. + unauthenticated: {…} + + # Custom denial status and other HTTP attributes for unauhtorized requests. + unauthorized: {…} + + # Custom response items when access is granted. + success: + # Custom response items wrapped as HTTP headers to be injected in the request + headers: + "my-custom-header": + # One-of: plain, json, wristband. + plain: {…} + + # Custom response items wrapped as envoy dynamic metadata. + dynamicMetadata: + # One-of: plain, json, wristband. + "my-custom-dyn-metadata": + json: {…} + + # Rules for post-authorization callback requests to external services. + # Triggered regardless of the result of the authorization request. + callbacks: + "my-webhook": + http: {…} +``` + +Check out the [API reference](reference/authpolicy.md) for a full specification of the AuthPolicy CRD. + +## Using the AuthPolicy + +### Targeting a HTTPRoute networking resource + +When an AuthPolicy targets a HTTPRoute, the policy is enforced to all traffic routed according to the rules and hostnames specified in the HTTPRoute, across all Gateways referenced in the `spec.parentRefs` field of the HTTPRoute. + +The targeted HTTPRoute's rules and/or hostnames to which the policy must be enforced can be filtered to specific subsets, by specifying the [`routeSelectors`](reference/route-selectors.md#the-routeselectors-field) field of the AuthPolicy spec. + +Target a HTTPRoute by setting the `spec.targetRef` field of the AuthPolicy as follows: + +```yaml +apiVersion: kuadrant.io/v1beta2 +kind: AuthPolicy +metadata: + name: my-route-auth +spec: + targetRef: + group: gateway.networking.k8s.io + kind: HTTPRoute + name: + rules: {…} +``` + +``` +┌───────────────────┐ ┌────────────────────┐ +│ (Infra namespace) │ │ (App namespace) │ +│ │ │ │ +│ ┌─────────┐ │ parentRefs │ ┌───────────┐ │ +│ │ Gateway │◄─────┼─────────────┼──┤ HTTPRoute │ │ +│ └─────────┘ │ │ └───────────┘ │ +│ │ │ ▲ │ +│ │ │ │ │ +│ │ │ │ │ +│ │ │ │ targetRef │ +│ │ │ │ │ +│ │ │ ┌─────┴──────┐ │ +│ │ │ │ AuthPolicy │ │ +│ │ │ └────────────┘ │ +│ │ │ │ +└───────────────────┘ └────────────────────┘ +``` + +#### Multiple HTTPRoutes with the same hostname + +Kuadrant currently does not support concurrent AuthPolicies targeting the exact same hostname. + +In case 2 or more AuthPolicies target resources that specify the same exact hostnames, the first AuthPolicy created claims the hostname; all the other AuthPolicies will not be enforced for the conflicting hostname and their status will be reported as not ready. + +This limitation only applies to identical hostnames. Different AuthPolicies can still be declared for different hostnames, as well as sets and strict subsets of hostnames. + +#### Hostnames and wildcards + +If an AuthPolicy targets a route defined for `*.com` and another AuthPolicy targets another route for `api.com`, the Kuadrant control plane will not merge these two AuthPolicies. Rather, it will mimic the behavior of gateway implementation by which the "most specific hostname wins", thus enforcing only the corresponding applicable policies and auth rules. + +E.g., a request coming for `api.com` will be protected according to the rules from the AuthPolicy that targets the route for `api.com`; while a request for `other.com` will be protected with the rules from the AuthPolicy targeting the route for `*.com`. + +Example with 3 AuthPolicies and 3 HTTPRoutes: +- AuthPolicy A → HTTPRoute A (`a.toystore.com`) +- AuthPolicy B → HTTPRoute B (`b.toystore.com`) +- AuthPolicy W → HTTPRoute W (`*.toystore.com`) + +Expected behavior: +- Request to `a.toystore.com` → AuthPolicy A will be enforced +- Request to `b.toystore.com` → AuthPolicy B will be enforced +- Request to `other.toystore.com` → AuthPolicy W will be enforced + +### Targeting a Gateway networking resource + +When an AuthPolicy targets a Gateway, the policy will be enforced to all HTTP traffic hitting the gateway, unless a more specific AuthPolicy targeting a matching HTTPRoute exists. + +Any new HTTPRoute referrencing the gateway as parent will be automatically covered by the AuthPolicy that targets the Gateway, as well as changes in the existing HTTPRoutes. + +This effectively provides cluster operators with the ability to set _defaults_ to protect the infrastructure against unplanned and malicious network traffic attempt, such as by setting preemptive "deny-all" policies for hostnames and hostname wildcards. + +Target a Gateway HTTPRoute by setting the `spec.targetRef` field of the AuthPolicy as follows: + +```yaml +apiVersion: kuadrant.io/v1beta2 +kind: AuthPolicy +metadata: + name: my-gw-auth +spec: + targetRef: + group: gateway.networking.k8s.io + kind: Gateway + name: + rules: {…} +``` + +``` +┌───────────────────┐ ┌────────────────────┐ +│ (Infra namespace) │ │ (App namespace) │ +│ │ │ │ +│ ┌─────────┐ │ parentRefs │ ┌───────────┐ │ +│ │ Gateway │◄─────┼─────────────┼──┤ HTTPRoute │ │ +│ └─────────┘ │ │ └───────────┘ │ +│ ▲ │ │ ▲ │ +│ │ │ │ │ │ +│ │ │ │ │ │ +│ │ targetRef │ │ │ targetRef │ +│ │ │ │ │ │ +│ ┌─────┴──────┐ │ │ ┌─────┴──────┐ │ +│ │ AuthPolicy │ │ │ │ AuthPolicy │ │ +│ └────────────┘ │ │ └────────────┘ │ +│ │ │ │ +└───────────────────┘ └────────────────────┘ +``` + +#### Overlapping Gateway and HTTPRoute AuthPolicies + +Gateway-targeted AuthPolicies will serve as a default to protect all traffic routed through the gateway until a more specific HTTPRoute-targeted AuthPolicy exists, in which case the HTTPRoute AuthPolicy prevails. + +Example with 4 AuthPolicies, 3 HTTPRoutes and 1 Gateway (plus 2 HTTPRoute and 2 Gateways without AuthPolicies attached): +- AuthPolicy A → HTTPRoute A (`a.toystore.com`) → Gateway G (`*.com`) +- AuthPolicy B → HTTPRoute B (`b.toystore.com`) → Gateway G (`*.com`) +- AuthPolicy W → HTTPRoute W (`*.toystore.com`) → Gateway G (`*.com`) +- AuthPolicy G → Gateway G (`*.com`) + +Expected behavior: +- Request to `a.toystore.com` → AuthPolicy A will be enforced +- Request to `b.toystore.com` → AuthPolicy B will be enforced +- Request to `other.toystore.com` → AuthPolicy W will be enforced +- Request to `other.com` (suppose a route exists) → AuthPolicy G will be enforced +- Request to `yet-another.net` (suppose a route and gateway exist) → No AuthPolicy will be enforced + +### Route selectors + +Route selectors allow targeting sections of a HTTPRoute, by specifying sets of HTTPRouteMatches and/or hostnames that make the policy controller look up within the HTTPRoute spec for compatible declarations, and select the corresponding HTTPRouteRules and hostnames, to then build conditions that activate the policy or policy rule. + +Check out [Route selectors](reference/route-selectors.md) for a full description, semantics and API reference. + +#### `when` conditions + +`when` conditions can be used to scope an AuthPolicy or auth rule within an AuthPolicy (i.e. to filter the traffic to which a policy or policy rule applies) without any coupling to the underlying network topology, i.e. without making direct references to HTTPRouteRules via [`routeSelectors`](reference/route-selectors.md#the-routeselectors-field). + +Use `when` conditions to conditionally activate policies and policy rules based on attributes that cannot be expressed in the HTTPRoutes' `spec.hostnames` and `spec.rules.matches` fields, or in general in AuthPolicies that target a Gateway. + +`when` conditions in an AuthPolicy are compatible with Authorino [conditions](https://docs.kuadrant.io/authorino/docs/features/#common-feature-conditions-when), thus supporting complex boolean expressions with AND and OR operators, as well as grouping. + +The selectors within the `when` conditions of an AuthPolicy are a subset of Kuadrant's Well-known Attributes ([RFC 0002](https://github.com/Kuadrant/architecture/blob/main/rfcs/0002-well-known-attributes.md)). Check out the reference for the full list of supported selectors. + +Authorino [JSON path string modifiers](https://docs.kuadrant.io/authorino/docs/features/#string-modifiers) can also be applied to the selectors within the `when` conditions of an AuthPolicy. + +### Examples + +Check out the following user guides for examples of protecting services with Kuadrant: +* [Enforcing authentication & authorization with Kuadrant AuthPolicy, for app developers and platform engineers](user-guides/auth-for-app-devs-and-platform-engineers.md) +* [Authenticated Rate Limiting for Application Developers](user-guides/authenticated-rl-for-app-developers.md) +* [Authenticated Rate Limiting with JWTs and Kubernetes RBAC](user-guides/authenticated-rl-with-jwt-and-k8s-authnz.md) + +### Known limitations + +* One HTTPRoute can only be targeted by one AuthPolicy. +* One Gateway can only be targeted by one AuthPolicy. +* AuthPolicies can only target HTTPRoutes/Gateways defined within the same namespace of the AuthPolicy. +* 2+ AuthPolicies cannot target network resources that define/inherit the same exact hotname. + +## Implementation details + +Under the hood, for each AuthPolicy, Kuadrant creates an Istio [`AuthorizationPolicy`](https://istio.io/latest/docs/reference/config/security/authorization-policy) and an Authorino [`AuthConfig`](https://docs.kuadrant.io/authorino/docs/architecture/#the-authorino-authconfig-custom-resource-definition-crd) custom resources. + +Only requests that matches the rules in the Istio `AuthorizationPolicy` cause an authorization request to be sent to the external authorization service ("Authorino"), i.e., only requests directed to the HTTPRouteRules targeted by the AuthPolicy (directly or indirectly), according to the declared top-level route selectors (if present), or all requests for which a matching HTTPRouteRule exists (otherwise). + +Authorino looks up for the auth scheme (`AuthConfig` custom resource) to enforce using the provided hostname of the original request as key. It then checks again if the request matches at least one of the selected HTTPRouteRules, in which case it enforces the auth scheme. + +
+ Exception to the rule + + Due to limitations imposed by the Istio `AuthorizationPolicy`, there are a few patterns of HTTPRouteRules that cannot be translated to filters for the external authorization request. Therefore, the following patterns used in HTTPRouteMatches of top-level route selectors of an AuthPolicy will not be included in the Istio AuthorizationPolicy rules that trigger the check request with Authorino: `PathMatchRegularExpression`, `HeaderMatchRegularExpression`, and `HTTPQueryParamMatch`. + + As a consequence to the above, requests that do not match these rules and otherwise would not be checked with Authorino will result in a request to the external authorization service. Authorino nonetheless will still verify those patterns and ensure the auth scheme is enforced only when it matches a selected HTTPRouteRule. Users of Kuadrant may observe an unnecessary call to the authorization service in those cases where the request is out of the scope of the AuthPolicy and therefore always authorized. +
+ +### Internal custom resources and namespaces + +While the Istio `AuthorizationPolicy` needs to be created in the same namespace as the gateway workload, the Authorino `AuthConfig` is created in the namespace of the `AuthPolicy` itself. This allows to simplify references such as to Kubernetes Secrets referred in the AuthPolicy, as well as the RBAC to support the architecture. diff --git a/doc/proposals/authpolicy-crd.md b/doc/proposals/authpolicy-crd.md deleted file mode 100644 index f53bd7aeb..000000000 --- a/doc/proposals/authpolicy-crd.md +++ /dev/null @@ -1,128 +0,0 @@ -# AuthPolicy Proposal -Authors: Rahul Anand (rahanand@redhat.com), Craig Brookes (cbrookes@redhat.com) - -## Introduction -Istio offers an [AuthorizationPolicy](https://istio.io/latest/docs/reference/config/security/authorization-policy/) resource which requires it to be applied in the namespace of the workload. This means that all the configuration is completely decoupled from routing logic like hostnames and paths. For managed gateway scenario, users need to either ask cluster operator to apply their policies in the gateway's namespace (which is not scalable) or use sidecars/personal gateway for their workloads in their own namepsace which is not optimal. - -The new [GatewayAPI](https://gateway-api.sigs.k8s.io/) defines a standard [policy attachment mechanism](https://gateway-api.sigs.k8s.io/v1alpha2/references/policy-attachment/) for hierarchical effect of vendor specific policies. We believe creating a new CRD with concepts from Gateway API that solves use cases of Istio's AuthorizationPolicy plus its limitations as described above. - -## Goals - -With `targetRef` from policy attachment concept, following are the goals: -- Application developer should be able to target [`HTTPRoute`](https://gateway-api.sigs.k8s.io/v1alpha2/references/spec/#gateway.networking.k8s.io/v1alpha2.HTTPRoute) object in their own namespace. This will define authorization policy at the hostname/domain/vHost level. -- Cluster operator should be able to target [`Gateway`](https://gateway-api.sigs.k8s.io/v1alpha2/references/spec/#gateway.networking.k8s.io/v1alpha2.Gateway) object along with HTTPRoute in the gateway's namespace. This will define policy at the listener level. -- To reduce context sharing at the gateway and external authorization provider, action type and auth-provider are defaulted to `CUSTOM` and authorino respectively. - -## Proposed Solution -Following is the proposed new CRD that combines policy attachment concepts with Istio's AuthorizationPolicy: - -```yaml -apiVersion: kuadrant.io/v1beta1 -kind: AuthPolicy -metadata: - name: toystore -spec: - targetRef: - group: # Only takes gateway.networking.k8s.io - kind: HTTPRoute | Gateway - name: toystore - rules: - - hosts: ["*.toystore.com"] - methods: ["GET", "POST"] - paths: ["/admin"] - authScheme: # Embedded AuthConfigs - hosts: ["admin.toystore.com"] - identity: - - name: idp-users - oidc: - endpoint: https://my-idp.com/auth/realm - authorization: - - name: check-claim - json: - rules: - - selector: auth.identity.group - operator: eq - value: allowed-users -status: - conditions: - - lastTransitionTime: "2022-06-06T11:03:04Z" - message: HTTPRoute/Gateway is protected/Error - reason: HTTPRouteProtected/GatewayProtected/Error - status: "True" | "False" - type: Available - observedGeneration: 1 -``` - -### Target Reference -`targetRef` field is taken from [policy attachment's target reference API](https://gateway-api.sigs.k8s.io/v1alpha2/references/policy-attachment/#target-reference-api). It can only target one resource at a time. Fields included inside: -- `Group` is the group of the target resource. Only valid option is `gateway.networking.k8s.io`. -- `Kind` is kind of the target resource. Only valid options are `HTTPRoute` and `Gateway`. -- `Name` is the name of the target resource. -- `Namespace` is the namespace of the referent. Currently only local objects can be referred so value is ignored. - -### Rule objects -`rules` field describe the requests that will be routed to external authorization provider (like authorino). It includes: -- `hosts`: a host is matched over `Host` request header or `SNI` if TLS is used. - -**Note**: Each rule's host in a route level policy must match at least one hostname regex described in [HTTPRoute's `hostnames`](https://gateway-api.sigs.k8s.io/v1alpha2/references/spec/#gateway.networking.k8s.io/v1alpha2.Hostname) but Gateway level policies have no such restriction. -``` - targetRef - HTTPRoute ◄───────────────────────── AuthPolicy - hostnames: ["*.toystore.com"] rules: - ┌────────────────────────────┐ - Rejected Rule: │- hosts: ["*.carstore.com"] │ - Regex mismatch │ methods: ["GET", "DELETE"]│ - └────────────────────────────┘ - - ┌───────────────────────────────┐ - Accepted Rule: │- hosts: ["admin.toystore.com"]│ - Regex match │ methods: ["POST", "DELETE"] │ - └───────────────────────────────┘ -``` - -- `paths`: a path matches over request path like `/admin/`. -- `methods`: a method matches over request method like `DELETE`. - -Fields in a rule object are ANDed together but inner fields follow OR semantics. For example, -```yaml -hosts: ["*.toystore.com"] -methods: ["GET", "POST"] -paths: ["/admin"] -``` -The above rule matches if the host matches`*.toystore.com` AND the method is `POST` OR `GET`; AND path is `/admin` - -Internally, All the rules in a AuthPolicy are translated into list of [`Operations`](https://istio.io/latest/docs/reference/config/security/authorization-policy/#Operation) under a single [Istio's AuthorizationPolicy](https://istio.io/latest/docs/reference/config/security/authorization-policy/) with CUSTOM [action](https://istio.io/latest/docs/reference/config/security/authorization-policy/#AuthorizationPolicy-Action) type and [external authorization provider](https://istio.io/latest/docs/reference/config/security/authorization-policy/#AuthorizationPolicy-ExtensionProvider) as authorino. - -### AuthScheme object -AuthScheme is embedded form of [Authorino's AuthConfig](https://github.com/Kuadrant/authorino/blob/main/docs/architecture.md#the-authorino-authconfig-custom-resource-definition-crd). Applying an AuthPolicy resource with AuthScheme defined, would create an AuthConfig in the Gateway's namespace. - -**Note**: Following the heirarchial constraints, `spec.AuthScheme.Hosts` must match at least one `spec.Hosts` for AuthPolicy to be validated. - -The example AuthPolicy showed above will create the following AuthConfig: - -```yaml -apiVersion: authorino.kuadrant.io/v1beta1 -kind: AuthConfig -metadata: - name: default-toystore-1 -spec: - hosts: - - "admin.toystore.com" - identity: - - name: idp-users - oidc: - endpoint: https://my-idp.com/auth/realm - authorization: - - name: check-claim - json: - rules: - - selector: auth.identity.group - operator: eq - value: allowed-users -``` - -Overall control structure looks like the following between the developer and the kuadrant operator: -![](images/authpolicy-control-structure.png) - -## Checklist -- Issue tracking this proposal: https://github.com/Kuadrant/kuadrant-operator/issues/130 diff --git a/doc/rate-limiting.md b/doc/rate-limiting.md index 6cb90b689..b096ca083 100644 --- a/doc/rate-limiting.md +++ b/doc/rate-limiting.md @@ -2,10 +2,10 @@ A Kuadrant RateLimitPolicy custom resource, often abbreviated "RLP": -1. Allows it to target Gateway API networking resources such as [HTTPRoutes](https://gateway-api.sigs.k8s.io/references/spec/#gateway.networking.k8s.io/v1beta1.HTTPRoute) and [Gateways](https://gateway-api.sigs.k8s.io/references/spec/#gateway.networking.k8s.io/v1beta1.Gateway), using these resources to obtain additional context, i.e., which traffic workload (HTTP attributes, hostnames, user attributes, etc) to rate limit. -2. Allows to specify which specific subsets of the targeted network resource to apply the limits to. +1. Targets Gateway API networking resources such as [HTTPRoutes](https://gateway-api.sigs.k8s.io/references/spec/#gateway.networking.k8s.io/v1beta1.HTTPRoute) and [Gateways](https://gateway-api.sigs.k8s.io/references/spec/#gateway.networking.k8s.io/v1beta1.Gateway), using these resources to obtain additional context, i.e., which traffic workload (HTTP attributes, hostnames, user attributes, etc) to rate limit. +2. Supports targeting subsets (sections) of a network resource resource to apply the limits to. 3. Abstracts the details of the underlying Rate Limit protocol and configuration resources, that have a much broader remit and surface area. -4. Supports cluster operators to set overrides (soon) and defaults that govern what can be done at the lower levels. +4. Enables cluster operators to set defaults that govern behavior at the lower levels of the network, until a more specific policy is applied. ## How it works @@ -88,7 +88,7 @@ spec: When a RLP targets a HTTPRoute, the policy is enforced to all traffic routed according to the rules and hostnames specified in the HTTPRoute, across all Gateways referenced in the `spec.parentRefs` field of the HTTPRoute. -The targeted HTTPRoute's rules and/or hostnames to which the policy must be enforced can be filtered to specific subsets, by specifying the `routeSelectors` field of the limit definition. +The targeted HTTPRoute's rules and/or hostnames to which the policy must be enforced can be filtered to specific subsets, by specifying the [`routeSelectors`](reference/route-selectors.md#the-routeselectors-field) field of the limit definition. Target a HTTPRoute by setting the `spec.targetRef` field of the RLP as follows: @@ -172,7 +172,7 @@ Expected behavior: ### Limit definition A limit will be activated whenever a request comes in and the request matches: -- any of the route rules selected by the limit (via `routeSelectors` or implicit "catch-all" selector), and +- any of the route rules selected by the limit (via [`routeSelectors`](reference/route-selectors.md#the-routeselectors-field) or implicit "catch-all" selector), and - all of the `when` conditions specified in the limit. A limit can define: @@ -226,36 +226,19 @@ spec: | `admin.toystore.com` | 250rps | | `other.toystore.com` | 5000rps | -#### Route selectors +### Route selectors -The `routeSelectors` field of the limit definition allows to specify **selectors of routes** (or parts of a route), that _transitively induce a set of conditions for a limit to be enforced_. It is defined as a set of route matching rules, where these rules must exist, partially or identically stated within the HTTPRouteRules of the HTTPRoute that is targeted by the RLP. +Route selectors allow targeting sections of a HTTPRoute, by specifying sets of HTTPRouteMatches and/or hostnames that make the policy controller look up within the HTTPRoute spec for compatible declarations, and select the corresponding HTTPRouteRules and hostnames, to then build conditions that activate the policy or policy rule. -The field is typed as a list of objects based on a special type defined from Gateway API's [HTTPRouteMatch](https://gateway-api.sigs.k8s.io/references/spec/#gateway.networking.k8s.io/v1beta1.HTTPPathMatch) type (`matches` subfield of the route selector object), and an additional field `hostnames`. - -Route selectors matches and the HTTPRoute's HTTPRouteMatches are pairwise compared to select or not select HTTPRouteRules that should activate a limit. To decide whether the route selector selects a HTTPRouteRule or not, for each pair of route selector HTTPRouteMatch and HTTPRoute HTTPRouteMatch: -1. The route selector selects the HTTPRoute's HTTPRouteRule if the HTTPRouteRule contains at least one HTTPRouteMatch that specifies fields that are literally identical to all the fields specified by at least one HTTPRouteMatch of the route selector. -2. A HTTPRouteMatch within a HTTPRouteRule may include other fields that are not specified in a route selector match, and yet the route selector match selects the HTTPRouteRule if all fields of the route selector match are identically included in the HTTPRouteRule's HTTPRouteMatch; the opposite is NOT true. -3. Each field `path` of a HTTPRouteMatch, as well as each field `method` of a HTTPRouteMatch, as well as each element of the fields `headers` and `queryParams` of a HTTPRouteMatch, is atomic – this is true for the HTTPRouteMatches within a HTTPRouteRule, as well as for HTTPRouteMatches of a route selector. - -Additionally, at least one hostname specified in a route selector must identically match one of the hostnames specified (or inherited, when omitted) by the targeted HTTPRoute. - -The semantics of the route selectors allows to assertively relate limit definitions to routing rules, with benefits for identifying the subsets of the network that are covered by a limit, while preventing unreachable definitions, as well as the overhead associated with the maintenance of such rules across multiple resources throughout time, according to network topology beneath. Moreover, the requirement of not having to be a full copy of the targeted HTTPRouteRule matches, but only partially identical, helps prevent repetition to some degree, as well as it enables to more easily define limits that scope across multiple HTTPRouteRules (by specifying less rules in the selector). - -A few rules and corner cases to keep in mind while using the RLP's `routeSelectors`: -1. **The golden rule –** The route selectors in a RLP are **not** to be read strictly as the route matching rules that activate a limit, but as selectors of the route rules that activate the limit. -2. Due to (1) above, this can lead to cases, e.g., where a route selector that states `matches: [{ method: POST }]` selects a HTTPRouteRule that defines `matches: [{ method: POST }, { method: GET }]`, effectively causing the limit to be activated on requests to the HTTP method `POST`, but **also** to the HTTP method `GET`. -3. The requirement for the route selector match to state patterns that are identical to the patterns stated by the HTTPRouteRule (partially or entirely) makes, e.g., a route selector such as `matches: { path: { type: PathPrefix, value: /foo } }` to select a HTTPRouteRule that defines `matches: { path: { type: PathPrefix, value: /foo }, method: GET }`, but **not** to select a HTTPRouteRule that only defines `matches: { method: GET }`, even though the latter includes technically all HTTP paths; **nor** it selects a HTTPRouteRule that only defines `matches: { path: { type: Exact, value: /foo } }`, even though all requests to the exact path `/foo` are also technically requests to `/foo*`. -4. The atomicity property of fields of the route selectors makes, e.g., a route selector such as `matches: { path: { value: /foo } }` to select a HTTPRouteRule that defines `matches: { path: { value: /foo } }`, but **not** to select a HTTPRouteRule that only defines `matches: { path: { type: PathPrefix, value: /foo } }`. (This case may actually never happen because `PathPrefix` is the default value for `path.type` and will be set automatically by the Kubernetes API server.) - -Due to the nature of route selectors of defining pointers to HTTPRouteRules, the `routeSelectors` field is not supported in a RLP that targets a Gateway resource. +Check out [Route selectors](reference/route-selectors.md) for a full description, semantics and API reference. #### `when` conditions -`when` conditions can be used to scope a limit (i.e. to filter the traffic to which a limit definition applies) without any coupling to the underlying network topology, i.e. without making direct references to HTTPRouteRules via `routeSelectors`. +`when` conditions can be used to scope a limit (i.e. to filter the traffic to which a limit definition applies) without any coupling to the underlying network topology, i.e. without making direct references to HTTPRouteRules via [`routeSelectors`](reference/route-selectors.md#the-routeselectors-field). -The syntax of the `when` conditions selectors comply with Kuadrant's [Well-known Attributes (RFC 0002)](https://github.com/Kuadrant/architecture/blob/main/rfcs/0002-well-known-attributes.md). +Use `when` conditions to conditionally activate limits based on attributes that cannot be expressed in the HTTPRoutes' `spec.hostnames` and `spec.rules.matches` fields, or in general in RLPs that target a Gateway. -Use the `when` conditions to conditionally activate limits based on attributes that cannot be expressed in the HTTPRoutes' `spec.hostnames` and `spec.rules.matches` fields, or in general in RLPs that target a Gateway. +The selectors within the `when` conditions of a RateLimitPolicy are a subset of Kuadrant's Well-known Attributes ([RFC 0002](https://github.com/Kuadrant/architecture/blob/main/rfcs/0002-well-known-attributes.md)). Check out the reference for the full list of supported selectors. ### Examples diff --git a/doc/reference/authpolicy.md b/doc/reference/authpolicy.md new file mode 100644 index 000000000..5dbe273b4 --- /dev/null +++ b/doc/reference/authpolicy.md @@ -0,0 +1,151 @@ +# The AuthPolicy Custom Resource Definition (CRD) + +- [AuthPolicy](#authpolicy) +- [AuthPolicySpec](#authpolicyspec) + - [AuthScheme](#authscheme) + - [AuthRuleCommon](#authrulecommon) + - [AuthenticationRule](#authenticationrule) + - [MetadataRule](#metadatarule) + - [AuthorizationRule](#authorizationrule) + - [ResponseSpec](#responsespec) + - [SuccessResponseSpec](#successresponsespec) + - [SuccessResponseItem](#successresponseitem) + - [CallbackRule](#callbackrule) + - [NamedPattern](#namedpattern) +- [AuthPolicyStatus](#authpolicystatus) + - [ConditionSpec](#conditionspec) + +## AuthPolicy + +| **Field** | **Type** | **Required** | **Description** | +|-----------|---------------------------------------|:------------:|-------------------------------------------------| +| `spec` | [AuthPolicySpec](#authpolicyspec) | Yes | The specfication for AuthPolicy custom resource | +| `status` | [AuthPolicyStatus](#authpolicystatus) | No | The status for the custom resource | + +## AuthPolicySpec + +| **Field** | **Type** | **Required** | **Description** | +|------------------|---------------------------------------------------------------------------------------------------------------------------------------------|--------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `targetRef` | [PolicyTargetReference](https://gateway-api.sigs.k8s.io/v1alpha2/references/spec/#gateway.networking.k8s.io/v1alpha2.PolicyTargetReference) | Yes | Reference to a Kuberentes resource that the policy attaches to | +| `rules` | [AuthScheme](#authscheme) | No | Authentication/authorization rules | +| `routeSelectors` | [][RouteSelector](route-selectors.md#routeselector) | No | List of selectors of HTTPRouteRules whose matching rules activate the policy. At least one HTTPRouteRule must be selected to activate the policy. If omitted, all HTTPRouteRules of the targeted HTTPRoute activate the policy. Do not use it in policies targeting a Gateway. | +| `patterns` | Map | No | Named patterns of lists of `selector`, `operator` and `value` tuples, to be reused in `when` conditions and pattern-matching authorization rules. | +| `when` | [][PatternExpressionOrRef](https://docs.kuadrant.io/authorino/docs/features/#common-feature-conditions-when) | No | List of additional dynamic conditions (expressions) to activate the policy. Use it for filterring attributes that cannot be expressed in the targeted HTTPRoute's `spec.hostnames` and `spec.rules.matches` fields, or when targeting a Gateway. | + +### AuthScheme + +| **Field** | **Type** | **Required** | **Description** | +|------------------|--------------------------------------------------------|:------------:|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `authentication` | Map | No | Authentication rules. At least one config MUST evaluate to a valid identity object for the auth request to be successful. If omitted or empty, anonymous access is assumed. | +| `metadata` | Map | No | Rules for fetching auth metadata from external sources. | +| `authorization` | Map | No | Authorization rules. All policies MUST allow access for the auth request be successful. | +| `response` | [ResponseSpec](#responsespec) | No | Customizations to the response to the authorization request. Use it to set custom values for unauthenticated, unauthorized, and/or success access request. | +| `callbacks` | Map | No | Rules for post-authorization callback requests to external services. Triggered regardless of the result of the authorization request. | + +#### AuthRuleCommon + +| **Field** | **Type** | **Required** | **Description** | +|-------------------------|--------------------------------------------------------------------------------------------------------------|:------------:|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `routeSelectors` | [][RouteSelector](route-selectors.md#routeselector) | No | List of selectors of HTTPRouteRules whose matching rules activate the auth rule. At least one HTTPRouteRule must be selected to activate the auth rule. If omitted, the auth rule is activated at all requests where the policy is enforced. Do not use it in policies targeting a Gateway. | +| `when` | [][PatternExpressionOrRef](https://docs.kuadrant.io/authorino/docs/features/#common-feature-conditions-when) | No | List of additional dynamic conditions (expressions) to activate the auth rule. Use it for filterring attributes that cannot be expressed in the targeted HTTPRoute's `spec.hostnames` and `spec.rules.matches` fields, or when targeting a Gateway. | +| `cache` | [Caching spec](https://docs.kuadrant.io/authorino/docs/features/#common-feature-caching-cache) | No | Caching options for the resolved object returned when applying this auth rule. (Default: disabled) | +| `priority` | Integer | No | Priority group of the auth rule. All rules in the same priority group are evaluated concurrently; consecutive priority groups are evaluated sequentially. (Default: `0`) | +| `metrics` | Boolean | No | Whether the auth rule emits individual observability metrics. (Default: `false`) | + +#### AuthenticationRule + +| **Field** | **Type** | **Required** | **Description** | +|-------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------|:------------:|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `apiKey` | [API Key authentication spec](https://docs.kuadrant.io/authorino/docs/features/#api-key-authenticationapikey) | No | Authentication based on API keys stored in Kubernetes secrets. Use one of: `apiKey`, `jwt`, `oauth2Introspection`, `kubernetesTokenReview`, `x509`, `plain`, `anonymous`. | +| `kubernetesTokenReview` | [KubernetesTokenReview spec](https://docs.kuadrant.io/authorino/docs/features/#kubernetes-tokenreview-authenticationkubernetestokenreview) | No | Authentication by Kubernetes token review. Use one of: `apiKey`, `jwt`, `oauth2Introspection`, `kubernetesTokenReview`, `x509`, `plain`, `anonymous`. | +| `jwt` | [JWT verification spec](https://docs.kuadrant.io/authorino/docs/features/#jwt-verification-authenticationjwt) | No | Authentication based on JSON Web Tokens (JWT). Use one of: `apiKey`, `jwt`, `oauth2Introspection`, `kubernetesTokenReview`, `x509`, `plain`, `anonymous`. | +| `oauth2Introspection` | [OAuth2 Token Introscpection spec](https://docs.kuadrant.io/authorino/docs/features/#oauth-20-introspection-authenticationoauth2introspection) | No | Authentication by OAuth2 token introspection. Use one of: `apiKey`, `jwt`, `oauth2Introspection`, `kubernetesTokenReview`, `x509`, `plain`, `anonymous`. | +| `x509` | [X.509 authentication spec](https://docs.kuadrant.io/authorino/docs/features/#x509-client-certificate-authentication-authenticationx509) | No | Authentication based on client X.509 certificates. The certificates presented by the clients must be signed by a trusted CA whose certificates are stored in Kubernetes secrets. Use one of: `apiKey`, `jwt`, `oauth2Introspection`, `kubernetesTokenReview`, `x509`, `plain`, `anonymous`. | +| `plain` | [Plain identity object spec](https://docs.kuadrant.io/authorino/docs/features/#plain-authenticationplain) | No | Identity object extracted from the context. Use this method when authentication is performed beforehand by a proxy and the resulting object passed to Authorino as JSON in the auth request. Use one of: `apiKey`, `jwt`, `oauth2Introspection`, `kubernetesTokenReview`, `x509`, `plain`, `anonymous`. | +| `anonymous` | [Anonymous access](https://docs.kuadrant.io/authorino/docs/features/#anonymous-access-authenticationanonymous) | No | Anonymous access. Use one of: `apiKey`, `jwt`, `oauth2Introspection`, `kubernetesTokenReview`, `x509`, `plain`, `anonymous`. | +| `credentials` | [Auth credentials spec](https://docs.kuadrant.io/authorino/docs/features/#extra-auth-credentials-authenticationcredentials) | No | Customizations to where credentials are required to be passed in the request for authentication based on this auth rule. Defaults to HTTP Authorization header with prefix "Bearer". | +| `overrides` | [Identity extension spec](https://docs.kuadrant.io/authorino/docs/features/#extra-identity-extension-authenticationdefaults-and-authenticationoverrides) | No | JSON overrides to set to the resolved identity object. Do not use it with identity objects of other JSON types (array, string, etc). | +| `defaults` | [Identity extension spec](https://docs.kuadrant.io/authorino/docs/features/#extra-identity-extension-authenticationdefaults-and-authenticationoverrides) | No | JSON defaults to set to the resolved identity object. Do not use it with identity objects of other JSON types (array, string, etc). | +| _(inline)_ | [AuthRuleCommon](#authrulecommon) | No | | + +#### MetadataRule + +| **Field** | **Type** | **Required** | **Description** | +|-------------|-----------------------------------------------------------------------------------------------------------------------------------|:------------:|-----------------------------------------------------------------------------------------------------------------------------------------| +| `http` | [HTTP GET/GET-by-POST external metadata spec](https://docs.kuadrant.io/authorino/docs/features/#http-getget-by-post-metadatahttp) | No | External source of auth metadata via HTTP request. Use one of: `http`, `userInfo`, `uma`. | +| `userInfo` | [OIDC UserInfo spec](https://docs.kuadrant.io/authorino/docs/features/#oidc-userinfo-metadatauserinfo) | No | OpendID Connect UserInfo linked to an OIDC authentication rule declared in this same AuthPolicy. Use one of: `http`, `userInfo`, `uma`. | +| `uma` | [UMA metadata spec](https://docs.kuadrant.io/authorino/docs/features/#user-managed-access-uma-resource-registry-metadatauma) | No | User-Managed Access (UMA) source of resource data. Use one of: `http`, `userInfo`, `uma`. | +| _(inline)_ | [AuthRuleCommon](#authrulecommon) | No | | + +#### AuthorizationRule + +| **Field** | **Type** | **Required** | **Description** | +|---------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------|:------------:|--------------------------------------------------------------------------------------------------------------------------------------------------------| +| `patternMatching` | [Pattern-matching authorization spec](https://docs.kuadrant.io/authorino/docs/features/#pattern-matching-authorization-authorizationpatternmatching) | No | Pattern-matching authorization rules. Use one of: `patternMatching`, `opa`, `kubernetesSubjectAccessReview`, `spicedb`. | +| `opa` | [OPA authorization spec](https://docs.kuadrant.io/authorino/docs/features/#open-policy-agent-opa-rego-policies-authorizationopa) | No | Open Policy Agent (OPA) Rego policy. Use one of: `patternMatching`, `opa`, `kubernetesSubjectAccessReview`, `spicedb`. | +| `kubernetesSubjectAccessReview` | [Kubernetes SubjectAccessReview spec](https://docs.kuadrant.io/authorino/docs/features/#kubernetes-subjectaccessreview-authorizationkubernetessubjectaccessreview) | No | Authorization by Kubernetes SubjectAccessReview. Use one of: `patternMatching`, `opa`, `kubernetesSubjectAccessReview`, `spicedb`. | +| `spicedb` | [SpiceDB authorization spec](https://docs.kuadrant.io/authorino/docs/features/#spicedb-authorizationspicedb) | No | Authorization decision delegated to external Authzed/SpiceDB server. Use one of: `patternMatching`, `opa`, `kubernetesSubjectAccessReview`, `spicedb`. | +| _(inline)_ | [AuthRuleCommon](#authrulecommon) | No | | + +#### ResponseSpec + +| **Field** | **Type** | **Required** | **Description** | +|-------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------|:------------:|------------------------------------------------------------------------------------------------------------------------------------| +| `unauthenticated` | [Custom denial status spec](https://docs.kuadrant.io/authorino/docs/features/#custom-denial-status-responseunauthenticated-and-responseunauthorized) | No | Customizations on the denial status and other HTTP attributes when the request is unauthenticated. (Default: `401 Unauthorized`) | +| `unauthorized` | [Custom denial status spec](https://docs.kuadrant.io/authorino/docs/features/#custom-denial-status-responseunauthenticated-and-responseunauthorized) | No | Customizations on the denial status and other HTTP attributes when the request is unauthorized. (Default: `403 Forbidden`) | +| `success` | [SuccessResponseSpec](#successresponsespec) | No | Response items to be included in the auth response when the request is authenticated and authorized. | + +##### SuccessResponseSpec + +| **Field** | **Type** | **Required** | **Description** | +|-------------------|----------------------------------------------------------|:------------:|---------------------------------------------------------------------------------------------------------------------------------------------------| +| `headers` | Map | No | Custom success response items wrapped as HTTP headers to be injected in the request. | +| `dynamicMetadata` | Map | No | Custom success response items wrapped as Envoy Dynamic Metadata. Use it to pass data along to other proxy filters, such as the rate-limit filter. | + +###### SuccessResponseItem + +| **Field** | **Type** | **Required** | **Description** | +|-------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------|:------------:|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `plain` | [Plain text response item](https://docs.kuadrant.io/authorino/docs/features/#plain-text-responsesuccessheadersdynamicmetadataplain) | No | Plain text content. Use one of: `plain`, `json`, `wristband`. | +| `json` | [JSON injection response item](https://docs.kuadrant.io/authorino/docs/features/#json-injection-responsesuccessheadersdynamicmetadatajson) | No | Specification of a JSON object. Use one of: `plain`, `json`, `wristband`. | +| `wristband` | [Festival Wristband token response item](https://docs.kuadrant.io/authorino/docs/features/#festival-wristband-tokens-responsesuccessheadersdynamicmetadatawristband) | No | Specification of a JSON object. Use one of: `plain`, `json`, `wristband`. | +| `key` | String | No | The key used to add the custom response item (name of the HTTP header or root property of the Dynamic Metadata object). Defaults to the name of the response item if omitted. | + +#### CallbackRule + +| **Field** | **Type** | **Required** | **Description** | +|------------------|----------------------------------------------------------------------------------------------------------------|:------------:|-----------------------------------------------------------------| +| `http` | [HTTP endpoints callback spec](https://docs.kuadrant.io/authorino/docs/features/#http-endpoints-callbackshttp) | No | HTTP endpoint settings to build the callback request (webhook). | +| _(inline)_ | [AuthRuleCommon](#authrulecommon) | No | | + +### NamedPattern + +| **Field** | **Type** | **Required** | **Description** | +|------------|----------|:------------:|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `selector` | String | Yes | A valid [Well-known attribute](https://github.com/Kuadrant/architecture/blob/main/rfcs/0002-well-known-attributes.md) whose resolved value in the data plane will be compared to `value`, using the `operator`. | +| `operator` | String | Yes | The binary operator to be applied to the resolved value specified by the selector. One of: `eq` (equal to), `neq` (not equal to), `incl` (includes; for arrays), `excl` (excludes; for arrays), `matches` (regex). | +| `value` | String | Yes | The static value to be compared to the one resolved from the selector. | + +## AuthPolicyStatus + +| **Field** | **Type** | **Description** | +|----------------------|-----------------------------------|-------------------------------------------------------------------------------------------------------------------------------------| +| `observedGeneration` | String | Number of the last observed generation of the resource. Use it to check if the status info is up to date with latest resource spec. | +| `conditions` | [][ConditionSpec](#conditionspec) | List of conditions that define that status of the resource. | + +### ConditionSpec + +* The *lastTransitionTime* field provides a timestamp for when the entity last transitioned from one status to another. +* The *message* field is a human-readable message indicating details about the transition. +* The *reason* field is a unique, one-word, CamelCase reason for the condition’s last transition. +* The *status* field is a string, with possible values **True**, **False**, and **Unknown**. +* The *type* field is a string with the following possible values: + * Available: the resource has successfully configured; + +| **Field** | **Type** | **Description** | +|----------------------|-----------|------------------------------| +| `type` | String | Condition Type | +| `status` | String | Status: True, False, Unknown | +| `reason` | String | Condition state reason | +| `message` | String | Condition state description | +| `lastTransitionTime` | Timestamp | Last transition timestamp | diff --git a/doc/ratelimitpolicy-reference.md b/doc/reference/ratelimitpolicy.md similarity index 70% rename from doc/ratelimitpolicy-reference.md rename to doc/reference/ratelimitpolicy.md index e5ee83ebc..435f344f3 100644 --- a/doc/ratelimitpolicy-reference.md +++ b/doc/reference/ratelimitpolicy.md @@ -4,7 +4,6 @@ - [RateLimitPolicySpec](#ratelimitpolicyspec) - [Limit](#limit) - [RateLimit](#ratelimit) - - [RouteSelector](#routeselector) - [WhenCondition](#whencondition) - [RateLimitPolicyStatus](#ratelimitpolicystatus) - [ConditionSpec](#conditionspec) @@ -25,12 +24,12 @@ ### Limit -| **Field** | **Type** | **Required** | **Description** | -|------------------|-----------------------------------|:------------:|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| `rates` | [][RateLimit](#ratelimit) | No | List of rate limits associated with the limit definition | -| `counters` | []String | No | List of rate limit counter qualifiers. Items must be a valid [Well-known attribute](https://github.com/Kuadrant/architecture/blob/main/rfcs/0002-well-known-attributes.md). Each distinct value resolved in the data plane starts a separate counter for each rate limit. | -| `routeSelectors` | [][RouteSelector](#routeselector) | No | List of selectors of HTTPRouteRules whose matching rules activate the limit. At least one HTTPRouteRule must be selected to activate the limit. If omitted, all HTTPRouteRules of the targeted HTTPRoute activate the limit. Do not use it in policies targeting a Gateway. | -| `when` | [][WhenCondition](#whencondition) | No | List of additional dynamic conditions (expressions) to activate the limit. All expression must evaluate to true for the limit to be applied. Use it for filterring attributes that cannot be expressed in the targeted HTTPRoute's `spec.hostnames` and `spec.rules.matches` fields, or when targeting a Gateway. | +| **Field** | **Type** | **Required** | **Description** | +|------------------|-----------------------------------------------------|:------------:|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `rates` | [][RateLimit](#ratelimit) | No | List of rate limits associated with the limit definition | +| `counters` | []String | No | List of rate limit counter qualifiers. Items must be a valid [Well-known attribute](https://github.com/Kuadrant/architecture/blob/main/rfcs/0002-well-known-attributes.md). Each distinct value resolved in the data plane starts a separate counter for each rate limit. | +| `routeSelectors` | [][RouteSelector](route-selectors.md#routeselector) | No | List of selectors of HTTPRouteRules whose matching rules activate the limit. At least one HTTPRouteRule must be selected to activate the limit. If omitted, all HTTPRouteRules of the targeted HTTPRoute activate the limit. Do not use it in policies targeting a Gateway. | +| `when` | [][WhenCondition](#whencondition) | No | List of additional dynamic conditions (expressions) to activate the limit. All expression must evaluate to true for the limit to be applied. Use it for filterring attributes that cannot be expressed in the targeted HTTPRoute's `spec.hostnames` and `spec.rules.matches` fields, or when targeting a Gateway. | #### RateLimit @@ -40,15 +39,6 @@ | `duration` | Number | Yes | The period of time in the specified unit that the limit applies | | `unit` | String | Yes | Unit of time for the duration of the limit. One-of: "second", "minute", "hour", "day". | -#### RouteSelector - -| **Field** | **Type** | **Required** | **Description** | -|-------------|--------------------------------------------------------------------------------------------------------------------------------|:------------:|-----------------------------------------------------------------------------| -| `hostnames` | [][Hostname](https://gateway-api.sigs.k8s.io/v1alpha2/references/spec/#gateway.networking.k8s.io/v1beta1.Hostname) | No | List of hostnames of the HTTPRoute that activate the limit | -| `matches` | [][HTTPRouteMatch](https://gateway-api.sigs.k8s.io/v1alpha2/references/spec/#gateway.networking.k8s.io/v1beta1.HTTPRouteMatch) | No | List of selectors of HTTPRouteRules whose matching rules activate the limit | - -Check out _Kuadrant Rate Limiting > [Route selectors](rate-limiting.md#route-selectors)_ for the semantics of how route selectors work. - #### WhenCondition | **Field** | **Type** | **Required** | **Description** | diff --git a/doc/reference/route-selectors.md b/doc/reference/route-selectors.md new file mode 100644 index 000000000..45f499611 --- /dev/null +++ b/doc/reference/route-selectors.md @@ -0,0 +1,41 @@ +# Route selectors + +The route selectors of a policy spec or policy rule (limit definition or auth rule) allow to specify **selectors of routes** or parts of a route, that _transitively induce a set of conditions for a policy or policy rule to be enforced_. It is defined as a set of HTTP route matching rules, where these matching rules must exist, partially or identically stated within the HTTPRouteRules of the HTTPRoute that is targeted by the policy. + +## The `routeSelectors` field + +The `routeSelectors` field can be found in policy specs and policy rules (limit definition or auth rule). + +| **Field** | **Type** | **Required** | **Description** | +|------------------|-----------------------------------|:------------:|------------------------------------------------------------------------------------------------------| +| `routeSelectors` | [][RouteSelector](#routeselector) | No | List of route selectors of HTTPRouteRules whose HTTPRouteMatches activate the policy or policy rule. | + +### RouteSelector + +Each `RouteSelector` is an object composed of a set of [HTTPRouteMatch](https://gateway-api.sigs.k8s.io/references/spec/#gateway.networking.k8s.io/v1beta1.HTTPPathMatch) objects (from Gateway API), and an additional `hostnames` field. + +| **Field** | **Type** | **Required** | **Description** | +|-------------|--------------------------------------------------------------------------------------------------------------------------------|:------------:|---------------------------------------------------------------------------------------------| +| `matches` | [][HTTPRouteMatch](https://gateway-api.sigs.k8s.io/v1alpha2/references/spec/#gateway.networking.k8s.io/v1beta1.HTTPRouteMatch) | No | List of selectors of HTTPRouteRules whose matching rules activate the policy or policy rule | +| `hostnames` | [][Hostname](https://gateway-api.sigs.k8s.io/v1alpha2/references/spec/#gateway.networking.k8s.io/v1beta1.Hostname) | No | List of hostnames of the HTTPRoute that activate the policy or policy rule | + +## Mechanics of the route selectors + +Route selectors matches and the HTTPRoute's HTTPRouteMatches are pairwise compared to select or not select HTTPRouteRules that should activate a policy rule. To decide whether the route selector selects a HTTPRouteRule or not, for each pair of route selector HTTPRouteMatch and HTTPRoute HTTPRouteMatch: +1. The route selector selects the HTTPRoute's HTTPRouteRule if the HTTPRouteRule contains at least one HTTPRouteMatch that specifies fields that are literally identical to all the fields specified by at least one HTTPRouteMatch of the route selector. +2. A HTTPRouteMatch within a HTTPRouteRule may include other fields that are not specified in a route selector match, and yet the route selector match selects the HTTPRouteRule if all fields of the route selector match are identically included in the HTTPRouteRule's HTTPRouteMatch; the opposite is NOT true. +3. Each field `path` of a HTTPRouteMatch, as well as each field `method` of a HTTPRouteMatch, as well as each element of the fields `headers` and `queryParams` of a HTTPRouteMatch, is atomic – this is true for the HTTPRouteMatches within a HTTPRouteRule, as well as for HTTPRouteMatches of a route selector. + +Additionally, at least one hostname specified in a route selector must identically match one of the hostnames specified (or inherited, when omitted) by the targeted HTTPRoute. + +The semantics of the route selectors allows to assertively relate policy rule definitions to routing rules, with benefits for identifying the subsets of the network that are covered by a policy rule, while preventing unreachable definitions, as well as the overhead associated with the maintenance of such rules across multiple resources throughout time, according to network topology beneath. Moreover, the requirement of not having to be a full copy of the targeted HTTPRouteRule matches, but only partially identical, helps prevent repetition to some degree, as well as it enables to more easily define policy rules that scope across multiple HTTPRouteRules (by specifying less rules in the selector). + +## Golden rules and corner cases + +A few rules and corner cases to keep in mind while using the RLP's `routeSelectors`: +1. **The golden rule –** The route selectors in a policy or policy rule are **not** to be interpreted as the route matching rules that activate the policy or policy rule, but as **selectors of the route rules** that activate the policy or policy rule. +2. Due to (1) above, this can lead to cases, e.g., where a route selector that states `matches: [{ method: POST }]` selects a HTTPRouteRule that defines `matches: [{ method: POST }, { method: GET }]`, effectively causing the policy or policy rule to be activated on requests to the HTTP method `POST`, but **also** to the HTTP method `GET`. +3. The requirement for the route selector match to state patterns that are identical to the patterns stated by the HTTPRouteRule (partially or entirely) makes, e.g., a route selector such as `matches: { path: { type: PathPrefix, value: /foo } }` to select a HTTPRouteRule that defines `matches: { path: { type: PathPrefix, value: /foo }, method: GET }`, but **not** to select a HTTPRouteRule that only defines `matches: { method: GET }`, even though the latter includes technically all HTTP paths; **nor** it selects a HTTPRouteRule that only defines `matches: { path: { type: Exact, value: /foo } }`, even though all requests to the exact path `/foo` are also technically requests to `/foo*`. +4. The atomicity property of fields of the route selectors makes, e.g., a route selector such as `matches: { path: { value: /foo } }` to select a HTTPRouteRule that defines `matches: { path: { value: /foo } }`, but **not** to select a HTTPRouteRule that only defines `matches: { path: { type: PathPrefix, value: /foo } }`. (This case may actually never happen because `PathPrefix` is the default value for `path.type` and will be set automatically by the Kubernetes API server.) + +Due to the nature of route selectors of defining pointers to HTTPRouteRules, the `routeSelectors` field is not supported in a RLP that targets a Gateway resource. diff --git a/doc/user-guides/auth-for-app-devs-and-platform-engineers.md b/doc/user-guides/auth-for-app-devs-and-platform-engineers.md new file mode 100644 index 000000000..4e1b13551 --- /dev/null +++ b/doc/user-guides/auth-for-app-devs-and-platform-engineers.md @@ -0,0 +1,285 @@ +# Enforcing authentication & authorization with Kuadrant AuthPolicy + +This guide walks you through the process of setting up a local Kubernetes cluster with Kuadrant where you will protect [Gateway API](gateway-api.sigs.k8s.io/) endpoints by declaring Kuadrant AuthPolicy custom resources. + +Two AuthPolicies will be declared: + +| Use case | AuthPolicy | +|--------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| **App developer** | 1 AuthPolicy targeting a HTTPRoute that routes traffic to a sample Toy Store application, and enforces API key authentication to all requests in this route, as well as requires API key owners to be mapped to `groups:admins` metadata to access a specific HTTPRouteRule of the route. | +| **Platform engineer use-case** | 1 AuthPolicy targeting the `istio-ingressgateway` Gateway that enforces a trivial "deny-all" policy that locks down any other HTTPRoute attached to the Gateway. | + +Topology: + +``` + ┌───────────────┐ + │ (AuthPolicy) │ + │ gw-auth │ + └───────┬───────┘ + │ + ▼ + ┌──────────────────────┐ + │ (Gateway) │ + │ istio-ingressgateway │ + ┌────►│ │◄───┐ + │ │ * │ │ + │ └──────────────────────┘ │ + │ │ + ┌────────┴─────────┐ ┌────────┴─────────┐ + │ (HTTPRoute) │ │ (HTTPRoute) │ + │ toystore │ │ other │ + │ │ │ │ + │ api.toystore.com │ │ *.other-apps.com │ + └──────────────────┘ └──────────────────┘ + ▲ + │ + ┌───────┴───────┐ + │ (AuthPolicy) │ + │ toystore │ + └───────────────┘ +``` + +## Requisites + +- [Docker](https://docker.io) + +## Run the guide ① → ④ + +### ① Setup (Persona: _Cluster admin_) + +Clone the repo: + +```sh +git clone git@github.com:Kuadrant/kuadrant-operator.git && cd kuadrant-operator +``` + +Run the following command to create a local Kubernetes cluster with [Kind](https://kind.sigs.k8s.io/), install & deploy Kuadrant: + +```sh +make local-setup +``` + +Request an instance of Kuadrant in the `kuadrant-system` namespace: + +```sh +kubectl -n kuadrant-system apply -f - <