/* * Input: AzureResourceInformation, KeyVaultInformation, Logger * Get the necessary credential information for VM management and KeyVault access. */ private async Task Initialize(AzureResourceInformation resourceInfo, KeyVaultInformation vault, ILogger log) { var azureServiceTokenProvider = new AzureServiceTokenProvider(); _kv = new KeyVaultClient(new KeyVaultClient.AuthenticationCallback(azureServiceTokenProvider.KeyVaultTokenCallback)); string _id = (await _kv.GetSecretAsync(vault.KeyVaultUri, vault.KV_SecretName_ServicePrinciple)).Value; string _cred = (await _kv.GetSecretAsync(vault.KeyVaultUri, vault.KV_SecretName_ServicePrinciplePwd)).Value; // Get the LabResourceGroup resourceInfo.LabResourceGroup = ParseLabResourceGroup(resourceInfo.ResourceUri); resourceInfo.LabName = await GetLabName(resourceInfo, log); AzureCredentials _azureCred = SdkContext.AzureCredentialsFactory.FromServicePrincipal( _id, _cred, resourceInfo.TenantId, AzureEnvironment.AzureGlobalCloud); _msiazure = Azure.Authenticate(_azureCred).WithSubscription(resourceInfo.SubscriptionId); _clientCred = new ClientCredential(_id, _cred); var context = new AuthenticationContext($"https://login.windows.net/{resourceInfo.TenantId}", false); var token = await context.AcquireTokenAsync("https://management.azure.com/", _clientCred); _accessToken = token.AccessToken; }
// Determine the VM that the artifact is being applied to. private async Task <List <string> > GetArtifactInfoAsync(AzureResourceInformation resourceInfo) { List <string> computeId = new List <string>(); string[] expandProperty = new string[] { "$expand=properties($expand=artifacts)", "api-version=2018-10-15-preview" }; // Get the VMs var response = await new Url($"https://management.azure.com/subscriptions/{resourceInfo.SubscriptionId}/resourceGroups/{resourceInfo.LabResourceGroup}/providers/Microsoft.DevTestLab/labs/{resourceInfo.LabName}/virtualmachines") .WithOAuthBearerToken(_accessToken) .SetQueryParams(expandProperty) .GetStringAsync(); // Find the vm with the artifact has a status to Installing JObject vmsObject = JObject.Parse(response); JArray vms = (JArray)vmsObject.SelectToken("value"); foreach (JToken vm in vms.Children()) { // Check for the artifact and check for installing var targetVM = vm.SelectToken("$..artifacts[?(@.artifactTitle == '" + resourceInfo.ArtifactTitle + "' && @.status == 'Installing')]", false); if ((targetVM != null) && (targetVM.HasValues)) { computeId.Add(vm.SelectToken("properties.computeId").Value <string>()); } } return(computeId); }
/* * Input: EventGrid Event * Determine the necessary event - artifacts * Parse the information and if the correct artifact folder and lab populate the AzureResourceInformation */ private static AzureResourceInformation GetVmResourceId(EventGridEvent evnt) { AzureResourceInformation returnData = new AzureResourceInformation(); returnData.ArtifactTitle = GetEnvironmentVariable("DevTestLabArtifact"); returnData.ArtifactFolder = GetEnvironmentVariable("DevTestLabArtifactFolder"); //returnData.LabName = GetEnvironmentVariable("DevTestLabName"); if (StringComparer.OrdinalIgnoreCase.Equals(evnt.EventType, "Microsoft.Resources.ResourceActionSuccess") && evnt.Data is JObject data && data.TryGetValue("operationName", out var operation) && StringComparer.OrdinalIgnoreCase.Equals(operation.ToString(), "Microsoft.DevTestLab/labs/artifactsources/artifacts/generateArmTemplate/action")) { returnData.ResourceUri = data.SelectToken("resourceUri")?.ToString(); returnData.TenantId = data.SelectToken("tenantId")?.ToString(); returnData.SubscriptionId = data.SelectToken("subscriptionId")?.ToString(); if (!returnData.ResourceUri.Contains(returnData.ArtifactFolder)) { returnData.ResourceUri = null; } } return returnData; }
public AzureResourceManager(AzureResourceInformation resourceId, KeyVaultInformation kvInfo, ILogger log) { Initialize(resourceId, kvInfo, log).Wait(); if (!String.IsNullOrEmpty(resourceId.LabName)) { AddIMSIToVMAsync(resourceId, kvInfo, log).Wait(); } }
// Get the lab with the resource group that the CSE is executed in private async Task <string> GetLabName(AzureResourceInformation resourceInfo, Microsoft.Extensions.Logging.ILogger log) { try { string[] expandProperty = new string[] { "api-version=2018-10-15-preview" }; log.LogInformation("[EnableVmMSIFunction] Before Get Lab URL:" + DateTime.Now.ToString()); var response = await new Url($"https://management.azure.com/subscriptions/{resourceInfo.SubscriptionId}/providers/Microsoft.DevTestLab/labs") .WithOAuthBearerToken(_accessToken) .SetQueryParams(expandProperty) .GetStringAsync(); log.LogInformation("[EnableVmMSIFunction] After Get Lab URL:" + DateTime.Now.ToString()); log.LogInformation("[EnableVmMSIFunction] After Get Lab URL:" + response.ToString()); JObject vmsObject = JObject.Parse(response); log.LogInformation("[EnableVmMSIFunction] After JObject:" + DateTime.Now.ToString()); JArray vms = (JArray)vmsObject.SelectToken("value"); log.LogInformation("[EnableVmMSIFunction] After JArray:" + vms.Count.ToString() + " : " + DateTime.Now.ToString()); foreach (JToken lab in vms.Children()) { int first = 0; string labRg = ""; string labName = ""; log.LogInformation("[EnableVmMSIFunction] After ForEach:" + DateTime.Now.ToString()); // The vmCreationResourceGroupId is the property where the VMs are created. JToken rgId = lab.SelectToken("$.properties.vmCreationResourceGroupId"); if (rgId != null) { first = (rgId.ToString().IndexOf("resourceGroups/") + 15); labRg = rgId.ToString().Substring(first, (rgId.ToString().Length - first)); log.LogInformation("[EnableVmMSIFunction] After labName:" + labName + " : " + DateTime.Now.ToString()); if (labRg == resourceInfo.LabResourceGroup) { return(lab.SelectToken("name").ToString()); } } } } catch (Exception e) { log.LogInformation(e.Message); } return(null); }
public static void Run([EventGridTrigger]EventGridEvent eventGridEvent, ILogger log) { // Get Environment variables. KeyVaultInformation djSecrets = new KeyVaultInformation(); djSecrets.KeyVaultName = GetEnvironmentVariable("AzureKeyVaultName"); //azureKeyVaultName; djSecrets.KeyVaultUri = "https://" + djSecrets.KeyVaultName + ".vault.azure.net"; djSecrets.KeyVaultResourceGroup = GetEnvironmentVariable("AzureKeyVaultResourceGroup"); djSecrets.KV_SecretName_ServicePrinciple = GetEnvironmentVariable("AzureServicePrincipalIdSecretName"); djSecrets.KV_SecretName_ServicePrinciplePwd = GetEnvironmentVariable("AzureServicePrincipalCredSecretName"); // Handle Azure Events AzureResourceInformation resourceId = GetVmResourceId(eventGridEvent); if (!string.IsNullOrWhiteSpace(resourceId.ResourceUri)) { AzureResourceManager arm = new AzureResourceManager(resourceId, djSecrets, log); } log.LogInformation(eventGridEvent.Data.ToString()); }
// Enable the IMSI on the Vm and add the IMSI id to the keyvault access policy public async Task AddIMSIToVMAsync(AzureResourceInformation resourceInfo, KeyVaultInformation vault, ILogger log) { // Handle multiple VMs in the same lab List <string> allVms = await GetArtifactInfoAsync(resourceInfo); if (allVms.Count > 0) { foreach (string vmResourceId in allVms) { if (!string.IsNullOrWhiteSpace(vmResourceId)) { try { var vm = await _msiazure.VirtualMachines.GetByIdAsync(vmResourceId); if (!vm.IsManagedServiceIdentityEnabled) { // Don't await this call as issue where hangs, handle manually below vm.Update().WithSystemAssignedManagedServiceIdentity().ApplyAsync(); // Handle await manually. TimeSpan timeSpan = new TimeSpan(0, 0, 10); int counter = 0; await Task.Delay(timeSpan); while ((!vm.IsManagedServiceIdentityEnabled) || (String.IsNullOrEmpty(vm.SystemAssignedManagedServiceIdentityPrincipalId))) { counter++; await Task.Delay(timeSpan); log.LogInformation("[EnableVmMSIFunction] Enable IMSI loop:" + DateTime.Now.ToString()); await vm.RefreshAsync(); if (counter == 20) { break; } } } await vm.RefreshAsync(); // Get the keyvault var _keyVault = _msiazure.Vaults.GetByResourceGroup(vault.KeyVaultResourceGroup, vault.KeyVaultName); // Add access policy await _keyVault.Update() .DefineAccessPolicy() .ForObjectId(vm.SystemAssignedManagedServiceIdentityPrincipalId) .AllowSecretPermissions(SecretPermissions.Get) .Attach() .ApplyAsync(); // Remove after 4 min log.LogInformation("[EnableVmMSIFunction] Cleanup:" + DateTime.Now.ToString()); await RemoveAccess(vm, _keyVault, log); } catch (Exception e) { log.LogInformation("[EnableVmMSIFunction][Error] " + e.Message); } } } } }