Repository: gruntwork-io/cloud-nuke
Pull request #569 (2023-08-25 02:11:59)

Skip AWS Managed AMIs
<!-- Prepend '[WIP]' to the title if this PR is still a work-in-progress. Remove it when it is ready for review! -->

## Description

partially fixes https://github.com/gruntwork-io/cloud-nuke/issues/563. 
Skipping AWS Managed AMIs when finding AMIs

<!-- Description of the changes introduced by this PR. -->

## TODOs

Read the [Gruntwork contribution guidelines](https://gruntwork.notion.site/Gruntwork-Coding-Methodology-02fdcd6e4b004e818553684760bf691e).

- [ ] Update the docs.
- [ ] Run the relevant tests successfully, including pre-commit checks.
- [ ] Ensure any 3rd party code adheres with our [license policy](https://www.notion.so/gruntwork/Gruntwork-licenses-and-open-source-usage-policy-f7dece1f780341c7b69c1763f22b1378) or delete this line if its not applicable.
- [ ] Include release notes. If this PR is backward incompatible, include a migration guide.
- [ ] Attention Grunts - if this PR adds support for a new resource, ensure the `nuke_sandbox` and `nuke_phxdevops` jobs in `.circleci/config.yml` have been updated with appropriate exclusions (either directly in the job or via the `.circleci/nuke_config.yml` file) to prevent nuking IAM roles, groups, resources, etc that are important for the test accounts.


## Release Notes (draft)

<!-- One-line description of the PR that can be included in the final release notes. -->
Added / Removed / Updated [X].

Updated [Skipping AWS Managed AMIs when finding AMIs]

### Migration Guide

<!-- Important: If you made any backward incompatible changes, then you must write a migration guide! -->




Patch:
diff --git a/aws/resources/ami.go b/aws/resources/ami.go
index ff84a1d..018976c 100644
--- a/aws/resources/ami.go
+++ b/aws/resources/ami.go
@@ -1,6 +1,7 @@
 package resources
 
 import (
+	"strings"
 	"time"
 
 	awsgo "github.com/aws/aws-sdk-go/aws"
@@ -34,6 +35,20 @@ func (ami *AMIs) getAll(configObj config.Config) ([]*string, error) {
 			return nil, err
 		}
 
+		// Check if the image has a tag that indicates AWS management
+		isAWSManaged := false
+		for _, tag := range image.Tags {
+			if *tag.Key == "aws-managed" && *tag.Value == "true" {
+				isAWSManaged = true
+				break
+			}
+		}
+
+		// Skip AWS managed images and images created by AWS Backup
+		if isAWSManaged || strings.HasPrefix(*image.Name, "AwsBackup") {
+			continue
+		}
+
 		if configObj.AMI.ShouldInclude(config.ResourceValue{
 			Name: image.Name,
 			Time: &createdTime,


Test patch:
diff --git a/aws/resources/ami_test.go b/aws/resources/ami_test.go
index c42af96..0f90a70 100644
--- a/aws/resources/ami_test.go
+++ b/aws/resources/ami_test.go
@@ -1,6 +1,7 @@
 package resources
 
 import (
+	"github.com/aws/aws-sdk-go-v2/aws"
 	"github.com/aws/aws-sdk-go/service/ec2/ec2iface"
 	"github.com/gruntwork-io/cloud-nuke/config"
 	"github.com/gruntwork-io/cloud-nuke/telemetry"
@@ -27,6 +28,51 @@ func (m mockedAMI) DeregisterImage(input *ec2.DeregisterImageInput) (*ec2.Deregi
 	return &m.DeregisterImageOutput, nil
 }
 
+func TestAMIGetAll_SkipAWSManaged(t *testing.T) {
+	telemetry.InitTelemetry("cloud-nuke", "")
+	t.Parallel()
+
+	testName := "test-ami"
+	testImageId1 := "test-image-id1"
+	testImageId2 := "test-image-id2"
+	now := time.Now()
+	acm := AMIs{
+		Client: mockedAMI{
+			DescribeImagesOutput: ec2.DescribeImagesOutput{
+				Images: []*ec2.Image{
+					{
+						ImageId:      &testImageId1,
+						Name:         &testName,
+						CreationDate: awsgo.String(now.Format("2006-01-02T15:04:05.000Z")),
+						Tags: []*ec2.Tag{
+							{
+								Key:   aws.String("aws-managed"),
+								Value: aws.String("true"),
+							},
+						},
+					},
+					{
+						ImageId:      &testImageId2,
+						Name:         aws.String("AwsBackup_Test"),
+						CreationDate: awsgo.String(now.Format("2006-01-02T15:04:05.000Z")),
+						Tags: []*ec2.Tag{
+							{
+								Key:   aws.String("aws-managed"),
+								Value: aws.String("true"),
+							},
+						},
+					},
+				},
+			},
+		},
+	}
+
+	amis, err := acm.getAll(config.Config{})
+	assert.NoError(t, err)
+	assert.NotContains(t, awsgo.StringValueSlice(amis), testImageId1)
+	assert.NotContains(t, awsgo.StringValueSlice(amis), testImageId2)
+}
+
 func TestAMIGetAll(t *testing.T) {
 	telemetry.InitTelemetry("cloud-nuke", "")
 	t.Parallel()