rules/Azure.APIM.Rule.ps1
# Copyright (c) Microsoft Corporation. # Licensed under the MIT License. # # Validation rules for API Management # # Synopsis: Enforce HTTPS for communication to API clients. Rule 'Azure.APIM.HTTPEndpoint' -Ref 'AZR-000042' -Type 'Microsoft.ApiManagement/service', 'Microsoft.ApiManagement/service/apis' -Tag @{ release = 'GA'; ruleSet = '2020_06'; 'Azure.WAF/pillar' = 'Security'; } -Labels @{ 'Azure.ASB.v3/control' = 'DP-3' } { if ($PSRule.TargetType -eq 'Microsoft.ApiManagement/service') { $apis = @(GetSubResources -ResourceType 'Microsoft.ApiManagement/service/apis') if ($apis.Length -eq 0) { return $Assert.Pass(); } foreach ($api in $apis) { $Assert.NotIn($api, 'properties.protocols', @('http')) } } elseif ($PSRule.TargetType -eq 'Microsoft.ApiManagement/service/apis') { $Assert.NotIn($TargetObject, 'properties.protocols', @('http')) } } # Synopsis: APIs should have descriptors set Rule 'Azure.APIM.APIDescriptors' -Ref 'AZR-000043' -Level Warning -Type 'Microsoft.ApiManagement/service', 'Microsoft.ApiManagement/service/apis' -Tag @{ release = 'GA'; ruleSet = '2020_09' } { $apis = @($TargetObject); if ($PSRule.TargetType -eq 'Microsoft.ApiManagement/service') { $apis = @(GetSubResources -ResourceType 'Microsoft.ApiManagement/service/apis'); } if ($apis.Length -eq 0) { return $Assert.Pass(); } foreach ($api in $apis) { $Assert. HasFieldValue($api, 'Properties.displayName'). Reason($LocalizedData.APIMDescriptors, 'API', $api.name, 'displayName'); $Assert. HasFieldValue($api, 'Properties.description'). Reason($LocalizedData.APIMDescriptors, 'API', $api.name, 'description'); } } # Synopsis: Use HTTPS for communication to backend services. Rule 'Azure.APIM.HTTPBackend' -Ref 'AZR-000044' -Type 'Microsoft.ApiManagement/service', 'Microsoft.ApiManagement/service/backends', 'Microsoft.ApiManagement/service/apis' -Tag @{ release = 'GA'; ruleSet = '2020_06'; 'Azure.WAF/pillar' = 'Security'; } -Labels @{ 'Azure.ASB.v3/control' = 'DP-3' } { $apis = @(); $backends = @(); if ($PSRule.TargetType -eq 'Microsoft.ApiManagement/service') { $backends = @(GetSubResources -ResourceType 'Microsoft.ApiManagement/service/backends' | Where-Object { $Assert.HasField($_, 'properties.url').Result }); $apis = @(GetSubResources -ResourceType 'Microsoft.ApiManagement/service/apis' | Where-Object { $Assert.HasField($_, 'properties.serviceUrl').Result }); } elseif ($PSRule.TargetType -eq 'Microsoft.ApiManagement/service/apis') { if ($Assert.HasField($TargetObject, 'properties.serviceUrl').Result) { $apis = @($TargetObject) } } elseif ($PSRule.TargetType -eq 'Microsoft.ApiManagement/service/backends') { if ($Assert.HasField($TargetObject, 'properties.url').Result) { $backends = @($TargetObject) } } if ($backends.Length -eq 0 -and $apis.Length -eq 0) { return $Assert.Pass(); } foreach ($backend in $backends) { $Assert. NotStartsWith($backend, 'properties.url', 'http://'). Reason($LocalizedData.BackendUrlNotHttps, $backend.name); } foreach ($api in $apis) { $Assert. NotStartsWith($api, 'properties.serviceUrl', 'http://'). Reason($LocalizedData.ServiceUrlNotHttps, $api.name); } } # Synopsis: Encrypt all named values Rule 'Azure.APIM.EncryptValues' -Ref 'AZR-000045' -Type 'Microsoft.ApiManagement/service', 'Microsoft.ApiManagement/service/properties', 'Microsoft.ApiManagement/service/namedValues' -Tag @{ release = 'GA'; ruleSet = '2020_06'; 'Azure.WAF/pillar' = 'Security'; } -Labels @{ 'Azure.ASB.v3/control' = @('IM-8', 'DP-7') } { $properties = @($TargetObject); if ($PSRule.TargetType -eq 'Microsoft.ApiManagement/service') { $properties = @(GetSubResources -ResourceType 'Microsoft.ApiManagement/service/properties', 'Microsoft.ApiManagement/service/namedValues'); } if ($properties.Length -eq 0) { return $Assert.Pass(); } foreach ($property in $properties) { $Assert. HasFieldValue($property, 'properties.secret', $True). WithReason(($LocalizedData.APIMSecretNamedValues -f $property.name), $True); } } # Synopsis: Require subscription for products Rule 'Azure.APIM.ProductSubscription' -Ref 'AZR-000046' -Type 'Microsoft.ApiManagement/service', 'Microsoft.ApiManagement/service/products' -Tag @{ release = 'GA'; ruleSet = '2020_06' } { $products = @($TargetObject); if ($PSRule.TargetType -eq 'Microsoft.ApiManagement/service') { $products = @(GetSubResources -ResourceType 'Microsoft.ApiManagement/service/products'); } if ($products.Length -eq 0) { return $Assert.Pass(); } foreach ($product in $products) { $Assert. HasFieldValue($product, 'Properties.subscriptionRequired', $True). WithReason(($LocalizedData.APIMProductSubscription -f $product.Name), $True); } } # Synopsis: Require approval for products Rule 'Azure.APIM.ProductApproval' -Ref 'AZR-000047' -Type 'Microsoft.ApiManagement/service', 'Microsoft.ApiManagement/service/products' -Tag @{ release = 'GA'; ruleSet = '2020_06' } { $products = @($TargetObject); if ($PSRule.TargetType -eq 'Microsoft.ApiManagement/service') { $products = @(GetSubResources -ResourceType 'Microsoft.ApiManagement/service/products'); } if ($products.Length -eq 0) { return $Assert.Pass(); } foreach ($product in $products) { $Assert. HasFieldValue($product, 'Properties.approvalRequired', $True). WithReason(($LocalizedData.APIMProductApproval -f $product.Name), $True); } } # Synopsis: Remove sample products Rule 'Azure.APIM.SampleProducts' -Ref 'AZR-000048' -Type 'Microsoft.ApiManagement/service', 'Microsoft.ApiManagement/service/products' -Tag @{ release = 'GA'; ruleSet = '2020_06' } { $products = @($TargetObject); if ($PSRule.TargetType -eq 'Microsoft.ApiManagement/service') { $products = @(GetSubResources -ResourceType 'Microsoft.ApiManagement/service/products'); } if ($products.Length -eq 0) { return $Assert.Pass(); } foreach ($product in $products) { $Assert.NotIn($product, 'Name', @('unlimited', 'starter')) } } # Synopsis: Products should have descriptors set Rule 'Azure.APIM.ProductDescriptors' -Ref 'AZR-000049' -Level Warning -Type 'Microsoft.ApiManagement/service', 'Microsoft.ApiManagement/service/products' -Tag @{ release = 'GA'; ruleSet = '2020_09' } { $products = @($TargetObject); if ($PSRule.TargetType -eq 'Microsoft.ApiManagement/service') { $products = @(GetSubResources -ResourceType 'Microsoft.ApiManagement/service/products'); } if ($products.Length -eq 0) { return $Assert.Pass(); } foreach ($product in $products) { $Assert. HasFieldValue($product, 'Properties.displayName'). WithReason(($LocalizedData.APIMDescriptors -f 'product', $product.name, 'displayName'), $True); $Assert. HasFieldValue($product, 'Properties.description'). WithReason(($LocalizedData.APIMDescriptors -f 'product', $product.name, 'description'), $True); } } # Synopsis: Use product terms Rule 'Azure.APIM.ProductTerms' -Ref 'AZR-000050' -Type 'Microsoft.ApiManagement/service', 'Microsoft.ApiManagement/service/products' -Tag @{ release = 'GA'; ruleSet = '2020_09' } { $products = @($TargetObject); if ($PSRule.TargetType -eq 'Microsoft.ApiManagement/service') { $products = @(GetSubResources -ResourceType 'Microsoft.ApiManagement/service/products'); } if ($products.Length -eq 0) { return $Assert.Pass(); } foreach ($product in $products) { $Assert. HasFieldValue($product, 'Properties.terms'). WithReason(($LocalizedData.APIMProductTerms -f $product.name), $True); } } # Synopsis: Renew expired certificates Rule 'Azure.APIM.CertificateExpiry' -Ref 'AZR-000051' -Type 'Microsoft.ApiManagement/service' -Tag @{ release = 'GA'; ruleSet = '2020_06'; 'Azure.WAF/pillar' = 'Security'; } -Labels @{ 'Azure.ASB.v3/control' = 'DP-7' } { $configurations = @($TargetObject.Properties.hostnameConfigurations | Where-Object { $Null -ne $_.certificate }) if ($configurations.Length -eq 0) { return $Assert.Pass(); } foreach ($configuration in $configurations) { $remaining = ($configuration.certificate.expiry - [DateTime]::Now).Days; $Assert. GreaterOrEqual($remaining, '.', $Configuration.Azure_MinimumCertificateLifetime). WithReason(($LocalizedData.APIMCertificateExpiry -f $configuration.hostName, $configuration.certificate.expiry.ToString('yyyy/MM/dd')), $True); } } -Configure @{ Azure_MinimumCertificateLifetime = 30 } # Synopsis: API management services deployed with Premium SKU should use availability zones in supported regions for high availability. Rule 'Azure.APIM.AvailabilityZone' -Ref 'AZR-000052' -Type 'Microsoft.ApiManagement/service' -If { IsPremiumAPIM } -Tag @{ release = 'GA'; ruleSet = '2021_12' } { $apiManagementServiceProvider = [PSRule.Rules.Azure.Runtime.Helper]::GetResourceType('Microsoft.ApiManagement', 'service'); $configurationZoneMappings = $Configuration.AZURE_APIM_ADDITIONAL_REGION_AVAILABILITY_ZONE_LIST; $providerZoneMappings = $apiManagementServiceProvider.ZoneMappings; $mergedAvailabilityZones = PrependConfigurationZoneWithProviderZone -ConfigurationZone $configurationZoneMappings -ProviderZone $providerZoneMappings; $primaryLocationAvailabilityZones = GetAvailabilityZone -Location $TargetObject.Location -Zone $mergedAvailabilityZones; # Validate primary location availability zones if (-not $primaryLocationAvailabilityZones) { $Assert.Pass(); } else { $hasValidUnits = $Assert.GreaterOrEqual($TargetObject, 'sku.capacity', $TargetObject.zones.Length).Result; $hasValidZones = $Assert.GreaterOrEqual($TargetObject, 'zones', 2).Result; $Assert.Create( ($hasValidUnits -and $hasValidZones), $LocalizedData.APIMAvailabilityZone, $TargetObject.name, $TargetObject.Location, ($primaryLocationAvailabilityZones -join ', ') ) } # Also validate any additional locations that are added to APIM if (-not $Assert.NullOrEmpty($TargetObject, 'Properties.additionalLocations').Result) { foreach ($additionalLocation in $TargetObject.Properties.additionalLocations) { $additionalLocationAvailabilityZones = GetAvailabilityZone -Location $additionalLocation.Location -Zone $mergedAvailabilityZones; if (-not $additionalLocationAvailabilityZones) { $Assert.Pass(); } else { $hasValidUnits = $Assert.GreaterOrEqual($additionalLocation, 'sku.capacity', $additionalLocation.zones.Length).Result; $hasValidZones = $Assert.GreaterOrEqual($additionalLocation, 'zones', 2).Result; $Assert.Create( ($hasValidUnits -and $hasValidZones), $LocalizedData.APIMAvailabilityZone, $TargetObject.name, $additionalLocation.Location, ($additionalLocationAvailabilityZones -join ', ') ); } } } } -Configure @{ AZURE_APIM_ADDITIONAL_REGION_AVAILABILITY_ZONE_LIST = @() } # Synopsis: API Management instances should limit control plane API calls to API Management with version '2021-08-01' or newer. Rule 'Azure.APIM.MinAPIVersion' -Ref 'AZR-000321' -Type 'Microsoft.ApiManagement/service' -Tag @{ release = 'GA'; ruleSet = '2022_12'; } { if ($TargetObject.apiVersion) { [datetime]$versionConfigured = $TargetObject.apiVersion -replace '-preview', '' [datetime]$minimumVersionExpected = $Configuration.AZURE_APIM_MIN_API_VERSION -replace '-preview', '' $Assert.Create($versionConfigured -ge $minimumVersionExpected, $LocalizedData.APIMApiVersionMin, $TargetObject.apiVersion, $Configuration.AZURE_APIM_MIN_API_VERSION).PathPrefix('apiVersion') } if ($TargetObject.properties.apiVersionConstraint.minApiVersion) { [datetime]$minApiVersionConfigured = $TargetObject.properties.apiVersionConstraint.minApiVersion -replace '-preview', '' [datetime]$minApiVersionExpected = $Configuration.AZURE_APIM_MIN_API_VERSION -replace '-preview', '' $Assert.Create($minApiVersionConfigured -ge $minApiVersionExpected, $LocalizedData.APIMApiVersionConstraintMinApiVersion, $TargetObject.properties.apiVersionConstraint.minApiVersion, $Configuration.AZURE_APIM_MIN_API_VERSION). PathPrefix('properties.apiVersionConstraint.minApiVersion') } else { $Assert.Fail().Reason($LocalizedData.APIMApiVersionConstraintMinApiVersionNotFound) } } -Configure @{ AZURE_APIM_MIN_API_VERSION = '2021-08-01' } # Synopsis: API Management instances should use multi-region deployment to improve service availability. Rule 'Azure.APIM.MultiRegion' -Ref 'AZR-000340' -Type 'Microsoft.ApiManagement/service' -If { IsPremiumAPIM } -Tag @{ release = 'GA'; ruleSet = '2022_12'; } { $Assert.GreaterOrEqual($TargetObject, 'properties.additionalLocations', 1).Reason($LocalizedData.APIMMultiRegion) } # Synopsis: API Management instances should have multi-region deployment gateways enabled. Rule 'Azure.APIM.MultiRegionGateway' -Ref 'AZR-000341' -Type 'Microsoft.ApiManagement/service' -If { (IsPremiumAPIM) -and (IsMultiRegion) } -Tag @{ release = 'GA'; ruleSet = '2022_12'; } { $gateways = $PSRule.GetPath($TargetObject, 'properties.additionalLocations') foreach ($gateway in $gateways) { $Assert.HasDefaultValue($gateway, 'disableGateway', $False) } } #region Helper functions function global:IsPremiumAPIM { [CmdletBinding()] [OutputType([System.Boolean])] param () process { return $Assert.HasFieldValue($TargetObject, 'sku.name', 'Premium').Result; } } function global:IsMultiRegion { [CmdletBinding()] [OutputType([System.Boolean])] param () process { $Assert.GreaterOrEqual($TargetObject, 'properties.additionalLocations', 1).Result } } #endregion Helper functions # SIG # Begin signature block # MIInsQYJKoZIhvcNAQcCoIInojCCJ54CAQExDzANBglghkgBZQMEAgEFADB5Bgor # BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG # KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCDwECC7evPPlZAA # tELdH5BlfaYpIDsUjEoup8Xjv6TvpqCCDYUwggYDMIID66ADAgECAhMzAAACzfNk # v/jUTF1RAAAAAALNMA0GCSqGSIb3DQEBCwUAMH4xCzAJBgNVBAYTAlVTMRMwEQYD # VQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNy # b3NvZnQgQ29ycG9yYXRpb24xKDAmBgNVBAMTH01pY3Jvc29mdCBDb2RlIFNpZ25p # bmcgUENBIDIwMTEwHhcNMjIwNTEyMjA0NjAyWhcNMjMwNTExMjA0NjAyWjB0MQsw # CQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9u # ZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMR4wHAYDVQQDExVNaWNy # b3NvZnQgQ29ycG9yYXRpb24wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB # AQDrIzsY62MmKrzergm7Ucnu+DuSHdgzRZVCIGi9CalFrhwtiK+3FIDzlOYbs/zz # HwuLC3hir55wVgHoaC4liQwQ60wVyR17EZPa4BQ28C5ARlxqftdp3H8RrXWbVyvQ # aUnBQVZM73XDyGV1oUPZGHGWtgdqtBUd60VjnFPICSf8pnFiit6hvSxH5IVWI0iO # nfqdXYoPWUtVUMmVqW1yBX0NtbQlSHIU6hlPvo9/uqKvkjFUFA2LbC9AWQbJmH+1 # uM0l4nDSKfCqccvdI5l3zjEk9yUSUmh1IQhDFn+5SL2JmnCF0jZEZ4f5HE7ykDP+ # oiA3Q+fhKCseg+0aEHi+DRPZAgMBAAGjggGCMIIBfjAfBgNVHSUEGDAWBgorBgEE # AYI3TAgBBggrBgEFBQcDAzAdBgNVHQ4EFgQU0WymH4CP7s1+yQktEwbcLQuR9Zww # VAYDVR0RBE0wS6RJMEcxLTArBgNVBAsTJE1pY3Jvc29mdCBJcmVsYW5kIE9wZXJh # dGlvbnMgTGltaXRlZDEWMBQGA1UEBRMNMjMwMDEyKzQ3MDUzMDAfBgNVHSMEGDAW # gBRIbmTlUAXTgqoXNzcitW2oynUClTBUBgNVHR8ETTBLMEmgR6BFhkNodHRwOi8v # d3d3Lm1pY3Jvc29mdC5jb20vcGtpb3BzL2NybC9NaWNDb2RTaWdQQ0EyMDExXzIw # MTEtMDctMDguY3JsMGEGCCsGAQUFBwEBBFUwUzBRBggrBgEFBQcwAoZFaHR0cDov # L3d3dy5taWNyb3NvZnQuY29tL3BraW9wcy9jZXJ0cy9NaWNDb2RTaWdQQ0EyMDEx # XzIwMTEtMDctMDguY3J0MAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQELBQADggIB # AE7LSuuNObCBWYuttxJAgilXJ92GpyV/fTiyXHZ/9LbzXs/MfKnPwRydlmA2ak0r # GWLDFh89zAWHFI8t9JLwpd/VRoVE3+WyzTIskdbBnHbf1yjo/+0tpHlnroFJdcDS # MIsH+T7z3ClY+6WnjSTetpg1Y/pLOLXZpZjYeXQiFwo9G5lzUcSd8YVQNPQAGICl # 2JRSaCNlzAdIFCF5PNKoXbJtEqDcPZ8oDrM9KdO7TqUE5VqeBe6DggY1sZYnQD+/ # LWlz5D0wCriNgGQ/TWWexMwwnEqlIwfkIcNFxo0QND/6Ya9DTAUykk2SKGSPt0kL # tHxNEn2GJvcNtfohVY/b0tuyF05eXE3cdtYZbeGoU1xQixPZAlTdtLmeFNly82uB # VbybAZ4Ut18F//UrugVQ9UUdK1uYmc+2SdRQQCccKwXGOuYgZ1ULW2u5PyfWxzo4 # BR++53OB/tZXQpz4OkgBZeqs9YaYLFfKRlQHVtmQghFHzB5v/WFonxDVlvPxy2go # a0u9Z+ZlIpvooZRvm6OtXxdAjMBcWBAsnBRr/Oj5s356EDdf2l/sLwLFYE61t+ME # iNYdy0pXL6gN3DxTVf2qjJxXFkFfjjTisndudHsguEMk8mEtnvwo9fOSKT6oRHhM # 9sZ4HTg/TTMjUljmN3mBYWAWI5ExdC1inuog0xrKmOWVMIIHejCCBWKgAwIBAgIK # YQ6Q0gAAAAAAAzANBgkqhkiG9w0BAQsFADCBiDELMAkGA1UEBhMCVVMxEzARBgNV # BAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jv # c29mdCBDb3Jwb3JhdGlvbjEyMDAGA1UEAxMpTWljcm9zb2Z0IFJvb3QgQ2VydGlm # aWNhdGUgQXV0aG9yaXR5IDIwMTEwHhcNMTEwNzA4MjA1OTA5WhcNMjYwNzA4MjEw # OTA5WjB+MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UE # BxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSgwJgYD # VQQDEx9NaWNyb3NvZnQgQ29kZSBTaWduaW5nIFBDQSAyMDExMIICIjANBgkqhkiG # 9w0BAQEFAAOCAg8AMIICCgKCAgEAq/D6chAcLq3YbqqCEE00uvK2WCGfQhsqa+la # UKq4BjgaBEm6f8MMHt03a8YS2AvwOMKZBrDIOdUBFDFC04kNeWSHfpRgJGyvnkmc # 6Whe0t+bU7IKLMOv2akrrnoJr9eWWcpgGgXpZnboMlImEi/nqwhQz7NEt13YxC4D # dato88tt8zpcoRb0RrrgOGSsbmQ1eKagYw8t00CT+OPeBw3VXHmlSSnnDb6gE3e+ # lD3v++MrWhAfTVYoonpy4BI6t0le2O3tQ5GD2Xuye4Yb2T6xjF3oiU+EGvKhL1nk # kDstrjNYxbc+/jLTswM9sbKvkjh+0p2ALPVOVpEhNSXDOW5kf1O6nA+tGSOEy/S6 # A4aN91/w0FK/jJSHvMAhdCVfGCi2zCcoOCWYOUo2z3yxkq4cI6epZuxhH2rhKEmd # X4jiJV3TIUs+UsS1Vz8kA/DRelsv1SPjcF0PUUZ3s/gA4bysAoJf28AVs70b1FVL # 5zmhD+kjSbwYuER8ReTBw3J64HLnJN+/RpnF78IcV9uDjexNSTCnq47f7Fufr/zd # sGbiwZeBe+3W7UvnSSmnEyimp31ngOaKYnhfsi+E11ecXL93KCjx7W3DKI8sj0A3 # T8HhhUSJxAlMxdSlQy90lfdu+HggWCwTXWCVmj5PM4TasIgX3p5O9JawvEagbJjS # 4NaIjAsCAwEAAaOCAe0wggHpMBAGCSsGAQQBgjcVAQQDAgEAMB0GA1UdDgQWBBRI # bmTlUAXTgqoXNzcitW2oynUClTAZBgkrBgEEAYI3FAIEDB4KAFMAdQBiAEMAQTAL # BgNVHQ8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAWgBRyLToCMZBD # uRQFTuHqp8cx0SOJNDBaBgNVHR8EUzBRME+gTaBLhklodHRwOi8vY3JsLm1pY3Jv # c29mdC5jb20vcGtpL2NybC9wcm9kdWN0cy9NaWNSb29DZXJBdXQyMDExXzIwMTFf # MDNfMjIuY3JsMF4GCCsGAQUFBwEBBFIwUDBOBggrBgEFBQcwAoZCaHR0cDovL3d3 # dy5taWNyb3NvZnQuY29tL3BraS9jZXJ0cy9NaWNSb29DZXJBdXQyMDExXzIwMTFf # MDNfMjIuY3J0MIGfBgNVHSAEgZcwgZQwgZEGCSsGAQQBgjcuAzCBgzA/BggrBgEF # BQcCARYzaHR0cDovL3d3dy5taWNyb3NvZnQuY29tL3BraW9wcy9kb2NzL3ByaW1h # cnljcHMuaHRtMEAGCCsGAQUFBwICMDQeMiAdAEwAZQBnAGEAbABfAHAAbwBsAGkA # YwB5AF8AcwB0AGEAdABlAG0AZQBuAHQALiAdMA0GCSqGSIb3DQEBCwUAA4ICAQBn # 8oalmOBUeRou09h0ZyKbC5YR4WOSmUKWfdJ5DJDBZV8uLD74w3LRbYP+vj/oCso7 # v0epo/Np22O/IjWll11lhJB9i0ZQVdgMknzSGksc8zxCi1LQsP1r4z4HLimb5j0b # pdS1HXeUOeLpZMlEPXh6I/MTfaaQdION9MsmAkYqwooQu6SpBQyb7Wj6aC6VoCo/ # KmtYSWMfCWluWpiW5IP0wI/zRive/DvQvTXvbiWu5a8n7dDd8w6vmSiXmE0OPQvy # CInWH8MyGOLwxS3OW560STkKxgrCxq2u5bLZ2xWIUUVYODJxJxp/sfQn+N4sOiBp # mLJZiWhub6e3dMNABQamASooPoI/E01mC8CzTfXhj38cbxV9Rad25UAqZaPDXVJi # hsMdYzaXht/a8/jyFqGaJ+HNpZfQ7l1jQeNbB5yHPgZ3BtEGsXUfFL5hYbXw3MYb # BL7fQccOKO7eZS/sl/ahXJbYANahRr1Z85elCUtIEJmAH9AAKcWxm6U/RXceNcbS # oqKfenoi+kiVH6v7RyOA9Z74v2u3S5fi63V4GuzqN5l5GEv/1rMjaHXmr/r8i+sL # gOppO6/8MO0ETI7f33VtY5E90Z1WTk+/gFcioXgRMiF670EKsT/7qMykXcGhiJtX # cVZOSEXAQsmbdlsKgEhr/Xmfwb1tbWrJUnMTDXpQzTGCGYIwghl+AgEBMIGVMH4x # CzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRt # b25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xKDAmBgNVBAMTH01p # Y3Jvc29mdCBDb2RlIFNpZ25pbmcgUENBIDIwMTECEzMAAALN82S/+NRMXVEAAAAA # As0wDQYJYIZIAWUDBAIBBQCgga4wGQYJKoZIhvcNAQkDMQwGCisGAQQBgjcCAQQw # HAYKKwYBBAGCNwIBCzEOMAwGCisGAQQBgjcCARUwLwYJKoZIhvcNAQkEMSIEIPsm # TvBQIpMp9Rnxs2FziGgKmVrx2UOxnlb0HtEnng5qMEIGCisGAQQBgjcCAQwxNDAy # oBSAEgBNAGkAYwByAG8AcwBvAGYAdKEagBhodHRwOi8vd3d3Lm1pY3Jvc29mdC5j # b20wDQYJKoZIhvcNAQEBBQAEggEA04FRCnnFv+1SN93t+Ax6Zu2cw5XF8DPlj7xD # HSAf70OSsaYhQfLoXwz6FZBRu8Dp7mz6780rk/nCr8hLFhAd0/TvUZrESi76enQC # 0wLA98kCL/xUUQZfDIadO91G5UQ8S2bHdElKeGs+efvhiwp+sBLmsOArrDBlMRZH # scWCKR2xMUMijC4QD9z5340/3aBXfvlDmsQmBFFjhOQUvnnzJ8DJxHiVDj9z/I6r # Nk6XMB8UoiNLMS1Uqxv03RSEgGORQM8RQHCbj0TtRk2U8K5Rx6eIVDQv8jc+bpda # 4sYAkT0njc/hfrbe89r+iz+svYcws0QtownqV+Z14n5UJavM8aGCFwwwghcIBgor # BgEEAYI3AwMBMYIW+DCCFvQGCSqGSIb3DQEHAqCCFuUwghbhAgEDMQ8wDQYJYIZI # AWUDBAIBBQAwggFVBgsqhkiG9w0BCRABBKCCAUQEggFAMIIBPAIBAQYKKwYBBAGE # WQoDATAxMA0GCWCGSAFlAwQCAQUABCC1D+huyee6RybXYTrB8aqvJHYZ6BG9uxzX # cdPCdcPdIQIGY8cWSUaPGBMyMDIzMDIwNTE1MTUyMy41MTNaMASAAgH0oIHUpIHR # MIHOMQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMH # UmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSkwJwYDVQQL # EyBNaWNyb3NvZnQgT3BlcmF0aW9ucyBQdWVydG8gUmljbzEmMCQGA1UECxMdVGhh # bGVzIFRTUyBFU046NjBCQy1FMzgzLTI2MzUxJTAjBgNVBAMTHE1pY3Jvc29mdCBU # aW1lLVN0YW1wIFNlcnZpY2WgghFfMIIHEDCCBPigAwIBAgITMwAAAaZZRYM5TZ7r # SwABAAABpjANBgkqhkiG9w0BAQsFADB8MQswCQYDVQQGEwJVUzETMBEGA1UECBMK # V2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0 # IENvcnBvcmF0aW9uMSYwJAYDVQQDEx1NaWNyb3NvZnQgVGltZS1TdGFtcCBQQ0Eg # MjAxMDAeFw0yMjAzMDIxODUxMjFaFw0yMzA1MTExODUxMjFaMIHOMQswCQYDVQQG # EwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwG # A1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSkwJwYDVQQLEyBNaWNyb3NvZnQg # T3BlcmF0aW9ucyBQdWVydG8gUmljbzEmMCQGA1UECxMdVGhhbGVzIFRTUyBFU046 # NjBCQy1FMzgzLTI2MzUxJTAjBgNVBAMTHE1pY3Jvc29mdCBUaW1lLVN0YW1wIFNl # cnZpY2UwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDZmL97UiPnyfzU # CZ48+ybwp3Pl5tKyqHvWCg+DLzGArpe3oHa0/87+bxW0IIzUO+Ou9nzcHms7ZEeu # VfMtvbuTy9rH9NafrnIXtGbuLUooPhrEOmUJfbYz0QGP9yEwRw3iGMr6vFp3vfuz # aDy4cQ0junbV+2ArkOM3Ez90hOjLweG+TYoIXbb6GVWmJNZV6Y1E33ZiqF9QAatb # CW1C0p0otEHeL75d5mfY8cL/XUf55WT+tpa2WGauyz7Rw+gZZnJQeT0/PQ50ptbI # 2mZxR6yszrJquRpZi+UhboAgmTqCs9d9xSXkGhTHFwWUgkIzQAVgWxyEQhNcrBxx # vNw3aJ0ZpwvBDpWHkcE1s/0As+qtK4jiG2MgvwNgYFBKbvf/RMpq07MjK9v80vBn # RMm0OVu39Fq3K5igf2OtvoOk5nzkvDbVPi9YxqCjRukOUZXycGbvCf0PXZeDschy # rsu/PsJuh7Be7gIs6bFoet1FGqCvzhkIgRtzSfpHn+XlqZ72uGSX4QJ6mEwGQ9bh # 4H/FX0I55dAQdmF8yvVmk6nXvHfvKgsVSq+YSWL2zvl9/tpOTwoq1Cv0m6K3l/sV # IVWkBIVQ2KpWrcj7bSO2diK5ITM8Bb3PqdEHsjIjZqNnAWXo8fInAznFIncMpg1G # KhjxOzAPL7Slt33nkkmCbAhJLlDv7wIDAQABo4IBNjCCATIwHQYDVR0OBBYEFDpU # ITv8xpaivfVJDS/xrvwK8jfYMB8GA1UdIwQYMBaAFJ+nFV0AXmJdg/Tl0mWnG1M1 # GelyMF8GA1UdHwRYMFYwVKBSoFCGTmh0dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9w # a2lvcHMvY3JsL01pY3Jvc29mdCUyMFRpbWUtU3RhbXAlMjBQQ0ElMjAyMDEwKDEp # LmNybDBsBggrBgEFBQcBAQRgMF4wXAYIKwYBBQUHMAKGUGh0dHA6Ly93d3cubWlj # cm9zb2Z0LmNvbS9wa2lvcHMvY2VydHMvTWljcm9zb2Z0JTIwVGltZS1TdGFtcCUy # MFBDQSUyMDIwMTAoMSkuY3J0MAwGA1UdEwEB/wQCMAAwEwYDVR0lBAwwCgYIKwYB # BQUHAwgwDQYJKoZIhvcNAQELBQADggIBAIDA8Vg06Rqi5xaD4Zv4g38BxhfMa9jW # 6yZfHoBINk4UybE39MARPmULJ2H60ZlwW3urAly1Te9Kj7iPjhGzeTDmouwbntf+ # I+VU5Fqrh+RmXlWrdjfnQ+5UlFqdHVPI/rgYQS+RhUpqA1VZvs1thkdo7jyNb9ue # ACU29peOfGp5ZCYxr5mJ9gbUUtd4f8A0e4a0GiOwYHch1gFefhxI+VIayK677cCY # or0mlBAN6iumSv62SEL/7jkQ5DjcPtqRxyBNUl5v1iJYa1UthyKIH69yY6r2YqJ+ # iyUg++NY/MVQy4gpcAG7KR6FRY8bcQXDI6j8emlgiUvL40qE54ZFeDzueZqrDO0P # F0ERkIQO8OMzUDibvZA+MRXWKT1Jizf3WiHBBJaHwYxs/rBHdQeMqqiJN7thuFco # E1xZrYS/HIUqO6/hiL06lioUgP7Gp0uDd4woAgntxU0ibKeIOZ8Gry71gLc3DiL0 # kaKxpgHjdJtsIMwSveU/6oKxhg10qLNSTQ1kVQZz9KrMNUKKuRtA/Icb0D7N1+Ny # gb9RiZdMKOa3AvvTjFsSZQet4LU6ELANQhK2KGCzGbVMyS++I8GZP4K6RxEISIQd # 7J3gvMMxiibn7e2Dvx1gqbsHQoSI8p05wYfshRjHYN8EayGznMP4ipl2aKTE0DDn # JiHiMCQHswOwMIIHcTCCBVmgAwIBAgITMwAAABXF52ueAptJmQAAAAAAFTANBgkq # hkiG9w0BAQsFADCBiDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24x # EDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlv # bjEyMDAGA1UEAxMpTWljcm9zb2Z0IFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5 # IDIwMTAwHhcNMjEwOTMwMTgyMjI1WhcNMzAwOTMwMTgzMjI1WjB8MQswCQYDVQQG # EwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwG # A1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSYwJAYDVQQDEx1NaWNyb3NvZnQg # VGltZS1TdGFtcCBQQ0EgMjAxMDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoC # ggIBAOThpkzntHIhC3miy9ckeb0O1YLT/e6cBwfSqWxOdcjKNVf2AX9sSuDivbk+ # F2Az/1xPx2b3lVNxWuJ+Slr+uDZnhUYjDLWNE893MsAQGOhgfWpSg0S3po5GawcU # 88V29YZQ3MFEyHFcUTE3oAo4bo3t1w/YJlN8OWECesSq/XJprx2rrPY2vjUmZNqY # O7oaezOtgFt+jBAcnVL+tuhiJdxqD89d9P6OU8/W7IVWTe/dvI2k45GPsjksUZzp # cGkNyjYtcI4xyDUoveO0hyTD4MmPfrVUj9z6BVWYbWg7mka97aSueik3rMvrg0Xn # Rm7KMtXAhjBcTyziYrLNueKNiOSWrAFKu75xqRdbZ2De+JKRHh09/SDPc31BmkZ1 # zcRfNN0Sidb9pSB9fvzZnkXftnIv231fgLrbqn427DZM9ituqBJR6L8FA6PRc6ZN # N3SUHDSCD/AQ8rdHGO2n6Jl8P0zbr17C89XYcz1DTsEzOUyOArxCaC4Q6oRRRuLR # vWoYWmEBc8pnol7XKHYC4jMYctenIPDC+hIK12NvDMk2ZItboKaDIV1fMHSRlJTY # uVD5C4lh8zYGNRiER9vcG9H9stQcxWv2XFJRXRLbJbqvUAV6bMURHXLvjflSxIUX # k8A8FdsaN8cIFRg/eKtFtvUeh17aj54WcmnGrnu3tz5q4i6tAgMBAAGjggHdMIIB # 2TASBgkrBgEEAYI3FQEEBQIDAQABMCMGCSsGAQQBgjcVAgQWBBQqp1L+ZMSavoKR # PEY1Kc8Q/y8E7jAdBgNVHQ4EFgQUn6cVXQBeYl2D9OXSZacbUzUZ6XIwXAYDVR0g # BFUwUzBRBgwrBgEEAYI3TIN9AQEwQTA/BggrBgEFBQcCARYzaHR0cDovL3d3dy5t # aWNyb3NvZnQuY29tL3BraW9wcy9Eb2NzL1JlcG9zaXRvcnkuaHRtMBMGA1UdJQQM # MAoGCCsGAQUFBwMIMBkGCSsGAQQBgjcUAgQMHgoAUwB1AGIAQwBBMAsGA1UdDwQE # AwIBhjAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFNX2VsuP6KJcYmjRPZSQ # W9fOmhjEMFYGA1UdHwRPME0wS6BJoEeGRWh0dHA6Ly9jcmwubWljcm9zb2Z0LmNv # bS9wa2kvY3JsL3Byb2R1Y3RzL01pY1Jvb0NlckF1dF8yMDEwLTA2LTIzLmNybDBa # BggrBgEFBQcBAQROMEwwSgYIKwYBBQUHMAKGPmh0dHA6Ly93d3cubWljcm9zb2Z0 # LmNvbS9wa2kvY2VydHMvTWljUm9vQ2VyQXV0XzIwMTAtMDYtMjMuY3J0MA0GCSqG # SIb3DQEBCwUAA4ICAQCdVX38Kq3hLB9nATEkW+Geckv8qW/qXBS2Pk5HZHixBpOX # PTEztTnXwnE2P9pkbHzQdTltuw8x5MKP+2zRoZQYIu7pZmc6U03dmLq2HnjYNi6c # qYJWAAOwBb6J6Gngugnue99qb74py27YP0h1AdkY3m2CDPVtI1TkeFN1JFe53Z/z # jj3G82jfZfakVqr3lbYoVSfQJL1AoL8ZthISEV09J+BAljis9/kpicO8F7BUhUKz # /AyeixmJ5/ALaoHCgRlCGVJ1ijbCHcNhcy4sa3tuPywJeBTpkbKpW99Jo3QMvOyR # gNI95ko+ZjtPu4b6MhrZlvSP9pEB9s7GdP32THJvEKt1MMU0sHrYUP4KWN1APMdU # bZ1jdEgssU5HLcEUBHG/ZPkkvnNtyo4JvbMBV0lUZNlz138eW0QBjloZkWsNn6Qo # 3GcZKCS6OEuabvshVGtqRRFHqfG3rsjoiV5PndLQTHa1V1QJsWkBRH58oWFsc/4K # u+xBZj1p/cvBQUl+fpO+y/g75LcVv7TOPqUxUYS8vwLBgqJ7Fx0ViY1w/ue10Cga # iQuPNtq6TPmb/wrpNPgkNWcr4A245oyZ1uEi6vAnQj0llOZ0dFtq0Z4+7X6gMTN9 # vMvpe784cETRkPHIqzqKOghif9lwY1NNje6CbaUFEMFxBmoQtB1VM1izoXBm8qGC # AtIwggI7AgEBMIH8oYHUpIHRMIHOMQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2Fz # aGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENv # cnBvcmF0aW9uMSkwJwYDVQQLEyBNaWNyb3NvZnQgT3BlcmF0aW9ucyBQdWVydG8g # UmljbzEmMCQGA1UECxMdVGhhbGVzIFRTUyBFU046NjBCQy1FMzgzLTI2MzUxJTAj # BgNVBAMTHE1pY3Jvc29mdCBUaW1lLVN0YW1wIFNlcnZpY2WiIwoBATAHBgUrDgMC # GgMVAGp0M62VvUwfd1Xuz2uFD2qNn3ytoIGDMIGApH4wfDELMAkGA1UEBhMCVVMx # EzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoT # FU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEmMCQGA1UEAxMdTWljcm9zb2Z0IFRpbWUt # U3RhbXAgUENBIDIwMTAwDQYJKoZIhvcNAQEFBQACBQDnifgFMCIYDzIwMjMwMjA1 # MTM0MDIxWhgPMjAyMzAyMDYxMzQwMjFaMHcwPQYKKwYBBAGEWQoEATEvMC0wCgIF # AOeJ+AUCAQAwCgIBAAICIToCAf8wBwIBAAICEO4wCgIFAOeLSYUCAQAwNgYKKwYB # BAGEWQoEAjEoMCYwDAYKKwYBBAGEWQoDAqAKMAgCAQACAwehIKEKMAgCAQACAwGG # oDANBgkqhkiG9w0BAQUFAAOBgQBlDDDUcRm/BulBlXZ5s2ndCoaHEoGEc6H+f+WB # vkoidEplB2QrSgxND6zDOnE0HxB888BKZBKTXVdb/6v0prgtnkqaIfNsYPPwQJ/K # VD9dnx36fAQ9T8wnUiUXLsFd1BkvTvNdZZSmEFBacoapjwakWh1k883tRqILzDTn # YfD76DGCBA0wggQJAgEBMIGTMHwxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNo # aW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29y # cG9yYXRpb24xJjAkBgNVBAMTHU1pY3Jvc29mdCBUaW1lLVN0YW1wIFBDQSAyMDEw # AhMzAAABpllFgzlNnutLAAEAAAGmMA0GCWCGSAFlAwQCAQUAoIIBSjAaBgkqhkiG # 9w0BCQMxDQYLKoZIhvcNAQkQAQQwLwYJKoZIhvcNAQkEMSIEIG7dcd6kJzWWQtKV # UMnjONQnzwB+H6nvOOI5u1pvT+xsMIH6BgsqhkiG9w0BCRACLzGB6jCB5zCB5DCB # vQQggwsZi8M/dH1r4TCmyUwEGirdw6F3ogIX6fEw/bYEqw0wgZgwgYCkfjB8MQsw # CQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9u # ZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSYwJAYDVQQDEx1NaWNy # b3NvZnQgVGltZS1TdGFtcCBQQ0EgMjAxMAITMwAAAaZZRYM5TZ7rSwABAAABpjAi # BCBP5ghrHW2Nk7k6RulF3Ryz9/jPfLn4nerb26Ih72bPPDANBgkqhkiG9w0BAQsF # AASCAgAir99tFA49Kt5jdCrI2IIw8uVMPQRux/TnW0ADJxn+62nI7QgKbL0CKu/E # ei8Spw4By53Xe/jiYp6a5U+IUF3tXKBZaCxvSDaPHZx/RS6kEDyuSqsP6tdYUNPy # QYibCytaqgaA1gWzx7k6kzHlyFpeo57y2a99g3yp8t/rFXdi6AN/0NRV8nL6qVoR # bAisiaJektFyNgYU1M1w6AlUoPWrnu5WbkzNEtz0MzMaLJs5/qJjzkMJAfjVWO3q # YqIpQVCL0rzDHVy5PCBPNy69i7PEFLExtnyysRurzoakvh1T5ZIwzEbftsHGh/WC # bMNXKjc+Ez3pT0RWw/wp75A59x2uQeVgGyr46d5klBDW3qRPM7Ti39OTAOxXXQus # Wno5kz/YYSkKelZmC/ejIi32Qi1q6jd24Wta99ldP6yVLgWUOSOy4bqyfmnJIlP9 # oXwmCsubvlWdq6cqHnVB0a0wkdty9F2yDRuf27PfyfkeLJvZHqp+ChQIu3u5llyq # nMh4R5bqs4e+9pOM3NXetUWavNHdW3e8PL+eD0vkAf6QA8TNF4HwGLFk83CAQpKu # tp/gS7juScdagSdq/m0UhlyO2okQ9k8KLfCxw7Fyl3ui+vASkKucYE34m0EqJfcB # ms2cG4274gdRZFUUjHKpMrcMR9QsBJaWBr/BxypuesjbCyJ7Qw== # SIG # End signature block |