Spring Boot 接入 KMS 托管中间件密码第三方接口密钥

news2024/11/16 4:40:10

1. 需求

Nacos中关于中间件的密码,还有第三方API的密钥等信息,都是明文存储,不符合系统安全要求。现需对这些信息进行加密处理,Nacos只存储密文,并在服务启动时,调用云厂商的KMS接口进行解密,将解密后的明文存储在内存中供服务后续使用。

2. 组件调研&增强

2.1. jasypt 组件

业界上已有jasypt组件可以很好地支持对配置文件中的敏感信息进行解密处理,并完全支持 Spring Boot 架构。但是唯一的缺点是,该组件默认仅支持一些核心的静态加解密算法,无法支持接入第三方KMS;并且,仅支持对一个完整配置项的解密处理,不支持对配置项中某段字符串进行解密操作。因此,不能直接使用在我们已有的服务上。

2.2. 增强

我们需对上述组件进行增强,主要是以下两点:

  1. 配置项部分解密:支持解密配置项中指定的某段字符串,使用ENC()CNE括住
  2. 第三方KMS解密:支持接入第三方KMS接口,对密文进行解密操作,支持将明文托管在KMS中(这里使用的是腾讯云的KMS)

我们不但要对jasypt组件进行增强,同时也需在此基础上再封装一个组件,用于整个平台的服务使用,避免冗余代码。

2.2.1. 引入相关依赖

核心是引入jasypt的 Spring Boot 组件,以及KMS(如腾讯云)组件:

<dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter</artifactId>
      <scope>provided</scope>
  </dependency>
  <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-web</artifactId>
      <scope>provided</scope>
  </dependency>
  <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-configuration-processor</artifactId>
      <optional>true</optional>
  </dependency>
  <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-autoconfigure</artifactId>
  </dependency>
  <dependency>
      <groupId>org.projectlombok</groupId>
      <artifactId>lombok</artifactId>
  </dependency>
  <dependency>
      <groupId>com.github.ulisesbocchio</groupId>
      <artifactId>jasypt-spring-boot</artifactId>
      <version>3.0.3</version>
  </dependency>
  <dependency>
      <groupId>com.tencentcloudapi</groupId>
      <artifactId>tencentcloud-sdk-java</artifactId>
      <version>3.1.927</version>
  </dependency>
  <dependency>
      <groupId>commons-codec</groupId>
      <artifactId>commons-codec</artifactId>
      <version>1.16.0</version>
  </dependency>

2.2.2. 启动配置解密注解

此注解作为服务引入KMS加密的钥匙,加了才会启动KMS解密功能:

/**
 * 开启kms配置密文解密
 * @author winfun
 * @since 2023-12-18
 **/
@Inherited
@Component
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Import({KmsConfig.class})
@EnableEncryptableProperties
public @interface EnableKmsPropertiesDecryption {
}

2.2.3. Kms配置类

主要包含上面提到的增强点:

  1. 增强Detector:用于识别ENC()CNE括住的密文
  2. 增强Encryptor:用于调用KMS的解密接口,返回解密后的明文供服务使用

需要注意的是,默认启用增强代码,如果我们需要临时关闭,可将配置项kms.enabled设置为false

/**
 * kms自动配置
 * @author howinfun
 * @since 2023/12/15
 */
@Slf4j
@Configuration
@EnableConfigurationProperties({KmsProperties.class})
@AutoConfigureBefore(EnableEncryptablePropertiesConfiguration.class)
@ConditionalOnProperty(name = "kms.enabled",havingValue = "true",matchIfMissing = true)
public class KmsConfig {

    private static final String prefix = "ENC(";
    private static final String suffix = ")CNE";

    @Bean
    public KmsClient kmsClient(KmsProperties kmsProperties) {
        Assert.notNull(kmsProperties.getSecretId(), "SecretId can't be null");
        Assert.notNull(kmsProperties.getSecretKey(), "SecretKey can't be null");
        Assert.notNull(kmsProperties.getRegion(), "Region can't be null");
        Credential cred = new Credential(kmsProperties.getSecretId(),kmsProperties.getSecretKey());
        // 实例化要请求产品的client对象,clientProfile是可选的
        return new KmsClient(cred, kmsProperties.getRegion());
    }

    /**
     * 自定义Detector,支持文本中带加密内容
     * @return EncryptablePropertyDetector
     */
    @Bean("encryptablePropertyDetector")
    public EncryptablePropertyDetector encryptablePropertyDetector() {

        return new EncryptablePropertyDetector() {

            @Override
            public boolean isEncrypted(String property) {
                if (property == null) {
                    return false;
                } else {
                    String trimmedValue = property.trim();
                    boolean isEncrypted = trimmedValue.contains(prefix) && trimmedValue.contains(suffix);
                    log.debug("收到配置:{},是否需要解密:{}",property,isEncrypted);
                    return isEncrypted;
                }
            }

            @Override
            public String unwrapEncryptedValue(String property) {
                return property;
            }
        };
    }

