【问题标题】:Can't access images in S3 bucket using cognito identity无法使用认知身份访问 S3 存储桶中的图像
【发布时间】:2020-09-16 00:31:33
【问题描述】:

我正在测试使用 javascript 显示来自 s3 存储桶的图像,然后再将其作为应用程序的一部分。

我有一个 s3 存储桶(非公开),以这篇文章命名:IMAGE-BUCKET 创建了一个身份角色:GET-IMAGE。 我暂时授予了对 GET-IMAGE 角色的完全 s3 访问权限。 我为存储桶定义了 CORS。 在测试时,我禁用了浏览器缓存。

3 个问题:

  • 当从 html/脚本如下。
  • 如果我将特定图像公开,则会显示该图像 -- 图像数量过多时会出现问题。
  • 如果我将整个存储桶公开,则不会显示图像

Cognito 身份似乎无法访问存储桶,或者下面的脚本中存在问题。

此外,将存储桶设置为公开也不起作用,除非每个图像也设置为公开。此存储桶将被私人使用,因此这只是故障排除时的问题。

我已将 AmazonS3FullAccess 附加到 GET-IMAGE,我还添加了以下策略:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "AccessS3BucketIMAGEBUCKET",
            "Action": [
                "s3:GetObject",
                "s3:PutObject",
                "s3:ListBucket"
            ],
            "Effect": "Allow",
            "Resource": "*"
        }
    ]
}

使用来自 AWS 文档的 html 和脚本(修改):

<script src="https://sdk.amazonaws.com/js/aws-sdk-2.487.0.js"></script>

<script>
        var albumBucketName = 'IMAGE-BUCKET';
        // Initialize the Amazon Cognito credentials provider for GET-IMAGE:
        AWS.config.region = 'us-east-1'; // Region
        AWS.config.credentials = new AWS.CognitoIdentityCredentials({
            IdentityPoolId: 'us-east-1:43ba4c15-ab2f-8880-93be-xxx',
        });

        // Create a new service object
        var s3 = new AWS.S3({
            apiVersion: '2006-03-01',
            params: { Bucket: albumBucketName }
        });

        // A utility function to create HTML.
        function getHtml(template) {
            return template.join('\n');
        }

          
// Show the photos that exist in an album.
         function viewAlbum(albumName) {
                    var albumPhotosKey = '/';
                    s3.listObjects(function (err, data) {
                        if (err) {
                            return alert('There was an error viewing your album: ' + err.message);
                        }
                        // 'this' references the AWS.Response instance that represents the response
                        var href = this.request.httpRequest.endpoint.href;
                        var bucketUrl = href + albumBucketName + '/';

                        var photos = data.Contents.map(function (photo) {
                            var photoKey = photo.Key;
                            var photoUrl = bucketUrl + encodeURIComponent(photoKey);
                            return getHtml([
                                '<span>',
                                '<div>',
                                '<br/>',
                                '<img style="width:128px;height:128px;" src="' + photoUrl + '"/>',
                                '</div>',
                                '<div>',
                                '<span>',
                                photoKey.replace(albumPhotosKey, ''),
                                '</span>',
                                '</div>',
                                '</span>',
                            ]);
                        });
                        var message = photos.length ?
                            '<p>The following photos are present.</p>' :
                            '<p>There are no photos in this album.</p>';
                        var htmlTemplate = [
                            '<div>',
                            '<button onclick="listAlbums()">',
                            'Back To Albums',
                            '</button>',
                            '</div>',
                            '<h2>',
                            'Album: ' + albumName,
                            '</h2>',
                            message,
                            '<div>',
                            getHtml(photos),
                            '</div>',
                            '<h2>',
                            'End of Album: ' + albumName,
                            '</h2>',
                            '<div>',
                            '<button onclick="listAlbums()">',
                            'Back To Albums',
                            '</button>',
                            '</div>',
                        ]
                        document.getElementById('viewer').innerHTML = getHtml(htmlTemplate);
                        document.getElementsByTagName('img')[0].setAttribute('style', 'display:none;');
                    });
                }


