App Service 診断用アプリを作ってみた

App Service を使う上で、ログの出力や、アクセス制限で制御するために受け付けている要求ヘッダーの内容などを確認したいという要件がたまに出てきます。

そんな希望を叶えるアプリを作ってみたので紹介。

# 診断アプリ
- https://github.com/ShogoOhe47/azure-appservice-logging-netframework4
現時点では、App Service ログへの記録と受取っているヘッダー情報の出力が出来るようになっています。
![無題1.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/349915/5e345fe7-7da6-260d-34ba-8bbd501aff1a.jpeg)

Logging タブにアクセスすると、何もないページが表示されます。
![無題2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/349915/03fc1118-8bd7-e6ec-0b53-a141a05420f4.jpeg)

これは、.NET Framework の MVC で書かれたアプリケーションで、コントローラ部分に [App Service のアプリケーションログを記録する方法](https://learn.microsoft.com/ja-jp/azure/app-service/troubleshoot-diagnostic-logs#add-log-messages-in-code) に従って書かれたコードが記載されています。

アクセスすると、コントローラを経由する際に、アプリケーションログや診断設定で指定された AppServiceAppLogs に記録されます。
メソッドによってはあるログに記録される、されないといった違いもあるので、動作確認結果もコメントに書かれているので確認してみてください。
https://github.com/ShogoOhe47/azure-appservice-logging-netframework4/blob/master/Controllers/HomeController.cs#L17
```c#
        public ActionResult Logging()
        {
            string className = GetType().Name;
            string methodName = System.Reflection.MethodBase.GetCurrentMethod().Name;
            if (System.Environment.GetEnvironmentVariable("WEBSITE_SITE_NAME").IsEmpty() == false)
            {
                // this code only running on Azure
                // System.Diagnostics.Trace.TraceInformation is logging to AppServiceLog:ApplicationLog
                System.Diagnostics.Trace.TraceInformation($"{className}#{methodName}: Logging page is called. records from from System.Diagnostics.Trace.TraceInformation() method.");
                // System.Diagnostics.Trace.TraceInformation is logging to AppServiceLog:ApplicationLog, DiagnosticsSettings:AppServiceAppLogs
                System.Diagnostics.Trace.TraceError($"{className}#{methodName}: Logging page is called. records from from System.Diagnostics.Trace.TraceError() method.");
            }
            // Console.WriteLine is not logging.
            Console.WriteLine($"{className}#{methodName}: Logging page is called. records from from Console.WriteLine() method.");
            return View();
        }

```

もう一つの機能が、App Service が受け付けた要求ヘッダーの出力。
App Service 認証を有効にしている場合に App Service が受取っている要求情報、ブラウザや中継するプロキシや Application Gateway などが暗黙的に送っているヘッダー情報を出力しています。
認証が上手く行かない、アクセス制限が上手く行かない、と言った場合のデバッグ用途に使えるかも知れません。
![無題3.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/349915/31793429-37f7-c0f4-a6cc-3c44f844e76b.jpeg)


ちなみに、.NET 6 版もあるのですが、ログの収集が上手く機能しないため延期中です。
要求ヘッダーの表に時間しては機能しているので、必要に応じて使用してみてください。
- https://github.com/ShogoOhe47/azure-appservice-logging-net6/tree/development

# App Service 認証に対するアクセス
- https://github.com/ShogoOhe47/azure-appservice-authentication-msid-sample

もう一つが App Service 認証が有効なサイトにアクセスするためのサンプルコードです。

[App Service 認証](https://learn.microsoft.com/ja-jp/azure/app-service/overview-authentication-authorization#feature-architecture) は有効な環境に対するアクセスにおいて、トークンが無い場合はアクセスを拒否する仕組み。
Web ブラウザベースだと、AAD (Entra ID) にリダイレクトされて、認証情報を入れればそのままアクセスできますが、似たようなことをクライアントアプリケーションで実装しようとすると、仕組みを理解するのが中々難しい。そこで、作ったサンプルコードが以下の通り。

トークンの取得に当たり、アクセス方法はいくつかあり、HttpClient を使用して認証エンドポイントにアクセスする方法、[MSAL](https://learn.microsoft.com/ja-jp/entra/identity-platform/msal-overview) に任せて、最小限の操作だけ行う方法などがあります。

Program.cs の Main メソッドで定義してあるようにそれぞれ対応するクラスを準備しており、使用する方のクラスを有効化することで、トークンの取得が試せます。
- ExampleHttpClient
- ExampleMSAL

```c#
        static async Task Main(string[] args)
        {
            Console.WriteLine("Azure App Service Authentication access sample.");

            Program p = new Program();

            //ICallAuthProviderSample authClient = new ExampleHttpClient(p.authInstance, p.appserviceAuthClientId);
            ICallAuthProviderSample authClient = new ExampleMSAL(p.authInstance, p.appserviceAuthClientId);
            String token = await authClient.getToken(p.authTenantId, p.authClientId, p.authClientSecret);
            String contents = await authClient.accessAppService(p.appServiceSiteUri, token);

            Console.WriteLine(contents);
        }
```

注意点として、アクセスを試すには、(1) App Service にアクセスするクライアントのサービスプリンシパルの認証情報、(2) アクセス先 App Service の URI、クライアント情報の 2 つが必要になります。
値を取得して appsettings.json に指定することで App Service 認証を通過してアクセスできるようになります。
![無題4.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/349915/4c547e42-9360-69dd-9322-fd31793eaa03.jpeg)

# まとめ
コード自体はまだまだ改善の余地 (Bearer token の JWT をパースする等) があるので、拡張を続けますが、いったん動くところまで来たので公開しておきます。
何かの参考になれば嬉しいです。