如何在Spring Boot中管理不同部署环境的多个.properties文件?

Dav*_*vid 2 java spring spring-boot

我有一个 Spring Boot 应用程序,在src/main/resources目录中有多个.properties文件,我正在使用下面通过代码给出的类似内容:

\n

@PropertySource(value = "classpath:properties/myfunctional.properties\xe2\x80\x9d)

\n

目前,我能够用它来完成我的工作,因为它是一个简单的功能。

\n

但问题是保留所有这些.properties文件src/main/resources并不是一个好主意,原因如下:

\n
    \n
  • 这些.properties文件将成为构建的一部分并打包到.jar文件中。
  • \n
  • 我想通过属性在代码库中存储诸如apikeytoken之类的敏感信息并不是一个好的做法。
  • \n
\n

所以,我对此有几个问题:

\n
    \n
  • 如何以及在何处将所有.properties文件移动到外部服务器?
  • \n
  • 如何在部署期间推出属性更改,因为这些值会根据开发测试阶段生产等环境而有所不同等环境而有所不同?
  • \n
\n

注意:我尝试过的技术很少有Spring Boot ConfigGit Secret Variable等。但我再次不确定这些技术的安全程度。

\n

因此,我正在寻找一个涵盖更广泛方面的答案。

\n

Ani*_* B. 8

您可以通过Spring Cloud Config ServerClient 来实现您的需求。

\n

请参阅此处的文档。

\n
\n

GitHub 方法:

\n

分步过程,其中Github存储库将充当包含机密/敏感数据的所有外部属性文件的源。

\n
    \n
  1. secrets-{env}.properties我已在我的 Github存储库上创建并托管了所有文件以进行测试和演示。
  2. \n
\n

在此输入图像描述

\n

秘密-dev.properties:

\n
secrets.api-key=<dev-api-key>\nsecrets.token=<dev-token>\n
Run Code Online (Sandbox Code Playgroud)\n

秘密阶段.属性:

\n
secrets.api-key=<stage-api-key>\nsecrets.token=<stage-token>\n
Run Code Online (Sandbox Code Playgroud)\n

秘密测试.属性:

\n
secrets.api-key=<test-api-key>\nsecrets.token=<test-token>\n
Run Code Online (Sandbox Code Playgroud)\n

秘密产品.属性:

\n
secrets.api-key=<prod-api-key>\nsecrets.token=<prod-token>\n
Run Code Online (Sandbox Code Playgroud)\n
    \n
  1. 您必须创建和设置 Spring Boot Cloud 配置服务器(充当外部服务器),它将负责连接到 Github 外部存储库,并为客户端提供根据环境访问属性文件的必要方法。
  2. \n
\n

项目结构:

\n

在此输入图像描述

\n

pom.xml:

\n
<?xml version="1.0" encoding="UTF-8"?>\n<project xmlns="http://maven.apache.org/POM/4.0.0"\n    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"\n    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">\n    <modelVersion>4.0.0</modelVersion>\n    <parent>\n        <groupId>org.springframework.boot</groupId>\n        <artifactId>spring-boot-starter-parent</artifactId>\n        <version>3.1.4</version>\n        <relativePath /> <!-- lookup parent from repository -->\n    </parent>\n    <groupId>com.example</groupId>\n    <artifactId>sb-externalize-config-server</artifactId>\n    <version>0.0.1-SNAPSHOT</version>\n    <name>sb-externalize-config-server</name>\n    <description>Demo project for Spring Boot</description>\n    <properties>\n        <java.version>17</java.version>\n        <spring-cloud.version>2022.0.4</spring-cloud.version>\n    </properties>\n    <dependencies>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-web</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.cloud</groupId>\n            <artifactId>spring-cloud-config-server</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.cloud</groupId>\n            <artifactId>spring-cloud-starter-config</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-configuration-processor</artifactId>\n            <optional>true</optional>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-test</artifactId>\n            <scope>test</scope>\n        </dependency>\n    </dependencies>\n    <dependencyManagement>\n        <dependencies>\n            <dependency>\n                <groupId>org.springframework.cloud</groupId>\n                <artifactId>spring-cloud-dependencies</artifactId>\n                <version>${spring-cloud.version}</version>\n                <type>pom</type>\n                <scope>import</scope>\n            </dependency>\n        </dependencies>\n    </dependencyManagement>\n\n    <build>\n        <plugins>\n            <plugin>\n                <groupId>org.springframework.boot</groupId>\n                <artifactId>spring-boot-maven-plugin</artifactId>\n            </plugin>\n        </plugins>\n    </build>\n\n</project>\n
Run Code Online (Sandbox Code Playgroud)\n

应用程序属性:

\n
spring.cloud.config.server.git.uri=https://github.com/anishb266/secrets-repo\nserver.port=8081\n
Run Code Online (Sandbox Code Playgroud)\n

需要注意的要点:

\n
    \n
  • 您必须设置spring.cloud.config.server.git.uri=https://github.com/anishb266/secrets-repo连接到该存储库。
  • \n
\n

创业班:

\n
package com.example;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.cloud.config.server.EnableConfigServer;\n\n@SpringBootApplication\n@EnableConfigServer\npublic class SbExternalizeConfigServerApplication {\n\n    public static void main(String[] args) {\n        SpringApplication.run(SbExternalizeConfigServerApplication.class, args);\n    }\n\n}\n
Run Code Online (Sandbox Code Playgroud)\n

您必须使用@EnableConfigServer它来使其成为外部配置服务器。

\n

现在,我将在端口 上运行外部配置服务器8081

\n

输出:

\n

访问属性之一,即Secrets-test.properties ,如下所示:

\n
http://localhost:8081/{application}/{env} \n\napplication - secrets\nenv - test\n
Run Code Online (Sandbox Code Playgroud)\n

在此输入图像描述

\n

配置服务器日志:

\n

在此输入图像描述

\n
    \n
  1. 您必须创建并设置 Spring boot Cloud Config 客户端,它将连接到配置服务器并根据环境获取属性值。
  2. \n
\n

项目结构:

\n

在此输入图像描述

\n

pom.xml:

\n
<?xml version="1.0" encoding="UTF-8"?>\n<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"\n    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">\n    <modelVersion>4.0.0</modelVersion>\n    <parent>\n        <groupId>org.springframework.boot</groupId>\n        <artifactId>spring-boot-starter-parent</artifactId>\n        <version>3.1.4</version>\n        <relativePath/> <!-- lookup parent from repository -->\n    </parent>\n    <groupId>com.example</groupId>\n    <artifactId>sb-externalize-config-client</artifactId>\n    <version>0.0.1-SNAPSHOT</version>\n    <name>sb-externalize-config-client</name>\n    <description>Demo project for Spring Boot</description>\n    <properties>\n        <java.version>17</java.version>\n        <spring-cloud.version>2022.0.4</spring-cloud.version>\n    </properties>\n    <dependencies>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-web</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.cloud</groupId>\n            <artifactId>spring-cloud-starter-config</artifactId>\n        </dependency>\n\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-configuration-processor</artifactId>\n            <optional>true</optional>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-test</artifactId>\n            <scope>test</scope>\n        </dependency>\n    </dependencies>\n    <dependencyManagement>\n        <dependencies>\n            <dependency>\n                <groupId>org.springframework.cloud</groupId>\n                <artifactId>spring-cloud-dependencies</artifactId>\n                <version>${spring-cloud.version}</version>\n                <type>pom</type>\n                <scope>import</scope>\n            </dependency>\n        </dependencies>\n    </dependencyManagement>\n\n    <build>\n        <plugins>\n            <plugin>\n                <groupId>org.springframework.boot</groupId>\n                <artifactId>spring-boot-maven-plugin</artifactId>\n            </plugin>\n        </plugins>\n    </build>\n\n</project>\n
Run Code Online (Sandbox Code Playgroud)\n

应用程序属性:

\n
spring.config.import=optional:configserver:http://localhost:8081\nserver.port=8080\nspring.application.name=secrets\nspring.profiles.active=test\n
Run Code Online (Sandbox Code Playgroud)\n

这里需要注意的要点:

\n
    \n
  • 在查找配置服务器之前,您已经设置了spring.application.name应用程序名称(此处为secrets) 。-{env}.properties否则,它将无法工作。基本上,它尝试通过应用程序的名称查找属性文件。默认情况下,只有名称application。因此,默认情况下它会尝试查找application-{env}.properties

    \n
  • \n
  • 为了测试,我保留,以便客户端尝试通过配置服务器从Secrets-test.propertiesspring.profiles.active=test获取属性。

    \n
  • \n
  • 您已将其设置spring.config.import=optional:configserver:http://localhost:8081为连接到外部服务器。

    \n
  • \n
\n

秘密属性:

\n
package com.example;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\n\n@ConfigurationProperties("secrets")\npublic class SecretsProperties {\n\n    private String apiKey;\n\n    private String token;\n\n    public SecretsProperties(String apiKey, String token) {\n        this.apiKey = apiKey;\n        this.token = token;\n    }\n\n    @Override\n    public String toString() {\n        return "SecretsProperties [apiKey=" + apiKey + ", token=" + token + "]";\n    }\n\n    public String getApiKey() {\n        return apiKey;\n    }\n\n    public void setApiKey(String apiKey) {\n        this.apiKey = apiKey;\n    }\n\n    public String getToken() {\n        return token;\n    }\n\n    public void setToken(String token) {\n        this.token = token;\n    }\n\n}\n
Run Code Online (Sandbox Code Playgroud)\n

该类用于映射加载的属性。

\n

启动类:

\n
package com.example;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\n\n@SpringBootApplication\n@EnableConfigurationProperties(SecretsProperties.class)\npublic class SbExternalizeConfigClientApplication {\n\n    public static void main(String[] args) {\n        SpringApplication.run(SbExternalizeConfigClientApplication.class, args);\n    }\n\n}\n
Run Code Online (Sandbox Code Playgroud)\n

用于测试的 TestController:

\n
package com.example;\n\nimport org.springframework.web.bind.annotation.GetMapping;\nimport org.springframework.web.bind.annotation.RestController;\n\n@RestController\npublic class TestController {\n\n    private SecretsProperties properties;\n\n    public TestController(SecretsProperties properties) {\n        this.properties = properties;\n    }\n\n    @GetMapping("test-external-properties")\n    public SecretsProperties testExternalProperties() {\n        return properties;\n    }\n\n}\n
Run Code Online (Sandbox Code Playgroud)\n

现在,我正在 8080 上运行带有配置文件的客户端test

\n

客户端日志:

\n

在此输入图像描述

\n

输出:

\n

在此输入图像描述

\n

提供外部配置服务器日志的一部分,以证明客户端能够通过带有 application-name 的配置服务器通过测试secrets配置文件选择所需的属性:

\n
2023-10-16T18:04:48.433+05:30  INFO 79167 --- [nio-8081-exec-2] o.s.c.c.s.e.NativeEnvironmentRepository  : Adding property source: Config resource \'file [/var/folders/yq/m5hjv94j18586b1gzwzjg1tw0000gn/T/config-repo-5291131953887905898/secrets-test.properties]\' via location \'file:/var/folders/yq/m5hjv94j18586b1gzwzjg1tw0000gn/T/config-repo-5291131953887905898/\'\n
Run Code Online (Sandbox Code Playgroud)\n

就这样。

\n
\n

HashiCorp Vault 方法:

\n

如果您正在寻找一种更安全和加密的方式来保存财产,那么请选择HashiCorp Vault

\n

注意: Vault 充当保密的外部服务器。因此,您不需要从头开始创建外部服务器。

\n

请阅读此处的Spring Boot 文档了解如何执行此操作。

\n

来自文档:

\n
\n

Vault 是一个秘密管理系统,允许您存储静态加密的敏感数据。它非常适合存储敏感的配置详细信息,例如密码、加密密钥、API 密钥。

\n
\n

过程非常相似,但会有一些变化。

\n
    \n
  • 首先在这里下载 Vault 。

    \n
  • \n
  • 提取它。将只有一个文件vault.sh

    \n
  • \n
  • 请按照此处的安装过程进行操作。

    \n
  • \n
  • 出于演示目的,我使用了此命令 -> ./vault server --dev --dev-root-token-id="abc",其中我将示例令牌设置为abc。请不要在产品中这样运行。

    \n
  • \n
  • 打开另一个控制台并执行此命令。

    \n
      export VAULT_TOKEN="abc"\n  export VAULT_ADDR="http://127.0.0.1:8200"\n
    Run Code Online (Sandbox Code Playgroud)\n
  • \n
  • 输入要保管库的值。格式:

    \n
      ./vault kv put secret/{application-name}/{env} key=value\n
    Run Code Online (Sandbox Code Playgroud)\n
  • \n
  • 将数据放入保管库的示例命令:

    \n
      ./vault kv put secret/secrets/test secrets.api-key=something secrets.token=something\n\n  ./vault kv put secret/secrets/dev secrets.api-key=nothing secrets.token=nothing\n
    Run Code Online (Sandbox Code Playgroud)\n
  • \n
  • 我将使用相同的现有客户端项目进行演示。

    \n
  • \n
\n

在 pom.xml 中添加此依赖项:

\n
<dependency>\n     <groupId>org.springframework.cloud</groupId>\n     <artifactId>spring-cloud-starter-vault-config</artifactId>. \n</dependency>\n
Run Code Online (Sandbox Code Playgroud)\n

您不再需要以下依赖项:

\n
    <dependency>\n        <groupId>org.springframework.cloud</groupId>\n        <artifactId>spring-cloud-starter-config</artifactId>\n    </dependency>\n
Run Code Online (Sandbox Code Playgroud)\n

请删除这个。

\n

pom.xml 将如下所示:

\n
<?xml version="1.0" encoding="UTF-8"?>\n<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"\n    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">\n    <modelVersion>4.0.0</modelVersion>\n    <parent>\n        <groupId>org.springframework.boot</groupId>\n        <artifactId>spring-boot-starter-parent</artifactId>\n        <version>3.1.4</version>\n        <relativePath/> <!-- lookup parent from repository -->\n    </parent>\n    <groupId>com.example</groupId>\n    <artifactId>sb-externalize-config-client</artifactId>\n    <version>0.0.1-SNAPSHOT</version>\n    <name>sb-externalize-config-client</name>\n    <description>Demo project for Spring Boot</description>\n    <properties>\n        <java.version>17</java.version>\n        <spring-cloud.version>2022.0.4</spring-cloud.version>\n    </properties>\n    <dependencies>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-web</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.cloud</groupId>\n            <artifactId>spring-cloud-starter-vault-config</artifactId>\n        </dependency>\n\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-configuration-processor</artifactId>\n            <optional>true</optional>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-test</artifactId>\n            <scope>test</scope>\n        </dependency>\n    </dependencies>\n    <dependencyManagement>\n        <dependencies>\n            <dependency>\n                <groupId>org.springframework.cloud</groupId>\n                <artifactId>spring-cloud-dependencies</artifactId>\n                <version>${spring-cloud.version}</version>\n                <type>pom</type>\n                <scope>import</scope>\n            </dependency>\n        </dependencies>\n    </dependencyManagement>\n\n    <build>\n        <plugins>\n            <plugin>\n                <groupId>org.springframework.boot</groupId>\n                <artifactId>spring-boot-maven-plugin</artifactId>\n            </plugin>\n        </plugins>\n    </build>\n\n</project>\n
Run Code Online (Sandbox Code Playgroud)\n

使用以下属性设置application.properties :

\n
spring.application.name=secrets\nspring.cloud.vault.token=abc\nspring.cloud.vault.scheme=http\nspring.cloud.vault.kv.enabled=true\nspring.cloud.vault.kv.default-context=\nspring.config.import=vault://secret/${spring.application.name}/${spring.profiles.active}\nspring.profiles.active=test\n
Run Code Online (Sandbox Code Playgroud)\n

注意事项:

\n
    \n
  • 默认情况下,Spring Cloud StarterVault 选择并附加/application应用程序名称以从Vault 中查找机密。为了防止这种情况,我们需要添加spring.cloud.vault.kv.default-context=属性。
  • \n
\n

TestController 、SecretsPropertiesSbExternalizeConfigClientApplication保持不变

\n

输出:

\n

我正在运行客户端以获取test配置文件。

\n

在此输入图像描述

\n

注意:这是我用 Vault 展示的一种非常基本的方法。

\n

请阅读文档,了解有关如何对 Vault 进行更高级设置的更多信息。

\n