Using Azure Functions to automate Just-in-time Access

Rick Jen
Microsoft Azure
Published in
4 min readApr 28, 2020
Mr. Brown Ave (伯朗大道), Taitung County, Taiwan (2020–01–01)

Update 2021–04–14: YouTube video version of this story in the Microsoft Security Community.

What is the problem we are trying to solve?

In Azure Security Center, you can lock down inbound traffic to your VMs with just-in-time (JIT) virtual machine (VM) access. This reduces exposure to attacks while providing easy access to connect to VMs when needed.

My customer recently implemented JIT for their Azure VMs (1500+) and raised the question of how to automate the JIT Access requests to VMs since there are so many maintenance tasks such as:

  • Invoke backup jobs on application VMs
  • Apply license/maintenance updates for virtual appliances

Those tasks require opening specific ports to allow traffic from specific IP addresses. Security Admins can manually approve the requests in Azure portal but it’s not practical since those maintenance tasks themselves are triggered by automation. Let’s see how we can automate the process with Azure Function App with a user-assigned identity.

By the end of this article, we will learn 3 things:

  1. What is Just-In-Time (JIT) Access and how to request for access.
  2. How to create a custom Azure AD RBAC role with just enough permissions to initiate JIT access.
  3. How to deploy a PowerShell Function App with user-assigned managed identity to initiate opening JIT Access.

How does JIT access work?

When JIT is enabled, Security Center locks down inbound traffic to your Azure VMs by creating an NSG rule. You select the ports on the VM to which inbound traffic will be locked down. These ports are controlled by the just-in-time solution.

When a user requests access to a VM, Security Center checks that the user has Role-Based Access Control (RBAC) permissions for that VM. If the request is approved, Security Center automatically configures the Network Security Groups (NSGs) and Azure Firewall to allow inbound traffic to the selected ports and requested source IP addresses or ranges, for the amount of time that was specified. After the time has expired, Security Center restores the NSGs to their previous states. Those connections that are already established are not being interrupted, however.

Let’s put the pieces together

Function App initiating JIT Access

The key component in the diagram above is the PowerShell Function App. It can be either HTTP-Triggered or Timer-Triggered to open up JIT access to VMs. The Function App has a user-assigned managed identity.

Create the Function App

Follow the instructions to create an HTTP-triggered Function App (with Runtime stack: PowerShell Core). If you need pre-warmed instances to avoid cold start, try Premium/Dedicated Plan instead of the default choice of Consumption Plan.

Let’s enable your Function app with user-assigned managed identity by following the instructions.

Take a note of the Client ID and Object ID of the managed identity, we will need those later:

What does the PowerShell Function do?

Your Function App should be deployed already, let’s use this run.ps1 from my GitHub repo as a reference. You can simply copy & paste into the editor in Azure portal and update the variables section based on your environment.

It basically does 2 things:

  1. Obtain the Access Token from Azure Active Directory (you will know why in the next section).
  2. Present the Access Token as the Bearer token while making our HTTP POST call to Security Center’s REST API endpoint. The JIT Access is submitted as JSON body.

Obtain the Access Token (refer to documentation, make sure to include &client_id=$UAMIClientId):

Obtain Access Token

Invoke HTTP POST to Security Center REST API:

HTTP POST

Security Team: “Wait! This function will open up port 22? Really?!”

In order for our Function app to initiate JIT access, we need to create a custom RBAC role with just enough permissions and proper scopes to JIT policies as well as to the target VM . See the following PowerShell example:

And then assign this custom role to the user assigned managed identity’s object ID (locate it in the Azure portal) you created earlier.

That’s it!

Once the Function app is triggered (either by HTTP or by a timer), the NSG inbound rule will be added to allow port 22 access from that specific IP address for 5 minutes (up to 24 hrs).

Test it with Postman

Since we are invoking HTTP POST to the Security Center REST API, let’s use Postman for a quick test:

Conclusion

This is a generic solution to automate JIT Access using Function App. You can simply change the ports and IP ranges in the function based on your requirement. If PowerShell is not your choice of language, you can easily implement the same REST calls in other languages such as Python.

Have fun with Azure ☁️ and Go Serverless!! 💪

--

--