Skip to content

Commit 6a8a87e

Browse files
authored
Merge pull request #346 from rabbitmq/340-default-user-pass
Configure default user/password through conf.d
2 parents 0d5b4fb + 706cf8f commit 6a8a87e

File tree

6 files changed

+178
-142
lines changed

6 files changed

+178
-142
lines changed

README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ Manage [RabbitMQ](https://www.rabbitmq.com/) clusters deployed to [Kubernetes](h
66

77
## Supported Versions
88

9-
The operator deploys RabbitMQ `3.8.8`, and requires a Kubernetes cluster of `1.16` or above.
9+
The operator deploys RabbitMQ `3.8.8` by default, and supports versions from `3.8.4` upwards. The operator requires a Kubernetes cluster of `1.16` or above.
1010

1111
## Versioning
1212

controllers/rabbitmqcluster_controller_test.go

+15-11
Original file line numberDiff line numberDiff line change
@@ -1213,21 +1213,25 @@ var _ = Describe("RabbitmqClusterController", func() {
12131213
},
12141214
},
12151215
corev1.Volume{
1216-
Name: "rabbitmq-admin",
1216+
Name: "rabbitmq-confd",
12171217
VolumeSource: corev1.VolumeSource{
1218-
Secret: &corev1.SecretVolumeSource{
1219-
DefaultMode: &defaultMode,
1220-
SecretName: "rabbitmq-sts-override-rabbitmq-admin",
1221-
Items: []corev1.KeyToPath{
1218+
Projected: &corev1.ProjectedVolumeSource{
1219+
Sources: []corev1.VolumeProjection{
12221220
{
1223-
Key: "username",
1224-
Path: "username",
1225-
},
1226-
{
1227-
Key: "password",
1228-
Path: "password",
1221+
Secret: &corev1.SecretProjection{
1222+
LocalObjectReference: corev1.LocalObjectReference{
1223+
Name: "rabbitmq-sts-override-rabbitmq-admin",
1224+
},
1225+
Items: []corev1.KeyToPath{
1226+
{
1227+
Key: "default_user.conf",
1228+
Path: "default_user.conf",
1229+
},
1230+
},
1231+
},
12291232
},
12301233
},
1234+
DefaultMode: &defaultMode,
12311235
},
12321236
},
12331237
},

internal/resource/admin_secret.go

+36-2
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,11 @@
1010
package resource
1111

1212
import (
13+
"bytes"
14+
1315
rabbitmqv1beta1 "github.com/rabbitmq/cluster-operator/api/v1beta1"
1416
"github.com/rabbitmq/cluster-operator/internal/metadata"
17+
"gopkg.in/ini.v1"
1518
corev1 "k8s.io/api/core/v1"
1619
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
1720
"k8s.io/apimachinery/pkg/runtime"
@@ -31,6 +34,31 @@ func (builder *RabbitmqResourceBuilder) AdminSecret() *AdminSecretBuilder {
3134
}
3235
}
3336

37+
func generateDefaultUserConf(username, password string) ([]byte, error) {
38+
39+
ini.PrettySection = false // Remove trailing new line because default_user.conf has only a default section.
40+
cfg, err := ini.Load([]byte{})
41+
if err != nil {
42+
return nil, err
43+
}
44+
defaultSection := cfg.Section("")
45+
46+
if _, err := defaultSection.NewKey("default_user", username); err != nil {
47+
return nil, err
48+
}
49+
50+
if _, err := defaultSection.NewKey("default_pass", password); err != nil {
51+
return nil, err
52+
}
53+
54+
var userConfBuffer bytes.Buffer
55+
if cfg.WriteTo(&userConfBuffer); err != nil {
56+
return nil, err
57+
}
58+
59+
return userConfBuffer.Bytes(), nil
60+
}
61+
3462
func (builder *AdminSecretBuilder) UpdateRequiresStsRestart() bool {
3563
return false
3664
}
@@ -53,15 +81,21 @@ func (builder *AdminSecretBuilder) Build() (runtime.Object, error) {
5381
return nil, err
5482
}
5583

84+
defaultUserConf, err := generateDefaultUserConf(username, password)
85+
if err != nil {
86+
return nil, err
87+
}
88+
5689
return &corev1.Secret{
5790
ObjectMeta: metav1.ObjectMeta{
5891
Name: builder.Instance.ChildResourceName(AdminSecretName),
5992
Namespace: builder.Instance.Namespace,
6093
},
6194
Type: corev1.SecretTypeOpaque,
6295
Data: map[string][]byte{
63-
"username": []byte(username),
64-
"password": []byte(password),
96+
"username": []byte(username),
97+
"password": []byte(password),
98+
"default_user.conf": defaultUserConf,
6599
},
66100
}, nil
67101
}

internal/resource/admin_secret_test.go

+70-52
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ package resource_test
1212
import (
1313
b64 "encoding/base64"
1414

15+
"gopkg.in/ini.v1"
1516
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
1617
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
1718

@@ -44,41 +45,58 @@ var _ = Describe("AdminSecret", func() {
4445
})
4546

4647
Context("Build with defaults", func() {
47-
BeforeEach(func() {
48+
It("creates the necessary admin secret", func() {
49+
var username []byte
50+
var password []byte
51+
var ok bool
52+
4853
obj, err := adminSecretBuilder.Build()
4954
Expect(err).NotTo(HaveOccurred())
5055
secret = obj.(*corev1.Secret)
51-
})
5256

53-
It("creates the secret with correct name and namespace", func() {
54-
Expect(secret.Name).To(Equal(instance.ChildResourceName("admin")))
55-
Expect(secret.Namespace).To(Equal("a namespace"))
56-
})
57-
58-
It("creates a 'opaque' secret ", func() {
59-
Expect(secret.Type).To(Equal(corev1.SecretTypeOpaque))
60-
})
61-
62-
It("creates a rabbitmq username that is base64 encoded and 24 characters in length", func() {
63-
username, ok := secret.Data["username"]
64-
Expect(ok).NotTo(BeFalse())
65-
decodedUsername, err := b64.URLEncoding.DecodeString(string(username))
66-
Expect(err).NotTo(HaveOccurred())
67-
Expect(len(decodedUsername)).To(Equal(24))
68-
69-
})
70-
71-
It("creates a rabbitmq password that is base64 encoded and 24 characters in length", func() {
72-
password, ok := secret.Data["password"]
73-
Expect(ok).NotTo(BeFalse())
74-
decodedPassword, err := b64.URLEncoding.DecodeString(string(password))
75-
Expect(err).NotTo(HaveOccurred())
76-
Expect(len(decodedPassword)).To(Equal(24))
57+
By("creating the secret with correct name and namespace", func() {
58+
Expect(secret.Name).To(Equal(instance.ChildResourceName("admin")))
59+
Expect(secret.Namespace).To(Equal("a namespace"))
60+
})
61+
62+
By("creating a 'opaque' secret ", func() {
63+
Expect(secret.Type).To(Equal(corev1.SecretTypeOpaque))
64+
})
65+
66+
By("creating a rabbitmq username that is base64 encoded and 24 characters in length", func() {
67+
username, ok = secret.Data["username"]
68+
Expect(ok).NotTo(BeFalse(), "Failed to find a key \"username\" in the generated Secret")
69+
decodedUsername, err := b64.URLEncoding.DecodeString(string(username))
70+
Expect(err).NotTo(HaveOccurred())
71+
Expect(len(decodedUsername)).To(Equal(24))
72+
})
73+
74+
By("creating a rabbitmq password that is base64 encoded and 24 characters in length", func() {
75+
password, ok = secret.Data["password"]
76+
Expect(ok).NotTo(BeFalse(), "Failed to find a key \"password\" in the generated Secret")
77+
decodedPassword, err := b64.URLEncoding.DecodeString(string(password))
78+
Expect(err).NotTo(HaveOccurred())
79+
Expect(len(decodedPassword)).To(Equal(24))
80+
})
81+
82+
By("creating a default_user.conf file that contains the correct sysctl config format to be parsed by RabbitMQ", func() {
83+
defaultUserConf, ok := secret.Data["default_user.conf"]
84+
Expect(ok).NotTo(BeFalse(), "Failed to find a key \"default_user.conf\" in the generated Secret")
85+
86+
cfg, err := ini.Load(defaultUserConf)
87+
Expect(err).NotTo(HaveOccurred())
88+
89+
Expect(cfg.Section("").HasKey("default_user")).To(BeTrue())
90+
Expect(cfg.Section("").HasKey("default_pass")).To(BeTrue())
91+
92+
Expect(cfg.Section("").Key("default_user").Value()).To(Equal(string(username)))
93+
Expect(cfg.Section("").Key("default_pass").Value()).To(Equal(string(password)))
94+
})
7795
})
7896
})
7997

8098
Context("Update with instance labels", func() {
81-
BeforeEach(func() {
99+
It("Updates the secret", func() {
82100
instance = rabbitmqv1beta1.RabbitmqCluster{
83101
ObjectMeta: metav1.ObjectMeta{
84102
Name: "rabbit-labelled",
@@ -102,26 +120,26 @@ var _ = Describe("AdminSecret", func() {
102120
}
103121
err := adminSecretBuilder.Update(secret)
104122
Expect(err).NotTo(HaveOccurred())
105-
})
106123

107-
It("adds new labels from the CR", func() {
108-
testLabels(secret.Labels)
109-
})
124+
By("adding new labels from the CR", func() {
125+
testLabels(secret.Labels)
126+
})
110127

111-
It("restores the default labels", func() {
112-
labels := secret.Labels
113-
Expect(labels["app.kubernetes.io/name"]).To(Equal(instance.Name))
114-
Expect(labels["app.kubernetes.io/component"]).To(Equal("rabbitmq"))
115-
Expect(labels["app.kubernetes.io/part-of"]).To(Equal("rabbitmq"))
116-
})
128+
By("restoring the default labels", func() {
129+
labels := secret.Labels
130+
Expect(labels["app.kubernetes.io/name"]).To(Equal(instance.Name))
131+
Expect(labels["app.kubernetes.io/component"]).To(Equal("rabbitmq"))
132+
Expect(labels["app.kubernetes.io/part-of"]).To(Equal("rabbitmq"))
133+
})
117134

118-
It("deletes the labels that are removed from the CR", func() {
119-
Expect(secret.Labels).NotTo(HaveKey("this-was-the-previous-label"))
135+
By("deleting the labels that are removed from the CR", func() {
136+
Expect(secret.Labels).NotTo(HaveKey("this-was-the-previous-label"))
137+
})
120138
})
121139
})
122140

123141
Context("Update with instance annotations", func() {
124-
BeforeEach(func() {
142+
It("updates the secret with the annotations", func() {
125143
instance = rabbitmqv1beta1.RabbitmqCluster{
126144
ObjectMeta: metav1.ObjectMeta{
127145
Name: "rabbit-labelled",
@@ -150,19 +168,19 @@ var _ = Describe("AdminSecret", func() {
150168
}
151169
err := adminSecretBuilder.Update(secret)
152170
Expect(err).NotTo(HaveOccurred())
153-
})
154-
155-
It("updates secret annotations on admin secret", func() {
156-
expectedAnnotations := map[string]string{
157-
"my-annotation": "i-like-this",
158-
"i-was-here-already": "please-dont-delete-me",
159-
"im-here-to-stay.kubernetes.io": "for-a-while",
160-
"kubernetes.io/name": "should-stay",
161-
"kubectl.kubernetes.io/name": "should-stay",
162-
"k8s.io/name": "should-stay",
163-
}
164171

165-
Expect(secret.Annotations).To(Equal(expectedAnnotations))
172+
By("updating secret annotations on admin secret", func() {
173+
expectedAnnotations := map[string]string{
174+
"my-annotation": "i-like-this",
175+
"i-was-here-already": "please-dont-delete-me",
176+
"im-here-to-stay.kubernetes.io": "for-a-while",
177+
"kubernetes.io/name": "should-stay",
178+
"kubectl.kubernetes.io/name": "should-stay",
179+
"k8s.io/name": "should-stay",
180+
}
181+
182+
Expect(secret.Annotations).To(Equal(expectedAnnotations))
183+
})
166184
})
167185
})
168186
})

internal/resource/statefulset.go

+26-30
Original file line numberDiff line numberDiff line change
@@ -258,24 +258,6 @@ func (builder *StatefulSetBuilder) podTemplateSpec(annotations, labels map[strin
258258
terminationGracePeriod := defaultGracePeriodTimeoutSeconds
259259

260260
volumes := []corev1.Volume{
261-
{
262-
Name: "rabbitmq-admin",
263-
VolumeSource: corev1.VolumeSource{
264-
Secret: &corev1.SecretVolumeSource{
265-
SecretName: builder.Instance.ChildResourceName(AdminSecretName),
266-
Items: []corev1.KeyToPath{
267-
{
268-
Key: "username",
269-
Path: "username",
270-
},
271-
{
272-
Key: "password",
273-
Path: "password",
274-
},
275-
},
276-
},
277-
},
278-
},
279261
{
280262
Name: "server-conf",
281263
VolumeSource: corev1.VolumeSource{
@@ -302,6 +284,28 @@ func (builder *StatefulSetBuilder) podTemplateSpec(annotations, labels map[strin
302284
EmptyDir: &corev1.EmptyDirVolumeSource{},
303285
},
304286
},
287+
{
288+
Name: "rabbitmq-confd",
289+
VolumeSource: corev1.VolumeSource{
290+
Projected: &corev1.ProjectedVolumeSource{
291+
Sources: []corev1.VolumeProjection{
292+
{
293+
Secret: &corev1.SecretProjection{
294+
LocalObjectReference: corev1.LocalObjectReference{
295+
Name: builder.Instance.ChildResourceName(AdminSecretName),
296+
},
297+
Items: []corev1.KeyToPath{
298+
{
299+
Key: "default_user.conf",
300+
Path: "default_user.conf",
301+
},
302+
},
303+
},
304+
},
305+
},
306+
},
307+
},
308+
},
305309
{
306310
Name: "rabbitmq-erlang-cookie",
307311
VolumeSource: corev1.VolumeSource{
@@ -378,10 +382,6 @@ func (builder *StatefulSetBuilder) podTemplateSpec(annotations, labels map[strin
378382
}
379383

380384
rabbitmqContainerVolumeMounts := []corev1.VolumeMount{
381-
{
382-
Name: "rabbitmq-admin",
383-
MountPath: "/opt/rabbitmq-secret/",
384-
},
385385
{
386386
Name: "persistence",
387387
MountPath: "/var/lib/rabbitmq/mnesia/",
@@ -390,6 +390,10 @@ func (builder *StatefulSetBuilder) podTemplateSpec(annotations, labels map[strin
390390
Name: "rabbitmq-etc",
391391
MountPath: "/etc/rabbitmq/",
392392
},
393+
{
394+
Name: "rabbitmq-confd",
395+
MountPath: "/etc/rabbitmq/conf.d/",
396+
},
393397
{
394398
Name: "rabbitmq-erlang-cookie",
395399
MountPath: "/var/lib/rabbitmq/",
@@ -561,14 +565,6 @@ func (builder *StatefulSetBuilder) podTemplateSpec(annotations, labels map[strin
561565
Resources: *builder.Instance.Spec.Resources,
562566
Image: builder.Instance.Spec.Image,
563567
Env: []corev1.EnvVar{
564-
{
565-
Name: "RABBITMQ_DEFAULT_PASS_FILE",
566-
Value: "/opt/rabbitmq-secret/password",
567-
},
568-
{
569-
Name: "RABBITMQ_DEFAULT_USER_FILE",
570-
Value: "/opt/rabbitmq-secret/username",
571-
},
572568
{
573569
Name: "MY_POD_NAME",
574570
ValueFrom: &corev1.EnvVarSource{

0 commit comments

Comments
 (0)