Skip to content

Upstream TLS trust: no config surface for a private CA, and no verification override #860

Description

@janiussyafiq

Description

Outbound TLS trust has no configuration surface. There is no ssl_verify-style switch and no way to point the gateway at a private CA bundle from config:

  • no tls / ca_file / verify field in the upstream: config section, which otherwise carries the connection-layer settings (timeouts, keepalive, pool, retries);

  • no TLS field on any resource in schemas/resources/ — in particular provider_key, which is where an upstream endpoint (api_base) is declared;

  • AISIX_UPSTREAM_SSL_VERIFY is rejected at boot:

    unknown field `upstream_ssl_verify`, expected one of `etcd`, `resources_file`,
    `proxy`, `admin`, `observability`, `cache`, `ratelimit`, `upstream`,
    `downstream`, `managed`, `bedrock_endpoint_url`
    

A private CA can be trusted today, but only as an OS-level side effect and only process-wide: SSL_CERT_FILE / SSL_CERT_DIR are honoured, and are additive to the built-in roots (setting SSL_CERT_FILE to a private CA alone still leaves public providers trusted). Neither is documented.

Requested, in order:

  1. Document the mechanism that already worksSSL_CERT_FILE / SSL_CERT_DIR, and the fact that it is additive. Zero code.
  2. A first-class config surface for a private CA, so trust is declared where the endpoint is declared rather than in the process environment — a deployment-level upstream.tls.ca_file, and/or a per-provider_key CA for deployments facing more than one private CA.
  3. An explicit, scoped verification override for test environments, as the peers below provide. Not global, and not the default.

Why

Self-hosted model endpoints and internal OIDC providers behind an enterprise CA are routine in on-prem deployments, and every outbound path is affected — the provider bridges, guardrails, MCP OAuth, A2A, OTLP export, and JWKS/discovery all share aisix_gateway::client_builder() (crates/aisix-gateway/src/upstream_http.rs:121).

The current answer is an environment variable that does not appear in the docs, the example config, or the resource schemas, so it is not discoverable from the failure. What operators see is a generic 502:

transport error: error sending request for url (https://...): client error (Connect): invalid peer certificate: UnknownIssuer

Worth flagging for whoever picks this up: the intuitive fix — dropping the CA in /usr/local/share/ca-certificates and running update-ca-certificatesdoes work, but only as root. The image runs as user aisix, so the command fails with Permission denied, leaves the bundle unchanged, and the gateway still rejects the certificate. It looks like the CA was installed when it was not.

Priority

Medium. A working workaround exists, but it is undocumented, process-wide, and cannot express "this one upstream, this one CA".

Reproduction

ghcr.io/api7/aisix:0.6.0, standalone (resources_file), against an HTTPS upstream whose certificate is signed by a private CA:

provider_keys:
  - display_name: private-pk
    provider: openai
    api_key: sk-mock
    api_base: https://internal-llm.example:8443/v1
Setting Result
(none) 502 invalid peer certificate: UnknownIssuer
SSL_CERT_FILE=/certs/ca.crt 200
SSL_CERT_DIR=/certs 200
CA into system store + update-ca-certificates, as root 200
CA into system store, as the default aisix user 502 — update-ca-certificates silently fails
REQUESTS_CA_BUNDLE=/certs/ca.crt 502

Prior art

Product Has it Reference
LiteLLM Yes ssl_verify: false or a CA path, plus SSL_VERIFY / SSL_CERT_FILE
Bifrost Yes ca_cert_pem and insecure_skip_verify in provider network_config
Kong Gateway Yes ca_certificates, tls_verify, tls_verify_depth on the Service entity
Envoy AI Gateway Yes BackendTLSPolicy.validation.caCertificateRefs
Apache APISIX Partial plugin-level ssl_verify, default true since 3.16.0; upstream server certs are not verified at all, and upstream tls.verify is Kafka-only
Cloudflare AI Gateway N/A managed edge service reached by base-URL redirect
Portkey Unknown not researched

Every self-hostable peer exposes at least a CA bundle; three of four also expose an explicit skip.

Surveyed 2026-07-31; every claim rests on a fetched docs/source page.

Metadata

Metadata

Assignees

Labels

enhancementNew feature or request

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions