《运维思索:操作系统配置规范化、自动化》一文介绍了对于一台基于安装规范交付的操作系统,还不能够直接用于生产环境,我们还需要进一步的优化,如内核参数、时间同步、排查工具、安全加固等等,保证主机安全的同时、避免因操作系统配置引发的问题。
需求
在此我们将操作系统基于安全、审计、管理 等角度出发,进行了一系列优化:
-
用户 服务器使用固定用户,主要为管理用户、应用用户、日志用户。此处可根据堡垒机的系统用户进行分配,避免用户混乱。 -
软件源 安装基础组件需要通过统一的软件源。 -
关闭服务 统一关闭selinux、iptables、sendmail、postfix等无用服务,保证服务的最小化。 -
初始目录 创建固定的初始目录,如应用、日志、备份等目录,可参照《运维思索:目录管理规范的重要性》中的目录规范。 -
limit及内核参数 文件句柄、进程数等 -
DNS及NTP -
环境变量及历史命令记录 终端超时 历史命令记录及远程备份 -
ssh优化 禁止root登录 ssh登录慢优化 修改默认端口 -
安全设置 密码复杂度及长度、禁止ctrl+alt+delete等,可按照具体的安全审计要求自行扩展。
规划
从上述需求来看,我们可以轻松利用ansible playbook来编排实现。但此时请先不要上头,我们还是来按以下场景来规划下:
因此,我们需要利用playbook的tag功能以及gather_facts获取操作系统版本,现将我们的需求按task进行分类:
vim task/main.yml
- include: user.yml
- include: repo.yml
- include: init_pkg.yml
- include: profile.yml
- include: selinux.yml
- include: dir.yml
- include: limits.yml
- include: iptables.yml
- include: sysctl.yml
- include: rc.local.yml
- include: dns.yml
- include: ntp.yml
- include: rsyslog.yml
- include: sshd.yml
- 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
ansible-playbook -b -e host_ip=10.10.2.10 -v os_init.yml -t user
ansible-playbook -b -e host_ip=10.10.2.10 -v os_init.yml -t safe
通过以上两种方式,我们就可以通过playbook实现按需订制了,满足以后的多样性需求的优化。
另外,为方便订制,我们还需要提前规划变量,即将在不同场景下将可变参数提取为变量,这样减少了对playbook的侵入,如:
vim vars/main.yml
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]
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_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
sudo_key_user: app
deploy_key_user: log
soft_dir: /usr/local/src
common_directory:
- /backup/logs
- /backup/apps
- /data/logs
- /app
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_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
- 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
when: ansible_distribution_major_version == "7"
tags: centos7_init_package
- name: centos6 init packages install
yum: name={{ centos6_pkgs }} update_cache=yes
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: ['{{ 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: ['{{ 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
- 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
- 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: "#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
ansible-playbook -b -e host_ip=10.10.2.10 -v os_init.yml -t user
ansible-playbook -b -e host_ip=10.10.2.10 -v os_init.yml -t safe
总结
经过playbook的编排,我们实现了基于《操作系统安装规范》、《操作系统配置规范》、《目录管理规范》等的操作自动化。此过程中最重要的不是playbook的具体实现,而是我们怎样去根据规范去有目的的去配置。
|