対象読者: AWSをこれから触る人。 AWS勉強シリーズの4本目です。全体の地図は索引記事にあります。前回のIAM入門で「誰が何をしていいか」を決めたので、今回はその権限で触る最初の置き場、S3です。
S3とは何か
Amazon Simple Storage Service(S3)は、ファイルをインターネット経由で置いたり取り出したりできる、容量無制限のオブジェクトストレージです。AWSの中でも最初期(2006年開始)のサービスで、ほぼ全てのAWSサービスがS3を読み書きの相手として想定しています。「AWSにファイルを置く」と言ったら、まずS3のことです。
サーバーの管理は要りません。ディスク容量の計画も要りません。置いた分だけ課金され、AWS側が複数の設備に自動で複製して保管します。設計上の耐久性は99.999999999%(イレブンナイン)で、1,000万個のファイルを置いて1万年に1個失う計算です。
何に使うか
- ファイルの保管: 画像・動画・PDF・CSV・ログ・バックアップなど、形式を問わず何でも置く
- 静的Webサイトの配信: HTML/CSS/JSを置いてそのまま公開する。サーバー不要
- データ分析の入り口: アプリのログやCSVをS3に溜め、Athena・Glue・Redshiftから直接読む(データレイク)
- 他サービスとの受け渡し: Lambdaが処理した結果を置く、EC2からバックアップを送る、CloudFrontで世界配信する
- 長期保存(アーカイブ): 法定保存の帳票などを、めったに読まない前提の安いクラスに移して置いておく
重要用語
| 用語 | 意味 |
|---|---|
| バケット | ファイルを入れる入れ物。名前は世界中で一意。リージョンを選んで作る |
| オブジェクト | S3に置く1個のファイル。データ本体+メタデータ。1個最大5TB |
| キー | オブジェクトの名前。reports/2026-08.csv のように / を含めてよいが、S3にフォルダの実体は無い(キーの文字列を見て、コンソールがフォルダ風に見せているだけ) |
| ストレージクラス | 保存の等級。よく読むなら Standard、たまに読むなら Standard-IA、ほぼ読まないなら Glacier 系。安いクラスほど取り出しが遅い・取り出し料金がかかる |
| バージョニング | 同じキーに上書きしても古い版を残す設定。誤削除・誤上書きの保険 |
| ライフサイクルルール | 「30日たったらIAへ、365日たったらGlacierへ、7年で削除」のような自動移行・自動削除の設定 |
| 署名付きURL | 期限付きの一時的なダウンロード/アップロードURL。バケットを公開せずに特定の人にだけ渡せる |
| ブロックパブリックアクセス | バケットを誤って全世界公開しないための安全装置。新規バケットは既定でON |
仕組みの要点
S3はキーと値のストアです。「バケット名+キー」がアドレスで、そこにバイト列を置きます。ファイルシステムではないので、ファイルの一部だけ書き換える(追記する)ことはできません。変更は必ずオブジェクトごとの丸ごと上書きです。
置いたデータはリージョン内の複数の建物(アベイラビリティゾーン)に自動複製されます。読み書きの整合性は「書いた直後に読めば最新が返る」強い整合性です(2020年12月以降)。
アクセス制御は2系統あります。IAMポリシー(前回やった「誰が」側)と、バケットポリシー(バケット側に「このバケットは誰に何を許すか」を書く)です。同じアカウント内なら、どちらかにAllowがあれば通ります。ただし明示的なDenyがどちらかにあれば、Allowがあっても拒否です。別アカウントから触るときだけ「両方でAllow」が要ります(組織のSCPやPermissions Boundaryなど、他の制約ポリシーが無い前提の話です)。
使い方
やることは4つだけです。倉庫を作って、箱を置いて、札を読んで探して、要らなくなったら捨てる。
この4コマがそのままコードの順番になります。Python(boto3)で書くと次のとおりです。
import boto3
s3 = boto3.client("s3", region_name="ap-northeast-1")
bucket = "my-first-bucket-20260816" # 世界で一意な名前にする
# ① バケットを作る(東京リージョン)
s3.create_bucket(Bucket=bucket,
CreateBucketConfiguration={"LocationConstraint": "ap-northeast-1"})
# ② ファイル(オブジェクト)を置く
s3.put_object(Bucket=bucket, Key="reports/2026-08.csv",
Body=b"date,sales\n2026-08-01,100\n")
# ③ 一覧を見る(Prefixで「フォルダ」相当を絞る)
for o in s3.list_objects_v2(Bucket=bucket, Prefix="reports/")["Contents"]:
print("list:", o["Key"], o["Size"], "bytes")
# ④ 取り出す
body = s3.get_object(Bucket=bucket, Key="reports/2026-08.csv")["Body"].read()
print("get:", body.decode())
# ⑤ 消す
s3.delete_object(Bucket=bucket, Key="reports/2026-08.csv")
実行結果はこうなります(motoでAWSアカウント無しに実行)。
list: reports/2026-08.csv 26 bytes
get: date,sales
2026-08-01,100
ローカルのファイルをそのまま上げたいときは s3.upload_file("local.csv", bucket, "reports/local.csv")、落とすときは s3.download_file(bucket, key, "saved.csv") が使えます。大きなファイルの分割アップロードもこの2つが自動でやってくれます。
バケットを公開せずに特定の人にファイルを渡すには署名付きURLを使います。
# 10分間だけ有効なダウンロードURL
url = s3.generate_presigned_url(
"get_object",
Params={"Bucket": bucket, "Key": "reports/2026-08.csv"},
ExpiresIn=600,
)
print(url)
出力(長いので改行を入れています。X-Amz-Expires=600 が10分の期限です)。
https://my-first-bucket-20260816.s3.amazonaws.com/reports/2026-08.csv
?X-Amz-Algorithm=AWS4-HMAC-SHA256
&X-Amz-Credential=FOOBARKEY%2F20260816%2Fap-northeast-1%2Fs3%2Faws4_request
&X-Amz-Date=20260816T090716Z&X-Amz-Expires=600&X-Amz-SignedHeaders=host
&X-Amz-Signature=0b837d818a8a83a0...
手元のmoto 5.2.2 + boto3 1.43.72は既定だと古い形式(Signature=...&Expires=...)のURLを返しました。本物のS3は新しいバケットでこの古い形式を受け付けないので、クライアント作成時に config=Config(signature_version="s3v4") を渡して上の形式にしています。このURLを知っている人だけが、期限内だけ取り出せます。「メールでダウンロードリンクを送る」「ブラウザから直接S3にアップロードさせる」はこれで実装します。
誤削除の保険にはバージョニングを有効にします。設定するとこう変わります。
左が何もしない場合、右が有効にした場合です。
s3.put_bucket_versioning(Bucket=bucket,
VersioningConfiguration={"Status": "Enabled"})
s3.put_object(Bucket=bucket, Key="v.txt", Body=b"v1")
s3.put_object(Bucket=bucket, Key="v.txt", Body=b"v2") # 上書き
print(len(s3.list_object_versions(Bucket=bucket, Prefix="v.txt")["Versions"])) # → 2
上書きしても古い版が残るので、戻せます。有効にすると古い版の分も課金されるので、ライフサイクルルールで古い版を一定期間後に消す設定とセットで使います。
使い分け。S3か、EBSか、EFSか
AWSの「保存する場所」は3種類。最初はどれも同じに見えるので、判断の軸を1行ずつ置きます。
| 場面 | 選ぶもの | 理由 |
|---|---|---|
| ファイルをアプリやユーザーがHTTPで出し入れする | S3 | 容量無制限・安い・どこからでも届く。サーバーに紐づかない |
| EC2のOSやデータベースのディスクが要る | EBS | 1台のEC2に接続するブロックストレージ。OSからは普通のディスクに見える |
| 複数のEC2から同じディレクトリを同時に読み書きしたい | EFS | NFSで共有できるファイルシステム。S3は「同時にファイルの一部を書く」ができない |
| めったに読まないが捨てられない | S3 Glacier系 | 保管料が最安。取り出しに分〜時間かかる |
迷ったらS3、「OSから普通のディスクとして見えてほしい」ならEBS、「複数台で共有するファイルシステム」ならEFS、と覚えます。
料金の考え方
課金は主に3つです。
- 保管料: 置いている容量×時間。東京リージョンのStandardで約0.025 USD/GB/月。100GBで月300円台
- リクエスト料: PUT/GET等の回数。GETは1,000回あたり約0.0004 USDと安いが、数億回叩くと効いてくる
- 転送料: インターネットへの送信にかかる。受信(アップロード)は無料。同じリージョン内のEC2やLambdaからの読み取りも無料
一度電卓を叩いてみると転送料の重さが分かります。100GBの動画を1,000人に配ると送信100TB。東京の段階料金(最初の10TBが0.114 USD/GB、その先は0.089→0.086)で計算すると約9,000 USD。保管料は月2.5 USDなので、誤差です。配信が主用途ならCloudFront(CDN)を前に置きます。
無料利用枠もあります(枠の形はアカウント作成時期で変わるので、公式の料金ページで確認してください)。個人の学習で課金が問題になることはまずありません。
実際に叩くと止まるところ
上のコードを書きながら、motoで意図的にエラーを起こして挙動を見ました。エラーコードは本物のS3と同じです。
create_bucket(Bucket=b) # 東京でLocationConstraint無し
→ IllegalLocationConstraintException
get_object(Bucket=b, Key="nope.txt") # 無いキー
→ NoSuchKey - The specified key does not exist.
delete_bucket(Bucket=b) # 中身が残ったまま
→ BucketNotEmpty - The bucket you tried to delete is not empty
delete_object(Bucket=b, Key="never.txt") # 無いキーを消す
→ HTTP 204(エラーにならない)
put_object(Bucket=b, Key="empty-folder/", Body=b"")
→ 一覧に ('empty-folder/', 0) が出る # 「フォルダ」の正体は0バイトのオブジェクト
1つ目は初見でまず引っかかります。us-east-1以外でバケットを作るときは CreateBucketConfiguration が必須で、省略するとこの例外です。4つ目は逆に注意で、消すつもりのキー名を打ち間違えても成功扱いになります。削除ログを見て安心していたら実は何も消えていなかった、が起きます。
よくある注意点
- バケットを公開しない。 ブロックパブリックアクセスは新しく作るバケットでは既定でONです。「静的サイトで公開したい」以外の理由で外さないでください。個人情報入りバケットの公開設定ミスは、毎年ニュースになっています
- バケット名は取り消せないし、他人と被る。 一度作ると名前変更はできず、消して作り直しです。会社名やプロジェクト名+用途+リージョンなど、被らない規則を決めてから作ります
-
フォルダは無い。
reports/を作ったつもりでも、中のオブジェクトを全部消せば「フォルダ」も消えます。S3の概念としてフォルダは無く、コンソールの「フォルダ作成」は0バイトのオブジェクトを置いているだけです(上の実測の5つ目) - 消したら基本戻らない。 バージョニングを入れていないバケットの delete は即時・不可逆です。大事なバケットにはバージョニング+ライフサイクルを最初から
- リージョンを間違えない。 バケットは作ったリージョンに固定です。東京のEC2から米国のバケットを読むと遅い上に転送料がかかります
まとめ
S3は「置く・取る・消す」の3動詞で足ります。バケットの中にキーで名前を付けて置く、それだけです。守るのは3つ。フォルダは無い、公開しない、消したら戻らない。この3つを押さえていれば、初心者がS3で事故る場面はほぼありません。
次に手を動かすなら、バージョニングをONにして put→上書き→list_object_versions で2版見えるところまでやってみてください。そこまでできればS3の基本は卒業です。
次回はEC2(仮想サーバー)を予定しています。
参考
- Amazon S3 公式ドキュメント
- Amazon S3 の料金
- シリーズ索引: AWSとは何か
- 前回: IAM入門


