Skip to content

Commit

Permalink
Allow service role for cloudforamtion, update msk, nf, waf, appstream (
Browse files Browse the repository at this point in the history
…#31)

Co-authored-by: bfisher8 <[email protected]>
  • Loading branch information
bjfish25 and bfisher8 authored Aug 8, 2024
1 parent de2d633 commit 38f8749
Show file tree
Hide file tree
Showing 10 changed files with 217 additions and 89 deletions.
5 changes: 5 additions & 0 deletions cmd/nuke.go
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,11 @@ func (n *Nuke) Scan() error {
ffGetter.FeatureFlags(n.Config.FeatureFlags)
}

settingsGetter, ok := item.Resource.(resources.SettingsGetter)
if ok {
settingsGetter.Settings(n.Config.Settings)
}

queue = append(queue, item)
err := n.Filter(item)
if err != nil {
Expand Down
11 changes: 7 additions & 4 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,14 @@ go 1.21

require (
github.com/aws/aws-sdk-go v1.53.15
github.com/aws/aws-sdk-go-v2 v1.30.0
github.com/aws/aws-sdk-go-v2 v1.30.3
github.com/aws/aws-sdk-go-v2/config v1.27.22
github.com/aws/aws-sdk-go-v2/credentials v1.17.22
github.com/aws/aws-sdk-go-v2/service/appstream v1.37.0
github.com/aws/aws-sdk-go-v2/service/kafka v1.35.3
github.com/aws/aws-sdk-go-v2/service/networkfirewall v1.40.0
github.com/aws/aws-sdk-go-v2/service/sts v1.30.0
github.com/aws/aws-sdk-go-v2/service/wafregional v1.23.3
github.com/fatih/color v1.17.0
github.com/golang/mock v1.6.0
github.com/google/uuid v1.6.0
Expand All @@ -24,14 +27,14 @@ require (

require (
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.8 // indirect
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.12 // indirect
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.12 // indirect
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.15 // indirect
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.15 // indirect
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.2 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.14 // indirect
github.com/aws/aws-sdk-go-v2/service/sso v1.22.0 // indirect
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.26.0 // indirect
github.com/aws/smithy-go v1.20.2 // indirect
github.com/aws/smithy-go v1.20.3 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/gemnasium/logrus-graylog-hook/v3 v3.1.0 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
Expand Down
22 changes: 14 additions & 8 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,23 +1,27 @@
github.com/aws/aws-sdk-go v1.53.15 h1:FtZmkg7xM8RfP2oY6p7xdKBYrRgkITk9yve2QV7N938=
github.com/aws/aws-sdk-go v1.53.15/go.mod h1:LF8svs817+Nz+DmiMQKTO3ubZ/6IaTpq3TjupRn3Eqk=
github.com/aws/aws-sdk-go-v2 v1.30.0 h1:6qAwtzlfcTtcL8NHtbDQAqgM5s6NDipQTkPxyH/6kAA=
github.com/aws/aws-sdk-go-v2 v1.30.0/go.mod h1:ffIFB97e2yNsv4aTSGkqtHnppsIJzw7G7BReUZ3jCXM=
github.com/aws/aws-sdk-go-v2 v1.30.3 h1:jUeBtG0Ih+ZIFH0F4UkmL9w3cSpaMv9tYYDbzILP8dY=
github.com/aws/aws-sdk-go-v2 v1.30.3/go.mod h1:nIQjQVp5sfpQcTc9mPSr1B0PaWK5ByX9MOoDadSN4lc=
github.com/aws/aws-sdk-go-v2/config v1.27.22 h1:TRkQVtpDINt+Na/ToU7iptyW6U0awAwJ24q4XN+59k8=
github.com/aws/aws-sdk-go-v2/config v1.27.22/go.mod h1:EYY3mVgFRUWkh6QNKH64MdyKs1YSUgatc0Zp3MDxi7c=
github.com/aws/aws-sdk-go-v2/credentials v1.17.22 h1:wu9kXQbbt64ul09v3ye4HYleAr4WiGV/uv69EXKDEr0=
github.com/aws/aws-sdk-go-v2/credentials v1.17.22/go.mod h1:pcvMtPcxJn3r2k6mZD9I0EcumLqPLA7V/0iCgOIlY+o=
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.8 h1:FR+oWPFb/8qMVYMWN98bUZAGqPvLHiyqg1wqQGfUAXY=
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.8/go.mod h1:EgSKcHiuuakEIxJcKGzVNWh5srVAQ3jKaSrBGRYvM48=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.12 h1:SJ04WXGTwnHlWIODtC5kJzKbeuHt+OUNOgKg7nfnUGw=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.12/go.mod h1:FkpvXhA92gb3GE9LD6Og0pHHycTxW7xGpnEh5E7Opwo=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.12 h1:hb5KgeYfObi5MHkSSZMEudnIvX30iB+E21evI4r6BnQ=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.12/go.mod h1:CroKe/eWJdyfy9Vx4rljP5wTUjNJfb+fPz1uMYUhEGM=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.15 h1:SoNJ4RlFEQEbtDcCEt+QG56MY4fm4W8rYirAmq+/DdU=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.15/go.mod h1:U9ke74k1n2bf+RIgoX1SXFed1HLs51OgUSs+Ph0KJP8=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.15 h1:C6WHdGnTDIYETAm5iErQUiVNsclNx9qbJVPIt03B6bI=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.15/go.mod h1:ZQLZqhcu+JhSrA9/NXRm8SkDvsycE+JkV3WGY41e+IM=
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0 h1:hT8rVHwugYE2lEfdFE0QWVo81lF7jMrYJVDWI+f+VxU=
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0/go.mod h1:8tu/lYfQfFe6IGnaOdrpVgEL2IrrDOf6/m9RQum4NkY=
github.com/aws/aws-sdk-go-v2/service/appstream v1.37.0 h1:novlmw4mzemK9FHfneoni0pG0eCPISgeW72apbWSxdY=
github.com/aws/aws-sdk-go-v2/service/appstream v1.37.0/go.mod h1:zgB9SASIAI0KWFuUSlo9pGC37f6DDjh1ZJfZEhQcPhU=
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.2 h1:Ji0DY1xUsUr3I8cHps0G+XM3WWU16lP6yG8qu1GAZAs=
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.2/go.mod h1:5CsjAbs3NlGQyZNFACh+zztPDI7fU6eW9QsxjfnuBKg=
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.14 h1:zSDPny/pVnkqABXYRicYuPf9z2bTqfH13HT3v6UheIk=
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.14/go.mod h1:3TTcI5JSzda1nw/pkVC9dhgLre0SNBFj2lYS4GctXKI=
github.com/aws/aws-sdk-go-v2/service/kafka v1.35.3 h1:MUx27PrqicGxgsiDWo7xv/Zsl4b0X8kHCRvMpX7XrQs=
github.com/aws/aws-sdk-go-v2/service/kafka v1.35.3/go.mod h1:mBWO7tOHjEvfZ88cUBhCfViO9vclCumFcTeiR1cB4IA=
github.com/aws/aws-sdk-go-v2/service/networkfirewall v1.40.0 h1:ZKjJJWxZ4cGM6LWxXsnviGlBpqPvifSod4U8gOXik9U=
github.com/aws/aws-sdk-go-v2/service/networkfirewall v1.40.0/go.mod h1:23qyfghRkv9qOMRIL9KdUHiKyhARU/0FddRMtvMSVV0=
github.com/aws/aws-sdk-go-v2/service/sso v1.22.0 h1:lPIAPCRoJkmotLTU/9B6icUFlYDpEuWjKeL79XROv1M=
Expand All @@ -26,8 +30,10 @@ github.com/aws/aws-sdk-go-v2/service/ssooidc v1.26.0 h1:/4r71ghx+hX9spr884cqXHPE
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.26.0/go.mod h1:z0P8K+cBIsFXUr5rzo/psUeJ20XjPN0+Nn8067Nd+E4=
github.com/aws/aws-sdk-go-v2/service/sts v1.30.0 h1:9ja34PaKybhCJjVKvxtDsUjbATUJGN+eF6QnO58u5cI=
github.com/aws/aws-sdk-go-v2/service/sts v1.30.0/go.mod h1:N2mQiucsO0VwK9CYuS4/c2n6Smeh1v47Rz3dWCPFLdE=
github.com/aws/smithy-go v1.20.2 h1:tbp628ireGtzcHDDmLT/6ADHidqnwgF57XOXZe6tp4Q=
github.com/aws/smithy-go v1.20.2/go.mod h1:krry+ya/rV9RDcV/Q16kpu6ypI4K2czasz0NC3qS14E=
github.com/aws/aws-sdk-go-v2/service/wafregional v1.23.3 h1:7dr6En0/6KRFoz8VmnYks9dVvL+tkL5RjRrxqGzr1zI=
github.com/aws/aws-sdk-go-v2/service/wafregional v1.23.3/go.mod h1:24TtlRsv4LKAE3VnRJQhpatr8cpX0yj8NSzg8/lxOCw=
github.com/aws/smithy-go v1.20.3 h1:ryHwveWzPV5BIof6fyDvor6V3iUL7nTfiTKXHiW05nE=
github.com/aws/smithy-go v1.20.3/go.mod h1:krry+ya/rV9RDcV/Q16kpu6ypI4K2czasz0NC3qS14E=
github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
Expand Down
16 changes: 15 additions & 1 deletion pkg/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ type Nuke struct {
ResourceTypes ResourceTypes `yaml:"resource-types"`
Presets map[string]PresetDefinitions `yaml:"presets"`
FeatureFlags FeatureFlags `yaml:"feature-flags"`
Settings Settings `yaml:"settings"`
CustomEndpoints CustomEndpoints `yaml:"endpoints"`
}

Expand All @@ -43,10 +44,23 @@ type FeatureFlags struct {
DisableFailOnKMSError bool `yaml:"disable-fail-on-kms-error"`
}

type Settings struct {
CloudFormationStack CloudFormationStackSettings `yaml:"CloudFormationStack"`
}

type ResourceSettings struct {
DisableDeletionProtection bool `yaml:"DisableDeletionProtection"`
}

type CloudFormationStackSettings struct {
ResourceSettings `yaml:",inline"`
ServiceRoleArn string `yaml:"ServiceRoleArn"`
}

type DisableDeletionProtection struct {
RDSInstance bool `yaml:"RDSInstance"`
EC2Instance bool `yaml:"EC2Instance"`
CloudformationStack bool `yaml:"CloudformationStack"`
CloudFormationStack bool `yaml:"CloudFormationStack"`
ELBv2 bool `yaml:"ELBv2"`
QLDBLedger bool `yaml:"QLDBLedger"`
DynamoDBTable bool `yaml:"DynamoDBTable"`
Expand Down
105 changes: 85 additions & 20 deletions resources/appstream-images.go
Original file line number Diff line number Diff line change
@@ -1,50 +1,99 @@
package resources

import (
"context"
"fmt"
"strings"

"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/service/appstream"
"github.com/aws/aws-sdk-go-v2/aws"
"github.com/rebuy-de/aws-nuke/v2/pkg/types"

"github.com/aws/aws-sdk-go-v2/service/appstream"
)

type AppStreamImage struct {
svc *appstream.AppStream
svc *appstream.Client
context context.Context

name *string
visibility *string
visibility string

sharedAccounts []*string
}

func init() {
register("AppStreamImage", ListAppStreamImages)
registerV2("AppStreamImage", ListAppStreamImages)
}

func ListAppStreamImages(sess *session.Session) ([]Resource, error) {
svc := appstream.New(sess)
func ListAppStreamImages(cfg *aws.Config) ([]Resource, error) {
svc := appstream.NewFromConfig(*cfg)
ctx := context.TODO()

resources := []Resource{}
var nextToken *string

params := &appstream.DescribeImagesInput{}
for ok := true; ok; ok = (nextToken != nil) {
params := &appstream.DescribeImagesInput{
NextToken: nextToken,
}

output, err := svc.DescribeImages(params)
if err != nil {
return nil, err
}
output, err := svc.DescribeImages(ctx, params)
if err != nil {
return nil, err
}
nextToken = output.NextToken

for _, image := range output.Images {
sharedAccounts := []*string{}
visibility := string(image.Visibility)

// Filter out public images
if strings.ToUpper(visibility) != "PUBLIC" {
imagePerms, err := svc.DescribeImagePermissions(ctx, &appstream.DescribeImagePermissionsInput{
Name: image.Name,
})

if err != nil {
return nil, err
}

for _, permission := range imagePerms.SharedImagePermissionsList {
sharedAccounts = append(sharedAccounts, permission.SharedAccountId)
}

resources = append(resources, &AppStreamImage{
svc: svc,
context: ctx,
name: image.Name,
visibility: visibility,
sharedAccounts: sharedAccounts,
})
}
}

for _, image := range output.Images {
resources = append(resources, &AppStreamImage{
svc: svc,
name: image.Name,
visibility: image.Visibility,
})
}

return resources, nil
}

func (f *AppStreamImage) Remove() error {
for _, account := range f.sharedAccounts {
_, err := f.svc.DeleteImagePermissions(f.context, &appstream.DeleteImagePermissionsInput{
Name: f.name,
SharedAccountId: account,
})
if err != nil {
fmt.Println("Error deleting image permissions", err)
return err
}
}

_, err := f.svc.DeleteImage(&appstream.DeleteImageInput{
_, err := f.svc.DeleteImage(f.context, &appstream.DeleteImageInput{
Name: f.name,
})
if err != nil {
fmt.Println("Error deleting image", err)
}

return err
}
Expand All @@ -54,8 +103,24 @@ func (f *AppStreamImage) String() string {
}

func (f *AppStreamImage) Filter() error {
if strings.ToUpper(*f.visibility) == "PUBLIC" {
if strings.ToUpper(f.visibility) == "PUBLIC" {
return fmt.Errorf("cannot delete public AWS images")
}
return nil
}

func (f *AppStreamImage) Properties() types.Properties {
properties := types.NewProperties()

properties.Set("Name", f.name)

sharedAccounts := make([]string, len(f.sharedAccounts))
for i, account := range f.sharedAccounts {
sharedAccounts[i] = *account
}
if len(sharedAccounts) > 0 {
properties.Set("Accounts with shared image", strings.Join(sharedAccounts, ", "))
}

return properties
}
26 changes: 21 additions & 5 deletions resources/cloudformation-stack.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package resources

import (
"errors"
"fmt"
"strings"
"time"

Expand Down Expand Up @@ -57,11 +58,15 @@ type CloudFormationStack struct {
svc cloudformationiface.CloudFormationAPI
stack *cloudformation.Stack
maxDeleteAttempts int
featureFlags config.FeatureFlags
settings config.Settings
}

func (cfs *CloudFormationStack) FeatureFlags(ff config.FeatureFlags) {
cfs.featureFlags = ff
func (cfs *CloudFormationStack) Settings(settings config.Settings) {
cfs.settings = settings

if cfs.settings.CloudFormationStack.ServiceRoleArn != "" {
fmt.Printf("ServiceRoleArn: %s\n", cfs.settings.CloudFormationStack.ServiceRoleArn)
}
}

func (cfs *CloudFormationStack) Remove() error {
Expand All @@ -74,7 +79,7 @@ func (cfs *CloudFormationStack) removeWithAttempts(attempt int) error {
awsErr, ok := err.(awserr.Error)
if ok && awsErr.Code() == "ValidationError" &&
awsErr.Message() == "Stack ["+*cfs.stack.StackName+"] cannot be deleted while TerminationProtection is enabled" {
if cfs.featureFlags.DisableDeletionProtection.CloudformationStack {
if cfs.settings.CloudFormationStack.DisableDeletionProtection {
logrus.Infof("CloudFormationStack stackName=%s attempt=%d maxAttempts=%d updating termination protection", *cfs.stack.StackName, attempt, cfs.maxDeleteAttempts)
_, err = cfs.svc.UpdateTerminationProtection(&cloudformation.UpdateTerminationProtectionInput{
EnableTerminationProtection: aws.Bool(false),
Expand All @@ -89,7 +94,7 @@ func (cfs *CloudFormationStack) removeWithAttempts(attempt int) error {
}
}
if attempt >= cfs.maxDeleteAttempts {
return errors.New("CFS might not be deleted after this run.")
return errors.New("CFS might not be deleted after this run")
} else {
return cfs.removeWithAttempts(attempt + 1)
}
Expand Down Expand Up @@ -140,9 +145,14 @@ func (cfs *CloudFormationStack) doRemove() error {
}
}

var roleArn *string
if cfs.settings.CloudFormationStack.ServiceRoleArn != "" {
roleArn = aws.String(cfs.settings.CloudFormationStack.ServiceRoleArn)
}
_, err = cfs.svc.DeleteStack(&cloudformation.DeleteStackInput{
StackName: cfs.stack.StackName,
RetainResources: retain,
RoleARN: roleArn,
})
if err != nil {
return err
Expand All @@ -151,10 +161,16 @@ func (cfs *CloudFormationStack) doRemove() error {
StackName: cfs.stack.StackName,
})
} else {
var roleArn *string
if cfs.settings.CloudFormationStack.ServiceRoleArn != "" {
roleArn = aws.String(cfs.settings.CloudFormationStack.ServiceRoleArn)
}

if err := cfs.waitForStackToStabilize(*stack.StackStatus); err != nil {
return err
} else if _, err := cfs.svc.DeleteStack(&cloudformation.DeleteStackInput{
StackName: cfs.stack.StackName,
RoleARN: roleArn,
}); err != nil {
return err
} else if err := cfs.svc.WaitUntilStackDeleteComplete(&cloudformation.DescribeStacksInput{
Expand Down
5 changes: 5 additions & 0 deletions resources/interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,11 @@ type FeatureFlagGetter interface {
FeatureFlags(config.FeatureFlags)
}

type SettingsGetter interface {
Resource
Settings(config.Settings)
}

var resourceListers = make(ResourceListers)
var resourceListersV2 = make(ResourceListersV2)

Expand Down
Loading

0 comments on commit 38f8749

Please sign in to comment.