Continuous Deployment with VSTS/TFS and App Service Environment (ASE)


My colleague Harshal Dharia and I have been exploring workflows for CI/CD using VSTS or TFS when using Azure App Service Environment (ASE). In this blog post, I provide some templates to illustrate this workflow.

The Azure App Service Environment (ASE) allows you to deploy Azure Web Apps into a private environment for enhanced security and access control. One challenge with this configuration is how to orchestrate Continuous Integration and Continuous Deployment (CI/CD) with Visual Studio Team Services (VSTS) or Team Foundation Server (TFS) into such environments. If you are unfamiliar with VSTS and CI/CD pipelines to Azure Web Apps, please see the VSTS Documentation and Tutorials for more details.

It is possible to let the Web Applications pull the application in from DropBox, etc., but that makes it a little less elegant to use VSTS/TFS for CI/CD. The solution to this problem is to deploy a VSTS/TFS build agent into the Virtual Network where the ASE is deployed and let that agent do the deployment. The VSTS/TFS agent does not need to be accessible from the internet. If you are using VSTS, the agent needs only outbound access to connect to VSTS. If you are using TFS deployed in a Virtual Network as described in a couple of my previous blog posts here (simple deployment)  and here (high-availability deployment), the agent can be completely isolated.

The proposed configuration looks like this:

When configuring the agent, it needs to know the DNS configuration of the Web App it is to deploy to. Since the private resources in the Virtual Network don't have entries in Azure DNS, you need to add the information to the hosts file on the agent machine. I have made a template for deploying the agent into the Virtual Network. The agent is configured with this Powershell DSC script; feel free to grab it and modify for your scenario. The template requires URL information for the VSTS/TFS instance and you need to have an Agent Pool and PA Token ready to allow the agent to join. Note, this template is only for deploying the agent, it assumes you have an ASE set up already.

I have also created an ASE DevOps template that deploys the complete scenario (including ASE and JumpBox) illustrated above. This template will take a while (on the order of one hour) to deploy, since deploying an ASE takes some time. The template requires a number of parameters (including a string blob for the SSL certificate). The repository includes a convenience script that will help you assemble the necessary components. It will also generate a self-signed certificate for your domain if you do not provide one. To use the script, issues a command like:

.\scripts\PrepareAseDeployment.ps1 -DomainName mydomain-internal.us `
-TSServerUrl "https://<VSTSPROJECT>.visualstudio.com" -AdminUsername EnterpriseAdmin`
-AgentPool <NAME OF POOL> -PAToken <PA Token for VSTS/TFS> `
-OutFile C:\temp\myase-devops.parameters.json

When the deployment is complete, you should be able to log into your VSTS or TFS instance and see that the build agent is registered in the agent pool:

You can then configure a Deployment Configuration that uses the associated agent pool:

If you have used a self-signed certificate for the ASE configuration, you will need to set the option "-allowUntrusted" for MSDeploy:

It is also recommended to set the variable VSTS_ARM_REST_IGNORE_SSL_ERRORS to true. If you have deployed your ASE with appropriate certificated from a certificate authority, this should not be necessary.

And that is it. Let me know if you have questions/comments/suggestions or you run into problems deploying.

Comments (7)

  1. Alex Beloff says:

    Where is this -allowUntrusted in the latest “Deploy Azure App Service” should be set?

    1. First check “Publish using Web Deploy” and the box will show up, just like the screenshot.

  2. Phydeauxman says:

    How does you approach differ from using the approach in the article below:
    https://docs.microsoft.com/en-us/vsts/build-release/concepts/definitions/release/deployment-groups/howto-provision-deployment-group-agents?view=vsts

    I have not been able to make your approach work yet…we use Terraform for deploying resources into Azure so I am sure it is a syntax issue. But, I have never had much luck with DSC. The article below seems like it might be easier to get working. It still uses a Custom Script Extension but the Publisher Microsoft.VisualStudio.Services is and the Type is TeamServicesAgent.

    1. @Phydeauxman, I think of deployment groups as groups of virtual machines that you would like to deploy code to. So specifically you may have a web server farm and you want to push code to 5 out of your VMs (or physical machines). You install the agent on the machines where you want to deploy and push the code to the machine hosting the agent. The scenario described here is for deploying to an Azure Web App running in an isolated App Service Environment (ASE). A Web App is not a VM, you don’t install the agent on the web server itself, it runs on a separate machine that pushes the code. In this case, because the Web App is isolated, you have to put a VM with the agent into the virtual network. Hope this helps. Feel free to reach out if you need to discuss further.

      1. Phydeauxman says:

        Thanks for the reply and great explanation. I honestly did not understand the difference before your response but had found there were things I could not do with a Deployment Group that I could do with an agent. Sure wish they would come up with an extension to easily deploy the agent like they did for the Deployment Group.

  3. Phydeauxman says:

    A better solution to creating host entries on the VM running the Build agent is to create a Private DNS zone in the vnet where the VM/ASE are deployed into and then adding records for the ASE app into the Private Zone. After figuring out how to manually create an Extension using your PS1, I was able to eliminate the host records and the need for the xNetworking resource by using the Private DNS zone. The sample app we are using for testing is a .NET Core app. The initial Build worked because it uses a Hosted Agent to create the build and the hosted agent machines have all of the necessary software. Once I switched it to use the Private agent we deployed, Builds started failing because we did not have .NET Core 2.0 framework installed. Going to add this to your PS1 file as well as the install of .NET 3.5 which is required for WebDeploy.exe.

    1. Good point about Private Zones. They are currently in preview and not available in Azure Government where I do a lot of my work, so I didn’t use them here. But certainly an option for organizations that have access to those features.

Skip to main content