diff --git a/dev-environments/keycloak-env/Makefile b/dev-environments/keycloak-env/Makefile new file mode 100644 index 000000000..71ff70a44 --- /dev/null +++ b/dev-environments/keycloak-env/Makefile @@ -0,0 +1,13 @@ +SHELL = /usr/bin/env bash -o pipefail +.SHELLFLAGS = -ec +.DEFAULT_GOAL := gateway +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +WORKDIR := $(patsubst %/,%,$(dir $(MKFILE_PATH))) +DOCKER ?= $(shell which docker 2> /dev/null || echo "docker") + +gateway: ## run gateway configured to keycloak integration + $(DOCKER) compose -f docker-compose.yml run --service-ports gateway + +clean: + $(DOCKER) compose down --volumes --remove-orphans + $(DOCKER) compose -f docker-compose.yml down --volumes --remove-orphans diff --git a/dev-environments/keycloak-env/README.md b/dev-environments/keycloak-env/README.md new file mode 100644 index 000000000..ae5d37533 --- /dev/null +++ b/dev-environments/keycloak-env/README.md @@ -0,0 +1,45 @@ +# Using 3scale API Gateway with OpenID Connect + +User (jwt) -> APIcast --> upstream plain HTTP 1.1 upstream + +APIcast configured with plain HTTP 1.1 upstream server equipped with traffic rely agent (socat) + +## Run the gateway + +Running local `apicast-test` docker image + +```sh +make gateway +``` + +Running custom apicast image + +```sh +make gateway IMAGE_NAME=quay.io/3scale/apicast:latest +``` + +Traffic between the proxy and upstream can be inspected looking at logs from `example.com` service + +``` +docker compose -p keycloak-env logs -f example.com +``` + +## Testing + +`GET` request + +```sh +curl --resolve get.example.com:8080:127.0.0.1 -v "http://get.example.com:8080/?user_key=123" +``` + +`POST` request + +```sh +curl --resolve post.example.com:8080:127.0.0.1 -v -X POST "http://post.example.com:8080/?user_key=123" +``` + +## Clean env + +```sh +make clean +``` diff --git a/dev-environments/keycloak-env/apicast-config.json b/dev-environments/keycloak-env/apicast-config.json new file mode 100644 index 000000000..9be1114e0 --- /dev/null +++ b/dev-environments/keycloak-env/apicast-config.json @@ -0,0 +1,151 @@ +{ + "services": [ + { + "id": 2, + "backend_version": "oauth", + "account_id": 2, + "name": "API", + "description": null, + "txt_support": null, + "created_at": "2024-01-16T13:46:50Z", + "updated_at": "2024-01-19T22:13:30Z", + "logo_file_name": null, + "logo_content_type": null, + "logo_file_size": null, + "state": "incomplete", + "intentions_required": false, + "terms": null, + "buyers_manage_apps": true, + "buyers_manage_keys": true, + "custom_keys_enabled": true, + "buyer_plan_change_permission": "request", + "buyer_can_select_plan": false, + "notification_settings": null, + "default_application_plan_id": 7, + "default_service_plan_id": 5, + "tenant_id": 2, + "system_name": "api", + "mandatory_app_key": true, + "buyer_key_regenerate_enabled": true, + "referrer_filters_required": false, + "deployment_option": "self_managed", + "kubernetes_service_link": null, + "proxiable?": true, + "backend_authentication_type": "service_token", + "backend_authentication_value": "my_token", + "proxy": { + "service_id": 2, + "id": 2, + "tenant_id": 2, + "endpoint": "https://prod.example.com:443", + "deployed_at": null, + "auth_app_key": "app_key", + "auth_app_id": "app_id", + "auth_user_key": "user_key", + "credentials_location": "query", + "error_auth_failed": "Authentication failed", + "error_auth_missing": "Authentication parameters missing", + "created_at": "2024-01-16T13:46:51Z", + "updated_at": "2024-01-19T22:13:30Z", + "error_status_auth_failed": 403, + "error_headers_auth_failed": "text/plain; charset=us-ascii", + "error_status_auth_missing": 403, + "error_headers_auth_missing": "text/plain; charset=us-ascii", + "error_no_match": "No Mapping Rule matched", + "error_status_no_match": 404, + "error_headers_no_match": "text/plain; charset=us-ascii", + "secret_token": "Shared_secret_sent_from_proxy_to_API_backend_00000000", + "hostname_rewrite": "", + "oauth_login_url": null, + "sandbox_endpoint": "https://stg.example.com:443", + "api_test_path": "/", + "api_test_success": null, + "apicast_configuration_driven": true, + "oidc_issuer_endpoint": "https://my-client-id:my-client-secret@keycloak/auth/realms/basic", + "lock_version": 4, + "authentication_method": "oidc", + "oidc_issuer_type": "keycloak", + "error_headers_limits_exceeded": "text/plain; charset=us-ascii", + "error_status_limits_exceeded": 429, + "error_limits_exceeded": "Usage limit exceeded", + "staging_domain": "stg.example.com", + "production_domain": "prod.example.com", + "endpoint_port": 443, + "api_backend": "http://example.com/get", + "valid?": true, + "service_backend_version": "oauth", + "hosts": [ + "prod.example.com", + "stg.example.com" + ], + "backend": { + "endpoint": "http://127.0.0.1:8081", + "host": "backend" + }, + "policy_chain": [ + { + "name": "token_introspection", + "version": "builtin", + "configuration": { + "auth_type": "use_3scale_oidc_issuer_endpoint" + } + }, + { + "name": "apicast", + "version": "builtin", + "configuration": {} + } + ], + "jwt_claim_with_client_id": "azp", + "jwt_claim_with_client_id_type": "plain", + "proxy_rules": [ + { + "id": 2, + "proxy_id": 2, + "http_method": "GET", + "pattern": "/", + "metric_id": 6, + "metric_system_name": "hits", + "delta": 1, + "tenant_id": 2, + "redirect_url": null, + "position": 1, + "last": false, + "owner_id": 2, + "owner_type": "Proxy", + "parameters": [], + "querystring_parameters": {} + } + ] + } + } + }, + { + "id": "1", + "backend_version": "1", + "proxy": { + "hosts": ["get.example.com"], + "api_backend": "http://example.com/get", + "backend": { + "endpoint": "http://127.0.0.1:8081", + "host": "backend" + }, + "policy_chain": [ + { + "name": "apicast.policy.apicast" + } + ], + "proxy_rules": [ + { + "http_method": "GET", + "pattern": "/", + "metric_system_name": "hits", + "delta": 1, + "parameters": [], + "querystring_parameters": {} + } + ] + } + } + ] +} diff --git a/dev-environments/keycloak-env/docker-compose.yml b/dev-environments/keycloak-env/docker-compose.yml new file mode 100644 index 000000000..7e671800a --- /dev/null +++ b/dev-environments/keycloak-env/docker-compose.yml @@ -0,0 +1,34 @@ +--- +version: '3.8' +services: + gateway: + image: ${IMAGE_NAME:-apicast-test} + depends_on: + - example.com + - two.upstream + environment: + THREESCALE_CONFIG_FILE: /tmp/config.json + THREESCALE_DEPLOYMENT_ENV: staging + APICAST_CONFIGURATION_LOADER: lazy + APICAST_WORKERS: 1 + APICAST_LOG_LEVEL: debug + APICAST_CONFIGURATION_CACHE: "0" + expose: + - "8080" + - "8090" + ports: + - "8080:8080" + - "8090:8090" + volumes: + - ./apicast-config.json:/tmp/config.json + example.com: + image: alpine/socat:1.7.4.4 + container_name: example.com + command: "-d -v -d TCP-LISTEN:80,reuseaddr,fork TCP:two.upstream:80" + expose: + - "80" + restart: unless-stopped + two.upstream: + image: kennethreitz/httpbin + expose: + - "80"