azure-redcap-paas/terraform
Mat Carboni 859988e173
Adding resources to match terraform (#22)
* adding vnets, snets and snet delegation for mysql flex

* adding filestorage, keyvault, secrets and acls

* adding private dns zones, vnetlinks and private endpoints

* updating app service, adding AVD host pool

* fixing OS disk name

* adding vm extensions

* removing registratingTokenOperation

* adding ps1 for bicep deploy

* moving to separate azuredeploysecure, adding Microsoft.Web SE to integrationSubnet and computeSubnet

* fixing bicepdeploysecure to point to correct bicep file

---------

Co-authored-by: Matheus Carboni <mcarboni@microsoft.com>
2023-06-27 07:51:35 -07:00
..
ansible terraform 2021-07-23 12:27:31 -07:00
media terraform 2021-07-23 12:27:31 -07:00
workspaces terraform 2021-07-23 12:27:31 -07:00
.gitignore terraform 2021-07-23 12:27:31 -07:00
.terraform.lock.hcl Adding MySQL Flexible Server (#20) 2023-02-04 22:57:13 -08:00
README.md terraform 2021-07-23 12:27:31 -07:00
autoshutdown.json terraform 2021-07-23 12:27:31 -07:00
azure-pipelines.yml terraform 2021-07-23 12:27:31 -07:00
backend.tf Adding MySQL Flexible Server (#20) 2023-02-04 22:57:13 -08:00
locals.tf terraform 2021-07-23 12:27:31 -07:00
main.tf Adding resources to match terraform (#22) 2023-06-27 07:51:35 -07:00
outputs.tf terraform 2021-07-23 12:27:31 -07:00
variables.tf Adding MySQL Flexible Server (#20) 2023-02-04 22:57:13 -08:00

README.md

Secure REDCap on Azure

This repo will deploy REDCap on Azure using Terraform. The Terraform configuration will provision all the infrastructure with necessary security controls in place. This repo assumes you have a hub/spoke network topology in place in Azure and this REDCap deployment will be a spoke within your overall Azure architecture. Once the infrastructure has been provisioned, you will need to establish a virtual network peering from the hub virtual network back to the REDCap virtual network and deploy source code to get the application up and running. From there, you can run the Ansible playbook (inventory file gets generated as part of this deployment) to configure Azure Virtual Desktop (AVD) session hosts which is going to be used as our secure entry points to the REDCap backend system. The front end of REDCap (i.e., survey URLs) will be accessible through the Azure Front Door service.

Solution Architecture

This repo does not include any REDCap shared services such as Azure FrontDoor or SendGrid (the box in the upper right portion of the diagram above). That needs to be managed from a separate repository. If you do not have Azure Front Door in place, you can access the app service front end and kudu console while logged into the AVD session host.

Prerequisites

Before you begin, make sure you have the following:

  • Understanding of and/or experience with Terraform on Azure

  • Implementation of Azure Enterprise Scale Landing Zones

  • As part of Azure Landing Zone architecture, you should have Hub/Spoke network topology.

    • The hub virtual network (VNET) should have to have an Azure Firewall or 3rd party Network Virtual Applicance (NVA) in place.
    • If your Active Directory Domain Controller or Azure AD Domain Services is in another spoke network, you'll need to have proper User Defined Routes (UDR) in place to ensure transitive networking is enabled from the REDCap spoke networks and the AD servers.
  • Azure Storage Account or Terraform Cloud to store your remote state files.

    Once you have these in place, update the backend.tf file to include your backend implementation

  • REDCap Community site credentials which the deployment automation will use to pull your copy of the REDCap source directly from the community site.

    NOTE: These values will be stored within the Azure Key Vault and the values will not be displayed within the Azure App Service configuration settings.

  • Virtual Network address allocation for the REDCap resources and divided into Subnets. Here are the minimum CIDR ranges you'll need:

    The deployment relies on the subnet names listed below. If you decide to change these, make sure you replace all instances in main.tf.

    • /25 for the virtual network
    • /27 for PrivateLinkSubnet
    • /27 for ComputeSubnet
    • /26 for IntegrationSubnet
  • DNS IP address(es) for domain joining virtual machines (for AVD).

  • Firewall IP address for configuring UDRs.

    Make sure your firewall is configured to allow traffic to pass from and to the REDCap virtual networks. See this link if you are using Azure Firewall.

  • VNET peering information. More on vnet peering here.

    The Terraform configuration in this repo will perform the one-way peer from REDCap to your hub virtual network.

  • Route table (UDR) routes.

    Hub/Spoke topology means you may be relying on resources that are deployed in another spoke vnet within your overall network topology. If resources are in a spoke vnet, you'll need to send the traffic to the firewall in the hub for spoke-to-spoke transit networking. More on vnet traffic routing here.

Naming conventions

The resources provisioned using this repo will be named using the naming conventions as outlined in the Cloud Adoption Framework. See this link for more info

Workspaces

In order to maintain multiple REDCap deployments with this repo, a decision was made to manage each deployment config using .tfvars files and terraform workspaces. Terraform workspaces will allow you to keep all deployment state information in a single storage account but logically separated using workspaces. With each deployment, you'll need to ensure you are selecting the right workspace and using the right .tfvars file. This can get difficult to manage and there's a high possibility of human error.

The alternative would be to create branches for each deployment but managing code changes between branches can become cumbersome over time as well.

So, what get's deployed?

Provisioning REDCap Infrastructure

  1. Create a new .tfvars file and drop into the workspaces directory.

    • The name of your .tfvars file and the terraform workspace should be the same.
  2. Execute the terraform plan and terraform apply commands and pass in your .tfvars file in the -var-file parameter.

    • You will be required to enter the local VM username and password and the REDCap zip file URL.

    • Here is a sample terraform plan command:

      workspace=sample1
      terraform workspace select $(workspace) || terraform workspace new $(workspace)
      terraform plan -var-file="workspaces/$(workspace).tfvars" -var="vm_username=$(local-vm-username)" -var="vm_password=$(local-vm-password)" -var="redcapAppZip=$(redcapzip)" -out=$(System.DefaultWorkingDirectory)/$(workspace).tfplan
      
    • Here is a sample terraform apply command:

      terraform apply --auto-approve $(workspace).tfplan
      
  3. After the resources have been provisioned, you'll need to create a vnet peering back from the hub vnet to the REDCap's vnet.

    • This codebase will only apply one half of the peering (from REDCap vnet to the Hub).
  4. Next, deploy the source code from the github repo

    • The command to deploy the source is in the terraform output as deploy_source

    • To get the value of the deploy_source output variable use this command:

      terraform output -raw deploy_source
      

Configure REDCap WVD Workstations

Ansible can automate configuration on Windows machines; however, the Ansible playbooks must be run from a Linux OS (Ubuntu, REDHat, CentOS, etc.).

Configuration of secure workstations will be automated using Ansible. The site.yml Ansible Playbook found in this repo relies on a few variables needed to domain join your virtual machines. Rather then saving credentials to the repo (never a good thing) we'll use ansible-vault to encrypt contents leveraging Ansible Vault and pass in a secrets.yml file on the ansible-playbook run.

Let's start by creating a vault file:

ansible-vault create secrets.yml

Type in a new vault password and enter the following contents:

You're using vi here so make sure you hit the i key be in insert mode

dns_domain_name: <YOUR_DOMAIN_NAME>
domain_admin_user: <YOUR_DOMAIN_JOIN_USER>
domain_admin_password: <YOUR_DOMAIN_JOIN_PASSWORD>
domain_ou_path: <YOUR_DOMAIN_OU_PATH>

Save the file using the following command :wq

The file secrets.yml needs to be saved to your repository or downloaded as a secure file within your pipeline.

To use view the ansible vault file you'll need to enter the vault password to decrypt the contents. However, in a pipeline scenario, you will not have the opportunity to enter the pipeline at runtime, but you can use a file and point the ansible-vault to that. This is the approach we'll use for the pipeline.

Create a vaultpass file.

echo '<YOUR_ANSIBLE_VAULT_PASSWORD>' > vaultpass

To ensure you did all this properly, you can use the view subcommand of ansible-vault. This will decrypt the vault and display the contents you entered.

ansible-vault view secrets.yml --vault-password-file vaultpass

If all looks good, be sure the variable names aligns with the variables we'll use in our playbook. When you are ready to run the playbook, you will run it by passing in additional variables from your secrets.yml file. This will be denoted using the -e flag and since we are referencing a file, you'll need to add the @ symbol in front of the file name

ansible-playbook -i inventory-sample2 -e @secrets.yml --vault-password-file vaultpass site.yml

Resources:

Deleting REDCap

  • If you have deployed a Recovery Services Vault, you'll need to make sure to stop and delete your VM and file share backups, unregister your storage account from Backup Infrastructure, and remove the management lock on the resource group (if necessary) before running the terraform destroy command.
  • Be sure to delete the vnet peering from the hub to the REDCap instance
  • Be sure to delete the terraform workspace

Azure DevOps Pipeline

This repo comes with an azure-pipelines.yml file. To use it, you'll need to setup a Variable Group and add the following secrets. Ideally you will be storing these values in Azure Key Vault and using that to link secrets:

  • client-id - used by terraform
  • client-secret - used by terraform
  • tenant-id - used by terraform
  • main-subscription-id - this is the id of the subscription where your storage account where remote state file lives
  • local-vm-username - this will passed dynamically to the terraform apply command
  • local-vm-password - this will passed dynamically to the terraform apply command
  • redcapzip - this is the publically accessible (yet secure) URL to your REDCap zip file
  • ansible-vault-password - this is used to decrypt your ansible-vault without being prompted for a password

You should also provision a small Linux VM in your REDCap shared services subscription and install the self-hosted Azure DevOps Build Agent software on it. This way, you will be able to use your build machine to invoke the Ansible playbook against the new session host VMs using private IP addresses within your Azure virtual network.

Alternatively, if you do not want to manage another VM, you can follow this guide to run an Azure DevOps Build Agent in a container using Azure Container Instances within your virtual network.

Lastly, add pipeline variables called notifyUsers and workspace that can be set at queue time.