任意のホストからAWS SDKを使ってS3へファイルをアップロードする

はじめに

 AWS上に構築したシステムに、システム外の外部ホストからファイルをアップロードするような業務はよくあると思います。やっていることは単純なのですが、ちょっとした手順になりますのでまとめておきます。なお、今回は AWS SDK for Python (boto3) を使ったプログラムを紹介します。

バケットの準備

 外部ホストからのアップロードファイルを受け取るバケットを作成します。

アップロードユーザーの作成

 今回、s3botosampleuser というユーザーを作成して、これを外部ホスト向けに割り当てることにしましょう。AWS マネジメントコンソールのホームで「Identify & Access Management」(IAM) を探してクリックします。

add-iam1

 左側メニューで「ユーザー」をクリックして、ボタン「新規ユーザーの追加」をクリックします。

add-iam2

 ユーザー名として「s3botosampleuser」を入力して、ボタン「作成」をクリックします。

add-iam3

 ユーザーが作成されると、このユーザー向けの「アクセスキーID」と「シークレットアクセスキー」が発行されます。「ユーザーのセキュリティ認証情報を表示」をクリックすると表示されますので、控えておきます。
 続いて、バケットにアクセス権限を追加するときに、ユーザー「s3botosampleuser」のARN (Amazon Resource Name) も必要になりますのでここで確認しておきます。
 この画面を閉じて、ユーザー一覧の画面に戻ります。

add-iam4

 ユーザー「s3botosampleuser」をクリックします。

add-iam5

 画面右上に表示される「概要」から、「ユーザーのARN」を控えておきます。

add-iam6

 これで、ユーザーの作成は完了です。

バケットの作成とアクセス許可設定

 s3botosample というバケットを用意して、ここにアップロードしてもらうようにしましょう。
 AWS マネジメントコンソールのホームで「S3」を探してクリックします。
 S3 のバケット一覧画面が表示されますので、ボタン「バケットを作成」をクリックします。

add-bucket1

 バケット名に「s3botosample」を、リージョンは適当なものをそれぞれ入力して、ボタン「作成」をクリックします。

add-bucket2

 バケット一覧に「s3botosample」が追加されます。引き続き、アクセス許可設定を進めます。「s3botosample」をクリックしてください。

add-bucket3

 画面右上のボタン「プロパティ」をクリックしてください。バケット「s3botosample」についての情報が表示されます。
 セクション「アクセス許可」にある「バケットポリシーの追加」をクリックしてください。

add-bucket4

 今回はポリシージェネレーターを使って、GUIでポリシー情報を生成してみます。「AWS Policy Generator」をクリックしてください。

add-bucket5

 別ウィンドウでポリシージェネレーターが表示されます。まず、バケットの中身の一覧を表示できるように、アクション「ListBucket」を許可します。
 下表のとおり入力して、ボタン「Add Statement」をクリックしてください。

項目
Select Type of PolicyS3 BucketPolicy
EffectAllow
Principal先ほど控えたユーザーのARN
AWS ServiceAmazon S3
ActionsListBucket
Amazon Resource Name (ARN)arn:aws:s3:::s3botosample
add-bucket6

 一度画面が下までスクロールして、生成されるポリシー情報が1件分表形式で表示されます。引き続き、バケットにファイルをアップロードできるようにアクション「PutObject」を許可したいので、画面を上までスクロールして2つ目のポリシー情報を入力します。  下表のとおり入力して、ボタン「Add Statement」をクリックしてください。

