Beanstalk / App Runnerとは
.Net CoreのウェブアプリケーションをAWSにホストするサービスとしてApp Runner / Beanstalkがある。
App Runnerは、Visual StudioからAWS Toolkitでデプロイするだけで、Load Balancerの設定など一通りの設定が自動で完了する。
BeanstalkもAWS Toolkitでデプロイすれば諸々の設定を行ってくれるが、もう少し設定する(できる)ことが増える。
ウェブアプリケーションにアクセスするときに一番最初に気がつく点は、Beanstalkはhttpがデフォルトに対し、App Runnerはhttpsでアクセスを行う。(Cognitoを使用して認証を行うときは、ここは重要。なぜならCognitoは、戻りURLとしてhttpsしか受け付けてくれない。)
Load Balancerから先の事
BeanstalkもApp RunnerもLoad Balancerが最初のアクセスポイントとなり、Load Balancerとウェブサーバ間の処理はhttpで行なわれる。(おそらくこの部分は、変更できないのではないかと思う。)
Beanstalk / App Runnerでホストされている.Net Coreのウェブアプリがホストされているウェブサーバには、httpでアクセスされることとなる。
Load Balancerにhttpでアクセスしても、httpsでアクセスしても、.Net的には、httpでアクセスされていると認識され、httpの処理となる。よって、Cognitoに接続する際に渡されるredirect urlもhttpとなってしまう。
※Visual Studioでローカル環境でデバッグする環境はhttps://localhost:xxxxのようなLoad Balancerが登場しない環境では、ウェブサーバにhttpsでアクセスし、ウェブサーバからCognitoへの接続時にもredirect urlはhttpsとして渡されるため、ローカルではうまくいくが、AWSにデプロイするとうまくいかないことがわかる。
簡単な図を書くとこのような流れとなる。(絵はBeanstalkだがApp Runnerも同様)
Cognitoにhttpsのredirect urlを渡す
Load Balancerから先をhttpsに設定できれば、そのままCognitoにhttpsのredirect urlが渡るが、それができないため、.Netの方で、強制的にredirect urlがhttpであれば、httpsにする設定を行う。
絵の中にはしれっと書いてある Cookieもその設定を行う必要がある。(おそらく認証時に発行されるTokenはCookieの中に保存される)
同じサイト内であっても、httpのページとhttpsのページでは、Cookieを共有することができない。そのため、Cookieを常にhttpsのページとして使用するように設定する。
上記絵の中では、Cookieがhttpsのサイトとして処理され、redirect urlがhttpsと強制的に変更する。
最後に
上記のよう.Net側の変更を行うことでCognitoでの認証が可能となる。App Runnerでホストされている場合は、ここでおしまいだが、Beanstalkでホストされている場合は、Load BalancerのListenerの設定やInbound/Outboundルールの設定が少しだが、必要となる。
以下、設定周りのスクリーンショット。
設定内容
Cognito
Cognitoの設定はこちらを参照できる。.Net CoreのApp Settingsの設定も後半に登場する。
Visual StudioプロジェクトのApp Settingsの設定(上記Cognitoサイトで作成された情報を使用する)
下記AppSettings.jsonの内容となる。これらの<>の中を埋めていく。
{
"Logging": {
"LogLevel": {
"Default": "Warning"
}
},
"AllowedHosts": "*",
"Authentication": {
"Cognito": {
"ClientId": "<app client id from AWS Cognito>",
"IncludeErrorDetails": true,
"MetadataAddress": "https://cognito-idp.<your region>.amazonaws.com/<your-pool id>/.well-known/openid-configuration",
"RequireHttpsMetadata": false,
"ResponseType": "code",
"SaveToken": true,
"TokenValidationParameters": {
"ValidateIssuer": true
},
"AppSignOutUrl": "",
"CognitoDomain": "https://<custom domain name>.auth.us-east-1.amazoncognito.com"
}
}
}
AWS Toolkitからデプロイ
{
"DetailedErrors": true,
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*",
"Authentication": {
"Cognito": {
"ClientId": "75gkrda7e6nnn85s99ssdhs5o5",
"IncludeErrorDetails": true,
"MetadataAddress": https://cognito-idp.us-east-1.amazonaws.com/us-east-1_PeCdkl5kq/.well-known/openid-configuration,
"RequireHttpsMetadata": false,
"ResponseType": "code",
"SaveToken": true,
"TokenValidationParameters": {
"ValidateIssuer": true
},
"AppSignOutUrl": "",
"CognitoDomain": https://test-demo-domain-101.auth.us-east-1.amazoncognito.com
}
}
}
Beanstalkへデプロイ
Load Balancerの設定
Cognitoの設定(App client settings > Callback URLs)
Visual Studioプロジェクト Program.csの変更(追加)
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Authentication.OpenIdConnect;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme;
options.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
})
.AddCookie()
.AddOpenIdConnect(options =>
{
options.CorrelationCookie.SecurePolicy = CookieSecurePolicy.Always;
options.NonceCookie.SecurePolicy = CookieSecurePolicy.Always;
options.ResponseType = builder.Configuration["Authentication:Cognito:ResponseType"];
options.MetadataAddress = builder.Configuration["Authentication:Cognito:MetadataAddress"];
options.ClientId = builder.Configuration["Authentication:Cognito:ClientId"];
options.Events = new OpenIdConnectEvents()
{
//OnRedirectToIdentityProviderForSignOut = OnRedirectToIdentityProviderForSignOut
OnRedirectToIdentityProvider = (context) =>
{
// force https for the redirect url.
if (context.ProtocolMessage.RedirectUri.StartsWith([http://]http://))
{
context.ProtocolMessage.RedirectUri = context.ProtocolMessage.RedirectUri.Replace([http://]http://, [https://]https://);
}
return Task.FromResult(0);
}
};
});
// Add services to the container.
builder.Services.AddRazorPages();
var app = builder.Build();
// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.MapRazorPages();
app.Run();