[命令] Linux 命令 grep (显示文本的行)

案例一:grep 使用 perl 正则表达式匹配

# grep -P '^root' /etc/passwd

或者:

# grep --perl-regexp '^root' /etc/passwd

(补充:这里以匹配 /etc/passwd 文件中开头为 root 的行为例)

案例二:grep 使用正则表达式匹配

# grep -e '^root' /etc/passwd

或者:

# grep --regexp=PATTERN '^root' /etc/passwd

(补充:这里以匹配 /etc/passwd 文件中开头为 root 的行为例)

案例三:grep 使用扩展正则表达式匹配

# grep -E '([1-9][0-9]{0,2}\.){3}[1-9][0-9]{0,2}' /etc/sysconfig/network-scripts/ifcfg-ens192

或者:

# grep --extended-regexp '([1-9][0-9]{0,2}\.){3}[1-9][0-9]{0,2}' /etc/sysconfig/network-scripts/ifcfg-ens192

或者:

# egrep '([1-9][0-9]{0,2}\.){3}[1-9][0-9]{0,2}' /etc/sysconfig/network-scripts/ifcfg-ens192

(补充:这里以匹配 /etc/sysconfig/network-scripts/ifcfg-ens192 文件里含有 IP 地址的行为例)

案例四:grep 显示行号

4.1 显示某些关键字所在行行号

# egrep -n '([1-9][0-9]{0,2}\.){3}[1-9][0-9]{0,2}' /etc/sysconfig/network-scripts/ifcfg-ens192

或者:

# egrep --line-number '([1-9][0-9]{0,2}\.){3}[1-9][0-9]{0,2}' /etc/sysconfig/network-scripts/ifcfg-ens192

或者:

# egrep --line-buffered '([1-9][0-9]{0,2}\.){3}[1-9][0-9]{0,2}' /etc/sysconfig/network-scripts/ifcfg-ens192

(补充:这里以匹配 /etc/sysconfig/network-scripts/ifcfg-ens192 文件里含有 IP 地址的行并显示行号为例)

4.2 显示哪些行号是空行

# egrep -n ^$ /etc/resolv.conf

或者:

# egrep --line-number ^$ /etc/resolv.conf

或者:

# egrep --line-buffered ^$ /etc/resolv.conf

(补充:这里以匹配 /etc/resolv.conf 里的空行并显示行号为例)

案例五:grep 取反匹配

5.1 取反不匹配某些关键字

# egrep -v '([1-9][0-9]{0,2}\.){3}[1-9][0-9]{0,2}' /etc/sysconfig/network-scripts/ifcfg-ens192

或者:

# egrep --invert-match '([1-9][0-9]{0,2}\.){3}[1-9][0-9]{0,2}' /etc/sysconfig/network-scripts/ifcfg-ens192

(补充:这里以匹配 /etc/sysconfig/network-scripts/ifcfg-ens192 文件里不含有 IP 地址的行并显示行号为例)

5.2 取反不显示空行

# egrep -v ^$ /etc/resolve.conf

或者:

# egrep --invert-match ^$ /etc/resolve.conf

(补充:这里以匹配 /etc/resolve.conf 文件里不为空的行为例)

5.3 取反不显示以井号 “#” 开头的行

# grep '^[^#]' /etc/resolve.conf

