Skip to content

Commit d1db350

Browse files
committed
Add spec.tls.disableNonTLSListeners property
- set to true to disable non TLS listeners for rmq core and enabled plugins (stomp, mqtt, web_stomp and web_mqtt) - can only configure to true if TLS is enabled
1 parent d2e2383 commit d1db350

13 files changed

+3742
-3631
lines changed

Diff for: api/v1beta1/rabbitmqcluster_types.go

+7
Original file line numberDiff line numberDiff line change
@@ -241,6 +241,9 @@ type TLSSpec struct {
241241
// The Secret must store this as ca.crt.
242242
// Used for mTLS, and TLS for rabbitmq_web_stomp and rabbitmq_web_mqtt.
243243
CaSecretName string `json:"caSecretName,omitempty"`
244+
// When set to true, the RabbitmqCluster disables non-TLS listeners for RabbitMQ and for any enabled plugins in the following list: stomp, mqtt, web_stomp, web_mqtt.
245+
// Only TLS-enabled clients will be able to connect.
246+
DisableNonTLSListeners bool `json:"disableNonTLSListeners,omitempty"`
244247
}
245248

246249
// kubebuilder validating tags 'Pattern' and 'MaxLength' must be specified on string type.
@@ -325,6 +328,10 @@ func (cluster *RabbitmqCluster) SingleTLSSecret() bool {
325328
return cluster.MutualTLSEnabled() && cluster.Spec.TLS.CaSecretName == cluster.Spec.TLS.SecretName
326329
}
327330

