gpt4 book ai didi

go - 这是在 Linux 上以 root 身份运行部分 go 代码的合理方法吗?

转载 作者:行者123 更新时间:2023-12-04 17:18:55 25 4
gpt4 key购买 nike

在 Linux 上以 root 身份运行部分 go 代码的最佳方式是什么?我正在编写一个相当大的网络应用程序,不想以 root 身份运行整个应用程序。一些代码需要操作网络堆栈、防火墙规则等,因此必须以 root 身份运行。

目前,我已经创建了一个小型 stub 可执行文件,可在我的大型应用程序中调用代码。然后我编译 stub 并设置 Linux suid 位。然后,我从我的主 go 应用程序中将其作为 shell 命令调用。

它有效。但这是最有效的方法吗?有惯用的方法吗?

B 计划是使用来自小型 HTTP 服务的 REST API。尽管这有点难以保护。

想法?

例如... exec doupdate 为 root 权限设置了 suid

从网络应用中...

// Elevate UpdateNft to root
func ElevateUpdateNFT() string {
out, err := exec.Command("doupdate", "nft").CombinedOutput()
if err != nil {
log.Print("exec doupdate ", err)
}
if len(out) > 0 {
log.Print(string(out))
}
return string(out)
}

在 doupdate 内部,以 root 身份执行...CallUpdateNft 返回到主 Web 应用程序中,但现在以 root 权限运行。

func main() {
...
case key == "nft":
models.CallUpdateNft()
...
}

最佳答案

您的方法没有任何问题,但 suid 二进制文件 have a poor reputation...


据我所知,至少有三种方法可以做到这一点。

  1. 以 root 身份启动,并删除不需要 root 的部分的权限
  2. 允许某些用户以 root 身份使用 sudo 运行命令
  3. 让特权进程做某事

一个

这将在没有特权的情况下运行 Web 服务器。


cmd := exec.Command("/bin/webserver", "--foo", "--bar")
cmd.SysProcAttr = &syscall.SysProcAttr{
Credential: &syscall.Credential{
Gid: uint32(33),
Uid: uint32(33)}}
cmd.Start();

两个

/etc/sudoers.d/www-数据:

www-data ALL=(ALL) NOPASSWD: /bin/webserver

cmd := exec.Command("sudo", "/bin/webserver", "--foo", "--bar")
cmd.Start();

三个

与特权进程通信并让它做事。

$ go run both.go library.go  /etc/shadow
0
open /etc/shadow: permission denied

作为根服务器:

$ make serve 
go build -o server server.go library.go ; sudo ./server

然后连接:

$ ./client /etc/shadow  | wc -l
1918
ok.
69

生成文件

all: stop
go build -o client client.go library.go
go build -o server server.go library.go
./server & sleep 0.2
./client $(path)
both:
go build -o sc both.go library.go && ./sc $(path)
stop: ; killall server || true
serve: ; go build -o server server.go library.go ; sudo ./server
clean: ; rm -vf client sc server

both.go

package main

import (
"fmt"
"os"
"sync"
)

func main() {
wg := &sync.WaitGroup{}
wg.Add(1)
go Server(wg, "")


path := "main.go"
if len(os.Args) > 1 {
path = os.Args[1]
}
resp, err := Client(path)

if nil == err {
fmt.Print(resp.Output)
} else {
println(err.Error())
}
wg.Wait()

}

客户端.go

package main

import (
"fmt"
"os"
)

func main() {
path := "/dev/null"
if len(os.Args) > 1 {
path = os.Args[1]
}
resp, err := Client(path)
if nil == err {
println("ok.")
fmt.Print(resp.Output)
} else {
println(err.Error())
}

}

图书馆.go

package main

import (
"net"
"net/rpc"
"os"
"sync"
"time"
)

const Addr = "localhost:31337"

type Api struct {
server *rpc.Server
quit *sync.WaitGroup
}

func newApi(address string, wg *sync.WaitGroup) (*Api, error) {
if len(address) == 0 {
address = Addr
}
rpcs := rpc.NewServer()
errR := rpcs.RegisterName("V1", &MethodsV1{ Quit : wg })
sock, errL := net.Listen("tcp", address)
if errR != nil {
return nil, errR
}
if errL != nil {
return nil, errL
}
go rpcs.Accept(sock)
return &Api{server: rpcs, quit: wg}, nil
}

func Server(wg *sync.WaitGroup, addr string) {
_, err := newApi(addr, wg)
if err != nil {
return
}
if wg != nil {
wg.Wait()
} else {
<- time.After(time.Second * 50)
}
}

func Client(path string) (RpcResponse, error) {
addr := Addr
if a := os.Getenv("ADDR"); len(a) > 0 {
addr = a
}
resp := RpcResponse{}
client, errC := rpc.Dial("tcp", addr)
if nil == errC {
errC = client.Call("V1.Cat", &path, &resp);
println(len(resp.Output))
}
return resp, errC
}

type RpcResponse struct { Output string }
type MethodsV1 struct {
Quit *sync.WaitGroup
}

func (m1 *MethodsV1) Cat(path *string, response *RpcResponse) error {
if m1.Quit != nil {
defer m1.Quit.Done()
}
o, err := os.ReadFile(*path)
response.Output = string(o)
return err
}

server.go

package main

func main() {
Server(nil, "")
}

关于go - 这是在 Linux 上以 root 身份运行部分 go 代码的合理方法吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/67347905/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com