From 95f9b611b3ffe57a256a0df12fdd3458e3b1ca1e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Tailland?= Date: Fri, 21 Aug 2026 14:53:52 +0200 Subject: [PATCH] Capture request/response bodies for audit-log via pre/post-function Body capture lives in dedicated audit-log-body-capture(-bindings).yaml files, separate from audit-log.yaml itself, so they can be dropped without touching the base logging plugin (degrades gracefully to metadata-only via nil custom_fields). Response body captured in body_filter (chunk-accumulated) rather than the log phase, which cannot call kong.response.get_raw_body() directly. --- kong/kustomization.yaml | 4 +++ kong/mcp/audit-log-body-capture-bindings.yaml | 35 +++++++++++++++++++ kong/mcp/audit-log-body-capture.yaml | 27 ++++++++++++++ kong/mcp/audit-log.yaml | 7 +++- .../rest/audit-log-body-capture-bindings.yaml | 35 +++++++++++++++++++ kong/rest/audit-log-body-capture.yaml | 27 ++++++++++++++ kong/rest/audit-log.yaml | 7 +++- 7 files changed, 140 insertions(+), 2 deletions(-) create mode 100644 kong/mcp/audit-log-body-capture-bindings.yaml create mode 100644 kong/mcp/audit-log-body-capture.yaml create mode 100644 kong/rest/audit-log-body-capture-bindings.yaml create mode 100644 kong/rest/audit-log-body-capture.yaml diff --git a/kong/kustomization.yaml b/kong/kustomization.yaml index b84d667..afc03db 100644 --- a/kong/kustomization.yaml +++ b/kong/kustomization.yaml @@ -9,6 +9,8 @@ resources: - rest/rate-limiting.yaml - rest/proxy-cache.yaml - rest/audit-log.yaml + - rest/audit-log-body-capture.yaml + - rest/audit-log-body-capture-bindings.yaml - rest/pluginbindings.yaml - mcp/service.yaml - mcp/routes.yaml @@ -16,4 +18,6 @@ resources: - mcp/ai-mcp-proxy.yaml - mcp/openid-connect.yaml - mcp/audit-log.yaml + - mcp/audit-log-body-capture.yaml + - mcp/audit-log-body-capture-bindings.yaml - mcp/pluginbindings.yaml diff --git a/kong/mcp/audit-log-body-capture-bindings.yaml b/kong/mcp/audit-log-body-capture-bindings.yaml new file mode 100644 index 0000000..34c6a24 --- /dev/null +++ b/kong/mcp/audit-log-body-capture-bindings.yaml @@ -0,0 +1,35 @@ +apiVersion: configuration.konghq.com/v1alpha1 +kind: KongPluginBinding +metadata: + name: ${NAME}-catalog-mcp-audit-capture-request-binding + namespace: ${NAMESPACE} +spec: + controlPlaneRef: + type: konnectNamespacedRef + konnectNamespacedRef: + name: ${CONTROL_PLANE_REF_NAME} + pluginRef: + name: ${NAME}-catalog-mcp-audit-capture-request + targets: + serviceRef: + group: configuration.konghq.com + kind: KongService + name: ${NAME}-catalog-mcp +--- +apiVersion: configuration.konghq.com/v1alpha1 +kind: KongPluginBinding +metadata: + name: ${NAME}-catalog-mcp-audit-capture-response-binding + namespace: ${NAMESPACE} +spec: + controlPlaneRef: + type: konnectNamespacedRef + konnectNamespacedRef: + name: ${CONTROL_PLANE_REF_NAME} + pluginRef: + name: ${NAME}-catalog-mcp-audit-capture-response + targets: + serviceRef: + group: configuration.konghq.com + kind: KongService + name: ${NAME}-catalog-mcp diff --git a/kong/mcp/audit-log-body-capture.yaml b/kong/mcp/audit-log-body-capture.yaml new file mode 100644 index 0000000..ea5ef18 --- /dev/null +++ b/kong/mcp/audit-log-body-capture.yaml @@ -0,0 +1,27 @@ +# dev only: captures raw request/response bodies into kong.ctx.shared for +# audit-log.yaml's custom_fields_by_lua to read back in the log phase. +# Drop this file (and its bindings) to stop body capture without touching +# audit-log.yaml itself — it degrades gracefully to metadata-only logging. +apiVersion: configuration.konghq.com/v1 +kind: KongPlugin +metadata: + name: ${NAME}-catalog-mcp-audit-capture-request + namespace: ${NAMESPACE} +plugin: pre-function +config: + access: + - "kong.ctx.shared.audit_request_body = kong.request.get_raw_body()" +--- +apiVersion: configuration.konghq.com/v1 +kind: KongPlugin +metadata: + name: ${NAME}-catalog-mcp-audit-capture-response + namespace: ${NAMESPACE} +plugin: post-function +config: + body_filter: + - | + local chunk = ngx.arg[1] + if chunk then + kong.ctx.shared.audit_response_body = (kong.ctx.shared.audit_response_body or "") .. chunk + end diff --git a/kong/mcp/audit-log.yaml b/kong/mcp/audit-log.yaml index 0e85083..9f118fb 100644 --- a/kong/mcp/audit-log.yaml +++ b/kong/mcp/audit-log.yaml @@ -5,8 +5,13 @@ metadata: namespace: ${NAMESPACE} plugin: http-log # dev only: the raw Authorization (JWT) header is captured in clear text, -# not acceptable as-is for a non-dev environment. +# not acceptable as-is for a non-dev environment. request_body/response_body +# below read from kong.ctx.shared, populated by audit-log-body-capture.yaml +# — nil (and silently omitted) if that file isn't applied. config: http_endpoint: ${AUDIT_LOG_ENDPOINT} method: POST content_type: application/json + custom_fields_by_lua: + request_body: "return kong.ctx.shared.audit_request_body" + response_body: "return kong.ctx.shared.audit_response_body" diff --git a/kong/rest/audit-log-body-capture-bindings.yaml b/kong/rest/audit-log-body-capture-bindings.yaml new file mode 100644 index 0000000..cc73f96 --- /dev/null +++ b/kong/rest/audit-log-body-capture-bindings.yaml @@ -0,0 +1,35 @@ +apiVersion: configuration.konghq.com/v1alpha1 +kind: KongPluginBinding +metadata: + name: ${NAME}-catalog-api-audit-capture-request-binding + namespace: ${NAMESPACE} +spec: + controlPlaneRef: + type: konnectNamespacedRef + konnectNamespacedRef: + name: ${CONTROL_PLANE_REF_NAME} + pluginRef: + name: ${NAME}-catalog-api-audit-capture-request + targets: + serviceRef: + group: configuration.konghq.com + kind: KongService + name: ${NAME}-catalog-api +--- +apiVersion: configuration.konghq.com/v1alpha1 +kind: KongPluginBinding +metadata: + name: ${NAME}-catalog-api-audit-capture-response-binding + namespace: ${NAMESPACE} +spec: + controlPlaneRef: + type: konnectNamespacedRef + konnectNamespacedRef: + name: ${CONTROL_PLANE_REF_NAME} + pluginRef: + name: ${NAME}-catalog-api-audit-capture-response + targets: + serviceRef: + group: configuration.konghq.com + kind: KongService + name: ${NAME}-catalog-api diff --git a/kong/rest/audit-log-body-capture.yaml b/kong/rest/audit-log-body-capture.yaml new file mode 100644 index 0000000..85a06f3 --- /dev/null +++ b/kong/rest/audit-log-body-capture.yaml @@ -0,0 +1,27 @@ +# dev only: captures raw request/response bodies into kong.ctx.shared for +# audit-log.yaml's custom_fields_by_lua to read back in the log phase. +# Drop this file (and its bindings) to stop body capture without touching +# audit-log.yaml itself — it degrades gracefully to metadata-only logging. +apiVersion: configuration.konghq.com/v1 +kind: KongPlugin +metadata: + name: ${NAME}-catalog-api-audit-capture-request + namespace: ${NAMESPACE} +plugin: pre-function +config: + access: + - "kong.ctx.shared.audit_request_body = kong.request.get_raw_body()" +--- +apiVersion: configuration.konghq.com/v1 +kind: KongPlugin +metadata: + name: ${NAME}-catalog-api-audit-capture-response + namespace: ${NAMESPACE} +plugin: post-function +config: + body_filter: + - | + local chunk = ngx.arg[1] + if chunk then + kong.ctx.shared.audit_response_body = (kong.ctx.shared.audit_response_body or "") .. chunk + end diff --git a/kong/rest/audit-log.yaml b/kong/rest/audit-log.yaml index 38e62a8..3621aff 100644 --- a/kong/rest/audit-log.yaml +++ b/kong/rest/audit-log.yaml @@ -5,8 +5,13 @@ metadata: namespace: ${NAMESPACE} plugin: http-log # dev only: the raw Authorization (JWT) header is captured in clear text, -# not acceptable as-is for a non-dev environment. +# not acceptable as-is for a non-dev environment. request_body/response_body +# below read from kong.ctx.shared, populated by audit-log-body-capture.yaml +# — nil (and silently omitted) if that file isn't applied. config: http_endpoint: ${AUDIT_LOG_ENDPOINT} method: POST content_type: application/json + custom_fields_by_lua: + request_body: "return kong.ctx.shared.audit_request_body" + response_body: "return kong.ctx.shared.audit_response_body"