項目
Select Type of PolicyS3 BucketPolicy
EffectAllow
Principal先ほど控えたユーザーのARN
AWS ServiceAmazon S3
ActionsPutObject
Amazon Resource Name (ARN)arn:aws:s3:::s3botosample/*
add-bucket7

 2つのアクションについてポリシー情報を作成できたら、ボタン「Fenerate Policy」をクリックしてください。

add-bucket8

 先ほど入力した2つのポリシー情報がJSONベースのテキストに変換されて表示されますので、これをコピーします。S3 バケットの詳細情報の画面(ポリシージェネレーターを表示する前の画面)に戻り、この内容を貼り付けて保存してください。

add-bucket9

 下記は生成されたJSONベースのテキストのサンプルです。

{
    "Version": "2012-10-17",
    "Id": "PolicyXXXXXXXXXXXXX",
    "Statement": [
        {
            "Sid": "StmtXXXXXXXXXXXXX",
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::XXXXXXXXXXXX:user/s3botosampleuser"
            },
            "Action": "s3:ListBucket",
            "Resource": "arn:aws:s3:::s3botosample"
        },
        {
            "Sid": "StmtXXXXXXXXXXXXX",
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::XXXXXXXXXXXX:user/s3botosampleuser"
            },
            "Action": "s3:PutObject",
            "Resource": "arn:aws:s3:::s3botosample/*"
        }
    ]
}

 これでバケットの作成と、アクセス許可設定が完了しました。

アップロード元の環境整備

 今回、ファイルのアップロードには AWS SDK for Python (boto3) を使います。botoCentOS7 + Python3.5 の環境でも動作しました。

(venv35)$ pip install boto3

アクセスキーのインストール

 控えておいた、ユーザー s3botosample 向けの「アクセスキーID」と「シークレットアクセスキー」をホストにインストールします。  boto3 をインポートすると自動的に適用されるため、Pythonプログラム中に「アクセスキーID」と「シークレットアクセスキー」を記述する必要がなくなります。

(venv35)$ mkdir -p ~/.aws
~/.aws/credentials
[default]
aws_access_key_id = <アクセスキーID>
aws_secret_access_key = <シークレットアクセスキー>

アップロードプログラムの作成と実行

 単純にするため、カレントディレクトリにプログラムファイルを作成します。同じくカレントディレクトリにファイル「sample.txt」があり、これをアップロードするようなプログラムを作成しました。
 今回、ファイルの一覧取得(ListBucket)とファイルのアップロード(PutObject)のみ許可するポリシーを適用しています。ファイルをダウンロードできないこと、ファイルを削除できないことも確認しました。
 【リファレンス】S3 — Boto 3 Docs 1.3.1 documentation

s3botosample.py
#!/usr/bin/env python
# -*- coding: utf-8 -*-

import boto3

s3 = boto3.resource('s3')
client = s3.Bucket('s3botosample')

print('01. show list objects in bucket.')
for obj in client.objects.limit(10):
    print(obj.Object)

print('02. upload file.')
#client.upload_file('sample.txt', 'sample/sample-uploaded.txt')
with open('sample.txt', 'rb') as f:
    result = client.put_object(Key='sample/sample-uploaded.txt', Body=f)
print(result)

print('03. show list objects in bucket again.')
for obj in client.objects.limit(10):
    print(obj.Object)

print('04. try to download file.')
try:
    client.download_file('sample/sample-uploaded.txt', 'sample-downloaded.txt')
except Exception as e:
    print(e)

print('05. try to delete file.')
delete_query = {
    'Objects': [{
            'Key': 'sample/sample-uploaded.txt'
        }]
}
response = client.delete_objects(Delete=delete_query)
print(response)

アップロード実行

 下記のような結果になりました。

(venv35)$ python s3botosample.py
01. show list objects in bucket.
02. upload file.
s3.Object(bucket_name='s3botosample', key='sample/sample-uploaded.txt')
03. show list objects in bucket again.
.create_resource of s3.ObjectSummary(bucket_name='s3botosample', key='sample/sample-uploaded.txt')>
04. try to download file.
An error occurred (403) when calling the HeadObject operation: Forbidden
05. try to delete file.
{'Errors': [{'Key': 'sample/sample-uploaded.txt', 'Message': 'Access Denied', 'Code': 'AccessDenied'}], 'ResponseMetadata': {'RequestId': 'F09B8B2FC7FE5F8C', 'HostId': '5cI109DInfkOSCm+R6ewEF2IfHZp7m/+FMGKOKDlASI3mzza25tJIuQLJLOqXXJzXdXpAOPPKXw=', 'HTTPStatusCode': 200}}

 01. ではバケットにはまだ何もないので出力はありません。
 02. でオブジェクトが帰ってきており、ファイルのアップロードに成功しています。
 03. ではいまアップロードしたファイルがオブジェクトとして取得できています。
 04. ダウンロードを許可していないため、403エラー(権限なしエラー)になっています。
 05. 削除も許可していないため、こちらはエラーレスポンスがオブジェクトとして帰ってきています。

おわりに

 AWS SDKを使うと、AWSの外にあるホストでも簡単にファイルを転送できます。バッチ処理結果の共有場所、バックアップアーカイブの保存場所、あるいはCMSのパブリッシュ結果のデプロイ先にしたWebサイトの運用など、いろいろな用途に使えそうですね!

コメントを残す

メールアドレスが公開されることはありません。

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください