【问题标题】:How to handle Docker-Secrets in application.properties files如何处理 application.properties 文件中的 Docker-Secrets
【发布时间】:2022-11-04 16:01:16
【问题描述】:

如何将 Docker 机密(来自 /run/secrets 的文件/数据)注入到 application.properties 文件中?使用环境变量是否安全?

【问题讨论】:

    标签: java spring spring-boot docker docker-secrets


    【解决方案1】:

    首先,将环境变量用于application.properties 的秘密数据是不安全的。

    在谈论秘密时,您主要有两种选择。

    1. 如果您使用 Docker Secrets没有 Docker Swarm然后你可以直接在一个秘密中加载整个application.properties,将它挂载在/run/secrets下,并将其作为带有Spring标志的配置文件。

    2. 如果您使用 Docker Secrets与 Docker 群然后您可以将您感兴趣的具体字段作为秘密存储,并使用 Swarm 的配置模板与它们相关联。

      例子:

      echo -n "myUser" | docker secret create db_user -
      echo -n "myPass" | docker secret create db_password -
      echo -n "jdbc://..." | docker secret create db_url -
      

      应用程序.properties.tmpl

      spring.datasource.url={{ secret "db_url" }}
      spring.datasource.user={{ secret "db_user" }}
      spring.datasource.password={{ secret "db_password" }}
      

      码头工人-compose.yml

      version: '3.9'
      services:
        api:
          image: yourapp:1.0.0
        configs:
          - source: application.properties
            target: /usr/app/config/application.properties
        secrets:
          - db_url
          - db_user
          - db_password
      
      configs:
        application.properties:
          template_driver: golang
          file: ./application.properties.tmpl
          name: myapp.application.properties
      
      secrets:
        db_url:
          external: true
        db_user:
          external: true
        db_password:
          external: true
      

      当您使用docker stack deploy -c docker-compose.yml myapp 进行部署时,它会自动使用机密内容填充配置,并将其挂载到目标路径中。

    【讨论】:

    • 哦哇!没有考虑码头配置!不错的方法,谢谢您的详细回答!
    • 如果这回答了您的问题,请将其标记为已接受,以便其他用户也一眼就能找到它。 stackoverflow.com/help/someone-answers
    • 是否可以将外部配置与模板一起使用? @丹尼尔-坎波斯
    • 我必须在“秘密”之前删除空格,然后它就可以工作了!
    • 我喜欢这个解决方案,但如果我理解正确,application.properties 文件在容器中以纯文本形式提供,因此可以通过将壳放入容器中来读取?然后假设任何可以访问撰写文件的人都可能访问正在运行的容器,因此这并不比使用环境变量更安全?秘密在集群中的节点之间安全传输而环境变量不是这样的真正好处是什么?
    【解决方案2】:

    如果您订阅十二因素应用程序configuration 上的哲学,环境变量是存储应用程序机密的合适位置。

    具体来说,使用 Spring Boot,可以按照 UPPER_SNAKE_CASE 命名约定将它们设置为容器中的环境变量,该命名约定映射到 application.propertiesapplication.yml 文件中的键。例如,如果您想设置数据库密码,就好像它在您的 database.password=i-am-the-password 文件中定义为 database.password=i-am-the-password 但从版本控制中忽略它,您可以这样做:

    $ export DATABASE_PASSWORD=i-am-the-password
    

    (或将 env var 注入容器运行时的另一种方法。)

    然后可以在 Java 代码中访问数据库密码,如下所示:

    import org.springframework.beans.factory.annotation.Value;
    
    public class Example {
    
      private final String databasePassword;
    
      public Example(
          @Value("${database.password}") String databasePassword) {
    
        this.databasePassword = databasePassword;
      }
    }
    

    【讨论】:

    • 谢谢您的回答!我确实认为在这里使用环境变量是不安全的(docs.docker.com/engine/swarm/secrets/…)。将对此进行更多研究
    • 不用担心!啊,我没有意识到你在使用 Docker Swarm。我没有使用它。对于更简单/单一的容器配置,可以很好地了解容器的生命周期,env vars 是可以的(在我看来)。
    【解决方案3】:

    目前在春天,这很容易。

    首先让我们创建 2 个秘密:

    docker secret create magic magic.yml 
    docker secret create arctos arctos.yml 
    

    在 magic.yml 和 arctos.yml 上方是您希望作为 docker 机密保存的配置文件,例如:

    #arctos.yml

    ---
    arctos:
      cold: "Very cold!"
    

    #magic.yml

    ---
    magic:
      value1: "Hello!"
      value2: 20
    
    

    现在让我们创建 Spring Boot 简单应用程序:

    @SpringBootApplication
    @EnableConfigurationProperties({MagicProperties.class, ArctosProperties.class})
    public class SimpleWebServiceApplication {
    
      public static void main(String[] args) {
        SpringApplication.run(SimpleWebServiceApplication.class, args);
      }
    
    }
    
    @ConfigurationProperties("arctos")
    record ArctosProperties(String cold) {
    }
    
    @ConfigurationProperties("magic")
    record MagicProperties(String value1, int value2) {
    }
    
    
    @RestController
    @RequiredArgsConstructor // lombok annotation pure constructor can be used
    class HelloController {
    
      private final MagicProperties magicProperties;
      private final ArctosProperties arctosProperties;
    
      @GetMapping("/magic")
      public MagicProperties magic() {
        return magicProperties;
      }
    
      @GetMapping("/arctos")
      public ArctosProperties arctos() {
        return arctosProperties;
      }
    
    }
    

    #application.yml

    ---
    spring:
      application:
        name: hello-secret
      config:
        import: 
          - optional:file:/run/secrets/magic.yml
          - optional:file:/run/secrets/arctos.yml
    

    #docker-compose.yml

    version: '3.9'
    
    networks:
      default:
        driver: overlay
        name: my-network
    
    services:
      hello-secret:
        image: <your_image_here>
        ports:
          - 8080:8080
        deploy:
          replicas: 1
          update_config:
            order: start-first
            monitor: 10s
            delay: 5s
        secrets:
          - source: magic
            target: magic.yml
          - source: arctos
            target: arctos.yml
    
    secrets:
      magic:
        external: true
      arctos:
        external: true
    

    现在运行:

    docker stack deploy -c docker-compose.yml mystack
    

    并调用:

    http :8080/magic
    http :8080/arctos
    

    #Post Scriptum

    事实上,我们可以让我们的应用程序更加灵活。如果例如在开发/测试期间我们不想使用秘密,我们可以稍微扩展我们的应用程序

    #application.yml 我们扩展

    # Properties
    arctos:
      cold: ${ARCTOS_COLD:}
    
    magic:
      value1: ${MAGIC_VALUE1:}
      value2: ${MAGIC_VALUE2:}
    

    #docker-compose.yml 我们扩展

    environment:
      MAGIC_VALUE1: "env_used"
      MAGIC_VALUE2: 0
      ARCTOS_COLD: "In fact in env area is hot ;]"
    

    在这种情况下,当秘密与我们的服务没有关联时,就会使用环境值。 (事实上​​,如果您提供环境值,它们具有优先权,所以最终无论如何它们都会获胜)。

    【讨论】:

      猜你喜欢
      • 2021-06-01
      • 1970-01-01
      • 2022-12-19
      • 1970-01-01
      • 2020-05-10
      • 1970-01-01
      • 1970-01-01
      • 2017-01-18
      • 1970-01-01
      相关资源
      最近更新 更多