プロジェクトを作成して起動
PowerShell
$app = "ManagedIdentityTestApp"
mkdir $app
cd $app
dotnet new sln --name $app
dotnet new webapi --output $app --framework net5.0
dotnet sln add $app\$app.csproj
start .\$app.sln
NuGet パッケージインストール
パッケージマネージャーコンソール
Install-Package Microsoft.EntityFrameworkCore.SqlServer
Install-Package Microsoft.EntityFrameworkCore.Tools
コーディング
Entities/Book.cs
namespace ManagedIdentityTestApp.Entities
{
public class Book
{
public int BookId { get; set; }
public string Title { get; set; }
public string Author { get; set; }
}
}
Data/AppDbContext.cs
using ManagedIdentityTestApp.Entities;
using Microsoft.EntityFrameworkCore;
namespace ManagedIdentityTestApp.Data
{
public class AppDbContext : DbContext
{
public AppDbContext(DbContextOptions options) : base(options)
{
}
public DbSet<Book> Books { get; set; }
}
}
Controllers/BookController.cs
using ManagedIdentityTestApp.Data;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using System.Threading.Tasks;
namespace ManagedIdentityTestApp.Controllers
{
[Route("api/books")]
[ApiController]
public class BookController : ControllerBase
{
private readonly AppDbContext context;
public BookController(AppDbContext context)
{
this.context = context;
}
[HttpGet]
public async Task<IActionResult> ListAsync()
{
var books = await context.Books.ToListAsync();
return Ok(books);
}
}
}
Startup.cs
using ManagedIdentityTestApp.Data;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.OpenApi.Models;
namespace ManagedIdentityTestApp
{
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new OpenApiInfo { Title = "ManagedIdentityTestApp", Version = "v1" });
});
services.AddDbContext<AppDbContext>(options => options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"))); //追加
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseSwagger();
app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "ManagedIdentityTestApp v1"));
}
app.UseHttpsRedirection();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
}
}
appsettings.json
{
"ConnectionStrings": {
"DefaultConnection": "Server=(localdb)\\mssqllocaldb;Database=ManagedIdentityTestAppDb;Trusted_Connection=True;"
},
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"AllowedHosts": "*"
}
データ準備
パッケージマネージャーコンソール
Add-Migration init
Update-Database
SQL Server でレコード追加クエリ実行。
INSERT INTO Books (Title, Author) VALUES (N'たったひとつの冴えたやりかた',N'ジェイムズ・ティプトリー・ジュニア');
INSERT INTO Books (Title, Author) VALUES (N'アンドロイドは電気羊の夢を見るか?',N'フィリップ・K・ディック');
INSERT INTO Books (Title, Author) VALUES (N'夏への扉',N'ロバート・A. ハインライン');
INSERT INTO Books (Title, Author) VALUES (N'幼年期の終り',N'アーサー C クラーク');
INSERT INTO Books (Title, Author) VALUES (N'われはロボット',N'アイザック・アシモフ');
動作確認
ローカル実行して api/books
にアクセスしてデータが取得できることを確認。
[
{
"bookId": 1,
"title": "たったひとつの冴えたやりかた",
"author": "ジェイムズ・ティプトリー・ジュニア"
},
{
"bookId": 2,
"title": "アンドロイドは電気羊の夢を見るか?",
"author": "フィリップ・K・ディック"
},
{
"bookId": 3,
"title": "夏への扉",
"author": "ロバート・A. ハインライン"
},
{
"bookId": 4,
"title": "幼年期の終り",
"author": "アーサー C クラーク"
},
{
"bookId": 5,
"title": "われはロボット",
"author": "アイザック・アシモフ"
}
]
Azure リソース作成
PowerShell
# Azure にログイン
az login
# リソースグループ作成
az group create --location japaneast --name ManagedIdentityTestRG
# App Service Plan 作成
az appservice plan create --name ManagedIdentityTestAppServicePlan --resource-group ManagedIdentityTestRG --location japaneast --sku FREE
# Web App 作成
$random = Get-Random
az webapp create --name web-app-$random --plan ManagedIdentityTestAppServicePlan --resource-group ManagedIdentityTestRG --runtime "DOTNET:5.0"
# SQL Server 作成
az sql server create --name sql-server-$random --resource-group ManagedIdentityTestRG --enable-ad-only-auth --external-admin-name SqlServerAdministrators --external-admin-principal-type Group --external-admin-sid 3329c7ca-75c6-4823-a9b0-8932a900fd37 --minimal-tls-version 1.2
# SQL Database 作成
az sql db create --name ManagedIdentityTestDb --resource-group ManagedIdentityTestRG --server sql-server-$random --collation Japanese_CI_AS --edition Free
# Azure サービスからのアクセスを許可
az sql server firewall-rule create --resource-group ManagedIdentityTestRG --server sql-server-$random --name allowAzureService --start-ip-address 0.0.0.0 --end-ip-address 0.0.0.0
# システム割り当てマネージド ID 有効化
az webapp identity assign --resource-group ManagedIdentityTestRG --name web-app-$random
# マネージド ID を管理者グループに追加
az ad group member add --group SqlServerAdministrators --member-id 24d820ca-8e3a-4b4d-987c-36fdd10e021b
# 接続文字列追加
az webapp config connection-string set --connection-string-type SQLServer --name web-app-$random --resource-group ManagedIdentityTestRG --settings DefaultConnection="Server=tcp:sql-server-$random.database.windows.net;Authentication=Active Directory Managed Identity; Database=ManagedIdentityTestDb;"
データ登録
DDL を取得する。
パッケージマネージャーコンソール
Script-Migration
こんなのが出力される。
IF OBJECT_ID(N'[__EFMigrationsHistory]') IS NULL
BEGIN
CREATE TABLE [__EFMigrationsHistory] (
[MigrationId] nvarchar(150) NOT NULL,
[ProductVersion] nvarchar(32) NOT NULL,
CONSTRAINT [PK___EFMigrationsHistory] PRIMARY KEY ([MigrationId])
);
END;
GO
BEGIN TRANSACTION;
GO
CREATE TABLE [Books] (
[BookId] int NOT NULL IDENTITY,
[Title] nvarchar(max) NULL,
[Author] nvarchar(max) NULL,
CONSTRAINT [PK_Books] PRIMARY KEY ([BookId])
);
GO
INSERT INTO [__EFMigrationsHistory] ([MigrationId], [ProductVersion])
VALUES (N'20211031085850_init', N'5.0.11');
GO
COMMIT;
GO
出力された DDL を SQL Database に流し込む。Azure Portal のクエリエディタを使用。
レコードも追加する。
INSERT INTO Books (Title, Author) VALUES (N'たったひとつの冴えたやりかた',N'ジェイムズ・ティプトリー・ジュニア');
INSERT INTO Books (Title, Author) VALUES (N'アンドロイドは電気羊の夢を見るか?',N'フィリップ・K・ディック');
INSERT INTO Books (Title, Author) VALUES (N'夏への扉',N'ロバート・A. ハインライン');
INSERT INTO Books (Title, Author) VALUES (N'幼年期の終り',N'アーサー C クラーク');
INSERT INTO Books (Title, Author) VALUES (N'われはロボット',N'アイザック・アシモフ');
NuGet パッケージを追加しておく。
パッケージマネージャーコンソール
Install-Package Microsoft.Data.SqlClient
Visual Studio から Web App に発行する。
api/books
にアクセスしてデータが取得できることを確認。
[
{
"bookId": 1,
"title": "たったひとつの冴えたやりかた",
"author": "ジェイムズ・ティプトリー・ジュニア"
},
{
"bookId": 2,
"title": "アンドロイドは電気羊の夢を見るか?",
"author": "フィリップ・K・ディック"
},
{
"bookId": 3,
"title": "夏への扉",
"author": "ロバート・A. ハインライン"
},
{
"bookId": 4,
"title": "幼年期の終り",
"author": "アーサー C クラーク"
},
{
"bookId": 5,
"title": "われはロボット",
"author": "アイザック・アシモフ"
}
]
VNet 統合
PowerShell
# 仮想ネットワーク作成
az network vnet create --name virtualnetwork --resource-group ManagedIdentityTestRG
# サブネット作成
az network vnet subnet create --address-prefixes 10.0.0.0/24 --name subnet1 --resource-group ManagedIdentityTestRG --vnet-name virtualnetwork
# サービスエンドポイント追加
az network vnet subnet update --name subnet1 --resource-group ManagedIdentityTestRG --vnet-name virtualnetwork --service-endpoints Microsoft.Sql
# 仮想ネットワークルール追加
az sql server vnet-rule create --server sql-server-$random --name vnetrule --resource-group ManagedIdentityTestRG --subnet subnet1 --vnet-name virtualnetwork
# App Service Plan スケールアップ
az appservice plan update --name ManagedIdentityTestAppServicePlan --resource-group ManagedIdentityTestRG --sku S1
# VNet 統合
az webapp vnet-integration add --name web-app-$random --resource-group ManagedIdentityTestRG --subnet subnet1 --vnet virtualnetwork
# Azure サービスからのアクセスを拒否
az sql server firewall-rule delete --name allowAzureService --resource-group ManagedIdentityTestRG --server sql-server-$random