我的项目中有一个基于 golang 的应用程序和关联的 systemd 文件。我正在开发一个 bash 脚本 ( install.sh
)(或者 Makefile,如果这是一个更好的选择),它有助于自动执行以下操作(基本上按此顺序),但遇到了权限问题:
目标:
以非 root 用户身份自动构建应用程序二进制文件
将systemd文件复制到正确的路径(需要提升权限)
停止/启动服务以加载更新的应用程序(需要提升的权限)。
bash 脚本中的理想步骤:
- 作为非 sudo/非提升用户,删除现有的二进制文件并重建它
go build -o binary_name .
。此步骤应该以我的用户身份运行(将代码编译为 sudo 不是一个好主意。) - 提升权限
- 删除现有
/etc/systemd/system/binary_name.service
文件。 - 将文件复制
binary_name.service
到,/etc/systemd/system/binary_name.service
以防其更新。 - 停止并重新启动该
binary_name
服务。
我遇到的问题: - 如果我执行sudo install.sh
,我们会遇到“不要编译为 sudo/root”问题。另外,go
由于环境设置不同,找不到该包。 - 如果我在没有 sudo 的情况下执行install.sh
,则当脚本尝试删除/复制服务文件时会出现权限问题。
以下是当前脚本的缩写版本:
#!/bin/bash
case "$1" in
(das_application)
cd /usr/local/apps/das_application/
# rebuild das_application binary
echo "Removing old das_application binary"
rm das_application
echo "Building updated das_application binary"
go build -o das_application .
echo "Done building das_application binary"
echo "Stopping das_application service"
sudo systemctl stop das_application
echo "Copying das_application.service to /etc/systemd/system"
rm /etc/systemd/system/das_application.service
cp ./conf/das_application.service /etc/systemd/system/das_application.service
systemctl daemon-reload
echo "Starting das_application service"
systemctl start das_application.service
exit 1
;;
(*)
echo "Use as ./install.sh das_application"
exit 2
;;
esac
答案1
好问题。可能的解决方案之一是检查脚本是否正在运行sudo
,如果不是则退出,并暂时放弃运行应以普通用户身份运行的命令的权限。像这样的东西:
#!/usr/bin/env sh
if [ -z "$SUDO_USER" ]
then
printf "Not running with sudo. Exiting\n"
exit 1
fi
touch SUDO-FILE
# drop privileges temporarily
su "$SUDO_USER" -c 'touch REGULAR-FILE'
运行后,您可以看到 2 个文件 -SUDO-FILE
由 root 及其主要组拥有,以及REGULAR-FILE
由普通用户及其主要组拥有的文件:
$ ls -Alhtr SUDO-FILE REGULAR-FILE
-rw-r--r-- 1 root root 0 Dec 5 21:06 SUDO-FILE
-rw-r--r-- 1 ja users 0 Dec 5 21:06 REGULAR-FILE
在 Slackware Linux 和 FreeBSD 上进行了测试。您还可以使用su -l
它来获取常规用户的 shell 登录脚本,例如~/.profile
.
我不确定该解决方案有哪些缺点和可能的陷阱,因此请确保在生产中使用它之前进行了一些测试。
答案2
我会把你的脚本分成两部分:
构建一个,不需要以 root 身份运行。 (您当前的
install.sh
将被重命名build.sh
)需要安装一个,需要以 root 身份运行。 (真实的
deploy.sh
)。
而且,为什么不调用第三个脚本install.sh
并执行以下操作:
- 定期打电话
build.sh
。 - 称呼
sudo deploy.sh