Skip to content

Commit

Permalink
category constants and resiliency library rules
Browse files Browse the repository at this point in the history
  • Loading branch information
cmendible committed May 17, 2023
1 parent 93c32c7 commit 49b6ba2
Show file tree
Hide file tree
Showing 28 changed files with 979 additions and 812 deletions.
24 changes: 17 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,27 @@

[![Open in vscode.dev](https://img.shields.io/badge/Open%20in-vscode.dev-blue)](https://vscode.dev/github/Azure/azqr)

Azure Quick Review (azqr) goal is to produce a high level assessment of an Azure Subscription or Resource Group providing the following information for each Azure Service:
Azure Quick Review (azqr) is a CLI tool used to identify Azure resources that may be or not compliant with Azure best practices and recommendations.

* SLA: current expected SLA
* Availability Zones: checks if the service is protected against Zone failures.
* Private Endpoints: checks if the service uses Private Endpoints.
* Diagnostic Settings: checks if there are Diagnostic Settings configured for the service.
* CAF Naming convention: checks if the service follows [CAF Naming convention](https://learn.microsoft.com/en-us/azure/cloud-adoption-framework/ready/azure-best-practices/resource-abbreviations).
Azure Quick Review (azqr) outputs includes an overview section with the following information:

* Subscription Id
* Resoource Group name
* Location
* Resource Type
* Resource Name
* SKU
* SLA: SLA for the service, given the current configuration.
* AZ: True if the service is Availability Zone aware.
* PVT: True if the service has a private IP address.
* DS: True if the service has diagnotics settings enabled.
* CAF: True if the service is compliant with the [Cloud Adoption Framework](https://docs.microsoft.com/en-us/azure/cloud-adoption-framework/) naming covention.

Check the [Scan Results](#scan-results) documentation for more information on Azure Quick Review (azqr) outputs.

## Azure Quick Review Rules

Azure Quick Review (azqr) uses a set of rules to determine the status of each Azure Service. These rules are listed in the [rules](docs/rules/README.md) documentation.
Azure Quick Review (azqr) recommendations are based on a set of rules. To learn more check the [rules](docs/rules/README.md) documentation.

## Supported Azure Services

Expand Down
26 changes: 21 additions & 5 deletions cmd/azqr/rules.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ package azqr

import (
"fmt"
"sort"

"github.com/cmendible/azqr/internal/scanners"
"github.com/cmendible/azqr/internal/scanners/afd"
Expand Down Expand Up @@ -69,13 +70,28 @@ var rulesCmd = &cobra.Command{
&mysql.MySQLFlexibleScanner{},
}

fmt.Println("Id | Category | Subcategory | Name | Severity | More Info")
fmt.Println("---|---|---|---|---|---")
fmt.Println("# | Id | Category | Subcategory | Name | Severity | More Info")
fmt.Println("---|---|---|---|---|---|---")

i := 0
for _, scanner := range serviceScanners {
rules := scanner.GetRules()
for _, rule := range rules {
fmt.Printf("%s | %s | %s | %s | %s | %s", rule.Id, rule.Category, rule.Subcategory, rule.Description, rule.Severity, rule.Url)
rulesMap := scanner.GetRules()

rules := map[string]scanners.AzureRule{}
for _, r := range rulesMap {
rules[r.Id] = r
}

keys := make([]string, 0, len(rules))
for k := range rules {
keys = append(keys, k)
}
sort.Strings(keys)

for _, k := range keys {
rule := rules[k]
i++
fmt.Printf("%s | %s | %s | %s | %s | %s | %s", fmt.Sprint(i), rule.Id, rule.Category, rule.Subcategory, rule.Description, rule.Severity, rule.Url)
fmt.Println()
}
}
Expand Down
367 changes: 186 additions & 181 deletions docs/rules/README.md

Large diffs are not rendered by default.

53 changes: 36 additions & 17 deletions docs/scan_results/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@ Azure Quick Review (azqr) creates an excel spreadsheet with the following sectio

* [Overview](#overview)
* [Recommendations](#recommendations)
* [Defender](#defender)
* [Services](#services)
* [Defender](#defender)
* [Advisor](#advisor)
* [Costs](#costs) (Disabled by default)

## Overview

Expand All @@ -17,11 +19,11 @@ The overview section contains the following information:
* Resource Type
* Resource Name
* SKU
* SLA: SLA for the instance given the current configuration.
* AZ: True if the instance is Availability Zone aware.
* PVT: True if the instance has a private IP address.
* DS: True if the instance has diagnotic settings enabled.
* CAF: True if the instance is compliant with the [Cloud Adoption Framework](https://docs.microsoft.com/en-us/azure/cloud-adoption-framework/) naming covention.
* SLA: SLA for the service given the current configuration.
* AZ: True if the service is Availability Zone aware.
* PVT: True if the service has a private IP address.
* DS: True if the service has diagnotic settings enabled.
* CAF: True if the service is compliant with the [Cloud Adoption Framework](https://docs.microsoft.com/en-us/azure/cloud-adoption-framework/) naming covention.

![overview](img/overview.png)

Expand All @@ -38,16 +40,6 @@ The recommendations section contains a summary of the recommendations for the sc

![recommendations](img/recommendations.png)

## Defender

The defender section contains the following information:

* Name: Microsoft Defender for Cloud plan name.
* Tier
* Deprecated: True if the plan is deprecated.

![defender](img/defender.png)

## Services

The services section contains the following information:
Expand All @@ -65,4 +57,31 @@ The services section contains the following information:
* Broken: True if the rule is broken
* Learn: Link to relevant documentation

![services](img/services.png)
![services](img/services.png)

## Defender

The defender section contains the following information:

* Name: Microsoft Defender for Cloud plan name.
* Tier
* Deprecated: True if the plan is deprecated.

![defender](img/defender.png)

## Advisor

This section shows the Azure Advisor Recommendations with the following information:

* Subscription Id
* Name
* Type
* Category
* Description
* PotentialBenefits
* Risk
* LearnMoreLink

## Costs

Shows the Azure Costs for the period between the 1st day of the previous month and the day Azure Quick Review (azqr) is used to scan the services.
30 changes: 15 additions & 15 deletions internal/scanners/afd/rules.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,10 @@ func (a *FrontDoorScanner) GetRules() map[string]scanners.AzureRule {
return map[string]scanners.AzureRule{
"DiagnosticSettings": {
Id: "afd-001",
Category: "Monitoring and Logging",
Subcategory: "Diagnostic Logs",
Category: scanners.RulesCategoryReliability,
Subcategory: scanners.RulesSubcategoryReliabilityDiagnosticLogs,
Description: "Azure FrontDoor should have diagnostic settings enabled",
Severity: "Medium",
Severity: scanners.SeverityMedium,
Eval: func(target interface{}, scanContext *scanners.ScanContext) (bool, string) {
service := target.(*armcdn.Profile)
hasDiagnostics, err := a.diagnosticsSettings.HasDiagnostics(*service.ID)
Expand All @@ -33,21 +33,21 @@ func (a *FrontDoorScanner) GetRules() map[string]scanners.AzureRule {
},
"SLA": {
Id: "afd-003",
Category: "High Availability and Resiliency",
Subcategory: "SLA",
Category: scanners.RulesCategoryReliability,
Subcategory: scanners.RulesSubcategoryReliabilitySLA,
Description: "Azure FrontDoor SLA",
Severity: "High",
Severity: scanners.SeverityHigh,
Eval: func(target interface{}, scanContext *scanners.ScanContext) (bool, string) {
return false, "99.99%"
},
Url: "https://www.azure.cn/en-us/support/sla/cdn/",
},
"SKU": {
Id: "afd-005",
Category: "High Availability and Resiliency",
Subcategory: "SKU",
Category: scanners.RulesCategoryReliability,
Subcategory: scanners.RulesSubcategoryReliabilitySKU,
Description: "Azure FrontDoor SKU",
Severity: "High",
Severity: scanners.SeverityHigh,
Eval: func(target interface{}, scanContext *scanners.ScanContext) (bool, string) {
c := target.(*armcdn.Profile)
return false, string(*c.SKU.Name)
Expand All @@ -56,10 +56,10 @@ func (a *FrontDoorScanner) GetRules() map[string]scanners.AzureRule {
},
"CAF": {
Id: "afd-006",
Category: "Governance",
Subcategory: "Naming Convention",
Category: scanners.RulesCategoryOperationalExcellence,
Subcategory: scanners.RulesSubcategoryOperationalExcellenceCAF,
Description: "Azure FrontDoor Name should comply with naming conventions",
Severity: "Low",
Severity: scanners.SeverityLow,
Eval: func(target interface{}, scanContext *scanners.ScanContext) (bool, string) {
c := target.(*armcdn.Profile)
caf := strings.HasPrefix(*c.Name, "afd")
Expand All @@ -69,10 +69,10 @@ func (a *FrontDoorScanner) GetRules() map[string]scanners.AzureRule {
},
"afd-007": {
Id: "afd-007",
Category: "Governance",
Subcategory: "Use tags to organize your resources",
Category: scanners.RulesCategoryOperationalExcellence,
Subcategory: scanners.RulesSubcategoryOperationalExcellenceTags,
Description: "Azure FrontDoor should have tags",
Severity: "Low",
Severity: scanners.SeverityLow,
Eval: func(target interface{}, scanContext *scanners.ScanContext) (bool, string) {
c := target.(*armcdn.Profile)
return c.Tags == nil || len(c.Tags) == 0, ""
Expand Down
36 changes: 18 additions & 18 deletions internal/scanners/afw/rules.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,10 @@ func (a *FirewallScanner) GetRules() map[string]scanners.AzureRule {
return map[string]scanners.AzureRule{
"DiagnosticSettings": {
Id: "afw-001",
Category: "Monitoring and Logging",
Subcategory: "Diagnostic Logs",
Category: scanners.RulesCategoryReliability,
Subcategory: scanners.RulesSubcategoryReliabilityDiagnosticLogs,
Description: "Azure Firewall should have diagnostic settings enabled",
Severity: "Medium",
Severity: scanners.SeverityMedium,
Eval: func(target interface{}, scanContext *scanners.ScanContext) (bool, string) {
service := target.(*armnetwork.AzureFirewall)
hasDiagnostics, err := a.diagnosticsSettings.HasDiagnostics(*service.ID)
Expand All @@ -32,10 +32,10 @@ func (a *FirewallScanner) GetRules() map[string]scanners.AzureRule {
},
"AvailabilityZones": {
Id: "afw-002",
Category: "High Availability and Resiliency",
Subcategory: "Availability Zones",
Category: scanners.RulesCategoryReliability,
Subcategory: scanners.RulesSubcategoryReliabilityAvailabilityZones,
Description: "Azure Firewall should have availability zones enabled",
Severity: "High",
Severity: scanners.SeverityHigh,
Eval: func(target interface{}, scanContext *scanners.ScanContext) (bool, string) {
g := target.(*armnetwork.AzureFirewall)
zones := len(g.Zones) > 1
Expand All @@ -45,10 +45,10 @@ func (a *FirewallScanner) GetRules() map[string]scanners.AzureRule {
},
"SLA": {
Id: "afw-003",
Category: "High Availability and Resiliency",
Subcategory: "SLA",
Category: scanners.RulesCategoryReliability,
Subcategory: scanners.RulesSubcategoryReliabilitySLA,
Description: "Azure Firewall SLA",
Severity: "High",
Severity: scanners.SeverityHigh,
Eval: func(target interface{}, scanContext *scanners.ScanContext) (bool, string) {
g := target.(*armnetwork.AzureFirewall)
sla := "99.95%"
Expand All @@ -62,10 +62,10 @@ func (a *FirewallScanner) GetRules() map[string]scanners.AzureRule {
},
"SKU": {
Id: "afw-005",
Category: "High Availability and Resiliency",
Subcategory: "SKU",
Category: scanners.RulesCategoryReliability,
Subcategory: scanners.RulesSubcategoryReliabilitySKU,
Description: "Azure Firewall SKU",
Severity: "High",
Severity: scanners.SeverityHigh,
Eval: func(target interface{}, scanContext *scanners.ScanContext) (bool, string) {
c := target.(*armnetwork.AzureFirewall)
return false, string(*c.Properties.SKU.Name)
Expand All @@ -74,10 +74,10 @@ func (a *FirewallScanner) GetRules() map[string]scanners.AzureRule {
},
"CAF": {
Id: "afw-006",
Category: "Governance",
Subcategory: "Naming Convention",
Category: scanners.RulesCategoryOperationalExcellence,
Subcategory: scanners.RulesSubcategoryOperationalExcellenceCAF,
Description: "Azure Firewall Name should comply with naming conventions",
Severity: "Low",
Severity: scanners.SeverityLow,
Eval: func(target interface{}, scanContext *scanners.ScanContext) (bool, string) {
c := target.(*armnetwork.AzureFirewall)
caf := strings.HasPrefix(*c.Name, "afw")
Expand All @@ -87,10 +87,10 @@ func (a *FirewallScanner) GetRules() map[string]scanners.AzureRule {
},
"afw-007": {
Id: "afw-007",
Category: "Governance",
Subcategory: "Use tags to organize your resources",
Category: scanners.RulesCategoryOperationalExcellence,
Subcategory: scanners.RulesSubcategoryOperationalExcellenceTags,
Description: "Azure Firewall should have tags",
Severity: "Low",
Severity: scanners.SeverityLow,
Eval: func(target interface{}, scanContext *scanners.ScanContext) (bool, string) {
c := target.(*armnetwork.AzureFirewall)
return c.Tags == nil || len(c.Tags) == 0, ""
Expand Down
Loading

0 comments on commit 49b6ba2

Please sign in to comment.