Added VMSS support to Azure MSI Authentication

Fixes gh-614
Original pull request: gh-615
This commit is contained in:
Willi Schönborn
2021-01-14 15:12:07 +01:00
committed by Mark Paluch
parent 27dc7c038d
commit f233f30779
3 changed files with 86 additions and 15 deletions

View File

@@ -169,11 +169,12 @@ public class AzureMsiAuthentication implements ClientAuthentication {
private static Map<String, String> getAzureLogin(String role, AzureVmEnvironment vmEnvironment, String jwt) {
Map<String, String> 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<String, String> 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);
}
}

View File

@@ -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;
}
}

View File

@@ -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\"}" + "}"));
}