Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[authpolicy-v2] AuthPolicy validation rules #281

Merged
merged 2 commits into from
Oct 20, 2023

Conversation

guicassolato
Copy link
Contributor

@guicassolato guicassolato commented Oct 20, 2023

  • Prevent usage of routeSelectors in a gateway AuthPolicy (enforced at reconciliation time)
  • AuthPolicy validation rules using Common Language Expression (CEL) (enforced at the level of the API)
    • Invalid targetRef.group
    • Invalid targetRef.kind
    • Route selectors not supported when targeting a Gateway
    • Note: cannot set a validation rule for !has(spec.targetRef.namespace) || spec.targetRef.namespace == metadata.namespace, because Kubernetes does not allow accessing metadata.namespace (ref)
    • Note: kubebuilder currently does not support other validation rules fields such as reason and fieldPath that would allow improving error messages

Verification steps

❶ Setup

make local-setup
kubectl -n kuadrant-system apply -f - <<EOF
apiVersion: kuadrant.io/v1beta1
kind: Kuadrant
metadata:
  name: kuadrant
spec: {}
EOF
kubectl apply -f examples/toystore/toystore.yaml

kubectl apply -f - <<EOF
apiVersion: gateway.networking.k8s.io/v1beta1
kind: HTTPRoute
metadata:
  name: toystore
spec:
  parentRefs:
  - name: istio-ingressgateway
    namespace: istio-system
  hostnames:
  - api.toystore.com
  rules:
  - matches:
    - method: GET
      path:
        type: PathPrefix
        value: "/cars"
    - method: GET
      path:
        type: PathPrefix
        value: "/dolls"
    backendRefs:
    - name: toystore
      port: 80
  - matches:
    - path:
        type: PathPrefix
        value: "/admin"
    backendRefs:
    - name: toystore
      port: 80
EOF

❷ AuthPolicies

kubectl apply -f -<<EOF
# The AuthPolicy "gw-auth-1" is invalid: spec.targetRef: Invalid value: "object": Invalid targetRef.group. The only supported value is 'gateway.networking.k8s.io'
apiVersion: kuadrant.io/v1beta2
kind: AuthPolicy
metadata:
  name: gw-auth-1
  namespace: istio-system
spec:
  targetRef:
    group: networking.istio.io # invalid
    kind: Gateway
    name: istio-ingressgateway
  rules:
    authorization:
      deny-all:
        opa:
          rego: "allow = false"
    response:
      unauthorized:
        headers:
          "content-type":
            value: application/json
        body:
          value: |
            {
              "error": "Forbidden",
              "message": "Access denied by default by the gateway operator. If you are the administrator of the service, create a specific auth policy for the route."
            }
---
# The AuthPolicy "gw-auth-2" is invalid: spec.targetRef: Invalid value: "object": Invalid targetRef.kind. The only supported values are 'HTTPRoute' and 'Gateway'
apiVersion: kuadrant.io/v1beta2
kind: AuthPolicy
metadata:
  name: gw-auth-2
  namespace: istio-system
spec:
  targetRef:
    group: gateway.networking.k8s.io
    kind: Service # invalid
    name: istio-ingressgateway
  rules:
    authorization:
      deny-all:
        opa:
          rego: "allow = false"
    response:
      unauthorized:
        headers:
          "content-type":
            value: application/json
        body:
          value: |
            {
              "error": "Forbidden",
              "message": "Access denied by default by the gateway operator. If you are the administrator of the service, create a specific auth policy for the route."
            }
---
# The AuthPolicy "gw-auth-3" is invalid: spec: Invalid value: "object": route selectors not supported when targeting a Gateway
apiVersion: kuadrant.io/v1beta2
kind: AuthPolicy
metadata:
  name: gw-auth-3
  namespace: istio-system
spec:
  targetRef:
    group: gateway.networking.k8s.io
    kind: Gateway
    name: istio-ingressgateway
  routeSelectors: # invalid
  - hostnames: ["api.toystore.com"]
  rules:
    authorization:
      deny-all:
        opa:
          rego: "allow = false"
    response:
      unauthorized:
        headers:
          "content-type":
            value: application/json
        body:
          value: |
            {
              "error": "Forbidden",
              "message": "Access denied by default by the gateway operator. If you are the administrator of the service, create a specific auth policy for the route."
            }
---
# The AuthPolicy "gw-auth-4" is invalid: spec: Invalid value: "object": route selectors not supported when targeting a Gateway
apiVersion: kuadrant.io/v1beta2
kind: AuthPolicy
metadata:
  name: gw-auth-4
  namespace: istio-system
spec:
  targetRef:
    group: gateway.networking.k8s.io
    kind: Gateway
    name: istio-ingressgateway
  rules:
    authorization:
      deny-all:
        opa:
          rego: "allow = false"
        routeSelectors: # invalid
        - hostnames: ["api.toystore.com"]
    response:
      unauthorized:
        headers:
          "content-type":
            value: application/json
        body:
          value: |
            {
              "error": "Forbidden",
              "message": "Access denied by default by the gateway operator. If you are the administrator of the service, create a specific auth policy for the route."
            }
---
# authpolicy.kuadrant.io/gw-auth-5 created
apiVersion: kuadrant.io/v1beta2
kind: AuthPolicy
metadata:
  name: gw-auth-5
  namespace: istio-system
spec:
  targetRef:
    group: gateway.networking.k8s.io
    kind: Gateway
    name: istio-ingressgateway
  rules:
    authorization:
      deny-all:
        opa:
          rego: "allow = false"
    response:
      unauthorized:
        headers:
          "content-type":
            value: application/json
        body:
          value: |
            {
              "error": "Forbidden",
              "message": "Access denied by default by the gateway operator. If you are the administrator of the service, create a specific auth policy for the route."
            }
---
# authpolicy.kuadrant.io/toystore created
apiVersion: kuadrant.io/v1beta2
kind: AuthPolicy
metadata:
  name: toystore
  namespace: default
spec:
  targetRef:
    group: gateway.networking.k8s.io
    kind: HTTPRoute
    name: toystore
  rules:
    authentication:
      "api-key-authn":
        apiKey:
          selector: {}
        credentials:
          authorizationHeader:
            prefix: APIKEY
    authorization:
      "only-admins":
        opa:
          rego: |
            groups := split(object.get(input.auth.identity.metadata.annotations, "kuadrant.io/groups", ""), ",")
            allow { groups[_] == "admins" }
        routeSelectors:
        - matches:
          - path:
              type: PathPrefix
              value: "/admin"
EOF

Expected:

authpolicy.kuadrant.io/gw-auth-5 created
authpolicy.kuadrant.io/toystore created
AuthPolicy.kuadrant.io "gw-auth-1" is invalid: spec.targetRef: Invalid value: "object": Invalid targetRef.group. The only supported value is 'gateway.networking.k8s.io'
AuthPolicy.kuadrant.io "gw-auth-2" is invalid: spec.targetRef: Invalid value: "object": Invalid targetRef.kind. The only supported values are 'HTTPRoute' and 'Gateway'
AuthPolicy.kuadrant.io "gw-auth-3" is invalid: spec: Invalid value: "object": route selectors not supported when targeting a Gateway
AuthPolicy.kuadrant.io "gw-auth-4" is invalid: spec: Invalid value: "object": route selectors not supported when targeting a Gateway

@guicassolato guicassolato self-assigned this Oct 20, 2023
@codecov
Copy link

codecov bot commented Oct 20, 2023

Codecov Report

Merging #281 (20d3ea3) into authpolicy-v2 (4bf902a) will increase coverage by 0.75%.
The diff coverage is 83.33%.

@@                Coverage Diff                @@
##           authpolicy-v2     #281      +/-   ##
=================================================
+ Coverage          64.03%   64.79%   +0.75%     
=================================================
  Files                 35       35              
  Lines               3776     3806      +30     
