Skip to content

[SECURESIGN-3115] feat: Add HAProxy rate-limiting support for Ingress resources - #2154

Open
jourdee-lab wants to merge 1 commit into
mainfrom
joutan/SECURESIGN-3115
Open

[SECURESIGN-3115] feat: Add HAProxy rate-limiting support for Ingress resources#2154
jourdee-lab wants to merge 1 commit into
mainfrom
joutan/SECURESIGN-3115

Conversation

@jourdee-lab

@jourdee-lab jourdee-lab commented Jul 28, 2026

Copy link
Copy Markdown
Member

Summary

OpenShift Routes auto-generated from Ingress resources had no rate-limiting, leaving Fulcio, Rekor, TSA, and Console endpoints exposed to traffic spikes. This PR adds opt-in (enabled
by default) HAProxy throttling annotations that the OpenShift router enforces natively.

  • Added a new throttling CRD field to Fulcio, Rekor, TSA, and Console specs for configuring per-source-IP connection and request rate limits
  • Operator would now apply sensible defaults when throttling is omitted (e.g. Rekor gets higher limits since every sign/verify hits it)
  • Users can override individual values or disable throttling entirely via throttling.enabled: false
  • Throttling annotations are only applied on OpenShift clusters; no-op on vanilla Kubernetes
  • v1alpha1 conversion preserves throttling fields via MarshalData round-trip

