Skip to content

Commit

Permalink
ER-790: Azure Refinements (#805)
Browse files Browse the repository at this point in the history
* ER-790: Autoscaling rules

* ER-790: Seed Development database

* ER-790: Global Firewall Rule

* ER-790: Generate Terraform variables

* ER-790: Lowercase variables

---------

Co-authored-by: Sunny Sidhu <[email protected]>
  • Loading branch information
sunny-sidhu-and and sunny-sidhu-and authored Sep 5, 2023
1 parent c8c2f63 commit 21e9c12
Show file tree
Hide file tree
Showing 8 changed files with 168 additions and 67 deletions.
61 changes: 20 additions & 41 deletions .github/workflows/tf-azure-deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,47 +32,6 @@ env:
ARM_CLIENT_ID: ${{ secrets.AZURE_CLIENT_ID }}
ARM_SUBSCRIPTION_ID: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
ARM_TENANT_ID: ${{ secrets.AZURE_TENANT_ID }}
TF_VAR_environment: ${{ vars.ENVIRONMENT }}
TF_VAR_resource_name_prefix: ${{ vars.RESOURCE_PREFIX }}
TF_VAR_kv_certificate_authority_username: ${{ secrets.CERTIFICATE_AUTHORITY_USERNAME }}
TF_VAR_kv_certificate_authority_password: ${{ secrets.CERTIFICATE_AUTHORITY_PASSWORD }}
TF_VAR_kv_certificate_authority_admin_email: ${{ vars.CERTIFICATE_AUTHORITY_ADMIN_EMAIL }}
TF_VAR_kv_certificate_authority_admin_first_name: ${{ secrets.CERTIFICATE_AUTHORITY_ADMIN_FIRST_NAME }}
TF_VAR_kv_certificate_authority_admin_last_name: ${{ secrets.CERTIFICATE_AUTHORITY_ADMIN_LAST_NAME }}
TF_VAR_kv_certificate_authority_admin_phone_no: ${{ secrets.CERTIFICATE_AUTHORITY_ADMIN_PHONE_NO }}
TF_VAR_kv_certificate_label: ${{ vars.CERTIFICATE_LABEL }}
TF_VAR_kv_certificate_subject: ${{ vars.CERTIFICATE_SUBJECT }}
TF_VAR_psqlfs_sku: ${{ vars.PSQLFS_SKU }}
TF_VAR_psqlfs_storage: ${{ vars.PSQLFS_STORAGE }}
TF_VAR_psqlfs_username: ${{ secrets.PSQLFS_USERNAME }}
TF_VAR_psqlfs_password: ${{ secrets.PSQLFS_PASSWORD }}
TF_VAR_psqlfs_geo_redundant_backup: ${{ vars.PSQLFS_GEO_REDUNDANT_BACKUP }}
TF_VAR_psqlfs_ha_enabled: ${{ vars.PSQLFS_HA_ENABLED }}
TF_VAR_asp_sku: ${{ vars.ASP_SKU }}
TF_VAR_webapp_worker_count: ${{ vars.WEBAPP_WORKER_COUNT }}
TF_VAR_webapp_name: ${{ vars.WEBAPP_NAME }}
TF_VAR_workerapp_name: ${{ vars.WORKERAPP_NAME }}
TF_VAR_reviewapp_name: ${{ vars.REVIEWAPP_NAME }}
TF_VAR_webapp_database_url: ${{ secrets.WEBAPP_DATABASE_URL }}
TF_VAR_webapp_docker_registry_url: https://ghcr.io
TF_VAR_webapp_docker_image: dfe-digital/early-years-foundation-recovery
TF_VAR_webapp_docker_image_tag: latest
TF_VAR_custom_domain_name: ${{ vars.CUSTOM_DOMAIN }}
TF_VAR_webapp_config_bot_token: ${{ secrets.WEBAPP_CONFIG_BOT_TOKEN }}
TF_VAR_webapp_config_contentful_environment: ${{ vars.WEBAPP_CONFIG_CONTENTFUL_ENVIRONMENT }}
TF_VAR_webapp_config_contentful_preview: ${{ vars.WEBAPP_CONFIG_CONTENTFUL_PREVIEW }}
TF_VAR_webapp_config_domain: ${{ vars.WEBAPP_CONFIG_DOMAIN }}
TF_VAR_webapp_config_editor: ${{ vars.WEBAPP_CONFIG_EDITOR }}
TF_VAR_webapp_config_feedback_url: ${{ vars.WEBAPP_CONFIG_FEEDBACK_URL }}
TF_VAR_webapp_config_grover_no_sandbox: ${{ vars.WEBAPP_CONFIG_GROVER_NO_SANDBOX }}
TF_VAR_webapp_config_google_cloud_bucket: ${{ vars.WEBAPP_CONFIG_GOOGLE_CLOUD_BUCKET }}
TF_VAR_webapp_config_node_env: ${{ vars.WEBAPP_CONFIG_NODE_ENV }}
TF_VAR_webapp_config_rails_env: ${{ vars.WEBAPP_CONFIG_RAILS_ENV }}
TF_VAR_webapp_config_rails_log_to_stdout: ${{ vars.WEBAPP_CONFIG_RAILS_LOG_TO_STDOUT }}
TF_VAR_webapp_config_rails_master_key: ${{ secrets.WEBAPP_CONFIG_RAILS_MASTER_KEY }}
TF_VAR_webapp_config_rails_max_threads: ${{ vars.WEBAPP_CONFIG_RAILS_MAX_THREADS }}
TF_VAR_webapp_config_rails_serve_static_files: ${{ vars.WEBAPP_CONFIG_RAILS_SERVE_STATIC_FILES }}
TF_VAR_webapp_config_web_concurrency: ${{ vars.WEBAPP_CONFIG_WEB_CONCURRENCY }}

jobs:
terraform-plan:
Expand Down Expand Up @@ -107,6 +66,16 @@ jobs:
- name: Terraform Format
run: terraform fmt -check

# Generates Terraform variable files
- name: Terraform Variables
shell: bash
env:
WEB_SECRETS: ${{ toJSON(secrets) }}
WEB_VARS: ${{ toJSON(vars) }
run: |
printf '%s\n' "${WEB_SECRETS,,}" > web-secrets.auto.tfvars.json
printf '%s\n' "${WEB_VARS,,}" > web-vars.auto.tfvars.json
# Generates an execution plan for Terraform
# An exit code of 0 indicated no changes, 1 a terraform failure, 2 there are pending changes.
- name: Terraform Plan
Expand Down Expand Up @@ -180,6 +149,16 @@ jobs:
-backend-config="container_name=${{ secrets.TERRAFORM_STATE_STORAGE_CONTAINER_NAME }}"
-backend-config="key=${{ secrets.TERRAFORM_STATE_KEY }}"
# Generates Terraform variable files
- name: Terraform Variables
shell: bash
env:
WEB_SECRETS: ${{ toJSON(secrets) }}
WEB_VARS: ${{ toJSON(vars) }
run: |
printf '%s\n' "${WEB_SECRETS,,}" > web-secrets.auto.tfvars.json
printf '%s\n' "${WEB_VARS,,}" > web-vars.auto.tfvars.json
# Download saved plan from artifacts
- name: Download Terraform Plan
uses: actions/download-artifact@v3
Expand Down
10 changes: 10 additions & 0 deletions docker-entrypoint.sh
Original file line number Diff line number Diff line change
Expand Up @@ -27,4 +27,14 @@ fi

bundle exec rails db:prepare assets:precompile

if [ -z ${ENVIRONMENT} ]
then
echo "ENVIRONMENT is not defined so development database may not contain seed data"
else
if [ !${ENVIRONMENT}=="development" ]
then
bundle exec rails db:seed
fi
fi

exec bundle exec "$@"
2 changes: 2 additions & 0 deletions terraform-azure/local.tf
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ locals {

# Web Application Configuration
webapp_app_settings = {
"ENVIRONMENT" = var.environment
"DATABASE_URL" = var.webapp_database_url
"WEBSITES_ENABLE_APP_SERVICE_STORAGE" = "false"
"GOVUK_APP_DOMAIN" = "london.cloudapps.digital" #TODO: Remove this dependency post-migration to Azure
Expand Down Expand Up @@ -47,6 +48,7 @@ locals {

# Review Application Configuration
reviewapp_app_settings = {
"ENVIRONMENT" = var.environment
"DATABASE_URL" = var.webapp_database_url
"WEBSITES_ENABLE_APP_SERVICE_STORAGE" = "false"
"GOVUK_APP_DOMAIN" = "london.cloudapps.digital" #TODO: Remove this dependency post-migration to Azure
Expand Down
11 changes: 6 additions & 5 deletions terraform-azure/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ module "network" {
kv_certificate_authority_name = "GlobalSign"
kv_certificate_authority_username = var.kv_certificate_authority_username
kv_certificate_authority_password = var.kv_certificate_authority_password
kv_certificate_authority_admin_email = var.kv_certificate_authority_admin_email
kv_certificate_authority_admin_email = var.admin_email_address
kv_certificate_authority_admin_first_name = var.kv_certificate_authority_admin_first_name
kv_certificate_authority_admin_last_name = var.kv_certificate_authority_admin_last_name
kv_certificate_authority_admin_phone_no = var.kv_certificate_authority_admin_phone_no
Expand Down Expand Up @@ -69,19 +69,20 @@ module "webapp" {
source = "./terraform-azure-web"

environment = var.environment
asp_sku = var.asp_sku
webapp_worker_count = var.webapp_worker_count
location = var.azure_region
resource_group = azurerm_resource_group.rg.name
resource_name_prefix = var.resource_name_prefix
asp_sku = var.asp_sku
webapp_admin_email_address = var.admin_email_address
webapp_worker_count = var.webapp_worker_count
webapp_subnet_id = module.network.webapp_subnet_id
webapp_name = var.webapp_name
webapp_app_settings = local.webapp_app_settings
webapp_docker_image = var.webapp_docker_image
webapp_docker_image_tag = var.webapp_docker_image_tag
webapp_docker_registry_url = var.webapp_docker_registry_url
webapp_session_cookie_name = "_early_years_foundation_recovery_session"
webapp_custom_domain_name = var.webapp_custom_domain_name
webapp_custom_domain_name = var.custom_domain_name
webapp_custom_domain_cert_secret_label = var.kv_certificate_label
webapp_health_check_path = "/health"
webapp_health_check_eviction_time_in_min = 10
Expand Down Expand Up @@ -117,10 +118,10 @@ module "review-apps" {
# Review Applications are only deployed to the Development subscription
count = var.environment == "development" ? 1 : 0

asp_sku = "P1v2"
location = var.azure_region
resource_group = azurerm_resource_group.rg.name
resource_name_prefix = "${var.resource_name_prefix}-review"
asp_sku = "P1v2"
webapp_vnet_name = module.network.vnet_name
webapp_name = var.reviewapp_name
webapp_app_settings = local.reviewapp_app_settings
Expand Down
10 changes: 0 additions & 10 deletions terraform-azure/terraform-azure-web/appgateway.tf
Original file line number Diff line number Diff line change
Expand Up @@ -22,16 +22,6 @@ resource "azurerm_web_application_firewall_policy" "agw_wafp" {
match_variable = "RequestCookieNames"
selector = var.webapp_session_cookie_name
selector_match_operator = "Equals"

excluded_rule_set {
type = "OWASP"
version = "3.2"

rule_group {
rule_group_name = "REQUEST-942-APPLICATION-ATTACK-SQLI"
excluded_rules = [942440]
}
}
}
}

Expand Down
6 changes: 6 additions & 0 deletions terraform-azure/terraform-azure-web/variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,12 @@ variable "asp_sku" {
type = string
}

variable "webapp_admin_email_address" {
description = "Email Address of the Admin"
type = string
sensitive = true
}

variable "webapp_worker_count" {
description = "Number of Workers for the App Service Plan"
type = string
Expand Down
117 changes: 117 additions & 0 deletions terraform-azure/terraform-azure-web/webapp.tf
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,123 @@ resource "azurerm_monitor_diagnostic_setting" "webapp_slot_logs_monitor" {
}
}

# Configure Web App Autoscaling
resource "azurerm_monitor_autoscale_setting" "asp_as" {
# Autoscaling rules only deployed to the Test and Production subscription
count = var.environment != "development" ? 1 : 0

name = "${var.resource_name_prefix}-asp-as"
location = var.location
resource_group_name = var.resource_group
target_resource_id = azurerm_service_plan.asp.id

profile {
name = "Autoscaling conditions"

capacity {
default = 2
minimum = 2
maximum = 5
}

rule {
metric_trigger {
metric_name = "CpuPercentage"
metric_namespace = "microsoft.web/serverfarms"
metric_resource_id = azurerm_service_plan.asp.id
statistic = "Average"
operator = "GreaterThan"
threshold = 75
time_aggregation = "Average"
time_grain = "PT1M"
time_window = "PT10M"
}

scale_action {
direction = "Increase"
type = "ChangeCount"
value = "1"
cooldown = "PT5M"
}
}

rule {
metric_trigger {
metric_name = "CpuPercentage"
metric_namespace = "microsoft.web/serverfarms"
metric_resource_id = azurerm_service_plan.asp.id
statistic = "Average"
operator = "LessThan"
threshold = 20
time_aggregation = "Average"
time_grain = "PT1M"
time_window = "PT10M"
}

scale_action {
direction = "Decrease"
type = "ChangeCount"
value = "1"
cooldown = "PT5M"
}
}

rule {
metric_trigger {
metric_name = "MemoryPercentage"
metric_namespace = "microsoft.web/serverfarms"
metric_resource_id = azurerm_service_plan.asp.id
statistic = "Average"
operator = "GreaterThan"
threshold = 70
time_aggregation = "Average"
time_grain = "PT1M"
time_window = "PT10M"
}

scale_action {
direction = "Increase"
type = "ChangeCount"
value = "1"
cooldown = "PT5M"
}
}

rule {
metric_trigger {
metric_name = "MemoryPercentage"
metric_namespace = "microsoft.web/serverfarms"
metric_resource_id = azurerm_service_plan.asp.id
statistic = "Average"
operator = "LessThan"
threshold = 50
time_aggregation = "Average"
time_grain = "PT1M"
time_window = "PT10M"
}

scale_action {
direction = "Decrease"
type = "ChangeCount"
value = "1"
cooldown = "PT5M"
}
}
}

notification {
email {
send_to_subscription_administrator = true
send_to_subscription_co_administrator = true
custom_emails = [var.webapp_admin_email_address]
}
}

lifecycle {
ignore_changes = [tags]
}
}

# Create Custom Domain Name
resource "azurerm_app_service_custom_hostname_binding" "webapp_custom_domain" {
# Custom hostname only deployed to the Test and Production subscription
Expand Down
18 changes: 7 additions & 11 deletions terraform-azure/variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -16,20 +16,20 @@ variable "resource_name_prefix" {
type = string
}

variable "kv_certificate_authority_username" {
description = "Username for the Certificate provider"
variable "admin_email_address" {
description = "Email Address of the Admin"
type = string
sensitive = true
}

variable "kv_certificate_authority_password" {
description = "Password the Certificate provider"
variable "kv_certificate_authority_username" {
description = "Username for the Certificate provider"
type = string
sensitive = true
}

variable "kv_certificate_authority_admin_email" {
description = "Email Address of the Certificate Authority Admin"
variable "kv_certificate_authority_password" {
description = "Password the Certificate provider"
type = string
sensitive = true
}
Expand Down Expand Up @@ -147,7 +147,7 @@ variable "webapp_docker_image_tag" {
type = string
}

variable "webapp_custom_domain_name" {
variable "custom_domain_name" {
description = "Custom domain hostname"
type = string
}
Expand Down Expand Up @@ -210,10 +210,6 @@ variable "webapp_config_rails_serve_static_files" {
type = bool
}

variable "webapp_config_training_modules" {
type = string
}

variable "webapp_config_web_concurrency" {
type = string
}

0 comments on commit 21e9c12

Please sign in to comment.