ansible自动化:操作系统初始化具体实现

《运维思索:操作系统配置规范化、自动化》一文介绍了对于一台基于安装规范交付的操作系统,还不能够直接用于生产环境,我们还需要进一步的优化,如内核参数、时间同步、排查工具、安全加固等等,保证主机安全的同时、避免因操作系统配置引发的问题。

需求

在此我们将操作系统基于安全、审计、管理等角度出发,进行了一系列优化:

  1. 用户
    服务器使用固定用户,主要为管理用户、应用用户、日志用户。此处可根据堡垒机的系统用户进行分配,避免用户混乱。

  2. 软件源
    安装基础组件需要通过统一的软件源。

  3. 关闭服务
    统一关闭selinux、iptables、sendmail、postfix等无用服务,保证服务的最小化。

  4. 初始目录
    创建固定的初始目录,如应用、日志、备份等目录,可参照《运维思索:目录管理规范的重要性》中的目录规范。

  5. limit及内核参数
    文件句柄、进程数等

  6. DNS及NTP

  7. 环境变量及历史命令记录
    终端超时
    历史命令记录及远程备份

  8. ssh优化
    禁止root登录
    ssh登录慢优化
    修改默认端口

  9. 安全设置
    密码复杂度及长度、禁止ctrl+alt+delete等,可按照具体的安全审计要求自行扩展。

规划

从上述需求来看,我们可以轻松利用ansible playbook来编排实现。但此时请先不要上头,我们还是来按以下场景来规划下:

  • 对于新服务器,我们可以playbook直接执行所有初始化操作;

  • 对于老服务器,我们只需单独执行某个优化即可;

  • playbook需要兼容Centos6、Centos7等多个版本;

因此,我们需要利用playbook的tag功能以及gather_facts获取操作系统版本,现将我们的需求按task进行分类:

vim task/main.yml
- include: user.yml  #用户管理
- include: repo.yml  #yum源
- include: init_pkg.yml  #安装基础组件
- include: profile.yml  #环境变量
- include: selinux.yml  #selinux
- include: dir.yml  #基础目录
- include: limits.yml   #系统参数
- include: iptables.yml  #防火墙
- include: sysctl.yml   #内核参数
- include: rc.local.yml   #开机启动
- include: dns.yml    #dns
- include: ntp.yml    #ntp
- include: rsyslog.yml  #日志同步
- include: sshd.yml  #ssh优化
- include: safe.yml   #安全配置

(1)需要区分操作系统版本号的task,如safe.yml、repo.yml、zabbix_agent.yml、iptables.yml、init_pkg.yml,可以通过gather_facts获取相关信息,并进行以下判断:

when: ansible_distribution_major_version == "7"
或
when: ansible_distribution_major_version == "6"

(2)需要区分功能的task,如safe.yml、user.yml、zabbix-agent.yml等,可以通过tag打上自定义标签,以便后续的个性化执行:

#服务器配置完全化
ansible-playbook -b -e host_ip=10.10.2.10 -v os_init.yml
#通过tag实现单独添加用户
ansible-playbook -b -e host_ip=10.10.2.10 -v os_init.yml -t user
#通过tag实现单独安全配置
ansible-playbook -b -e host_ip=10.10.2.10 -v os_init.yml -t safe

通过以上两种方式,我们就可以通过playbook实现按需订制了,满足以后的多样性需求的优化。

另外,为方便订制,我们还需要提前规划变量,即将在不同场景下将可变参数提取为变量,这样减少了对playbook的侵入,如:

vim vars/main.yml
# zabbix_server地址
zabbix_server_ip: 10.10.2.34
# 系统初始化组
grouplist:
  - name: app
    gid: 500
  - name: log
    gid: 501
# 系统初始用户
userlist:
  - name: app
    pass: sljdoxf
    uid: 500
    groups: wheel
  - name: log
    pass: welsdjf
    groups: wheel
    
  .........

具体实现

1.目录结构

[root@test roles]# tree os_init/
os_init.yl
roles
├───os_init/
├    ├── files
│    │   ├── ansible_key
│    │   │   └── id_rsa.pub
│    │   ├── blueking_key
│    │   │   └── id_rsa.pub
│    │   ├── CentOS6-Base-LAN.repo
│    │   ├── CentOS7-Base-LAN.repo
│    │   ├── client.xml
│    │   ├── deploy_key
│    │   │   └── id_rsa.pub
│    │   ├── epel7-LAN.repo
│    │   ├── zabbix-agent-3.0.14-1.el7.x86_64.rpm
│    │   ├── zabbix-agent-4.2.1-1.el6.x86_64.rpm
│    │   ├── zabbix-release-3.0-1.el7.noarch.rpm
│    │   ├── zabbix-release-4.2-1.el6.noarch.rpm
│    │   ├── zabbix-sender-3.0.14-1.el7.x86_64.rpm
│    │   └── zabbix-sender-4.2.1-1.el6.x86_64.rpm
├    ├── handlers
│    │   └── main.yml
├    ├── tasks
│    │   ├── dir.yml
│    │   ├── dns.yml
│    │   ├── init_pkg.yml
│    │   ├── iptables.yml
│    │   ├── limits.yml
│    │   ├── main.yml
│    │   ├── ntp.yml
│    │   ├── profile.yml
│    │   ├── rc.local.yml
│    │   ├── repo.yml
│    │   ├── rsyslog.yml
│    │   ├── safe.yml
│    │   ├── selinux.yml
│    │   ├── sshd.yml
│    │   ├── sysctl.yml
│    │   ├── user.yml
│    │   └── zabbix_agent.yml
├    ├── templates
│    │   └── sysctl.conf.j2
└    └── vars
        ├── main.yml

2.vars变量


vim vars/main.yml

# zabbix_server地址
zabbix_server_ip: 10.10.2.34
# 系统初始化组
grouplist:
  - name: app
    gid: 500
  - name: log
    gid: 501
# 系统初始用户
userlist:
  - name: app
    pass: sljdoxf
    uid: 500
    groups: wheel
  - name: log
    pass: welsdjf
    groups: wheel

#用户key
sudo_key_user: app
deploy_key_user: log

#软件存放目录
soft_dir: /usr/local/src

#系统初始统一目录
common_directory:
  - /backup/logs
  - /backup/apps
  - /data/logs
  - /app

#Centos7基础工具
centos7_pkgs:
  - vim
  - ntpdate
  - sysstat
  - lrzsz
  - tree
  - telnet
  - wget
  - gzip
  - zip
  - unzip
  - lsof
  - make
  - gcc
  - gcc-c++
  - automake
  - autoconf
  - libtool
  - git
  - openssl
  - openssl-devel
  - cmake
  - net-tools
  - psmisc
  - bash-completion
  - curl
  - rsync
  - bash

#Centos6基础工具
centos6_pkgs:
  - vim
  - ntpdate
  - sysstat
  - lrzsz
  - tree
  - telnet
  - wget
  - gzip
  - zip
  - unzip
  - lsof
  - make
  - gcc
  - gcc-c++
  - automake
  - autoconf
  - libtool
  - git
  - openssl
  - openssl-devel
  - cmake
  - net-tools
  - curl
  - rsync
  - bash

3.task 任务

(1)user.yml

# 用户订制
vim user.yml
- name: add group
  group:
    name: "{
    
    { item.name }}"
    gid: "{
    
    { item.gid }}"
    state: present
  loop: "{
    
    { grouplist }}"
  tags: user

- name: add user 
  user: 
    name: "{
    
    { item.name }}" 
    password: "{
    
    { item.pass | password_hash('sha512') }}"
    uid: "{
    
    { item.uid }}"
    group: "{
    
    { item.group }}"
    groups: "{
    
    { item.groups }}"
    state: present
  loop: "{
    
    { userlist }}"
  tags: user

- name: Set up multiple authorized keys
  authorized_key:
    user: '{
    
    { sudo_key_user }}'
    state: present
    key: '{
    
    { item }}'
  with_file:
    - ansible_key/id_rsa.pub
    - blueking_key/id_rsa.pub
  tags: user

- name: Config /etc/sudoers
  lineinfile: dest=/etc/sudoers state=present  line='{
    
    {item}}' 
  with_items:
    - "{
    
    { sudo_key_user }} ALL=(ALL) NOPASSWD: ALL"
  tags: user

(2)repl.yml


# 修改本地yum源
- name: find repo file
  find:
    path: /etc/yum.repos.d
    patterns: '*.repo'
  register: repo_to_delete
