Skip to content

Commit

Permalink
chore: add vpngw
Browse files Browse the repository at this point in the history
  • Loading branch information
vanwinkelseppe committed Apr 23, 2024
1 parent 177378b commit 68ddaa6
Show file tree
Hide file tree
Showing 9 changed files with 255 additions and 1 deletion.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
# Output of the go coverage tool, specifically when used with LiteIDE
*.out

# Jetbrains IDE
.idea/
# Dependency directories (remove the comment below to include it)
# vendor/

Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ To learn more about the recommendations used by **Azure Quick Review (azqr)**, y
* Azure Virtual Machine
* Azure Virtual Network
* Azure Virtual WAN
* Azure VPN Gateway
* Azure Web PubSub

## Usage
Expand Down
28 changes: 28 additions & 0 deletions cmd/azqr/vpng.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/vpng"
"github.com/spf13/cobra"
)

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

var vpngCmd = &cobra.Command{
Use: "vpng",
Short: "Scan Azure VPN Gateway",
Long: "Scan Azure VPN Gateway",
Args: cobra.NoArgs,
Run: func(cmd *cobra.Command, args []string) {
serviceScanners := []scanners.IAzureScanner{
&vpng.VPNGatewayScanner{},
}

scan(cmd, serviceScanners)
},
}
1 change: 1 addition & 0 deletions docs/content/en/docs/Overview/_index.md
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ To learn more about the recommendations used by **Azure Quick Review (azqr)**, y
* Azure Virtual Machine
* Azure Virtual Network
* Azure Virtual WAN
* Azure VPN Gateway
* Azure Web PubSub