    /**
     * 自定义Encryptor,支持kms解密
     * @return StringEncryptor
     */
    @Bean("jasyptStringEncryptor")
    public StringEncryptor jasyptStringEncryptor(KmsClient kmsClient) {

        return new StringEncryptor() {

            @Override
            public String encrypt(String message) {
                return message;
            }

            @Override
            public String decrypt(String encryptedMessage) {
                try {
                    String trim = encryptedMessage.trim();
                    String encryptedMsg = trim.substring((trim.indexOf(prefix) + prefix.length()), trim.indexOf(suffix));
                    String prefixMsg = "";
                    String suffixMsg = "";
                    if (!trim.startsWith(prefix) || !trim.endsWith(suffix)) {
                        prefixMsg = trim.substring(0, trim.indexOf(prefix));
                        suffixMsg = trim.substring(trim.indexOf(suffix) + suffix.length());
                    }
                    DecryptRequest req = new DecryptRequest();
                    req.setCiphertextBlob(encryptedMsg);
                    DecryptResponse resp = kmsClient.Decrypt(req);
                    String pass = new String(Base64.decodeBase64(resp.getPlaintext()));
                    log.debug("密码解密成功,待处理密文:{},明文:{}", trim, pass);
                    return prefixMsg + pass + suffixMsg;
                } catch (Exception e) {
                    log.error("密文解密失败", e);
                }
                return encryptedMessage;
            }
        };
    }
}

2.3.4. Kms配置类

因为调用 KMS 接口,也是需要sk相关信息,但是这里有一个要注意的点,不要写在Nacos等配置中心中,而是以环境变量注入较好。

/**
 * kms配置
 * @author winfun
 * @since 2023/12/18
 **/
@Data
@ConfigurationProperties(prefix = "kms")
public class KmsProperties {

    private String secretId;
    private String secretKey;
    private String region;
}

3. 打包组件&使用

我们根据上述代码,可以打包成一个 Spring Boot 的 starter,供后续的所有服务使用。
下面拿我自己本地的作为例子看看:
1、引入KMS组件依赖:
image.png
2、加入kms配置:
因为是本地启动调试,就直接先写在配置里头了
image.png
3、明文密码替换为密文,并用ENC()CNE括住
image.png
4、应用加入启动KMS解密注解:
image.png
5、服务启动成功
image.png

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

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

相关文章

【十九】【动态规划】518. 零钱兑换 II、279. 完全平方数、474. 一和零,三道题目深度解析

动态规划 动态规划就像是解决问题的一种策略&#xff0c;它可以帮助我们更高效地找到问题的解决方案。这个策略的核心思想就是将问题分解为一系列的小问题&#xff0c;并将每个小问题的解保存起来。这样&#xff0c;当我们需要解决原始问题的时候&#xff0c;我们就可以直接利…

LoRa网关在智能冷链物流中的应用解决方案

随着物联网技术的不断发展&#xff0c;智能冷链物流成为了物流行业的一个重要领域。在冷链物流中&#xff0c;对于货物的温度、湿度等环境变量的监测和控制非常关键&#xff0c;而这些数据的传输需要一个高效可靠的通信方式。LoRa技术作为一种低功耗广域网通信技术&#xff0c;…

详解java继承

目录 一 、为什么需要继承 二、准备工作&#xff1a;用java代码先定义狗类、猫类、动物类&#xff0c;这是代码准备如下 三、继承代码实现 四、 子类中访问父类的成员方法 4.1. 成员方法名字不同 4.2 成员方法名字相同 五、子类构造方法 扩展&#xff1a;如果你对子类和…

jvm虚拟机初识

JVM Java虚拟机就是二进制字节码的运行环境&#xff0c;负责装载字节码到其内部&#xff0c;解释/编译为对应平台上的机器指令执行。每一条Java指令&#xff0c;Java虚拟机规范中都有详细定义&#xff0c;如怎么取操作数&#xff0c;怎么处理操作数&#xff0c;处理结果放在哪…

什么是API网关代理?

带有API网关的代理服务显着增强了用户体验和性能。特别是对于那些使用需要频繁创建和轮换代理的工具的人来说&#xff0c;使用 API 可以节省大量时间并提高效率。 了解API API&#xff08;即应用程序编程接口&#xff09;充当服务提供商和用户之间的连接网关。通过 API 连接&a…

Python pip 常用指令

前言 Python的pip是一个强大的包管理工具&#xff0c;它可以帮助我们安装、升级和管理Python的第三方库。以下是一些常用的pip指令。 1. 安装第三方库 使用pip安装Python库非常简单&#xff0c;只需要使用pip install命令&#xff0c;后面跟上库的名字即可。 # 安装virtuale…

Java中的网络编程

文章目录 网络基础知识IP 地址端口协议 Java 中网络编程InetAddress&#xff08;静态类&#xff09;UDP 通信原理UDP 发送数据步骤UDP 接收数据步骤UDP 发送接收案例 TCP 通信原理TCP 发送数据步骤TCP 接收数据步骤TCP 发送接收案例 网络基础知识 概述&#xff1a;在网络通信协…

计算机组成原理19——控制单元的功能和实现1

