Skip to content

Commit

Permalink
Merge pull request #1441 from 3scale/dev-environment-camel-proxy
Browse files Browse the repository at this point in the history
Camel proxy dev environment
  • Loading branch information
eguzki authored Feb 5, 2024
2 parents 9a7a545 + 5d9942e commit 49722c9
Show file tree
Hide file tree
Showing 13 changed files with 357 additions and 7 deletions.
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

0 comments on commit 49722c9

Please sign in to comment.