## Code of Conduct
Expand Down
6 changes: 5 additions & 1 deletion docs/content/en/docs/Recommendations/_index.md
Original file line number Diff line number Diff line change
Expand Up @@ -328,4 +328,8 @@ Azure Quick Review checks the following recommendations for Azure resources. The
316 | Governance | Low | Azure Synapse Spark Pool should have tags | [Learn](https://learn.microsoft.com/en-us/azure/azure-resource-manager/management/tag-resources?tabs=json)
317 | High Availability | High | Azure Synapse Dedicated SQL Pool SLA | [Learn](https://www.microsoft.com/licensing/docs/view/Service-Level-Agreements-SLA-for-Online-Services)
318 | Governance | Low | Azure Synapse Dedicated SQL Pool Name should comply with naming conventions | [Learn](https://learn.microsoft.com/en-us/azure/cloud-adoption-framework/ready/azure-best-practices/resource-abbreviations)
319 | Governance | Low | Azure Synapse Dedicated SQL Pool should have tags | [Learn](https://learn.microsoft.com/en-us/azure/azure-resource-manager/management/tag-resources?tabs=json)
319 | Governance | Low | Azure Synapse Dedicated SQL Pool should have tags | [Learn](https://learn.microsoft.com/en-us/azure/azure-resource-manager/management/tag-resources?tabs=json)
320 | Monitoring and Alerting | Low | VPN Gateway should have diagnostic settings enabled | [Learn](https://learn.microsoft.com/en-us/azure/vpn-gateway/monitor-vpn-gateway)
321 | Governance | Low | VPN Gateway Name should comply with naming conventions | [Learn](https://learn.microsoft.com/en-us/azure/cloud-adoption-framework/ready/azure-best-practices/resource-abbreviations)
322 | High Availability | Low | VPN Gateway should have tags | [Learn](https://learn.microsoft.com/en-us/azure/azure-resource-manager/management/tag-resources?tabs=json)
323 | High Availability | High | VPN Gateway should have a SLA | [Learn](https://www.microsoft.com/licensing/docs/view/Service-Level-Agreements-SLA-for-Online-Services)
2 changes: 2 additions & 0 deletions internal/scan.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"context"
"errors"
"fmt"
"github.com/Azure/azqr/internal/scanners/vpng"
"sync"
"time"

Expand Down Expand Up @@ -477,6 +478,7 @@ func GetScanners() []scanners.IAzureScanner {
&st.StorageScanner{},
&vm.VirtualMachineScanner{},
&vnet.VirtualNetworkScanner{},
&vpng.VPNGatewayScanner{},
&wps.WebPubSubScanner{},
}
}
63 changes: 63 additions & 0 deletions internal/scanners/vpng/rules.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

package vpng

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 VPNGatewayScanner
func (a *VPNGatewayScanner) GetRules() map[string]scanners.AzureRule {
return map[string]scanners.AzureRule{
"vpng-001": {
Id: "vpng-001",
Category: scanners.RulesCategoryMonitoringAndAlerting,
Recommendation: "VPN Gateway should have diagnostic settings enabled",
Impact: scanners.ImpactLow,
Eval: func(target interface{}, scanContext *scanners.ScanContext) (bool, string) {
service := target.(*armnetwork.VPNGateway)
_, ok := scanContext.DiagnosticsSettings[strings.ToLower(*service.ID)]
return !ok, ""
},
Url: "https://learn.microsoft.com/en-us/azure/vpn-gateway/monitor-vpn-gateway",
},
"vpng-002": {
Id: "vpng-002",
Category: scanners.RulesCategoryGovernance,
Recommendation: "VPN Gateway Name should comply with naming conventions",
Impact: scanners.ImpactLow,
Eval: func(target interface{}, scanContext *scanners.ScanContext) (bool, string) {
c := target.(*armnetwork.VPNGateway)
caf := strings.HasPrefix(*c.Name, "vpng")
return !caf, ""
},
Url: "https://learn.microsoft.com/en-us/azure/cloud-adoption-framework/ready/azure-best-practices/resource-abbreviations",
},
"vpng-003": {
Id: "vpng-003",
Category: scanners.RulesCategoryGovernance,
Recommendation: "VPN Gateway should have tags",
Impact: scanners.ImpactLow,
Eval: func(target interface{}, scanContext *scanners.ScanContext) (bool, string) {
c := target.(*armnetwork.VPNGateway)
return len(c.Tags) == 0, ""
},
Url: "https://learn.microsoft.com/en-us/azure/azure-resource-manager/management/tag-resources?tabs=json",
},
"vpng-004": {
Id: "vpng-004",
Category: scanners.RulesCategoryHighAvailability,
Recommendation: "VPN Gateway should have a SLA",
Impact: scanners.ImpactHigh,
Eval: func(target interface{}, scanContext *scanners.ScanContext) (bool, string) {
return false, "99.9%"
//TODO: Filter SKU based on tier (BASIC / Or others)
},
Url: "https://www.microsoft.com/licensing/docs/view/Service-Level-Agreements-SLA-for-Online-Services",
},
}
}
89 changes: 89 additions & 0 deletions internal/scanners/vpng/rules_test.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 vpng

import (
"reflect"
"testing"

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

func TestVPNGatewayScanner_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: "VPNGatewayScanner DiagnosticSettings",
fields: fields{
rule: "vpng-001",
target: &armnetwork.VPNGateway{
ID: to.Ptr("test"),
},
scanContext: &scanners.ScanContext{
DiagnosticsSettings: map[string]bool{
"test": true,
},
},
},
want: want{
broken: false,
result: "",
},
},
{
name: "VPNGatewayScanner CAF",
fields: fields{
rule: "vpng-002",
target: &armnetwork.VPNGateway{
Name: to.Ptr("vpng-test"),
},
scanContext: &scanners.ScanContext{},
},
want: want{
broken: false,
result: "",
},
},
{
name: "VPNGatewayScanner SLA 99.9%",
fields: fields{
rule: "vpng-004",
target: &armnetwork.VPNGateway{},
scanContext: &scanners.ScanContext{},
},
want: want{
broken: false,
result: "99.9%",
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
s := &VPNGatewayScanner{}
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("VPNGatewayScanner Rule.Eval() = %v, want %v", got, tt.want)
}
})
}
}
64 changes: 64 additions & 0 deletions internal/scanners/vpng/vpng.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

package vpng

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

// VPNGatewayScanner - Scanner for VPN Gateway
type VPNGatewayScanner struct {
config *scanners.ScannerConfig
client *armnetwork.VPNGatewaysClient
}

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

// Scan - Scans all VirtualNetwork in a Resource Group
func (c *VPNGatewayScanner) Scan(resourceGroupName string, scanContext *scanners.ScanContext) ([]scanners.AzureServiceResult, error) {
scanners.LogResourceGroupScan(c.config.SubscriptionID, resourceGroupName, "VPN Gateway")

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

for _, w := range vpns {
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 *VPNGatewayScanner) list(resourceGroupName string) ([]*armnetwork.VPNGateway, error) {
pager := c.client.NewListByResourceGroupPager(resourceGroupName, nil)

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

0 comments on commit 68ddaa6

Please sign in to comment.