【完全保存版】CloudFront × Angular × Django API[403 を完全解消する正しい API 呼び出し方法と実装例まとめ]
403 を完全解消する正しい API 呼び出し方法と実装例まとめ
Angular + CloudFront + ALB + Django という構成で SPA を構築していると、
**「API を呼ぶと 403 Forbidden が返る」**という問題が高確率で発生します。
結論から言うと、この 403 は **設定ミスではなく、あなたの構成上“正しい挙動”**です。
本記事では、
-
なぜ 403 が発生するのか(重要)
-
なぜ CloudFront を経由すべきなのか
-
Angular 側で API URL をどう書くべきか
-
実際の Angular 画面(トップ/管理画面)コピペ実装
これらを分かりやすくまとめます。
❌ まず結論:403 は「正しい」動作でした
あなたの ALB(API) + WAF は、次のような Origin Header 認証方式を採用しています。
CloudFront → x-origin-auth → ALB → WAF → Django
CloudFront から来た場合だけ、x-origin-auth: <secret> という秘密ヘッダが付与されます。
しかし…
❌ Angular が API を直接叩くとヘッダが無いため必ず 403
例:
https://api.example.com/api/ping/
これは Angular から ALB(API) に直接アクセスしているため
秘密ヘッダが付かず、WAF に Block されます。
🔥 なぜ直接呼ぶと必ず 403 になるのか?
あなたの API 周りのセキュリティはこうです:
CloudFront 以外からのアクセス → 全て 403
CloudFront からのアクセス:
-
x-origin-auth ヘッダ付与される → 許可
ブラウザや curl や Postman:
-
ヘッダが付かない → 403 → 正常
✔ 403 を解消する唯一の方法
→ API を CloudFront 経由で呼ぶこと
つまり Angular の API 呼び出し URL をこうします:
/api/ping/
完全な URL が:
https://example.com/api/ping/
すると CloudFront が判定し:
PathPattern: api/*
↓
API Origin に転送(x-origin-auth を付与)
↓
ALB
↓
Django
→ 403 が完全に解消されます。
📌 403 が消える仕組みを図にするとこう
Angular (example.com)
↓
CloudFront
↓ (x-origin-auth を付与)
ALB(API)
↓
WAF 通過
↓
Django
🔍 逆にこうすると必ず 403
Angular → https://api.example.com/api/ping/
(CloudFrontを経由しない)
→ ヘッダなし
→ WAF Block(403)
これは セキュリティ的に正しい挙動です。
🧩 Angular 実装:API を CloudFront 経由で呼ぶ修正版
✔ API サービス(api.service.ts)
return this.http.get('/api/ping/');
絶対に直接の完全URL(https://api.example.com/...)は使わない。
🌎 Angular の環境ファイルで dev/stg/prod を切り替える方法(重要)
🔧 environment.dev.ts
export const environment = {
production: false,
apiBaseUrl: '/api', // CloudFront 経由で API を呼ぶ
baseUrl: 'https://csirt.dev.example.com'
};
🔧 environment.stg.ts
export const environment = {
production: false,
apiBaseUrl: '/api',
baseUrl: 'https://csirt.stg.example.com'
};
🔧 environment.prod.ts
export const environment = {
production: true,
apiBaseUrl: '/api',
baseUrl: 'https://csirt.prod.example.com'
};
✔ Angular.json のビルド設定に環境を追加
"configurations": {
"production": {
"fileReplacements": [
{
"replace": "src/environments/environment.ts",
"with": "src/environments/environment.prod.ts"
}
]
},
"stg": {
"fileReplacements": [
{
"replace": "src/environments/environment.ts",
"with": "src/environments/environment.stg.ts"
}
]
},
"dev": {
"fileReplacements": [
{
"replace": "src/environments/environment.ts",
"with": "src/environments/environment.dev.ts"
}
]
}
}
各環境のビルド:
ng build --configuration=dev
ng build --configuration=stg
ng build --configuration=production
✔ API 呼び出しはこう書く(CloudFront経由)
this.http.get(environment.apiBaseUrl + '/ping/');
🎨 画面実装:トップページと管理画面(コピペOK)
✔ Routing(app-routing.module.ts)
const routes: Routes = [
{ path: 'top', component: TopComponent },
{ path: 'admin', component: AdminComponent },
{ path: '', redirectTo: 'top', pathMatch: 'full' },
{ path: '**', redirectTo: 'top' }
];
✔ トップ画面
top.component.html
<h1>Top Page</h1>
<a routerLink="/admin">Go to Admin Page</a>
✔ 管理画面
admin.component.ts
callPing() {
this.api.ping().subscribe({
next: (res) => this.result = JSON.stringify(res),
error: (err) => this.result = 'Error: ' + JSON.stringify(err)
});
}
🔍 動作確認
成功ルート:
https://example.com/api/ping/ → 200
失敗ルート:
https://api.example.com/api/ping/ → 403(正常)
🎯 最終まとめ
| 動作 | 結果 |
|---|---|
| Angular → CloudFront → API | ✔ 200 |
| Angular → API 直接 | ❌ 403 |
| CloudFront 経由の場合だけ OriginAuth ヘッダが付与 | ✔ 200 |
| dev/stg/prod の API 切替は environment.ts で管理 | ✔ 安定 |
🚀 必要であれば追加記事も作成します
-
ECS Fargate CI/CD(GitHub Actions)
-
Angular の SPA キャッシュ制御
どれを追記しましょうか?