- name: delete repo file
  file:
    path: "{
    
    { item.path }}"
    state: absent
  with_items: "{
    
    { repo_to_delete.files }}"
- name: centos7 yum.repos for lan
  copy: src={
    
    {
    
     item.src_name }} dest=/etc/yum.repos.d/{
    
    {
    
     item.dst_name }} force=yes
  with_items:
    - {
    
     src_name: "CentOS7-Base-LAN.repo", dst_name: "CentOS7-Base-LAN.repo" }
    - {
    
     src_name: "epel7-LAN.repo", dst_name: "epel7-LAN.repo" }
  when: ansible_distribution_major_version == "7"
  tags: centos7_yum_repos

- name: centos6 yum.repos for lan
  copy: src={
    
    {
    
     item.src_name }} dest=/etc/yum.repos.d/{
    
    {
    
     item.dst_name }} force=yes
  with_items:
    - {
    
     src_name: "CentOS6-Base-LAN.repo", dst_name: "CentOS6-Base-LAN.repo" }
  when: ansible_distribution_major_version == "6"
  tags: centos6_yum_repos

(3)init_pkg.yml

# 安装基础包
- name: centos7 init packages install
  yum: name={
    
    {
    
     centos7_pkgs }} update_cache=yes
  #yum: name={
    
    { item }} update_cache=yes
  #with_items: "{
    
    { centos7_pkgs }}"
  when: ansible_distribution_major_version == "7"
  tags: centos7_init_package

- name: centos6 init packages install
  yum: name={
    
    {
    
     centos6_pkgs }} update_cache=yes
  #yum: name={
    
    { item }} update_cache=yes
  #with_items: "{
    
    { centos7_pkgs }}"
  when: ansible_distribution_major_version == "6"
  tags: centos6_init_package

(4)profile.yml

# 环境变量
- name: /etc/profile
  lineinfile: 
    path: /etc/profile
    line: "{
    
    { item }}"
  with_items:
    - "readonly TMOUT=1800"
    - 'export HISTTIMEFORMAT="%F %T # "'
    - "export HISTSIZE=10240"
    - "export PROMPT_COMMAND=\'{ msg=$(history 1 | {
      
       read x y; echo $y; });logger -p local3.notice \"[euid=$(whoami)]\":$(who am i):[`pwd`]\"$msg\"; }\'"
    - 'readonly PROMPT_COMMAND'

(5)selinux.yml

- name: stop selinux
  selinux: state=disabled
  tags: stop_selinux

- name: disable selinux
  replace: path=/etc/selinux/config regexp=^SELINUX=enforcing replace=SELINUX=disabled
  tags: disable_selinux

(6)dir.yml

# 创建统一目录
- name: create directory
  file:
    path: "{
    
    { item }}"
    state: directory
    owner: hcuser
    group: wheel
  with_items: "{
    
    { common_directory }}"

(7)limit.yml

- name: change limits
  lineinfile: path=/etc/security/limits.conf line={
    
    {
    
     item }}
  with_items:
    - "* soft nofile 655350"
    - "* hard nofile 655350"
    - "* soft nproc 65535"
    - "* hard nproc 65535"
  tags: limits

(8)iptables.yml

- name: stop firewalld
  service: enabled=false name=firewalld state=stopped
  when: ansible_distribution_major_version == "7"

- name: stop iptables
  service: enabled=false name=iptables state=stopped
  when: ansible_distribution_major_version == "6"

(9)sysctl.yml

- name: set sysctl.conf
  template:
    src: sysctl.conf.j2
    dest: /etc/sysctl.conf
    backup: yes
  tags: set_sysctl

- name: "sysctl -p"
  command: sysctl -p
  ignore_errors: True
  tags: reload_sysctl

(10)rc.local.yml

- name: chmod +x /etc/rc.d/rc.local
  file: path=/etc/rc.d/rc.local mode=0755

(11)dns.yml

- name:  config dns
  lineinfile:
    path: /etc/resolv.conf
    line: "{
    
    { item }}"
  with_items:
    - "search test.com"
    - "nameserver 10.10.58.2"

(12)ntp.yml

- name: set ntp
  cron: name="time sync for ntp" job="/usr/sbin/ntpdate ntp.test.com && /sbin/hwclock -w" hour="*" state=present
  tags: set_ntp

(13)rsyslog.yml

- name: modify rsyslog.conf
  replace:
    path: /etc/rsyslog.conf
    regexp: 'cron.none'
    replace: 'cron.none;local3.none'
  notify: restart rsyslog
  tags: rsyslog

- name: add rsyslog.conf
  lineinfile: 
    path: /etc/rsyslog.conf
    line: "{
    
    { item }}"
  with_items:
    - "local3.notice @10.164.201.114:514"
    - ':msg, contains, "zabbix" ~'
    - 'authpriv.* @10.164.201.114:514'
  notify: restart rsyslog
  tags: rsyslog

- name: restart rsyslog
  service: enabled=true name=rsyslog state=restarted
  tags: restart rsyslog

(14)zabbix_agent.yml

- name: copy zabbix-agent7 rpm file to server
  copy:
    src: "{
    
    { item }}" 
    dest: "{
    
    { soft_dir }}"
  with_items:
    - "zabbix-agent-3.0.14-1.el7.x86_64.rpm"
    - "zabbix-release-3.0-1.el7.noarch.rpm"
    - "zabbix-sender-3.0.14-1.el7.x86_64.rpm"
  when: ansible_distribution_major_version == "7"
  tags: zabbix-agent

- name: install rpm
  yum:
    #name: ['/usr/local/src/zabbix-agent-3.0.14-1.el7.x86_64.rpm', '/usr/local/src/zabbix-release-3.0-1.el7.noarch.rpm', '/usr/local/src/zabbix-sender-3.0.14-1.el7.x86_64.rpm']
    name: ['{
    
    { soft_dir }}/zabbix-agent-3.0.14-1.el7.x86_64.rpm', '{
    
    { soft_dir }}/zabbix-release-3.0-1.el7.noarch.rpm', '{
    
    { soft_dir }}/zabbix-sender-3.0.14-1.el7.x86_64.rpm']
    state: present
  when: ansible_distribution_major_version == "7"
  tags: zabbix-agent

- name: copy zabbix-agent6 rpm file to server
  copy:
    src: "{
    
    { item }}" 
    dest: "{
    
    { soft_dir }}"
  with_items:
    - "zabbix-agent-4.2.1-1.el6.x86_64.rpm"
    - "zabbix-release-4.2-1.el6.noarch.rpm"
    - "zabbix-sender-4.2.1-1.el6.x86_64.rpm"
  when: ansible_distribution_major_version == "6"
  tags: zabbix-agent

- name: install rpm
  yum:
    #name: ['/usr/local/src/zabbix-agent-3.0.14-1.el7.x86_64.rpm', '/usr/local/src/zabbix-release-3.0-1.el7.noarch.rpm', '/usr/local/src/zabbix-sender-3.0.14-1.el7.x86_64.rpm']
    name: ['{
    
    { soft_dir }}/zabbix-agent-4.2.1-1.el6.x86_64.rpm', '{
    
    { soft_dir }}/zabbix-release-4.2-1.el6.noarch.rpm', '{
    
    { soft_dir }}/zabbix-sender-4.2.1-1.el6.x86_64.rpm']
    state: present
  when: ansible_distribution_major_version == "6"
  tags: zabbix-agent
- name: change /etc/zabbix/zabbix_agentd.conf
  lineinfile: path=/etc/zabbix/zabbix_agentd.conf regexp={
    
    {
    
     item.conf_item }} line={
    
    {
    
     item.conf_value }} backrefs=yes
  with_items:
    - {
    
     conf_item: "^Server=127.0.0.1", conf_value: "Server={
    
    { zabbix_server_ip }}" }
    - {
    
     conf_item: "^ServerActive=127.0.0.1", conf_value: "ServerActive={
    
    { zabbix_server_ip }}" }
    - {
    
     conf_item: "^Hostname=Zabbix server", conf_value: "Hostname={
    
    { host_ip }}" }
  notify: restart zabbix-agent
  tags: zabbix-agent

- name: restart zabbix-agent
  service: name=zabbix-agent enabled=true state=restarted
  tags: zabbix-agent

(15)safe.yml

# 禁止control-alt-delete
- name: Centos7 ban control-alt-delete
  file:
    path: /usr/lib/systemd/system/ctrl-alt-del.target
    state: absent
  when: ansible_distribution_major_version == "7"
  tags: safe

# 禁止control-alt-delete
- name: Centos6 ban control-alt-delete
  lineinfile:
    path: /etc/init/control-alt-delete.conf
    regexp: "start on control-alt-delete"
    line: "#start on control-alt-delete"
  when: ansible_distribution_major_version == "6"
  tags: safe

# 密码过期时间
- name: set authentication rule
  lineinfile:
    path: /etc/login.defs
    regexp: "{
    
    { item.regexp_string }}"
    line: "{
    
    { item.rule }}"
  with_items:
    - {
    
     regexp_string: "^PASS_MAX_DAYS", rule: "PASS_MAX_DAYS   90"}
    - {
    
     regexp_string: "^PASS_MIN_DAYS", rule: "PASS_MIN_DAYS   0"}
    - {
    
     regexp_string: "^PASS_MIN_LEN", rule: "PASS_MIN_LEN   5"}
    - {
    
     regexp_string: "^PASS_WARN_AGE", rule: "PASS_WARN_AGE   10"}
  tags: safe
 
 # 关闭无用服务
- name: os close service
  service:
    name: "{
    
    { item }}"
    state: stopped 
    enabled: no
  with_items:
    - "httpd"
    - "postfix"
    - "sendmail"
  ignore_errors: yes
  tags: safe

注意:在密码过期策略之前创建的用户不受过期策略限制,但是在密码过期策略之后创建的用户则会受限
(16)ssh.yml

 - name: set sshd_config
  replace: path=/etc/ssh/sshd_config regexp={
    
    {
    
     item.regexp }} replace={
    
    {
    
     item.replace }}
  with_items:
#    - { regexp: "#Port 22", replace: "Port 1022" }
    - {
    
     regexp: "#UseDNS yes", replace: "UseDNS no" }
    - {
    
     regexp: "#PermitRootLogin yes", replace: "PermitRootLogin no" }
    - {
    
     regexp: "GSSAPIAuthentication yes", replace: "GSSAPIAuthentication no" }
  notify: restart sshd
  tags: ssh

 - name: restart sshd
  service: enabled=true name=sshd state=restarted
  tags: restart_sshd

注意:请最后执行ssh.yml,由于进行了ssh优化,一旦过程中有问题,会导致root无法登录。

4.templates 模板

# 内核参数优化使用
kernel.sysrq = 1
vm.swappiness = 0
kernel.threads-max = 655350
kernel.pid_max = 65535
vm.max_map_count = 131070
net.ipv4.tcp_fin_timeout = 30
net.ipv4.neigh.default.gc_stale_time=120
net.ipv4.conf.all.rp_filter=0
net.ipv4.conf.default.rp_filter=0
net.ipv4.ip_local_port_range = 1024 65535
net.ipv4.tcp_max_tw_buckets = 5000
net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_max_syn_backlog = 131072
net.ipv4.tcp_synack_retries = 2
net.ipv4.tcp_tw_recycle = 0
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_timestamps = 1
net.ipv4.tcp_keepalive_time = 1200
net.ipv4.tcp_keepalive_intvl = 15
net.ipv4.tcp_keepalive_probes = 3
net.ipv4.tcp_max_orphans = 65536
net.ipv4.tcp_rmem = 4096 87380 6291456
net.ipv4.tcp_wmem = 4096 16384 4194304
net.ipv6.conf.all.disable_ipv6 = 1
net.ipv6.conf.default.disable_ipv6 = 1
net.ipv6.conf.lo.disable_ipv6 = 1

5.handlers

- name: restart sshd
  service: name=sshd state=restarted
- name: restart rsyslog
  service: name=rsyslog state=restarted
- name: restart zabbix-agent
  service: name=zabbix-agent state=restarted

6.files

files目录中主要存放task所有需要的源文件。

执行

#服务器配置完全化
ansible-playbook -b -e host_ip=10.10.2.10 -v os_init.yml
#通过tag实现单独添加用户
ansible-playbook -b -e host_ip=10.10.2.10 -v os_init.yml -t user
#通过tag实现单独安全配置
ansible-playbook -b -e host_ip=10.10.2.10 -v os_init.yml -t safe

总结

经过playbook的编排,我们实现了基于《操作系统安装规范》、《操作系统配置规范》、《目录管理规范》等的操作自动化。此过程中最重要的不是playbook的具体实现,而是我们怎样去根据规范去有目的的去配置。

猜你喜欢

转载自blog.csdn.net/yanggd1987/article/details/119521551