(补充:这里以匹配 /etc/resolve.conf 文件里不以井号 “#” 开头的行为例)

5.4 取反不显示以井号 “#” 或空格 “ ” 开头的行

# grep '^[^#| ]' /etc/resolve.conf

(补充:这里以匹配 /etc/resolve.conf 文件里不以井号 “#” 和空格 “ ” 开头的行为例)

案例六:grep 只显示匹配的部分

# egrep -o '([1-9][0-9]{0,2}\.){3}[1-9][0-9]{0,2}' /etc/sysconfig/network-scripts/ifcfg-ens192

或者:

# egrep --only-matching '([1-9][0-9]{0,2}\.){3}[1-9][0-9]{0,2}' /etc/sysconfig/network-scripts/ifcfg-ens192

(补充:这里以匹配 /etc/sysconfig/network-scripts/ifcfg-ens192 里的 IP 地址为例)

(注意:这里匹配后只显示 IP 地址,而不显示 IP 地址所在行里的其他内容)

案例七:grep 匹配时忽略大小写

# egrep -i '([1-9][0-9]{0,2}\.){3}[1-9][0-9]{0,2}' /etc/sysconfig/network-scripts/ifcfg-ens192

或者:

# egrep --ignore-case '([1-9][0-9]{0,2}\.){3}[1-9][0-9]{0,2}' /etc/sysconfig/network-scripts/ifcfg-ens192

(补充:这里以匹配 /etc/sysconfig/network-scripts/ifcfg-ens192 文件里含有 IP 地址的行并忽略大小写为例)

案例八:grep 统计匹配成功次数

# egrep -c '([1-9][0-9]{0,2}\.){3}[1-9][0-9]{0,2}' /etc/sysconfig/network-scripts/ifcfg-ens192

或者:

# egrep --count '([1-9][0-9]{0,2}\.){3}[1-9][0-9]{0,2}' /etc/sysconfig/network-scripts/ifcfg-ens192

(补充:这里以匹配 /etc/sysconfig/network-scripts/ifcfg-ens192 文件里含有 IP 地址的行的数量为例)

案例九:grep 将匹配成功的部分自动添加颜色

# egrep --color=auto '([1-9][0-9]{0,2}\.){3}[1-9][0-9]{0,2}' /etc/sysconfig/network-scripts/ifcfg-ens192

(补充:这里以匹配 /etc/sysconfig/network-scripts/ifcfg-ens192 文件里含有 IP 地址的行并自动添加颜色为例)

案例十:grep 将匹配成功的部分自动取消颜色

# egrep --color=no '([1-9][0-9]{0,2}\.){3}[1-9][0-9]{0,2}' /etc/sysconfig/network-scripts/ifcfg-ens192  

(补充:这里以匹配 /etc/sysconfig/network-scripts/ifcfg-ens192 文件里含有 IP 地址的行并取消自动添加颜色为例)

案例十一:grep 一次匹配多个参数

# grep -e root -e zhumingyu /etc/passwd

(补充:这里以匹配 /etc/passwd 文件中包含 root 或 zhumingyu 的行为例)

案例十二:grep 显示匹配内容附近的内容

12.1 显示匹配内容的前 10 行

# grep -a 10 eternalcenter test.txt

或者:

# grep --text 10 eternalcenter test.txt

(补充:这里以匹配 test.txt 文件中包含 eternalcenter 的行并显示其前 10 行为例)

12.2 显示匹配内容的后 10 行

# grep -b 10 eternalcenter test.txt

或者:

# grep --byte-offset 10 eternalcenter test.txt

(补充:这里以匹配 test.txt 文件中包含 eternalcenter 的行并显示其后 10 行为例)

12.3 显示匹配内容的前后 10 行

# grep -a -b 10 eternalcenter test.txt

或者:

# grep --text --byte-offset 10 eternalcenter test.txt

(补充:这里以匹配 test.txt 文件中包含 eternalcenter 的行并显示其前后 10 行为例)

案例十三:grep 安静匹配

# grep -q root /etc/passwd

或者:

# grep --quiet root /etc/passwd

或者:

# grep --silent root /etc/passwd
# echo $?
0


补充:
1) 这种方法主要用于在 Shell 脚本中,随后使用 if 判断判断匹配是否成功
2) 这里以匹配 /etc/passwd 中是否包含 root 用户为例

[排错] 解决 Linux 删除数据后依旧无法释放空间

解决方法

步骤一:理解出现问题的原因

当删除某些数据时,此数据正在被某个进程使用,则这些数据需要 kill 掉这个进程后才能被删除掉

步骤二:显示目录的使用状态

# df -h

(注意:如果出现已用存储加剩余存储小于总存储的情况,就代表出现了被删除的数据正在被进程使用的情况 )

步骤三:显示对应目录里所有一级子目录的大小

# du -ah --max-depth=1

步骤四:显示是否有进程在使用正在被删除的数据

# lsof | grep delete

