Skip to content

Commit

Permalink
feat: added Subscription Name and Recommendation Id to the results #239
Browse files Browse the repository at this point in the history
…. Added exclusions filter #238
  • Loading branch information
cmendible committed May 21, 2024
1 parent 9076e3d commit 966b15e
Show file tree
Hide file tree
Showing 58 changed files with 547 additions and 309 deletions.
32 changes: 31 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ The output generated by **Azure Quick Review (azqr)** is presented by default in

* **azqr-YYYY-MM-DD-HH-MM-SS.services.csv:** This file contains the details of the Azure services scanned by the tool, including:
* Subscription: The unique identifier for the Azure subscription under which the resource is deployed.
* Subscription Name: The name of the Azure subscription.
* Resource Group: The resource group where the resource is deployed.
* Location: The geographical region where the resource is deployed.
* Type: The specific type or category of the Azure resource.
Expand All @@ -27,13 +28,16 @@ The output generated by **Azure Quick Review (azqr)** is presented by default in
* Recommendation: The specific recommendation or best practice.
* Result: The result or value resulting from the evaluation of the recommendation (i.e. Service SLA or SKU).
* Learn: A link to additional information or documentation related to the recommendation.
* RId: The Recommendation Id.
* **azqr-YYYY-MM-DD-HH-MM-SS.defender.csv:**
* Subscription: The unique identifier for the Azure subscription under which the resource is deployed.
* Subscription Name: The name of the Azure subscription.
* Name: Microsoft Defender for Cloud plan name.
* Tier: The tier of the plan.
* Deprecated: a Boolean value indicating whether the plan is deprecated.
* **azqr-YYYY-MM-DD-HH-MM-SS.advisor.csv:**
* Subscription: The unique identifier for the Azure subscription under which the resource is deployed.
* Subscription Name: The name of the Azure subscription.
* Name: The name of the resource identified by Advisor.
* Type: The resource type of the resource identified by Advisor.
* Category: The category of the recommendation.
Expand All @@ -45,11 +49,12 @@ The output generated by **Azure Quick Review (azqr)** is presented by default in
* From: the start date of the cost analysis period.
* To: the end date of the cost analysis period.
* Subscription: The unique identifier for the Azure subscription under which the resource is deployed.
* Subscription Name: The name of the Azure subscription.
* ServiceName: The type of the Azure service for which the cost is calculated.
* Value: The cost value associated with the service.
* Currency: The currency in which the cost is calculated.

> By default, Azure Quick Review (azqr) masks the Subscription Ids in the spreadsheet, ensuring that they are not directly visible in the output. This helps protect sensitive information and maintain data privacy and security. To view the Subscription Ids, you can use the `--mask=false` flag when running the tool.
> By default, Azure Quick Review (azqr) masks the Subscription Ids, ensuring that they are not directly visible in the output. This helps protect sensitive information and maintain data privacy and security. To unmask the Subscription Ids, you can use the `--mask=false` flag when running the tool.
> Azure Quick Review can also generate an Excel file with the same information as the CSV files. To generate the Excel file, you can use the `--excel` (or `-x`) flag when running the tool.
Expand Down Expand Up @@ -183,6 +188,31 @@ For information on available commands and help run:
./azqr -h
```

### Excluding Recommendations and more

To prevent Azure Quick Review from scanning specific subscriptions, resource groups, services or recommendations, create a `yaml` file with the following format:

```yaml
azqr:
exclude:
subscriptions:
- <subscription_id> # format: <subscription_id>
resourceGroups:
- <resource_group_resource_id> # format: /subscriptions/<subscription_id>/resourceGroups/<resource_group_name>
services:
- <service_resource_id> # format: /subscriptions/<subscription_id>/resourceGroups/<resource_group_name>/providers/<service_provider>/<service_name>
recommendations:
- <recommendation_id> # format: <recommendation_id>
```

Then run the scan with the `--exclude` flag:

```bash
./azqr scan --exclude <path_to_yaml_file>
```

> Check the [rules](https://azure.github.io/azqr/docs/recommendations/) to get the recommendation ids.
## Troubleshooting

If you encounter any issue while using **Azure Quick Review (azqr)**, please set the `AZURE_SDK_GO_LOGGING` environment variable to `all`, run the tool with the `--debug` flag and then share the console output with us by filing a new [issue](https://github.com/Azure/azqr/issues).
Expand Down
6 changes: 3 additions & 3 deletions cmd/azqr/rules.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ var rulesCmd = &cobra.Command{
Run: func(cmd *cobra.Command, args []string) {
serviceScanners := internal.GetScanners()

fmt.Println("# | Category | Impact | Recommendation | More Info")
fmt.Println("---|---|---|---|---")
fmt.Println("# | Id | Category | Impact | Recommendation | More Info")
fmt.Println("---|---|---|---|---|---")

i := 0
for _, scanner := range serviceScanners {
Expand All @@ -45,7 +45,7 @@ var rulesCmd = &cobra.Command{
for _, k := range keys {
rule := rules[k]
i++
fmt.Printf("%s | %s | %s | %s | [Learn](%s)", fmt.Sprint(i), rule.Category, rule.Impact, rule.Recommendation, rule.Url)
fmt.Printf("%s | %s | %s | %s | %s | [Learn](%s)", fmt.Sprint(i), rule.Id, rule.Category, rule.Impact, rule.Recommendation, rule.Url)
fmt.Println()
}
}
Expand Down
3 changes: 3 additions & 0 deletions cmd/azqr/scan.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ func init() {
scanCmd.PersistentFlags().BoolP("mask", "m", true, "Mask the subscription id in the report")
scanCmd.PersistentFlags().BoolP("azure-cli-credential", "f", false, "Force the use of Azure CLI Credential")
scanCmd.PersistentFlags().BoolP("debug", "", false, "Set log level to debug")
scanCmd.PersistentFlags().StringP("exclusions", "e", "", "Exclusions file (YAML format)")

rootCmd.AddCommand(scanCmd)
}
Expand All @@ -47,6 +48,7 @@ func scan(cmd *cobra.Command, serviceScanners []scanners.IAzureScanner) {
mask, _ := cmd.Flags().GetBool("mask")
debug, _ := cmd.Flags().GetBool("debug")
forceAzureCliCredential, _ := cmd.Flags().GetBool("azure-cli-credential")
exclusionFile, _ := cmd.Flags().GetString("exclusions")

params := internal.ScanParams{
SubscriptionID: subscriptionID,
Expand All @@ -60,6 +62,7 @@ func scan(cmd *cobra.Command, serviceScanners []scanners.IAzureScanner) {
Debug: debug,
ServiceScanners: serviceScanners,
ForceAzureCliCredential: forceAzureCliCredential,
ExclusionsFile: exclusionFile,
}

internal.Scan(&params)
Expand Down
7 changes: 6 additions & 1 deletion docs/content/en/docs/Overview/_index.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ The output generated by **Azure Quick Review (azqr)** is presented by default in

* **azqr-YYYY-MM-DD-HH-MM-SS.services.csv:** This file contains the details of the Azure services scanned by the tool, including:
* Subscription: The unique identifier for the Azure subscription under which the resource is deployed.
* Subscription Name: The name of the Azure subscription.
* Resource Group: The resource group where the resource is deployed.
* Location: The geographical region where the resource is deployed.
* Type: The specific type or category of the Azure resource.
Expand All @@ -22,13 +23,16 @@ The output generated by **Azure Quick Review (azqr)** is presented by default in
* Recommendation: The specific recommendation or best practice.
* Result: The result or value resulting from the evaluation of the recommendation (i.e. Service SLA or SKU).
* Learn: A link to additional information or documentation related to the recommendation.
* RId: The Recommendation Id.
* **azqr-YYYY-MM-DD-HH-MM-SS.defender.csv:**
* Subscription: The unique identifier for the Azure subscription under which the resource is deployed.
* Subscription Name: The name of the Azure subscription.
* Name: Microsoft Defender for Cloud plan name.
* Tier: The tier of the plan.
* Deprecated: a Boolean value indicating whether the plan is deprecated.
* **azqr-YYYY-MM-DD-HH-MM-SS.advisor.csv:**
* Subscription: The unique identifier for the Azure subscription under which the resource is deployed.
* Subscription Name: The name of the Azure subscription.
* Name: The name of the resource identified by Advisor.
* Type: The resource type of the resource identified by Advisor.
* Category: The category of the recommendation.
Expand All @@ -40,11 +44,12 @@ The output generated by **Azure Quick Review (azqr)** is presented by default in
* From: the start date of the cost analysis period.
* To: the end date of the cost analysis period.
* Subscription: The unique identifier for the Azure subscription under which the resource is deployed.
* Subscription Name: The name of the Azure subscription.
* ServiceName: The type of the Azure service for which the cost is calculated.
* Value: The cost value associated with the service.
* Currency: The currency in which the cost is calculated.

> By default, Azure Quick Review (azqr) masks the Subscription Ids in the spreadsheet, ensuring that they are not directly visible in the output. This helps protect sensitive information and maintain data privacy and security. To view the Subscription Ids, you can use the `--mask=false` flag when running the tool.
> By default, Azure Quick Review (azqr) masks the Subscription Ids, ensuring that they are not directly visible in the output. This helps protect sensitive information and maintain data privacy and security. To unmask the Subscription Ids, you can use the `--mask=false` flag when running the tool.
> Azure Quick Review can also generate an Excel file with the same information as the CSV files. To generate the Excel file, you can use the `--excel` (or `-x`) flag when running the tool.
Expand Down
27 changes: 26 additions & 1 deletion docs/content/en/docs/Usage/_index.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,4 +44,29 @@ For information on available commands and help run:

```bash
./azqr -h
```
```

## Excluding Recommendations and more

To prevent Azure Quick Review from scanning specific subscriptions, resource groups, services or recommendations, create a `yaml` file with the following format:

```yaml
azqr:
exclude:
subscriptions:
- <subscription_id> # format: <subscription_id>
resourceGroups:
- <resource_group_resource_id> # format: /subscriptions/<subscription_id>/resourceGroups/<resource_group_name>
services:
- <service_resource_id> # format: /subscriptions/<subscription_id>/resourceGroups/<resource_group_name>/providers/<service_provider>/<service_name>
recommendations:
- <recommendation_id> # format: <recommendation_id>
```

Then run the scan with the `--exclude` flag:

```bash
./azqr scan --exclude <path_to_yaml_file>
```

> Check the [rules](https://azure.github.io/azqr/docs/recommendations/) to get the recommendation ids.
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ require (
github.com/rs/zerolog v1.32.0
github.com/spf13/cobra v1.8.0
github.com/xuri/excelize/v2 v2.8.1
gopkg.in/yaml.v3 v3.0.1
)

require (
Expand Down
1 change: 1 addition & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,7 @@ golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o=
golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
Expand Down
Binary file modified internal/embeded/azqr.pbit
Binary file not shown.
3 changes: 2 additions & 1 deletion internal/renderers/excel/recommendations.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ func renderRecommendations(f *excelize.File, data *renderers.ReportData) {

renderedRules := map[string]bool{}

headers := []string{"Category", "Impact", "Recommendation", "Learn"}
headers := []string{"Category", "Impact", "Recommendation", "Learn", "RId"}
rows := [][]string{}
for _, result := range data.MainData {
for _, rr := range result.Rules {
Expand All @@ -31,6 +31,7 @@ func renderRecommendations(f *excelize.File, data *renderers.ReportData) {
"Impact": string(rr.Impact),
"Recommendation": rr.Recommendation,
"Learn": rr.Learn,
"RId": rr.Id,
}
renderedRules[rr.Id] = true
rows = append(rows, mapToRow(headers, rulesToRender)...)
Expand Down
13 changes: 9 additions & 4 deletions internal/renderers/report_data.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,15 @@ type ReportData struct {
}

func (rd *ReportData) ServicesTable() [][]string {
headers := []string{"Subscription", "Resource Group", "Location", "Type", "Service Name", "Compliant", "Impact", "Category", "Recommendation", "Result", "Learn"}
headers := []string{"Subscription", "Subscription Name", "Resource Group", "Location", "Type", "Service Name", "Compliant", "Impact", "Category", "Recommendation", "Result", "Learn", "RId"}

rbroken := [][]string{}
rok := [][]string{}
for _, d := range rd.MainData {
for _, r := range d.Rules {
row := []string{
scanners.MaskSubscriptionID(d.SubscriptionID, rd.Mask),
d.SubscriptionName,
d.ResourceGroup,
scanners.ParseLocation(d.Location),
d.Type,
Expand All @@ -37,6 +38,7 @@ func (rd *ReportData) ServicesTable() [][]string {
r.Recommendation,
r.Result,
r.Learn,
r.Id,
}
if r.NotCompliant {
rbroken = append([][]string{row}, rbroken...)
Expand All @@ -52,14 +54,15 @@ func (rd *ReportData) ServicesTable() [][]string {
}

func (rd *ReportData) CostTable() [][]string {
headers := []string{"From", "To", "Subscription", "ServiceName", "Value", "Currency"}
headers := []string{"From", "To", "Subscription", "Subscription Name", "ServiceName", "Value", "Currency"}

rows := [][]string{}
for _, r := range rd.CostData.Items {
row := []string{
rd.CostData.From.Format("2006-01-02"),
rd.CostData.To.Format("2006-01-02"),
scanners.MaskSubscriptionID(r.SubscriptionID, rd.Mask),
r.SubscriptionName,
r.ServiceName,
r.Value,
r.Currency,
Expand All @@ -72,11 +75,12 @@ func (rd *ReportData) CostTable() [][]string {
}

func (rd *ReportData) DefenderTable() [][]string {
headers := []string{"Subscription", "Name", "Tier", "Deprecated"}
headers := []string{"Subscription", "Subscription Name", "Name", "Tier", "Deprecated"}
rows := [][]string{}
for _, d := range rd.DefenderData {
row := []string{
scanners.MaskSubscriptionID(d.SubscriptionID, rd.Mask),
d.SubscriptionName,
d.Name,
d.Tier,
fmt.Sprintf("%t", d.Deprecated),
Expand All @@ -89,11 +93,12 @@ func (rd *ReportData) DefenderTable() [][]string {
}

func (rd *ReportData) AdvisorTable() [][]string {
headers := []string{"Subscription", "Name", "Type", "Category", "Description", "PotentialBenefits", "Risk", "LearnMoreLink"}
headers := []string{"Subscription", "Subscription Name", "Name", "Type", "Category", "Description", "PotentialBenefits", "Risk", "LearnMoreLink"}
rows := [][]string{}
for _, d := range rd.AdvisorData {
row := []string{
scanners.MaskSubscriptionID(d.SubscriptionID, rd.Mask),
d.SubscriptionName,
d.Name,
d.Type,
d.Category,
Expand Down
Loading

0 comments on commit 966b15e

Please sign in to comment.