Skip to content

feat: mount a custom CA certificate into MCP containers and the Obot pod - #7109

Open
jbittner-dimensional wants to merge 2 commits into
obot-platform:mainfrom
jbittner-dimensional:pr/ca-cert
Open

feat: mount a custom CA certificate into MCP containers and the Obot pod#7109
jbittner-dimensional wants to merge 2 commits into
obot-platform:mainfrom
jbittner-dimensional:pr/ca-cert

Conversation

@jbittner-dimensional

Copy link
Copy Markdown

Motivation

Enterprise and airgapped deployments frequently front internal services with a private CA that isn't in the default system trust store. MCP containers (and the Obot pod itself) then fail TLS verification when talking to those services. This adds first-class support for mounting a custom PEM CA bundle so Go, Python, and Node.js runtimes all trust it.

What's added

Docker backend

  • OBOT_SERVER_MCPCACERT_FILE: bind-mounts a PEM file (read-only) into every MCP container and sets SSL_CERT_FILE, REQUESTS_CA_BUNDLE, NODE_EXTRA_CA_CERTS. Validated at startup.

Kubernetes backend

  • OBOT_SERVER_MCPCACERT_SECRET_NAME / OBOT_SERVER_MCPCACERT_SECRET_KEY: mounts the named Secret on every MCP container with the same three env vars. No-op when unset.

Helm chart

  • New top-level mcpCACertificate section (content / existingSecret / secretKey) that creates the Secret in the release and MCP namespaces and mounts the bundle on the Obot pod. Config keys are emitted into the internal ConfigMap.

Notes

The bundle replaces the default trust store for Go (SSL_CERT_FILE) and Python (REQUESTS_CA_BUNDLE); if public-internet TLS must also work, concatenate the custom CA with the system bundle before supplying it (documented in values.yaml).

Testing

  • go build ./pkg/mcp/... passes.
  • Chart values validated.

🤖 Generated with Claude Code

Enterprise/airgapped deployments often front internal services with a
private CA that isn't in the default trust store. Add support for mounting
a custom PEM CA bundle so Go, Python, and Node.js runtimes in MCP
containers (and the Obot pod) trust it.

- Docker backend: OBOT_SERVER_MCPCACERT_FILE bind-mounts a PEM file into
  every MCP container and sets SSL_CERT_FILE / REQUESTS_CA_BUNDLE /
  NODE_EXTRA_CA_CERTS.
- Kubernetes backend: OBOT_SERVER_MCPCACERT_SECRET_NAME / _SECRET_KEY mount
  a Secret on every MCP container with the same env vars.
- Helm: new top-level `mcpCACertificate` section (content / existingSecret /
  secretKey) that creates the Secret in the release and MCP namespaces and
  mounts the bundle on the Obot pod. Config keys live in the internal
  ConfigMap.
Copilot AI review requested due to automatic review settings July 3, 2026 15:08

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Adds first-class support for supplying a custom PEM CA bundle so MCP workloads (Docker containers or Kubernetes pods) and the Obot pod can trust internal/private TLS CAs in enterprise/airgapped deployments.

Changes:

  • Adds new server options/env config for custom CA injection: file bind-mount for Docker runtime, Secret mount for Kubernetes runtime.
  • Implements CA bundle mounting + runtime env vars (SSL_CERT_FILE, REQUESTS_CA_BUNDLE, NODE_EXTRA_CA_CERTS) for MCP deployments (Docker + Kubernetes backends).
  • Extends the Helm chart with an mcpCACertificate section, Secret creation (when inline content is provided), and pod mounts/env wiring.

Reviewed changes

Copilot reviewed 8 out of 8 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
pkg/mcp/loader.go Adds new CLI/env options for CA bundle configuration (file for Docker, Secret name/key for Kubernetes).
pkg/mcp/kubernetes.go Adds Secret-backed CA bundle volume/env injection into generated MCP Deployments.
pkg/mcp/docker.go Adds optional CA bundle bind-mount + env vars for Docker-backed MCP containers, plus startup validation.
chart/values.yaml Documents new mcpCACertificate values and Docker-side CA file setting.
chart/templates/mcp-ca-certificate.yaml Creates the CA bundle Secret(s) when inline PEM content is provided.
chart/templates/internal-configmap.yaml Emits CA Secret name/key into internal config when MCP runtime backend is Kubernetes.
chart/templates/deployment.yaml Mounts CA Secret into Obot pod and sets runtime trust env vars.
chart/templates/_helpers.tpl Adds helper to compute the effective CA Secret name.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +96 to +100
{{- if include "obot.mcpCACertificate.secretName" . }}
- name: mcp-ca-bundle
mountPath: /etc/ssl/certs/obot-ca-bundle
readOnly: true
{{- end }}
Comment on lines +172 to +176
{{- if include "obot.mcpCACertificate.secretName" . }}
- name: mcp-ca-bundle
secret:
secretName: {{ include "obot.mcpCACertificate.secretName" . }}
{{- end }}
Comment thread chart/values.yaml
Comment on lines +399 to +401
# mcpCACertificate -- Mount a custom PEM CA bundle into the Obot pod and every MCP server pod so they trust TLS certificates issued by an internal CA (airgapped / enterprise deployments).
# Only used when config.OBOT_SERVER_MCPRUNTIME_BACKEND is "kubernetes". For the Docker backend, use config.OBOT_SERVER_MCPCACERT_FILE.
# The bundle replaces the default trust store for Go (SSL_CERT_FILE) and Python (REQUESTS_CA_BUNDLE); if public-internet TLS must also work, concatenate your CA with the system bundle before supplying it.
Comment thread pkg/mcp/kubernetes.go
Comment on lines +957 to +960
Secret: &corev1.SecretVolumeSource{
SecretName: k.caCertSecretName,
},
},
Comment thread pkg/mcp/docker.go
Comment on lines +102 to +106
if d.caCertFile != "" {
if _, err := os.Stat(d.caCertFile); err != nil {
return nil, fmt.Errorf("MCP CA cert file %q not accessible: %w", d.caCertFile, err)
}
}
- deployment.yaml: emit the CA volume + volumeMount whenever mcpCACertificate
  is set (previously nested under an unrelated persistence/encryption if, so
  enabling only mcpCACertificate set the trust-store env vars without mounting
  the Secret).
- kubernetes.go: project only the configured secretKey via Items so a wrong
  key fails fast at mount time instead of pointing SSL_CERT_FILE at a missing
  path.
- docker.go: validate the CA file is a readable regular file at startup.
- values.yaml: clarify the Obot pod always mounts the bundle; MCP pods only on
  the kubernetes backend.
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