apisix-helm-chart icon indicating copy to clipboard operation
apisix-helm-chart copied to clipboard

Admin API allowlist bypassed when ingress-controller enabled (+ missing IPv6)

Open twellck opened this issue 4 months ago • 0 comments

Description

The admin API allowlist logic in templates/configmap.yaml has two critical issues when ingress-controller.enabled: true:

  1. Security bypass: User-specified allowlist is overridden by unconditionally appending 0.0.0.0/0
  2. Missing IPv6 support: Only 0.0.0.0/0 is added, breaking IPv6-only clusters

Environment

  • Helm Chart Version: 2.12.4
  • Kubernetes Version: 1.34
  • Helm Version: 3.18.4 (through Terraform's Helm provider)

Current Behavior

The template always appends 0.0.0.0/0 when ingress-controller is enabled:

allow_admin:
{{- if .Values.apisix.admin.allow.ipList }}
  {{- range $ips := .Values.apisix.admin.allow.ipList }}
  - {{ $ips }}
  {{- end }}
{{- else }}
  - 0.0.0.0/0
{{- end}}
{{- if (index .Values "ingress-controller" "enabled") }}
  - 0.0.0.0/0  # Always appended - overrides user security
{{- end}}

Default values.yaml:

apisix:
  admin:
    allow:
      ipList:
        - 127.0.0.1/24  # Secure default - localhost only

⚠️ Edge Case Note: Currently, an empty ipList: [] defaults to 0.0.0.0/0 via the {{- else }} branch. This is likely unintentional behavior, but exists in production. All proposed options below change this edge case.

Problem 1: Security Bypass

Steps to Reproduce

  1. Configure values.yaml with restricted allowlist:
    apisix:
      admin:
        allow:
          ipList:
            - 10.244.0.0/16  # Restrict to pod network only
    ingress-controller:
      enabled: true
    
  2. Deploy the chart: helm install apisix apisix/apisix -f values.yaml
  3. Check the generated ConfigMap: kubectl get configmap apisix -o yaml

Expected Behavior

Admin API should only be accessible from 10.244.0.0/16:

allow_admin:
  - 10.244.0.0/16

Actual Behavior

User's restriction is bypassed:

allow_admin:
  - 10.244.0.0/16
  - 0.0.0.0/0  # Unconditionally added - allows all traffic

Impact

Users cannot properly secure the admin API through the allowlist when using ingress-controller. Security hardening attempts are silently ignored.

Example with default values:

# User expects: localhost only
allow_admin:
  - 127.0.0.1/24    # Secure default
  - 0.0.0.0/0       # Auto-added - silently weakens security!

Problem 2: IPv6 Not Supported

Steps to Reproduce

  1. Deploy to an IPv6-only Kubernetes cluster
  2. Enable ingress-controller with default settings
  3. Check ingress-controller pod logs

Expected Behavior

Ingress-controller should be able to access the admin API using its IPv6 address.

Actual Behavior

Access is denied because the allowlist only includes 0.0.0.0/0 (IPv4):

[error] access forbidden by rule, client: [2001:db8::1]

Impact

Chart is non-functional in IPv6-only clusters without manual workarounds.


Proposed Solutions

I see three potential approaches, each with different tradeoffs:

Option A: Always Append (Fixes IPv6, Maintains Current Behavior)

allow_admin:
{{- range $ips := .Values.apisix.admin.allow.ipList }}
  - {{ $ips | quote }}
{{- end }}
{{- if (index .Values "ingress-controller" "enabled") }}
  - 0.0.0.0/0
  - "::/0"
{{- end }}

Pros:

  • Minimal change - most backward compatible
  • Fixes IPv6 support
  • Simple logic

Cons:

  • Still overrides user security (documents the issue but doesn't fix it)
  • Users with custom ipList still get wildcards appended

Breaking Changes:

  • Empty ipList: [] no longer defaults to allow-all (see edge case note above)
  • Otherwise maintains current behavior + adds IPv6

Option B: Respect User Configuration (Most Secure)

allow_admin:
{{- if .Values.apisix.admin.allow.ipList }}
  {{- range $ips := .Values.apisix.admin.allow.ipList }}
  - {{ $ips | quote }}
  {{- end }}
{{- else }}
{{- if (index .Values "ingress-controller" "enabled") }}
  - 0.0.0.0/0
  - "::/0"
{{- end }}
{{- end }}

Pros:

  • Respects user security choices
  • No more silent security bypass
  • IPv6 support in defaults

Cons:

  • Breaking change for users relying on the current buggy behavior
  • Users must explicitly allow ingress-controller access when using custom ipList

Breaking Changes:

  • Empty ipList: [] no longer defaults to allow-all (see edge case note above)
  • Users with custom ipList who relied on auto-added 0.0.0.0/0 must add it explicitly
apisix:
  admin:
    allow:
      ipList:
        - 10.244.0.0/16      # Custom restriction
        - 0.0.0.0/0          # Must add explicitly for ingress-controller (if cidr is unknown)
        - "::/0"             # IPv6 support

Option C: Make It Configurable (Future-Proof)

Add new value to control behavior:

apisix:
  admin:
    allow:
      ipList:
        - 127.0.0.1/24
      autoAddIngressControllerAccess: true  # New option (default: true)

Template logic:

allow_admin:
{{- range $ips := .Values.apisix.admin.allow.ipList }}
  - {{ $ips | quote }}
{{- end }}
{{- if and (index .Values "ingress-controller" "enabled") .Values.apisix.admin.allow.autoAddIngressControllerAccess }}
  - 0.0.0.0/0
  - "::/0"
{{- end }}

Pros:

  • Gives users explicit control
  • Backward compatible (default: true maintains current behavior)
  • Clear and self-documenting
  • Easy to disable for security-conscious users

Cons:

  • More complex (adds new configuration option)
  • Requires documentation updates

Breaking Changes:

  • Empty ipList: [] no longer defaults to allow-all (see edge case note above)

Recommendation

I'm inclined to suggest Option C as it balances all concerns:

  • Fixes IPv6 support
  • Maintains backward compatibility
  • Gives users control over security
  • Makes behavior explicit and documented

However, I'm happy to implement whichever approach is preferred.

I'm also happy to submit a PR for this fix, combined with my other issue (#920) about IPv6 quoting since both touch the same ConfigMap template file.


Note: AI helped format this issue. The issue identification and proposed solutions are my own work.

twellck avatar Dec 17 '25 06:12 twellck