What changed

  • CRD types (api/v1/): new IngressThrottling struct, added Throttling field to Fulcio, Rekor, TSA, Console specs
  • Ingress actions (internal/controller/*/actions/): each controller's ingress action wires EnsureIngressHAProxyThrottling with component-specific defaults
  • Shared utility (internal/utils/kubernetes/ingress.go): EnsureIngressHAProxyThrottling() handles annotation set/remove logic
  • Tests: shared generic test helper (internal/testing/action/haproxy_throttling.go) validates all 4 controllers with a single parameterized harness
  • v1alpha1 conversion: round-trip tests ensure the v1-only throttling field survives spoke conversion (they will be deleted once v1alpha1 is removed)
  • Docs: docs/ingress-throttling.md documents defaults, customization, and disabling

@jourdee-lab
jourdee-lab force-pushed the joutan/SECURESIGN-3115 branch from 24e0f3e to 0bfb90a Compare July 28, 2026 09:50
@codecov-commenter

codecov-commenter commented Jul 28, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 22.75862% with 112 lines in your changes missing coverage. Please review.
✅ Project coverage is 56.99%. Comparing base (9c019bb) to head (adb0825).

Files with missing lines Patch % Lines
internal/testing/action/haproxy_throttling.go 0.00% 70 Missing ⚠️
api/v1/zz_generated.deepcopy.go 0.00% 37 Missing and 3 partials ⚠️
cmd/main.go 0.00% 2 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #2154      +/-   ##
==========================================
- Coverage   57.13%   56.99%   -0.14%     
==========================================
  Files         284      285       +1     
  Lines       15991    16134     +143     
==========================================
+ Hits         9136     9196      +60     
- Misses       5907     5986      +79     
- Partials      948      952       +4     
Flag Coverage Δ
e2e 69.55% <50.00%> (+0.13%) ⬆️
unit 35.97% <22.75%> (+0.49%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

- Introduced a new `throttling` field in the Console, Fulcio, Rekor, and TSA CRDs to configure HAProxy rate-limiting annotations.
- Implemented default throttling values for each component, with the ability to override via the CRD.
- Added logic to ensure appropriate annotations are set on Ingress resources based on the throttling configuration.
- Created unit tests to validate the behavior of the new throttling feature, including default values, custom overrides, and disabling throttling.
- Updated the Ingress utility functions to handle the new throttling settings and annotations.
@jourdee-lab
jourdee-lab force-pushed the joutan/SECURESIGN-3115 branch from 0bfb90a to adb0825 Compare July 28, 2026 13:13
@jourdee-lab jourdee-lab changed the title feat: Add HAProxy rate-limiting support for Ingress resources [SECURESIGN-3115] feat: Add HAProxy rate-limiting support for Ingress resources Jul 28, 2026
@jourdee-lab
jourdee-lab marked this pull request as ready for review July 28, 2026 14:32
@qodo-for-securesign

Copy link
Copy Markdown

PR Summary by Qodo

Add configurable HAProxy throttling to OpenShift ingress routes

✨ Enhancement 🧪 Tests 📝 Documentation 🕐 40+ Minutes

Grey Divider

AI Description

• Adds default-on configurable HAProxy throttling for Fulcio, Rekor, TSA, and Console routes.
• Restricts annotations to OpenShift and preserves settings through v1alpha1 conversion round-trips.
• Documents behavior and tests defaults, overrides, disabling, cleanup, and Kubernetes no-op
 handling.
Diagram

graph TD
  CR["Component CR"] --> API["v1 API"] --> CTRL["Ingress Actions"] --> UTIL["Throttle Utility"] --> ING["Kubernetes Ingress"] --> ROUTE["OpenShift Route"] --> HAP["HAProxy Router"]
  CONV["v1alpha1 Conversion"] --> API
Loading
High-Level Assessment

The current approach is appropriate: typed CRD fields provide validation and stable defaults, while native OpenShift annotations avoid additional infrastructure and remain a no-op on Kubernetes. Direct Route management would conflict with Ingress-generated Routes, and an external rate-limiting proxy would add unnecessary operational complexity.

Files changed (33) +1114 / -6

Enhancement (10) +158 / -0
console_types.goExpose throttling configuration for Console UI ingress +6/-0

Expose throttling configuration for Console UI ingress

• Adds optional HAProxy throttling settings to Console UI, with documented default-on behavior and OpenShift-only semantics.

api/v1/console_types.go

fulcio_types.goDefine shared ingress throttling API and Fulcio configuration +32/-0

Define shared ingress throttling API and Fulcio configuration

• Introduces the validated IngressThrottling type with enablement, concurrent TCP, HTTP rate, and TCP rate controls. Adds the optional configuration to FulcioSpec.

api/v1/fulcio_types.go

rekor_types.goExpose higher-capacity throttling controls for Rekor +6/-0

Expose higher-capacity throttling controls for Rekor

• Adds optional throttling configuration to RekorSpec and documents Rekor's higher component defaults.

api/v1/rekor_types.go

timestampauthority_types.goExpose throttling configuration for TSA ingress +6/-0

Expose throttling configuration for TSA ingress

• Adds optional OpenShift HAProxy throttling controls to TimestampAuthoritySpec with the standard endpoint defaults.

api/v1/timestampauthority_types.go

annotations.goDefine managed HAProxy throttling annotations +8/-0

Define managed HAProxy throttling annotations

• Centralizes the four OpenShift HAProxy rate-limiting annotation keys and the enabling value used by ingress reconciliation.

internal/annotations/annotations.go

ingress.goApply Console throttling during ingress reconciliation +10/-0

Apply Console throttling during ingress reconciliation

• Defines Console's 100/50/100 defaults and invokes shared throttling reconciliation only on OpenShift.

internal/controller/console/actions/ui/ingress.go

ingress.goApply Fulcio throttling during ingress reconciliation +10/-0

Apply Fulcio throttling during ingress reconciliation

• Defines Fulcio's 100/50/100 defaults and wires OpenShift-only throttling into its ingress action.

internal/controller/fulcio/actions/ingress.go

ingress.goApply higher Rekor throttling defaults +11/-0

Apply higher Rekor throttling defaults

• Adds OpenShift-only throttling to Rekor server ingress with 200 concurrent TCP, 100 HTTP, and 200 TCP-rate defaults.

internal/controller/rekor/actions/server/ingress.go

ingress.goApply TSA throttling during ingress reconciliation +10/-0

Apply TSA throttling during ingress reconciliation

• Defines TSA's 100/50/100 defaults and applies shared throttling logic on OpenShift ingress resources.

internal/controller/tsa/actions/ingress.go

ingress.goReconcile HAProxy throttling annotations +59/-0

Reconcile HAProxy throttling annotations

• Adds component fallback values and a shared ingress mutator that resolves partial overrides, sets HAProxy annotations, or removes managed annotations when disabled.

internal/utils/kubernetes/ingress.go

Refactor (2) +8 / -4
main.goCentralize the OpenShift cluster resource name +8/-2

Centralize the OpenShift cluster resource name

• Introduces a shared constant for the fixed cluster-scoped OpenShift Ingress and APIServer resource name and uses it in cache selectors.

cmd/main.go

action.goRemove an unused Trillian deployment constant +0/-2

Remove an unused Trillian deployment constant

• Removes the unused local logserverDeploymentName declaration.

internal/action/tree/action.go

Tests (9) +543 / -2
conversion_roundtrip_test.goInclude throttling in conversion fuzz coverage +6/-0

Include throttling in conversion fuzz coverage

• Adds an IngressThrottling fuzzer that always initializes Enabled, allowing stable v1 conversion round-trip checks.

api/v1alpha1/conversion_roundtrip_test.go

conversion_unit_test.goVerify v1-only throttling survives spoke conversions +169/-0

Verify v1-only throttling survives spoke conversions

• Adds Securesign and standalone Fulcio, Rekor, and TSA round-trip tests. The tests confirm MarshalData preservation of every throttling field through v1alpha1.

api/v1alpha1/conversion_unit_test.go

main_test.goUse the shared OpenShift resource name in tests +2/-2

Use the shared OpenShift resource name in tests

• Updates APIServer test fixtures and lookup keys to reference the centralized cluster resource name constant.

cmd/main_test.go

ingress_test.goTest Console HAProxy throttling behavior +36/-0

Test Console HAProxy throttling behavior

• Runs the shared controller harness against Console UI ingress with the expected baseline defaults.

internal/controller/console/actions/ui/ingress_test.go

ingress_test.goTest Fulcio HAProxy throttling behavior +33/-0

Test Fulcio HAProxy throttling behavior

• Configures the shared throttling test harness for Fulcio services, ingress resources, and defaults.

internal/controller/fulcio/actions/ingress_test.go

ingress_test.goTest Rekor HAProxy throttling behavior +34/-0

Test Rekor HAProxy throttling behavior

• Runs shared throttling scenarios for Rekor and verifies its higher component defaults.

internal/controller/rekor/actions/server/ingress_test.go

ingress_test.goTest TSA HAProxy throttling behavior +33/-0

Test TSA HAProxy throttling behavior

• Configures shared throttling scenarios for TimestampAuthority ingress and its standard defaults.

internal/controller/tsa/actions/ingress_test.go

haproxy_throttling.goAdd reusable controller throttling test harness +130/-0

Add reusable controller throttling test harness

• Introduces parameterized tests covering OpenShift defaults, custom values, explicit disabling, and non-OpenShift behavior for all supported controllers.

internal/testing/action/haproxy_throttling.go

ingress_test.goTest shared ingress throttling reconciliation +100/-0

Test shared ingress throttling reconciliation

• Covers default and custom limits, partial fallback, annotation preservation, nil annotation initialization, and cleanup when throttling is disabled.

internal/utils/kubernetes/ingress_test.go

Documentation (1) +96 / -0
ingress-throttling.mdDocument OpenShift ingress throttling +96/-0

Document OpenShift ingress throttling

• Explains supported components, default limits, HAProxy annotation mappings, partial overrides, disabling behavior, and the Kubernetes no-op behavior. Includes Rekor, Console, and Fulcio configuration examples.

docs/ingress-throttling.md

Other (11) +309 / -0
zz_generated.deepcopy.goGenerate deep-copy support for throttling fields +55/-0

Generate deep-copy support for throttling fields

• Deep-copies throttling pointers on Console, Fulcio, Rekor, and TSA specifications and adds copy methods for IngressThrottling.

api/v1/zz_generated.deepcopy.go

fulcio_conversion.goRestore Fulcio throttling during hub conversion +1/-0

Restore Fulcio throttling during hub conversion

• Restores the v1-only Fulcio throttling configuration from MarshalData when converting from v1alpha1.

api/v1alpha1/fulcio_conversion.go

rekor_conversion.goRestore Rekor throttling during hub conversion +1/-0

Restore Rekor throttling during hub conversion

• Preserves the v1-only Rekor throttling configuration when converting a v1alpha1 resource back to v1.

api/v1alpha1/rekor_conversion.go

securesign_conversion.goPreserve component throttling in Securesign conversions +3/-0

Preserve component throttling in Securesign conversions

• Restores Fulcio, Rekor, and optional TSA throttling settings when converting aggregate Securesign resources to the v1 hub.

api/v1alpha1/securesign_conversion.go

timestampauthority_conversion.goRestore TSA throttling during hub conversion +1/-0

Restore TSA throttling during hub conversion

• Restores the v1-only TimestampAuthority throttling configuration from conversion MarshalData.

api/v1alpha1/timestampauthority_conversion.go

zz_generated.conversion.goMark throttling as requiring manual conversion +3/-0

Mark throttling as requiring manual conversion

• Records generated conversion warnings for the v1-only Fulcio, Rekor, and TSA throttling fields.

api/v1alpha1/zz_generated.conversion.go

rhtas.redhat.com_consoles.yamlPublish Console throttling fields in the CRD +35/-0

Publish Console throttling fields in the CRD

• Adds the Console UI throttling schema, defaults, descriptions, int32 formats, and minimum-value validation.

config/crd/bases/rhtas.redhat.com_consoles.yaml

rhtas.redhat.com_fulcios.yamlPublish Fulcio throttling fields in the CRD +35/-0

Publish Fulcio throttling fields in the CRD

• Adds validated, default-enabled HAProxy throttling configuration to the Fulcio CRD schema.

config/crd/bases/rhtas.redhat.com_fulcios.yaml

rhtas.redhat.com_rekors.yamlPublish Rekor throttling fields in the CRD +35/-0

Publish Rekor throttling fields in the CRD

• Adds the throttling schema to Rekor and documents its higher default connection and request limits.

config/crd/bases/rhtas.redhat.com_rekors.yaml

rhtas.redhat.com_securesigns.yamlPublish component throttling in the Securesign CRD +105/-0

Publish component throttling in the Securesign CRD

• Adds validated throttling schemas for embedded Fulcio, Rekor, and TimestampAuthority specifications, including their component-specific defaults.

config/crd/bases/rhtas.redhat.com_securesigns.yaml

rhtas.redhat.com_timestampauthorities.yamlPublish TSA throttling fields in the CRD +35/-0

Publish TSA throttling fields in the CRD

• Adds the default-enabled and validated throttling configuration to the TimestampAuthority CRD schema.

config/crd/bases/rhtas.redhat.com_timestampauthorities.yaml

@qodo-for-securesign

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (0) 📘 Rule violations (0) 📎 Requirement gaps (0)

Grey Divider

Great, no issues found!

Qodo reviewed your code and found no material issues that require review

Grey Divider

To customize comments, go to the Qodo configuration screen, or learn more in the docs.

Qodo Logo

@jourdee-lab
jourdee-lab requested review from bouskaJ and osmman July 29, 2026 14:09

@osmman osmman left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Design concern: HAProxy-specific API surface in the CRD

The IngressThrottling type is a 1:1 mapping of haproxy.router.openshift.io/rate-limit-connections.* annotations, which ties the CRD permanently to one specific ingress controller implementation. On OpenShift clusters running a different ingress controller (nginx, traefik, etc.) these fields are silently ignored — no error, no warning, no condition — and on non-OpenShift deployments (EKS, GKE, vanilla k8s) the entire struct is completely inert. Since CRD fields in v1 are permanent, we'd be locked into this HAProxy-specific surface even if we later need to support other rate-limiting backends.

Proposed alternative

Add an Annotations field to the existing Ingress type — the same pattern already used for Labels:

type Ingress struct {
    Enabled     *bool             `json:"enabled,omitempty"`
    Host        string            `json:"host,omitempty"`
    Labels      map[string]string `json:"labels,omitempty"`
    Annotations map[string]string `json:"annotations,omitempty"`  // new
}

This gives users full control over any ingress/route annotations their environment needs — HAProxy throttling, nginx rate-limiting, custom headers — without baking vendor-specific semantics into the API. For our managed default deployments, the operator would internally apply sensible HAProxy throttling annotations when running on OpenShift (just like we already set TLS annotations), without requiring any CRD configuration. Users who want to override or disable defaults can do so via the annotations map.

This keeps the CRD vendor-neutral and portable, still gives us throttling-by-default on OCP, lets users on any platform configure their own ingress annotations, and doesn't pollute the API surface with implementation-specific fields.

Rate-limit values concern

Where do the proposed default values come from? They look too restrictive for API endpoints. HAProxy's rate-http uses a hardcoded 10-second sliding window, so rateHTTP=50 means only 5 req/sec per source IP — automated signing clients, CI pipelines, or frontends making parallel requests will hit this very quickly. Similarly rateTCP=100 uses a 3-second window (~33 new connections/sec), which is tight. Only concurrentTCP=100 looks reasonable for most workloads.

These are per-source-IP limits enforced by HAProxy's stick-table, not global. There's also a known issue where TCP-based limits may not be reliably enforced for parallel connections, so these shouldn't be treated as a hard security boundary. I'd suggest bumping rateHTTP to at least 100-200 for API endpoints (Fulcio, Rekor, TSA) and being more conservative only for the Console UI.

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.

3 participants