Azure Blob Storage に画像をアップロードできるのに、ブラウザでURLを開くと「Resource not found」になる──一方で Storage Explorer からは正常に見える。これは「本当にファイルが無い」のではなく、匿名アクセス(パブリック公開)の既定値やネットワーク制限が原因で“見えないように見せられている”ときに起きやすい症状です。
現象を整理:アップロード成功なのにURLだけ「Resource not found」
まずは状況を冷静に分解すると、ポイントは「どの経路で見ているか」です。
| 操作 | 結果 | 裏で起きていること | 疑うべき設定 |
|---|---|---|---|
| アプリ/SDKでアップロード | 成功 | 認証済み(キー、接続文字列、Managed Identityなど)で書き込みできている | 書き込み権限は問題ない |
| Azure Portal の Storage Explorer で参照 | 見える | Azure AD やアカウントキーで認証して読めている | Blob自体は存在している可能性が高い |
| ブラウザでURL直アクセス(匿名) | Resource not found(404系) | 匿名アクセスが許可されていない/ネットワーク的に到達できないため「無いように見える」 | パブリックアクセス、ネットワーク制限、URLの誤り |
この時点で、「アップロードは成功」「認証付きでは見える」「匿名だと見えない」という構図がほぼ確定します。つまり、原因は大きく分けて次の3カテゴリに収束します。
- 匿名アクセス(パブリック公開)が無効(ストレージアカウント側/コンテナー側)
- ネットワーク制限(ファイアウォール、Selected networks、Private Endpoint など)
- URLやBlob名の不一致(大文字小文字、エンコード、パス違い、別アカウント参照)
「Resource not found」は“本当に無い”とは限らない
Azure Blob Storage のエラーは、匿名アクセスのときに少し紛らわしい挙動をします。典型的には以下です。
- ファイル名が違うなど、本当に存在しない → 404(Resource not found / BlobNotFound 系)
- 存在はしているが、匿名アクセスできない → 403ではなく、あえて404相当(Resource not found)に見せるケースがある
これは「第三者に存在有無を推測させない」ためのセキュリティ設計として理解すると納得しやすいです。したがって、ブラウザで「見つからない」=アップロード失敗とは限りません。Storage Explorer で見えるなら、むしろ公開経路(匿名アクセス)だけ塞がっていると考えるのが自然です。
最優先で確認する3つの設定(ここで9割決まる)
ストレージアカウント側:Blob のパブリックアクセス許可
最近の環境では、ストレージアカウント作成時の既定や組織ポリシーの影響で、Blobの匿名アクセスをアカウント単位で禁止していることが増えています。ここが禁止だと、コンテナー側を公開にしても反映できなかったり、公開できたように見えてもアクセスできなかったりします。
Portalでの確認手順(代表例)
- Azure Portal → 対象のストレージアカウント
- 「構成(Configuration)」
- 「Blob へのパブリックアクセスを許可」(Allow Blob anonymous/public access)を確認
ここが「無効」なら、匿名でURL直アクセスは基本的に失敗します。過去に作った別コンテナーが動くのは、当時のアカウント設定が許可だったか、別アカウント上にある、あるいはポリシー適用前だった、といった差で説明できます。
コンテナー側:パブリックアクセスレベル(公開レベル)
ストレージアカウント側が許可されている場合でも、コンテナーが「プライベート」のままだと匿名アクセスはできません。公開したい用途(画像配信など)なら、コンテナーの公開レベルを適切に設定します。
| 公開レベル | 匿名でBlobを開ける | 匿名で一覧取得 | 画像配信用途のおすすめ |
|---|---|---|---|
| プライベート(匿名アクセスなし) | 不可 | 不可 | 社内/限定配布なら最有力 |
| Blob(匿名の読み取りアクセス) | 可 | 不可 | 公開画像の最小公開としておすすめ |
| コンテナー(匿名の読み取りアクセス) | 可 | 可 | 一覧が露出するので基本は避けたい |
Portalでの確認手順(代表例)
- Azure Portal → ストレージアカウント →「データストレージ」→「コンテナー」
- 問題のコンテナーを選択
- 「アクセス レベルの変更(Change access level)」
- 「Blob」または「コンテナー」になっているか確認
「まったく同じ設定に見える」場合でも、ここが実は違う、あるいはアカウント側の禁止で変更が反映されていない、というのが頻出パターンです。
ネットワーク:ファイアウォール/Selected networks/Private Endpoint
匿名アクセスの設定が正しくても、ネットワーク設定でインターネットからの到達自体が遮断されていると、ブラウザからは見えません。
特に次の設定がある場合は要注意です。
- Public network access が無効(Disabled)
- Selected networks で許可IP/VNetだけに限定
- Private Endpoint を構成しており、パブリック経路を意図的に閉じている
この場合、Storage Explorer は社内ネットワークや認証済み経路で見えてしまうため、「公開されているはず」と誤認しがちです。しかしブラウザの匿名アクセスは、基本的に“インターネットからのパブリック経路”になるため、遮断されていると失敗します。
まずはここから:最短で原因を切り分けるチェックリスト
時間を溶かさないために、次の順番で確認するのが効率的です。
| 手順 | 確認内容 | OKなら | NGなら |
|---|---|---|---|
| 1 | URLが正しいか(コンテナー名/Blob名/拡張子/エンコード) | 手順2へ | URL修正で解決の可能性 |
| 2 | Storage Explorerで実物のBlob名をコピペしてURLと一致するか | 手順3へ | パス違い・別環境参照の可能性 |
| 3 | コンテナーの公開レベルが「Blob」以上か | 手順4へ | 公開レベル変更で解決見込み |
| 4 | アカウントでBlobパブリックアクセス許可が有効か | 手順5へ | アカウント設定変更が必要 |
| 5 | Networkingでパブリック到達が許可されているか | 公開URLで閲覧できる可能性が高い | ネットワーク設計(Private化/SAS/CDN)を検討 |
落とし穴になりやすい「URL・命名」のチェックポイント
公開設定の話に行く前に、意外と多いのが「URLが厳密に一致していない」ケースです。Azure Blobはコンテナー名もBlob名も基本的にケースセンシティブ(大文字小文字の違いは別物)として扱う前提で進めると安全です。
よくあるミス
- 拡張子の違い(.jpg と .jpeg、.png のつもりが .PNG など)
- スペースや日本語を含むBlob名をURLエンコードしていない
- # や ? などURL上で意味を持つ文字が含まれている
- アップロードしたのは「path/to/a.png」なのに、アクセスは「path/a.png」になっている
- 参照しているストレージアカウントが別(dev/prod取り違え)
確実なやり方は、Storage Explorer または Portal で対象Blobを選び、表示されるパス(Blob名)をそのままコピーしてURLと突き合わせることです。
エンコードが怪しいときの目安
Blob名に日本語やスペースが入っている場合、ブラウザのアドレスバーに貼ると勝手にエンコードされたり、逆に途中で切れたりします。アプリでURLを組み立てているなら、パス部分を正しくURLエンコードするのが鉄則です。
例(概念的な例)
誤: https://{account}.blob.core.windows.net/{container}/画像 01.png
正: https://{account}.blob.core.windows.net/{container}/%E7%94%BB%E5%83%8F%2001.png
ただし、すでに動いている別コンテナーがあり「同じ命名規則で同じように作っている」なら、URL要因よりも公開設定・ネットワーク要因の比率が上がります。
原因の本命:匿名アクセス(パブリックアクセス)の既定値・制御が変わっている
「数週間前に作った同設定のコンテナーはOK」「新しく作ったものだけNG」という差は、プラットフォーム側のセキュリティ既定値や、組織のポリシー適用タイミング差で起きがちです。見た目の設定が似ていても、裏側では次のような差が入ります。
- ストレージアカウント作成時点で、匿名アクセス許可が既定で無効になっている
- 管理者が Azure Policy で「パブリックアクセス禁止」を後から適用した
- 新しいアカウントは「Public network access 無効」が標準になっている
結果として、同じアプリでアップロードは成功するのに、ブラウザの直URLは失敗します。これは「アプリは認証付きでアクセスできる」一方、「ブラウザ直アクセスは匿名前提」だからです。
解決策:要件別にベストな公開方法を選ぶ
「とにかくURLを開けるようにしたい」だけで進めると、セキュリティ事故につながることがあります。そこで、要件別に現実的な選択肢を整理します。
誰でも見られる必要がある(Webサイトの公開画像など)
このケースは、匿名アクセスを許可して公開するのが最短です。ただし、公開範囲は最小化します。
- ストレージアカウント:Blobのパブリックアクセスを許可
- コンテナー:「Blob(匿名の読み取りアクセス)」にする(一覧取得はさせない)
- Blob名:推測されにくい命名(連番だけ、日時だけ、は避ける)
設定後、次の形式でブラウザ表示できるか確認します。
https://{ストレージアカウント名}.blob.core.windows.net/{コンテナー名}/{Blob名}
運用のコツ
- 公開用のコンテナーを分ける(公開画像専用、非公開データ専用)
- 誤って個人情報を入れないよう、アップロード先の設計段階で分離する
- 「コンテナー公開」ではなく「Blob公開」に留める(一覧が取れると漏えい範囲が広がる)
特定の人・アプリだけに見せたい(推奨:SASトークン)
公開URLのように「誰でも見える」状態を避けたいなら、SAS(Shared Access Signature)を使うのが定番です。匿名アクセスをオフのままでも、SAS付きURLならブラウザで閲覧できます。
SASでできる制御例
- 読み取りのみ(Write/Delete不可)
- 期限付き(例:30分だけ有効)
- HTTPS限定
- アクセス元IP制限(運用が許すなら強力)
SAS付きURLのイメージ(概形)
https://{account}.blob.core.windows.net/{container}/{blob}?sv=...&se=...&sp=r&sig=...
現場でよくある誤解として、「公開が必要だからコンテナーをPublicにするしかない」と思い込むケースがあります。しかし、アプリが配布するURLが限定的で良いなら、SASのほうが安全かつ柔軟です。
外部公開したいが、ストレージ自体は極力閉じたい(CDN/Front Doorの活用)
画像配信を高速化したい、DDoSや直叩きを抑えたい、公開/非公開を運用で切り替えたい、といった要件があるなら、ストレージを直接インターネットにさらすのではなく、CDNやFront Door経由に寄せる設計も有効です。
- 配信はCDN/Front Doorのドメインに統一
- オリジンとしてBlob Storageを使う
- 必要に応じてSASやPrivate Link等でオリジン保護
この構成は少し設計が増えますが、「セキュリティ」と「配信性能」の両立がしやすく、長期的に見てトラブルが減ります。
具体的な確認・設定手順(Portal / CLI / PowerShell)
運用環境では「Portalで直す」だけでなく、「IaCやスクリプトで再現できる」ことも重要です。代表的な操作例をまとめます。
Portalで確認・変更する(最速)
- コンテナーの公開レベル
ストレージアカウント → コンテナー → 対象コンテナー → アクセス レベルの変更 → 「Blob」 - アカウントのパブリックアクセス許可
ストレージアカウント → 構成(Configuration) → 「Blob へのパブリックアクセスを許可」 - ネットワーク制限
ストレージアカウント → ネットワーク(Networking) → Public network access / Firewall / Private endpoint を確認
Azure CLIでの代表例(再現性を重視する場合)
環境によりコマンドや権限が異なるため、まずは読み取り(show)で現状を確認し、変更(update / set-permission)を行います。
# 1) ストレージアカウントの「Blobパブリックアクセス許可」を確認(概念例)
az storage account show --name {account} --resource-group {rg} --query "allowBlobPublicAccess"
# 2) 許可を有効化(公開が要件の場合)
az storage account update --name {account} --resource-group {rg} --allow-blob-public-access true
# 3) コンテナーの公開レベルを Blob に設定(匿名で個別Blobのみ読める)
az storage container set-permission --account-name {account} --name {container} --public-access blob
注意点として、組織で Azure Policy により「パブリックアクセス禁止」が強制されていると、update が失敗したり、すぐに元に戻されたりします。その場合は技術ではなくガバナンス(ポリシー設計)側の対応が必要です。
PowerShellでの代表例(Azモジュール)
# コンテキスト作成(認証方法は運用に合わせて)
$ctx = (Get-AzStorageAccount -ResourceGroupName {rg} -Name {account}).Context
# コンテナーの公開レベルを設定
Set-AzStorageContainerAcl -Name {container} -Permission Blob -Context $ctx
PowerShell/CLIは、運用で同じ設定を別環境へ展開する際に特に効きます。「新しいコンテナーだけ動かない」問題は、手作業差分が原因になりがちなので、スクリプト化して差分を潰すのが根治策になります。
Storage Explorerで見えるのにブラウザで見えない理由(ここが最大の勘違いポイント)
この症状でハマる理由は、「Storage Explorerで見える=公開できている」と思ってしまうからです。しかし実際は真逆で、Storage Explorerはだいたい次のいずれかでアクセスしています。
- Azure AD(ロール割り当て)
- ストレージアカウントキー
- SAS
つまり“鍵を持っている人として見ている”状態です。一方、ブラウザでURLを叩くのは“鍵を持っていない匿名ユーザー”としてのアクセスです。両者は別物なので、設定も別に考える必要があります。
ネットワーク制限が原因だった場合の現実的な落としどころ
ネットワーク制限(Selected networks / Private Endpoint)が意図的な設計として入っている場合、「公開レベルを上げれば解決」という話ではありません。むしろ、公開しないことが正解です。
この場合の選択肢は次のどれかになります。
| 選択肢 | 向いているケース | メリット | 注意点 |
|---|---|---|---|
| SASで限定公開 | 一時的に共有したい/ログイン不要で見せたい | 公開範囲を最小化できる | URL漏えい対策(短期限、IP制限等)が重要 |
| アプリ経由で配信 | 会員向けコンテンツ、権限管理が必要 | 認可をアプリで統一できる | 実装負荷、配信性能の工夫が必要 |
| CDN/Front Door + オリジン保護 | 配信性能もセキュリティも両立したい | 大規模配信に強い | 設計要素が増える(運用設計が必須) |
「インターネットから誰でもアクセスできる必要があるのか」「アクセスできる人を限定したいのか」を要件として先に固定すると、設定の迷走が止まります。
最終確認:直す前にやっておくと安全なこと
公開設定を変更する前に、次の確認を入れると事故が減ります。
- そのコンテナーに個人情報・機密ファイルが混在していないか
- 公開用途なら、公開専用コンテナーへ移す(分離運用)
- 「コンテナー公開」ではなく「Blob公開」で足りないか検討する
- 公開するなら、CDNやキャッシュ戦略(画像最適化)も一緒に考える
まとめ:このケースで実際にやるべきこと
- Storage Explorerで見えるのにブラウザで「Resource not found」なら、まず匿名アクセス(パブリックアクセス)とネットワーク制限を疑う
- 最優先チェックはコンテナーの公開レベルとストレージアカウント側のパブリックアクセス許可
- ネットワークが閉じている設計なら、無理に公開せずSAS(期限付きURL)やアプリ経由配信が安全
- 「同じ設定に見える」の罠を避けるため、Portal目視だけでなくCLI/スクリプトで差分確認すると根治しやすい
結局のところ、アップロード経路(認証付き)と閲覧経路(匿名/非匿名)の違いを意識して設定を揃えるのが最短ルートです。新しく作成したコンテナーほどセキュリティ既定値やポリシーの影響を受けやすいため、公開が必要な用途は「公開専用の設計」に寄せると、同じトラブルを繰り返しにくくなります。

コメント