场景
微服务API接口认证的方式有很多,Kong官网关于上游API认证的插件只有一个Upstream HTTP Basic Authentication,是基于基本的用户名和密码认证的。其它的都是前端认证认证插件。如果后端微服务API采用的是HMAC-SHA256
签名认证,就接入不了了,怎么办?首先Google了一番,没有找到此类插件。那么问题来了,如果要用这种认证方式接入Kong,那么就要自己写插件造轮子了。
相关知识
先看看Lua的基本语法,由于是菜鸟,就去看了Lua 菜鸟教程。
再熟悉学习了Kong的插件大致怎么写,大概看了以下文章:
kong插件官方文档翻译
API网关Kong学习笔记(十一):自己动手写一个插件
Kong Api网关简介(二) 插件
kong 网关插件快速开发指南
好了,看过这几篇文章后,大概了解了Kong的插件是一个怎样的套路了。
还需要了解ngx模块里面的var、ctx、req
等内置变量和方法。
签名认证过程
API的签名认证用的是Python的httpsig
模块,签名算法采用HMAC-SHA256
。由于是相对于后端来说,Kong的转发相当于客户端请求,要完成这个插件就需要了解HMAC-SHA256
签名的详细认证过程。
通过阅读和调试httpsig
模块相关代码,签名的过程是以下这样的:
客户端获取自己的公私钥对
1 | local key = conf.key |
计算加密消息
加密的消息一般采用当前时间date
1 | local date = os.date("%Y-%m-%d %H:%M:%S", os.time()) |
加密
将自己的密钥和加密消息,用HMAC-SHA256
算法进行签名。
1 | local signature_salt = string.format("date: %s", date) |
组装和注入
将date
,x-api-key
,authorization
三个值注入到HTTP头字段HTTP header fields
。其中authorization
字段格式有一定的要求,必须包含公钥Signature keyId
、签名算法algorithm
、签名signature
,类似这样的字符串
1 | 'authorization': u'Signature keyId="d1eaffbcb543r357",algorithm="hmac-sha256",signature="pp18H0zla/kvKZP/jAKCTkgqiVO92RRAqTsybZJao/o="' |
组装authorization
字段,signature
的值需要对原始签名的二进制数据进行Base64编码。
1 | local authorization = string.format('Signature keyId="%s",algorithm="hmac-sha256",signature="%s"', key, ngx.encode_base64(signature)) |
用ngx.req.set_header
注入相应值。其中的date
字段值是签名时用的加密消息,x-api-key
是自己的公钥。
1 | req_set_header("date", date) |
最后得到的HTTP头字段类似这样
1 | { |
认证
后端微服务拿到公钥、加密消息、签名算法后,先查询公钥对应的私钥,在用一样的签名算法,计算私钥和加密消息,如果得到的结果一样,那么就认证成功,如果不一样那么就认证失败,返回相应错误。
代码
插件的核心代码handler.lua
,目前只支持HMAC-SHA256
签名认证,自己动手改一改就可以支持其它签名认证了。
1 | local BasePlugin = require "kong.plugins.base_plugin" |
插件GitHub开源地址kong-plugin-upstream-auth-signature