Skip to content

Commit

Permalink
Add Upstream TLS Support (envoyproxy#2247)
Browse files Browse the repository at this point in the history
* add upstream tls support

Signed-off-by: Tasdidur Rahman <tasdidurrahmannahyan@gmail.com>

* update backendtlspolicy status

Signed-off-by: TasdidurRahman <tasdid@appscode.com>

* cleanup

Signed-off-by: TasdidurRahman <tasdid@appscode.com>

* ignore ca check in secrets

Signed-off-by: Tasdidur Rahman <tasdidurrahmannahyan@gmail.com>

* fix status condition

Signed-off-by: Tasdidur Rahman <tasdidurrahmannahyan@gmail.com>

* update error handling

Signed-off-by: Tasdidur Rahman <tasdidurrahmannahyan@gmail.com>

* add test for backendtlspolicy

Signed-off-by: Tasdidur Rahman <tasdidurrahmannahyan@gmail.com>

* rebase

Signed-off-by: Tasdidur Rahman <tasdidurrahmannahyan@gmail.com>

* update test for backendtlspolicy

Signed-off-by: Tasdidur Rahman <tasdidurrahmannahyan@gmail.com>

* reuse tls structures

Signed-off-by: Tasdidur Rahman <tasdidurrahmannahyan@gmail.com>

* remove mtls

Signed-off-by: Tasdidur Rahman <tasdidurrahmannahyan@gmail.com>

* move CA config to destination settings

Signed-off-by: TasdidurRahman <tasdid@appscode.com>

* update alias

Signed-off-by: TasdidurRahman <tasdid@appscode.com>

* add upstream tls support

Signed-off-by: TasdidurRahman <tasdid@appscode.com>

* fix linter

Signed-off-by: Tasdidur Rahman <tasdidurrahmannahyan@gmail.com>

* fix rbac for backendtlspolicy

Signed-off-by: Tasdidur Rahman <tasdidurrahmannahyan@gmail.com>

* fix testdata

Signed-off-by: Tasdidur Rahman <tasdidurrahmannahyan@gmail.com>

---------

Signed-off-by: Tasdidur Rahman <tasdidurrahmannahyan@gmail.com>
Signed-off-by: TasdidurRahman <tasdid@appscode.com>
  • Loading branch information
TasdidurRahman authored Mar 4, 2024
1 parent e8a2b5e commit ce1eb54
Show file tree
Hide file tree
Showing 30 changed files with 1,511 additions and 3 deletions.
2 changes: 2 additions & 0 deletions charts/gateway-helm/templates/_rbac.tpl
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,7 @@ apiGroups:
- gateway.networking.k8s.io
resources:
- gatewayclasses
- backendtlspolicies
verbs:
- get
- list
Expand All @@ -164,6 +165,7 @@ apiGroups:
- gateway.networking.k8s.io
resources:
- gatewayclasses/status
- backendtlspolicies/status
verbs:
- update
{{- end }}
45 changes: 45 additions & 0 deletions internal/gatewayapi/backendtlspolicy.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
// Copyright Envoy Gateway Authors
// SPDX-License-Identifier: Apache-2.0
// The full text of the Apache license is available in the LICENSE file at
// the root of the repo.

package gatewayapi

import (
"sigs.k8s.io/gateway-api/apis/v1alpha2"
)

func (t *Translator) ProcessBackendTLSPoliciesAncestorRef(backendTLSPolicies []*v1alpha2.BackendTLSPolicy, gateways []*GatewayContext) []*v1alpha2.BackendTLSPolicy {

var res []*v1alpha2.BackendTLSPolicy

for _, btlsPolicy := range backendTLSPolicies {

policy := btlsPolicy.DeepCopy()
res = append(res, policy)

if policy.Status.Ancestors != nil {
for k, status := range policy.Status.Ancestors {
exist := false
for _, gwContext := range gateways {
gw := gwContext.Gateway
if gw.Name == string(status.AncestorRef.Name) && gw.Namespace == NamespaceDerefOrAlpha(status.AncestorRef.Namespace, "default") {
for _, lis := range gw.Spec.Listeners {
if lis.Name == *status.AncestorRef.SectionName {
exist = true
}
}
}
}

if !exist {
policy.Status.Ancestors = append(policy.Status.Ancestors[:k], policy.Status.Ancestors[k+1:]...)
}
}
} else {
policy.Status.Ancestors = []v1alpha2.PolicyAncestorStatus{}
}
}

return res
}
2 changes: 2 additions & 0 deletions internal/gatewayapi/resource.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ type Resources struct {
ClientTrafficPolicies []*egv1a1.ClientTrafficPolicy `json:"clientTrafficPolicies,omitempty" yaml:"clientTrafficPolicies,omitempty"`
BackendTrafficPolicies []*egv1a1.BackendTrafficPolicy `json:"backendTrafficPolicies,omitempty" yaml:"backendTrafficPolicies,omitempty"`
SecurityPolicies []*egv1a1.SecurityPolicy `json:"securityPolicies,omitempty" yaml:"securityPolicies,omitempty"`
BackendTLSPolicies []*gwapiv1a2.BackendTLSPolicy `json:"backendTLSPolicies,omitempty" yaml:"backendTLSPolicies,omitempty"`
}

func NewResources() *Resources {
Expand All @@ -70,6 +71,7 @@ func NewResources() *Resources {
ClientTrafficPolicies: []*egv1a1.ClientTrafficPolicy{},
BackendTrafficPolicies: []*egv1a1.BackendTrafficPolicy{},
SecurityPolicies: []*egv1a1.SecurityPolicy{},
BackendTLSPolicies: []*gwapiv1a2.BackendTLSPolicy{},
}
}

Expand Down
129 changes: 129 additions & 0 deletions internal/gatewayapi/route.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ package gatewayapi

import (
"fmt"
"strconv"
"strings"
"time"

Expand Down Expand Up @@ -1096,6 +1097,7 @@ func (t *Translator) processDestination(backendRefContext BackendRefContext,
addrType *ir.DestinationAddressType
)
protocol := inspectAppProtocolByRouteKind(routeType)
var backendTLS *ir.TLSUpstreamConfig
switch KindDerefOr(backendRef.Kind, KindService) {
case KindServiceImport:
serviceImport := resources.GetServiceImport(backendNamespace, string(backendRef.Name))
Expand Down Expand Up @@ -1146,6 +1148,7 @@ func (t *Translator) processDestination(backendRefContext BackendRefContext,
uint32(*backendRef.Port))
endpoints = append(endpoints, ep)
}
backendTLS = t.processBackendTLSPolicy(*backendRef, backendNamespace, parentRef, resources)
}

// TODO: support mixed endpointslice address type for the same backendRef
Expand All @@ -1162,6 +1165,7 @@ func (t *Translator) processDestination(backendRefContext BackendRefContext,
Protocol: protocol,
Endpoints: endpoints,
AddressType: addrType,
TLS: backendTLS,
}
return ds, weight
}
Expand Down Expand Up @@ -1315,3 +1319,128 @@ func getIREndpointsFromEndpointSlice(endpointSlice *discoveryv1.EndpointSlice, p

return endpoints
}

func GetTargetBackendReference(backendRef gwapiv1a1.BackendRef, namespace string) gwapiv1a1.PolicyTargetReferenceWithSectionName {
ref := gwapiv1a1.PolicyTargetReferenceWithSectionName{
PolicyTargetReference: gwapiv1a1.PolicyTargetReference{
Group: func() gwapiv1a1.Group {
if backendRef.Group == nil {
return ""
}
return *backendRef.Group
}(),
Kind: func() gwapiv1.Kind {
if backendRef.Kind == nil {
return "Service"
}
return *backendRef.Kind
}(),
Name: backendRef.Name,
Namespace: NamespacePtr(NamespaceDerefOr(backendRef.Namespace, namespace)),
},
SectionName: func() *gwapiv1.SectionName {
if backendRef.Port != nil {
return SectionNamePtr(strconv.Itoa(int(*backendRef.Port)))
}
return nil
}(),
}
return ref
}

func backendTLSTargetMatched(policy gwapiv1a1.BackendTLSPolicy, target gwapiv1a1.PolicyTargetReferenceWithSectionName) bool {

policyTarget := policy.Spec.TargetRef

if target.Group == policyTarget.Group &&
target.Kind == policyTarget.Kind &&
target.Name == policyTarget.Name &&
NamespaceDerefOr(policyTarget.Namespace, policy.Namespace) == string(*target.Namespace) {
if policyTarget.SectionName != nil && *policyTarget.SectionName != *target.SectionName {
return false
}
return true
}
return false
}

