プログラミング備忘録

仕事で覚えたことのまとめ

S3にファイルアップロードさせたい ~SDKを使ってみる~

目標

AWSCLIをインストールしていない人間でもファイルをS3にアップできるようにしたい。 社内の人間だけが利用できる状態だとベスト。

今回作るもの

ファイルを選び、ボタン押下で所定のバケットへファイルをアップロードするだけのHTMLの画面。

見栄えやセキュリティとかはいったん無視して、まずは基本骨子を作成する。

工程

  1. ファイルをアップするバケットを作る
  2. CognitoでUserPoolIdを取得する
  3. HTMLで画面を作る
  4. JavaScriptSDKでファイルアップロードのコーディングを行う
  5. HTMLにJavaScriptを連携する

Step1 ファイルをアップするバケットを作る

通常のバケット同様に作成し、アクセス許可のタブから一番下のCross-Origin Resource Sharing (CORS)を編集します。

CORSは複数のオリジン間におけるHTTPリクエストの許可情報、すごいざっくり表現するならAWS以外のWebページからのHTTPリクエストを許容するか、という設定になります。ここが空白だと、HTMLとJavaScriptを作って画像をアップするというHTTPリクエストを行ってもバケット側が拒否してしまいます。

そのため、編集のボタンを押し下記のJsonを貼り付け、リクエストを許可させます。

[
    {
        "AllowedHeaders": [
            "*"
        ],
        "AllowedMethods": [
            "HEAD",
            "GET",
            "PUT",
            "POST",
            "DELETE"
        ],
        "AllowedOrigins": [
            "*"
        ],
        "ExposeHeaders": [
            "ETag"
        ]
    }
]

なおこの時、ブロックパブリックアクセスはすべてONで問題ないです。

f:id:nigou2:20210719101858p:plain

Step2 CognitoでUserPoolIdを取得する

AWSのコンソールにログインした後、Cognitoにアクセスし、左側のIDプールの管理ボタンを押します。 f:id:nigou2:20210717161909p:plain

表示される画面で# 目標 AWSCLIをインストールしていない人間でもファイルをS3にアップできるようにしたい。 社内の人間だけが利用できる状態だとベスト。

工程

  1. ファイルをアップするバケットを作る
  2. CognitoでUserPoolIdを取得する
  3. HTMLで画面を作る
  4. JavaScriptSDKでファイルアップロードのコーディングを行う
  5. HTMLにJavaScriptを連携する

Step1 ファイルをアップするバケットを作る

通常のバケット同様に作成し、アクセス許可のタブから一番下のCross-Origin Resource Sharing (CORS)を編集します。

CORSは複数のオリジン間におけるHTTPリクエストの許可情報、すごいざっくり表現するならAWS以外のWebページからのHTTPリクエストを許容するか、という設定になります。 ここが空白だと、HTMLとJavaScriptを作って画像をアップするというHTTPリクエストを行ってもバケット側が拒否してしまいます。

そのため、編集のボタンを押し下記のJsonを貼り付け、リクエストを許可させます。

[
    {
        "AllowedHeaders": [
            "*"
        ],
        "AllowedMethods": [
            "HEAD",
            "GET",
            "PUT",
            "POST",
            "DELETE"
        ],
        "AllowedOrigins": [
            "*"
        ],
        "ExposeHeaders": [
            "ETag"
        ]
    }
]

Step2 CognitoでアイデンティティプールIDを取得する

Cognitoって何?

AWSアカウントの認証情報がなくてもAWSソリューションを使用できるようになるアイデンティティプール(トークンのようなもの)を発行する。このアイデンティティプールには必要十分のIAMロールを紐づけておく必要がある。

アイデンティティプールの設定方法

AWSのコンソールにログインした後、Cognitoにアクセスし、左側の「IDプールの管理」ボタンを押します。 f:id:nigou2:20210717161909p:plain

表示される画面で「新しいIDプールの作成」を押し、IDプール名を入力します。 またこの時、認証されていないIDに対するアクセスの許可のチェックボックスをONにします。 f:id:nigou2:20210717162404p:plain

次に、Cognitoで発行されるIAMロールを確認します。

f:id:nigou2:20210717163955p:plain

新規で発行されるアイデンティティプールに紐づき新規で作成されるIAMロールについて表示されます。 この後各種AWSのリソースを触れるようにロールにポリシーを設定するので、(デフォルトではPutEventsのみ許可) 検索しやすいように名称を変更しても構いません。

画面右下の「許可」のボタンを押したらアイデンティティプールの作成は完了です。

