diff --git a/spring-vault-core/src/main/java/org/springframework/vault/authentication/AzureMsiAuthentication.java b/spring-vault-core/src/main/java/org/springframework/vault/authentication/AzureMsiAuthentication.java index 5720b97d..de1c83b5 100644 --- a/spring-vault-core/src/main/java/org/springframework/vault/authentication/AzureMsiAuthentication.java +++ b/spring-vault-core/src/main/java/org/springframework/vault/authentication/AzureMsiAuthentication.java @@ -169,11 +169,12 @@ public class AzureMsiAuthentication implements ClientAuthentication { private static Map getAzureLogin(String role, AzureVmEnvironment vmEnvironment, String jwt) { Map loginBody = new LinkedHashMap<>(); + loginBody.put("role", role); + loginBody.put("jwt", jwt); + loginBody.put("subscription_id", vmEnvironment.getSubscriptionId()); loginBody.put("resource_group_name", vmEnvironment.getResourceGroupName()); loginBody.put("vm_name", vmEnvironment.getVmName()); - loginBody.put("subscription_id", vmEnvironment.getSubscriptionId()); - loginBody.put("jwt", jwt); - loginBody.put("role", role); + loginBody.put("vmss_name", vmEnvironment.getVmScaleSetName()); return loginBody; } @@ -207,10 +208,11 @@ public class AzureMsiAuthentication implements ClientAuthentication { Map compute = (Map) instanceMetadata.get("compute"); String subscriptionId = compute.get("subscriptionId"); - String vmName = compute.get("name"); String resourceGroupName = compute.get("resourceGroupName"); + String vmName = compute.get("name"); + String vmScaleSetName = compute.get("vmScaleSetName"); - return new AzureVmEnvironment(subscriptionId, resourceGroupName, vmName); + return new AzureVmEnvironment(subscriptionId, resourceGroupName, vmName, vmScaleSetName); } } diff --git a/spring-vault-core/src/main/java/org/springframework/vault/authentication/AzureVmEnvironment.java b/spring-vault-core/src/main/java/org/springframework/vault/authentication/AzureVmEnvironment.java index 316607b3..ee83c74c 100644 --- a/spring-vault-core/src/main/java/org/springframework/vault/authentication/AzureVmEnvironment.java +++ b/spring-vault-core/src/main/java/org/springframework/vault/authentication/AzureVmEnvironment.java @@ -37,6 +37,8 @@ public class AzureVmEnvironment { private final String vmName; + private final String vmScaleSetName; + /** * Creates a new {@link AzureVmEnvironment}. * @param subscriptionId must not be {@literal null}. @@ -44,14 +46,27 @@ public class AzureVmEnvironment { * @param vmName must not be {@literal null}. */ public AzureVmEnvironment(String subscriptionId, String resourceGroupName, String vmName) { + this(subscriptionId, resourceGroupName, vmName, ""); + } + + /** + * Creates a new {@link AzureVmEnvironment}. + * @param subscriptionId must not be {@literal null}. + * @param resourceGroupName must not be {@literal null}. + * @param vmName must not be {@literal null}. + * @param vmScaleSetName must not be {@literal null}. + */ + public AzureVmEnvironment(String subscriptionId, String resourceGroupName, String vmName, String vmScaleSetName) { Assert.notNull(subscriptionId, "SubscriptionId must not be null"); Assert.notNull(resourceGroupName, "Resource group name must not be null"); Assert.notNull(vmName, "VM name must not be null"); + Assert.notNull(vmScaleSetName, "VMSS name must not be null"); this.subscriptionId = subscriptionId; this.resourceGroupName = resourceGroupName; this.vmName = vmName; + this.vmScaleSetName = vmScaleSetName; } public String getSubscriptionId() { @@ -66,4 +81,8 @@ public class AzureVmEnvironment { return this.vmName; } + public String getVmScaleSetName() { + return vmScaleSetName; + } + } diff --git a/spring-vault-core/src/test/java/org/springframework/vault/authentication/AzureMsiAuthenticationUnitTests.java b/spring-vault-core/src/test/java/org/springframework/vault/authentication/AzureMsiAuthenticationUnitTests.java index 9153b8a8..cf2cf924 100644 --- a/spring-vault-core/src/test/java/org/springframework/vault/authentication/AzureMsiAuthenticationUnitTests.java +++ b/spring-vault-core/src/test/java/org/springframework/vault/authentication/AzureMsiAuthenticationUnitTests.java @@ -60,9 +60,9 @@ class AzureMsiAuthenticationUnitTests { AzureMsiAuthenticationOptions options = AzureMsiAuthenticationOptions.builder().role("dev-role") // .build(); - expectMetadataRequest(); + expectVmMetadataRequest(); expectIdentityTokenRequest(); - expectLoginRequest(); + expectVmLoginRequest(); AzureMsiAuthentication authentication = new AzureMsiAuthentication(options, this.restTemplate); @@ -78,7 +78,7 @@ class AzureMsiAuthenticationUnitTests { .vmEnvironment(new AzureVmEnvironment("foobar-subscription", "vault", "vault-client")).build(); expectIdentityTokenRequest(); - expectLoginRequest(); + expectVmLoginRequest(); AzureMsiAuthentication authentication = new AzureMsiAuthentication(options, this.restTemplate); @@ -93,9 +93,9 @@ class AzureMsiAuthenticationUnitTests { AzureMsiAuthenticationOptions options = AzureMsiAuthenticationOptions.builder().role("dev-role") // .build(); - expectMetadataRequest(); + expectVmMetadataRequest(); expectIdentityTokenRequest(); - expectLoginRequest(); + expectVmLoginRequest(); AuthenticationStepsExecutor authentication = new AuthenticationStepsExecutor( AzureMsiAuthentication.createAuthenticationSteps(options), this.restTemplate); @@ -112,7 +112,7 @@ class AzureMsiAuthenticationUnitTests { .vmEnvironment(new AzureVmEnvironment("foobar-subscription", "vault", "vault-client")).build(); expectIdentityTokenRequest(); - expectLoginRequest(); + expectVmLoginRequest(); AuthenticationStepsExecutor authentication = new AuthenticationStepsExecutor( AzureMsiAuthentication.createAuthenticationSteps(options), this.restTemplate); @@ -122,14 +122,51 @@ class AzureMsiAuthenticationUnitTests { assertThat(login.getToken()).isEqualTo("my-token"); } - private void expectMetadataRequest() { + @Test + void loginFromScaleSetShouldObtainToken() { + + AzureMsiAuthenticationOptions options = AzureMsiAuthenticationOptions.builder().role("dev-role") // + .build(); + + expectVmssMetadataRequest(); + expectIdentityTokenRequest(); + expectVmssLoginRequest(); + + AzureMsiAuthentication authentication = new AzureMsiAuthentication(options, this.restTemplate); + + VaultToken login = authentication.login(); + assertThat(login).isInstanceOf(LoginToken.class); + assertThat(login.getToken()).isEqualTo("my-token"); + } + + private void expectVmMetadataRequest() { this.mockRest.expect(requestTo(AzureMsiAuthenticationOptions.DEFAULT_INSTANCE_METADATA_SERVICE_URI)) .andExpect(method(HttpMethod.GET)).andExpect(header("Metadata", "true")) .andRespond(withSuccess().contentType(MediaType.APPLICATION_JSON) - .body("{\n" + " \"compute\": {\n" + " \"name\": \"vault-client\",\n" + .body("{\n" + + " \"compute\": {\n" + + " \"name\": \"vault-client\",\n" + + " \"vmScaleSetName\": \"\",\n" + " \"resourceGroupName\": \"vault\",\n" - + " \"subscriptionId\": \"foobar-subscription\"\n" + " }\n" + "}")); + + " \"subscriptionId\": \"foobar-subscription\"\n" + + " }\n" + + "}")); + } + + private void expectVmssMetadataRequest() { + + this.mockRest.expect(requestTo(AzureMsiAuthenticationOptions.DEFAULT_INSTANCE_METADATA_SERVICE_URI)) + .andExpect(method(HttpMethod.GET)).andExpect(header("Metadata", "true")) + .andRespond(withSuccess().contentType(MediaType.APPLICATION_JSON) + .body("{\n" + + " \"compute\": {\n" + + " \"name\": \"vault-client-scale-set_0\",\n" + + " \"vmScaleSetName\": \"vault-client-scale-set\",\n" + + " \"resourceGroupName\": \"vault\",\n" + + " \"subscriptionId\": \"foobar-subscription\"\n" + + " }\n" + + "}")); } private void expectIdentityTokenRequest() { @@ -140,13 +177,26 @@ class AzureMsiAuthenticationUnitTests { } - private void expectLoginRequest() { + private void expectVmLoginRequest() { this.mockRest.expect(requestTo("/auth/azure/login")).andExpect(method(HttpMethod.POST)) .andExpect(jsonPath("$.role").value("dev-role")).andExpect(jsonPath("$.jwt").value("my-token")) .andExpect(jsonPath("$.subscription_id").value("foobar-subscription")) .andExpect(jsonPath("$.resource_group_name").value("vault")) .andExpect(jsonPath("$.vm_name").value("vault-client")) + .andExpect(jsonPath("$.vmss_name").value("")) + .andRespond(withSuccess().contentType(MediaType.APPLICATION_JSON) + .body("{" + "\"auth\":{\"client_token\":\"my-token\"}" + "}")); + } + + private void expectVmssLoginRequest() { + + this.mockRest.expect(requestTo("/auth/azure/login")).andExpect(method(HttpMethod.POST)) + .andExpect(jsonPath("$.role").value("dev-role")).andExpect(jsonPath("$.jwt").value("my-token")) + .andExpect(jsonPath("$.subscription_id").value("foobar-subscription")) + .andExpect(jsonPath("$.resource_group_name").value("vault")) + .andExpect(jsonPath("$.vm_name").value("vault-client-scale-set_0")) + .andExpect(jsonPath("$.vmss_name").value("vault-client-scale-set")) .andRespond(withSuccess().contentType(MediaType.APPLICATION_JSON) .body("{" + "\"auth\":{\"client_token\":\"my-token\"}" + "}")); }