diff --git a/CHANGELOG.md b/CHANGELOG.md
index 6d7f8c140..268f23a07 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -43,6 +43,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
- Dev environment: keycloak [PR #1439](https://github.com/3scale/APIcast/pull/1439)
+- Dev environment: Camel proxy [PR #1441](https://github.com/3scale/APIcast/pull/1441)
+
## [3.14.0] 2023-07-25
### Fixed
diff --git a/dev-environments/camel-proxy/.gitignore b/dev-environments/camel-proxy/.gitignore
new file mode 100644
index 000000000..1c0baf51d
--- /dev/null
+++ b/dev-environments/camel-proxy/.gitignore
@@ -0,0 +1 @@
+cert/
diff --git a/dev-environments/camel-proxy/Makefile b/dev-environments/camel-proxy/Makefile
new file mode 100644
index 000000000..ae88a493b
--- /dev/null
+++ b/dev-environments/camel-proxy/Makefile
@@ -0,0 +1,43 @@
+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 access upstream powered with TLS
+ @if [ ! -d "$(WORKDIR)/cert" ]; then \
+ echo "$(WORKDIR)/cert does not exist! run make certs!"; \
+ exit 1; \
+ fi
+ $(DOCKER) compose -f docker-compose.yml up --attach gateway
+
+$(WORKDIR)/cert:
+ mkdir -p cert
+
+ifeq ($(origin USER),environment)
+$(WORKDIR)/cert/keystore.jks: USER := $(shell id -u $(USER))
+$(WORKDIR)/cert/keystore.jks: GROUP := $(shell id -g $(USER))
+endif
+$(WORKDIR)/cert/keystore.jks: ## use same JVM version as camel-netty-proxy, currently openjdk 11.0.9
+ $(MAKE) $(WORKDIR)/cert -f $(WORKDIR)/Makefile
+ $(DOCKER) run -t --rm \
+ -v $(WORKDIR)/cert:/tmp/cert \
+ --user $(USER):$(GROUP) \
+ openjdk:11.0.9 \
+ keytool -genkeypair -keystore /tmp/cert/keystore.jks -dname "CN=tls.camel.proxy" -keypass changeit -storepass changeit -alias camel -keyalg RSA -ext SAN=dns:tls.camel.proxy
+ $(DOCKER) run -t --rm \
+ -v $(WORKDIR)/cert:/tmp/cert \
+ --user $(USER):$(GROUP) \
+ openjdk:11.0.9 \
+ keytool -list -v -keystore /tmp/cert/keystore.jks -storepass changeit
+
+.PHONY: certs
+certs: clean
+ $(MAKE) $(WORKDIR)/cert/keystore.jks -f $(WORKDIR)/Makefile
+
+clean:
+ $(DOCKER) compose down --volumes --remove-orphans
+ $(DOCKER) compose -f docker-compose.yml down --volumes --remove-orphans
+ - rm -rf $(WORKDIR)/cert
+
diff --git a/dev-environments/camel-proxy/README.md b/dev-environments/camel-proxy/README.md
new file mode 100644
index 000000000..93ccdb137
--- /dev/null
+++ b/dev-environments/camel-proxy/README.md
@@ -0,0 +1,173 @@
+# Camel PROXY
+
+Development environment to test integration between APIcast and proxies built
+on top of [Camel framework](https://camel.apache.org/components/4.0.x/netty-http-component.html)
+
+This dev environment uses [Camel Netty Proxy example](https://github.com/zregvart/camel-netty-proxy).
+Any request that is received using the HTTP PROXY protocol,
+i.e specifying the absolute form for the request target will be forwarded to the
+target service with the HTTP body converted to uppercase.
+
+Both `http_proxy` and `https_proxy` scenarios are setup.
+
+`http_proxy` use case: APIcast --> camel "uppercase" proxy --> upstream (plain HTTP/1.1)
+
+`https_proxy` use case: APIcast --> camel "uppercase" proxy --> upstream (TLS)
+
+## Create the SSL Certificates
+
+```sh
+make certs
+```
+
+## 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
+```
+
+## Testing `http_proxy` use case: APIcast --> camel proxy --> upstream (plain HTTP/1.1)
+
+```sh
+curl --resolve http-proxy.example.com:8080:127.0.0.1 -v "http://http-proxy.example.com:8080/?user_key=123"
+```
+
+Expected result:
+
+
+
+```
+ Added http-proxy.example.com:8080:127.0.0.1 to DNS cache
+* Hostname http-proxy.example.com was found in DNS cache
+* Trying 127.0.0.1:8080...
+* Connected to http-proxy.example.com (127.0.0.1) port 8080 (#0)
+> GET /?user_key=123 HTTP/1.1
+> Host: http-proxy.example.com:8080
+> User-Agent: curl/7.81.0
+> Accept: */*
+>
+* Mark bundle as not supporting multiuse
+< HTTP/1.1 200 OK
+< Server: openresty
+< Date: Fri, 02 Feb 2024 10:12:56 GMT
+< Content-Type: application/json
+< Content-Length: 254
+< Connection: keep-alive
+< Access-Control-Allow-Credentials: true
+< Access-Control-Allow-Origin: *
+<
+{
+ "ARGS": {
+ "USER_KEY": "123"
+ },
+ "HEADERS": {
+ "ACCEPT": "*/*",
+ "CONNECTION": "KEEP-ALIVE",
+ "HOST": "EXAMPLE.COM",
+ "USER-AGENT": "CURL/7.81.0"
+ },
+ "ORIGIN": "172.21.0.2",
+ "URL": "HTTP://EXAMPLE.COM/GET?USER_KEY=123"
+}
+* Connection #0 to host http-proxy.example.com left intact
+```
+
+
+
+Traffic between APIcast and the camel proxy can be inspected looking at logs from `proxy.socat` service
+
+```
+docker compose -p camel-proxy logs -f proxy.socat
+```
+
+Traffic between the camel proxy and upstream can be inspected looking at logs from `example.com` service
+
+```
+docker compose -p camel-proxy logs -f example.com
+```
+
+Camel proxy can be inspected looking at logs from `camel.proxy` service
+
+```
+docker compose -p camel-proxy logs -f camel.proxy
+```
+
+## Testing `https_proxy` use case: APIcast --> camel proxy --> upstream (TLS)
+
+> TLS Upstream based on service with trusted (well known) CA certificate. `https://echo-api.3scale.net:443`
+
+> Failed trying to setup connection between camel proxy and service with self-signed cert.
+
+> TODO: upstream service running in docker compose env with a self signed cert and import that self signed certificate in the java keystore to be validated by camel.
+
+```sh
+curl --resolve https-proxy.example.com:8080:127.0.0.1 -v "http://https-proxy.example.com:8080/?user_key=123"
+```
+
+Expected result:
+
+
+
+```
+* Added https-proxy.example.com:8080:127.0.0.1 to DNS cache
+* Hostname https-proxy.example.com was found in DNS cache
+* Trying 127.0.0.1:8080...
+* Connected to https-proxy.example.com (127.0.0.1) port 8080 (#0)
+> GET /?user_key=123 HTTP/1.1
+> Host: https-proxy.example.com:8080
+> User-Agent: curl/7.81.0
+> Accept: */*
+>
+* Mark bundle as not supporting multiuse
+< HTTP/1.1 200 OK
+< Date: Fri, 02 Feb 2024 10:17:33 GMT
+< Content-Type: application/json
+< Transfer-Encoding: chunked
+< Connection: keep-alive
+< x-envoy-upstream-service-time: 0
+< vary: Origin
+< x-3scale-echo-api: echo-api/1.0.3
+< x-content-type-options: nosniff
+< server: envoy
+<
+{
+ "METHOD": "GET",
+ "PATH": "/",
+ "ARGS": "USER_KEY=123",
+ "BODY": "",
+ "HEADERS": {
+ "HTTP_VERSION": "HTTP/1.1",
+ "HTTP_HOST": "ECHO-API.3SCALE.NET:443",
+ "HTTP_ACCEPT": "*/*",
+ "HTTP_USER_AGENT": "CURL/7.81.0",
+ "HTTP_X_FORWARDED_FOR": "81.61.128.254",
+ "HTTP_X_FORWARDED_PROTO": "HTTPS",
+ "HTTP_X_ENVOY_EXTERNAL_ADDRESS": "81.61.128.254",
+ "HTTP_X_REQUEST_ID": "F0463914-3C0B-4CA3-9E61-5E40C01DBFD3",
+ "HTTP_X_ENVOY_EXPECTED_RQ_TIMEOUT_MS": "15000"
+ },
+ "UUID": "500CA72C-A106-4BFB-91F5-0C2D2D78CF05"
+* Connection #0 to host https-proxy.example.com left intact
+```
+
+
+
+Camel proxy can be inspected looking at logs from `tls.camel.proxy` service
+
+```
+docker compose -p camel-proxy logs -f tls.camel.proxy
+```
+
+## Clean env
+
+```sh
+make clean
+```
diff --git a/dev-environments/camel-proxy/apicast-config.json b/dev-environments/camel-proxy/apicast-config.json
new file mode 100644
index 000000000..91201afa7
--- /dev/null
+++ b/dev-environments/camel-proxy/apicast-config.json
@@ -0,0 +1,70 @@
+{
+ "services": [
+ {
+ "id": "1",
+ "backend_version": "1",
+ "proxy": {
+ "hosts": ["http-proxy.example.com"],
+ "api_backend": "http://example.com:80/get",
+ "backend": {
+ "endpoint": "http://127.0.0.1:8081",
+ "host": "backend"
+ },
+ "policy_chain": [
+ {
+ "name": "apicast.policy.camel",
+ "configuration": {
+ "http_proxy": "http://proxy.socat:8080/"
+ }
+ },
+ {
+ "name": "apicast.policy.apicast"
+ }
+ ],
+ "proxy_rules": [
+ {
+ "http_method": "GET",
+ "pattern": "/",
+ "metric_system_name": "hits",
+ "delta": 1,
+ "parameters": [],
+ "querystring_parameters": {}
+ }
+ ]
+ }
+ },
+ {
+ "id": "2",
+ "backend_version": "1",
+ "proxy": {
+ "hosts": ["https-proxy.example.com"],
+ "api_backend": "https://echo-api.3scale.net:443",
+ "backend": {
+ "endpoint": "http://127.0.0.1:8081",
+ "host": "backend"
+ },
+ "policy_chain": [
+ {
+ "name": "apicast.policy.camel",
+ "configuration": {
+ "https_proxy": "http://tls.camel.proxy:8443/"
+ }
+ },
+ {
+ "name": "apicast.policy.apicast"
+ }
+ ],
+ "proxy_rules": [
+ {
+ "http_method": "GET",
+ "pattern": "/",
+ "metric_system_name": "hits",
+ "delta": 1,
+ "parameters": [],
+ "querystring_parameters": {}
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/dev-environments/camel-proxy/docker-compose.yml b/dev-environments/camel-proxy/docker-compose.yml
new file mode 100644
index 000000000..b1e78f153
--- /dev/null
+++ b/dev-environments/camel-proxy/docker-compose.yml
@@ -0,0 +1,61 @@
+---
+version: '3.8'
+services:
+ gateway:
+ image: ${IMAGE_NAME:-apicast-test}
+ depends_on:
+ - proxy.socat
+ - camel.proxy
+ - tls.camel.proxy
+ - example.com
+ - actual.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
+ proxy.socat:
+ image: alpine/socat:1.7.4.4
+ container_name: proxy
+ restart: unless-stopped
+ command: "-d -v -d TCP-LISTEN:8080,reuseaddr,fork TCP:camel.proxy:8080"
+ camel.proxy:
+ image: zregvart/camel-netty-proxy
+ container_name: camel.proxy
+ expose:
+ - "8080:8080"
+ tls.camel.proxy:
+ image: quay.io/zregvart/camel-netty-proxy
+ container_name: tls.camel.proxy
+ entrypoint:
+ - java
+ - -Dcom.sun.net.ssl.checkRevocation=false
+ - -cp
+ - camel-netty-proxy.jar:lib/*
+ - com.github.zregvart.cnp.ProxyApp
+ expose:
+ - "8443:8443"
+ volumes:
+ - ./cert/keystore.jks:/tls/keystore.jks
+ example.com:
+ image: alpine/socat:1.7.4.4
+ container_name: example.com
+ command: "-d -v -d TCP-LISTEN:80,reuseaddr,fork TCP:actual.upstream:80"
+ expose:
+ - "443"
+ restart: unless-stopped
+ actual.upstream:
+ image: kennethreitz/httpbin
+ container_name: actual.upstream
+ expose:
+ - "80"
diff --git a/dev-environments/http-proxy-plain-http-upstream/Makefile b/dev-environments/http-proxy-plain-http-upstream/Makefile
index a616c6e74..ccd279341 100644
--- a/dev-environments/http-proxy-plain-http-upstream/Makefile
+++ b/dev-environments/http-proxy-plain-http-upstream/Makefile
@@ -6,7 +6,7 @@ WORKDIR := $(patsubst %/,%,$(dir $(MKFILE_PATH)))
DOCKER ?= $(shell which docker 2> /dev/null || echo "docker")
gateway: ## run gateway configured to access upstream powered with TLS
- $(DOCKER) compose -f docker-compose.yml up --attach gateway
+ $(DOCKER) compose -f docker-compose.yml run --service-ports gateway
clean:
$(DOCKER) compose down --volumes --remove-orphans
diff --git a/dev-environments/https-proxy-upstream-tlsv1.3/Makefile b/dev-environments/https-proxy-upstream-tlsv1.3/Makefile
index 741676947..fe6780662 100644
--- a/dev-environments/https-proxy-upstream-tlsv1.3/Makefile
+++ b/dev-environments/https-proxy-upstream-tlsv1.3/Makefile
@@ -6,7 +6,7 @@ WORKDIR := $(patsubst %/,%,$(dir $(MKFILE_PATH)))
DOCKER ?= $(shell which docker 2> /dev/null || echo "docker")
gateway: ## run gateway configured to access upstream powered with TLS
- $(DOCKER) compose -f docker-compose.yml up --attach gateway
+ $(DOCKER) compose -f docker-compose.yml run --service-ports gateway
clean:
$(DOCKER) compose down --volumes --remove-orphans
diff --git a/dev-environments/keycloak-env/Makefile b/dev-environments/keycloak-env/Makefile
index 622752bea..87695cedb 100644
--- a/dev-environments/keycloak-env/Makefile
+++ b/dev-environments/keycloak-env/Makefile
@@ -6,7 +6,7 @@ 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 up --attach gateway
+ $(DOCKER) compose -f docker-compose.yml run --service-ports gateway
keycloak-data: ## Keycloak provisioning
# Keycloak 23.0.4 REST API reference
diff --git a/dev-environments/listen-tls/Makefile b/dev-environments/listen-tls/Makefile
index 741676947..fe6780662 100644
--- a/dev-environments/listen-tls/Makefile
+++ b/dev-environments/listen-tls/Makefile
@@ -6,7 +6,7 @@ WORKDIR := $(patsubst %/,%,$(dir $(MKFILE_PATH)))
DOCKER ?= $(shell which docker 2> /dev/null || echo "docker")
gateway: ## run gateway configured to access upstream powered with TLS
- $(DOCKER) compose -f docker-compose.yml up --attach gateway
+ $(DOCKER) compose -f docker-compose.yml run --service-ports gateway
clean:
$(DOCKER) compose down --volumes --remove-orphans
diff --git a/dev-environments/opentelemetry-instrumented-gateway/Makefile b/dev-environments/opentelemetry-instrumented-gateway/Makefile
index 60f9565e4..7e0707631 100644
--- a/dev-environments/opentelemetry-instrumented-gateway/Makefile
+++ b/dev-environments/opentelemetry-instrumented-gateway/Makefile
@@ -6,7 +6,7 @@ WORKDIR := $(patsubst %/,%,$(dir $(MKFILE_PATH)))
DOCKER ?= $(shell which docker 2> /dev/null || echo "docker")
gateway: ## run gateway configured to access plain HTTP 1.1 upstream
- $(DOCKER) compose -f docker-compose.yml up --attach gateway
+ $(DOCKER) compose -f docker-compose.yml run --service-ports gateway
clean:
$(DOCKER) compose down --volumes --remove-orphans
diff --git a/dev-environments/plain-http-upstream/Makefile b/dev-environments/plain-http-upstream/Makefile
index 60f9565e4..7e0707631 100644
--- a/dev-environments/plain-http-upstream/Makefile
+++ b/dev-environments/plain-http-upstream/Makefile
@@ -6,7 +6,7 @@ WORKDIR := $(patsubst %/,%,$(dir $(MKFILE_PATH)))
DOCKER ?= $(shell which docker 2> /dev/null || echo "docker")
gateway: ## run gateway configured to access plain HTTP 1.1 upstream
- $(DOCKER) compose -f docker-compose.yml up --attach gateway
+ $(DOCKER) compose -f docker-compose.yml run --service-ports gateway
clean:
$(DOCKER) compose down --volumes --remove-orphans
diff --git a/dev-environments/upstream-tlsv1.3/Makefile b/dev-environments/upstream-tlsv1.3/Makefile
index 741676947..fe6780662 100644
--- a/dev-environments/upstream-tlsv1.3/Makefile
+++ b/dev-environments/upstream-tlsv1.3/Makefile
@@ -6,7 +6,7 @@ WORKDIR := $(patsubst %/,%,$(dir $(MKFILE_PATH)))
DOCKER ?= $(shell which docker 2> /dev/null || echo "docker")
gateway: ## run gateway configured to access upstream powered with TLS
- $(DOCKER) compose -f docker-compose.yml up --attach gateway
+ $(DOCKER) compose -f docker-compose.yml run --service-ports gateway
clean:
$(DOCKER) compose down --volumes --remove-orphans