一、安全概况
对与一台全新安装的服务器,尤其是直接面向公网的服务器来说:最重要的一项配置就是安全配置。
针对非授权连接和截取通信信息等攻击行为,避免攻击手段带来的危害,处理方法有以下方法:
- 使用安全加密的通信方式——使用https加密传输;
- 禁止root用户远程登录并充分利用sudo;
- 移除非必需的软件,只开发需要用到的端口;
- 遵守权限最小化原则;
- 及时更新操作系统和软件——修复旧版本的bug,并使用新版本的最佳性能;
- 使用合理配置过的、有针对性的防火墙;
- 确保日志文件被及时迁移、存放和切割;
- 监测系统登录情况,封掉可疑的IP地址;
- 正确使用SELinux和AppArmor。
二、SSH与远程连接简介
一、Telnet
Telnet协议诞生于20世纪60年代后期,最初被应用到基于TCP协议的大型私有网络之中,默认端口是23号端口。
Telnet是一种文本协议,用于在不同网络间传输数据。Telnet属于底层协议,至今它依然是我们现在使用的很多通信协议的基础,比如HTTP、FTP以及POP3。
随着SSH的到来,Telnet开始逐渐退出远程管理的舞台。
二、SSH
SSH(Secure Shell)诞生于1995年,由芬兰人Tatu Ylonen开发。他看到了文本通信的安全缺陷,这促使他开发一款强加密的远程管理工具——SSH。
SSH的连接加密方式非常类似于HTTP的SSL加密,同时SSH的认证层还增加了更高的安全机制。
三、通信加密
一、为了保证服务器的安全性,我们需要:
- 禁止SSH基于密码登录(禁止密码登录之前,务必确认SSH可以成功秘钥认证登录),使用更为安全的秘钥认证来加密通信
- 禁止root用户远程登录
- 同时改变SSH服务的默认端口号
二、实现功能
1、实现sshd_config.yml文件如下
- hosts: example
tasks:
- name: 修改SSH配置文件的安全选项
lineinfile:
dest: /etc.ssh/sshd_config
regexp: "{{ item.regexp }}"
line: "{{ item.line }}"
state: present
with_items:
- {
regexp: "^PasswordAuthentication",
line: "PasswordAuthentication no"
}
- {
regexp: "^PermitRootLogin",
line: "PermitRootLogin no"
}
- {
regexp: "^Port",
line: "Port 2849"
}
notify: restart ssh
handlers:
- name: restart ssh
service: name=ssh state=restarted
2、实现方法
使用ansible的linefile模块对SSH的三大安全配置选项进行设置,随便使用handler了重启,来使修改生效。
3、需要注意的点
若改变了某些Inentory主机的SSH配置,比如更改了默认的端口号,此时我们需要在ansible的Inventory文件中使用ansible_ssh_port变量明确地为该主机重新指定新配置的端口号。
四、禁止root远程登录
使用lineinfile模块来配置SSH完全禁止使用root用户远程登录。
一、权限控制简介
Linux系统的sudo命令可以让普通用户以root(也可以指定为其他用户)的权限来执行指定命令,这样不仅减少了root用户和管理时间,同样也提高了安全性。sudo命令可以在执行敏感的高权限命令时,更加有针对性,从而减少高权限命令误操作的几率。
ansible本身也提倡尽量使用普通用户来管理主机,只有必须使用root权限的任务中,才使用sudo变量来实现Linux命令行中的sudo功能。
---
- name: Restart Apache.
service: name=httpd state=restarted
sudo: yes
在任务或playbook中可以通过添加sudo_user:[username]关键字来指定sudo后具体以哪个用户的权限来执行操作,而不仅仅是root用户。
需要注意的是:sudo_user关键字必须在有sudo关键字的前提下才生效。
** 二、ansible将普通用户提权**
使用ansible修改sudo的配置文件,使普通用户拥有和root用户一样的权限。
1、实现方式一:使用lineinfile
---
- name: 为普通用户赋予所有root权限
lineinfile:
dest: /etc/sudoers
regexp: '^%wzs'
line: 'wzs ALL=(All) NOPASSWD: ALL'
state: present
使用lininfile模块操作可能达不到预期的效果。所以使用这种方式时,应该认真检查,确保修改后语法的正确性。
更好的更改方式是远程执行visudo命令,更改sudo命令,并防止错误修改造成命令的不可用。
2、实现方式二:ansible主机修改sudo配置文件,使用visudo命令
---
- name: Copy validated sudoers file into place.
copy:
src: sudoers
dest: /etc/sudoers
validate: 'visudo -cf %s'
%s是一个文件路径的占位符,在文件被复制到远程主机之前,他会被替换为src后面的文件。
五、操作系统简介
一、未使用配置文件管理工具的痛点
在配置文件管理工具流行之前,服务器经常会残留一些不再使用的软件服务,以及这些服务所使用的端口。这不仅使服务器变得缓慢臃肿,同时这些开放的端口和老旧的软件都易受到外部攻击,造成潜在风险。
及时关闭服务器上不再需要的服务,卸载不相关的软件,并清理不再需要执行crontab任务,这不仅可以帮助服务器“瘦身”,还可以提高服务器的安全性。
二、使用ansible配置管理
使用ansible来管理维护服务器架构,上面的痛点轻松解决。
1、解决方式:
- 使用事先写好的Playbook或Role快速地部署一台全新的服务器来取代旧服务器。
- 简单地列出一个需要删除的软件列表,利用ansible进行批量卸载。
2、使用ansible批量卸载不需要的软件
---
- name: 卸载不需要的软件
yum: name={{ item }} state=absent purge=yes
with_items:
- apache2
- nano
- php
注意:state不同选项的区别
- present,installed是安装套件,而latest则是指安装最新的套件,也就是会使用 yum mirror 上最新的版本。
- absent, removed 是删除套件,没有什么区别
3、ansible批量操作
1、服务、文件
在ansible中,像yum、apt、file、mysql_db这些模块,他们都有一个相同的选项state,设置其值为absent,可以将指定的任务软件、文件或者数据库删除掉。妥善利用这些功能,可以大大提高运维人员的工作效率,节省大量时间。
2、端口
只开放需要用到的端口,关闭哪些可有可无的端口,将大大减少外部环境对主机的攻击面,同时也会降低防火墙的复杂度。
举例:不加任何限制就对外开放25端口会给外部网络提供大量的主机信息。所以。若你的主机不是一台SMTP服务器的话,务必关闭这个端口。同时,也要确保哪些需要被开启的端口,只能连接依赖的客户端。
六、遵守权限最小化原则
生产环境中,主机上的所有用户、应用以及进程都应该只允许访问他们本身需要访问的信息(文件)和资源(内存、网络等)——一点也不多,一点也不少。
在权限最小化原则实施的过程中,最直接的也是最基本的两个方向:用户权限管理和文件权限管理。
一、用户管理
系统上的每一个新增用户的权限默认都是被适当限制过的。新增用户通常都有一个家目录,且用户对家目录下的所有文件和目录具有最搞权限,但是对于家目录以外的目录与文件的权限都需要重新赋予。
** 为用户新增权限的方法有两种**
- 添加用户到其他用户组中,已继承该用户组的权限
- 为用户开放sudo权限,使得其可以以root或者其他用户的身份来执行命令或者访问文件
二、文件权限管理
ansible中每一个与文件管理相关的模块中都有文件权限管理的选项可用,这些选项包括:owner、group和mode。每一次使用copy、template、file等模块来操作管理文件时,都应该使用这些选项来明确指定文件的权限及其归属。
1、实践:gitlab的配置文件应该只能被root用户读取和修改,其他任何用户都没有权限
---
- name: 设置gitlab配置文件的权限
file:
path: /etc/gitlab/gitlab.rb
owner: root
group: root
mode: 0600
2、配置文件或者目录权限
为了满足用户对某些文件或目录的权限需求,正确的做法是修改文件或目录的权限来适应用户,而不是扩大用户权限来得到某些权限的满足。
例如:web服务器上httpd用户或者Nginx用户对网站文件拥有权限。
七、定期维护更新
服务器每一年所有软件的安全更新有上百次甚至更多。其中有一些是针对修复对系统有严重威胁的漏洞的,若这些漏洞没有及时更新软件或打相应的补丁,将会对系统安全造成严重威胁。
应该定期进行补丁维护和软件更新检查。在对线上生产服务器上的软件打补丁或者更新升级之前,应该在非关键服务器或环境相同的测试服务器上进行测试,在确定没问题的情况下再对线上生产服务器进行操作。
一、手动更新
使用ansible命令对服务器上所有软件更新升级操作。
然而,在有些情况下我们只需实施与安全相关的更新,或者只更新某些软件;在仍需要使用这两个命令的前提下,可以通过修改yum软件和apt软件的配置文件来进行定义。
1、对于RedHat和CentOS等系统来说,使用如下命令
ansible webservers -m yum -a "name=* state=latest"
2、对于Debian和Ubuntu等系统来说,使用如下命令
ansible webservers -m apt -a "upgrade=dist update_cache=yes"
二、自动定时更新
可以在系统上设置每天或每周定时进行软件更新,这样可以使系统更新这一动作更稳定、更有规律地执行下去,从而减少人力成本。
但在现实中,有些环境是不允许机器自动更新软件的,因为自动更新本身蕴含着一些风险。比如:有些软件的最新版确实修正了之前版本的一些不足,但是它的新增功能可能与系统上自己开发的一些程序的兼容性不足,从而使得整个系统不可用。
若你的系统上不存在这些问题,那么使用自动定时更新软件,可以更进一步增加系统安全性。
1、自动更新RedHat系统上的软件
对于RedHat 6及其以后的版本的系统(包括Fedora和CentOS)都可以使用一个叫YUM-cron的软件进行软件包更新管理。其用法很简单,使用yum安全后,保证开机开启就可以了。使用ansible来实现如下即可
---
- name: 安装yum-cron
yum: name=yum-cron state=present
- name: 运行yum-cron并设置开机启动
services: name=yum-cron state=started enabled=yes
更多的配置可以通过修改yum的配置文件/etc/yum.conf
2、自动更新Debian系统上的软件
Debian系统及其衍生版都使用一款名叫unattended-upgrades的软件来实现自动化软件包更新管理,这款软件和前面讲的YUM-cron一样,非常便于安装和配置,并且支持多配置文件,存放于/etc/apt/apt.conf.d/。
---
- name: 安装unattended-upgrades
apt: name=unattended-upgrades state=present
- name: 将配置文件复制到配置目录中
template:
src: "../templates/{{ item }}.j2"
dest: "/etc/apt/apt.conf.d/{{ item }}"
owner: root
group: root
mode: 0644
with_items:
- 10periodic
- 50unattended-upgrades
复制unattended-upgrades配置文件中10periodic的内容如下
APT::Periodic::Update-Package-Lists "1"; //显示更新包列表,0表示停用设置
APT::Periodic::Download-Upgradeable-Packages "1"; //下载更新包,0表示停用设置
APT::Periodic::AutocleanInterval "7"; //7天自动删除
APT::Periodic::Unattended-Upgrade "1"; //启动自动更新,0表示停用自动更新
配置文件50unattended-upgrades的内容如下
Unattended-Upgrade::Automatic-Reboot "false";
Unattended-Upgrade::Allowed-Origins {
"Ubuntu lucid-security";
"Ubuntu lucid-updates;
};
这个配置文件提供了更新配置选项,比如对于那些更新后需要重启服务器才能生效的软件,在更新过这些软件后,是否自动重启服务器,以及在检查更新软件,需要检测那些APT源来查找更新等。
八、iptables防火墙
管理防火墙的工具,比如iptables、ufw以及firewalld等。
一、在Debian及衍生系统,ansible的ufw模块来完成
使用ansible开关闭Debian系统中除了22(SSH)、80(HTTP)、123(NTP)端口以外的其他的所有端口。
1、代码实现
---
- name: 使用ufw模块来管理那些端口需要开启
ufw:
rule: "{{ item.rule }}"
port: "{{ item.port }}"
proto: "{{ item.proto }}"
with_item:
- { rule: 'allow', port: 22, proto: 'tcp' }
- { rule: 'allow', port: 80, proto: 'tcp' }
- { rule: 'allow', port: 123, proto: 'ucp' }
- name: 配置网络进出方向的默认规则
ufw:
direction: "{{ item.direction }}"
policy: "{{ item.policy }}"
state: enabled
with_items:
- { direction: outgoing, policy: allow }
- { direction: incoming, policy: deny }
2、上面playbook任务运行之后,登录对方主机,使用sudo ufw status verbose命令
二、在RedHat及其衍生系统中,我们使用ansible的firewalld模块来管理防火墙
1、代码实现
---
- name: 使用firewalld模块管理端口
firewalled:
state: "{{ item.state }}"
port: "{{ item.port }}"
zone: external
immediate: yes
permanent: yes
with_items:
- { state: 'enabled', port: '22/tcp' }
- { state: 'enabled', port: '80/tcp' }
- { state: 'enabled', port: '123/ucp' }
注意:
1、immediate选项从ansible版本1.9之外开始引入,用来定义规则在配置完成是否立即生效。若使用的是1.9之前的版本的,那么需要重启防火墙来让新规则生效,或者将permanent选项的值设为no。
2、firewalld模块并不能针对网络进出口方向进行管理,但是我们可以借助iptables模块或者直接修改/etc/firewalld目录下的防火墙配置文件来进行配置。
2、查看被放行的端口
sudo firewall-cmd --zone=external --list-all
版权归原作者 happy_king_zi 所有, 如有侵权,请联系我们删除。