diff --git a/CHANGELOG.md b/CHANGELOG.md index d06eecf54..2eebb6d76 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,15 @@ Also check this project's [releases](https://github.com/powerhome/redis-operator ## Unreleased +## [v2.0.1] - 2024-02-09 + +### Fixed +- [Sentinels shoud only be allowed to talk to pods belonging to their RedisFailover Custom Resource](https://github.com/powerhome/redis-operator/pull/42). + +Update notes: + +This update modifies how the operator generates network policies. In version v2.0.0, there were two separate network policies: one for Redis and another for Redis Sentinels. From version v2.0.1 onwards, the operator will only generate a network policy for Sentinels. It is crucial to be aware that following the upgrade to this version, the existing network policy for Redis instances will persist and must be deleted manually. + ## [v2.0.0] - 2024-01-18 ### Added diff --git a/Makefile b/Makefile index d68a7b97a..498766eb5 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -VERSION := v2.0.0 +VERSION := v2.0.1 # Name of this service/application SERVICE_NAME := redis-operator diff --git a/mocks/operator/redisfailover/service/RedisFailoverClient.go b/mocks/operator/redisfailover/service/RedisFailoverClient.go index 794f43cbb..de464abb9 100644 --- a/mocks/operator/redisfailover/service/RedisFailoverClient.go +++ b/mocks/operator/redisfailover/service/RedisFailoverClient.go @@ -168,20 +168,6 @@ func (_m *RedisFailoverClient) EnsureRedisMasterService(rFailover *v1.RedisFailo return r0 } -// EnsureRedisNetworkPolicy provides a mock function with given fields: rFailover, labels, ownerRefs -func (_m *RedisFailoverClient) EnsureRedisNetworkPolicy(rFailover *v1.RedisFailover, labels map[string]string, ownerRefs []metav1.OwnerReference) error { - ret := _m.Called(rFailover, labels, ownerRefs) - - var r0 error - if rf, ok := ret.Get(0).(func(*v1.RedisFailover, map[string]string, []metav1.OwnerReference) error); ok { - r0 = rf(rFailover, labels, ownerRefs) - } else { - r0 = ret.Error(0) - } - - return r0 -} - // EnsureRedisReadinessConfigMap provides a mock function with given fields: rFailover, labels, ownerRefs func (_m *RedisFailoverClient) EnsureRedisReadinessConfigMap(rFailover *v1.RedisFailover, labels map[string]string, ownerRefs []metav1.OwnerReference) error { ret := _m.Called(rFailover, labels, ownerRefs) diff --git a/operator/redisfailover/ensurer.go b/operator/redisfailover/ensurer.go index 392309b76..ee008eb9b 100644 --- a/operator/redisfailover/ensurer.go +++ b/operator/redisfailover/ensurer.go @@ -20,9 +20,6 @@ func (w *RedisFailoverHandler) Ensure(rf *redisfailoverv1.RedisFailover, labels } if !(len(rf.Spec.NetworkPolicyNsList) == 0) { - if err := w.rfService.EnsureRedisNetworkPolicy(rf, labels, or); err != nil { - return err - } if err := w.rfService.EnsureSentinelNetworkPolicy(rf, labels, or); err != nil { return err } diff --git a/operator/redisfailover/service/client.go b/operator/redisfailover/service/client.go index 41ab26ec1..3e6b52f99 100644 --- a/operator/redisfailover/service/client.go +++ b/operator/redisfailover/service/client.go @@ -19,7 +19,6 @@ type RedisFailoverClient interface { EnsureHAProxyRedisMasterConfigmap(rFailover *redisfailoverv1.RedisFailover, labels map[string]string, ownerRefs []metav1.OwnerReference) error EnsureHAProxyRedisMasterService(rFailover *redisfailoverv1.RedisFailover, labels map[string]string, ownerRefs []metav1.OwnerReference) error EnsureRedisHeadlessService(rFailover *redisfailoverv1.RedisFailover, labels map[string]string, ownerRefs []metav1.OwnerReference) error - EnsureRedisNetworkPolicy(rFailover *redisfailoverv1.RedisFailover, labels map[string]string, ownerRefs []metav1.OwnerReference) error EnsureSentinelNetworkPolicy(rFailover *redisfailoverv1.RedisFailover, labels map[string]string, ownerRefs []metav1.OwnerReference) error EnsureSentinelService(rFailover *redisfailoverv1.RedisFailover, labels map[string]string, ownerRefs []metav1.OwnerReference) error EnsureSentinelConfigMap(rFailover *redisfailoverv1.RedisFailover, labels map[string]string, ownerRefs []metav1.OwnerReference) error @@ -87,14 +86,6 @@ func generateComponentLabel(componentType string) map[string]string { } } -// EnsureRedisNetworkPolicy makes sure the redis network policy exists -func (r *RedisFailoverKubeClient) EnsureRedisNetworkPolicy(rf *redisfailoverv1.RedisFailover, labels map[string]string, ownerRefs []metav1.OwnerReference) error { - svc := generateRedisNetworkPolicy(rf, labels, ownerRefs) - err := r.K8SService.CreateOrUpdateNetworkPolicy(rf.Namespace, svc) - r.setEnsureOperationMetrics(svc.Namespace, svc.Name, "EnsureRedisNetworkPolicy", rf.Name, err) - return err -} - // EnsureSentinelNetworkPolicy makes sure the redis network policy exists func (r *RedisFailoverKubeClient) EnsureSentinelNetworkPolicy(rf *redisfailoverv1.RedisFailover, labels map[string]string, ownerRefs []metav1.OwnerReference) error { svc := generateSentinelNetworkPolicy(rf, labels, ownerRefs) diff --git a/operator/redisfailover/service/generator.go b/operator/redisfailover/service/generator.go index d0162a817..cb15228e2 100644 --- a/operator/redisfailover/service/generator.go +++ b/operator/redisfailover/service/generator.go @@ -456,63 +456,6 @@ func generateHAProxyRedisSlaveService(rf *redisfailoverv1.RedisFailover, labels } } -func generateRedisNetworkPolicy(rf *redisfailoverv1.RedisFailover, labels map[string]string, ownerRefs []metav1.OwnerReference) *np.NetworkPolicy { - name := GetRedisNetworkPolicyName(rf) - namespace := rf.Namespace - - networkPolicyNsList := rf.Spec.NetworkPolicyNsList - - selectorLabels := generateSelectorLabels(redisRoleName, rf.Name) - labels = util.MergeLabels(labels, selectorLabels) - - metricsTargetPort := intstr.FromInt(9121) - redisTargetPort := intstr.FromInt(int(rf.Spec.Redis.Port)) - - peers := []np.NetworkPolicyPeer{} - - for _, inputPeer := range networkPolicyNsList { - - labelKey := inputPeer.MatchLabelKey - labelValue := inputPeer.MatchLabelValue - - peers = append(peers, np.NetworkPolicyPeer{ - NamespaceSelector: &metav1.LabelSelector{ - MatchLabels: map[string]string{labelKey: labelValue}, - }, - }) - } - - ports := make([]np.NetworkPolicyPort, 0) - ports = append(ports, np.NetworkPolicyPort{ - Port: &redisTargetPort, - }, np.NetworkPolicyPort{ - Port: &metricsTargetPort, - }) - - return &np.NetworkPolicy{ - ObjectMeta: metav1.ObjectMeta{ - Name: name, - Namespace: namespace, - Labels: labels, - OwnerReferences: ownerRefs, - }, - Spec: np.NetworkPolicySpec{ - PodSelector: metav1.LabelSelector{ - MatchLabels: util.MergeLabels( - map[string]string{"redisfailovers.databases.spotahome.com/name": rf.Name}, - generateComponentLabel("redis"), - ), - }, - Ingress: []np.NetworkPolicyIngressRule{ - np.NetworkPolicyIngressRule{ - From: peers, - Ports: ports, - }, - }, - }, - } -} - func generateSentinelNetworkPolicy(rf *redisfailoverv1.RedisFailover, labels map[string]string, ownerRefs []metav1.OwnerReference) *np.NetworkPolicy { name := GetSentinelNetworkPolicyName(rf) namespace := rf.Namespace @@ -543,6 +486,8 @@ func generateSentinelNetworkPolicy(rf *redisfailoverv1.RedisFailover, labels map Port: &sentinelTargetPort, }) + redisfailoverLabels := map[string]string{"redisfailovers.databases.spotahome.com/name": rf.Name} + return &np.NetworkPolicy{ ObjectMeta: metav1.ObjectMeta{ Name: name, @@ -553,7 +498,7 @@ func generateSentinelNetworkPolicy(rf *redisfailoverv1.RedisFailover, labels map Spec: np.NetworkPolicySpec{ PodSelector: metav1.LabelSelector{ MatchLabels: util.MergeLabels( - map[string]string{"redisfailovers.databases.spotahome.com/name": rf.Name}, + redisfailoverLabels, generateComponentLabel("sentinel"), ), }, @@ -563,6 +508,17 @@ func generateSentinelNetworkPolicy(rf *redisfailoverv1.RedisFailover, labels map Ports: ports, }, }, + Egress: []np.NetworkPolicyEgressRule{ + np.NetworkPolicyEgressRule{ + To: []np.NetworkPolicyPeer{ + np.NetworkPolicyPeer{ + PodSelector: &metav1.LabelSelector{ + MatchLabels: redisfailoverLabels, + }, + }, + }, + }, + }, }, } } diff --git a/operator/redisfailover/service/generator_test.go b/operator/redisfailover/service/generator_test.go index 888b4b353..91567f75e 100644 --- a/operator/redisfailover/service/generator_test.go +++ b/operator/redisfailover/service/generator_test.go @@ -1416,12 +1416,12 @@ func TestHaproxyService(t *testing.T) { } } -func TestRedisNetworkPolicy(t *testing.T) { +func TestSentinelNetworkPolicy(t *testing.T) { tests := []struct { name string rfName string rfNamespace string - rfRedisPort int + rfSentinelPort int rfNetworkPolicyNamespaceEntries []redisfailoverv1.NetworkPolicyNamespaceEntry rfLabels map[string]string expected networkingv1.NetworkPolicy @@ -1436,10 +1436,10 @@ func TestRedisNetworkPolicy(t *testing.T) { }, expected: networkingv1.NetworkPolicy{ ObjectMeta: metav1.ObjectMeta{ - Name: "rfr-np-" + name, + Name: "rfs-np-" + name, Namespace: namespace, Labels: map[string]string{ - "app.kubernetes.io/component": "redis", + "app.kubernetes.io/component": "sentinel", "app.kubernetes.io/name": name, "app.kubernetes.io/part-of": "redis-failover", }, @@ -1453,7 +1453,7 @@ func TestRedisNetworkPolicy(t *testing.T) { Spec: networkingv1.NetworkPolicySpec{ PodSelector: metav1.LabelSelector{ MatchLabels: map[string]string{ - "redisfailovers.databases.spotahome.com/component": "redis", + "redisfailovers.databases.spotahome.com/component": "sentinel", "redisfailovers.databases.spotahome.com/name": name, }, }, @@ -1471,209 +1471,32 @@ func TestRedisNetworkPolicy(t *testing.T) { Ports: []networkingv1.NetworkPolicyPort{ networkingv1.NetworkPolicyPort{ Port: &intstr.IntOrString{ - IntVal: 6379, - Type: intstr.Int, - }, - }, - networkingv1.NetworkPolicyPort{ - Port: &intstr.IntOrString{ - IntVal: 9121, + IntVal: 26379, Type: intstr.Int, }, }, }, }, }, - }, - }, - }, - { - name: "with custom redis Port", - rfRedisPort: 6698, - rfNetworkPolicyNamespaceEntries: []redisfailoverv1.NetworkPolicyNamespaceEntry{ - redisfailoverv1.NetworkPolicyNamespaceEntry{ - MatchLabelKey: "app.kubernetes.io/instance", - MatchLabelValue: namespace, - }, - }, - expected: networkingv1.NetworkPolicy{ - ObjectMeta: metav1.ObjectMeta{ - Name: "rfr-np-" + name, - Namespace: namespace, - Labels: map[string]string{ - "app.kubernetes.io/component": "redis", - "app.kubernetes.io/name": name, - "app.kubernetes.io/part-of": "redis-failover", - }, - Annotations: nil, - OwnerReferences: []metav1.OwnerReference{ - { - Name: "testing", - }, - }, - }, - Spec: networkingv1.NetworkPolicySpec{ - PodSelector: metav1.LabelSelector{ - MatchLabels: map[string]string{ - "redisfailovers.databases.spotahome.com/component": "redis", - "redisfailovers.databases.spotahome.com/name": name, - }, - }, - Ingress: []networkingv1.NetworkPolicyIngressRule{ - networkingv1.NetworkPolicyIngressRule{ - From: []networkingv1.NetworkPolicyPeer{ + Egress: []networkingv1.NetworkPolicyEgressRule{ + networkingv1.NetworkPolicyEgressRule{ + To: []networkingv1.NetworkPolicyPeer{ networkingv1.NetworkPolicyPeer{ - NamespaceSelector: &metav1.LabelSelector{ + PodSelector: &metav1.LabelSelector{ MatchLabels: map[string]string{ - "app.kubernetes.io/instance": namespace, + "redisfailovers.databases.spotahome.com/name": name, }, }, }, }, - Ports: []networkingv1.NetworkPolicyPort{ - networkingv1.NetworkPolicyPort{ - Port: &intstr.IntOrString{ - IntVal: 6698, - Type: intstr.Int, - }, - }, - networkingv1.NetworkPolicyPort{ - Port: &intstr.IntOrString{ - IntVal: 9121, - Type: intstr.Int, - }, - }, - }, }, }, }, }, }, { - name: "with custom NetorkPolicyNamespaceEntries", - rfNetworkPolicyNamespaceEntries: []redisfailoverv1.NetworkPolicyNamespaceEntry{ - redisfailoverv1.NetworkPolicyNamespaceEntry{ - MatchLabelKey: "app.kubernetes.io/instance", - MatchLabelValue: namespace, - }, - redisfailoverv1.NetworkPolicyNamespaceEntry{ - MatchLabelKey: "app.kubernetes.io/instance", - MatchLabelValue: "extra-namespace", - }, - }, - expected: networkingv1.NetworkPolicy{ - ObjectMeta: metav1.ObjectMeta{ - Name: "rfr-np-" + name, - Namespace: namespace, - Labels: map[string]string{ - "app.kubernetes.io/component": "redis", - "app.kubernetes.io/name": name, - "app.kubernetes.io/part-of": "redis-failover", - }, - Annotations: nil, - OwnerReferences: []metav1.OwnerReference{ - { - Name: "testing", - }, - }, - }, - Spec: networkingv1.NetworkPolicySpec{ - PodSelector: metav1.LabelSelector{ - MatchLabels: map[string]string{ - "redisfailovers.databases.spotahome.com/component": "redis", - "redisfailovers.databases.spotahome.com/name": name, - }, - }, - Ingress: []networkingv1.NetworkPolicyIngressRule{ - networkingv1.NetworkPolicyIngressRule{ - From: []networkingv1.NetworkPolicyPeer{ - networkingv1.NetworkPolicyPeer{ - NamespaceSelector: &metav1.LabelSelector{ - MatchLabels: map[string]string{ - "app.kubernetes.io/instance": namespace, - }, - }, - }, - networkingv1.NetworkPolicyPeer{ - NamespaceSelector: &metav1.LabelSelector{ - MatchLabels: map[string]string{ - "app.kubernetes.io/instance": "extra-namespace", - }, - }, - }, - }, - Ports: []networkingv1.NetworkPolicyPort{ - networkingv1.NetworkPolicyPort{ - Port: &intstr.IntOrString{ - IntVal: 6379, - Type: intstr.Int, - }, - }, - networkingv1.NetworkPolicyPort{ - Port: &intstr.IntOrString{ - IntVal: 9121, - Type: intstr.Int, - }, - }, - }, - }, - }, - }, - }, - }, - } - - for _, test := range tests { - t.Run(test.name, func(t *testing.T) { - assert := assert.New(t) - - // Generate a default RedisFailover and attaching the required annotations - rf := generateRF() - if test.rfName != "" { - rf.Name = test.rfName - } - if test.rfNamespace != "" { - rf.Namespace = test.rfNamespace - } - if test.rfRedisPort <= 0 { - rf.Spec.Redis.Port = 6379 - - } else { - rf.Spec.Redis.Port = redisfailoverv1.Port(test.rfRedisPort) - } - if test.rfNetworkPolicyNamespaceEntries != nil { - rf.Spec.NetworkPolicyNsList = test.rfNetworkPolicyNamespaceEntries - } - - generated := networkingv1.NetworkPolicy{} - - ms := &mK8SService.Services{} - ms.On("CreateOrUpdateNetworkPolicy", rf.Namespace, mock.Anything).Once().Run(func(args mock.Arguments) { - s := args.Get(1).(*networkingv1.NetworkPolicy) - generated = *s - }).Return(nil) - - client := rfservice.NewRedisFailoverKubeClient(ms, log.Dummy, metrics.Dummy) - err := client.EnsureRedisNetworkPolicy(rf, test.rfLabels, []metav1.OwnerReference{{Name: "testing"}}) - - assert.Equal(test.expected, generated) - assert.NoError(err) - }) - } -} - -func TestSentinelNetworkPolicy(t *testing.T) { - tests := []struct { - name string - rfName string - rfNamespace string - rfSentinelPort int - rfNetworkPolicyNamespaceEntries []redisfailoverv1.NetworkPolicyNamespaceEntry - rfLabels map[string]string - expected networkingv1.NetworkPolicy - }{ - { - name: "with defaults", + name: "with custom sentinel Port", + rfSentinelPort: 17781, rfNetworkPolicyNamespaceEntries: []redisfailoverv1.NetworkPolicyNamespaceEntry{ redisfailoverv1.NetworkPolicyNamespaceEntry{ MatchLabelKey: "app.kubernetes.io/instance", @@ -1717,67 +1540,24 @@ func TestSentinelNetworkPolicy(t *testing.T) { Ports: []networkingv1.NetworkPolicyPort{ networkingv1.NetworkPolicyPort{ Port: &intstr.IntOrString{ - IntVal: 26379, + IntVal: 17781, Type: intstr.Int, }, }, }, }, }, - }, - }, - }, - { - name: "with custom sentinel Port", - rfSentinelPort: 17781, - rfNetworkPolicyNamespaceEntries: []redisfailoverv1.NetworkPolicyNamespaceEntry{ - redisfailoverv1.NetworkPolicyNamespaceEntry{ - MatchLabelKey: "app.kubernetes.io/instance", - MatchLabelValue: namespace, - }, - }, - expected: networkingv1.NetworkPolicy{ - ObjectMeta: metav1.ObjectMeta{ - Name: "rfs-np-" + name, - Namespace: namespace, - Labels: map[string]string{ - "app.kubernetes.io/component": "sentinel", - "app.kubernetes.io/name": name, - "app.kubernetes.io/part-of": "redis-failover", - }, - Annotations: nil, - OwnerReferences: []metav1.OwnerReference{ - { - Name: "testing", - }, - }, - }, - Spec: networkingv1.NetworkPolicySpec{ - PodSelector: metav1.LabelSelector{ - MatchLabels: map[string]string{ - "redisfailovers.databases.spotahome.com/component": "sentinel", - "redisfailovers.databases.spotahome.com/name": name, - }, - }, - Ingress: []networkingv1.NetworkPolicyIngressRule{ - networkingv1.NetworkPolicyIngressRule{ - From: []networkingv1.NetworkPolicyPeer{ + Egress: []networkingv1.NetworkPolicyEgressRule{ + networkingv1.NetworkPolicyEgressRule{ + To: []networkingv1.NetworkPolicyPeer{ networkingv1.NetworkPolicyPeer{ - NamespaceSelector: &metav1.LabelSelector{ + PodSelector: &metav1.LabelSelector{ MatchLabels: map[string]string{ - "app.kubernetes.io/instance": namespace, + "redisfailovers.databases.spotahome.com/name": name, }, }, }, }, - Ports: []networkingv1.NetworkPolicyPort{ - networkingv1.NetworkPolicyPort{ - Port: &intstr.IntOrString{ - IntVal: 17781, - Type: intstr.Int, - }, - }, - }, }, }, }, @@ -1846,6 +1626,19 @@ func TestSentinelNetworkPolicy(t *testing.T) { }, }, }, + Egress: []networkingv1.NetworkPolicyEgressRule{ + networkingv1.NetworkPolicyEgressRule{ + To: []networkingv1.NetworkPolicyPeer{ + networkingv1.NetworkPolicyPeer{ + PodSelector: &metav1.LabelSelector{ + MatchLabels: map[string]string{ + "redisfailovers.databases.spotahome.com/name": name, + }, + }, + }, + }, + }, + }, }, }, },