蚊章汇 - Daniel J Walsh
type: channel
link: https://linuxcn.bwsl.wang/author/494/
description: Daniel J Walsh
items: Podman 和用户命名空间：天作之合
items: Podman：一个更安全的运行容器的方式
items: 面向系统管理员的容器手册
items: Linux 容器演化史
items: 看漫画学 SELinux 强制策略
items: 50 种系统免遭黑客侵袭的方法 [2017 年版]

Podman 和用户命名空间：天作之合
type: item
date: 2019-08-26T06:02:00+08:00
description: 了解如何使用 Podman 在单独的用户空间运行容器。Podman 是 libpod 库的一部分，使用户能够管理 pod、容器和容器镜像。在我的上一篇文章中，我写过将 Podman 作为一种更安全的运行容器的方式。在这里，我将解释如何使用 Podman 在单独的用户命名空间中运行容器。作为分离容器的一个很棒的功能，我一直在思考 用户命名空间 user namespace ，它主要是由 Red Hat 的 Eric Biederman 开发的。用户命名空间允许你指定用于运行容器的用户标识符（UID）和组标识符（GID）映射。这意味着你可以在容器内以 UID 0 运行，在容器外以 UID 100000 运行。如果容器进程逃逸出了容器，内核会将它们视为以 UID 100000 运行。不仅如此，任何未映射到用户命名空间的 UID 所拥有的文件对象都将被视为 nobody 所拥有（UID 是 65534， 由 kernel.overflowuid 指定），并且不允许容器进程访问，除非该对象可由“其他人”访问（即世界可读/可写）。如果你拥有一个权限为 660 的属主为“真实” root 的文件，而当用户命名空间中的容器进程尝试读取它时，会阻止它们访问它，并且会将该文件视为 nobody 所拥有。示例以下是它是如何工作的。首先，我在 root 拥有的系统中创建一个文件。$ sudo bash -c "echo Test > /tmp/test" $ sudo chmod 600 /tmp/test $ sudo ls -l /tmp/test -rw-------. 1 root root 5 Dec 17 16:40 /tmp/test接下来，我将该文件卷挂载到一个使用用户命名空间映射 0:100000:5000 运行的容器中。$ sudo podman run -ti -v /tmp/test:/tmp/test:Z --uidmap 0:100000:5000 fedora sh # id uid=0(root) gid=0(root) groups=0(root) # ls -l /tmp/test -rw-rw----. 1 nobody nobody 8 Nov 30 12:40 /tmp/test # cat /tmp/test cat: /tmp/test: Permission denied上面的 --uidmap 设置告诉 Podman 在容器内映射一系列的 5000 个 UID，从容器外的 UID 100000 开始的范围（100000-104999）映射到容器内 UID 0 开始的范围（0-4999）。在容器内部，如果我的进程以 UID 1 运行，则它在主机上为 100001。由于实际的 UID=0 未映射到容器中，因此 root 拥有的任何文件都将被视为 nobody 所拥有。即使容器内的进程具有 CAP_DAC_OVERRIDE 能力，也无法覆盖此种保护。DAC_OVERRIDE 能力使得 root 的进程能够读/写系统上的任何文件，即使进程不是 root 用户拥有的，也不是全局可读或可写的。用户命名空间的功能与宿主机上的功能不同。它们是命名空间的功能。这意味着我的容器的 root 只在容器内具有功能 —— 实际上只有该范围内的 UID 映射到内用户命名空间。如果容器进程逃逸出了容器，则它将没有任何非映射到用户命名空间的 UID 之外的功能，这包括 UID=0。即使进程可能以某种方式进入另一个容器，如果容器使用不同范围的 UID，它们也不具备这些功能。请注意，SELinux 和其他技术还限制了容器进程破开容器时会发生的情况。使用 podman top 来显示用户名字空间我们在 podman top 中添加了一些功能，允许你检查容器内运行的进程的用户名，并标识它们在宿主机上的真实 UID。让我们首先使用我们的 UID 映射运行一个 sleep 容器。$ sudo podman run --uidmap 0:100000:5000 -d fedora sleep 1000现在运行 podman top：$ sudo podman top --latest user huser USER HUSER root 100000 $ ps -ef | grep sleep 100000 21821 21809 0 08:04 ? 00:00:00 /usr/bin/coreutils --coreutils-prog-shebang=sleep /usr/bin/sleep 1000注意 podman top 报告用户进程在容器内以 root 身份运行，但在宿主机（HUSER）上以 UID 100000 运行。此外，ps 命…