本系列文章是学习了网课《哈尔滨工业大学–计算机组成原理》之后&#xff0c;用以梳理思路而整理的听课笔记及相关思维拓展。本文涉及到的观点均为个人观点&#xff0c;如有不同意见&#xff0c;欢迎在评论区讨论。 目录 四种周期下的微操作命令取指周期间址周期执行周期非访存…

antv/x6_2.0学习使用(四、边)

一、添加边 节点和边都有共同的基类 Cell&#xff0c;除了从 Cell 继承属性外&#xff0c;还支持以下选项。 属性名类型默认值描述sourceTerminalData-源节点或起始点targetTerminalData-目标节点或目标点verticesPoint.PointLike[]-路径点routerRouterData-路由connectorCon…

智慧旅游景区解决方案:PPT全文49页,附下载

关键词&#xff1a;智慧景区建设&#xff0c;智慧旅游平台&#xff0c;智慧旅游运营检测系统项目&#xff0c;智慧文旅&#xff0c;智慧景区开发与管理&#xff0c;智慧景区建设核心&#xff0c;智慧景区开发与管理 一、智慧景区建设现状 1、基础设施建设&#xff1a;智慧景区…

离散数学2

复习一下&#xff0c;P->Q,只有真的原因推假的结果&#xff0c;才是错的&#xff08;正常逻辑&#xff09;&#xff0c;其余情况都是对的&#xff08;善意规定以及正常逻辑&#xff09; 反P析取Q&#xff0c;可以这样理解&#xff0c;因为是析取&#xff0c;结果为T的可能性…

强化学习求解TSP:Qlearning求解旅行商问题(Traveling salesman problem, TSP)提供Python代码

一、Qlearning简介 Q-learning是一种强化学习算法&#xff0c;用于解决基于奖励的决策问题。它是一种无模型的学习方法&#xff0c;通过与环境的交互来学习最优策略。Q-learning的核心思想是通过学习一个Q值函数来指导决策&#xff0c;该函数表示在给定状态下采取某个动作所获…

Spark Core--加强

RDD的持久化 RDD缓存 当RDD被重复使用&#xff0c;或者计算该RDD比较容易出错&#xff0c;而且需要消耗比较多的资源和时间的时候&#xff0c;我们就可以将该RDD缓存起来。 主要作用: 提升Spark程序的计算效率 注意事项: RDD的缓存可以存储在内存或者是磁盘上&#xff0c;甚至…

为布偶猫精心挑选的三款主食冻干,K9、sc、希喂深度解析对比

喂养布偶猫的小技巧&#xff1a;如何满足其食肉天性同时呵护其肠胃&#xff1f;主食冻干是答案&#xff01;它不仅符合猫咪天然的饮食结构&#xff0c;还采用新鲜生肉为原料。搭配其他营养元素&#xff0c;既美味又营养&#xff0c;还能增强抵抗力。我们将为您测评市场上热门的…

ubuntu 20.04下 Tesla P100加速卡使用

1.系统环境&#xff1a;系统ubuntu 20.04, python 3.8 2.查看cuDNN/CUDA与tensorflow的版本关系如下&#xff1a; Build from source | TensorFlow 从上图可以看出&#xff0c;python3.8 对应的tensorflow/cuDNN/CUDA版本。 3.安装tensorflow #pip3 install tensorflow 新版…

C++其他语法总结

目录 《C基础语法总结》《C面向对象语法总结(一&#xff09;》《C面向对象语法总结(二&#xff09;》《C面向对象语法总结(三&#xff09;》 一、运算符重载 运算符重载可以为运算符增加一些新的功能全局函数、成员函数都支持运算符重载常用的运算符重载示例 class Point {…

Python私有变量的定义与访问

class Student():def __init__(self, name, age):self.name nameself.age ageself.__score 0def marking(self, score):if score < 0:return 分数不能为0self.__score scoreprint(self.name 同学本次得分是: str(self.__score)) def __talk(self): # 私有的类可通过在…

qss设置某一个widget下的Checkbox的样式

#ObjectName 控件名称{属性&#xff1a;值&#xff1b;属性1&#xff1a;值1} 如下&#xff1a; 效果&#xff1a;

【大数据】分布式协调系统 Zookeeper

分布式协调系统 Zookeeper 1.Zookeeper 的特点2.Zookeeper 的数据结构3.Zookeeper 的应用场景3.1 统一命名服务3.2 统一配置管理3.3 统一集群管理3.4 服务器动态上下线3.5 软负载均衡 Zookeeper 是 Apache 开源的一个顶级项目&#xff0c;目的是为分布式应用提供协调服务&#…

910b上跑Chatglm3-6b进行流式输出【pytorch框架】

文章目录 准备阶段避坑阶段添加代码结果展示 准备阶段 配套软件包Ascend-cann-toolkit和Ascend-cann-nnae适配昇腾的Pytorch适配昇腾的Torchvision Adapter下载ChatGLM3代码下载chatglm3-6b模型&#xff0c;或在modelscope里下载 避坑阶段 每个人的服务器都不一样&#xff0…