教程:安全手册(第二部分)

关于教程的注意事项:我们鼓励用户尝试教程,但是我们的团队并不完全支持我们 – 当出现问题时,我们不能总是提供支持。在继续之前,请务必检查其测试的操作系统和版本。如果您遇到问题,请发表评论,我们会尽力帮助。

如果您想要一个完全管理的体验,专门支持您可能想要运行的任何应用程序,请联系我们获取更多信息。

上次,我们开始构建一个更为复杂的可复制的安全手册。我们通过一些简单但合乎逻辑的编辑,使SSH变得更加强硬/etc/ssh/sshd_config,但是我们还可以做更多的工作来改进剧本的即时功能。

如果您还没有看到本教程系列的第一部分,请先跳过该手册,以了解有关Playbook功能的基本结构:教程:安全手册(第二部分)

总而言之,让我们开始吧。

步骤6.创建iptables / tasks / main.yml

使用Ansible 2.0,有一个内置的iptables模块,可以让我们创建规则,而不必依靠运行plain bash命令。这真的很方便,但不是很好的记录,可悲的是。但在我们达成这些规则之前,让我们在铺设基础上进行实地考察。

- name: Install the `iptables` package
 package:
 name: iptables
 state: latest

使用该package模块是现在熟悉的领域 – 我们只是iptables安装的双重检查。

下面开始:

- name: Flush existing firewall rules
 iptables:
 flush: true

我们使用iptables Ansible模块的第一个例子,只是为了刷新可能存在的任何现有规则。

现在,创建规则:

- name: Firewall rule - allow all loopback traffic
 iptables:
 action: append
 chain: INPUT
 in_interface: lo
 jump: ACCEPT

我们首先要允许现在或将来可能在VPS上运行的各种应用程序和服务之间可能存在的任何环回流量。我们现在可以看到我们如何指定chain,可以设置为任何内置的链iptables:“INPUT”,“FORWARD”,“OUTPUT”,“PREROUTING”,“POSTROUTING”,“SECMARK”,“CONNSECMARK ”。该jump参数是我们指定了我们希望与希望的链和我们接口匹配的流量做ACCEPT这个业务,但我们也可以REJECT和DROP它。

为方便起见,我们也希望允许建立连接。

- name: Firewall rule - allow established connections
 iptables:
 chain: INPUT
 ctstate: ESTABLISHED,RELATED
 jump: ACCEPT

这是我们的第一个(也是唯一)的ctstate参数的味道,可以用来创建一些更复杂的规则。

现在,让我们来看看多汁的位 – 允许在某些端口上的特定类型的通信,通常是VPS上想要的。

- name: Firewall rule - allow port ping traffic
 iptables:
 chain: INPUT
 jump: ACCEPT
 protocol: icmp

- name: Firewall rule - allow port 22/SSH traffic
 iptables:
 chain: INPUT
 destination_port: 22
 jump: ACCEPT
 protocol: tcp

- name: Firewall rule - allow port 80/HTTP traffic
 iptables:
 chain: INPUT
 destination_port: 80
 jump: ACCEPT
 protocol: tcp

- name: Firewall rule - allow port 443/HTTPS traffic
 iptables:
 chain: INPUT
 destination_port: 443
 jump: ACCEPT
 protocol: tcp

使用icmp协议的第一个示例允许您ping像往常一样运行您的服务器 – 如果您不允许icmp流量,您的ping将被丢弃或拒绝。

对于其他三个项目,我们只是允许某些目标端口基于人们通常希望在其VPS:端口22上启用的流行服务,用于SSH流量; 端口80,用于HTTP流量; 端口433,用于HTTPS流量。没有这些例外,您会发现许多VPS应用程序将无法正常工作。

现在您已经知道如何根据需要打开端口,您可以根据需要对您的手册进行自定义。

最后,让防火墙有能力做最好的事情:阻止流量。

- name: Firewall rule - drop any traffic without rule
 iptables:
 chain: INPUT
 jump: DROP

