基于腾讯云平台之自动化运维工具Ansible实践

2022-09-18 10:14:07 浏览数 (2)

本篇将主要描述在腾讯云平台如何构建Ansible自动化运维管理工具平台/环境,如何批量管理云上服务器,批量分发配置等设置,同时这里将引入某客户真实的案例进行整体的阐述。将从Ansible的基础、架构、常见功能模块,案例解决示例方法进行展开。

1. Ansible概述

1.1. 什么是Ansible

Ansible 是一款开源自动化平台,基于Python开发,无需客户端,轻量级,配置语言采用YAML,可以管理强大的自动化任务,提高工作效率。

1.2. Ansible 功能特点

  • 简单明了,易于阅读;
  • 无代理: 通过SSH管理节点
  • 模块化: 自带管理模块库
  • 通过YAML描述系统
  • 依赖Python 2.4或以上
  • 跨平台支持

1.3. 主流自动化运维管理工具

  • Puppet:基于Ruby开发,采用C/S架构,扩展性强,基于SSL认证
  • SaltStack:基于Python开发,采用C/S架构,相对于puppet更轻量级,配置语法采用YMAL,使得配置脚本更为简单
  • Ansible:基于Pyton开发,分布式,无需客户端,轻量级,配置语言采用YAML

1.4. 为什么选择Ansible

  • 相对于puppet和saltstack,ansible无需客户端,更轻量级
  • ansible都不用启动服务,以更轻松的实现分布式扩展
  • 更强的远程命令执行操作
  • 不输于puppet和saltstack的其他功能,且ansible 也最受欢迎的是自动化和编排技术之一

1.5. Ansible基本架构

Ansible 架构存在两种计算类型,即控制节点和受控主机/被管主机。

  • 连接插件:默认是SSH,也支持其他的连接方法
  • 核心模块:ansible的操作依赖于具体的模块
  • 自定义模块:可以扩展自定义模块
  • playbooks:定义Ansible任务的一个配置文件,可以将多个任务定义在一个playbook,由Ansible自动执行
  • 主机配置清单:定义需要执行任务的主机

2. Ansible环境部署

这里为了更直观看到效果,采用3台centos7.6 1台ubuntu进行自动运维环境的构建,如果需要覆盖更多被管主机,则通过下面的方法扩展即可。

2.1. Ansible 安装及相关配置

2.1.1. 安装Ansible

代码语言:javascript复制
[root@master]# yum -y install ansible

2.1.2. 设置本地解析及主机名

代码语言:javascript复制
[root@master ~]# hostnamectl set-hostname master.example.com
[root@master ~]# cat /etc/hosts
127.0.0.1 VM-6-10-centos VM-6-10-centos
127.0.0.1 localhost.localdomain localhost
127.0.0.1 localhost4.localdomain4 localhost4
::1 VM-6-10-centos VM-6-10-centos
::1 localhost.localdomain localhost
::1 localhost6.localdomain6 localhost6
10.0.6.10 master.example.com master
10.0.6.4 node1.example.com node1
10.0.6.13 node2.example.com node2
10.0.6.8 node3.example.com node3
备注: node1 – node3 均像master 节点一样设置

2.1.3. ssh key免密登录设置

代码语言:javascript复制
[root@master ~]# ssh-keygen
Generating public/private rsa key pair.
Enter file in which to save the key (/root/.ssh/id_rsa):
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /root/.ssh/id_rsa.
Your public key has been saved in /root/.ssh/id_rsa.pub.
The key fingerprint is:
SHA256:afVk9vExWqYP3sxC0Pj1 kIaLFpKiUr8slNea3gxPPI root@master.example.com
The key's randomart image is:
 ---[RSA 2048]---- 
| |
| o |
| .o ..* |
| o =o.*o |
| . oS. ..*. o|
| o  .O o = B. |
| . = * O . *.= |
|     E . o. |
| .  o ..|
 ----[SHA256]----- 
[root@master ~]# ssh-copy-id root@node1.example.com 输入node1 密码, node2, node3类似,机器多则可通过for脚本批量实现。

2.1.4. Ansible环境验证

代码语言:javascript复制
[root@master ~]# tail /etc/ansible/hosts
[nodes]
node1
node2
node3
node4
[root@master ~]# ansible all -m ping
node2 | SUCCESS => {
 "ansible_facts": {
 "discovered_interpreter_python": "/usr/bin/python"
 },
 "changed": false,
 "ping": "pong"
}
node3 | SUCCESS => {
 "ansible_facts": {
 "discovered_interpreter_python": "/usr/bin/python"
 },
 "changed": false,
 "ping": "pong"
}
node1 | SUCCESS => {
 "ansible_facts": {
 "discovered_interpreter_python": "/usr/bin/python"
 },
 "changed": false,
 "ping": "pong"
}
node4 | SUCCESS => {
 "ansible_facts": {
 "discovered_interpreter_python": "/usr/bin/python"
 },
 "changed": false,
 "ping": "pong"
}
[root@master ~]#

2.2. Ansible 相关核心配置文件

代码语言:javascript复制
[root@master ~]# rpm -ql ansible |less
/etc/ansible/ansible.cfg //ansible 主配置文件
/etc/ansible/hosts //主机清单文件
/etc/ansible/roles  //角色目录
/usr/bin/ansible //主程序,临时命令执行工具
/usr/bin/ansible-config  //查看ansible配置
/usr/bin/ansible-connection //基于Console界面与用户交互的执行工具
/usr/bin/ansible-doc //查看配置文档,模块功能查看工具
/usr/bin/ansible-galaxy //下载/上传Roles模块的官网
/usr/bin/ansible-inventory // 查看inventory信息
/usr/bin/ansible-playbook //定制自动化任务,编排剧本工具
/usr/bin/ansible-vault //文件加密工具
/usr/share/ansible/roles //角色目录

2.3. Ansible主配置核心项说明

Ansible默认配置文件: /etc/ansible/ansible.cfg

代码语言:javascript复制
#forks = 5 并发执行数量,默认5
#poll_interval = 15 拉取数据间隔时间,默认15秒
#sudo_user = root sudo命令默认用户
#remote_port = 22 连接远程端口号
#host_key_checking = False 检查对应服务器的host_key,建议取消注释
#log_path=/var/log/ansible.log 日志文件,建议取消注释

2.4. Ansible配置文件优先级

ansible配置文件以及读取优先级,如下顺序:

1) ANSIBLE_CONFIG变量

2) 当前目录 ansible.cfg

3) 家目录下 ansible.cfg

4) 默认配置文件 /etc/ansible/ansible.cfg

本篇采用系统默认的配置,若生产环境且涉及多人协作,使用普通用户选择2)或3)方法去配置Ansible环境。

3. Ansible 常用模块

3.1. 查看模块

代码语言:javascript复制
[root@master ansible]# ansible-doc yum //查看模块帮助
[root@master ansible]# ansible-doc -s yum //显示模块简要说明
[root@master ansible]# ansible-doc -l //列出ansible模块

3.2. Command 模块

功能:默认模块,在远程主机执行命令,可忽略-m选项

代码语言:javascript复制
​[root@master ansible]# ansible all -m command -a "touch /tmp/test.txt" 
[root@master ansible]# ansible all -m command -a 'systemctl restart httpd'

3.3. Shell模块

功能:和command相似,用shell执行命令

代码语言:javascript复制
[root@master ansible]# ansible node1 -m shell -a 'useradd user01'
[root@master ansible]# ansible node1 -m shell -a "echo 123456 |passwd --stdin user01“

3.4. Scripts脚本模块

功能:运行脚本,不需要将脚本复制到被控端

代码语言:javascript复制
​[root@master ansible]#ansible node1-m script -a test.sh
[root@master ansible]# ansible all -m script -a ./test.sh
[root@master ansible]# ansible all -m command -a 'ls -l /tmp'
[root@master ansible]# ansible node1 -m script -a ./host-name.sh

3.5. Yum 模块

功能:通过yum 安装软件包

安装vsftpd软件包

代码语言:javascript复制
[root@master ansible]# ansible node1 -m yum -a "name=vsftpd state=present"

卸载vsftpd软件包

代码语言:javascript复制
[root@master ansible]# ansible all -m yum -a "name=vsftpd state=absent"

安装Development Tools (软件包组)

代码语言:javascript复制
[root@master ansible]# ansible node1 -m yum -a "name='@Development Tools'"

3.6. File模块

功能:设置文件属性,创建/删除等操作

创建新文件:

代码语言:javascript复制
​[root@master ansible]# ansible node1 -m file -a 'name=/tmp/file1 state=touch'

删除文件:

代码语言:javascript复制
​[root@master ansible]# ansible node1 -m file -a 'name=/tmp/file1 state=absent'

创建目录:

代码语言:javascript复制
​[root@master ansible]# ansible node1 -m file -a 'name=/tmp/dir state=directory'

删除目录:

代码语言:javascript复制
[root@master ansible]# ansible node1 -m file -a 'name=/tmp/dir state=absent'

3.7. Copy模块

功能:从服务器复制文件到客户端,

代码语言:javascript复制
[root@master ansible]# ansible node1 -m copy -a 'src=/etc/hostname dest=/opt' //将控制主机的hosname

文件拷贝到被控主机的/opt下

3.8. Service 模块

代码语言:javascript复制
功能:管理服务
停止httpd服务:
​[root@master ansible]# ansible node1 -m service -a "name=httpd state=stopped"
开启httpd服务:
​[root@master ansible]# ansible node1 -m service -a "name=httpd state=started"
重新加载httod服务:
​[root@master ansible]# ansible node1 -m service -a "name=httpd state=reloaded"
重启httpd服务:
​[root@master ansible]# ansible node1 -m service -a "name=httpd state=restarted"
开启ftp服务,同时设置开机自动启动:
​[root@master ansible]# ansible node1 -m service -a "name=vsftpd state=started enabled=yes"
重启ftp服务:
​[root@master ansible]# ansible node1 -m service -a "name=vsftpd state=restarted"

3.9. User模块

代码语言:javascript复制
功能:管理用户
添加用户,指定uid、家目录、主组及注释:
[root@master ansible]# ansible node1 -m user -a 'name=user1 comment="test user" uid=2000 home=/home/user1'

3.10. Hostname 模块

代码语言:javascript复制
功能:管理主机名,生效同时更改文件永久生效
[root@master ansible]# ansible node1 -m hostname -a "name=node1.example.com"

由于ansible支持的模块是非常丰富的,上面仅列出了常用的一些模块,还有其他模块可通过ansible-doc 命令来获取。

4. 案例说明

近期某客户基于腾讯云镜(主机安全)进行等保安全基线扫描,发现有上百台云服务器的安全基线不符合客户安全部门的安全需求,需要进行整改,涉及的机器量也比较大,而客户侧人员较少,日常运维常用采用简单脚本方式进行云上运维管理。一开始比较倾向云上的产品进行批量或自动修复,发现比较难找到合适的产品完全吻合,因此这里推荐采用Ansible自动化运维的方式进行批量修复云服务器的安全隐患问题,这里简单列举几项高危风险示例:

序号

风险项

威胁等级

描述

处理建议

1

确保已配置SSH空闲超时间隔

高危

这两个选项ClientAliveInterval和ClientAliveCountMax控制SSH会话超时。当ClientAliveInterval变量被设置,对指定的时间长度没有活动的SSH会话被终止。当ClientAliveCountMax变量被设置,sshd将在每一个客户端发送活动消息ClientAliveInterval的时间间隔。当连续发送的客户端活动消息数没有客户端响应时,ssh会话将终止。

编辑/etc/ssh/sshd_config文件以设置参数: ClientAliveInterval 300 ClientAliveCountMax 0

2

确保SSH MaxAuthTries设置为4或更低

高危

MaxAuthTries参数指定每个连接允许的最大身份验证尝试次数。登录失败次数达到设置参数一半时,错误消息将写入syslog文件,详细说明登录失败。

编辑/etc/ssh/sshd_config文件以设置参数,如下所示:  MaxAuthTries 4

3

确保默认用户umask限制为027或更高

高危

umask默认值确定用户创建的文件的权限。创建文件的用户可以通过chmod命令自行决定使其他人可以读取其文件和目录

编辑/etc/bash.bashrc,/etc/profile文件(以及系统上支持的任何其他Shell的适当文件),并添加或编辑umask参数,如下所示: umask 027

4

确保默认用户shell超时为900秒或更短

高危

默认值TMOUT确定用户的shell超时时间。TMOUT值以秒为单位。

