from azure.identity import ClientSecretCredential from azure.mgmt.alertsmanagement import AlertsManagementClient from app import app from app.alarms import get_proxy_alarm from app.extensions import db from app.models.mirrors import Proxy from app.models.alarms import AlarmState from app.terraform.proxy import ProxyAutomation class ProxyAzureCdnAutomation(ProxyAutomation): short_name = "proxy_azure_cdn" provider = "azure_cdn" subgroup_max = 25 parallelism = 1 template_parameters = [ "azure_resource_group_name", "azure_storage_account_name", "azure_location", "azure_client_id", "azure_client_secret", "azure_subscription_id", "azure_tenant_id" ] template = """ terraform { required_providers { azurerm = { source = "hashicorp/azurerm" version = "=2.99.0" } } } provider "azurerm" { features {} client_id = "{{ azure_client_id }}" client_secret = "{{ azure_client_secret }}" subscription_id = "{{ azure_subscription_id }}" tenant_id = "{{ azure_tenant_id }}" skip_provider_registration = true } data "azurerm_resource_group" "this" { name = "{{ azure_resource_group_name }}" } resource "azurerm_storage_account" "this" { name = "{{ azure_storage_account_name }}" resource_group_name = data.azurerm_resource_group.this.name location = "{{ azure_location }}" account_tier = "Standard" account_replication_type = "RAGRS" } {% for group in groups %} module "label_{{ group.id }}" { source = "cloudposse/label/null" version = "0.25.0" namespace = "{{ global_namespace }}" tenant = "{{ group.group_name }}" label_order = ["namespace", "tenant", "name", "attributes"] } {% for subgroup in subgroups[group.id] %} resource "azurerm_cdn_profile" "profile_{{ group.id }}_{{ subgroup }}" { name = "${module.label_{{ group.id }}.id}-sub{{ subgroup }}" location = "{{ azure_location }}" resource_group_name = data.azurerm_resource_group.this.name sku = "Standard_Microsoft" tags = module.label_{{ group.id }}.tags } resource "azurerm_monitor_diagnostic_setting" "profile_diagnostic_{{ group.id }}_{{ subgroup }}" { name = "cdn-diagnostics" target_resource_id = azurerm_cdn_profile.profile_{{ group.id }}_{{ subgroup }}.id storage_account_id = azurerm_storage_account.this.id log { category = "AzureCDNAccessLog" enabled = true retention_policy { enabled = true days = 90 } } metric { category = "AllMetrics" enabled = true retention_policy { enabled = true days = 90 } } } resource "azurerm_monitor_metric_alert" "response_alert_{{ group.id }}_{{ subgroup }}" { name = "bandwidth-out-high-${module.label_{{ group.id }}.id}-sub{{ subgroup }}" resource_group_name = data.azurerm_resource_group.this.name scopes = [azurerm_cdn_profile.profile_{{ group.id }}_{{ subgroup }}.id] description = "Action will be triggered when response size is too high." criteria { metric_namespace = "Microsoft.Cdn/profiles" metric_name = "ResponseSize" aggregation = "Total" operator = "GreaterThan" threshold = 21474836481 } window_size = "PT1H" } {% endfor %} {% endfor %} {% for proxy in proxies %} resource "azurerm_cdn_endpoint" "endpoint_{{ proxy.id }}" { name = "{{ proxy.slug }}" profile_name = azurerm_cdn_profile.profile_{{ proxy.origin.group.id }}_{{ proxy.psg }}.name location = "{{ azure_location }}" resource_group_name = data.azurerm_resource_group.this.name origin_host_header = "{{ proxy.origin.domain_name }}" origin { name = "upstream" host_name = "{{ proxy.origin.domain_name }}" } global_delivery_rule { modify_request_header_action { action = "Append" name = "Bypass-Rate-Limit-Token" value = "{{ bypass_token }}" } } } resource "azurerm_monitor_diagnostic_setting" "diagnostic_{{ proxy.id }}" { name = "cdn-diagnostics" target_resource_id = azurerm_cdn_endpoint.endpoint_{{ proxy.id }}.id storage_account_id = azurerm_storage_account.this.id log { category = "CoreAnalytics" enabled = true retention_policy { enabled = true days = 90 } } } {% endfor %} """ def import_state(self, state): proxies = Proxy.query.filter( Proxy.provider == self.provider, Proxy.destroyed == None ).all() for proxy in proxies: proxy.url = f"https://{proxy.slug}.azureedge.net" db.session.commit() def import_monitor_alerts(): credential = ClientSecretCredential( tenant_id=app.config['AZURE_TENANT_ID'], client_id=app.config['AZURE_CLIENT_ID'], client_secret=app.config['AZURE_CLIENT_SECRET']) client = AlertsManagementClient( credential, app.config['AZURE_SUBSCRIPTION_ID'] ) firing = [x.name[len("bandwidth-out-high-bc-"):] for x in client.alerts.get_all() if x.name.startswith("bandwidth-out-high-bc-") and x.properties.essentials.monitor_condition == "Fired"] for proxy in Proxy.query.filter( Proxy.provider == "azure_cdn", Proxy.destroyed == None ): alarm = get_proxy_alarm(proxy.id, "bandwidth-out-high") if proxy.origin.group.group_name.lower() not in firing: alarm.update_state(AlarmState.OK, "Azure monitor alert not firing") else: alarm.update_state(AlarmState.CRITICAL, "Azure monitor alert firing") if __name__ == "__main__": with app.app_context(): auto = ProxyAzureCdnAutomation() auto.automate() import_monitor_alerts()