与此规则的唯一区别在于使用jump参数DROP,我们只是阻止到达任何端口的流量,并通过任何使用上述规则未打开的协议。您还可以设置jump到REJECT,这将返回关于端口不可达消息。

最后,我们希望在服务器重新启动之间保持这些新规则。这是在Ubuntu和基于Debian的VPS上执行此操作的方法。

- name: Install `netfilter-persistent` && `iptables-persistent` packages
 package:
 name: "{{item}}"
 state: present
 with_items:
 - iptables-persistent
 - netfilter-persistent
 when: ansible_os_family == "Debian"

我们使用相同的旧package模块在这里,结合一个with_items列表,同时安装iptables-persistent和netfilter-persistent。这似乎是在Ubuntu上做的伎俩,因此使用when: ansible_os_family == “Ubuntu”。

步骤7.创建fail2ban / tasks / main.yml

接下来,我们想要快速设置,fail2ban以帮助阻止对我们的服务器的暴力攻击。

- name: Install the `fail2ban` package
 package:
 name: fail2ban
 state: latest

- name: Override some basic fail2ban configurations
 copy:
 src: ../templates/jail.local.j2
 dest: /etc/fail2ban/jail.local
 owner: root
 group: root
 mode: 0644

在这里,我们正在使用该package模块进行安装fail2ban。完成该操作后,我们要为运行建立一些自定义配置fail2ban。为了达到这个目的,我们要复制一个保留在playbook结构内的文件/etc/fail2ban/jail.local。copy除了建立正确的所有权和权限之外,该模块还允许我们做到这一点。

什么是jail.local文件?那么,fail2ban/templates/jail.local.j2在下面创建一个新文件并粘贴到以下内容中:

[DEFAULT]
# Ban hosts for one hour:
bantime = 3600

# Override /etc/fail2ban/jail.d/00-firewalld.conf:
banaction = iptables-multiport

[sshd]
enabled = true
maxretry = 3

所有这些配置都是确保fail2ban使用iptables,并启用该工具sshd。您可以使用这些设置进行更多操作,您可以通过官方文档进行探索。

第八步奖金!启用无人值守升级

我们快速回到我们的roles/packages/tasks/main.yml文件中配置无人参与的升级,这将有助于使服务器更安全一些。

以下是我们添加到packages角色的内容:

- name: Install the `unattended-upgrades` package
 package:
 name: unattended-upgrades
 state: installed
 when: ansible_os_family == "Debian"

- name: Copy the `20auto-upgrades` configuration file
 copy:
 src: ../templates/20auto-upgrades.j2
 dest: /etc/apt/apt.conf.d/20auto-upgrades
 owner: root
 group: root
 mode: 0644
 when: ansible_os_family == "Debian"

首先,我们正在安装unattended-upgrades,然后复制一个配置文件tasks/packages/templates/20auto-upgrades.j2。那个文件里面有什么?

APT::Periodic::Update-Package-Lists "1";
APT::Periodic::Unattended-Upgrade "1";

只需要启用该过程所需的准系统选项。同样,此配置可实现自动安全升级,但在这些更新需要时,不会自动重新启动服务器。如果您想要进一步了解其他一些选项,则/etc/apt/apt.conf.d/50unattended-upgrades您的VPS有详细的记录,可以根据您的具体需求进行重新配置。

向前!

该剧本现在是“完成”!自然地,还有更多的可以做到这一点,以改进这个手册的功能,包括更好地支持更多的操作系统选项。在接下来的几个星期里,我将会更新这两个文章,当内置这些支持时,我会根据需要更新这两篇文章。另外还有就是自动安装Docker,记录软件等等。

我把完整的手册放在GitHub上,这样你就可以轻松地看到整个结构,以防万一你一直困惑着。或者,您可以简单地克隆资源库并拥有它。

$ git clone https://github.com/joelhans/ssdnodes-ansible-provision.git

如果您想查看添加的任何功能,或者有关如何将此手册放在一起的问题,请随时通过评论或电子邮件通知我。很高兴在GitHub上采取问题和/或提出请求!

教程:安全手册(第一部分)

关于教程的注意事项:我们鼓励用户尝试教程,但是我们的团队并不完全支持我们 – 当出现问题时,我们不能总是提供支持。在继续之前,请务必检查其测试的操作系统和版本。如果您遇到问题,请发表评论,我们会尽力帮助。

如果您想要一个完全管理的体验,专门支持您可能想要运行的任何应用程序,请联系我们获取更多信息。

在我们最后的可以安全的教程中,我们介绍了Ansible的配置管理方法的基础知识,可以帮助您更快地设置新的服务器并提供更高的可靠性。我们在那里创建的可靠的手册是相当基本的,所以我认为是时候建立一个更复杂的手册,支持更多的安全性,而不是牺牲通过通常的方式访问服务器。

这个“安全”课程的目标是:

使用sudo访问设置非root用户。
升级所有安装的软件包
安装几个基本软件包,使初始管理更容易,如nano。这些可以根据您的需要轻松定制。
将您的SSH密钥复制到VPS以启用无密码登录。
硬化SSH具有一些基本的安全措施,例如禁用root和基于密码的登录。
iptables如果需要安装,并设置一些基本限制,以提高安全性。
安装fail2ban以防止暴力攻击。
最后两个步骤将在下周在本Ansys教程的第二部分中概述。

这个剧本不是全面的,当涉及到便利性或安全性 – 一旦你使用这个手册提供服务器,你应该可以研究一些额外的步骤,你可以采取,如使用Lynis审计您的安全。

这里的目标不仅仅是让您在此处复制代码并重新创建自己的手册 – 而是逐步介绍各种组件,以便您可以使用本手册作为自己的自定义设置的基础。

要求:

运行我们的任何操作系统选项的新配置或重建服务器 – CentOS,Debian或Ubuntu。
可以安装在本地机器上 – 有关详细信息,请参阅这些说明
使用您的服务器的IP设置的可安装主机文件 – 请参阅我们上一个教程的步骤2
步骤1.设置playbook结构

可以通过多种不同的方式构建可读的剧本,但是开发者们也有其建议。这个Anisble脚本与系统的可能性相比还是比较简单的,所以我们的结构也会变得简单得多。

以下是我们的一般结构:

provision.yml

roles
 common/
 tasks/
 main.yml
 ssh
 tasks/
 main.yml
 packages
 tasks/
 main.yml
 iptables
 tasks/
 main.yml

如果你愿意,你可以继续创建目录,只是为了让你更好地了解如何将其逻辑分为不同的区域。

步骤2.创建provisioning.yml

该provision.yml文件是我们的Playbook的核心 – 它是我们定义哪些服务器,我们将要使用的几个全局变量,并告诉可以在哪里查找其任务。

---
- name: Provision a new server with hardened SSH and basic iptables.

# Specify the hosts you want to target
 hosts: <b>HOST</b>

# Specify the user you want to connect to the server.
 # With a new installation, you will connect with `root`. If you want to
 # re-run this playbook at a later date, you should change `remote_user` to
 # the user you specified under `vars/username` below and uncomment the
 # `become: true` line. You should then run the playbook using the
 # `--ask-become-pass` flag, like so:
 # `ansible-playbook -k provision.yml --ask-become-pass`.
 remote_user: root
 # become: true

vars:
 username: <b>USER</b>
 # Before first using the playbook, run the below command to create a hashed
 # password that Ansible will assign to your new user.
 # python -c 'import crypt; print crypt.crypt("<b>password</b>", "$1$<b>SALT</b>$")'
 password: <b>PASSWORD GOES HERE</b>
 public_key: ~/.ssh/id_rsa.pub

roles:
 - user
 - packages
 - ssh
 - iptables

您需要根据需要更改许多变量。

步骤3.创建用户/任务/ main.yml

我们的第一个主要步骤是为新的非root用户设置正确的环境,然后创建该用户。这是第一个组件:

- name: Ensure wheel group is present
 group:
 name: wheel
 state: present

这个可执行的任务是一个简单的任务:它检查wheel您的服务器上是否存在该组。如果它不是由于某种原因 – 它应该在我们的所有操作系统选项上 – 剧本将失败,然后您可以用groupadd命令修复它。

