A Spring Boot REST service for testing and diagnosing HTTP routes in Kubernetes clusters with Istio service mesh. It acts as a configurable HTTP proxy that forwards requests to any target URL and returns the response along with timing, status and header information. Additionally it exposes Kubernetes and Istio diagnostic endpoints to inspect the service mesh configuration from within the cluster.
- HTTP proxy — forward GET, POST, PUT, DELETE, PATCH, HEAD and OPTIONS requests to any URL, with optional header forwarding and custom headers
- Kubernetes context — read namespace, pod name and Istio sidecar status directly from the Kubernetes API
- Istio diagnostics — list VirtualServices, DestinationRules, Gateways, ServiceEntries, Sidecars, EnvoyFilters, PeerAuthentications, RequestAuthentications and AuthorizationPolicies
- Istio full report — fetch all Envoy configurations and error statistics of the Istio sidecar
- URL correlation — check whether a given URL is covered by a VirtualService and which routes/DestinationRules apply
- TLS inspection — open a direct TLS connection to a target and return protocol, cipher suite, certificate chain and SPIFFE/mTLS information
- Web UI — browser-based frontend to interact with all endpoints
- OpenAPI/Swagger — fully documented REST API with SpringDoc
| Component | Version |
|---|---|
| Java | 25 |
| Spring Boot | 4.0.6 |
| Servlet Container | Jetty (Tomcat excluded) |
| OpenAPI | SpringDoc 3.0.3 |
| Kubernetes Client | client-java 26.0.0 |
| Observability | Micrometer Tracing + Actuator |
mvn packagemvn verify starts the application as part of the integration test phase, calls /api-docs, writes the result to target/openapi.json and stops the application again. The file at the project root is the committed result of the last run.
mvn verify
cp target/openapi.json openapi.jsonUses the Red Hat UBI9 base image with the full OpenJDK 25 JRE. Includes Spring Boot AOT processing and CDS (Class Data Sharing) archive for faster startup.
docker build -f Dockerfile25 -t javahttpclient:jre .Uses jlink to create a custom JRE containing only the required modules, then packages it into a gcr.io/distroless/cc image. Includes AOT processing and a CDS archive built with the custom JRE.
docker build -f Dockerfile25Jlink -t javahttpclient:jlink .javahttpclient jre 510MB
javahttpclient jlink 295MB
docker run --rm --name httpclient --publish 8080:8080 javahttpclient:jre
docker run --rm --name httpclient --publish 8080:8080 javahttpclient:jlinkbash multiarch-build.shdocker build -t wlanboy/javahttpclient:latest .The full OpenAPI 3.1 specification is available in openapi.json.
Interactive Swagger UI: http://localhost:8080/swagger-ui/index.html
Forwards an HTTP request with the specified method, URL and optional body to the target system and returns the response.
Request body (application/json):
| Field | Type | Required | Description |
|---|---|---|---|
url |
string | yes | Target URL — must start with http:// or https:// |
method |
string | yes | HTTP method: GET, POST, PUT, DELETE, PATCH, HEAD, OPTIONS |
body |
string | no | Optional request body |
contentType |
string | no | Content-Type of the body, e.g. application/json |
copyHeaders |
boolean | no | Copy incoming request headers to the forwarded request |
customHeaders |
object | no | Additional headers to add, as {"Header-Name": "value"} |
Responses: 200 response from target, 400 validation error, 502 connection error.
Simple GET request:
curl -X POST http://localhost:8080/client \
-H 'Content-Type: application/json' \
-d '{"url": "https://github.com", "method": "GET", "copyHeaders": false}'POST with body and custom content type:
curl -X POST http://localhost:8080/client \
-H 'Content-Type: application/json' \
-d '{
"url": "https://httpbin.org/post",
"method": "POST",
"body": "{\"hello\": \"world\"}",
"contentType": "application/json",
"copyHeaders": false
}'Forward incoming headers and add a custom header:
curl -X POST http://localhost:8080/client \
-H 'Content-Type: application/json' \
-H 'X-Correlation-Id: abc-123' \
-d '{
"url": "http://my-service.default.svc.cluster.local/api/v1/data",
"method": "GET",
"copyHeaders": true,
"customHeaders": {"Authorization": "Bearer mytoken"}
}'DNS resolution via a MirrorService:
curl -X POST http://localhost:8080/client \
-H 'Content-Type: application/json' \
-d '{
"url": "http://gmk:8003/resolve/google.com",
"method": "GET",
"copyHeaders": false
}'Returns the current namespace, pod name and Istio sidecar status. Used by the web UI navbar on page load.
curl http://localhost:8080/api/k8s/contextShows whether the Kubernetes API client was initialized successfully and lists supported Istio resource types and API versions.
curl http://localhost:8080/api/k8s/statusLists specific Istio resources in a namespace. The namespace query parameter defaults to default.
Supported types: virtualservices, destinationrules, gateways, serviceentries, sidecars, envoyfilters, peerauthentications, requestauthentications, authorizationpolicies
# List all VirtualServices in the default namespace
curl "http://localhost:8080/api/k8s/istio/virtualservices"
# List DestinationRules in a specific namespace
curl "http://localhost:8080/api/k8s/istio/destinationrules?namespace=production"
# List PeerAuthentications (mTLS policies)
curl "http://localhost:8080/api/k8s/istio/peerauthentications?namespace=istio-system"Fetches all Envoy configurations and error statistics of the Istio sidecar. Returns 200 even on error — the body contains the error description in that case.
curl http://localhost:8080/api/k8s/istio/full-reportChecks whether the given URL is covered by a VirtualService and which routes and DestinationRules apply.
curl "http://localhost:8080/api/k8s/correlate?url=http://my-service.default.svc.cluster.local/api/v1&namespace=default"Opens a direct TLS connection to the target URL and returns protocol, cipher suite, the full certificate chain and SPIFFE/mTLS information. The URL must use https://.
curl "http://localhost:8080/api/k8s/tls?url=https://example.com"
# Inspect mTLS within the mesh
curl "http://localhost:8080/api/k8s/tls?url=https://my-service.default.svc.cluster.local"mirrord lets you run the application locally while it intercepts traffic from a pod running in the cluster — useful for debugging without a full cluster deployment.
# Install mirrord
curl -fsSL https://raw.githubusercontent.com/metalbear-co/mirrord/main/scripts/install.sh | bash
# Look up the target pod
POD=$(kubectl get pod -n javahttpclient -l app=javahttpclient -o jsonpath='{.items[0].metadata.name}')
# Run with Maven (hot reload)
mirrord exec -n javahttpclient --target deployment/javahttpclient -- mvn spring-boot:run
# Run the packaged JAR against a specific pod
mirrord exec -n javahttpclient --target pod/$POD -- java -jar target/javahttpclient-0.0.1-SNAPSHOT.jar
# Run the packaged JAR against the deployment
mirrord exec -n javahttpclient --target deployment/javahttpclient -- java -jar target/javahttpclient-0.0.1-SNAPSHOT.jarThe chart is located in javahttpclient-chart/. It includes Deployment, Service, ServiceAccount, RBAC, ConfigMap, Certificate, Gateway and VirtualService templates.
# Install
helm install httpclient ./javahttpclient-chart -n clients --create-namespace
# Verify
kubectl get gateway,virtualservice -n clients
kubectl get secret httpclient-tls -n istio-ingress
# Upgrade
helm upgrade httpclient ./javahttpclient-chart -n clients
# Uninstall
helm uninstall httpclient -n clients- MirrorService — echo/mirror service for testing HTTP routing and response simulation



