Skip to content

fix: parse hmac-auth signed_headers from Secret as a header list#436

Open
shreemaan-abhishek wants to merge 3 commits into
masterfrom
fix/hmac-signed-headers-secret-parsing
Open

fix: parse hmac-auth signed_headers from Secret as a header list#436
shreemaan-abhishek wants to merge 3 commits into
masterfrom
fix/hmac-signed-headers-secret-parsing

Conversation

@shreemaan-abhishek

@shreemaan-abhishek shreemaan-abhishek commented Jul 19, 2026

Copy link
Copy Markdown
Contributor

What this PR does

translateConsumerHMACAuthPlugin read signed_headers from a Secret by ranging over its raw bytes:

signedHeadersRaw := sec.Data["signed_headers"] // []byte
for _, b := range signedHeadersRaw {           // ranges over bytes
    signedHeaders = append(signedHeaders, string(b)) // one 1-char entry per byte
}

Ranging over a []byte yields (index, byte), so "X-Date,Host" became ["X","-","D","a","t","e",",","H","o","s","t"]. The data-plane hmac-auth policy then bound those single-character names into the signature, which never match real headers, so the operator's intended headers were silently not enforced as part of the HMAC signature. Only the secretRef path was affected; the inline Value path already passes a []string.

Fix

  • Split the signed_headers value on commas and trim entries.
  • Surface strconv.ParseInt failures for clock_skew and max_req_body instead of discarding them, so a typo no longer coerces silently to a default.

Tests

  • New unit tests: signed_headers from a Secret yields the correct header list; an unparseable clock_skew is rejected.

Paired open-source PR: apache/apisix-ingress-controller#2809. Fixes FINDING-050 (rfcs#184).

Summary by CodeRabbit

  • Bug Fixes
    • Improved HMAC authentication secret handling by validating numeric settings and returning clear errors for invalid values.
    • Correctly parses signed_headers from Secrets by splitting on commas or whitespace, trimming entries, and ignoring empty values.
    • Keeps existing default behavior for negative or missing numeric settings.
  • Tests
    • Added coverage for signed-header parsing across multiple input formats.
    • Added tests to ensure unparseable numeric fields are rejected with helpful error details.
  • Documentation
    • Clarified signed_headers storage format for HMAC secret references in API docs and CRD schema.

@coderabbitai

coderabbitai Bot commented Jul 19, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: e0f2bc33-c295-4369-bfde-acf998420724

📥 Commits

Reviewing files that changed from the base of the PR and between 6e300ed and f1600ca.

📒 Files selected for processing (1)
  • docs/en/latest/reference/api-reference.md
🚧 Files skipped from review as they are similar to previous changes (1)
  • docs/en/latest/reference/api-reference.md

📝 Walkthrough

Walkthrough

HMAC Secret translation now validates numeric fields, preserves negative-value defaults, and tokenizes signed_headers using commas or Unicode whitespace. Tests cover parsing and invalid numeric input, while API and CRD documentation describe the Secret format.

Changes

HMAC secret translation

Layer / File(s) Summary
Strict HMAC parsing and validation
internal/adc/translator/apisixconsumer.go, internal/adc/translator/apisixconsumer_test.go
clock_skew and max_req_body now return errors for invalid values while retaining negative-value defaults. signed_headers is split on commas or Unicode whitespace, with tests covering supported formats and errors.
Secret format documentation
api/v2/apisixconsumer_types.go, config/crd/bases/..., docs/en/latest/reference/api-reference.md
API comments, CRD descriptions, and reference documentation describe signed_headers as one comma- or whitespace-separated Secret value.

Estimated code review effort: 2 (Simple) | ~10 minutes

🚥 Pre-merge checks | ✅ 5 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
E2e Test Quality Review ⚠️ Warning Coverage is only translator unit tests; there’s no live API→controller→data-plane E2E for the HMAC SecretRef flow. Add/extend test/e2e/crds/v2/consumer.go to apply an ApisixConsumer+Secret and verify signed_headers and malformed numeric secrets through the real stack.
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly matches the main change: parsing HMAC auth signed_headers from Secret data into a header list.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Security Check ✅ Passed No security regressions found: HMAC SecretRef parsing stays in-memory, no new logging/serialization or auth-bypass paths, and error messages expose only key names.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/hmac-signed-headers-secret-parsing

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@internal/adc/translator/apisixconsumer_test.go`:
- Around line 68-82: Extend
TestTranslateApisixConsumer_HMACAuthRejectsInvalidClockSkew with cases covering
an invalid max_req_body value and an empty entry in signed_headers. For each
case, configure the corresponding secret data, call TranslateApisixConsumer, and
assert an error mentioning the affected field, while preserving the existing
clock_skew coverage.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 0edda70f-e478-4d19-8882-e40479af60b9

📥 Commits

Reviewing files that changed from the base of the PR and between 5f84a00 and 1cde587.

📒 Files selected for processing (2)
  • internal/adc/translator/apisixconsumer.go
  • internal/adc/translator/apisixconsumer_test.go

Comment thread internal/adc/translator/apisixconsumer_test.go Outdated
@github-actions

github-actions Bot commented Jul 19, 2026

Copy link
Copy Markdown
Contributor

conformance test report - apisix-standalone mode

apiVersion: gateway.networking.k8s.io/v1
date: "2026-07-24T10:09:59Z"
gatewayAPIChannel: experimental
gatewayAPIVersion: v1.3.0
implementation:
  contact: null
  organization: APISIX
  project: apisix-ingress-controller
  url: https://github.com/apache/apisix-ingress-controller.git
  version: v2.0.0
kind: ConformanceReport
mode: default
profiles:
- core:
    result: success
    statistics:
      Failed: 0
      Passed: 12
      Skipped: 0
  name: GATEWAY-GRPC
  summary: Core tests succeeded.
- core:
    result: partial
    skippedTests:
    - HTTPRouteHTTPSListener
    statistics:
      Failed: 0
      Passed: 32
      Skipped: 1
  extended:
    result: partial
    skippedTests:
    - HTTPRouteRedirectPortAndScheme
    statistics:
      Failed: 0
      Passed: 11
      Skipped: 1
    supportedFeatures:
    - GatewayAddressEmpty
    - GatewayPort8080
    - HTTPRouteBackendProtocolWebSocket
    - HTTPRouteDestinationPortMatching
    - HTTPRouteHostRewrite
    - HTTPRouteMethodMatching
    - HTTPRoutePathRewrite
    - HTTPRoutePortRedirect
    - HTTPRouteQueryParamMatching
    - HTTPRouteRequestMirror
    - HTTPRouteResponseHeaderModification
    - HTTPRouteSchemeRedirect
    unsupportedFeatures:
    - GatewayHTTPListenerIsolation
    - GatewayInfrastructurePropagation
    - GatewayStaticAddresses
    - HTTPRouteBackendProtocolH2C
    - HTTPRouteBackendRequestHeaderModification
    - HTTPRouteBackendTimeout
    - HTTPRouteParentRefPort
    - HTTPRoutePathRedirect
    - HTTPRouteRequestMultipleMirrors
    - HTTPRouteRequestPercentageMirror
    - HTTPRouteRequestTimeout
  name: GATEWAY-HTTP
  summary: Core tests partially succeeded with 1 test skips. Extended tests partially
    succeeded with 1 test skips.
- core:
    result: partial
    skippedTests:
    - TLSRouteSimpleSameNamespace
    statistics:
      Failed: 0
      Passed: 10
      Skipped: 1
  name: GATEWAY-TLS
  summary: Core tests partially succeeded with 1 test skips.

@github-actions

github-actions Bot commented Jul 19, 2026

Copy link
Copy Markdown
Contributor

conformance test report - apisix mode

apiVersion: gateway.networking.k8s.io/v1
date: "2026-07-24T10:11:07Z"
gatewayAPIChannel: experimental
gatewayAPIVersion: v1.3.0
implementation:
  contact: null
  organization: APISIX
  project: apisix-ingress-controller
  url: https://github.com/apache/apisix-ingress-controller.git
  version: v2.0.0
kind: ConformanceReport
mode: default
profiles:
- core:
    result: success
    statistics:
      Failed: 0
      Passed: 12
      Skipped: 0
  name: GATEWAY-GRPC
  summary: Core tests succeeded.
- core:
    failedTests:
    - HTTPRouteInvalidBackendRefUnknownKind
    - HTTPRouteMatchingAcrossRoutes
    result: failure
    skippedTests:
    - HTTPRouteHTTPSListener
    statistics:
      Failed: 2
      Passed: 30
      Skipped: 1
  extended:
    result: partial
    skippedTests:
    - HTTPRouteRedirectPortAndScheme
    statistics:
      Failed: 0
      Passed: 11
      Skipped: 1
    supportedFeatures:
    - GatewayAddressEmpty
    - GatewayPort8080
    - HTTPRouteBackendProtocolWebSocket
    - HTTPRouteDestinationPortMatching
    - HTTPRouteHostRewrite
    - HTTPRouteMethodMatching
    - HTTPRoutePathRewrite
    - HTTPRoutePortRedirect
    - HTTPRouteQueryParamMatching
    - HTTPRouteRequestMirror
    - HTTPRouteResponseHeaderModification
    - HTTPRouteSchemeRedirect
    unsupportedFeatures:
    - GatewayHTTPListenerIsolation
    - GatewayInfrastructurePropagation
    - GatewayStaticAddresses
    - HTTPRouteBackendProtocolH2C
    - HTTPRouteBackendRequestHeaderModification
    - HTTPRouteBackendTimeout
    - HTTPRouteParentRefPort
    - HTTPRoutePathRedirect
    - HTTPRouteRequestMultipleMirrors
    - HTTPRouteRequestPercentageMirror
    - HTTPRouteRequestTimeout
  name: GATEWAY-HTTP
  summary: Core tests failed with 2 test failures. Extended tests partially succeeded
    with 1 test skips.
- core:
    result: partial
    skippedTests:
    - TLSRouteSimpleSameNamespace
    statistics:
      Failed: 0
      Passed: 10
      Skipped: 1
  name: GATEWAY-TLS
  summary: Core tests partially succeeded with 1 test skips.

@github-actions

github-actions Bot commented Jul 19, 2026

Copy link
Copy Markdown
Contributor

conformance test report

apiVersion: gateway.networking.k8s.io/v1
date: "2026-07-24T10:27:16Z"
gatewayAPIChannel: experimental
gatewayAPIVersion: v1.3.0
implementation:
  contact: null
  organization: APISIX
  project: apisix-ingress-controller
  url: https://github.com/apache/apisix-ingress-controller.git
  version: v2.0.0
kind: ConformanceReport
mode: default
profiles:
- core:
    failedTests:
    - GatewayModifyListeners
    result: failure
    statistics:
      Failed: 1
      Passed: 11
      Skipped: 0
  name: GATEWAY-GRPC
  summary: Core tests failed with 1 test failures.
- core:
    failedTests:
    - GatewayModifyListeners
    result: failure
    skippedTests:
    - HTTPRouteHTTPSListener
    statistics:
      Failed: 1
      Passed: 31
      Skipped: 1
  extended:
    result: partial
    skippedTests:
    - HTTPRouteRedirectPortAndScheme
    statistics:
      Failed: 0
      Passed: 11
      Skipped: 1
    supportedFeatures:
    - GatewayAddressEmpty
    - GatewayPort8080
    - HTTPRouteBackendProtocolWebSocket
    - HTTPRouteDestinationPortMatching
    - HTTPRouteHostRewrite
    - HTTPRouteMethodMatching
    - HTTPRoutePathRewrite
    - HTTPRoutePortRedirect
    - HTTPRouteQueryParamMatching
    - HTTPRouteRequestMirror
    - HTTPRouteResponseHeaderModification
    - HTTPRouteSchemeRedirect
    unsupportedFeatures:
    - GatewayHTTPListenerIsolation
    - GatewayInfrastructurePropagation
    - GatewayStaticAddresses
    - HTTPRouteBackendProtocolH2C
    - HTTPRouteBackendRequestHeaderModification
    - HTTPRouteBackendTimeout
    - HTTPRouteParentRefPort
    - HTTPRoutePathRedirect
    - HTTPRouteRequestMultipleMirrors
    - HTTPRouteRequestPercentageMirror
    - HTTPRouteRequestTimeout
  name: GATEWAY-HTTP
  summary: Core tests failed with 1 test failures. Extended tests partially succeeded
    with 1 test skips.
- core:
    failedTests:
    - GatewayModifyListeners
    - TLSRouteSimpleSameNamespace
    result: failure
    statistics:
      Failed: 2
      Passed: 9
      Skipped: 0
  name: GATEWAY-TLS
  summary: Core tests failed with 2 test failures.

@shreemaan-abhishek shreemaan-abhishek self-assigned this Jul 20, 2026
clockSkew, err = strconv.ParseInt(string(clockSkewRaw), 10, 64)
if err != nil {
return nil, fmt.Errorf("hmac-auth: invalid clock_skew %q in secret: %w", string(clockSkewRaw), err)
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This pair has already drifted from apache/apisix-ingress-controller#2809: upstream commit 8b165835 now includes the Secret namespace/name in both parse errors, while this branch still emits context-free messages. Please forward-port that follow-up to both the clock_skew and max_req_body paths so the shared translator behavior stays aligned and operators can identify the offending Secret.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Forward-ported in 6e300ed — both the clock_skew and max_req_body paths now include the Secret namespace/name, matching upstream 8b165835.

This branch also picks up the wider follow-up from apache/apisix-ingress-controller#2824 (whitespace-tolerant signed_headers split, CRD field docs, test-helper rename), so internal/adc/translator/apisixconsumer.go is now byte-identical to the upstream version.

translateConsumerHMACAuthPlugin ranged over the raw bytes of the
signed_headers Secret value, emitting one single-character string per
byte instead of the configured header names. The data-plane signature
policy then bound nonsensical headers, silently voiding the operator's
intended integrity control. Only the secretRef path was affected; the
inline Value path already passed a []string.

Split the value on commas and trim entries. Also surface strconv.ParseInt
failures for clock_skew and max_req_body instead of discarding them, so a
typo no longer coerces silently to a default.
Forward-ports apache/apisix-ingress-controller#2809 follow-up 8b165835 so
both parse errors name the offending Secret, and brings over the follow-up
in apache/apisix-ingress-controller#2824:

- accept whitespace as well as commas when splitting signed_headers, so a
  newline- or space-separated Secret value no longer collapses into one
  bogus header name
- document the Secret-vs-Value format difference on the CRD field
- rename the ambiguous hmacConsumerWithSecret parameter
- cover the delimiter variants, the empty case and the previously
  untested max_req_body parse failure
@shreemaan-abhishek
shreemaan-abhishek force-pushed the fix/hmac-signed-headers-secret-parsing branch from 1cde587 to 6e300ed Compare July 24, 2026 08:51
crd-ref-docs joins consecutive godoc lines with spaces and only emits
<br /> for blank-line paragraph breaks, so the hand-written version did
not match the generator.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants