Skip to content

Commit 241e9d8

Browse files
Merge pull request #849 from olliewalsh/rabbitmq_cluster_tls
Configure rabbitmq inter-node TLS
2 parents dc1db38 + 095609b commit 241e9d8

File tree

3 files changed

+170
-19
lines changed

3 files changed

+170
-19
lines changed

pkg/openstack/rabbitmq.go

Lines changed: 88 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99
networkv1 "github.com/openstack-k8s-operators/infra-operator/apis/network/v1beta1"
1010
"github.com/openstack-k8s-operators/lib-common/modules/certmanager"
1111
condition "github.com/openstack-k8s-operators/lib-common/modules/common/condition"
12+
"github.com/openstack-k8s-operators/lib-common/modules/common/configmap"
1213
"github.com/openstack-k8s-operators/lib-common/modules/common/helper"
1314
"github.com/openstack-k8s-operators/lib-common/modules/common/ocp"
1415
"github.com/openstack-k8s-operators/lib-common/modules/common/util"
@@ -22,6 +23,7 @@ import (
2223

2324
corev1beta1 "github.com/openstack-k8s-operators/openstack-operator/apis/core/v1beta1"
2425
corev1 "k8s.io/api/core/v1"
26+
"k8s.io/utils/ptr"
2527

2628
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2729
ctrl "sigs.k8s.io/controller-runtime"
@@ -154,17 +156,56 @@ func reconcileRabbitMQ(
154156
if err != nil {
155157
return mqFailed, ctrl.Result{}, err
156158
}
159+
clusterNodeTLSArgs := "-proto_dist inet_tls -ssl_dist_optfile /etc/rabbitmq/inter-node-tls.config"
157160
if fipsEnabled {
158-
fipsModeStr := "-crypto fips_mode true"
159-
160-
envVars = append(envVars, corev1.EnvVar{
161-
Name: "RABBITMQ_SERVER_ADDITIONAL_ERL_ARGS",
162-
Value: fipsModeStr,
163-
}, corev1.EnvVar{
164-
Name: "RABBITMQ_CTL_ERL_ARGS",
165-
Value: fipsModeStr,
166-
})
161+
clusterNodeTLSArgs += " -crypto fips_mode true"
167162
}
163+
164+
envVars = append(envVars, corev1.EnvVar{
165+
Name: "RABBITMQ_SERVER_ADDITIONAL_ERL_ARGS",
166+
Value: clusterNodeTLSArgs,
167+
}, corev1.EnvVar{
168+
Name: "RABBITMQ_CTL_ERL_ARGS",
169+
Value: clusterNodeTLSArgs,
170+
})
171+
}
172+
173+
cms := []util.Template{
174+
{
175+
Name: fmt.Sprintf("%s-config-data", rabbitmq.Name),
176+
Namespace: rabbitmq.Namespace,
177+
Type: util.TemplateTypeConfig,
178+
InstanceType: "rabbitmq",
179+
Labels: map[string]string{},
180+
CustomData: map[string]string{
181+
"inter_node_tls.config": `[
182+
{server, [
183+
{cacertfile,"/etc/rabbitmq-tls/ca.crt"},
184+
{certfile,"/etc/rabbitmq-tls/tls.crt"},
185+
{keyfile,"/etc/rabbitmq-tls/tls.key"},
186+
{secure_renegotiate, true},
187+
{fail_if_no_peer_cert, true},
188+
{verify, verify_peer},
189+
{versions, ['tlsv1.2','tlsv1.3']}
190+
]},
191+
{client, [
192+
{cacertfile,"/etc/rabbitmq-tls/ca.crt"},
193+
{certfile,"/etc/rabbitmq-tls/tls.crt"},
194+
{keyfile,"/etc/rabbitmq-tls/tls.key"},
195+
{secure_renegotiate, true},
196+
{verify, verify_peer},
197+
{versions, ['tlsv1.2','tlsv1.3']}
198+
]}
199+
].
200+
`,
201+
},
202+
},
203+
}
204+
205+
err := configmap.EnsureConfigMaps(ctx, helper, instance, cms, nil)
206+
if err != nil {
207+
Log.Error(err, "Unable to create rabbitmq config maps")
208+
return mqFailed, ctrl.Result{}, err
168209
}
169210

170211
defaultStatefulSet := rabbitmqv2.StatefulSet{
@@ -197,6 +238,15 @@ func reconcileRabbitMQ(
197238

198239
hostname := fmt.Sprintf("%s.%s.svc", name, instance.Namespace)
199240
hostnameHeadless := fmt.Sprintf("%s-nodes.%s.svc", name, instance.Namespace)
241+
hostnames := []string{
242+
hostname,
243+
fmt.Sprintf("%s.%s", hostname, ClusterInternalDomain),
244+
hostnameHeadless,
245+
fmt.Sprintf("%s.%s", hostnameHeadless, ClusterInternalDomain),
246+
}
247+
for i := 0; i < int(*spec.Replicas); i++ {
248+
hostnames = append(hostnames, fmt.Sprintf("%s-server-%d.%s-nodes.%s", name, i, name, instance.Namespace))
249+
}
200250

201251
tlsCert := ""
202252
commonName := fmt.Sprintf("%s.%s", hostname, ClusterInternalDomain)
@@ -206,14 +256,7 @@ func reconcileRabbitMQ(
206256
IssuerName: instance.GetInternalIssuer(),
207257
CertName: fmt.Sprintf("%s-svc", rabbitmq.Name),
208258
CommonName: &commonName,
209-
Hostnames: []string{
210-
hostname,
211-
fmt.Sprintf("%s.%s", hostname, ClusterInternalDomain),
212-
hostnameHeadless,
213-
fmt.Sprintf("%s.%s", hostnameHeadless, ClusterInternalDomain),
214-
fmt.Sprintf("*.%s", hostnameHeadless),
215-
fmt.Sprintf("*.%s.%s", hostnameHeadless, ClusterInternalDomain),
216-
},
259+
Hostnames: hostnames,
217260
Subject: &certmgrv1.X509Subject{
218261
Organizations: []string{fmt.Sprintf("%s.%s", rabbitmq.Namespace, ClusterInternalDomain)},
219262
},
@@ -346,6 +389,34 @@ func reconcileRabbitMQ(
346389
]}
347390
].
348391
`
392+
393+
rabbitmq.Spec.Override.StatefulSet.Spec.Template.Spec.Volumes = []corev1.Volume{
394+
{
395+
Name: "config-data",
396+
VolumeSource: corev1.VolumeSource{
397+
ConfigMap: &corev1.ConfigMapVolumeSource{
398+
LocalObjectReference: corev1.LocalObjectReference{
399+
Name: fmt.Sprintf("%s-config-data", rabbitmq.Name),
400+
},
401+
DefaultMode: ptr.To[int32](0o420),
402+
Items: []corev1.KeyToPath{
403+
{
404+
Key: "inter_node_tls.config",
405+
Path: "inter_node_tls.config",
406+
},
407+
},
408+
},
409+
},
410+
},
411+
}
412+
rabbitmq.Spec.Override.StatefulSet.Spec.Template.Spec.Containers[0].VolumeMounts = []corev1.VolumeMount{
413+
{
414+
MountPath: "/etc/rabbitmq/inter-node-tls.config",
415+
ReadOnly: true,
416+
Name: "config-data",
417+
SubPath: "inter_node_tls.config",
418+
},
419+
}
349420
}
350421

351422
// overrides

tests/functional/base_test.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ import (
2929
"github.com/openstack-k8s-operators/lib-common/modules/common/condition"
3030
openstackclientv1 "github.com/openstack-k8s-operators/openstack-operator/apis/client/v1beta1"
3131
corev1 "github.com/openstack-k8s-operators/openstack-operator/apis/core/v1beta1"
32+
rabbitmqv2 "github.com/rabbitmq/cluster-operator/v2/api/v1beta1"
3233
)
3334

3435
type Names struct {
@@ -455,3 +456,11 @@ func CreateClusterConfigCM() client.Object {
455456

456457
return cm
457458
}
459+
460+
func GetRabbitMQCluster(name types.NamespacedName) *rabbitmqv2.RabbitmqCluster {
461+
instance := &rabbitmqv2.RabbitmqCluster{}
462+
Eventually(func(g Gomega) {
463+
g.Expect(k8sClient.Get(ctx, name, instance)).Should(Succeed())
464+
}, timeout, interval).Should(Succeed())
465+
return instance
466+
}

tests/functional/openstackoperator_controller_test.go

Lines changed: 73 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -546,7 +546,12 @@ var _ = Describe("OpenStackOperator controller", func() {
546546
g.Expect(memcached.Spec.Replicas).Should(Equal(ptr.To[int32](1)))
547547
}, timeout, interval).Should(Succeed())
548548

549-
// TODO rabbitmq exists
549+
// rabbitmq exists
550+
Eventually(func(g Gomega) {
551+
rabbitmq := GetRabbitMQCluster(names.RabbitMQName)
552+
g.Expect(rabbitmq).Should(Not(BeNil()))
553+
g.Expect(rabbitmq.Spec.Replicas).Should(Equal(ptr.To[int32](1)))
554+
}, timeout, interval).Should(Succeed())
550555

551556
// keystone exists
552557
Eventually(func(g Gomega) {
@@ -759,14 +764,73 @@ var _ = Describe("OpenStackOperator controller", func() {
759764
g.Expect(memcached.Spec.Replicas).Should(Equal(ptr.To[int32](1)))
760765
}, timeout, interval).Should(Succeed())
761766

762-
// TODO rabbitmq exists
767+
// rabbitmq exists
768+
Eventually(func(g Gomega) {
769+
rabbitmq := GetRabbitMQCluster(names.RabbitMQName)
770+
g.Expect(rabbitmq).Should(Not(BeNil()))
771+
g.Expect(rabbitmq.Spec.Replicas).Should(Equal(ptr.To[int32](1)))
772+
}, timeout, interval).Should(Succeed())
763773

764774
// keystone exists
765775
Eventually(func(g Gomega) {
766776
keystoneAPI := keystone.GetKeystoneAPI(names.KeystoneAPIName)
767777
g.Expect(keystoneAPI).Should(Not(BeNil()))
768778
}, timeout, interval).Should(Succeed())
769779
})
780+
Describe("Rabbitmq inter node TLS config", func() {
781+
It("should create and mount inter node tls config file", func() {
782+
Eventually(func(g Gomega) {
783+
cm := th.GetConfigMap(types.NamespacedName{
784+
Namespace: names.RabbitMQName.Namespace,
785+
Name: names.RabbitMQName.Name + "-config-data",
786+
})
787+
g.Expect(cm).ShouldNot(BeNil())
788+
g.Expect(cm.Data).Should(HaveKey("inter_node_tls.config"))
789+
}, timeout, interval).Should(Succeed())
790+
Eventually(func(g Gomega) {
791+
rabbitmq := GetRabbitMQCluster(names.RabbitMQName)
792+
g.Expect(rabbitmq).Should(Not(BeNil()))
793+
794+
var vFindings []k8s_corev1.Volume
795+
g.Expect(rabbitmq.Spec.Override.StatefulSet.Spec.Template.Spec.Volumes).Should(
796+
ContainElement(HaveField("Name", "config-data"), &vFindings),
797+
)
798+
g.Expect(vFindings[0].VolumeSource.ConfigMap.Items[0]).Should(And(
799+
HaveField("Key", "inter_node_tls.config"),
800+
HaveField("Path", "inter_node_tls.config"),
801+
))
802+
803+
var vmFindings []k8s_corev1.VolumeMount
804+
g.Expect(rabbitmq.Spec.Override.StatefulSet.Spec.Template.Spec.Containers[0].VolumeMounts).Should(
805+
ContainElement(HaveField("Name", "config-data"), &vmFindings),
806+
)
807+
g.Expect(vmFindings[0]).Should(And(
808+
HaveField("SubPath", "inter_node_tls.config"),
809+
HaveField("MountPath", "/etc/rabbitmq/inter-node-tls.config"),
810+
))
811+
}, timeout, interval).Should(Succeed())
812+
})
813+
It("should set the TLS arg env vars", func() {
814+
Eventually(func(g Gomega) {
815+
rabbitmq := GetRabbitMQCluster(names.RabbitMQName)
816+
g.Expect(rabbitmq).Should(Not(BeNil()))
817+
818+
var findings []k8s_corev1.EnvVar
819+
g.Expect(rabbitmq.Spec.Override.StatefulSet.Spec.Template.Spec.Containers[0].Env).Should(
820+
ContainElement(HaveField("Name", "RABBITMQ_CTL_ERL_ARGS"), &findings),
821+
)
822+
g.Expect(findings[0].Value).Should(ContainSubstring(
823+
"-proto_dist inet_tls -ssl_dist_optfile /etc/rabbitmq/inter-node-tls.config",
824+
))
825+
g.Expect(rabbitmq.Spec.Override.StatefulSet.Spec.Template.Spec.Containers[0].Env).Should(
826+
ContainElement(HaveField("Name", "RABBITMQ_SERVER_ADDITIONAL_ERL_ARGS"), &findings),
827+
)
828+
g.Expect(findings[0].Value).Should(ContainSubstring(
829+
"-proto_dist inet_tls -ssl_dist_optfile /etc/rabbitmq/inter-node-tls.config",
830+
))
831+
}, timeout, interval).Should(Succeed())
832+
})
833+
})
770834
// Default route timeouts are set
771835
It("should have default timeout for the routes set", func() {
772836
OSCtlplane := GetOpenStackControlPlane(names.OpenStackControlplaneName)
@@ -1194,6 +1258,13 @@ var _ = Describe("OpenStackOperator controller", func() {
11941258
g.Expect(memcached.Spec.Replicas).Should(Equal(ptr.To[int32](1)))
11951259
}, timeout, interval).Should(Succeed())
11961260

1261+
// rabbitmq exists
1262+
Eventually(func(g Gomega) {
1263+
rabbitmq := GetRabbitMQCluster(names.RabbitMQName)
1264+
g.Expect(rabbitmq).Should(Not(BeNil()))
1265+
g.Expect(rabbitmq.Spec.Replicas).Should(Equal(ptr.To[int32](1)))
1266+
}, timeout, interval).Should(Succeed())
1267+
11971268
// keystone exists
11981269
Eventually(func(g Gomega) {
11991270
keystoneAPI := keystone.GetKeystoneAPI(names.KeystoneAPIName)

0 commit comments

Comments
 (0)