Podman：一个更安全的运行容器的方式
type: item
date: 2019-08-24T07:50:08+08:00
description: Podman 使用传统的 fork/exec 模型（相对于客户端/服务器模型）来运行容器。在进入本文的主要主题 Podman 和容器之前，我需要了解一点 Linux 审计功能的技术。什么是审计？Linux 内核有一个有趣的安全功能，叫做审计。它允许管理员在系统上监视安全事件，并将它们记录到audit.log 中，该文件可以本地存储或远程存储在另一台机器上，以防止黑客试图掩盖他的踪迹。/etc/shadow 文件是一个经常要监控的安全文件，因为向其添加记录可能允许攻击者获得对系统的访问权限。管理员想知道是否有任何进程修改了该文件，你可以通过执行以下命令来执行此操作：# auditctl -w /etc/shadow现在让我们看看当我修改了 /etc/shadow 文件会发生什么：# touch /etc/shadow # ausearch -f /etc/shadow -i -ts recent type=PROCTITLE msg=audit(10/10/2018 09:46:03.042:4108) : proctitle=touch /etc/shadow type=SYSCALL msg=audit(10/10/2018 09:46:03.042:4108) : arch=x86_64 syscall=openat success=yes exit=3 a0=0xffffff9c a1=0x7ffdb17f6704 a2=O_WRONLY|O_CREAT|O_NOCTTY| O_NONBLOCK a3=0x1b6 items=2 ppid=2712 pid=3727 auid=dwalsh uid=root gid=root euid=root suid=root fsuid=root egid=root sgid=root fsgid=root tty=pts1 ses=3 comm=touch exe=/usr/bin/touch subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 key=(null)`审计记录中有很多信息，但我重点注意到它记录了 root 修改了 /etc/shadow 文件，并且该进程的审计 UID（auid）的所有者是 dwalsh。内核修改了这个文件了么？跟踪登录 UID登录 UID（loginuid），存储在 /proc/self/loginuid 中，它是系统上每个进程的 proc 结构的一部分。该字段只能设置一次；设置后，内核将不允许任何进程重置它。当我登录系统时，登录程序会为我的登录过程设置 loginuid 字段。我（dwalsh）的 UID 是 3267。$ cat /proc/self/loginuid 3267现在，即使我变成了 root，我的登录 UID 仍将保持不变。$ sudo cat /proc/self/loginuid 3267请注意，从初始登录过程 fork 并 exec 的每个进程都会自动继承 loginuid。这就是内核知道登录的人是 dwalsh 的方式。容器现在让我们来看看容器。sudo podman run fedora cat /proc/self/loginuid 3267甚至容器进程也保留了我的 loginuid。 现在让我们用 Docker 试试。sudo docker run fedora cat /proc/self/loginuid 4294967295为什么不一样？Podman 对于容器使用传统的 fork/exec 模型，因此容器进程是 Podman 进程的后代。Docker 使用客户端/服务器模型。我执行的 docker 命令是 Docker 客户端工具，它通过客户端/服务器操作与 Docker 守护进程通信。然后 Docker 守护程序创建容器并处理 stdin/stdout 与 Docker 客户端工具的通信。进程的默认 loginuid（在设置 loginuid 之前）是 4294967295（LCTT 译注：2 32 - 1）。由于容器是 Docker 守护程序的后代，而 Docker 守护程序是 init 系统的子代，所以，我们看到 systemd、Docker 守护程序和容器进程全部具有相同的 loginuid：4294967295，审计系统视其为未设置审计 UID。cat /proc/1/loginuid 4294967295怎么会被滥用？让我们来看看如果 Docker 启动的容器进程修改 /etc/shadow 文件会发生什么。$ sudo docker run --privileged -v /:/host fedora touch /host/et…

面向系统管理员的容器手册
type: item
date: 2018-10-28T19:15:26+08:00
description: 你所需了解的容器如何工作的知识。现在人们严重过度使用了“容器”这个术语。另外，对不同的人来说，它可能会有不同的含义，这取决于上下文。传统的 Linux 容器只是系统上普通的进程。一组进程与另外一组进程是相互隔离的，实现方法包括：资源限制（控制组 [cgoups]）、Linux 安全限制（文件权限，基于 Capability 的安全模块、SELinux、AppArmor、seccomp 等）还有名字空间（进程 ID、网络、挂载等）。如果你启动一台现代 Linux 操作系统，使用 cat /proc/PID/cgroup 命令就可以看到该进程是属于一个控制组的。还可以从 /proc/PID/status 文件中查看进程的 Capability 信息，从 /proc/self/attr/current 文件中查看进程的 SELinux 标签信息，从 /proc/PID/ns 目录下的文件查看进程所属的名字空间。因此，如果把容器定义为带有资源限制、Linux 安全限制和名字空间的进程，那么按照这个定义，Linux 操作系统上的每一个进程都在一个容器里。因此我们常说 Linux 就是容器，容器就是 Linux。而容器运行时是这样一种工具，它调整上述资源限制、安全限制和名字空间，并启动容器。Docker 引入了容器镜像的概念，镜像是一个普通的 TAR 包文件，包含了：rootfs（容器的根文件系统）：一个目录，看起来像是操作系统的普通根目录（/），例如，一个包含 /usr, /var, /home 等的目录。JSON 文件（容器的配置）：定义了如何运行 rootfs；例如，当容器启动的时候要在 rootfs 里运行什么命令（CMD）或者入口（ENTRYPOINT），给容器定义什么样的环境变量（ENV），容器的工作目录（WORKDIR）是哪个，以及其他一些设置。Docker 把 rootfs 和 JSON 配置文件打包成基础镜像。你可以在这个基础之上，给 rootfs 安装更多东西，创建新的 JSON 配置文件，然后把相对于原始镜像的不同内容打包到新的镜像。这种方法创建出来的是分层的镜像。 开放容器计划 Open Container Initiative （OCI）标准组织最终把容器镜像的格式标准化了，也就是 镜像规范 OCI Image Specification （OCI）。用来创建容器镜像的工具被称为容器镜像构建器。有时候容器引擎做这件事情，不过可以用一些独立的工具来构建容器镜像。Docker 把这些容器镜像（tar 包）托管到 web 服务中，并开发了一种协议来支持从 web 拉取镜像，这个 web 服务就叫 容器仓库 container registry 。容器引擎是能从镜像仓库拉取镜像并装载到容器存储上的程序。容器引擎还能启动容器运行时（见下图）。容器存储一般是 写入时复制 copy-on-write （COW）的分层文件系统。从容器仓库拉取一个镜像时，其中的 rootfs 首先被解压到磁盘。如果这个镜像是多层的，那么每一层都会被下载到 COW 文件系统的不同分层。 COW 文件系统保证了镜像的每一层独立存储，这最大化了多个分层镜像之间的文件共享程度。容器引擎通常支持多种容器存储类型，包括 overlay、devicemapper、btrfs、aufs 和 zfs。容器引擎将容器镜像下载到容器存储中之后，需要创建一份容器运行时配置，这份配置是用户/调用者的输入和镜像配置的合并。例如，容器的调用者可能会调整安全设置，添加额外的环境变量或者挂载一些卷到容器中。容器运行时配置的格式，和解压出来的 rootfs 也都被开放容器计划 OCI 标准组织做了标准化，称为 OCI 运行时规范。最终，容器引擎启动了一个容器运行时来读取运行时配置，修改 Linux 控制组、安全限制和名字空间，并执行容器命令来创建容器的 PID 1 进程。至此，容器引擎已经可以把容器的标准输入/标准输出转给调用方，并控制容器了（例如，stop、start、attach）。值得一提的是，现在出现了很多新的容器运行时，它们使用 Linux 的不同特性来隔离容器。可以使用 KVM 技术来隔离容器（想想迷你虚拟机），或者使用其他虚拟机监视器策略（例如拦截所有从容器内的进程发起的系统调用）。既然我们有了标准的运行时规范，这些工具都能被相同的容器引擎来启动。即使在 Windows 系统下，也可以使用 OCI 运行时规范来启动 Windows 容器。容器编排器是一个更高层次的概念。它是在多个不同的节点上协调容器执行的工具。容器编排工具通过和容器引擎的通信来管理容器。编排器控制容器引擎做容器的启动和容器间的网络连接，它能够监控容器，在负载变高的时候进行容器扩容。via: https…