331+
func (cluster *RabbitmqCluster) DisableNonTLSListeners() bool {
332+
return cluster.Spec.TLS.DisableNonTLSListeners
333+
}
334+
328335
func (cluster *RabbitmqCluster) AdditionalPluginEnabled(plugin Plugin) bool {
329336
for _, p := range cluster.Spec.Rabbitmq.AdditionalPlugins {
330337
if p == plugin {

Diff for: config/crd/bases/rabbitmq.com_rabbitmqclusters.yaml

+3,150-3,459
Large diffs are not rendered by default.

Diff for: controllers/rabbitmqcluster_controller.go

+2-5
Original file line numberDiff line numberDiff line change
@@ -106,11 +106,8 @@ func (r *RabbitmqClusterReconciler) Reconcile(req ctrl.Request) (ctrl.Result, er
106106
return ctrl.Result{}, err
107107
}
108108

109-
// TLS: check if specified, and if secret exists
110-
if rabbitmqCluster.TLSEnabled() {
111-
if result, err := r.checkTLSSecrets(ctx, rabbitmqCluster); err != nil {
112-
return result, err
113-
}
109+
if err := r.reconcileTLS(ctx, rabbitmqCluster); err != nil {
110+
return ctrl.Result{}, err
114111
}
115112

116113
childResources, err := r.getChildResources(ctx, *rabbitmqCluster)

Diff for: controllers/reconcile_tls.go

+22-7
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,25 @@ import (
88
corev1 "k8s.io/api/core/v1"
99
"k8s.io/apimachinery/pkg/api/errors"
1010
"k8s.io/apimachinery/pkg/types"
11-
ctrl "sigs.k8s.io/controller-runtime"
1211
)
1312

14-
func (r *RabbitmqClusterReconciler) checkTLSSecrets(ctx context.Context, rabbitmqCluster *rabbitmqv1beta1.RabbitmqCluster) (ctrl.Result, error) {
13+
func (r *RabbitmqClusterReconciler) reconcileTLS(ctx context.Context, rabbitmqCluster *rabbitmqv1beta1.RabbitmqCluster) error {
14+
if rabbitmqCluster.DisableNonTLSListeners() && !rabbitmqCluster.TLSEnabled() {
15+
err := errors.NewBadRequest("TLS must be enabled if disableNonTLSListeners is set to true")
16+
r.Recorder.Event(rabbitmqCluster, corev1.EventTypeWarning, "TLSError", err.Error())
17+
r.Log.Error(err, "Error setting up TLS", "namespace", rabbitmqCluster.Namespace, "name", rabbitmqCluster.Name)
18+
return err
19+
}
20+
21+
if rabbitmqCluster.TLSEnabled() {
22+
if err := r.checkTLSSecrets(ctx, rabbitmqCluster); err != nil {
23+
return err
24+
}
25+
}
26+
return nil
27+
}
28+
29+
func (r *RabbitmqClusterReconciler) checkTLSSecrets(ctx context.Context, rabbitmqCluster *rabbitmqv1beta1.RabbitmqCluster) error {
1530
secretName := rabbitmqCluster.Spec.TLS.SecretName
1631
r.Log.Info("TLS enabled, looking for secret", "secret", secretName, "namespace", rabbitmqCluster.Namespace)
1732

@@ -21,7 +36,7 @@ func (r *RabbitmqClusterReconciler) checkTLSSecrets(ctx context.Context, rabbitm
2136
r.Recorder.Event(rabbitmqCluster, corev1.EventTypeWarning, "TLSError",
2237
fmt.Sprintf("Failed to get TLS secret %s in namespace %s: %v", secretName, rabbitmqCluster.Namespace, err.Error()))
2338
r.Log.Error(err, "Error setting up TLS", "namespace", rabbitmqCluster.Namespace, "name", rabbitmqCluster.Name)
24-
return ctrl.Result{}, err
39+
return err
2540
}
2641
// check if secret has the right keys
2742
_, hasTLSKey := secret.Data["tls.key"]
@@ -30,7 +45,7 @@ func (r *RabbitmqClusterReconciler) checkTLSSecrets(ctx context.Context, rabbitm
3045
err := errors.NewBadRequest(fmt.Sprintf("TLS secret %s in namespace %s does not have the fields tls.crt and tls.key", secretName, rabbitmqCluster.Namespace))
3146
r.Recorder.Event(rabbitmqCluster, corev1.EventTypeWarning, "TLSError", err.Error())
3247
r.Log.Error(err, "Error setting up TLS", "namespace", rabbitmqCluster.Namespace, "name", rabbitmqCluster.Name)
33-
return ctrl.Result{}, err
48+
return err
3449
}
3550

3651
// Mutual TLS: check if CA certificate is stored in a separate secret
@@ -45,7 +60,7 @@ func (r *RabbitmqClusterReconciler) checkTLSSecrets(ctx context.Context, rabbitm
4560
r.Recorder.Event(rabbitmqCluster, corev1.EventTypeWarning, "TLSError",
4661
fmt.Sprintf("Failed to get CA certificate secret %v in namespace %v: %v", secretName, rabbitmqCluster.Namespace, err.Error()))
4762
r.Log.Error(err, "Error setting up TLS", "namespace", rabbitmqCluster.Namespace, "name", rabbitmqCluster.Name)
48-
return ctrl.Result{}, err
63+
return err
4964
}
5065
}
5166

@@ -54,8 +69,8 @@ func (r *RabbitmqClusterReconciler) checkTLSSecrets(ctx context.Context, rabbitm
5469
err := errors.NewBadRequest(fmt.Sprintf("TLS secret %s in namespace %s does not have the field ca.crt", rabbitmqCluster.Spec.TLS.CaSecretName, rabbitmqCluster.Namespace))
5570
r.Recorder.Event(rabbitmqCluster, corev1.EventTypeWarning, "TLSError", err.Error())
5671
r.Log.Error(err, "Error setting up TLS", "namespace", rabbitmqCluster.Namespace, "name", rabbitmqCluster.Name)
57-
return ctrl.Result{}, err
72+
return err
5873
}
5974
}
60-
return ctrl.Result{}, nil
75+
return nil
6176
}

Diff for: controllers/reconcile_tls_test.go

+14
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,20 @@ var _ = Describe("Reconcile TLS", func() {
201201
})
202202
})
203203
})
204+
205+
When("DiableNonTLSListeners set to true", func() {
206+
It("errors and logs TLSError when TLS is not enabled", func() {
207+
tlsSpec := rabbitmqv1beta1.TLSSpec{
208+
DisableNonTLSListeners: true,
209+
}
210+
cluster = rabbitmqClusterWithTLS(ctx, "rabbitmq-disablenontlslisteners", defaultNamespace, tlsSpec)
211+
212+
verifyTLSErrorEvents(ctx, cluster, "TLS must be enabled if disableNonTLSListeners is set to true")
213+
214+
_, err := clientSet.AppsV1().StatefulSets(cluster.Namespace).Get(ctx, cluster.ChildResourceName("server"), metav1.GetOptions{})
215+
Expect(err).To(HaveOccurred())
216+
})
217+
})
204218
})
205219

