diff --git a/spring-cloud-modules/pom.xml b/spring-cloud-modules/pom.xml index 68c7d45b7c..dafc5b628e 100644 --- a/spring-cloud-modules/pom.xml +++ b/spring-cloud-modules/pom.xml @@ -54,7 +54,8 @@ spring-cloud-bus spring-cloud-data-flow spring-cloud-sleuth - spring-cloud-open-telemetry + spring-cloud-open-telemetry + spring-cloud-azure diff --git a/spring-cloud-modules/spring-cloud-azure/README.md b/spring-cloud-modules/spring-cloud-azure/README.md new file mode 100644 index 0000000000..810efbc8dc --- /dev/null +++ b/spring-cloud-modules/spring-cloud-azure/README.md @@ -0,0 +1,13 @@ +# Spring Cloud Azure + +# Relevant Articles + +# Azure KeyVault: +In order to create the secrets, follow these steps: +- create an Azure account +- install the Azure Cli an run the following commands +- login on Azure -> _az-login_ +- create a resource group: _az group create --name spring_cloud_azure --location eastus_ +- create a keyvault storage: _az keyvault create --name new_keyvault --resource-group spring_cloud_azure --location eastus_ +- create the secrets: > az keyvault secret set --name my-database-secret --value my-database-secret-value --vault-name new_keyvault,> az keyvault secret set --name my-secret --value my-secret-value --vault-name new_keyvault +``` \ No newline at end of file diff --git a/spring-cloud-modules/spring-cloud-azure/pom.xml b/spring-cloud-modules/spring-cloud-azure/pom.xml new file mode 100644 index 0000000000..86706c794f --- /dev/null +++ b/spring-cloud-modules/spring-cloud-azure/pom.xml @@ -0,0 +1,59 @@ + + + 4.0.0 + com.baeldung.spring.cloud + spring-cloud-azure + spring-cloud-azure + + + + org.apache.maven.plugins + maven-compiler-plugin + + + + jar + Spring Cloud Azure Examples + 1.0.0-SNAPSHOT + + + com.baeldung.spring.cloud + spring-cloud-modules + 1.0.0-SNAPSHOT + + + + + org.springframework.boot + spring-boot-dependencies + 2.7.8 + pom + import + + + org.springframework.cloud + spring-cloud-dependencies + ${spring-cloud-dependencies.version} + pom + import + + + + + + + + com.azure.spring + spring-cloud-azure-starter-keyvault-secrets + ${azure-key-vault-extension-version} + + + + + 2021.0.3 + 4.0.0 + + + \ No newline at end of file diff --git a/spring-cloud-modules/spring-cloud-azure/src/main/java/com/baeldung/spring/cloud/azure/keyvault/Application.java b/spring-cloud-modules/spring-cloud-azure/src/main/java/com/baeldung/spring/cloud/azure/keyvault/Application.java new file mode 100644 index 0000000000..8a44a502de --- /dev/null +++ b/spring-cloud-modules/spring-cloud-azure/src/main/java/com/baeldung/spring/cloud/azure/keyvault/Application.java @@ -0,0 +1,36 @@ +package com.baeldung.spring.cloud.azure.keyvault; + +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.CommandLineRunner; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +import com.azure.security.keyvault.secrets.models.KeyVaultSecret; +import com.baeldung.spring.cloud.azure.keyvault.service.KeyVaultClient; +import com.baeldung.spring.cloud.azure.keyvault.service.KeyVaultAutoconfiguredClient; + +@SpringBootApplication +public class Application implements CommandLineRunner { + + @Value("${database.secret.value}") + private String mySecret; + + private final KeyVaultClient keyVaultClient; + + public Application(@Qualifier(value = "KeyVaultAutoconfiguredClient") KeyVaultAutoconfiguredClient keyVaultAutoconfiguredClient) { + this.keyVaultClient = keyVaultAutoconfiguredClient; + } + + public static void main(String[] args) { + SpringApplication.run(Application.class); + + } + + @Override + public void run(String... args) throws Exception { + //KeyVaultSecret keyVaultSecret = keyVaultClient.getSecret("my-secret"); + //System.out.println("Hey, our secret is here ->" + keyVaultSecret.getValue()); + //System.out.println("Hey, our secret is here from application properties file ->" + mySecret); + } +} diff --git a/spring-cloud-modules/spring-cloud-azure/src/main/java/com/baeldung/spring/cloud/azure/keyvault/data/KeyVaultProperties.java b/spring-cloud-modules/spring-cloud-azure/src/main/java/com/baeldung/spring/cloud/azure/keyvault/data/KeyVaultProperties.java new file mode 100644 index 0000000000..edd7c01416 --- /dev/null +++ b/spring-cloud-modules/spring-cloud-azure/src/main/java/com/baeldung/spring/cloud/azure/keyvault/data/KeyVaultProperties.java @@ -0,0 +1,52 @@ +package com.baeldung.spring.cloud.azure.keyvault.data; + +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.boot.context.properties.ConstructorBinding; + +@ConfigurationProperties("azure.keyvault") +@ConstructorBinding +public class KeyVaultProperties { + private String vaultUrl; + private String tenantId; + private String clientId; + private String clientSecret; + + public KeyVaultProperties(String vaultUrl, String tenantId, String clientId, String clientSecret) { + this.vaultUrl = vaultUrl; + this.tenantId = tenantId; + this.clientId = clientId; + this.clientSecret = clientSecret; + } + + public String getVaultUrl() { + return vaultUrl; + } + + public void setVaultUrl(String vaultUrl) { + this.vaultUrl = vaultUrl; + } + + public String getTenantId() { + return tenantId; + } + + public void setTenantId(String tenantId) { + this.tenantId = tenantId; + } + + public String getClientId() { + return clientId; + } + + public void setClientId(String clientId) { + this.clientId = clientId; + } + + public String getClientSecret() { + return clientSecret; + } + + public void setClientSecret(String clientSecret) { + this.clientSecret = clientSecret; + } +} diff --git a/spring-cloud-modules/spring-cloud-azure/src/main/java/com/baeldung/spring/cloud/azure/keyvault/service/KeyVaultAutoconfiguredClient.java b/spring-cloud-modules/spring-cloud-azure/src/main/java/com/baeldung/spring/cloud/azure/keyvault/service/KeyVaultAutoconfiguredClient.java new file mode 100644 index 0000000000..392c15c6b4 --- /dev/null +++ b/spring-cloud-modules/spring-cloud-azure/src/main/java/com/baeldung/spring/cloud/azure/keyvault/service/KeyVaultAutoconfiguredClient.java @@ -0,0 +1,19 @@ +package com.baeldung.spring.cloud.azure.keyvault.service; + +import org.springframework.stereotype.Component; + +import com.azure.security.keyvault.secrets.SecretClient; + +@Component("KeyVaultAutoconfiguredClient") +public class KeyVaultAutoconfiguredClient implements KeyVaultClient { + private final SecretClient secretClient; + + public KeyVaultAutoconfiguredClient(SecretClient secretClient) { + this.secretClient = secretClient; + } + + @Override + public SecretClient getSecretClient() { + return secretClient; + } +} diff --git a/spring-cloud-modules/spring-cloud-azure/src/main/java/com/baeldung/spring/cloud/azure/keyvault/service/KeyVaultClient.java b/spring-cloud-modules/spring-cloud-azure/src/main/java/com/baeldung/spring/cloud/azure/keyvault/service/KeyVaultClient.java new file mode 100644 index 0000000000..4f4148250e --- /dev/null +++ b/spring-cloud-modules/spring-cloud-azure/src/main/java/com/baeldung/spring/cloud/azure/keyvault/service/KeyVaultClient.java @@ -0,0 +1,21 @@ +package com.baeldung.spring.cloud.azure.keyvault.service; + +import java.util.NoSuchElementException; + +import com.azure.security.keyvault.secrets.SecretClient; +import com.azure.security.keyvault.secrets.models.KeyVaultSecret; + +public interface KeyVaultClient { + + SecretClient getSecretClient(); + + default KeyVaultSecret getSecret(String key) { + KeyVaultSecret secret; + try { + secret = getSecretClient().getSecret(key); + } catch (Exception ex) { + throw new NoSuchElementException(); + } + return secret; + } +} diff --git a/spring-cloud-modules/spring-cloud-azure/src/main/java/com/baeldung/spring/cloud/azure/keyvault/service/KeyVaultManuallyConfiguredClient.java b/spring-cloud-modules/spring-cloud-azure/src/main/java/com/baeldung/spring/cloud/azure/keyvault/service/KeyVaultManuallyConfiguredClient.java new file mode 100644 index 0000000000..33a85f6bb9 --- /dev/null +++ b/spring-cloud-modules/spring-cloud-azure/src/main/java/com/baeldung/spring/cloud/azure/keyvault/service/KeyVaultManuallyConfiguredClient.java @@ -0,0 +1,31 @@ +package com.baeldung.spring.cloud.azure.keyvault.service; + +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.stereotype.Component; + +import com.azure.identity.ClientSecretCredentialBuilder; +import com.azure.security.keyvault.secrets.SecretClient; +import com.azure.security.keyvault.secrets.SecretClientBuilder; +import com.baeldung.spring.cloud.azure.keyvault.data.KeyVaultProperties; + +@EnableConfigurationProperties(KeyVaultProperties.class) +@Component("KeyVaultManuallyConfiguredClient") +public class KeyVaultManuallyConfiguredClient implements KeyVaultClient { + + private KeyVaultProperties keyVaultProperties; + + private SecretClient secretClient; + + @Override + public SecretClient getSecretClient() { + if (secretClient == null) { + secretClient = new SecretClientBuilder().vaultUrl(keyVaultProperties.getVaultUrl()) + .credential(new ClientSecretCredentialBuilder().tenantId(keyVaultProperties.getTenantId()) + .clientId(keyVaultProperties.getClientId()) + .clientSecret(keyVaultProperties.getClientSecret()) + .build()) + .buildClient(); + } + return secretClient; + } +} diff --git a/spring-cloud-modules/spring-cloud-azure/src/main/resources/application.yaml b/spring-cloud-modules/spring-cloud-azure/src/main/resources/application.yaml new file mode 100644 index 0000000000..4bea8d789b --- /dev/null +++ b/spring-cloud-modules/spring-cloud-azure/src/main/resources/application.yaml @@ -0,0 +1,21 @@ +spring: + cloud: + azure: + compatibility-verifier: + enabled: false + keyvault: + secret: + property-sources[0]: + name: key-vault-property-source-1 + endpoint: https://spring-cloud-azure.vault.azure.net/ + property-source-enabled: true + endpoint: https://spring-cloud-azure.vault.azure.net/ +azure: + keyvault: + vaultUrl: myVaultUrl + tenantId: myTenantId + clientId: myClientId + clientSecret: myClientSecret +database: + secret: + value: ${my-database-secret} \ No newline at end of file diff --git a/spring-cloud-modules/spring-cloud-azure/src/test/java/com/baeldung/spring/cloud/azure/keyvault/KeyVaultAutoconfiguredClientUnitTest.java b/spring-cloud-modules/spring-cloud-azure/src/test/java/com/baeldung/spring/cloud/azure/keyvault/KeyVaultAutoconfiguredClientUnitTest.java new file mode 100644 index 0000000000..0e3779e2c2 --- /dev/null +++ b/spring-cloud-modules/spring-cloud-azure/src/test/java/com/baeldung/spring/cloud/azure/keyvault/KeyVaultAutoconfiguredClientUnitTest.java @@ -0,0 +1,26 @@ +package com.baeldung.spring.cloud.azure.keyvault; + +import java.util.NoSuchElementException; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.boot.test.context.SpringBootTest; + +import com.baeldung.spring.cloud.azure.keyvault.service.KeyVaultAutoconfiguredClient; + +@SpringBootTest(classes = Application.class) +public class KeyVaultAutoconfiguredClientUnitTest { + + @Autowired + @Qualifier(value = "KeyVaultAutoconfiguredClient") + private KeyVaultAutoconfiguredClient keyVaultAutoconfiguredClient; + + @Test + void whenANotExistingKeyIsProvided_thenShouldReturnAnError() { + String secretKey = "mySecret"; + Assertions.assertThrows(NoSuchElementException.class, () -> keyVaultAutoconfiguredClient.getSecret(secretKey)); + } + +} diff --git a/spring-cloud-modules/spring-cloud-azure/src/test/resources/application.yaml b/spring-cloud-modules/spring-cloud-azure/src/test/resources/application.yaml new file mode 100644 index 0000000000..88c54b32eb --- /dev/null +++ b/spring-cloud-modules/spring-cloud-azure/src/test/resources/application.yaml @@ -0,0 +1,21 @@ +spring: + cloud: + azure: + compatibility-verifier: + enabled: false + keyvault: + secret: + endpoint: https://spring-cloud-azure.vault.azure.net/ + property-source-enabled: true + property-sources: + name: key-vault-property-source-1 + endpoint: https://spring-cloud-azure.vault.azure.net/ +azure: + keyvault: + vaultUrl: myVaultUrl + tenantId: myTenantId + clientId: myClientId + clientSecret: myClientSecret +database: + secret: + value: my-database-secret \ No newline at end of file