Skip to content

v0.7.0

Choose a tag to compare

@github-actions github-actions released this 20 Oct 21:32
· 78 commits to main since this release
8387dce

[0.7.0] - 2026-10-20

HAPTIC 0.7 hardens two trust boundaries: raw HAProxy configuration annotations,
which let an Ingress writer change the configuration for every host, need an
explicit opt-in, and every HTTP frontend replaces client-sent forwarded headers,
so clients can't forge their address. Chart upgrades roll the controller to the
new image before applying new templates.

Before upgrading: check your Ingresses for raw configuration annotations and
haproxy-ingress.github.io/forwardfor, and list any L7 proxies in front of
HAPTIC. Read the upgrade notes.

Added

  • watchedResources.<name>.namespaces restricts watches and template lookups to listed namespaces; namespacesSetting identifies the setting in rejection messages.
  • Metrics:
    • haptic_config_validated{status,reason}: each replica's Validated condition, one series per state, so an alert can match a configuration stuck at Unknown or False.
    • haptic_config_validation_total{result}: valid, invalid, and inconclusive verdicts on the HAProxyTemplateConfig, the startup load gate included. haptic_validation_errors_total counts only HAProxy's verdicts on rendered configurations.
  • on_own_lines(render_glob "prefix-*") template function: renders the matching snippets so that each starts on a new line.

Changed

  • haptic_render_total and haptic_render_errors_total export every cache_state at zero, and haptic_config_rejected_total every validator, so increase() and the HAProxyControllerConfigRejected alert see the first failure.
  • A change to a server's maxconn is applied with HAProxy's runtime API instead of a reload.
  • The controller logs Reload required at INFO with the pod and the reasons whenever it reloads a pod, instead of only at DEBUG.

