この記事のゴール
1枚のHTMLファイルを、URLを知っている人だけが見られる形でネットに公開したい。
でもコストはかけたくないし、閲覧期間も自分で設定したい、そしてせっかくなのでAWSの勉強もしたい。
この記事では、その実現方法として 「S3 + CloudFront 署名付きURL」 を選び、構築するまでの流れを書きます。あわせて「他の方法はなぜ採用しなかったのか」「途中の設計判断(WAF・料金プラン・ファイル名・独自ドメイン・鍵の置き場所)をどう決めたのか」も、初学者向けに理由つきで残します。
この記事の構成・設計判断は、実際に手を動かしながら整理したものです。専門用語にはたとえ話を添えています。
まずは全体像を「お姫様と城」でイメージ
技術用語を並べる前に、完成形をたとえ話で掴みましょう。
最初に載せたイラスト画像が、どのAWSリソースに相当するかを対応させると次のとおりです。
| イラストの要素 | 対応するAWSリソース/概念 |
|---|---|
| 🏰 門のない密室のお城 | 非公開のS3バケット(入口がない=直接アクセス不可) |
| 👑 お城の中のお姫様 | 公開したいHTML(S3オブジェクト) |
| 🛎️ お城の前の受付 | CloudFront(唯一の窓口・CDN) |
| 🔑 受付が照合する「印章の見本」 | 公開鍵(CloudFrontに登録/キーグループ) |
| 📜 封蝋つきの招待状 | 署名付きURL(手元の秘密鍵で封をしたもの) |
| ✅ 招待状を見せて中へ通る人 | 正しい署名つきURLでアクセス → 表示OK(200) |
| ❌ 受付で赤い×で断られる人 | 署名なしのアクセス → 403で拒否(MissingKey) |
| ☁️ 背景の空と雲 | インターネット/世界中に広がるCDN配信網 |
- 公開したいHTML = お姫様
- お姫様が住む 門のない密室の城 = 非公開のS3バケット(外から入る入口がない)
- 城の前にある 唯一の公式受付 = CloudFront(世界中に窓口を持つ案内所)
- 「この受付の人だけ奥に通す」という約束 = OAC(後述)
- 王様の印章(門外不出) = 秘密鍵
- 受付に預けた 印章の見本 = 公開鍵
- 封蝋つきの招待状(期限つき) = 署名付きURL
閲覧者は、王様(あなた)が印章で封をした招待状を持って受付(CloudFront)に行きます。受付は印章の見本と照合し、本物で期限内なら奥のお姫様(HTML)に会わせます。招待状を持たない人は門前払い。これがこれから作る仕組みの正体です。
そもそもどんな方法がある?(採用・不採用の比較)
「リンクを知ってる人だけに公開」を実現する方法はいくつもあります。最初に候補を並べ、なぜCloudFront署名付きURLにしたかを書きます。
候補A:Cloudflare Pages / Netlify / Vercel などのホスティングサービス
ドラッグ&ドロップで即公開でき、HTTPSもCDNも自動。一番ラク。
不採用の理由:手軽すぎて「AWSの勉強がしたい」という今回の目的に合わない。また、ランダムURLでの限定公開は「推測されにくい」だけで、暗号的に守るわけではない。
候補B:GitHub Pages
リポジトリにpushするだけ。
不採用の理由:URLが推測されやすく、リポジトリ名から公開がバレやすい。やはり「URLを知ってる人だけ」を厳密には守れない。
候補C:S3 の静的ウェブサイトホスティング(公開設定)
定番。ただし「URLを知ってる人だけ」を厳密にやろうとすると、バケットを公開する必要があり、設定ミスで全公開事故が起きやすい。
不採用の理由:厳密な限定公開には向かない。事故リスクが高い。
候補D:S3 署名付きURL(presigned URL)
S3が直接発行する期限つきURL。新しい鍵を作らず、既存のAWS認証情報で署名できるのが利点。
一部不採用の理由:CloudFrontを通らずS3直アクセスになるため、CDNや拡張性の利点がない。さらに 有効期限が最大7日。今回は「もっと長い期限」「CDN経由」「AWSをちゃんと学ぶ」を重視したので見送り。
(※「鍵を作りたくない」が最優先なら、これは有力な代替案です)
候補E:CloudFront 署名付きURL ← ★採用
S3を完全非公開にしてCloudFront経由のみアクセス可能にし、RSA鍵で署名したURLを知っている人だけが開ける方式。
採用の理由:
- URLを推測されても署名がなければ403で拒否=厳密な「リンクを知ってる人だけ」を満たす
- 有効期限を自由に長く設定できる(presignedの7日制限がない)
- CDN・HTTPS・独自ドメイン拡張など発展性がある
- 構成要素(S3 / CloudFront / OAC / 署名)がAWS学習の王道
「厳密さ × AWS学習 × 発展性」のバランスで、今回はこれを選びました。
構築手順(ダイジェスト)
実際の手順を、初学者がたどれる粒度で並べます。リージョンは東京(ap-northeast-1)、CloudFrontはグローバルです。
手順0:署名用のRSA鍵ペアを作る
ローカルのターミナルで2つの鍵を作ります。
openssl genrsa -out private_key.pem 2048
openssl rsa -pubout -in private_key.pem -out public_key.pem
-
private_key.pem… 署名用の秘密鍵。王様の印章。絶対に公開しない。 -
public_key.pem… CloudFrontに登録する公開鍵。印章の見本。
🔑 RSA鍵ペアとは:対になった2つの鍵。片方(秘密鍵)で封をし、もう片方(公開鍵)で「本物の封か」を確認できる。封はできるが偽造はできない、という非対称性がミソ。
手順1:S3バケットを非公開で作る
S3で新しいバケットを作成。「パブリックアクセスをすべてブロック」はONのまま(デフォルト)。これで「門のない城」になります。
手順2:HTMLをアップロード
作ったバケットにHTMLを1つアップロード。これでお姫様が城に入りました(まだ誰も会えません)。
手順3:CloudFrontにパブリックキーを登録
CloudFront →「キー管理 > パブリックキー」で、手順0の public_key.pem を貼り付けて登録。発行される キーID(例:KXXXXXXXXXX) をメモ。これが署名時に使う「印章の見本のラベル」。
手順4:キーグループを作る
「キー管理 > キーグループ」で、登録した公開鍵を含むグループを作成。CloudFrontは「このグループの鍵で署名されていればOK」と判断します。
手順5:CloudFrontディストリビューションを作る
-
料金プラン:
Pay as you go(従量課金)を選択(理由は後述) -
オリジン:手順1のバケットを選択し、「Allow private S3 bucket access to CloudFront」にチェック
→ これが OAC。CloudFrontが自動でバケットポリシーを書き換え、「このCloudFront経由のときだけS3を読める」ようにしてくれる - WAF:今回は無効(理由は後述)
🛡 OAC(Origin Access Control)とは:S3を完全非公開のまま、「この特定のCloudFrontだけは読んでよい」と許可する仕組み。城が「この受付の人だけ通す」と決めるのに相当。設定後、S3のバケットポリシーには自動でこんな許可が入ります(一部伏字)。
{
"Effect": "Allow",
"Principal": { "Service": "cloudfront.amazonaws.com" },
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::<バケット名>/*",
"Condition": { "StringLike": { "AWS:SourceArn": "arn:aws:cloudfront::<アカウントID>:distribution/<ディストリビューションID>" } }
}
手順6:ビヘイビアで「署名付きURLを必須」にする
ディストリビューションの「ビヘイビア」を編集し、「ビューワーのアクセスを制限する=Yes」、信頼された認可タイプ=Trusted key groups、で手順4のキーグループを指定。これで「招待状(署名)がないと通さない」受付になります。
手順7:署名付きURLを生成して動作確認
秘密鍵で署名したURLを発行します(仕組みは「ポリシーJSONをRSA-SHA1で署名し、URLのクエリに付ける」)。
- 署名つきURL → HTMLが表示される ✅
-
署名なしURL →
403 / MissingKey(招待状なしは門前払い)✅
この2つが確認できれば完成です。
細かい設計判断と「採用・不採用」の理由
ここが初学者にいちばん役立つ部分かもしれません。途中で迷ったポイントと、その決め方です。
① 料金プラン:Pay as you go を採用 / 定額プランは不採用
CloudFrontの作成時に「定額プラン($0〜$1,000/月)」と「Pay as you go(従量課金)」を選べます。
- 採用:Pay as you go … 全機能が使え、後述の無料枠でほぼ$0に収まる。今回のような小規模・低トラフィック用途に最適。
- 不採用:定額プラン … WAFやサーバーレス機能など“全部入り”だが、個人の限定公開には過剰。月額固定が発生しうる。
② WAF:不採用
WAF(Web Application Firewall)は、城の周りに傭兵を雇って怪しい攻撃を防ぐようなもの。
- 不採用の理由:今回は署名付きURL(招待状)でアクセス自体を絞っているので、追加の傭兵は不要。作成画面の見積もりでも 月14 USD相当 と表示され、コスト的に見合わない。
🧱 WAFとは:Webへの不正アクセス(SQLインジェクション等)をフィルタする仕組み。公開Webサイトには有効だが、限定公開には必須ではない。
③ ファイル名:日本語名 → ランダムなASCII名に変更
最初は日本語ファイル名のままでしたが、これだとURLが
...com/%E7%89%A9%E4%BB%B6...(日本語をエンコードした長い文字列)になってしまう。
-
採用:
ab6b974f.htmlのような中身が分からないランダム名に変更。 - 注意:末尾の
?Expires=...&Signature=...&Key-Pair-Id=...は署名の本体なので消せません(これが安全性そのもの)。
④ 独自ドメイン:検討したが不採用
cloudfront.net ではなく files.example.com のような独自ドメインにしたい、という案も検討。
- 不採用の理由:独自ドメイン化には ドメインの保有が前提。今回のアカウントにはドメインもRoute 53ホストゾーンも無かった。
- 「無料でドメインは?」も検討したが、昔の無料TLD(Freenom系)は実質終了、無料サブドメイン系も第三者サービスのアカウントが必要で実用性・信頼性が低い。
- 結論:
cloudfront.netのままで十分(無料・HTTPS付き)。独自ドメインは、将来ドメインを取得したら ACM証明書(us-east-1)+ CloudFrontのCNAME追加 + DNS設定、で対応可能。
⑤ 秘密鍵の置き場所:ローカル → AWSへ。Parameter Store(無料)を採用
「ローカルの鍵ファイルを無くしそう/忘れそう。AWSで管理したい」という要望から、鍵の保管先をAWSに移しました。
- 採用:SSM パラメータストア(SecureString) … 暗号化保存でき、標準枠は無料。
- 不採用:Secrets Manager … 専用サービスで機能は豊富だが 1シークレットあたり月約$0.40。今回の用途なら無料のParameter Storeで十分。
-
実行役:CloudShell … URL生成(署名)を動かす場所として採用。ブラウザ内のターミナルで、
opensslもawsコマンドも最初から使え、追加インストール不要。Lambdaも候補だったが、署名ライブラリの同梱が手間なので、学習・手軽さでCloudShellを選択。
これで「秘密鍵=Parameter Store」「生成スクリプト=CloudShell」となり、ローカルには何も残さずURLを作り直せます。CloudShellなら次のように1コマンド。
bash ~/gen_url.sh 90 # 90日有効なURLを生成
🗝 SecureStringとは:パラメータストアで値をKMS(鍵管理サービス)で暗号化して保存する形式。金庫に入れて預ける感覚。
💻 CloudShellとは:AWSコンソール内で使える無料のLinuxターミナル。自分のPCに何も入れずにコマンドを実行できる。
料金まとめ(2026年6月時点)
| サービス | 課金 | 今回の目安 |
|---|---|---|
| S3 ストレージ | 保存量課金(東京 約$0.025/GB・月) | 数MBなので月$0.01未満 |
| CloudFront | 転送・リクエスト課金 | 毎月1TB転送+1000万リクエストが恒久無料枠。個人共有なら実質**$0** |
| WAF | 今回無効 | $0(有効なら月14 USD相当) |
| SSM パラメータストア | 標準枠は無料 | $0 |
| (比較)Secrets Manager | $0.40/シークレット・月 | 不採用 |
| ACM 証明書 | 無料 | (独自ドメイン化する場合のみ) |
| (参考)独自ドメイン | 登録 年12〜15 USD、Route 53ホストゾーン 月$0.5 | 今回は不要 |
待機コスト(使っていなくても発生する固定費)がほぼ無いのがこの構成の強み。アクセスが少なければ月額ほぼゼロです。
用語集(やさしい版)
- S3:ファイルを置くAWSの倉庫。今回は「門のない城」として完全非公開に。
- オブジェクト:S3に置いた個々のファイル(今回のHTML=お姫様)。
- CloudFront:世界中に拠点を持つ配信網(CDN)。今回は「唯一の公式受付」。
- OAC:S3を非公開のまま「この受付だけ通す」と許可する仕組み。
- 署名付きURL:秘密鍵で封をした、期限つきの「招待状」。これを持つ人だけが開ける。
- 鍵ペア(公開鍵/秘密鍵):封をする印章(秘密)と、本物か確かめる見本(公開)のセット。
- キーグループ:CloudFrontが「この公開鍵の署名なら信頼する」とまとめた束。
- WAF:怪しいアクセスを弾く傭兵。今回は雇わず。
- パラメータストア(SecureString):秘密の値を暗号化して預けるAWSの金庫(無料枠あり)。
- CloudShell:ブラウザ内の無料Linuxターミナル。鍵を取り出して署名する作業場。
まとめ
- 「URLを知っている人だけ」を厳密にやるなら、CloudFront署名付きURLが王道。
- S3は非公開のまま、CloudFront(OAC)経由のみ許可。署名がないと403。
- WAFは無効、料金はPay as you goで、無料枠内ならほぼ$0。
- ファイル名はランダムASCIIにして個人情報を隠す。
- 秘密鍵はパラメータストア(無料)に、生成はCloudShellで。ローカルに鍵を残さない運用に。
一番大事なのは、秘密鍵(印章)を絶対に他人に渡さないこと。これさえ守れば、招待状を配った相手だけがお姫様に会えます。





