istio中基于JWT(json web token)实战
本文主要介绍如何在istio中,通过使用jwt为应用进行授权,实现权限访问。本文实战代码环境:k8s(1.19)+istio(1.8.0)+python(3.7)/js(node v10.24.0)实战内容:用户调用接口生成jwk(代码实战),调用接口生成token(代码实战),并通过token访问应用。1、什么是JWK,JWKS,JWT?jwt:json web token,访问网站或请求时,用
本文主要介绍如何在istio中,通过使用jwt为应用进行授权,实现权限访问。
本文实战代码环境:k8s(1.19)+istio(1.8.0)+python(3.7)/js(node v10.24.0)
实战内容:用户调用接口生成jwk(代码实战),调用接口生成token(代码实战),并通过token访问应用。
1、什么是JWK,JWKS,JWT?
jwt:json web token,访问网站或请求时,用来证明自己身份的一种凭证。
jwk:json web key,注意这个key,可以理解为一把钥匙,实际上就是去验证jwt的东西。
jwks:json web token key set ,不难理解,JWKS 描述一组 JWK 密钥
所以,Istio 使用 JWK 描述验证 JWT 签名所需要的信息。在使用 RSA 签名算法时,JWK 描述的应该是用于验证的 RSA 公钥。
2、怎么验证各方身份?
一个通常你看到的jwt,由以下三部分组成,它们分别是:
header:主要声明了JWT的签名算法;
payload:主要承载了各种声明并传递明文数据;
signture:拥有该部分的JWT被称为JWS,也就是签了名的JWS;没有该部分的JWT被称为nonsecure JWT也就是不安全的JWT,此时header中声明的签名算法为none。
三个部分用 英文句点分割,可以使用shell 命令
cut -d . -f 1 |base64 -d
直接查看里面的内容。
istio中,除了jws的验证之外,更关键的地方在于不仅要验证签名,还要验证你的iss和sub,而什么是iss和sub?
iss 【issuer】发布者的url地址
sub 【subject】该JWT所面向的用户,用于处理特定应用
aud 【audience】接受者的url地址
exp 【expiration】 该jwt销毁的时间;unix时间戳
nbf 【not before】 该jwt的使用时间不能早于该时间;unix时间戳
iat 【issued at】 该jwt的发布时间;unix 时间戳
jti 【JWT ID】 该jwt的唯一ID编号
所以,Istio 在接收到用户的请求jwt后,根据header获取你的加密算法,然后解析你的payload,根据你提供的签名,对token进行验证。验证时,在签名正确的基础上,会去判断你的应用的发布者、使用者是否与应用token中所携带的一致,不一致时,则拒绝用户请求。
3、实战
具体的流程大致如下:
其中包含了几个环节:istio鉴权请求发布、istio鉴权策略发布、jwk生成、jwt生成、用户请求。我们将根据涉及到的环节来逐步介绍。
(1)istio鉴权请求发布
istio中,如果使用jwt鉴权,需要完成两步,第一步便是配置RequestAuthentication,具体官方文档可参考:https://istio.io/latest/docs/tasks/security/authorization/authz-jwt/
本案例中,istio的RequestAuthentication的配置如下:
apiVersion: security.istio.io/v1beta1
kind: RequestAuthentication
metadata:
name: sklearn-jwt-example
namespace: test
spec:
jwtRules:
- issuer: testing@istio.io
jwksUri: https://raw.githubusercontent.com/istio/istio/release-1.8/security/tools/jwt/samples/jwks.json
具体来说:在test的ns中的所有istio sidecar,凡是token发布者为testing@istio.io的鉴权都生效,同时需要去请求jwkuri获取jwk内容,而这里获取的jwk则是前面所说到用来验证签名的内容,但实际上,jwksURL这个请求访问起来有困难,容易到时后期鉴权时出现jwt认证出现失败的情况,所以这就为jwk的生成提供了进一步的需求。
(2)jwk生成
要生成 JWK 公钥,需要先生成私钥,下面是一个简单的生成命令。
openssl genrsa -out key.pem 2048
生成的key.pem只是私钥,不能用,且需要转换为jwk(公钥的另一种表达方式)格式,这里介绍两种,python:
# 需要先安装依赖: pip install jwcrypto
from jwcrypto.jwk import JWK
from pathlib import Path
private_key = Path("key.pem").read_bytes()
jwk = JWK.from_pem(private_key)
# 导出公钥 RSA Public Key
public_key = jwk.public().export_to_pem()
print(public_key)
print("="*30)
# 导出 JWK
jwk_bytes = jwk.public().export()
print(jwk_bytes)
javascript:
const fs = require('fs');
const jose = require('jose');#需要安装jose ,版本为2.0.2 yarn add jose@2.0.2
const privateKey = fs.readFileSync('key.pem');
const privateJwk = jose.JWK.asKey(privateKey).toJWK();
console.log(privateJwk)
之后,便可以通过express或者flask等框架,快速发布的到服务器中,这样就实现了jwk的生成
(3)istio鉴权策略发布
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
name: require-jwt
namespace: test
spec:
selector:
matchLabels:
abc: bcd
action: ALLOW
rules:
- from:
- source:
requestPrincipals: ["testing@istio.io/appID"]
这里面,有几个需要注意的点,matchlabel是为了能够将你的策略配置到对应istio应用上,使得整个策略生效,而requestPrincipals这表示,你这个策略的令牌对应的istio应用是由testing@istio.io颁发给appID(这个很重要)的。到此为止,我们似乎就在k8s中,配置好了istio中所需要的一切,现在就是如何访问了。
(4)jwt生成
访问时,需要携带jwt,所以,如何生成jwt,成为关键。给出python和js的代码如下:
python:https://github.com/istio/istio/blob/release-1.8/security/tools/jwt/samples/gen-jwt.py
python可以参考这个istio官方代码,就不贴出来了
js:
const jwt = require('jsonwebtoken');
const fs = require('fs');
const privateKey = fs.readFileSync('key.pem');
const token = jwt.sign(
{ "userinfo":"用户自定义" },
privateKey,
{
algorithm: 'RS256',
expiresIn: '8760h', // 1 years
issuer: 'testing@istio.io',
subject: "appID",
},
);
console.log(token)
代码中,可以看到对issuer和subject做了定义,这也就是和istio的yaml中对应上了。需要说明的是,用户自定义内容在JWT中,不应该在载荷里面加入任何敏感的数据。像密码这样的内容就不能被放在JWT中了。如果将用户的密码放在了JWT中,那么怀有恶意的第三方通过Base64解码就能很快地知道你的密码了。
(5)用户请求
激动人心的一步,你只需要拿着你的token就可以发送请求访问请求了,具体方法,在postman中,可在header中添加autority信息,或者在authorization中添加bearer token即可。
更多推荐
所有评论(0)