分布式架构-可靠通讯-服务安全

news2024/10/7 18:24:17

系列目录

分布式架构-可靠通讯-零信任网络

分布式架构-可靠通讯-服务安全

引子

上一节“分布式架构-可靠通讯-零信任网络”里,我们探讨了与微服务运作特点相适应的零信任安全模型。本节,我们将从实践和编码的角度出发,介绍在前微服务时代(以 Spring Cloud 为例)云原生时代(以 Istio over Kubernetes 为例)分别是如何实现安全传输、认证和授权的,通过这两者的对比,探讨在微服务架构下,应如何将业界的安全技术标准引入并实际落地,实现零信任网络下安全的服务访问。

注:本节内容快速看完即可。关注核心思路即可。主要看云原生Istio为例,是如何实现服务安全校验的。

一、建立信任

零信任网络里不存在默认的信任关系,一切服务调用、资源访问成功与否,均需以调用者与提供者间已建立的信任关系为前提。目前通用方案就是使用PKI:公开密钥基础设施(Public Key Infrastructure),基本结构如下图:

PKI基本结构由证书认证机构(certificate authority, CA)、证书持有者(certificate holder)、依赖方(relying party)三方构成:

  • 1.CA是一个独立的可信第三方,为证书持有者签发数字证书,数字证书中声明了证书持有者的身份和公钥。CA在签发证书前应对证书持有者的身份信息进行核实验证,并根据其核验结果为其签发证书。
  • 2.证书持有者向CA申请数字证书,并向CA提供必要的信息以证明其身份及能力,获得由CA签发的证书;证书持有者在与依赖方进行交互时,需向依赖方提供由CA签发的数字证书证明其有效身份。
  • 3.依赖方是证书的验证方,依赖方与证书持有者进行交互(如建立通信连接)时,需获取证书持有者的数字证书,验证数字证书的真实性和有效性。依赖方可以指定其信任的CA列表,若证书持有者提供的数字证书不是受信CA签发的数字证书,依赖方将不认可该证书所声明的信息。

       PKI 是构建传输安全层(Transport Layer Security,TLS)的必要基础。在任何网络设施都不可信任的假设前提下,无论是 DNS 服务器、代理服务器、负载均衡器还是路由器,传输路径上的每一个节点都有可能监听或者篡改通信双方传输的信息。要保证通信过程不受到中间人攻击的威胁,启用 TLS 对传输通道本身进行加密,让发送者发出的内容只有接受者可以解密是唯一具备可行性的方案。除了随服务节点动态扩缩而来的运维压力外,比起公众互联网中主流单向的 TLS 认证,在零信任网络中,往往要启用双向 TLS 认证(Mutual TLS Authentication,常简写为 mTLS),即不仅要确认服务端的身份,还需要确认调用者的身份。

  • 单向 TLS 认证:只需要服务端提供证书,客户端通过服务端证书验证服务器的身份,但服务器并不验证客户端的身份。单向 TLS 用于公开的服务,即任何客户端都被允许连接到服务进行访问,它保护客户端免遭冒牌服务器的欺骗

  • 双向 TLS 认证:客户端、服务端双方都要提供证书,双方各自通过对方提供的证书来验证对方的身份。双向 TLS 用于私密的服务,即服务只允许特定身份的客户端访问,它除了保护客户端不连接到冒牌服务器外,也保护服务端不遭到非法用户的越权访问

对于以上提到的围绕 TLS 而展开的密钥生成、证书分发、签名请求(Certificate Signing Request,CSR)、更新轮换等是一套操作起来非常繁琐的流程,稍有疏忽就会产生安全漏洞,所以尽管理论上可行,但实践中如果没有自动化的基础设施的支持,仅靠应用程序和运维人员的努力,是很难成功实施零信任安全模型的。下面我们聚焦于“认证”和“授权”两个最基本的安全需求,看它们在微服务架构下,有或者没有基础设施支持时,各是如何实现的。

二、认证

根据认证的目标对象可以把认证分为两种类型:

服务认证:以机器作为认证对象,即访问服务的流量来源是另外一个服务,称为服务认证(Peer Authentication,直译过来是“节点认证”)。

请求认证:以人类作为认证对象,即访问服务的流量来自于最终用户,称为请求认证(Request Authentication)。

2.1 服务认证

2.1.1 云原生架构Istio-服务认证

如果每一个服务提供者、调用者均受 Istio 管理,那 mTLS 就是最理想的认证方案。你只需要参考以下简单的 PeerAuthentication CRD配置,即可对某个Kubernetes 名称空间范围内所有的流量均启用 mTLS:

apiVersion: security.istio.io/v1beta1
kind: PeerAuthentication
metadata:
  name: authentication-mtls
  namespace: bookstore-servicemesh
spec:
  mtls:
    mode: STRICT

如果你的分布式系统还没有达到完全云原生的程度,其中仍存在部分不受 Istio 管理(即未注入 Sidecar)的服务端或者客户端(这是颇为常见的),你也可以将 mTLS 传输声明为“宽容模式”(Permissive Mode)。宽容模式为普通微服务向服务网格迁移提供了良好的灵活性。

2.1.2 Spring Cloud非云原生-服务认证

举例使用OAtuh2 协议的客户端模式。

  • 客户端:提前配置好客户端密钥,客户端调用服务时,会先使用该密钥向认证服务器申请到 JWT 令牌,然后通过令牌证明自己的身份,最后访问服务。
/**
 * 客户端列表
 */
private static final List<Client> clients = Arrays.asList(
    new Client("bookstore_frontend", "bookstore_secret", new String[]{GrantType.PASSWORD, GrantType.REFRESH_TOKEN}, new String[]{Scope.BROWSER}),
    // 微服务一共有Security微服务、Account微服务、Warehouse微服务、Payment微服务四个客户端
    // 如果正式使用,这部分信息应该做成可以配置的,以便快速增加微服务的类型。clientSecret也不应该出现在源码中,应由外部配置传入
    new Client("account", "account_secret", new String[]{GrantType.CLIENT_CREDENTIALS}, new String[]{Scope.SERVICE}),
    new Client("warehouse", "warehouse_secret", new String[]{GrantType.CLIENT_CREDENTIALS}, new String[]{Scope.SERVICE}),
    new Client("payment", "payment_secret", new String[]{GrantType.CLIENT_CREDENTIALS}, new String[]{Scope.SERVICE}),
    new Client("security", "security_secret", new String[]{GrantType.CLIENT_CREDENTIALS}, new String[]{Scope.SERVICE})
);
  • 每一个对外提供服务的服务端,都扮演着 OAuth 2 中的资源服务器的角色,它们均声明为要求提供客户端模式的凭证,如以下代码所示。客户端要调用受保护的服务,就必须先出示能证明调用者身份的 JWT 令牌,否则就会遭到拒绝,这个操作本质上是授权,但是在授权过程中已实现了服务的身份认证。
public ClientCredentialsResourceDetails clientCredentialsResourceDetails() {
    return new ClientCredentialsResourceDetails();
}

由于每一个微服务都同时具有服务端和客户端两种身份,既消费其他服务,也提供服务供别人消费,所以这些代码在每个微服务中都应有包含(放在公共 infrastructure 工程里)。Spring Security 提供的过滤器会自动拦截请求、驱动认证、授权检查的执行,申请和验证 JWT 令牌等操作无论在开发期对程序员,还是运行期对用户都能做到相对透明。尽管如此,以上做法仍然是一种应用层面的、不加密传输的解决方案。这种方案不适用于零信任安全模型,只能在默认内网节点间具备信任关系的边界安全模型上才能良好工作。

2.2 用户认证

2.2.1 云原生架构Istio-用户认证

当来自最终用户的请求进入服务网格时,Istio 会自动根据配置中的JWKS(JSON Web Key Set)来验证令牌的合法性,如果令牌没有被篡改过且在有效期内,就信任 Payload 中的用户身份,并从令牌的 Iss 字段中获得 Principal。以下是 Istio 用户认证配置,其中jwks字段配的就是 JWKS 全文(实际生产中并不推荐这样做,应该使用jwksUri来配置一个 JWKS 地址,以方便密钥轮换),根据这里配置的密钥信息,Istio 就能够验证请求中附带的 JWT 是否合法。

apiVersion: security.istio.io/v1beta1
kind: RequestAuthentication
metadata:
  name: authentication-jwt-token
  namespace: bookstore-servicemesh
spec:
  jwtRules:
    - issuer: "icyfenix@gmail.com"
      # Envoy默认只认“Bearer”作为JWT前缀,之前其他地方用的都是小写,这里专门兼容一下
      fromHeaders:
        - name: Authorization
          prefix: "bearer "
      # 在rsa-key目录下放了用来生成这个JWKS的证书,最初是用java keytool生成的jks格式,一般转jwks都是用pkcs12或者pem格式,为方便使用也一起附带了
      jwks: |
        {
            "keys": [
                {
                    "e": "AQAB",
                    "kid": "bookstore-jwt-kid",
                    "kty": "RSA",
                    "n": "i-htQPOTvNMccJjOkCAzd3YlqBElURzkaeRLDoJYskyU59JdGO-p_q4JEH0DZOM2BbonGI4lIHFkiZLO4IBBZ5j2P7U6QYURt6-AyjS6RGw9v_wFdIRlyBI9D3EO7u8rCA4RktBLPavfEc5BwYX2Vb9wX6N63tV48cP1CoGU0GtIq9HTqbEQs5KVmme5n4XOuzxQ6B2AGaPBJgdq_K0ZWDkXiqPz6921X3oiNYPCQ22bvFxb4yFX8ZfbxeYc-1rN7PaUsK009qOx-qRenHpWgPVfagMbNYkm0TOHNOWXqukxE-soCDI_Nc--1khWCmQ9E2B82ap7IXsVBAnBIaV9WQ"
                }
            ]
        }
      forwardOriginalToken: true

2.2.2 Spring Cloud非云原生-用户认证

Spring Cloud,采用 JWT 令牌+在Spring Security过滤器实现。Spring Security 已经做好了认证所需的绝大部分的工作,真正要开发者去编写的代码是令牌的具体实现,即代码中名为RSA256PublicJWTAccessToken的实现类。它的作用是加载 Resource 目录下的公钥证书public.cert(实在是怕“抄作业不改名字”的行为,笔者再一次强调不要将密码、密钥、证书这类敏感信息打包到程序中,示例代码只是为了演示,实际生产应该由运维人员管理密钥),验证请求中的 JWT 令牌是否合法。

@Named
public class RSA256PublicJWTAccessToken extends JWTAccessToken {
    RSA256PublicJWTAccessToken(UserDetailsService userDetailsService) throws IOException {
        super(userDetailsService);
        Resource resource = new ClassPathResource("public.cert");
        String publicKey = new String(FileCopyUtils.copyToByteArray(resource.getInputStream()));
        setVerifierKey(publicKey);
    }
}

如果 JWT 令牌合法,Spring Security 的过滤器就会放行调用请求,并从令牌中提取出 Principals,放到自己的安全上下文中。(即SecurityContextHolder.getContext())。

三、授权

 经过认证之后,合法的调用者就有了可信任的身份,此时就已经不再需要区分调用者到底是机器(服务)还是人类(最终用户)了,只根据其身份角色来进行权限访问控制,即我们常说的 RBAC(Role-Based Access Control )。举个具体例子,如果我们准备把一部分微服务视为私有服务,限制它只接受来自集群内部其他服务的请求,另外一部分微服务视为公共服务,允许它可接受来自集群外部的最终用户发出的请求;

2.3.1云原生架构Istio-授权

通过以下配置,限制了来自bookstore-servicemesh名空间的内部流量只允许访问accountsproductspaysettlements四个端点的 GET、POST、PUT、PATCH 方法,而对于来自istio-system名空间(Istio Ingress Gateway 所在的名空间)的外部流量就不作限制,直接放行。

apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
  name: authorization-peer
  namespace: bookstore-servicemesh
spec:
  action: ALLOW
  rules:
    - from:
        - source:
            namespaces: ["bookstore-servicemesh"]
      to:
        - operation:
            paths:
              - /restful/accounts/*
              - /restful/products*
              - /restful/pay/*
              - /restful/settlements*
            methods: ["GET","POST","PUT","PATCH"]
    - from:
        - source:
            namespaces: ["istio-system"]

Istio 已经提供了比较完善的目标匹配工具,如上面配置中用到的源from、目标to,还有未用到的条件匹配when,以及其他如通配符、IP、端口、名空间、JWT 字段,等等。要说灵活和功能强大,肯定还是不可能跟在应用中由代码实现的授权相媲美,但对绝大多数场景已经够用了。在便捷性、安全性、无侵入、统一管理等方面,Istio 这种在基础设施上实现授权方案显然就要更具优势。

2.3.1非云原生架构SpringCloud-授权

常见的 Spring Security 授权方法有两种,

  • 1.代码配置:一种是使用它的ExpressionUrlAuthorizationConfigurer,即类似如下编码所示的写法来进行集中配置,也是 Spring Security 资料中都有介绍的最主流方式,适合对批量端点进行控制。
http.authorizeRequests()
    .antMatchers("/restful/accounts/**").hasScope(Scope.BROWSER)
    .antMatchers("/restful/pay/**").hasScope(Scope.SERVICE)
  • 2.注解标识:Spring 的全局方法级安全(Global Method Security)以及JSR 250的@RolesAllowed注解来做授权控制。这种写法对代码的侵入性更强,要以注解的形式分散写到每个服务甚至是每个方法中,但好处是能以更方便的形式做出更加精细的控制效果。譬如要控制服务中某个方法只允许来自服务或者来自浏览器的调用,那直接在该方法上标注@PreAuthorize注解即可,还支持SpEL 表达式来做条件。表达式中用到的SERVICEBROWSER代表授权范围,就是在声明客户端列表时传入的,具体可参见开头声明客户端列表的代码清单。
/**
 * 根据用户名称获取用户详情
 */
