【发布时间】:2022-11-04 16:01:16
【问题描述】:
如何将 Docker 机密(来自 /run/secrets 的文件/数据)注入到 application.properties 文件中?使用环境变量是否安全?
【问题讨论】:
标签: java spring spring-boot docker docker-secrets
如何将 Docker 机密(来自 /run/secrets 的文件/数据)注入到 application.properties 文件中?使用环境变量是否安全?
【问题讨论】:
标签: java spring spring-boot docker docker-secrets
首先,将环境变量用于application.properties 的秘密数据是不安全的。
在谈论秘密时,您主要有两种选择。
如果您使用 Docker Secrets没有 Docker Swarm然后你可以直接在一个秘密中加载整个application.properties,将它挂载在/run/secrets下,并将其作为带有Spring标志的配置文件。
如果您使用 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 进行部署时,它会自动使用机密内容填充配置,并将其挂载到目标路径中。
【讨论】:
application.properties 文件在容器中以纯文本形式提供,因此可以通过将壳放入容器中来读取?然后假设任何可以访问撰写文件的人都可能访问正在运行的容器,因此这并不比使用环境变量更安全?秘密在集群中的节点之间安全传输而环境变量不是这样的真正好处是什么?
如果您订阅十二因素应用程序configuration 上的哲学,环境变量是存储应用程序机密的合适位置。
具体来说,使用 Spring Boot,可以按照 UPPER_SNAKE_CASE 命名约定将它们设置为容器中的环境变量,该命名约定映射到 application.properties 或 application.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;
}
}
【讨论】:
目前在春天,这很容易。
首先让我们创建 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 ;]"
在这种情况下,当秘密与我们的服务没有关联时,就会使用环境值。 (事实上,如果您提供环境值,它们具有优先权,所以最终无论如何它们都会获胜)。
【讨论】: