你当前正在访问 Microsoft Azure Global Edition 技术文档网站。 如果需要访问由世纪互联运营的 Microsoft Azure 中国技术文档网站,请访问 https://docs.azure.cn。
本文将指导你如何在 Microsoft Planetary Computer Pro GeoCatalog 前,将 Azure API 管理(APIM)设置为一个 API 代理。 使用此配置,可以:
- 启用匿名访问:调用方不需要自己的Microsoft Entra 凭据。 APIM 使用托管标识代表其向 GeoCatalog 进行身份验证。
- 非 Entra 身份验证:调用方可以支持基于非 Entra 的身份验证方法。 APIM 使用托管标识代表其向 GeoCatalog 进行身份验证。
- 强制实施集合级访问控制:限制哪些 Spatiotemporal Access Catalog (STAC) 集合通过代理可见,即使 GeoCatalogs 本身不支持集合级基于角色的访问控制(RBAC)。
下图演示了添加 APIM 代理前后的体系结构:
之前 每个调用方都直接向 GeoCatalog 进行身份验证:
caller ──(Entra token)──► GeoCatalog
后 APIM 位于调用方和 GeoCatalog 之间,处理身份验证和访问控制:
caller ──(anonymous / APIM Subscription Keys)──► APIM ──(managed identity token)──► GeoCatalog
先决条件
- 拥有有效订阅的 Azure 帐户。 免费创建帐户。
- 现有的 GeoCatalog 资源。
- Azure API 管理实例。
- 分配给 APIM 实例的用户分配的托管标识,该实例在 GeoCatalog 资源上具有 GeoCatalog 读者的角色。 请参阅 “管理访问权限” 以获取角色分配说明。
将托管标识分配到 APIM
在 APIM 向 GeoCatalog 进行身份验证之前,需要将用户分配的托管标识与 APIM 实例相关联。
- 在 Azure 门户中,导航到 API 管理实例。
- 从左侧栏中选择“身份”。
- 选择“用户分配”选项卡。
- 选择“添加”,然后选择在 GeoCatalog 上具有 GeoCatalog 读者角色的用户分配的托管标识。
- 选择“添加”以确认。
在 APIM 中创建 API
在 APIM 中定义一个新的 API,该 APIM 将请求代理到 GeoCatalog 后端。
在 APIM 实例中,从左侧栏中选择 API 。
选择 “+ 添加 API>HTTP”。
使用以下设置配置 API:
设置 价值 显示名称 描述性名称(例如) GeoCatalog APIWeb 服务 URL GeoCatalog 终结点(例如 https://<name>.<id>.<region>.geocatalog.spatio.azure.com)URL 架构 HTTPS API URL 后缀 留空(根路径) 需要订阅 否,用于匿名访问; 是,对于基于订阅密钥的访问 选择“创建”。
定义 API 操作
添加以下操作以匹配 GeoCatalog API 图面。 通配符 (/*) 操作将所有匹配的请求转发到后端。 显式集合操作使你以后能够应用特定于集合的策略进行访问控制。
| 显示名称 | 方法 | URL 模板 |
|---|---|---|
| GET | GET | /* |
| 获取集合项 | GET | /stac/collections/{collection_id}/items |
| 获取单个集合 | GET | /stac/collections/{collection_id} |
| 获取集合子资源 | GET | /stac/collections/{collection_id}/* |
| POST | POST | /* |
若要添加每个操作,请执行以下操作:
- 选择创建的 API。
- 选择 “+ 添加操作”。
- 输入上表中的 显示名称、 方法和URL 模板 。
- 选择“保存”。
配置 API 级策略
API 级策略处理整个 API 的身份验证和 URL 重写。 此策略从用户分配的托管标识获取令牌,并将其附加到转发到 GeoCatalog 后端的每个请求。
- 选择创建的 API,然后选择 “所有操作”。
- 在 “入站处理 ”部分中,选择 </> (代码编辑器)图标。
- 将策略内容替换为以下策略:
<policies>
<inbound>
<base />
<authentication-managed-identity
resource="https://geocatalog.spatio.azure.com"
client-id="<managed-identity-client-id>" />
<set-header name="Accept-Encoding"
exists-action="delete" />
</inbound>
<backend>
<base />
</backend>
<outbound>
<base />
<find-and-replace
from="https://<name>.<id>.<region>.geocatalog.spatio.azure.com"
to="https://<apim-name>.azure-api.net" />
</outbound>
<on-error>
<base />
</on-error>
</policies>
替换以下占位符:
| Placeholder | 价值 |
|---|---|
<managed-identity-client-id> |
分配给 APIM 的用户分配的托管标识的客户端 ID |
<name>.<id>.<region> |
GeoCatalog 终结点组件 |
<apim-name> |
APIM 实例的名称 |
下表描述了每个策略元素:
| 政策要素 | Purpose |
|---|---|
authentication-managed-identity |
使用指定的托管标识为 https://geocatalog.spatio.azure.com 受众获取令牌,然后将令牌附加到传出请求中。 |
set-header (删除 Accept-Encoding) |
从入站请求中删除 Accept-Encoding 请求头。 请参阅 为什么要删除 Accept-Encoding。 |
find-and-replace |
将响应正文中的 GeoCatalog 后端 URL 重写为 APIM 网关 URL。 如果不进行此重写,STAC 链接(self、 root等 parent)会将后端 URL 公开给调用方。 |
为什么删除 Accept-Encoding
默认情况下,Python requests 和 httpx 等客户端将发送 Accept-Encoding: gzip, deflate。 当后端收到此标头时,它将返回压缩的响应。 APIM 出站策略(如 find-and-replace 对原始响应正文进行操作)无法解压缩,因此它们无提示地不执行任何操作。 去除标头会强制后端返回出站策略可以处理的未压缩响应。
注释
curl 默认情况下 wget 不发送 Accept-Encoding 。 这意味着,在使用这些测试工具进行测试时,出站策略似乎正常工作。 不一致仅在请求压缩的客户端中出现。
强制实施集合级访问控制
默认情况下,GeoCatalog 向任何经过身份验证的调用方公开其所有集合。 若要限制哪些集合通过 APIM 可见,请应用操作级别策略来阻止广泛的 STAC 发现并强制实施允许列表。
定义允许的集合
在 APIM 中创建命名值以存储允许的集合 ID 列表:
- 在 APIM 实例中,从左侧栏中选择 “命名”值 。
- 选择+ 添加。
- 将 Name 设置为
allowed-collections. - 将 值 设置为允许的集合 ID 的逗号分隔列表(例如,
sentinel-2-l2a,landsat-8-c2-l2)。 - 选择“保存”。
阻止登陆页和集合列表
阻止显示目录中每个集合的路由。 添加以下操作并附加立即返回 404 的策略:
| 显示名称 | 方法 | URL 模板 |
|---|---|---|
| 阻止根目录 | GET | / |
| 阻止集合 | GET | /stac/collections |
将以下操作级别策略应用于这两个操作:
<policies>
<inbound>
<base />
<return-response>
<set-status code="404" reason="Not Found" />
</return-response>
</inbound>
<backend>
<base />
</backend>
<outbound>
<base />
</outbound>
<on-error>
<base />
</on-error>
</policies>
在 STAC 搜索中强制实施允许的集合
STAC /stac/search 终结点接受 collections 参数 - 用作 GET 中的查询字符串或用于 POST 中的 JSON 正文。 如果没有限制措施,调用者可以搜索目录中的每个集合。 以下策略将验证是否仅请求来自允许集的集合。
添加两个操作:
| 显示名称 | 方法 | URL 模板 |
|---|---|---|
| GET 搜索 | GET | /stac/search |
| POST 搜索 | POST | /stac/search |
GET /stac/search policy
此策略验证 collections 查询参数。 每个逗号分隔的值必须在允许的集合内。 不使用collections参数的请求将被拒绝。403 Forbidden
将以下策略应用于 GET 搜索 操作:
<policies>
<inbound>
<base />
<set-variable name="allowedCsv"
value="{{allowed-collections}}" />
<choose>
<when condition='@{
var allowed = ((string)context
.Variables["allowedCsv"])
.Trim().ToLower();
var raw = context.Request.Url.Query
.GetValueOrDefault("collections", "");
if (string.IsNullOrWhiteSpace(raw)) {
return true;
}
foreach (var c in raw.ToLower().Split(
new [] { "," },
StringSplitOptions.RemoveEmptyEntries))
{
if (!c.Trim().Equals(allowed)) {
return true;
}
}
return false;
}'>
<return-response>
<set-status code="403"
reason="Forbidden" />
<set-body>
Collection not allowed.
</set-body>
</return-response>
</when>
</choose>
</inbound>
<backend>
<base />
</backend>
<outbound>
<base />
</outbound>
<on-error>
<base />
</on-error>
</policies>
注释
APIM 策略表达式在受限的 C# 环境中运行。 使用 condition='@{...}' (单引号属性),因此双引号在表达式内工作。 避免使用泛型类型参数(例如 GetValueOrDefault<string>)和 LINQ lambda - 改用显式强制转换和 foreach 循环。
POST /stac/search 策略
此策略分析 JSON 正文并验证 collections 数组。 不使用collections参数的请求将被拒绝。403 Forbidden
将以下策略应用于 POST 搜索 操作:
<policies>
<inbound>
<base />
<set-variable name="allowedCsv"
value="{{allowed-collections}}" />
<set-variable name="requestBody"
value="@(context.Request.Body
.As<string>(
preserveContent: true))" />
<choose>
<when condition='@{
var allowed = ((string)context
.Variables["allowedCsv"])
.Trim().ToLower();
var body = (string)context
.Variables["requestBody"];
var json = Newtonsoft.Json.Linq
.JObject.Parse(body);
var arr = json["collections"]
as Newtonsoft.Json.Linq.JArray;
if (arr == null || arr.Count == 0) {
return true;
}
foreach (var token in arr) {
if (!token.ToString().Trim()
.ToLower().Equals(allowed))
{
return true;
}
}
return false;
}'>
<return-response>
<set-status code="403"
reason="Forbidden" />
<set-body>
Collection not allowed.
</set-body>
</return-response>
</when>
</choose>
</inbound>
<backend>
<base />
</backend>
<outbound>
<base />
</outbound>
<on-error>
<base />
</on-error>
</policies>
在集合终结点强制实施允许的集合
如果没有显式操作,请求(如 GET /stac/collections/sentinel-2-l2a 或 GET /stac/collections/sentinel-2-l2a/items)会直接通过 GET /* 通配符到达后端,而不进行任何集合级检查。 将能够验证collection_id与{{allowed-collections}}之间关系的路径参数策略应用到您在定义 API 操作中创建的以下操作:
| 显示名称 | 方法 | URL 模板 |
|---|---|---|
| 获取单个集合 | GET | /stac/collections/{collection_id} |
| 获取集合子资源 | GET | /stac/collections/{collection_id}/* |
| 获取集合项 | GET | /stac/collections/{collection_id}/items |
将以下策略应用于所有三个操作:
<policies>
<inbound>
<base />
<set-variable name="allowedCsv"
value="{{allowed-collections}}" />
<choose>
<when condition='@{
var allowed = ((string)context
.Variables["allowedCsv"])
.Trim().ToLower();
var collectionId = (string)context
.Request.MatchedParameters[
"collection_id"];
return !collectionId.Trim()
.ToLower().Equals(allowed);
}'>
<return-response>
<set-status code="403"
reason="Forbidden" />
<set-body>
Collection not allowed.
</set-body>
</return-response>
</when>
</choose>
</inbound>
<backend>
<base />
</backend>
<outbound>
<base />
</outbound>
<on-error>
<base />
</on-error>
</policies>
在 SAS 令牌路由中强制实施允许的集合
GeoCatalog SAS API 允许调用方生成存储令牌并对资产 HREF 进行签名。 在没有任何限制的情况下,调用方可以获取任意集合的令牌。 以下策略确保只能访问允许的集合。
添加以下操作:
| 显示名称 | 方法 | URL 模板 |
|---|---|---|
| 获取 SAS 令牌 | GET | /sas/token/{collection_id} |
| 阻止 SAS 签名 | GET | /sas/sign |
将 404 阻止策略(与 根块和集合块相同)应用于 阻止 SAS 签名 操作。 调用方应改用 /sas/token/{collection_id} 来获取集合级 SAS 令牌。
将以下策略应用于 GET SAS 令牌 操作:
<policies>
<inbound>
<base />
<set-variable name="allowedCsv"
value="{{allowed-collections}}" />
<choose>
<when condition='@{
var allowed = ((string)context
.Variables["allowedCsv"])
.Trim().ToLower();
var collectionId = (string)context
.Request.MatchedParameters[
"collection_id"];
return !collectionId.Trim()
.ToLower().Equals(allowed);
}'>
<return-response>
<set-status code="403"
reason="Forbidden" />
<set-body>
Collection not allowed.
</set-body>
</return-response>
</when>
</choose>
</inbound>
<backend>
<base />
</backend>
<outbound>
<base />
</outbound>
<on-error>
<base />
</on-error>
</policies>
在数据路由中强制实施允许的集合
/data/mosaic/ 终结点提供图块渲染、边界框裁剪和搜索注册。 需要两个策略组:
-
寄存器搜索 - 验证 JSON 正文中的
collections数组。 -
所有其他集合路由 - 验证
collectionId路径参数。
添加以下操作:
| 显示名称 | 方法 | URL 模板 |
|---|---|---|
| POST 寄存器搜索 | POST | /data/mosaic/register |
| GET 数据收集 | GET | /data/mosaic/collections/{collectionId}/* |
POST /data/mosaic/register 策略
此策略将验证 JSON 正文中的 collections 数组是否符合允许集的标准。 缺少 collections 参数的请求将被拒绝。
<policies>
<inbound>
<base />
<set-variable name="allowedCsv"
value="{{allowed-collections}}" />
<set-variable name="requestBody"
value="@(context.Request.Body
.As<string>(
preserveContent: true))" />
<choose>
<when condition='@{
var allowed = ((string)context
.Variables["allowedCsv"])
.Trim().ToLower();
var body = (string)context
.Variables["requestBody"];
var json = Newtonsoft.Json.Linq
.JObject.Parse(body);
var arr = json["collections"]
as Newtonsoft.Json.Linq.JArray;
if (arr == null || arr.Count == 0) {
return true;
}
foreach (var token in arr) {
if (!token.ToString().Trim()
.ToLower().Equals(allowed))
{
return true;
}
}
return false;
}'>
<return-response>
<set-status code="403"
reason="Forbidden" />
<set-body>
Collection not allowed.
</set-body>
</return-response>
</when>
</choose>
</inbound>
<backend>
<base />
</backend>
<outbound>
<base />
</outbound>
<on-error>
<base />
</on-error>
</policies>
GET /data/mosaic/collections/{collectionId}/* 策略
此策略会对 collectionId 路径参数进行验证,以确保其属于许可的集合。 将此策略应用于 GET 数据收集 操作。
<policies>
<inbound>
<base />
<set-variable name="allowedCsv"
value="{{allowed-collections}}" />
<choose>
<when condition='@{
var allowed = ((string)context
.Variables["allowedCsv"])
.Trim().ToLower();
var collectionId = (string)context
.Request.MatchedParameters[
"collectionId"];
return !collectionId.Trim()
.ToLower().Equals(allowed);
}'>
<return-response>
<set-status code="403"
reason="Forbidden" />
<set-body>
Collection not allowed.
</set-body>
</return-response>
</when>
</choose>
</inbound>
<backend>
<base />
</backend>
<outbound>
<base />
</outbound>
<on-error>
<base />
</on-error>
</policies>
常见问题解答
如何更新允许的集合列表?
在 APIM 实例中编辑allowed-collections命名值。 不需要任何策略更改。
如果调用方省略集合参数,会发生什么情况?
请求被拒绝。403 Forbidden 调用方必须始终指定要搜索的集合。