Mitigate RDP attacks on Azure VM’s with Just-in-Time Access

Introduction

There are organizations who have migrated some of their on-premise machines to the Cloud of Azure, because it can reduce the workload. What’s great about this is the fact, that you don’t need to maintain all the physical hardware anymore.

However it’s becomes a shared responsibility, when you have resources running in Azure. This means that you’re still responsible for tasks, such as configuring, patching, installing software, and of course. Securing it as well, but Microsoft has done a lot by providing all the security tools to you need to make your life much easier.

One of those tools is the Just-In-Time access that can mitigate brute-force attacks on your Azure virtual machines. Yes, I’m aware of Azure Bastion, but I won’t cover it in this blog post.

We know that exposing RDP to the internet is a security risk, because it gives attackers a management port, that they can target to establish a foothold in an environment.

Despite the fact that it’s a huge risk. There are many machines with RDP exposed to the internet, which clearly tells that the awareness around this topic isn’t clear for everybody.

When taking a look how many Azure virtual machines have RDP exposed to the internet. We can see a lot as well, but I’m pretty sure the numbers will increase. Do all of them have additional security measures like Just-in-Time Access for example?

McAfee has released in 2019 an article about how RDP is the most common attack vector in ransomware attacks. Attackers would brute-force the management port, get initial access, and move laterally across a victim’s network.

  • Just-In-Time Access

Let’s say that you did had valid reasons to ”really” open RDP to the internet. It means that the machine becomes immediately a target for attackers. However, that doesn’t mean that a virtual machine needs to be 24/7 available for everyone on the internet.

Just-In-Time Access provides organizations, the need to grant access to a system for a specific period of time. When JIT is enabled on a virtual machine. It will create NSG rule(s) to block inbound traffic for the selected port(s), and if a user wants to request access to a virtual machine. Security Center will take a look to see if the user has the permissions to request access.

If the request has been approved, Security Center will allow inbound traffic to the selected ports and the requested source IP address(es) or ranges, but only for the amount of time that it has been specified.

After the time has been expired, Security Center will restore the NSG rules to it’s previous state, which means that it will block inbound traffic again to the selected ports.

What I like about JIT is that it provides the principle of least-privileges. Users only get access for the minimum amount of time they need it, and it automatically removes the access when time has expired. Access can be granted for a few hours to a few months, depending how it has been configured.

  • Configure Just-In-Time Access

We are now going to configure a JIT Access Policy on the SQLSERVER003 machine that is located in the SQLLab Resource group, where we specify that RDP (3389) is only allowed for 3 hours after someone has request access, and it has been approved by the Security Center.

Connect-AzAccount

$JitPolicy = (@{
>>  id="/subscriptions/SUBSCRIPTIONID/resourceGroups/SQLLab/providers/Microsoft.Compute/virtualMachines/SQLSERVER003"
>> ports=(@{
>>      number=3389;
>>      protocol="*";
>>      allowedSourceAddressPrefix=@("*");
>>      maxRequestAccessDuration="PT3H"})})

Insert the VM just-in-time VM access policy to an array

$JitPolicyArr=@($JitPolicy)

Now the final step is to configure the JIT Access Policy on the selected virtual machine, which is in this case. SQLSERVER003.

Set-AzJitNetworkAccessPolicy -Kind "Basic" -Location "East US" -Name "default" -ResourceGroupName "SQLLab" -VirtualMachine $JitPolicyArr
  • Verify that RDP is not accessible anymore

Our JIT Access Policy has been set and we can verify that a NSG rule has been configured by the Security Center to block inbound traffic for port 3389 (RDP).

Security Center will create a NSG rule that starts with something like ”SecurityCenter-JITRule

Get-AzNetworkSecurityGroup -Name SQLSERVER003-nsg -ResourceGroupName SQLLab | Get-AzNetworkSecurityRuleConfig -Name "SecurityCenter-JITRule_1559496662_516D0FA5FCF242E58FAE96122DB6EF4A"

Now when we’re trying to RDP in to our machine, we can’t.

mstsc /v:IPADDRESS
  • Grant rights to request access

A user needs to have the rights before access can be requested to a virtual machine, but it was pretty vague how this was documented, and because of this. I’ve decided to figure out what rights are really required to make this work. I did have read the JIT doc of Microsoft, but it didn’t work for me. I wasn’t the only one that struggled with this problem.

The first thing you need to do is create a custom role with the following permissions at the Resource Group that manages your JIT virtual machine.

A JSON file needs to be created where you specify all the information, such as the name of the group, description, and of course. All the permissions that are required. I will save this JSON file in the C:\Temp directory.

{
  "Name": "JIT-Requestor",
  "Id": null,
  "IsCustom": true,
  "Description": "Users can request access to JIT virtual machines",
  "Actions": [
    "Microsoft.Security/locations/jitNetworkAccessPolicies/read",
    "Microsoft.Security/locations/jitNetworkAccessPolicies/write",
    "Microsoft.Security/locations/jitNetworkAccessPolicies/initiate/action",
    "Microsoft.Compute/virtualMachines/read",
    "Microsoft.Network/networkInterfaces/read",
    "Microsoft.Compute/virtualMachines/write",
    "Microsoft.Network/networkInterfaces/write"
  ],
  "NotActions": [
  ],
  "AssignableScopes": [
    "/subscriptions/SUBSCRIPTIONID/resourceGroups/SQLLab"
  ]
}

We are now going to create our custom role.

New-AzRoleDefinitation -InputFile "C:\Temp\CustomRoles.json"

Verify that the custom role has been created.

Get-AzRoleDefinition -Name JIT-Requestor

Now add a user to our custom role. In this example. I will add the user Alice to it.

New-AzureRmRoleAssignment -SignInName Alice@contoso.onmicrosoft.com -RoleDefinitionName "JIT-Requestor" -ResourceGroupName SQLLab

The last step is to add the user (Alice) to the Reader role at the current Azure subscription that manages all the resources in your tenant.

New-AzureRmRoleAssignment -SignInName Alice@contoso.onmicrosoft.com  -Scope "/subscriptions/SUBSCRIPTIONID" -RoleDefinitionName Reader

Request access to JIT virtual machine

Now Alice can request access through the Portal of Azure or via PowerShell.

Click on Security Center -> Just in time VM access -> SQLSERVER003 -> Request access

Security Center will take a look if you have the correct permissions and will flip a NSG rule to allow inbound connection for the selected port(s). You can even specify that RDP will only be allowed for a specific IP range or address.

We can now RDP again to our SQLSERVER003 machine as you can see.

  • Recommendation

If you have virtual machines running in Azure and there’s a reason to allow RDP to the internet. It is recommended to configure a JIT Access Policy for all the VM’s.

One thought on “Mitigate RDP attacks on Azure VM’s with Just-in-Time Access

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: