Skip to main content

Azure Subscription Linking

Introduction#

Azure subscription linking creates the required Rimo3 resources for testing with the Rimo3 Cloud platform in a customer's own Azure subscription. This enables applications being tested to have access to backend systems such as databases and license servers.

The Rimo3 resources that are created are:

  • The Gateway - which facilitates secure communication between the Web Host and the Task Tunners
  • Task Runners - the testing resources that execute test workloads
note

With the introduction of on demand task runner provisioning and deprovisioning task runners are only recreated when needed and are disposed of when no longer required.

Linking an Azure Subscription to a Rimo3 Tenant is done in 2 steps:

  1. Populate the settings.json file
  2. Execute the Create-R3AzureLinkedSubscription.ps1 script

The above files are described in detail below.

Understanding the settings.json file#

The settings.json file is used by the Tenant Creation Script to populate variables. Instead of having to edit the script directly, the variable information that is required to connect to the customer tenant and create the necessary resources is easily edited here.

A sample settings.json file is shown below.

settings.json
{
"AzureTenant": "1da88047-e243-4290-9cc0-4554d4a11ceb",
"AzureSubscription": "120cbf29-0ed0-431e-8232-d84ba4bccc79",
"AzureRegion": "UKSouth",
"AzureProjectName": "r3prj",
"TenantName": "Rimo3Tenant",
"HostUrl": "https://rimo3cloud.com",
"SubNetAddressPrefix": "10.3.0.0/24",
"RdpIpAddresses": [ "154.14.209.226" ],
}
  • AzureTenant is the tenant ID that can be found in the Azure Portal under Azure Active Directory – Tenant ID.
  • AzureSubscription is the subscription ID found in the Azure Portal under Subscriptions.
  • AzureRegion is used to specify where the Azure Region where the virtual machines necessary to use Rimo3 will be located.
  • AzureProjectName is supplied by Rimo3 and should not be edited. This is a prefix used by Rimo3 to identify resources created in the customer tenant by Rimo3. For example, the resource group created by the script would be r3prj-Rimo3Tenant-rg.
  • TenantName is supplied by Rimo3 and should not be changed. This refers to the tenant created by Rimo3 for the customer in the Rimo3 back end.
  • HostUrl is supplied by Rimo3 and should not be changed. This is the URL used by the Gateway virtual machine to communicate with Rimo3.
  • SubNetAddressPrefix The script will create a new subnet within the customer tenant. This information is supplied by the customer to align with their networking.
  • RdpipAddresses is used in the Network Security Group to secure RDP to only allow from the specified IP address(s). The prepopulated address is supplied by Rimo3 and is included for support but is not required. The customer can define a list of IP addresses for their own support and management or include both theirs and the Rimo3 address. The Gateway virtual machine is not given a public IP address.
important

settings.json must be saved to the same location as the resource creation script.

Understanding the Create-R3AzureLinkedSubscription.ps1 script#

This is the script that is run against the customer tenant to create the necessary Azure resources to be able to use Rimo3. The script uses only publicly available Azure PowerShell cmdlets. This section will break down each step of the PowerShell script.

  • To Successfully Run the Script the PowerShell execution policy must be set to Unrestricted:

    Set-ExecutionPolicy Unrestricted
  • The person running the script should be an Owner of the Azure subscription.

Connect to Azure Subscription & Assign Variables#

This section is connecting to Azure and importing the data from the settings.json and creating the variables that will be used in the rest of the script.

You will be prompted to "Remove all accounts and subscriptions in all sessions for the current user?" this is only clearing active connections to Azure to ensure that we login to the correct subscription in the next step. You will then be prompted for Azure credentials, these need to be for a user who is a Subscription Owner to ensure that the script can properly assign roles.

#Read the settings file containing all the necessary information to create the tenant resource group under the right azure tenant/subscription
$settings = Get-Content "settings.json" | Out-String | ConvertFrom-Json
Clear-AzContext
Connect-AzAccount -Tenant $settings.AzureTenant -Subscription $settings.AzureSubscription
$azureResources = @{
InfrastructureStorageAccountName = [string]::Concat($settings.AzureProjectName, "sa")
TenantStorageAccountName = [string]::Concat($settings.AzureProjectName, $settings.TenantName, "sa")
ResourceGroupName = [string]::Concat($settings.AzureProjectName, "-", $settings.TenantName, "-rg")
VNetName = [string]::Concat($settings.AzureProjectName, "-", $settings.TenantName, "-vnet")
SubNetName = [string]::Concat($settings.AzureProjectName, "-", $settings.TenantName, "-default-subnet")
NsgName = [string]::Concat($settings.AzureProjectName, "-", $settings.TenantName, "-nsg")
GatewayVmName = [string]::Concat($settings.AzureProjectName, "-", $settings.TenantName, "-gw-vm")
GatewayNetworkInterfaceCardName = [string]::Concat($settings.AzureProjectName, "-", $settings.TenantName, "-gw-nic")
FileShareName = "customerarea"
}

Provide Credentials#

Here the customer is prompted for two sets of credentials:

  • The first prompt for credentials will be for the Gateway virtual machine that will be created. This is provided by the customer and can be whatever they prefer. This account is used to autologin and allow the Gateway components to run.

  • The second set of credentials are the credentials created by the customer when they registered on the Rimo3 Portal. These credentials are used to register the Gateway with the Rimo3 Portal.

$gatewayCredential = Get-Credential -Message "Credentials are required for the gateway virtual machine we're about to create."
$rimo3Credential = Get-Credential -Message "Rimo3 credentials are required to auto register gateway."
$customData = @{
Tenant = $settings.TenantName
UserEmail = $rimo3Credential.UserName
Password = $rimo3Credential.GetNetworkCredential().Password
AgentName = [string]::Concat($settings.TenantName, "_GW")
RegionName = $settings.AzureRegion
AdminUserName = $gatewayCredential.UserName
AdminPassword = $gatewayCredential.GetNetworkCredential().Password
ComputerName = [string]::Concat($settings.TenantName, "-gw")
}
$customDataJsonString = $customData | ConvertTo-Json

Resource Group, Storage Account and File Share Creation#

These next few sections the script is creating the resource group, a storage account, file share and saving the Access Key to the Key Vault.

note

By default, the file share has a quota of 50GB but the quota can be edited or the Quota line can be removed as preferred (see below).

Write-Host "About to create resource group: $($azureResources.ResourceGroupName)"
New-AzResourceGroup -Name $azureResources.ResourceGroupName -Location $settings.AzureRegion -Tag @{ Empty=$null; Money=$settings.AzureProjectName }
Write-Host "About to create storage account: $($azureResources.TenantStorageAccountName)"
New-AzStorageAccount -ResourceGroupName $azureResources.ResourceGroupName `
-Name $azureResources.TenantStorageAccountName `
-Location $settings.AzureRegion `
-SkuName Standard_LRS `
-Kind StorageV2
Write-Host "About to create file share"
New-AzRmStorageShare `
-ResourceGroupName $azureResources.ResourceGroupName `
-StorageAccountName $azureResources.TenantStorageAccountName `
-Name $azureResources.FileShareName `
-QuotaGiB 50 | Out-Null
try
{
Write-Host "About to push storage account Key1 to KeyVault"
$tenantStorageAccountKey = ((Get-AzStorageAccountKey -ResourceGroupName $azureResources.ResourceGroupName -AccountName $azureResources.TenantStorageAccountName) | Where-Object {$_.KeyName -eq "key1"}).Value
$body = "{
`n `"Tenant`": `"$($settings.TenantName)`",
`n `"UserEmail`": `"$($rimo3Credential.UserName)`",
`n `"Password`": `"$($rimo3Credential.GetNetworkCredential().Password)`",
`n `"StorageAccountAccessKey`": `"$tenantStorageAccountKey`"
`n}"
$uri = [String]::Concat($settings.HostUrl, "/api/storageRegistration/register")
$response = Invoke-RestMethod $uri -Method 'POST' -Body $body -ContentType 'application/json'
}
catch
{
Write-Host "Unable to add the Storage Account Access Key to the Azure Storage Vault. This is likely because the script is being run from behind a proxy server or firewall. The key can be added manually via the Edit Tenant screen in your Rimo3 Cloud Tenant. You will need Admin rights to your tenant to set the Storage Account Access Key." -ForegroundColor Red
Write-Host "Exception: " -ForegroundColor Red -NoNewline
Write-Host $_ -ForegroundColor Red
}
info

Proxy servers can sometimes prevent the Access Key from being saved to the Azure Key Vault. If an error occurs stating "Unable to add the Storage Account Access Key to the Azure Storage Vault" then you can manually add the Access Key via the Edit Tenant screen in your Rimo3 Cloud Tenant. You will need Admin rights to your tenant to set the Storage Account Access Key.

Subnet, Network Security Group, and virtual Network Card#

These sections create the Subnet, Network Security Group and rules, and the virtual network card.

  • There is an inbound and outbound rule named SignalR that is for communication between the Gateway and Rimo3 portal. The port used is 5000.

  • There is an Inbound RDP rule to allow the RDPIPAddress specified in the settings.json file to be able to access the subnet through port 3389 but there is no public IP address assigned to the virtual machine.

note

The rule is in place if support by Rimo3 is required and access to the Gateway is required. At that time, a public IP can be assigned temporarily for support.

Write-Host "About to create subnet"
$subnet = New-AzVirtualNetworkSubnetConfig -Name $azureResources.SubNetName -AddressPrefix $settings.SubnetAddressPrefix
Write-Host "About to create virtual network"
$virtualNetwork = New-AzVirtualNetwork -Name $azureResources.VNetName -ResourceGroupName $azureResources.ResourceGroupName -Location $settings.AzureRegion -AddressPrefix $settings.SubnetAddressPrefix -Subnet $subnet
Write-Host "About to create network security group"
$nsg = New-AzNetworkSecurityGroup -ResourceGroupName $azureResources.ResourceGroupName -Location $settings.AzureRegion -Name $azureResources.NsgName
# Get the NSG resource
$nsg = Get-AzNetworkSecurityGroup -Name $azureResources.NsgName -ResourceGroupName $azureResources.ResourceGroupName
# Add the inbound security rule.
Write-Host "Adding RDP inbound rule"
$nsg | Add-AzNetworkSecurityRuleConfig -Name "RDP" -Description "Allow RDP port" -Access Allow `
-Protocol * -Direction Inbound -Priority 101 -SourceAddressPrefix $settings.RdpIpAddresses -SourcePortRange * `
-DestinationAddressPrefix * -DestinationPortRange "3389"
# Add the inbound security rule.
Write-Host "Adding SignalR inbound rule"
$nsg | Add-AzNetworkSecurityRuleConfig -Name "SignalR_in" -Description "Allow SignalR_in port" -Access Allow `
-Protocol * -Direction Inbound -Priority 201 -SourceAddressPrefix "*" -SourcePortRange * `
-DestinationAddressPrefix * -DestinationPortRange "5000"
# Add the outbound security rule.
Write-Host "Adding SignalR outbound rule"
$nsg | Add-AzNetworkSecurityRuleConfig -Name "SignalR_out" -Description "Allow SignalR_out port" -Access Allow `
-Protocol * -Direction Outbound -Priority 401 -SourceAddressPrefix "*" -SourcePortRange * `
-DestinationAddressPrefix * -DestinationPortRange "5000"
# Update the NSG.
Write-Host "Updating NSG"
$nsg | Set-AzNetworkSecurityGroup

Gateway Virtual Machine Creation and Role Assignment#

The last part of the script creates the Gateway virtual machine, assigns a custom extension to configure the virtual machine after it boots, and then assigns the Gateway as ‘Owner’ of the resource group. This is accomplished by enabling system managed identity which gives it its own entry in the customers Azure Active Directory. the Gateway virtual machine This role is required for the Gateway to be able to create Task Runners and manage other tasks within the resource group as required.

System manage ID enabled so it will get an entry in the customers Azure Active Directory.

# Create a virtual network card and associate with NSG
Write-Host "Creating network interface: $($azureResources.GatewayNetworkInterfaceCardName)"
$nic = New-AzNetworkInterface -Name $azureResources.GatewayNetworkInterfaceCardName -ResourceGroupName $azureResources.ResourceGroupName -Location $settings.AzureRegion `
-SubnetId $virtualNetwork.Subnets[0].Id -NetworkSecurityGroupId $nsg.Id
# Create a virtual machine configuration
Write-Host "Creating GW VM configuration with custom data"
$vmConfig = New-AzVMConfig -VMName $azureResources.GatewayVmName -VMSize Standard_B2s -IdentityType SystemAssigned | `
Set-AzVMOperatingSystem -Windows -ComputerName "$($settings.TenantName)-gw" -Credential $gatewayCredential -CustomData $customDataJsonString | `
Set-AzVMSourceImage -PublisherName MicrosoftWindowsServer -Offer WindowsServer -Skus 2019-Datacenter -Version latest | `
Add-AzVMNetworkInterface -Id $nic.Id
# Create a virtual machine
Write-Host "Creating GW Virtual Machine"
New-AzVM -ResourceGroupName $azureResources.ResourceGroupName -Location $settings.AzureRegion -VM $vmConfig
# Define custom script extension
Write-Host "Defining custom script extension"
$fileUri = @("https://$($azureResources.InfrastructureStorageAccountName).blob.core.windows.net/gwscripts/gw.ps1", "https://$($azureResources.InfrastructureStorageAccountName).blob.core.windows.net/gwscripts/Autologon.exe")
Set-AzVMCustomScriptExtension -ResourceGroupName $azureResources.ResourceGroupName -VMName $azureResources.GatewayVmName -Location $settings.AzureRegion -FileUri $fileUri -Run gw.ps1 -Name GWScriptExtension
# Identify Gateway VM resource
Write-Host "Retrieving GW resource"
$gatewayVm = Get-AzResource -ResourceGroupName $azureResources.ResourceGroupName -Name $azureResources.GatewayVmName
# Assign owner role for GW over tenant resource group
Write-Host "Assigning owner role to GW over resource group"
New-AzRoleAssignment -ObjectId $gatewayVm.Identity.PrincipalId `
-RoleDefinitionName "Owner" `
-ResourceGroupName $azureResources.ResourceGroupName

Further Information and Support#

For further information or if you have any issues with the resource creation script please contact technicalsupport@rimo3.com