ラベル Azure の投稿を表示しています。 すべての投稿を表示
ラベル Azure の投稿を表示しています。 すべての投稿を表示

2026年4月18日土曜日

【AI-900合格】実質2週間!最新Udemy問題集×Geminiを「相棒」にした最短攻略法




 4月からの大規模プロジェクトを控え、「今のうちにAIの基礎を固めておきたい」と考え、Microsoftの認定試験 AI-900(Azure AI Fundamentals) を受験しました。

結果、ちょっと危ないカテゴリもありましたが、実質2週間足らずの独学で一発合格。


今回は、あえて「動画学習」を捨て、「最新のUdemy問題集」と「AI(Gemini)」を相棒にして最短ルートで合格した勉強法を公開します。

 なぜ「動画学習」をやめたのか?

最近は動画教材が人気ですが、多忙なマネージャー職にとって動画には3つの弱点がありました。

 1. スピードが遅い: 理解している部分を飛ばしにくい。

 2. 場所を選ぶ: 電車内や家族がいるリビングで、音声を出しながら集中するのは重い。

 3. 検索性が低い: 「あの用語、なんだっけ?」と戻るのに時間がかかる。

そこで今回は、「テキストベースの模擬試験」と「AIへの質問」に絞った、徹底的な隙間時間活用スタイルを選択しました。

合格へ導いた「最強の相棒」教材3選

私が実際に使用した、2026年最新版対応の教材をご紹介します。

  【基礎固め】Microsoft公式学習ガイド(無料)

まずは公式の学習ガイドで全体像を把握しました。

 * 感想: 無料で網羅性は高いですが、日本語が少し機械翻訳的で、これだけで「腹落ち」させるのは少し大変かもしれません。

 【土台作り】Udemy:対策テスト4回+用語問題集

AI-900 / Microsoft Azure AI Fundamentals 対策テスト4回+用語問題集

 * 感想: 「まずは用語から」という初学者に最適。4回分のテストがあり、コストパフォーマンス抜群です。基礎体力をつけるのに最適でした。

 ③ 【総仕上げ】2026年版 模擬問題集(全6回)

【2026年版】AI-900 模擬問題集|生成AI・Copilot・Foundry完全対応|全問丁寧な日本語解説付き

 * 感想: 生成AI、Copilot、Azure AI Foundryといった最新範囲をがっつりカバー。本番に近い「手応え」のある問題が多く、仕上げにはこれ一択です。

 【本命】Geminiを「最強の家庭教師」にする勉強法

今回、私が最も強調したいのが、「Udemyで問題を解き、Geminiと議論する」というハイブリッド学習法です。

正直に言うと、Udemyの模擬試験の解説だけでは、「なぜこれが正解なのか?」がスッキリしない瞬間もありました。そんな時、私は Gemini にこう投げかけました。

プロンプト例:

「この問題の正解が『回帰』で、なぜ『分類』ではないのか。わかりやすく教えて。」


もっとわからないときは、udemy の問題自体をコピペして、

「以下はどう考れば良いか教えて

(問題文)」

として聞いていました。


Geminiは、私が納得するまで何度でも、時には表やコードを交えて解説してくれます。

 この「相棒」がいたからこそ、2週間という短期間で深い理解を得ることができました。


 本番の試験はどうだったか?

万全を期して挑みましたが、実際の試験では「初見の表現」もいくつか出現しました。

しかし、Geminiとの「対話」を通じてAIの設計思想(ロジック)が頭に入っていたため、慌てることなく消去法で正解を導き出すことができました。

単なる丸暗記ではなく、「なぜそうなるのか」をAIと一緒に突き止めるプロセスが、合格への一番の近道だったと確信しています。


 最後に

AI-900の合格後、バッジがCredly(デジタル証明プラットフォーム)に並んだときは、やはり嬉しいものです。

「AIを学ぶために、AIを使い倒す」。

この楽しさを、ぜひ皆さんにも体験してほしいと思います!

2026年4月4日土曜日

【Azure】接続文字列をコードに書かない!App Service環境変数とKey Vaultの使い分け

 

はじめに

AzureでWebアプリを開発している際、DBの接続文字列やAPIキーなどの「機密情報」をどう扱うべきか悩んだことはありませんか?

「ソースコードに直書きするのはNG」というのは共通認識ですが、いざAzureで管理しようとすると「App Serviceの環境変数(構成)」と「Azure Key Vault」のどちらを使うべきか、その境界線が分かりにくいものです。

今回は、私が実際に開発で「Key Vaultを使いたかったけれど、結局環境変数で対応した」という経験をベースに、それぞれの違いと使い分けのポイントを整理しました。

なぜソースコードに「機密情報」を書いてはいけないのか?

まず大前提として、パスワードや接続文字列をソースコードや appsettings.json にハードコーディングしてはいけません。

• GitHubなどのリポジトリ経由で漏洩するリスク

• 環境(開発・本番)ごとの切り替えが困難になる

この対策として、Azureには主に2つの逃げ道があります。

1. App Serviceの「環境変数(構成)」による管理

今回私が採用したのが、Azure App Serviceのメニューにある「構成(環境変数)」に値を設定する方法です。

メリット

• 設定が非常に簡単: Azureポータルからポチポチ入力するだけで即反映されます。

• コードの修正が最小限: .NETであれば Configuration["Key名"] で読み取る標準的な手法がそのまま使えます。

デメリット

• 閲覧権限の問題: Azureポータルの該当リソースにアクセスできる人なら、誰でも値が見えてしまいます。

• 共有ができない: 別のApp ServiceやFunctionsでも同じ値を使いたい場合、それぞれにコピーする必要があります。

2. Azure Key Vaultによる管理

本来、より高いセキュリティを求めるならこちらが本命です。

メリット

• 最高レベルの機密性: 値そのものを隠蔽でき、誰がいつアクセスしたかのログも残ります。

• 一元管理: 複数のサービスで一つのパスワードを使い回す場合、Key Vault側を更新するだけで全サービスに反映されます。

デメリット

• 設定のハードル: 「マネージドID(Managed Identity)」の設定や、アクセス権限(RBAC)の付与など、初見では少し難解な概念が登場します。

結局、どう使い分けるのが正解?

結論から言うと、以下のような基準で使い分けるのがスムーズです。


• App Serviceの環境変数(構成)で管理すべきもの

• アプリの動作設定(例:ログレベル、デバッグモードのON/OFF)

• 頻繁に変更する非機密なパラメータ(例:表示件数の上限、外部APIのベースURL)

• Azure Key Vaultで管理すべきもの

• 機密情報(例:データベースの接続パスワード、外部サービスのAPIキー)

• 証明書や暗号化キー(例:SSL証明書、署名用秘密鍵)

【Tips】「とりあえず動かす」から「理想」へのステップアップ

もし私のように「Key Vaultは難しそうで、今回は環境変数で済ませた」という場合でも、実は「Key Vault参照」という機能を使えば、後から簡単に移行できます。

App Serviceの環境変数に、直接値を入れるのではなく以下のような形式で記述します。

@Microsoft.KeyVault(SecretUri=https://myvault.vault.azure.net/secrets/mysecret/)

これなら、アプリのコードは1行も変えずに、裏側の保存先だけをKey Vaultに格上げすることができるのです。

まとめ:まずは「外に出す」ことが第一歩

Azure開発において、「Key Vaultを使いこなせなかった」というのは決して失敗ではありません。「ソースコードから機密情報を追い出した」という時点で、セキュリティレベルは大きく向上しているからです。

1. まずはApp Serviceの環境変数で「外出し」に慣れる。

2. 余裕が出てきたら「Key Vault参照」に挑戦してみる。

このステップで進めるのが、挫折しないAzure運用のコツだと感じました。


2026年3月29日日曜日

Azure DevOpsの無料枠「5人の壁」とは?知人のリーダーが悩んでいたコストと権限の話

 


1. 導入(設定の提示)

先日、別会社でチームリーダーをしている知人のエンジニアから相談を受けました。

『Azure DevOpsを使ってReposでソース管理を始めようとしたら、インフラ担当から開発メンバーは5人まで、管理者は1人という制限を言い渡された。これってAzureの仕様なの?それともうちの会社のケチなルール?』

という内容です。

2. 「5人制限」の正体は、Azure DevOpsのBasicプラン

結論から言うと、これは会社のケチなルールではなく、Azure DevOpsの標準的なライセンス仕様(Basicプラン)によるものです。

• 5人まで: Basicユーザーは5人まで無料。

• 6人目から: 月額料金(約$6〜/人)が発生。

知人のチームも、最初は『無料の範囲内でスモールスタートしたい』というインフラ側の意向があったようです。

こちらに詳しく書かられていました。

Azure DevOps の料金


3. 「管理者は1人」という運用の背景

さらに彼を悩ませていたのが『管理者は1人』という制約。

これはシステム上の制限というより、ガバナンス(統制)の側面が強いとアドバイスしました。

• Organization Ownerは1人。

• マスターへのマージやデプロイ権限を絞ることで、事故を防ぐ運用。

• ただし、リーダーとしてコード管理をスムーズにしたいなら、権限(Project Administratorsなど)を適切に切り分けてもらう交渉が必要かもしれません。

4. 解決策として提示したアドバイス

相談に来た彼には、以下の3つのチェックポイントを伝えました。

1. Stakeholder(ステークホルダー)の活用: コードを見ないメンバー(進捗確認のみのPMなど)は、無料枠の5人にカウントされず無制限に招待できる。

2. Visual Studio サブスクリプションの確認: もし既にVSのライセンスを持っていれば、その人は5人の枠を使わずにBasic機能が使える。

3. 役割の明確化: 誰がマージ権限を持ち、誰がリリースを承認するか。人数を増やす前に、この『交通整理』をインフラチームと握っておくことが重要。

5. まとめ

クラウドサービスは便利ですが、こうした『人数の壁』が突然現れます。

実体験(相談)を通じて感じたのは、開発効率とライセンス費用のバランスを、リーダーがいかに把握しておくかという大切さでした。


2026年3月22日日曜日

【Azure】Azure App ServiceやDBを夜間停止してコスト削減!Azure AutomationとPython SDKで自動化する方法


 個人開発や検証環境でAzureを使っていると、気になるのが「コスト」ですよね。

特に Application Gateway (Agw) や App Service、PostgreSQL は、動かしっぱなしにすると地味に費用が嵩みます。

これまでは「使う時だけポータルから手動で起動・停止」していましたが、ついつい消し忘れて翌朝絶望することも…。そこで、Azure Automation を使って、これらをスマートに自動管理する仕組みを調べて実装してみました。

1. なぜ「手動」から「自動化」へ?

手動運用の課題は、単に「面倒」なだけではありません。

• 消し忘れリスク: 24時間稼働による無駄な課金。

• 依存関係の複雑さ: App Serviceだけ起動しても、Agwが止まっているとサイトにアクセスできないといった「起動順序」のミス。

• デプロイ時の手間: 開発のたびにポータルを開くスイッチ作業のロス。

これらを解決するのが Azure Automation です。

2. Azure Automationによる自動化の仕組み

今回採用したのは、Azure Automationの 「Runbook」 機能です。

PythonのSDKを使用して、複数のリソースを一括でコントロールします。

構成のポイント

• Managed Identity: Automationアカウントに権限を付与し、パスワードレスで操作。

• Automation 変数: サブスクリプションIDやリソースグループ名をコードに直書きせず、変数として管理。

3. 【実践】Python SDKでリソースを制御するコード

実際のコードの肝となる部分を解説します。

GetAutomationVariable を使い、動的にリソースを特定して操作する流れです。



# イメージとしてのコード例

from azure.mgmt.web import WebSiteManagementClient

from azure.mgmt.rdbms.postgresql_flexibleservers import PostgreSQLManagementClient

# (中略) 認証処理など


# Automation変数から情報を取得

rg_name = get_automation_variable("ResourceGroupName")


# App Serviceの起動例

for app in web_client.web_apps.list_by_resource_group(rg_name):

    if app.name == "対象のサービス名":

        web_client.web_apps.start(rg_name, app.name)

        print(f"{app.name} を起動しました。")



このように、xxxManagementClient を使って、リソースを探索し、start() や stop() を呼び出すだけでOKです。


4. ハマったポイント:サイトにアクセスできない!?

自動化を実装した際、App ServiceとDBを起動したのに「このサイトにアクセスできません」となることがありました。原因は Application Gateway (Agw)。

Agwはポータルに停止ボタンがないため見落としがちですが、SDK経由で停止されている場合、ここも明示的に start させる必要があります。



5. まとめと今後の展望

Azure Automationを設定すれば、スケジュール機能(Schedule)を使って「平日の夜間だけ止める」といった運用が数クリックで実現します。

• メリット: 確実なコスト削減と、ポータル操作からの解放。

• 次の一歩: 今後は「デプロイ時だけ一時的に起動し、終わったら自動で閉じる」といったGitHub Actionsとの連携も試してみたいと思います。


2026年3月8日日曜日

【2026年最新】AZ-900合格体験記!Udemyの的中率は?初見問題3割を突破した最短攻略法

 


■ はじめに

本日、Microsoft Azure Fundamentals(AZ-900)に無事合格しました!


実務でAzureに触れる機会が増えたため受験しましたが、効率的な学習のおかげで短期間でパスすることができました。今回は私が活用した教材と、本番で焦らないための対策を共有します。

■ 使用した教材:Udemy「これだけで合格!AZ-900 模擬試験問題集」

私が活用したのは、Udemyの人気講座です。

講座リンク

この問題集のおかげで、基本的な知識の土台を固めることができました。特におすすめしたいポイントは以下の2点です。

1. 更新日時が新しく、2026年最新版に対応

Azureはアップデートが激しいですが、この講座は2026年1月更新と非常に新しいため、安心して取り組めました。

2. 「高度な模擬試験」が2回分付いている

基本レベルだけでなく、少しひねった「高度な模擬試験」が2回分含まれています。これが本番の「初見問題」への対応力を養ってくれました。

■ 本番のリアル:3割は見たことのない問題!?

正直に言うと、模擬試験を完璧にしても、本番では約3割ほど「見たことがない問題」が出て焦りました。

しかし、この問題集の解説を読み込み、「なぜこれが正解なのか」「似たサービスとの境界線はどこか」という本質を理解していたため、消去法や論理的思考で正解を導き出すことができました。

■ 私が実践した「直前仕上げ」のコツ

試験直前、完成度を一気に高めたのはこの方法です。

「模擬試験で間違えた問題だけを、繰り返し見直す」

正解した問題に時間をかけず、不正解だった選択肢の「なぜ間違えたか」の解説を読み込む。これを徹底することで、自分の弱点を完全に潰した状態で本番に挑めました。

■ まとめ

AZ-900は、しっかりとした土台があれば怖くありません。これから受験される方は、ぜひ最新の情報を反映したこのUdemy教材を活用してみてください!

【最短合格を狙うならこちら





2026年3月5日木曜日

Azure DevOps障害に翻弄された月曜日

 



■ はじめに

知り合い数人と進めている共同開発プロジェクト。3月に入った途端、メンバーの一人から「Gitのpushで認証エラーが出るようになった」と連絡が。

「あぁ、またPAT(アクセストークン)の期限切れか、月替わりの認証情報の更新かな」なんて、この時はまだ高を括っていた。

■ 迷走の始まり:自分だけ「成功」するという罠

まずは状況の切り分け。

「こっちでは普通にpullもpushもできるよ」

この一言が、原因特定を遅らせる最大のフラグになった。

自分ができる以上、プロジェクトの設定やAzure側の障害ではないはず。メンバーのローカル環境の問題だと断定し、以下の指示を飛ばした。

• 資格情報マネージャーの古い情報を消してみて

• git config --global credential.useHttpPath true を試して

• ブラウザのキャッシュをクリアして……

しかし、返ってくるのは「全部ダメだった」という絶望のレスポンス。

■ エラーメッセージとの格闘

送られてきた画面には、無慈悲なメッセージ。

TF10216: Azure DevOps services are currently unavailable.

Activity Id: 35b9da34...

Activity IDまで出ているのに、Azure DevOpsのStatus Portal(稼働状況)は「All Green」。アジアリージョンも正常。

「Activity IDまで出てるんだから、そっち(Azure)のせいだろう」と思いつつも、公式が「正常」と言い張る以上、こちら側の設定(認証ポリシーの変更など)を疑わざるを得ない。

■ 衝撃の結末

数時間が経過し、再度Status Portalをリロードしてみると……。

さっきまで鮮やかな緑色だった「Asia」のアイコンが、真っ赤な「Unhealthy」に変わっていた。

結局、Microsoft側の認証基盤の障害。

私がpushできていたのは、たまたま認証セッションが有効なサーバーに繋がっていたか、キャッシュが生きていただけだった。時間が経てば、いずれ私の環境でもエラーが出ていたはず。

■ 今回の教訓:ステータスサイトは「後出しジャンケン」

今回の件で学んだ教訓は3つ。

1. 「自分だけ動く」は環境が正常な証拠にはならない。(運がいいだけの場合がある)

2. 公式ステータスの「All Green」は、リアルタイムとは限らない。(反映にラグがある)

3. Activity IDが出たら、それはもう自分たちの範疇を超えている。

特に月替わりのタイミングは「自分のミス」を疑いがちだが、メンバー全員で一斉に起きた時は、公式ステータスが緑でも「コーヒーを飲んで1時間待つ」のが、精神衛生上もっとも正しいエンジニアの振る舞いかもしれない。

締めの一言

「Activity IDを必死にググっていたあの時間を返してほしい……(笑)」

2026年3月2日月曜日

Azure Database for PostgreSQLで突然の504。ログから遅延SQLを特定して改善するまで



 はじめに


自習環境でPDF出力機能を検証していたときのことです。

ある日、突然処理が終わらなくなりました。


しばらく待っていると、画面には 504 Gateway Timeout。


「メモリが足りないのか?」


最初はそう思いました。


メモリを疑う


Azure App Service のメトリクスを確認。

メモリ使用率はおよそ45%。


上限に張り付いているわけではありません。


念のため、コンテナ内でも確認しました。


cat /sys/fs/cgroup/memory/memory.limit_in_bytes


表示された値は、実質無制限に近い数字。


少なくとも、メモリ制限で落ちているわけではなさそうでした。


ではなぜ504が出るのか。


「タイムアウトかもしれない」


処理時間を見直す


ログを丁寧に追っていくと、リクエストが300秒以上かかっていることが分かりました。


これなら504になってもおかしくありません。


問題はメモリではなく、単純に「遅い」ということでした。


SQLを疑う


PDF出力処理では、データを取得してループしながら帳票を組み立てています。


もしかして、特定のSQLが遅いのでは?


そう思ってAzure Database for PostgreSQLを確認しました。


しかし、Query Storeは無効。


さらにサーバーパラメータを見ると、


log_min_duration_statement = -1


遅いSQLは一切ログに出力されていませんでした。


見えないものは、直せない。


まずは可視化から


log_min_duration_statement を 1000 に変更しました。


これで1秒以上かかったSQLがログに出ます。


その状態で、問題のPDF出力をもう一度実行。


Azureポータルのログを開き、息を詰めて確認しました。


出てきました。


duration: xxxx ms


同じSELECT文が何度も並んでいます。


そして、1回あたりも決して軽くない。


ようやく、ボトルネックが見えました。


インデックス不足


検索条件に使っているいくつかの列があります。


しかし、それらをまとめてカバーするインデックスはありませんでした。


複合インデックスを追加しました。


ロック影響を避けるため CONCURRENTLY を使用。


そして再度実行。


結果は


約10秒 → 約2秒。


はっきり分かる改善でした。


学び


今回の一件で感じたことがあります。


最初にメモリを疑ったのは、完全に思い込みでした。


504が出ると「リソース不足」と考えてしまう。

でも実際は、単純なインデックス不足。


そして何より大きかったのは、


推測ではなく、ログで確認したこと。


log_min_duration_statement が -1 のままだと、何も見えません。


見えないまま議論しても前に進みません。


まずは可視化。


そこからボトルネックを特定し、最小限の対処をする。


遠回りに見えて、それが一番早いと感じました。


おわりに


今回の問題はインデックスで改善しました。


ただし、ループ内でのクエリ実行は構造的な負荷を生みやすい部分でもあります。

N+1の可能性も含め、設計レベルでの見直しも今後の課題です。


それでも、504の正体を一つずつ剥がしていく過程は、とても良い学びになりました。


エラーの裏には、必ず理由がある。

焦らず、数字を見て、順番に潰す。


改めてその大切さを実感した出来事でした。


2026年2月17日火曜日

夜間はタダ!?Azure Container Apps vs App Service 料金比較と使い分けのポイント

 



1.Azure App serviceが最高だと思ってました

「誰も使っていない夜中のサーバー代、もったいないな…」と思ったことはありませんか?


開発した社内ツールや個人開発のアプリ。便利に使っているけれど、ふとコスト画面を見ると、誰もアクセスしていない深夜や休日も律儀に課金が続いている。Azure App Serviceを使っていると、これは「当たり前」の光景ですよね。


でも、AZ-900の勉強をしていたら見つけてしまったんです。「リクエストがない時は料金をタダにできる」という、魔法のようなサービスを。


今回は、App ServiceからAzure Container Appsに乗り換えるだけで、どれだけコストが浮くのか、その衝撃の事実をまとめました。


2. 詳細な料金計算の比較

※ 料金は目安(東日本リージョン、2024年現在の概算)としてご覧ください。

前提条件

• アプリのスペック: 1 vCPU / 2GB RAM 相当

• 稼働状況: 平日9:00〜18:00(月20日)だけリクエストがあり、それ以外はアクセスゼロ。

• 月間稼働時間: * 稼働中:9時間 × 20日 = 180時間

• アイドル中(夜間・休日):550時間

A. Azure App Service (Basic B1プラン)

App Serviceは、アクセスがなくてもサーバーを維持するため、730時間フルで課金されます。

• 計算: 月額固定 約 $13.00〜$15.00

• 特徴: アクセスがなくても、常にこの金額が発生。

B. Azure Container Apps (消費プラン)

アクセスがない時間は「0」にスケールアウト(停止)させると仮定します。

• 稼働中の料金: * vCPU: $0.000024/秒 × 3,600秒 × 180時間 ≒ $15.55


• メモリ: $0.000003/秒 × 3,600秒 × 180時間 ≒ $1.94

• 停止中(夜間・休日)の料金: $0

• 合計: 約 $17.49 > あれ?高くなった? と思われるかもしれませんが、ここがポイントです!実はContainer Appsには、毎月の 「無料枠」 があります。

C. Container Apps(無料枠適用後)

Container Appsには、毎月以下の無料枠がついてきます。

• 無料枠: 最初の180,000 vCPU秒、360,000 GiB秒

• 実質コスト: このシミュレーションの規模(月180時間稼働)だと、無料枠を差し引くと 月額 数ドル(約$2〜$5程度) まで抑えられるケースが多いです。

3. 比較まとめ表

• Azure App Service (PaaS)

• Cost Model: Fixed Monthly Fee (固定料金)

• Nighttime Cost: Always On (夜間も課金継続)

• Key Strength: Easy setup for Web Apps (Webアプリ特化で管理が楽)

• Best For: High-traffic sites (24時間安定稼働が必要なサイト)

• Azure Container Apps (Serverless)

• Cost Model: Pay-per-use (使った分だけ秒単位課金)

• Nighttime Cost: Zero / Free (夜間停止で0円が可能)

• Key Strength: Scale-to-Zero (リクエストがなければ自動停止)

• Best For: Internal tools & Dev environments (社内ツールや検証環境)


補足: 

App Serviceも手動やスクリプトで停止(Stop)できますが、プラン自体の料金(インスタンス予約代)は発生し続けるため、Container Appsのように「動いていない時は本当にタダ」というレベルにするには、プランの削除・再作成が必要で手間がかかります。


まとめ

個人でやる分にはコスパ最高のContainer Appsなのですが、お客様向けには、Webサイトを安全に運用するための機能が全部入りのApp serviceが良さそうです。そんなに甘くはなかったか、、、。でも、要件によっては使えそうなサービスと感じました。

2026年2月14日土曜日

Azure DevOpsで「Invalid clientid or client secret」エラーが出た時の解決策!Workload Identity Federationへの移行手順




Azure DevOpsからApp ServiceへDockerイメージをデプロイしようとしたら、突然のエラー。

Invalid clientid or client secret.

昨日まで動いていたのになぜ?

原因はサービス接続(Service Connection)の裏側にある「アプリの登録」の有効期限切れでした。

今回は、今後二度と期限切れに悩まされない「Workload Identity Federation」を使った最新の修正方法をまとめます。

1. 発生したエラー:Build and Push Web Imageで失敗

まずは、私が発生したエラーログを共有します。
• ##[error]error from registry: Invalid clientid or client secret.
• ##[error]The process '/usr/bin/docker' failed with exit code 1
一見するとApp Service側の問題に見えますが、実はAzure Container Registry (ACR) へのログイン失敗が原因でした。


2. 原因:サービス接続(サービスプリンシパル)の有効期限切れ

Azure DevOpsの「サービス接続」は、裏側でAzure Entra ID(旧Azure AD)の「アプリの登録」を利用しています。
インフラ管理画面(Entra ID > アプリの登録 > 証明書とシークレット)を確認したところ、シークレットの有効期限がバッチリ切れていました。


3. 解決策:Workload Identity Federation (automatic) で再作成

シークレットを更新しても直りますが、また数年後に同じエラーが起きます。
今回は、Microsoftが推奨している「パスワードレス」な方式、Workload Identity Federation を使って作り直しました。
設定の手順:
• Project Settings > Service connections > New service connection
• Azure Resource Manager > Workload Identity Federation (automatic) を選択
• 対象のサブスクリプションとリソースを選択して保存

4. YAMLファイルの修正と承認(Permit)

接続を新しく作った後は、azure-pipelines.yml の containerRegistry や azureSubscription の名前を新しいものに書き換えます。
初回実行時は、パイプライン画面で 「Permit(許可)」 ボタンを押すのを忘れないようにしましょう。
※パイプライン実行した後、しばらくしてサイト見てみたら表示できなくて、焦ってパイプライン状況をみたら途中で止まっててびっくりしました。許可が必要だなんて知らなかった、、、

2026年1月28日水曜日

【Azure】WAFとの死闘168時間。ASP.NET CoreアプリをAzure WAFで守ろうとして学んだこと

 



1. イントロダクション

Azureを勉強して、ASP.NET Coreでポートフォリオ兼用のWebアプリを公開してみた。

「せっかくなら実戦的に」とAzure Web Application Firewall (WAF) を導入したが、ここからが本当の戦いの始まりだった……。

2. 最初の壁:ログインできない!

公開直後、ログインしようとすると謎の403エラー。ログを確認すると……

Restricted SQL Character Anomaly Detection (args): # of special characters exceeded (12)

何が起きていたのか?

ASP.NETの認証用Cookieに含まれる記号の多さが、「攻撃用コードを隠している」と判定されていた。

• 原因: WAFの「異常検知ルール(942450など)」。

• 気づき: セキュリティを強くしすぎると、標準的なフレームワークの挙動すら「悪」とみなされる。

3. 第二の壁:いたちごっこの泥沼

特定のCookieを除外設定(Exclusion)して「勝った!」と思ったのも束の間。今度は別のログが。

• SQL Injection Attack: SQL Tautology Detected(1=1攻撃の誤認)

• Multiple URL Encoding Detected(二重エンコードの誤認)

しかも、よく見るとCookieだけでなく、URLの引数(ARGS)でも発生している。

ここで私は、「1つ1つ除外設定を書いていたら、いつまでもアプリがまともに動かない」という現実に直面した。

4. 決戦:ログから読み解く「真犯人」

WAFのログに記録された detail_message_s をデコードして、じっくり眺めてみた。

そこには、攻撃コードではなく、ただの「日付データ」や「パスワードの記号」があった。

今回の学び(技術的な急所)

1. 多重エンコードの正体: URLの中にURLを入れる(ReturnUrl)際、記号が %252F のように多重変換される。これはモダンなWebフレームワークの「標準仕様」であって攻撃ではない。

2. パスワードの宿命: 強力なパスワードには記号が必須。これをWAFのSQLIルールで検査すること自体が、実はアンチパターン。

5. 解決策:多層防御の再設計

「WAFの設定をいじり続ける」のをやめ、「どこをWAFに任せ、どこをアプリに任せるか」の役割分担を見直した。

• WAF側: パスワードやReturnUrlなど、正規の処理で記号が入り混じる箇所は、勇気を持って「検査除外」または「特定ルールの無効化」を行う。

• アプリ側: ASP.NET Core Identityを正しく使い、「パラメータ化クエリ(静的プレースホルダ)」と「アカウントロック機能」を有効にする。

6. おわりに:本当のセキュリティとは

WAFは「魔法の杖」ではなかった。

ただボタンをポチポチして「最強」に設定するのではなく、「自分のアプリがどういうURLを吐き出し、どういうCookieを使うのか」を理解して、初めて正しく運用できる。

「いたちごっこ」を終わらせたのは、WAFの知識ではなく、自作したASP.NET Coreのソースコードの中にあった一行のエビデンスだった。


2026年1月25日日曜日

【Azure】 ASP.NETアプリを公開したら、正常な通信がブロックされまくった話(解決編)




Azureを勉強して、ASP.NETでWebアプリを作ってみました。
Application Gateway(WAF)も立てて、セキュリティは万全!……のはずが、いざ公開してみると、自分や友人のログインが突然ブロックされるという謎の現象に遭遇しました。
今回は、初心者がハマりがちな「WAF運用いたちごっこ」の正体と、スマートな解決策を共有します。

1. 犯人は「ランダムすぎるCookie」

ASP.NET(特にCore)には、セキュリティを守るための仕組みが標準で備わっています。
その代表格が、以下のようなCookieやトークンです。
• .AspNetCore.Mvc.CookieTempDataProvider
• .AspNetCore.Antiforgery
これらの中身は、セキュリティのために「推測不可能なランダム文字列」になっています。
ところが、このランダムな文字列の中に、たまたまSQLインジェクション攻撃に似たパターン(-- など)が紛れ込んでしまうことがあるのです。

2. 初心者が陥る「ID除外の罠」

WAFのログ(Log Analytics)を見ると、「ルールID: 942440 でブロック」と出ます。
そこで「よし、この 942440 を許可リストに入れよう!」と設定するのが、最初の落とし穴です。
実は、Cookieの中身は毎回変わるため、「昨日は 942440 だったけど、今日は 942441 でブロックされる」という現象が起きます。これが「いたちごっこ」の始まりです。

3. 正解は「変数のグローバル除外」

特定のルール番号を許可するのではなく、「この名前のCookieについては、WAFの全検査をスキップしていいよ」という設定をするのが正解です。
設定のコツ(Azureポータル)
WAFポリシーの「管理ルール」→「除外」設定で、以下のように登録します。
• 一致変数: 要求のCookieの名前
• セレクター: .AspNetCore.Mvc.CookieTempDataProvider
• ルールセット: ここを特定のIDにせず、全体(Global)にするのがポイント!
これで、どんなランダムな値が入ってきても、WAFが「あ、このCookieは安全な枠組みのやつだね」とスルーしてくれるようになります。

4. もっと安心するために:Azure Advisorを活用しよう

「除外設定を増やすとセキュリティが弱くならない?」と不安になるかもしれません。
そんな時は、Azure Advisor や Microsoft Defender for Cloud の「セキュリティ態勢」をチェックしましょう。
「基盤となる CSPM(無料版)」を有効にするだけで、Azureが「他にも設定ミス(暗号化漏れなど)はない?」と自動で診断してくれます。今回のWAF設定だけでなく、サイト全体の健康診断をセットで行うのが、モダンなクラウド運用のコツです。

最後に

WAFは「ただ置くだけ」では、時に味方を攻撃してしまうことがあります。
「いたちごっこ」に疲れたら、ぜひ除外設定の「範囲(スコープ)」を見直してみてください。
「ログを見て、原因を突き止め、ベストプラクティスを適用する」。この流れを一度経験すると、クラウドのセキュリティがぐっと身近に感じられるようになりますよ!  

【おまけ】WAFのブロック理由を特定するKQLクエリ

Azure WAFが「何を」「どのルールで」ブロックしたのかを調べるためのクエリです。
Azure Portalの Log Analytics で実行してください。

1. 直近のブロック履歴を一覧表示する

まずは「何が起きているか」の全体像を把握するクエリです。

// WAFのブロックログを新しい順に100件表示
AzureDiagnostics
| where ResourceProvider == "MICROSOFT.NETWORK" 
| where Category == "ApplicationGatewayFirewallLog"
| where action_s == "Blocked"
| project TimeGenerated, clientIp_s, requestUri_s, ruleId_s, Message, details_data_s
| order by TimeGenerated desc
| take 100


2. 特定のCookieが原因でブロックされているか特定する

今回の「犯人(Cookie)」を追い詰めるためのクエリです。

// 特定のCookie名が含まれるブロックログを抽出
AzureDiagnostics
| where ResourceProvider == "MICROSOFT.NETWORK" 
| where Category == "ApplicationGatewayFirewallLog"
| where action_s == "Blocked"
// ↓ここに調べたいCookie名(.AspNetCore.Mvc.CookieTempDataProviderなど)を入れます
| where details_data_s contains "CookieTempDataProvider" 
| project TimeGenerated, clientIp_s, ruleId_s, details_data_s, details_message_s
| order by TimeGenerated desc

3. どのルールIDによく引っかかっているか集計する

「いたちごっこ」が起きていることを証明するためのクエリです。

// ブロックされたルールIDのランキングを表示
AzureDiagnostics
| where ResourceProvider == "MICROSOFT.NETWORK" 
| where Category == "ApplicationGatewayFirewallLog"
| where action_s == "Blocked"
| summarize Count = count() by ruleId_s, Message
| order by Count desc


ワンポイントチェック
ruleId_s: どのルールに触れたかがわかります。

details_data_s: Cookieやリクエストの中身の「どの文字列」がダメだったのか、具体的な中身が表示されます。ここを見て Password=... ではなく、ランダムな英数字の羅列であれば、誤検知の可能性大です!





2026年1月2日金曜日

【解決】Azure VMで「The target machine has denied access」エラー!原因はパスワード間違いによるロックアウト?(0xC0000234)

 


Azureの仮想マシン(VM)に突然RDP接続できなくなったことはありませんか?

「The target machine has denied access to this connection」というエラーが表示された場合、原因はネットワーク設定ではなく、パスワードの入力ミスによる「アカウントロックアウト」かもしれません。

本記事では、シリアルコンソールを使った原因特定方法から、具体的な復旧手順までを解説します。

1. 発生した事象とエラーメッセージ

まずは、どのような状況で接続できなくなったのかを記載します。

• 現象: RDP(リモートデスクトップ)接続時に拒否される。

• エラー文: The target machine has denied access to this connection.

• 心当たり: パスワードを数回間違えて入力した。

2. 原因の特定:シリアルコンソールでログを確認する

「本当にパスワード間違いが原因か?」を外側から特定する方法を紹介します。

手順:

Azureポータルから対象VMの「シリアルコンソール」を開く。

cmd → ch -si 1 でコマンドプロンプトを起動。

以下のコマンドでイベントログを確認。

wevtutil qe Security /q:"*[System[(EventID=4625)]]" /c:5 /f:text /rd:true


特定ポイント:

ログの中に以下の情報があれば、ロックアウトが確定です。

• 失敗の原因: アカウントのロックアウト

• 状態コード: 0xC0000234

3. 解決策:アカウントロックを解除する方法

ロックアウトされた場合の対処法は3つあります。

① 自動解除を待つ(30分〜1時間)

多くの設定では、一定時間経過するとロックが自動解除されます。急ぎでない場合は、「一切の操作をせず待つ」のが最も安全です。

② Azureポータルからパスワードをリセット(即時)

急ぎの場合は、Azureポータルの「パスワードのリセット」機能を使います。

Tips: 既存のパスワード(チームで共有しているもの等)を変えたくない場合は、一度「別パスワード」に変更してログインした後、OS内部の設定から元のパスワードに戻すのがコツです。


③ ネットワーク設定(NSG)の確認

もし上記でもダメな場合は、念のためNSG(ファイアウォール)でRDPポート(3389)が開放されているか、自分のIPアドレスが許可されているかを確認しましょう。

まとめ:予防策

• パスワード管理ツールを使用し、打ち間違いを防ぐ。

• 踏み台サーバー(Bastion)の利用を検討する。


2025年12月31日水曜日

Azure Pipelinesで.NET Coreビルドが失敗する原因と解決策|デフォルトYAMLの修正ポイント

 



以前書こうと思っていたのですが、バタバタしていてまとめる機会がなかなか無く、やっと時間が取れたので、昔を思い出しながら書いてみます。


1. はじめに:Azure Pipelinesは「おまかせ」で動かない?

Azure DevOpsを使い始めたばかりの頃、私は感動しました。

「.NET Core」というテンプレートを選ぶだけで、勝手にYAMLファイルが生成され、あとは実行ボタンを押すだけ。

「これでCI/CD対応完了だ!」と意気揚々と実行した結果、画面に表示されたのは無情な赤いバツ印(Failed)でした。

なぜ、Microsoft純正のテンプレートなのにそのままでは動かないのか?

今回は、初心者が必ずハマる「デフォルトYAMLの落とし穴」と、その修正ポイントをまとめます。

2. 【罠1】SDKのバージョンが合っていない

デフォルトのYAMLには、多くの場合「どのバージョンの.NET SDKを使うか」という指定が抜けています。その結果、Agent(ビルド用マシン)にインストールされている最新バージョンが使われ、古いプロジェクトや新しすぎるプロジェクトがビルドエラーになります。

解決策:UseDotNet@2 タスクを最初に追加する

ビルド(Build)タスクの前に、明示的にバージョンを指定するタスクを差し込みます。


steps:

- task: UseDotNet@2

  displayName: 'Install .NET SDK 8.x'

  inputs:

    packageType: 'sdk'

    version: '8.x' # 自分のプロジェクトのバージョンに合わせる



3. 【罠2】プロジェクトファイルが見つからない

デフォルトでは、リポジトリのルート(一番上の階層)に .csproj や .sln があることを想定しています。しかし、実際の開発では src/ フォルダの中にコードをまとめていることが多いはずです。

解決策:projects プロパティを書き換える

テンプレートのままだと、以下のようなエラーで止まります。

##[error]Project file(s) matching the specified pattern were not found.

これを防ぐために、ワイルドカードを使ってプロジェクトファイルを指定します。

修正前(デフォルト):

- task: DotNetCoreCLI@2

  inputs:

    command: 'build'

    arguments: '--configuration $(buildConfiguration)'


修正後:

- task: DotNetCoreCLI@2

  inputs:

    command: 'build'

    # リポジトリ全体から.csprojを探すように指定

    projects: '**/*.csproj' 

    arguments: '--configuration $(buildConfiguration)'



4. 【罠3】NuGetリストアの失敗

「ビルドタスクの中で一緒にリストア(ライブラリの復元)もやってくれるだろう」と思いがちですが、ここでも認証エラーやパスの問題が起きることがあります。

解決策:Restoreタスクを分離して明示する

ビルドとは別に restore コマンドを明示的に実行するのが、安定させるコツです。

- task: DotNetCoreCLI@2

  displayName: 'Restore NuGet Packages'

  inputs:

    command: 'restore'

    projects: '**/*.csproj'


5. まとめ:デフォルトは「完成品」ではなく「下書き」

Azure Pipelinesが用意してくれるデフォルトのスクリプトは、あくまで「最低限の構成案」です。

1. SDKバージョンを指定する

2. プロジェクトの階層(パス)を正しく伝える

3. リストア、ビルド、テストを順序よく構成する

この3点を意識するだけで、あの赤いエラー画面から卒業できるはずです。






2025年12月29日月曜日

【Azure】App ServiceのIP制限でハマった話。「確認くん」と違うIPが届く原因と調査法




Azure App Serviceで特定の拠点のみアクセスを許可しようと「アクセス制限」を設定したのに、なぜか自分すら弾かれる……。

「ログストリームを見れば原因がわかるはず」と思いきや、実はここには大きな罠があります。
今回は、App Service(特にLinuxベース)を使い始めたばかりの人が必ずハマる「IP制限の正体」と、正しいトラブルシューティング術について実体験を元に解説します。

1. 罠:403エラーのログは「ログストリーム」には出ない

ApacheやNginxの感覚でいると、「アクセス拒否(403エラー)されたならログが出るはず」と考えがちです。しかし、App Serviceのログストリームをどれだけ眺めても、IP制限で拒否されたログは1行も流れてきません。
なぜ出ないのか?
App ServiceのIP制限は、アプリに届く前の「Azureのプラットフォーム階層」で遮断されるからです。
• アプリ側のログ: アプリまで到達したリクエストの記録。
• IP制限: アプリに届く前に門前払いするため、アプリ側は「アクセスがあったこと」すら知りません。

2. 解決策A:ログが見れないなら「外側」から叩く

App Service側のログが見れない状況で、私が「真の接続元IP」を特定した方法が curl や tcpping です。
「確認くん」などのWebサービスで見えるIPは、ブラウザ(プロキシ経由)のIPに過ぎません。実際の通信がどう見えているかを直接叩いて確認します。
• curlで叩く: curl -v https://your-app.azurewebsites.net
• tcpping / pspingで叩く: ポート443に対して直接疎通を確認。
私のケースでは、これらを試す中で「確認くん」とは別のIPがゲートウェイとして使われていることが判明し、そのIPを許可することで解決しました。

3. 解決策B:どうしてもログを見たいなら「診断設定」

「どうしてもAzure側で拒否されたIPの履歴を特定したい」という場合は、診断設定(AzureAppServiceHTTPLogs)を有効にする必要があります。
ただし、ここで注意したいのがコストです。
インフラチームから「Log Analyticsは高額になりがち」と釘を刺されることがありますが、これは大量のログを溜め続けると課金が膨らむためです。
• 賢い使い方: 調査時だけ有効にし、接続元IPが特定できたらすぐにオフにする。
これでコストを最小限に抑えつつ、確実に「Azureが拒否したIP」をあぶり出せます。

4. まとめ:クラウドを使いこなす「引き出し」を持とう

今回の教訓は以下の3点です。
1. IP制限のログは、アプリのログストリームには出ない。
2. Web用のIPと通信用のIPが違う可能性を疑い、curl等で直接叩く。
3. 診断設定は強力だが、コストを意識して「使い終わったら消す」のがプロの作法。
「設定したのに動かない、ログも出ない」と焦る前に、この構造を知っていれば数分で解決できます。プログラムのコードだけでなく、こうした「クラウドの仕様」を知ることこそが、開発をスムーズに進める鍵となります。

2025年12月28日日曜日

【Azure】App Serviceで「勝手にログアウトされる」謎の現象。Data Protectionの罠と解決策

 


「ローカルでは正常にログインできるのに、Azureに上げたらセッションが維持されない…」

「しばらく放置すると、すぐにログイン画面に戻されてしまう…」

もし、ASP.NET CoreなどのWebアプリをAzure App Service(特にLinux版)で動かしてこのような現象が起きたら、それはコードのバグではなく「Data Protection(データ保護)キーの永続化」が原因かもしれません。

今回は、中級者でも意外と見落としがちな、クラウド環境におけるセッション管理の急所について解説します。

1. 現象:なぜかセッションが維持されない

App ServiceにデプロイしたWebシステムで、以下のような不安定な挙動が発生することがあります。

• ログインして操作している最中に、突然ログアウトされる。

• アプリを再デプロイ(スロット切替含む)すると、全員強制ログアウトされる。

• インスタンスを2つ以上に増やす(スケールアウト)と、ログインがほぼ不可能になる。

これらはすべて、「認証Cookieを復号するための鍵(マスターキー)」が失われているサインです。

2. 原因:Azure App Serviceの「揮発性」

ASP.NET Coreなどは、デフォルトで「Data Protection(データ保護)」という仕組みを使い、ログイン情報を暗号化しています。この暗号化に使う「鍵」の保存先が問題です。

• ローカル環境: Windowsのレジストリやファイルシステムに鍵が半永久的に保存されます。

• App Service (Linux): デフォルトではコンテナ内のファイルシステムに保存されます。しかし、App Serviceは再起動やデプロイのたびに中身がリセットされる「揮発性」を持っています。

つまり、サーバーが再起動するたびに「鍵」が捨てられ、新しく作り直されてしまうのです。古い鍵で作られたCookieは、新しい鍵では解読できないため、システムは「不正なユーザー」とみなしてログアウトさせてしまいます。

3. 解決策:鍵の保存先を「外部」に固定する

この問題を解決するには、Azureのストレージサービスを使って、鍵をコンテナの外に逃がしてあげる必要があります。

もっとも一般的な方法は、Azure Blob Storage を鍵の保管庫にすることです。

実装のイメージ(Startup.cs / Program.cs)

public void ConfigureServices(IServiceCollection services)

{

    // Blob Storageに鍵を保存する設定を追加

    services.AddDataProtection()

        .PersistKeysToAzureBlobStorage(new Uri("<BlobのSASトークン付URI>"));

}


※実際には、Azure Key Vaultを使って鍵自体をさらに暗号化するのがベストプラクティスです。

4. 初学者が知っておくべき「クラウドの流法」

今回のトラブルの教訓は、「サーバーの中を信用してはいけない」ということです。

• サーバーはいつでも使い捨てられる(ステートレス)。

• 消えて困る情報(鍵、ファイル、セッション)は必ず外部サービス(Blob, Redis, DB)に預ける。

この「クラウドの作法」を知っているだけで、デバッグに費やす数時間を節約できます。

5. まとめ:知れば怖くないData Protection

私もWebシステムの経験がありましたが、Azure特有のこの挙動には驚かされました。しかし、一度仕組みを理解してしまえば、設定一つで解決できる問題です。

「なぜかログインが切れる」と悩んでいる初学者の方がいたら、まずはData Protectionの保存先を疑ってみてください。



2025年12月27日土曜日

【Azure】PostgreSQLの登録日時が9時間ズレる?コードを直す前に確認すべき「魔法の1行」



 ローカル環境では完璧だった自作アプリ。しかし、Azure(App Service + PostgreSQL)にデプロイした途端、データの登録日時が「9時間前」を指している……。


「プログラムのバグか?」「PostgreSQLのタイムゾーン設定をSQLで直すべきか?」と焦って調査を開始しましたが、実は解決策はAzureポータル上の「環境変数」を1行足すだけでした。

今回は、知っているだけでトラブルを秒速で解決できる、クラウドサービスを使いこなすことの重要性について共有します。


1. 迫りくる「9時間の壁」

AzureのApp Service(Linux)やデータベースは、デフォルトでは世界標準時(UTC)で動いています。日本(JST)との時差はちょうど9時間。

未設定のままデプロイすると、アプリが「いま何時?」とサーバーに聞いた際にUTCが返ってきてしまい、そのままDBに「9時間前の過去」が刻まれてしまうのです。


2. 解決策:コード修正不要。Azureの環境変数を追加するだけ

当初は「プログラム内で AddHours(9) するか?」とも考えましたが、それは悪手です。Azureというプラットフォーム側で解決するのがスマートな方法でした。

実際に行った手順はこれだけです:

1. Azure Portalで対象の App Service を選択。

2. [設定] > [環境変数] を開く。

3. アプリケーション設定に以下の設定を追加して保存。

• 名前: WEBSITE_TIMEZONE

• 値: Asia/Tokyo

これだけで、App Service上のLinux OSの時間が日本時間に切り替わり、プログラムが吐き出す時刻も、DBに保存される時刻も一発で正常化しました。


3. 「調査」も大事だが「クラウドの仕様」を知る方が早い

今回の件で痛感したのは、「クラウドサービスを使いこなす」ことの威力です。

• プログラムの調査: コードを追い、テストし、再デプロイする(数時間〜)。

• DBの調査: パラメータを調べ、再起動の影響を考える(数十分〜)。

• Azureの設定: 環境変数を1行足すだけ(わずか30秒)。

「何かがおかしい」と思ったとき、まずは「Azure側で用意されているスイッチはないか?」と疑ってみる。この視点を持つだけで、開発効率は劇的に変わります。


4. 知ればすぐ対応できる。それがAzureの便利さ

クラウドのトラブルは「難しい」と思われがちですが、実は「知っているか、知らないか」だけの違いであることも多いです。

今回のように、WEBSITE_TIMEZONE というキーワードさえ知っていれば、余計な工数を使わずに済みます。プログラミングスキルと同じくらい、「クラウドという道具をどう使いこなすか」という知識をアップデートし続けることの重要さを改めて実感しました。


まとめ:トラブルを「仕様の理解」でねじ伏せる

Azure App Service + PostgreSQLの構成で日時のズレに遭遇したら、まずはポータルへ向かいましょう。

1. WEBSITE_TIMEZONE = Asia/Tokyo を設定する。

2. 動作確認する。

3. 浮いた時間で、より本質的な開発に集中する。

これこそが、現代のエンジニアにとっての「最短ルート」です。

2025年12月26日金曜日

【Azure】 WAFでログインできない?CookieのSQLインジェクション誤検知を解消する方法

 



Azure Application Gateway(AGW)でWAFを運用していると、昨日まで動いていたのに、急に特定のユーザーだけログインできなくなった」という謎のトラブルに遭遇することがあります。

ログを解析してみると、犯人はシステムへの攻撃ではなく、皮肉にも「セキュリティのために暗号化されたログインCookie」でした。今回は、WAFの誤検知(False Positive)との戦いと、その解決策についてまとめます。



1. 発生したトラブル:ログインボタンを押すと「403 Forbidden」

システム開発の最終盤、受入テストを目前に控えたタイミングで、一部のユーザーから「ログインできない」という報告が上がりました。

ブラウザのデベロッパーツールで確認すると、ログインリクエストに対して 403 Forbidden が返されています。アプリ側のログには何も残っておらず、どうやらアプリに到達する前の「WAF(Web Application Firewall)」で遮断されているようでした。


2. 原因:暗号化されたCookieがSQLインジェクションに見えた

Azureのログストリーム(または診断ログ)を調査したところ、以下の不穏な検知ログが見つかりました。

• 検知されたパターン: ?:/*!?|*/|[';]--|--[\s\r\n\v\f]|--[^-]*?-

• 検知対象: REQUEST_COOKIES:.システムで利用しているソリューション名


なぜこれが「攻撃」と判定されたのか?

ASP.NET Coreの認証システムが発行するCookieは、セキュリティを担保するために強力に暗号化されています。その結果、中身は CfDJ8Iwnl6yp... といったランダムな英数字・記号の羅列になります。

しかし、このランダムな文字列の中に、運悪く --(ハイフン2つ) が含まれてしまうことがあります。WAFの標準ルール(OWASP規則など)は、この -- を 「SQLのコメントアウトを悪用した攻撃コード」 と見なして、通信を即座にブロックしてしまったのです。

つまり、「セキュリティを高く保とうとした暗号化Cookieが、セキュリティ製品(WAF)に攻撃と間違えられた」という皮肉な構図です。


3. 解決策:特定のCookieを監視対象から除外する

全てのSQLインジェクション対策をオフにするわけにはいきません。そこで、「この名前のCookieだけは安全だから、チェックを通す」というピンポイントな除外設定(Exclusion)を行います。


Azure Portal での設定手順

1. WAF ポリシーのリソースを開きます。

2. 左メニューの [設定] > [管理ルール] を選択します。

3. 上部のタブから [除外] をクリックし、[追加] を押します。

4. 以下の通り設定します。

• 対象: 要求クッキー名 (Request cookie name)

• 演算子: 等しい (Equals)

• セレクター: . (※ご自身のシステムの認証Cookie名)

5. [保存] をクリックして適用します。

これで、WAFは「このCookieの中身がどうあれ、SQLインジェクションのチェックは行わない」という挙動になり、誤検知によるブロックが解消されます。


4. まとめ:WAFは「導入して終わり」ではない

今回の件で痛感したのは、WAFは導入後のチューニングが不可欠であるということです。

特にASP.NET CoreやJava Springなどのフレームワークを使っている場合、フレームワークが自動生成するCookieやトークンがWAFのルールに抵触することは珍しくありません。


「403エラーでログインできない」という報告を受けたら、まずはWAFのログを疑ってみてください。正しく「除外設定」を行うことで、鉄壁の守りとスムーズなユーザー体験を両立させることができます。

2025年12月22日月曜日

【Azure App Service】1台構成でもログインが消える原因。セッションアフィニティが必要だった話

 



最近AzureAppServiceを使ってサイト構築をしているのですが、

色々新しい学びがあり、楽しんでいます。


そこで、最近あった事象について共有したいと思います。


AzueのApp Serviceというのは、MicrosoftのクラウドサービスであるAzureが提供するPaaS環境で、要はOSのことを意識しないで、自分が作ったアプリを乗せることができる環境です。

そこにwebアプリとして.net coreで作った会員管理システムをリリースしました。

ログイン後、メニュー画面に遷移した瞬間に

未ログイン状態に戻されたり、404エラーがでたりしていました。


最初はアプリが落ちてしまったのか、サーバーが落ちてしまったのか、と考えたのですが、ログには例外エラーは出ておらず、原因不明でした。


調べていると、app serviceを複数使っていて、その前段にAGW

Azure Gatewayがあると、「セッションアフィニティ」を有効にするのが良いらしい、というところまでは調べました。


ただ、今回はapp serviceは一つしか使っておらず関係ないかな、思っていました。



しかし、一つでも、AGWがいる場合や、App Service側の内部プロセスが再起動した際、アフィニティCookieARRAffinity)がないとセッション情報の解読に失敗することがあるらしく、onにすることで改善しました。



Cookieの暗号化対応で、以前、暗号化キーの保存対応を行なったことがあったのですが、それをすればセッションも維持されるのでは、と勝手に考えていました。



AGWがいる場合や、App Service側の内部プロセスが再起動した際、アフィニティCookie(ARRAffinity)がないとセッション情報の解読に失敗することがあるようです。



解決した手順

1. Azure Portalでの設定:

• App Service > 構成 > 全般設定 > セッションアフィニティを「オン」にする。

※ Linux版では「セッションアフィニティプロキシ」という項目もあり、混乱しやすいので注意。

2. ブラウザの掃除:

• 古い鍵で暗号化されたCookieが残っているとエラーが続くため、一度ブラウザのCookieを全削除して再ログイン。


まとめ

• 「インスタンスが1台だからアフィニティは不要」という先入観は危険。

• 特にAGWなどのプロキシを挟む構成では、迷わず「オン」にすべき。

• まずはログストリームを見て 問題が出ていないか確認しよう。


、、、、ずっとモヤモヤしていたのですが、

アフィニティ

とは?

「アフィニティ(Affinity)」は、人や物に対する「親近感」「好意」「相性」「一体感」「類似性」などを意味する言葉

うーん。
どれの意味かな、、、

これかな


セッション アフィニティ ( セッション永続化 または スティッキー セッションとも呼ばれます) は、クライアントの要求が常に同じサーバーに送信されるように負荷分散で使用される手法です。

無理矢理訳すなら、セッション一体感、、、?

これが、インフラチームから渡された時はoffだったかな、

これはハマりますね、、、

皆さんがazureでサイト構築する場合は、ぜひお気をつけてください。


2025年10月6日月曜日

【開発】ASP.NET Core Identityを自分のユーザーマスタに組み込む:独自テーブルと連携するやさしい手順

最近、asp.net coreで開発をしていて、改めてその良さがわかったのでまとめたいと思います。

ASP.NET Core Identityは、ログイン機能を“ほぼ自動で”実装してくれる便利な仕組みです。ユーザー登録・パスワード管理・ロックアウト・2段階認証まで、すべて組み込み済みです。

ただし最初につまずくのがここです。

「うちのシステムには、すでに独自の社員マスタ(UserMaster)テーブルがある。
Identityのテーブルとはどうつなげばいいの?」

本記事では、レガシーな「社員マスタ」と、Identityの「認証管理」をきれいに統合する方法を解説します。

---

1. Identityの正体をざっくり理解する

Identityを使うと、自動的に次のようなテーブルが生成されます。

テーブル名役割
AspNetUsersユーザーの基本情報(ID、メール、パスワードハッシュなど)
AspNetRoles権限(Admin, Userなど)
AspNetUserRolesユーザーとロールの紐づけ
AspNetUserClaimsユーザーの属性(メール確認済みなど)

つまり、AspNetUsers が“認証の中心”です。 このテーブルに、あなたのシステム独自の情報(部署、社員番号、権限区分など)を追加すればOKです。

---

2. IdentityUserを継承してカラムを追加する(最も基本的な方法)

最もシンプルなやり方は、IdentityUserを継承したクラスに独自カラムを追加することです。

using Microsoft.AspNetCore.Identity;

public class ApplicationUser : IdentityUser
{
    public string EmployeeCode { get; set; }   // 社員コード
    public string Department { get; set; }     // 部署名
}

DbContextの拡張

using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore;

public class AppDbContext : IdentityDbContext<ApplicationUser>
{
    public AppDbContext(DbContextOptions<AppDbContext> options) : base(options) { }

    public DbSet<Product> Products { get; set; }  // 他のテーブルも共存可能
}

Program.cs(またはStartup)で設定

builder.Services.AddIdentity<ApplicationUser, IdentityRole>()
    .AddEntityFrameworkStores<AppDbContext>()
    .AddDefaultTokenProviders();

Migrationで反映

dotnet ef migrations add AddIdentityTables
dotnet ef database update

これで、AspNetUsersに新しい列(EmployeeCode、Department)が追加されます。

---

3. 既存の「UserMaster」テーブルを残したまま、Identityと連携する

public class ApplicationUser : IdentityUser
{
    public int UserMasterId { get; set; }    // 既存テーブルの主キー
    public virtual UserMaster UserMaster { get; set; }
}

DbContextで関連付け

public class AppDbContext : IdentityDbContext<ApplicationUser>
{
    public DbSet<UserMaster> UserMasters { get; set; }

    protected override void OnModelCreating(ModelBuilder builder)
    {
        base.OnModelCreating(builder);

        builder.Entity<ApplicationUser>()
            .HasOne(u => u.UserMaster)
            .WithOne()
            .HasForeignKey<ApplicationUser>(u => u.UserMasterId);
    }
}
---

4. ログイン画面の実装例

public class AccountController : Controller
{
    private readonly SignInManager<ApplicationUser> _signInManager;

    public AccountController(SignInManager<ApplicationUser> signInManager)
    {
        _signInManager = signInManager;
    }

    [HttpPost]
    public async Task<IActionResult> Login(LoginViewModel model)
    {
        var result = await _signInManager.PasswordSignInAsync(
            model.UserName, model.Password, model.RememberMe, lockoutOnFailure: false);

        if (result.Succeeded)
        {
            return RedirectToAction("Index", "Home");
        }

        ModelState.AddModelError("", "ログインに失敗しました。");
        return View(model);
    }
}
---

5. Identity拡張のコツと注意点

項目内容
カラム追加時ApplicationUserに列を追加したら、必ずdotnet ef migrations addを実行
外部キー連携循環参照に注意し、Navigation Propertyを最小限に
既存データ活用IdentityのUserIdと社員コードのマッピング方針を決めておく
---

6. まとめ

ASP.NET Core Identityは「全部作り直し」ではなく、既存のユーザーマスタと共存できる認証エンジンです。

  • パスワードの暗号化・認証管理 → Identityに任せる
  • 社員情報・業務ロジック → 自社マスタで管理

一言で言うと:
Identityは「既存システムの認証エンジンとして使う」のが正解です。