如果您不想在 root 上运行,为什么 Linux 自托管运行器上的 Github Action 需要对每个命令进行用户交换

问题描述

我编写了一个工作流,用于在 Linux 自托管 GitHub 运行器 VM 上安装一些工具依赖项。我正在使用自制软件来安装工具。使用自制软件要求它不能在 GitHub Runner 登录的 root 用户上运行。我想知道为什么当我创建一个用户从 root 切换到我的测试用户的步骤时,事情会中断,但是当我在每一步都向该用户 sudo 时一切正常,我想我对此的解释很糟糕,因此请参见下文:

Failing Workflow(你可以看到第一步将用户切换到了testUser):

 installHomebrew:
    name: Install Homebrew
    runs-on: [self-hosted]
        
    steps:
      - name: Switch to etpAdmin user
        run: sudo -u testUser -i

      - name: Install Homebrew silently
        run: sudo apt install linuxbrew-wrapper -y
        
      - name: Run brew for the first time to create the .linuxbrew directory
        run: brew -h

这将在最后一步失败,声称自制软件不应在 root 上运行,而以下工作流程工作正常。

 installHomebrew:
    name: Install Homebrew
    runs-on: [self-hosted]
        
    steps:
      - name: Install Homebrew silently
        run: sudo apt install linuxbrew-wrapper -y
        
      - name: Run brew for the first time to create the .linuxbrew directory
        run: sudo -u testUser -i brew -h

我的 Linux 有点生疏,但我的印象是使用 sudo -u (username) -i 会将终端登录到指定用户,直到再次注销/切换用户,我错了还是有更好的方法来完成此操作?

解决方法

免责声明;我不熟悉您运行的平台或您使用的工具,但我确实有一个有根据的猜测..我希望这也是 -i 标志的行为方式。

由于大多数供应商的工作,他们通常(大部分)独立于其他步骤运行每个步骤。这(同样,通常)意味着从一个步骤开始的环境不会延续到下一个步骤。所以在这种情况下,在一个步骤中运行 sudo -i 不会对后续步骤产生任何影响。你可以试试这个,看看你的情况下的供应商是如何运作的:

testUserChange:
    name: Test active user
    runs-on: [self-hosted]
        
    steps:
      - name: Default user
        run: whoami
        
      - name: Sudo user
        run: sudo -u testUser -i whoami

      - name: Should be default user again
        run: whoami

      - name: Maybe interactive shell like in first attempt
        run: sudo -u testUser -i

      - name: Who am I now
        run: whoami

现在对于 -i,手册指出:

这意味着 shell 将读取特定于登录名的资源文件,例如 .profile 或 .login。如果指定了命令,则会通过 shell 的 -c 选项将其传递给 shell 以执行。如果未指定命令,则执行交互式 shell。

虽然这可能有点令人困惑,因为大多数供应商不希望在运行时用户交互输入,他们通常会关闭 STDIN 句柄(进程的输入)。如果我们有两个用户,user0neusertw0,我希望我可以演示该行为;

$ export PS1="This is user0ne env \$ " # just to show when environment variables are re-set due to loading the login scripts
This is user0ne env $
This is user0ne env $ whoami
user0ne
This is user0ne env $ sudo -u usertw0 /bin/sh
This is user0ne env $ whoami
usertw0
This is user0ne env $ exit
This is user0ne env $ whoami
user0ne
This is user0ne env $

在上面的例子中,你可以看到,虽然有效用户是tw0,但环境仍然设置为0ne所设置的。让我们试试 -i

This is user0ne env $ sudo -u usertw0 -i /bin/sh
$ whoami
usertw0
$ exit
This is user0ne env $

现在,看起来 -i 将环境(和登录)设置为 tw0。现在,虽然文档确实声明没有任何参数会打开交互式 shell:

This is user0ne env $ sudo -u usertw0 -i
To run a command as administrator (user "root"),use "sudo <command>".
See "man sudo_root" for details.

usertw0@ubuntu:~$ logout
This is user0ne env $

让我们看看如果我们关闭输入处理程序(或者更准确地说,什么都不输入)会发生什么:

This is user0ne env $ sudo -u usertw0 -i < /dev/null
This is user0ne env $ whoami
user0ne
This is user0ne env $

即使您提供 /bin/sh 作为要运行的命令,也会发生同样的情况,如上面的代码片段所示:

This is user0ne env $ sudo -u usertw0 -i /bin/sh < /dev/null
This is user0ne env $ whoami
user0ne
This is user0ne env $

因此,即使文档确实声明它将打开一个交互式 shell,但一旦没有要读取的输入,shell 就会关闭,并且状态返回给前一个用户。

干杯! :)