← Recipes

api-management-proxy v1.0.0

API-Management-Endpoint mit OAuth-2.0 (Keycloak) + Rate-Limiting + Message-Mapping zu externer API

↗ Deploy Instance

Voraussetzungen

  • tenant camel-k crd integrations.camel.apache.org
  • tenant apisix deploy apisix -n apisix
  • hub keycloak sts keycloak-keycloakx -n keycloak

Parameter

  • tenant *Pflicht
    schema: {"pattern": "^[a-z][a-z0-9-]{1,30}$", "type": "string"}
  • instance *Pflicht
    schema: {"pattern": "^[a-z][a-z0-9-]{1,30}$", "type": "string"}
  • route_uri default: /api/v1/price
    schema: {"pattern": "^/[a-zA-Z0-9/_-]+$", "type": "string"}
  • rate_limit_count default: 60
    schema: {"maximum": 10000, "minimum": 1, "type": "integer"}
  • rate_limit_window default: 60
    schema: {"maximum": 3600, "minimum": 1, "type": "integer"}
  • upstream_api default: https://api.coinbase.com/v2/prices/BTC-EUR/spot
    schema: {"pattern": "^https?://.+", "type": "string"}
  • realm default: demo-realm
    schema: {"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