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
1 change: 0 additions & 1 deletion api/v1alpha1/tls_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,6 @@ type ClientValidationContext struct {

// Crl specifies the crl configuration that can be used to validate the client initiating the TLS connection
// +optional
// +notImplementedHide
Crl *CrlContext `json:"crl,omitempty"`
}

Expand Down
4 changes: 2 additions & 2 deletions internal/gatewayapi/backendtlspolicy.go
Original file line number Diff line number Diff line change
Expand Up @@ -468,7 +468,7 @@ func getCaCertsFromCARefs(namespace string, caCertificates []gwapiv1.LocalObject
case resource.KindConfigMap:
cm := resources.GetConfigMap(namespace, string(caRef.Name))
if cm != nil {
if crt, dataOk := getCaCertFromConfigMap(cm); dataOk {
if crt, dataOk := getOrFirstFromData(cm.Data, caCertKey); dataOk {
if ca != "" {
ca += "\n"
}
Expand All @@ -482,7 +482,7 @@ func getCaCertsFromCARefs(namespace string, caCertificates []gwapiv1.LocalObject
case resource.KindSecret:
secret := resources.GetSecret(namespace, string(caRef.Name))
if secret != nil {
if crt, dataOk := getCaCertFromSecret(secret); dataOk {
if crt, dataOk := getOrFirstFromData(secret.Data, caCertKey); dataOk {
if ca != "" {
ca += "\n"
}
Expand Down
106 changes: 65 additions & 41 deletions internal/gatewayapi/clienttrafficpolicy.go
Original file line number Diff line number Diff line change
Expand Up @@ -857,56 +857,43 @@ func (t *Translator) buildListenerTLSParameters(policy *egv1a1.ClientTrafficPoli
}

for _, caCertRef := range tlsParams.ClientValidation.CACertificateRefs {
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
}

secretCertBytes, ok := getCaCertFromSecret(secret)
if !ok || len(secretCertBytes) == 0 {
return irTLSConfig, fmt.Errorf(
"caCertificateRef secret [%s] not found", caCertRef.Name)
}
caCertBytes = secretCertBytes
case resource.KindConfigMap:
configMap, err := t.validateConfigMapRef(false, from, caCertRef, resources)
if err != nil {
return irTLSConfig, err
}

configMapData, ok := getCaCertFromConfigMap(configMap)
if !ok || len(configMapData) == 0 {
return irTLSConfig, fmt.Errorf(
"caCertificateRef configmap [%s] not found", caCertRef.Name)
}
caCertBytes = []byte(configMapData)
case resource.KindClusterTrustBundle:
trustBundle := resources.GetClusterTrustBundle(string(caCertRef.Name))
if trustBundle == nil {
return irTLSConfig, fmt.Errorf(
"caCertificateRef ClusterTrustBundle [%s] not found", caCertRef.Name)
}
caCertBytes = []byte(trustBundle.Spec.TrustBundle)
default:
return irTLSConfig, fmt.Errorf("unsupported caCertificateRef kind:%s", caCertRefKind)
caCertBytes, err := t.validateAndGetDataAtKeyInRef(caCertRef, caCertKey, resources, from)
if err != nil {
return irTLSConfig, fmt.Errorf("failed to get certificate from ref: %w", err)
}

if err := validateCertificate(caCertBytes); err != nil {
return irTLSConfig, fmt.Errorf(
"invalid certificate in %s %s: %w", caCertRefKind, caCertRef.Name, err)
if err := validateCertificates(caCertBytes); err != nil {
return irTLSConfig, fmt.Errorf("invalid certificate in %s: %w", caCertRef.Name, err)
}
irCACert.Certificate = append(irCACert.Certificate, caCertBytes...)
}

if len(irCACert.Certificate) > 0 {
irTLSConfig.CACertificate = irCACert
irTLSConfig.RequireClientCertificate = !tlsParams.ClientValidation.Optional
setTLSClientValidationContext(tlsParams.ClientValidation, irTLSConfig)
}

irCrl := &ir.TLSCrl{
Name: irTLSCrlName(policy.Namespace, policy.Name),
}

if tlsParams.ClientValidation.Crl != nil {
for _, crlRef := range tlsParams.ClientValidation.Crl.Refs {
crlBytes, err := t.validateAndGetDataAtKeyInRef(crlRef, crlKey, resources, from)
if err != nil {
return irTLSConfig, fmt.Errorf("failed to get crl from ref: %w", err)
}
if err := validateCrl(crlBytes); err != nil {
return irTLSConfig, fmt.Errorf("invalid crl in %s: %w", crlRef.Name, err)
}
irCrl.Data = append(irCrl.Data, crlBytes...)
}
if len(irCrl.Data) > 0 {
irTLSConfig.Crl = irCrl
if tlsParams.ClientValidation.Crl.OnlyVerifyLeafCertificate != nil {
irCrl.OnlyVerifyLeafCertificate = *tlsParams.ClientValidation.Crl.OnlyVerifyLeafCertificate
}
}
}
}

if tlsParams.Session != nil && tlsParams.Session.Resumption != nil {
Expand All @@ -921,6 +908,43 @@ func (t *Translator) buildListenerTLSParameters(policy *egv1a1.ClientTrafficPoli
return irTLSConfig, nil
}

// validateAndGetDataAtKeyInRef validates the secret object reference and gets the data at the key in the secret or configmap
func (t *Translator) validateAndGetDataAtKeyInRef(ref gwapiv1.SecretObjectReference, key string, resources *resource.Resources, from crossNamespaceFrom) ([]byte, error) {
refKind := string(ptr.Deref(ref.Kind, resource.KindSecret))
switch refKind {
case resource.KindSecret:
secret, err := t.validateSecretRef(false, from, ref, resources)
if err != nil {
return nil, err
}

secretCertBytes, ok := getOrFirstFromData(secret.Data, key)
if !ok || len(secretCertBytes) == 0 {
return nil, fmt.Errorf("ref secret [%s] has no key %s and more than one entry", ref.Name, key)
}
return secretCertBytes, nil
case resource.KindConfigMap:
configMap, err := t.validateConfigMapRef(false, from, ref, resources)
if err != nil {
return nil, err
}

configMapData, ok := getOrFirstFromData(configMap.Data, key)
if !ok || len(configMapData) == 0 {
return nil, fmt.Errorf("ref configmap [%s] has no key %s and more than one entry", ref.Name, key)
}
return []byte(configMapData), nil
case resource.KindClusterTrustBundle:
trustBundle := resources.GetClusterTrustBundle(string(ref.Name))
if trustBundle == nil {
return nil, fmt.Errorf("ref ClusterTrustBundle [%s] not found", ref.Name)
}
return []byte(trustBundle.Spec.TrustBundle), nil
default:
return nil, fmt.Errorf("unsupported ref kind:%s", refKind)
}
}

func setTLSClientValidationContext(tlsClientValidation *egv1a1.ClientValidationContext, irTLSConfig *ir.TLSConfig) {
if len(tlsClientValidation.SPKIHashes) > 0 {
irTLSConfig.VerifyCertificateSpki = append(irTLSConfig.VerifyCertificateSpki, tlsClientValidation.SPKIHashes...)
Expand Down
44 changes: 14 additions & 30 deletions internal/gatewayapi/helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ const (
L7Protocol = "L7"

caCertKey = "ca.crt"
crlKey = "ca.crl"
)

type NamespacedNameWithSection struct {
Expand Down Expand Up @@ -466,6 +467,10 @@ func irTLSCACertName(namespace, name string) string {
return fmt.Sprintf("%s/%s/%s", namespace, name, caCertKey)
}

func irTLSCrlName(namespace, name string) string {
return fmt.Sprintf("%s/%s/%s", namespace, name, crlKey)
}

func IsMergeGatewaysEnabled(resources *resource.Resources) bool {
return resources.EnvoyProxyForGatewayClass != nil && resources.EnvoyProxyForGatewayClass.Spec.MergeGateways != nil && *resources.EnvoyProxyForGatewayClass.Spec.MergeGateways
}
Expand Down Expand Up @@ -712,38 +717,17 @@ func getPreserveRouteOrder(envoyProxy *egv1a1.EnvoyProxy) bool {
return false
}

func getCaCertFromConfigMap(cm *corev1.ConfigMap) (string, bool) {
var data string
data, exits := cm.Data[caCertKey]
switch {
case exits:
return data, true
case len(cm.Data) == 1: // Fallback to the first key if ca.crt is not found
for _, value := range cm.Data {
data = value
break
}
return data, true
default:
return "", false
}
}

func getCaCertFromSecret(s *corev1.Secret) ([]byte, bool) {
var data []byte
data, exits := s.Data[caCertKey]
switch {
case exits:
return data, true
case len(s.Data) == 1: // Fallback to the first key if ca.crt is not found
for _, value := range s.Data {
data = value
break
// getOrFirstFromData returns the value of the key in the data map
// or the first value if the key is not found only if data map has exactly one entry
func getOrFirstFromData[T any](data map[string]T, key string) (T, bool) {
if val, exists := data[key]; exists {
return val, true
} else if len(data) == 1 {
for _, value := range data {
return value, true
}
return data, true
default:
return nil, false
}
return *new(T), false
}

func irStringMatch(name string, match egv1a1.StringMatch) *ir.StringMatch {
Expand Down
4 changes: 2 additions & 2 deletions internal/gatewayapi/helpers_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -757,7 +757,7 @@ func TestGetCaCertFromConfigMap(t *testing.T) {

for _, tc := range cases {
t.Run(tc.name, func(t *testing.T) {
got, found := getCaCertFromConfigMap(tc.cm)
got, found := getOrFirstFromData(tc.cm.Data, caCertKey)
require.Equal(t, tc.expectedFound, found)
require.Equal(t, tc.expected, got)
})
Expand Down Expand Up @@ -803,7 +803,7 @@ func TestGetCaCertFromSecret(t *testing.T) {

for _, tc := range cases {
t.Run(tc.name, func(t *testing.T) {
got, found := getCaCertFromSecret(tc.s)
got, found := getOrFirstFromData(tc.s.Data, caCertKey)
require.Equal(t, tc.expectedFound, found)
require.Equal(t, tc.expected, string(got))
})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +263,19 @@ tcpRoutes:
- backendRefs:
- name: service-1
port: 8080
services:
- apiVersion: v1
kind: Service
metadata:
namespace: envoy-gateway
name: service-1
spec:
selector:
app: service-1
ports:
- name: http
protocol: TCP
port: 8080
secrets:
- apiVersion: v1
kind: Secret
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@ clientTrafficPolicies:
conditions:
- lastTransitionTime: null
message: |-
TLS: caCertificateRef secret [tls-secret-1] not found
TLS: caCertificateRef secret [tls-secret-1] not found.
TLS: failed to get certificate from ref: ref secret [tls-secret-1] has no key ca.crt and more than one entry
TLS: failed to get certificate from ref: ref secret [tls-secret-1] has no key ca.crt and more than one entry.
reason: Invalid
status: "False"
type: Accepted
Expand Down Expand Up @@ -69,8 +69,8 @@ clientTrafficPolicies:
conditions:
- lastTransitionTime: null
message: |-
TLS: configmap default/tls-cm-1 does not exist
TLS: configmap default/tls-cm-1 does not exist.
TLS: failed to get certificate from ref: configmap default/tls-cm-1 does not exist
TLS: failed to get certificate from ref: configmap default/tls-cm-1 does not exist.
reason: Invalid
status: "False"
type: Accepted
Expand Down Expand Up @@ -107,8 +107,8 @@ clientTrafficPolicies:
conditions:
- lastTransitionTime: null
message: |-
TLS: caCertificateRef ClusterTrustBundle [tls-ctb-1] not found
TLS: caCertificateRef ClusterTrustBundle [tls-ctb-1] not found.
TLS: failed to get certificate from ref: ref ClusterTrustBundle [tls-ctb-1] not found
TLS: failed to get certificate from ref: ref ClusterTrustBundle [tls-ctb-1] not found.
reason: Invalid
status: "False"
type: Accepted
Expand Down
Loading
Loading