</script>
   
</head>
<body>
    <h1>Photo Album Viewer</h1>
    <div id="viewer" />
    <button onclick="viewAlbum('');">View All Images</button>
</body>
</html>

更新: 如果我在 S3 存储桶策略中授予公开读取权限:

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

它允许访问每个图像;解决问题#2 和#3。 但这使得桶基本上是公开的。

如果我将 Bucket 策略更改为限制为 Cognito 身份,如下更改主体,我再次无法通过 html/script 访问图像,出现 403 错误。

"Principal": {
    "AWS": "arn:aws:iam::547299998870:role/Cognito_GET-IMAGEIDUnauth_Role" 
}

更新: 我一直在网上阅读,检查了一些其他相关的帖子...... 我已将其简化为基本组件,这是最新配置。配置应该很简单,根据文档授予对 GET-IMAGE 角色的访问权限:

在 IAM 管理控制台 > 角色 > GET-IMAGE 角色(未经身份验证)下 我添加了一个内联策略:

        {
        "Sid": "VisualEditor2",
        "Effect": "Allow",
        "Action": ["s3:GetObject","s3:ListBucket"],
        "Resource": "arn:aws:s3:::IMAGE-BUCKET/*"
        }

我删除了 Bucket 策略——这不应该是必需的,GET-IMAGE 角色已经拥有访问权限。默认情况下已包含角色信任。 HTML 包含凭据: IdentityPoolId: 'us-east-1:9bfadd6a-xxxx-41d4-xxxx-79ad7347xxa1

这些是最基本的组件,不需要其他任何东西。但是,它不起作用。我公开了其中 1 张图片并显示了该图片,其他图片错误并显示 403 Forbidden。

【问题讨论】:

  • 澄清一下,在设置您的身份池时,您是否将 GET-IMAGE 角色分配给 Unuathorized Identities?因此,您在顶部显示的策略已分配给 Cognito_GET-IMAGEIDUnauth_Role?
  • 我添加到 s3 Bucket Policy 中的上述策略(在权限选项卡下)。我还为未经授权的 id 分配了 GET-IMAGE 策略。虽然我上面提到的主要 arn 是有效的并且被政策接受,但我认为使用可能不正确。到目前为止,我正在研究但没有取得多大成功。
  • 您的 listObjects() 方法不应该将params 对象作为第一个参数吗?
  • 它是内联的。我找到了指定主体的正确格式,"Principal": { "Federated": "arn:aws:iam::54729999970:role/Cognito_GET-IMAGEIDUnauth_Role" .. 这也不起作用。如果我设置 Principal: "*" ,这一切都有效。另外,bucket policy 不喜欢 "Conditions" ,我试过不同的版本。

标签: amazon-s3 amazon-cognito


【解决方案1】:

您未正确为未经身份验证的角色定义信任策略。

根据this documentation on cognito role trust and permissions,未经身份验证角色的信任策略可以定义如下:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "",
      "Effect": "Allow",
      "Principal": {
        "Federated": "cognito-identity.amazonaws.com"
      },
      "Action": "sts:AssumeRoleWithWebIdentity",
      "Condition": {
        "StringEquals": {
          "cognito-identity.amazonaws.com:aud": "YOUR_IDENTITY_POOL_ID"
        },
        "ForAnyValue:StringLike": {
          "cognito-identity.amazonaws.com:amr": "unauthenticated"
        }
      }
    }
  ]
}

当您使用AWS.CognitoIdentityCredentials 时,您的 Cognito 身份池将首先为您的用户获取一个网络身份 ID。由于您没有使用来自 Cognito 用户池或 Facebook 等身份提供商的经过身份验证的令牌提供登录,因此该 ID 用于未经授权的 Web 身份。

