Skip to content

Commit 1760d9e

Browse files
committed
Automatically allow egress IPs on ManagedSeeds
Signed-off-by: Justin Lamp <[email protected]>
1 parent a2359a5 commit 1760d9e

File tree

5 files changed

+288
-1
lines changed

5 files changed

+288
-1
lines changed

charts/gardener-extension-acl/templates/rbac.yaml

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,16 @@ rules:
1818
- delete
1919
resources:
2020
- envoyfilters
21+
- apiGroups:
22+
- ""
23+
resources:
24+
- services
25+
resourceNames:
26+
- istio-ingressgateway
27+
verbs:
28+
- get
29+
- list
30+
- watch
2131
- apiGroups:
2232
- extensions.gardener.cloud
2333
resources:
@@ -144,6 +154,23 @@ rules:
144154
- watch
145155
---
146156
apiVersion: rbac.authorization.k8s.io/v1
157+
kind: Role
158+
metadata:
159+
labels:
160+
{{ include "labels" . | indent 4 }}
161+
name: {{ include "name" . }}
162+
namespace: kube-system
163+
rules:
164+
- apiGroups:
165+
- ""
166+
resources:
167+
- configmaps
168+
resourceNames:
169+
- shoot-info
170+
verbs:
171+
- get
172+
---
173+
apiVersion: rbac.authorization.k8s.io/v1
147174
kind: ClusterRoleBinding
148175
metadata:
149176
name: {{ include "name" . }}
@@ -157,3 +184,19 @@ subjects:
157184
- kind: ServiceAccount
158185
name: {{ include "name" . }}
159186
namespace: {{ .Release.Namespace }}
187+
---
188+
apiVersion: rbac.authorization.k8s.io/v1
189+
kind: RoleBinding
190+
metadata:
191+
name: {{ include "name" . }}
192+
namespace: kube-system
193+
labels:
194+
{{ include "labels" . | indent 4 }}
195+
roleRef:
196+
apiGroup: rbac.authorization.k8s.io
197+
kind: Role
198+
name: {{ include "name" . }}
199+
subjects:
200+
- kind: ServiceAccount
201+
name: {{ include "name" . }}
202+
namespace: {{ .Release.Namespace }}

deploy/extension/base/controller-registration.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ kind: ControllerDeployment
44
metadata:
55
name: acl
66
helm:
7-
rawChart: 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
7+
rawChart: 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
88
values:
99
image:
1010
tag: latest

