in internal/scanners/apim/rules.go [15:190]
func (a *APIManagementScanner) GetRecommendations() map[string]models.AzqrRecommendation {
return map[string]models.AzqrRecommendation{
"apim-001": {
RecommendationID: "apim-001",
ResourceType: "Microsoft.ApiManagement/service",
Category: models.CategoryMonitoringAndAlerting,
Recommendation: "APIM should have diagnostic settings enabled",
Impact: models.ImpactLow,
Eval: func(target interface{}, scanContext *models.ScanContext) (bool, string) {
service := target.(*armapimanagement.ServiceResource)
_, ok := scanContext.DiagnosticsSettings[strings.ToLower(*service.ID)]
return !ok, ""
},
LearnMoreUrl: "https://learn.microsoft.com/en-us/azure/api-management/api-management-howto-use-azure-monitor#resource-logs",
},
"apim-003": {
RecommendationID: "apim-003",
ResourceType: "Microsoft.ApiManagement/service",
Category: models.CategoryHighAvailability,
Recommendation: "APIM should have a SLA",
RecommendationType: models.TypeSLA,
Impact: models.ImpactHigh,
Eval: func(target interface{}, scanContext *models.ScanContext) (bool, string) {
a := target.(*armapimanagement.ServiceResource)
sku := string(*a.SKU.Name)
sla := "99.95%"
if strings.Contains(sku, "Premium") && (len(a.Zones) > 0 || len(a.Properties.AdditionalLocations) > 0) {
sla = "99.99%"
} else if strings.Contains(sku, "Developer") {
sla = "None"
}
return sla == "None", sla
},
LearnMoreUrl: "https://www.azure.cn/en-us/support/sla/api-management/",
},
"apim-004": {
RecommendationID: "apim-004",
ResourceType: "Microsoft.ApiManagement/service",
Category: models.CategorySecurity,
Recommendation: "APIM should have private endpoints enabled",
Impact: models.ImpactHigh,
Eval: func(target interface{}, scanContext *models.ScanContext) (bool, string) {
a := target.(*armapimanagement.ServiceResource)
pe := len(a.Properties.PrivateEndpointConnections) > 0
return !pe, ""
},
LearnMoreUrl: "https://learn.microsoft.com/en-us/azure/api-management/private-endpoint",
},
"apim-006": {
RecommendationID: "apim-006",
ResourceType: "Microsoft.ApiManagement/service",
Category: models.CategoryGovernance,
Recommendation: "APIM should comply with naming conventions",
Impact: models.ImpactLow,
Eval: func(target interface{}, scanContext *models.ScanContext) (bool, string) {
c := target.(*armapimanagement.ServiceResource)
caf := strings.HasPrefix(*c.Name, "apim")
return !caf, ""
},
LearnMoreUrl: "https://learn.microsoft.com/en-us/azure/cloud-adoption-framework/ready/azure-best-practices/resource-abbreviations",
},
"apim-007": {
RecommendationID: "apim-007",
ResourceType: "Microsoft.ApiManagement/service",
Category: models.CategoryGovernance,
Recommendation: "APIM should have tags",
Impact: models.ImpactLow,
Eval: func(target interface{}, scanContext *models.ScanContext) (bool, string) {
c := target.(*armapimanagement.ServiceResource)
return len(c.Tags) == 0, ""
},
LearnMoreUrl: "https://learn.microsoft.com/en-us/azure/azure-resource-manager/management/tag-resources?tabs=json",
},
"apim-008": {
RecommendationID: "apim-008",
ResourceType: "Microsoft.ApiManagement/service",
Category: models.CategorySecurity,
Recommendation: "APIM should use Managed Identities",
Impact: models.ImpactMedium,
Eval: func(target interface{}, scanContext *models.ScanContext) (bool, string) {
c := target.(*armapimanagement.ServiceResource)
return c.Identity == nil || c.Identity.Type == nil || *c.Identity.Type == armapimanagement.ApimIdentityTypeNone, ""
},
LearnMoreUrl: "https://learn.microsoft.com/en-us/azure/api-management/api-management-howto-use-managed-service-identity",
},
"apim-009": {
RecommendationID: "apim-009",
ResourceType: "Microsoft.ApiManagement/service",
Category: models.CategorySecurity,
Recommendation: "APIM should only accept a minimum of TLS 1.2",
Impact: models.ImpactHigh,
Eval: func(target interface{}, scanContext *models.ScanContext) (bool, string) {
notAllowed := []string{
"Microsoft.WindowsAzure.ApiManagement.Gateway.Security.Protocols.Tls10",
"Microsoft.WindowsAzure.ApiManagement.Gateway.Security.Protocols.Tls11",
"Microsoft.WindowsAzure.ApiManagement.Gateway.Security.Protocols.Ssl30",
"Microsoft.WindowsAzure.ApiManagement.Gateway.Security.Backend.Protocols.Tls10",
"Microsoft.WindowsAzure.ApiManagement.Gateway.Security.Backend.Protocols.Tls11",
"Microsoft.WindowsAzure.ApiManagement.Gateway.Security.Backend.Protocols.Ssl30",
}
c := target.(*armapimanagement.ServiceResource)
if c.Properties.CustomProperties != nil {
for _, v := range notAllowed {
broken := c.Properties.CustomProperties[v] == nil || strings.ToLower(*c.Properties.CustomProperties[v]) == "true"
if broken {
return broken, ""
}
}
} else {
return true, ""
}
return false, ""
},
LearnMoreUrl: "https://learn.microsoft.com/en-us/azure/api-management/api-management-howto-manage-protocols-ciphers",
},
"apim-010": {
RecommendationID: "apim-010",
ResourceType: "Microsoft.ApiManagement/service",
Category: models.CategorySecurity,
Recommendation: "APIM should should not accept weak or deprecated ciphers.",
Impact: models.ImpactHigh,
Eval: func(target interface{}, scanContext *models.ScanContext) (bool, string) {
notAllowed := []string{
"Microsoft.WindowsAzure.ApiManagement.Gateway.Security.Ciphers.TripleDes168",
"Microsoft.WindowsAzure.ApiManagement.Gateway.Security.Ciphers.TLS_RSA_WITH_AES_128_CBC_SHA",
"Microsoft.WindowsAzure.ApiManagement.Gateway.Security.Ciphers.TLS_RSA_WITH_AES_256_CBC_SHA",
"Microsoft.WindowsAzure.ApiManagement.Gateway.Security.Ciphers.TLS_RSA_WITH_AES_128_CBC_SHA256",
"Microsoft.WindowsAzure.ApiManagement.Gateway.Security.Ciphers.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA",
"Microsoft.WindowsAzure.ApiManagement.Gateway.Security.Ciphers.TLS_RSA_WITH_AES_256_CBC_SHA256",
"Microsoft.WindowsAzure.ApiManagement.Gateway.Security.Ciphers.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA",
"Microsoft.WindowsAzure.ApiManagement.Gateway.Security.Ciphers.TLS_RSA_WITH_AES_128_GCM_SHA256",
}
c := target.(*armapimanagement.ServiceResource)
if c.Properties.CustomProperties != nil {
for _, v := range notAllowed {
broken := c.Properties.CustomProperties[v] == nil || strings.ToLower(*c.Properties.CustomProperties[v]) == "true"
if broken {
return broken, ""
}
}
} else {
return true, ""
}
return false, ""
},
LearnMoreUrl: "https://learn.microsoft.com/en-us/azure/api-management/api-management-howto-manage-protocols-ciphers",
},
"apim-011": {
RecommendationID: "apim-011",
ResourceType: "Microsoft.ApiManagement/service",
Category: models.CategorySecurity,
Recommendation: "APIM: Renew expiring certificates",
Impact: models.ImpactHigh,
Eval: func(target interface{}, scanContext *models.ScanContext) (bool, string) {
c := target.(*armapimanagement.ServiceResource)
if c.Properties.HostnameConfigurations != nil {
for _, v := range c.Properties.HostnameConfigurations {
if v.Certificate != nil && v.Certificate.Expiry != nil {
days := time.Until(*v.Certificate.Expiry).Hours() / 24
if days <= 30 {
return true, ""
}
}
}
}
return false, ""
},
LearnMoreUrl: "https://learn.microsoft.com/en-us/azure/api-management/configure-custom-domain?tabs=custom",
},
}
}