Skip to content
Merged
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
8 changes: 8 additions & 0 deletions charts/gateway-helm/templates/_rbac.tpl
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,14 @@ verbs:
- delete
- deletecollection
- patch
- apiGroups:
- certificates.k8s.io
resources:
- clustertrustbundles
verbs:
- list
- get
- watch
{{- end }}

{{- define "eg.rbac.infra.tokenreview" -}}
Expand Down
10 changes: 10 additions & 0 deletions internal/gatewayapi/backendtlspolicy.go
Original file line number Diff line number Diff line change
Expand Up @@ -327,6 +327,16 @@ func getCaCertsFromCARefs(namespace string, caCertificates []gwapiv1.LocalObject
} else {
return nil, fmt.Errorf("secret %s not found in namespace %s", caRef.Name, namespace)
}
case resource.KindClusterTrustBundle:
ctb := resources.GetClusterTrustBundle(string(caRef.Name))
if ctb != nil {
if ca != "" {
ca += "\n"
}
ca += ctb.Spec.TrustBundle
} else {
return nil, fmt.Errorf("cluster trust bundle %s not found", caRef.Name)
}
}
}

Expand Down
46 changes: 24 additions & 22 deletions internal/gatewayapi/clienttrafficpolicy.go
Original file line number Diff line number Diff line change
Expand Up @@ -835,47 +835,49 @@ func (t *Translator) buildListenerTLSParameters(policy *egv1a1.ClientTrafficPoli
}

for _, caCertRef := range tlsParams.ClientValidation.CACertificateRefs {
if caCertRef.Kind == nil || string(*caCertRef.Kind) == resource.KindSecret { // nolint
caCertRefKind := string(ptr.Deref(caCertRef.Kind, resource.KindSecret))
var caCertBytes []byte
switch caCertRefKind {
case resource.KindSecret:
secret, err := t.validateSecretRef(false, from, caCertRef, resources)
if err != nil {
return irTLSConfig, err
}

secretBytes, ok := getCaCertFromSecret(secret)
if !ok || len(secretBytes) == 0 {
secretCertBytes, ok := getCaCertFromSecret(secret)
if !ok || len(secretCertBytes) == 0 {
return irTLSConfig, fmt.Errorf(
"caCertificateRef not found in secret %s", caCertRef.Name)
"caCertificateRef secret [%s] not found", caCertRef.Name)
}

if err := validateCertificate(secretBytes); err != nil {
return irTLSConfig, fmt.Errorf(
"invalid certificate in secret %s: %w", caCertRef.Name, err)
}

irCACert.Certificate = append(irCACert.Certificate, secretBytes...)

} else if string(*caCertRef.Kind) == resource.KindConfigMap {
caCertBytes = secretCertBytes
case resource.KindConfigMap:
configMap, err := t.validateConfigMapRef(false, from, caCertRef, resources)
if err != nil {
return irTLSConfig, err
}

configMapBytes, ok := getCaCertFromConfigMap(configMap)
if !ok || len(configMapBytes) == 0 {
configMapData, ok := getCaCertFromConfigMap(configMap)
if !ok || len(configMapData) == 0 {
return irTLSConfig, fmt.Errorf(
"caCertificateRef not found in configMap %s", caCertRef.Name)
"caCertificateRef configmap [%s] not found", caCertRef.Name)
}

if err := validateCertificate([]byte(configMapBytes)); err != nil {
caCertBytes = []byte(configMapData)
case resource.KindClusterTrustBundle:
trustBundle := resources.GetClusterTrustBundle(string(caCertRef.Name))
if trustBundle == nil {
return irTLSConfig, fmt.Errorf(
"invalid certificate in configmap %s: %w", caCertRef.Name, err)
"caCertificateRef ClusterTrustBundle [%s] not found", caCertRef.Name)
}
caCertBytes = []byte(trustBundle.Spec.TrustBundle)
default:
return irTLSConfig, fmt.Errorf("unsupported caCertificateRef kind:%s", caCertRefKind)
}

irCACert.Certificate = append(irCACert.Certificate, configMapBytes...)
} else {
if err := validateCertificate(caCertBytes); err != nil {
return irTLSConfig, fmt.Errorf(
"unsupported caCertificateRef kind:%s", string(*caCertRef.Kind))
"invalid certificate in %s %s: %w", caCertRefKind, caCertRef.Name, err)
}
irCACert.Certificate = append(irCACert.Certificate, caCertBytes...)
}

