Skip to content

Commit

Permalink
Merge pull request #74 from rebuy-de/improve-filters
Browse files Browse the repository at this point in the history
 Add resource filters to config
  • Loading branch information
svenwltr committed Feb 9, 2018
2 parents 9779273 + 88419ca commit 44434a3
Show file tree
Hide file tree
Showing 13 changed files with 331 additions and 37 deletions.
61 changes: 61 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,67 @@ for debugging, if the error is not about dependencies.
*aws-nuke* retries deleting all resources until all specified ones are deleted
or until there are only resources with errors left.

### Specifying Resource Types to Delete

*aws-nuke* deletes a lot of resources and there might be added more at any
release. Eventually, every resources should get deleted. You might want to
restrict which resources to delete. There are multiple ways to configure this.

One way are filters, which already got mentioned. This requires to know the
identifier of each resource. It is also possible to prevent whole resource
types (eg `S3Bucket`) from getting deleted with two methods.

* The `--target` flag limits nuking to the specified resource types.
* The `--exclude` flag prevent nuking of the specified resource types.

It is also possible to configure the resource types in the config file like in
these examples:

```
---
regions:
- "eu-west-1"
account-blacklist:
- 1234567890
resource-types:
# only nuke these three resources
targets:
- S3Object
- S3Bucket
- IAMRole
accounts:
555133742: {}
```

```
---
regions:
- "eu-west-1"
account-blacklist:
- 1234567890
resource-types:
# don't nuke IAM users
exclude:
- IAMUser
accounts:
555133742: {}
```

If targets are specified in multiple places (eg CLI and account specific), then
a resource type must be specified in all places. In other words each
configuration limits the previous ones.

If an exclude is used, then all its resource types will not be deleted.

**Hint:** You can see all available resource types with this command:

```
aws-nuke resource-types
```

## Install

Expand Down
11 changes: 10 additions & 1 deletion cmd/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,26 @@ import (
"io/ioutil"
"strings"

"github.com/rebuy-de/aws-nuke/pkg/types"

"gopkg.in/yaml.v2"
)

type ResourceConfig struct {
Targets types.Collection `yaml:"targets"`
Excludes types.Collection `yaml:"excludes"`
}

type NukeConfig struct {
AccountBlacklist []string `yaml:"account-blacklist"`
Regions []string `yaml:"regions"`
Accounts map[string]NukeConfigAccount `yaml:"accounts"`
ResourceTypes ResourceConfig `yaml:"resource-types"`
}

type NukeConfigAccount struct {
Filters map[string][]string `yaml:"filters"`
Filters map[string][]string `yaml:"filters"`
ResourceTypes ResourceConfig `yaml:"resource-types"`
}

func LoadConfig(path string) (*NukeConfig, error) {
Expand Down
25 changes: 20 additions & 5 deletions cmd/nuke.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"time"

"github.com/rebuy-de/aws-nuke/pkg/awsutil"
"github.com/rebuy-de/aws-nuke/pkg/types"
"github.com/rebuy-de/aws-nuke/resources"
)

Expand All @@ -13,6 +14,8 @@ type Nuke struct {
Account awsutil.Account
Config *NukeConfig

ResourceTypes types.Collection

ForceSleep time.Duration

items Queue
Expand Down Expand Up @@ -106,6 +109,22 @@ func (n *Nuke) Run() error {
}

func (n *Nuke) Scan() error {
accountConfig := n.Config.Accounts[n.Account.ID()]

resourceTypes := ResolveResourceTypes(
resources.GetListerNames(),
[]types.Collection{
n.Parameters.Targets,
n.Config.ResourceTypes.Targets,
accountConfig.ResourceTypes.Targets,
},
[]types.Collection{
n.Parameters.Excludes,
n.Config.ResourceTypes.Excludes,
accountConfig.ResourceTypes.Excludes,
},
)

queue := make(Queue, 0)

for _, regionName := range n.Config.Regions {
Expand All @@ -119,12 +138,8 @@ func (n *Nuke) Scan() error {
Session: sess,
}

items := Scan(region)
items := Scan(region, resourceTypes)
for item := range items {
if !n.Parameters.WantsTarget(item.Type) {
continue
}

queue = append(queue, item)
n.Filter(item)
item.Print()
Expand Down
17 changes: 2 additions & 15 deletions cmd/params.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ import (
type NukeParameters struct {
ConfigPath string

Targets []string
Targets []string
Excludes []string

NoDryRun bool
Force bool
Expand All @@ -21,17 +22,3 @@ func (p *NukeParameters) Validate() error {

return nil
}

func (p *NukeParameters) WantsTarget(name string) bool {
if p.Targets == nil || len(p.Targets) < 1 {
return true
}

for _, wants := range p.Targets {
if wants == name {
return true
}
}

return false
}
37 changes: 23 additions & 14 deletions cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,25 +53,38 @@ func NewRootCommand() *cobra.Command {

command.PersistentFlags().StringVarP(
&params.ConfigPath, "config", "c", "",
"path to config (required)")
"(required) Path to the nuke config file.")
command.PersistentFlags().StringVar(
&creds.Profile, "profile", "",
"profile name to nuke")
"Name of the AWS profile name for accessing the AWS API. "+
"Cannot be used together with --access-key-id and --secret-access-key.")
command.PersistentFlags().StringVar(
&creds.AccessKeyID, "access-key-id", "",
"AWS access-key-id")
"AWS access key ID for accessing the AWS API. "+
"Must be used together with --secret-access-key."+
"Cannot be used together with --profile.")
command.PersistentFlags().StringVar(
&creds.SecretAccessKey, "secret-access-key", "",
"AWS secret-access-key")
"AWS secret access key for accessing the AWS API. "+
"Must be used together with --access-key-id."+
"Cannot be used together with --profile.")

command.PersistentFlags().StringSliceVarP(
&params.Targets, "target", "t", []string{},
"limit nuking to certain resource types (eg IAMServerCertificate)")
"Limit nuking to certain resource types (eg IAMServerCertificate). "+
"This flag can be used multiple times.")
command.PersistentFlags().StringSliceVarP(
&params.Excludes, "exclude", "e", []string{},
"Prevent nuking of certain resource types (eg IAMServerCertificate). "+
"This flag can be used multiple times.")
command.PersistentFlags().BoolVar(
&params.NoDryRun, "no-dry-run", false,
"actually delete found resources")
"If specified, it actually deletes found resources. "+
"Otherwise it just lists all candidates.")
command.PersistentFlags().BoolVar(
&params.Force, "force", false,
"don't ask for confirmation")
"Don't ask for confirmation before deleting resources. "+
"Instead it waits 15s before continuing.")

command.AddCommand(NewVersionCommand())
command.AddCommand(NewResourceTypesCommand())
Expand All @@ -84,14 +97,10 @@ func NewResourceTypesCommand() *cobra.Command {
Use: "resource-types",
Short: "lists all available resource types",
Run: func(cmd *cobra.Command, args []string) {
types := []string{}
for resourceType, _ := range resources.GetListers() {
types = append(types, resourceType)
}

sort.Strings(types)
names := resources.GetListerNames()
sort.Strings(names)

for _, resourceType := range types {
for _, resourceType := range names {
fmt.Println(resourceType)
}
},
Expand Down
5 changes: 3 additions & 2 deletions cmd/scan.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,12 @@ import (
"github.com/rebuy-de/aws-nuke/resources"
)

func Scan(region Region) <-chan *Item {
func Scan(region Region, resourceTypes []string) <-chan *Item {
items := make(chan *Item, 100)

go func() {
for resourceType, lister := range resources.GetListers() {
for _, resourceType := range resourceTypes {
lister := resources.GetLister(resourceType)
rs, err := safeLister(region.Session, lister)
if err != nil {
LogErrorf(fmt.Errorf("\n=============\n\n"+
Expand Down
10 changes: 10 additions & 0 deletions cmd/test-fixtures/example.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,18 @@ regions:
account-blacklist:
- 1234567890

resource-types:
target:
- S3Object
- S3Bucket
exclude:
- IAMRole

accounts:
555133742:
resource-types:
target:
- S3Bucket
filters:
IAMRole:
- "uber.admin"
Expand Down
16 changes: 16 additions & 0 deletions cmd/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import (
"fmt"
"os"
"strings"

"github.com/rebuy-de/aws-nuke/pkg/types"
)

func Prompt(expect string) error {
Expand All @@ -22,3 +24,17 @@ func Prompt(expect string) error {

return nil
}

func ResolveResourceTypes(base types.Collection, include, exclude []types.Collection) types.Collection {
for _, i := range include {
if len(i) > 0 {
base = base.Intersect(i)
}
}

for _, e := range exclude {
base = base.Remove(e)
}

return base
}
63 changes: 63 additions & 0 deletions cmd/util_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package cmd

import (
"fmt"
"sort"
"testing"

"github.com/rebuy-de/aws-nuke/pkg/types"
)

func TestResolveResourceTypes(t *testing.T) {
cases := []struct {
base types.Collection
include []types.Collection
exclude []types.Collection
result types.Collection
}{
{
base: types.Collection{"a", "b", "c", "d"},
include: []types.Collection{types.Collection{"a", "b", "c"}},
result: types.Collection{"a", "b", "c"},
},
{
base: types.Collection{"a", "b", "c", "d"},
exclude: []types.Collection{types.Collection{"b", "d"}},
result: types.Collection{"a", "c"},
},
{
base: types.Collection{"a", "b"},
include: []types.Collection{types.Collection{}},
result: types.Collection{"a", "b"},
},
{
base: types.Collection{"c", "b"},
exclude: []types.Collection{types.Collection{}},
result: types.Collection{"c", "b"},
},
{
base: types.Collection{"a", "b", "c", "d"},
include: []types.Collection{types.Collection{"a", "b", "c"}},
exclude: []types.Collection{types.Collection{"a"}},
result: types.Collection{"b", "c"},
},
}

for i, tc := range cases {
t.Run(fmt.Sprint(i), func(t *testing.T) {
r := ResolveResourceTypes(tc.base, tc.include, tc.exclude)

sort.Strings(r)
sort.Strings(tc.result)

var (
want = fmt.Sprint(tc.result)
have = fmt.Sprint(r)
)

if want != have {
t.Fatalf("Wrong result. Want: %s. Have: %s", want, have)
}
})
}
}
10 changes: 10 additions & 0 deletions config/example.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,18 @@ regions:
account-blacklist:
- 1234567890

resource-types:
targets:
- S3Object
- S3Bucket
excludes:
- IAMRole

accounts:
555133742:
resource-types:
targets:
- S3Bucket
filters:
IAMRole:
- "uber.admin"
Expand Down
Loading

0 comments on commit 44434a3

Please sign in to comment.