'
+param location = 'global'
```
-### Example 4: _Using large parameter set_
+### Example 4: _Using maximum parameter set_
-This instance deploys the module with most of its features enabled.
+This instance deploys the module with all available features and parameters for Premium_AzureFrontDoor SKU.
@@ -816,8 +816,81 @@ module profile 'br/public:avm/res/cdn/profile:' = {
params: {
// Required parameters
name: 'dep-test-cdnpmax'
- sku: 'Standard_Microsoft'
+ sku: 'Premium_AzureFrontDoor'
// Non-required parameters
+ afdEndpoints: [
+ {
+ autoGeneratedDomainNameLabelScope: 'TenantReuse'
+ enabledState: 'Enabled'
+ name: 'dep-test-cdnpmax-afd-endpoint-1'
+ routes: [
+ {
+ cacheConfiguration: {
+ compressionSettings: {
+ contentTypesToCompress: [
+ 'application/json'
+ 'text/css'
+ 'text/html'
+ ]
+ isCompressionEnabled: true
+ }
+ queryParameters: 'version,locale'
+ queryStringCachingBehavior: 'IncludeSpecifiedQueryStrings'
+ }
+ customDomainNames: [
+ 'dep-test1-cdnpmax-custom-domain'
+ ]
+ enabledState: 'Enabled'
+ forwardingProtocol: 'MatchRequest'
+ httpsRedirect: 'Enabled'
+ linkToDefaultDomain: 'Enabled'
+ name: 'dep-test-cdnpmax-afd-route-1'
+ originGroupName: 'dep-test-cdnpmax-origin-group-1'
+ patternsToMatch: [
+ '/api/*'
+ '/health'
+ ]
+ ruleSets: [
+ {
+ name: 'deptestcdnpmaxruleset1'
+ }
+ ]
+ supportedProtocols: [
+ 'Http'
+ 'Https'
+ ]
+ }
+ ]
+ }
+ ]
+ customDomains: [
+ {
+ certificateType: 'ManagedCertificate'
+ hostName: 'dep-test1-cdnpmax-custom-domain.azurewebsites.net'
+ minimumTlsVersion: 'TLS12'
+ name: 'dep-test1-cdnpmax-custom-domain'
+ }
+ {
+ certificateType: 'ManagedCertificate'
+ cipherSuiteSetType: 'TLS12_2022'
+ hostName: 'dep-test2-cdnpmax-custom-domain.azurewebsites.net'
+ minimumTlsVersion: 'TLS12'
+ name: 'dep-test2-cdnpmax-custom-domain'
+ }
+ {
+ certificateType: 'ManagedCertificate'
+ cipherSuiteSetType: 'Customized'
+ customizedCipherSuiteSet: {
+ cipherSuiteSetForTls13: [
+ 'TLS_AES_128_GCM_SHA256'
+ 'TLS_AES_256_GCM_SHA384'
+ ]
+ }
+ hostName: 'dep-test3-cdnpmax-custom-domain.azurewebsites.net'
+ minimumTlsVersion: 'TLS13'
+ name: 'dep-test3-cdnpmax-custom-domain'
+ }
+ ]
diagnosticSettings: [
{
eventHubAuthorizationRuleResourceId: ''
@@ -839,61 +912,109 @@ module profile 'br/public:avm/res/cdn/profile:' = {
workspaceResourceId: ''
}
]
- endpointProperties: {
- contentTypesToCompress: [
- 'application/javascript'
- 'application/json'
- 'application/x-javascript'
- 'application/xml'
- 'text/css'
- 'text/html'
- 'text/javascript'
- 'text/plain'
+ location: 'global'
+ lock: {
+ kind: 'CanNotDelete'
+ name: 'myCustomLockName'
+ notes: 'This resource cannot be deleted for security reasons.'
+ }
+ managedIdentities: {
+ systemAssigned: true
+ userAssignedResourceIds: [
+ ''
]
- geoFilters: []
- isCompressionEnabled: true
- isHttpAllowed: true
- isHttpsAllowed: true
- originGroups: []
- originHostHeader: ''
- origins: [
- {
- name: 'dep-cdn-endpoint01'
- properties: {
- enabled: true
+ }
+ originGroups: [
+ {
+ healthProbeSettings: {
+ probeIntervalInSeconds: 120
+ probePath: '/health'
+ probeProtocol: 'Https'
+ probeRequestType: 'GET'
+ }
+ loadBalancingSettings: {
+ additionalLatencyInMilliseconds: 50
+ sampleSize: 4
+ successfulSamplesRequired: 3
+ }
+ name: 'dep-test-cdnpmax-origin-group-1'
+ origins: [
+ {
+ enabledState: 'Enabled'
+ enforceCertificateNameCheck: true
hostName: ''
httpPort: 80
httpsPort: 443
+ name: 'dep-test-cdnpmax-origin-1'
+ priority: 1
+ weight: 1000
}
- }
- ]
- queryStringCachingBehavior: 'IgnoreQueryString'
- }
- location: ''
- lock: {
- kind: 'CanNotDelete'
- name: 'myCustomLockName'
- }
- originResponseTimeoutSeconds: 60
- roleAssignments: [
+ ]
+ sessionAffinityState: 'Enabled'
+ trafficRestorationTimeToHealedOrNewEndpointsInMinutes: 15
+ }
{
- name: '50362c78-6910-43c3-8639-9cae123943bb'
- principalId: ''
- principalType: 'ServicePrincipal'
- roleDefinitionIdOrName: 'Owner'
+ loadBalancingSettings: {
+ additionalLatencyInMilliseconds: 100
+ sampleSize: 6
+ successfulSamplesRequired: 4
+ }
+ name: 'dep-test-cdnpmax-origin-group-2'
+ origins: [
+ {
+ enabledState: 'Enabled'
+ enforceCertificateNameCheck: true
+ hostName: ''
+ httpPort: 80
+ httpsPort: 443
+ name: 'dep-test-cdnpmax-origin-2'
+ priority: 1
+ weight: 1000
+ }
+ ]
+ sessionAffinityState: 'Disabled'
+ trafficRestorationTimeToHealedOrNewEndpointsInMinutes: 10
}
+ ]
+ originResponseTimeoutSeconds: 240
+ roleAssignments: [
{
- name: ''
principalId: ''
principalType: 'ServicePrincipal'
- roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c'
+ roleDefinitionIdOrName: 'CDN Profile Contributor'
}
+ ]
+ ruleSets: [
{
- principalId: ''
- principalType: 'ServicePrincipal'
- roleDefinitionIdOrName: ''
+ name: 'deptestcdnpmaxruleset1'
+ rules: [
+ {
+ actions: [
+ {
+ name: 'UrlRedirect'
+ parameters: {
+ customHostname: 'api.example.com'
+ customPath: '/v2/api/'
+ destinationProtocol: 'Https'
+ redirectType: 'PermanentRedirect'
+ typeName: 'DeliveryRuleUrlRedirectActionParameters'
+ }
+ }
+ ]
+ conditions: []
+ matchProcessingBehavior: 'Continue'
+ name: 'deptestcdnpmaxrule1'
+ order: 1
+ }
+ ]
}
]
+ tags: {
+ Application: 'CDN'
+ CostCenter: '12345'
+ Environment: 'Test'
+ Owner: 'TestTeam'
+ }
}
}
```
@@ -915,9 +1036,86 @@ module profile 'br/public:avm/res/cdn/profile:' = {
"value": "dep-test-cdnpmax"
},
"sku": {
- "value": "Standard_Microsoft"
+ "value": "Premium_AzureFrontDoor"
},
// Non-required parameters
+ "afdEndpoints": {
+ "value": [
+ {
+ "autoGeneratedDomainNameLabelScope": "TenantReuse",
+ "enabledState": "Enabled",
+ "name": "dep-test-cdnpmax-afd-endpoint-1",
+ "routes": [
+ {
+ "cacheConfiguration": {
+ "compressionSettings": {
+ "contentTypesToCompress": [
+ "application/json",
+ "text/css",
+ "text/html"
+ ],
+ "isCompressionEnabled": true
+ },
+ "queryParameters": "version,locale",
+ "queryStringCachingBehavior": "IncludeSpecifiedQueryStrings"
+ },
+ "customDomainNames": [
+ "dep-test1-cdnpmax-custom-domain"
+ ],
+ "enabledState": "Enabled",
+ "forwardingProtocol": "MatchRequest",
+ "httpsRedirect": "Enabled",
+ "linkToDefaultDomain": "Enabled",
+ "name": "dep-test-cdnpmax-afd-route-1",
+ "originGroupName": "dep-test-cdnpmax-origin-group-1",
+ "patternsToMatch": [
+ "/api/*",
+ "/health"
+ ],
+ "ruleSets": [
+ {
+ "name": "deptestcdnpmaxruleset1"
+ }
+ ],
+ "supportedProtocols": [
+ "Http",
+ "Https"
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ "customDomains": {
+ "value": [
+ {
+ "certificateType": "ManagedCertificate",
+ "hostName": "dep-test1-cdnpmax-custom-domain.azurewebsites.net",
+ "minimumTlsVersion": "TLS12",
+ "name": "dep-test1-cdnpmax-custom-domain"
+ },
+ {
+ "certificateType": "ManagedCertificate",
+ "cipherSuiteSetType": "TLS12_2022",
+ "hostName": "dep-test2-cdnpmax-custom-domain.azurewebsites.net",
+ "minimumTlsVersion": "TLS12",
+ "name": "dep-test2-cdnpmax-custom-domain"
+ },
+ {
+ "certificateType": "ManagedCertificate",
+ "cipherSuiteSetType": "Customized",
+ "customizedCipherSuiteSet": {
+ "cipherSuiteSetForTls13": [
+ "TLS_AES_128_GCM_SHA256",
+ "TLS_AES_256_GCM_SHA384"
+ ]
+ },
+ "hostName": "dep-test3-cdnpmax-custom-domain.azurewebsites.net",
+ "minimumTlsVersion": "TLS13",
+ "name": "dep-test3-cdnpmax-custom-domain"
+ }
+ ]
+ },
"diagnosticSettings": {
"value": [
{
@@ -941,70 +1139,124 @@ module profile 'br/public:avm/res/cdn/profile:' = {
}
]
},
- "endpointProperties": {
- "value": {
- "contentTypesToCompress": [
- "application/javascript",
- "application/json",
- "application/x-javascript",
- "application/xml",
- "text/css",
- "text/html",
- "text/javascript",
- "text/plain"
- ],
- "geoFilters": [],
- "isCompressionEnabled": true,
- "isHttpAllowed": true,
- "isHttpsAllowed": true,
- "originGroups": [],
- "originHostHeader": "",
- "origins": [
- {
- "name": "dep-cdn-endpoint01",
- "properties": {
- "enabled": true,
- "hostName": "",
- "httpPort": 80,
- "httpsPort": 443
- }
- }
- ],
- "queryStringCachingBehavior": "IgnoreQueryString"
- }
- },
"location": {
- "value": ""
+ "value": "global"
},
"lock": {
"value": {
"kind": "CanNotDelete",
- "name": "myCustomLockName"
+ "name": "myCustomLockName",
+ "notes": "This resource cannot be deleted for security reasons."
}
},
- "originResponseTimeoutSeconds": {
- "value": 60
+ "managedIdentities": {
+ "value": {
+ "systemAssigned": true,
+ "userAssignedResourceIds": [
+ ""
+ ]
+ }
},
- "roleAssignments": {
+ "originGroups": {
"value": [
{
- "name": "50362c78-6910-43c3-8639-9cae123943bb",
- "principalId": "",
- "principalType": "ServicePrincipal",
- "roleDefinitionIdOrName": "Owner"
+ "healthProbeSettings": {
+ "probeIntervalInSeconds": 120,
+ "probePath": "/health",
+ "probeProtocol": "Https",
+ "probeRequestType": "GET"
+ },
+ "loadBalancingSettings": {
+ "additionalLatencyInMilliseconds": 50,
+ "sampleSize": 4,
+ "successfulSamplesRequired": 3
+ },
+ "name": "dep-test-cdnpmax-origin-group-1",
+ "origins": [
+ {
+ "enabledState": "Enabled",
+ "enforceCertificateNameCheck": true,
+ "hostName": "",
+ "httpPort": 80,
+ "httpsPort": 443,
+ "name": "dep-test-cdnpmax-origin-1",
+ "priority": 1,
+ "weight": 1000
+ }
+ ],
+ "sessionAffinityState": "Enabled",
+ "trafficRestorationTimeToHealedOrNewEndpointsInMinutes": 15
},
{
- "name": "",
- "principalId": "",
- "principalType": "ServicePrincipal",
- "roleDefinitionIdOrName": "b24988ac-6180-42a0-ab88-20f7382dd24c"
- },
+ "loadBalancingSettings": {
+ "additionalLatencyInMilliseconds": 100,
+ "sampleSize": 6,
+ "successfulSamplesRequired": 4
+ },
+ "name": "dep-test-cdnpmax-origin-group-2",
+ "origins": [
+ {
+ "enabledState": "Enabled",
+ "enforceCertificateNameCheck": true,
+ "hostName": "",
+ "httpPort": 80,
+ "httpsPort": 443,
+ "name": "dep-test-cdnpmax-origin-2",
+ "priority": 1,
+ "weight": 1000
+ }
+ ],
+ "sessionAffinityState": "Disabled",
+ "trafficRestorationTimeToHealedOrNewEndpointsInMinutes": 10
+ }
+ ]
+ },
+ "originResponseTimeoutSeconds": {
+ "value": 240
+ },
+ "roleAssignments": {
+ "value": [
{
"principalId": "",
"principalType": "ServicePrincipal",
- "roleDefinitionIdOrName": ""
+ "roleDefinitionIdOrName": "CDN Profile Contributor"
+ }
+ ]
+ },
+ "ruleSets": {
+ "value": [
+ {
+ "name": "deptestcdnpmaxruleset1",
+ "rules": [
+ {
+ "actions": [
+ {
+ "name": "UrlRedirect",
+ "parameters": {
+ "customHostname": "api.example.com",
+ "customPath": "/v2/api/",
+ "destinationProtocol": "Https",
+ "redirectType": "PermanentRedirect",
+ "typeName": "DeliveryRuleUrlRedirectActionParameters"
+ }
+ }
+ ],
+ "conditions": [],
+ "matchProcessingBehavior": "Continue",
+ "name": "deptestcdnpmaxrule1",
+ "order": 1
+ }
+ ]
}
]
+ },
+ "tags": {
+ "value": {
+ "Application": "CDN",
+ "CostCenter": "12345",
+ "Environment": "Test",
+ "Owner": "TestTeam"
+ }
}
}
}
@@ -1022,92 +1274,213 @@ using 'br/public:avm/res/cdn/profile:'
// Required parameters
param name = 'dep-test-cdnpmax'
-param sku = 'Standard_Microsoft'
+param sku = 'Premium_AzureFrontDoor'
// Non-required parameters
-param diagnosticSettings = [
+param afdEndpoints = [
{
- eventHubAuthorizationRuleResourceId: ''
- eventHubName: ''
- logCategoriesAndGroups: [
- {
- categoryGroup: 'allLogs'
- enabled: true
- }
- ]
- metricCategories: [
+ autoGeneratedDomainNameLabelScope: 'TenantReuse'
+ enabledState: 'Enabled'
+ name: 'dep-test-cdnpmax-afd-endpoint-1'
+ routes: [
{
- category: 'AllMetrics'
- enabled: true
+ cacheConfiguration: {
+ compressionSettings: {
+ contentTypesToCompress: [
+ 'application/json'
+ 'text/css'
+ 'text/html'
+ ]
+ isCompressionEnabled: true
+ }
+ queryParameters: 'version,locale'
+ queryStringCachingBehavior: 'IncludeSpecifiedQueryStrings'
+ }
+ customDomainNames: [
+ 'dep-test1-cdnpmax-custom-domain'
+ ]
+ enabledState: 'Enabled'
+ forwardingProtocol: 'MatchRequest'
+ httpsRedirect: 'Enabled'
+ linkToDefaultDomain: 'Enabled'
+ name: 'dep-test-cdnpmax-afd-route-1'
+ originGroupName: 'dep-test-cdnpmax-origin-group-1'
+ patternsToMatch: [
+ '/api/*'
+ '/health'
+ ]
+ ruleSets: [
+ {
+ name: 'deptestcdnpmaxruleset1'
+ }
+ ]
+ supportedProtocols: [
+ 'Http'
+ 'Https'
+ ]
}
]
- name: 'customSetting'
- storageAccountResourceId: ''
- workspaceResourceId: ''
}
]
-param endpointProperties = {
- contentTypesToCompress: [
- 'application/javascript'
- 'application/json'
- 'application/x-javascript'
- 'application/xml'
- 'text/css'
- 'text/html'
- 'text/javascript'
- 'text/plain'
- ]
- geoFilters: []
- isCompressionEnabled: true
- isHttpAllowed: true
- isHttpsAllowed: true
- originGroups: []
- originHostHeader: ''
- origins: [
- {
- name: 'dep-cdn-endpoint01'
- properties: {
- enabled: true
- hostName: ''
- httpPort: 80
- httpsPort: 443
- }
+param customDomains = [
+ {
+ certificateType: 'ManagedCertificate'
+ hostName: 'dep-test1-cdnpmax-custom-domain.azurewebsites.net'
+ minimumTlsVersion: 'TLS12'
+ name: 'dep-test1-cdnpmax-custom-domain'
+ }
+ {
+ certificateType: 'ManagedCertificate'
+ cipherSuiteSetType: 'TLS12_2022'
+ hostName: 'dep-test2-cdnpmax-custom-domain.azurewebsites.net'
+ minimumTlsVersion: 'TLS12'
+ name: 'dep-test2-cdnpmax-custom-domain'
+ }
+ {
+ certificateType: 'ManagedCertificate'
+ cipherSuiteSetType: 'Customized'
+ customizedCipherSuiteSet: {
+ cipherSuiteSetForTls13: [
+ 'TLS_AES_128_GCM_SHA256'
+ 'TLS_AES_256_GCM_SHA384'
+ ]
}
- ]
- queryStringCachingBehavior: 'IgnoreQueryString'
-}
-param location = ''
+ hostName: 'dep-test3-cdnpmax-custom-domain.azurewebsites.net'
+ minimumTlsVersion: 'TLS13'
+ name: 'dep-test3-cdnpmax-custom-domain'
+ }
+]
+param diagnosticSettings = [
+ {
+ eventHubAuthorizationRuleResourceId: ''
+ eventHubName: ''
+ logCategoriesAndGroups: [
+ {
+ categoryGroup: 'allLogs'
+ enabled: true
+ }
+ ]
+ metricCategories: [
+ {
+ category: 'AllMetrics'
+ enabled: true
+ }
+ ]
+ name: 'customSetting'
+ storageAccountResourceId: ''
+ workspaceResourceId: ''
+ }
+]
+param location = 'global'
param lock = {
kind: 'CanNotDelete'
name: 'myCustomLockName'
+ notes: 'This resource cannot be deleted for security reasons.'
}
-param originResponseTimeoutSeconds = 60
-param roleAssignments = [
+param managedIdentities = {
+ systemAssigned: true
+ userAssignedResourceIds: [
+ ''
+ ]
+}
+param originGroups = [
{
- name: '50362c78-6910-43c3-8639-9cae123943bb'
- principalId: ''
- principalType: 'ServicePrincipal'
- roleDefinitionIdOrName: 'Owner'
+ healthProbeSettings: {
+ probeIntervalInSeconds: 120
+ probePath: '/health'
+ probeProtocol: 'Https'
+ probeRequestType: 'GET'
+ }
+ loadBalancingSettings: {
+ additionalLatencyInMilliseconds: 50
+ sampleSize: 4
+ successfulSamplesRequired: 3
+ }
+ name: 'dep-test-cdnpmax-origin-group-1'
+ origins: [
+ {
+ enabledState: 'Enabled'
+ enforceCertificateNameCheck: true
+ hostName: ''
+ httpPort: 80
+ httpsPort: 443
+ name: 'dep-test-cdnpmax-origin-1'
+ priority: 1
+ weight: 1000
+ }
+ ]
+ sessionAffinityState: 'Enabled'
+ trafficRestorationTimeToHealedOrNewEndpointsInMinutes: 15
}
{
- name: ''
- principalId: ''
- principalType: 'ServicePrincipal'
- roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c'
+ loadBalancingSettings: {
+ additionalLatencyInMilliseconds: 100
+ sampleSize: 6
+ successfulSamplesRequired: 4
+ }
+ name: 'dep-test-cdnpmax-origin-group-2'
+ origins: [
+ {
+ enabledState: 'Enabled'
+ enforceCertificateNameCheck: true
+ hostName: ''
+ httpPort: 80
+ httpsPort: 443
+ name: 'dep-test-cdnpmax-origin-2'
+ priority: 1
+ weight: 1000
+ }
+ ]
+ sessionAffinityState: 'Disabled'
+ trafficRestorationTimeToHealedOrNewEndpointsInMinutes: 10
}
+]
+param originResponseTimeoutSeconds = 240
+param roleAssignments = [
{
principalId: ''
principalType: 'ServicePrincipal'
- roleDefinitionIdOrName: ''
+ roleDefinitionIdOrName: 'CDN Profile Contributor'
+ }
+]
+param ruleSets = [
+ {
+ name: 'deptestcdnpmaxruleset1'
+ rules: [
+ {
+ actions: [
+ {
+ name: 'UrlRedirect'
+ parameters: {
+ customHostname: 'api.example.com'
+ customPath: '/v2/api/'
+ destinationProtocol: 'Https'
+ redirectType: 'PermanentRedirect'
+ typeName: 'DeliveryRuleUrlRedirectActionParameters'
+ }
+ }
+ ]
+ conditions: []
+ matchProcessingBehavior: 'Continue'
+ name: 'deptestcdnpmaxrule1'
+ order: 1
+ }
+ ]
}
]
+param tags = {
+ Application: 'CDN'
+ CostCenter: '12345'
+ Environment: 'Test'
+ Owner: 'TestTeam'
+}
```
-### Example 5: _WAF-aligned_
+### Example 5: _WAF-aligned Premium AFD_
-This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework.
+This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework using Premium_AzureFrontDoor SKU.
@@ -1119,41 +1492,291 @@ module profile 'br/public:avm/res/cdn/profile:' = {
name: 'profileDeployment'
params: {
// Required parameters
- name: 'dep-test-cdnpwaf'
- sku: 'Standard_Microsoft'
+ name: 'dep-waf-cdnpwaf'
+ sku: 'Premium_AzureFrontDoor'
// Non-required parameters
- endpointProperties: {
- contentTypesToCompress: [
- 'application/javascript'
- 'application/json'
- 'application/x-javascript'
- 'application/xml'
- 'text/css'
- 'text/html'
- 'text/javascript'
- 'text/plain'
- ]
- geoFilters: []
- isCompressionEnabled: true
- isHttpAllowed: true
- isHttpsAllowed: true
- originGroups: []
- originHostHeader: ''
- origins: [
- {
- name: 'dep-cdn-endpoint01'
- properties: {
+ afdEndpoints: [
+ {
+ autoGeneratedDomainNameLabelScope: 'TenantReuse'
+ enabledState: 'Enabled'
+ name: 'dep-waf-primary-endpoint'
+ routes: [
+ {
+ cacheConfiguration: {
+ compressionSettings: {
+ contentTypesToCompress: [
+ 'application/json'
+ 'application/xml'
+ 'text/xml'
+ ]
+ isCompressionEnabled: true
+ }
+ queryParameters: 'timestamp,nonce'
+ queryStringCachingBehavior: 'IgnoreSpecifiedQueryStrings'
+ }
+ customDomainNames: [
+ 'dep-waf-api-cdnpwaf-domain'
+ ]
+ enabledState: 'Enabled'
+ forwardingProtocol: 'HttpsOnly'
+ httpsRedirect: 'Enabled'
+ linkToDefaultDomain: 'Disabled'
+ name: 'dep-waf-api-route'
+ originGroupName: 'dep-waf-api-origin-group'
+ patternsToMatch: [
+ '/api/*'
+ '/v1/*'
+ '/v2/*'
+ ]
+ ruleSets: [
+ {
+ name: 'depwafsecurityrulescdnpwaf'
+ }
+ ]
+ supportedProtocols: [
+ 'Https'
+ ]
+ }
+ ]
+ }
+ ]
+ customDomains: [
+ {
+ certificateType: 'ManagedCertificate'
+ cipherSuiteSetType: 'TLS12_2023'
+ hostName: 'dep-waf-primary-cdnpwaf.example.com'
+ minimumTlsVersion: 'TLS12'
+ name: 'dep-waf-primary-cdnpwaf-domain'
+ }
+ {
+ certificateType: 'ManagedCertificate'
+ cipherSuiteSetType: 'Customized'
+ customizedCipherSuiteSet: {
+ cipherSuiteSetForTls13: [
+ 'TLS_AES_128_GCM_SHA256'
+ 'TLS_AES_256_GCM_SHA384'
+ ]
+ }
+ hostName: 'api-dep-waf-cdnpwaf.example.com'
+ minimumTlsVersion: 'TLS13'
+ name: 'dep-waf-api-cdnpwaf-domain'
+ }
+ ]
+ diagnosticSettings: [
+ {
+ eventHubAuthorizationRuleResourceId: ''
+ eventHubName: ''
+ logCategoriesAndGroups: [
+ {
+ categoryGroup: 'allLogs'
enabled: true
+ }
+ ]
+ metricCategories: [
+ {
+ category: 'AllMetrics'
+ enabled: true
+ }
+ ]
+ name: 'waf-comprehensive-diagnostics'
+ storageAccountResourceId: ''
+ workspaceResourceId: ''
+ }
+ ]
+ location: 'global'
+ lock: {
+ kind: 'CanNotDelete'
+ name: 'waf-protection-lock'
+ notes: 'WAF: Protected against accidental deletion for business continuity'
+ }
+ managedIdentities: {
+ systemAssigned: true
+ userAssignedResourceIds: [
+ ''
+ ]
+ }
+ originGroups: [
+ {
+ healthProbeSettings: {
+ probeIntervalInSeconds: 15
+ probePath: '/api/health'
+ probeProtocol: 'Https'
+ probeRequestType: 'GET'
+ }
+ loadBalancingSettings: {
+ additionalLatencyInMilliseconds: 25
+ sampleSize: 6
+ successfulSamplesRequired: 4
+ }
+ name: 'dep-waf-api-origin-group'
+ origins: [
+ {
+ enabledState: 'Enabled'
+ enforceCertificateNameCheck: true
hostName: ''
httpPort: 80
httpsPort: 443
+ name: 'dep-waf-api-origin'
+ priority: 1
+ weight: 1000
}
- }
- ]
- queryStringCachingBehavior: 'IgnoreQueryString'
- }
- location: ''
+ ]
+ sessionAffinityState: 'Disabled'
+ trafficRestorationTimeToHealedOrNewEndpointsInMinutes: 2
+ }
+ ]
originResponseTimeoutSeconds: 60
+ roleAssignments: [
+ {
+ principalId: ''
+ principalType: 'ServicePrincipal'
+ roleDefinitionIdOrName: 'CDN Profile Reader'
+ }
+ ]
+ ruleSets: [
+ {
+ name: 'depwafsecurityrulescdnpwaf'
+ rules: [
+ {
+ actions: [
+ {
+ name: 'UrlRedirect'
+ parameters: {
+ destinationProtocol: 'Https'
+ redirectType: 'PermanentRedirect'
+ typeName: 'DeliveryRuleUrlRedirectActionParameters'
+ }
+ }
+ ]
+ conditions: [
+ {
+ name: 'RequestScheme'
+ parameters: {
+ matchValues: [
+ 'HTTP'
+ ]
+ negateCondition: false
+ operator: 'Equal'
+ typeName: 'DeliveryRuleRequestSchemeConditionParameters'
+ }
+ }
+ ]
+ matchProcessingBehavior: 'Stop'
+ name: 'HTTPSRedirectRule'
+ order: 1
+ }
+ {
+ actions: [
+ {
+ name: 'ModifyResponseHeader'
+ parameters: {
+ headerAction: 'Overwrite'
+ headerName: 'Strict-Transport-Security'
+ typeName: 'DeliveryRuleHeaderActionParameters'
+ value: 'max-age=31536000; includeSubDomains; preload'
+ }
+ }
+ {
+ name: 'ModifyResponseHeader'
+ parameters: {
+ headerAction: 'Overwrite'
+ headerName: 'X-Content-Type-Options'
+ typeName: 'DeliveryRuleHeaderActionParameters'
+ value: 'nosniff'
+ }
+ }
+ {
+ name: 'ModifyResponseHeader'
+ parameters: {
+ headerAction: 'Overwrite'
+ headerName: 'X-Frame-Options'
+ typeName: 'DeliveryRuleHeaderActionParameters'
+ value: 'DENY'
+ }
+ }
+ {
+ name: 'ModifyResponseHeader'
+ parameters: {
+ headerAction: 'Overwrite'
+ headerName: 'X-XSS-Protection'
+ typeName: 'DeliveryRuleHeaderActionParameters'
+ value: '1; mode=block'
+ }
+ }
+ {
+ name: 'ModifyResponseHeader'
+ parameters: {
+ headerAction: 'Overwrite'
+ headerName: 'Referrer-Policy'
+ typeName: 'DeliveryRuleHeaderActionParameters'
+ value: 'strict-origin-when-cross-origin'
+ }
+ }
+ ]
+ conditions: [
+ {
+ name: 'RequestScheme'
+ parameters: {
+ matchValues: [
+ 'HTTPS'
+ ]
+ negateCondition: false
+ operator: 'Equal'
+ typeName: 'DeliveryRuleRequestSchemeConditionParameters'
+ }
+ }
+ ]
+ matchProcessingBehavior: 'Continue'
+ name: 'SecurityHeadersRule'
+ order: 2
+ }
+ {
+ actions: [
+ {
+ name: 'ModifyResponseHeader'
+ parameters: {
+ headerAction: 'Overwrite'
+ headerName: 'X-RateLimit-Limit'
+ typeName: 'DeliveryRuleHeaderActionParameters'
+ value: '1000'
+ }
+ }
+ ]
+ conditions: [
+ {
+ name: 'RequestUri'
+ parameters: {
+ matchValues: [
+ '/api/'
+ ]
+ negateCondition: false
+ operator: 'BeginsWith'
+ transforms: [
+ 'Lowercase'
+ ]
+ typeName: 'DeliveryRuleRequestUriConditionParameters'
+ }
+ }
+ ]
+ matchProcessingBehavior: 'Continue'
+ name: 'APIRateLimitRule'
+ order: 3
+ }
+ ]
+ }
+ ]
+ tags: {
+ Application: 'CDN-WAF-Aligned'
+ BackupRequired: 'Yes'
+ BusinessUnit: 'Digital-Services'
+ CostCenter: 'IT-Infrastructure'
+ Criticality: 'High'
+ DataClassification: 'Internal'
+ Environment: 'Production'
+ MonitoringRequired: 'Yes'
+ Owner: 'Platform-Team'
+ 'WAF-Pillar': 'All'
+ }
}
}
```
@@ -1172,49 +1795,315 @@ module profile 'br/public:avm/res/cdn/profile:' = {
"parameters": {
// Required parameters
"name": {
- "value": "dep-test-cdnpwaf"
+ "value": "dep-waf-cdnpwaf"
},
"sku": {
- "value": "Standard_Microsoft"
+ "value": "Premium_AzureFrontDoor"
},
// Non-required parameters
- "endpointProperties": {
- "value": {
- "contentTypesToCompress": [
- "application/javascript",
- "application/json",
- "application/x-javascript",
- "application/xml",
- "text/css",
- "text/html",
- "text/javascript",
- "text/plain"
- ],
- "geoFilters": [],
- "isCompressionEnabled": true,
- "isHttpAllowed": true,
- "isHttpsAllowed": true,
- "originGroups": [],
- "originHostHeader": "",
- "origins": [
- {
- "name": "dep-cdn-endpoint01",
- "properties": {
- "enabled": true,
- "hostName": "",
- "httpPort": 80,
- "httpsPort": 443
- }
- }
- ],
- "queryStringCachingBehavior": "IgnoreQueryString"
- }
+ "afdEndpoints": {
+ "value": [
+ {
+ "autoGeneratedDomainNameLabelScope": "TenantReuse",
+ "enabledState": "Enabled",
+ "name": "dep-waf-primary-endpoint",
+ "routes": [
+ {
+ "cacheConfiguration": {
+ "compressionSettings": {
+ "contentTypesToCompress": [
+ "application/json",
+ "application/xml",
+ "text/xml"
+ ],
+ "isCompressionEnabled": true
+ },
+ "queryParameters": "timestamp,nonce",
+ "queryStringCachingBehavior": "IgnoreSpecifiedQueryStrings"
+ },
+ "customDomainNames": [
+ "dep-waf-api-cdnpwaf-domain"
+ ],
+ "enabledState": "Enabled",
+ "forwardingProtocol": "HttpsOnly",
+ "httpsRedirect": "Enabled",
+ "linkToDefaultDomain": "Disabled",
+ "name": "dep-waf-api-route",
+ "originGroupName": "dep-waf-api-origin-group",
+ "patternsToMatch": [
+ "/api/*",
+ "/v1/*",
+ "/v2/*"
+ ],
+ "ruleSets": [
+ {
+ "name": "depwafsecurityrulescdnpwaf"
+ }
+ ],
+ "supportedProtocols": [
+ "Https"
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ "customDomains": {
+ "value": [
+ {
+ "certificateType": "ManagedCertificate",
+ "cipherSuiteSetType": "TLS12_2023",
+ "hostName": "dep-waf-primary-cdnpwaf.example.com",
+ "minimumTlsVersion": "TLS12",
+ "name": "dep-waf-primary-cdnpwaf-domain"
+ },
+ {
+ "certificateType": "ManagedCertificate",
+ "cipherSuiteSetType": "Customized",
+ "customizedCipherSuiteSet": {
+ "cipherSuiteSetForTls13": [
+ "TLS_AES_128_GCM_SHA256",
+ "TLS_AES_256_GCM_SHA384"
+ ]
+ },
+ "hostName": "api-dep-waf-cdnpwaf.example.com",
+ "minimumTlsVersion": "TLS13",
+ "name": "dep-waf-api-cdnpwaf-domain"
+ }
+ ]
+ },
+ "diagnosticSettings": {
+ "value": [
+ {
+ "eventHubAuthorizationRuleResourceId": "",
+ "eventHubName": "",
+ "logCategoriesAndGroups": [
+ {
+ "categoryGroup": "allLogs",
+ "enabled": true
+ }
+ ],
+ "metricCategories": [
+ {
+ "category": "AllMetrics",
+ "enabled": true
+ }
+ ],
+ "name": "waf-comprehensive-diagnostics",
+ "storageAccountResourceId": "",
+ "workspaceResourceId": ""
+ }
+ ]
},
"location": {
- "value": ""
+ "value": "global"
+ },
+ "lock": {
+ "value": {
+ "kind": "CanNotDelete",
+ "name": "waf-protection-lock",
+ "notes": "WAF: Protected against accidental deletion for business continuity"
+ }
+ },
+ "managedIdentities": {
+ "value": {
+ "systemAssigned": true,
+ "userAssignedResourceIds": [
+ ""
+ ]
+ }
+ },
+ "originGroups": {
+ "value": [
+ {
+ "healthProbeSettings": {
+ "probeIntervalInSeconds": 15,
+ "probePath": "/api/health",
+ "probeProtocol": "Https",
+ "probeRequestType": "GET"
+ },
+ "loadBalancingSettings": {
+ "additionalLatencyInMilliseconds": 25,
+ "sampleSize": 6,
+ "successfulSamplesRequired": 4
+ },
+ "name": "dep-waf-api-origin-group",
+ "origins": [
+ {
+ "enabledState": "Enabled",
+ "enforceCertificateNameCheck": true,
+ "hostName": "",
+ "httpPort": 80,
+ "httpsPort": 443,
+ "name": "dep-waf-api-origin",
+ "priority": 1,
+ "weight": 1000
+ }
+ ],
+ "sessionAffinityState": "Disabled",
+ "trafficRestorationTimeToHealedOrNewEndpointsInMinutes": 2
+ }
+ ]
},
"originResponseTimeoutSeconds": {
"value": 60
+ },
+ "roleAssignments": {
+ "value": [
+ {
+ "principalId": "",
+ "principalType": "ServicePrincipal",
+ "roleDefinitionIdOrName": "CDN Profile Reader"
+ }
+ ]
+ },
+ "ruleSets": {
+ "value": [
+ {
+ "name": "depwafsecurityrulescdnpwaf",
+ "rules": [
+ {
+ "actions": [
+ {
+ "name": "UrlRedirect",
+ "parameters": {
+ "destinationProtocol": "Https",
+ "redirectType": "PermanentRedirect",
+ "typeName": "DeliveryRuleUrlRedirectActionParameters"
+ }
+ }
+ ],
+ "conditions": [
+ {
+ "name": "RequestScheme",
+ "parameters": {
+ "matchValues": [
+ "HTTP"
+ ],
+ "negateCondition": false,
+ "operator": "Equal",
+ "typeName": "DeliveryRuleRequestSchemeConditionParameters"
+ }
+ }
+ ],
+ "matchProcessingBehavior": "Stop",
+ "name": "HTTPSRedirectRule",
+ "order": 1
+ },
+ {
+ "actions": [
+ {
+ "name": "ModifyResponseHeader",
+ "parameters": {
+ "headerAction": "Overwrite",
+ "headerName": "Strict-Transport-Security",
+ "typeName": "DeliveryRuleHeaderActionParameters",
+ "value": "max-age=31536000; includeSubDomains; preload"
+ }
+ },
+ {
+ "name": "ModifyResponseHeader",
+ "parameters": {
+ "headerAction": "Overwrite",
+ "headerName": "X-Content-Type-Options",
+ "typeName": "DeliveryRuleHeaderActionParameters",
+ "value": "nosniff"
+ }
+ },
+ {
+ "name": "ModifyResponseHeader",
+ "parameters": {
+ "headerAction": "Overwrite",
+ "headerName": "X-Frame-Options",
+ "typeName": "DeliveryRuleHeaderActionParameters",
+ "value": "DENY"
+ }
+ },
+ {
+ "name": "ModifyResponseHeader",
+ "parameters": {
+ "headerAction": "Overwrite",
+ "headerName": "X-XSS-Protection",
+ "typeName": "DeliveryRuleHeaderActionParameters",
+ "value": "1; mode=block"
+ }
+ },
+ {
+ "name": "ModifyResponseHeader",
+ "parameters": {
+ "headerAction": "Overwrite",
+ "headerName": "Referrer-Policy",
+ "typeName": "DeliveryRuleHeaderActionParameters",
+ "value": "strict-origin-when-cross-origin"
+ }
+ }
+ ],
+ "conditions": [
+ {
+ "name": "RequestScheme",
+ "parameters": {
+ "matchValues": [
+ "HTTPS"
+ ],
+ "negateCondition": false,
+ "operator": "Equal",
+ "typeName": "DeliveryRuleRequestSchemeConditionParameters"
+ }
+ }
+ ],
+ "matchProcessingBehavior": "Continue",
+ "name": "SecurityHeadersRule",
+ "order": 2
+ },
+ {
+ "actions": [
+ {
+ "name": "ModifyResponseHeader",
+ "parameters": {
+ "headerAction": "Overwrite",
+ "headerName": "X-RateLimit-Limit",
+ "typeName": "DeliveryRuleHeaderActionParameters",
+ "value": "1000"
+ }
+ }
+ ],
+ "conditions": [
+ {
+ "name": "RequestUri",
+ "parameters": {
+ "matchValues": [
+ "/api/"
+ ],
+ "negateCondition": false,
+ "operator": "BeginsWith",
+ "transforms": [
+ "Lowercase"
+ ],
+ "typeName": "DeliveryRuleRequestUriConditionParameters"
+ }
+ }
+ ],
+ "matchProcessingBehavior": "Continue",
+ "name": "APIRateLimitRule",
+ "order": 3
+ }
+ ]
+ }
+ ]
+ },
+ "tags": {
+ "value": {
+ "Application": "CDN-WAF-Aligned",
+ "BackupRequired": "Yes",
+ "BusinessUnit": "Digital-Services",
+ "CostCenter": "IT-Infrastructure",
+ "Criticality": "High",
+ "DataClassification": "Internal",
+ "Environment": "Production",
+ "MonitoringRequired": "Yes",
+ "Owner": "Platform-Team",
+ "WAF-Pillar": "All"
+ }
}
}
}
@@ -1231,41 +2120,291 @@ module profile 'br/public:avm/res/cdn/profile:' = {
using 'br/public:avm/res/cdn/profile:'
// Required parameters
-param name = 'dep-test-cdnpwaf'
-param sku = 'Standard_Microsoft'
+param name = 'dep-waf-cdnpwaf'
+param sku = 'Premium_AzureFrontDoor'
// Non-required parameters
-param endpointProperties = {
- contentTypesToCompress: [
- 'application/javascript'
- 'application/json'
- 'application/x-javascript'
- 'application/xml'
- 'text/css'
- 'text/html'
- 'text/javascript'
- 'text/plain'
- ]
- geoFilters: []
- isCompressionEnabled: true
- isHttpAllowed: true
- isHttpsAllowed: true
- originGroups: []
- originHostHeader: ''
- origins: [
- {
- name: 'dep-cdn-endpoint01'
- properties: {
+param afdEndpoints = [
+ {
+ autoGeneratedDomainNameLabelScope: 'TenantReuse'
+ enabledState: 'Enabled'
+ name: 'dep-waf-primary-endpoint'
+ routes: [
+ {
+ cacheConfiguration: {
+ compressionSettings: {
+ contentTypesToCompress: [
+ 'application/json'
+ 'application/xml'
+ 'text/xml'
+ ]
+ isCompressionEnabled: true
+ }
+ queryParameters: 'timestamp,nonce'
+ queryStringCachingBehavior: 'IgnoreSpecifiedQueryStrings'
+ }
+ customDomainNames: [
+ 'dep-waf-api-cdnpwaf-domain'
+ ]
+ enabledState: 'Enabled'
+ forwardingProtocol: 'HttpsOnly'
+ httpsRedirect: 'Enabled'
+ linkToDefaultDomain: 'Disabled'
+ name: 'dep-waf-api-route'
+ originGroupName: 'dep-waf-api-origin-group'
+ patternsToMatch: [
+ '/api/*'
+ '/v1/*'
+ '/v2/*'
+ ]
+ ruleSets: [
+ {
+ name: 'depwafsecurityrulescdnpwaf'
+ }
+ ]
+ supportedProtocols: [
+ 'Https'
+ ]
+ }
+ ]
+ }
+]
+param customDomains = [
+ {
+ certificateType: 'ManagedCertificate'
+ cipherSuiteSetType: 'TLS12_2023'
+ hostName: 'dep-waf-primary-cdnpwaf.example.com'
+ minimumTlsVersion: 'TLS12'
+ name: 'dep-waf-primary-cdnpwaf-domain'
+ }
+ {
+ certificateType: 'ManagedCertificate'
+ cipherSuiteSetType: 'Customized'
+ customizedCipherSuiteSet: {
+ cipherSuiteSetForTls13: [
+ 'TLS_AES_128_GCM_SHA256'
+ 'TLS_AES_256_GCM_SHA384'
+ ]
+ }
+ hostName: 'api-dep-waf-cdnpwaf.example.com'
+ minimumTlsVersion: 'TLS13'
+ name: 'dep-waf-api-cdnpwaf-domain'
+ }
+]
+param diagnosticSettings = [
+ {
+ eventHubAuthorizationRuleResourceId: ''
+ eventHubName: ''
+ logCategoriesAndGroups: [
+ {
+ categoryGroup: 'allLogs'
+ enabled: true
+ }
+ ]
+ metricCategories: [
+ {
+ category: 'AllMetrics'
enabled: true
+ }
+ ]
+ name: 'waf-comprehensive-diagnostics'
+ storageAccountResourceId: ''
+ workspaceResourceId: ''
+ }
+]
+param location = 'global'
+param lock = {
+ kind: 'CanNotDelete'
+ name: 'waf-protection-lock'
+ notes: 'WAF: Protected against accidental deletion for business continuity'
+}
+param managedIdentities = {
+ systemAssigned: true
+ userAssignedResourceIds: [
+ ''
+ ]
+}
+param originGroups = [
+ {
+ healthProbeSettings: {
+ probeIntervalInSeconds: 15
+ probePath: '/api/health'
+ probeProtocol: 'Https'
+ probeRequestType: 'GET'
+ }
+ loadBalancingSettings: {
+ additionalLatencyInMilliseconds: 25
+ sampleSize: 6
+ successfulSamplesRequired: 4
+ }
+ name: 'dep-waf-api-origin-group'
+ origins: [
+ {
+ enabledState: 'Enabled'
+ enforceCertificateNameCheck: true
hostName: ''
httpPort: 80
httpsPort: 443
+ name: 'dep-waf-api-origin'
+ priority: 1
+ weight: 1000
}
- }
- ]
- queryStringCachingBehavior: 'IgnoreQueryString'
-}
-param location = ''
+ ]
+ sessionAffinityState: 'Disabled'
+ trafficRestorationTimeToHealedOrNewEndpointsInMinutes: 2
+ }
+]
param originResponseTimeoutSeconds = 60
+param roleAssignments = [
+ {
+ principalId: ''
+ principalType: 'ServicePrincipal'
+ roleDefinitionIdOrName: 'CDN Profile Reader'
+ }
+]
+param ruleSets = [
+ {
+ name: 'depwafsecurityrulescdnpwaf'
+ rules: [
+ {
+ actions: [
+ {
+ name: 'UrlRedirect'
+ parameters: {
+ destinationProtocol: 'Https'
+ redirectType: 'PermanentRedirect'
+ typeName: 'DeliveryRuleUrlRedirectActionParameters'
+ }
+ }
+ ]
+ conditions: [
+ {
+ name: 'RequestScheme'
+ parameters: {
+ matchValues: [
+ 'HTTP'
+ ]
+ negateCondition: false
+ operator: 'Equal'
+ typeName: 'DeliveryRuleRequestSchemeConditionParameters'
+ }
+ }
+ ]
+ matchProcessingBehavior: 'Stop'
+ name: 'HTTPSRedirectRule'
+ order: 1
+ }
+ {
+ actions: [
+ {
+ name: 'ModifyResponseHeader'
+ parameters: {
+ headerAction: 'Overwrite'
+ headerName: 'Strict-Transport-Security'
+ typeName: 'DeliveryRuleHeaderActionParameters'
+ value: 'max-age=31536000; includeSubDomains; preload'
+ }
+ }
+ {
+ name: 'ModifyResponseHeader'
+ parameters: {
+ headerAction: 'Overwrite'
+ headerName: 'X-Content-Type-Options'
+ typeName: 'DeliveryRuleHeaderActionParameters'
+ value: 'nosniff'
+ }
+ }
+ {
+ name: 'ModifyResponseHeader'
+ parameters: {
+ headerAction: 'Overwrite'
+ headerName: 'X-Frame-Options'
+ typeName: 'DeliveryRuleHeaderActionParameters'
+ value: 'DENY'
+ }
+ }
+ {
+ name: 'ModifyResponseHeader'
+ parameters: {
+ headerAction: 'Overwrite'
+ headerName: 'X-XSS-Protection'
+ typeName: 'DeliveryRuleHeaderActionParameters'
+ value: '1; mode=block'
+ }
+ }
+ {
+ name: 'ModifyResponseHeader'
+ parameters: {
+ headerAction: 'Overwrite'
+ headerName: 'Referrer-Policy'
+ typeName: 'DeliveryRuleHeaderActionParameters'
+ value: 'strict-origin-when-cross-origin'
+ }
+ }
+ ]
+ conditions: [
+ {
+ name: 'RequestScheme'
+ parameters: {
+ matchValues: [
+ 'HTTPS'
+ ]
+ negateCondition: false
+ operator: 'Equal'
+ typeName: 'DeliveryRuleRequestSchemeConditionParameters'
+ }
+ }
+ ]
+ matchProcessingBehavior: 'Continue'
+ name: 'SecurityHeadersRule'
+ order: 2
+ }
+ {
+ actions: [
+ {
+ name: 'ModifyResponseHeader'
+ parameters: {
+ headerAction: 'Overwrite'
+ headerName: 'X-RateLimit-Limit'
+ typeName: 'DeliveryRuleHeaderActionParameters'
+ value: '1000'
+ }
+ }
+ ]
+ conditions: [
+ {
+ name: 'RequestUri'
+ parameters: {
+ matchValues: [
+ '/api/'
+ ]
+ negateCondition: false
+ operator: 'BeginsWith'
+ transforms: [
+ 'Lowercase'
+ ]
+ typeName: 'DeliveryRuleRequestUriConditionParameters'
+ }
+ }
+ ]
+ matchProcessingBehavior: 'Continue'
+ name: 'APIRateLimitRule'
+ order: 3
+ }
+ ]
+ }
+]
+param tags = {
+ Application: 'CDN-WAF-Aligned'
+ BackupRequired: 'Yes'
+ BusinessUnit: 'Digital-Services'
+ CostCenter: 'IT-Infrastructure'
+ Criticality: 'High'
+ DataClassification: 'Internal'
+ Environment: 'Production'
+ MonitoringRequired: 'Yes'
+ Owner: 'Platform-Team'
+ 'WAF-Pillar': 'All'
+}
```
@@ -1955,6 +3094,7 @@ The minimum TLS version.
[
'TLS10'
'TLS12'
+ 'TLS13'
]
```
diff --git a/avm/res/cdn/profile/afd-endpoint/main.json b/avm/res/cdn/profile/afd-endpoint/main.json
index 4059cd82266..abc4c8d36f5 100644
--- a/avm/res/cdn/profile/afd-endpoint/main.json
+++ b/avm/res/cdn/profile/afd-endpoint/main.json
@@ -5,8 +5,8 @@
"metadata": {
"_generator": {
"name": "bicep",
- "version": "0.36.1.42791",
- "templateHash": "10968148801425056098"
+ "version": "0.37.4.10188",
+ "templateHash": "1610449730249909746"
},
"name": "CDN Profiles AFD Endpoints",
"description": "This module deploys a CDN Profile AFD Endpoint."
@@ -382,8 +382,8 @@
"metadata": {
"_generator": {
"name": "bicep",
- "version": "0.36.1.42791",
- "templateHash": "17117420688790383138"
+ "version": "0.37.4.10188",
+ "templateHash": "15191299450065701668"
},
"name": "CDN Profiles AFD Endpoint Route",
"description": "This module deploys a CDN Profile AFD Endpoint route."
diff --git a/avm/res/cdn/profile/afd-endpoint/route/main.json b/avm/res/cdn/profile/afd-endpoint/route/main.json
index e35a78fedfe..e120fdbb707 100644
--- a/avm/res/cdn/profile/afd-endpoint/route/main.json
+++ b/avm/res/cdn/profile/afd-endpoint/route/main.json
@@ -5,8 +5,8 @@
"metadata": {
"_generator": {
"name": "bicep",
- "version": "0.36.1.42791",
- "templateHash": "17117420688790383138"
+ "version": "0.37.4.10188",
+ "templateHash": "15191299450065701668"
},
"name": "CDN Profiles AFD Endpoint Route",
"description": "This module deploys a CDN Profile AFD Endpoint route."
diff --git a/avm/res/cdn/profile/custom-domain/README.md b/avm/res/cdn/profile/custom-domain/README.md
index b5cffda1402..33cbdab38ee 100644
--- a/avm/res/cdn/profile/custom-domain/README.md
+++ b/avm/res/cdn/profile/custom-domain/README.md
@@ -12,7 +12,7 @@ This module deploys a CDN Profile Custom Domains.
| Resource Type | API Version | References |
| :-- | :-- | :-- |
-| `Microsoft.Cdn/profiles/customDomains` | 2025-04-15 |
- [AzAdvertizer](https://www.azadvertizer.net/azresourcetypes/microsoft.cdn_profiles_customdomains.html)
- [Template reference](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Cdn/2025-04-15/profiles/customDomains)
|
+| `Microsoft.Cdn/profiles/customDomains` | 2025-06-01 | - [AzAdvertizer](https://www.azadvertizer.net/azresourcetypes/microsoft.cdn_profiles_customdomains.html)
- [Template reference](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Cdn/2025-06-01/profiles/customDomains)
|
## Parameters
@@ -114,6 +114,7 @@ The minimum TLS version required for the custom domain. Default value: TLS12.
[
'TLS10'
'TLS12'
+ 'TLS13'
]
```
diff --git a/avm/res/cdn/profile/custom-domain/main.bicep b/avm/res/cdn/profile/custom-domain/main.bicep
index 51ec1fe616c..edad3023cbf 100644
--- a/avm/res/cdn/profile/custom-domain/main.bicep
+++ b/avm/res/cdn/profile/custom-domain/main.bicep
@@ -30,6 +30,7 @@ param certificateType string
@allowed([
'TLS10'
'TLS12'
+ 'TLS13'
])
@description('Optional. The minimum TLS version required for the custom domain. Default value: TLS12.')
param minimumTlsVersion string = 'TLS12'
@@ -51,7 +52,7 @@ resource profile 'Microsoft.Cdn/profiles@2025-04-15' existing = {
}
}
-resource customDomain 'Microsoft.Cdn/profiles/customDomains@2025-04-15' = {
+resource customDomain 'Microsoft.Cdn/profiles/customDomains@2025-06-01' = {
name: name
parent: profile
properties: {
@@ -125,7 +126,7 @@ type customDomainType = {
secretName: string?
@description('Optional. The minimum TLS version.')
- minimumTlsVersion: 'TLS10' | 'TLS12' | null
+ minimumTlsVersion: 'TLS10' | 'TLS12' | 'TLS13' | null
@description('Optional. Extended properties.')
extendedProperties: object?
diff --git a/avm/res/cdn/profile/custom-domain/main.json b/avm/res/cdn/profile/custom-domain/main.json
index 8061c2448dc..8fa19e5cead 100644
--- a/avm/res/cdn/profile/custom-domain/main.json
+++ b/avm/res/cdn/profile/custom-domain/main.json
@@ -5,8 +5,8 @@
"metadata": {
"_generator": {
"name": "bicep",
- "version": "0.36.1.42791",
- "templateHash": "4152856745534187528"
+ "version": "0.37.4.10188",
+ "templateHash": "1486369118418758330"
},
"name": "CDN Profiles Custom Domains",
"description": "This module deploys a CDN Profile Custom Domains."
@@ -63,7 +63,8 @@
"type": "string",
"allowedValues": [
"TLS10",
- "TLS12"
+ "TLS12",
+ "TLS13"
],
"nullable": true,
"metadata": {
@@ -184,7 +185,8 @@
"defaultValue": "TLS12",
"allowedValues": [
"TLS10",
- "TLS12"
+ "TLS12",
+ "TLS13"
],
"metadata": {
"description": "Optional. The minimum TLS version required for the custom domain. Default value: TLS12."
@@ -228,7 +230,7 @@
},
"customDomain": {
"type": "Microsoft.Cdn/profiles/customDomains",
- "apiVersion": "2025-04-15",
+ "apiVersion": "2025-06-01",
"name": "[format('{0}/{1}', parameters('profileName'), parameters('name'))]",
"properties": {
"azureDnsZone": "[if(not(empty(parameters('azureDnsZoneResourceId'))), createObject('id', parameters('azureDnsZoneResourceId')), null())]",
diff --git a/avm/res/cdn/profile/endpoint/main.json b/avm/res/cdn/profile/endpoint/main.json
index 64dd4928667..f6f46c08109 100644
--- a/avm/res/cdn/profile/endpoint/main.json
+++ b/avm/res/cdn/profile/endpoint/main.json
@@ -5,8 +5,8 @@
"metadata": {
"_generator": {
"name": "bicep",
- "version": "0.36.1.42791",
- "templateHash": "3222821096361861437"
+ "version": "0.37.4.10188",
+ "templateHash": "5226882540835560084"
},
"name": "CDN Profiles Endpoints",
"description": "This module deploys a CDN Profile Endpoint."
@@ -121,8 +121,8 @@
"metadata": {
"_generator": {
"name": "bicep",
- "version": "0.36.1.42791",
- "templateHash": "13368120440571907708"
+ "version": "0.37.4.10188",
+ "templateHash": "10119907844998577144"
},
"name": "CDN Profiles Endpoints Origins",
"description": "This module deploys a CDN Profile Endpoint Origin."
diff --git a/avm/res/cdn/profile/endpoint/origin/main.json b/avm/res/cdn/profile/endpoint/origin/main.json
index cc5ffa34b1b..dafb9ad55a5 100644
--- a/avm/res/cdn/profile/endpoint/origin/main.json
+++ b/avm/res/cdn/profile/endpoint/origin/main.json
@@ -5,8 +5,8 @@
"metadata": {
"_generator": {
"name": "bicep",
- "version": "0.36.1.42791",
- "templateHash": "13368120440571907708"
+ "version": "0.37.4.10188",
+ "templateHash": "10119907844998577144"
},
"name": "CDN Profiles Endpoints Origins",
"description": "This module deploys a CDN Profile Endpoint Origin."
diff --git a/avm/res/cdn/profile/main.bicep b/avm/res/cdn/profile/main.bicep
index 22f8670d7c9..80f6263ea62 100644
--- a/avm/res/cdn/profile/main.bicep
+++ b/avm/res/cdn/profile/main.bicep
@@ -145,7 +145,7 @@ resource avmTelemetry 'Microsoft.Resources/deployments@2025-04-01' = if (enableT
}
}
-resource profile 'Microsoft.Cdn/profiles@2025-04-15' = {
+resource profile 'Microsoft.Cdn/profiles@2025-06-01' = {
name: name
location: location
identity: identity
diff --git a/avm/res/cdn/profile/main.json b/avm/res/cdn/profile/main.json
index 3660b7b3d87..5344701b939 100644
--- a/avm/res/cdn/profile/main.json
+++ b/avm/res/cdn/profile/main.json
@@ -6,7 +6,7 @@
"_generator": {
"name": "bicep",
"version": "0.37.4.10188",
- "templateHash": "5810889614348598823"
+ "templateHash": "9277089994275321905"
},
"name": "CDN Profiles",
"description": "This module deploys a CDN Profile."
@@ -434,7 +434,8 @@
"type": "string",
"allowedValues": [
"TLS10",
- "TLS12"
+ "TLS12",
+ "TLS13"
],
"nullable": true,
"metadata": {
@@ -1183,7 +1184,7 @@
},
"profile": {
"type": "Microsoft.Cdn/profiles",
- "apiVersion": "2025-04-15",
+ "apiVersion": "2025-06-01",
"name": "[parameters('name')]",
"location": "[parameters('location')]",
"identity": "[variables('identity')]",
@@ -1820,7 +1821,7 @@
"_generator": {
"name": "bicep",
"version": "0.37.4.10188",
- "templateHash": "1129107995084048204"
+ "templateHash": "1486369118418758330"
},
"name": "CDN Profiles Custom Domains",
"description": "This module deploys a CDN Profile Custom Domains."
@@ -1877,7 +1878,8 @@
"type": "string",
"allowedValues": [
"TLS10",
- "TLS12"
+ "TLS12",
+ "TLS13"
],
"nullable": true,
"metadata": {
@@ -1998,7 +2000,8 @@
"defaultValue": "TLS12",
"allowedValues": [
"TLS10",
- "TLS12"
+ "TLS12",
+ "TLS13"
],
"metadata": {
"description": "Optional. The minimum TLS version required for the custom domain. Default value: TLS12."
@@ -2042,7 +2045,7 @@
},
"customDomain": {
"type": "Microsoft.Cdn/profiles/customDomains",
- "apiVersion": "2025-04-15",
+ "apiVersion": "2025-06-01",
"name": "[format('{0}/{1}', parameters('profileName'), parameters('name'))]",
"properties": {
"azureDnsZone": "[if(not(empty(parameters('azureDnsZoneResourceId'))), createObject('id', parameters('azureDnsZoneResourceId')), null())]",
@@ -4202,7 +4205,7 @@
"metadata": {
"description": "The location the resource was deployed into."
},
- "value": "[reference('profile', '2025-04-15', 'full').location]"
+ "value": "[reference('profile', '2025-06-01', 'full').location]"
},
"endpointName": {
"type": "string",
@@ -4231,7 +4234,7 @@
"metadata": {
"description": "The principal ID of the system assigned identity."
},
- "value": "[tryGet(tryGet(reference('profile', '2025-04-15', 'full'), 'identity'), 'principalId')]"
+ "value": "[tryGet(tryGet(reference('profile', '2025-06-01', 'full'), 'identity'), 'principalId')]"
},
"dnsValidation": {
"type": "array",
diff --git a/avm/res/cdn/profile/origin-group/main.json b/avm/res/cdn/profile/origin-group/main.json
index f4383e9e9bd..16f6ab81ac2 100644
--- a/avm/res/cdn/profile/origin-group/main.json
+++ b/avm/res/cdn/profile/origin-group/main.json
@@ -5,8 +5,8 @@
"metadata": {
"_generator": {
"name": "bicep",
- "version": "0.36.1.42791",
- "templateHash": "17376902853351027070"
+ "version": "0.37.4.10188",
+ "templateHash": "14962728161506551015"
},
"name": "CDN Profiles Origin Group",
"description": "This module deploys a CDN Profile Origin Group."
@@ -352,8 +352,8 @@
"metadata": {
"_generator": {
"name": "bicep",
- "version": "0.36.1.42791",
- "templateHash": "3654686564131775119"
+ "version": "0.37.4.10188",
+ "templateHash": "8524246809029737366"
},
"name": "CDN Profiles Origin",
"description": "This module deploys a CDN Profile Origin."
diff --git a/avm/res/cdn/profile/origin-group/origin/main.json b/avm/res/cdn/profile/origin-group/origin/main.json
index ad8882e1cc0..5263acfdbce 100644
--- a/avm/res/cdn/profile/origin-group/origin/main.json
+++ b/avm/res/cdn/profile/origin-group/origin/main.json
@@ -5,8 +5,8 @@
"metadata": {
"_generator": {
"name": "bicep",
- "version": "0.36.1.42791",
- "templateHash": "3654686564131775119"
+ "version": "0.37.4.10188",
+ "templateHash": "8524246809029737366"
},
"name": "CDN Profiles Origin",
"description": "This module deploys a CDN Profile Origin."
diff --git a/avm/res/cdn/profile/rule-set/main.json b/avm/res/cdn/profile/rule-set/main.json
index 8f2d49de289..611d8ab0922 100644
--- a/avm/res/cdn/profile/rule-set/main.json
+++ b/avm/res/cdn/profile/rule-set/main.json
@@ -5,8 +5,8 @@
"metadata": {
"_generator": {
"name": "bicep",
- "version": "0.36.1.42791",
- "templateHash": "9308092005992913249"
+ "version": "0.37.4.10188",
+ "templateHash": "2563031334159492138"
},
"name": "CDN Profiles Rule Sets",
"description": "This module deploys a CDN Profile rule set."
@@ -165,8 +165,8 @@
"metadata": {
"_generator": {
"name": "bicep",
- "version": "0.36.1.42791",
- "templateHash": "13557087255389320076"
+ "version": "0.37.4.10188",
+ "templateHash": "14802510232650562515"
},
"name": "CDN Profiles Rules",
"description": "This module deploys a CDN Profile rule."
diff --git a/avm/res/cdn/profile/rule-set/rule/main.json b/avm/res/cdn/profile/rule-set/rule/main.json
index 4476fdd9b2b..a2ff2de21d1 100644
--- a/avm/res/cdn/profile/rule-set/rule/main.json
+++ b/avm/res/cdn/profile/rule-set/rule/main.json
@@ -5,8 +5,8 @@
"metadata": {
"_generator": {
"name": "bicep",
- "version": "0.36.1.42791",
- "templateHash": "13557087255389320076"
+ "version": "0.37.4.10188",
+ "templateHash": "14802510232650562515"
},
"name": "CDN Profiles Rules",
"description": "This module deploys a CDN Profile rule."
diff --git a/avm/res/cdn/profile/secret/main.json b/avm/res/cdn/profile/secret/main.json
index 41cfe5045a9..fd82adbece8 100644
--- a/avm/res/cdn/profile/secret/main.json
+++ b/avm/res/cdn/profile/secret/main.json
@@ -4,8 +4,8 @@
"metadata": {
"_generator": {
"name": "bicep",
- "version": "0.36.1.42791",
- "templateHash": "10255459755240506859"
+ "version": "0.37.4.10188",
+ "templateHash": "932660675787735782"
},
"name": "CDN Profiles Secret",
"description": "This module deploys a CDN Profile Secret."
diff --git a/avm/res/cdn/profile/security-policy/main.json b/avm/res/cdn/profile/security-policy/main.json
index 1797a680e5e..be99f0dfcdd 100644
--- a/avm/res/cdn/profile/security-policy/main.json
+++ b/avm/res/cdn/profile/security-policy/main.json
@@ -5,8 +5,8 @@
"metadata": {
"_generator": {
"name": "bicep",
- "version": "0.36.1.42791",
- "templateHash": "564000263660798116"
+ "version": "0.37.4.10188",
+ "templateHash": "15025860363241476047"
},
"name": "CDN Profiles Security Policy",
"description": "This module deploys a CDN Profile Security Policy."
diff --git a/avm/res/cdn/profile/tests/e2e/afd.premium/main.test.bicep b/avm/res/cdn/profile/tests/e2e/afd.premium/main.test.bicep
index b6089adcc05..f67743e2e3b 100644
--- a/avm/res/cdn/profile/tests/e2e/afd.premium/main.test.bicep
+++ b/avm/res/cdn/profile/tests/e2e/afd.premium/main.test.bicep
@@ -50,7 +50,7 @@ module testDeployment '../../../main.bicep' = [
scope: resourceGroup
name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}'
params: {
- name: 'dep-${namePrefix}-test-${serviceShort}'
+ name: 'dep-${namePrefix}-test-afd-${serviceShort}'
location: 'global'
originResponseTimeoutSeconds: 60
sku: 'Premium_AzureFrontDoor'
@@ -102,7 +102,7 @@ module testDeployment '../../../main.bicep' = [
]
afdEndpoints: [
{
- name: 'dep-${namePrefix}-test-${serviceShort}-afd-endpoint'
+ name: 'dep-${namePrefix}-test-afd-${serviceShort}-afd-endpoint'
routes: [
{
name: 'dep-${namePrefix}-test-${serviceShort}-afd-route'
@@ -127,9 +127,9 @@ module testDeployment '../../../main.bicep' = [
id: resourceId(
subscription().subscriptionId,
resourceGroup.name,
- 'Microsoft.Cdn/profiles/afdEndpoints',
- 'dep-${namePrefix}-test-${serviceShort}',
- 'dep-${namePrefix}-test-${serviceShort}-afd-endpoint'
+ 'Microsoft.Cdn/profiles/customDomains',
+ 'dep-${namePrefix}-test-afd-${serviceShort}',
+ 'dep-${namePrefix}-test-${serviceShort}-custom-domain'
)
}
]
diff --git a/avm/res/cdn/profile/tests/e2e/defaults/main.test.bicep b/avm/res/cdn/profile/tests/e2e/defaults/main.test.bicep
index 68c415ae4d7..88d186d2e96 100644
--- a/avm/res/cdn/profile/tests/e2e/defaults/main.test.bicep
+++ b/avm/res/cdn/profile/tests/e2e/defaults/main.test.bicep
@@ -38,8 +38,8 @@ module testDeployment '../../../main.bicep' = [
name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}'
params: {
name: 'dep-${namePrefix}-test-${serviceShort}'
- location: resourceLocation
- sku: 'Standard_Microsoft'
+ location: 'global'
+ sku: 'Standard_AzureFrontDoor'
}
}
]
diff --git a/avm/res/cdn/profile/tests/e2e/max/dependencies.bicep b/avm/res/cdn/profile/tests/e2e/max/dependencies.bicep
index 72f40561cee..9b8c2c7183b 100644
--- a/avm/res/cdn/profile/tests/e2e/max/dependencies.bicep
+++ b/avm/res/cdn/profile/tests/e2e/max/dependencies.bicep
@@ -35,4 +35,7 @@ output storageAccountResourceId string = storageAccount.id
output storageAccountName string = storageAccount.name
@description('The resource ID of the created Managed Identity.')
+output managedIdentityResourceId string = managedIdentity.id
+
+@description('The principal ID of the created Managed Identity.')
output managedIdentityPrincipalId string = managedIdentity.properties.principalId
diff --git a/avm/res/cdn/profile/tests/e2e/max/main.test.bicep b/avm/res/cdn/profile/tests/e2e/max/main.test.bicep
index dcb647e5f30..e5c92799c4f 100644
--- a/avm/res/cdn/profile/tests/e2e/max/main.test.bicep
+++ b/avm/res/cdn/profile/tests/e2e/max/main.test.bicep
@@ -1,7 +1,7 @@
targetScope = 'subscription'
-metadata name = 'Using large parameter set'
-metadata description = 'This instance deploys the module with most of its features enabled.'
+metadata name = 'Using maximum parameter set'
+metadata description = 'This instance deploys the module with all available features and parameters for Premium_AzureFrontDoor SKU.'
// ========== //
// Parameters //
@@ -9,7 +9,7 @@ metadata description = 'This instance deploys the module with most of its featur
@description('Optional. The name of the resource group to deploy for testing purposes.')
@maxLength(90)
-param resourceGroupName string = 'dep-${namePrefix}-cdn.profiles-${serviceShort}-rg'
+param resourceGroupName string = 'dep-${namePrefix}-cdn.profiles.max-${serviceShort}-rg'
@description('Optional. The location to deploy resources to.')
param resourceLocation string = deployment().location
@@ -66,43 +66,203 @@ module testDeployment '../../../main.bicep' = [
name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}'
params: {
name: 'dep-${namePrefix}-test-${serviceShort}'
- location: resourceLocation
+ location: 'global'
+ sku: 'Premium_AzureFrontDoor'
+ originResponseTimeoutSeconds: 240
+
+ // Managed Identity
+ managedIdentities: {
+ systemAssigned: true
+ userAssignedResourceIds: [
+ nestedDependencies.outputs.managedIdentityResourceId
+ ]
+ }
+
+ // Lock configuration
lock: {
kind: 'CanNotDelete'
name: 'myCustomLockName'
+ notes: 'This resource cannot be deleted for security reasons.'
}
- originResponseTimeoutSeconds: 60
- sku: 'Standard_Microsoft'
- endpointProperties: {
- originHostHeader: '${nestedDependencies.outputs.storageAccountName}.blob.${environment().suffixes.storage}'
- contentTypesToCompress: [
- 'text/plain'
- 'text/html'
- 'text/css'
- 'text/javascript'
- 'application/x-javascript'
- 'application/javascript'
- 'application/json'
- 'application/xml'
- ]
- isCompressionEnabled: true
- isHttpAllowed: true
- isHttpsAllowed: true
- queryStringCachingBehavior: 'IgnoreQueryString'
- origins: [
- {
- name: 'dep-${namePrefix}-cdn-endpoint01'
- properties: {
+
+ // Tags
+ tags: {
+ Environment: 'Test'
+ Application: 'CDN'
+ CostCenter: '12345'
+ Owner: 'TestTeam'
+ }
+
+ // Custom Domains with simplified configurations (FIXED)
+ customDomains: [
+ {
+ name: 'dep-${namePrefix}-test1-${serviceShort}-custom-domain'
+ hostName: 'dep-${namePrefix}-test1-${serviceShort}-custom-domain.azurewebsites.net'
+ certificateType: 'ManagedCertificate'
+ minimumTlsVersion: 'TLS12'
+ }
+ {
+ name: 'dep-${namePrefix}-test2-${serviceShort}-custom-domain'
+ hostName: 'dep-${namePrefix}-test2-${serviceShort}-custom-domain.azurewebsites.net'
+ certificateType: 'ManagedCertificate'
+ minimumTlsVersion: 'TLS12'
+ cipherSuiteSetType: 'TLS12_2022'
+ }
+ {
+ name: 'dep-${namePrefix}-test3-${serviceShort}-custom-domain'
+ hostName: 'dep-${namePrefix}-test3-${serviceShort}-custom-domain.azurewebsites.net'
+ certificateType: 'ManagedCertificate'
+ minimumTlsVersion: 'TLS13'
+ cipherSuiteSetType: 'Customized'
+ customizedCipherSuiteSet: {
+ // cipherSuiteSetForTls12: [
+ // 'DHE_RSA_AES128_GCM_SHA256'
+ // 'DHE_RSA_AES256_GCM_SHA384'
+ // 'ECDHE_RSA_AES128_GCM_SHA256'
+ // 'ECDHE_RSA_AES256_GCM_SHA384'
+ // ]
+ cipherSuiteSetForTls13: [
+ 'TLS_AES_128_GCM_SHA256'
+ 'TLS_AES_256_GCM_SHA384'
+ ]
+ }
+ }
+ ]
+
+ // Origin Groups with realistic hostnames (FIXED)
+ originGroups: [
+ {
+ name: 'dep-${namePrefix}-test-${serviceShort}-origin-group-1'
+ loadBalancingSettings: {
+ additionalLatencyInMilliseconds: 50
+ sampleSize: 4
+ successfulSamplesRequired: 3
+ }
+ healthProbeSettings: {
+ probePath: '/health'
+ probeProtocol: 'Https'
+ probeRequestType: 'GET'
+ probeIntervalInSeconds: 120
+ }
+ sessionAffinityState: 'Enabled'
+ trafficRestorationTimeToHealedOrNewEndpointsInMinutes: 15
+ origins: [
+ {
+ name: 'dep-${namePrefix}-test-${serviceShort}-origin-1'
hostName: '${nestedDependencies.outputs.storageAccountName}.blob.${environment().suffixes.storage}'
httpPort: 80
httpsPort: 443
- enabled: true
+ priority: 1
+ weight: 1000
+ enabledState: 'Enabled'
+ enforceCertificateNameCheck: true
}
+ ]
+ }
+ {
+ name: 'dep-${namePrefix}-test-${serviceShort}-origin-group-2'
+ loadBalancingSettings: {
+ additionalLatencyInMilliseconds: 100
+ sampleSize: 6
+ successfulSamplesRequired: 4
}
- ]
- originGroups: []
- geoFilters: []
- }
+ sessionAffinityState: 'Disabled'
+ trafficRestorationTimeToHealedOrNewEndpointsInMinutes: 10
+ origins: [
+ {
+ name: 'dep-${namePrefix}-test-${serviceShort}-origin-2'
+ hostName: '${nestedDependencies.outputs.storageAccountName}.blob.${environment().suffixes.storage}'
+ httpPort: 80
+ httpsPort: 443
+ priority: 1
+ weight: 1000
+ enabledState: 'Enabled'
+ enforceCertificateNameCheck: true
+ }
+ ]
+ }
+ ]
+
+ // Rule Sets with comprehensive rules
+ ruleSets: [
+ {
+ name: 'dep${namePrefix}test${serviceShort}ruleset1'
+ rules: [
+ {
+ name: 'dep${namePrefix}test${serviceShort}rule1'
+ order: 1
+ matchProcessingBehavior: 'Continue'
+ conditions: [
+ // {
+ // name: 'RequestMethod'
+ // parameters: {
+ // typeName: 'DeliveryRuleRequestMethodConditionParameters'
+ // operator: 'Equal'
+ // negateCondition: false
+ // matchValues: ['GET', 'POST']
+ // transforms: []
+ // }
+ // }
+ ]
+ actions: [
+ {
+ name: 'UrlRedirect'
+ parameters: {
+ typeName: 'DeliveryRuleUrlRedirectActionParameters'
+ redirectType: 'PermanentRedirect'
+ destinationProtocol: 'Https'
+ customPath: '/v2/api/'
+ customHostname: 'api.example.com'
+ }
+ }
+ ]
+ }
+ ]
+ }
+ ]
+
+ // AFD Endpoints with simplified routing (FIXED)
+ afdEndpoints: [
+ {
+ name: 'dep-${namePrefix}-test-${serviceShort}-afd-endpoint-1'
+ autoGeneratedDomainNameLabelScope: 'TenantReuse'
+ enabledState: 'Enabled'
+ routes: [
+ {
+ name: 'dep-${namePrefix}-test-${serviceShort}-afd-route-1'
+ originGroupName: 'dep-${namePrefix}-test-${serviceShort}-origin-group-1'
+ customDomainNames: [
+ 'dep-${namePrefix}-test1-${serviceShort}-custom-domain'
+ ]
+ enabledState: 'Enabled'
+ forwardingProtocol: 'MatchRequest'
+ httpsRedirect: 'Enabled'
+ linkToDefaultDomain: 'Enabled'
+ patternsToMatch: ['/api/*', '/health']
+ supportedProtocols: ['Http', 'Https']
+ cacheConfiguration: {
+ queryStringCachingBehavior: 'IncludeSpecifiedQueryStrings'
+ queryParameters: 'version,locale'
+ compressionSettings: {
+ contentTypesToCompress: [
+ 'application/json'
+ 'text/css'
+ 'text/html'
+ ]
+ isCompressionEnabled: true
+ }
+ }
+ ruleSets: [
+ {
+ name: 'dep${namePrefix}test${serviceShort}ruleset1'
+ }
+ ]
+ }
+ ]
+ }
+ ]
+
+ // Diagnostics settings
diagnosticSettings: [
{
name: 'customSetting'
@@ -124,24 +284,11 @@ module testDeployment '../../../main.bicep' = [
workspaceResourceId: diagnosticDependencies.outputs.logAnalyticsWorkspaceResourceId
}
]
+
+ // Role assignments
roleAssignments: [
{
- name: '50362c78-6910-43c3-8639-9cae123943bb'
- roleDefinitionIdOrName: 'Owner'
- principalId: nestedDependencies.outputs.managedIdentityPrincipalId
- principalType: 'ServicePrincipal'
- }
- {
- name: guid('Custom seed ${namePrefix}${serviceShort}')
- roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c'
- principalId: nestedDependencies.outputs.managedIdentityPrincipalId
- principalType: 'ServicePrincipal'
- }
- {
- roleDefinitionIdOrName: subscriptionResourceId(
- 'Microsoft.Authorization/roleDefinitions',
- 'acdd72a7-3385-48ef-bd42-f606fba81ae7'
- )
+ roleDefinitionIdOrName: 'CDN Profile Contributor'
principalId: nestedDependencies.outputs.managedIdentityPrincipalId
principalType: 'ServicePrincipal'
}
@@ -149,3 +296,25 @@ module testDeployment '../../../main.bicep' = [
}
}
]
+
+// =========== //
+// Outputs //
+// =========== //
+
+@description('The name of the CDN profile.')
+output profileName string = testDeployment[0].outputs.name
+
+@description('The resource ID of the CDN profile.')
+output profileResourceId string = testDeployment[0].outputs.resourceId
+
+@description('The DNS validation records for custom domains.')
+output dnsValidationRecords array = testDeployment[0].outputs.dnsValidation
+
+@description('The AFD endpoint host names.')
+output afdEndpointNames array = testDeployment[0].outputs.frontDoorEndpointHostNames
+
+@description('The resource group name.')
+output resourceGroupName string = resourceGroup.name
+
+@description('The system-assigned managed identity principal ID.')
+output systemAssignedMIPrincipalId string = testDeployment[0].outputs.?systemAssignedMIPrincipalId
diff --git a/avm/res/cdn/profile/tests/e2e/waf-aligned/dependencies.bicep b/avm/res/cdn/profile/tests/e2e/waf-aligned/dependencies.bicep
index 99f4f8887b7..822673cf323 100644
--- a/avm/res/cdn/profile/tests/e2e/waf-aligned/dependencies.bicep
+++ b/avm/res/cdn/profile/tests/e2e/waf-aligned/dependencies.bicep
@@ -1,27 +1,92 @@
@description('Optional. The location to deploy resources to.')
param location string = resourceGroup().location
-@description('Required. The name of the Storage Account to create.')
+@description('Required. The name of the primary Storage Account to create.')
param storageAccountName string
+@description('Required. The name of the Managed Identity to create.')
+param managedIdentityName string
+
+// WAF: Reliability - Primary storage account with geo-redundancy
resource storageAccount 'Microsoft.Storage/storageAccounts@2024-01-01' = {
name: storageAccountName
location: location
sku: {
- name: 'Standard_LRS'
+ name: 'Standard_GRS' // WAF: Reliability - Geo-redundant storage
+ }
+ kind: 'StorageV2'
+ properties: {
+ allowBlobPublicAccess: true // Required for CDN access
+ minimumTlsVersion: 'TLS1_2' // WAF: Security - Minimum TLS version
+ supportsHttpsTrafficOnly: true // WAF: Security - HTTPS only
+ accessTier: 'Hot' // WAF: Performance - Hot tier for frequently accessed data
+ networkAcls: {
+ defaultAction: 'Allow' // WAF: Allow CDN access
+ bypass: 'AzureServices'
+ }
+ encryption: {
+ services: {
+ blob: {
+ enabled: true // WAF: Security - Encryption at rest
+ }
+ file: {
+ enabled: true
+ }
+ }
+ keySource: 'Microsoft.Storage'
+ }
+ }
+}
+
+// WAF: Reliability - Secondary storage account for failover
+resource secondaryStorageAccount 'Microsoft.Storage/storageAccounts@2024-01-01' = {
+ name: '${take(storageAccountName, 20)}sec'
+ location: location
+ sku: {
+ name: 'Standard_LRS' // WAF: Cost Optimization - LRS for secondary
}
kind: 'StorageV2'
properties: {
- allowBlobPublicAccess: false
+ allowBlobPublicAccess: true
+ minimumTlsVersion: 'TLS1_2'
+ supportsHttpsTrafficOnly: true
+ accessTier: 'Cool' // WAF: Cost Optimization - Cool tier for backup
networkAcls: {
- defaultAction: 'Deny'
+ defaultAction: 'Allow'
bypass: 'AzureServices'
}
+ encryption: {
+ services: {
+ blob: {
+ enabled: true
+ }
+ file: {
+ enabled: true
+ }
+ }
+ keySource: 'Microsoft.Storage'
+ }
}
}
-@description('The resource ID of the created Storage Account.')
+// WAF: Security - Managed identity for secure access
+resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2024-11-30' = {
+ name: managedIdentityName
+ location: location
+}
+
+// Outputs
+@description('The resource ID of the primary Storage Account.')
output storageAccountResourceId string = storageAccount.id
-@description('The name of the created Storage Account.')
+@description('The name of the primary Storage Account.')
output storageAccountName string = storageAccount.name
+
+@description('The name of the secondary Storage Account.')
+output secondaryStorageAccountName string = secondaryStorageAccount.name
+
+@description('The resource ID of the Managed Identity.')
+output managedIdentityResourceId string = managedIdentity.id
+
+@description('The principal ID of the Managed Identity.')
+output managedIdentityPrincipalId string = managedIdentity.properties.principalId
diff --git a/avm/res/cdn/profile/tests/e2e/waf-aligned/main.test.bicep b/avm/res/cdn/profile/tests/e2e/waf-aligned/main.test.bicep
index 3ac6419d8d8..c5023dd8f07 100644
--- a/avm/res/cdn/profile/tests/e2e/waf-aligned/main.test.bicep
+++ b/avm/res/cdn/profile/tests/e2e/waf-aligned/main.test.bicep
@@ -1,7 +1,7 @@
targetScope = 'subscription'
-metadata name = 'WAF-aligned'
-metadata description = 'This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework.'
+metadata name = 'WAF-aligned Premium AFD'
+metadata description = 'This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework using Premium_AzureFrontDoor SKU.'
// ========== //
// Parameters //
@@ -35,7 +35,23 @@ module nestedDependencies 'dependencies.bicep' = {
scope: resourceGroup
name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies'
params: {
- storageAccountName: 'dep${namePrefix}cdnstore${serviceShort}'
+ storageAccountName: 'dep${namePrefix}wafsa${serviceShort}'
+ managedIdentityName: 'dep-${namePrefix}-waf-msi-${serviceShort}'
+ // keyVaultName: 'dep-${namePrefix}-kv-${uniqueString(resourceGroupName)}'
+ location: resourceLocation
+ }
+}
+
+// Diagnostics
+// ===========
+module diagnosticDependencies '../../../../../../../utilities/e2e-template-assets/templates/diagnostic.dependencies.bicep' = {
+ scope: resourceGroup
+ name: '${uniqueString(deployment().name, resourceLocation)}-diagnosticDependencies'
+ params: {
+ storageAccountName: 'dep${namePrefix}diasa${serviceShort}03'
+ logAnalyticsWorkspaceName: 'dep-${namePrefix}-law-${serviceShort}'
+ eventHubNamespaceEventHubName: 'dep-${namePrefix}-evh-${serviceShort}01'
+ eventHubNamespaceName: 'dep-${namePrefix}-evhns-${serviceShort}01'
location: resourceLocation
}
}
@@ -50,43 +66,357 @@ module testDeployment '../../../main.bicep' = [
scope: resourceGroup
name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}'
params: {
- name: 'dep-${namePrefix}-test-${serviceShort}'
- location: resourceLocation
- originResponseTimeoutSeconds: 60
- sku: 'Standard_Microsoft'
- endpointProperties: {
- originHostHeader: '${nestedDependencies.outputs.storageAccountName}.blob.${environment().suffixes.storage}'
- contentTypesToCompress: [
- 'text/plain'
- 'text/html'
- 'text/css'
- 'text/javascript'
- 'application/x-javascript'
- 'application/javascript'
- 'application/json'
- 'application/xml'
- ]
- isCompressionEnabled: true
- isHttpAllowed: true
- isHttpsAllowed: true
- queryStringCachingBehavior: 'IgnoreQueryString'
- origins: [
- {
- name: 'dep-${namePrefix}-cdn-endpoint01'
- properties: {
+ name: 'dep-${namePrefix}-waf-${serviceShort}'
+ location: 'global'
+ sku: 'Premium_AzureFrontDoor' // WAF: Premium SKU for advanced security features
+ originResponseTimeoutSeconds: 60 // WAF: Reasonable timeout for reliability
+
+ // WAF: Security - Resource locking to prevent accidental deletion
+ lock: {
+ kind: 'CanNotDelete'
+ name: 'waf-protection-lock'
+ notes: 'WAF: Protected against accidental deletion for business continuity'
+ }
+
+ // WAF: Cost Optimization & Operational Excellence - Comprehensive tagging
+ tags: {
+ Environment: 'Production'
+ Application: 'CDN-WAF-Aligned'
+ CostCenter: 'IT-Infrastructure'
+ Owner: 'Platform-Team'
+ BusinessUnit: 'Digital-Services'
+ Criticality: 'High'
+ DataClassification: 'Internal'
+ BackupRequired: 'Yes'
+ MonitoringRequired: 'Yes'
+ 'WAF-Pillar': 'All'
+ // 'Last-Review': utcNow('yyyy-MM-dd')
+ }
+
+ // WAF: Security - Custom domains with strong TLS configuration
+ customDomains: [
+ {
+ name: 'dep-${namePrefix}-waf-primary-${serviceShort}-domain'
+ hostName: 'dep-${namePrefix}-waf-primary-${serviceShort}.example.com'
+ certificateType: 'ManagedCertificate'
+ minimumTlsVersion: 'TLS12' // WAF: Security - Use latest TLS version
+ cipherSuiteSetType: 'TLS12_2023' // WAF: Security - Modern cipher suites
+ }
+ {
+ name: 'dep-${namePrefix}-waf-api-${serviceShort}-domain'
+ hostName: 'api-dep-${namePrefix}-waf-${serviceShort}.example.com'
+ certificateType: 'ManagedCertificate'
+ minimumTlsVersion: 'TLS13' // WAF: Security - Use latest TLS version
+ cipherSuiteSetType: 'Customized' // WAF: Security - Custom cipher suite for enhanced security
+ customizedCipherSuiteSet: {
+ // cipherSuiteSetForTls12: [
+ // 'ECDHE_RSA_AES256_GCM_SHA384' // Strong encryption
+ // 'ECDHE_RSA_AES128_GCM_SHA256' // Performance balance
+ // ]
+ cipherSuiteSetForTls13: [
+ 'TLS_AES_256_GCM_SHA384' // Strong TLS 1.3 cipher
+ 'TLS_AES_128_GCM_SHA256' // Performance balance
+ ]
+ }
+ }
+ ]
+
+ // WAF: Reliability & Performance - Multi-origin setup with health probes
+ originGroups: [
+ {
+ name: 'dep-${namePrefix}-waf-api-origin-group'
+ loadBalancingSettings: {
+ additionalLatencyInMilliseconds: 25 // WAF: Performance - Lower latency for APIs
+ sampleSize: 6 // WAF: Reliability - More samples for critical APIs
+ successfulSamplesRequired: 4 // WAF: Reliability - Higher threshold for APIs
+ }
+ healthProbeSettings: {
+ probePath: '/api/health' // WAF: Reliability - API-specific health check
+ probeProtocol: 'Https' // WAF: Security - Encrypted health checks
+ probeRequestType: 'GET'
+ probeIntervalInSeconds: 15 // WAF: Reliability - More frequent for APIs
+ }
+ sessionAffinityState: 'Disabled'
+ trafficRestorationTimeToHealedOrNewEndpointsInMinutes: 2 // WAF: Reliability - Faster recovery for APIs
+ origins: [
+ {
+ name: 'dep-${namePrefix}-waf-api-origin'
hostName: '${nestedDependencies.outputs.storageAccountName}.blob.${environment().suffixes.storage}'
httpPort: 80
httpsPort: 443
+ priority: 1
+ weight: 1000
+ enabledState: 'Enabled'
+ enforceCertificateNameCheck: true // WAF: Security - Certificate validation
+ }
+ ]
+ }
+ ]
+
+ // WAF: Security & Performance - Comprehensive routing rules
+ ruleSets: [
+ {
+ name: 'dep${namePrefix}wafsecurityrules${serviceShort}'
+ rules: [
+ {
+ name: 'HTTPSRedirectRule'
+ order: 1
+ matchProcessingBehavior: 'Stop' // WAF: Security - Force HTTPS immediately
+ conditions: [
+ {
+ name: 'RequestScheme'
+ parameters: {
+ typeName: 'DeliveryRuleRequestSchemeConditionParameters'
+ operator: 'Equal'
+ negateCondition: false
+ matchValues: ['HTTP']
+ }
+ }
+ ]
+ actions: [
+ {
+ name: 'UrlRedirect'
+ parameters: {
+ typeName: 'DeliveryRuleUrlRedirectActionParameters'
+ redirectType: 'PermanentRedirect' // WAF: Security - Permanent HTTPS enforcement
+ destinationProtocol: 'Https'
+ }
+ }
+ ]
+ }
+ {
+ name: 'SecurityHeadersRule'
+ order: 2
+ matchProcessingBehavior: 'Continue'
+ conditions: [
+ {
+ name: 'RequestScheme'
+ parameters: {
+ typeName: 'DeliveryRuleRequestSchemeConditionParameters'
+ operator: 'Equal'
+ negateCondition: false
+ matchValues: ['HTTPS']
+ }
+ }
+ ]
+ actions: [
+ {
+ name: 'ModifyResponseHeader'
+ parameters: {
+ typeName: 'DeliveryRuleHeaderActionParameters'
+ headerAction: 'Overwrite'
+ headerName: 'Strict-Transport-Security'
+ value: 'max-age=31536000; includeSubDomains; preload' // WAF: Security - HSTS
+ }
+ }
+ {
+ name: 'ModifyResponseHeader'
+ parameters: {
+ typeName: 'DeliveryRuleHeaderActionParameters'
+ headerAction: 'Overwrite'
+ headerName: 'X-Content-Type-Options'
+ value: 'nosniff' // WAF: Security - MIME type sniffing protection
+ }
+ }
+ {
+ name: 'ModifyResponseHeader'
+ parameters: {
+ typeName: 'DeliveryRuleHeaderActionParameters'
+ headerAction: 'Overwrite'
+ headerName: 'X-Frame-Options'
+ value: 'DENY' // WAF: Security - Clickjacking protection
+ }
+ }
+ {
+ name: 'ModifyResponseHeader'
+ parameters: {
+ typeName: 'DeliveryRuleHeaderActionParameters'
+ headerAction: 'Overwrite'
+ headerName: 'X-XSS-Protection'
+ value: '1; mode=block' // WAF: Security - XSS protection
+ }
+ }
+ {
+ name: 'ModifyResponseHeader'
+ parameters: {
+ typeName: 'DeliveryRuleHeaderActionParameters'
+ headerAction: 'Overwrite'
+ headerName: 'Referrer-Policy'
+ value: 'strict-origin-when-cross-origin' // WAF: Security - Referrer policy
+ }
+ }
+ ]
+ }
+ {
+ name: 'APIRateLimitRule'
+ order: 3
+ matchProcessingBehavior: 'Continue'
+ conditions: [
+ {
+ name: 'RequestUri'
+ parameters: {
+ typeName: 'DeliveryRuleRequestUriConditionParameters'
+ operator: 'BeginsWith'
+ negateCondition: false
+ matchValues: ['/api/']
+ transforms: ['Lowercase']
+ }
+ }
+ ]
+ actions: [
+ {
+ name: 'ModifyResponseHeader'
+ parameters: {
+ typeName: 'DeliveryRuleHeaderActionParameters'
+ headerAction: 'Overwrite'
+ headerName: 'X-RateLimit-Limit'
+ value: '1000' // WAF: Reliability - Rate limiting for APIs
+ }
+ }
+ ]
+ }
+ ]
+ }
+ ]
+
+ // WAF: Performance & Reliability - Optimized AFD endpoints
+ afdEndpoints: [
+ {
+ name: 'dep-${namePrefix}-waf-primary-endpoint'
+ autoGeneratedDomainNameLabelScope: 'TenantReuse' // WAF: Cost Optimization - Reuse domains
+ enabledState: 'Enabled'
+ routes: [
+ {
+ name: 'dep-${namePrefix}-waf-api-route'
+ originGroupName: 'dep-${namePrefix}-waf-api-origin-group'
+ customDomainNames: [
+ 'dep-${namePrefix}-waf-api-${serviceShort}-domain'
+ ]
+ enabledState: 'Enabled'
+ forwardingProtocol: 'HttpsOnly' // WAF: Security - HTTPS only for APIs
+ httpsRedirect: 'Enabled'
+ linkToDefaultDomain: 'Disabled' // WAF: Security - Custom domain only for APIs
+ patternsToMatch: ['/api/*', '/v1/*', '/v2/*']
+ supportedProtocols: ['Https'] // WAF: Security - HTTPS only
+ cacheConfiguration: {
+ queryStringCachingBehavior: 'IgnoreSpecifiedQueryStrings' // WAF: Performance - API-specific caching
+ queryParameters: 'timestamp,nonce' // WAF: Performance - Ignore security parameters
+ compressionSettings: {
+ contentTypesToCompress: [
+ 'application/json'
+ 'application/xml'
+ 'text/xml'
+ ]
+ isCompressionEnabled: true // WAF: Performance - API response compression
+ }
+ }
+ ruleSets: [
+ {
+ name: 'dep${namePrefix}wafsecurityrules${serviceShort}'
+ }
+ ]
+ }
+ ]
+ }
+ ]
+
+ // WAF: Operational Excellence - Comprehensive diagnostics and monitoring
+ diagnosticSettings: [
+ {
+ name: 'waf-comprehensive-diagnostics'
+ logCategoriesAndGroups: [
+ {
+ categoryGroup: 'allLogs'
enabled: true
}
- }
+ ]
+ metricCategories: [
+ {
+ category: 'AllMetrics'
+ enabled: true
+ }
+ ]
+ eventHubName: diagnosticDependencies.outputs.eventHubNamespaceEventHubName
+ eventHubAuthorizationRuleResourceId: diagnosticDependencies.outputs.eventHubAuthorizationRuleId
+ storageAccountResourceId: diagnosticDependencies.outputs.storageAccountResourceId
+ workspaceResourceId: diagnosticDependencies.outputs.logAnalyticsWorkspaceResourceId
+ }
+ ]
+
+ // WAF: Security - Role-based access control
+ roleAssignments: [
+ {
+ roleDefinitionIdOrName: 'CDN Profile Reader' // WAF: Security - Principle of least privilege
+ principalId: nestedDependencies.outputs.managedIdentityPrincipalId
+ principalType: 'ServicePrincipal'
+ }
+ ]
+
+ // WAF: Reliability - Enable managed identities for secure access
+ managedIdentities: {
+ systemAssigned: true
+ userAssignedResourceIds: [
+ nestedDependencies.outputs.managedIdentityResourceId
]
- originGroups: []
- geoFilters: []
}
}
- dependsOn: [
- nestedDependencies
- ]
}
]
+
+// =========== //
+// Outputs //
+// =========== //
+
+@description('The name of the WAF-aligned CDN profile.')
+output profileName string = testDeployment[0].outputs.name
+
+@description('The resource ID of the WAF-aligned CDN profile.')
+output profileResourceId string = testDeployment[0].outputs.resourceId
+
+@description('The DNS validation records for custom domains.')
+output dnsValidationRecords array = testDeployment[0].outputs.dnsValidation
+
+@description('The AFD endpoint host names.')
+output afdEndpointNames array = testDeployment[0].outputs.frontDoorEndpointHostNames
+
+@description('The resource group name.')
+output resourceGroupName string = resourceGroup.name
+
+@description('WAF compliance summary.')
+output wafComplianceSummary object = {
+ reliability: {
+ multiOriginSetup: true
+ healthProbes: true
+ loadBalancing: true
+ failoverConfiguration: true
+ quickRecovery: true
+ }
+ security: {
+ httpsOnly: true
+ tls13Support: true
+ securityHeaders: true
+ certificateValidation: true
+ managedIdentities: true
+ rbacImplemented: true
+ resourceLocks: true
+ }
+ costOptimization: {
+ comprehensiveTagging: true
+ efficientCaching: true
+ domainReuse: true
+ rightsizedSku: true
+ }
+ operationalExcellence: {
+ comprehensiveMonitoring: true
+ structuredLogging: true
+ automatedDiagnostics: true
+ documentedConfiguration: true
+ }
+ performance: {
+ compressionEnabled: true
+ optimizedCaching: true
+ lowLatencyThresholds: true
+ efficientRouting: true
+ staticContentOptimization: true
+ }
+}
diff --git a/avm/res/cdn/profile/version.json b/avm/res/cdn/profile/version.json
index ed8416987fa..804998a2ad3 100644
--- a/avm/res/cdn/profile/version.json
+++ b/avm/res/cdn/profile/version.json
@@ -1,4 +1,4 @@
{
"$schema": "https://aka.ms/bicep-registry-module-version-file-schema#",
- "version": "0.14"
+ "version": "0.15"
}