编辑/etc/bashrc,/etc/profile和/etc/profile.d/*.sh文件(以及系统上支持的任何其他Shell的适当文件),并根据站点策略添加或编辑任何TMOUT参数: TMOUT=900

4.1. 案例实现方法1

由于客户侧使用操作系统为:RedHat/CentOS、Ubuntu, 这里采用不同操作系统的yml文件进行。

4.1.1. 针对Ubuntu系统

代码语言:javascript复制
[root@master method1]# cat ubuntu.yml-m1
---
- name: repair system security issue
  hosts: node4
  tasks:
    - name: session timeout
      lineinfile:
        path: /etc/profile
        regexp: '^export TMOUT=600'
        line: export TMOUT=300

    - name: set MaxAuthTries
      lineinfile:
        path: /etc/ssh/sshd_config
        regexp: '^#MaxAuthTries 6'
        line:  MaxAuthTries 4

    - name: set ClientAliveInterval
      lineinfile:
        path: /etc/ssh/sshd_config
        regexp: '^#ClientAliveInterval 0'
        line:  ClientAliveInterval 300

    - name: set ClientAliveCountMax
      lineinfile:
        path: /etc/ssh/sshd_config
        regexp: '^#ClientAliveCountMax 3'
        line:  ClientAliveCountMax 0

    - name: reloaded service
      service:
        name: sshd
        state: reloaded


    - name: set umask1
      lineinfile:
        path: /etc/profile
        regexp: '002'
        line: "umask 027"

    - name: set umask2
      lineinfile:
        path: /etc/bash.bashrc
        regexp: '002'
        line: "umask 027"

4.1.2. 针对centos/rhel机器

代码语言:javascript复制
[root@master method1]# cat centos.yml
---
- name: repair system security issue
  hosts: node1
  tasks:
    - name: session timeout
      lineinfile:
        path: /etc/profile
        regexp: '^export TMOUT=600'
        line: export TMOUT=300

    - name: set MaxAuthTries
      lineinfile:
        path: /etc/ssh/sshd_config
        regexp: '^#MaxAuthTries 6'
        line:  MaxAuthTries 4

    - name: set ClientAliveInterval
      lineinfile:
        path: /etc/ssh/sshd_config
        regexp: '^#ClientAliveInterval 0'
        line:  ClientAliveInterval 300

    - name: set ClientAliveCountMax
      lineinfile:
        path: /etc/ssh/sshd_config
        regexp: '^#ClientAliveCountMax 3'
        line:  ClientAliveCountMax 0

    - name: reloaded service
      service:
        name: sshd
        state: reloaded

4.1.3. 验证效果

代码语言:javascript复制
[root@master ansible]# ansible-playbook ubuntu.yml-m1

[root@master ansible]# ansible-playbook centos.yml

代码语言:javascript复制
root@node4:~# grep MaxAuthTries /etc/ssh/sshd_config
MaxAuthTries 4  
#简单查一下修复情况,符合预期

4.2. 案例实现方法2

第一种实现的方法相对简单与直接,临时用下还不错。针对云上机器量大,第一种方式就不是适用管理大型的项目,第二种方法则采用导入外部文件方式管理playbook

4.2.1. 导入任务文件

这里采用import_tasks 功能将任务文件静态导入playbook中。

代码语言:javascript复制
[root@master ansible]# cat fixsec.yml
---
- name: fix security issue
  hosts: node1,node4
  tasks:
    - name: Centos/RedHat System
      import_tasks: centos.yml
      when: ansible_distribution == "CentOS" or ansible_distribution == "RedHat"


    - name: Centos/RedHat System
      import_tasks: ubuntu.yml
      when: ansible_distribution == "Ubuntu"
[root@master ansible]#

4.2.2. 静态任务内容

代码语言:javascript复制
########### centos/rhel #################
[root@master method2]# cat centos.yml
---
- name: set MaxAuthTries
  lineinfile:
    path: /etc/ssh/sshd_config
    regexp: '^#MaxAuthTries 6'
    line:  MaxAuthTries 4

- name: set ClientAliveInterval
  lineinfile:
    path: /etc/ssh/sshd_config
    regexp: '^#ClientAliveInterval 0'
    line:  ClientAliveInterval 300

- name: set ClientAliveCountMax
  lineinfile:
    path: /etc/ssh/sshd_config
    regexp: '^#ClientAliveCountMax 3'
    line:  ClientAliveCountMax 0

- name: reloaded service
  service:
    name: sshd
    state: reloaded
    
    
########### Ubuntu #################
[root@master method2]# cat ubuntu.yml
---
- name: session timeout
  lineinfile:
    path: /etc/profile
    regexp: '^export TMOUT=600'
    line: export TMOUT=300

- name: set MaxAuthTries
  lineinfile:
    path: /etc/ssh/sshd_config
    regexp: '^#MaxAuthTries 6'
    line:  MaxAuthTries 4

- name: set ClientAliveInterval
  lineinfile:
    path: /etc/ssh/sshd_config
    regexp: '^#ClientAliveInterval 0'
    line:  ClientAliveInterval 300

- name: set ClientAliveCountMax
  lineinfile:
    path: /etc/ssh/sshd_config
    regexp: '^#ClientAliveCountMax 3'
    line:  ClientAliveCountMax 0

- name: reloaded service
  service:
    name: sshd
    state: reloaded

- name: set umask
  lineinfile:
    path: /etc/{{item}}
    regexp: '002'
    line: "umask 027"
  loop:
    - profile
    - bash.bashrc

4.2.3. 执行方法2

代码语言:javascript复制
[root@master ansible]# ansible-playbook fixsec.yml

4.3. 案例实现方法3

案例实现方法3采用通过roles方式进行解决。因在生成环境中, 为了实现不同的功能, 需要编写大量的playbook文件,而且每个playbook还可能会调用其他文件(如变量文件),对于海量的、无规律的文件,管理起来非常痛苦。Roles是管理ansible文件的一种规范(目录结构),roles会按照标准的规范, 自动到特定的目录和文件中读取数据,从而达到实现重复使用。

4.3.1. 初始化角色

Ansible galaxy是官方提供的一个共享roles的平台,这里采用ansible-galaxy初始化角色,让其创建规范的目录结构。Roles目录结构说明

  • defualts/main.yml:定义变量的缺省值,优先级较低
  • files目录:存储静态文件的目录,如tar包、文件等
  • handlers/main.yml:定义handlers,如包含角色的处理程序文件
  • meta/main.yml:写作者、版本等描述信息
  • README.md:整个角色(role)的描述信息
  • tasks/main.yml:定义任务的地方
  • templates目录:存放动态数据文件的地方(文件中包含了变量的模板文件)
  • tests目录:此目录可以包含清单和test.yml playbook 用于测试角色
  • vars/main.yml:定义变量,优先级高
代码语言:javascript复制
[root@master ansible]# ansible-galaxy init roles/ossec
- Role roles/ossec was created successfully
[root@master ansible]# tree roles/ossec/
roles/ossec/
|-- defaults
| `-- main.yml
|-- files
|-- handlers
| `-- main.yml
|-- meta
| `-- main.yml
|-- README.md
|-- tasks
| `-- main.yml
|-- templates
|-- tests
| |-- inventory
| `-- test.yml
`-- vars
 `-- main.yml

4.3.2. 确定sshd配置模板文件与任务

本次高危安全隐患主要是sshd配置不符合等保的安全需求,这里直接将对应不同系统类的sshd_config 制定模板,让其通过roles规范目录结构进行分发,同时也方便后续的灵活改动与复用。

代码语言:javascript复制
[root@master ansible]# tree roles/ossec/
roles/ossec/
|-- defaults
|   `-- main.yml
|-- files
|-- handlers
|   `-- main.yml
|-- meta
|   `-- main.yml
|-- README.md
|-- tasks
|   |-- main.yml
|   `-- main.yml-bak
|-- templates
|   |-- sshd_config_centos.j2 # ssh模板文件
|   `-- sshd_config_ubuntu.j2 # sshd模板文件
|-- tests
|   |-- inventory
|   `-- test.yml
`-- vars
    `-- main.yml
代码语言:javascript复制
[root@master ansible]# cat roles/ossec/tasks/main.yml
---
# tasks file for ossec
- name: deploy ssh_config file on ubuntu
  template:
    src: sshd_config_ubuntu.j2
    dest: /etc/ssh/sshd_config
  when: ansible_distribution == "Ubuntu"


- name: deploy ssh_config file on centos
  template:
    src: sshd_config_centos.j2
    dest: /etc/ssh/sshd_config
  when: ansible_distribution == "CentOS" or ansible_distribution == "RedHat"

- name: reload sshd service based on new config info
  service:
    name: sshd
    state: reloaded

4.3.3. 执行ossec角色

代码语言:javascript复制
[root@master ansible]# cat ossec.yml
---
- name: fix ossec by roles
  hosts: node1,node4 # 如果执行所有被管主机,写被管主机组名即可
  roles:
    - ossec
    

案例方法3实现起来更简洁,更直接,playbook目录结构清晰,可结合生产环境需求对其目录进行相关设定,如4.3.1目录功能说明。

5. 总结

本篇从Ansible定义、功能特点、架构、环境部署、常用模块等,以及结合了真实的案例进行实践说明。关于生产环境的引用,建议根据需求及生产环境的差异进行调整,测试与验证后再大规模的投入使用。

6. 参考资料

  • https://www.ansible.com/
  • https://github.com/ansible/ansible
  • https://www.redhat.com/en/technologies/management/ansible
  • https://ansible-tran.readthedocs.io/en/latest/docs/intro.html

0 人点赞