「AmazonCognitoでの作業開始」と表示されたページが表示されますので、プラットフォームのプルダウンから「javaScript」にします。

AWS認証情報の取得」の枠に下記が表示されます。実際にJavaScriptをコーディングする際に使用しますので、コピーしておきます。

// Amazon Cognito 認証情報プロバイダーを初期化します
AWS.config.region = 'ap-hogehoge-1'; // リージョン
AWS.config.credentials = new AWS.CognitoIdentityCredentials({
    IdentityPoolId: 'ap-hogehoge-1:XXXXXXXXXXXXXXXXXXXXXXXXXXXXX',
});

アイデンティティプールの使用するIAMロールのポリシーを変更

AWSの検索窓などからIAMのコンソールを表示し、左にある「ロール」を選択します。 f:id:nigou2:20210719095926p:plain 表示される検索窓に、先ほどCognitoのアイデンティティプールを作成したときに同時に発行されているIAMのうち、 認証なしアクセスのときに使用されるロール(UnAuthなどとついているもの)を検索します。

f:id:nigou2:20210719100247p:plain 押下後に表示される画面の中程にある「ポリシーをアタッチします」という青いボタンを押します。

ポリシーのリストが表示されるので、検索窓に「AmazonS3FullAccess」を入力し、チェックボックスを入れて、画面右下の「ポリシーをアタッチ」のボタンを押します。 f:id:nigou2:20210719100805p:plain これで、Cognitoで発行されるアイデンティティプールはS3のファイルにアクセスできるようになりました。

※もし特定のバケットにのみアクセスさせる、あるいはファイルを置くのみにしたい場合は、上記方法ではなくポリシーの作成を行う必要があります。

Step3 HTMLで画面を作る

<html>
    <head>
    <title>Sample</title>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
    </head>
    <body>

        <div class="container" >
            <div class="content">
                <div>
                ファイル選択
                </div>
                <input type="file" id="getfile-button" multiple /> 
            </div>
            <div class="content">
                <button id="upload-button">アップロード</button>
                <div id="results"></div>
            </div>
        </div>
    </body>
</html>

実際の画面 f:id:nigou2:20210717144255p:plain

この時、inputタグとbuttonタグにはIDを付与しておきます。

Step4 JavaScriptを用意する

下記のJSファイルを準備します。

// S3の認証情報
AWS.config.region = 'ap-northeast-1'; 
AWS.config.credentials = new AWS.CognitoIdentityCredentials({IdentityPoolId: 'XXXXXXXX'});

// アップするS3のバケット、フォルダ情報
var bucket = new AWS.S3({params: {Bucket: 'upload_bucket'}});
var foldername = 'myFolder';
var rightNow =  new Date();
var format_date = rightNow.toLocaleDateString();
var format_time = rightNow.toLocaleTimeString();
var folder_Path = foldername + '/' + format_date + '/' + format_time

// HTML側のオブジェクト
var getfile_button = document.getElementById('getfile-button');
var upload_button = document.getElementById('upload-button');
var results = document.getElementById('results');

// アップロードボタン押下時の動作
upload_button.addEventListener('click', function() {
  var file = getfile_button.files[0];
  if (file) {
      for (let i=0 ; i < getfile_button.files.length;i++ ){
          var tgtfile =getfile_button.files[i];
          var params = {Key:folder_Path + "/"+ tgtfile.name, ContentType: file.type, Body: file};
          bucket.putObject(params, function (err, data){
              results.innerHTML = err ? 'ERROR!' : 'uploaded';
          });
          results.innerHTML = 'error';
      };    
  } else {
      results.innerHTML = 'no file';
  };

})

// S3の認証情報の2行に、Cognito設定時にコピーした認証情報そのままです。

// アップするS3のバケット、フォルダ情報の1行目にアップするバケット、2行目のfoldernameバケット直下のフォルダの名称、folder_Pathはボタン押下差荒れた日時をもとにファイルを分けるために使用しています。

// アップロードボタン押下時の動作以降は、ボタンに対してイベントを付与し、アップ対象として指定したファイルの分だけbucket.putObjectを繰り返します。

Step5 HTMLにJavaScriptを連携する

最後にHTML側の</body>の直前に

    <script src="https://sdk.amazonaws.com/js/aws-sdk-2.922.0.min.js"></script>
    <script src="上記のJSのパス"></script>

を記載すると、HTMLにScriptが連携されます。

公式を見ながら設定していきます。

まとめ

あとはこのHTML、JSファイルを社内の人間しかアクセスできない場所に置くなど、セキュリティ面だけ整理すれば、CLIを持っていなくても