Skip to content

Commit

Permalink
added vwa support
Browse files Browse the repository at this point in the history
  • Loading branch information
cmendible committed Jul 4, 2023
1 parent b236e0d commit 42ecaf4
Show file tree
Hide file tree
Showing 5 changed files with 302 additions and 0 deletions.
2 changes: 2 additions & 0 deletions cmd/azqr/rules.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import (
"github.com/Azure/azqr/internal/scanners/sql"
"github.com/Azure/azqr/internal/scanners/st"
"github.com/Azure/azqr/internal/scanners/wps"
"github.com/Azure/azqr/internal/scanners/vwan"
"github.com/spf13/cobra"
)

Expand Down Expand Up @@ -70,6 +71,7 @@ var rulesCmd = &cobra.Command{
&mysql.MySQLScanner{},
&mysql.MySQLFlexibleScanner{},
&appi.AppInsightsScanner{},
&vwan.VirtualWanScanner{},
}

fmt.Println("# | Id | Category | Subcategory | Name | Severity | More Info")
Expand Down
28 changes: 28 additions & 0 deletions cmd/azqr/vwan.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

package azqr

import (
"github.com/Azure/azqr/internal/scanners"
"github.com/Azure/azqr/internal/scanners/vwan"
"github.com/spf13/cobra"
)

func init() {
scanCmd.AddCommand(vwanCmd)
}

var vwanCmd = &cobra.Command{
Use: "vwan",
Short: "Scan Azure Virtual WAN",
Long: "Scan Azure Virtual WAN",
Args: cobra.NoArgs,
Run: func(cmd *cobra.Command, args []string) {
serviceScanners := []scanners.IAzureScanner{
&vwan.VirtualWanScanner{},
}

scan(cmd, serviceScanners)
},
}
89 changes: 89 additions & 0 deletions internal/scanners/vwan/rules.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

package vwan

import (
"strings"

"github.com/Azure/azqr/internal/scanners"
"github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork"
)

// GetRules - Returns the rules for the VirtualWanScanner
func (a *VirtualWanScanner) GetRules() map[string]scanners.AzureRule {
return map[string]scanners.AzureRule{
"DiagnosticSettings": {
Id: "vwa-001",
Category: scanners.RulesCategoryReliability,
Subcategory: scanners.RulesSubcategoryReliabilityDiagnosticLogs,
Description: "Virtual Wan should have diagnostic settings enabled",
Severity: scanners.SeverityMedium,
Eval: func(target interface{}, scanContext *scanners.ScanContext) (bool, string) {
service := target.(*armnetwork.VirtualWAN)
_, ok := scanContext.DiagnosticsSettings[strings.ToLower(*service.ID)]
return !ok, ""
},
Url: "https://learn.microsoft.com/en-us/azure/virtual-wan/monitor-virtual-wan",
},
"AvailabilityZones": {
Id: "vwa-002",
Category: scanners.RulesCategoryReliability,
Subcategory: scanners.RulesSubcategoryReliabilityAvailabilityZones,
Description: "Virtual Wan should have availability zones enabled",
Severity: scanners.SeverityHigh,
Eval: func(target interface{}, scanContext *scanners.ScanContext) (bool, string) {
return false, ""
},
Url: "https://learn.microsoft.com/en-us/azure/virtual-wan/virtual-wan-faq#how-are-availability-zones-and-resiliency-handled-in-virtual-wan",
},
"SLA": {
Id: "vwa-003",
Category: scanners.RulesCategoryReliability,
Subcategory: scanners.RulesSubcategoryReliabilitySLA,
Description: "Virtual Wan should have a SLA",
Severity: scanners.SeverityHigh,
Eval: func(target interface{}, scanContext *scanners.ScanContext) (bool, string) {
return false, "99.95%"
},
Url: "https://learn.microsoft.com/en-us/azure/virtual-wan/virtual-wan-faq#how-is-virtual-wan-sla-calculated",
},
"SKU": {
Id: "vwa-005",
Category: scanners.RulesCategoryReliability,
Subcategory: scanners.RulesSubcategoryReliabilitySKU,
Description: "Virtual Wan Type",
Severity: scanners.SeverityHigh,
Eval: func(target interface{}, scanContext *scanners.ScanContext) (bool, string) {
i := target.(*armnetwork.VirtualWAN)
return false, string(*i.Properties.Type)
},
Url: "https://learn.microsoft.com/en-us/azure/virtual-wan/virtual-wan-about#basicstandard",
},
"CAF": {
Id: "vwa-006",
Category: scanners.RulesCategoryOperationalExcellence,
Subcategory: scanners.RulesSubcategoryOperationalExcellenceCAF,
Description: "Virtual Wan Name should comply with naming conventions",
Severity: scanners.SeverityLow,
Eval: func(target interface{}, scanContext *scanners.ScanContext) (bool, string) {
c := target.(*armnetwork.VirtualWAN)
caf := strings.HasPrefix(*c.Name, "vwa")
return !caf, ""
},
Url: "https://learn.microsoft.com/en-us/azure/cloud-adoption-framework/ready/azure-best-practices/resource-abbreviations",
},
"vwa-007": {
Id: "vwa-007",
Category: scanners.RulesCategoryOperationalExcellence,
Subcategory: scanners.RulesSubcategoryOperationalExcellenceTags,
Description: "Virtual Wan should have tags",
Severity: scanners.SeverityLow,
Eval: func(target interface{}, scanContext *scanners.ScanContext) (bool, string) {
c := target.(*armnetwork.VirtualWAN)
return c.Tags == nil || len(c.Tags) == 0, ""
},
Url: "https://learn.microsoft.com/en-us/azure/azure-resource-manager/management/tag-resources?tabs=json",
},
}
}
117 changes: 117 additions & 0 deletions internal/scanners/vwan/rules_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

package vwan

import (
"reflect"
"testing"

"github.com/Azure/azqr/internal/scanners"
"github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork"
"github.com/Azure/go-autorest/autorest/to"
)

func TestVirtualWanScanner_Rules(t *testing.T) {
type fields struct {
rule string
target interface{}
scanContext *scanners.ScanContext
}
type want struct {
broken bool
result string
}
tests := []struct {
name string
fields fields
want want
}{
{
name: "VirtualWanScanner DiagnosticSettings",
fields: fields{
rule: "DiagnosticSettings",
target: &armnetwork.VirtualWAN{
ID: to.StringPtr("test"),
},
scanContext: &scanners.ScanContext{
DiagnosticsSettings: map[string]bool{
"test": true,
},
},
},
want: want{
broken: false,
result: "",
},
},
{
name: "VirtualWanScanner Availability Zones",
fields: fields{
rule: "AvailabilityZones",
target: &armnetwork.VirtualWAN{},
scanContext: &scanners.ScanContext{},
},
want: want{
broken: false,
result: "",
},
},
{
name: "VirtualWanScanner SLA 99.95%",
fields: fields{
rule: "SLA",
target: &armnetwork.VirtualWAN{},
scanContext: &scanners.ScanContext{},
},
want: want{
broken: false,
result: "99.95%",
},
},
{
name: "VirtualWanScanner SKU",
fields: fields{
rule: "SKU",
target: &armnetwork.VirtualWAN{
Properties: &armnetwork.VirtualWanProperties{
Type: to.StringPtr("Standard"),
},
},
scanContext: &scanners.ScanContext{},
},
want: want{
broken: false,
result: "Standard",
},
},
{
name: "VirtualWanScanner CAF",
fields: fields{
rule: "CAF",
target: &armnetwork.VirtualWAN{
Name: to.StringPtr("vwa-test"),
},
scanContext: &scanners.ScanContext{},
},
want: want{
broken: false,
result: "",
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
s := &VirtualWanScanner{}
rules := s.GetRules()
b, w := rules[tt.fields.rule].Eval(tt.fields.target, tt.fields.scanContext)
got := want{
broken: b,
result: w,
}
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("VirtualWanScanner Rule.Eval() = %v, want %v", got, tt.want)
}
})
}
}
66 changes: 66 additions & 0 deletions internal/scanners/vwan/vwan.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

package vwan

import (
"github.com/rs/zerolog/log"

"github.com/Azure/azqr/internal/scanners"
"github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork"
)

// VirtualWanScanner - Scanner for WebPubSub
type VirtualWanScanner struct {
config *scanners.ScannerConfig
client *armnetwork.VirtualWansClient
}

// Init - Initializes the VirtualWanScanner
func (c *VirtualWanScanner) Init(config *scanners.ScannerConfig) error {
c.config = config
var err error
c.client, err = armnetwork.NewVirtualWansClient(config.SubscriptionID, config.Cred, config.ClientOptions)
return err
}

// Scan - Scans all WebPubSub in a Resource Group
func (c *VirtualWanScanner) Scan(resourceGroupName string, scanContext *scanners.ScanContext) ([]scanners.AzureServiceResult, error) {
log.Info().Msgf("Scanning WebPubSub in Resource Group %s", resourceGroupName)

WebPubSub, err := c.list(resourceGroupName)
if err != nil {
return nil, err
}
engine := scanners.RuleEngine{}
rules := c.GetRules()
results := []scanners.AzureServiceResult{}

for _, w := range WebPubSub {
rr := engine.EvaluateRules(rules, w, scanContext)

results = append(results, scanners.AzureServiceResult{
SubscriptionID: c.config.SubscriptionID,
ResourceGroup: resourceGroupName,
ServiceName: *w.Name,
Type: *w.Type,
Location: *w.Location,
Rules: rr,
})
}
return results, nil
}

func (c *VirtualWanScanner) list(resourceGroupName string) ([]*armnetwork.VirtualWAN, error) {
pager := c.client.NewListByResourceGroupPager(resourceGroupName, nil)

vwas := make([]*armnetwork.VirtualWAN, 0)
for pager.More() {
resp, err := pager.NextPage(c.config.Ctx)
if err != nil {
return nil, err
}
vwas = append(vwas, resp.Value...)
}
return vwas, nil
}

0 comments on commit 42ecaf4

Please sign in to comment.