下一步是关键的一步,所以让我们来看看:

- name: Ensure wheel group has sudo privileges
 lineinfile:
 dest: /etc/sudoers
 state: present
 regexp: "^%wheel"
 line: "%wheel ALL=(ALL:ALL) ALL"
 validate: "/usr/sbin/visudo -cf %s"

这是使用正则表达式替换文本中的一行与不同文本字符串的示例。我们正在查看/etc/sudoers文件内部,并请求开始(^)的行%wheel。当找到该行时,我们将整个行替换为%wheel ALL=(ALL:ALL) ALL允许wheel组中的用户执行命令sudo。在编辑方面/etc/sudoers,最后validate一行是至关重要的,因为您不喜欢由于不正确的文件而导致剧本失败而不是破坏管理员功能。

我们也想确保sudo软件包安装好了。

- name: Install the `sudo` package
 package:
 name: sudo
 state: latest

安装任何软件包,无论是CentOS,Ubuntu还是Debian,都以完全相同的方式运行。这就是Ansible的美丽 – 你可以创建一个任务,因为内置的逻辑工作。

最后,我们创建在其中的变量中指定的非root用户帐户provision.yml。

- name: Create the non-root user account
 user:
 name: ""
 password: ""
 shell: /bin/bash
 update_password: on_create
 groups: wheel
 append: yes

append: yes

此任务将使用您创建的散列密码设置用户,并将shell设置为/bin/bash。因为我们把这个用户放在wheel组里,我们可以直接使用sudo。

步骤4.创建packages / tasks / main.yml

该packages任务非常简单:我们只想更新所有软件包,以便我们拥有最新的安全修复程序,然后根据我们的具体需求安装多个额外的软件包。

- name: Upgrading all packages (Ubuntu/Debian)
 apt:
 upgrade: dist
 when: ansible_os_family == "Debian" or ansible_os_family == "Ubuntu"

- name: Upgrading all packages (CentOS)
 yum:
 name: '*'
 state: latest
 when: ansible_os_family == "RedHat"

这两个任务的关键是when选项 – 这允许您指定何时根据您选择的操作系统运行某些命令。这是必要的,因为yum在Ubuntu上不起作用,apt不能在CentOS上工作。在这两种情况下,我们只是要求相应的软件包管理器更新每个安装的软件包。

我们还可以安装其他软件包:

- name: Install a few more packages
 package:
 name: "{{item}}"
 state: installed
 with_items:
 - vim
 - htop

本质上,我们要求package任务查看下面的项目列表with_items,然后依次安装它们。如果您想要一些自己的软件包,只需将该列表自定义为您的内容。

步骤5.创建ssh / tasks / main.yml

接下来,我们要启用使用SSH密钥登录到新创建的用户,而不是密码 – 这是简单而有效的安全措施。除此之外,我们希望使用Ansible对SSH守护进程进行一些配置更改,这将使其不会受到一些基本攻击。这不是万无一失的,但它肯定是高于默认值的一大步。

- name: Add local public key for key-based SSH authentication
 authorized_key:
 user: ""
 state: present
 key: ""

此命令在本地机器上在该vars部分中指定的位置查找SSH密钥provision.yml,然后将其复制到服务器。比使用更容易ssh-copy-id吗?

接下来,让我们使SSH更安全一些。

- name: Harden sshd configuration
 lineinfile:
 dest: /etc/ssh/sshd_config
 regexp: "{{item.regexp}}"
 line: "{{item.line}}"
 state: present
 with_items:
 - regexp: "^#?PermitRootLogin"
 line: "PermitRootLogin no"
 - regexp: "^^#?PasswordAuthentication"
 line: "PasswordAuthentication no"
 - regexp: "^#?AllowAgentForwarding"
 line: "AllowAgentForwarding no"
 - regexp: "^#?AllowTcpForwarding"
 line: "AllowTcpForwarding no"
 - regexp: "^#?MaxAuthTries"
 line: "MaxAuthTries 2"
 - regexp: "^#?MaxSessions"
 line: "MaxSessions 2"
 - regexp: "^#?TCPKeepAlive"
 line: "TCPKeepAlive no"
 - regexp: "^#?UseDNS"
 line: "UseDNS no"
 - regexp: "^#?AllowAgentForwarding"
 line: "AllowAgentForwarding no"

在lineinfile和regexp应该熟悉你在这一点上,与在修改/etc/sudoers,我们正在寻找/etc/ssh/sshd_config和更换一批以新的现有生产线的。如果这些行当前不存在,则Ansible将在包含我们的修订版本的文件的底部创建新行。在^#?正则表达式使我们能够取代线是否他们注释掉,从而与一个开始#。

最后,让我们拥有SSD守护进程,以确保我们的更改已被应用。

- name: Restart sshd
 systemd:
 state: restarted
 daemon_reload: yes
 name: sshd

这个systemd任务允许我们运行相当于systemd restart sshd。

最后的想法

如上所述,我们在这里暂停一会儿,并将从本教程的下半部分返回一个星期,这将通过一个基本的iptables配置和安装fail2ban。

但是,在此期间,你现在可以运行这个剧本和更高版本。这是一个正确配置的可疑剧本的好东西 – 它们是幂等的,这意味着它们可以一次又一次地运行,而不会改变超出初始安装的结果。你可以运行一下这个playbook,做一个小小的变化,比如添加另外一个package来安装这个packages角色,然后再运行一下这个playbook,没有错误。

一旦你把所有的东西都运行起来,你如何实际运行这个剧本?这很简单

生成一个散列密码。您首先需要将非root用户所需的密码转换为散列密码。该命令应该在Linux和OS X上工作,并确保password用您选择的密码替换:python -c ‘import crypt; print crypt.crypt(“password”, “$1$AnsibleSalt$”)’。

复制你的新哈希provision.yml。

运行Ansible。通过一个简单的命令,运行本书本身就是直截了当的:$ ansible-playbook -k provision.yml

如果您需要在第一次运行后重新运行该手册,您需要对provision.yml上述代码(以及您创建的版本)进行一些更改,以获取一些基本说明。

请继续关注后期的教程,以及您需要在自己的服务器上运行此剧本的完整代码,并使之更快地工作。

教程:服务器的入门和可配置管理

在本教程中,我们将介绍如何使用Ansible作为CM工具来设置一个基本的访问和服务器硬件工具和设置的CentOS,Debian和Ubuntu服务器。

我们的目标:

  1. 设置非root用户
  2. 给新用户sudo访问
  3. 禁用基于密码的登录
  4. 禁用

要求:

运行我们的任何操作系统选项的新配置或重建服务器 – CentOS,Debian或Ubuntu。

步骤1:在本地机器上安装可执行文件

在开始编写可执行的手册之前,您需要将其安装在本地机器上。有各种平台的安装说明,包括各种* nix发行版和OS X.

步骤2:编辑可安装的主机文件

为了使Ansible连接到VPS,您需要在Ansible的hosts文件中指定其IP地址。在Linux和OS X机器上可以找到/etc/ansible/hosts。文件的开头应该是这样的。

# This is the default ansible 'hosts' file.
 #
 # It should live in /etc/ansible/hosts
 #
 # - Comments begin with the '#' character
 # - Blank lines are ignored
 # - Groups of hosts are delimited by [header] elements
 # - You can enter hostnames or ip addresses
 # - A hostname/ip can be a member of multiple groups

# Ex 1: Ungrouped hosts, specify before any group headers.

green.example.com
 ## blue.example.com
 ## 192.168.100.1
 ## 192.168.100.10

要启用您的服务器,只需将IP地址添加到此文件中的任何位置,即[ssdnodes]分组。应该没有其他符号,如#评论一样。

[ssdnodes]
 123.45.67.89

现在,通过ping你的服务器测试你的配置。现在,您必须使用它-u root来确保您尝试通过root帐户进行连接。

$ ansible all -m ping -u root

如果成功,您将看到以下输出:

123.45.67.89 | SUCCESS => {
 "changed": false,
 "ping": "pong"
 }

步骤3:创建一个基本的可复制的剧本

为了使上述任何一个目标成为现实,我们需要创建一个可靠的手册来定义我们需要完成的任务。The Ansible playbook是一种通用.yaml语言。

$ mkdir ansible && cd ansible
 $ touch create_user.yaml
 $ nano create_user.yaml

这是一个完成我们目标的基本手册。注意:本手册旨在在裸机CentOS 7服务器上运行。如果要在Ubuntu / Debian服务器上运行,只需更改yum行apt。

---
 - hosts: ssdnodes
 remote_user: root

vars_prompt:

- name: "user_name"
 prompt: "Enter a name for the new user"
 private: no
 confirm: yes

- name: "user_password"
 prompt: "Enter a password for the new user"
 private: yes
 encrypt: "sha512_crypt"
 confirm: yes
 salt_size: 7

tasks:

- name: Check to make sure we have a 'wheel' group
 group:
 name: wheel
 state: present

- name: Install the 'sudo' package
 yum:
 name: sudo
 state: latest

- name: Create the non-root user
 user:
 name: ""
 password: ""
 shell: "/bin/bash"
 groups: "wheel"

- name: Add local public key for key-based SSH authentication
 authorized_key:
 user: ""
 key: "{{item}}"
 with_file:
 - ~/.ssh/id_rsa.pub

- name: Restrict root SSH logins
 lineinfile:
 dest: /etc/ssh/sshd_config
 state: present
 regexp: '^#PermitRootLogin'
 line: 'PermitRootLogin no'

- name: Restrict SSH logins to keys only
 lineinfile:
 dest: /etc/ssh/sshd_config
 state: present
 regexp: '^#PasswordAuthentication'
 line: 'PasswordAuthentication no'

- name: Restart sshd
 systemd:
 state: restarted
 daemon_reload: yes
 name: sshd

在我们介绍你如何运行这个命令之前,让我们来看一下这些行在实践中所做的一切。

- hosts: ssdnodes
 remote_user: root

这两行决定了我们将要使用的主机组 – 在这种情况下,ssdnodes我们之前创建的组,并指定我们正在使用根登录(只需一次)来完成我们的步骤。

vars_prompt:

- name: "user_name"
 prompt: "Enter a name for the new user"
 private: no
 confirm: yes

- name: "user_password"
 prompt: "Enter a password for the new user"
 private: yes
 encrypt: "sha512_crypt"
 confirm: yes
 salt_size: 7

这两个vars_prompt命令将要求用户输入来定义他们想要与新创建的帐户相关联的用户名和密码。

除此之外,开始的每个嵌套的脚本块都- name:定义了一个新任务,一旦先前的任务成功完成,Ansys将按顺序完成。失败的任务将导致整个剧本停止运行。如果您遵循每项任务,您可以看到我们正在安装sudo,创建新用户,将SSH公钥添加到服务器,并sshd在重新启动之前对其进行了一些基本限制。

步骤4:运行可执行的剧本
运行这本剧本是相当简单的。这是我们将要使用的命令:

ansible-playbook create_user.yaml --ask-pass

我们需要包括,–ask-pass以便Ansible使用密码登录服务器,而不是尝试使用不在那里的SSH密钥。

一旦你运行命令,你将被要求输入SSH password:。这是您的服务器的根登录名,该密码可以在会在您的服务器交付时发给您。

输入root密码后,系统将提示您指定并确认用户名和密码。一旦完成,Ansible将会工作!

Ansible如果运行顺利,您的终端中看到以下内容:

 ____________
 < PLAY RECAP >
 ------------
 \ ^__^
 \ (oo)\_______
 (__)\ )\/\
 ||----w |
 || ||

123.45.67.89 : ok=8 changed=6 unreachable=0 failed=0

这里不能发太多空格,效果如下图。

此时,您可以使用SSH密钥登录到新用户帐户。恭喜!您现在可以轻松开始配置新服务器,并着眼于安全。有关如何深入了解可自动化服务器强化的更多信息,请查看以下这些资源:

ansible-OS

ansible-SSH

ansible-角色的安全性