然后,Cognito 将代表您调用安全令牌服务的 assumeRoleWithWebIdentity 方法,以获取具有您在未经身份验证角色的访问策略中定义的权限的凭据,该权限将允许 Web 身份访问 s3 存储桶。

这就是为什么信任策略中的主体需要是cognito-identity.amazonaws.com。即授予 cognito 身份池以 Web 身份调用 sts:AssumeRoleWithWebIdentity 方法的权限,以获取 IAM 凭证。

角色的访问策略部分定义了未经身份验证的用户实际上可以做什么,将继续如您在帖子中最初定义的那样:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "AccessS3BucketIMAGEBUCKET",
      "Action": [
        "s3:GetObject",
        "s3:PutObject",
        "s3:ListBucket"
      ],
      "Effect": "Allow",
      "Resource": "*"
    }
  ]
}

更新

我注意到您为未经身份验证的角色发布的最后一个内联策略不适用于 s3.listObjects()。它将返回 403,因为它需要稍微不同的资源语句来指示存储桶本身,而不是存储桶的内容。

您可以按如下方式更新您的政策:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "s3:GetObject"
      ],
      "Resource": [
        "arn:aws:s3:::IMAGE-BUCKET/*"
      ]
    },
    {
      "Effect": "Allow",
      "Action": [
        "s3:ListBucket"
      ],
      "Resource": [
        "arn:aws:s3:::IMAGE-BUCKET"
      ]
    }
  ]
}

【讨论】:

  • 谢谢。我检查了未经授权角色下的信任策略,它已经以与您指出的相同形式存在。它不工作。
  • 嗯...好的。但是,在您上次编辑中,您正在使用策略做某事并使用角色作为委托人?您是否可以重新编辑帖子以明确您当前在用户池和其他地方使用的政策?
  • 好的,我正在更新帖子,请检查上面。我已经减少了部分——所以基本上,ID 被授予对 s3 存储桶的读取访问权限,html 使用 ID。它应该是那么简单,但不像宣传的那样工作......
  • 好的,好的。我想我已经深究了。您的访问策略没有 s3:ListBucket 权限的正确资源策略元素,这就是您的 listBucket() 方法返回 403 的原因。s3:ListBucket 的资源策略元素需要引用存储桶本身,而不是桶内容。我已将示例添加到帖子的末尾。
  • 因此,作为记录,listbucket 权限并没有解决此问题,似乎有人将其标记为答案 - 它可能是答案的一部分,但它没有解决访问权限问题;我仍然收到此设置的 getobject 错误。请参阅我发布的带有详细解释的最终答案,如果有任何问题,请告诉我。感谢您在整个过程中的帮助。
【解决方案2】:

我已经解决了 s3 访问问题,我包含了我使用的所有设置和方法。为了进行故障排除,我开始使用实际的 AWS 用户进行测试,然后退回到 cognito 身份。我包含有关 AWS 用户访问的注释以供参考。我还放弃了 AWS 示例 HTML 代码,并使用了一个简单的短函数在控制台中显示输出,利用 getsignedurl 函数。我不熟悉 AWS 库,找到 getsignedurl 有助于加快测试并最终解决问题。

始终使用以下示例名称: Cognito 角色:GET-IMAGE S3 存储桶:IMAGE-BUCKET

我将介绍 Cognito 和 AWS 用户对 S3 的访问,使用 HTML 进行简单的演示和测试。

使用 Cognito:

设置:

角色:创建认知身份。有关说明和创建,请遵循此向导: https://console.aws.amazon.com/cognito/create/ 记下 AWS 在创建后提供的示例代码 - 您需要池 ID。

权限:添加角色级别和 S3 级别权限

角色级别:IAM > 角色 > GET-IMAGE_Unauth_Role

向 Auth 和 UnAuth 角色添加 (JSON)

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

S3: IMAGE-BUCKET > 权限 > 存储桶策略:

(JSON)