Fixed

  • haptic preflight validates sidecar configurations even when a restrictive umask would prevent the container user from reading temporary files.
  • When an upgrade adds runtime operations, older agents still apply supported runtime changes without a reload.
  • Frequent per-pod status writes no longer block publication of a changed HAProxyCfg with resource-version conflicts.
  • An unchanged successful render-gate verdict no longer rewrites HAProxyCfg status on every render.
  • A change to the credentials Secret that leaves dataplane_username and dataplane_password unchanged, such as every Helm upgrade, no longer restarts the controller iteration, which briefly doubled controller memory and could OOMKill large installs (#456).
  • A controller container restarted during its startup validation no longer fails every validationTest with no space left on device. Each test's scratch files are removed when it finishes, instead of when the whole suite does.
  • A controller could stop deploying, leaving HAProxy pods unready, when the render gate's verdict reached the deployment scheduler before the render it named. Each component now receives an event before any reaction to it.
  • A configuration change on a large install no longer hands leadership to a replica with a cold render graph while the warm-up render is still running, which delayed deployments until the new leader rendered from scratch.
  • Deployments no longer contend with leader Lease renewals or log spurious Failed to update lease errors.
  • A new leader preserves the latest configuration validation verdict instead of reporting an older accepted configuration as valid over a newer rejected or unvalidated generation.
  • Configuration changes fetch watched-resource schemas in parallel, and API discovery timeouts leave validation inconclusive and retry it instead of rejecting templates that use typed fields.
  • Admission denials show the governance rule's message and the watched object; other render errors identify the watched object without exposing encoded cache keys.
  • Startup-validation messages describe retrying NotReady pods and stalled rollouts instead of claiming the controller exits on rejection.
  • A deployment cancelled because the HAProxy pod set changed no longer logs context canceled errors, emits ApplyFailed Pod events, or counts in haptic_deployment_errors_total (#430).
  • Expected events log at INFO instead of WARN: config publisher API calls cancelled by its own shutdown, the wait for the render gate's first verdict after a start or configuration change, and a leader drained during a configuration hand-over (#444, #445, #453).

Helm chart

Added

  • extraContext.forwardedHeaders.trustedProxies: the L7 load balancers whose X-Forwarded-For, -Proto, -Host, and -Port headers HAPTIC keeps.
  • controller.rbac.releaseNamespaceSecretsOnly limits Secret reads to the release namespace and rejects references elsewhere.
  • A watched resource that lists namespaces is granted by a Role in each listed namespace instead of the ClusterRole.
  • HAProxyControllerConfigNotValidated alert (controller.monitoring.prometheusRule.defaultRules.configNotValidated): a replica hasn't validated its newest HAProxyTemplateConfig for 10 minutes.

Changed

  • The pre-upgrade hook rolls the controller Deployment to the new image before Helm applies new templates, so old replicas no longer reject a valid incoming configuration. See controller preparation for custom image tags and deployments without hooks.
  • BREAKING: haproxy-ingress: haproxy-ingress.github.io/forwardfor: add replaces the client's X-Forwarded-For and update appends to it, as upstream does; HAPTIC had them the other way round. Check your Ingresses before upgrading.
  • An Ingress that sets X-Forwarded-For handling through annotations from two families is rejected at admission, like other mixed-family features.
  • A helm upgrade that changes only the chart version no longer changes the HAProxyTemplateConfig, so running controllers don't start a new iteration mid-rollout. The controller-managed HAProxy Service drops its helm.sh/chart, app.kubernetes.io/version, and app.kubernetes.io/managed-by labels.
  • Controller pods no longer carry the helm.sh/chart and app.kubernetes.io/version labels; the Deployment keeps them. A chart upgrade then rolls the controllers once instead of twice; the upgrade to 0.7.0 itself still rolls them twice (#467).

Fixed

  • Preflight compiles Varnish configurations with the deployed image when caching is enabled and a released fixture image when it is disabled.
  • Custom TCP frontends that accept PROXY protocol pass validation when the built-in HTTP/HTTPS PROXY listeners are disabled.
  • haproxy.org/pod-maxconn and haproxy-haptic.org/pod-maxconn set maxconn on each server line, so a change in the ready HAProxy pod count (for example during a rollout) updates it at runtime instead of reloading every HAProxy pod (#474).
  • haproxy-haptic.org/forwardfor and haproxy-ingress.github.io/forwardfor: add and update no longer send the client address twice, and ifmissing and ignore no longer append it to the client's header.
  • haproxytech: haproxy.org/forwarded-for: "false" forwards the client's X-Forwarded-For unchanged; it was ignored.
  • A snippet at an extension point starts on its own line whether or not its template begins or ends with a newline. A frontend-extra-* or other snippet without a leading newline could join the previous line and fail validation.

Security

  • BREAKING: Raw HAProxy configuration annotations (haproxy-haptic.org/config-*, haproxy-ingress.github.io/config-*, haproxy.org/backend-config-snippet, and nginx.ingress.kubernetes.io/configuration-snippet) are rejected unless controller.config.templatingSettings.extraContext.ingressPermissions.allowRawHAProxyConfig is true. Any Ingress writer in a watched namespace could otherwise change the configuration for every host or read HAProxy's TLS keys. waf.ingressPermissions.allowRawHAProxyConfig can only narrow it. Check your Ingresses before upgrading.
  • WAF governance's allowRawHAProxyConfig: false also rejects raw configuration annotations when the hapticAnnotations library is disabled.
  • BREAKING: Every HTTP frontend replaces a client-sent X-Forwarded-For with the client address, sets X-Forwarded-Proto to https or http, and drops a client-sent X-Forwarded-Host and X-Forwarded-Port, so clients can't forge their address or scheme (#406). X-Forwarded-Host, -Port, and -Proto set by frontend-extra-* snippets are kept. Behind an L7 load balancer, list it in trustedProxies; trustedProxies: ["0.0.0.0/0", "::/0"] restores the old X-Forwarded-For handling.