1+ package com.wafflestudio.spring.ocivault.config
2+
3+ import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
4+ import com.fasterxml.jackson.module.kotlin.readValue
5+ import com.oracle.bmc.Region
6+ import com.oracle.bmc.auth.BasicAuthenticationDetailsProvider
7+ import com.oracle.bmc.auth.ConfigFileAuthenticationDetailsProvider
8+ import com.oracle.bmc.auth.okeworkloadidentity.OkeWorkloadIdentityAuthenticationDetailsProvider
9+ import com.oracle.bmc.secrets.SecretsClient
10+ import com.oracle.bmc.secrets.model.Base64SecretBundleContentDetails
11+ import com.oracle.bmc.secrets.requests.GetSecretBundleRequest
12+ import org.springframework.boot.EnvironmentPostProcessor
13+ import org.springframework.boot.SpringApplication
14+ import org.springframework.core.env.ConfigurableEnvironment
15+ import org.springframework.core.env.MapPropertySource
16+ import java.util.Base64
17+
18+ class OciVaultEnvironmentPostProcessor : EnvironmentPostProcessor {
19+ private val objectMapper = jacksonObjectMapper()
20+
21+ override fun postProcessEnvironment (
22+ environment : ConfigurableEnvironment ,
23+ application : SpringApplication ,
24+ ) {
25+ val isAotProcessing = environment.getProperty(" spring.aot.processing" , Boolean ::class .java, false )
26+ if (isAotProcessing) {
27+ return
28+ }
29+ val secretIdsProperty = environment.getProperty(" oci-vault-secret-ids" ) ? : return
30+ val secretIds = secretIdsProperty.split(" ," ).map { it.trim() }
31+ val region = Region .fromRegionId(
32+ environment.getProperty(" oci.vault.region" , " ap-chuncheon-1" ),
33+ )
34+
35+ val authProvider = createAuthProvider(environment)
36+ val client = SecretsClient .builder().region(region).build(authProvider)
37+ val secrets = mutableMapOf<String , Any >()
38+
39+ try {
40+ secretIds.forEach { secretId ->
41+ val secretString = getSecretString(client, secretId)
42+ val parsedSecrets = objectMapper.readValue<Map <String , Any >>(secretString)
43+ secrets.putAll(
44+ parsedSecrets.filterKeys {
45+ environment.getProperty(it).isNullOrEmpty()
46+ },
47+ )
48+ }
49+ } finally {
50+ client.close()
51+ }
52+
53+ if (secrets.isNotEmpty()) {
54+ environment.propertySources.addFirst(
55+ MapPropertySource (" oci-vault-secrets" , secrets),
56+ )
57+ }
58+ }
59+
60+ private fun createAuthProvider (environment : ConfigurableEnvironment ): BasicAuthenticationDetailsProvider {
61+ val profiles = environment.activeProfiles.toSet()
62+ return if (profiles.contains(" dev" ) || profiles.contains(" prod" )) {
63+ OkeWorkloadIdentityAuthenticationDetailsProvider .builder().build()
64+ } else {
65+ ConfigFileAuthenticationDetailsProvider (" DEFAULT" )
66+ }
67+ }
68+
69+ private fun getSecretString (client : SecretsClient , secretId : String ): String {
70+ val request = GetSecretBundleRequest .builder()
71+ .secretId(secretId)
72+ .build()
73+ val response = client.getSecretBundle(request)
74+ val content = (response.secretBundle.secretBundleContent as Base64SecretBundleContentDetails ).content
75+ return String (Base64 .getDecoder().decode(content))
76+ }
77+ }
0 commit comments