More Related Content Similar to Azure API Management 俺的マニュアル (20) Azure API Management 俺的マニュアル10. Developers Guests
カスタム
Admins
API Management 全体像
API Management
グループ
API
サブスクリプション
Policy
Frontend Backend Api
/path https://~
https://<APIM Name>.azure-api.net
アクセス制御
開発者(ユーザー)
N:N
Operations
In
Out
Err
Policy
N:N
開発者ポータル
Nextscape Inc. 10
API
(Backend)
(Publisher)
Client
(FrontEnd)
(Consumer)
成果物(製品)
N:N
11. Developers Guests
カスタム
Admins
N:N
API Management 全体像
API Management
サブスクリプション
Policy
Frontend Backend Api
/path https://~
https://<APIM Name>.azure-api.net
アクセス制御
開発者(ユーザー)
N:N
API
(Backend)
(Publisher)
Operations
In
Out
Err
Policy
N:N
開発者ポータル
Client
(FrontEnd)
(Consumer)
Nextscape Inc. 11
API
成果物(製品)
グループ
API:
API Managementから到達できるAPIであればなんでも登録
できる。まずはここへ API を登録するところからスタート。
PolicyではRequest/Response/Errorに対して処理をC#で書
くことができる。
12. Developers Guests
カスタム
Admins
グループ
API Management 全体像
API Management
サブスクリプション
Policy
Frontend Backend Api
/path https://~
https://<APIM Name>.azure-api.net
アクセス制御
開発者(ユーザー)
N:N
Operations
In
Out
Err
Policy
N:N
開発者ポータル
Nextscape Inc. 12
API
(Backend)
(Publisher)
Client
(FrontEnd)
(Consumer) API
N:N
成果物(製品/Products):
docsでは「成果物」もしくは「製品」と記載されている。
Portalでは「製品」となっているので要注意。
APIに対してアクセス制御を行うのが主な役割。
APIと成果物はN:Nの関係性。APIは複数の成果物に登録がで
きる。
成果物(製品)
13. グループ
Developers Guests
カスタム
Admins
API Management 全体像
API Management
サブスクリプション
Policy
Frontend Backend Api
/path https://~
https://<APIM Name>.azure-api.net
アクセス制御
開発者(ユーザー)
N:N
Operations
In
Out
Err
Policy
N:N
開発者ポータル
Nextscape Inc. 13
API
(Backend)
(Publisher)
Client
(FrontEnd)
(Consumer) API
グループ:
開発者は複数の(カスタム)グループに所属することができる。
ユーザー登録した開発者は必ずDevelopersグループに所属する。
成果物のアクセス制御にグループを登録することで、そのグ
ループに所属する開発者はその成果物を使用することができる
ようになる。
グループと成果物はN:Nで紐づけることができる。
成果物(製品)
N:N
14. Developers Guests
カスタム
Admins
N:N
グループ
API Management 全体像
API Management
サブスクリプション
Policy
Frontend Backend Api
/path https://~
https://<APIM Name>.azure-api.net
アクセス制御
開発者(ユーザー)
N:N
Operations
In
Out
Err
Policy
N:N
開発者ポータル
Nextscape Inc. 14
API
(Backend)
(Publisher)
Client
(FrontEnd)
(Consumer)
Policyでできること(やること)の代表格
セキュリティ&アクセス制限
• API キー、JWT トークン、証明書、その他の資格情報を検証
• 使用量クォータとレート制限を適用
• IPアドレスやユーザーIDで接続を制限・スロットリング
キャッシュ
• Backend APIのResponseをキャッシュ
その他
• Request/Reponseログを転送
• 外部サービスをHttpで呼び出し
API
成果物(製品)Policy:
PolicyはBackend APIへRequestを投げる前後に処理を入れることができる。処理
はC#で実装する。
PolicyはBackend APIが公開する複数の操作(Operation)ごとに設定もできるし、
Backend API全てに共通の設定もできるなど、スコープが4段階ある。
(操作の例: /id)
実に多彩な処理の実装が可能。テンプレートもあるが、外部にReqeustを投げるこ
とができるので独自実装を頑張ればかなりのことができる。
15. Developers Guests
カスタム
Admins
N:N
グループ
API Management 全体像
API Management
サブスクリプション
Policy
Frontend Backend Api
/path https://~
https://<APIM Name>.azure-api.net
アクセス制御
開発者(ユーザー)
N:N
Operations
In
Out
Err
Policy
N:N
開発者ポータル
Nextscape Inc. 15
API
(Backend)
(Publisher)
Client
(FrontEnd)
(Consumer) API
アクセス制御:
アクセス制御は成果物を使用できるグループを設定す
ることで可能となる。
ここでいうアクセス制御とは、開発者(ユーザー)に
対してのものであることに注意。
Policyによるアクセス制限:
成果物にもPolicyが設定できる。API単位より上の
スコープでの設定と思えばOK。
例えば使用量上限があるプランのAPI群を公開し
たい場合、そのプラン用の成果物を作成して使用
量クォータによる制限のPolicy実装をここに設定
することになる。
成果物(製品)
サブスクリプション:
成果物では、開発者(ユーザー)に対して利用許諾の
申請を求める設定がある。その設定をONにした場合、
開発者&成果物ごとのサブスクリプションキーが発行
され、それをHeaderに入れないとRequestが失敗す
る。
(申請を自動承認するか、手動で承認するか選択)
20. • APIを登録しただけだと動かない!
• missing subscription key というエラーが出たときの原因は大抵コレ
成果物へAPIを紐づける
Nextscape Inc. 20
GroupA
グループ
アクセス制御
開発者(ユーザー)成果物(製品)API
既存API
新規API
成果物に紐づけないと、
開発者からは見えない。
自分がAdminsグループに
所属する管理者の場合、
Portalからは見えるが実行
時はエラーになる。
成果物に紐づいていないので実
行するとエラーになる
24. • ポリシーはXML形式。4ブロックに分かれている
ポリシーの基本形
<policies>
<inbound>
<!–- Backend APIを叩く前に呼びたい処理 -->
<base />
</inbound>
<backend>
<!–- Policyは1つだけしか実装できない。Backend APIを叩くための
Poilicyがデフォルトで実装されている -->
<base />
</backend>
<outbound>
<base />
<!–- Backend APIからのreponseを返す前に呼びたい処理 -->
</outbound>
<on-error>
<base />
</on-error>
</policies>
Nextscape Inc. 24
詳細は後述
詳細は後述
25. • C#の実装方法は2つの形式がある。
• どちらも括弧の前に@付ける
XMLの属性値にC#で実装していく
<set-variable name=“date1" value="@(context.Timestamp.ToString("R"))" />
<set-variable name=“date2" value="@{
var results = DateTime.Now.ToString(“yyyy/MM/dd HH:mm:ss.fffff”);
return results;
}" />
Nextscape Inc. 25
単文の場合は@()
複文の場合は@{}
• ポリシー式で使用できる .NET framework の型は決まっているため、usingは不要
• 保存時に名前空間を解決してくれているっぽい(解決できないとエラーになる)
• 言い換えると外部dll を読み込ませることができない(Nugetもできない)
っていうかこれラムダ式だわ インテリセンスが効かないんだよね・・・
26. • Reqeust/Response含めたあらゆる情報はこいつが持っている
暗黙的なオブジェクト context
Nextscape Inc. 26
Context
Timestamp: DateTime
Variables: IReadOnlyDictionary<string, object>
Response
Request
LastError
Headers: IReadOnlyDictionary<string, string[]>
IpAddress: string
Body
※一部抜粋
アクセス日時
<set-variables>でセットされた値を保持
Requestのヘッダー値
Request元のIPAddress
RequestのBody
28. • ちょっと見方にコツがいる。
• 例:Requestの情報がほしい
• まず、contextから探す。
• context.Requestというプロパティが
あるのはわかったが、Requestの型も
プロパティもわからない・・・
• Requestでこの画面内を検索する
contextの中身を知らないと実装できない
Nextscape Inc. 28
34. • 同期リクエストの場合は<send-request>
• Responseを取得できる
• 非同期リクエストの場合は< send-request-one-way >
• Responseは取得できない
外部へリクエストを投げるポリシー
• <send-request>のResponseは、指定した変数名でcontext.Variablesディク
ショナリに格納される
<send-request mode="new" response-variable-name="testResponse" timeout="5" ignore-
error="true">
・・・
</send-request>
Nextscape Inc. 34
35. • Blob SDKが使えないのでREST Apiで実装
• ログを書く処理は非同期にしたいので、 send-request-one-way使用したい
• でもエラーでまくって辛かった。どうやってデバッグするか悩んだ
• 編み出したやり方は以下
• まずはsend-requestで実装。
• send-reqeustにはresponseを変数に入れる機能がある
• responseは、IReseponseクラス。
• responseの中身を見るために、set-variableの実行結果をTraceで見ることに(詳しくはこの後)
追加Blobにログを書くPolicy作ってみた
<set-variable name="test" value="@{
var hoge = ((IResponse)context.Variables["testResponse"]).Body.As<string>();
return hoge;
}" />
<send-request mode="new" response-variable-name="testResponse" timeout="5" ignore-
error="true">
・・・
</send-request>
Nextscape Inc. 35
responseを格納する変数
変数値をTraceで表示させるために意味なく
他の変数にセットする
36. • これを埋めていく
追加Blobにログを書くPolicy作ってみた
<inbound>
<base />
<set-variable name="version" value="@("2015-04-05")" />
<set-variable name="putDate" value="@(context.Timestamp.ToString("R"))" />
<set-variable name="logData" value="@{
// ログに出力する内容を作る
return something;
}" />
<set-variable name="authorizationHeader" value="@{
// BlobのBearer Authorizationヘッダーを作る
return authorizationHeader;
}" />
<send-one-way-request mode="new">
// 非同期のリクエストを投げる
</send-one-way-request>
</inbound>
Nextscape Inc. 36
39. Globalレベル(API の All APIsに設定する)
成果物レベル(製品)
API レベル(API の All Operationsに設定する)
各Operationsレベル
ポリシーには階層がある
• 上から順に評価される。
Nextscape Inc. 39
42. • <backend>には1つだけしかPolicyを実装できない制約がある!
<backend>について
Nextscape Inc. 42
<backend>
<retry condition="@(context.Response.StatusCode == 500)" count="3" interval="1">
<forward-request />
</retry>
</backend>
<backend>
<base />
<retry condition="@(context.Response.StatusCode == 500)" count="3" interval="1">
</retry>
</backend>
エラーとなってしまう例
入れ子にして回避
上位スコープに
<forward-request />
が設定されているため必要
<base />を削除
43. • Visual Studio Code用のスニペットならある・・・けど使えないかな
• https://github.com/Azure/api-management-policy-snippets
ポリシーの素敵なエディタはないのか
Nextscape Inc. 43
46. 開発者とグループ
• デフォルトで用意されているグループは3つ
• Administrators, Develpers, Guests
• 開発者を新規追加すると、デフォルトでDevelopersグループ所属になる
Nextscape Inc. 46
開発者(ユーザー)
Developers
Guests
Admins
デフォルトグループ
GroupA
GroupB
カスタムグループ
開発者をPortalから追加しても、開発者
ポータルから開発者自身がサインアップ
しても、必ずDevelpersグループの所属に
なる
49. API Manegement Role別機能差
APIM作成者 or APIM 共同作成者 APIM Operator Role APIM Reader Role
Portal フル権限 参照のみ。変更設定できるのは
スケールアップ・ダウン、SSL、
カスタムドメインの設定ぐらい
メトリックス参照で
きるぐらい。その他
は参照すらできない
開発者ポータル フル権限 × ×
所属Group Administrator Guest Guest
• APIMの作成者、またはAPIM 共同作成者ロール
の権限があるAzureユーザーは、暗黙的に
Administratorグループに所属する(共同作成者
は画面にユーザーとしては表示されない)
• APIM Service Reader Role, Operator Roleの権限を
もつAzureユーザー、もしくはユーザー登録を
していない(認証していない)場合は暗黙的
にGuestグループに所属する
Nextscape Inc. 49
51. 試してみた
Nextscape Inc. 51
• 承認が必要な成果物を作る
• 成果物に対してカスタムグループを紐づけておく
• 開発者ポータルからこの成果物に対して
サブスクリプション申請
• Portalからサブスクリプションを承認
• 紐づいたカスタムグループにユーザが登録されるか
52. 試してみた
Nextscape Inc. 52
• 承認が必要な成果物を作る
• 成果物に対してカスタムグループを紐づけておく
• 開発者ポータルからこの成果物に対して
サブスクリプション申請
• Portalからサブスクリプションを承認
• 紐づいたカスタムグループにユーザが登録されるか
Developerグループも紐づけておかないと、開発
者ポータルに成果物が表示されない
53. 試してみた
Nextscape Inc. 53
• 承認が必要な成果物を作る
• 成果物に対してカスタムグループを紐づけておく
• 開発者ポータルからこの成果物に対して
サブスクリプション申請
• Portalからサブスクリプションを承認
• 紐づいたカスタムグループにユーザが登録されるか
55. 試してみた
Nextscape Inc. 55
• 承認が必要な成果物を作る
• 成果物に対してカスタムグループを紐づけておく
• 開発者ポータルからこの成果物に対して
サブスクリプション申請
• Portalからサブスクリプションを承認
• 紐づいたカスタムグループにユーザが登録されるか
57. 試してみた
Nextscape Inc. 57
• 承認が必要な成果物を作る
• 成果物に対してカスタムグループを紐づけておく
• 開発者ポータルからこの成果物に対して
サブスクリプション申請
• Portalからサブスクリプションを承認
• 紐づいたカスタムグループにユーザが登録されるか
追加されなかった・・・残念
59. • 開発者への成果物に対する利用許諾のこと。
• 登録したユーザーだけが使用できるようにしたい場合の設定。
• Front APIへのRequestにsubscription keyのセットを必須にする
• 開発者は利用許諾の申請を開発者ポータルより行う。(Azureポータルじゃない)
サブスクリプション
Nextscape Inc. 59
• 申請を自動承認にした場合は、申請
されたら即時 subscription key が発行
される。
• 要承認にした場合は、Portalから管
理者が手動で承認する必要がある。
• 利用許諾の申請が発生してもメール
が飛ぶ、Webhookを叩くなどのメン
ションを飛ばすことができない(不
便すぎて困る)
60. • Portalに
• 「サブスクリプションの追加」
• 「サブスクライバーの追加」
• の2つの表記があり、用途の違いがわからなくて混乱しちゃうので整理しておく。
サブスクリプション
「サブスクリプションの追加」とは、成果物(製品)と開発者(ユーザー)の両方を指定して承認すること
Nextscape Inc. 60
70. • 開発者が
• 自らユーザーとして登録する機能
• 開発者が使いたい成果物(APIを含んでいる)に対して利用許諾を申請する機能
• APIをお手軽に試すテスト機能
• 不具合を報告する機能(管理者にはmailが飛んでくる)
• などを持つ、開発者のための画面。
• APIMagementインスタンスとは全く別のリソースと思ったほうが良い
• 開発者ポータルはAPIMagementとは無関係のWebクライアントとして認識したほう
がdocsが読みやすい
• AzurePortalでは、(基本的に)開発者ポータルへのログインユーザーの権
限管理しかしない
• 権限管理以外だと、開発者ポータルがAPIMgmtに対してRequestする前に外部
IDProviderからid_token(JWT)を得る、もしくは認証サーバーからaccess_tokenを得
るための機能のための設定をするぐらい(ややこしいので後述する)
そもそも開発者ポータルとは何か
Nextscape Inc. 70
87. Nextscape Inc. 87
用途が混在していてわかりにくいので要注意
Portalのセキュリティセクション
開発者ポータルの認証方式の設定
• クライアント認証の検証時に使う証明書をUploadする
• APIを呼び出す時に使う証明書をUploadする
(どちらもUploadだけじゃダメで、Policyにて実装が必要)
独自に実装した開発者認証、成果物のサブスクリプションを
行う認証サーバーの設定
• 開発者ポータルの認証方式の設定
• 開発者ポータルからAPIをテストする時にTokenを取得する
ために必要な認可サーバー(or IDProvider)の設定
1 2
3
3
4
APIClient
3
「開発者ポータル」で
説明済み
3
2
4は証明書の検証もできるが、PolicyでJWTの検証をするのがメイン1
1
説明済み
94. • API Managementは認証・認可(承認)の機能は持っていない。あくまでJWTの検証をするPolicy
がデフォルトで用意されているだけ
• JWTを検証する、ということはIDProviderはAzureAD、B2Cだけしか使えないわけじゃない。
OpenIdConnectをサポートするIDProviderであればなんでも大丈夫
validate-jwt 1 2
3
APIClient 4
は証明書の検証もできるが、PolicyでJWTの検証をするのがメイン1
Client
API Mgmt
B2C
IDProvider
JWT
JWT
• OAuth2.0ではなくOpenId Connectであることに注意。
OAuth2.0の返すaccess_tokenは仕様が策定されてないし、
通常JWTは使用されない。(ランダム文字列)
• OpenId Connectであれば、id_tokenがJWTで返却される。
• id_tokenの中にClameが格納されている。
Nextscape Inc. 94
104. • ASP.NET Core 2.1で作る
• VS, VSCodeのどっちでもいいけど個人認証ありでプロ
ジェクトを作る
• dotnet new mvc --auth Individual (VSCodeの場合)
Webクライアントを作る
JWTJWT
ValidateOpenId Connect JWT
Nextscape Inc. 104
105. • GoogleのOpenId Connectによる認証を実施する設定
• StartUpクラスのConfigureServicesメソッドに次の実装をする
Webクライアントを作る
services.AddAuthentication()
.AddGoogle(googleOptions =>
{
googleOptions.ClientId = Configuration["Authentication:Google:ClientId"];
googleOptions.ClientSecret = Configuration["Authentication:Google:ClientSecret"];
googleOptions.Scope.Add("https://www.googleapis.com/auth/plus.login");
googleOptions.SaveTokens = true;
});
• SaveTokens = trueにセットしておくと、id_tokenがHttpContextにセットされて
ほしいんだけどされない。(access token, refresh token専用らしい)
• Contollerで
• とすればid_tokenが取得できて、これをHeaderに入れてWebAPIに投げたかった
• でもどうやってもid_tokenをControllerに渡せなかった・・・。
HttpContext.GetTokenAsync("id_token")
ClientId、ClientSecretは
Google Dev Consoleで認証
作成した結果をセットする
「ユーザーシートク
レット]ってやつ
dotnet user-secrets –h
でヘルプが出る
Nextscape Inc. 105
115. • services.AddMvcメソッドの上に実装する
JWTのValidation実装をStartupクラスにする
Nextscape Inc. 117
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.SaveToken = true;
options.Audience = Configuration["Authentication:Google:ClientId"];
options.Authority = "https://accounts.google.com";
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidateAudience = true,
ValidateLifetime = true,
ValidateIssuerSigningKey = true,
NameClaimType = "name",
AuthenticationType = "Google." + JwtBearerDefaults.AuthenticationScheme,
ValidIssuers = new[] { options.Authority, "accounts.google.com" },
};
});
ClientIdはGoogle Dev
Consoleで認証作成した結
果をセットする
125. • ClientIdを入れるだけで実装終了
validate-jwtを実装する(APIレベルに対して)
<inbound>
<base />
<validate-jwt header-name="Authorization" failed-validation-httpcode="401" failed-
validation-error-message="Unauthorized" require-expiration-time="true" require-
scheme="Bearer" require-signed-tokens="true" clock-skew="0">
<openid-config url="https://accounts.google.com/.well-known/openid-configuration" />
<audiences>
<audience><!-- ClientId --></audience>
</audiences>
<issuers>
<issuer>accounts.google.com</issuer>
<issuer>https://accounts.google.com</issuer>
</issuers>
</validate-jwt>
</inbound>
Nextscape Inc. 127
130. • Clientが渡してきたクライアント証明書を検証する実装
証明書の使い方
• クライアント認証の検証時に使う証明書をUploadする
• APIを呼び出す時に使う証明書をUploadする
(どちらもUploadだけじゃダメで、Policyにて実装が必要)2
1
<choose>
<when condition="@(context.Request.Certificate == null
|| !context.Deployment.Certificates.Any(c => c.Value.Thumbprint ==
context.Request.Certificate.Thumbprint))" >
<return-response>
<set-status code="403" reason="Invalid client certificate" />
</return-response>
</when>
</choose>
※未検証
Nextscape Inc. 132
1 2
3
APIClient 4
140. リビジョン
Nextscape Inc. 142
• Revisionを作成すると、Revsion番号が新しく発番されて、;rev=<num>という文字列が
入った新しいURLが作成される
WebAppsのスロット同じ目的の機能と理解すればいい
URLの例
https://<resourceName>.azure-
api.net/echo;rev=2/resource
• 特定のRevisionをメインに切り替えると、;rev=<num>の付与も切り替わる
メインURL(Revision=1)
https://<resourceName>.azure-api.net/echo/resource
Revision=2のURL
https://<resourceName>.azure-
api.net/echo;rev=2/resource
Revision=1のURL
https://<resourceName>.azure-
api.net/echo;rev=1/resource
メインのURL
https://<resourceName>.azure-api.net/echo/resource
Revision=2をメインに切り替え
141. リビジョン
Nextscape Inc. 143
• Revsionが入ったURLは、知っていれば誰でもアクセスできてしまうので、サブスクリプション
キー必須にするなどしてAPIを守るようにすること
リビジョン使用時の注意
• 本番で稼働しているAPI定義やPoliciyに影響を与えることなく、安全に変更することができる
• APIM定義をPublishする前に稼働確認ができる
• 切り替え時に変更点を記載すると開発者ポータルに表示できるため、開発者に対して何をし
たのかアナウンスできる
• リビジョンの切り替えがすぐ反映されるので、問題があったらすぐにロールバックできる
(即時反映なので、DNS切り替えではないみたい)
リビジョンを使用する理由
148. • 例 /v1, /ver1
パス
• 例 ?ver=1, ?api-ver=2, ?api-version=2018-11-01
クエリ文字列
• 例 ver:v1, api-ver:2, api-ver:2018-11-01
Header
バージョン
Nextscape Inc. 150
同時に複数のバージョンのAPIを公開する機能
バージョン文字列は、好き
な文字列が使用可能(数字、
日付、名前など)
バージョンの差異はバージョン文字列を次の3種類のいずれかに埋め込む
156. Nextscape Inc. 158
docs では透過的バージョンアップという手法が提案されている
• https://docs.microsoft.com/ja-jp/azure/api-management/api-management-sample-cache-
by-key#transparent-versioning
• APIM側のバージョンアップにクライアントが合わせるのではなく、クライアント
に合わせてAPIM側がバージョンを切り替えるやり方のことらしい
クライアントに影響を与えないバージョンアップ戦略
API
APIM
通常はクライアントが
バージョンを選択する
API
APIM
透過的バージョンアップは
APIMがバージョンを選択する
BackendAPI
v1
v2
v3
v1
v2
v3
BackendAPI
v1
v2
v3
157. Nextscape Inc. 159
docsに記載されているサンプルの図解
• どのクライアントがアクセスしてきたのかをSubscriptionKeyで判定する方法
透過的バージョンアップの構成
API
APIM
BackendAPI
v1
v2
v3
1.HeaderにSubscriptionKey
を入れてRequest
バージョン管理
2. SubscriptionKeyをキーにキャッシュに
データがあるかを確認
3. データがキャッシュがな
かったら、SubscriptionKeyを
キーに外部からバージョンを
取得し、キャッシュへ格納
4.BackendAPIのURLを取得し
たバージョンに書き換え
キャッシュにはSubscriptionKeyを
キーにバージョンが格納されている
KeyValueのキャッシュ機能が
APIMにはある(フラグメント
キャッシュ)
158. Nextscape Inc. 160
docs の日本語が難しいが、恐らくこういうことが言いたいんだと思われる
• https://docs.microsoft.com/ja-jp/azure/api-management/api-management-sample-cache-
by-key#tenant-isolation
バックエンドの障害対応と段階的ロールアウト
API
APIM
BackendAPI
v1
BackendAPI
v1
BackendAPI
v1
v1
同じバージョンのBackendAPIを複数用意
しておき、クライアントがどの
BackendAPIにアクセスするのかをAPIMが
判定するように設計する
• 設定方法は透過的バージョンアップとほ
ぼ同じ
• BackendAPIのハードウェア障害が起こった時
に、影響があるクライアントが限定される
• BackendAPIのハードウェアごとにバージョン
アップをしていくことで段階的にロールアウ
トが可能となる(似非カナリアリリース)
160. API Management のエラー処理
Nextscape Inc. 162
• API Mamagementでいうエラーは、Policyで発生したエラーと、Backend API
で発生したエラーと二種類あることを意識しておくこと
Policy
In
Out
Err
API
(Backend)
(Publisher)
Client
(FrontEnd)
(Consumer)
Backend
BackendAPIのResponseが
4xx, 5xxの場合
<outbound>でエラーハン
ドリング
PolicyがエラーをThrowの場合
<on-error>でハンドリング
API Management
162. • エラー処理の例
Policyで発生したエラーへの対処
Nextscape Inc. 164
<policies>
<inbound>
<rate-limit calls="5" renewal-period="60" />
<quota calls="100" renewal-period="604800" />
<base />
</inbound>
・・・
<on-error>
<base />
</on-error>
</policies>
エラー処理はまだ入れていない
1分間に5回までのリクエスト制限 わざと1分以内に6回リクエストした
Policyが返却した
独自のStatusCode
163. • エラー処理を実装した
Policyで発生したエラーへの対処
Nextscape Inc. 165
<on-error>
<base />
<choose>
<when condition="@(context.Response.StatusCode == 429)">
<return-response>
<set-status code="499" reason="catch error in onerror" />
<set-header name="ErrorSource" exists-action="override">
<value>@(context.LastError.Source)</value>
</set-header>
<set-header name="ErrorReason" exists-action="override">
<value>@(context.LastError.Reason)</value>
</set-header>
・・・
<set-body>Response is customized in on-error.</set-body>
</return-response>
</when>
<otherwise />
</choose>
</on-error>
ResponseのStatusCodeが429の場合は499を返却する
わざと1分以内に6回リクエストした
※API Managementでは、Custom の Http StatusCodeは101~599の範囲のみ設定可能
エラー詳細をHeaderへセット(全実装は次ページ)
なぜかReason
を表示してく
れない・・・
164. • エラーの詳細情報をheaderへセットする実装(docsまんまだけど)
Policyで発生したエラーへの対処
<on-error>
<set-header name="ErrorSource" exists-action="override">
<value>@(context.LastError.Source)</value>
</set-header>
<set-header name="ErrorReason" exists-action="override">
<value>@(context.LastError.Reason)</value>
</set-header>
<set-header name="ErrorMessage" exists-action="override">
<value>@(context.LastError.Message)</value>
</set-header>
<set-header name="ErrorSection" exists-action="override">
<value>@(context.LastError.Section)</value>
</set-header>
<set-header name="ErrorStatusCode" exists-action="override">
<value>@(context.Response.StatusCode.ToString())</value>
</set-header>
<base />
</on-error>
Nextscape Inc. 166
• デバッグ用途の実装ならこ
れでいい
• 本番用の実装では逆に詳細
を出力しすぎないようにし
ないといけない
• Sectionの情報は出力し
ない、とか
• 本番用の実装では、エラー
発生時にだけロギングする
仕掛けが必要。<on-error>
でEventHubへの出力を検討
すること
• Storageへの出力だと確
実に出力される保証が
ない
165. • context.Response.StatusCodeを使って、対処方法を分岐させる
• 基本的なエラー処理の方針は、Responseの加工となる(必要なら加工する)
• エラーの発生時のログ出力は通常はAPI側で実装していなければいけないが、APIMでログ出力
をする必要があるならここでEventHubへ出力する実装をする
エラーハンドリングは <outbound>セクション に実装する
Backend APIで発生したエラーへの対処
Nextscape Inc. 167
<outbound>
<base />
<choose>
<when condition="@(context.Response.StatusCode>=500)">
<return-response>
<set-status code="499" reason="ChangeStatusCode" />
<set-body>Error Raised in backend API.</set-body>
</return-response>
</when>
<otherwise />
</choose>
</outbound>
ResponseのStatusCodeが5xx系の場
合は499を返却する
172. • GatewayLogにて出力され
るエラーログはこんな感
じ
ロギング
Nextscape Inc. 174
{
"Level": 4,
"isRequestSuccess": 0,
"time": "2018-11-05T13:57:09.0583391Z",
"operationName": "Microsoft.ApiManagement/GatewayLogs",
"category": "GatewayLogs",
"durationMs": 0,
"callerIpAddress": "13.91.254.72",
"correlationId": “********-****-****-****-************",
"location": "Japan West",
"properties": {
"lastError": {
"source": "validate-jwt",
"reason": "TokenNotPresent",
"message": "JWT not present.",
"scope": "api",
"section": "inbound"
},
"method": "GET",
"url": "https://nsuesaka.azure-api.net/echo/resource?param1=sample",
"responseCode": 401,
"responseSize": 118,
"cache": "none",
"apiId": "echo-api",
"operationId": "retrieve-resource",
"productId": "starter",
"clientProtocol": "HTTP/1.1",
"apiRevision": "1"
},
“resourceId”: “/SUBSCRIPTIONS/*******-****-****-…"
}
エラーを出力したポリシー
ポリシーのスコープ
ポリシーを実装したセクション
• この情報以上は出力できな
いので、例えばこのリクエ
ストは誰?という特定はで
きない
173. • フルカスタマイズしたログを出力したいならこのポリシーを使う
• docsにはREST APIを使用する例しかないが、PowerShellのほうが全然簡単
EventHubへ出力するポリシー
Nextscape Inc. 175
$context = New-AzureRmApiManagementContext `
-ResourceGroupName <resourceGroupName> `
-ServiceName <serviceName>
New-AzureRmApiManagementLogger `
-Context $apimContext `
-LoggerId "LoggerId123" `
-Name “eventHubName" `
-ConnectionString `
"Endpoint=sb://<eventHubNameSpace>.servicebus.windows.net/;SharedAccessKeyName=SendKey;SharedAc
cessKey=<key>" `
-Description “Test logger"
設定先のAPI Management のContextオブジェクトを取得する
任意の文字列
任意の文字列
EventHub名
API ManagementにEventHub対応のロガーを作成
175. Nextscape Inc. 177
• <log-to-eventhub>ポリシーの書き方
• <log-to-eventhub>は<inbound>, <backend>, <outbound>, <on-error>で記載可
EventHubへ出力するポリシー
<inbound>
<base />
<log-to-eventhub logger-id=“<LoggerId>”>@(“文字列ならOK!”)</log-to-eventhub>
</inbound>
<inbound>
<base />
<log-to-eventhub logger-id="LoggerCreatedFromPowerShell">@( string.Join(",",
DateTime.UtcNow, context.Deployment.ServiceName, context.RequestId,
context.Request.IpAddress, context.Operation.Name) )</log-to-eventhub>
</inbound>
• 実装例
• contextから色々引っ張ってくるべし
176. Nextscape Inc. 178
• うまく実装できると、Traceにこんな感じで出力される
EventHubへ出力するポリシー
log-to-eventhub (0.163 ms)
{
"message": "Expression was successfully evaluated.",
"expression": " string.Join(¥",¥", DateTime.UtcNow, context.Deployment.ServiceName, context.RequestId,
context.Request.IpAddress, context.Operation.Name) ",
"value": "11/20/2018 12:13:58 PM,nsuesaka.azure-api.net,545118f2-18db-4044-8ac2-
4d0102fdfcd2,13.91.254.72,Retrieve resource“
}
log-to-eventhub (0.055 ms)
{
"message": "Log to EventHub Policy was successfully processed“
}
178. Nextscape Inc. 180
• ゴリゴリに加工したログ(docsより)
EventHubへ出力するポリシー
<log-to-eventhub logger-id="conferencelogger" partition-id="0">
@{
var requestLine = string.Format("{0} {1} HTTP/1.1¥r¥n",
context.Request.Method,
context.Request.Url.Path + context.Request.Url.QueryString);
var body = context.Request.Body?.As<string>(true);
if (body != null && body.Length > 1024)
{
body = body.Substring(0, 1024);
}
var headers = context.Request.Headers
.Where(h => h.Key != "Authorization" && h.Key != "Ocp-Apim-Subscription-Key")
.Select(h => string.Format("{0}: {1}", h.Key, String.Join(", ", h.Value)))
.ToArray<string>();
var headerString = (headers.Any()) ? string.Join("¥r¥n", headers) + "¥r¥n" : string.Empty;
return "request:" + "¥n"
+ requestLine + headerString + "¥r¥n" + body;
}
</log-to-eventhub>
180. Nextscape Inc. 182
• Log Analyticsへの結果出力は1時間に1回
ぐらい?すごく遅いので、名前の通り
あくまで分析用
Log Analyticsへ接続する
通信量
182. ユニット、という単位でスケールする
スケーリング
Nextscape Inc. 184
レベル Developer Basic Standard Premium
最大ユニット数 1 2 4 10/リージョン
料金 5483.28/月 16,799.52/月 78,387.84/月 319,064.4/月
7.37/時間 22.58/時間 105.36/時間 428.85/時間
SLA 99.9% 99.9% 99.9% 99.95%
予測最大スループット/ユニットごと 500 Req/Sec 1000 Req/Sec 2500 Req/Sec 4000 Req/Sec
(2018/11 東日本の単価。課金は時間単位)
• 1ユニットの作成には15分~40分かかる
※ユニット=APIMインスタンス、の理解で間違いない
187. Nextscape Inc. 189
パフォーマンスへの影響
• BackendAPIは元のリージョンに1つだけだと、プライマリリージョン以外にデプロイされたAPIMはアクセ
スがある度に異なるリージョンのBackendAPIを叩きに行くため、パフォーマンスが悪い
解決方法は2つ
• BackendAPIも各リージョンへデプロイし、APIMがデプロイされている場所に応じてBackendAPIを切り替え
るようにポリシーを作成する
• キャッシュを使う(キャッシュのセクションを参照)
複数リージョンへのデプロイの懸念点
188. Nextscape Inc. 190
• APIM自身がどのリージョンにデプロイされているかを判定して、
BackendAPIを切り替えるポリシーの例
複数リージョンへのデプロイ
<inbound>
<base />
<choose>
<when condition="@("West US".Equals(context.Deployment.Region, StringComparison.OrdinalIgnoreCase))">
<set-backend-service base-url="http://contoso-us.com/" />
</when>
<when condition="@("East Asia".Equals(context.Deployment.Region, StringComparison.OrdinalIgnoreCase))">
<set-backend-service base-url="http://contoso-asia.com/" />
</when>
<otherwise>
<set-backend-service base-url="http://contoso-other.com/" />
</otherwise>
</choose>
</inbound>
docに記載されているもの
194. キャッシュは2つのポリシーを対で設定する
• キャッシュからデータを取得するポリシー cache-lookup を inboundに設定
• データをキャッシュに格納するポリシー cache-store を outboundに設定
キャッシュ
Nextscape Inc. 196
<inbound>
<base />
<cache-lookup vary-by-developer="false" vary-by-developer-groups="false>
<vary-by-header>Accept</vary-by-header>
<vary-by-query-parameter>version</vary-by-query-parameter>
</cache-lookup>
</inbound>
<outbound>
<cache-store duration="seconds" />
<base />
</outbound>
開発者キーごとに応答
をキャッシュするか
開発者グループごとに応
答をキャッシュするか
キャッシュするポリシーを設定
キャッシュを検索す
るポリシー
キャッシュ保持時間を設定
キャッシュする単位。
複数指定可能
195. • キャッシュする場所と数
CDNとの違い
Nextscape Inc. 197
• 事前キャッシュ
CDN
Edgeサーバーが全世界各地に配置してある。Edgeまでの物理的な距離が近いほどEdgeまで
の到達時間は早いためキャッシュしてあればレスポンスは速い。が、キャッシュする場所
が多いということはOriginアクセスも意外と多い
API Management
テナント単位の共有データ キャッシュ。(テナント=作成済みAPIMリソース)が使用され
るため、1リージョン1キャッシュ。複数のユニットにスケールアップしても、同じ
キャッシュ データにアクセス可能。ただし、複数リージョンにデプロイした場合はそれぞ
れのリージョン別のキャッシュとなる
CDN できる。Poralから、もしくはAPIを使用したキャッシュも可能
API Management できない。<outbound>ポリシーでキャッシュするので、事前にはできない
196. • パージ
CDNとの違い
Nextscape Inc. 198
• キャッシュコントロール
CDN
任意のタイミングでキャッシュを削除できる。Poralから、もしくはAPIを使用した削除も
可能
API Management 任意に削除できない。キャッシュ保持経過時間が過ぎるのを待つしかない
CDN
• クエリ文字列ごとに違うキャッシュにできる
• Http-Headerの各種メタごとに違うキャッシュにできる
API Management CDNと同じ
198. • docs記載のシナリオを図解
Nextscape Inc. 200
フラグメントキャッシュとは
1. Request API
2. キー使ってキャッシュに
顧客データがあるかを確認
顧客データ
航空予約システム
4.予約データを取得
3. キャッシュに顧客データが
なかったら、外部からデータ
を取得し、キャッシュへ格納
6. Response
5.取得した予約デー
タの一部のプレース
ホルダに対して、顧
客データをセット顧客データを埋めるプ
レースホルダが予約デー
タにある、という前提が
現実的じゃない
199. フラグメントキャッシュとは
Nextscape Inc. 201
• フラグメントキャッシュポリシーは3つのポリシーを使う
キャッシュから値を取得するポリシーcache-lookup-value
• このポリシーで取得した値は、context.variables[keyName]に格納される
値をキャッシュに格納するポリシーcache-store-value
• key, value, durationを設定する
必要に応じてフラグメントキャッシュを削除する
• cache-remove-value ポリシー
詳しくはこちら
https://docs.microsoft.com/ja-jp/azure/api-management/api-management-caching-policies
200. • 実装例(docsより)
Nextscape Inc. 202
フラグメントキャッシュとは
<inbound>
<cache-lookup-value
key="@("userprofile-" + context.Variables["enduserid"])“ variable-name="userprofile" />
<choose>
<when condition="@(!context.Variables.ContainsKey("userprofile"))">
<send-request mode="new“
response-variable-name="userprofileresponse“ timeout=“10“ ignore-error="true">
・・・
</send-request>
<set-variable name="userprofile“
value="@(((IResponse)context.Variables["userprofileresponse"]).Body.As<string>())" />
<cache-store-value key="@("userprofile-" + context.Variables["enduserid"])“
value="@((string)context.Variables["userprofile"])“ duration="100000" />
</inbound>
“userprofile-xxxx”というキーで
キャッシュから値を取得
値がなかったら
データをキャッシュへ格納
外部からデータを取得して 変数に格納
203. Backup / Restore コマンド
誰もがイメージする Backup/Restoreはこの機能のこと
REST APIもしくはPowerShellコマンドしか用意されていない(Portal に該当機能なし)
バックアップした結果はBlob Storageへ格納される(Blobのリージョンとレベルに注意。
APIMと同じリージョンにLRSで保存するとDR的には意味がないってこと)
Backup時と同じレベル(Dev, Basic, Std, Prem)のインスタンスしかRestoreできない
30日以内のバックアップしか復元できない!(エラーになってしまう)
バックアップを元に新しいAPI Managementインスタンスを作成可能
Nextscape Inc. 205
REST APIを使うためにはAzrueADに
設定が必要。かなり面倒なのでお
勧めしない(PowerShellがいい)
204. Backup / Restore コマンド
Nextscape Inc. 206
PS C:¥> # バックアップ先のStorageのContextを取得する
PS C:¥> $storageContext = New-AzureStorageContext -StorageAccountName "ContosoStorage" -StorageAccountKey $storageKey
PS C:¥>
PS C:¥> # バックアップ実行
PS C:¥> Backup-AzureRmApiManagement `
>> -ResourceGroupName "ContosoGroup02" `
>> -Name "ContosoApi" `
>> -StorageContext $storageContext `
>> -TargetContainerName "ContosoBackups" `
>> -TargetBlobName "ContosoBackup.apimbackup"
PowerShell によるバックアップ(REST APIに比べて圧倒的に簡単!)
• バックアップしてみる
たった2つのコマンドだけ!
205. Backup / Restore コマンド
Nextscape Inc. 207
PS C:¥> # バックアップ先のStorageのContextを取得する
PS C:> $storageContext = New-AzureStorageContext -StorageAccountName "ContosoStorage" -StorageAccountKey $storageKey
PS C:¥>
PS C:¥> # 復元実行
PS C:> Restore-AzureRmApiManagement `
>> -ResourceGroupName "ContosoGroup" `
>> -Name "RestoredContosoApi" `
>> -StorageContext $storageContext `
>> -SourceContainerName "ContosoBackups" `
>> -SourceBlobName "ContosoBackup.apimbackup"
PowerShell による復元方法(こっちも2つのコマンドだけ。書き方ほぼ同じ)
• Restore してみる
• 復元先の API Managementインスタンスはあらかじめ作成しておくこと
• Backup時と同じインスタンスレベル(Dev, Basic, Std, Premium)にすること
• Restoreはめっちゃ時間かかる。15分~45分ぐらい
206. APIの設定に限定した Backup / Restore機能
ImportでAPI のコピーが可能(違うAPIMインスタンスへのImportもOK)
Azure Portal, REST API, Powershellコマンドのいずれかで実行可能
バックアップデータはファイルダウンロードしてローカルに格納
(Azure上に格納ではない)
Importかなり早い(数秒)
API の Export / Import
Nextscape Inc. 208
209. Nextscape Inc. 211
• Open API形式を選んだ場合、こんな内容ファイルがダウンロードされる
API の Export / Import
{
"swagger": "2.0",
"info": {
"title": "Echo API",
"version": "1.0"
},
"host": "nsuesaka2.azure-api.net",
"basePath": "/echo",
"schemes": [
"https"
],
…
"paths": {
"/resource": {
"get": {
"description": "A demonstration of a GET call on a sample resource. …",
"operationId": "retrieve-resource",
"summary": "Retrieve resource",
"parameters": [
{
"name": "param1",
"in": "query",
"description": "A sample parameter that is required and has …",
"required": true,
210. Nextscape Inc. 212
• Import でAPIをコピーしてみる
• titleをImport先の他のAPIと重複しないように修正する
• basePathは他のAPIと重複しても気にしないでいい(Import 時に反映されない)
API の Export / Import
{
"swagger": "2.0",
"info": {
"title": "Echo API2",
"version": "1.0"
},
"host": "nsuesaka2.azure-api.net",
"basePath": "/echo",
"schemes": [
"https"
],
…
「Echo API」→ 「Echo API2」
211. Nextscape Inc. 213
• Blank APIテンプレートで APIを新規に作成する
API の Export / Import
• Display Nameに適当な値を入れる。どうせImportすると上書
きされるので、なんでもOK
• API URL suffix とは前頁の basePathのこと。他APIと重複しない
値を設定する必要がある。(後から変更可能)
215. Nextscape Inc. 217
• Import した APIの定義を見てみる
API の Export / Import
{
"swagger": "2.0",
"info": {
"title": "Echo API2",
"version": "1.0"
},
"host": "nsuesaka2.azure-api.net",
"basePath": "/fuga",
"schemes": [
"https"
],
…
"paths": {
"/resource": {
"get": {
"description": "A demonstration of a GET call on a sample resource. …",
"operationId": "retrieve-resource",
"summary": "Retrieve resource",
"parameters": [
{
"name": "param1",
"in": "query",
"description": "A sample parameter that is required and has …",
API作成時につけた API URL suffix
216. API, Policy, 成果物、グループの設定情報がファイル形式(json)で
APIM内部の Git Repositoryに存在する
Git へ Pushすると、 APIM のRepositoryからAPIMへDeployするらしい
(WebAppsとそっくりな動作だ)
同じインスタンスに対するBackup/ Restoreのみ?
ユーザー、サブスクリプション、仮想ネットワークの接続設定はフ
jsonファイルに書き込まれていない(Restore されない)
Git の Repository を Clone する
Nextscape Inc. 218
222. Nextscape Inc. 224
• ローカルの Clone から、API Managementへ反映
• ローカルから Push し、その後API Management へデプロイする
(Push だけじゃ反映されないので注意!)
Git の Repository を Clone する
Pushしてから
デプロイ
223. Nextscape Inc. 225
異なるAPI Management インスタンスへ Push&Deployできるのか実験
Git の Repository を Clone する
Loggerを全部削除すれば、できるのかも・・・。試していない
• remote 先を 異なる APIM にして git push --force で無理やりPush&Deploy
• Push 先の構成も git clone して、ローカルで置き換えてから Push&Deploy
次の2つを試し
たがNGだった
Editor's Notes OAuth2.0の時、FacebookやAzureADは認可サーバーと呼ばれ、OpenIdConnectの場合はIDProviderと呼ばれる。
意味合い的には同じもの。 カナリアリリースは、新バージョンと旧バージョンの二つの環境をLBなどで少しずつ重みを変えていく手法。
段階的ロールアウトは複数回の新バージョンデプロイがあるのでちょっと違う。似てるけど。 Login-AzureRmAccount
Select-AzureRmSubscription -Subscription Azure機能検証環境 予測最大スループット2(ユニットごと)500 要求/秒1,000 要求/秒2,500 要求/秒4,000 要求/秒