if len(irCACert.Certificate) > 0 {
Expand Down
13 changes: 13 additions & 0 deletions internal/gatewayapi/resource/resource.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"reflect"

"golang.org/x/exp/slices"
certificatesv1b1 "k8s.io/api/certificates/v1beta1"
corev1 "k8s.io/api/core/v1"
discoveryv1 "k8s.io/api/discovery/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
Expand Down Expand Up @@ -66,6 +67,8 @@ type Resources struct {
Backends []*egv1a1.Backend `json:"backends,omitempty" yaml:"backends,omitempty"`
HTTPRouteFilters []*egv1a1.HTTPRouteFilter `json:"httpFilters,omitempty" yaml:"httpFilters,omitempty"`

ClusterTrustBundles []*certificatesv1b1.ClusterTrustBundle `json:"clusterTrustBundles,omitempty" yaml:"clusterTrustBundles,omitempty"`

serviceMap map[types.NamespacedName]*corev1.Service
}

Expand Down Expand Up @@ -160,6 +163,16 @@ func (r *Resources) GetSecret(namespace, name string) *corev1.Secret {
return nil
}

func (r *Resources) GetClusterTrustBundle(name string) *certificatesv1b1.ClusterTrustBundle {
for _, ctb := range r.ClusterTrustBundles {
if ctb.Name == name {
return ctb
}
}

return nil
}

func (r *Resources) GetConfigMap(namespace, name string) *corev1.ConfigMap {
for _, configMap := range r.ConfigMaps {
if configMap.Namespace == namespace && configMap.Name == name {
Expand Down
1 change: 1 addition & 0 deletions internal/gatewayapi/resource/supported_kind.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,4 +28,5 @@ const (
KindSecret = "Secret"
KindHTTPRouteFilter = "HTTPRouteFilter"
KindReferenceGrant = "ReferenceGrant"
KindClusterTrustBundle = "ClusterTrustBundle"
)
12 changes: 12 additions & 0 deletions internal/gatewayapi/resource/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
gateways:
- apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: gateway-btls
namespace: envoy-gateway
spec:
gatewayClassName: envoy-gateway-class
listeners:
- name: http
protocol: HTTP
port: 80
allowedRoutes:
namespaces:
from: All
httpRoutes:
- apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: httproute-btls
namespace: envoy-gateway
spec:
parentRefs:
- namespace: envoy-gateway
name: gateway-btls
sectionName: http
rules:
- matches:
- path:
type: Exact
value: "/exact"
backendRefs:
- name: http-backend
namespace: backends
port: 8080

referenceGrants:
- apiVersion: gateway.networking.k8s.io/v1alpha2
kind: ReferenceGrant
metadata:
name: refg-route-svc
namespace: backends
spec:
from:
- group: gateway.networking.k8s.io
kind: HTTPRoute
namespace: envoy-gateway
to:
- group: ""
kind: Service
services:
- apiVersion: v1
kind: Service
metadata:
name: http-backend
namespace: backends
spec:
clusterIP: 10.11.12.13
ports:
- port: 8080
name: http
protocol: TCP
targetPort: 8080

endpointSlices:
- apiVersion: discovery.k8s.io/v1
kind: EndpointSlice
metadata:
name: endpointslice-http-backend
namespace: backends
labels:
kubernetes.io/service-name: http-backend
addressType: IPv4
ports:
- name: http
protocol: TCP
port: 8080
endpoints:
- addresses:
- "10.244.0.11"
conditions:
ready: true
clusterTrustBundles:
- apiVersion: certificates.k8s.io/v1beta1
kind: ClusterTrustBundle
metadata:
creationTimestamp: "2025-06-18T03:19:03Z"
name: ca-cluster-trust-bundle
spec:
trustBundle: |
-----BEGIN CERTIFICATE-----
MIIDQzCCAiugAwIBAgIBATANBgkqhkiG9w0BAQsFADBCMRMwEQYDVQQKEwpFbnZv
eVByb3h5MRAwDgYDVQQLEwdHYXRld2F5MRkwFwYDVQQDExBFbnZveSBHYXRld2F5
IENBMCAXDTI0MDMxMDE1MzIxN1oYDzIxMjQwMzEwMTYzMjE3WjBCMRMwEQYDVQQK
EwpFbnZveVByb3h5MRAwDgYDVQQLEwdHYXRld2F5MRkwFwYDVQQDExBFbnZveSBH
YXRld2F5IENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA7ZFmGB4e
m1KdGEohAZBfqydAEGLDHJ1YyfHWdd+vBAevdW64bZx3pggJOtgCnePuFd02rDQS
dlsJlX/6mFtoQilo6wvxDSJRfaTDbtfTjw+7k8yfd/Jsmh0RWG+UeyI7Na9sXAz7
b57mpxsCoNowzeK5ETiOGGNWPcjENJkSnBarz5muN00xIZWBU+yN5PLJNxZvxpZJ
Ol/SSI8sno0e0PxAmp3fe7QaXiZj/TAGJPGuTJkUxrHqyZGJtYUxsS8A0dT1zBjj
izA5Dp+b5yzYo23Hh7BgpbZ7X4gsDThFuwCD6fHyepuv2zHPqvSsdqg2hAhDp91R
zrn7a9GxG2VSIwIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUw
AwEB/zAdBgNVHQ4EFgQUUpP1aZ1M2KIuPPWrNPDV2c5CngowDQYJKoZIhvcNAQEL
BQADggEBAGSEkAVz+Z0qS4FmA0q4SCpIIq64bsdEjiUzev7pK1LEK0/Y28QBPixV
cUXfax18VPR9pls1JgXto9qY+C0hnRZic6611QTJlWK1p6dinQ/eDdYCBC+nv5xx
ssASwmplIxMvj3S1qF6dr7sMI2ZVD5HElTWdO19UBLyhiKKZW2KxDsYj+5NRwGFe
G+JuDgq7njUM8mdyYk0NehefdBUEUUCQtnwUtW95/429XwqQROuRDteGT9kjD+Y5
ea5mW4mfqLeuGJXZs9bdWjKKdLQPrn9IshPysWqz2Hz8dQ1f7N9/g8UWVSjd4cyx
S5EAolzVv0yB7wHCWCgfG/ckdOTUNnE=
-----END CERTIFICATE-----
backendTLSPolicies:
- apiVersion: gateway.networking.k8s.io/v1alpha2
kind: BackendTLSPolicy
metadata:
name: policy-btls
namespace: backends
spec:
targetRefs:
- group: ""
kind: Service
name: http-backend
sectionName: http
validation:
caCertificateRefs:
- name: ca-cluster-trust-bundle
group: ""
kind: ClusterTrustBundle
hostname: example.com
Loading
Loading