diff --git a/Makefile b/Makefile index 5362a265..e7944622 100644 --- a/Makefile +++ b/Makefile @@ -79,3 +79,21 @@ chmod a+x $(1)/bin/protoc ;\ rm -rf $$TMP_DIR ;\ } endef + +##@ Util + +# go-install-tool will 'go install' any package $2 and install it to $1. +PROJECT_DIR := $(shell dirname $(abspath $(lastword $(MAKEFILE_LIST)))) +define go-install-tool +@[ -f $(1) ] || { \ +set -e ;\ +TMP_DIR=$$(mktemp -d) ;\ +cd $$TMP_DIR ;\ +go mod init tmp ;\ +echo "Downloading $(2)" ;\ +GOBIN=$(PROJECT_DIR)/bin go install $(2) ;\ +rm -rf $$TMP_DIR ;\ +} +endef + +include ./make/*.mk diff --git a/make/auth.mk b/make/auth.mk new file mode 100644 index 00000000..04823d9f --- /dev/null +++ b/make/auth.mk @@ -0,0 +1,102 @@ +##@ Kind + +.PHONY: kind kind-create-cluster kind-delete-cluster + +KIND = $(PROJECT_PATH)/bin/kind +KIND_VERSION = v0.23.0 +$(KIND): + $(call go-install-tool,$(KIND),sigs.k8s.io/kind@$(KIND_VERSION)) + +kind: $(KIND) ## Download kind locally if necessary. + +KIND_CLUSTER_NAME ?= wasm-auth-local + +kind-create-cluster: BUILD?=debug +kind-create-cluster: WASM_DEBUG_PATH=$(PROJECT_PATH)/target/wasm32-unknown-unknown/$(BUILD) +kind-create-cluster: WASM_PATH=$(subst /,\/,$(WASM_DEBUG_PATH)) +kind-create-cluster: kind ## Create the "wasm-auth-local" kind cluster. + @{ \ + TEMP_FILE=/tmp/kind-cluster-$$(openssl rand -hex 4).yaml ;\ + cp utils/kind/cluster.yaml $$TEMP_FILE ;\ + $(SED) -i "s/\$$(WASM_PATH)/$(WASM_PATH)/g" $$TEMP_FILE ;\ + KIND_EXPERIMENTAL_PROVIDER=$(CONTAINER_ENGINE) $(KIND) create cluster --name $(KIND_CLUSTER_NAME) --config $$TEMP_FILE ;\ + rm -rf $$TEMP_FILE ;\ + } + +kind-delete-cluster: ## Delete the "wasm-auth-local" kind cluster. + - KIND_EXPERIMENTAL_PROVIDER=$(CONTAINER_ENGINE) $(KIND) delete cluster --name $(KIND_CLUSTER_NAME) + + +##@ Authorino + +.PHONY: install-authorino-operator certs deploy-authorino + +AUTHORINO_IMAGE ?= quay.io/kuadrant/authorino:latest +AUTHORINO_OPERATOR_NAMESPACE ?= authorino-operator +install-authorino-operator: ## Installs Authorino Operator and dependencies into the Kubernetes cluster configured in ~/.kube/config + curl -sL https://raw.githubusercontent.com/Kuadrant/authorino-operator/main/utils/install.sh | bash -s -- --git-ref main + 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 + +TLS_ENABLED ?= true +AUTHORINO_INSTANCE ?= authorino +NAMESPACE ?= default +certs: sed ## Requests TLS certificates for the Authorino instance if TLS is enabled, cert-manager.io is installed, and the secret is not already present +ifeq (true,$(TLS_ENABLED)) +ifeq (,$(shell kubectl -n $(NAMESPACE) get secret/authorino-oidc-server-cert 2>/dev/null)) + curl -sl https://raw.githubusercontent.com/kuadrant/authorino/main/deploy/certs.yaml | $(SED) "s/\$$(AUTHORINO_INSTANCE)/$(AUTHORINO_INSTANCE)/g;s/\$$(NAMESPACE)/$(NAMESPACE)/g" | kubectl -n $(NAMESPACE) apply -f - +else + echo "tls cert secret found." +endif +else + echo "tls disabled." +endif + +deploy-authorino: certs sed ## Deploys an instance of Authorino into the Kubernetes cluster configured in ~/.kube/config + @{ \ + set -e ;\ + TEMP_FILE=/tmp/authorino-deploy-$$(openssl rand -hex 4).yaml ;\ + curl -sl https://raw.githubusercontent.com/kuadrant/authorino/main/deploy/authorino.yaml > $$TEMP_FILE ;\ + $(SED) -i "s/\$$(AUTHORINO_INSTANCE)/$(AUTHORINO_INSTANCE)/g;s/\$$(TLS_ENABLED)/$(TLS_ENABLED)/g" $$TEMP_FILE ;\ + kubectl -n $(NAMESPACE) apply -f $$TEMP_FILE ;\ + kubectl patch -n $(NAMESPACE) authorino/$(AUTHORINO_INSTANCE) --type='merge' -p '{"spec":{"image": "$(AUTHORINO_IMAGE)"}}' ;\ + rm -rf $$TEMP_FILE ;\ + } + + +##@ User Apps + +.PHONY: user-apps + +user-apps: ## Deploys talker API and envoy + kubectl -n $(NAMESPACE) apply -f https://raw.githubusercontent.com/kuadrant/authorino-examples/main/talker-api/talker-api-deploy.yaml + kubectl -n $(NAMESPACE) apply -f utils/deploy/envoy.yaml + + +##@ Util + +.PHONY: local-setup local-env-setup local-cleanup sed + +local-setup: local-env-setup + kubectl -n $(NAMESPACE) wait --timeout=300s --for=condition=Available deployments --all + +local-env-setup: + $(MAKE) kind-delete-cluster + $(MAKE) kind-create-cluster + $(MAKE) install-authorino-operator + $(MAKE) deploy-authorino + $(MAKE) user-apps + +local-cleanup: kind ## Delete the "wasm-auth-local" kind cluster. + $(MAKE) kind-delete-cluster + +ifeq ($(shell uname),Darwin) +SED=$(shell which gsed) +else +SED=$(shell which sed) +endif +sed: ## Checks if GNU sed is installed +ifeq ($(SED),) + @echo "Cannot find GNU sed installed." + exit 1 +endif diff --git a/utils/deploy/envoy.yaml b/utils/deploy/envoy.yaml new file mode 100644 index 00000000..fd5f3b20 --- /dev/null +++ b/utils/deploy/envoy.yaml @@ -0,0 +1,279 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + labels: + app: envoy + name: envoy +data: + envoy.yaml: | + static_resources: + clusters: + - name: authorino + connect_timeout: 0.25s + type: STRICT_DNS + lb_policy: ROUND_ROBIN + http2_protocol_options: { } + load_assignment: + cluster_name: authorino + endpoints: + - lb_endpoints: + - endpoint: + address: + socket_address: + address: authorino-authorino-authorization + port_value: 50051 + transport_socket: + name: envoy.transport_sockets.tls + typed_config: + "@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.UpstreamTlsContext + common_tls_context: + validation_context: + trusted_ca: + filename: /etc/ssl/certs/authorino-ca-cert.crt + - name: limitador + connect_timeout: 1s + type: STRICT_DNS + lb_policy: ROUND_ROBIN + http2_protocol_options: { } + load_assignment: + cluster_name: limitador + endpoints: + - lb_endpoints: + - endpoint: + address: + socket_address: + address: limitador + port_value: 8081 + - name: talker-api + connect_timeout: 0.25s + type: STRICT_DNS + lb_policy: ROUND_ROBIN + load_assignment: + cluster_name: talker-api + endpoints: + - lb_endpoints: + - endpoint: + address: + socket_address: + address: talker-api + port_value: 3000 + - name: talker-web + connect_timeout: 0.25s + type: STRICT_DNS + lb_policy: ROUND_ROBIN + load_assignment: + cluster_name: talker-web + endpoints: + - lb_endpoints: + - endpoint: + address: + socket_address: + address: talker-web + port_value: 8888 + - name: opentelemetry + connect_timeout: 0.25s + type: STRICT_DNS + lb_policy: ROUND_ROBIN + http2_protocol_options: { } + load_assignment: + cluster_name: opentelemetry + endpoints: + - lb_endpoints: + - endpoint: + address: + socket_address: + address: otel-collector + port_value: 4317 + listeners: + - address: + socket_address: + address: 0.0.0.0 + port_value: 8000 + filter_chains: + - filters: + - name: envoy.http_connection_manager + typed_config: + "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager + stat_prefix: local + use_remote_address: true + route_config: + name: local_route + virtual_hosts: + - name: local_service + domains: [ '*' ] + routes: + - match: { prefix: /web } + route: + cluster: talker-web + typed_per_filter_config: + envoy.filters.http.ext_authz: + "@type": type.googleapis.com/envoy.extensions.filters.http.ext_authz.v3.ExtAuthzPerRoute + disabled: true + - match: { prefix: / } + route: + cluster: talker-api + rate_limits: + - actions: + - metadata: + metadata_key: + key: "envoy.filters.http.ext_authz" + path: + - key: ext_auth_data + - key: username + descriptor_key: user_id + http_filters: + - name: envoy.filters.http.header_to_metadata + typed_config: + "@type": type.googleapis.com/envoy.extensions.filters.http.header_to_metadata.v3.Config + request_rules: + - header: x-dyn-user-id + on_header_present: + key: user_id + type: STRING + remove: false + - name: envoy.filters.http.wasm + typed_config: + "@type": type.googleapis.com/envoy.extensions.filters.http.wasm.v3.Wasm + config: + name: kuadrant_wasm + root_id: kuadrant_wasm + vm_config: + vm_id: vm.sentinel.kuadrant_wasm + runtime: envoy.wasm.runtime.v8 + code: + local: + filename: /opt/kuadrant/wasm/wasm_shim.wasm + allow_precompiled: true + configuration: + "@type": "type.googleapis.com/google.protobuf.StringValue" + value: > + { + "failureMode": "deny", + "rateLimitPolicies": [ + { + "name": "rlp-ns-A/rlp-name-A", + "domain": "rlp-ns-A/rlp-name-A", + "service": "authorino", + "hostnames": ["*.a.com"], + "rules": [ + { + "data": [ + { + "selector": { + "selector": "unknown.path" + } + } + ] + } + ] + } + ] + } + - name: envoy.filters.http.router + typed_config: + "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router + + # # Uncomment to enable tracing + # tracing: + # provider: + # name: envoy.tracers.opentelemetry + # typed_config: + # "@type": type.googleapis.com/envoy.config.trace.v3.OpenTelemetryConfig + # grpc_service: + # envoy_grpc: + # cluster_name: opentelemetry + # timeout: 1s + # service_name: envoy + admin: + access_log_path: "/tmp/admin_access.log" + address: + socket_address: + address: 0.0.0.0 + port_value: 8001 +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + labels: + app: envoy + name: envoy +spec: + replicas: 1 + selector: + matchLabels: + app: envoy + template: + metadata: + labels: + app: envoy + spec: + containers: + - args: + - --config-path /usr/local/etc/envoy/envoy.yaml + - --service-cluster front-proxy + - --log-level info + - --component-log-level filter:trace,http:debug,router:debug + command: + - /usr/local/bin/envoy + image: envoyproxy/envoy:v1.25-latest + name: envoy + ports: + - containerPort: 8000 + name: web + - containerPort: 8001 + name: admin + volumeMounts: + - mountPath: /usr/local/etc/envoy + name: config + readOnly: true + - mountPath: /etc/ssl/certs/authorino-ca-cert.crt + name: authorino-ca-cert + readOnly: true + subPath: ca.crt + - mountPath: /opt/kuadrant/wasm + name: wasm + volumes: + - configMap: + items: + - key: envoy.yaml + path: envoy.yaml + name: envoy + name: config + - name: authorino-ca-cert + secret: + defaultMode: 420 + secretName: authorino-ca-cert + - name: wasm + hostPath: + path: /opt/kuadrant/wasm +--- +apiVersion: v1 +kind: Service +metadata: + labels: + app: envoy + name: envoy +spec: + ports: + - name: web + port: 8000 + protocol: TCP + selector: + app: envoy +--- +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: ingress-wildcard-host +spec: + rules: + - host: talker-api.127.0.0.1.nip.io + http: + paths: + - backend: + service: + name: envoy + port: + number: 8000 + path: / + pathType: Prefix diff --git a/utils/kind/cluster.yaml b/utils/kind/cluster.yaml new file mode 100644 index 00000000..9ec18f83 --- /dev/null +++ b/utils/kind/cluster.yaml @@ -0,0 +1,9 @@ +--- +kind: Cluster +apiVersion: kind.x-k8s.io/v1alpha4 +nodes: + - role: control-plane + image: kindest/node:v1.30.0 + extraMounts: + - hostPath: $(WASM_PATH) + containerPath: /opt/kuadrant/wasm