func getBackendTLSPolicy(policies []*gwapiv1a1.BackendTLSPolicy, backendRef gwapiv1a1.BackendRef, backendNamespace string) *gwapiv1a1.BackendTLSPolicy {
target := GetTargetBackendReference(backendRef, backendNamespace)
for _, policy := range policies {
if backendTLSTargetMatched(*policy, target) {
return policy
}
}
return nil
}

func getBackendTLSBundle(policies []*gwapiv1a1.BackendTLSPolicy, configmaps []*corev1.ConfigMap, backendRef gwapiv1a1.BackendRef, backendNamespace string) (*ir.TLSUpstreamConfig, error) {

backendTLSPolicy := getBackendTLSPolicy(policies, backendRef, backendNamespace)

if backendTLSPolicy == nil {
return nil, nil
}

tlsBundle := &ir.TLSUpstreamConfig{}

caRefMap := make(map[string]string)

for _, caRef := range backendTLSPolicy.Spec.TLS.CACertRefs {
caRefMap[string(caRef.Name)] = string(caRef.Kind)
}

ca := ""

for _, cmap := range configmaps {
if kind, ok := caRefMap[cmap.Name]; ok && kind == cmap.Kind {
if crt, dataOk := cmap.Data["ca.crt"]; dataOk {
if ca != "" {
ca += "\n"
}
ca += crt
} else {
return nil, fmt.Errorf("no ca found in configmap %s", cmap.Name)
}
}
}

if ca == "" {
return nil, fmt.Errorf("no ca found in referred configmaps")
}

tlsBundle.CACertificate.Certificate = []byte(ca)

tlsBundle.CACertificate.Name = fmt.Sprintf("%s/%s-ca", backendTLSPolicy.Name, backendTLSPolicy.Namespace)

tlsBundle.SNI = string(backendTLSPolicy.Spec.TLS.Hostname)

return tlsBundle, nil
}

func (t *Translator) processBackendTLSPolicy(backendRef gwapiv1.BackendRef, backendNamespace string, parentRef *RouteParentContext, resources *Resources) *ir.TLSUpstreamConfig {
tlsBundle, err := getBackendTLSBundle(resources.BackendTLSPolicies, resources.ConfigMaps, backendRef, backendNamespace)
if err == nil && tlsBundle == nil {
return nil
}
policy := getBackendTLSPolicy(resources.BackendTLSPolicies, backendRef, backendNamespace)
ancestor := gwapiv1a1.PolicyAncestorStatus{
AncestorRef: gwapiv1a1.ParentReference{
Group: parentRef.Group,
Kind: parentRef.Kind,
Namespace: parentRef.Namespace,
Name: parentRef.Name,
SectionName: parentRef.SectionName,
Port: parentRef.Port,
},
ControllerName: gwapiv1.GatewayController(t.GatewayControllerName),
}
if err != nil {
messeg := status.Error2ConditionMsg(err)
status.SetBackendTLSPolicyCondition(policy, ancestor, gwapiv1a1.PolicyConditionAccepted, metav1.ConditionFalse, gwapiv1a1.PolicyReasonInvalid, messeg)
return nil
} else {
status.SetBackendTLSPolicyCondition(policy, ancestor, gwapiv1a1.PolicyConditionAccepted, metav1.ConditionTrue, gwapiv1a1.PolicyReasonAccepted, "BackendTLSPolicy is Accepted")
return tlsBundle
}
}
5 changes: 5 additions & 0 deletions internal/gatewayapi/runner/runner.go
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,11 @@ func (r *Runner) subscribeAndTranslate(ctx context.Context) {
key := utils.NamespacedName(securityPolicy)
r.ProviderResources.SecurityPolicyStatuses.Store(key, &securityPolicy.Status)
}
for _, backendTLSPolicy := range result.BackendTLSPolicies {
backendTLSPolicy := backendTLSPolicy
key := utils.NamespacedName(backendTLSPolicy)
r.ProviderResources.BackendTLSPolicyStatuses.Store(key, &backendTLSPolicy.Status)
}
}
// Delete keys
// There is a 1:1 mapping between infra and xds IR keys
Expand Down
137 changes: 137 additions & 0 deletions internal/gatewayapi/testdata/backendtlspolicy-ca-only.in.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
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
- group: gateway.networking.k8s.io
kind: Gateway
namespace: envoy-gateway
- group: gateway.networking.k8s.io
kind: BackendTLSPolicy
namespace: policies
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

