Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(redis): RedisDBHA密码随机化接入 #2206

Merged
merged 1 commit into from
Nov 29, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions dbm-ui/backend/db_meta/flatten/proxy_instance.py
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ def proxy_instance(proxies: QuerySet) -> List[Dict]:
info["bind_entry"] = dict(bind_entry)
for cluster in ins.cluster.all():
info["cluster"] = cluster.immute_domain
info["cluster_id"] = cluster.id
# 只取第一个即可退出
break

Expand Down
1 change: 1 addition & 0 deletions dbm-ui/backend/db_meta/flatten/storage_instance.py
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,7 @@ def storage_instance(storages: QuerySet) -> List[Dict]:

for cluster in ins.cluster.all():
info["cluster"] = cluster.immute_domain
info["cluster_id"] = cluster.id
info["tbinlogdumpers"] = [
{"ip": dumper.ip, "port": dumper.listen_port}
for dumper in dumper_infos.get(cluster.id, {}).get(ins.machine.ip, [])
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
# -*- coding: utf-8 -*-
"""
TencentBlueKing is pleased to support the open source community by making 蓝鲸智云-DB管理系统(BlueKing-BK-DBM) available.
Copyright (C) 2017-2023 THL A29 Limited, a Tencent company. All rights reserved.
Licensed under the MIT License (the "License"); you may not use this file except in compliance with the License.
You may obtain a copy of the License at https://opensource.org/licenses/MIT
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.
"""

import base64

from django.utils.translation import ugettext as _

from backend.components import DBConfigApi, MySQLPrivManagerApi
from backend.db_meta.models import Cluster
from backend.flow.consts import DBM_JOB, DEFAULT_INSTANCE, MySQLPrivComponent, UserName
from backend.flow.utils.base.payload_handler import PayloadHandler


def decode_password_ret(data) -> dict:
ret = {"redis_password": "", "redis_proxy_admin_password": "", "redis_proxy_password": ""}
for item in data["items"]:
if (
item["username"] == UserName.REDIS_DEFAULT.value
and item["component"] == MySQLPrivComponent.REDIS_PROXY_ADMIN.value
):
ret["redis_proxy_admin_password"] = base64.b64decode(item["password"]).decode("utf-8")
elif (
item["username"] == UserName.REDIS_DEFAULT.value
and item["component"] == MySQLPrivComponent.REDIS_PROXY.value
):
ret["redis_proxy_password"] = base64.b64decode(item["password"]).decode("utf-8")
elif item["username"] == UserName.REDIS_DEFAULT.value and item["component"] == MySQLPrivComponent.REDIS.value:
ret["redis_password"] = base64.b64decode(item["password"]).decode("utf-8")
return ret


def redis_migate_cluster_password(cluster: Cluster):
# cluster_port = cluster.proxyinstance_set.first().port
cluster_port = 0
query_params = {
"instances": [{"ip": str(cluster.id), "port": cluster_port, "bk_cloud_id": cluster.bk_cloud_id}],
"users": [
{"username": UserName.REDIS_DEFAULT.value, "component": MySQLPrivComponent.REDIS_PROXY_ADMIN.value},
{"username": UserName.REDIS_DEFAULT.value, "component": MySQLPrivComponent.REDIS_PROXY.value},
{"username": UserName.REDIS_DEFAULT.value, "component": MySQLPrivComponent.REDIS.value},
],
}
data = MySQLPrivManagerApi.get_password(query_params)
ret = decode_password_ret(data)
if ret["redis_password"] and ret["redis_proxy_password"] and ret["redis_proxy_admin_password"]:
print(_("cluster:{} 密码已经正确存储").format(cluster.immute_domain))
return
cluster_port = cluster.proxyinstance_set.first().port
query_params = {
"instances": [{"ip": str(cluster.id), "port": cluster_port, "bk_cloud_id": cluster.bk_cloud_id}],
"users": [
{"username": UserName.REDIS_DEFAULT.value, "component": MySQLPrivComponent.REDIS_PROXY_ADMIN.value},
{"username": UserName.REDIS_DEFAULT.value, "component": MySQLPrivComponent.REDIS_PROXY.value},
{"username": UserName.REDIS_DEFAULT.value, "component": MySQLPrivComponent.REDIS.value},
],
}
data = MySQLPrivManagerApi.get_password(query_params)
ret = decode_password_ret(data)
if ret["redis_password"] and ret["redis_proxy_password"] and ret["redis_proxy_admin_password"]:
print(_("cluster:{} 密码已存储port不正确,重新存储").format(cluster.immute_domain))
PayloadHandler.redis_save_password_by_cluster(
cluster, ret["redis_password"], ret["redis_proxy_password"], ret["redis_proxy_admin_password"]
)
PayloadHandler.redis_delete_cluster_password(
cluster_id=cluster.id, cluster_port=cluster_port, bk_cloud_id=cluster.bk_cloud_id
)
return
# 从 dbconfig 中获取密码
conf_passwd = PayloadHandler.redis_get_cluster_pass_from_dbconfig(cluster)
if not conf_passwd["redis_password"].startswith("{{") and not conf_passwd["redis_proxy_password"].startswith("{{"):
print(_("cluster:{} 密码从dbconfig中迁移到密码服务中").format(cluster.immute_domain))
PayloadHandler.redis_save_password_by_cluster(cluster, conf_passwd, conf_passwd, conf_passwd)
return
raise Exception(_("cluster:{} 在 dbconfig和密码服务中均不存在").format(cluster.immute_domain))
44 changes: 37 additions & 7 deletions dbm-ui/backend/flow/utils/base/payload_handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -218,7 +218,8 @@ def redis_get_cluster_password(cluster: Cluster):
- 优先从密码服务中获取
- 如果密码服务为空,则从dbconfig中获取
"""
cluster_port = cluster.proxyinstance_set.first().port
# cluster_port 先全部统一设置为 0,便于DBHA获取密码
cluster_port = 0
query_params = {
"instances": [{"ip": str(cluster.id), "port": cluster_port, "bk_cloud_id": cluster.bk_cloud_id}],
"users": [
Expand Down Expand Up @@ -282,6 +283,8 @@ def redis_save_cluster_password(
"""
存储redis集群的密码到密码服务
"""
# cluster_port 先全部统一设置为 0,便于DBHA获取密码
cluster_port = 0
query_params = {
"instances": [{"ip": str(cluster_id), "port": cluster_port, "bk_cloud_id": bk_cloud_id}],
"username": UserName.REDIS_DEFAULT.value,
Expand Down Expand Up @@ -315,10 +318,9 @@ def redis_save_password_by_cluster(
redis_proxy_password: str = "",
redis_proxy_admin_password: str = "",
):
cluster_port = cluster.proxyinstance_set.first().port
return PayloadHandler.redis_save_cluster_password(
cluster.id,
cluster_port,
0,
cluster.bk_cloud_id,
redis_password,
redis_proxy_password,
Expand All @@ -330,10 +332,9 @@ def redis_save_password_by_cluster_id(
cluster_id: int, redis_password: str = "", redis_proxy_password: str = "", redis_proxy_admin_password: str = ""
):
cluster = Cluster.objects.get(id=cluster_id)
cluster_port = cluster.proxyinstance_set.first().port
return PayloadHandler.redis_save_cluster_password(
cluster.id,
cluster_port,
0,
cluster.bk_cloud_id,
redis_password,
redis_proxy_password,
Expand All @@ -348,16 +349,45 @@ def redis_save_password_by_domain(
redis_proxy_admin_password: str = "",
):
cluster = Cluster.objects.get(immute_domain=immute_domain)
cluster_port = cluster.proxyinstance_set.first().port
return PayloadHandler.redis_save_cluster_password(
cluster.id,
cluster_port,
0,
cluster.bk_cloud_id,
redis_password,
redis_proxy_password,
redis_proxy_admin_password,
)

@staticmethod
def redis_delete_cluster_password(cluster_id: int, cluster_port: int, bk_cloud_id: int):
"""
删除redis集群的密码
"""
delete_params = {
"instances": [{"ip": str(cluster_id), "port": cluster_port, "bk_cloud_id": bk_cloud_id}],
"users": [
{"username": UserName.REDIS_DEFAULT.value, "component": MySQLPrivComponent.REDIS_PROXY_ADMIN.value},
{"username": UserName.REDIS_DEFAULT.value, "component": MySQLPrivComponent.REDIS_PROXY.value},
{"username": UserName.REDIS_DEFAULT.value, "component": MySQLPrivComponent.REDIS.value},
],
}
MySQLPrivManagerApi.delete_password(delete_params)

@staticmethod
def redis_delete_password_by_cluster(cluster: Cluster):
"""
根据cluster对象,删除redis集群的密码
"""
PayloadHandler.redis_delete_cluster_password(cluster.id, 0, cluster.bk_cloud_id)

@staticmethod
def redis_delete_password_by_immute_domain(immute_domain: str):
"""
根据域名删除redis集群的密码
"""
cluster = Cluster.objects.get(immute_domain=immute_domain)
PayloadHandler.redis_delete_cluster_password(cluster.id, 0, cluster.bk_cloud_id)

@staticmethod
def redis_get_os_account() -> dict:
"""
Expand Down
Loading