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

Camel proxy dev environment #1441

Merged
merged 3 commits into from
Feb 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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 CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions dev-environments/camel-proxy/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
cert/
43 changes: 43 additions & 0 deletions dev-environments/camel-proxy/Makefile
Original file line number Diff line number Diff line change
@@ -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

173 changes: 173 additions & 0 deletions dev-environments/camel-proxy/README.md
Original file line number Diff line number Diff line change
@@ -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:

<details>

```
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
```

</details>

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:

<details>

```
* 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
```

</details>

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
```
70 changes: 70 additions & 0 deletions dev-environments/camel-proxy/apicast-config.json
Original file line number Diff line number Diff line change
@@ -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": {}
}
]
}
}
]
}
61 changes: 61 additions & 0 deletions dev-environments/camel-proxy/docker-compose.yml
Original file line number Diff line number Diff line change
@@ -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"
2 changes: 1 addition & 1 deletion dev-environments/http-proxy-plain-http-upstream/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion dev-environments/https-proxy-upstream-tlsv1.3/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion dev-environments/keycloak-env/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion dev-environments/listen-tls/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Loading
Loading