From 298c333ac7e08b3877dd766fd4eb99565df69efb Mon Sep 17 00:00:00 2001 From: Vasyl Saienko Date: Fri, 13 Sep 2024 11:29:06 +0000 Subject: [PATCH] [rabbitmq] Allow to bootstrap rabbitmq with initial config Prepare rabbitmq to be running in non clustered mode, in which it may be useful to bootstrap cluster with fresh data each time since we do not use durable queues in openstack that are stored on filesystem. The two new data strucutre in rabbitmq Values are added: users: auth: keystone_service: username: keystone password: password path: /keystone aux_conf: policies: - vhost: "keystone" name: "ha_ttl_keystone" definition: ha-mode: "all" ha-sync-mode: "automatic" message-ttl: 70000 priority: 0 apply-to: all pattern: '^(?!amq\.).*' Change-Id: Ia0dd1a8afe7b6e894bcbeafedf75131de0023df0 --- rabbitmq/Chart.yaml | 2 +- .../bin/_rabbitmq-password-hash.py.tpl | 68 ++++++++++++++++--- .../secret-rabbitmq-users-credentials.yaml | 30 ++++++++ rabbitmq/templates/statefulset.yaml | 11 +++ rabbitmq/values.yaml | 32 +++++++++ releasenotes/notes/rabbitmq.yaml | 1 + 6 files changed, 132 insertions(+), 12 deletions(-) create mode 100644 rabbitmq/templates/secret-rabbitmq-users-credentials.yaml diff --git a/rabbitmq/Chart.yaml b/rabbitmq/Chart.yaml index 71d715071..53d20cc0c 100644 --- a/rabbitmq/Chart.yaml +++ b/rabbitmq/Chart.yaml @@ -15,6 +15,6 @@ apiVersion: v1 appVersion: v3.12.0 description: OpenStack-Helm RabbitMQ name: rabbitmq -version: 0.1.38 +version: 0.1.39 home: https://github.com/rabbitmq/rabbitmq-server ... diff --git a/rabbitmq/templates/bin/_rabbitmq-password-hash.py.tpl b/rabbitmq/templates/bin/_rabbitmq-password-hash.py.tpl index ffedc1956..ae7e1099f 100644 --- a/rabbitmq/templates/bin/_rabbitmq-password-hash.py.tpl +++ b/rabbitmq/templates/bin/_rabbitmq-password-hash.py.tpl @@ -22,30 +22,76 @@ import base64 import json import os import hashlib -import struct +import re user = os.environ['RABBITMQ_ADMIN_USERNAME'] password = os.environ['RABBITMQ_ADMIN_PASSWORD'] output_file = os.environ['RABBITMQ_DEFINITION_FILE'] -salt = os.urandom(4) - -tmp0 = salt + password.encode('utf-8') - -tmp1 = hashlib.sha512(tmp0).digest() - -salted_hash = salt + tmp1 - -pass_hash = base64.b64encode(salted_hash) +def hash_rabbit_password(password): + salt = os.urandom(4) + tmp0 = salt + password.encode('utf-8') + tmp1 = hashlib.sha512(tmp0).digest() + salted_hash = salt + tmp1 + pass_hash = base64.b64encode(salted_hash) + return pass_hash.decode("utf-8") output = { "users": [{ "name": user, - "password_hash": pass_hash.decode("utf-8"), + "password_hash": hash_rabbit_password(password), "hashing_algorithm": "rabbit_password_hashing_sha512", "tags": "administrator" }] } + +if 'RABBITMQ_USERS' in os.environ: + output.update({'vhosts': []}) + output.update({'permissions': []}) + users_creds = json.loads(os.environ['RABBITMQ_USERS']) + for user, creds in users_creds.items(): + if 'auth' in creds: + for auth_key, auth_val in creds['auth'].items(): + username = auth_val['username'] + password = auth_val['password'] + user_struct = { + "name": username, + "password_hash": hash_rabbit_password(password), + "hashing_algorithm": "rabbit_password_hashing_sha512", + "tags": "" + } + output['users'].append(user_struct) + if 'path' in creds: + for path in ( + creds["path"] + if isinstance(creds["path"], list) + else [creds["path"]] + ): + vhost = re.sub("^/", "", path) + vhost_struct = {"name": vhost} + + perm_struct = { + "user": username, + "vhost": vhost, + "configure": ".*", + "write": ".*", + "read": ".*" + } + + output['vhosts'].append(vhost_struct) + output['permissions'].append(perm_struct) + +if 'RABBITMQ_AUXILIARY_CONFIGURATION' in os.environ: + aux_conf = json.loads(os.environ['RABBITMQ_AUXILIARY_CONFIGURATION']) + if aux_conf.get('policies', []): + output['policies'] = aux_conf['policies'] + if aux_conf.get('bindings', []): + output['bindings'] = aux_conf['bindings'] + if aux_conf.get('queues', []): + output['queues'] = aux_conf['queues'] + if aux_conf.get('exchanges', []): + output['exchanges'] = aux_conf['exchanges'] + with open(output_file, 'w') as f: f.write(json.dumps(output)) f.close() diff --git a/rabbitmq/templates/secret-rabbitmq-users-credentials.yaml b/rabbitmq/templates/secret-rabbitmq-users-credentials.yaml new file mode 100644 index 000000000..fc0bf4832 --- /dev/null +++ b/rabbitmq/templates/secret-rabbitmq-users-credentials.yaml @@ -0,0 +1,30 @@ +{{/* +Copyright 2019 Mirantis Inc. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/}} + +{{- if .Values.conf.users }} + +{{- $envAll := . }} +--- +apiVersion: v1 +kind: Secret +metadata: + name: {{ printf "%s-%s" $envAll.deployment_name "users-credentials" | quote }} + labels: +{{ tuple $envAll "rabbitmq" "server" | include "helm-toolkit.snippets.kubernetes_metadata_labels" | indent 4 }} +type: Opaque +data: + RABBITMQ_USERS: {{ toJson .Values.conf.users | b64enc }} +{{- end }} diff --git a/rabbitmq/templates/statefulset.yaml b/rabbitmq/templates/statefulset.yaml index 81d3c8bf2..d347d4634 100644 --- a/rabbitmq/templates/statefulset.yaml +++ b/rabbitmq/templates/statefulset.yaml @@ -146,6 +146,17 @@ spec: key: RABBITMQ_ADMIN_PASSWORD - name: RABBITMQ_DEFINITION_FILE value: "{{ index $envAll.Values.conf.rabbitmq "management.load_definitions" }}" +{{- if .Values.conf.users }} + - name: RABBITMQ_USERS + valueFrom: + secretKeyRef: + name: {{ printf "%s-%s" $envAll.deployment_name "users-credentials" | quote }} + key: RABBITMQ_USERS +{{- end }} +{{- if .Values.conf.aux_conf }} + - name: RABBITMQ_AUXILIARY_CONFIGURATION + value: {{ toJson $envAll.Values.conf.aux_conf | quote }} +{{- end }} volumeMounts: - name: pod-tmp mountPath: /tmp diff --git a/rabbitmq/values.yaml b/rabbitmq/values.yaml index 06db8f8bf..8c8a9fa1e 100644 --- a/rabbitmq/values.yaml +++ b/rabbitmq/values.yaml @@ -240,6 +240,38 @@ conf: # To deploy with specific feature, separate each feature with comma # To deploy with all features disabled, leave blank or empty feature_flags: default + users: {} + # define users in the section below which have to be + # created by rabbitmq at start up stage through definitions.json + # file and enable job_users_create manifest. + # users: + # keystone_service: + # auth: + # keystone_username: + # username: keystone + # password: password + # path: /keystone + aux_conf: {} + # aux_conf can be used to pass additional options to definitions.json, allowed keys are: + # - policies + # - bindings + # - parameters + # - queues + # - exchanges + # vhosts,users and permissions are created in users section of values. + # aux_conf: + # policies: + # - vhost: "keystone" + # name: "ha_ttl_keystone" + # definition: + # #mirror messges to other nodes in rmq cluster + # ha-mode: "all" + # ha-sync-mode: "automatic" + # #70s + # message-ttl: 70000 + # priority: 0 + # apply-to: all + # pattern: '^(?!amq\.).*' dependencies: dynamic: common: diff --git a/releasenotes/notes/rabbitmq.yaml b/releasenotes/notes/rabbitmq.yaml index 17fb17bde..0b8fb0ac7 100644 --- a/releasenotes/notes/rabbitmq.yaml +++ b/releasenotes/notes/rabbitmq.yaml @@ -38,4 +38,5 @@ rabbitmq: - 0.1.36 Use quay.io/airshipit/kubernetes-entrypoint:latest-ubuntu_focal by default - 0.1.37 Update rabbitmq readiness/liveness command - 0.1.38 Do not use hardcoded username in rabbitmq chown container + - 0.1.39 Allow to bootstrap rabbitmq with initial config ...