使用 NGINX Unit 实施应用隔离
原文作者:Artem Konev - Senior Technical Writer
原文链接:使用 NGINX Unit 实施应用隔离
转载来源:NGINX 中文官网
NGINX 唯一中文官方社区 ,尽在 nginx.org.cn
NGINX Unit 特性集的最新动态之一是支持应用隔离,该特性于 1.11.0 版中引入,通过 Linux 命名空间实施。
下面我们先简单回顾一下 Linux 命名空间:它本质上是一种内核机制,支持一个进程组将多种系统资源与其他进程组共享的资源分开共享。内核能够确保命名空间中的进程仅访问分配给该命名空间的资源。尽管两个不同命名空间中的进程可以共享一些资源,但其他资源对于另一个命名空间中的进程“不可见”。可在命名空间中隔离的资源类型因操作系统而异,包括进程和用户 ID、进程间通信实体、文件系统中的挂载点、网络对象等。
听起来有点乏味?也许如此,特别是在您不了解操作系统技术的情况下。但命名空间是容器化变革背后的关键因素之一,在单个操作系统实例中隔离应用进程可实现在容器中运行应用所需的关键安全和扩展机制。
想法
现在我们已经确定命名空间可能是个好东西,但 NGINX Unit 拿它有何用呢?在进一步阐释前,我们先概括介绍相关背景信息,了解一下 Tiago 本人的想法:
“我正在研究更好的方法以有效监控和拦截来自应用的流量。闲暇之余,我一直在研究 NGINX Unit 的内部机制,并认为进程隔离可能非常适用。但是,我还不确定是否是最佳方案。之前,我曾考虑 eBPF并研究它如何在内核级别重定向数据包,但后来我有了不同的想法。由于 NGINX Unit 以类似于容器运行时的方式运行并管理应用,那么如果我们为 NGINX Unit 添加应用隔离支持并使用它代替运行时,将会怎样?这一想法与 NGINX Unit 团队未来构思设计之一不谋而合。
在集群中,容器运行时启动和停止应用,因此我们了解集群中运行的一切。NGINX Unit 架构不仅做了同样的事情,而且还默认实施流量监控和拦截:到达应用的唯一途径是 NGINX Unit 的共享内存模型。值得注意的是,我们甚至能够隔离网络,类似于跳过容器内的接口设置,但应用仍可通过与 NGINX Unit 共享内存来与外界通信,而不会遭遇任何代价高昂的网络攻击。”
配置
从配置的角度来看,一切都离不开全新 isolation 对象,它定义了应用对象中的命名空间相关设置。
isolation 对象中的命名空间选项取决于系统,因为可隔离到命名空间的资源类型因操作系统而异。下面是为应用创建单独的用户 ID 和挂载点命名空间的基本示例:
{"applications": { "isolation_app": { "type": "external","executable": "/tmp/go-app","isolation": { "namespaces": { "credential": true,"mount": "true"}}}}
}
目前,NGINX Unit 支持配置 Linux 内核支持的 7 种命名空间隔离类型中的 6 种。相应配置选项为 cgroup、credential、pid、mount、network 及 uname。暂不支持最后一个类型 ipc。
默认情况下,禁用所有隔离类型(选项设置为 false),这意味着应用驻留在 NGINX Unit 命名空间中。当您通过将其选项设置为 true 来为应用启用特定隔离类型时,NGINX Unit 将为该应用创建这一类型的单独命名空间。例如,除了自身有一个单独的 mount 或 credential 命名空间外,应用还可与 NGINX Unit 位于同一命名空间。
有关 isolation 对象中选项的更多详细信息,请参阅 NGINX Unit 文档。
注:在撰写本文时,所有应用均需使用与 NGINX Unit 相同的 ipc 命名空间;此为共享内存机制要求。您可将 ipc 选项添加至配置中,但其设置无效。这一要求可能会在未来版本中发生变化。
用户和组 ID 映射
NGINX Unit 中的应用隔离包括支持 UID 和 GID 映射,如果启用 credential 隔离(这意味着您的应用在单独的凭证命名空间中运行),则可对其进行配置。您可以将应用命名空间(我们称之为 “container(容器)命名空间”)中的一系列 ID 映射至该应用父进程凭证命名空间(我们称之为 “host(主机)命名空间”)中的相同长度 ID 范围。
例如,假设您的一款应用采用非特权用户凭证运行,并启用了 credential 隔离,以便为该应用创建一个容器命名空间。NGINX Unit 支持您将主机命名空间中非特权用户的 UID 映射到容器命名空间中的 UID 0 (root)。根据设计,任何命名空间中取值为 0 的 UID 在该命名空间中拥有全部权限,而其在主机命名空间中映射对应 UID 的权限仍然受限。因此,该应用似乎拥有 root 功能,但仅可用于其命名空间内的资源。GID 映射也是如此。
此处,我们将主机命名空间中从 UID 500 开始的 10 项 UID 范围值映射到容器命名空间中从 UID 0 开始的 UID 范围值(主机:500-509,容器:0-9)。同样,我们将主机命名空间中从 GID 1000 开始的 20 项 GID 范围值映射到容器命名空间中从 GID 0 开始的范围值(主机:1000-1019,容器:0-19):
{"applications": { "isolation_app": { "type": "external","executable": "/bin/app","isolation": { "namespaces": { "credential": true},"uidmap": [ { "container": 0,"host": 500,"size": 10}],"gidmap": [ { "container": 0,"host": 1000,"size": 20}]}}}
}
如果您未创建显式 UID 和 GID 映射,默认情况下,主机命名空间中非特权 NGINX Unit 进程的当前有效 UID (EUID) 将映射到容器命名空间中的 root UID。另请注意,仅当主机操作系统支持用户命名空间时,UID/GID 映射才可用。说到这里,让我们继续了解一下应用隔离对 NGINX Unit 中运行的应用的影响。
入门:基本应用隔离
下面我们从基础开始,了解该特性运行时的行为。为此,我们将采用我们官方存储库中的一个 Go 应用(在测试新版本时运行):
package mainimport ("encoding/json""fmt""net/http""nginx/unit""os""strconv"
)type (NS struct {USER uint64PID uint64IPC uint64CGROUP uint64UTS uint64MNT uint64NET uint64}Output struct {PID intUID intGID intNS NS}
)func abortonerr(err error) {if err != nil {panic(err)}
}func getns(nstype string) uint64 {// readlink returns: [nstype]:[4026531835]str, err := os.Readlink(fmt.Sprintf("/proc/self/ns/%s", nstype))if err != nil {return 0}str = str[len(nstype)+2:]str = str[:len(str)-1]val, err := strconv.ParseUint(str, 10, 64)abortonerr(err)return val
}func handler(w http.ResponseWriter, r *http.Request) {pid := os.Getpid()out := &Output{PID: pid,UID: os.Getuid(),GID: os.Getgid(),NS: NS{PID: getns("pid"),USER: getns("user"),MNT: getns("mnt"),IPC: getns("ipc"),UTS: getns("uts"),NET: getns("net"),CGROUP: getns("cgroup"),},}data, err := json.Marshal(out)if err != nil {w.WriteHeader(http.StatusInternalServerError)return}w.Write(data)
}func main() {http.HandleFunc("/", handler)unit.ListenAndServe(": 7080", nil)
}
这段代码使用应用进程和命名空间 ID 的 JSON 格式清单响应请求,枚举 /proc/self/ns/ 目录的内容。下面我们在 NGINX Unit 中配置应用,暂时忽略 isolation 对象:
{ "listeners": { "*:8080": { "pass": "applications/go-app"}},"applications": { "go-app": { "type": "external","executable": "/tmp/go-app"}}
}
来自运行中应用实例的 HTTP 响应:
$ curl -X GET http://localhost:8080{ "PID": 5778,"UID": 65534,"GID": 65534,"NS": { "USER": 4026531837,"PID": 4026531836,"IPC": 4026531839,"CGROUP": 4026531835,"UTS": 4026531838,"MNT": 4026531840,"NET": 4026531992}
}
现在我们添加 isolation 对象,以启用应用隔离。隔离机制需要重启应用才可生效。NGINX Unit 将在幕后执行这一任务,因此从最终用户的角度来看,更新非常透明。
{ "listeners": { "*:8080": { "pass": "applications/go-app"}},"applications": { "go-app": { "type": "external","user": "root","executable": "/tmp/go-app","isolation": { "namespaces": { "cgroup": true,"credential": true,"mount": true,"network": true,"pid": true,"uname": true},"uidmap": [ { "host": 1000,"container": 0,"size": 1000}],"gidmap": [ { "host": 1000,"container": 0,"size": 1000}]}}}
}
请注意,user 选项设置为 root。启用映射到容器命名空间中的 UID/GID 0 需要执行这一设置。
我们再次发出命令:
$ curl -X GET http://localhost:8080{ "PID": 1,"UID": 0,"GID": 0,"NS": { "USER": 4026532180,"PID": 4026532184,"IPC": 4026531839,"CGROUP": 4026532185,"UTS": 4026532183,"MNT": 4026532181,"NET": 4026532187}
}
我们现已启用应用隔离,命名空间 ID 已变更 — 它们现在是容器命名空间中的 ID,而非主机命名空间中的 ID。唯一保持不变的是 IPC,原因如上所述。
深入探究:网络应用隔离
为进行深入了解,下面我们将探讨应用隔离对网络的实际影响,这对 Web 应用而言非常重要。我们为此选择的工具是 nsenter,它适用于 NGINX Unit 支持的许多操作系统发行版。该实用程序允许我们在进程命名空间内运行任意命令,我们将使用它来演示由前面配置的同一 Go 应用 isolation 对象中的不同设置引起的变化。首先,我们找出主机 PID:
更多代码详情查看NGINX社区官网
确定 PID 后,我们可以进入容器命名空间并查看其内部组成
请注意,仅环回接口可用;但该应用完全能够通过 NGINX Unit 处理外部 HTTP 请求。接下来,我们将从配置的命名空间列表中删除 network 选项,以查看禁用网络隔离的应用的最终网络接口配置
然后,我们重复执行上述相同步骤
现在还有应用进程在启动时沿用 NGINX Unit 的接口 (eth0)。
NGINX 唯一中文官方社区 ,尽在 nginx.org.cn
更多 NGINX 相关的技术干货、互动问答、系列课程、活动资源: 开源社区官网 | 微信公众号
相关文章:
使用 NGINX Unit 实施应用隔离
原文作者:Artem Konev - Senior Technical Writer 原文链接:使用 NGINX Unit 实施应用隔离 转载来源:NGINX 中文官网 NGINX 唯一中文官方社区 ,尽在 nginx.org.cn NGINX Unit 特性集的最新动态之一是支持应用隔离,该特…...

2023/09/12 qtc++
实现一个图形类(Shape) ,包含受保护成员属性:周长、面积, 公共成员函数:特殊成员函数书写 定义一个圆形类(Circle) ,继承自图形类,包含私有属性:半径 公共成员函数:特殊成员函数…...

全科医学科常用评估量表汇总,建议收藏!
根据全科医学科医生的量表使用情况,笔者整理了10个常用的全科医学科量表,可在线评测直接出结果,可转发使用,可生成二维码使用,可创建项目进行数据管理,有需要的小伙伴赶紧收藏! 日常生活能力量表…...

了解消息中间件的基础知识
为什么要使用消息中间件? 解耦:消息中间件可以使不同的应用程序通过解耦的方式进行通信,减少系统间的依赖关系提供异步通信:消息中间件可以实现异步消息传递,提高系统的响应性能。流量削峰:消息中间件可以…...

【linux】Linux wps字体缺失、加粗乱码解决
解决wps字体缺失问题 1、下载字体包 git clone https://github.com/iamdh4/ttf-wps-fonts.git2、创建单独放置字体的目录 mkdir /usr/share/fonts/wps-fonts3、复制字体到系统目录下 cp ttf-wps-fonts/* /usr/share/fonts/wps-fonts4、修改字体权限 chmod 644 /usr/share/f…...
每日两题 103二叉树的锯齿形层序遍历(数组) 513找树左下角的值(队列)
103 题目 103 给你二叉树的根节点 root ,返回其节点值的 锯齿形层序遍历 。(即先从左往右,再从右往左进行下一层遍历,以此类推,层与层之间交替进行)。 示例 1: 输入:root [3,9,…...
ROS2报错:ImportError: cannot import name ‘Log‘ from ‘rosgraph_msgs.msg‘
在使用ros2的bag命令查看数据集信息时报错 Traceback (most recent call last):File "/opt/ros/noetic/bin/rosbag", line 34, in <module>import rosbagFile "/opt/ros/noetic/lib/python3/dist-packages/rosbag/__init__.py", line 33, in <mo…...
【Vue】Vue中的代码分为哪几种类型?
在 Vue 中的代码可以分为以下几种类型: 1.模板代码 模板代码是 Vue 中用来生成 HTML 的一种语法,可以通过 Vue 的模板语法和指令来动态渲染页面。模板代码一般写在 Vue 组件的 template 标签中。 2.JavaScript 代码 JavaScript 代码是 Vue 组件中用来…...
es6中includes用法
js中的includes用法 1.数组 includes 可以判断一个数组中是否包含某一个元素,并返回true 或者false [a,b,c].includes(a) true [a,b,c].includes(1) false includes可以包含两个参数,第二个参数表示判断的起始位置 起始位置第一个数字是0。 2.字符串 …...
QT中QRadioButton实现分组C++
通过对QRadioButton组件进行分组可解决QRadioButton组件的互斥性 实现如下。 假设已设计好UI并且有UI代码情况: 头文件引用: #include <QButtonGroup> 分组功能 ,cpp文件代码实现: Your_Project::Your_Project(QWidge…...

kafka实战报错解决问题
需求 在一个在线商城中,用户下单后需要进行订单的处理。为了提高订单处理的效率和可靠性,我们使用Kafka来实现订单消息的异步处理。当用户下单后,订单信息会被发送到Kafka的一个Topic中,然后订单处理系统会从该Topic中消费订单消…...

vite+react 使用 react-activation 实现缓存页面
对应的版本 "react": "^18.2.0", "react-activation": "^0.12.4", "react-dom": "^18.2.0", "react-router-dom": "^6.15.0",react-activation 这是一个npm包,在react keep alive…...
【android 蓝牙开发——蓝牙耳机】
【android 蓝牙开发——传统蓝牙】 【android 蓝牙开发——BLE(低功耗)蓝牙 2021-10-09更新】 总结一下蓝牙开发的基本使用以及蓝牙耳机的断开和链接。 所以需权限: <uses-permission android:name"android.permission.ACCESS_FIN…...

Golang goroutine 进程、线程、并发、并行
goroutine 看一个需求 需求:要求统计1-200000000000的数字中,哪些是素数? 分析思路: 1)传统的方法,就是使用一个循环,循环的判断各个数是不是素数(一个任务就分配给一个cpu去做,这样很不划算…...

如何做到安全上网
随着信息化的发展,企业日常办公越来越依赖互联网,而访问互联网过程中,会遇到各种各样不容忽视的风险,例如员工主动故意的数据泄漏,后台应用程序偷偷向外部发信息,木马间谍软件的外联,以及各种挖…...

优维低代码实践:菜单
优维低代码技术专栏,是一个全新的、技术为主的专栏,由优维技术委员会成员执笔,基于优维7年低代码技术研发及运维成果,主要介绍低代码相关的技术原理及架构逻辑,目的是给广大运维人提供一个技术交流与学习的平台。 优维…...
git merge 如何撤销
如果只是 git merge 未进行其他 git 操作,可以使用 git merge --abort 撤销如果 git merge 之后,再 git add,可以使用 git reset HEAD 或 git reset HEAD file (前者多个文件,后者单个文件)如果 git merge 之后,再 git…...

解读package.json 中的功能
使用 npm init 比较全 一步一步的走,用于完成 package.json 中的各个声明 npm init -y 生成简易的模板下面解读下 package.json 中的功能"version": "1.0.0", //版本号1. 主版本号:非常大的改动 vue2 和 vue3 的改变 2. 功能的升级,…...

UMA 2 - Unity Multipurpose Avatar☀️四.UMA人物部位的默认颜色和自定义(共享)颜色
文章目录 🟥 人物颜色介绍1️⃣ 使用默认颜色2️⃣ 使用自定义颜色🟧 UMA自定义颜色的作用🟨 自定义颜色还可作为共享颜色🟥 人物颜色介绍 UMA不同部位的颜色分为默认的内置颜色和我们新定义的颜色. 1️⃣ 使用默认颜色 比如不勾选UseSharedColor时,使用的眼睛的默认…...

phpstorm配置php运行环境
1,首先安装phpstrom,按照提示的步骤一步一步来就行 2,新建一个项目然后在里面找到这个位置 3,找到php所在的位置,找不到就直接在搜索框中搜索 4,这里要配置php的运行环境,一定要记得自己安装软…...
Golang 面试经典题:map 的 key 可以是什么类型?哪些不可以?
Golang 面试经典题:map 的 key 可以是什么类型?哪些不可以? 在 Golang 的面试中,map 类型的使用是一个常见的考点,其中对 key 类型的合法性 是一道常被提及的基础却很容易被忽视的问题。本文将带你深入理解 Golang 中…...
STM32+rt-thread判断是否联网
一、根据NETDEV_FLAG_INTERNET_UP位判断 static bool is_conncected(void) {struct netdev *dev RT_NULL;dev netdev_get_first_by_flags(NETDEV_FLAG_INTERNET_UP);if (dev RT_NULL){printf("wait netdev internet up...");return false;}else{printf("loc…...

YSYX学习记录(八)
C语言,练习0: 先创建一个文件夹,我用的是物理机: 安装build-essential 练习1: 我注释掉了 #include <stdio.h> 出现下面错误 在你的文本编辑器中打开ex1文件,随机修改或删除一部分,之后…...

【SQL学习笔记1】增删改查+多表连接全解析(内附SQL免费在线练习工具)
可以使用Sqliteviz这个网站免费编写sql语句,它能够让用户直接在浏览器内练习SQL的语法,不需要安装任何软件。 链接如下: sqliteviz 注意: 在转写SQL语法时,关键字之间有一个特定的顺序,这个顺序会影响到…...

涂鸦T5AI手搓语音、emoji、otto机器人从入门到实战
“🤖手搓TuyaAI语音指令 😍秒变表情包大师,让萌系Otto机器人🔥玩出智能新花样!开整!” 🤖 Otto机器人 → 直接点明主体 手搓TuyaAI语音 → 强调 自主编程/自定义 语音控制(TuyaAI…...

零基础设计模式——行为型模式 - 责任链模式
第四部分:行为型模式 - 责任链模式 (Chain of Responsibility Pattern) 欢迎来到行为型模式的学习!行为型模式关注对象之间的职责分配、算法封装和对象间的交互。我们将学习的第一个行为型模式是责任链模式。 核心思想:使多个对象都有机会处…...
Fabric V2.5 通用溯源系统——增加图片上传与下载功能
fabric-trace项目在发布一年后,部署量已突破1000次,为支持更多场景,现新增支持图片信息上链,本文对图片上传、下载功能代码进行梳理,包含智能合约、后端、前端部分。 一、智能合约修改 为了增加图片信息上链溯源,需要对底层数据结构进行修改,在此对智能合约中的农产品数…...

排序算法总结(C++)
目录 一、稳定性二、排序算法选择、冒泡、插入排序归并排序随机快速排序堆排序基数排序计数排序 三、总结 一、稳定性 排序算法的稳定性是指:同样大小的样本 **(同样大小的数据)**在排序之后不会改变原始的相对次序。 稳定性对基础类型对象…...

Scrapy-Redis分布式爬虫架构的可扩展性与容错性增强:基于微服务与容器化的解决方案
在大数据时代,海量数据的采集与处理成为企业和研究机构获取信息的关键环节。Scrapy-Redis作为一种经典的分布式爬虫架构,在处理大规模数据抓取任务时展现出强大的能力。然而,随着业务规模的不断扩大和数据抓取需求的日益复杂,传统…...

软件工程 期末复习
瀑布模型:计划 螺旋模型:风险低 原型模型: 用户反馈 喷泉模型:代码复用 高内聚 低耦合:模块内部功能紧密 模块之间依赖程度小 高内聚:指的是一个模块内部的功能应该紧密相关。换句话说,一个模块应当只实现单一的功能…...