V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
Distributions
Ubuntu
Fedora
CentOS
中文资源站
网易开源镜像站
guanzhangzhang
V2EX  ›  Linux

有没有非 root 用户下,能创建出一个隔离 rootfs 内的交互式 shell 的轮子

  •  
  •   guanzhangzhang ·
    zhangguanzhang · 2023-10-12 19:34:20 +08:00 · 2180 次点击
    这是一个创建于 436 天前的主题,其中的信息可能已经有所发展或是发生改变。

    比如 test01 执行个轮子后,进入了一个隔离的 chroot 类似。

    主要是 web 上点击提供一个 web shell 类似,里面的 rootfs 带了 kubectl ,目前同事用 webkubectl 项目使用,但是前不久客户让改为非 root 启动。大致看了下它的实现

    1. 特权容器内 root 用户执行 gotty 启动 start-session.sh 作为 pid 为 1 的角色
    2. 每次访问 web 就是执行 start-session.sh 的内容
      1. unshare --fork --pid --mount-proc --mount xxx.sh 启动隔离空间
      2. mkdir -p /nonexistent ,mount -t tmpfs -o size=${SESSION_STORAGE_SIZE} tmpfs /nonexistent 和一系列处理文件
      3. exec su nobody bash

    然后改为非 root 启动 gotty 后,没有执行 unshare 和 mount 权限,所以来问下有没有什么轮子,非 root 用户执行,能 chroot 到一个小巧的 rootfs 内的 shell 交互(该 shell 内什么用户都行,对 chroot 之前的无影响)。目前试过 proot ,容器内 root 都无法启动

    第 1 条附言  ·  2023-10-13 09:27:35 +08:00
    1. 不是换掉 docker 和用 rootless ,目前是逐步改所有容器,可能最后有些容器改不了(技术方案下业务进程必须 root 启动),暂时不能换掉 docker 的😁
    2. 还有最好这个轮子能够简单且少依赖或者静态编译到 arm64/loongarch64 架构😘
    29 条回复    2023-10-13 16:20:35 +08:00
    vcn8yjOogEL
        1
    vcn8yjOogEL  
       2023-10-12 19:38:18 +08:00
    podman?
    codehz
        2
    codehz  
       2023-10-12 21:22:01 +08:00
    你都 unshare 了,不如再 map-root-user 一下(也就是用 user namespace )
    不过你这个“小巧的 rootfs 内的 shell 交互”真的可以在非特权用户下跑吗?
    你这个 rootfs 要可变的还是不可变的呢
    不可变的话,我这有一个封装 rootfs 的小工具 https://github.com/codehz/EasyPak ,本来是用于快速封装一个二进制及其依赖到单文件
    只是单纯 chroot 的话,unshare 的 map-root-user 应该就可以用了
    ysc3839
        3
    ysc3839  
       2023-10-12 21:30:13 +08:00 via Android
    直接用 Docker ?不过 docker daemon 也是要 root 的。这类系统级的功能估计都很难绕开 root ,真要搞的话只能依靠一些复杂的用户模式沙盒/虚拟化来实现了。
    huahsiung
        4
    huahsiung  
       2023-10-12 23:00:46 +08:00
    proot 行啊。假如 rootfs 根目录为/home/user0/rootfs 。直接 proot -S /home/user0/rootfs /bin/bash 就进入容器内的 bash 了。

    你试试

    ```bash
    ~$:whoami
    user0

    ~$:proot -S /home/user0/rootfs /bin/bash
    ~$:whoami
    root
    ```

    用 proot 当轻量容器我用很久了
    deorth
        5
    deorth  
       2023-10-12 23:26:25 +08:00 via Android
    proot
    wizardyhnr
        6
    wizardyhnr  
       2023-10-13 06:29:54 +08:00
    @ysc3839 docker 有 rootless 的模式
    guanzhangzhang
        7
    guanzhangzhang  
    OP
       2023-10-13 09:24:39 +08:00
    @codehz 大佬,咨询下,你说的情况在非 root 用户下,unshare 参数是多少😘
    guanzhangzhang
        8
    guanzhangzhang  
    OP
       2023-10-13 09:29:02 +08:00
    @huahsiung 难道是我下载的 proot 不对吗,我是在 https://github.com/proot-me/proot-static-build 下载的
    codehz
        9
    codehz  
       2023-10-13 09:58:58 +08:00
    @guanzhangzhang unshare --fork --pid --map-root-user --mount-proc --propagation slave --setgroups deny
    里面直接 mount/chroot 都没问题
    codehz
        10
    codehz  
       2023-10-13 10:00:36 +08:00
    哦,不要加 setgroups
    ysc3839
        11
    ysc3839  
       2023-10-13 10:06:51 +08:00 via Android
    @wizardyhnr 那不就完美解决楼主的问题了?程序自带一个 Docker 即可。
    guanzhangzhang
        12
    guanzhangzhang  
    OP
       2023-10-13 10:11:10 +08:00
    @codehz #10 大佬,map-root-user 后无法给结尾 nobody 需要的家目录,而且看似乎是--mount 配合形成 webkubectl 的 shell 隔离的
    ```
    guanzhang@guan:~$ unshare --fork --pid --map-root-user --mount-proc --propagation slave bash
    root@guan:~# mkdir -p /nonexistent
    mkdir: cannot create directory ‘/nonexistent’: Permission denied
    ```
    codehz
        13
    codehz  
       2023-10-13 10:15:18 +08:00
    @guanzhangzhang 生活小技巧
    在/tmp 上再挂一层 tmpfs ,然后把其他目录 bind mount 进去,接着 chroot 进/tmp ,然后再执行 mkdir 一类的操作
    codehz
        14
    codehz  
       2023-10-13 10:20:37 +08:00
    此外你可以选择先切到 nobody 再执行上面说的 unshare ,因为在 map-root-user 的模式下,没有办法再切别的用户了
    codehz
        15
    codehz  
       2023-10-13 10:21:35 +08:00
    仔细想你这只是为了家目录可写入的话,可以简单的直接在 unshare 里面 mount -t tmpfs tmpfs /root ,这样/root 就是可写入的家目录了
    guanzhangzhang
        16
    guanzhangzhang  
    OP
       2023-10-13 11:25:41 +08:00
    @codehz #14 😢我发现容器内非 root 用户执行 unshare 的时候不能带--pid ,否则 unshare: unshare(0x20000000): Operation not permitted
    codehz
        17
    codehz  
       2023-10-13 11:28:15 +08:00
    pid namespace 好像问题不大,主要是方便一键咔掉子进程,这个可以用原用户开()
    guanzhangzhang
        18
    guanzhangzhang  
    OP
       2023-10-13 11:29:07 +08:00
    @huahsiung 我发现 proot 能杀掉父进程,有隔离进程的吗,容器内非 root 执行 unshare 不能带--pid 的隔离
    guanzhangzhang
        19
    guanzhangzhang  
    OP
       2023-10-13 11:30:52 +08:00
    @codehz #17 大佬,没看懂这个怎么搞
    codehz
        20
    codehz  
       2023-10-13 11:38:55 +08:00
    @guanzhangzhang 就是先用容器内的 root ,unshare --fork --pid
    然后里面再 su nobody unshare ...
    huahsiung
        21
    huahsiung  
       2023-10-13 11:54:03 +08:00
    @guanzhangzhang proot 不要下 static 编译的版本,可以直接从 apt 源安装。static 版本不依赖 so 库,trace 注入就有毛病。

    static 版本有一些 bug 。不是静态版本的 proot ,如果杀掉父进程,子进程会被一起杀掉。
    huahsiung
        22
    huahsiung  
       2023-10-13 13:18:55 +08:00
    没注意到这句话"容器内 root 用户执行 gotty 启动 start-session.sh 作为 pid 为 1 的角色",然后再 unshare ??

    原来已经是在容器中了??

    容器中是已经 chroot 的环境了,在 chroot 下,unshare 会有点问题。chroot 是这样的,可以看看 pivot_root
    guanzhangzhang
        23
    guanzhangzhang  
    OP
       2023-10-13 14:51:24 +08:00
    @huahsiung d618c8435f6d:/# proot -S /nonexistent/test /bin/sh
    d618c8435f6d:/# echo $?
    255
    执行不了。。。
    guanzhangzhang
        24
    guanzhangzhang  
    OP
       2023-10-13 14:54:32 +08:00
    @codehz #20 看了下逻辑流程不行,主要是非 root 的 gotty 执行脚本创建环境,如果 entrypoint.sh 隔离 pid ,然后内部 gotty 和最终的都是同一个 pid namespace ,😘,不过我们不用一个 webkubectl 操作多个 k8s ,不隔离也行。我去折腾下 proot
    codehz
        25
    codehz  
       2023-10-13 15:40:47 +08:00
    @guanzhangzhang 哦,也不是完全不行
    我就整了一个 https://github.com/codehz/nobodyexec 编译好之后,
    unshare --pid --mount-proc --fork --propagation slave ./nobodyexec unshare --map-root-user bash start-session.sh
    start-session.sh 现在就是 pid 1 的位置了
    huahsiung
        26
    huahsiung  
       2023-10-13 15:52:06 +08:00
    @guanzhangzhang 看看/nonexistent/test 是完整的 rootfs ,并且/nonexistent/test/bin/sh 的依赖存在(/nonexistent/test/etc,/nonexistent/test/usr 等等),另外你可以试试 static 版本的 bash 。

    http://ftp.debian.org/debian/pool/main/b/bash/bash-static_5.2.15-2+b2_amd64.deb
    62742a40
        27
    62742a40  
       2023-10-13 15:54:01 +08:00
    看看我的文章满足你的需求吗
    blog.fansluck.top/non-root-container-guide.html
    guanzhangzhang
        28
    guanzhangzhang  
    OP
       2023-10-13 16:00:38 +08:00
    @62742a40 不是。。。你这只适用于简单的命令和单个二进制启动
    Jirajine
        29
    Jirajine  
       2023-10-13 16:20:35 +08:00 via Android
    你直接起 rootless container 不就完了,不需要自己手动 unshare 。
    单应用 oci 镜像就用 podman ,系统镜像自己管理 rootfs 用 lxc 。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2411 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 25ms · UTC 15:46 · PVG 23:46 · LAX 07:46 · JFK 10:46
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.