Skip to content

Add mTLS proxy support for enterprise proxies#4498

Open
dhawalseth wants to merge 9 commits into
actions:masterfrom
dhawalseth:feature/mtls-proxy-support
Open

Add mTLS proxy support for enterprise proxies#4498
dhawalseth wants to merge 9 commits into
actions:masterfrom
dhawalseth:feature/mtls-proxy-support

Conversation

@dhawalseth
Copy link
Copy Markdown
Contributor

@dhawalseth dhawalseth commented May 19, 2026

Summary

Add mTLS (mutual TLS) proxy support for enterprise environments that require client certificate authentication for egress traffic (e.g., corporate proxies like Kraken, Zscaler, or other TLS-terminating proxies).

Motivation

Many enterprise environments route all egress traffic through proxies that require mutual TLS authentication. Currently, ARC only supports basic auth (username/password) for proxy authentication via credentialSecretRef. This PR adds the infrastructure to support mTLS by:

  1. Mounting client certificates and CA certificates to listener and runner pods
  2. Controller reads TLS certs directly from K8s secrets for its own API calls
  3. Providing a clear configuration interface in Helm values
  4. Extending the CRD schema to include TLS configuration

Changes

New ProxyTLSConfig type

type ProxyTLSConfig struct {
    // Secret with 'tls.crt' and 'tls.key' for client auth
    ClientCertSecretRef string `json:"clientCertSecretRef,omitempty"`
    
    // Secret with 'ca.crt' for server verification
    CACertSecretRef string `json:"caCertSecretRef,omitempty"`
    
    // ConfigMap with 'ca.crt' (alternative to secret)
    CACertConfigMapRef string `json:"caCertConfigMapRef,omitempty"`
    
    // Skip server cert verification (testing only)
    InsecureSkipVerify bool `json:"insecureSkipVerify,omitempty"`
}

Updated Helm Configuration

proxy:
  https:
    url: https://proxy.example.com:443
    tls:
      # Create with: kubectl create secret tls proxy-client-cert --cert=client.crt --key=client.key
      clientCertSecretRef: proxy-client-cert
      # Create with: kubectl create secret generic proxy-ca --from-file=ca.crt=ca.pem
      caCertSecretRef: proxy-ca-cert

Certificate Mount Paths

Certificates are mounted to listener/runner pods at:

  • /etc/proxy-tls/https-proxy/client/tls.crt - Client certificate
  • /etc/proxy-tls/https-proxy/client/tls.key - Client private key
  • /etc/proxy-tls/https-proxy/ca/ca.crt - CA certificate

mTLS Support by Component

Component Client Cert CA Bundle How
Controller Reads secrets via K8s API at runtime
Listener Volume mounts + scaleset library
Runner Volume mounts + env vars

Controller mTLS Implementation

The controller reads TLS certificates directly from Kubernetes secrets (it has RBAC access to read secrets). When an AutoscalingRunnerSet has proxy TLS configured:

  1. secretresolver loads client certs from clientCertSecretRef
  2. secretresolver loads CA certs from caCertSecretRef or caCertConfigMapRef
  3. Certificates are passed to the scaleset HTTP client via WithTLSClientCertificate() and WithRootCAs()
  4. All GitHub API calls use mTLS through the proxy

Files Changed

  • apis/actions.github.com/v1alpha1/autoscalingrunnerset_types.go - New ProxyTLSConfig type
  • controllers/actions.github.com/resourcebuilder.go - Volume mount logic for listener/runner
  • controllers/actions.github.com/multiclient/multi_client.go - TLS client cert support
  • controllers/actions.github.com/secretresolver/secret_resolver.go - Load certs from secrets
  • charts/gha-runner-scale-set/values.yaml - Configuration examples
  • charts/gha-runner-scale-set/templates/autoscalingrunnerset.yaml - Template updates
  • CRDs regenerated

Usage Example

# Create client certificate secret
kubectl create secret tls proxy-mtls-client \
  --cert=client.crt \
  --key=client.key \
  -n arc-runners

# Create CA certificate secret
kubectl create secret generic proxy-mtls-ca \
  --from-file=ca.crt=proxy-ca.pem \
  -n arc-runners

# Install with mTLS proxy config
helm install arc-runner-set oci://ghcr.io/actions/actions-runner-controller-charts/gha-runner-scale-set \
  --set githubConfigUrl="https://github.com/myorg" \
  --set githubConfigSecret="github-secret" \
  --set proxy.https.url="https://proxy.example.com:443" \
  --set proxy.https.tls.clientCertSecretRef="proxy-mtls-client" \
  --set proxy.https.tls.caCertSecretRef="proxy-mtls-ca"

Related PRs

This is part of a coordinated effort to add mTLS proxy support across the GitHub Actions ecosystem:

Repository PR Description
actions/scaleset #101 ✅ Merged Add WithTLSClientCertificate() HTTPOption for Go HTTP client
actions/runner #4430 Add HTTPS_PROXY_CLIENT_CERT/KEY/CA_CERT environment variables

Test Plan

  • Unit tests for proxy TLS certificate loading
  • Helm template rendering tests with TLS config
  • Integration test with mock mTLS proxy
  • Manual verification of certificate mounts in pods

🤖 Generated with Claude Code

dseth-linkedin and others added 2 commits May 6, 2026 23:20
Addresses CVEs found in container image scanning:
- CVE-2026-27143 (Critical, CVSS 9.8)
- CVE-2026-27140 (High, CVSS 8.8)
- CVE-2026-33810 (High, CVSS 8.2)
- CVE-2026-32280 (High, CVSS 7.5)
- CVE-2026-32281 (High, CVSS 7.5)
- CVE-2026-32283 (High, CVSS 7.5)
- CVE-2026-27144 (High, CVSS 7.1)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This change adds support for mTLS authentication when connecting through
proxies that require client certificates (e.g., corporate proxies like Kraken).

Changes:
- Add ProxyTLSConfig type with fields for:
  - clientCertSecretRef: K8s secret with tls.crt and tls.key
  - caCertSecretRef: K8s secret with ca.crt
  - caCertConfigMapRef: ConfigMap with ca.crt (alternative)
  - insecureSkipVerify: Skip server cert verification (testing only)

- Update ProxyServerConfig to include optional TLS configuration

- Add proxyTLSVolumesAndMounts helper to create volumes and mounts
  for proxy TLS certificates

- Update listener pod creation to mount proxy TLS certs at
  /etc/proxy-tls/{http,https}-proxy/{client,ca}/

- Update runner pod creation to mount proxy TLS certs

- Update Helm values.yaml with mTLS configuration examples

- Update Helm templates to pass TLS config to CRD

- Regenerate CRDs with new ProxyTLSConfig schema

Note: This provides the infrastructure to mount certificates. The actual
TLS client configuration in ghalistener requires corresponding changes
in the github.com/actions/scaleset library to use these certificates.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
dhawalseth and others added 5 commits May 26, 2026 15:30
Enable the controller to use TLS client certificates when making
GitHub API calls through mTLS-enabled proxies.

Changes:
- multiclient: Add TLSClientCertificates field to ClientForOptions
- multiclient: Pass certificates to scaleset.WithTLSClientCertificate()
- secretresolver: Add loadProxyTLSClientCerts() to read certs from K8s secrets
- secretresolver: Load certs from proxy.http.tls.clientCertSecretRef and
  proxy.https.tls.clientCertSecretRef when configured
- Update scaleset dependency to include mTLS support (v0.4.1-0.20260520143653)

The controller reads TLS certificates directly from Kubernetes secrets
(it has RBAC access), unlike listener/runner pods which get certs
mounted as volumes or passed via environment variables.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The ProxyTLSConfig CRD fields CACertSecretRef and CACertConfigMapRef
were defined but never used. This caused proxy TLS verification to fail
with "certificate signed by unknown authority" when using mTLS proxies
like Kraken that have certificates signed by internal CAs.

Changes:
- Add loadProxyCACerts() to load CA certs from secrets or configmaps
- Add addProxyCACertsToPool() helper to parse and add CA certs
- Call loadProxyCACerts() in GetActionsService() before creating client
- Merge proxy CAs with system cert pool for proper TLS verification

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add fallback support for loading proxy TLS certificates from file paths
when K8s secret/configmap refs are not configured. This enables use with
systems like k8s-lare that provision certificates to pod volumes.

Environment variables supported:
- HTTPS_PROXY_CA_CERT: file path to CA cert for proxy TLS verification
- HTTPS_PROXY_CLIENT_CERT: file path to client cert for mTLS
- HTTPS_PROXY_CLIENT_KEY: file path to client key for mTLS

The K8s secret/configmap refs take precedence when configured.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The previous implementation only loaded proxy TLS certificates when
proxy was configured in the AutoscalingRunnerSet CR. However, when
using HTTPS_PROXY environment variable (common in enterprise setups),
the CR proxy config is nil and the env var loading code was skipped.

This fix adds explicit checks for HTTPS_PROXY/HTTP_PROXY env vars and
loads TLS certificates from env vars in that case:
- loadProxyTLSClientCertsFromEnv() for mTLS client certs
- loadProxyCACertsFromEnv() for proxy CA verification

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@dhawalseth dhawalseth force-pushed the feature/mtls-proxy-support branch from b7d0e57 to 6c638de Compare May 27, 2026 17:10
Load TLS client certificate for proxy mTLS authentication when
HTTPS_PROXY_CLIENT_CERT and HTTPS_PROXY_CLIENT_KEY env vars are set.

This enables the listener to authenticate with mTLS proxies like
Kraken that require client certificates for egress.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
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