=================================================
+ Hits                2418     2466      +48     
+ Misses              1164     1148      -16     
+ Partials             194      192       -2     
Flag Coverage Δ
integration 70.53% <ø> (+0.59%) ⬆️
unit 58.20% <83.33%> (+1.06%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

Components Coverage Δ
api/v1beta1 (u) ∅ <ø> (∅)
pkg/common (u) 73.92% <ø> (ø)
pkg/istio (u) 30.24% <ø> (ø)
pkg/log (u) 31.81% <ø> (ø)
pkg/reconcilers (u) 33.68% <ø> (ø)
pkg/rlptools (u) 56.41% <ø> (ø)
controllers (i) 70.53% <ø> (+0.59%) ⬆️
Files Coverage Δ
api/v1beta2/authpolicy_types.go 77.57% <83.33%> (+16.53%) ⬆️

... and 5 files with indirect coverage changes

@guicassolato guicassolato force-pushed the authpolicy-v2-gw-policy-validation branch from 05916cd to de8fc68 Compare October 20, 2023 05:26
@guicassolato guicassolato force-pushed the authpolicy-v2-gw-policy-validation branch from de8fc68 to 53776b3 Compare October 20, 2023 10:47
@guicassolato guicassolato marked this pull request as ready for review October 20, 2023 10:48
@guicassolato guicassolato requested a review from a team as a code owner October 20, 2023 10:48
Copy link
Member

@adam-cattermole adam-cattermole left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

minor typo but the verification passed and the code looks good to me!

api/v1beta2/authpolicy_types_test.go Outdated Show resolved Hide resolved
- Invalid targetRef.group
- Invalid targetRef.kind
- Route selectors not supported when targeting a Gateway

Note: cannot set a validation rule for !has(spec.targetRef.namespace) || spec.targetRef.namespace == metadata.namespace, because Kubernetes does not allow accessing `metadata.namespace`. See https://kubernetes.io/docs/tasks/extend-kubernetes/custom-resources/custom-resource-definitions/#validation-rules
@guicassolato guicassolato force-pushed the authpolicy-v2-gw-policy-validation branch from 53776b3 to 20d3ea3 Compare October 20, 2023 12:18
@guicassolato guicassolato merged commit c639e93 into authpolicy-v2 Oct 20, 2023
13 checks passed
@guicassolato guicassolato deleted the authpolicy-v2-gw-policy-validation branch October 20, 2023 13:17
guicassolato added a commit that referenced this pull request Oct 20, 2023
* AuthPolicy v1beta2

Defines new `v1beta2` version of the `AuthPolicy` CRD, based on Authorino's `AuthConfig/v1beta2`.

Closes #247

Depends on Kuadrant/authorino#417, Kuadrant/authorino-operator#137

Bump Authorino to latest (unreleased) version

Bump Authorino to latest (unreleased) version

Bump Authorino to latest (unreleased) version

Update AuthPolicy manifests based on latest AuthConfig v1beta2 changes

Bump Authorino to latest (unreleased) version

Bump Authorino to latest (unreleased) version

* Bump Authorino Operator to v0.9.0

Closes #263

* Superseding of strict host subsets between AuthConfigs

Enables [superseding of strict host subsets](https://github.com/Kuadrant/authorino/blob/main/docs/architecture.md#avoiding-host-name-collision) in Authorino – i.e., set `SupersedingHostSubsets` to `true` in the Authorino CR.

Closes #264.

* Route selectors for the AuthPolicy

* Merge the hostnames of HTTPRoute (direct or inherited from the Gateway) into all Istio AuthorizationPolicy rules that do not include hostnames already built from the route selectors, so we don't send a request to authorino for hosts that are not in the scope of the policy

* AuthConfig with OR conditions between HTTPRouteMatches of a HTTPRouteRule and between HTTPRouteRules themselves

* Fix reconciliation of gateway AuthPolicies

Skips creation of Istio AuthorizationPolicies and Authorino AuthConfigs for gateways without any accepted HTTPRoutes.

* Ensure Gateway API group is used when checking the targetRef kind

* Trigger reconciliation of possibly affected gateway policies after reconciling HTTPRoute ones

* Mapper of HTTPRoute events to policy events that goes through the parentRefs of the route and finds all policies that target one of its parent resources, thus yielding events for those policies.

* AuthConfig condition from GWAPI QueryParamMatchRegularExpression

* Skip Istio AuthorizationPolicy rules for GWAPI PathMatchRegularExpression and HeaderMatchRegularExpression

* Generate Istio AuthorizationPolicy rules out of top-level conditions or full HTTPRoute only (i.e. ignore config-level conditions)

* tests: fix integration tests for authpolicy with route selectors

* fix: AuthorizationPolicy rules when PathMatchRegularExpression

+ unit tests from Istio AuthorizationPolicy rules from HTTPRouteRules and hostnames

* tests: unit tests from AuthConfig conditions from HTTPRouteRules and hostnames

* tests: unit tests for the AuthPolicy type

* tests: unit test for RateLimitPolicyList.GetItems()

* tests: unit test for RouteSelectors.HostnamesForConditions()

* tests: integration test for Gateway policy with having other policies attached to HTTPRoutes

* fixup: AuthPolicy SuccessResponseSpec type

* tests: integration tests for AuthPolicy <-> AuthConfig mapping

* tests: integration tests gateway policies whith all HTTPRoutes talken

* Well-known attributes used in the generated AuthConfigs

Closes:
- #265

* tests: integration tests for policies only with unmatching route selectors

* lint: fix duplicated imported package

* Move AuthPolicy v1beta top-level 'patterns' and 'when' fields one level up

This will pair the level of these policy-wide options to the top-level 'routeSelectors', rather than having two things that have semantics over the same scope defined at different levels in the API.

This change also separates the auth scheme, making it now exclusively about auth rules.

* [authpolicy-v2] docs (#275)

* docs: authpolicy v1beta2

* docs: addressing suggestions of enhancements to the authpolicy docs

* Add mandatory Gateway API label to the AuthPolicy CRD (#279)

Closes #278

* docs: fix typos

* [authpolicy-v2] AuthPolicy validation rules (#281)

* prevent usage of routeSelectors in a gateway AuthPolicy

* AuthPolicy CEL validation rules

- Invalid targetRef.group
- Invalid targetRef.kind
- Route selectors not supported when targeting a Gateway

Note: cannot set a validation rule for !has(spec.targetRef.namespace) || spec.targetRef.namespace == metadata.namespace, because Kubernetes does not allow accessing `metadata.namespace`. See https://kubernetes.io/docs/tasks/extend-kubernetes/custom-resources/custom-resource-definitions/#validation-rules
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants