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

AuthConfig v1beta2 #417

Merged
merged 35 commits into from
Sep 19, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
8b7acdd
AuthConfig v1beta2 CRD
guicassolato Jul 21, 2023
1eaead9
conversion webhook
guicassolato Jul 25, 2023
7d4603c
fix one-of restriction for pattern expression of pattern ref
guicassolato Jul 27, 2023
3aada04
Conversion webhook service managed by the Operator
guicassolato Aug 29, 2023
9a216b0
fix: unexport spicedb conversion functions
guicassolato Aug 29, 2023
86455df
add tests for the conversion + fix conversion of a couple nil arrays/…
guicassolato Aug 29, 2023
aca78c6
One-of constraints for fields of AuthConfig v1beta2
guicassolato Aug 29, 2023
0599684
Use Authorino Operator install script
guicassolato Aug 31, 2023
af96b5b
fix: set status field hostReady in the conversion
guicassolato Sep 4, 2023
d968a60
docs: updated README, architecture and features pages for the v1beta2…
guicassolato Sep 4, 2023
99e5ecf
remove: unimplemented spec.authentication.jwt.jwksUrl
guicassolato Sep 5, 2023
8eaeca1
remove: unimplemented spec.authentication.credentials.customHeader.pr…
guicassolato Sep 5, 2023
d99b225
remove: unimplemented spec.(metadata|authorization.opa.externalPolicy…
guicassolato Sep 5, 2023
6202b26
Add description to not use unimplemented fields of the OPA external p…
guicassolato Sep 5, 2023
c22d500
docs: fixup: opa.externalPolicy
guicassolato Sep 5, 2023
b556c26
docs: fixup: wristband.issuer example
guicassolato Sep 5, 2023
3527edf
Add deprecation notice of v1beta1 reponse.wrapperKey field
guicassolato Sep 5, 2023
c70f9b6
Revert "docs: fixup: wristband.issuer example"
guicassolato Sep 5, 2023
cf14ba3
remove: unimplemented spec.response.success.headers.prefix
guicassolato Sep 5, 2023
b61838f
Add field spec.response.success.(headers|dynamicMetadata).key
guicassolato Sep 5, 2023
7e92eaf
docs: update for v1beta2: 'Getting started'
guicassolato Sep 5, 2023
3207f52
docs: fixup: inlineRego → rego
guicassolato Sep 5, 2023
3b12430
docs: update for v1beta2: user guides
guicassolato Sep 5, 2023
6b3ed14
docs: fix broken links to feature description
guicassolato Sep 5, 2023
278acb9
fix: conversion of v1beta2.ValueOrSelector type missing to parse stri…
guicassolato Sep 5, 2023
07a2a2f
docs: fixup: 'Using Authorino as ValidatingWebhook service' user guide
guicassolato Sep 5, 2023
c4416d1
fix: set default http header custom response wrapper when converting …
guicassolato Sep 6, 2023
bb89344
e2e tests for v1beta2
guicassolato Sep 6, 2023
6c22f27
Remove unnecessary steps to install cert-manager when relying on the …
guicassolato Sep 6, 2023
2fa28d7
docs: fixup: 'Edge Authentication Architecture (EAA)' user guide
guicassolato Sep 6, 2023
166c088
docs: fixup: 'Authenticated rate limiting (with Envoy Dynamic Metadat…
guicassolato Sep 6, 2023
bf6e068
fix: docs: typo in the oauth2 token introspection user guide
guicassolato Sep 13, 2023
5059dca
fix: docs: use net.cidr_contains instead of regex.match in opa exampl…
guicassolato Sep 13, 2023
4343ef8
fix: docs: wrong kubectl command in the cleanup section of a user guide
guicassolato Sep 13, 2023
90ce6fe
docs: urls with interpolated json paths within authconfig resources w…
guicassolato Sep 13, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .github/workflows/e2e-test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ jobs:
matrix:
go-version: [1.19.x]
platform: [ubuntu-latest]
authconfig_version: [v1beta1, v1beta2]
runs-on: ${{ matrix.platform }}
defaults:
run:
Expand All @@ -34,5 +35,6 @@ jobs:
- name: Run make e2e
env:
OPERATOR_VERSION: ${{ github.event.inputs.operatorVersion }}
AUTHCONFIG_VERSION: ${{ matrix.authconfig_version }}
run: |
make e2e
12 changes: 3 additions & 9 deletions .github/workflows/integration-test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -31,15 +31,9 @@ jobs:
run: go install sigs.k8s.io/kind@v0.20.0
- name: Create kind cluster
run: kind create cluster --name authorino-smoke-tests
- name: Install cert-manager
run: |
kubectl apply -f https://github.com/jetstack/cert-manager/releases/download/v1.4.0/cert-manager.yaml
kubectl delete mutatingwebhookconfiguration.admissionregistration.k8s.io/cert-manager-webhook
kubectl delete validatingwebhookconfigurations.admissionregistration.k8s.io/cert-manager-webhook
kubectl -n cert-manager wait --timeout=300s --for=condition=Available deployments --all
- name: Install Authorino Operator
run: |
kubectl apply -f https://raw.githubusercontent.com/Kuadrant/authorino-operator/main/config/deploy/manifests.yaml
curl -sL https://raw.githubusercontent.com/Kuadrant/authorino-operator/main/utils/install.sh | bash -s
kubectl -n authorino-operator wait --timeout=300s --for=condition=Available deployments --all
- name: Create the namespace
run: |
Expand Down Expand Up @@ -79,7 +73,7 @@ jobs:
- name: Run e2e tests
env:
NAMESPACE: authorino
AUTHCONFIG: https://raw.githubusercontent.com/Kuadrant/authorino/main/tests/authconfig.yaml
AUTHCONFIG_INVALID: https://raw.githubusercontent.com/Kuadrant/authorino/main/tests/authconfig-invalid.yaml
AUTHCONFIG: https://raw.githubusercontent.com/Kuadrant/authorino/main/tests/v1beta2/authconfig.yaml
AUTHCONFIG_INVALID: https://raw.githubusercontent.com/Kuadrant/authorino/main/tests/v1beta2/authconfig-invalid.yaml
run: |
curl -sSL https://raw.githubusercontent.com/Kuadrant/authorino/main/tests/e2e-test.sh | bash
36 changes: 20 additions & 16 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,8 @@ generate: vendor controller-gen ## Generates types deepcopy code
$(MAKE) fmt vet

manifests: controller-gen kustomize ## Generates the manifests in $PROJECT_DIR/install
controller-gen crd:crdVersions=v1 rbac:roleName=manager-role webhook paths="./..." output:crd:artifacts:config=install/crd output:rbac:artifacts:config=install/rbac && kustomize build install > $(AUTHORINO_MANIFESTS)
controller-gen crd:crdVersions=v1 rbac:roleName=manager-role webhook paths="./..." output:crd:artifacts:config=install/crd output:rbac:artifacts:config=install/rbac && $(KUSTOMIZE) build install > $(AUTHORINO_MANIFESTS)
$(MAKE) patch-webhook

run: generate manifests ## Runs the application against the Kubernetes cluster configured in ~/.kube/config
go run -ldflags "-X main.version=$(VERSION)" ./main.go server
Expand Down Expand Up @@ -143,22 +144,15 @@ report-benchmarks:
cover: ## Shows test coverage
go tool cover -html=cover.out

AUTHCONFIG_VERSION ?= v1beta2
VERBOSE ?= 0
e2e: ## Runs the end-to-end tests on a local environment setup
$(MAKE) local-setup NAMESPACE=authorino KIND_CLUSTER_NAME=authorino-e2e AUTHORINO_IMAGE=$(AUTHORINO_IMAGE) TLS_ENABLED=$(TLS_ENABLED) OPERATOR_BRANCH=$(OPERATOR_BRANCH) AUTHORINO_MANIFESTS=$(AUTHORINO_MANIFESTS) AUTHORINO_INSTANCE=$(AUTHORINO_INSTANCE) ENVOY_OVERLAY=$(ENVOY_OVERLAY) DEPLOY_KEYCLOAK=1 FF=1
NAMESPACE=authorino VERBOSE=$(VERBOSE) ./tests/e2e-test.sh
NAMESPACE=authorino AUTHCONFIG_VERSION=$(AUTHCONFIG_VERSION) VERBOSE=$(VERBOSE) ./tests/e2e-test.sh

##@ Apps

.PHONY: cert-manager user-apps keycloak dex limitador

cert-manager: ## Installs CertManager into the Kubernetes cluster configured in ~/.kube/config
ifeq (true,$(TLS_ENABLED))
kubectl apply -f https://github.com/jetstack/cert-manager/releases/download/v1.4.0/cert-manager.yaml
kubectl delete mutatingwebhookconfiguration.admissionregistration.k8s.io/cert-manager-webhook
kubectl delete validatingwebhookconfigurations.admissionregistration.k8s.io/cert-manager-webhook
kubectl -n cert-manager wait --timeout=300s --for=condition=Available deployments --all
endif
.PHONY: user-apps keycloak dex limitador

DEPLOY_KEYCLOAK ?= $(DEPLOY_IDPS)
DEPLOY_DEX ?= $(DEPLOY_IDPS)
Expand Down Expand Up @@ -188,16 +182,19 @@ limitador: ## Deploys Limitador from kuadrant/authorino-examples into the Kubern

##@ Installation

.PHONY: install-operator uninstall-operator install uninstall
.PHONY: install-operator uninstall-operator install uninstall patch-webhook

AUTHORINO_OPERATOR_NAMESPACE ?= authorino-operator

ifeq (latest,$(OPERATOR_VERSION))
OPERATOR_BRANCH = main
else
OPERATOR_BRANCH = $(OPERATOR_VERSION)
endif
install-operator: ## Installs Authorino Operator and corresponding version of the manifests into the Kubernetes cluster configured in ~/.kube/config
kubectl apply -f https://raw.githubusercontent.com/Kuadrant/authorino-operator/$(OPERATOR_BRANCH)/config/deploy/manifests.yaml
kubectl -n authorino-operator wait --timeout=300s --for=condition=Available deployments --all
install-operator: ## Installs Authorino Operator and dependencies into the Kubernetes cluster configured in ~/.kube/config
curl -sL https://raw.githubusercontent.com/Kuadrant/authorino-operator/$(OPERATOR_BRANCH)/utils/install.sh | bash -s -- --git-ref $(OPERATOR_BRANCH)
Copy link
Collaborator

Choose a reason for hiding this comment

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

For the future, for this kind of tasks, I would use kustomize

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Following the same pattern adopted by https://docs.kuadrant.io/getting-started/#set-up-clusters-and-multicluster-gateway-controller.

kustomize is also bit more cumbersome when you need to support many options (even with overlays). Besides, it isn't much helpful for things like sequencing commands, e.g. https://github.com/Kuadrant/authorino-operator/blob/152a1627a0b2f5d36c3983192644ec8c5d625bad/utils/install.sh#L140

kubectl patch deployment/authorino-webhooks -n $(AUTHORINO_OPERATOR_NAMESPACE) -p '{"spec":{"template":{"spec":{"containers":[{"name":"webhooks","image":"$(AUTHORINO_IMAGE)","imagePullPolicy":"IfNotPresent"}]}}}}'
kubectl -n $(AUTHORINO_OPERATOR_NAMESPACE) wait --timeout=300s --for=condition=Available deployments --all

uninstall-operator: ## Uninstalls Authorino Operator and corresponding version of the manifests from the Kubernetes cluster configured in ~/.kube/config
kubectl delete -f https://raw.githubusercontent.com/Kuadrant/authorino-operator/$(OPERATOR_BRANCH)/config/deploy/manifests.yaml
Expand All @@ -208,6 +205,13 @@ install: manifests ## Installs the current manifests (CRD, RBAC) into the Kubern
uninstall: manifests ## Uninstalls the current manifests (CRD, RBAC) from the Kubernetes cluster configured in ~/.kube/config
kubectl delete -f $(AUTHORINO_MANIFESTS)

patch-webhook: export WEBHOOK_NAMESPACE=$(AUTHORINO_OPERATOR_NAMESPACE)
patch-webhook:
envsubst \
< $(AUTHORINO_MANIFESTS) \
> $(AUTHORINO_MANIFESTS).tmp && \
mv $(AUTHORINO_MANIFESTS).tmp $(AUTHORINO_MANIFESTS)

##@ Deployment

.PHONY: namespace certs deploy
Expand Down Expand Up @@ -250,7 +254,7 @@ cluster: kind ## Starts a local Kubernetes cluster using Kind
local-build: kind docker-build ## Builds an image based on the current branch and pushes it to the registry into the local Kubernetes cluster started with Kind
$(KIND) load docker-image $(AUTHORINO_IMAGE) --name $(KIND_CLUSTER_NAME)

local-setup: cluster local-build cert-manager install-operator install namespace deploy user-apps ## Sets up a test/dev local Kubernetes server using Kind, loaded up with a freshly built Authorino image and apps
local-setup: cluster local-build install-operator install namespace deploy user-apps ## Sets up a test/dev local Kubernetes server using Kind, loaded up with a freshly built Authorino image and apps
kubectl -n $(NAMESPACE) wait --timeout=300s --for=condition=Available deployments --all
@{ \
echo "Now you can export the envoy service by doing:"; \
Expand Down
3 changes: 3 additions & 0 deletions PROJECT
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ resources:
- group: config
kind: AuthConfig
version: v1beta1
- group: config
kind: AuthConfig
version: v1beta2
version: 3-alpha
plugins:
go.sdk.operatorframework.io/v2-alpha: {}
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -287,7 +287,7 @@ For a detailed description of the features above, refer to the [Features](./docs
<details>
<summary><strong>Can't I just use Envoy JWT Authentication and RBAC filters?</strong></summary>

Envoy's [JWT Authentication](https://www.envoyproxy.io/docs/envoy/latest/api-v3/extensions/filters/http/jwt_authn/v3/config.proto.html) works pretty much similar to Authorino's [JOSE/JWT verification and validation for OpenID Connect](./docs/features.md#openid-connect-oidc-jwtjose-verification-and-validation-identityoidc). In both cases, the JSON Web Key Sets (JWKS) to verify the JWTs are auto-loaded and cached to be used in request-time. Moreover, you can configure for details such as where to extract the JWT from the HTTP request (header, param or cookie) and do some cool tricks regarding how dynamic metadata based on JWT claims can be injected to consecutive filters in the chain.
Envoy's [JWT Authentication](https://www.envoyproxy.io/docs/envoy/latest/api-v3/extensions/filters/http/jwt_authn/v3/config.proto.html) works pretty much similar to Authorino's [JOSE/JWT verification and validation for OpenID Connect](./docs/features.md#jwt-verification-authenticationjwt). In both cases, the JSON Web Key Sets (JWKS) to verify the JWTs are auto-loaded and cached to be used in request-time. Moreover, you can configure for details such as where to extract the JWT from the HTTP request (header, param or cookie) and do some cool tricks regarding how dynamic metadata based on JWT claims can be injected to consecutive filters in the chain.

However, in terms of authorization, while Envoy's implementation essentially allows to check for the list of audiences (`aud` JWT claim), Authorino opens up for a lot more options such as pattern-matching rules with operators and conditionals, built-in OPA and other methods of evaluating authorization policies.

Expand All @@ -307,7 +307,7 @@ For a detailed description of the features above, refer to the [Features](./docs

Authorino is an Envoy-compatible external authorization service. One can use Authorino with or without Istio.

In particular, [Istio Authorization Policies](https://istio.io/latest/docs/reference/config/security/authorization-policy/) can be seen, in terms of functionality and expressiveness, as a subset of one type of authorization policies supported by Authorino, the [JSON pattern-matching authorization](./docs/features.md#json-pattern-matching-authorization-rules-authorizationjson) policies. While Istio, however, is heavily focused on specific use cases of API Management, offering a relatively limited list of [supported attribute conditions](https://istio.io/latest/docs/reference/config/security/conditions/), Authorino is more generic, allowing to express authorization rules for a wider spectrum of use cases – ACLs, RBAC, ABAC, etc, pretty much counting on any attribute of the Envoy payload, identity object and external metadata available.
In particular, [Istio Authorization Policies](https://istio.io/latest/docs/reference/config/security/authorization-policy/) can be seen, in terms of functionality and expressiveness, as a subset of one type of authorization policies supported by Authorino, the [pattern-matching authorization](./docs/features.md#pattern-matching-authorization-authorizationpatternmatching) policies. While Istio, however, is heavily focused on specific use cases of API Management, offering a relatively limited list of [supported attribute conditions](https://istio.io/latest/docs/reference/config/security/conditions/), Authorino is more generic, allowing to express authorization rules for a wider spectrum of use cases – ACLs, RBAC, ABAC, etc, pretty much counting on any attribute of the Envoy payload, identity object and external metadata available.

Authorino also provides built-in OPA authorization, several other methods of authentication and identity verification (e.g. Kubernetes token validation, API key-based authentication, OAuth token introspection, OIDC-discoverable JWT verification, etc), and features like fetching of external metadata (HTTP services, OIDC userinfo, UMA resource data), token normalization, wristband tokens and dynamic responses. These all can be used independently or combined, in a simple and straightforward Kubernetes-native fashion.

Expand All @@ -327,7 +327,7 @@ For a detailed description of the features above, refer to the [Features](./docs

No, you do not. However, if you are comfortable with [Rego](https://www.openpolicyagent.org/docs/latest/policy-language/) from Open Policy Agent (OPA), there are some quite interesting things you can do in Authorino, just as you would in any OPA server or OPA plugin, but leveraging Authorino's [built-in OPA module](./docs/features.md#open-policy-agent-opa-rego-policies-authorizationopa) instead. Authorino's OPA module is compiled as part of Authorino's code directly from the Golang packages, and imposes no extra latency to the evaluation of your authorization policies. Even the policies themselves are pre-compiled in reconciliation-time, for fast evaluation afterwards, in request-time.

On the other hand, if you do not want to learn Rego or in any case would like to combine it with declarative and Kubernetes-native authN/authZ spec for your services, Authorino does complement OPA with at least two other methods for expressing authorization policies – i.e. [JSON pattern-matching authorization rules](./docs/features.md#json-pattern-matching-authorization-rules-authorizationjson) and [Kubernetes SubjectAccessReview](./docs/features.md#kubernetes-subjectaccessreview-authorizationkubernetes), the latter allowing to rely completely on the Kubernetes RBAC.
On the other hand, if you do not want to learn Rego or in any case would like to combine it with declarative and Kubernetes-native authN/authZ spec for your services, Authorino does complement OPA with at least two other methods for expressing authorization policies – i.e. [pattern-matching authorization](./docs/features.md#pattern-matching-authorization-authorizationpatternmatching) and [Kubernetes SubjectAccessReview](./docs/features.md#kubernetes-subjectaccessreview-authorizationkubernetessubjectaccessreview), the latter allowing to rely completely on the Kubernetes RBAC.

You break down, mix and combine these methods and technolgies in as many authorization policies as you want, potentially applying them according to specific conditions. Authorino will trigger the evaluation of concurrent policies in parallel, aborting the context if any of the processes denies access.

Expand Down
4 changes: 4 additions & 0 deletions api/v1beta1/auth_config_conversion.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
package v1beta1

// Hub marks this version as a conversion hub.
func (a *AuthConfig) Hub() {}
1 change: 1 addition & 0 deletions api/v1beta1/auth_config_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -774,6 +774,7 @@ func (s *AuthConfigStatus) Ready() bool {
// AuthConfig is the schema for Authorino's AuthConfig API
// +kubebuilder:object:root=true
// +kubebuilder:subresource:status
Copy link
Collaborator

Choose a reason for hiding this comment

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

considered adding kubebuilder:deprecatedversion ??

Copy link
Collaborator

Choose a reason for hiding this comment

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

Should not be done in this step. check my comment above.

// +kubebuilder:storageversion
Copy link
Collaborator

Choose a reason for hiding this comment

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

shouldn't be v1beta2 the one to be stored?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Not necessarily. Usually, first you introduce a new version of the API and allow time for users to adapt; then the newer version becomes the stored one in a subsequent rolling update. This way, when they install the new version of the CRD, previously existing CRs based on the old version won't be a blocker.

For ref: https://kubernetes.io/docs/tasks/extend-kubernetes/custom-resources/custom-resource-definition-versioning/#version-removal

Copy link
Collaborator

Choose a reason for hiding this comment

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

I am missing something. If the stored version is the old one, even the clients of the new version will store CR with the old version. then the newer version becomes the stored one in a subsequent rolling update. Then, there will be the same situation, all the CR stored versions would be the old one and the CRD's stored one will be the new one. I do not see any advantage of postponing the stored version.

What I was assuming, and correct me if I am wrong, whenever a client updates / creates an object, if the object's version is not the stored one, the webhook conversion API will be called and the object converted.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Looking at the Versions in CustomResourceDefinitions, the workflow for upgrading CRD version would be (high level):

  • Release 1: Add a new version to the version list. The old version is the stored one. Both versions will be served. No deprecation flag.
  • Release 2 (or later): Old version deprecation. The old version is served, but not stored and added deprecation warning. The new version is the stored (and served) one. Just after installing the new CRD with the changes, the stored (in old version) CR's need to be migrated. This is procedure needs to be run by some cluster admin.
  • Release 3 (or later): Version removal. When all the clients have migrated to the new version (one option is checking kube-apiserver logs), the old version can either be disabled for serving (served: false) or just removed from the CRD spec.versions list.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Excellent summary, @eguzki. Thank you for this!

// +kubebuilder:printcolumn:name="Ready",type=string,JSONPath=`.status.summary.ready`,description="Ready for all hosts"
// +kubebuilder:printcolumn:name="Hosts",type=string,JSONPath=`.status.summary.numHostsReady`,description="Number of hosts ready"
// +kubebuilder:printcolumn:name="Authentication",type=integer,JSONPath=`.status.summary.numIdentitySources`,description="Number of trusted identity sources",priority=2
Expand Down
Loading
Loading