secrets-manager.adoc 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336
  1. = Secrets Manager Integration
  2. https://aws.amazon.com/secrets-manager/[Secrets Manager] helps to protect secrets needed to access your applications, services, and IT resources. The service enables you to easily rotate, manage, and retrieve database credentials, API keys, and other secrets throughout their lifecycle.
  3. Spring Cloud AWS adds support for loading configuration properties from Secrets Manager through Spring Boot https://docs.spring.io/spring-boot/docs/current/reference/html/spring-boot-features.html#boot-features-external-config-files-importing[config import feature].
  4. Maven coordinates, using <<index.adoc#bill-of-materials, Spring Cloud AWS BOM>>:
  5. [source,xml]
  6. ----
  7. <dependency>
  8. <groupId>io.awspring.cloud</groupId>
  9. <artifactId>spring-cloud-aws-starter-secrets-manager</artifactId>
  10. </dependency>
  11. ----
  12. == Loading External Configuration
  13. To fetch secrets from Secrets Manager and add them to Spring's environment properties, add `spring.config.import` property to `application.properties`:
  14. For example, assuming that the secret name in Secrets Manager is `/secrets/database-secrets`:
  15. [source,properties]
  16. ----
  17. spring.config.import=aws-secretsmanager:/secrets/database-secrets
  18. ----
  19. If a secret with given name does not exist in Secrets Manager, application will fail to start. If secret value is not required for the application, and it should continue to startup even when secret is missing, add `optional` before prefix:
  20. [source,properties]
  21. ----
  22. spring.config.import=optional:aws-secretsmanager:/secrets/database-secrets
  23. ----
  24. To load multiple secrets, separate their names with `;`:
  25. [source,properties]
  26. ----
  27. spring.config.import=aws-secretsmanager:/secrets/database-secrets;/secrets/webclient-secrets
  28. ----
  29. If some secrets are required, and other ones are optional, list them as separate entries in `spring.config.import` property:
  30. [source,properties]
  31. ----
  32. spring.config.import[0]=optional:aws-secretsmanager=/secrets/required-secret
  33. spring.config.import[1]=aws-secretsmanager=/secrets/optional-secret
  34. ----
  35. Fetched secrets can be referenced with `@Value`, bound to `@ConfigurationProperties` classes, or referenced in `application.properties` file.
  36. === Using Key-Value (JSON) Secrets
  37. Secrets resolved with `spring.config.import` can be also referenced in `application.properties`.
  38. When a content of `SecretString` in a JSON, all top level JSON keys are added as properties to Spring Environment.
  39. For example, with a file `mycreds.json` containing following JSON structure:
  40. [source,json]
  41. ----
  42. {
  43. "username": "saanvi",
  44. "password": "EXAMPLE-PASSWORD"
  45. }
  46. ----
  47. Secret is created with a command:
  48. [source]
  49. ----
  50. $ aws secretsmanager create-secret --name /secrets/database-secrets --secret-string file://mycreds.json
  51. ----
  52. `spring.config.import` entry is added to `application.properties`:
  53. [source, properties]
  54. ----
  55. spring.config.import=aws-secretsmanager:/secrets/database-secrets
  56. ----
  57. Secret values can be referenced by JSON key names:
  58. [source, java]
  59. ----
  60. @Value("${username}"
  61. private String username;
  62. @Value("${password}"
  63. private String password;
  64. ----
  65. === Using plain text secrets
  66. If a `SecretString` is a plain text or if you are using `SecretBinary` , use secret name to retrieve its value.
  67. For example, we will JDBC saved as plain text secret type with name `/secrets/my-certificate`:
  68. [source]
  69. ----
  70. $ aws secretsmanager create-secret --name /secrets/prod/jdbc-url --secret-string jdbc:url
  71. ----
  72. `spring.config.import` entry is added to `application.properties`:
  73. [source, properties]
  74. ----
  75. spring.config.import=aws-secretsmanager:/secrets/prod/jdbc-url
  76. ----
  77. Secret value can be retrieved by referencing secret name:
  78. [source,properties]
  79. ----
  80. spring.datasource.url=${jdbc-url}
  81. ----
  82. === Adding prefix to property keys
  83. To avoid property keys collisions it is possible to configure property key prefix that gets added to each resolved property from a secret.
  84. As an example lets consider following JSON secret with a name `/secrets/database-secrets`:
  85. [source,json]
  86. ----
  87. {
  88. "username": "saanvi",
  89. "password": "EXAMPLE-PASSWORD"
  90. }
  91. ----
  92. By default, `usernmame` and `password` properties will be added to the Spring environment. To add a prefix to property keys configure `spring.config.import` property with `?prefix=` added to the secret name:
  93. [source,properties]
  94. ----
  95. spring.config.import=optional:aws-secretsmanager:/secrets/database-secrets?prefix=db.
  96. ----
  97. With such config, properties `db.username` and `db.password` are added to the Spring environment.
  98. NOTE: Prefixes are added as-is to all property names returned by Secrets Manager. If you want key names to be separated with a dot between the prefix and key name, make sure to add a trailing dot to the prefix.
  99. == Using SecretsManagerClient
  100. The starter automatically configures and registers a `SecretsManagerClient` bean in the Spring application context. The `SecretsManagerClient` bean can be used to create or retrieve secrets imperatively.
  101. [source,java]
  102. ----
  103. import org.springframework.stereotype.Component;
  104. import software.amazon.awssdk.services.secretsmanager.SecretsManagerClient;
  105. import software.amazon.awssdk.services.secretsmanager.model.CreateSecretRequest;
  106. ...
  107. @Autowired
  108. private SecretsManagerClient secretsManagerClient;
  109. ...
  110. secretsManagerClient.createSecret(CreateSecretRequest.builder().name(name).secretString(secret).build());
  111. ----
  112. == Customizing SecretsManagerClient
  113. To use custom `SecretsManagerClient` in `spring.config.import`, provide an implementation of `BootstrapRegistryInitializer`. For example:
  114. [source,java]
  115. ----
  116. package com.app;
  117. import software.amazon.awssdk.auth.credentials.AwsBasicCredentials;
  118. import software.amazon.awssdk.auth.credentials.AwsCredentialsProvider;
  119. import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider;
  120. import software.amazon.awssdk.regions.Region;
  121. import software.amazon.awssdk.services.secretsmanager.SecretsManagerClient;
  122. import org.springframework.boot.BootstrapRegistry;
  123. import org.springframework.boot.BootstrapRegistryInitializer;
  124. public class SecretsManagerBootstrapConfiguration implements BootstrapRegistryInitializer {
  125. @Override
  126. public void initialize(BootstrapRegistry registry) {
  127. registry.register(SecretsManagerClient.class, context -> {
  128. AwsCredentialsProvider awsCredentialsProvider = StaticCredentialsProvider.create(AwsBasicCredentials.create("yourAccessKey", "yourSecretKey"));
  129. return SecretsManagerClient.builder().credentialsProvider(awsCredentialsProvider).region(Region.EU_WEST_2).build();
  130. });
  131. }
  132. }
  133. ----
  134. Note that this class must be listed under `org.springframework.boot.BootstrapRegistryInitializer` key in `META-INF/spring.factories`:
  135. [source, properties]
  136. ----
  137. org.springframework.boot.BootstrapRegistryInitializer=com.app.SecretsManagerBootstrapConfiguration
  138. ----
  139. If you want to use autoconfigured `SecretsManagerClient` but change underlying SDKClient or ClientOverrideConfiguration you will need to register bean of type `AwsClientConfigurerSecretsManager`:
  140. Autoconfiguration will configure `SecretsManagerClient` Bean with provided values after that, for example:
  141. [source,java]
  142. ----
  143. package com.app;
  144. import io.awspring.cloud.autoconfigure.config.secretsmanager.AwsSecretsManagerClientCustomizer;
  145. import java.time.Duration;
  146. import org.springframework.boot.BootstrapRegistry;
  147. import org.springframework.boot.BootstrapRegistryInitializer;
  148. import software.amazon.awssdk.core.client.config.ClientOverrideConfiguration;
  149. import software.amazon.awssdk.http.SdkHttpClient;
  150. import software.amazon.awssdk.http.apache.ApacheHttpClient;
  151. import software.amazon.awssdk.services.secretsmanager.SecretsManagerClientBuilder;
  152. class SecretsManagerBootstrapConfiguration implements BootstrapRegistryInitializer {
  153. @Override
  154. public void initialize(BootstrapRegistry registry) {
  155. registry.register(AwsSecretsManagerClientCustomizer.class,
  156. context -> new AwsSecretsManagerClientCustomizer() {
  157. @Override
  158. public ClientOverrideConfiguration overrideConfiguration() {
  159. return ClientOverrideConfiguration.builder().apiCallTimeout(Duration.ofMillis(500))
  160. .build();
  161. }
  162. @Override
  163. public SdkHttpClient httpClient() {
  164. return ApacheHttpClient.builder().connectionTimeout(Duration.ofMillis(1000)).build();
  165. }
  166. });
  167. }
  168. }
  169. ----
  170. == `PropertySource` Reload
  171. Some applications may need to detect changes on external property sources and update their internal status to reflect the new configuration.
  172. The reload feature of Spring Cloud AWS Secrets Manager integration is able to trigger an application reload when a related secret value changes.
  173. By default, this feature is disabled. You can enable it by using the `spring.cloud.aws.secretsmanager.reload.strategy` configuration property (for example, in the `application.properties` file).
  174. The following levels of reload are supported (by setting the `spring.cloud.aws.secretsmanager.reload.strategy` property):
  175. * `refresh` (default): Only configuration beans annotated with `@ConfigurationProperties` or `@RefreshScope` are reloaded.
  176. This reload level leverages the refresh feature of Spring Cloud Context.
  177. * `restart_context`: the whole Spring `ApplicationContext` is gracefully restarted. Beans are recreated with the new configuration.
  178. In order for the restart context functionality to work properly you must enable and expose the restart actuator endpoint
  179. [source,yaml]
  180. ====
  181. ----
  182. management:
  183. endpoint:
  184. restart:
  185. enabled: true
  186. endpoints:
  187. web:
  188. exposure:
  189. include: restart
  190. ----
  191. ====
  192. Assuming that the reload feature is enabled with default settings (`refresh` mode), the following bean is refreshed when the secret changes:
  193. ====
  194. [java, source]
  195. ----
  196. @Configuration
  197. @ConfigurationProperties(prefix = "bean")
  198. public class MyConfig {
  199. private String message = "a message that can be changed live";
  200. // getter and setters
  201. }
  202. ----
  203. ====
  204. To see that changes effectively happen, you can create another bean that prints the message periodically, as follows
  205. ====
  206. [source,java]
  207. ----
  208. @Component
  209. public class MyBean {
  210. @Autowired
  211. private MyConfig config;
  212. @Scheduled(fixedDelay = 5000)
  213. public void hello() {
  214. System.out.println("The message is: " + config.getMessage());
  215. }
  216. }
  217. ----
  218. ====
  219. The reload feature periodically re-creates the configuration from config maps and secrets to see if it has changed.
  220. You can configure the polling period by using the `spring.cloud.aws.secretsmanager.reload.period` (default value is 1 minute).
  221. == Configuration
  222. The Spring Boot Starter for Secrets Manager provides the following configuration options:
  223. [cols="2,3,1,1"]
  224. |===
  225. | Name | Description | Required | Default value
  226. | `spring.cloud.aws.secretsmanager.endpoint` | Configures endpoint used by `SecretsManagerClient`. | No | `null`
  227. | `spring.cloud.aws.secretsmanager.region` | Configures region used by `SecretsManagerClient`. | No | `null`
  228. | `spring.cloud.aws.secretsmanager.reload.strategy` | `Enum` | `refresh` | The strategy to use when firing a reload (`refresh`, `restart_context`)
  229. | `spring.cloud.aws.secretsmanager.reload.period` | `Duration`| `15s` | The period for verifying changes
  230. | `spring.cloud.aws.secretsmanager.reload.max-wait-time-for-restart` | `Duration`| `2s` | The maximum time between the detection of changes in property source and the application context restart when `restart_context` strategy is used.
  231. |===
  232. == IAM Permissions
  233. Following IAM permissions are required by Spring Cloud AWS:
  234. [cols="2"]
  235. |===
  236. | Get secret value:
  237. | `secretsmanager:GetSecretValue`
  238. |===
  239. Sample IAM policy granting access to Secrets Manager:
  240. [source,json,indent=0]
  241. ----
  242. {
  243. "Version": "2012-10-17",
  244. "Statement": [
  245. {
  246. "Effect": "Allow",
  247. "Action": "secretsmanager:GetSecretValue",
  248. "Resource": "yourArn"
  249. }
  250. ]
  251. }
  252. ----