206220
func tlsSecretWithCACert(ctx context.Context, secretName, namespace string) {

Diff for: internal/resource/configmap.go

+25
Original file line numberDiff line numberDiff line change
@@ -89,15 +89,30 @@ func (builder *ServerConfigMapBuilder) Update(object runtime.Object) error {
8989
if err := cfg.Append([]byte(defaultTLSConf)); err != nil {
9090
return err
9191
}
92+
if builder.Instance.DisableNonTLSListeners() {
93+
if _, err := defaultSection.NewKey("listeners.tcp", "none"); err != nil {
94+
return err
95+
}
96+
}
9297
if builder.Instance.AdditionalPluginEnabled("rabbitmq_mqtt") {
9398
if _, err := defaultSection.NewKey("mqtt.listeners.ssl.default", "8883"); err != nil {
9499
return err
95100
}
101+
if builder.Instance.DisableNonTLSListeners() {
102+
if _, err := defaultSection.NewKey("mqtt.listeners.tcp", "none"); err != nil {
103+
return err
104+
}
105+
}
96106
}
97107
if builder.Instance.AdditionalPluginEnabled("rabbitmq_stomp") {
98108
if _, err := defaultSection.NewKey("stomp.listeners.ssl.1", "61614"); err != nil {
99109
return err
100110
}
111+
if builder.Instance.DisableNonTLSListeners() {
112+
if _, err := defaultSection.NewKey("stomp.listeners.tcp", "none"); err != nil {
113+
return err
114+
}
115+
}
101116
}
102117
}
103118

@@ -125,6 +140,11 @@ func (builder *ServerConfigMapBuilder) Update(object runtime.Object) error {
125140
if _, err := defaultSection.NewKey("web_mqtt.ssl.keyfile", tlsKeyPath); err != nil {
126141
return err
127142
}
143+
if builder.Instance.DisableNonTLSListeners() {
144+
if _, err := defaultSection.NewKey("web_mqtt.tcp.listener", "none"); err != nil {
145+
return err
146+
}
147+
}
128148
}
129149
if builder.Instance.AdditionalPluginEnabled("rabbitmq_web_stomp") {
130150
if _, err := defaultSection.NewKey("web_stomp.ssl.port", "15673"); err != nil {
@@ -139,6 +159,11 @@ func (builder *ServerConfigMapBuilder) Update(object runtime.Object) error {
139159
if _, err := defaultSection.NewKey("web_stomp.ssl.keyfile", tlsKeyPath); err != nil {
140160
return err
141161
}
162+
if builder.Instance.DisableNonTLSListeners() {
163+
if _, err := defaultSection.NewKey("web_stomp.tcp.listener", "none"); err != nil {
164+
return err
165+
}
166+
}
142167
}
143168
}
144169

Diff for: internal/resource/configmap_test.go

+122
Original file line numberDiff line numberDiff line change
@@ -401,6 +401,128 @@ management.ssl.cacertfile = /etc/rabbitmq-tls/ca.crt
401401
})
402402
})
403403

