ブラウザ(JavaScript)からのAmazon S3へのアップロードの環境をCloudFormationでサクッと作ってみた。
福岡オフィスの梶原です。
AWSのドキュメントで公開されているJavascriptによるサンプル
ブラウザから Amazon S3 への写真のアップロード
https://docs.aws.amazon.com/ja_jp/sdk-for-javascript/v2/developer-guide/s3-example-photo-album.html
を参考に、作成対象のAWSのリソースをCloudFormation化したので公開します。
※注意
Cognitoの未認可で割り当てられるRoleについては、アクセス元のIPアドレスだけで制限をかけていますがテンプレートのデフォルトのパラメータ0.0.0.0/0
では
世界中のすべてのユーザーに、バケット、およびバケット内のすべてのオブジェクトへの書き込みアクセス許可が付与されますので、制限がかからない状態になりますので、アクセス元のIPアドレスを設定するか、
実際に使用する場合はCognitoの認証を用いて、認証されているユーザに対しては書込み、認証されていないユーザは読み込みのみなどの権限を適切に割り当ててください。
構成図
環境構築
CloudFormationの実行
- 作成するバケット(Website用)
- アップロード先のバケット名
- IP制限用のIPアドレス
を入力して、CloudFormationのテンプレートを実行してください。
IAMロールを作成するため
□AWS CloudFormation によって IAM リソースが作成される場合があることを承認します。
にチェックを入れて実行します。
S3バケット(Webサイト)、S3バケット(アップロード)、Cognito ID プール, IAMRoleが作成されます。
HTML, Javascriptの配置
index.hmtl, javascriptを取得します。 (githubに上げてますのでご参照ください)
git clone https://github.com/ambasad/javascript-s3-upload-cfn.git cd javascript-s3-upload-cfn/website/
Javascriptの編集
app.jsの
- アップロード先のバケット名
- Cognito ID プールを変更します。
IdentityPoolIdは、CloudFormationの出力またCognitoのコンソールから確認できます。
https://ap-northeast-1.console.aws.amazon.com/cognito/federated?region=ap-northeast-1
var albumBucketName = 'js-album-upload-bucket'; <== バケット名 var IdentityPoolId = 'ap-northeast-1:XXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXX';
HTML, Javascriptの配置
S3BucketWebsite=js-album-website <== (CloudFormationのパラメータで指定したWebsite用のバケット名) # S3 へHTMLとjavascriptを配置します(--dryrun) aws s3 sync . s3://$S3BucketWebsite --acl public-read --dryrun (dryrun) upload: ./app.js to s3://js-album-website/app.js (dryrun) upload: ./index.html to s3://js-album-website/index.html # S3 へHTMLとjavascriptを配置します aws s3 sync . s3://$S3BucketWebsite --acl public-read upload: ./index.html to s3://js-album-website/index.html upload: ./app.js to s3://js-album-website/app.js
配置後
http://バケット名.s3-website-ap-northeast-1.amazonaws.com
にアクセスしてみてください。特にエラーが表示されず
の画面が正常に表示されていれば、javasciptは正常に動作しており 各ボタンを押下することにより、
Create New Album
(S3バケットへフォルダ作成)Add Photo
(S3バケットへファイルを保存)X
(フォルダ or ファイルを削除)
等が実施されます。 可能であれば、アクセス元のIPアドレスを変更して同じ動作をしてみてください。SDKの実行時にAccess Deniedになるかと思います。 (読み取りはpublicReadにより可能ですのでアップロードする画像についてはご注意ください) プログラムの内容については、参考元に詳細は記載されていますので、割愛させて頂きます。
https://docs.aws.amazon.com/ja_jp/sdk-for-javascript/v2/developer-guide/s3-example-photo-album.html
まとめ
コンソールでCognitoの認証周りの動作確認をするために、いくつか作っていたのですが 何度も環境を作るのが面倒だったのでCloudFormation化しました。次回はCognitoと連携させてみたいと思います。
参考
CloudFormation で Cognito
https://qiita.com/y13i/items/1923b47079bdf7c44eec
CloudFormation Template
AWSTemplateFormatVersion: "2010-09-09" Parameters: S3BucketNameUpload: Type: String Default: js-album-upload-bucket Description: S3 BucketName for Upload S3BucketNameWebsite: Type: String Default: js-album-website Description: S3 BucketName for Website SourceIp: Type: String Default: 0.0.0.0/0 Description: Allow S3 Bucket IpAddress ex. 10.0.48.0/32 Resources: # S3 Bucket (Upload) S3BucketUpload: Type: AWS::S3::Bucket Properties: BucketName: !Ref S3BucketNameUpload AccessControl: PublicRead CorsConfiguration: CorsRules: - AllowedOrigins: ['*'] AllowedMethods: [POST, GET, PUT, DELETE, HEAD] AllowedHeaders: ['*'] # S3 Bucket (Website) S3BucketWebsite: Type: AWS::S3::Bucket Properties: BucketName: !Ref S3BucketNameWebsite AccessControl: PublicRead WebsiteConfiguration: IndexDocument: "index.html" # IAM Role UnauthenticatedRole: Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Principal: Federated: cognito-identity.amazonaws.com Action: sts:AssumeRoleWithWebIdentity Condition: StringEquals: cognito-identity.amazonaws.com:aud: !Ref CognitoIdentityPool ForAnyValue:StringLike: cognito-identity.amazonaws.com:amr: unauthenticated Policies: - PolicyName: "Allow-S3-Policy" PolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Action: - s3:* Resource: - !Sub arn:aws:s3:::${S3BucketUpload}/* Condition: IpAddress: aws:SourceIp: - !Ref SourceIp - PolicyName: "CognitoRole" PolicyDocument: Version: "2012-10-17" Statement: - Effect: "Allow" Action: - mobileanalytics:PutEvents - cognito-sync:* Resource: '*' # Cognite ID pool CognitoIdentityPool: Type: AWS::Cognito::IdentityPool Properties: AllowUnauthenticatedIdentities: true CognitoIdentityPoolRoleAttachment: Type: AWS::Cognito::IdentityPoolRoleAttachment Properties: IdentityPoolId: !Ref CognitoIdentityPool Roles: unauthenticated: !GetAtt [UnauthenticatedRole, Arn] Outputs: WebsiteURL: Value: !GetAtt [S3BucketWebsite, WebsiteURL] Description: URL for website hosted on S3 CognitoIdentityPool: Value: !Ref CognitoIdentityPool Description: Cognito IdentityPool Id UploadBucketName: Value: !Ref S3BucketUpload Description: Upload BucketName WebsiteBucketName: Value: !Ref S3BucketWebsite Description: Website BucketName