Skip to content

Latest commit

 

History

History
234 lines (177 loc) · 25 KB

File metadata and controls

234 lines (177 loc) · 25 KB

This documentation covers the deployment of the infrastructure to host the app.

Azure infrastructure

The infrastructure is managed using Terraform.
The state is stored remotely in encrypted Azure storage.
Terraform workspaces are used to separate environments.

Configuring the storage backend

The Terraform state is stored remotely in Azure, this allows multiple team members to make changes and means the state file is backed up. The state file contains sensitive information so access to it should be restricted, and it should be stored encrypted at rest.

Create a new storage backend

This step only needs to be done once per project (eg. not per environment). If it has already been created, obtain the storage backend attributes and skip to the next step.

The Azure tutorial outlines the steps to create a storage account and container for the state file. You will need:

  • resource_group_name: The name of the resource group used for the Azure Storage account.
  • storage_account_name: The name of the Azure Storage account.
  • container_name: The name of the blob container.
  • key: The name of the state store file to be created.
Create a backend configuration file

Create a new file named backend.vars with the following content:

resource_group_name  = [the name of the Azure resource group]
storage_account_name = [the name of the Azure Storage account]
container_name       = [the name of the blob container]
key                  = "terraform.tstate"
Install dependencies

We can use Homebrew to install the dependecies we need to deploy the infrastructure (eg. tfenv, Azure cli). These are listed in the Brewfile

to install, run:

$ brew bundle
Log into azure with the Azure CLI

Log in to your account:

$ az login

Confirm which account you are currently using:

$ az account show

To list the available subscriptions, run:

$ az account list

Then if needed, switch to it using the 'id':

$ az account set --subscription <id>
Initialise Terraform

Install the required terraform version with the Terraform version manager tfenv:

$ tfenv install

Initialize Terraform to download the required Terraform modules and configure the remote state backend to use the settings you specified in the previous step.

$ terraform init -backend-config=backend.vars

Create a Terraform variables file

Each environment will need it's own tfvars file.

Copy the terraform.tfvars.example to environment-name.tfvars and modify the contents as required

Create the infrastructure

Now Terraform has been initialised you can create a workspace if needed:

$ terraform workspace new staging

Or to check what workspaces already exist:

$ terraform workspace list

Switch to the new or existing workspace:

$ terraform workspace select staging

Plan the changes:

$ terraform plan -var-file=staging.tfvars

Terraform will ask you to provide any variables not specified in an *.auto.tfvars file. Now you can run:

$ terraform apply -var-file=staging.tfvars

If everything looks good, answer yes and wait for the new infrastructure to be created.

Azure resources

Requirements

Name Version
terraform ~> 1.9
azapi ~> 1.13
azurerm ~> 4.0
statuscake ~> 2.1

Providers

No providers.

Modules

Name Source Version
azure_container_apps_hosting github.com/DFE-Digital/terraform-azurerm-container-apps-hosting v1.16.2
azurerm_key_vault github.com/DFE-Digital/terraform-azurerm-key-vault-tfvars v0.5.1
statuscake-tls-monitor github.com/dfe-digital/terraform-statuscake-tls-monitor v0.1.5

Resources

No resources.

Inputs

Name Description Type Default Required
azure_client_id Service Principal Client ID string n/a yes
azure_client_secret Service Principal Client Secret string n/a yes
azure_location Azure location in which to launch resources. string n/a yes
azure_subscription_id Service Principal Subscription ID string n/a yes
azure_tenant_id Service Principal Tenant ID string n/a yes
cdn_frontdoor_custom_domains Azure CDN Front Door custom domains. If they are within the DNS zone (optionally created), the Validation TXT records and ALIAS/CNAME records will be created list(string) [] no
cdn_frontdoor_enable_rate_limiting Enable CDN Front Door Rate Limiting. This will create a WAF policy, and CDN security policy. For pricing reasons, there will only be one WAF policy created. bool n/a yes
cdn_frontdoor_forwarding_protocol Azure CDN Front Door forwarding protocol string "HttpsOnly" no
cdn_frontdoor_host_redirects CDN Front Door host redirects [{ "from" = "example.com", "to" = "www.example.com" }] list(map(string)) [] no
cdn_frontdoor_origin_fqdn_override Manually specify the hostname that the CDN Front Door should target. Defaults to the Container App FQDN string "" no
cdn_frontdoor_origin_host_header_override Manually specify the host header that the CDN sends to the target. Defaults to the recieved host header. Set to null to set it to the host_name (cdn_frontdoor_origin_fqdn_override) string "" no
cdn_frontdoor_rate_limiting_duration_in_minutes CDN Front Door rate limiting duration in minutes number 5 no
cdn_frontdoor_rate_limiting_threshold Maximum number of concurrent requests before Rate Limiting policy is applied number n/a yes
cdn_frontdoor_vdp_destination_hostname Requires 'enable_cdn_frontdoor_vdp_redirects' to be set to 'true'. Hostname to redirect security.txt and thanks.txt to string "vdp.security.education.gov.uk" no
container_apps_allow_ips_inbound Restricts access to the Container Apps by creating a network security group rule that only allow inbound traffic from the provided list of IPs list(string) [] no
container_command Container command list(any) n/a yes
container_health_probe_protocol Use HTTPS or a TCP connection for the Container liveness probe string n/a yes
container_min_replicas Container min replicas number 1 no
container_port Container port number 3000 no
container_scale_http_concurrency When the number of concurrent HTTP requests exceeds this value, then another replica is added. Replicas continue to add to the pool up to the max-replicas amount. number 10 no
container_secret_environment_variables Container secret environment variables map(string) n/a yes
custom_container_apps Custom container apps, by default deployed within the container app environment managed by this module.
map(object({
container_app_environment_id = optional(string, "")
resource_group_name = optional(string, "")
revision_mode = optional(string, "Single")
container_port = optional(number, 0)
ingress = optional(object({
external_enabled = optional(bool, true)
target_port = optional(number, null)
traffic_weight = object({
percentage = optional(number, 100)
})
cdn_frontdoor_custom_domain = optional(string, "")
cdn_frontdoor_origin_fqdn_override = optional(string, "")
cdn_frontdoor_origin_host_header_override = optional(string, "")
enable_cdn_frontdoor_health_probe = optional(bool, false)
cdn_frontdoor_health_probe_protocol = optional(string, "")
cdn_frontdoor_health_probe_interval = optional(number, 120)
cdn_frontdoor_health_probe_request_type = optional(string, "")
cdn_frontdoor_health_probe_path = optional(string, "")
cdn_frontdoor_forwarding_protocol_override = optional(string, "")
}), null)
identity = optional(list(object({
type = string
identity_ids = list(string)
})), [])
secrets = optional(list(object({
name = string
value = string
})), [])
registry = optional(object({
server = optional(string, "")
username = optional(string, "")
password_secret_name = optional(string, "")
identity = optional(string, "")
}), null),
image = string
cpu = number
memory = number
command = list(string)
liveness_probes = optional(list(object({
interval_seconds = number
transport = string
port = number
path = optional(string, null)
})), [])
env = optional(list(object({
name = string
value = optional(string, null)
secretRef = optional(string, null)
})), [])
min_replicas = number
max_replicas = number
}))
{} no
dns_mx_records DNS MX records to add to the DNS Zone
map(
object({
ttl : optional(number, 300),
records : list(
object({
preference : number,
exchange : string
})
)
})
)
{} no
dns_ns_records DNS NS records to add to the DNS zone
map(
object({
ttl : optional(number),
records : list(string)
})
)
{} no
dns_txt_records DNS TXT records to add to the DNS zone
map(
object({
ttl : optional(number),
records : list(string)
})
)
{} no
dns_zone_domain_name DNS zone domain name. If specified, records will automatically be created to point to the CDN. string n/a yes
enable_cdn_frontdoor Enable Azure CDN FrontDoor. This will use the Container Apps endpoint as the origin. bool n/a yes
enable_cdn_frontdoor_health_probe Enable CDN Front Door health probe bool false no
enable_cdn_frontdoor_vdp_redirects Deploy redirects for security.txt and thanks.txt to an external Vulnerability Disclosure Program service bool true no
enable_container_app_file_share Create an Azure Storage Account and File Share to be mounted to the Container Apps bool false no
enable_container_health_probe Enable liveness probes for the Container bool n/a yes
enable_container_registry Set to true to create a container registry bool false no
enable_dns_zone Conditionally create a DNS zone bool n/a yes
enable_event_hub Send Azure Container App logs to an Event Hub sink bool false no
enable_health_insights_api Deploys a Function App that exposes the last 3 HTTP Web Tests via an API endpoint. 'enable_app_insights_integration' and 'enable_monitoring' must be set to 'true'. bool false no
enable_logstash_consumer Create an Event Hub consumer group for Logstash bool false no
enable_monitoring Create an App Insights instance and notification group for the Container App bool n/a yes
enable_mssql_database Set to true to create an Azure SQL server/database, with aprivate endpoint within the virtual network bool n/a yes
enable_redis_cache Set to true to create a Redis Cache bool n/a yes
enable_worker_container Conditionally launch a worker container. This container uses the same image and environment variables as a the default container app, but allows a different container commanmd to be ran. The worker container does not expose any ports. bool n/a yes
environment Environment name. Will be used along with project_name as a prefix for all resources. string n/a yes
eventhub_export_log_analytics_table_names List of Log Analytics table names that you want to export to Event Hub. See https://learn.microsoft.com/en-gb/azure/azure-monitor/logs/logs-data-export?tabs=portal#supported-tables for a list of supported tables list(string) [] no
existing_logic_app_workflow Name, and Resource Group of an existing Logic App Workflow. Leave empty to create a new Resource
object({
name : string
resource_group_name : string
})
{
"name": "",
"resource_group_name": ""
}
no
existing_network_watcher_name Use an existing network watcher to add flow logs. string n/a yes
existing_network_watcher_resource_group_name Existing network watcher resource group. string n/a yes
health_insights_api_cors_origins List of hostnames that are permitted to contact the Health insights API list(string)
[
"*"
]
no
health_insights_api_ipv4_allow_list List of IPv4 addresses that are permitted to contact the Health insights API list(string) [] no
image_name Image name string n/a yes
key_vault_access_ipv4 List of IPv4 Addresses that are permitted to access the Key Vault list(string) n/a yes
monitor_email_receivers A list of email addresses that should be notified by monitoring alerts list(string) n/a yes
monitor_endpoint_healthcheck Specify a route that should be monitored for a 200 OK status string n/a yes
mssql_azuread_admin_object_id Object ID of a User within Azure AD that you want to assign as the SQL Server Administrator string n/a yes
mssql_azuread_admin_username Username of a User within Azure AD that you want to assign as the SQL Server Administrator string n/a yes
mssql_database_name The name of the MSSQL database to create. Must be set if enable_mssql_database is true string n/a yes
mssql_firewall_ipv4_allow_list A list of IPv4 Addresses that require remote access to the MSSQL Server
map(object({
start_ip_range : string,
end_ip_range : optional(string, "")
}))
{} no
mssql_managed_identity_assign_role Assign the 'Storage Blob Data Contributor' Role to the SQL Server User-Assigned Managed Identity. Note: If you do not have 'Microsoft.Authorization/roleAssignments/write' permission, you will need to manually assign the 'Storage Blob Data Contributor' Role to the identity bool false no
mssql_server_admin_password The local administrator password for the MSSQL server string n/a yes
mssql_server_public_access_enabled Enable public internet access to your MSSQL instance. Be sure to specify 'mssql_firewall_ipv4_allow_list' to restrict inbound connections bool false no
mssql_sku_name Specifies the name of the SKU used by the database string "Basic" no
project_name Project name. Will be used along with environment as a prefix for all resources. string n/a yes
redis_cache_sku Redis Cache SKU string "Basic" no
redis_config Overrides for Redis Cache Configuration options
object({
maxmemory_reserved : optional(number),
maxmemory_delta : optional(number),
maxfragmentationmemory_reserved : optional(number),
maxmemory_policy : optional(string),
})
{} no
registry_admin_enabled Do you want to enable access key based authentication for your Container Registry? bool false no
registry_managed_identity_assign_role Assign the 'AcrPull' Role to the Container App User-Assigned Managed Identity. Note: If you do not have 'Microsoft.Authorization/roleAssignments/write' permission, you will need to manually assign the 'AcrPull' Role to the identity bool false no
registry_server Container registry server string "" no
registry_use_managed_identity Create a User-Assigned Managed Identity for the Container App. Note: If you do not have 'Microsoft.Authorization/roleAssignments/write' permission, you will need to manually assign the 'AcrPull' Role to the identity bool true no
statuscake_api_token API token for StatusCake string "00000000000000000000000000000" no
statuscake_contact_group_email_addresses List of email address that should receive notifications from StatusCake list(string) [] no
statuscake_contact_group_integrations List of Integration IDs to connect to your Contact Group list(string) [] no
statuscake_contact_group_name Name of the contact group in StatusCake string "" no
statuscake_monitored_resource_addresses The URLs to perform TLS checks on list(string) [] no
storage_account_ipv4_allow_list A list of public IPv4 address to grant access to the Storage Account list(string) [] no
storage_account_public_access_enabled Should the Azure Storage Account have Public visibility? bool false no
tags Tags to be applied to all resources map(string) n/a yes
tfvars_filename tfvars filename. This file is uploaded and stored encrupted within Key Vault, to ensure that the latest tfvars are stored in a shared place. string n/a yes
virtual_network_address_space Virtual network address space CIDR string n/a yes
worker_container_command Container command for the Worker container. enable_worker_container must be set to true for this to have any effect. list(string) n/a yes
worker_container_max_replicas Worker container max replicas number 1 no

Outputs

No outputs.