Go Lambda在S3 PutObject上具有完全访问策略时出现403访问被拒绝的问题。

huangapple go评论89阅读模式
英文:

Go Lambda with Full Access Policy 403 Access Denied on S3 PutObject

问题

我正在尝试使用Go语言通过Lambda将文件上传到S3存储桶。我可以无问题地从存储桶中读取对象,但是每当我尝试将对象上传到存储桶时,就会出现"Access Denied"错误。

为了调试,我创建了以下简单的Lambda函数:

package main

import (
	"bytes"
	"context"
	"log"

	"github.com/aws/aws-lambda-go/lambda"
	"github.com/aws/aws-sdk-go-v2/aws"
	"github.com/aws/aws-sdk-go-v2/service/s3"
)

func LambdaMainWrapper() {
	data := []byte("this is some data stored as a byte slice in Go Lang!")

	// convert byte slice to io.Reader
	reader := bytes.NewReader(data)

	// upload to s3
	client := s3.New(s3.Options{Region: "us-east-2"})
	putObjectInput := &s3.PutObjectInput{
		Bucket: aws.String(<MY_BUCKET_NAME>),
		Key:    aws.String("test-file"),
		Body:   reader,
	}
	res, err := client.PutObject(context.Background(), putObjectInput)
	if err != nil {
		log.Fatal("Error uploading object to S3: ", err)
	}

	log.Println("[s3 res]", res)
}

func main() {
	lambda.Start(LambdaMainWrapper)
}

这是函数执行角色上附加的策略,据我理解,它授予函数上传对象到存储桶所需的所有权限:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "ExampleStmt",
            "Action": [
                "s3:GetObject"
            ],
            "Effect": "Allow",
            "Resource": [
                "arn:aws:s3:::<MY_BUCKET_NAME>/*"
            ]
        },
        {
            "Sid": "ExampleStmt2",
            "Action": [
                "s3:PutObject"
            ],
            "Effect": "Allow",
            "Resource": [
                "arn:aws:s3:::<MY_BUCKET_NAME>/*"
            ]
        },
        {
            "Sid": "ExampleStmt3",
            "Action": [
                "s3:PutObjectAcl"
            ],
            "Effect": "Allow",
            "Resource": [
                "arn:aws:s3:::<MY_BUCKET_NAME>/*"
            ]
        }
    ]
}

Lambda返回以下信息:

START RequestId: XXX Version: $LATEST
2022/01/25 16:39:06 Error uploading object to S3: operation error S3: PutObject, https response error StatusCode: 403, RequestID: XXXXXXXXXX, HostID: XXXXXXXXXXXXXXXXXXXXXXXXXXXXX, api error AccessDenied: Access Denied
2022/01/25 16:39:06 unexpected EOF
2022/01/25 16:39:06 unexpected EOF
END RequestId: XXX

我正在努力找出这个问题的根本原因,是我的Go S3客户端配置错误,还是我在AWS中配置了错误的权限。甚至可能是我错误地发送了对象的Body,这可能解释了"unexpected EOF"的消息。非常感谢您的帮助!

英文:

I'm attempting to upload a file to an S3 bucket via Lambda in Go. I am able to read objects from the bucket with no issues, but I get Access Denied errors whenever I try to upload an object to the bucket.

To debug, I created the following simple Lambda function:

package main

import (
	&quot;bytes&quot;
	&quot;context&quot;
	&quot;log&quot;

	&quot;github.com/aws/aws-lambda-go/lambda&quot;
	&quot;github.com/aws/aws-sdk-go-v2/aws&quot;
	&quot;github.com/aws/aws-sdk-go-v2/service/s3&quot;
)

func LambdaMainWrapper() {
	data := []byte(&quot;this is some data stored as a byte slice in Go Lang!&quot;)

	// convert byte slice to io.Reader
	reader := bytes.NewReader(data)

	// upload to s3
	client := s3.New(s3.Options{Region: &quot;us-east-2&quot;})
	putObjectInput := &amp;s3.PutObjectInput{
		Bucket: aws.String(&lt;MY_BUCKET_NAME&gt;),
		Key:    aws.String(&quot;test-file&quot;),
		Body:   reader,
	}
	res, err := client.PutObject(context.Background(), putObjectInput)
	if err != nil {
		log.Fatal(&quot;Error uploading object to S3: &quot;, err)
	}

	log.Println(&quot;[s3 res]&quot;, res)
}

func main() {
	lambda.Start(LambdaMainWrapper)
}

And here is the attached policy on the execution role for the function, which to my understanding grants it all the permissions it would need to upload an object to the bucket:

{
    &quot;Version&quot;: &quot;2012-10-17&quot;,
    &quot;Statement&quot;: [
        {
            &quot;Sid&quot;: &quot;ExampleStmt&quot;,
            &quot;Action&quot;: [
                &quot;s3:GetObject&quot;
            ],
            &quot;Effect&quot;: &quot;Allow&quot;,
            &quot;Resource&quot;: [
                &quot;arn:aws:s3:::&lt;MY_BUCKET_NAME&gt;/*&quot;
            ]
        },
        {
            &quot;Sid&quot;: &quot;ExampleStmt2&quot;,
            &quot;Action&quot;: [
                &quot;s3:PutObject&quot;
            ],
            &quot;Effect&quot;: &quot;Allow&quot;,
            &quot;Resource&quot;: [
                &quot;arn:aws:s3:::&lt;MY_BUCKET_NAME&gt;/*&quot;
            ]
        },
        {
            &quot;Sid&quot;: &quot;ExampleStmt3&quot;,
            &quot;Action&quot;: [
                &quot;s3:PutObjectAcl&quot;
            ],
            &quot;Effect&quot;: &quot;Allow&quot;,
            &quot;Resource&quot;: [
                &quot;arn:aws:s3:::&lt;MY_BUCKET_NAME&gt;/*&quot;
            ]
        }
    ]
}

Lambda reports back:

START RequestId: XXX Version: $LATEST
2022/01/25 16:39:06 Error uploading object to S3: operation error S3: PutObject, https response error StatusCode: 403, RequestID: XXXXXXXXXX, HostID: XXXXXXXXXXXXXXXXXXXXXXXXXXXXX, api error AccessDenied: Access Denied
2022/01/25 16:39:06 unexpected EOF
2022/01/25 16:39:06 unexpected EOF
END RequestId: XXX

I'm struggling to root cause this as an error with my Go S3 client configuration or if I've configured permissions within AWS incorrectly. It could even be that I'm sending the Body of the object incorrectly - which might explain the unexpected EOF messages. Any help is much appreciated, thanks!

e: using local S3 client (no lambda), I was able to succesfully upload and download objects from S3.

答案1

得分: 4

问题已翻译完成:

原来问题出在凭证上。我访问的存储桶允许公开读取访问权限,所以我的 GetObject 调用是有效的。然而,它不允许公开写入访问权限,所以 PutObject 调用导致了 403 Access Denied 错误 🤦‍♂️ 我以为我的 GetObject 调用已经通过身份验证,但你知道人们常说的那句话...

修复方法很简单,只需将代码更改为:

// 上传到 S3
client := s3.New(s3.Options{Region: "us-east-2"})

改为

cfg, err := config.LoadDefaultConfig(context.TODO())
cfg.Region = "us-east-2"
client := s3.NewFromConfig(cfg)

感谢 @jarmod 让我意识到我应该尝试使用 Lambda 函数的本地默认配置,就像在本地主机上运行时一样!

英文:

Turns out the issue was credentials. The bucket I am accessing allows public read access, hence why my GetObject calls were working. However, it does not allow public write access, so PutObject calls were resulting in 403 Access Denied 🤦‍♂️ I assumed my GetObject calls were authenticated, but you know what they say about assuming...

The fix was simply changing

// upload to s3
client := s3.New(s3.Options{Region: &quot;us-east-2&quot;})

to

cfg, err := config.LoadDefaultConfig(context.TODO())
cfg.Region = &quot;us-east-2&quot;
client := s3.NewFromConfig(cfg)

thanks @jarmod for making me realize I should attempt to use the lambda function's local default config, as one does when running on localhost !

huangapple
  • 本文由 发表于 2022年1月26日 00:48:54
  • 转载请务必保留本文链接:https://go.coder-hub.com/70852535.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定