{
"Version": "2012-10-17",
"Statement": [
    {
        "Sid": "PublicRead",
        "Effect": "Allow",
        "Principal": {
            "AWS": [
                "arn:aws:iam::547999998899:user/anAWSUser",
                "arn:aws:iam::547999998899:role/Cognito_GET-IMAGEIDUnauth_Role",
                "arn:aws:iam::547999998899:role/Cognito_GET-IMAGEIDAuth_Role"
            ]
        },
        "Action": [
            "s3:GetObject"
        ],
        "Resource": [
            "arn:aws:s3:::IMAGE-BUCKET/*"
        ]
    }
]}

** 注意:我还为凭证版本添加了一个 AWSUser,用于下一节“使用凭证”

CORS:

IMAGE-BUCKET> 权限 > CORS

<?xml version="1.0" encoding="UTF-8"?>
<CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
<CORSRule>
<AllowedOrigin>*</AllowedOrigin>
<AllowedMethod>GET</AllowedMethod>
<AllowedMethod>HEAD</AllowedMethod>
<AllowedHeader>*</AllowedHeader>
</CORSRule>
</CORSConfiguration>

**注意:您可以在 AllowedOrigin 参数中限制来源。

HTML:

<!DOCTYPE html>
<html>
<head>
    <script src="https://sdk.amazonaws.com/js/aws-sdk-2.487.0.js"></script>
    <script>
    //   Replace IMAGE-BUCKET with your bucket name.
    var BucketName = 'IMAGE-BUCKET';

    // Cognito credentials (from Cognito ID creation sample code) 
    AWS.config.region = 'us-east-1'; // Region
    AWS.config.credentials = new AWS.CognitoIdentityCredentials({
         IdentityPoolId: 'us-east-1:9999996a-f099-99d4-b999-79a99999aaa1',

    });

    // Create a new service object
    var s3 = new AWS.S3({
            apiVersion: '2006-03-01',
            params: { Bucket: BucketName }
    });

    // Test Function.  REPLACE Key with test file name from s3
function show1() {
  var UrlExpireSeconds = 180 * 1;
  var params = {
  Bucket: BucketName, 
  Key: "20190815_file_name.jpg",    
  Expires: UrlExpireSeconds
               };
var url = s3.getSignedUrl('getObject', params);
console.log('The URL is', url);
document.getElementById('viewer').innerHTML = 
                                '<span>'+
                                '<div>'+
                                '<br/>'+
                                '<img style="width:128px;height:128px;" src="' +
                                url + '"/>' +
                                '</div>'+
                                '<div>'+
                                '<span>'  	
};

	show1();
  	</script>

</head>
<body>
    <h1>S3 Test Image Display</h1>
    <div id="viewer" />
    <button onclick="show1();">View Image</button>
</body>
</html>

使用用户凭据

您还可以使用凭据对用户进行身份验证以访问 s3。在上面的 javascript 中, 注释掉 cognito 凭据并改用以下内容:

//access key ID, Secret
var cred = new AWS.Credentials('AKXXX283988CCCAA-ACCESS-KEY','kKsCuq7a9WNohmOYY8SApewie77493LgV-SECRET');
AWS.config.credentials=cred;

从 AWS 控制台获取访问密钥和密钥: IAM > 用户 > an-AWSUser > 安全凭证

在“访问密钥”下,单击“创建访问密钥”

====================

请注意,当您创建 Cognito ID 角色时,AWS 会自动创建未经身份验证角色的信任策略;它不必像前面提到的那样手动定义。

还不需要列表桶和桶级别的资源权限,如“IMAGE-BUCKET”中的; Getobject 是直接访问文件所需的全部内容。就我而言,我通过密钥访问图像,不需要列出存储桶内容。

我同时设置了角色和 S3 存储桶权限;我没有测试没有角色权限,桶策略可能就足够了。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-10-27
    • 2017-08-17
    • 2023-02-19
    • 1970-01-01
    • 1970-01-01
    • 2022-01-23
    • 2018-08-17
    • 1970-01-01
    相关资源
    最近更新 更多