Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/amazon-web-services/14.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Amazon web services 执行任意二进制文件时不允许执行操作_Amazon Web Services_Go_Aws Lambda_Terraform - Fatal编程技术网

Amazon web services 执行任意二进制文件时不允许执行操作

Amazon web services 执行任意二进制文件时不允许执行操作,amazon-web-services,go,aws-lambda,terraform,Amazon Web Services,Go,Aws Lambda,Terraform,在中,AWS解释道: 包含您自己的可执行文件很容易;只需将它们打包到上载的ZIP文件中,然后在从Node.js或之前启动的其他进程调用它们时引用它们(包括创建的ZIP文件中的相对路径)。确保在功能代码的开头包含以下内容: process.env['PATH']=process.env['PATH']+':'+process.env['LAMBDA_TASK_ROOT'] 您可以使用所有常用的进程间通信形式以及/tmp中的文件与您创建的任何进程进行通信 我想在我的代码中使用Go Terraform

在中,AWS解释道:

包含您自己的可执行文件很容易;只需将它们打包到上载的ZIP文件中,然后在从Node.js或之前启动的其他进程调用它们时引用它们(包括创建的ZIP文件中的相对路径)。确保在功能代码的开头包含以下内容: process.env['PATH']=process.env['PATH']+':'+process.env['LAMBDA_TASK_ROOT'] 您可以使用所有常用的进程间通信形式以及/tmp中的文件与您创建的任何进程进行通信

我想在我的代码中使用Go Terraform library
tfexec
,但我总是被拒绝

main/tf中的代码

package main

import (
    "context"
    "fmt"
    "os"
    "path/filepath"
    "runtime"
    "strings"

    "github.com/aws/aws-lambda-go/lambda"
    "github.com/hashicorp/terraform-exec/tfexec"
)

func Start() error {
    fmt.Printf("Go version: %s\n", runtime.Version())
    fmt.Println()

    // set environment variable, cf https://aws.amazon.com/blogs/compute/running-executables-in-aws-lambda/
    newPath := []string{
        os.Getenv("PATH"),
        ":",
        os.Getenv("LAMBDA_TASK_ROOT"),
    }
    os.Setenv("PATH", strings.Join(newPath, ""))

    // Get path to binary
    fmt.Println("Start terraform")
    currDir, err := os.Getwd()
    if err != nil {
        return err
    }
    tfBinary := filepath.Join(currDir, "terraform")

    stat, err := os.Stat(tfBinary)
    if err != nil {
        return err
    }
    fmt.Printf("Stat %s: ", tfBinary)
    fmt.Println(stat.Mode())

    // Start new instance of terraform
    tf, err := tfexec.NewTerraform(currDir, tfBinary)
    if err != nil {
        return err
    }

    tf.SetStdout(os.Stdout)
    tf.SetStderr(os.Stderr)

    // run terraform init
    fmt.Println("Tf init")
    if err = tf.Init(context.Background()); err != nil {
        return err
    }

    return nil
}

func main() {
    // Start()
    lambda.Start(Start)
}
设置:

curl -X GET -o terraform https://releases.hashicorp.com/terraform/0.12.29/terraform_0.12.29_linux_amd64.zip
chmod 755 terraform
GOOS=linux GOARCH=amd64 go build create-vpc-tf.go
zip zip.zip terraform main
# Create Lambda running on go1.x with `main` as handler
结果:

START RequestId: f23e4122-3595-48ef-808f-ef7951531f59 Version: $LATEST
Go version: go1.16

Start terraform
Stat /var/task/terraform: -rwxr-xr-x
Tf init
fork/exec /var/task/terraform: operation not permitted
fork/exec /var/task/terraform: operation not permitted: PathError
null
END RequestId: f23e4122-3595-48ef-808f-ef7951531f59
REPORT RequestId: f23e4122-3595-48ef-808f-ef7951531f59  Duration: 2.26 ms   Billed Duration: 3 ms   Memory Size: 512 MB Max Memory Used: 32 MB  Init Duration: 83.85 ms 


这在本地可以正常工作(我没有提供
*.tf
文件,所以terraform正确地报告
在空目录中初始化的terraform!

您已经下载了terraform二进制文件作为zip文件,因此它的格式无法执行

在使用
zip
重新打包之前,您需要对其进行解压缩

替换:

curl -X GET -o terraform https://releases.hashicorp.com/terraform/0.12.29/terraform_0.12.29_linux_amd64.zip
与:


当您在本地运行此程序时,应该会看到如下内容:

你的Terraform版本已经过时了

因为问题中使用的是…过时了

如果您没有看到这样的消息,则表明您的本地测试实际上没有使用您在显示的安装程序中下载的文件


下载Terraform二进制文件的更安全的方法 或者,您可以使用
tfinstall
在运行时下载并隐式解压缩最新版本,如中所示

此方法使用Hashicorp的自定义下载程序,该程序同时执行。tfinstall甚至使用Hashicorp的公钥,以确保校验和文件本身未被篡改


如果您希望避免每次运行时下载terraform,您可以在本地使用
tfinstall
,并捕获结果以供重用(基本上只是在您的设置中替换
curl
).

此问题与
tfexec
库及其在AWS lambda/Fire鞭炮环境中的可操作性有关。不允许在Fire鞭炮环境中分叉进程

Pdeathsig
强制使用叉,因此不能在AWS lambda中使用

Terraform本身不使用它,但
tfexec
使用它

例如,谷歌快速搜索显示,其他项目也遇到了同样的问题

我们打包了显示的修复程序,以防止设置
Pdeathsig
。这是对
tfexec
库的直接更改,希望它们能够吸收上游。同时,我们在
供应商
目录中直接打包
tfexec
,并直接使用
go mod
进行更改很好用

go mod init [repo]
go mod download
go mod vendor
更新供应商/github.com/hashicorp/terraform exec/tfexec/cmd_linux.go如下:


if _, ok := os.LookupEnv("LAMBDA_TASK_ROOT"); !ok {
    cmd.SysProcAttr = &syscall.SysProcAttr{
        // kill children if parent is dead
        Pdeathsig: syscall.SIGKILL,
        // set process group ID
        Setpgid: true,
    }
}
重建项目:
go1.16 build main.go


重新打包并上传到您的lambda。

在lambda中,
/var/task
是只读的。因此
terraform init
将失败,因为它无法写入
.terraform
目录。但是,由于您的错误消息表明fork或exec存在问题,这似乎不是问题。我发现一个错误可能会导致您出现一些问题ems…:)…但我无法解释它在本地是如何工作的,如果这确实是您运行的…提示-将此添加到您的脚本:
文件terraform
以下是我认为我看到的。您已经下载了
terraform\u 0.12.29\u linux\u amd64.zip
,然后尝试执行该.zip文件。它需要在某个点解压。我看不出有任何迹象表明NewTerraform不需要原始的可执行文件:下载后验证校验和也是一种良好的做法,如这里所述:,但是在解压之前你需要这样做。试图按照指示的
gpg
指令进行操作会让我发疯。你可以
tfinstall
直接获取二进制文件并验证其校验和。我最初是这样做的,但改变了我的方法,因为它导致了与帖子中所示相同的问题。我想在
/tmp
文件夹上可能会有一个
noexec
选项,出于安全原因,这是有意义的(
/tmp
是唯一可写的文件夹,所以它是唯一可以下载的地方)。我选择参考AWS文档,其中建议直接打包二进制文件@Pauline,关于
/tmp
文件夹:您可以从那里执行——我通过使用类似
exec.Command(execPath,“init”).Run()的命令运行下载的二进制文件来验证。我还发现,正如您的回答所述,您可以在调用
Run()
之前在
SysProcAttr
中设置
Pdeathsig:syscall.SIGKILL
,从而打破这一局面……但是,是的,我的回答只解决了问题中提出的部分问题。:)
go mod init [repo]
go mod download
go mod vendor

if _, ok := os.LookupEnv("LAMBDA_TASK_ROOT"); !ok {
    cmd.SysProcAttr = &syscall.SysProcAttr{
        // kill children if parent is dead
        Pdeathsig: syscall.SIGKILL,
        // set process group ID
        Setpgid: true,
    }
}