@GET
@Path("/{username}")
@Cacheable(key = "#username")
@PreAuthorize("#oauth2.hasAnyScope('SERVICE','BROWSER')")
public Account getUser(@PathParam("username") String username) {
    return service.findAccountByUsername(username);
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/403476.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Lambda表达式与函数式接口

目录 自定义函数式接口 常用的内置函数式接口 1.Supplier接口 2.Consumer接口 3.Predicate接口 4.Function接口 自定义函数式接口 需求&#xff1a;实现两数的加减乘除 接口&#xff0c;函数式接口只能有一个抽象方法&#xff0c;且需要用注释FunctionInterface。 Func…

JUC高级一: CompletableFuture

JUC高级: CompletableFuture 1. 线程基础知识复习 1.1 JUC四大口诀 高内聚低耦合前提下&#xff0c;封装思想 线程—>操作---->资源类 判断、干活、通知 防止虚假唤醒,wait方法要注意使用while判断 注意标志位flag&#xff0c;可能是volatile的 1.2 为什么多线程及…

Webpack打包———处理样式资源

基本使用 本质上&#xff0c;webpack 是一个用于现代 JavaScript 应用程序的 静态模块打包工具。当 webpack 处理应用程序时&#xff0c;它会在内部从一个或多个入口点构建一个 依赖图(dependency graph)&#xff0c;然后将你项目中所需的每一个模块组合成一个或多个 bundles&a…

2.JVM常识之 jvm常见配置参数

1.常见的配置参数说明 常见配置 -Xms3072M -Xmx3072M -Xss1M -Xmn2048M -XX:MetaspaceSize256M -XX:MaxMetaspaceSize256M -XX:SurvivorRatio8 **-Xss&#xff1a;**每个线程的栈内存大小 默认是1M 说明一个线程栈里能分配的栈帧越少&#xff0c;但是对JVM整体来说能开启…

文档团队怎样使用GIT做版本管理

有不少小型文档团队想转结构化写作和发布&#xff0c;但是因为有限的IT技能和IT资源而受阻。本文为这样的小型文档团队而准备&#xff0c;描述怎样使用Git做内容的版本管理。 - 1 - 为什么需要版本管理 当一个团队进行协同创作内容时&#xff0c;有以下需要&#xff1a; 在对…

【C++】图

本文包含了图的基本概念 1.相关概念 1.1 无/有向 无向图&#xff1a;每一个顶点之间的连线没有方向 有向图&#xff1a;连线有方向&#xff08;类似离散数学的二元关系 <A,B>代表从A到B的边&#xff0c;有方向&#xff09; <A,B>中A为始点&#xff0c;B为终点在…

JDBC的API详解

&#x1f34e;道阻且长&#xff0c;行则将至。&#x1f353; 目录 一、DriverManager 驱动管理类 1.注册驱动 2.获取数据库连接 二、Connection 数据库连接对象 1.获取执行对象 2.事务管理 三、Statement 1.执行DDL、DML语句 2.执行DQL语句 四、ResultSet 以JDBC快速…

【漏洞复现】Grafana任意文件读取(CVE-2021-43798)

docker环境搭建 #进入环境 cd vulhub/grafana/CVE-2021-43798#启动环境&#xff0c;这个过程可能会有点慢&#xff0c;保持网络通畅 docker-compose up -d#查看环境 docker-compose ps直接访问虚拟机 IP地址:3000 目录遍历原理 目录遍历原理&#xff1a;攻击者可以通过将包含…

CNCF x Alibaba云原生技术公开课 第七章 应用编排与管理:Job和DaemonSet

1、Job&#xff1a;管理任务的控制器 概念 首先 kubernetes 的 Job 是一个管理任务的控制器&#xff0c;它可以创建一个或多个 Pod 来指定 Pod 的数量&#xff0c;并可以监控它是否成功地运行或终止&#xff1b;可以根据 Pod 的状态来给 Job 设置重置的方式及重试的次数&…

【Qt网络编程】实现TCP协议通信

文章目录概要&#xff1a;本期主要讲解QT中对于TCP协议通信的实现。一、TCP协议二、Qt中TCP协议处理1.QTcpSocket2.QTcpServer三、Qt实现TCP通信1.客户端2.服务器端结尾概要&#xff1a;本期主要讲解QT中对于TCP协议通信的实现。 一、TCP协议 传输控制协议&#xff08;TCP&am…

有哪些值得推荐的办公软件下载网站

新买了电脑之后&#xff0c;我们需要安装一些常用的办公软件才能方便我们的办公使用。很多小白不知道在哪里下载办公软件比较好&#xff0c;下面小编就来为大家分享几个值得推荐的办公软件下载网站。 1.常用软件下载 对于常用软件如果我们通过百度搜索&#xff0c;能够辨别官方…

【2】Dijkstra与SPFA等常见最短路算法的分析与比较——Bellman-Ford与SPFA

合集目录&#xff1a; 前言 一、Dijkstra 二、Bellman-Ford与SPFA&#xff08;本文&#xff09; 三、Dijkstra与SPFA的比较 四、Floyd 五、启发式搜索 Bellman-Ford 1. 算法介绍 The algorithm was first proposed by Alfonso Shimbel (1955), but is instead named af…

哪个牌子的洗地机耐用?耐用的洗地机推荐

作为当下非常热销的洗地机&#xff0c;它不仅解放了双手&#xff0c;使用也非常的便捷。是生活品质提高的最好代表&#xff0c;但是面对市面上让人眼花缭乱的洗地机&#xff0c;挑选几个来回都决定不了到底入手哪个好&#xff01;为了能帮助大家选购到合适的洗地机&#xff0c;…

gcc 编译的过程

#include <stdio.h> #define PI 3.14 int main(int argc, char const *argv[]) { //打印IP的值printf("PI %lf\n", PI);return 0; }编译的过程&#xff1a;预处理、编译、汇编、链接1.预处理&#xff1a;宏替换、删除注释、头文件包含、条件编译 -E &#xf…

问心 | 再看token、session和cookie

什么是cookie HTTP Cookie&#xff08;也叫 Web Cookie或浏览器 Cookie&#xff09;是服务器发送到用户浏览器并保存在本地的一小块数据&#xff0c;它会在浏览器下次向同一服务器再发起请求时被携带并发送到服务器上。 什么是session Session 代表着服务器和客户端一次会话…

Paddle项目调试记录

PaddlePaddle是百度公司提出的深度学习框架。近年来深度学习在很多机器学习领域都有着非常出色的表现&#xff0c;在图像识别、语音识别、自然语言处理、机器人、网络广告投放、医学自动诊断和金融等领域有着广泛应用。面对繁多的应用场景&#xff0c;深度学习框架有助于建模者…

MyBatis-Plus(狂神)

一.特点 无侵入&#xff1a;只做增强不做改变&#xff0c;引入它不会对现有工程产生影响&#xff0c;如丝般顺滑损耗小&#xff1a;启动即会自动注入基本 CURD&#xff0c;性能基本无损耗&#xff0c;直接面向对象操作强大的 CRUD 操作&#xff1a;内置通用 Mapper、通用 Serv…

GDB调试快速入门

什么是GDB&#xff1a; GDB - - - (GNU symbolic debugger)是Linux平台下最常用的一款程序调试器。 自己的Linux是否安装GDB? 一般来说&#xff0c;使用Ubuntu的话&#xff0c;系统就会自带的有GDB调试器的 命令窗口输入如下命令可以查看是否安装了gdb&#xff1a; gdb -v …

制作一个简单的信用卡验证表

下载:https://download.csdn.net/download/mo3408/87559584 效果图: 您可以从文章顶部附近的下载按钮获取该项目的完整代码。这些文件的概述如下所示: 我们需要将两个 .css 文件和两个 .js 文件包含在我们的 HTML 中。所有其他资源,例如 Bootstrap 框架、jQuery 和 Web 字…

SecureCRT 安装并绑定ENSP设备终端

软件下载链接链接&#xff1a;https://pan.baidu.com/s/1WFxmQgaO9bIiUTwBLSR4OA?pwd2023 提取码&#xff1a;2023 CRT安装&#xff1a;软件可以从上面链接进行下载&#xff0c;下载完成后解压如下&#xff1a;首先双击运行scrt-x64.8.5.4 软件&#xff0c;进行安装点击NEXT选…