首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往
30 篇文章
1
迁移到MySQL的业务架构演进实战
2
如何优化MySQL千万级大表,我写了6000字的解读
3
MySQL中的SQL优化建议那么多,该如何有的放矢
4
说几点关于数据库的见解
5
迁移至MySQL的数据流转流程优化
6
引入TiDB方案的一些思考
7
MySQL数据克隆的用户权限设计
8
MySQL逻辑数据恢复体系的设计
9
MySQL随机恢复的设计思路
10
从Oracle到MySQL,金融核心场景在线换库落地实战
11
基于Maxwell的MySQL数据传输服务整体设计
12
MySQL数据库升级的一些坑
13
数据架构选型必读:4月数据库产品技术解析
14
基于数据库中间件配置的几类问题
15
关于中间件服务的配置管理,分为5个阶段
16
MySQL中10多张表关联要做优化,怎么理解逻辑幂等
17
关于MySQL拓扑关系的梳理
18
对于新技术栈落地和架构思维的建议
19
MyCAT让人诟病的配置文件,说说破局的思路
20
MySQL多活数据消费服务设计方案
21
数据双向复制中的6个数据冲突场景和解决思路
22
MySQL双主模式下是如何避免数据回环冲突的
23
一个MySQL服务CPU 100%的优化案例反思
24
MySQL表添加了一个字段,竟然导致数据无法写入,反思
25
MySQL周期表管理太繁琐,通过Python自定义工具方法优雅解决
26
MySQL业务双活的初步设计方案
27
数据库修改密码风险高,如何保证业务持续,这几种密码双活方案可以参考
28
一道经典的MySQL面试题,答案出现三次反转
29
​业务双活的数据切换思路设计(下)
30
基于Consul的MySQL高可用服务,健康检查怎么做?这里有一个完整脚本

数据库修改密码风险高,如何保证业务持续,这几种密码双活方案可以参考

这是学习笔记的第 2147 篇文章

今天下午的时候,有个朋友(感谢Crane.Chen氵)提了一个Oracle的问题,引起了我的好奇,问题的描述如下:

出于安全需要,这边的数据库密码必须90天更改一次,否则账号过期自动锁定。目前我们改密码都需要停掉应用,然后改密码后,启动应用。这样业务就会有中断。有什么方案可以保障即能更改密码,又能热更新应用里连接池的账号密码。现在若不停机,不管先更改连接池还是先改库,都可能因为密码不匹配而锁定账号。

乍一看是个“不合理”的需求,数据库层面我们遵从安全规范来修改密码,我们照做就是了,但是显然做这个事情的成本实在太高,而且存在极高的风险,因为防御导致业务不可用带来的损失其实是很大的。 从一个层面来说,其实是孤立的看待了这个问题,只是考虑了自己,而没有考虑到应用层和全盘。做完自我批评,我来给出这个问题的一些解决之道。

首先我们把这个密码修改的过程和应用层结合起来,应用层通常是使用连接池,而且主要是长连接的方式,如果修改了密码,那么会在数据库的字典配置里面修改密码信息,密码会在新的会话中立刻生效,但是已有的连接还是会保持,通常在业务层也是做了密码的配置文件,很可能看到的密码是一个加密串。

所以最严重的的情况下无非是下面几种:

1)数据库先改密码,应用层后改,已有的长连接依旧可用,但是新连接失败,数据库密码错误超过3次,数据库账号就会被锁定,导致业务不可用。

2)应用层先改密码,数据库层后改,新连接会全部失败,错误密码超过3次,导致账号被锁定,业务不可用。

小结:从以上看出来,不管是什么样的顺序都会导致同样严重的后果,所以也就无所谓先后顺序了。

而回到这个问题本身,我们可以做一些补救措施,我又了解了一些背景信息,这是使用weblogic中间件,通常这些配置都是启动时加载的,连接池目前我知道的还不支持动态热更新,所以要解决的重要问题是防止账号被锁定,数据库这边可以写一个脚本去实时检测账号的状态,如果被锁定,可以快速解锁, 这是一种不够优雅但是快速实用的解决方法。

如果我们更近一步,从整个应用架构的层面来考虑,这个问题是否有解呢。

我们来看下面的这个图:

密码信息在应用层是配置形式,而且是启动自加载的模式,数据库密码是数据字典的基础信息,数据库层面是可以实时变化的,我们要保证业务的持续连接,一种方案就是建立影子账户,这个账户没有实际的数据,只有对等的权限,它平时处于锁定状态,即不可用。而应用层来建立连接的部分可以加一个动态的逻辑,如果连接失败,可以使用影子账户,这个影子账户的密码信息是约定好的,不会轻易发生改变,当需要修改密码的时候,可以按照如下的流程来操作:

  • 1)DBA解锁影子账户
  • 2)DBA修改账户密码
  • 3)应用层修改用户密码配置信息
  • 4)应用层分批次启动应用服务,使得配置生效
  • 5)DBA锁定影子账户

在这个过程中如果连接检测失败,会启用影子账户的来建立连接,在应用服务重启完成之后,就可以将影子账户锁定,应用层来再次动态适配,这样对于业务层来说就是一个动态平衡的过程。

其实对于很多公司来说,随着业务的快速变化,安全问题是挥之不去的隐患。所以密码修改也是一种合情合理的解决方式,当然在这个过程中会有一些可用性的影响,整体来说,我们要保证的是可控。

可能到了这里,我们才进行了一半,上面的方案应用层改造其实还是比较大的,而且对于权限的维护来说需要保证影子账户的权限也要完全一致,否则产生业务影响就很被动了。

我们有没有更好的方案呢,其实最透明的方案是数据库层面来做好这种双层校验,这时我想到了MySQL 8.0的新特性。

在MySQL 8.0.14的release note中是这么低调的一段描述。

我们通俗些可以理解为双密码,retain current password这个语法只在修改密码的场景中使用,在create user中是不能用的。意思是修改密码的时候原来的密码依旧可用,这样对于业务是最友好的方式。

正确理解这个语法的姿势是查看官方文档的解读:

不演示一下不尽兴,我们来看看这个特性的效果。

首先创建一个用户:

代码语言:javascript
复制
mysql>  create user test_pwd identified by 'test_pwd1';
Query OK, 0 rows affected (0.01 sec)

然后赋予一些基本的权限

代码语言:javascript
复制
mysql> grant usage on *.* to test_pwd ;
Query OK, 0 rows affected (0.01 sec)

这个时候通过客户端连接是OK的。

代码语言:javascript
复制
# mysql -utest_pwd -ptest_pwd1 -P33061 -h127.0.0.1
mysql>

我们开始关键部分,修改用户密码,使用retain current password语法:

代码语言:javascript
复制
mysql> alter user test_pwd identified by 'test_pwd1' retain current password;
ERROR 1227 (42000): Access denied; you need (at least one of) the CREATE USER or APPLICATION_PASSWORD_ADMIN privilege(s) for this operation

很遗憾失败了,因为这个操作是需要基本的权限的,根据提示需要APPLICATION_PASSWORD_ADMIN 或者CREATE USER的权限。

我们使用管理员账户修正下权限。

代码语言:javascript
复制
mysql> grant APPLICATION_PASSWORD_ADMIN on *.* to test_pwd;
Query OK, 0 rows affected (0.01 sec)

再次修改就可以了。

代码语言:javascript
复制
mysql> alter user test_pwd identified by 'test_pwd2' retain current password; 
Query OK, 0 rows affected (0.01 sec)

这个时候就达到了密码双活的状态,两个密码都可以用,而且校验始终都可用,幸福感大大增强。

当然我不建议对于业务无限制开放,毕竟这种方式会让双方都很难持续维护密码,所以在业务修改密码,批次启动应用服务后,我们可以回收原来的密码,使用discard old password子句。

代码语言:javascript
复制
mysql> alter user test_pwd DISCARD OLD PASSWORD;
Query OK, 0 rows affected (0.01 sec)

这个时候连接会再次失败。

代码语言:javascript
复制
# mysql -utest_pwd -ptest_pwd1 -P33061 -h127.0.0.1      
mysql: [Warning] Using a password on the command line interface can be insecure.
ERROR 1045 (28000): Access denied for user 'test_pwd'@'localhost' (using password: YES)

这应该算是我们最希望看到的错误场景了,满满的完成任务的使命感。

期待MySQL 8.0更多更好的新特性。。。

下一篇
举报
领券