Linux 容器演化史
type: item
date: 2017-08-27T00:10:00+08:00
description: 容器在过去几年内取得很大的进展。现在我们来回顾它发展的时间线。Linux 容器是如何演变的在过去几年内，容器不仅成为了开发者们热议的话题，还受到了企业的关注。持续增长的关注使得在它的安全性、可扩展性以及互用性等方面的需求也得以增长。满足这些需求需要很大的工程量，下面我们讲讲在红帽这样的企业级这些工程是如何发展的。我在 2013 年秋季第一次遇到 Docker 公司（Docker.io）的代表，那时我们在设法使 Red Hat Enterprise Linux (RHEL) 支持 Docker 容器（现在 Docker 项目的一部分已经更名为 Moby）的运行。在移植过程中，我们遇到了一些问题。处理容器镜像分层所需的写时拷贝（COW）文件系统成了我们第一个重大阻碍。Red Hat 最终贡献了一些 COW 文件系统实现，包括 Device Mapper、btrf，以及 OverlayFS 的第一个版本。在 RHEL 上，我们默认使用 Device Mapper， 但是我们在 OverlayFS 上也已经取得了很大进展。我们在用于启动容器的工具上遇到了第二个主要障碍。那时的上游 docker 使用 LXC 工具来启动容器，然而我们不想在 RHEL 上支持 LXC 工具集。而且在与上游 docker 合作之前，我们已经与 libvrit 团队携手构建了 virt-sandbox 工具，它使用 libvrit-lxc 来启动容器。在那时，红帽里有员工提到一个好办法，换掉 LXC 工具集而添加桥接器，以便 docker 守护进程通过 libvirt-lxc 与 libvirt 通讯来启动容器。这个方案也有一些顾虑。考虑下面这个例子，使用 Docker 客户端（docker-cli）来启动容器，各层调用会在容器进程（pid1OfContainer）之前依次启动：docker-cli → docker-daemon → libvirt-lxc → pid1OfContainer我不是很喜欢这个方案，因为它在启动容器的工具与最终的容器进程之间有两个守护进程。我的团队与上游 docker 开发者合作实现了一个原生的 Go 编程语言 版本的容器运行时，叫作 libcontainer。这个库作为 [OCI 运行时规范]的最初版实现与 runc 一同发布。docker-cli → docker-daemon @ pid1OfContainer大多数人误认为当他们执行一个容器时，容器进程是作为 docker-cli 的子进程运行的。实际上他们执行的是一个客户端/服务端请求操作，容器进程是在一个完全单独的环境作为子进程运行的。这个客户端/服务端请求会导致不稳定性和潜在的安全问题，而且会阻碍一些实用特性的实现。举个例子，systemd 有个叫做套接字唤醒的特性，你可以将一个守护进程设置成仅当相应的套结字被连接时才启动。这意味着你的系统可以节约内存并按需执行服务。套结字唤醒的工作原理是 systemd 代为监听 TCP 套结字，并在数据包到达套结字时启动相应的服务。一旦服务启动完毕，systemd 将套结字交给新启动的守护进程。如果将守护进程运行在基于 docker 的容器中就会出现问题。systemd 的 unit 文件通过 Docker CLI 执行容器，然而这时 systemd 却无法简单地经由 Docker CLI 将套结字转交给 Docker 守护进程。类似这样的问题让我们意识到我们需要一个运行容器的替代方案。容器编排问题上游的 docker 项目简化了容器的使用过程，同时也是一个绝佳的 Linux 容器学习工具。你可以通过一条简单的命令快速地体验如何启动一个容器，例如运行 docker run -ti fedora sh 然后你就立即处于一个容器之中。当开始把许多容器组织成一个功能更为强大的应用时，你才能体会到容器真正的能力。但是问题在于伴随多容器应用而来的高复杂度使得简单的 Docker 命令无法胜任编排工作。你要如何管理容器应用在有限资源的集群节点间的布局与编排？如何管理它们的生命周期等等？在第一届 DockerCon，至少有 7 种不同的公司/开源项目展示了其容器的编排方案。红帽演示了 OpenShift 的 geard 项目，它基于 OpenShift v2 的容器（叫作 gears）。红帽觉得我们需要重新审视容器编排，而且可能要与开源社区的其他人合作。Google 则演示了 Kubernetes 容器编排工具，它来源于 Google 对其自内部架构进行编排时所积累的知识经验。OpenShift 决定放弃 Gear 项目，开始和 Google 一同开发 Kubernetes。 现在 Kubernetes 是 GitHub 上最大的社区项目之…

