From 33c7045ba6ccf8f9d243d76aae6dfb8ae7a7dc05 Mon Sep 17 00:00:00 2001 From: Yoriyasu Yano <430092+yorinasub17@users.noreply.github.com> Date: Mon, 25 Apr 2022 14:10:31 -0500 Subject: [PATCH] Add config support for EKS and exclude ghost cluster in our account (#295) * Add config support for EKS and exclude ghost cluster in our account * Exclude ap-southeast-1 from EKS testing --- .circleci/nuke_config.yml | 6 +++++ README.md | 52 +++++++++++++++++++++------------------ aws/aws.go | 2 +- aws/eks.go | 21 ++++++++++++---- aws/eks_test.go | 20 +++++++++------ config/config.go | 1 + config/config_test.go | 1 + 7 files changed, 66 insertions(+), 37 deletions(-) diff --git a/.circleci/nuke_config.yml b/.circleci/nuke_config.yml index d97b5076..e51a9d07 100644 --- a/.circleci/nuke_config.yml +++ b/.circleci/nuke_config.yml @@ -40,6 +40,12 @@ OIDCProvider: # We have an active OIDC Provider used by github actions - ".*token.actions.githubusercontent.com.*" +EKSCluster: + exclude: + names_regex: + # This EKS cluster is a ghost cluster in our account in the ap-southeast-1 region that can not be deleted. + - "^cloud-nuke-TestListEksClusters-o8DrEi$" + CloudWatchLogGroup: # Use an allow list instead of block list because we haven't done the due diligence yet to figure out what log groups # we need to keep. This is hard to do in the current scenario as we have thousands of log groups in the accounts. diff --git a/README.md b/README.md index e1c1efe1..5db24652 100644 --- a/README.md +++ b/README.md @@ -216,6 +216,9 @@ The following resources support the Config file: - EC2 Instances - Resource type: `ec2` - Config key: `EC2` +- EKS Clusters + - Resource type: `ekscluster` + - Config key: `EKSCluster` #### Example @@ -302,30 +305,31 @@ To find out what we options are supported in the config file today, consult this | resource type | names | names_regex | tags | tags_regex | |--------------------|-------|-------------|------|------------| -| s3 | none | ✅ | none | none | -| iam | none | ✅ | none | none | -| ecsserv | none | ✅ | none | none | -| ecscluster | none | ✅ | none | none | -| secretsmanager | none | ✅ | none | none | -| nat-gateway | none | ✅ | none | none | -| accessanalyzer | none | ✅ | none | none | -| dynamodb | none | ✅ | none | none | -| ebs | none | ✅ | none | none | -| lambda | none | ✅ | none | none | -| elbv2 | none | ✅ | none | none | -| ecs | none | ✅ | none | none | -| elasticache | none | ✅ | none | none | -| vpc | none | ✅ | none | none | -| oidcprovider | none | ✅ | none | none | -| cloudwatch-loggroup | none | ✅ | none | none | -| kmscustomerkeys | none | ✅ | none | none | -| asg | none | ✅ | none | none | -| lc | none | ✅ | none | none | -| eip | none | ✅ | none | none | -| ec2 | none | ✅ | none | none | -| acmpca | none | none | none | none | -| iam role | none | none | none | none | -| ... (more to come) | none | none | none | none | +| s3 | none | ✅ | none | none | +| iam | none | ✅ | none | none | +| ecsserv | none | ✅ | none | none | +| ecscluster | none | ✅ | none | none | +| secretsmanager | none | ✅ | none | none | +| nat-gateway | none | ✅ | none | none | +| accessanalyzer | none | ✅ | none | none | +| dynamodb | none | ✅ | none | none | +| ebs | none | ✅ | none | none | +| lambda | none | ✅ | none | none | +| elbv2 | none | ✅ | none | none | +| ecs | none | ✅ | none | none | +| elasticache | none | ✅ | none | none | +| vpc | none | ✅ | none | none | +| oidcprovider | none | ✅ | none | none | +| cloudwatch-loggroup | none | ✅ | none | none | +| kmscustomerkeys | none | ✅ | none | none | +| asg | none | ✅ | none | none | +| lc | none | ✅ | none | none | +| eip | none | ✅ | none | none | +| ec2 | none | ✅ | none | none | +| eks | none | ✅ | none | none | +| acmpca | none | none | none | none | +| iam role | none | none | none | none | +| ... (more to come) | none | none | none | none | diff --git a/aws/aws.go b/aws/aws.go index 2b3f8642..8e498c9c 100644 --- a/aws/aws.go +++ b/aws/aws.go @@ -502,7 +502,7 @@ func GetAllResources(targetRegions []string, excludeAfter time.Time, resourceTyp // EKS resources eksClusters := EKSClusters{} if IsNukeable(eksClusters.ResourceName(), resourceTypes) { - eksClusterNames, err := getAllEksClusters(session, excludeAfter) + eksClusterNames, err := getAllEksClusters(session, excludeAfter, configObj) if err != nil { return nil, errors.WithStackTrace(err) } diff --git a/aws/eks.go b/aws/eks.go index 976428a8..3e46e53b 100644 --- a/aws/eks.go +++ b/aws/eks.go @@ -7,30 +7,41 @@ import ( "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/aws/session" "github.com/aws/aws-sdk-go/service/eks" + "github.com/gruntwork-io/cloud-nuke/config" "github.com/gruntwork-io/cloud-nuke/logging" "github.com/gruntwork-io/go-commons/errors" "github.com/hashicorp/go-multierror" ) // getAllEksClusters returns a list of strings of EKS Cluster Names that uniquely identify each cluster. -func getAllEksClusters(awsSession *session.Session, excludeAfter time.Time) ([]*string, error) { +func getAllEksClusters(awsSession *session.Session, excludeAfter time.Time, configObj config.Config) ([]*string, error) { svc := eks.New(awsSession) result, err := svc.ListClusters(&eks.ListClustersInput{}) if err != nil { return nil, errors.WithStackTrace(err) } - filteredClusters, err := filterOutRecentEksClusters(svc, result.Clusters, excludeAfter) + filteredClusters, err := filterOutEksClusters(svc, result.Clusters, excludeAfter, configObj) if err != nil { return nil, errors.WithStackTrace(err) } return filteredClusters, nil } -// filterOutRecentEksClusters will take in the list of clusters and filter out any clusters that were created after -// `excludeAfter`. -func filterOutRecentEksClusters(svc *eks.EKS, clusterNames []*string, excludeAfter time.Time) ([]*string, error) { +// filterOutEksClusters will take in the list of clusters and filter out any clusters that were created after +// `excludeAfter`, and those that are excluded by the config file. +func filterOutEksClusters(svc *eks.EKS, clusterNames []*string, excludeAfter time.Time, configObj config.Config) ([]*string, error) { var filteredEksClusterNames []*string for _, clusterName := range clusterNames { + // Since we already have the name here, avoid an extra API call by applying the name based config filter first. + shouldInclude := config.ShouldInclude( + aws.StringValue(clusterName), + configObj.EKSCluster.IncludeRule.NamesRegExp, + configObj.EKSCluster.ExcludeRule.NamesRegExp, + ) + if !shouldInclude { + continue + } + describeResult, err := svc.DescribeCluster(&eks.DescribeClusterInput{ Name: clusterName, }) diff --git a/aws/eks_test.go b/aws/eks_test.go index f2ef5399..3fe7f427 100644 --- a/aws/eks_test.go +++ b/aws/eks_test.go @@ -7,18 +7,24 @@ import ( awsgo "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/aws/session" + "github.com/gruntwork-io/cloud-nuke/config" "github.com/gruntwork-io/cloud-nuke/util" "github.com/gruntwork-io/terratest/modules/logger" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) +var ( + // Exclude ap-southeast-1, which currently has a ghost EKS cluster that messes cloud-nuke up. + excludeRegionsForEKSTest = []string{"ap-southeast-1"} +) + // Test that we can successfully list clusters by manually creating a cluster, and then using the list function to find // it. func TestListEksClusters(t *testing.T) { t.Parallel() - region, err := getRandomRegion() + region, err := getRandomRegionWithExclusions(excludeRegionsForEKSTest) require.NoError(t, err) awsSession, err := session.NewSession(&awsgo.Config{ @@ -34,13 +40,13 @@ func TestListEksClusters(t *testing.T) { cluster := createEKSCluster(t, awsSession, uniqueID, *role.Arn) defer nukeAllEksClusters(awsSession, []*string{cluster.Name}) - eksClusterNames, err := getAllEksClusters(awsSession, time.Now().Add(1*time.Hour*-1)) + eksClusterNames, err := getAllEksClusters(awsSession, time.Now().Add(1*time.Hour*-1), config.Config{}) if err != nil { assert.Failf(t, "Unable to fetch list of clusters: %s", err.Error()) } assert.NotContains(t, awsgo.StringValueSlice(eksClusterNames), *cluster.Name) - eksClusterNames, err = getAllEksClusters(awsSession, time.Now().Add(1*time.Hour)) + eksClusterNames, err = getAllEksClusters(awsSession, time.Now().Add(1*time.Hour), config.Config{}) if err != nil { assert.Failf(t, "Unable to fetch list of clusters: %s", err.Error()) } @@ -52,7 +58,7 @@ func TestListEksClusters(t *testing.T) { func TestNukeEksClusters(t *testing.T) { t.Parallel() - region, err := getRandomRegion() + region, err := getRandomRegionWithExclusions(excludeRegionsForEKSTest) require.NoError(t, err) awsSession, err := session.NewSession(&awsgo.Config{ @@ -69,7 +75,7 @@ func TestNukeEksClusters(t *testing.T) { err = nukeAllEksClusters(awsSession, []*string{cluster.Name}) require.NoError(t, err) - eksClusterNames, err := getAllEksClusters(awsSession, time.Now().Add(1*time.Hour)) + eksClusterNames, err := getAllEksClusters(awsSession, time.Now().Add(1*time.Hour), config.Config{}) require.NoError(t, err) assert.NotContains(t, awsgo.StringValueSlice(eksClusterNames), *cluster.Name) } @@ -78,7 +84,7 @@ func TestNukeEksClusters(t *testing.T) { func TestNukeEksClustersWithCompute(t *testing.T) { t.Parallel() - region, err := getRandomRegion() + region, err := getRandomRegionWithExclusions(excludeRegionsForEKSTest) require.NoError(t, err) awsSession, err := session.NewSession(&awsgo.Config{ @@ -121,7 +127,7 @@ func TestNukeEksClustersWithCompute(t *testing.T) { err = nukeAllEksClusters(awsSession, []*string{cluster.Name}) require.NoError(t, err) - eksClusterNames, err := getAllEksClusters(awsSession, time.Now().Add(1*time.Hour)) + eksClusterNames, err := getAllEksClusters(awsSession, time.Now().Add(1*time.Hour), config.Config{}) require.NoError(t, err) assert.NotContains(t, awsgo.StringValueSlice(eksClusterNames), *cluster.Name) } diff --git a/config/config.go b/config/config.go index 3732c2cd..a52d77c0 100644 --- a/config/config.go +++ b/config/config.go @@ -32,6 +32,7 @@ type Config struct { EC2 ResourceType `yaml:"EC2"` CloudWatchLogGroup ResourceType `yaml:"CloudWatchLogGroup"` KMSCustomerKeys ResourceType `yaml:"KMSCustomerKeys"` + EKSCluster ResourceType `yaml:"EKSCluster"` } type ResourceType struct { diff --git a/config/config_test.go b/config/config_test.go index bb2f424b..c6927b27 100644 --- a/config/config_test.go +++ b/config/config_test.go @@ -33,6 +33,7 @@ func emptyConfig() *Config { ResourceType{FilterRule{}, FilterRule{}}, ResourceType{FilterRule{}, FilterRule{}}, ResourceType{FilterRule{}, FilterRule{}}, + ResourceType{FilterRule{}, FilterRule{}}, } }