404+
When("DisableNonTLSListeners is set to true", func() {
405+
It("disables non tls listeners in rabbitmq.conf", func() {
406+
instance = rabbitmqv1beta1.RabbitmqCluster{
407+
ObjectMeta: metav1.ObjectMeta{
408+
Name: "rabbit-tls",
409+
},
410+
Spec: rabbitmqv1beta1.RabbitmqClusterSpec{
411+
TLS: rabbitmqv1beta1.TLSSpec{
412+
SecretName: "some-secret",
413+
DisableNonTLSListeners: true,
414+
},
415+
},
416+
}
417+
418+
expectedRabbitmqConf := iniString(defaultRabbitmqConf(builder.Instance.Name) + `
419+
ssl_options.certfile = /etc/rabbitmq-tls/tls.crt
420+
ssl_options.keyfile = /etc/rabbitmq-tls/tls.key
421+
listeners.ssl.default = 5671
422+
423+
management.ssl.certfile = /etc/rabbitmq-tls/tls.crt
424+
management.ssl.keyfile = /etc/rabbitmq-tls/tls.key
425+
management.ssl.port = 15671
426+
427+
listeners.tcp = none
428+
`)
429+
430+
Expect(configMapBuilder.Update(configMap)).To(Succeed())
431+
Expect(configMap.Data).To(HaveKeyWithValue("rabbitmq.conf", expectedRabbitmqConf))
432+
})
433+
434+
It("disables non tls listeners for mqtt and stomp when enabled", func() {
435+
instance = rabbitmqv1beta1.RabbitmqCluster{
436+
ObjectMeta: metav1.ObjectMeta{
437+
Name: "rabbit-tls",
438+
},
439+
Spec: rabbitmqv1beta1.RabbitmqClusterSpec{
440+
TLS: rabbitmqv1beta1.TLSSpec{
441+
SecretName: "some-secret",
442+
DisableNonTLSListeners: true,
443+
},
444+
Rabbitmq: rabbitmqv1beta1.RabbitmqClusterConfigurationSpec{
445+
AdditionalPlugins: []rabbitmqv1beta1.Plugin{
446+
"rabbitmq_mqtt",
447+
"rabbitmq_stomp",
448+
},
449+
},
450+
},
451+
}
452+
453+
expectedRabbitmqConf := iniString(defaultRabbitmqConf(builder.Instance.Name) + `
454+
ssl_options.certfile = /etc/rabbitmq-tls/tls.crt
455+
ssl_options.keyfile = /etc/rabbitmq-tls/tls.key
456+
listeners.ssl.default = 5671
457+
458+
management.ssl.certfile = /etc/rabbitmq-tls/tls.crt
459+
management.ssl.keyfile = /etc/rabbitmq-tls/tls.key
460+
management.ssl.port = 15671
461+
listeners.tcp = none
462+
463+
mqtt.listeners.ssl.default = 8883
464+
mqtt.listeners.tcp = none
465+
466+
stomp.listeners.ssl.1 = 61614
467+
stomp.listeners.tcp = none
468+
`)
469+
470+
Expect(configMapBuilder.Update(configMap)).To(Succeed())
471+
Expect(configMap.Data).To(HaveKeyWithValue("rabbitmq.conf", expectedRabbitmqConf))
472+
})
473+
474+
It("disables non tls listeners for web mqtt and web stomp when enabled", func() {
475+
instance = rabbitmqv1beta1.RabbitmqCluster{
476+
ObjectMeta: metav1.ObjectMeta{
477+
Name: "rabbit-tls",
478+
},
479+
Spec: rabbitmqv1beta1.RabbitmqClusterSpec{
480+
TLS: rabbitmqv1beta1.TLSSpec{
481+
SecretName: "some-secret",
482+
CaSecretName: "some-mutual-secret",
483+
DisableNonTLSListeners: true,
484+
},
485+
Rabbitmq: rabbitmqv1beta1.RabbitmqClusterConfigurationSpec{
486+
AdditionalPlugins: []rabbitmqv1beta1.Plugin{
487+
"rabbitmq_web_mqtt",
488+
"rabbitmq_web_stomp",
489+
},
490+
},
491+
},
492+
}
493+
494+
expectedRabbitmqConf := iniString(defaultRabbitmqConf(builder.Instance.Name) + `
495+
ssl_options.certfile = /etc/rabbitmq-tls/tls.crt
496+
ssl_options.keyfile = /etc/rabbitmq-tls/tls.key
497+
listeners.ssl.default = 5671
498+
499+
management.ssl.certfile = /etc/rabbitmq-tls/tls.crt
500+
management.ssl.keyfile = /etc/rabbitmq-tls/tls.key
501+
management.ssl.port = 15671
502+
listeners.tcp = none
503+
504+
ssl_options.cacertfile = /etc/rabbitmq-tls/ca.crt
505+
ssl_options.verify = verify_peer
506+
management.ssl.cacertfile = /etc/rabbitmq-tls/ca.crt
507+
508+
web_mqtt.ssl.port = 15676
509+
web_mqtt.ssl.cacertfile = /etc/rabbitmq-tls/ca.crt
510+
web_mqtt.ssl.certfile = /etc/rabbitmq-tls/tls.crt
511+
web_mqtt.ssl.keyfile = /etc/rabbitmq-tls/tls.key
512+
web_mqtt.tcp.listener = none
513+
514+
web_stomp.ssl.port = 15673
515+
web_stomp.ssl.cacertfile = /etc/rabbitmq-tls/ca.crt
516+
web_stomp.ssl.certfile = /etc/rabbitmq-tls/tls.crt
517+
web_stomp.ssl.keyfile = /etc/rabbitmq-tls/tls.key
518+
web_stomp.tcp.listener = none
519+
`)
520+
521+
Expect(configMapBuilder.Update(configMap)).To(Succeed())
522+
Expect(configMap.Data).To(HaveKeyWithValue("rabbitmq.conf", expectedRabbitmqConf))
523+
})
524+
})
525+
404526
Context("Memory Limits", func() {
405527
It("sets a RabbitMQ memory limit with headroom when memory limits are specified", func() {
406528
const GiB int64 = 1073741824

Diff for: internal/resource/service.go

+63-2
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,65 @@ func applySvcOverride(svc *corev1.Service, override *rabbitmqv1beta1.Service) er
109109
return nil
110110
}
111111

112-
func (builder *ServiceBuilder) updatePorts(servicePorts []corev1.ServicePort) []corev1.ServicePort {
112+
func (builder *ServiceBuilder) generateServicePortsMapOnlyTLSListeners() map[string]corev1.ServicePort {
113+
servicePortsMap := map[string]corev1.ServicePort{
114+
"amqps": {
115+
Protocol: corev1.ProtocolTCP,
116+
Port: 5671,
117+
TargetPort: intstr.FromInt(5671),
118+
Name: "amqps",
119+
},
120+
"management-tls": {
121+
Protocol: corev1.ProtocolTCP,
122+
Port: 15671,
123+
TargetPort: intstr.FromInt(15671),
124+
Name: "management-tls",
125+
},
126+
}
127+
128+
if builder.Instance.AdditionalPluginEnabled("rabbitmq_stomp") {
129+
servicePortsMap["stomps"] = corev1.ServicePort{
130+
Protocol: corev1.ProtocolTCP,
131+
Port: 61614,
132+
Name: "stomps",
133+
TargetPort: intstr.FromInt(61614),
134+
}
135+
}
136+
if builder.Instance.AdditionalPluginEnabled("rabbitmq_mqtt") {
137+
servicePortsMap["mqtts"] = corev1.ServicePort{
138+
Protocol: corev1.ProtocolTCP,
139+
Port: 8883,
140+
Name: "mqtts",
141+
TargetPort: intstr.FromInt(8883),
142+
}
143+
}
144+
145+
if builder.Instance.MutualTLSEnabled() {
146+
if builder.Instance.AdditionalPluginEnabled("rabbitmq_web_stomp") {
147+
servicePortsMap["web-stomp-tls"] = corev1.ServicePort{
148+
Protocol: corev1.ProtocolTCP,
149+
Port: 15673,
150+
Name: "web-stomp-tls",
151+
TargetPort: intstr.FromInt(15673),
152+
}
153+
}
154+
if builder.Instance.AdditionalPluginEnabled("rabbitmq_web_mqtt") {
155+
servicePortsMap["web-mqtt-tls"] = corev1.ServicePort{
156+
Protocol: corev1.ProtocolTCP,
157+
Port: 15676,
158+
Name: "web-mqtt-tls",
159+
TargetPort: intstr.FromInt(15676),
160+
}
161+
}
162+
}
163+
return servicePortsMap
164+
}
165+
166+
func (builder *ServiceBuilder) generateServicePortsMap() map[string]corev1.ServicePort {
167+
if builder.Instance.DisableNonTLSListeners() {
168+
return builder.generateServicePortsMapOnlyTLSListeners()
169+
}
170+
113171
servicePortsMap := map[string]corev1.ServicePort{
114172
"amqp": {
115173
Protocol: corev1.ProtocolTCP,
@@ -204,7 +262,11 @@ func (builder *ServiceBuilder) updatePorts(servicePorts []corev1.ServicePort) []
204262
}
205263
}
206264
}
265+
return servicePortsMap
266+
}
207267

268+
func (builder *ServiceBuilder) updatePorts(servicePorts []corev1.ServicePort) []corev1.ServicePort {
269+
servicePortsMap := builder.generateServicePortsMap()
208270
var updatedServicePorts []corev1.ServicePort
209271

210272
for _, servicePort := range servicePorts {
@@ -221,7 +283,6 @@ func (builder *ServiceBuilder) updatePorts(servicePorts []corev1.ServicePort) []
221283
}
222284

223285
return updatedServicePorts
224-
225286
}
226287

227288
func (builder *ServiceBuilder) setAnnotations(service *corev1.Service) {

0 commit comments

Comments
 (0)