步骤五:杀死这些进程以让这些数据被成功删除

# kill -9 `lsof | grep delete | awk '{print $2}'` 

(注意:kill 进程有一定的风险,请小心执行)

[排错] 解决 openSUSE & SLE 通过 YaST 设置 IP 地址时报错 “Network is currently handled by NetworkManager”

报错代码

Network is currently handled by NetworkManager

解决方法

步骤一:报错现象和原因分析

1.1 报错现象

通过 yast 给 openSUSE 和 SUSE 设置 IP 地址时可能会出现以下报错

(图:1)

1.2 原因分析

如果是带桌面安装 openSUSE 和 SUSE ,系统则会默认使用 NetworkManager 管理网络,这样会导致 yast 无法设置 IP 地址

步骤二:排错

2.1 取消开机自启 NetworkManager

# systemctl disable NetworkManager

2.2 停止 NetworkManager 服务

# systemctl stop NetworkManager

2.3 在 yast 中将 General Network Settings 从 NetworkManager Service 换成 Wicked Service

2.3.1 进入 yast
# yast
2.3.2 进入 System 下面的 Network Settings
2.3.3 在 Global Options 选项中将 General Network Settings 从 NetworkManager Service 换成 Wicked Service
(图:2)

[实验] Linux 硬盘的加密 (通过 crypt 实现)

纪念:站主于 2019 年 11 月完成了此开源实验,并将过程中的所有命令经过整理和注释以后,形成以下教程

步骤一:硬盘加密后的注意事项

1) 加密后不能直接挂载
2) 加密后硬盘丢失也不用担心数据被盗
3) 加密后必须做映射才能挂载

步骤二:生成一个新的分区

2.1 显示现有的分区

# lsblk
NAME   MAJ:MIN RM  SIZE RO TYPE MOUNTPOINT
sr0     11:0    1 1024M  0 rom  
vda    253:0    0   10G  0 disk 
└─vda1 253:1    0   10G  0 part /
vdb    253:16   0   10G  0 disk 

(补充:在这里是加了一个 vdb 硬盘用来进行分区并加密)

2.2 创建一个新的分区

# fdisk /dev/vdb
命令(输入 m 获取帮助):n
分区号 (1-8,默认 1):
起始 扇区 (0-20971440,默认 0):
Last 扇区 or +扇区 or +size{K,M,G,T,P} (0-20971440,默认 20971440):+5G
分区 1 已设置为 Linux native 类型,大小设为 5 GiB

命令(输入 m 获取帮助):w
The partition table has been altered!

2.2 显示新的分区

# lsblk
NAME   MAJ:MIN RM  SIZE RO TYPE MOUNTPOINT
sr0     11:0    1 1024M  0 rom  
vda    253:0    0   10G  0 disk 
└─vda1 253:1    0   10G  0 part /
vdb    253:16   0   10G  0 disk 
└─vdb1 253:17   0    5G  0 part 

步骤三:创建逻辑卷

3.1 创建卷组

# vgcreate mysqldatavg /dev/vdb1
WARNING: sun signature detected on /dev/vdb1 at offset 508. Wipe it? [y/n]: y
  Wiping sun signature on /dev/vdb1.
  Physical volume "/dev/vdb1" successfully created.
  Volume group "mysqldatavg" successfully created

3.2 创建逻辑卷

# lvcreate -n mysqldatalv -L 1G mysqldatavg
  Logical volume "mysqldatalv" created.

步骤四:给逻辑卷加密

4.1 给逻辑卷加密

# cryptsetup luksFormat /dev/mapper/mysqldatavg-mysqldatalv

WARNING!
========
这将覆盖 /dev/mapper/mysqldatavg-mysqldatalv 上的数据,该动作不可取消。

Are you sure? (Type uppercase yes): YES
输入 /dev/mapper/mysqldatavg-mysqldatalv 的口令:
确认密码:

4.2 解锁逻辑卷

# cryptsetup luksOpen /dev/mapper/mysqldatavg-mysqldatalv mysqldata
输入 /dev/mapper/mysqldatavg-mysqldatalv 的口令:

(补充:这里的 mysqldata 是解锁后的硬件名称)

4.3 格式化逻辑卷

# mkfs.ext4 /dev/mapper/mysqldata

(注意:要先解锁了逻辑卷以后才能格式化逻辑卷)

4.4 锁住逻辑卷

# cryptsetup luksClose mysqldata

内容五:自动挂载加密逻辑卷

5.1 修改系统自动挂载文件

# vim /etc/fstab

添加以下内容:

......
/dev/mapper/mysqldata /var/lib/mysql ext4 defaults 0 0

5.2 创建一个映射器

# vim /etc/cypttab

添加以下内容:

......
mysqldata /dev/mapper/mysqldatavg-mysqldatalv /root/keyfile luks

(补充:这里的三个参数分别代表:虚拟设备名、真实设备、密码的存储文件)

5.3 创建随机密钥文件

# dd if=/dev/urandom of=/root/keyfile bs=1024 count=4

5.4 将密钥文件设为只读

# chmod 0400 /root/keyfile

5.5 将密码添到 luks 中,让密码立刻生效

# cryptsetup luksAddKey /dev/mysqldatavg/mysqldatalv /root/keyfile
输入任意已存在的口令:

5.6 测试挂载效果

5.6.1 挂载加密逻辑卷
# mount -a
5.6.2 测试加密效果
# df -h

[内容] MariaDB & MySQL 安全调优思路

内容一:数据库运行环境安全

1.1 保证运行数据库的系统是安全的

(步骤略)

1.2 以最小权限用户运行数据库

1.2.1 停止数据库
# systemctl stop mariadb

(补充:这里以停止 MariaDB 数据库为例)

1.2.2 修改数据库目录的
# chown -R mysql /var/lib/mysql

(补充:MariaDB&MySQL 数据库数据默认存放位置是 /var/lib/mysql)

1.2.3 修改配置文件
# vim /etc/my.cnf

在:

......
[mysqld]

下面添加:

user=mysql
......

(补充:这里以 MariaDB 数据库的配置文件是 /etc/my.cnf 为例)

1.2.4 启动数据库
# systemctl start mariadb

(补充:这里以启动 MariaDB 数据库为例)

1.3 将数据库版本升级到更新的版本

(步骤略)

内容二:数据库库安全

2.1 删除所有不用的库

2.1.1 查看所有库的列表
> show databases;
2.1.2 删除测试库
> drop database <database>

2.2 删除所有测试库

2.2.1 方法一:手动删除所有测试库
2.2.1.1 查看所有库的列表
> show databases;
2.2.1.2 删除测试库
> drop database <database>
2.2.2 方法二:使用工具删除所有测试库
# sudo mysql_secure_installation

2.3 禁用客户端本地数据被读取

2.3.1 修改配置文件
# vim /etc/my.cnf

在:

......
[mysqld]

下面添加:

local-infile=0
......

(补充:这里以 MariaDB 数据库的配置文件是 /etc/my.cnf 为例)

(注意:此参数对 MariaDB 数据库无效)

2.3.2 重启数据库
# systemctl restart mariadb

(补充:这里以重启 MariaDB 数据库为例)

2.4 保护数据的本地存储

思路如下:
1) 使用加密的文件系统存储存放数据库的数据文件
2) 使用数据库之外的存储加密产品
3) 使用其他加密产品实现适当的数据保护

内容三:数据库登录安全

3.1 限制数据的导入导出

3.1.1 案例一:禁止数据的导入导出
3.1.1.1 修改配置文件
# vim /etc/my.cnf

在:

......
[mysqld]

下面添加:

secure_file_priv=null
...... 

(补充:这里以 MariaDB 数据库的配置文件是 /etc/my.cnf 为例)

(注意:此参数对 MariaDB 数据库无效)

3.1.1.2 重启数据库
# systemctl restart mariadb

(补充:这里以重启 MariaDB 数据库为例)

3.1.2 案例二:只允许将数据从 /root 目录导入或导出到 /root 目录
3.1.2.1 修改配置文件
# vim /etc/my.cnf

在:

......
[mysqld]

下面添加:

