天天看点

ansible安全优化篇

一、安全概况

  对与一台全新安装的服务器,尤其是直接面向公网的服务器来说:最重要的一项配置就是安全配置。

  针对非授权连接和截取通信信息等攻击行为,避免攻击手段带来的危害,处理方法有以下方法:

  1. 使用安全加密的通信方式——使用https加密传输;
  2. 禁止root用户远程登录并充分利用sudo;
  3. 移除非必需的软件,只开发需要用到的端口;
  4. 遵守权限最小化原则;
  5. 及时更新操作系统和软件——修复旧版本的bug,并使用新版本的最佳性能;
  6. 使用合理配置过的、有针对性的防火墙;
  7. 确保日志文件被及时迁移、存放和切割;
  8. 监测系统登录情况,封掉可疑的IP地址;
  9. 正确使用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的认证层还增加了更高的安全机制。

  

ansible安全优化篇

三、通信加密

  一、为了保证服务器的安全性,我们需要:

  1. 禁止SSH基于密码登录(禁止密码登录之前,务必确认SSH可以成功秘钥认证登录),使用更为安全的秘钥认证来加密通信
  2. 禁止root用户远程登录
  3. 同时改变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、解决方式:

  1. 使用事先写好的Playbook或Role快速地部署一台全新的服务器来取代旧服务器。
  2. 简单地列出一个需要删除的软件列表,利用ansible进行批量卸载。

  2、使用ansible批量卸载不需要的软件

---
    - name: 卸载不需要的软件
        yum: name={{ item }} state=absent purge=yes
        with_items:
            - apache2
            - nano
            - php      

  注意:state不同选项的区别

  1. present,installed是安装套件,而latest则是指安装最新的套件,也就是会使用 yum mirror 上最新的版本。
  2. absent, removed 是删除套件,没有什么区别

  3、ansible批量操作

    1、服务、文件

  在ansible中,像yum、apt、file、mysql_db这些模块,他们都有一个相同的选项state,设置其值为absent,可以将指定的任务软件、文件或者数据库删除掉。妥善利用这些功能,可以大大提高运维人员的工作效率,节省大量时间。

    2、端口

  只开放需要用到的端口,关闭哪些可有可无的端口,将大大减少外部环境对主机的攻击面,同时也会降低防火墙的复杂度。

  举例:不加任何限制就对外开放25端口会给外部网络提供大量的主机信息。所以。若你的主机不是一台SMTP服务器的话,务必关闭这个端口。同时,也要确保哪些需要被开启的端口,只能连接依赖的客户端。

六、遵守权限最小化原则

  生产环境中,主机上的所有用户、应用以及进程都应该只允许访问他们本身需要访问的信息(文件)和资源(内存、网络等)——一点也不多,一点也不少。

  在权限最小化原则实施的过程中,最直接的也是最基本的两个方向:用户权限管理和文件权限管理。

  一、用户管理

  系统上的每一个新增用户的权限默认都是被适当限制过的。新增用户通常都有一个家目录,且用户对家目录下的所有文件和目录具有最搞权限,但是对于家目录以外的目录与文件的权限都需要重新赋予。

  为用户新增权限的方法有两种

  1. 添加用户到其他用户组中,已继承该用户组的权限
  2. 为用户开放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、查看被放行的端口

sudo firewall-cmd --zone=external --list-all      

继续阅读