Azure API管理認証-パート.2
18320 ワード
概要
記事パートの後で.1は、Azure API管理認証がどのように機能するかを共有します.The sample code Apaure広告、基本的な認証、クライアント証明書とAPI管理ゲートウェイの2つのパターンを確認します.一部.2ゲートウェイの検証パターンについて話します.
TOC
Gateway validation
建築
As mentioned in , the APIs that have different types of authentication are behind API Management.
ゲートウェイ検証
- API Management Gateway validates each type of credential, Azure AD token, Basic Authentication username and password, and Client certificate.
- For Azure AD and Basic Authentication, the credentials attached on the request header are passed through the gateway to the backend.
- For Client Certificate Authentication, it is difficult to pass through to the backend. Once a client certificate is validated at the API Management Gateway, another client certificate is retrieved from Azure Key Vault and attached to the backend request.
設定- Azure広告トークンの検証
- It uses
<validate-jwt>
and sees if the header includes the right claims.
- It checks
aud
and appid
claims.
Policy example
Named values
Comments
aadTenantId
Azure AD tenant ID
backendAppId
Azure AD application ID of client app
clientAppId
Azure AD applicaiton ID of backend app
<policies>
<inbound>
<base />
<validate-jwt header-name="Authorization" failed-validation-httpcode="401" failed-validation-error-message="Unauthorized. Access token is missing or invalid.">
<openid-config url="https://login.microsoftonline.com/{{aadTenantId}}/.well-known/openid-configuration" />
<audiences>
<audience>api://{{backendAppId}}</audience>
</audiences>
<required-claims>
<claim name="appid" match="all">
<value>{{clientAppId}}</value>
</claim>
</required-claims>
</validate-jwt>
</inbound>
<backend>
<base />
</backend>
<outbound>
<base />
</outbound>
<on-error>
<base />
</on-error>
</policies>
- In Bicep deployment, the Policy depends on Named Values. It uses
dependsOn
to specify the deployment order.
Bicep example
resource ApiManagementPolicyAzureAd 'Microsoft.ApiManagement/service/apis/policies@2021-08-01' = {
name: '${ApiManagementApiAzureAd.name}/policy'
dependsOn: [
ApiManagementNamedValueClientAppId
ApiManagementNamedValueBackendAppId
ApiManagementNamedValueAadTenantId
]
properties: {
value: '<policies>\r\n <inbound>\r\n <base />\r\n <validate-jwt header-name="Authorization" failed-validation-httpcode="401" failed-validation-error-message="Unauthorized. Access token is missing or invalid.">\r\n <openid-config url="${environment().authentication.loginEndpoint}{{${apim_nv_aadtenantid}}}/.well-known/openid-configuration" />\r\n <audiences>\r\n <audience>api://{{${apim_nv_backendappid}}}</audience>\r\n </audiences>\r\n <required-claims>\r\n <claim name="appid" match="all">\r\n <value>{{${apim_nv_clientappid}}}</value>\r\n </claim>\r\n </required-claims>\r\n </validate-jwt>\r\n </inbound>\r\n <backend>\r\n <base />\r\n </backend>\r\n <outbound>\r\n <base />\r\n </outbound>\r\n <on-error>\r\n <base />\r\n </on-error>\r\n</policies>'
format: 'xml'
}
}
resource ApiManagementNamedValueClientAppId 'Microsoft.ApiManagement/service/namedValues@2021-08-01' = {
name: '${ApiManagement.name}/${apim_nv_clientappid}'
properties: {
displayName: apim_nv_clientappid
value: aad_appid_client
}
}
resource ApiManagementNamedValueBackendAppId 'Microsoft.ApiManagement/service/namedValues@2021-08-01' = {
name: '${ApiManagement.name}/${apim_nv_backendappid}'
properties: {
displayName: apim_nv_backendappid
value: aad_appid_backend
}
}
resource ApiManagementNamedValueAadTenantId 'Microsoft.ApiManagement/service/namedValues@2021-08-01' = {
name: '${ApiManagement.name}/${apim_nv_aadtenantid}'
properties: {
displayName: apim_nv_aadtenantid
value: aad_tenantid
}
}
ConfigaLiton -基本認証認証
- API Management Gateway validates if an username and password on the request header is identical with those which registered as Named Values in API Management. The password is stored in Azure Key Vault and API Management refers to it.
Policy example
Named values
Comments
basicAuthUserName
Username for Basic Authentication
basicAuthPass
Password for Basic Authentication
<policies>
<inbound>
<base />
<set-variable name="user-pass" value="{{basicAuthUserName}}:{{basicAuthPass}}" />
<check-header name="Authorization" failed-check-httpcode="401" failed-check-error-message="Not authorized" ignore-case="false">
<value>@("Basic " + System.Convert.ToBase64String(Encoding.UTF8.GetBytes((string)context.Variables["user-pass"])))</value>
</check-header>
</inbound>
<backend>
<base />
</backend>
<outbound>
<base />
</outbound>
<on-error>
<base />
</on-error>
</policies>
- In Bicep deployment, the Policy depends on the Named Values registered in API Management. It uses
dependsOn
to specify the deployment order.
Bicep example
resource ApiManagementPolicyBasic 'Microsoft.ApiManagement/service/apis/policies@2021-08-01' = {
name: '${ApiManagementApiBasic.name}/policy'
dependsOn: [
ApiManagementNamedValueBasicAuthName
ApiManagementNamedValueBasicAuthPass
]
properties: {
value: '<policies>\r\n <inbound>\r\n <base />\r\n <set-variable name="user-pass" value="{{${apim_nv_basicauthuser}}}:{{${apim_nv_basicauthpass}}}" />\r\n <check-header name="Authorization" failed-check-httpcode="401" failed-check-error-message="Not authorized" ignore-case="false">\r\n <value>@("Basic " + System.Convert.ToBase64String(Encoding.UTF8.GetBytes((string)context.Variables["user-pass"])))</value>\r\n </check-header>\r\n </inbound>\r\n <backend>\r\n <base />\r\n </backend>\r\n <outbound>\r\n <base />\r\n </outbound>\r\n <on-error>\r\n <base />\r\n </on-error>\r\n</policies>'
format: 'xml'
}
}
resource ApiManagementNamedValueBasicAuthName 'Microsoft.ApiManagement/service/namedValues@2021-08-01' = {
name: '${ApiManagement.name}/${apim_nv_basicauthuser}'
properties: {
displayName: apim_nv_basicauthuser
value: basic_auth_user
}
}
resource ApiManagementNamedValueBasicAuthPass 'Microsoft.ApiManagement/service/namedValues@2021-08-01' = {
name: '${ApiManagement.name}/${apim_nv_basicauthpass}'
dependsOn: [
KeyVaultAccessPolicies
]
properties: {
displayName: apim_nv_basicauthpass
keyVault: {
secretIdentifier: 'https://${kv_name}${environment().suffixes.keyvaultDns}/secrets/${kvsecret_name_basic_pass}'
}
secret: true
}
}
クライアント証明書の妥当性検査
- It requires to configure
negotiateClientCertificate: true
so API Management accepts a client certificate during TLS handshake. Without it, the Policy does not work for client certificate authentication.
-
negotiateClientCertificate: true
works for other request patterns without a client certificate. If you turn true/false back and forth, it takes an half hour or more to change the API Management configuration.
- It uses
<validate-client-certificate>
policy and validates the thumbprint stored in Azure Key Vault.
-
validate-trust
should turn to false
for a self-signed certificate to work.
-
<authentication-certificate certificate-id="apicert" />
is needed to send a backend request with a certificate.
Bicep example
properties: {
hostnameConfigurations: [
{
type: 'Proxy'
hostName: '${apim_name}.azure-api.net'
negotiateClientCertificate: true
}
]
}
ポリシーの例
値
コメント
証明書
証明書のアップロード
<policies>
<inbound>
<base />
<validate-client-certificate validate-revocation="true" validate-trust="false" validate-not-before="true" validate-not-after="true" ignore-error="false">
<identities>
<identity thumbprint="{{certificateThumbprint}}" />
</identities>
</validate-client-certificate>
<authentication-certificate certificate-id="apicert" />
</inbound>
<backend>
<base />
</backend>
<outbound>
<base />
</outbound>
<on-error>
<base />
</on-error>
</policies>
- API Management Gateway validates each type of credential, Azure AD token, Basic Authentication username and password, and Client certificate.
- For Azure AD and Basic Authentication, the credentials attached on the request header are passed through the gateway to the backend.
- For Client Certificate Authentication, it is difficult to pass through to the backend. Once a client certificate is validated at the API Management Gateway, another client certificate is retrieved from Azure Key Vault and attached to the backend request.
設定- Azure広告トークンの検証
- It uses
<validate-jwt>
and sees if the header includes the right claims. - It checks
aud
andappid
claims.
Policy example
Named values | Comments |
---|---|
aadTenantId | Azure AD tenant ID |
backendAppId | Azure AD application ID of client app |
clientAppId | Azure AD applicaiton ID of backend app |
<policies>
<inbound>
<base />
<validate-jwt header-name="Authorization" failed-validation-httpcode="401" failed-validation-error-message="Unauthorized. Access token is missing or invalid.">
<openid-config url="https://login.microsoftonline.com/{{aadTenantId}}/.well-known/openid-configuration" />
<audiences>
<audience>api://{{backendAppId}}</audience>
</audiences>
<required-claims>
<claim name="appid" match="all">
<value>{{clientAppId}}</value>
</claim>
</required-claims>
</validate-jwt>
</inbound>
<backend>
<base />
</backend>
<outbound>
<base />
</outbound>
<on-error>
<base />
</on-error>
</policies>
- In Bicep deployment, the Policy depends on Named Values. It uses
dependsOn
to specify the deployment order.
resource ApiManagementPolicyAzureAd 'Microsoft.ApiManagement/service/apis/policies@2021-08-01' = {
name: '${ApiManagementApiAzureAd.name}/policy'
dependsOn: [
ApiManagementNamedValueClientAppId
ApiManagementNamedValueBackendAppId
ApiManagementNamedValueAadTenantId
]
properties: {
value: '<policies>\r\n <inbound>\r\n <base />\r\n <validate-jwt header-name="Authorization" failed-validation-httpcode="401" failed-validation-error-message="Unauthorized. Access token is missing or invalid.">\r\n <openid-config url="${environment().authentication.loginEndpoint}{{${apim_nv_aadtenantid}}}/.well-known/openid-configuration" />\r\n <audiences>\r\n <audience>api://{{${apim_nv_backendappid}}}</audience>\r\n </audiences>\r\n <required-claims>\r\n <claim name="appid" match="all">\r\n <value>{{${apim_nv_clientappid}}}</value>\r\n </claim>\r\n </required-claims>\r\n </validate-jwt>\r\n </inbound>\r\n <backend>\r\n <base />\r\n </backend>\r\n <outbound>\r\n <base />\r\n </outbound>\r\n <on-error>\r\n <base />\r\n </on-error>\r\n</policies>'
format: 'xml'
}
}
resource ApiManagementNamedValueClientAppId 'Microsoft.ApiManagement/service/namedValues@2021-08-01' = {
name: '${ApiManagement.name}/${apim_nv_clientappid}'
properties: {
displayName: apim_nv_clientappid
value: aad_appid_client
}
}
resource ApiManagementNamedValueBackendAppId 'Microsoft.ApiManagement/service/namedValues@2021-08-01' = {
name: '${ApiManagement.name}/${apim_nv_backendappid}'
properties: {
displayName: apim_nv_backendappid
value: aad_appid_backend
}
}
resource ApiManagementNamedValueAadTenantId 'Microsoft.ApiManagement/service/namedValues@2021-08-01' = {
name: '${ApiManagement.name}/${apim_nv_aadtenantid}'
properties: {
displayName: apim_nv_aadtenantid
value: aad_tenantid
}
}
ConfigaLiton -基本認証認証
- API Management Gateway validates if an username and password on the request header is identical with those which registered as Named Values in API Management. The password is stored in Azure Key Vault and API Management refers to it.
Policy example
Named values | Comments |
---|---|
basicAuthUserName | Username for Basic Authentication |
basicAuthPass | Password for Basic Authentication |
<policies>
<inbound>
<base />
<set-variable name="user-pass" value="{{basicAuthUserName}}:{{basicAuthPass}}" />
<check-header name="Authorization" failed-check-httpcode="401" failed-check-error-message="Not authorized" ignore-case="false">
<value>@("Basic " + System.Convert.ToBase64String(Encoding.UTF8.GetBytes((string)context.Variables["user-pass"])))</value>
</check-header>
</inbound>
<backend>
<base />
</backend>
<outbound>
<base />
</outbound>
<on-error>
<base />
</on-error>
</policies>
- In Bicep deployment, the Policy depends on the Named Values registered in API Management. It uses
dependsOn
to specify the deployment order.
resource ApiManagementPolicyBasic 'Microsoft.ApiManagement/service/apis/policies@2021-08-01' = {
name: '${ApiManagementApiBasic.name}/policy'
dependsOn: [
ApiManagementNamedValueBasicAuthName
ApiManagementNamedValueBasicAuthPass
]
properties: {
value: '<policies>\r\n <inbound>\r\n <base />\r\n <set-variable name="user-pass" value="{{${apim_nv_basicauthuser}}}:{{${apim_nv_basicauthpass}}}" />\r\n <check-header name="Authorization" failed-check-httpcode="401" failed-check-error-message="Not authorized" ignore-case="false">\r\n <value>@("Basic " + System.Convert.ToBase64String(Encoding.UTF8.GetBytes((string)context.Variables["user-pass"])))</value>\r\n </check-header>\r\n </inbound>\r\n <backend>\r\n <base />\r\n </backend>\r\n <outbound>\r\n <base />\r\n </outbound>\r\n <on-error>\r\n <base />\r\n </on-error>\r\n</policies>'
format: 'xml'
}
}
resource ApiManagementNamedValueBasicAuthName 'Microsoft.ApiManagement/service/namedValues@2021-08-01' = {
name: '${ApiManagement.name}/${apim_nv_basicauthuser}'
properties: {
displayName: apim_nv_basicauthuser
value: basic_auth_user
}
}
resource ApiManagementNamedValueBasicAuthPass 'Microsoft.ApiManagement/service/namedValues@2021-08-01' = {
name: '${ApiManagement.name}/${apim_nv_basicauthpass}'
dependsOn: [
KeyVaultAccessPolicies
]
properties: {
displayName: apim_nv_basicauthpass
keyVault: {
secretIdentifier: 'https://${kv_name}${environment().suffixes.keyvaultDns}/secrets/${kvsecret_name_basic_pass}'
}
secret: true
}
}
クライアント証明書の妥当性検査
- It requires to configure
negotiateClientCertificate: true
so API Management accepts a client certificate during TLS handshake. Without it, the Policy does not work for client certificate authentication. -
negotiateClientCertificate: true
works for other request patterns without a client certificate. If you turn true/false back and forth, it takes an half hour or more to change the API Management configuration. - It uses
<validate-client-certificate>
policy and validates the thumbprint stored in Azure Key Vault. -
validate-trust
should turn tofalse
for a self-signed certificate to work. -
<authentication-certificate certificate-id="apicert" />
is needed to send a backend request with a certificate.
properties: {
hostnameConfigurations: [
{
type: 'Proxy'
hostName: '${apim_name}.azure-api.net'
negotiateClientCertificate: true
}
]
}
ポリシーの例値
コメント
証明書
証明書のアップロード
<policies>
<inbound>
<base />
<validate-client-certificate validate-revocation="true" validate-trust="false" validate-not-before="true" validate-not-after="true" ignore-error="false">
<identities>
<identity thumbprint="{{certificateThumbprint}}" />
</identities>
</validate-client-certificate>
<authentication-certificate certificate-id="apicert" />
</inbound>
<backend>
<base />
</backend>
<outbound>
<base />
</outbound>
<on-error>
<base />
</on-error>
</policies>
!context.Request.Certificate.Verify()
or context.Request.Certificate.VerifyNoRevocation()
自己署名証明書とCA証明書を使用するので、API管理にアップロードされません.<policies>
<inbound>
<base />
<choose>
<when condition="@(context.Request.Certificate == null || context.Request.Certificate.Thumbprint != "{Thumbprint uploaded in Key Vault}")">
<return-response>
<set-status code="403" reason="Invalid client certificate" />
</return-response>
</when>
</choose>
</inbound>
<backend>
<base />
</backend>
<outbound>
<base />
</outbound>
<on-error>
<base />
</on-error>
</policies>
resource ApiManagementPolicyCert 'Microsoft.ApiManagement/service/apis/policies@2021-08-01' = {
name: '${ApiManagementApiCert.name}/policy'
dependsOn: [
ApiManagementNamedValueThumbprint
ApiManagementCertificate
]
properties: {
value: '<policies>\r\n <inbound>\r\n <base />\r\n <validate-client-certificate validate-revocation="true" validate-trust="false" validate-not-before="true" validate-not-after="true" ignore-error="false">\r\n <identities>\r\n <identity thumbprint="{{${apim_nv_thumbprint}}}" />\r\n </identities>\r\n </validate-client-certificate>\r\n <authentication-certificate certificate-id="${apim_certificate_id}" />\r\n </inbound>\r\n <backend>\r\n <base />\r\n </backend>\r\n <outbound>\r\n <base />\r\n </outbound>\r\n <on-error>\r\n <base />\r\n </on-error>\r\n</policies>'
format: 'xml'
}
}
resource ApiManagementNamedValueThumbprint 'Microsoft.ApiManagement/service/namedValues@2021-08-01' = {
name: '${ApiManagement.name}/${apim_nv_thumbprint}'
dependsOn: [
KeyVaultAccessPolicies
]
properties: {
displayName: apim_nv_thumbprint
keyVault: {
secretIdentifier: 'https://${kv_name}${environment().suffixes.keyvaultDns}/secrets/${kvsecret_name_cert_thumbprint}'
}
secret: true
}
}
resource ApiManagementCertificate 'Microsoft.ApiManagement/service/certificates@2021-08-01' = {
name: '${ApiManagement.name}/${apim_certificate_id}'
dependsOn: [
KeyVaultAccessPolicies
]
properties: {
keyVault: {
secretIdentifier: 'https://${kv_name}${environment().suffixes.keyvaultDns}/secrets/${kvcert_name_api}'
}
}
}
リクエスト
Powershell for AzureAdAuthAPI
$clientSecret = "{Azure AD client app secret}"
$authorizeUri = "https://login.microsoftonline.com/{Azure AD tenant ID}/oauth2/v2.0/token"
$body = 'grant_type=client_credentials' + `
'&client_id={Azure AD client app ID}' + `
'&client_secret=' + $clientSecret + `
'&scope=api://{Azure AD backend app ID}/.default'
$token = (Invoke-RestMethod -Method Post -Uri $authorizeUri -Body $body).access_token
$Uri = "https://{API Management name}.azure-api.net/AzureAdAuth/Weatherforecast/RequireAuth"
$headers = @{
"Authorization" = 'Bearer ' + $token
}
Invoke-RestMethod -Uri $Uri -Method Get -Headers $headers
Powershell for BasicAuthAPI
$basicAuthUsername = "{Basic Authenticaiton user}"
$basicAuthSecret = "{Basic Authenticaiton password}"
$bytes = [System.Text.Encoding]::ASCII.GetBytes($basicAuthUsername + ':' + $basicAuthSecret)
$authHeader = [Convert]::ToBase64String($bytes)
$Uri = "https://{API Management name}.azure-api.net/BasicAuth/Weatherforecast/RequireAuth"
$headers = @{
"Authorization" = 'Basic ' + $authHeader
}
Invoke-RestMethod -Uri $Uri -Method Get -Headers $headers
Powershell for CertificateAuthAPI
$parameters = @{
Method = "GET"
Uri = "https://{API Management name}.azure-api.net/CertificateAuth/Weatherforecast/RequireAuth"
Certificate = (Get-PfxCertificate "{PFX file path}")
}
Invoke-RestMethod @parameters
Reference
この問題について(Azure API管理認証-パート.2), 我々は、より多くの情報をここで見つけました
https://dev.to/koheikawata/azure-api-management-authentication-part2-pd9
テキストは自由に共有またはコピーできます。ただし、このドキュメントのURLは参考URLとして残しておいてください。
Collection and Share based on the CC Protocol
$clientSecret = "{Azure AD client app secret}"
$authorizeUri = "https://login.microsoftonline.com/{Azure AD tenant ID}/oauth2/v2.0/token"
$body = 'grant_type=client_credentials' + `
'&client_id={Azure AD client app ID}' + `
'&client_secret=' + $clientSecret + `
'&scope=api://{Azure AD backend app ID}/.default'
$token = (Invoke-RestMethod -Method Post -Uri $authorizeUri -Body $body).access_token
$Uri = "https://{API Management name}.azure-api.net/AzureAdAuth/Weatherforecast/RequireAuth"
$headers = @{
"Authorization" = 'Bearer ' + $token
}
Invoke-RestMethod -Uri $Uri -Method Get -Headers $headers
$basicAuthUsername = "{Basic Authenticaiton user}"
$basicAuthSecret = "{Basic Authenticaiton password}"
$bytes = [System.Text.Encoding]::ASCII.GetBytes($basicAuthUsername + ':' + $basicAuthSecret)
$authHeader = [Convert]::ToBase64String($bytes)
$Uri = "https://{API Management name}.azure-api.net/BasicAuth/Weatherforecast/RequireAuth"
$headers = @{
"Authorization" = 'Basic ' + $authHeader
}
Invoke-RestMethod -Uri $Uri -Method Get -Headers $headers
$parameters = @{
Method = "GET"
Uri = "https://{API Management name}.azure-api.net/CertificateAuth/Weatherforecast/RequireAuth"
Certificate = (Get-PfxCertificate "{PFX file path}")
}
Invoke-RestMethod @parameters
Reference
この問題について(Azure API管理認証-パート.2), 我々は、より多くの情報をここで見つけました https://dev.to/koheikawata/azure-api-management-authentication-part2-pd9テキストは自由に共有またはコピーできます。ただし、このドキュメントのURLは参考URLとして残しておいてください。
Collection and Share based on the CC Protocol