secure_file_priv=/root/
...... 

(补充:这里以 MariaDB 数据库的配置文件是 /etc/my.cnf 为例)

(注意:此参数对 MariaDB 数据库无效)

3.1.2.2 重启数据库
# systemctl restart mariadb

(补充:这里以重启 MariaDB 数据库为例)

3.1.3 案例三:不对数据作出导入和导出的限制
3.1.3.1 修改配置文件
# vim /etc/my.cnf

删除以下内容:

......
secure_file_priv=*
...... 

(补充:这里以 MariaDB 数据库的配置文件是 /etc/my.cnf 为例)

(注意:此参数对 MariaDB 数据库无效)

3.1.3.2 重启数据库
# systemctl restart mariadb

(补充:这里以重启 MariaDB 数据库为例)

3.2 删除无用和不需要的用户

3.2.1 查看所有用户
> select user,host from mysql.user;
3.2.2 删除不需要的用户
3.2.2.1 方法一:使用 drop 命令删除用户
> drop <user>;
3.2.2.2 方法二:使用 delete 命令删除用户
> delete from mysql.user where user='<user>' and host='<host>';

3.3 强制用户使用强密码

3.3.1 修改配置文件
# vim /etc/my.cnf

在:

......
[mysqld]

下面添加:

plugin-load=validate_password.so
......

(补充:这里以 MariaDB 数据库的配置文件是 /etc/my.cnf 为例)

3.3.2 重启数据库
# systemctl restart mariadb

(补充:这里以重启 MariaDB 数据库为例)

3.3.3 确保 validate_password_policy 被设置的参数是 MEDIUM
3.3.3.1 进入数据库
# mysql -p
3.3.3.2 查看 validate_password_policy 参数
> show variables like 'validate_password_policy';
+--------------------------+--------+
| Variable_name            | Value  |
+--------------------------+--------+
| validate_password.policy | MEDIUM |
| validate_password_policy | MEDIUM |
+--------------------------+--------+
2 rows in set (0.01 sec)

(补充:MEDIUM 的含义是密码最小的长度是 8 ,并且必须要有一个特殊字符和一个数字)

3.4 设置用户密码有效期

3.4.1 对于 MariaDB 和 MySQL 5.7 及以下的版本无法设置有效期,只能定期修改密码
> alter user 'root'@'localhost' identified by '<password>';
3.4.2 设置用户默认有效期的方法
3.4.2.1 修改用户密码默认的自动过期时间
> set global default_password_lifetime=<number>;

(补充:这里的数字代表天数)

3.4.2.2 让用户密码立刻过期
> aleter user '<user>'@'<host>' password expire;
3.4.2.3 让用户密码永不过期
> aleter user '<user>'@'<host>' password expire never;

(补充:建议普通用户每 90 天修改一次密码,敏感用户每 30 天修改一次密码,服务用户每 365 天修改一次密码)

3.5 删除无密码用户

3.5.1 方法一:手动删除无密码用户
3.5.1.1 查看无密码用户
3.5.1.1.1 MariaDB 和 MySQL 5.7 及以下版本查看无密码用户的方法
> select user, host, password from mysql.user;
3.5.1.1.2 MySQL 8.0 及以上版本查看无密码用户的方法
> select user, host, authentication_string from mysql.user;
3.5.1.2 手动删除不需要的用户的方法
3.5.1.2.1 手动删除用户的第一种方法:使用 drop 命令删除用户
> drop user <user>;
3.5.1.2.2 手动删除用户的第二种方法:使用 delete 命令删除用户
> delete from mysql.user where user='<user>' and host='<host>';
3.5.2 方法二:使用工具删除无密码用户
# sudo mysql_secure_installation

3.6 禁止非 root 用户 拥有 mysql.user 表访问权限

> show grants for root@localhost \G;
> select * from mysql.user where user='test' \G;

3.7 让用户只拥有最小但够用的权限

3.7.1 查看所有用户
> select user,host from mysql.user;
3.7.2 数据库权限层级

1) 全局层级权限:是指整个数据库级别的权限,存储在 mysql.user 表中
格式:

> grant all on *.* ......
> show grants for <user>;
> select * from mysql.user where user='<user>'\G;

2) 库级层级权限:是指数据库中某个库的权限,存储在 mysql.db 和 mysql.host 表中
格式:

> grant all on <database>.* ......
> show grants for <user>;
> select * from mysql.db where user='<user>'\G;

3) 表级层级权限:是指数据库中某个库的某个表的权限,存储在 mysql.tables_priv 表中
格式:

> grant all on <database>.<table> ......
> show grants for <user>;
> select * from mysql.tables_priv where user='<user>'\G;

4) 列级层级权限:是指数据库中某个库的某个表的某一单列的权限,存储在 mysql.columns_priv 表中
格式:

> grant select(<field>,<field>) on <database>.<table> ......
> show grants for <user>;
> select * from mysql.columns_priv where user='<user>'\G;

5) 子程序层级权限:适用于已存储的子程序
create routing, alter routing, execute 和 grant 权限适用于已存储的子程序
create routing, alter routing, execute 和 grant 权限可以被授予为全局层级和数据库层级
alter routing, execute 和 grant 权限可以被授予为子程序层级,并存储在 mysql.procs_priv 表中
格式:

> grant execute on <subroutine> <database>.<table> ......
> show grants for <user>;
> select * from mysql.procs_priv where user='<user>'\G;
3.7.3 查看每一个用户的权限
> show grants for '<user>'@'<host>';
3.7.4 删除用户多余的权限

如果有全局权限(如: FILE,PROCESS,SUPER, or SHUTDOWN 等权限),就删除这些权限
格式:

> revoke <privilege> on *.* from <user>@<host>;
> flush privileages;

内容四:数据库网络安全

4.1 禁止或者限制远程登录

(步骤略)

(
补充:
查看可以远程登录的用户的案例

> select user, host from mysql.user where host not in ('::1','127.0.0.1','localhost');

4.1.1 禁止远程登录

4.1.1.1 通过 MariaDB & MySQL 的配置文件禁止远程登录
4.1.1.1.1 修改配置文件
# vim /etc/my.cnf

在:

......
[mysqld]

下面添加:

skip-networking
bind-address=127.0.0.1
......

(补充:这里以 MariaDB 数据库的配置文件是 /etc/my.cnf 为例)

(注意:加入 skip-networking 这一行会让 MariaDB&MySQL 不再使用和监听任何端口)

4.1.1.1.2 重启数据库
# systemctl restart mariadb

(补充:这里以重启 MariaDB 数据库为例)

4.1.1.2 通过防火墙禁止远程登录
4.1.2 如果非要进行远程登录则要限制远程登录
4.1.2.1 限制访问数据库 TCP 端口的具体 IP 地址

(步骤略)

(补充:MariaDB&MySQL 数据库的默认端口号是 3306)

4.1.2.2 禁止有较大权限的用户被远程登录

1) 有 grant option 权限的用户
2) 被给予了全局权限像是 grant all on . 权限的用户
3) 一个可以访问 mysql.user 表的用户

4.2 对网络数据进行加密传输

4.2.1 生成 SSL
4.2.1.1 创建 CA 证书
# openssl genrsa 2048 > ca-key.pem
Generating RSA private key, 2048 bit long modulus
..+++
...................................+++
e is 65537 (0x10001)

