I'm testing to display images from an s3 bucket using javascript, prior to making this part of an application.
I have an s3 bucket (non-public), named for this post: IMAGE-BUCKET Created an identity role : GET-IMAGE. I have temporarily given full s3 access to GET-IMAGE role. I have CORS defined for the bucket. While testing I have disabled the browser cache.
3 issues:
- Getting "403 Forbidden" response when images are accessed from the html/script below.
- If I make a particular image public, that image displays -- an issue with large # of images.
- If I make the entire bucket public, images do not display
It seems Cognito identiy is not able to access the bucket, or there's an issue in the script below.
Also, setting the bucket public doesn't work either, unless each image is also set public. This bucket will be used privately, so this is only an issue while troubleshooting.
I have attached AmazonS3FullAccess to GET-IMAGE, I also added the following policy:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AccessS3BucketIMAGEBUCKET",
"Action": [
"s3:GetObject",
"s3:PutObject",
"s3:ListBucket"
],
"Effect": "Allow",
"Resource": "*"
}
]
}
Using html and script from AWS documentation (modified):
<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>
UPDATE: If I grant public read in S3 Bucket Policy:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "PublicRead",
"Effect": "Allow",
"Principal": "*",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::IMAGE-BUCKET/*"
}
]
}
It allows to access each image; solving the issue #2 and #3. But this makes the bucket basically public.
If I change the Bucket policy to limit to the Cognito identity, changing the principal as follows, again I am not able to access images via the html/script, getting 403 errors.
"Principal": {
"AWS": "arn:aws:iam::547299998870:role/Cognito_GET-IMAGEIDUnauth_Role"
}
UPDATE: I've been reading online, checking some of the other related posts ... I've it reduced to the basic components, here's the latest configuration. The configuration should be as simple as, giving access to the GET-IMAGE role based on the documentation:
Under IAM Management Console > Roles > GET-IMAGE role (unauthenticated) I added an inline policy:
{
"Sid": "VisualEditor2",
"Effect": "Allow",
"Action": ["s3:GetObject","s3:ListBucket"],
"Resource": "arn:aws:s3:::IMAGE-BUCKET/*"
}
I removed the Bucket policy -- this shouldn't be needed, the GET-IMAGE role already has access. Role trust is already included by default. HTML contains the credential: IdentityPoolId: 'us-east-1:9bfadd6a-xxxx-41d4-xxxx-79ad7347xxa1
Those are the most basic components, nothing else should be needed. However, it does not work. I made 1 of the images public and that image is displayed, other images error with 403 Forbidden.
params
objects as the first parameter? – lemming