pkg/controller/actuator.go

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ import (
3636
"github.com/pkg/errors"
3737
istionetworkv1beta1 "istio.io/client-go/pkg/apis/networking/v1beta1"
3838
appsv1 "k8s.io/api/apps/v1"
39+
corev1 "k8s.io/api/core/v1"
3940
"k8s.io/apimachinery/pkg/runtime"
4041
"k8s.io/apimachinery/pkg/runtime/serializer"
4142
"k8s.io/client-go/rest"
@@ -48,6 +49,8 @@ import (
4849
"github.com/stackitcloud/gardener-extension-acl/pkg/extensionspec"
4950
"github.com/stackitcloud/gardener-extension-acl/pkg/helper"
5051
"github.com/stackitcloud/gardener-extension-acl/pkg/imagevector"
52+
53+
apierrors "k8s.io/apimachinery/pkg/api/errors"
5154
)
5255

5356
const (
@@ -87,13 +90,15 @@ func NewActuator(mgr manager.Manager, cfg config.Config) extension.Actuator {
8790
return &actuator{
8891
extensionConfig: cfg,
8992
client: mgr.GetClient(),
93+
reader: mgr.GetAPIReader(),
9094
config: mgr.GetConfig(),
9195
decoder: serializer.NewCodecFactory(mgr.GetScheme(), serializer.EnableStrict).UniversalDecoder(),
9296
}
9397
}
9498

9599
type actuator struct {
96100
client client.Client
101+
reader client.Reader
97102
config *rest.Config
98103
decoder runtime.Decoder
99104
extensionConfig config.Config
@@ -147,6 +152,18 @@ func (a *actuator) Reconcile(ctx context.Context, log logr.Logger, ex *extension
147152

148153
alwaysAllowedCIDRs = append(alwaysAllowedCIDRs, helper.GetSeedSpecificAllowedCIDRs(cluster.Seed)...)
149154

155+
// In casese where the istio-ingressgateway is exposed with the Proxy IPMode some
156+
// CNIs (like cilium for example) do not hairpin NAT the traffic to it, which
157+
// will result in the destination IP being set to the egressIP of the cluster.
158+
// In that case the AlertManager ApiServerNoteReachable check will fail.
159+
if a.usesProxyTypeLBService(ctx, log, istioLabels) {
160+
egressCIDRs, err := a.getSeedEgressIPOnManagedSeeds(ctx)
161+
if err != nil {
162+
return err
163+
}
164+
alwaysAllowedCIDRs = append(alwaysAllowedCIDRs, egressCIDRs...)
165+
}
166+
150167
if len(a.extensionConfig.AdditionalAllowedCIDRs) >= 1 {
151168
alwaysAllowedCIDRs = append(alwaysAllowedCIDRs, a.extensionConfig.AdditionalAllowedCIDRs...)
152169
}
@@ -446,3 +463,68 @@ func (a *actuator) findDefaultIstioLabels(
446463

447464
return gw.Spec.Selector, nil
448465
}
466+
467+
// usesProxyTypeLBService checks the `istio-ingressgateway` LoadBalancer Service
468+
// selected by its labels whether it is exposing the service with the Proxy IPMode
469+
func (a *actuator) usesProxyTypeLBService(
470+
ctx context.Context,
471+
log logr.Logger,
472+
labels map[string]string,
473+
) bool {
474+
svcs := corev1.ServiceList{}
475+
labelsSelector := client.MatchingLabels(labels)
476+
fieldSelector := client.MatchingFields{"metadata.name": v1beta1constants.DefaultSNIIngressServiceName}
477+
err := a.reader.List(ctx, &svcs, labelsSelector, fieldSelector)
478+
if err != nil {
479+
log.Error(err, "unable to fetch Services for Istio Ingressgateways", "labels", labels)
480+
return false
481+
}
482+
483+
switch len(svcs.Items) {
484+
case 1:
485+
for _, ing := range svcs.Items[0].Status.LoadBalancer.Ingress {
486+
if m := ing.IPMode; m != nil && *m == corev1.LoadBalancerIPModeProxy {
487+
return true
488+
}
489+
}
490+
case 0:
491+
log.Error(nil, "unable to find Istio Ingressgateway service", "name", v1beta1constants.DefaultSNIIngressServiceName, "labels", labels)
492+
default:
493+
log.Error(nil, "found more than one IngressGateway service", "name", v1beta1constants.DefaultSNIIngressServiceName, "labels", labels)
494+
}
495+
496+
return false
497+
}
498+
499+
// getSeedEgressIPOnManagedSeeds returns the egressIP CIDRs of the ManagedSeed, if the
500+
// Seed is not a shoot, it will return an empty list
501+
func (a *actuator) getSeedEgressIPOnManagedSeeds(ctx context.Context) ([]string, error) {
502+
cm := corev1.ConfigMap{}
503+
if err := a.client.Get(ctx,
504+
client.ObjectKey{
505+
Name: v1beta1constants.ConfigMapNameShootInfo,
506+
Namespace: "kube-system",
507+
},
508+
&cm); err != nil {
509+
if apierrors.IsNotFound(err) {
510+
return []string{}, nil
511+
}
512+
return nil, err
513+
}
514+
515+
cidrsStr, ok := cm.Data["egressCIDRs"]
516+
if !ok {
517+
return nil, errors.New("unable to get egress CIDRs from shoot-info ConfigMap")
518+
}
519+
520+
var cidrs []string
521+
for i := range strings.SplitSeq(cidrsStr, ",") {
522+
_, _, err := net.ParseCIDR(i)
523+
if err != nil {
524+
return nil, err
525+
}
526+
cidrs = append(cidrs, i)
527+
}
528+
529+
return cidrs, nil
530+
}

pkg/controller/actuator_test.go

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,15 @@ import (
77
extensionsv1alpha1 "github.com/gardener/gardener/pkg/apis/extensions/v1alpha1"
88
"github.com/gardener/gardener/pkg/apis/resources/v1alpha1"
99
. "github.com/gardener/gardener/pkg/utils/test/matchers"
10+
"github.com/go-logr/logr"
1011
. "github.com/onsi/ginkgo/v2"
1112
. "github.com/onsi/gomega"
1213
istionetworkingv1beta1 "istio.io/client-go/pkg/apis/networking/v1beta1"
1314
corev1 "k8s.io/api/core/v1"
1415
apierrors "k8s.io/apimachinery/pkg/api/errors"
1516
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
1617
"k8s.io/apimachinery/pkg/types"
18+
"k8s.io/utils/ptr"
1719

1820
"github.com/stackitcloud/gardener-extension-acl/pkg/controller/config"
1921
"github.com/stackitcloud/gardener-extension-acl/pkg/envoyfilters"
@@ -26,11 +28,13 @@ var _ = Describe("actuator test", func() {
2628
shootNamespace1, shootNamespace2 string
2729
istioNamespace1, istioNamespace2 string
2830
istioNamespace1Selector, istioNamespace2Selector map[string]string
31+
istioIngressGatewayServiceName string
2932
)
3033

3134
BeforeEach(func() {
3235
shootNamespace1 = createNewShootNamespace()
3336
istioNamespace1 = createNewIstioNamespace()
37+
istioIngressGatewayServiceName = "istio-ingressgateway"
3438
istioNamespace1Selector = map[string]string{
3539
"app": "istio-ingressgateway",
3640
"istio": istioNamespace1,
@@ -41,6 +45,24 @@ var _ = Describe("actuator test", func() {
4145
createNewIstioDeployment(istioNamespace1, istioNamespace1Selector)
4246
createNewCluster(shootNamespace1)
4347
createNewInfrastructure(shootNamespace1)
48+
createNewService(
49+
istioIngressGatewayServiceName,
50+
istioNamespace1,
51+
istioNamespace1Selector,
52+
corev1.ServiceTypeLoadBalancer,
53+
)
54+
updateServiceStatus(
55+
istioIngressGatewayServiceName,
56+
istioNamespace1,
57+
corev1.ServiceStatus{
58+
LoadBalancer: corev1.LoadBalancerStatus{
59+
Ingress: []corev1.LoadBalancerIngress{{
60+
IP: "1.1.1.1",
61+
IPMode: ptr.To(corev1.LoadBalancerIPModeProxy),
62+
}},
63+
},
64+
},
65+
)
4466

4567
a = getNewActuator()
4668
})
@@ -222,6 +244,87 @@ var _ = Describe("actuator test", func() {
222244
})
223245
})
224246

247+
Describe("reconciliation of an extension object running on a managedSeed", func() {
248+
AfterEach(func() {
249+
deleteShootInfo()
250+
})
251+
252+
It("should not get the egressIPs if the LoadBalancer IPMode is not set to Proxy", func() {
253+
updateServiceStatus(
254+
istioIngressGatewayServiceName,
255+
istioNamespace1,
256+
corev1.ServiceStatus{},
257+
)
258+
Expect(a.usesProxyTypeLBService(ctx, logr.Logger{}, istioNamespace1Selector)).To(BeFalse())
259+
260+
updateServiceStatus(
261+
istioIngressGatewayServiceName,
262+
istioNamespace1,
263+
corev1.ServiceStatus{
264+
LoadBalancer: corev1.LoadBalancerStatus{
265+
Ingress: []corev1.LoadBalancerIngress{{
266+
IP: "1.1.1.1",
267+
IPMode: ptr.To(corev1.LoadBalancerIPModeVIP),
268+
}},
269+
},
270+
},
271+
)
272+
Expect(a.usesProxyTypeLBService(ctx, logr.Logger{}, istioNamespace1Selector)).To(BeFalse())
273+
})
274+
275+
It("should get the egressIPs if the LoadBalancer IPMode is set to Proxy", func() {
276+
Expect(a.usesProxyTypeLBService(ctx, logr.Logger{}, istioNamespace1Selector)).To(BeTrue())
277+
})
278+
279+
It("should return an empty slice of egressIPs if no shoot-info ConfigMap exists", func() {
280+
cidrs, err := a.getSeedEgressIPOnManagedSeeds(ctx)
281+
Expect(err).ToNot(HaveOccurred())
282+
Expect(cidrs).To(BeEmpty())
283+
})
284+
285+
It("should fail to return egressIPs if the shoot-info ConfigMap contains invalid CIDRs", func() {
286+
createShootInfo([]string{"1.1.1.1", "1.1.1.2/32"})
287+
288+
_, err := a.getSeedEgressIPOnManagedSeeds(ctx)
289+
Expect(err).To(HaveOccurred())
290+
})
291+
292+
It("should return the egressIP CIDRs of the shoot-info ConfigMap", func() {
293+
c := []string{"1.1.1.1/32", "1.1.1.2/32"}
294+
createShootInfo(c)
295+
296+
cidrs, err := a.getSeedEgressIPOnManagedSeeds(ctx)
297+
Expect(err).ToNot(HaveOccurred())
298+
Expect(cidrs).To(BeEquivalentTo(c))
299+
})
300+
301+
It("should create ACLs including egressIPs of managedSeed", func() {
302+
createShootInfo([]string{"1.1.1.1/32", "1.1.1.2/32"})
303+
304+
extSpec := extensionspec.ExtensionSpec{
305+
Rule: &envoyfilters.ACLRule{
306+
Cidrs: []string{"1.2.3.4/24"},
307+
Action: "ALLOW",
308+
Type: "remote_ip",
309+
},
310+
}
311+
extSpecJSON, err := json.Marshal(extSpec)
312+
Expect(err).NotTo(HaveOccurred())
313+
ext := createNewExtension(shootNamespace1, extSpecJSON)
314+
Expect(ext).To(Not(BeNil()))
315+
316+
Expect(a.Reconcile(ctx, logger, ext)).To(Succeed())
317+
318+
mr := &v1alpha1.ManagedResource{}
319+
Expect(k8sClient.Get(ctx, types.NamespacedName{Name: ResourceNameSeed, Namespace: shootNamespace1}, mr)).To(Succeed())
320+
secret := &corev1.Secret{}
321+
Expect(k8sClient.Get(ctx, types.NamespacedName{Name: mr.Spec.SecretRefs[0].Name, Namespace: shootNamespace1}, secret)).To(Succeed())
322+
Expect(secret.Data["seed"]).To(ContainSubstring("1.2.3.4"))
323+
Expect(secret.Data["seed"]).To(ContainSubstring("1.1.1.1"))
324+
Expect(secret.Data["seed"]).To(ContainSubstring("1.1.1.2"))
325+
})
326+
})
327+
225328
Describe("a shoot switching the istio namespace (e.g. when being migrated to HA)", func() {
226329
It("should modify the EnvoyFilter objects accordingly", func() {
227330
By("1) creating the EnvoyFilter object correctly in the ORIGINAL namespace")
@@ -453,6 +556,7 @@ var _ = Describe("actuator unit test", func() {
453556
func getNewActuator() *actuator {
454557
return &actuator{
455558
client: k8sClient,
559+
reader: k8sClient,
456560
config: cfg,
457561
extensionConfig: config.Config{
458562
ChartPath: "../../charts",

0 commit comments

Comments
 (0)