Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 40 additions & 0 deletions charts/substrate/templates/atenet-egress.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -70,8 +70,15 @@ data:
- backends:
- dynamic: {}
policies:
{{- if .Values.atenetEgress.upstreamTrust.caBundle }}
{{- /* No root: the gateway then trusts the native roots, which are
the image's public bundle plus upstreamTrust (SSL_CERT_FILE and
SSL_CERT_DIR on the agentgateway container). */}}
backendTLS: {}
{{- else }}
backendTLS:
root: /etc/ssl/certs/ca-certificates.crt
{{- end }}
policies:
substrateEgress:
host: {{ include "substrate.fullname" (list "api" .) }}.{{ .Release.Namespace }}.svc:443
Expand Down Expand Up @@ -115,6 +122,17 @@ data:
tcpRoutes:
- backends:
- dynamic: {}
{{- with .Values.atenetEgress.upstreamTrust.caBundle }}
---
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ include "substrate.fullname" (list "atenet-egress-upstream-trust" $) }}
namespace: {{ $.Release.Namespace }}
data:
ca.crt: |
{{- . | nindent 4 }}
{{- end }}
---
apiVersion: apps/v1
kind: Deployment
Expand All @@ -132,6 +150,10 @@ spec:
metadata:
labels:
app: atenet-egress
{{- with .Values.atenetEgress.upstreamTrust.caBundle }}
annotations:
checksum/upstream-trust: {{ . | sha256sum }}
{{- end }}
spec:
serviceAccountName: {{ include "substrate.fullname" (list "atenet-egress" .) }}
securityContext:
Expand All @@ -155,6 +177,14 @@ spec:
fieldPath: status.podIP
- name: RUST_LOG
value: debug
{{- if .Values.atenetEgress.upstreamTrust.caBundle }}
# Both set: the upstream roots are the image's public bundle plus
# upstreamTrust (rustls-native-certs reads the two and nothing else).
- name: SSL_CERT_FILE
value: /etc/ssl/certs/ca-certificates.crt
- name: SSL_CERT_DIR
value: /run/egress-upstream-trust
{{- end }}
ports:
- name: https
containerPort: 8443
Expand Down Expand Up @@ -189,7 +219,17 @@ spec:
- name: actor-id-ca-certs
mountPath: /run/actor-id-ca-certs
readOnly: true
{{- if .Values.atenetEgress.upstreamTrust.caBundle }}
- name: upstream-trust
mountPath: /run/egress-upstream-trust
readOnly: true
{{- end }}
volumes:
{{- if .Values.atenetEgress.upstreamTrust.caBundle }}
- name: upstream-trust
configMap:
name: {{ include "substrate.fullname" (list "atenet-egress-upstream-trust" .) }}
{{- end }}
- name: egress-mitm
secret:
secretName: egress-mitm-ca-pool
Expand Down
119 changes: 119 additions & 0 deletions charts/substrate/tests/atenet_egress_upstream_trust_test.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
# Copyright 2026 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

suite: atenet egress upstream trust
templates:
- atenet-egress.yaml
tests:
- it: trusts the image's public roots only by default
documentSelector:
path: kind
value: Deployment
asserts:
- notContains:
path: spec.template.spec.containers[0].env
content:
name: SSL_CERT_DIR
value: /run/egress-upstream-trust
- notExists:
path: spec.template.metadata.annotations
- lengthEqual:
path: spec.template.spec.volumes
count: 5

- it: pins the dynamic HTTPS backend to the image's public bundle by default
documentSelector:
path: metadata.name
value: RELEASE-NAME-atenet-egress-agentgateway-config
asserts:
- matchRegex:
path: data["config.yaml"]
pattern: '- dynamic: \{\}\s+policies:\s+backendTLS:\s+root: /etc/ssl/certs/ca-certificates.crt'

- it: renders no upstream trust ConfigMap by default
asserts:
- containsDocument:
kind: ConfigMap
apiVersion: v1
name: RELEASE-NAME-atenet-egress-upstream-trust
not: true

- it: publishes the bundle as a ConfigMap
set:
atenetEgress.upstreamTrust.caBundle: |
-----BEGIN CERTIFICATE-----
MIIBlab
-----END CERTIFICATE-----
documentSelector:
path: metadata.name
value: RELEASE-NAME-atenet-egress-upstream-trust
asserts:
- equal:
path: data["ca.crt"]
value: |
-----BEGIN CERTIFICATE-----
MIIBlab
-----END CERTIFICATE-----

- it: adds the bundle to the public roots of the egress agentgateway and rolls on a change
set:
atenetEgress.upstreamTrust.caBundle: |
-----BEGIN CERTIFICATE-----
MIIBlab
-----END CERTIFICATE-----
documentSelector:
path: kind
value: Deployment
asserts:
- contains:
path: spec.template.spec.containers[0].env
content:
name: SSL_CERT_FILE
value: /etc/ssl/certs/ca-certificates.crt
- contains:
path: spec.template.spec.containers[0].env
content:
name: SSL_CERT_DIR
value: /run/egress-upstream-trust
- contains:
path: spec.template.spec.containers[0].volumeMounts
content:
name: upstream-trust
mountPath: /run/egress-upstream-trust
readOnly: true
- contains:
path: spec.template.spec.volumes
content:
name: upstream-trust
configMap:
name: RELEASE-NAME-atenet-egress-upstream-trust
- exists:
path: spec.template.metadata.annotations["checksum/upstream-trust"]

- it: leaves root out of the dynamic HTTPS backend so the gateway loads the native roots
set:
atenetEgress.upstreamTrust.caBundle: |
-----BEGIN CERTIFICATE-----
MIIBlab
-----END CERTIFICATE-----
documentSelector:
path: metadata.name
value: RELEASE-NAME-atenet-egress-agentgateway-config
asserts:
- matchRegex:
path: data["config.yaml"]
pattern: '- dynamic: \{\}\s+policies:\s+backendTLS: \{\}'
- notMatchRegex:
path: data["config.yaml"]
pattern: /etc/ssl/certs/ca-certificates.crt
8 changes: 8 additions & 0 deletions charts/substrate/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,14 @@ atenetEgress:
limits:
cpu: "2"
memory: 1Gi
# Extra CAs the egress gateway trusts on the actors' upstream HTTPS, next to
# the public roots of its image: a PEM bundle for model or tool endpoints
# behind a private CA (an in-cluster Gateway, a corporate proxy). Empty
# trusts the public roots only. The egress gateway terminates the actors' TLS
# and dials the upstream itself, so a CA the runtime trusts counts for
# nothing here. A change rolls the gateway: the roots are read at start.
upstreamTrust:
caBundle: ""

# Kubernetes Secret provider and AGW HTTP/HTTPS credential injection.
# Includes get-only Secret RBAC. HTTPS requires egress-mitm-ca-pool and actor trust.
Expand Down