api-management-proxy v1.0.0
API-Management-Endpoint mit OAuth-2.0 (Keycloak) + Rate-Limiting + Message-Mapping zu externer API
Voraussetzungen
- tenant camel-k crd integrations.camel.apache.org
- tenant apisix deploy apisix -n apisix
- hub keycloak sts keycloak-keycloakx -n keycloak
Parameter
-
tenant *Pflichtschema:
{"pattern": "^[a-z][a-z0-9-]{1,30}$", "type": "string"} -
instance *Pflichtschema:
{"pattern": "^[a-z][a-z0-9-]{1,30}$", "type": "string"} -
route_uri default:
/api/v1/priceschema:{"pattern": "^/[a-zA-Z0-9/_-]+$", "type": "string"} -
rate_limit_count default:
60schema:{"maximum": 10000, "minimum": 1, "type": "integer"} -
rate_limit_window default:
60schema:{"maximum": 3600, "minimum": 1, "type": "integer"} -
upstream_api default:
https://api.coinbase.com/v2/prices/BTC-EUR/spotschema:{"pattern": "^https?://.+", "type": "string"} -
realm default:
demo-realmschema:{"minLength": 1, "type": "string"}
Komponenten (2)
Phase 2
tenant
declarative
camel-integration
waitFor: integration-ready
Template anzeigen
apiVersion: camel.apache.org/v1
kind: Integration
metadata:
name: ${INSTANCE}-proxy
namespace: ipaas-flows
labels:
${RECIPE_LABELS}
spec:
dependencies:
- mvn:org.apache.camel.quarkus:camel-quarkus-jsonpath
- mvn:org.apache.camel.quarkus:camel-quarkus-http
traits:
service:
enabled: true
ingress:
enabled: false
# OpenTelemetry — Spans gehen via Tenant-Alloy (4317 OTLP-gRPC) zu Hub-Tempo
# Camel-K 2.10: Trait heißt `telemetry`. service-name wird aus dem
# Integration-Namen abgeleitet ({INSTANCE}-proxy).
telemetry:
enabled: true
endpoint: http://alloy.monitoring.svc.cluster.local:4317
sampler: "on"
flows:
- from:
uri: platform-http:${ROUTE_URI}
parameters:
httpMethodRestrict: GET,POST
steps:
# 1. Inbound-Logging (Request-Mapping startet hier)
- log:
message: "${INSTANCE} REQ headers=${headers} body=${body}"
# 2. Request-Mapping: timestamp + correlation-id setzen
- setHeader:
name: X-Correlation-Id
simple: "${exchangeId}"
- setHeader:
name: X-Request-Time
simple: "${date:now:yyyy-MM-dd'T'HH:mm:ss'Z'}"
# 3. HTTP-Outbound-Headers vorbereiten (Camel-Required)
- removeHeaders:
pattern: "CamelHttp*"
- setHeader:
name: CamelHttpMethod
constant: GET
- setHeader:
name: Accept
constant: application/json
- setBody:
constant: ""
# 4. Externe API aufrufen (Message-Mapping → Backend)
- to:
uri: "${UPSTREAM_API}"
# 5. Response-Mapping: Backend-Response strukturiert anreichern
- log:
message: "${INSTANCE} UPSTREAM ${header.CamelHttpResponseCode}: ${body}"
- setHeader:
name: upstream_status
simple: "${header.CamelHttpResponseCode}"
- setHeader:
name: upstream_price
jsonpath: "$.data.amount"
- setBody:
simple: |-
{
"instance": "${INSTANCE}",
"tenant": "${TENANT}",
"correlation_id": "${header.X-Correlation-Id}",
"request_time": "${header.X-Request-Time}",
"upstream_status": ${header.upstream_status},
"data": {
"asset": "bitcoin",
"currency": "EUR",
"price": "${header.upstream_price}"
}
}
- setHeader:
name: Content-Type
constant: application/json
- log:
message: "${INSTANCE} RESP: ${body}"
Phase 3
tenant
imperative
apisix-route
Template anzeigen
#!/usr/bin/env bash
# APISIX-Route mit OAuth-2.0 (Keycloak) + Rate-Limiting → Camel-K-Backend
set -euo pipefail
ROUTE_ID="${INSTANCE}-apim"
ADMIN_KEY=$(VAULT_ADDR=https://vault.contiva.cloud vault kv get -field=api_key secret/ipaas-platform/tenants/${TENANT}/apisix/admin)
CLIENT_SECRET=$(VAULT_ADDR=https://vault.contiva.cloud vault kv get -field=client_secret secret/ipaas-platform/hub/keycloak/${REALM}-client)
CLIENT_ID_VAL=$(VAULT_ADDR=https://vault.contiva.cloud vault kv get -field=client_id secret/ipaas-platform/hub/keycloak/${REALM}-client)
KUBECONFIG="$TENANT_KUBECONFIG" kubectl -n apisix port-forward svc/apisix-admin 19180:9180 >/tmp/ap-admin-${INSTANCE}.log 2>&1 &
PF=$!
trap "kill $PF 2>/dev/null || true" EXIT
sleep 3
cat > /tmp/route-${INSTANCE}.json <<JSON
{
"id": "$ROUTE_ID",
"name": "${INSTANCE}-api-management",
"uri": "${ROUTE_URI}",
"methods": ["GET", "POST"],
"labels": {
"recipe.ipaas/name": "${RECIPE_NAME}",
"recipe.ipaas/version": "${RECIPE_VERSION}",
"recipe.ipaas/instance": "${INSTANCE}",
"recipe.ipaas/tenant": "${TENANT}"
},
"plugins": {
"openid-connect": {
"discovery": "https://auth.ctva.it/realms/${REALM}/.well-known/openid-configuration",
"client_id": "$CLIENT_ID_VAL",
"client_secret": "$CLIENT_SECRET",
"realm": "${REALM}",
"bearer_only": true,
"ssl_verify": false,
"set_userinfo_header": false,
"set_id_token_header": false,
"set_access_token_header": false
},
"limit-count": {
"count": ${RATE_LIMIT_COUNT},
"time_window": ${RATE_LIMIT_WINDOW},
"key_type": "var",
"key": "consumer_name",
"rejected_code": 429,
"rejected_msg": "Rate limit exceeded — ${RATE_LIMIT_COUNT} req/${RATE_LIMIT_WINDOW}s",
"policy": "local"
},
"response-rewrite": {
"headers": {
"set": {
"X-RateLimit-Policy": "${RATE_LIMIT_COUNT}/${RATE_LIMIT_WINDOW}s",
"X-Recipe-Instance": "${INSTANCE}"
}
}
},
"proxy-rewrite": {
"uri": "${ROUTE_URI}"
}
},
"upstream": {
"type": "roundrobin",
"scheme": "http",
"nodes": {
"${INSTANCE}-proxy.ipaas-flows.svc.cluster.local:80": 1
},
"timeout": {
"connect": 6,
"send": 30,
"read": 30
}
}
}
JSON
curl -sf -X PUT \
-H "X-API-KEY: $ADMIN_KEY" \
-H "Content-Type: application/json" \
-d @/tmp/route-${INSTANCE}.json \
"http://127.0.0.1:19180/apisix/admin/routes/$ROUTE_ID" >/dev/null
echo "✓ APISIX API-Mgmt-Route $ROUTE_ID (URI ${ROUTE_URI}, ${RATE_LIMIT_COUNT}req/${RATE_LIMIT_WINDOW}s) deployed"
Deployed Instances (1)
| Name | Tenant | Phase | Erstellt |
|---|---|---|---|
| btc-price | acme | Applying | 2026-04-29T14:40:06Z |