# openssl req -new -x509 -nodes -days 3600 -key ca-key.pem -out ca.pem
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [XX]:
State or Province Name (full name) []:
Locality Name (eg, city) [Default City]:
Organization Name (eg, company) [Default Company Ltd]:
Organizational Unit Name (eg, section) []:
Common Name (eg, your name or your server's hostname) []:ca
Email Address []:

(注意:创建 CA 证书、服务端证书、客户端证书时 Common Name 必须要有值,且必须相互不一样)

4.2.1.2 创建服务端证书,并去除加密,并使用刚刚的 CA 证书进行签名
# openssl req -newkey rsa:2048 -days 3600 -nodes -keyout server-key.pem -out server-req.pem
Generating a 2048 bit RSA private key
.............+++
...+++
writing new private key to 'server-key.pem'
-----
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [XX]:
State or Province Name (full name) []:
Locality Name (eg, city) [Default City]:
Organization Name (eg, company) [Default Company Ltd]:
Organizational Unit Name (eg, section) []:
Common Name (eg, your name or your server's hostname) []:
Email Address []:

Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:

# openssl rsa -in server-key.pem -out server-key.pem
writing RSA key

# openssl x509 -req -in server-req.pem -days 3600 -CA ca.pem -CAkey ca-key.pem -set_serial 01 -out server-cert.pem
Signature ok
subject=/C=XX/L=Default City/O=Default Company Ltd
Getting CA Private Key

(注意:创建 CA 证书、服务端证书、客户端证书时 Common Name 必须要有值,且必须相互不一样)

4.2.1.3 创建客户端证书,并去除加密,并使用刚刚的 CA 证书进行签名
# openssl req -newkey rsa:2048 -days 3600 -nodes -keyout client-key.pem -out client-req.pem
Generating a 2048 bit RSA private key
..................+++
..............................................+++
writing new private key to 'client-key.pem'
-----
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [XX]:
State or Province Name (full name) []:
Locality Name (eg, city) [Default City]:
Organization Name (eg, company) [Default Company Ltd]:
Organizational Unit Name (eg, section) []:
Common Name (eg, your name or your server's hostname) []:
Email Address []:

Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:

# openssl rsa -in client-key.pem -out client-key.pem
writing RSA key

# openssl x509 -req -in client-req.pem -days 3600 -CA ca.pem -CAkey ca-key.pem -set_serial 01 -out client-cert.pem
Signature ok
subject=/C=XX/L=Default City/O=Default Company Ltd
Getting CA Private Key
4.2.1.4 对生成的证书进行验证
# openssl verify -CAfile ca.pem server-cert.pem client-cert.pem
server-cert.pem: OK
client-cert.pem: OK
4.2.2 将 SSL 添加到 MariaDB & MySQL
4.2.2.1 将 SSL 放在指定的位置
# mv ca.pem /home/mysql/sslconfig/ca.pem
# mv server-cert.pem /home/mysql/sslconfig/server-cert.pem
# mv server-key.pem /home/mysql/sslconfig/server-key.pem
4.2.2.2 修改配置文件
# vim /etc/my.cnf

在:

......
[mysqld]

下面添加:

ssl-ca=/home/mysql/sslconfig/ca.pem
ssl-cert=/home/mysql/sslconfig/server-cert.pem
ssl-key=/home/mysql/sslconfig/server-key.pem
......

(补充:这里以 MariaDB 数据库的配置文件是 /etc/my.cnf 为例)

4.2.3 重启数据库
# systemctl restart mariadb

(补充:这里以重启 MariaDB 数据库为例)

4.2.4 验证 SSL
4.2.4.1 查看 have_ssl 和 ssl 变量
> show variables like 'have_%ssl';
> show variables like '%ssl%';

(补充:如果它们的参数为 yes ,表示服务端已经开启 SSL)

4.2.4.2 查看 SSL 的状态
> show status like 'ssl_cipher'

(补充:如果出现 “SSL:Cipher in use is DHE-RSA-AES256-SHA“ 则表示客户端已经使用 SSL 连接了)

4.2.5 确保所有数据库用户使用 SSL
> grant usage on <database>.<table> to '<user>'@'<host>' reouter ssl;
4.2.6 用户通过 SSL 连接数据库的方法
> mysql -u <user> -p -h <host> --ssl-ca=/home/mysql/sslconfig/ca.pem

内容五:开启审计

5.1 开启审计

5.1.1 MariaDB 和 MySQL 5.7 及以下版本开启审计的方法
> set global log_warning=2;
5.1.2 MySQL 8.0 及以上版本开启审计的方法
> set global general_log = on;
> set global log_timestamps = SYSTEM;
5.2 查看 MariaDB & MySQL 日志
# find /I "Access denied for user" <logfile_name>.log
# grep -i 'Access denied for user' <logfile_name>.log

(补充:中止连接、失败连接、尝试连接都将被写进日志)