看漫画学 SELinux 强制策略
type: item
date: 2017-03-22T16:24:00+08:00
description: 今年是我们一起庆祝 SELinux 纪念日的第十个年头了（LCTT 译者注：本文发表于 2013 年）。真是太难以置信了！SELinux 最初在 Fedora Core 3 中被引入，随后加入了红帽企业版 Linux 4。从来没有使用过 SELinux 的家伙，你可要好好儿找个理由了……SElinux 是一个标签型系统。每一个进程都有一个标签。操作系统中的每一个文件/目录 客体 （ object ） 也都有一个标签。甚至连网络端口、设备，乃至潜在的主机名都被分配了标签。我们把控制访问进程的标签的规则写入一个类似文件的客体标签中，这些规则我们称之为 策略 （ policy ） 。内核强制实施了这些规则。有时候这种“强制”被称为 强制访问控制体系 （ Mandatory Access Control ） （MAC）。一个客体的拥有者对客体的安全属性并没有自主权。标准 Linux 访问控制体系，拥有者/分组 + 权限标志如 rwx，常常被称作 自主访问控制 （ Discretionary Access Control ） （DAC）。SELinux 没有文件 UID 或拥有权的概念。一切都被标签控制，这意味着在没有至高无上的 root 权限进程时，也可以设置 SELinux 系统。注意： SELinux 不允许你摒弃 DAC 控制。SELinux 是一个并行的强制模型。一个应用必须同时支持 SELinux 和 DAC 来完成特定的行为。这可能会导致管理员迷惑为什么进程被拒绝访问。管理员被拒绝访问是因为在 DAC 中有些问题，而不是在 SELinux 标签。类型强制让我们更深入的研究下标签。SELinux 最主要的“模型”或“强制”叫做 类型强制 （ type enforcement ） 。基本上这意味着我们根据进程的类型来定义其标签，以及根据文件系统客体的类型来定义其标签。打个比方想象一下在一个系统里定义客体的类型为猫和狗。猫（CAT）和狗（DOG）都是 进程类型 （ process type ） 。我们有一类希望能与之交互的客体，我们称之为食物。而我希望能够为食物增加类型：cat_food （猫的食物）和 dog_food（狗的食物）。作为一个策略制定者，我可以说一只狗有权限去吃狗粮（dog_chow），而一只猫有权限去吃猫粮（cat_chow）。在 SELinux 中我可以将这条规则写入策略中。allow cat cat_chow:food eat;允许 猫 猫粮：食物 吃；allow dog dog_chow:food eat;允许 狗 狗粮：食物 吃；有了这些规则，内核会允许猫进程去吃打上猫粮标签 cat_chow 的食物，允许狗去吃打上狗粮标签 dog_chow 的食物。此外，在 SELinux 系统中，由于禁止是默认规则，这意味着，如果狗进程想要去吃猫粮 cat_chow，内核会阻止它。同理，猫也不允许去接触狗粮。现实例子我们将 Apache 进程标为 httpd_t，将 Apache 上下文标为 httpd_sys_content_t 和 httpdsys_content_rw_t。假设我们把信用卡数据存储在 MySQL 数据库中，其标签为 msyqld_data_t。如果一个 Apache 进程被劫持，黑客可以获得 httpd_t 进程的控制权，从而能够去读取 httpd_sys_content_t 文件并向 httpd_sys_content_rw_t 文件执行写操作。但是黑客却不允许去读信用卡数据（mysqld_data_t），即使 Apache 进程是在 root 下运行。在这种情况下 SELinux 减轻了这次闯入的后果。多类别安全强制打个比方上面我们定义了狗进程和猫进程，但是如果你有多个狗进程：Fido 和 Spot，而你想要阻止 Fido 去吃 Spot 的狗粮 dog_chow 怎么办呢?一个解决方式是创建大量的新类型，如 Fido_dog 和 Fido_dog_chow。但是这很快会变得难以驾驭因为所有的狗都有差不多相同的权限。为了解决这个问题我们发明了一种新的强制形式，叫做 多类别安全 （ Multi Category Security ） （MCS）。在 MCS 中，我们在狗进程和狗粮的标签上增加了另外一部分标签。现在我们将狗进程标记为 dog:random1(Fido) 和 dog:random2(Spot)。我们将狗粮标记为 dog_chow:random1(Fido) 和 dog_chow:random2(Spot)。MCS 规则声明如果类型强制规则被遵守而且该 MCS 随机标签正确匹配，则访问是允许的，否则就会被拒绝。Fido (dog:random1) 尝试去吃 cat_chow:foo…

50 种系统免遭黑客侵袭的方法 [2017 年版]
type: item
date: 2017-01-22T04:33:00+08:00
description: Paul Simon 概括了“与爱人分手的 50 法”，而这里，我们提供了提高系统安全性的 50 种方法。当我还是小孩子，耳畔萦绕着 Paul Simon 的流行歌“与爱人分手的 50 法”。当我渐渐地长大，突然受歌的启发，收集了 50 种方法，免得你——门内汉和门外汉——遭受黑客侵袭啊：“你刚刚从后头溜出去了，杰克”1、 备份你的数据。如果你不幸被勒索软件光顾，那么你就不用支付赎金，因为你做了备份。2、 当你需要在公共场所为你的手机充电，那就使用 sysncstop吧，或者你也可以用你的备份电池。（LCTT 译注：sysncstop 是一种可以在公共场所安全充电的 USB 设备。在公共场所充电的风险，你知道的。）3、 利用好你的审计系统，里头有好多很酷的工具可以帮助你监控系统。如果你确实遭到了入侵，那么审计系统也许就可以告诉你发生了什么，以及攻击者做了些什么。4、 说到日志，把日志定向到集中式服务器上总是一个不错的想法，因为如果某个黑客侵入你的系统里，他首先要攻击的就是日志系统以便隐藏他的踪迹。构建一个好的入侵检测系统来监控日志，这对于防范黑客也很有帮助。“做份新的计划吧，斯坦”5、 以强制模式运行 SELinux（见 StopDisablingSelinux.com）。不要觉得我现在还在喋喋不休地说这个可笑。SELinux 可以防止 0day 漏洞的影响。当破壳漏洞出现的时候，SELinux 曾是唯一的防护手段。6、 如果可能，在 SELinux 沙盒中运行应用程序吧——在容器火遍全球前，它就已经是容器了。同时，请关注 Flatpack 开发，这个工具很快会开发沙盒功能。7、 不要安装或者使用 Flash。Firefox 不再支持它了，同时也希望大多数 web 服务器正在远离它。8、 使用受约束的 SELinux 用户来控制用户在你的系统中所能做的事。如果你正运行着一台共享登录的系统，设置用户为 guest_t。“你不必害羞，罗伊”9、 利用 systemd 工具的能力来帮助你提升系统安全。大多数系统攻击是通过那些监听着网络的服务来实现的，而 Systemd 提供了一些很棒的方法来锁定服务。例如，使用 PrivateTmp=yes 。Privatemp 利用挂载命名空间来为服务器的 /tmp 设置一个私有的 tmpfs 挂载，这可以阻止被入侵的服务访问到主机 /tmp 中的内容，以及针对系统中基于监听 /tmp 的服务的潜在攻击。10、 InaccessibleDirectories=/home 是一个 systemd 单元的选项，它使用挂载命名空间的方式使从服务的角度看不到 /home 目录（或者其它任何目录），这会使得被入侵的服务攻击到数据更为困难。11、 ReadOnlyDirectories=/var 是另外一个 systemd 单元的选项，它使用挂载命名空间的方式来将目录内容变成只读模式。基本上你总是可以让 /usr 运行在只读模式。这可以阻止一个被入侵的应用程序重写二进制文件，因为那可以在下次服务重启时，该服务依旧是被入侵的。12、 降低服务权限（CapabilityBoundingSet=CAP_CHOWN CAP_KILL）。在内核中，特权服务被分解成一些列不同的权限。大多数服务不需要很多权限（如果需要一些的话），而 systemd 提供了一个简单的开关来从服务中剥离这些权限。13、 如果服务不使用网络，那么你可以使用 PrivateNetwork=yes 来为该服务关闭网络功能。只需在服务的单元文件中开启该选项，就可以享受它带来的好处，关闭服务所有可用的网络。黑客常常并不是真的想破坏你的机器——他只是想用它作为攻击服务器来攻击其它机器。如果服务连不上网络，那么就不会受到攻击。14、 控制服务可用的设备。 Systemd 提供了 DeviceAllow 配置，它控制了该服务可用的设备。DeviceAllow=/dev/null rw 将访问限制为 /dev/null，且仅可访问该设备节点，不允许对其它任何设备节点的访问。该功能实现于设备的 cgroup 控制器顶端。15、 Systemd 系统即将迎来的一个新功能是 ProtectSystem Strict，该功能可以开启所有这些命名空间以完全锁定服务运行的环境。“刚刚重获自由”16、 不要使用没有运行着 SELinux（SEAndroid）强制模式的手机。幸运的是，我听说目前超过 90% 的安卓手机都运行着 SEAndroid 的强制模式，这真让我高兴。现在要是我们能让那些果粉们使用 SELinux 就好了。17、 只从受信源安装软件。不要安装你从因特网找来的危险东西，对于你的手机、计算机系统、虚拟机以及容器等等也一样。18、 我不会在我的手机上进行网上银…