I am having my local spring boot application which is trying to read the keyvault secret by using the below code .
@Component
public class KeyVaultHelper {
private static final Logger LOGGER = LoggerFactory.getLogger(KeyVaultHelper.class);
public SecretClient getSecretClient() {
return new SecretClientBuilder()
.vaultUrl("https://mba-key-vault-int.vault.azure.net/")
.credential(new ClientSecretCredentialBuilder()
.tenantId("de8e2ba9-95c1-4fbb-b558-6bf8bb1d8081")
.clientId("b74bcf37-n044-4242-9187-d85b486379c1")
.clientSecret("mU48Q~LpWJL7EZDpTzjiNDzqVywcmseUKaR62b5P")
.build())
.buildClient();
}
public String saveSecretToFile() {
String secretValue = getSecretClient().getSecret("secretName").getValue();
System.out.println("secret name", secretValue);
}
}
While calling saveSecretToFile() from other class, I am getting the exception as com.azure.security.keyvault.secrets.implementation.models.KeyVaultErrorException: Status code 401, "{"error":{"code":"Unauthorized","message":"AKV10000: Request is missing a Bearer or PoP token."}}"
Note: I set the service principal as per the link https://azuresdkdocs.blob.core.windows.net/$web/java/azure-security-keyvault-secrets/4.2.3/index.html
I'm getting the access token by using
public String getAccessToken() {
MultiValueMap<String,String> formData = prepareFormData();
ResponseEntity<JsonNode> response = restTemplate.postForEntity(
String.format("https://login.microsoftonline.com/%s/oauth2/v2.0/token", tenantId),
httpEntity(formData),JsonNode.class);
JsonNode jsonNode=response.getBody();
return jsonNode.get("access_token").asText();
}
MultiValueMap<String, String> prepareFormData() {
MultiValueMap<String, String> map = new LinkedMultiValueMap<>();
map.add("grant_type", "client_credentials");
map.add("client_id", "b74bcf37-n044-4242-9187-d85b486379c1");
map.add("client_secret", "mU48Q~LpWJL7EZDpTzjiNDzqVywcmseUKaR62b5P");
map.add("scope", "https://vault.azure.net/.default");
return map;
}
HttpEntity<MultiValueMap<String, String>> httpEntity(MultiValueMap<String, String> map) {
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
httpHeaders.add("Accept", MediaType.APPLICATION_JSON_VALUE);
HttpEntity<MultiValueMap<String, String>> request = new HttpEntity<>(map, httpHeaders);
return request;
}
But , I am not sure where to use the access token as there is no REST call in the key vault access code.
The access token can be given as follows
public SecretClient getSecretClient() {
return new SecretClientBuilder()
.vaultUrl("https://mba-key-vault-int.vault.azure.net/")
.addPolicy(new CustomHeaderPolicy("AUTHORIZATION","Bearer "+getAccessToken()))
.credential(new ClientSecretCredentialBuilder()
.tenantId("de8e2ba9-95c1-4fbb-b558-6bf8bb1d8081")
.clientId("b74bcf37-n044-4242-9187-d85b486379c1")
.clientSecret("mU48Q~LpWJL7EZDpTzjiNDzqVywcmseUKaR62b5P")
.build())
.buildClient();
}
And the custom header policy file can be created like below.
import com.azure.core.http.HttpPipelineCallContext;
import com.azure.core.http.HttpPipelineNextPolicy;
import com.azure.core.http.HttpResponse;
import com.azure.core.http.policy.HttpPipelinePolicy;
import reactor.core.publisher.Mono;
public class CustomHeaderPolicy implements HttpPipelinePolicy {
private final String headerName;
private final String headerValue;
public CustomHeaderPolicy(String headerName, String headerValue) {
this.headerName = headerName;
this.headerValue = headerValue;
}
@Override
public Mono<HttpResponse> process(HttpPipelineCallContext context, HttpPipelineNextPolicy next) {
// Add the custom header to the request
context.getHttpRequest().setHeader(headerName, headerValue);
return next.process();
}
}
After providing access token , I am able to connect to Azure key vault from my local Spring boot application