configMaps:
- apiVersion: v1
kind: ConfigMap
metadata:
name: ca-cmap
namespace: policies
data:
ca.crt: |
-----BEGIN CERTIFICATE-----
MIIDJzCCAg+gAwIBAgIUAl6UKIuKmzte81cllz5PfdN2IlIwDQYJKoZIhvcNAQEL
BQAwIzEQMA4GA1UEAwwHbXljaWVudDEPMA0GA1UECgwGa3ViZWRiMB4XDTIzMTAw
MjA1NDE1N1oXDTI0MTAwMTA1NDE1N1owIzEQMA4GA1UEAwwHbXljaWVudDEPMA0G
A1UECgwGa3ViZWRiMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwSTc
1yj8HW62nynkFbXo4VXKv2jC0PM7dPVky87FweZcTKLoWQVPQE2p2kLDK6OEszmM
yyr+xxWtyiveremrWqnKkNTYhLfYPhgQkczib7eUalmFjUbhWdLvHakbEgCodn3b
kz57mInX2VpiDOKg4kyHfiuXWpiBqrCx0KNLpxo3DEQcFcsQTeTHzh4752GV04RU
Ti/GEWyzIsl4Rg7tGtAwmcIPgUNUfY2Q390FGqdH4ahn+mw/6aFbW31W63d9YJVq
ioyOVcaMIpM5B/c7Qc8SuhCI1YGhUyg4cRHLEw5VtikioyE3X04kna3jQAj54YbR
bpEhc35apKLB21HOUQIDAQABo1MwUTAdBgNVHQ4EFgQUyvl0VI5vJVSuYFXu7B48
6PbMEAowHwYDVR0jBBgwFoAUyvl0VI5vJVSuYFXu7B486PbMEAowDwYDVR0TAQH/
BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAMLxrgFVMuNRq2wAwcBt7SnNR5Cfz
2MvXq5EUmuawIUi9kaYjwdViDREGSjk7JW17vl576HjDkdfRwi4E28SydRInZf6J
i8HZcZ7caH6DxR335fgHVzLi5NiTce/OjNBQzQ2MJXVDd8DBmG5fyatJiOJQ4bWE
A7FlP0RdP3CO3GWE0M5iXOB2m1qWkE2eyO4UHvwTqNQLdrdAXgDQlbam9e4BG3Gg
d/6thAkWDbt/QNT+EJHDCvhDRKh1RuGHyg+Y+/nebTWWrFWsktRrbOoHCZiCpXI1
3eXE6nt0YkgtDxG22KqnhpAg9gUSs2hlhoxyvkzyF0mu6NhPlwAgnq7+/Q==
-----END CERTIFICATE-----
backendTLSPolicies:
- apiVersion: gateway.networking.k8s.io/v1alpha2
kind: BackendTLSPolicy
metadata:
name: policy-btls
namespace: policies
spec:
targetRef:
group: ''
kind: Service
name: http-backend
namespace: backends
sectionName: "8080"
tls:
caCertRefs:
- name: ca-cmap
group: ''
kind: ConfigMap
hostname: example.com
Loading

0 comments on commit ce1eb54

Please sign in to comment.