介绍
当运行一个可供公众使用的Web服务器时,使您的内容易于访问和建立安全配置之间的平衡可能变得困难。
一个名为firejail
的项目旨在通过提供一个轻量级的安全容器化机制来帮助这一领域,该机制利用内核命名空间来执行分离政策。
在本指南中,我们将向您展示如何使用 firejail 以便在其自己的 chroot 环境中隔离流程. 以一个真实的例子来证明这一点,我们将设置两个 chroot 环境,其中一个使用 Nginx 网络服务器服务 WordPress,另一个使用 MySQL 数据库来处理网站数据. 这两个实例将有自己的文件系统和安装,并通过桥梁网络设备进行通信。
前提和目标
在本指南中,我们将使用 64 位 Ubuntu 14.04 服务器作为我们的基本安装,这将允许我们使用预先构建的firejail
包,并允许我们轻松创建chroot环境。
要获得安装的良好基础,请确保您在这里完成了 [Ubuntu 14.04 的初始服务器设置(https://andsky.com/tech/tutorials/initial-server-setup-with-ubuntu-14-04)。
这些实际上将是 Debian 稳定的环境,这是一个选择,因为 Debian 环境通过我们将使用的debootstrap
工具进行了更好的测试。
我们的主机将配置为公共IP地址,并作为我们将设置的桥梁网络的通道,以与监狱进行通信。
我们将配置的三个环境将具有以下属性:
Environment | Public IP Address | Bridge IP Address |
---|---|---|
Host | 192.0.2.1 | 10.10.20.1 |
Web Server | (none) | 10.10.20.10 |
Database Server | (none) | 10.10.20.20 |
请注意,上面红色的值应该被您的主机服务器的公共IP地址取代,但是,桥梁IP地址应该被用作是,因为我们将在整个指南中设置这个界面和这些地址。
在本指南中,所有命令都将作为 root用户执行。
下载和配置主机组件
要开始,我们需要下载一些我们将使用的工具到我们的服务器。
首先,我们需要下载 firejail 程序的 .deb
包. 在 网站下载页面上找到最新的 .deb
包名称,并将下面的 URL 名称部分替换为该版本。
1cd ~
2wget http://downloads.sourceforge.net/project/firejail/firejail/firejail_0.9.8.1_1_amd64.deb
一旦下载了文件,请使用dpkg
来安装它:
1dpkg -i firejail*
在安装 firejail 程序后,我们需要从 Ubuntu 的默认存储库中获取一些额外的软件包,具体来说,我们需要debootstrap
工具,这将帮助我们创建我们的 root 文件系统,以及bridge-utils
,这将允许我们创建网络桥接口,我们的监狱将使用它来通信:
1apt-get update
2apt-get install debootstrap bridge-utils
设置桥接口
在我们开始实际监狱之前,我们将设置桥梁网络接口。
我们可以使用brctl
命令创建新的界面,该命令是bridge-utils
包的一部分,我们的桥梁将被称为br0
:
1brctl addbr br0
接下来,我们需要引进接口,并激活接口,我们正在分配一个 CIDR 网络范围,我们的主机服务器将在这个接口上有 10.10.20.1的地址:
1ifconfig br0 10.10.20.1/24
随着接口的启动和运行,我们需要告诉内核允许IP转发,或路由,我们的接口之间。
1echo "1" > /proc/sys/net/ipv4/ip_forward
现在,我们需要设置一个iptables
规则,这将允许我们主机服务器上的端口80的流量被路由到我们将在我们的监狱中安装的Web服务器上。
1iptables -t nat -A PREROUTING -p tcp --dport 80 -j DNAT --to 10.10.20.10:80
这将一个规则添加到NAT
表中的PREROUTING
链的底部,当用于端口80的TCP包击中时,通过网络地址翻译将流量重定向到端口80。
我们还需要设置一系列规则,允许我们的数据库和网页服务器查询互联网,以便他们可以更新来自WordPress的组件。
1iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
然后,我们可以通过调整 FORWARD 链条中的规则来锁定我们的接口之间的通信。
首先,我们应该反映我们以前建立的NAT规则,以便我们可以明确允许从端口80到我们的br0
网络的流量:
1iptables -A FORWARD -i eth0 -o br0 -p tcp -m tcp --dport 80 -j ACCEPT
我们还希望允许与我们已经建立的连接相关的流量:
1iptables -A FORWARD -i eth0 -o br0 -m state --state RELATED,ESTABLISHED -j ACCEPT
我们希望允许在br0
界面上传输所有流量,以便我们的监狱彼此和外部世界进行通信:
1iptables -A FORWARD -i br0 -j ACCEPT
最后,我们将放弃所有其他转发连接,以便仅允许从br0
网络的出发连接进行转发。
1iptables -P FORWARD DROP
现在我们的主机系统配置了桥梁界面,它将用来与监狱环境进行通信。
创建 Chroot 目录结构
现在,我们已经准备好创建我们的chroot目录结构。
正如我们之前所说的,我们的Web服务器和我们的数据库服务器将以完全独立的文件系统运行,我们将将这两个文件系统保存在一个名为/jails
的目录中。
1mkdir /jails
进入您刚刚创建的目录:
1cd /jails
现在,我们需要创建将被我们的监狱操作系统使用的文件结构。 为了做到这一点,我们将使用debootstrap
工具。 这个实用程序是为了在现有文件系统中启动 Debian 环境。
虽然debootstrap
可以用来启动Ubuntu环境,但我们会选择稳定的Debian安装程序。
我们将我们的数据库环境安装到一个名为db
的目录中,以创建适当的目录结构,并下载并安装必要的包,键入:
1debootstrap --arch=amd64 stable db
现在我们已经在/jails/db
目录下构建了我们的文件系统,我们可以使用rsync
来将结构复制到我们的网页服务器可以使用的另一个目录中。新目录将被称为www
。 请确保您注意下列命令中的切片(/) 这将将第一目录的 contents 复制到第二目录中,而不是复制目录本身:
1rsync -azvh db/ www
现在,我们有两个chroot目录结构,我们可以与我们的firejail
程序一起使用。
使用 Firejail 设置 WordPress 数据库
现在我们有我们的目录结构,我们可以使用firejail
在我们的/jails/db
目录结构中创建一个chroot环境。
要创建一个chroot环境并在内部启动一个bash会话,我们只需要指定chroot root的目录位置和我们想要用于该会话的主机名称:
1firejail --chroot=/jails/db --name=db
1Parent pid 17390, child pid 17391
2Interface IP Mask Status
3lo 127.0.0.1 255.0.0.0 UP
4eth0 192.0.2.1 255.255.255.0 UP
5eth1 10.128.1.228 255.255.0.0 UP
6br0 10.10.20.1 255.255.255.0 UP
7
8Child process initialized
9[root@db ~]$
该命令将输出家长Pid,儿童Pid,以及在这个监狱会话中配置的界面(我们在这一点上没有限制或配置界面)。
我们需要做的第一件事是更新我们的包数据库,并在chroot环境中安装MySQL服务器。
1apt-get update
2apt-get install mysql-server
在更新过程中,您应该看到 Debian 存储库正在被检查,这是因为我们的 chroot 环境是 Debian 安装。
在安装过程中,您将被要求为 root MySQL 帐户选择并确认密码。
安装完成后,我们应该通过键入生成MySQL数据目录结构:
1mysql_install_db
接下来,用包含的脚本锁定一些不安全的默认文件:
1mysql_secure_installation
您将被要求在安装过程中设置的 root MySQL 密码。之后,您将被问及是否想要更改密码。如果您满意您的选择,请选择不
。
创建WordPress数据库和用户
接下来,我们要为 WordPress 设置一个单独的数据库。 使用 MySQL 根帐户登录 MySQL 服务器。 请在提示时输入您为该用户选择的密码:
1mysql -u root -p
创建一个新的WordPress数据库以使用:
1CREATE DATABASE wordpress;
接下来,我们将从网页服务器监狱创建一个用户来使用这个数据库. 网页服务器在桥梁界面上将有一个IP地址 10.10.20.10,所以我们需要将该用户与该地址相关联。
1CREATE USER 'wordpressuser'@'10.10.20.10' IDENTIFIED BY 'password';
2GRANT ALL PRIVILEGES ON wordpress.* TO 'wordpressuser'@'10.10.20.10';
现在,我们只需要清除特权表和出口:
1FLUSH PRIVILEGES;
2exit
更改 MySQL 设置以连接到桥梁地址
接下来,我们需要修改 MySQL 配置文件. 现在与您的编辑器一起打开它:
1nano /etc/mysql/my.conf
这个文件分为部分,找到开始于此的部分:
1[mysqld]
您应该看到一个名为bind-address
的指令,目前设置为127.0.0.1
。我们希望在桥梁界面上启动我们的MySQL实例收听。
1bind-address = 10.10.20.20
保存并关闭文件,当你完成。
现在,我们可以停止当前运行的 MySQL 实例并退出这个监狱:
1service mysql stop
2exit
使用 Firejail 设置 WordPress Web 服务器
现在我们的数据库已经配置了,我们可以转到我们的监狱,它将用于Web服务器。
1firejail --chroot=/jail/www --name=www
我们需要做的第一件事是更新我们的本地包数据库,并安装 Nginx Web 服务器和 PHP 组件,这些是需要处理动态请求并连接到 MySQL 数据库的:
1apt-get update
2apt-get install nginx php5-fpm php5-mysql
配置 PHP
我们将开始编辑PHP处理器的配置文件,以禁用可能是一个安全问题的功能:
1nano /etc/php5/fpm/php.ini
搜索文件中的cgi.fix_pathinfo
指令,它将被评论并设置为1
。我们需要删除评论并将其更改为0
:
1cgi.fix_pathinfo=0
保存并关闭文件,当你完成。
配置 Nginx
现在我们需要设置 Nginx 以正确地服务 WordPress 文件,这涉及在 /var/www/html 建立一个新的文档根,将
server_name’ 设置为我们的主机系统的公共 IP 地址,并配置 PHP 处理。
打开默认的 Nginx 配置文件:
1vim /etc/nginx/sites-available/default
以下是我们需要做的更改的摘要:
*不遵守Listen 80
指令以明确指定端口号.
- 更改
root
指令的值以指向/var/www/html
,我们将保留我们的WordPress文件的位置。 - 更改
index
参数以搜索其他索引文件之前的index.php
文件。 - 更改
server_name
指令的值,以指向主机服务器的IP地址或域
** - 调整
try_files
指令的最后值,以便将请求传递到index.php
文件时,它们没有被找到作为文件或目录。 这是位于位置/地址
区块内。 - 所有错误页面指
当您完成上述更改时,该文件应该看起来类似于下面的文件(评论已被删除为简要性):
1server {
2 listen 80;
3 root /var/www/html;
4 index index.php index.html index.htm;
5 server_name 192.0.2.1;
6 location / {
7 try_files $uri $uri/ /index.php?q=$uri&$args;
8 }
9 location /doc/ {
10 alias /usr/share/doc/;
11 autoindex on;
12 allow 127.0.0.1;
13 allow ::1;
14 deny all;
15 }
16 error_page 404 /404.html;
17 error_page 500 502 503 504 /50x.html;
18 location = /50x.html {
19 root /usr/share/nginx/www;
20 }
21 location ~ \.php$ {
22 try_files $uri =404;
23 fastcgi_split_path_info ^(.+\.php)(/.+)$;
24 fastcgi_pass unix:/var/run/php5-fpm.sock;
25 fastcgi_index index.php;
26 include fastcgi_params;
27 }
28}
您只需要调整server_name
指令以参考您的主机系统的公共 IP 地址或域名。
保存并关闭文件,当你完成。
下载和配置WordPress文件
现在 Nginx 已配置为正确服务的文件,我们可以下载、配置和安装它们。
首先,转到 root 用户的主目录并下载最新的 WordPress tarball:
1cd ~
2wget http://wordpress.org/latest.tar.gz
提取 tarball 的内容,创建一个名为 `~/wordpress 的目录:
1tar xzvf latest.tar.gz
将样本配置文件复制到将被检查的有效配置文件名:
1cd ~/wordpress
2cp wp-config-sample.php wp-config.php
现在,在文本编辑器中打开新的配置文件:
1nano wp-config.php
内部,我们需要更改与数据库存储相关的值,我们需要用我们在MySQL数据库中做出的选择的详细信息填写配置选项。
除了您早些时候应该修改到自己的值的密码字段外,您可以使用下面的值:
1/** The name of the database for WordPress */
2define('DB_NAME', 'wordpress');
3
4/** MySQL database username */
5define('DB_USER', 'wordpressuser');
6
7/** MySQL database password */
8define('DB_PASSWORD', 'password');
9
10/** MySQL hostname */
11define('DB_HOST', '10.10.20.20');
完成后,保存并关闭文件。
接下来,我们需要创建我们在 Nginx 配置文件中引用为文档根的 /var/www/html
目录,然后将我们所有的 WordPress 文件复制到该目录:
1mkdir -p /var/www/html
2cp -r ~/wordpress/* /var/www/html
现在我们可以将文件的所有权交给网页用户:
1cd /var/www/html
2chown -R www-data:www-data /var/www/html/*
您的 Web 服务器监狱现在已经完全配置了,我们可以通过键入来轻松关闭我们的 Web 服务器和 PHP 流程:
1service nginx stop
2service php5-fpm stop
现在,离开监狱以返回主机服务器会话:
1exit
开始监狱
我们现在已经完全配置了我们的监狱,我们可以通过我们的网络桥接口单独启动它们。
首先,我们将启动数据库服务器,因为它更简单。我们需要像以前一样指定chroot根位置。这次,我们还将使用 --net
参数来指定桥接。我们将与 --ip
参数一起使用此参数来指定我们想要给这个监狱的确切地址(10.10.20.20
,如果你想起我们的配置)。
我们还将通过私人
旗帜,在监狱内安装新的/tmp
,/root
和/home/user
目录,然后我们需要指定我们希望在监狱中开始的过程,并将其放入背景中,结尾为&
。
我们应该启动的流程是MySQL服务器流程,还有一个睡眠 inf
流程,这将使监狱无限期运行,而不是在以前的流程完成时退出。
1firejail --chroot=/jails/db --private --net=br0 --ip=10.10.20.20 \
2 "/etc/init.d/mysql start; \
3 sleep inf" &
监狱将启动,指定的进程将开始连续执行. 您可以通过使用firejail
的--list
选项查看此进程的结果:
1firejail --list
121913:root:firejail --chroot=/jails/db --private --net=br0 --ip=10.10.20.20 /etc/init.d/mysql
2 21916:root:bash -c /etc/init.d/mysql start; sleep inf
3 21970:root:/bin/sh /usr/bin/mysqld_safe
4 22322:syslog:/usr/sbin/mysqld --basedir=/usr --datadir=/var/lib/mysql --plugin-dir=/usr/
5 22323:root:logger -t mysqld -p daemon.error
6 22409:root:sleep inf
正如你所看到的,流程树可从我们的主机系统中获取,因为我们可以看到睡眠信息
运行,并看到MySQL流程仍在运行,我们可以看到监狱已经完成了启动。
对于 web 服务器监狱,需要相同的基本设置,我们需要指定 chroot 根位置、桥接接口和被分配的实际 IP 地址(‘10.10.20.10’),以及‘--私人’旗帜。
就进程列表而言,我们有一些额外的考虑,首先,监狱中的/var/log
目录在每次启动时都被动态地创建。
此外, Nginx 进程依赖于系统日志器,我们也会在 Nginx 之前启动rsyslog
进程,在 Nginx 启动后,我们还需要记住启动我们的 PHP 处理器,在需要时将请求传递到数据库监狱。
最后,我们启动我们的Web服务器监狱的命令将看起来像这样:
1firejail --chroot=/jails/www --private --net=br0 --ip=10.10.20.10 \
2 "mkdir -p /var/log/nginx; \
3 touch /var/log/nginx/error.log; \
4 touch /var/log/nginx/access.log; \
5 /etc/init.d/rsyslog start; \
6 /etc/init.d/nginx start; \
7 /etc/init.d/php5-fpm start; \
8 sleep inf" &
网络服务器监狱可能需要一段时间才能启动,继续用firejail -list
检查,看看这个过程是否达到sleep inf
状态。
现在,如果您在 Web 浏览器中访问主机服务器的公共 IP 地址或域名,您应该看到 WordPress 初始安装页面:
1http://host_server_domain_or_IP
填写相应的值并点击安装WordPress
在底部,当你准备好了。你将需要使用新创建的管理帐户登录。
如果这里的一切都按预期运行,这意味着安装成功了,我们现在可以努力使此配置可重复和持久。
消防局提供服务
现在我们已经完成了配置并运行,我们希望确保在重新启动后能够轻松返回这里。
- 配置主机到监狱和监狱到监狱网络,以便在启动时出现。
- 使我们的
iptables
更改持久。
我们可以马上开始这三个。
在船上设置监狱网络
首先,我们将专注于建立和运行桥梁网络,这在我们担心防火墙规则和启动监狱环境之前是必要的。
我们需要配置实际的桥接连接. 要实现此连接并在启动时运行,我们需要修改 /etc/network/interfaces
文件。
1nano /etc/network/interfaces
在内部,你会看到一些部分决定在启动时启动哪些接口,以及描述每个接口的其他行. 开始将br0
网络附加到第二行auto
的末尾,以启动我们将在启动时定义的接口:
1auto eth0 eth1 br0
接下来,我们需要设置一个将界面定义的部分,因为这是一个桥梁界面,并且不像一个传统的桥梁来组合两个网络,我们将手动定义我们的界面,这意味着我们将给出确切的命令,应该用来配置网络。
请从 header 部分开始:
1iface br0 inet manual
在此下,我们将使用预备
,上
,后下
和下
指令来定义在每个步骤中应该执行的命令。对于预备
和上
命令,我们希望创建桥梁,然后将界面以我们之前手动所做的同样的方式提升。
1iface br0 inet manual
2 pre-up brctl addbr $IFACE
3 up ifconfig $IFACE 10.10.20.1/24
对于下载
和下载
的命令,我们只想扭转这些命令,然后将界面重新下载,然后删除桥梁:
1iface br0 inet manual
2 pre-up brctl addbr $IFACE
3 up ifconfig $IFACE 10.10.20.1/24
4 down ifconfig $IFACE down
5 post-down brctl delbr $IFACE
我们的br0
界面现在已定义,我们已设置为在启动时自动启动。
设置IPTables,允许限制转移到监狱
接下来,我们需要使用我们之前添加的规则来设置iptables。
通过键入安装包:
1apt-get install iptables-persistent
在安装过程中,您将被问及是否要保存当前的 IPv4 和 IPv6 规则集。 在这些提示中选择 是,以自动保存当前的规则集。
如果您需要调整在启动时应用的规则,请执行您想要使用的更改,然后键入:
1/etc/init.d/iptables-persistent save
现行规则将更新。
我们的iptables规则现在被设置为在服务器启动时返回,但还有另一个问题我们还没有解决:我们需要确保我们的内核允许转发。
之前,我们在/proc
伪文件系统中的文件中响应了1
,以启用此功能。
1nano /etc/sysctl.conf
无视下列线条:
1net.ipv4.ip_forward=1
保存并关闭文件,当你完成。
创建一个升级脚本来启动WordPress监狱
要将我们的监狱配置为在启动时启动,我们需要创建一个升级脚本,我们将我们的脚本称为firejail_wp.conf。
在您的文本编辑器中的 /etc/init
目录中打开这个名称的文件:
1nano /etc/init/firejail_wp.conf
在内部,我们首先填写了这项服务的简短描述:
1description "WordPress jail"
接下来,我们将配置该服务自动启动的条件,我们希望确保文件系统可用,我们还需要确保br0
网络已经建立。
要做到这一点,我们将使用启动
指令和本地文件系统
和网络设备
规格来构建我们的启动条件。
1description "WordPress jail"
2
3start on (local-filesystems and net-device-up IFACE=br0)
4stop on runlevel [!12345]
最后,我们需要确定在启动此服务时将执行的实际命令. 由于服务的运行方式,我们将将 firejail 命令放置在外部脚本中,所以我们只需要引用脚本名称:
1description "WordPress jail"
2
3start on (local-filesystems and net-device-up IFACE=br0)
4stop on runlevel [!12345]
5
6exec /startjails.sh
完成后,保存并关闭文件。
现在,我们需要创建我们刚刚参考的实际脚本文件. 使用您的文本编辑器在这个位置打开文件:
1nano /startjails.sh
由于这是一个 bash 脚本,请从标准 shebang 调用 bash 开始:
1#!/bin/bash
接下来,我们将添加我们的两个 firejail 命令,其中有一个小的修改. 出于未知的原因,在由 upstart 启动时,在监狱环境中运行 Nginx init 脚本存在问题。
为了绕过这一点,我们将简单地称之为 Nginx 可执行,而不是内部监狱 init 脚本。
1#!/bin/bash
2
3firejail --chroot=/jails/db --private --net=br0 --ip=10.10.20.20 "/etc/init.d/mysql start; sleep inf" &
4
5firejail --chroot=/jails/www --private --net=br0 --ip=10.10.20.10 "mkdir -p /var/log/nginx; touch /var/log/nginx/error.log; touch /var/log/nginx/access.log; /etc/init.d/rsyslog start; /usr/sbin/nginx; /etc/init.d/php5-fpm start; sleep inf" &
另一个命令是必要的,以确保这是一个持续的服务,而不是一个任务,将结束在监狱开始后立即。我们需要添加睡眠 inf
作为脚本的最后一行。
1#!/bin/bash
2
3firejail --chroot=/jails/db --private --net=br0 --ip=10.10.20.20 "/etc/init.d/mysql start; sleep inf" &
4
5firejail --chroot=/jails/www --private --net=br0 --ip=10.10.20.10 "mkdir -p /var/log/nginx; touch /var/log/nginx/error.log; touch /var/log/nginx/access.log; /etc/init.d/rsyslog start; /usr/sbin/nginx; /etc/init.d/php5-fpm start; sleep inf" &
6
7sleep inf
完成后,保存并关闭文件。
现在,我们只需要使这个文件可执行,以便升级脚本可以启动它:
1chmod +x /startjails.sh
通过此步骤,WordPress监狱环境完全配置为在启动时启动。
您可以重新启动您的主机服务器来尝试这些:
1shutdown -r now
如果一切都已正确配置,你将能够访问你的WordPress网站,一旦一切都有时间开始。
结论
虽然有许多其他方法来为您的服务器设置孤立组件,但由于其灵活性和能够以最少的资源处理如此多的不同场景,firejail是一个很好的解决方案。