generated from padok-team/yatas-template
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(compute): Add instance checks GCS_VM_ (#11)
* feat(instance): GCP_VM_001: check instance does not have public IP * feat(instance): GCP_VM_002: check disk are encrypted customer-managed * chore(deps): run go mod tidy
- Loading branch information
1 parent
ff84bca
commit 4da74a7
Showing
9 changed files
with
440 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
plugins: | ||
- name: "gcp" | ||
enabled: true | ||
source: "github.com/padok-team/yatas-gcp" | ||
version: "latest" | ||
description: "Check for GCP good practices" | ||
|
||
pluginsConfiguration: | ||
- pluginName: "gcp" | ||
accounts: | ||
- project: "project-1" | ||
computeRegions: | ||
- europe-west1 | ||
- europe-west2 | ||
- europe-west3 | ||
- project: "project-2" | ||
computeRegions: | ||
- us-east1 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,108 @@ | ||
package instance | ||
|
||
import ( | ||
"context" | ||
"strings" | ||
|
||
compute "cloud.google.com/go/compute/apiv1" | ||
"cloud.google.com/go/compute/apiv1/computepb" | ||
"github.com/padok-team/yatas-gcp/internal" | ||
"github.com/padok-team/yatas-gcp/logger" | ||
"google.golang.org/api/iterator" | ||
) | ||
|
||
// Get the compute zones based on the list of compute regions provided in the config | ||
func GetComputeZones(account internal.GCPAccount) []string { | ||
ctx := context.Background() | ||
client, err := compute.NewZonesRESTClient(ctx) | ||
if err != nil { | ||
logger.Logger.Error("Failed to create Compute Zones client", "error", err) | ||
} | ||
defer client.Close() | ||
|
||
req := &computepb.ListZonesRequest{ | ||
Project: account.Project, | ||
} | ||
var zones []string | ||
it := client.List(ctx, req) | ||
for { | ||
resp, err := it.Next() | ||
if err == iterator.Done { | ||
break | ||
} | ||
if err != nil { | ||
logger.Logger.Error("Failed to list Compute Zones", "error", err.Error()) | ||
break | ||
} | ||
|
||
region := resp.GetRegion() | ||
for _, r := range account.ComputeRegions { | ||
if strings.HasSuffix(region, r) { | ||
zones = append(zones, resp.GetName()) | ||
} | ||
} | ||
} | ||
|
||
logger.Logger.Debug("Compute Zones", "zones", zones) | ||
|
||
return zones | ||
} | ||
|
||
// Get all the VM instances of the account for the given compute zone | ||
func GetInstances(account internal.GCPAccount, computeZone string) []computepb.Instance { | ||
ctx := context.Background() | ||
client, err := compute.NewInstancesRESTClient(ctx) | ||
if err != nil { | ||
logger.Logger.Error("Failed to create Instance client", "error", err) | ||
} | ||
defer client.Close() | ||
|
||
req := &computepb.ListInstancesRequest{ | ||
Project: account.Project, | ||
Zone: computeZone, | ||
} | ||
var instances []computepb.Instance | ||
it := client.List(ctx, req) | ||
for { | ||
resp, err := it.Next() | ||
if err == iterator.Done { | ||
break | ||
} | ||
if err != nil { | ||
logger.Logger.Error("Failed to list VM Instances", "error", err.Error()) | ||
break | ||
} | ||
instances = append(instances, *resp) | ||
} | ||
|
||
return instances | ||
} | ||
|
||
func GetDisks(account internal.GCPAccount, computeZone string) []computepb.Disk { | ||
ctx := context.Background() | ||
client, err := compute.NewDisksRESTClient(ctx) | ||
if err != nil { | ||
logger.Logger.Error("Failed to create Disk client", "error", err) | ||
} | ||
defer client.Close() | ||
|
||
req := &computepb.ListDisksRequest{ | ||
Project: account.Project, | ||
Zone: computeZone, | ||
} | ||
var disks []computepb.Disk | ||
it := client.List(ctx, req) | ||
for { | ||
resp, err := it.Next() | ||
if err == iterator.Done { | ||
break | ||
} | ||
if err != nil { | ||
logger.Logger.Error("Failed to list Disks", "error", err.Error()) | ||
break | ||
} | ||
disks = append(disks, *resp) | ||
} | ||
|
||
return disks | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
package instance | ||
|
||
import ( | ||
"sync" | ||
|
||
"cloud.google.com/go/compute/apiv1/computepb" | ||
"github.com/padok-team/yatas-gcp/internal" | ||
"github.com/padok-team/yatas/plugins/commons" | ||
) | ||
|
||
func RunChecks(wa *sync.WaitGroup, account internal.GCPAccount, c *commons.Config, queue chan []commons.Check) { | ||
var checkConfig commons.CheckConfig | ||
checkConfig.Init(c) | ||
var checks []commons.Check | ||
|
||
computeZones := GetComputeZones(account) | ||
|
||
// Get all the instances in all the compute zones specified | ||
var instances []computepb.Instance | ||
for _, zone := range computeZones { | ||
instances = append(instances, GetInstances(account, zone)...) | ||
} | ||
|
||
// Get all the disks in all the compute zones specified | ||
var disks []computepb.Disk | ||
for _, zone := range computeZones { | ||
disks = append(disks, GetDisks(account, zone)...) | ||
} | ||
|
||
instanceChecks := []commons.CheckDefinition{ | ||
{ | ||
Title: "GCP_VM_001", | ||
Description: "Check if VM instance is not using a public IP address", | ||
Categories: []string{"Security", "Good Practice"}, | ||
ConditionFn: InstanceNoPublicIPAttached, | ||
SuccessMessage: "VM instance is not using a public IP address", | ||
FailureMessage: "VM instance is using a public IP address", | ||
}, | ||
} | ||
|
||
diskChecks := []commons.CheckDefinition{ | ||
{ | ||
Title: "GCP_VM_002", | ||
Description: "Check if VM Disk is encrypted with a customer-managed key", | ||
Categories: []string{"Security", "Good Practice"}, | ||
ConditionFn: DiskIsCustomerEncrypted, | ||
SuccessMessage: "VM Disk is encrypted with a customer-managed key", | ||
FailureMessage: "VM Disk is not encrypted with a customer-managed key", | ||
}, | ||
} | ||
|
||
var resources []commons.Resource | ||
for _, instance := range instances { | ||
resources = append(resources, &VMInstance{Instance: instance}) | ||
} | ||
var diskResources []commons.Resource | ||
for _, disk := range disks { | ||
diskResources = append(diskResources, &VMDisk{Disk: disk}) | ||
} | ||
|
||
commons.AddChecks(&checkConfig, instanceChecks) | ||
commons.AddChecks(&checkConfig, diskChecks) | ||
go commons.CheckResources(checkConfig, resources, instanceChecks) | ||
go commons.CheckResources(checkConfig, diskResources, diskChecks) | ||
|
||
go func() { | ||
for t := range checkConfig.Queue { | ||
t.EndCheck() | ||
checks = append(checks, t) | ||
|
||
checkConfig.Wg.Done() | ||
} | ||
}() | ||
|
||
checkConfig.Wg.Wait() | ||
|
||
queue <- checks | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
package instance | ||
|
||
import ( | ||
"github.com/padok-team/yatas/plugins/commons" | ||
) | ||
|
||
func InstanceNoPublicIPAttached(resource commons.Resource) bool { | ||
instance, ok := resource.(*VMInstance) | ||
if !ok { | ||
return false | ||
} | ||
|
||
if instance.Instance.NetworkInterfaces != nil { | ||
for _, networkInterface := range instance.Instance.NetworkInterfaces { | ||
if networkInterface.AccessConfigs != nil { | ||
for _, accessConfig := range networkInterface.AccessConfigs { | ||
// If there is an external IPv4 or IPv6 address, return false | ||
if accessConfig.NatIP != nil && *accessConfig.NatIP != "" { | ||
return false | ||
} | ||
if accessConfig.ExternalIpv6 != nil { | ||
return false | ||
} | ||
} | ||
} | ||
} | ||
} | ||
return true | ||
} | ||
|
||
func DiskIsCustomerEncrypted(resource commons.Resource) bool { | ||
disk, ok := resource.(*VMDisk) | ||
if !ok { | ||
return false | ||
} | ||
return disk.Disk.DiskEncryptionKey != nil | ||
} |
Oops, something went wrong.