Amazon S3存储桶返回403禁止访问错误

74

我最近继承了一个使用S3存储资源的Rails应用程序。我已经将所有资源转移到我的S3存储桶中,没有任何问题。但是,当我更改应用程序指向新存储桶时,我收到403禁止状态。

我的S3存储桶设置如下:

权限

所有人都可以列出

存储桶策略

{
 "Version": "2012-10-17",
 "Statement": [
    {
        "Sid": "PublicReadGetObject",
        "Effect": "Allow",
        "Principal": "*",
        "Action": "s3:GetObject",
        "Resource": "arn:aws:s3:::bucketname/*"
    }
 ]
}

CORS配置

<?xml version="1.0" encoding="UTF-8"?>
<CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
    <CORSRule>
        <AllowedOrigin>*</AllowedOrigin>
        <AllowedMethod>GET</AllowedMethod>
        <MaxAgeSeconds>3000</MaxAgeSeconds>
    </CORSRule>
    <CORSRule>
        <AllowedOrigin>https://www.appdomain.com</AllowedOrigin>
        <AllowedMethod>PUT</AllowedMethod>
        <AllowedMethod>POST</AllowedMethod>
        <AllowedMethod>DELETE</AllowedMethod>
        <AllowedHeader>*</AllowedHeader>
    </CORSRule>
</CORSConfiguration>

静态网站托管

已启用。

我还能做什么来让公众可以访问这些资源?


在我的情况下,错误是由于S3存储桶的公共访问被禁用而导致的,因为它与CloudFront相关联。目前还没有找到解决方案。可能我需要设置PreSignedUrl机制,但相关内容较少,文档看起来像大学生的考试副本,充斥着无关/无用的内容,以写长答案获得更高分数。 - Lalit Fauzdar
17个回答

52

我知道这是一个旧帖子,但我遇到了同样的问题。我已经让一切正常工作了几个月,但它突然停止工作并给出了一个403 Forbidden错误。原来系统时钟是罪魁祸首。我认为S3使用一些基于时间的令牌,其寿命非常短。在我的情况下,我只运行了:

ntpdate pool.ntp.org

问题已经解决了。如果相关的话,我正在运行CentOS 6。这是样例输出:

19 Aug 20:57:15 ntpdate[63275]: step time server ip_address offset 438.080758 sec

希望这能有所帮助!


1
谢谢您的发布。我刚刚在Windows上遇到了同样的问题。更正系统时间解决了它。 - Marc Guillot
22
愿神保佑你,善良的人。请不要犹豫回答那些旧帖子。 - Yaroslav
1
这是我的问题。不知怎么的,我的 Docker 容器里的时钟已经漂移了,这不是一个容易诊断的问题! - Joe
3
我一直在使用虚拟机快照,让自己抓狂。我想给这个答案点赞十次。 - batwad
即使时间偏差为0.1秒,校正时间仍会导致tick。s3返回403禁止错误。 - KTYP
显示剩余3条评论

43

可能需要根据AWS文档设置适当的策略。

请将相关存储桶设置为以下策略:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "PublicReadGetObject",
      "Effect": "Allow",
      "Principal": "*",
      "Action": [
        "s3:GetObject"
      ],
      "Resource": "arn:aws:s3:::YOUR-BUCKET-NAME/*"
    }
  ]
}

1
我不得不添加一条语句,其中从资源中删除了“/*”。 - ram4nd
如果我从资源字符串的末尾删除/*,策略编辑器会返回Action does not apply to any resources - timbo
2
在我的情况下,我忘记添加 BUCKET_NAME/*,只给了自己对存储桶根目录的访问权限。谢谢! - SovietFrontier

30
问题在于转移是按照这个线程进行的,这本身并不是问题。问题出在之前的开发人员在转移前没有更改文件的权限。这意味着尽管这些文件在我的 bucket 中,但我无法管理它们。
通过从之前的桶重新下载干净的文件,删除旧的虚假文件,重新上传新鲜的文件并设置其权限以允许公共读取文件,解决了此问题。

由于这是被接受的答案,我想补充一点,即AWS s3同步不会传输每个对象的ACL设置。有可能使用ACL列表单独将对象设置为公共。该项目https://github.com/cobbzilla/s3s3mirror提供了-C选项,但我无法使其正常工作。作为最后的手段,您可以为存储桶中的每个文件夹设置存储桶策略,允许Principal:*获取对象。 - Djonatan

14

我曾经遇到过同样的问题,只需在策略桶资源结尾添加*即可解决。

{
  "Version":"2012-10-17",
  "Statement":[{
    "Sid":"PublicReadGetObject",
        "Effect":"Allow",
      "Principal": "*",
      "Action":["s3:GetObject"],
      "Resource":["arn:aws:s3:::example-bucket/*"
      ]
    }
  ]
}

5
为什么会被踩?在我的资源末尾加上 /* 可以解决这个问题。 - Alkarin
我不知道是哪些人给它投了反对票,但这确实是正确的答案。 - Manoj Rammoorthy
@user3470929 我没有点踩,但是它正在被踩是因为原始问题已经使用了 /* - 或者至少他们已经编辑了问题以反映这一点。 - emmdee

4
以下是我用来使我的 S3 存储桶中的 index.html 文件可以公开访问的 Bucket 策略:

enter image description here

我还需要前往权限管理 -> "阻止公共访问" 并移除存储桶的阻止公共访问规则。操作如下所示:

enter image description here

此外,请确保每个桶内各个对象的访问权限对公众开放。在这里检查: 输入图像描述

我缺少的是“公开”按钮! - Yitzchak
编辑 - 我的错误是我忘记使用正确的AWS配置文件:( - Yitzchak

2

自2023年6月底至8月,S3强制使用TLS 1.2或更高版本。 https://aws.amazon.com/blogs/security/tls-1-2-required-for-aws-endpoints/

如果您的应用程序通过HTTPS连接到S3,请确保其配置为使用TLS 1.2。
使用较旧的TLS版本的应用程序将收到403错误(例如可能发生在.Net 4.5及更低版本的情况下)。

对于.Net应用程序,一个简单的解决方案是将应用程序设置为至少在应用或Web配置中使用.Net 4.6.2。


1
我曾经束手无策。但是你的解决方案对我来说完美无缺。我使用的是.NET 4.7.2版本,但仍然遇到相同的问题。所以在访问S3文件URL之前,我不得不添加以下代码行:ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12;PdfReader reader = new PdfReader(s3FilePath); - undefined

1
在我设置了正确的权限之后,一个奇怪的事情让我解决了问题,那就是我从文件名中删除了扩展名。所以,我在桶里放了很多项,它们都有相同的权限,有些工作正常,有些返回403错误。唯一的区别是那些不起作用的项在文件名末尾有.png。当我把它们删除后,它们就可以正常工作了。不知道为什么。

1
另一个“解决方案”:我正在使用Buddy自动将github repo上传到s3存储桶,这需要对存储桶进行编程写访问。IAM用户的访问策略最初看起来像下面这样:(仅允许在目标存储桶中执行这6个操作)。
    {
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "VisualEditor0",
            "Effect": "Allow",
            "Action": [
                "s3:PutObject",
                "s3:GetObject",
                "s3:ListAllMyBuckets",
                "s3:ListBucket",
                "s3:DeleteObject",
                "s3:PutObjectAcl"
            ],
            "Resource": ""arn:aws:s3:::<bucket_name>/*"
        }
    ]
}

我的存储桶访问策略如下:(允许IAM用户读写访问)。

{
"Version": "2012-10-17",
"Id": "1234",
"Statement": [
    {
        "Sid": "5678",
        "Effect": "Allow",
        "Principal": {
            "AWS": "arn:aws:iam::<IAM_user_arn>"
        },
        "Action": [
            "s3:DeleteObject",
            "s3:GetObject",
            "s3:GetObjectAcl",
            "s3:PutObject"
        ],
        "Resource": "arn:aws:s3:::<bucket_name>/*"
    }

然而,这一直给我带来了403错误。
我的解决方案是将IAM用户访问所有s3资源的权限。
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "VisualEditor0",
            "Effect": "Allow",
            "Action": [
                "s3:PutObject",
                "s3:GetObject",
                "s3:ListAllMyBuckets",
                "s3:ListBucket",
                "s3:DeleteObject",
                "s3:PutObjectAcl"
            ],
            "Resource": "*"
        }
    ]
}

这让我避免了403错误,尽管显然这不是正确的做法。

0

我在尝试使用Python中的URL预签名从JavaScript将文件PUT到S3时遇到了此错误。结果发现我的Python需要ContentType属性。

一旦我添加了这个属性,以下内容就可以正常工作:

import boto3
import requests

access_key_id = 'AKIA....'
secret_access_key = 'LfNHsQ....'
bucket = 'images-dev'
filename = 'pretty.png'

s3_client = boto3.client(
  's3',
  aws_access_key_id=access_key_id,
  aws_secret_access_key=secret_access_key
)

# sign url
response = s3_client.generate_presigned_url(
  ClientMethod = 'put_object',
  Params = {
    'Bucket': bucket,
    'Key': filename,
    'ContentType': 'image/png',
  }
)

print(" * GOT URL", response)

# NB: to run the PUT command in Python, one must remove the ContentType attr above!
# r = requests.put(response, data=open(filename, 'rb'))
# print(r.status_code)

然后客户端可以使用该URL将图像PUT到S3:

var xhr = new XMLHttpRequest();
xhr.open('PUT', url);
xhr.onreadystatechange = () => {
  if (xhr.readyState === 4) {
    if (xhr.status !== 200) {
      console.log('Could not upload file.');
    }
  }
};

xhr.send(file);

0
如果这里的任何方法都无法帮助您,只需在Windows上同步日期和时间即可。我之前也遇到过同样的错误,因为我的Windows电脑上的时间总是不准,直到我按下“时间”按钮并同步时间。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接