.Net Core で サーバー証明書の検証をスキップする

自分に対するメモ。

.NET Core で、REST-API にアクセスしたいときに、サーバー証明書の検証をスキップしたい時がある。その時のコードの書き方。今やりたいのは、Kubernetesの REST API のアクセスを.NET Core からしたい。その時に、Kubernetes は独自の証明書を使っているから普通にはアクセスできません。次のサイトにまとまっています。

* [kubernetes REST API に外部から接続する](https://qiita.com/zaru/items/bf5b4e60ad4d67be8bea)

本来の方法は、上記のブログにかいてあるとおり、ルート証明書を k8s から取得してコンフィグするのでしょうが、最初のステップとして、SSL証明書をスキップして、ちゃんとREST-API が呼べるかどうかを確認しましょう。

# 実装

.Net Core での書き方は依然とは異なるようで、基本的には、下記のように書いてあげればOK. つまりコールバックの関数をわたすところで、カスタムのコールバックとして、常にTrueを返すという感じ。

```csharp
var httpClientHandler = new HttpClientHandler();
httpClientHandler.ServerCertificateCustomValidationCallback = (message, cert, chain, sslPlicyErrors) => true;
client = new HttpClient(httpClientHandler);    
```

ちなみにソースコードは、Resource のところに、[GitHub](https://github.com/TsuyoshiUshio/BindingSample/blob/master/KubernetesRestSpike/Program.cs) に置いておきました。

# エラーメッセージ

実は、サーバー証明書の検証をスキップするところで結構はまりました。もともと、`curl`では、動いていたのですが、C#で実装すると、`セキュリティエラー` というあいまいなエラーメッセージがでて全然原因がわかりませんでした。結局 `curl` のほうで、`--insecure`オプションをつけていたのを忘れたので、気づいたのですが、エラーメッセージからわからないのはつらすぎるので、コントリビュートしてみることを画策中です。

```
System.Net.Http.HttpRequestException
  HResult=0x80072F8F
  Message=An error occurred while sending the request.
  Source=System.Private.CoreLib
  StackTrace:
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.ConfiguredTaskAwaitable`1.ConfiguredTaskAwaiter.GetResult()
   at System.Net.Http.DiagnosticsHandler.<SendAsync>d__2.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.ConfiguredTaskAwaitable`1.ConfiguredTaskAwaiter.GetResult()
   at System.Net.Http.HttpClient.<FinishSendAsyncBuffered>d__58.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
   at KubernetesRestSpike.Program.<RunAsync>d__7.MoveNext() in C:\Users\tsushi\Source\Repos\CustomBindingsSample\KubernetesRestSpike\Program.cs:line 42
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at KubernetesRestSpike.Program.Main(String[] args) in C:\Users\tsushi\Source\Repos\CustomBindingsSample\KubernetesRestSpike\Program.cs:line 31

Inner Exception 1:
WinHttpException: セキュリティ エラーが発生しました
```

実装はたぶんこの辺り。まだ見つけられていないので、見つけたらおしえてください。
ServerCertificate

* [HttpClientHandler.Windows.cs](https://github.com/dotnet/corefx/blob/master/src/System.Net.Http/src/System/Net/Http/HttpClientHandler.Windows.cs)
* [WinHttpHandler](https://github.com/dotnet/corefx/blob/master/src/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpHandler.cs)
* [WinHttpRequestCallback: L289](https://github.com/dotnet/corefx/blob/7e6396b2bcb4d372b199cfb7b3b13e290c441124/src/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpRequestCallback.cs#L289)

と、思ったら元同僚が助けてくれた。やっぱ彼イケメン！ありがとう！
ちなみに、エラーメッセージはどうやら、Windows からとっているようなので、多分Windows のほうがこのメッセージを変えることは望み薄なので、まずはIssue から始めるといいんじゃない？ってアドバイスくれました。

> Hi Tsuyoshi,
>
> Looking at the code, it seems that whenever there is a ServerCertificateValidationCallback set and it returns false, a generic WinHttpException is created with an error message from an error message id:
>
>https://github.com/dotnet/corefx/blob/7e6396b2bcb4d372b199cfb7b3b13e290c441124/src/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpRequestCallback.cs#L312-L313
>
>The message is coming from Windows itself via a call to the Windows API function FormatMessage (https://msdn.microsoft.com/en-us/library/windows/desktop/ms679351(v=vs.85).aspx) passing in ERROR_WINHTTP_SECURE_FAILURE (12175).
>
>Given Windows is unlikely to change this message, perhaps the CoreFx maintainers would accept a PR to improve the experience.

> Your best bet is to file an issue in the dotnet/corefx repo with a full repro.
>
>I hope that helps!
>
> Peter

Issue をポストしておきました。（Resource参照)

今回の反省としては、コードを読めば自分でも理解できる（かも）レベルだったのに、実装のありかにとらわれてエラーメッセージを変更したいという本来のゴールをわすれていたので、探すのに苦労しました。もっと目的にフォーカスしよう。


# Resource
 
* [kubernetes REST API に外部から接続する](https://qiita.com/zaru/items/bf5b4e60ad4d67be8bea)
* [サンプルコード(GitHub)](https://github.com/TsuyoshiUshio/BindingSample/blob/master/KubernetesRestSpike/Program.cs)
* [dotnet / corefx: issue : Ambigous error message for SSL validation error.](https://github.com/dotnet/corefx/issues/27458)
* [bypass invalid SSL certificate in .net core](https://stackoverflow.com/questions/38138952/bypass-invalid-ssl-certificate-in-net-core)
* [Understanding Kubernetes Authentication and Authorization](http://cloudgeekz.com/1045/kubernetes-authentication-and-authorization.html)