博客 | NGINX

使用声明式 API 从 OpenAPI 到 NGINX 作为 API 网关

NGINX-F5-horiz-black-type-RGB 的一部分
Fabrizio Fiorucci 缩略图
法布里奇奥·菲奥鲁奇
2024 年 6 月 17 日发布

NGINX 一直被公认为支持高性能 Web 服务器和负载均衡器的首选之一。 然而,随着微服务架构的兴起和高效API管理的需求,NGINX也成为构建API网关的热门选择。

在此博客中,我们将探讨如何使用声明性 API 方法将 OpenAPI 模式定义转换为功能齐全的 NGINX 配置,该配置作为具有Webapplication防火墙安全性的 API 网关和开发人员门户运行。

我们将提供分步说明和见解,指导如何利用 NGINX Plus 简化您的 API 管理流程并确保您的应用获得最佳性能。

介绍 API 网关

API 网关作为管理和保护客户端和后端服务之间通信的中央枢纽。 它充当客户端和后端服务器之间的反向代理,路由传入的请求并将其分发到适当的服务。 这使得客户端和服务之间的通信更加有效,并且使得 API 网关能够处理诸如身份验证授权速率限制和缓存等任务。

此外,API 网关可以充当安全层,保护后端服务免受潜在威胁和攻击。 它可以实施加密、基于令牌的身份验证和访问控制等安全措施,确保只有授权用户才能访问服务。 通过在一个地方整合和管理这些安全功能,API 网关有助于简化系统的整体安全架构,并降低跨多个服务实施安全措施的复杂性。

NGINX 声明式 API 项目

社区支持的NGINX Declarative API项目为NGINX Instance Manager提供了一组声明式 REST API。

它可用于管理 NGINX Plus 配置生命周期并使用 JSON 服务定义创建 NGINX Plus 配置。 与 NGINX 实例管理器一起使用时支持 GitOps 集成:检查引用对象更新的真实来源,并自动保持 NGINX 配置同步。

OpenAPI 模式可用于自动将 NGINX 配置为 API 网关。 通过Redocly支持开发人员门户创建。

先决条件

要运行本博客的内容,您需要:

实验室概述

安装并运行所有先决条件后,NGINX 实例管理器会显示 NGINX Plus 实例与 NGINX App Protect WAF 在线。

NGINX Plus 实例是declarativeAPI 测试实例组的一部分

部署声明式 API

NGINX Declarative API 项目依赖于 NGINX Instance Manager 提供的 REST API,并提供基于 JSON 的声明式抽象。 按照以下说明运行声明性 API 项目:

1. 运行 docker ps 来验证 Docker 是否正在运行:


f5@ubuntu:~$ docker ps
容器 ID 镜像 命令 创建状态 端口 名称


2. 在 Linux 主机上克隆 Github 存储库:


f5@ubuntu:~$ git clone https://github.com/f5devcentral/NGINX-Declarative-API/
克隆到“NGINX-Declarative-API”...
远程: 枚举对象: 4072,完成。
远程: 计数对象: 100% (1982/1982),已完成。
远程: 压缩对象: 100% (1332/1332),完成。
远程: 总计 4072(增量 668),重用 876(增量 609),打包重用 2090
接收对象: 100% (4072/4072),19.05 MiB | 4.88 MiB/s,完成。
解决差异: 100%(1154/1154),完成。
f5@ubuntu:~$


3. 切换到 docker-compose 目录:


f5@ubuntu:~$ cd NGINX-Declarative-API/contrib/docker-compose/


4. 使用nginx-dapi.sh脚本通过docker-compose启动所有容器。 在初始启动期间,所有 docker 镜像都会自动构建:


f5@ubuntu:~/NGINX-Declarative-API/contrib/docker-compose$ ./nginx-dapi.sh -c start
-> 更新 docker 镜像
[+] 拉取 11/11
[...]
-> 部署 NGINX Declarative API
[+] 运行 4/4
✔ 网络 nginx-dapi_dapi-network 创建 0.1 秒 
✔ 容器 redis 启动 1.5 秒 
✔ 容器 devportal 启动 1.5 秒 
✔ 容器 nginx-dapi 启动


5. 检查正在运行的docker容器:


f5@ubuntu:~/NGINX-Declarative-API/contrib/docker-compose$ docker ps
容器 ID 图像 命令 创建状态 端口 名称
e29a2f783da2 nginx-declarative-api "/deployment/env/bin…" 5 分钟前 启动 5 分钟 0.0.0.0:5000->5000/tcp, :::5000->5000/tcp nginx-dapi
97142840eaf7 redis "docker-entrypoint.s…" 5 分钟前 启动 5 分钟 0.0.0.0:6379->6379/tcp, :::6379->6379/tcp redis
6b50c0426643 nginx-declarative-api-devportal “/deployment/src/sta…” 5 分钟前 启动 5 分钟 0.0.0.0:5001->5000/tcp, :::5001->5000/tcp devportal


6. 在客户端主机上运行 Postman 并导入 NGINX Declarative API 集合,网址为https://raw.githubusercontent.com/f5devcentral/NGINX-Declarative-API/main/contrib/postman/NGINX%20Declarative%20API.postman_collection.json

7. 编辑 Postman 集合变量以使其适应您的环境:

8. 设置以下变量:

  • ncg_host - 运行声明式 API docker-compose 的 Linux 主机的主机名或 IP 地址
  • ncg_port -NGINX Declarative API 的 TCP 端口: 5000 是默认值
  • nim_host - NGINX 实例管理器基本 URL(即 https://nms.k8s.ie.ff.lan)
  • nim_username - NGINX 实例管理器身份验证用户名
  • nim_password - NGINX 实例管理器身份验证密码

9. 保存 Postman 上的所有更改

10. 在 Postman 集合中浏览到Petstore API Gateway RateLimit + JWT AuthN/AuthZ + WAF并打开请求

JSON 声明如下:


{
“输出”:{
“类型”:“nms”,
“nms”:{
“url”:“{{nim_host}}”,
“用户名”:“{{nim_username}}”,
“密码”:“{{nim_password}}”,
“实例组”:“{{nim_instancegroup}}”,
“同步时间”: 0,
“模块”:[
“ngx_http_app_protect_module”
],
“证书”:[
{
“类型”: “证书”,
“名称”: “test_cert”,
“内容”:{
“内容”: “{{github_gitops_root}}/v4.2/testcert.crt”
}
},
{
“类型”: “密钥”,
“名称”: “test_key”,
“内容”:{
“内容”: “{{github_gitops_root}}/v4.2/testcert.key”
}
}
],
“政策”:[
{
“类型”: “app_protect”,
“名称”: “production-policy”,
“active_tag”: “xss-blocked”,
“版本”:[
{
“标签”: “xss-blocked”,
“显示名称”: “生产政策 - XSS 被阻止”,
“描述”: “这是一项可用于生产的政策 - 阻止 XSS”,
“contents”:{
“content”:“{{github_gitops_root}}/v4.2/nap-policy-xss-blocked-bot-allowed.json”
}
},
{
“tag”:“xss-allowed”,
“displayName”: “生产政策 - 允许 XSS”,
“说明”: “这是一项可用于生产的策略 - 允许 XSS”,
“contents”:{
“content”:“{{github_gitops_root}}/v4.2/nap-policy-xss-allowed.json”
}
}
]
}
]
}
},
“declaration”:{
“http”:{
“servers”:[
{
“name”: “Petstore API”,
“名称”:[
“apigw.nginx.lab”
],
“解析器”: “8.8.8.8”,
“监听”: {
“地址”: “0.0.0.0:443”,
“http2”: true,
“tls”: {
“certificate”: “test_cert”,
“key”: “test_key”,
“ciphers”: “默认”,
“协议”:[
“TLSv1.2”,
“TLSv1.3”
]
}
},
“日志”:{
“访问”:“/var/log/nginx/apigw.nginx.lab-access_log”,
“错误”:“/var/log/nginx/apigw.nginx.lab-error_log”
},
“位置”:[
{
“uri”:“/petstore”,
“urimatch”:“前缀”,
“apigateway”:{
“openapi_schema”:{
“内容”:“http://petstore.swagger.io/v2/swagger.json”
},
“api_gateway”:{
“启用”:true,
“strip_uri”:true,
“server_url”:“https://petstore.swagger.io/v2”
},
“developer_portal”:{
“启用”:true,
“uri”: "/petstore-devportal.html"
},
"身份验证": {
"客户端": [
{
"配置文件": “Petstore JWT 身份验证”
}
],
“enforceOnPaths”: true,
“paths”: [
“/user/login”,
“/user/logout”
]
},
“authorization”: [
{
“profile”: “基于 JWT 角色的授权”,
“enforceOnPaths”: true,
“paths”: [
“/user/login”,
“/user/logout”
]
}
],
“rate_limit”: [
{
“profile”: “petstore_ratelimit”,
“httpcode”: 429,
“爆发”: 0,
“延迟”: 0,
“enforceOnPaths”:true,
“paths”:[
“/user/login”,
“/user/logout”
]
}
]
},
“log”:{
“access”:“/var/log/nginx/petstore-access_log”,
“error”:“/var/log/nginx/petstore-error_log”
},
“app_protect”:{
“enabled”:true,
“policy”:“production-policy”,
“log”:{
“profile_name”:“secops_dashboard”,
“enabled”:true,
“destination”: “127.0.0.1:514”
}
}
}
]
}
],
“rate_limit”: [
{
“name”: “petstore_ratelimit”,
“key”: “$binary_remote_addr”,
“size”: "10m",
"速率": “2r/s”
}
],
“身份验证”:{
“客户端”:[
{
“名称”: “Petstore JWT 身份验证”,
“type”:“jwt”,
“jwt”:{
“realm”: “Petstore 身份验证”,
“key”:“{\“keys\”:[{\“k\”:\“ZmFudGFzdGljand0\”,\“kty\”:\“oct\”,\“kid\”:\“0001\”}]}”,
“cachetime”: 5
}
}
]
},
"授权": [
{
"名称": “基于 JWT 角色的授权”,
“type”: “jwt”,
“jwt”: {
“claims”: [
{
“name”: “roles”,
“value”: [
“~(devops)”
],
“errorcode”: 第403章
                            }
                        ]
                    }
                }
            ]
        }
    }
}


输出部分定义:

  • Declarative API 将把 NGINX 配置发布到 NGINX 实例管理器服务器
  • TLS 证书和密钥 - 这些可以通过存储它们的可信来源的 URL 来引用
  • NGINX App 保护 WAF 安全策略 - 这些可以通过存储事实来源的 URL 来引用

声明部分描述:

  • 要创建的 NGINX 服务器
  • 是否执行 TLS 卸载
  • 在哪里记录访问和错误条目
  • /petstore基本 URI,API 网关配置将部署在此 URI 中,并可供客户端访问
  • 待发布的API网关配置和开发者门户
  • 如何启用 NGINX App Protect WAF、使用什么安全策略以及将安全违规记录到何处
  • 如何验证和授权客户端请求

API 网关声明部分描述了声明性 API 将如何提供其结果。

OpenAPI 模式通过其完整 URL 来引用:


“apigateway”:{
“openapi_schema”:{
“content”:“http://petstore.swagger.io/v2/swagger.json”
},


请求创建 NGINX API 网关配置,并定义上游服务器。 当 NGINX 反向代理向上游发出请求时, /petstore基本 URI 将被删除:


“api_gateway”:{
“enabled”:true,
“strip_uri”:true,
“server_url”:“https://petstore.swagger.io/v2”
},




请求在特定 URI 下创建并部署开发人员门户:


“developer_portal”:{
“enabled”:true,
“uri”:“/petstore-devportal.html”
},


根据指定的客户端身份验证配置文件对/user/login/user/logout强制执行客户端身份验证:


“身份验证”:{
“客户端”:[
{
“配置文件”: “Petstore JWT 身份验证”
}
],
“enforceOnPaths”: true,
“paths”: [
“/user/login”,
“/user/logout”
]
},


根据指定的客户端授权配置文件对/user/login/user/logout强制执行客户端授权:


“授权”:[
{
“个人资料”: “基于 JWT 角色的授权”,
“enforceOnPaths”: true,
“paths”: [
“/user/login”,
“/user/logout”
]
}
],




根据指定的配置文件对/user/login/user/logout进行速率限制:


“rate_limit”:[
{
“profile”:“petstore_ratelimit”,
“httpcode”: 429,
“爆发”: 0,
“延迟”: 0,
“enforceOnPaths”: true,
“paths”: [
“/user/login”,
“/user/logout”
]
}
]
},


12. 使用 Postman的“发送”按钮将请求发布到声明性 API。响应类似于:


{
    “代码”: 200,
“内容”:{
“创建时间”: “2024-04-26T17:09:10.419574328Z”,
“详细信息”: {
“失败”: [],
“待处理”: [],
“成功”: [
{
“名称”:“vm-test”
}
]
},
“id”: “1060ec49-120e-45ca-820b-5203c8b3538d”,
“消息”: “实例组配置已成功发布至 declarativeAPITest”,
“status”:“成功”,
“updateTime”: “2024-04-26T17:09:10.881509913Z”
},
“configUid”:“eecf1da6-9d8f-4e44-89cc-a470af79379d”
}


13. 在此阶段,NGINX 实例配置为 API 网关,强制实施 WAF 安全性并发布开发人员门户。

测试 API 网关

注意:假定 FQDN apigw.nginx.lab解析为运行 NGINX 实例的虚拟机的 IP 地址

1. 切换到jwt目录:


f5@ubuntu:~$ cd ~/NGINX-Declarative-API/contrib/gitops-examples/jwt


2. 访问未经身份验证的 REST API 端点:


$ curl -w '\n' -ki https://apigw.nginx.lab/petstore/store/inventory
HTTP/2 200
日期: 2024 年 4 月 26 日星期五 17:13:54 GMT
内容类型:应用/json
访问控制允许来源:*
访问控制允许方法: 获取、发布、删除、放置
访问控制允许标头: 内容类型、api_key、授权

{"totvs":5,"aut":1,"FORsold":1,[...]



3. 速率限制:

    
    $ curl -w '\n' -ki https://apigw.nginx.lab/petstore/user/login;curl -w '\n' -ki 
https://apigw.nginx.lab/petstore/user/login
HTTP/2 401 
日期: 2024 年 4 月 26 日星期五 17:14:51 GMT
内容类型:text/html
内容长度: 179
www-身份验证: Bearer realm="Petstore 身份验证"
<html>
<head><title>401 需要授权</title></head>
<body>
<center><h1>401 需要授权</h1></center>
<hr><center>nginx/1.25.3</center>
</body>
</html>
HTTP/2 429 
日期: 2024 年 4 月 26 日星期五 17:14:51 GMT
内容类型:text/html
内容长度: 169
<html>
<head><title>429 请求过多</title></head>
<body>
<center><h1>429 请求过多</h1></center>
<hr><center>nginx/1.25.3</center>
</body>
</html>
    

4. 身份验证及有效授权:


$ curl -w '\n' -ki https://apigw.nginx.lab/petstore/user/login -H "授权: 承载者 `cat jwt.devops`"
HTTP/2 200
日期: 2024 年 4 月 26 日星期五 17:15:41 GMT
内容类型:应用/json
访问控制允许来源:*
访问控制允许方法: 获取、发布、删除、放置
访问控制允许标头: 内容类型、api_key、授权
x-expires-after: 2024 年 4 月 26 日星期五 18:15:41 UTC
x-rate-limit: 5000

{"code":200,"type":"unknown","message":"已登录用户会话:1714151741883"}



5. 身份验证和无效授权:


$ curl -w '\n' -ki https://apigw.nginx.lab/petstore/user/login -H "授权: Bearer `cat jwt.guest`"
HTTP/2 403
日期: 2024 年 4 月 26 日星期五 17:16:07 GMT
内容类型:text/html
内容长度: 153
<html>
<head><title>403 禁止</title></head>
<body>
<center><h1>403 禁止</h1></center>
<hr><center>nginx/1.25.3</center>
</body>
</html>


6. NGINX App Protect WAF 和跨站点脚本安全违规:


$ curl -w'\n'-ki“https://apigw.nginx.lab/petstore/store/inventory?
“
HTTP/2 200 内容类型:text/html;字符集=utf-8 缓存控制:无缓存指令:无缓存内容长度: 246
<html><head><title>请求被拒绝</title></head><body>请求的 URL 被拒绝。 请咨询您的管理员。您的支持 ID 是: 7283327928460093545[返回]

7. 可以通过以下方式访问开发者门户:


https://apigw.nginx.lab/petstore/petstore-devportal.html


立即开始

要试用本文讨论的 NGINX 解决方案,请立即开始 30 天免费试用,或联系我们讨论您的用例:

下载NGINX Agent – 它是免费且开源的。


“这篇博文可能引用了不再可用和/或不再支持的产品。 有关 F5 NGINX 产品和解决方案的最新信息,请探索我们的NGINX 产品系列。 NGINX 现在是 F5 的一部分。 所有之前的 NGINX.com 链接都将重定向至 F5.com 上的类似 NGINX 内容。”