├── .dockerignore ├── .github ├── FUNDING.yml ├── workflows │ ├── commit-lint.yaml │ ├── semantic-lint.yml │ ├── golangci-lint.yml │ ├── tests.yml │ ├── semantic.yml │ ├── aws-sdk-mocks.yml │ └── docs.yaml └── renovate.json ├── pkg ├── config │ ├── testdata │ │ ├── invalid.yaml │ │ ├── deprecated-keys-config.yaml │ │ ├── deprecated-feature-flags.yaml │ │ ├── bypass-alias.yaml │ │ ├── incomplete.yaml │ │ └── example.yaml │ └── testsuite_test.go ├── awsutil │ ├── errors.go │ ├── consts.go │ ├── util_test.go │ └── util.go ├── common │ ├── commands.go │ └── version.go ├── testsuite │ └── logrus.go ├── nuke │ ├── prompt.go │ └── resource.go └── commands │ ├── list │ └── list.go │ └── global │ └── global.go ├── resources ├── comprehend.go ├── ecs-mock_test.go ├── dynamodb_mock_test.go ├── elasticache-mock_test.go ├── iam_mock_test.go ├── kms_mock_test.go ├── sqs_mock_test.go ├── glue_mock_test.go ├── budgets_mock_test.go ├── sagemaker_mock_test.go ├── autoscaling_mock_test.go ├── cloudformation_mock_test.go ├── secretsmanager_mock_test.go ├── servicediscovery_mock_test.go ├── route53_mock_test.go ├── amplify-app_mock_test.go ├── iam-groups_mock_test.go ├── iam-server-certificate_mock_test.go ├── iam-saml-provider_mock_test.go ├── iam-user-policy_mock_test.go ├── iam-group-policies_mock_test.go ├── iam-user-ssh-keys_mock_test.go ├── iam-open-id-connect-provider_mock_test.go ├── iam-user-group-attachments_mock_test.go ├── iam-user-access-key_mock_test.go ├── iam-role-policy_mock_test.go ├── iam-user-policy-attachment_mock_test.go ├── iam-group-policy-attachments_mock_test.go ├── iam-role-policy-attachments_mock_test.go ├── iam-signing-certificate_mock_test.go ├── cloudcontrol_test.go ├── iam-service-specific-credentials_mock_test.go ├── iam-user_test.go ├── macie2.go ├── opsworkscm-backups.go ├── cloudsearch-domains.go ├── inspector-assessment-runs.go ├── glue-jobs.go ├── iot-streams.go ├── appstream-stacks.go ├── mq-broker.go ├── inspector-assessment-targets.go ├── kms-key_test.go ├── lightsail-disks.go ├── cloudtrail-trails.go ├── glue-crawlers.go ├── glue-triggers.go ├── iot-jobs.go ├── iot-topicrules.go ├── devicefarm-projects.go ├── inspector-assessment-templates.go ├── iot-otaupdates.go ├── glue-databases.go ├── inspector2.go ├── iot-thingtypes.go ├── ses-identities.go ├── ses-templates.go ├── iot-rolealiases.go ├── medialive-inputs.go ├── cloudwatchevents-buses.go ├── opsworks-apps.go ├── securityhub-hub.go ├── lightsail-keypairs.go ├── ssm-activations.go ├── codestar-projects.go ├── batch-job-queues.go ├── gluedatabrew-jobs.go ├── medialive-channels.go ├── sagemaker-models.go ├── elasticbeanstalk-applications.go ├── iam-server-certificate.go ├── iot-authorizers.go ├── lightsail-staticips.go ├── sfn-statemachines.go ├── opsworks-layers.go ├── opsworkscm-serverstates.go ├── datapipeline-pipelines.go ├── simpledb-domains.go ├── sqs-queues_mock_test.go ├── codepipeline-pipelines.go ├── appstream-fleets.go ├── iot-cacertificates.go ├── mediaconvert-presets.go ├── codebuild-report.go ├── ecs-taskdefinitions.go ├── glue-connections.go ├── mediapackage-channels.go ├── mobile-projects.go ├── neptune-clusters.go ├── waf-webacls.go ├── resource-explorer2-views.go ├── cloudhsmv2-cluster.go ├── ec2-volume.go ├── gluedatabrew-datasets.go ├── gluedatabrew-projects.go ├── gluedatabrew-rulesets.go ├── mediastore-containers.go ├── neptune-instances.go ├── storagegateway-volumes.go ├── cloud9-environments.go ├── cloudwatch-dashboards.go ├── codedeploy-applications.go ├── opsworks-instances.go ├── sagemaker-endpoints.go ├── ses-configurationsets.go ├── storagegateway-gateways.go ├── apigateway-apikeys.go ├── apigateway-domainnames.go ├── ec2-key-pair.go ├── gluedatabrew-schedules.go ├── guardduty.go ├── lightsail-loadbalancers.go ├── resource-explorer2-indexes.go └── ssm-maintenancewindows.go ├── .gitignore ├── cosign.pub ├── docs ├── features │ ├── signed-binaries.md │ ├── global-filters.md │ ├── enabled-regions.md │ ├── bypass-alias-check.md │ └── overview.md ├── standards.md ├── development.md ├── releases.md ├── cli-examples.md ├── installation.md ├── migration-guide.md ├── config-presets.md ├── cli-options.md ├── config-migration.md ├── resources │ └── s3-bucket.md └── cli-experimental.md ├── .codeclimate.yml ├── .releaserc.yml ├── mocks └── generate_mocks.sh ├── Makefile ├── Dockerfile ├── LICENSE ├── main.go ├── go.mod └── .golangci.yaml /.dockerignore: -------------------------------------------------------------------------------- 1 | dist 2 | vendor 3 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: ekristen 2 | -------------------------------------------------------------------------------- /pkg/config/testdata/invalid.yaml: -------------------------------------------------------------------------------- 1 | this is 2 | not a 3 | valid 4 | yaml file -------------------------------------------------------------------------------- /resources/comprehend.go: -------------------------------------------------------------------------------- 1 | package resources 2 | 3 | const ComprehendUnnamedJob = "Unnamed Job" 4 | -------------------------------------------------------------------------------- /pkg/config/testdata/deprecated-keys-config.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | account-blocklist: 3 | - 1234567890 4 | -------------------------------------------------------------------------------- /resources/ecs-mock_test.go: -------------------------------------------------------------------------------- 1 | //go:generate ../mocks/generate_mocks.sh ecs ecsiface 2 | package resources 3 | -------------------------------------------------------------------------------- /resources/dynamodb_mock_test.go: -------------------------------------------------------------------------------- 1 | //go:generate ../mocks/generate_mocks.sh dynamodb dynamodbiface 2 | package resources 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | releases 2 | .envrc 3 | .idea 4 | cosign.key 5 | /config*.yaml 6 | /*-config.yaml 7 | /config.*.yaml 8 | *.p12 9 | *.p8 -------------------------------------------------------------------------------- /resources/elasticache-mock_test.go: -------------------------------------------------------------------------------- 1 | //go:generate ../mocks/generate_mocks.sh elasticache elasticacheiface 2 | package resources 3 | -------------------------------------------------------------------------------- /pkg/awsutil/errors.go: -------------------------------------------------------------------------------- 1 | package awsutil 2 | 3 | const ErrCodeInvalidAction = "InvalidAction" 4 | const ErrCodeOperationNotPermitted = "OperationNotPermitted" 5 | -------------------------------------------------------------------------------- /resources/iam_mock_test.go: -------------------------------------------------------------------------------- 1 | //go:generate ../mocks/generate_mocks.sh iam iamiface 2 | package resources 3 | 4 | // Note: empty on purpose, this file exist purely to generate mocks for the IAM service 5 | -------------------------------------------------------------------------------- /resources/kms_mock_test.go: -------------------------------------------------------------------------------- 1 | //go:generate ../mocks/generate_mocks.sh kms kmsiface 2 | package resources 3 | 4 | // Note: empty on purpose, this file exist purely to generate mocks for the KMS service 5 | -------------------------------------------------------------------------------- /resources/sqs_mock_test.go: -------------------------------------------------------------------------------- 1 | //go:generate ../mocks/generate_mocks.sh sqs sqsiface 2 | package resources 3 | 4 | // Note: empty on purpose, this file exist purely to generate mocks for the IAM service 5 | -------------------------------------------------------------------------------- /cosign.pub: -------------------------------------------------------------------------------- 1 | -----BEGIN PUBLIC KEY----- 2 | MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEzwDt3+veru3N3fCnc0kYxm4mnCO4 3 | 464OTkXk2z+PjI11g5ZRv7UrORXcZ20mmuGUN3/aVfexq+aGb5Bi+uHrPw== 4 | -----END PUBLIC KEY----- 5 | -------------------------------------------------------------------------------- /resources/glue_mock_test.go: -------------------------------------------------------------------------------- 1 | //go:generate ../mocks/generate_mocks.sh glue glueiface 2 | package resources 3 | 4 | // Note: empty on purpose, this file exist purely to generate mocks for the glue service 5 | -------------------------------------------------------------------------------- /resources/budgets_mock_test.go: -------------------------------------------------------------------------------- 1 | //go:generate ../mocks/generate_mocks.sh budgets budgetsiface 2 | package resources 3 | 4 | // Note: empty on purpose, this file exist purely to generate mocks for the IAM service 5 | -------------------------------------------------------------------------------- /resources/sagemaker_mock_test.go: -------------------------------------------------------------------------------- 1 | //go:generate ../mocks/generate_mocks.sh sagemaker sagemakeriface 2 | package resources 3 | 4 | // Note: empty on purpose, this file exist purely to generate mocks for the SageMaker service 5 | -------------------------------------------------------------------------------- /docs/features/signed-binaries.md: -------------------------------------------------------------------------------- 1 | # Signed Binaries 2 | 3 | All darwin binaries are now signed and notarized by Apple. This means that you can now run the binaries without 4 | needing to bypass the security settings on your Mac. 5 | -------------------------------------------------------------------------------- /resources/autoscaling_mock_test.go: -------------------------------------------------------------------------------- 1 | //go:generate ../mocks/generate_mocks.sh autoscaling autoscalingiface 2 | package resources 3 | 4 | // Note: empty on purpose, this file exist purely to generate mocks for the AutoScaling service 5 | -------------------------------------------------------------------------------- /resources/cloudformation_mock_test.go: -------------------------------------------------------------------------------- 1 | //go:generate ../mocks/generate_mocks.sh cloudformation cloudformationiface 2 | package resources 3 | 4 | // Note: empty on purpose, this file exist purely to generate mocks for the CloudFormation service 5 | -------------------------------------------------------------------------------- /resources/secretsmanager_mock_test.go: -------------------------------------------------------------------------------- 1 | //go:generate ../mocks/generate_mocks.sh secretsmanager secretsmanageriface 2 | package resources 3 | 4 | // Note: empty on purpose, this file exist purely to generate mocks for the Secrets Manager service 5 | -------------------------------------------------------------------------------- /resources/servicediscovery_mock_test.go: -------------------------------------------------------------------------------- 1 | //go:generate ../mocks/generate_mocks.sh servicediscovery servicediscoveryiface 2 | package resources 3 | 4 | // Note: empty on purpose, this file exist purely to generate mocks for the CloudFormation service 5 | -------------------------------------------------------------------------------- /.codeclimate.yml: -------------------------------------------------------------------------------- 1 | checks: 2 | return-statements: 3 | enabled: false 4 | plugins: 5 | duplication: 6 | enabled: true 7 | checks: 8 | Similar code: 9 | enabled: false 10 | exclude_patterns: 11 | - "mocks/" 12 | - "**/*_test.go" -------------------------------------------------------------------------------- /.releaserc.yml: -------------------------------------------------------------------------------- 1 | plugins: 2 | - "@semantic-release/commit-analyzer" 3 | - "@semantic-release/release-notes-generator" 4 | - "@semantic-release/github" 5 | 6 | branches: 7 | - name: main 8 | - name: v2 9 | - name: next 10 | prerelease: 'beta' 11 | channel: beta -------------------------------------------------------------------------------- /resources/route53_mock_test.go: -------------------------------------------------------------------------------- 1 | //go:generate ../mocks/generate_mocks.sh route53 route53iface 2 | //go:generate ../mocks/generate_mocks.sh route53resolver route53resolveriface 3 | package resources 4 | 5 | // Note: empty on purpose, this file exist purely to generate mocks for the Route53 service 6 | -------------------------------------------------------------------------------- /pkg/config/testdata/deprecated-feature-flags.yaml: -------------------------------------------------------------------------------- 1 | feature-flags: 2 | disable-ec2-instance-stop-protection: true 3 | force-delete-lightsail-addons: true 4 | disable-deletion-protection: 5 | RDSInstance: true 6 | EC2Instance: true 7 | CloudformationStack: true 8 | ELBv2: true 9 | QLDBLedger: true -------------------------------------------------------------------------------- /mocks/generate_mocks.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | SERVICE=$1 4 | INTERFACE=$2 5 | 6 | go get github.com/golang/mock/mockgen@v1.6.0 7 | 8 | go run github.com/golang/mock/mockgen -source $(go list -m -mod=mod -f "{{.Dir}}" "github.com/aws/aws-sdk-go")/service/$SERVICE/$INTERFACE/interface.go -destination ../mocks/mock_$INTERFACE/mock.go 9 | -------------------------------------------------------------------------------- /docs/features/global-filters.md: -------------------------------------------------------------------------------- 1 | # Global Filters 2 | 3 | Global filters are filters that are applied to all resources. They are defined using a special resource name called 4 | `__global__`. The global filters are pre-pended to all resources before any other filters for the specific resource 5 | are applied. 6 | 7 | [Full Documentation](../config-filtering.md#global) -------------------------------------------------------------------------------- /docs/standards.md: -------------------------------------------------------------------------------- 1 | # Standards 2 | 3 | This is an attempt to describe the standards we use in developing this project. Currently most of the standards 4 | are captured in the contributing guide. 5 | 6 | ## Git 7 | 8 | See the [contributing guide](contributing.md) for more information. 9 | 10 | ## CLI Standards 11 | 12 | - Use `--no-` prefix for boolean flags 13 | 14 | 15 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | docs-build: 2 | docker run --rm -it -p 8000:8000 -v ${PWD}:/docs squidfunk/mkdocs-material build 3 | 4 | docs-serve: 5 | docker run --rm -it -p 8000:8000 -v ${PWD}:/docs squidfunk/mkdocs-material 6 | 7 | docs-seed: 8 | cp README.md docs/index.md 9 | 10 | generate: 11 | go generate ./... 12 | 13 | test: 14 | go test ./... 15 | 16 | test-integration: 17 | go test ./... -tags=integration -------------------------------------------------------------------------------- /pkg/config/testdata/bypass-alias.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | regions: 3 | - "us-east-1" 4 | 5 | blocklist: 6 | - 1234567890 7 | 8 | bypass-alias-check-accounts: 9 | - 123654654 10 | 11 | accounts: 12 | 123654654: 13 | resource-types: 14 | targets: 15 | - S3Bucket 16 | filters: 17 | IAMRole: 18 | - "uber.admin" 19 | IAMRolePolicyAttachment: 20 | - "uber.admin -> AdministratorAccess" 21 | -------------------------------------------------------------------------------- /.github/workflows/commit-lint.yaml: -------------------------------------------------------------------------------- 1 | name: commit-lint 2 | 3 | on: 4 | pull_request_target: 5 | types: 6 | - opened 7 | - edited 8 | - synchronize 9 | 10 | permissions: 11 | contents: read 12 | pull-requests: read 13 | 14 | jobs: 15 | commit-lint: 16 | name: commit-lint 17 | runs-on: ubuntu-latest 18 | steps: 19 | - uses: actions/checkout@v4 20 | - uses: wagoid/commitlint-github-action@v6 -------------------------------------------------------------------------------- /docs/features/enabled-regions.md: -------------------------------------------------------------------------------- 1 | # Feature: All Enabled Regions 2 | 3 | There is a special region called `all` that can be provided to the regions block in the configuration. If `all` is 4 | provided then the special `global` region and all regions that are enabled for the account will automatically be 5 | included. Any other regions that are provided will be **ignored**. 6 | 7 | See [Full Documentation](../config.md#all-enabled-regions) for more information. -------------------------------------------------------------------------------- /.github/workflows/semantic-lint.yml: -------------------------------------------------------------------------------- 1 | name: semantic-lint 2 | 3 | on: 4 | pull_request_target: 5 | types: 6 | - opened 7 | - edited 8 | - synchronize 9 | 10 | permissions: 11 | contents: read 12 | pull-requests: read 13 | 14 | jobs: 15 | semantic-lint: 16 | runs-on: ubuntu-latest 17 | steps: 18 | - uses: amannn/action-semantic-pull-request@v5 19 | env: 20 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 21 | -------------------------------------------------------------------------------- /pkg/config/testsuite_test.go: -------------------------------------------------------------------------------- 1 | package config 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/sirupsen/logrus" 7 | ) 8 | 9 | type TestGlobalHook struct { 10 | t *testing.T 11 | tf func(t *testing.T, e *logrus.Entry) 12 | } 13 | 14 | func (h *TestGlobalHook) Levels() []logrus.Level { 15 | return logrus.AllLevels 16 | } 17 | 18 | func (h *TestGlobalHook) Fire(e *logrus.Entry) error { 19 | if h.tf != nil { 20 | h.tf(h.t, e) 21 | } 22 | 23 | return nil 24 | } 25 | -------------------------------------------------------------------------------- /docs/development.md: -------------------------------------------------------------------------------- 1 | # Development 2 | 3 | ## Building 4 | 5 | The following will build the binary for the current platform and place it in the `releases` directory. 6 | 7 | ```console 8 | goreleaser build --clean --snapshot --single-target 9 | ``` 10 | 11 | ## Documentation 12 | 13 | This is built using Material for MkDocs and can be run very easily locally providing you have docker available. 14 | 15 | ### Running Locally 16 | 17 | ```console 18 | make docs-serve 19 | ``` 20 | -------------------------------------------------------------------------------- /pkg/awsutil/consts.go: -------------------------------------------------------------------------------- 1 | package awsutil 2 | 3 | // Default is a generic constant for the word default 4 | const Default = "default" 5 | 6 | // StateDeleted is a generic constant for the word deleted for state 7 | const StateDeleted = "deleted" 8 | 9 | // StateDeleting is a generic constant for the word deleting for state 10 | const StateDeleting = "deleting" 11 | 12 | // StateRejected is a generic constant for the word rejected for state 13 | const StateRejected = "rejected" 14 | -------------------------------------------------------------------------------- /pkg/config/testdata/incomplete.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | regions: 3 | - "eu-west-1" 4 | - stratoscale 5 | 6 | accounts: 7 | 555133742: 8 | presets: 9 | - "terraform" 10 | resource-types: 11 | targets: 12 | - S3Bucket 13 | filters: 14 | IAMRole: 15 | - "uber.admin" 16 | IAMRolePolicyAttachment: 17 | - "uber.admin -> AdministratorAccess" 18 | 19 | presets: 20 | terraform: 21 | filters: 22 | S3Bucket: 23 | - type: glob 24 | value: "my-statebucket-*" -------------------------------------------------------------------------------- /pkg/common/commands.go: -------------------------------------------------------------------------------- 1 | package common 2 | 3 | import ( 4 | "github.com/sirupsen/logrus" 5 | "github.com/urfave/cli/v2" 6 | ) 7 | 8 | var commands []*cli.Command 9 | 10 | // Commander -- 11 | type Commander interface { 12 | Execute(c *cli.Context) 13 | } 14 | 15 | // RegisterCommand -- 16 | func RegisterCommand(command *cli.Command) { 17 | logrus.Debugln("Registering", command.Name, "command...") 18 | commands = append(commands, command) 19 | } 20 | 21 | // GetCommands -- 22 | func GetCommands() []*cli.Command { 23 | return commands 24 | } 25 | -------------------------------------------------------------------------------- /.github/workflows/golangci-lint.yml: -------------------------------------------------------------------------------- 1 | name: golangci-lint 2 | on: 3 | pull_request: 4 | branches: 5 | - main 6 | 7 | permissions: 8 | contents: read 9 | 10 | jobs: 11 | golangci-lint: 12 | name: golangci-lint 13 | runs-on: ubuntu-latest 14 | steps: 15 | - uses: actions/checkout@v4 16 | - uses: actions/setup-go@v5 17 | with: 18 | go-version: '1.21.x' 19 | cache: false 20 | - name: golangci-lint 21 | uses: golangci/golangci-lint-action@v6 22 | with: 23 | args: --timeout=10m -------------------------------------------------------------------------------- /.github/workflows/tests.yml: -------------------------------------------------------------------------------- 1 | name: tests 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | pull_request: 8 | branches: 9 | - main 10 | 11 | jobs: 12 | test: 13 | name: test 14 | runs-on: ubuntu-latest 15 | steps: 16 | - uses: actions/checkout@v4 17 | - uses: actions/setup-go@v5 18 | with: 19 | go-version: '1.21.x' 20 | - name: download go mods 21 | run: | 22 | go mod download 23 | - name: run go tests 24 | run: | 25 | go test -timeout 60s -race -coverprofile=coverage.txt -covermode=atomic ./... 26 | -------------------------------------------------------------------------------- /resources/amplify-app_mock_test.go: -------------------------------------------------------------------------------- 1 | package resources 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/gotidy/ptr" 7 | "github.com/stretchr/testify/assert" 8 | ) 9 | 10 | var app = &AmplifyApp{ 11 | Name: ptr.String("app1"), 12 | AppID: ptr.String("appId1"), 13 | Tags: map[string]*string{ 14 | "key1": ptr.String("value1"), 15 | }, 16 | } 17 | 18 | func Test_AmplifyApp_Properties(t *testing.T) { 19 | a := assert.New(t) 20 | 21 | properties := app.Properties() 22 | a.Equal("app1", properties.Get("Name")) 23 | a.Equal("appId1", properties.Get("AppID")) 24 | a.Equal("value1", properties.Get("tag:key1")) 25 | } 26 | 27 | func Test_AmplifyApp_Stringer(t *testing.T) { 28 | a := assert.New(t) 29 | 30 | a.Equal("appId1", app.String()) 31 | } 32 | -------------------------------------------------------------------------------- /pkg/common/version.go: -------------------------------------------------------------------------------- 1 | package common 2 | 3 | import "fmt" 4 | 5 | // NAME of the App 6 | var NAME = "aws-nuke" 7 | 8 | // SUMMARY of the Version 9 | var SUMMARY = "3.0.0-dev" 10 | 11 | // BRANCH of the Version 12 | var BRANCH = "dev" 13 | 14 | var COMMIT = "dirty" 15 | 16 | // AppVersion -- 17 | var AppVersion AppVersionInfo 18 | 19 | // AppVersionInfo -- 20 | type AppVersionInfo struct { 21 | Name string 22 | Branch string 23 | Summary string 24 | Commit string 25 | } 26 | 27 | func (a *AppVersionInfo) String() string { 28 | return fmt.Sprintf("%s - %s - %s", a.Name, a.Summary, a.Commit) 29 | } 30 | 31 | func init() { 32 | AppVersion = AppVersionInfo{ 33 | Name: NAME, 34 | Branch: BRANCH, 35 | Summary: SUMMARY, 36 | Commit: COMMIT, 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | # syntax=docker/dockerfile:1.10-labs 2 | FROM alpine:3.20.3 as base 3 | RUN apk add --no-cache ca-certificates 4 | RUN adduser -D aws-nuke 5 | 6 | FROM ghcr.io/acorn-io/images-mirror/golang:1.21 AS build 7 | COPY / /src 8 | WORKDIR /src 9 | ENV CGO_ENABLED=0 10 | RUN \ 11 | --mount=type=cache,target=/go/pkg \ 12 | --mount=type=cache,target=/root/.cache/go-build \ 13 | go build -ldflags '-s -w -extldflags="-static"' -o bin/aws-nuke main.go 14 | 15 | FROM base AS goreleaser 16 | ENTRYPOINT ["/usr/local/bin/aws-nuke"] 17 | COPY aws-nuke /usr/local/bin/aws-nuke 18 | USER aws-nuke 19 | 20 | FROM base 21 | ENTRYPOINT ["/usr/local/bin/aws-nuke"] 22 | COPY --from=build --chmod=755 /src/bin/aws-nuke /usr/local/bin/aws-nuke 23 | RUN chmod +x /usr/local/bin/aws-nuke 24 | USER aws-nuke -------------------------------------------------------------------------------- /docs/releases.md: -------------------------------------------------------------------------------- 1 | # Releases 2 | 3 | Releases are performed automatically based on semantic commits. The versioning is then determined from the commits. 4 | We use a tool called [semantic-release](https://semantic-release.gitbook.io/) to determine if a release should occur 5 | and what the version should be. This takes away the need for humans to be involved. 6 | 7 | ## Release Assets 8 | 9 | You can find Linux, macOS and Windows binaries on the [releases page](https://github.com/ekristen/aws-nuke/releases), but we also provide containerized 10 | versions on [ghcr.io/ekristen/aws-nuke](https://ghcr.io/ekristen/aws-nuke). 11 | 12 | Both are available for multiple architectures (amd64, arm64 & armv7) using Docker manifests. You can reference the 13 | main tag on any system and get the correct docker image automatically. -------------------------------------------------------------------------------- /resources/iam-groups_mock_test.go: -------------------------------------------------------------------------------- 1 | package resources 2 | 3 | import ( 4 | "context" 5 | "testing" 6 | 7 | "github.com/golang/mock/gomock" 8 | "github.com/stretchr/testify/assert" 9 | 10 | "github.com/aws/aws-sdk-go/aws" 11 | "github.com/aws/aws-sdk-go/service/iam" 12 | 13 | "github.com/ekristen/aws-nuke/v3/mocks/mock_iamiface" 14 | ) 15 | 16 | func Test_Mock_IAMGroup_Remove(t *testing.T) { 17 | a := assert.New(t) 18 | ctrl := gomock.NewController(t) 19 | defer ctrl.Finish() 20 | 21 | mockIAM := mock_iamiface.NewMockIAMAPI(ctrl) 22 | 23 | iamGroup := IAMGroup{ 24 | svc: mockIAM, 25 | name: "foobar", 26 | } 27 | 28 | mockIAM.EXPECT().DeleteGroup(gomock.Eq(&iam.DeleteGroupInput{ 29 | GroupName: aws.String(iamGroup.name), 30 | })).Return(&iam.DeleteGroupOutput{}, nil) 31 | 32 | err := iamGroup.Remove(context.TODO()) 33 | a.Nil(err) 34 | } 35 | -------------------------------------------------------------------------------- /pkg/testsuite/logrus.go: -------------------------------------------------------------------------------- 1 | package testsuite 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/sirupsen/logrus" 7 | ) 8 | 9 | type GlobalHook struct { 10 | T *testing.T 11 | TF func(t *testing.T, e *logrus.Entry) 12 | } 13 | 14 | func (h *GlobalHook) Levels() []logrus.Level { 15 | return logrus.AllLevels 16 | } 17 | 18 | func (h *GlobalHook) Fire(e *logrus.Entry) error { 19 | if h.TF != nil { 20 | h.TF(h.T, e) 21 | } 22 | 23 | return nil 24 | } 25 | 26 | func (h *GlobalHook) Cleanup() { 27 | logrus.StandardLogger().ReplaceHooks(make(logrus.LevelHooks)) 28 | } 29 | 30 | // NewGlobalHook creates a new GlobalHook for logrus testing 31 | func NewGlobalHook(t *testing.T, tf func(t *testing.T, e *logrus.Entry)) *GlobalHook { 32 | gh := &GlobalHook{ 33 | T: t, 34 | TF: tf, 35 | } 36 | logrus.SetReportCaller(true) 37 | logrus.AddHook(gh) 38 | return gh 39 | } 40 | -------------------------------------------------------------------------------- /docs/cli-examples.md: -------------------------------------------------------------------------------- 1 | # Examples 2 | 3 | ## Basic usage 4 | 5 | ```bash 6 | aws-nuke run --config config.yml 7 | ``` 8 | 9 | ## Using a profile 10 | 11 | !!! note 12 | This assumes you have configured your AWS credentials file with a profile named `my-profile`. 13 | 14 | ```bash 15 | aws-nuke run --config config.yml --profile my-profile 16 | ``` 17 | 18 | ## Using the prompt flags 19 | 20 | !!! note 21 | This used be called the `--force` flag. It has been renamed to `--no-prompt` to better reflect its purpose. 22 | 23 | !!! danger 24 | Running without prompts can be dangerous. Make sure you understand what you are doing before using these flags. 25 | 26 | The following is an example of how you automate the command to run without any prompts of the user. This is useful 27 | for running in a CI/CD pipeline. 28 | 29 | ```bash 30 | aws-nuke run --config config.yml --no-prompt --prompt-delay 5 31 | ``` -------------------------------------------------------------------------------- /resources/iam-server-certificate_mock_test.go: -------------------------------------------------------------------------------- 1 | package resources 2 | 3 | import ( 4 | "context" 5 | "testing" 6 | 7 | "github.com/golang/mock/gomock" 8 | "github.com/stretchr/testify/assert" 9 | 10 | "github.com/aws/aws-sdk-go/service/iam" 11 | 12 | "github.com/ekristen/aws-nuke/v3/mocks/mock_iamiface" 13 | ) 14 | 15 | func Test_Mock_IAMServerCertificate_Remove(t *testing.T) { 16 | a := assert.New(t) 17 | ctrl := gomock.NewController(t) 18 | defer ctrl.Finish() 19 | 20 | mockIAM := mock_iamiface.NewMockIAMAPI(ctrl) 21 | 22 | iamServerCertificate := IAMServerCertificate{ 23 | svc: mockIAM, 24 | name: "server-cert-foobar", 25 | } 26 | 27 | mockIAM.EXPECT().DeleteServerCertificate(gomock.Eq(&iam.DeleteServerCertificateInput{ 28 | ServerCertificateName: &iamServerCertificate.name, 29 | })).Return(&iam.DeleteServerCertificateOutput{}, nil) 30 | 31 | err := iamServerCertificate.Remove(context.TODO()) 32 | a.Nil(err) 33 | } 34 | -------------------------------------------------------------------------------- /resources/iam-saml-provider_mock_test.go: -------------------------------------------------------------------------------- 1 | package resources 2 | 3 | import ( 4 | "context" 5 | "testing" 6 | 7 | "github.com/gotidy/ptr" 8 | 9 | "github.com/golang/mock/gomock" 10 | "github.com/stretchr/testify/assert" 11 | 12 | "github.com/aws/aws-sdk-go/service/iam" 13 | 14 | "github.com/ekristen/aws-nuke/v3/mocks/mock_iamiface" 15 | ) 16 | 17 | func Test_Mock_IAMSAMLProvider_Remove(t *testing.T) { 18 | a := assert.New(t) 19 | ctrl := gomock.NewController(t) 20 | defer ctrl.Finish() 21 | 22 | mockIAM := mock_iamiface.NewMockIAMAPI(ctrl) 23 | 24 | iamSAMLProvider := IAMSAMLProvider{ 25 | svc: mockIAM, 26 | ARN: ptr.String("arn:mock-saml-provider-foobar"), 27 | } 28 | 29 | mockIAM.EXPECT().DeleteSAMLProvider(gomock.Eq(&iam.DeleteSAMLProviderInput{ 30 | SAMLProviderArn: iamSAMLProvider.ARN, 31 | })).Return(&iam.DeleteSAMLProviderOutput{}, nil) 32 | 33 | err := iamSAMLProvider.Remove(context.TODO()) 34 | a.Nil(err) 35 | } 36 | -------------------------------------------------------------------------------- /resources/iam-user-policy_mock_test.go: -------------------------------------------------------------------------------- 1 | package resources 2 | 3 | import ( 4 | "context" 5 | "testing" 6 | 7 | "github.com/golang/mock/gomock" 8 | "github.com/stretchr/testify/assert" 9 | 10 | "github.com/aws/aws-sdk-go/aws" 11 | "github.com/aws/aws-sdk-go/service/iam" 12 | 13 | "github.com/ekristen/aws-nuke/v3/mocks/mock_iamiface" 14 | ) 15 | 16 | func Test_Mock_IAMUserPolicy_Remove(t *testing.T) { 17 | a := assert.New(t) 18 | ctrl := gomock.NewController(t) 19 | defer ctrl.Finish() 20 | 21 | mockIAM := mock_iamiface.NewMockIAMAPI(ctrl) 22 | 23 | iamUserPolicy := IAMUserPolicy{ 24 | svc: mockIAM, 25 | userName: "foobar", 26 | policyName: "foobar", 27 | } 28 | 29 | mockIAM.EXPECT().DeleteUserPolicy(gomock.Eq(&iam.DeleteUserPolicyInput{ 30 | UserName: aws.String(iamUserPolicy.userName), 31 | PolicyName: aws.String(iamUserPolicy.policyName), 32 | })).Return(&iam.DeleteUserPolicyOutput{}, nil) 33 | 34 | err := iamUserPolicy.Remove(context.TODO()) 35 | a.Nil(err) 36 | } 37 | -------------------------------------------------------------------------------- /docs/features/bypass-alias-check.md: -------------------------------------------------------------------------------- 1 | # Bypass AWS Alias Check 2 | 3 | While we take security and precautions serious with a tool that can have devastating effects, we understand that some 4 | users may want to skip the alias check. This is not recommended, but we understand that some users may want to do this. 5 | 6 | This feature allows you to skip the alias check but requires additional configuration to enable. 7 | 8 | ## How it Works 9 | 10 | There are two components to this feature: 11 | 12 | 1. The `--no-alias-check` flag (also available as `NO_ALIAS_CHECK` environment variable) 13 | 2. The `bypass-alias-check-accounts` configuration in the `config.yml` file 14 | 15 | The account ID must be in the `bypass-alias-check-accounts` configuration for the `--no-alias-check` flag to work. 16 | 17 | ## Example Configuration 18 | 19 | ```yaml 20 | bypass-alias-check-accounts: 21 | - 123456789012 22 | ``` 23 | 24 | ## Example Usage 25 | 26 | ```console 27 | aws-nuke run --config=example-config.yaml --no-alias-check 28 | ``` -------------------------------------------------------------------------------- /resources/iam-group-policies_mock_test.go: -------------------------------------------------------------------------------- 1 | package resources 2 | 3 | import ( 4 | "context" 5 | "testing" 6 | 7 | "github.com/golang/mock/gomock" 8 | "github.com/stretchr/testify/assert" 9 | 10 | "github.com/aws/aws-sdk-go/aws" 11 | "github.com/aws/aws-sdk-go/service/iam" 12 | 13 | "github.com/ekristen/aws-nuke/v3/mocks/mock_iamiface" 14 | ) 15 | 16 | func Test_Mock_IAMGroupPolicy_Remove(t *testing.T) { 17 | a := assert.New(t) 18 | ctrl := gomock.NewController(t) 19 | defer ctrl.Finish() 20 | 21 | mockIAM := mock_iamiface.NewMockIAMAPI(ctrl) 22 | 23 | iamGroupPolicy := IAMGroupPolicy{ 24 | svc: mockIAM, 25 | policyName: "foobar", 26 | groupName: "foobar", 27 | } 28 | 29 | mockIAM.EXPECT().DeleteGroupPolicy(gomock.Eq(&iam.DeleteGroupPolicyInput{ 30 | PolicyName: aws.String(iamGroupPolicy.policyName), 31 | GroupName: aws.String(iamGroupPolicy.groupName), 32 | })).Return(&iam.DeleteGroupPolicyOutput{}, nil) 33 | 34 | err := iamGroupPolicy.Remove(context.TODO()) 35 | a.Nil(err) 36 | } 37 | -------------------------------------------------------------------------------- /resources/iam-user-ssh-keys_mock_test.go: -------------------------------------------------------------------------------- 1 | package resources 2 | 3 | import ( 4 | "context" 5 | "testing" 6 | 7 | "github.com/golang/mock/gomock" 8 | "github.com/stretchr/testify/assert" 9 | 10 | "github.com/aws/aws-sdk-go/aws" 11 | "github.com/aws/aws-sdk-go/service/iam" 12 | 13 | "github.com/ekristen/aws-nuke/v3/mocks/mock_iamiface" 14 | ) 15 | 16 | func Test_Mock_IAMUserSSHKeys_Remove(t *testing.T) { 17 | a := assert.New(t) 18 | ctrl := gomock.NewController(t) 19 | defer ctrl.Finish() 20 | 21 | mockIAM := mock_iamiface.NewMockIAMAPI(ctrl) 22 | 23 | iamUserSSHKey := IAMUserSSHKey{ 24 | svc: mockIAM, 25 | userName: "foobar", 26 | sshKeyID: "foobar", 27 | } 28 | 29 | mockIAM.EXPECT().DeleteSSHPublicKey(gomock.Eq(&iam.DeleteSSHPublicKeyInput{ 30 | UserName: aws.String(iamUserSSHKey.userName), 31 | SSHPublicKeyId: aws.String(iamUserSSHKey.sshKeyID), 32 | })).Return(&iam.DeleteSSHPublicKeyOutput{}, nil) 33 | 34 | err := iamUserSSHKey.Remove(context.TODO()) 35 | a.Nil(err) 36 | } 37 | -------------------------------------------------------------------------------- /pkg/config/testdata/example.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | regions: 3 | - "eu-west-1" 4 | - stratoscale 5 | 6 | account-blocklist: 7 | - 1234567890 8 | 9 | endpoints: 10 | - region: stratoscale 11 | tls_insecure_skip_verify: true 12 | services: 13 | - service: ec2 14 | url: https://stratoscale.cloud.internal/api/v2/aws/ec2 15 | - service: s3 16 | url: https://stratoscale.cloud.internal:1060 17 | tls_insecure_skip_verify: true 18 | 19 | resource-types: 20 | targets: 21 | - DynamoDBTable 22 | - S3Bucket 23 | - S3Object 24 | excludes: 25 | - IAMRole 26 | 27 | accounts: 28 | 555133742: 29 | presets: 30 | - "terraform" 31 | resource-types: 32 | targets: 33 | - S3Bucket 34 | filters: 35 | IAMRole: 36 | - "uber.admin" 37 | IAMRolePolicyAttachment: 38 | - "uber.admin -> AdministratorAccess" 39 | 40 | presets: 41 | terraform: 42 | filters: 43 | S3Bucket: 44 | - type: glob 45 | value: "my-statebucket-*" -------------------------------------------------------------------------------- /resources/iam-open-id-connect-provider_mock_test.go: -------------------------------------------------------------------------------- 1 | package resources 2 | 3 | import ( 4 | "context" 5 | "testing" 6 | 7 | "github.com/golang/mock/gomock" 8 | "github.com/stretchr/testify/assert" 9 | 10 | "github.com/aws/aws-sdk-go/aws" 11 | "github.com/aws/aws-sdk-go/service/iam" 12 | 13 | "github.com/ekristen/aws-nuke/v3/mocks/mock_iamiface" 14 | ) 15 | 16 | func Test_Mock_IAMOpenIDConnectProvider_Remove(t *testing.T) { 17 | a := assert.New(t) 18 | ctrl := gomock.NewController(t) 19 | defer ctrl.Finish() 20 | 21 | mockIAM := mock_iamiface.NewMockIAMAPI(ctrl) 22 | 23 | iamOpenIDConnectProvider := IAMOpenIDConnectProvider{ 24 | svc: mockIAM, 25 | arn: "arn:openid-connect-provider", 26 | } 27 | 28 | mockIAM.EXPECT().DeleteOpenIDConnectProvider(gomock.Eq(&iam.DeleteOpenIDConnectProviderInput{ 29 | OpenIDConnectProviderArn: aws.String(iamOpenIDConnectProvider.arn), 30 | })).Return(&iam.DeleteOpenIDConnectProviderOutput{}, nil) 31 | 32 | err := iamOpenIDConnectProvider.Remove(context.TODO()) 33 | a.Nil(err) 34 | } 35 | -------------------------------------------------------------------------------- /resources/iam-user-group-attachments_mock_test.go: -------------------------------------------------------------------------------- 1 | package resources 2 | 3 | import ( 4 | "context" 5 | "testing" 6 | 7 | "github.com/golang/mock/gomock" 8 | "github.com/stretchr/testify/assert" 9 | 10 | "github.com/aws/aws-sdk-go/aws" 11 | "github.com/aws/aws-sdk-go/service/iam" 12 | 13 | "github.com/ekristen/aws-nuke/v3/mocks/mock_iamiface" 14 | ) 15 | 16 | func Test_Mock_IAMUserGroup_Remove(t *testing.T) { 17 | a := assert.New(t) 18 | ctrl := gomock.NewController(t) 19 | defer ctrl.Finish() 20 | 21 | mockIAM := mock_iamiface.NewMockIAMAPI(ctrl) 22 | 23 | iamUserGroup := IAMUserGroupAttachment{ 24 | svc: mockIAM, 25 | userName: "user:foobar", 26 | groupName: "group:foobar", 27 | } 28 | 29 | mockIAM.EXPECT().RemoveUserFromGroup(gomock.Eq(&iam.RemoveUserFromGroupInput{ 30 | UserName: aws.String(iamUserGroup.userName), 31 | GroupName: aws.String(iamUserGroup.groupName), 32 | })).Return(&iam.RemoveUserFromGroupOutput{}, nil) 33 | 34 | err := iamUserGroup.Remove(context.TODO()) 35 | a.Nil(err) 36 | } 37 | -------------------------------------------------------------------------------- /resources/iam-user-access-key_mock_test.go: -------------------------------------------------------------------------------- 1 | package resources 2 | 3 | import ( 4 | "context" 5 | "testing" 6 | 7 | "github.com/golang/mock/gomock" 8 | "github.com/stretchr/testify/assert" 9 | 10 | "github.com/aws/aws-sdk-go/aws" 11 | "github.com/aws/aws-sdk-go/service/iam" 12 | 13 | "github.com/ekristen/aws-nuke/v3/mocks/mock_iamiface" 14 | ) 15 | 16 | func Test_Mock_IAMUserAccessKey_Remove(t *testing.T) { 17 | a := assert.New(t) 18 | ctrl := gomock.NewController(t) 19 | defer ctrl.Finish() 20 | 21 | mockIAM := mock_iamiface.NewMockIAMAPI(ctrl) 22 | 23 | iamUserAccessKey := IAMUserAccessKey{ 24 | svc: mockIAM, 25 | accessKeyID: "EXAMPLEfoobar", 26 | userName: "foobar", 27 | status: "unknown", 28 | } 29 | 30 | mockIAM.EXPECT().DeleteAccessKey(gomock.Eq(&iam.DeleteAccessKeyInput{ 31 | AccessKeyId: aws.String(iamUserAccessKey.accessKeyID), 32 | UserName: aws.String(iamUserAccessKey.userName), 33 | })).Return(&iam.DeleteAccessKeyOutput{}, nil) 34 | 35 | err := iamUserAccessKey.Remove(context.TODO()) 36 | a.Nil(err) 37 | } 38 | -------------------------------------------------------------------------------- /resources/iam-role-policy_mock_test.go: -------------------------------------------------------------------------------- 1 | package resources 2 | 3 | import ( 4 | "context" 5 | "testing" 6 | 7 | "github.com/golang/mock/gomock" 8 | "github.com/stretchr/testify/assert" 9 | 10 | "github.com/aws/aws-sdk-go/aws" 11 | "github.com/aws/aws-sdk-go/service/iam" 12 | 13 | "github.com/ekristen/aws-nuke/v3/mocks/mock_iamiface" 14 | ) 15 | 16 | func Test_Mock_IAMRolePolicy_Remove(t *testing.T) { 17 | a := assert.New(t) 18 | ctrl := gomock.NewController(t) 19 | defer ctrl.Finish() 20 | 21 | mockIAM := mock_iamiface.NewMockIAMAPI(ctrl) 22 | 23 | iamRolePolicy := IAMRolePolicy{ 24 | svc: mockIAM, 25 | roleID: "role:foobar-id", 26 | roleName: "role:foobar", 27 | policyName: "policy:foobar", 28 | roleTags: []*iam.Tag{}, 29 | } 30 | 31 | mockIAM.EXPECT().DeleteRolePolicy(gomock.Eq(&iam.DeleteRolePolicyInput{ 32 | RoleName: aws.String(iamRolePolicy.roleName), 33 | PolicyName: aws.String(iamRolePolicy.policyName), 34 | })).Return(&iam.DeleteRolePolicyOutput{}, nil) 35 | 36 | err := iamRolePolicy.Remove(context.TODO()) 37 | a.Nil(err) 38 | } 39 | -------------------------------------------------------------------------------- /resources/iam-user-policy-attachment_mock_test.go: -------------------------------------------------------------------------------- 1 | package resources 2 | 3 | import ( 4 | "context" 5 | 6 | "testing" 7 | 8 | "github.com/golang/mock/gomock" 9 | "github.com/stretchr/testify/assert" 10 | 11 | "github.com/aws/aws-sdk-go/aws" 12 | "github.com/aws/aws-sdk-go/service/iam" 13 | 14 | "github.com/ekristen/aws-nuke/v3/mocks/mock_iamiface" 15 | ) 16 | 17 | func Test_Mock_IAMUserPolicyAttachment_Remove(t *testing.T) { 18 | a := assert.New(t) 19 | ctrl := gomock.NewController(t) 20 | defer ctrl.Finish() 21 | 22 | mockIAM := mock_iamiface.NewMockIAMAPI(ctrl) 23 | 24 | iamUserPolicyAttachment := IAMUserPolicyAttachment{ 25 | svc: mockIAM, 26 | policyArn: "arn:foobar", 27 | policyName: "foobar", 28 | userName: "foobar", 29 | } 30 | 31 | mockIAM.EXPECT().DetachUserPolicy(gomock.Eq(&iam.DetachUserPolicyInput{ 32 | UserName: aws.String(iamUserPolicyAttachment.userName), 33 | PolicyArn: aws.String(iamUserPolicyAttachment.policyArn), 34 | })).Return(&iam.DetachUserPolicyOutput{}, nil) 35 | 36 | err := iamUserPolicyAttachment.Remove(context.TODO()) 37 | a.Nil(err) 38 | } 39 | -------------------------------------------------------------------------------- /docs/installation.md: -------------------------------------------------------------------------------- 1 | # Install 2 | 3 | ## Install the pre-compiled binary 4 | 5 | ### Homebrew Tap (MacOS/Linux) 6 | 7 | ```console 8 | brew install ekristen/tap/aws-nuke 9 | ``` 10 | 11 | !!! warning "Brew Warning" 12 | `brew install aws-nuke` will install the rebuy-aws version of aws-nuke, which is not the same as this version. 13 | 14 | ## Releases 15 | 16 | You can download pre-compiled binaries from the [releases](https://github.com/ekristen/aws-nuke/releases) page. 17 | 18 | ## Docker 19 | 20 | Registries: 21 | 22 | - [ghcr.io/ekristen/aws-nuke](https://github.com/ekristen/aws-nuke/pkgs/container/aws-nuke) 23 | 24 | You can run **aws-nuke** with Docker by using a command like this: 25 | 26 | ## Source 27 | 28 | To compile **aws-nuke** from source you need a working [Golang](https://golang.org/doc/install) development environment and [goreleaser](https://goreleaser.com/install/). 29 | 30 | **aws-nuke** uses go modules and so the clone path should not matter. Then simply change directory into the clone and run: 31 | 32 | ```bash 33 | goreleaser build --clean --snapshot --single-target 34 | ``` 35 | 36 | -------------------------------------------------------------------------------- /resources/iam-group-policy-attachments_mock_test.go: -------------------------------------------------------------------------------- 1 | package resources 2 | 3 | import ( 4 | "context" 5 | "testing" 6 | 7 | "github.com/golang/mock/gomock" 8 | "github.com/stretchr/testify/assert" 9 | 10 | "github.com/aws/aws-sdk-go/aws" 11 | "github.com/aws/aws-sdk-go/service/iam" 12 | 13 | "github.com/ekristen/aws-nuke/v3/mocks/mock_iamiface" 14 | ) 15 | 16 | func Test_Mock_IAMGroupPolicyAttachment_Remove(t *testing.T) { 17 | a := assert.New(t) 18 | ctrl := gomock.NewController(t) 19 | defer ctrl.Finish() 20 | 21 | mockIAM := mock_iamiface.NewMockIAMAPI(ctrl) 22 | 23 | iamGroupPolicyAttachment := IAMGroupPolicyAttachment{ 24 | svc: mockIAM, 25 | policyArn: "foobar", 26 | policyName: "foobar", 27 | groupName: "foobar", 28 | } 29 | 30 | mockIAM.EXPECT().DetachGroupPolicy(gomock.Eq(&iam.DetachGroupPolicyInput{ 31 | PolicyArn: aws.String(iamGroupPolicyAttachment.policyArn), 32 | GroupName: aws.String(iamGroupPolicyAttachment.groupName), 33 | })).Return(&iam.DetachGroupPolicyOutput{}, nil) 34 | 35 | err := iamGroupPolicyAttachment.Remove(context.TODO()) 36 | a.Nil(err) 37 | } 38 | -------------------------------------------------------------------------------- /docs/migration-guide.md: -------------------------------------------------------------------------------- 1 | There's only **one** real breaking change between version 2 and version 3 and that is that the root command will 2 | no longer trigger a run, you must use the `run` command to trigger a run. 3 | 4 | There are a number of other changes that have been made, but they are 100% backwards compatible and warnings are provided 5 | during run time if you are using deprecated flags or resources. 6 | 7 | ## CLI Changes 8 | 9 | - `root` command no longer triggers the run, must use subcommand `run` (alias: `nuke`) 10 | - `target` is deprecated, use `include` instead (on `run` command) 11 | - `feature-flag` is a new flag used to change behavior of the tool, for resource behavior changes see [settings](config.md#settings) 12 | 13 | ## Config Changes 14 | 15 | ### New 16 | 17 | * `settings` is a new section in the config file that allows you to change the behavior of a resource, formerly these 18 | were called `feature-flags` and were a top level key in the config file. 19 | 20 | ### Deprecated 21 | 22 | - `targets` is now deprecated, use `includes` instead 23 | - `feature-flags` is now deprecated, use `settings` instead 24 | -------------------------------------------------------------------------------- /pkg/awsutil/util_test.go: -------------------------------------------------------------------------------- 1 | package awsutil_test 2 | 3 | import ( 4 | "fmt" 5 | "testing" 6 | 7 | "github.com/ekristen/aws-nuke/v3/pkg/awsutil" 8 | ) 9 | 10 | func TestSecretRegex(t *testing.T) { 11 | cases := []struct{ in, out string }{ 12 | { 13 | in: "GET / HTTP/1.1\nAuthorization: Never gonna give you up\nHost: bish", 14 | out: "GET / HTTP/1.1\nAuthorization: \nHost: bish", 15 | }, 16 | { 17 | in: "GET / HTTP/1.1\nX-Amz-Security-Token: Never gonna let you down\nHost: bash", 18 | out: "GET / HTTP/1.1\nX-Amz-Security-Token: \nHost: bash", 19 | }, 20 | { 21 | in: "GET / HTTP/1.1\nX-Amz-Security-Token: Never gonna run around and desert you\nAuthorization: Never gonna make you cry", 22 | out: "GET / HTTP/1.1\nX-Amz-Security-Token: \nAuthorization: ", 23 | }, 24 | } 25 | 26 | for i, tc := range cases { 27 | t.Run(fmt.Sprint(i), func(t *testing.T) { 28 | want := tc.out 29 | have := string(awsutil.HideSecureHeaders([]byte(tc.in))) 30 | 31 | if want != have { 32 | t.Errorf("Assertion failed. Want: %#v. Have: %#v", want, have) 33 | } 34 | }) 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /resources/iam-role-policy-attachments_mock_test.go: -------------------------------------------------------------------------------- 1 | package resources 2 | 3 | import ( 4 | "context" 5 | "testing" 6 | 7 | "github.com/golang/mock/gomock" 8 | "github.com/stretchr/testify/assert" 9 | 10 | "github.com/aws/aws-sdk-go/aws" 11 | "github.com/aws/aws-sdk-go/service/iam" 12 | 13 | "github.com/ekristen/aws-nuke/v3/mocks/mock_iamiface" 14 | ) 15 | 16 | func Test_Mock_IAMRolePolicyAttachment_Remove(t *testing.T) { 17 | a := assert.New(t) 18 | ctrl := gomock.NewController(t) 19 | defer ctrl.Finish() 20 | 21 | mockIAM := mock_iamiface.NewMockIAMAPI(ctrl) 22 | 23 | iamRolePolicyAttachment := IAMRolePolicyAttachment{ 24 | svc: mockIAM, 25 | policyArn: "arn:foobar", 26 | policyName: "foobar", 27 | role: &iam.Role{ 28 | RoleName: aws.String("foo"), 29 | }, 30 | } 31 | 32 | mockIAM.EXPECT().DetachRolePolicy(gomock.Eq(&iam.DetachRolePolicyInput{ 33 | RoleName: iamRolePolicyAttachment.role.RoleName, 34 | PolicyArn: aws.String(iamRolePolicyAttachment.policyArn), 35 | })).Return(&iam.DetachRolePolicyOutput{}, nil) 36 | 37 | err := iamRolePolicyAttachment.Remove(context.TODO()) 38 | a.Nil(err) 39 | } 40 | -------------------------------------------------------------------------------- /resources/iam-signing-certificate_mock_test.go: -------------------------------------------------------------------------------- 1 | package resources 2 | 3 | import ( 4 | "context" 5 | "testing" 6 | 7 | "github.com/golang/mock/gomock" 8 | "github.com/stretchr/testify/assert" 9 | 10 | "github.com/aws/aws-sdk-go/aws" 11 | "github.com/aws/aws-sdk-go/service/iam" 12 | 13 | "github.com/ekristen/aws-nuke/v3/mocks/mock_iamiface" 14 | ) 15 | 16 | func Test_Mock_IAMSigningCertificate_Remove(t *testing.T) { 17 | a := assert.New(t) 18 | ctrl := gomock.NewController(t) 19 | defer ctrl.Finish() 20 | 21 | mockIAM := mock_iamiface.NewMockIAMAPI(ctrl) 22 | 23 | iamSigningCertificate := IAMSigningCertificate{ 24 | svc: mockIAM, 25 | certificateID: aws.String("certid:foobar"), 26 | userName: aws.String("user:foobar"), 27 | status: aws.String("unknown"), 28 | } 29 | 30 | mockIAM.EXPECT().DeleteSigningCertificate(gomock.Eq(&iam.DeleteSigningCertificateInput{ 31 | UserName: iamSigningCertificate.userName, 32 | CertificateId: iamSigningCertificate.certificateID, 33 | })).Return(&iam.DeleteSigningCertificateOutput{}, nil) 34 | 35 | err := iamSigningCertificate.Remove(context.TODO()) 36 | a.Nil(err) 37 | } 38 | -------------------------------------------------------------------------------- /.github/workflows/semantic.yml: -------------------------------------------------------------------------------- 1 | name: semantic 2 | on: 3 | push: 4 | branches: 5 | - main 6 | - next 7 | 8 | permissions: 9 | contents: read # for checkout 10 | 11 | jobs: 12 | release: 13 | name: release 14 | runs-on: ubuntu-latest 15 | permissions: 16 | contents: write # to be able to publish a GitHub release 17 | issues: write # to be able to comment on released issues 18 | pull-requests: write # to be able to comment on released pull requests 19 | id-token: write # to enable use of OIDC for npm provenance 20 | steps: 21 | - name: checkout 22 | uses: actions/checkout@v4 23 | with: 24 | fetch-depth: 0 25 | - name: setup node.js 26 | uses: actions/setup-node@v4 27 | with: 28 | node-version: "lts/*" 29 | - name: release 30 | env: 31 | GITHUB_TOKEN: ${{ secrets.SEMANTIC_GITHUB_TOKEN }} 32 | run: | 33 | npx \ 34 | -p @semantic-release/commit-analyzer \ 35 | -p @semantic-release/release-notes-generator \ 36 | -p @semantic-release/github \ 37 | semantic-release 38 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 reBuy reCommerce GmbH 4 | Copyright (c) 2021 Erik Kristensen 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. -------------------------------------------------------------------------------- /pkg/nuke/prompt.go: -------------------------------------------------------------------------------- 1 | package nuke 2 | 3 | import ( 4 | "fmt" 5 | "time" 6 | 7 | libnuke "github.com/ekristen/libnuke/pkg/nuke" 8 | "github.com/ekristen/libnuke/pkg/utils" 9 | 10 | "github.com/ekristen/aws-nuke/v3/pkg/awsutil" 11 | ) 12 | 13 | // Prompt struct provides a way to provide a custom prompt to the libnuke library this allows 14 | // custom data to be available to the Prompt func when it's executed by the libnuke library 15 | type Prompt struct { 16 | Parameters *libnuke.Parameters 17 | Account *awsutil.Account 18 | } 19 | 20 | // Prompt is the actual function called by the libnuke process during it's run 21 | func (p *Prompt) Prompt() error { 22 | forceSleep := time.Duration(p.Parameters.ForceSleep) * time.Second 23 | 24 | fmt.Printf("Do you really want to nuke the account with "+ 25 | "the ID %s and the alias '%s'?\n", p.Account.ID(), p.Account.Alias()) 26 | if p.Parameters.Force { 27 | fmt.Printf("Waiting %v before continuing.\n", forceSleep) 28 | time.Sleep(forceSleep) 29 | } else { 30 | fmt.Printf("Do you want to continue? Enter account alias to continue.\n") 31 | if err := utils.Prompt(p.Account.Alias()); err != nil { 32 | return err 33 | } 34 | } 35 | 36 | return nil 37 | } 38 | -------------------------------------------------------------------------------- /resources/cloudcontrol_test.go: -------------------------------------------------------------------------------- 1 | package resources 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/sirupsen/logrus" 7 | "github.com/stretchr/testify/assert" 8 | ) 9 | 10 | func TestCloudControlParseProperties(t *testing.T) { 11 | logrus.SetLevel(logrus.DebugLevel) 12 | 13 | cases := []struct { 14 | name string 15 | payload string 16 | want []string 17 | }{ 18 | { 19 | name: "ActualEC2VPC", 20 | payload: `{"VpcId":"vpc-456","InstanceTenancy":"default","CidrBlockAssociations":["vpc-cidr-assoc-1234", "vpc-cidr-assoc-5678"],"CidrBlock":"10.10.0.0/16","Tags":[{"Value":"Kubernetes VPC","Key":"Name"}]}`, //nolint:lll 21 | want: []string{ 22 | `CidrBlock: "10.10.0.0/16"`, 23 | `Tags.["Name"]: "Kubernetes VPC"`, 24 | `VpcId: "vpc-456"`, 25 | `InstanceTenancy: "default"`, 26 | `CidrBlockAssociations.["vpc-cidr-assoc-1234"]: "true"`, 27 | `CidrBlockAssociations.["vpc-cidr-assoc-5678"]: "true"`, 28 | }, 29 | }, 30 | } 31 | 32 | for _, tc := range cases { 33 | t.Run(tc.name, func(t *testing.T) { 34 | result, err := cloudControlParseProperties(tc.payload) 35 | assert.NoError(t, err) 36 | for _, w := range tc.want { 37 | assert.Contains(t, result.String(), w) 38 | } 39 | }) 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "os" 5 | 6 | "github.com/sirupsen/logrus" 7 | "github.com/urfave/cli/v2" 8 | 9 | "github.com/ekristen/aws-nuke/v3/pkg/common" 10 | 11 | _ "github.com/ekristen/aws-nuke/v3/pkg/commands/account" 12 | _ "github.com/ekristen/aws-nuke/v3/pkg/commands/config" 13 | _ "github.com/ekristen/aws-nuke/v3/pkg/commands/list" 14 | _ "github.com/ekristen/aws-nuke/v3/pkg/commands/nuke" 15 | 16 | _ "github.com/ekristen/aws-nuke/v3/resources" 17 | ) 18 | 19 | func main() { 20 | defer func() { 21 | if r := recover(); r != nil { 22 | // log panics forces exit 23 | if _, ok := r.(*logrus.Entry); ok { 24 | os.Exit(1) 25 | } 26 | panic(r) 27 | } 28 | }() 29 | 30 | app := cli.NewApp() 31 | app.Name = common.AppVersion.Name 32 | app.Usage = "remove everything from an aws account" 33 | app.Version = common.AppVersion.Summary 34 | app.Authors = []*cli.Author{ 35 | { 36 | Name: "Erik Kristensen", 37 | Email: "erik@erikkristensen.com", 38 | }, 39 | } 40 | 41 | app.Commands = common.GetCommands() 42 | app.CommandNotFound = func(context *cli.Context, command string) { 43 | logrus.Fatalf("Command %s not found.", command) 44 | } 45 | 46 | if err := app.Run(os.Args); err != nil { 47 | logrus.Fatal(err) 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /resources/iam-service-specific-credentials_mock_test.go: -------------------------------------------------------------------------------- 1 | package resources 2 | 3 | import ( 4 | "context" 5 | "testing" 6 | 7 | "github.com/golang/mock/gomock" 8 | "github.com/gotidy/ptr" 9 | "github.com/stretchr/testify/assert" 10 | 11 | "github.com/aws/aws-sdk-go/service/iam" 12 | 13 | "github.com/ekristen/aws-nuke/v3/mocks/mock_iamiface" 14 | ) 15 | 16 | func Test_Mock_IAMServiceSpecificCredential_Remove(t *testing.T) { 17 | a := assert.New(t) 18 | ctrl := gomock.NewController(t) 19 | defer ctrl.Finish() 20 | 21 | mockIAM := mock_iamiface.NewMockIAMAPI(ctrl) 22 | 23 | iamServiceSpecificCredential := IAMServiceSpecificCredential{ 24 | svc: mockIAM, 25 | name: ptr.String("user:foobar"), 26 | serviceName: ptr.String("service:foobar"), 27 | id: ptr.String("user:service:foobar"), 28 | userName: ptr.String("user:foobar"), 29 | } 30 | 31 | mockIAM.EXPECT().DeleteServiceSpecificCredential(gomock.Eq(&iam.DeleteServiceSpecificCredentialInput{ 32 | UserName: iamServiceSpecificCredential.userName, 33 | ServiceSpecificCredentialId: iamServiceSpecificCredential.id, 34 | })).Return(&iam.DeleteServiceSpecificCredentialOutput{}, nil) 35 | 36 | err := iamServiceSpecificCredential.Remove(context.TODO()) 37 | a.Nil(err) 38 | } 39 | -------------------------------------------------------------------------------- /pkg/nuke/resource.go: -------------------------------------------------------------------------------- 1 | package nuke 2 | 3 | import ( 4 | "github.com/aws/aws-sdk-go/aws/session" 5 | 6 | "github.com/ekristen/libnuke/pkg/registry" 7 | ) 8 | 9 | // Account is the resource scope that all resources in AWS Nuke are registered against. 10 | const Account registry.Scope = "account" 11 | 12 | // ListerOpts are the options for the Lister functions of each individual resource. It is passed in as an interface{} 13 | // so that each implementing tool can define their own options for the lister. Each resource then asserts the type on 14 | // the interface{} to get the options it needs. 15 | type ListerOpts struct { 16 | Region *Region 17 | Session *session.Session 18 | } 19 | 20 | // MutateOpts is a function that will be called for each resource type to mutate the options for the scanner based on 21 | // whatever criteria you want. However, in this case for the aws-nuke tool, it's mutating the opts to create the proper 22 | // session for the proper region for the resourceType. For example IAM only happens in the global region, not us-east-2. 23 | var MutateOpts = func(opts interface{}, resourceType string) interface{} { 24 | o := opts.(*ListerOpts) 25 | 26 | session, err := o.Region.Session(resourceType) 27 | if err != nil { 28 | panic(err) 29 | } 30 | 31 | o.Session = session 32 | return o 33 | } 34 | -------------------------------------------------------------------------------- /resources/iam-user_test.go: -------------------------------------------------------------------------------- 1 | //go:build integration 2 | 3 | package resources 4 | 5 | import ( 6 | "context" 7 | "errors" 8 | "testing" 9 | 10 | "github.com/stretchr/testify/assert" 11 | 12 | "github.com/aws/aws-sdk-go/aws" 13 | "github.com/aws/aws-sdk-go/aws/awserr" 14 | "github.com/aws/aws-sdk-go/aws/session" 15 | "github.com/aws/aws-sdk-go/service/iam" 16 | ) 17 | 18 | func Test_IAMUser_Remove(t *testing.T) { 19 | sess := session.Must(session.NewSession()) 20 | svc := iam.New(sess) 21 | 22 | createInput := &iam.CreateUserInput{ 23 | UserName: aws.String("test-user"), 24 | Tags: []*iam.Tag{ 25 | { 26 | Key: aws.String("test-key"), 27 | Value: aws.String("test-value"), 28 | }, 29 | }, 30 | } 31 | out, err := svc.CreateUser(createInput) 32 | 33 | assert.NoError(t, err) 34 | assert.Equal(t, "test-user", *out.User.UserName) 35 | 36 | iamUser := IAMUser{ 37 | svc: svc, 38 | name: aws.String("test-user"), 39 | tags: createInput.Tags, 40 | } 41 | 42 | removeError := iamUser.Remove(context.TODO()) 43 | assert.NoError(t, removeError) 44 | 45 | _, err = svc.GetUser(&iam.GetUserInput{ 46 | UserName: aws.String("test-user"), 47 | }) 48 | var awsError awserr.Error 49 | if errors.As(err, &awsError) { 50 | assert.Equal(t, "NoSuchEntity", awsError.Code()) 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /docs/config-presets.md: -------------------------------------------------------------------------------- 1 | # Presets 2 | 3 | It might be the case that some filters are the same across multiple accounts. This especially could happen, if 4 | provisioning tools like Terraform are used or if IAM resources follow the same pattern. 5 | 6 | For this case *aws-nuke* supports presets of filters, that can applied on multiple accounts. 7 | 8 | `Presets` are defined globally. They can then be referenced in the `accounts` section of the configuration. 9 | 10 | A preset configuration could look like this: 11 | 12 | ```yaml 13 | presets: 14 | common: 15 | filters: 16 | IAMAccountSettingPasswordPolicy: 17 | - custom 18 | IAMRole: 19 | - "OrganizationAccountAccessRole" 20 | ``` 21 | 22 | An account referencing a preset would then look something like this: 23 | 24 | ```yaml 25 | accounts: 26 | 1234567890: 27 | presets: 28 | - common 29 | ``` 30 | 31 | Putting it all together it would look something like this: 32 | 33 | ```yaml 34 | blocklist: 35 | - 0012345678 36 | 37 | regions: 38 | - global 39 | - us-east-1 40 | 41 | accounts: 42 | 1234567890: 43 | presets: 44 | - common 45 | 46 | presets: 47 | common: 48 | filters: 49 | IAMAccountSettingPasswordPolicy: 50 | - custom 51 | IAMRole: 52 | - OrganizationAccountAccessRole 53 | ``` -------------------------------------------------------------------------------- /pkg/commands/list/list.go: -------------------------------------------------------------------------------- 1 | package list 2 | 3 | import ( 4 | "sort" 5 | "strings" 6 | 7 | "github.com/fatih/color" 8 | "github.com/urfave/cli/v2" 9 | 10 | "github.com/ekristen/aws-nuke/v3/pkg/commands/global" 11 | "github.com/ekristen/aws-nuke/v3/pkg/common" 12 | 13 | _ "github.com/ekristen/aws-nuke/v3/resources" 14 | "github.com/ekristen/libnuke/pkg/registry" 15 | ) 16 | 17 | func execute(c *cli.Context) error { 18 | ls := registry.GetNames() 19 | 20 | sort.Strings(ls) 21 | 22 | for _, name := range ls { 23 | if strings.HasPrefix(name, "AWS::") { 24 | continue 25 | } 26 | 27 | reg := registry.GetRegistration(name) 28 | 29 | if reg.AlternativeResource != "" { 30 | color.New(color.Bold).Printf("%-55s\n", name) 31 | color.New(color.Bold, color.FgYellow).Printf(" > %-55s", reg.AlternativeResource) 32 | color.New(color.FgCyan).Printf("alternative cloud-control resource\n") 33 | } else { 34 | color.New(color.Bold).Printf("%-55s\n", name) 35 | } 36 | } 37 | 38 | return nil 39 | } 40 | 41 | func init() { 42 | cmd := &cli.Command{ 43 | Name: "resource-types", 44 | Aliases: []string{"list-resources"}, 45 | Usage: "list available resources to nuke", 46 | Flags: global.Flags(), 47 | Before: global.Before, 48 | Action: execute, 49 | } 50 | 51 | common.RegisterCommand(cmd) 52 | } 53 | -------------------------------------------------------------------------------- /docs/features/overview.md: -------------------------------------------------------------------------------- 1 | There are a number of new features with this version these features range from usability to debugging purposes. 2 | 3 | Some of the new features include: 4 | 5 | - [Global Filters](global-filters.md) 6 | - [Run Against All Enabled Regions](enabled-regions.md) 7 | - [Bypass Alias Check - Allow the skip of an alias on an account](bypass-alias-check.md) 8 | - [Signed Binaries](signed-binaries.md) 9 | 10 | Additionally, there are a few new sub commands to the tool to help with setup and debugging purposes: 11 | 12 | First, there is a new `explain-account` command that will attempt to perform basic authentication against AWS with 13 | whatever information is has available to it, and print it out to screen, this is useful for seeing which account is 14 | actually being targeted and what credentials the tool and AWS sees as being used. 15 | [more information](../cli-usage.md#aws-nuke-explain-account) 16 | 17 | Second, there is a new `explain-config` command that will attempt to parse the config file and print out the information 18 | for the configuration file, such as total resource types, filtered resources types, number of includes or excludes with 19 | optional flags to describe in detail all the resource types that fit the various categories. 20 | [more information](../cli-usage.md#aws-nuke-explain-config) 21 | 22 | 23 | -------------------------------------------------------------------------------- /docs/cli-options.md: -------------------------------------------------------------------------------- 1 | # Options 2 | 3 | This is not a comprehensive list of options, but rather a list of features that I think are worth highlighting. 4 | 5 | ## Cloud Control API 6 | 7 | `--cloud-control` will allow you to use the Cloud Control API for specific resource types. This is useful if you want to use the Cloud Control API for specific resource types. 8 | 9 | ## Skip Alias Checks 10 | 11 | `--no-alias-check` will skip the check for the AWS account alias. This is useful if you are running in an account that does not have an alias. 12 | 13 | ## Skip Prompts 14 | 15 | `--no-prompt` will skip the prompt to verify you want to run the command. This is useful if you are running in a CI/CD environment. 16 | `--prompt-delay` will set the delay before the command runs. This is useful if you want to give yourself time to cancel the command. 17 | 18 | ## Logging 19 | 20 | - `--log-level` will set the log level. This is useful if you want to see more or less information in the logs. 21 | - `--log-caller` will log the caller (aka line number and file). This is useful if you are debugging. 22 | - `--log-disable-color` will disable log coloring. This is useful if you are running in an environment that does not support color. 23 | - `--log-full-timestamp` will force log output to always show full timestamp. This is useful if you want to see the full timestamp in the logs. -------------------------------------------------------------------------------- /docs/config-migration.md: -------------------------------------------------------------------------------- 1 | # Configuration Migration 2 | 3 | ## Version 2.x to 3.x 4 | 5 | The configuration file format has changed from version 2.x to 3.x. However, it is still 100% backward compatible with 6 | the old format. The new format is more flexible and allows for more complex configurations. 7 | 8 | ### Changes 9 | 10 | - The `targets` key has been deprecated in favor of `includes`. 11 | - The `feature-flags` key has been deprecated in favor of `settings`. 12 | 13 | ### Migration 14 | 15 | The migration for `targets` is very simply, simply rename the key to `includes` 16 | 17 | ```yaml 18 | resource-types: 19 | targets: 20 | - S3Object 21 | - S3Bucket 22 | - IAMRole 23 | ``` 24 | 25 | Becomes 26 | 27 | ```yaml 28 | resource-types: 29 | includes: 30 | - S3Object 31 | - S3Bucket 32 | - IAMRole 33 | ``` 34 | 35 | The migration for `feature-flags` takes a little more than renaming the key. The `settings` key is now used to map 36 | settings to a specific resource and that resource's definition within the tool announces the need for a setting. 37 | 38 | ```yaml 39 | feature-flags: 40 | disable-deletion-protection: 41 | RDSInstance: true 42 | EC2Instance: true 43 | ``` 44 | 45 | Becomes 46 | 47 | ```yaml 48 | settings: 49 | EC2Instance: 50 | DisableDeletionProtection: true 51 | RDSInstance: 52 | DisableDeletionProtection: true 53 | ``` -------------------------------------------------------------------------------- /.github/renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["config:recommended"], 3 | "packageRules": [ 4 | { 5 | "matchManagers": ["dockerfile"], 6 | "matchUpdateTypes": ["pin", "digest"], 7 | "automerge": true, 8 | "automergeStrategy": "squash" 9 | }, 10 | { 11 | "matchPackagePatterns": ["^golang.*"], 12 | "groupName": "golang", 13 | "groupSlug": "golang" 14 | }, 15 | { 16 | "matchFileNames": [".github/workflows/*.yml"], 17 | "matchDepTypes": ["action"], 18 | "matchCurrentVersion": "!/^0/", 19 | "automerge": true, 20 | "automergeStrategy": "squash", 21 | "labels": ["bot"], 22 | "commitMessageSuffix": " [release skip]" 23 | }, 24 | { 25 | "matchPackagePatterns": "aws-sdk-go", 26 | "separateMinorPatch": true 27 | } 28 | ], 29 | "customManagers": [ 30 | { 31 | "customType": "regex", 32 | "fileMatch": ["^.github/workflows/.*"], 33 | "matchStrings": ["go-version: (?.*?)\n"], 34 | "depNameTemplate": "golang", 35 | "datasourceTemplate": "docker" 36 | } 37 | ], 38 | "gitIgnoredAuthors": [ 39 | "github-actions@github.com", 40 | "169176299+ekristen-dev[bot]@users.noreply.github.com" 41 | ] 42 | } 43 | -------------------------------------------------------------------------------- /pkg/awsutil/util.go: -------------------------------------------------------------------------------- 1 | package awsutil 2 | 3 | import ( 4 | "bytes" 5 | "errors" 6 | "net/http" 7 | "net/http/httputil" 8 | "regexp" 9 | 10 | "github.com/sirupsen/logrus" 11 | 12 | "github.com/aws/aws-sdk-go/aws/awserr" 13 | 14 | "github.com/ekristen/libnuke/pkg/utils" 15 | ) 16 | 17 | var ( 18 | RESecretHeader = regexp.MustCompile(`(?m:^([^:]*(Auth|Security)[^:]*):.*$)`) 19 | ) 20 | 21 | func HideSecureHeaders(dump []byte) []byte { 22 | return RESecretHeader.ReplaceAll(dump, []byte("$1: ")) 23 | } 24 | 25 | func DumpRequest(r *http.Request) string { 26 | dump, err := httputil.DumpRequest(r, true) 27 | if err != nil { 28 | logrus.WithField("Error", err).Warnf("failed to dump HTTP request") 29 | return "" 30 | } 31 | 32 | dump = bytes.TrimSpace(dump) 33 | dump = HideSecureHeaders(dump) 34 | dump = utils.IndentBytes(dump, []byte(" > ")) 35 | return string(dump) 36 | } 37 | 38 | func DumpResponse(r *http.Response) string { 39 | dump, err := httputil.DumpResponse(r, true) 40 | if err != nil { 41 | logrus.WithField("Error", err).Warnf("failed to dump HTTP response") 42 | return "" 43 | } 44 | 45 | dump = bytes.TrimSpace(dump) 46 | dump = utils.IndentBytes(dump, []byte(" < ")) 47 | return string(dump) 48 | } 49 | 50 | func IsAWSError(err error, code string) bool { 51 | var aerr awserr.Error 52 | ok := errors.As(err, &aerr) 53 | if !ok { 54 | return false 55 | } 56 | 57 | return aerr.Code() == code 58 | } 59 | -------------------------------------------------------------------------------- /.github/workflows/aws-sdk-mocks.yml: -------------------------------------------------------------------------------- 1 | name: aws-sdk-update-mocks 2 | 3 | on: 4 | push: 5 | branches: 6 | - 'renovate/aws-sdk-go-monorepo' 7 | 8 | permissions: 9 | contents: write 10 | pull-requests: read 11 | 12 | jobs: 13 | go-generate: 14 | name: go-generate 15 | runs-on: ubuntu-latest 16 | if: github.actor == 'renovate[bot]' 17 | steps: 18 | - uses: actions/checkout@v4 19 | with: 20 | persist-credentials: false 21 | fetch-depth: 0 22 | - uses: actions/setup-go@v5 23 | with: 24 | go-version: '1.21.x' 25 | - name: generate-token 26 | id: generate_token 27 | uses: tibdex/github-app-token@v2 28 | with: 29 | app_id: ${{ secrets.BOT_APP_ID }} 30 | private_key: ${{ secrets.BOT_APP_PRIVATE_KEY }} 31 | revoke: true 32 | - name: download go mods 33 | run: | 34 | go mod download 35 | - name: go-generate 36 | run: | 37 | go generate ./... 38 | - name: git-commit 39 | run: | 40 | git config --global user.name 'ekristen-dev[bot]' 41 | git config --global user.email '169176299+ekristen-dev[bot]@users.noreply.github.com' 42 | git add . 43 | git commit -a -m 'chore: update mocks' 44 | - name: git-push 45 | uses: ad-m/github-push-action@master 46 | with: 47 | github_token: ${{ steps.generate_token.outputs.token }} 48 | branch: ${{ github.ref }} -------------------------------------------------------------------------------- /resources/macie2.go: -------------------------------------------------------------------------------- 1 | package resources 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/aws/aws-sdk-go/service/macie2" 7 | 8 | "github.com/ekristen/libnuke/pkg/registry" 9 | "github.com/ekristen/libnuke/pkg/resource" 10 | 11 | "github.com/ekristen/aws-nuke/v3/pkg/nuke" 12 | ) 13 | 14 | const MacieResource = "Macie" 15 | 16 | func init() { 17 | registry.Register(®istry.Registration{ 18 | Name: MacieResource, 19 | Scope: nuke.Account, 20 | Lister: &MacieLister{}, 21 | }) 22 | } 23 | 24 | type MacieLister struct{} 25 | 26 | func (l *MacieLister) List(_ context.Context, o interface{}) ([]resource.Resource, error) { 27 | opts := o.(*nuke.ListerOpts) 28 | 29 | svc := macie2.New(opts.Session) 30 | 31 | status, err := svc.GetMacieSession(&macie2.GetMacieSessionInput{}) 32 | if err != nil { 33 | if err.Error() == "AccessDeniedException: Macie is not enabled" { 34 | return nil, nil 35 | } else { 36 | return nil, err 37 | } 38 | } 39 | 40 | resources := make([]resource.Resource, 0) 41 | if *status.Status == macie2.AdminStatusEnabled { 42 | resources = append(resources, &Macie{ 43 | svc: svc, 44 | }) 45 | } 46 | 47 | return resources, nil 48 | } 49 | 50 | type Macie struct { 51 | svc *macie2.Macie2 52 | } 53 | 54 | func (b *Macie) Remove(_ context.Context) error { 55 | _, err := b.svc.DisableMacie(&macie2.DisableMacieInput{}) 56 | if err != nil { 57 | return err 58 | } 59 | return nil 60 | } 61 | 62 | func (b *Macie) String() string { 63 | return "macie" 64 | } 65 | -------------------------------------------------------------------------------- /docs/resources/s3-bucket.md: -------------------------------------------------------------------------------- 1 | # S3 Bucket 2 | 3 | This will remove all S3 buckets from an AWS account. The following actions are performed, some with control settings. 4 | 5 | - Remove Bucket Policy 6 | - Remove Logging Configuration 7 | - Remove All Legal Holds 8 | - This only happens if the `RemoveObjectLegalHold` setting is set to `true` 9 | - Remove All Versions 10 | - This will include bypassing any Object Lock governance retention settings if the `BypassGovernanceRetention` 11 | setting is set to `true` 12 | - Remove All Objects 13 | - This will include bypassing any Object Lock governance retention settings if the `BypassGovernanceRetention` 14 | setting is set to `true` 15 | 16 | ## Settings 17 | 18 | - `BypassGovernanceRetention` 19 | - `RemoveObjectLegalHold` 20 | 21 | ### BypassGovernanceRetention 22 | 23 | Specifies whether an S3 Object Lock should bypass Governance-mode restrictions to process object retention configuration 24 | changes or deletion. Default is `false`. 25 | 26 | ### BypassLegalHold 27 | 28 | !!! warning 29 | This will result in additional S3 API calls. The entire bucket has to be enumerated for all the objects, every 30 | object then is the result of an API call to remove the legal hold. Regardless if a legal hold existed or not. This 31 | is because it would require an additional API call to check if a legal hold exists on an object. 32 | 33 | Specifies whether S3 Object Lock should remove any legal hold configuration from objects in the S3 bucket. 34 | Default is `false`. 35 | 36 | -------------------------------------------------------------------------------- /resources/opsworkscm-backups.go: -------------------------------------------------------------------------------- 1 | package resources 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/aws/aws-sdk-go/service/opsworkscm" 7 | 8 | "github.com/ekristen/libnuke/pkg/registry" 9 | "github.com/ekristen/libnuke/pkg/resource" 10 | 11 | "github.com/ekristen/aws-nuke/v3/pkg/nuke" 12 | ) 13 | 14 | const OpsWorksCMBackupResource = "OpsWorksCMBackup" 15 | 16 | func init() { 17 | registry.Register(®istry.Registration{ 18 | Name: OpsWorksCMBackupResource, 19 | Scope: nuke.Account, 20 | Lister: &OpsWorksCMBackupLister{}, 21 | }) 22 | } 23 | 24 | type OpsWorksCMBackupLister struct{} 25 | 26 | func (l *OpsWorksCMBackupLister) List(_ context.Context, o interface{}) ([]resource.Resource, error) { 27 | opts := o.(*nuke.ListerOpts) 28 | 29 | svc := opsworkscm.New(opts.Session) 30 | resources := make([]resource.Resource, 0) 31 | 32 | params := &opsworkscm.DescribeBackupsInput{} 33 | 34 | output, err := svc.DescribeBackups(params) 35 | if err != nil { 36 | return nil, err 37 | } 38 | 39 | for _, backup := range output.Backups { 40 | resources = append(resources, &OpsWorksCMBackup{ 41 | svc: svc, 42 | ID: backup.BackupId, 43 | }) 44 | } 45 | 46 | return resources, nil 47 | } 48 | 49 | type OpsWorksCMBackup struct { 50 | svc *opsworkscm.OpsWorksCM 51 | ID *string 52 | } 53 | 54 | func (f *OpsWorksCMBackup) Remove(_ context.Context) error { 55 | _, err := f.svc.DeleteBackup(&opsworkscm.DeleteBackupInput{ 56 | BackupId: f.ID, 57 | }) 58 | 59 | return err 60 | } 61 | 62 | func (f *OpsWorksCMBackup) String() string { 63 | return *f.ID 64 | } 65 | -------------------------------------------------------------------------------- /docs/cli-experimental.md: -------------------------------------------------------------------------------- 1 | # Experimental Features 2 | 3 | ## Overview 4 | 5 | These are the experimental features hidden behind feature flags that are currently available in aws-nuke. They are all 6 | disabled by default. These are switches that changes the actual behavior of the tool itself. Changing the behavior of 7 | a resource is done via resource settings. 8 | 9 | !!! note 10 | The original tool had configuration options called `feature-flags` which were used to enable/disable certain 11 | behaviors with resources, those are now called settings and `feature-flags` have been deprecated in the config. 12 | 13 | ## Usage 14 | 15 | ```console 16 | aws-nuke run --feature-flag "wait-on-dependencies" 17 | ``` 18 | 19 | **Note:** other CLI arguments are omitted for brevity. 20 | 21 | ## Available Feature Flags 22 | 23 | - `wait-on-dependencies` - This feature flag will cause aws-nuke to wait for all resource type dependencies to be 24 | deleted before deleting the next resource type. 25 | 26 | ### wait-on-dependencies 27 | 28 | This feature flag will cause aws-nuke to wait for all resource type dependencies to be deleted before deleting the next 29 | resource type. This is useful for resources that have dependencies on other resources. For example, an IAM Role that has 30 | an attached policy. 31 | 32 | The problem is that if you delete the IAM Role first, it will fail because it has a dependency on the policy. 33 | 34 | This feature flag will cause aws-nuke to wait for all resources of a given type to be deleted before deleting the next 35 | resource type. This will reduce the number of errors and unnecessary API calls. -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/ekristen/aws-nuke/v3 2 | 3 | go 1.21.6 4 | 5 | require ( 6 | github.com/aws/aws-sdk-go v1.54.20 7 | github.com/ekristen/libnuke v0.19.0 8 | github.com/fatih/color v1.17.0 9 | github.com/golang/mock v1.6.0 10 | github.com/google/uuid v1.6.0 11 | github.com/gotidy/ptr v1.4.0 12 | github.com/pkg/errors v0.9.1 13 | github.com/sirupsen/logrus v1.9.3 14 | github.com/stretchr/testify v1.9.0 15 | github.com/urfave/cli/v2 v2.27.4 16 | go.uber.org/ratelimit v0.3.1 17 | golang.org/x/text v0.18.0 18 | gopkg.in/yaml.v3 v3.0.1 19 | ) 20 | 21 | require ( 22 | github.com/benbjohnson/clock v1.3.0 // indirect 23 | github.com/cpuguy83/go-md2man/v2 v2.0.4 // indirect 24 | github.com/davecgh/go-spew v1.1.1 // indirect 25 | github.com/jmespath/go-jmespath v0.4.0 // indirect 26 | github.com/kr/pretty v0.3.1 // indirect 27 | github.com/mattn/go-colorable v0.1.13 // indirect 28 | github.com/mattn/go-isatty v0.0.20 // indirect 29 | github.com/mb0/glob v0.0.0-20160210091149-1eb79d2de6c4 // indirect 30 | github.com/pmezard/go-difflib v1.0.0 // indirect 31 | github.com/rogpeppe/go-internal v1.11.0 // indirect 32 | github.com/russross/blackfriday/v2 v2.1.0 // indirect 33 | github.com/stevenle/topsort v0.2.0 // indirect 34 | github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 // indirect 35 | golang.org/x/mod v0.17.0 // indirect 36 | golang.org/x/sync v0.8.0 // indirect 37 | golang.org/x/sys v0.20.0 // indirect 38 | golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect 39 | gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect 40 | gopkg.in/yaml.v2 v2.4.0 // indirect 41 | ) 42 | -------------------------------------------------------------------------------- /.golangci.yaml: -------------------------------------------------------------------------------- 1 | linters-settings: 2 | dupl: 3 | threshold: 100 4 | funlen: 5 | lines: 100 6 | statements: 50 7 | goconst: 8 | min-len: 2 9 | min-occurrences: 3 10 | gocritic: 11 | enabled-tags: 12 | - diagnostic 13 | - experimental 14 | - opinionated 15 | - performance 16 | - style 17 | disabled-checks: 18 | - dupImport # https://github.com/go-critic/go-critic/issues/845 19 | - ifElseChain 20 | - octalLiteral 21 | - whyNoLint 22 | gocyclo: 23 | min-complexity: 15 24 | golint: 25 | min-confidence: 0 26 | lll: 27 | line-length: 140 28 | maligned: 29 | suggest-new: true 30 | misspell: 31 | locale: US 32 | 33 | linters: 34 | # please, do not use `enable-all`: it's deprecated and will be removed soon. 35 | # inverted configuration with `enable-all` and `disable` is not scalable during updates of golangci-lint 36 | disable-all: true 37 | enable: 38 | - bodyclose 39 | - dogsled 40 | - errcheck 41 | - exportloopref 42 | - funlen 43 | - goconst 44 | - gocritic 45 | - gocyclo 46 | - gofmt 47 | - goimports 48 | - goprintffuncname 49 | - gosec 50 | - gosimple 51 | - govet 52 | - ineffassign 53 | - lll 54 | - misspell 55 | - nakedret 56 | - nilnil 57 | - noctx 58 | - nolintlint 59 | - staticcheck 60 | - stylecheck 61 | - typecheck 62 | - unconvert 63 | - unparam 64 | - unused 65 | - whitespace 66 | 67 | issues: 68 | exclude-rules: 69 | - path: _test\.go 70 | linters: 71 | - funlen 72 | 73 | run: 74 | timeout: 2m -------------------------------------------------------------------------------- /resources/cloudsearch-domains.go: -------------------------------------------------------------------------------- 1 | package resources 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/aws/aws-sdk-go/service/cloudsearch" 7 | 8 | "github.com/ekristen/libnuke/pkg/registry" 9 | "github.com/ekristen/libnuke/pkg/resource" 10 | 11 | "github.com/ekristen/aws-nuke/v3/pkg/nuke" 12 | ) 13 | 14 | const CloudSearchDomainResource = "CloudSearchDomain" 15 | 16 | func init() { 17 | registry.Register(®istry.Registration{ 18 | Name: CloudSearchDomainResource, 19 | Scope: nuke.Account, 20 | Lister: &CloudSearchDomainLister{}, 21 | }) 22 | } 23 | 24 | type CloudSearchDomainLister struct{} 25 | 26 | func (l *CloudSearchDomainLister) List(_ context.Context, o interface{}) ([]resource.Resource, error) { 27 | opts := o.(*nuke.ListerOpts) 28 | 29 | svc := cloudsearch.New(opts.Session) 30 | 31 | params := &cloudsearch.DescribeDomainsInput{} 32 | 33 | resp, err := svc.DescribeDomains(params) 34 | if err != nil { 35 | return nil, err 36 | } 37 | 38 | resources := make([]resource.Resource, 0) 39 | for _, domain := range resp.DomainStatusList { 40 | resources = append(resources, &CloudSearchDomain{ 41 | svc: svc, 42 | domainName: domain.DomainName, 43 | }) 44 | } 45 | return resources, nil 46 | } 47 | 48 | type CloudSearchDomain struct { 49 | svc *cloudsearch.CloudSearch 50 | domainName *string 51 | } 52 | 53 | func (f *CloudSearchDomain) Remove(_ context.Context) error { 54 | _, err := f.svc.DeleteDomain(&cloudsearch.DeleteDomainInput{ 55 | DomainName: f.domainName, 56 | }) 57 | 58 | return err 59 | } 60 | 61 | func (f *CloudSearchDomain) String() string { 62 | return *f.domainName 63 | } 64 | -------------------------------------------------------------------------------- /resources/inspector-assessment-runs.go: -------------------------------------------------------------------------------- 1 | package resources 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/aws/aws-sdk-go/service/inspector" 7 | 8 | "github.com/ekristen/libnuke/pkg/registry" 9 | "github.com/ekristen/libnuke/pkg/resource" 10 | 11 | "github.com/ekristen/aws-nuke/v3/pkg/nuke" 12 | ) 13 | 14 | const InspectorAssessmentRunResource = "InspectorAssessmentRun" 15 | 16 | func init() { 17 | registry.Register(®istry.Registration{ 18 | Name: InspectorAssessmentRunResource, 19 | Scope: nuke.Account, 20 | Lister: &InspectorAssessmentRunLister{}, 21 | }) 22 | } 23 | 24 | type InspectorAssessmentRunLister struct{} 25 | 26 | func (l *InspectorAssessmentRunLister) List(_ context.Context, o interface{}) ([]resource.Resource, error) { 27 | opts := o.(*nuke.ListerOpts) 28 | 29 | svc := inspector.New(opts.Session) 30 | 31 | resp, err := svc.ListAssessmentRuns(nil) 32 | if err != nil { 33 | return nil, err 34 | } 35 | 36 | resources := make([]resource.Resource, 0) 37 | for _, out := range resp.AssessmentRunArns { 38 | resources = append(resources, &InspectorAssessmentRun{ 39 | svc: svc, 40 | arn: *out, 41 | }) 42 | } 43 | 44 | return resources, nil 45 | } 46 | 47 | type InspectorAssessmentRun struct { 48 | svc *inspector.Inspector 49 | arn string 50 | } 51 | 52 | func (e *InspectorAssessmentRun) Remove(_ context.Context) error { 53 | _, err := e.svc.DeleteAssessmentRun(&inspector.DeleteAssessmentRunInput{ 54 | AssessmentRunArn: &e.arn, 55 | }) 56 | if err != nil { 57 | return err 58 | } 59 | 60 | return nil 61 | } 62 | 63 | func (e *InspectorAssessmentRun) String() string { 64 | return e.arn 65 | } 66 | -------------------------------------------------------------------------------- /resources/glue-jobs.go: -------------------------------------------------------------------------------- 1 | package resources 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/aws/aws-sdk-go/aws" 7 | "github.com/aws/aws-sdk-go/service/glue" 8 | 9 | "github.com/ekristen/libnuke/pkg/registry" 10 | "github.com/ekristen/libnuke/pkg/resource" 11 | 12 | "github.com/ekristen/aws-nuke/v3/pkg/nuke" 13 | ) 14 | 15 | const GlueJobResource = "GlueJob" 16 | 17 | func init() { 18 | registry.Register(®istry.Registration{ 19 | Name: GlueJobResource, 20 | Scope: nuke.Account, 21 | Lister: &GlueJobLister{}, 22 | }) 23 | } 24 | 25 | type GlueJobLister struct{} 26 | 27 | func (l *GlueJobLister) List(_ context.Context, o interface{}) ([]resource.Resource, error) { 28 | opts := o.(*nuke.ListerOpts) 29 | 30 | svc := glue.New(opts.Session) 31 | resources := make([]resource.Resource, 0) 32 | 33 | params := &glue.GetJobsInput{ 34 | MaxResults: aws.Int64(100), 35 | } 36 | 37 | for { 38 | output, err := svc.GetJobs(params) 39 | if err != nil { 40 | return nil, err 41 | } 42 | 43 | for _, job := range output.Jobs { 44 | resources = append(resources, &GlueJob{ 45 | svc: svc, 46 | jobName: job.Name, 47 | }) 48 | } 49 | 50 | if output.NextToken == nil { 51 | break 52 | } 53 | 54 | params.NextToken = output.NextToken 55 | } 56 | 57 | return resources, nil 58 | } 59 | 60 | type GlueJob struct { 61 | svc *glue.Glue 62 | jobName *string 63 | } 64 | 65 | func (f *GlueJob) Remove(_ context.Context) error { 66 | _, err := f.svc.DeleteJob(&glue.DeleteJobInput{ 67 | JobName: f.jobName, 68 | }) 69 | 70 | return err 71 | } 72 | 73 | func (f *GlueJob) String() string { 74 | return *f.jobName 75 | } 76 | -------------------------------------------------------------------------------- /resources/iot-streams.go: -------------------------------------------------------------------------------- 1 | package resources 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/aws/aws-sdk-go/aws" 7 | "github.com/aws/aws-sdk-go/service/iot" 8 | 9 | "github.com/ekristen/libnuke/pkg/registry" 10 | "github.com/ekristen/libnuke/pkg/resource" 11 | 12 | "github.com/ekristen/aws-nuke/v3/pkg/nuke" 13 | ) 14 | 15 | const IoTStreamResource = "IoTStream" 16 | 17 | func init() { 18 | registry.Register(®istry.Registration{ 19 | Name: IoTStreamResource, 20 | Scope: nuke.Account, 21 | Lister: &IoTStreamLister{}, 22 | }) 23 | } 24 | 25 | type IoTStreamLister struct{} 26 | 27 | func (l *IoTStreamLister) List(_ context.Context, o interface{}) ([]resource.Resource, error) { 28 | opts := o.(*nuke.ListerOpts) 29 | 30 | svc := iot.New(opts.Session) 31 | resources := make([]resource.Resource, 0) 32 | 33 | params := &iot.ListStreamsInput{ 34 | MaxResults: aws.Int64(100), 35 | } 36 | for { 37 | output, err := svc.ListStreams(params) 38 | if err != nil { 39 | return nil, err 40 | } 41 | 42 | for _, stream := range output.Streams { 43 | resources = append(resources, &IoTStream{ 44 | svc: svc, 45 | ID: stream.StreamId, 46 | }) 47 | } 48 | if output.NextToken == nil { 49 | break 50 | } 51 | 52 | params.NextToken = output.NextToken 53 | } 54 | 55 | return resources, nil 56 | } 57 | 58 | type IoTStream struct { 59 | svc *iot.IoT 60 | ID *string 61 | } 62 | 63 | func (f *IoTStream) Remove(_ context.Context) error { 64 | _, err := f.svc.DeleteStream(&iot.DeleteStreamInput{ 65 | StreamId: f.ID, 66 | }) 67 | 68 | return err 69 | } 70 | 71 | func (f *IoTStream) String() string { 72 | return *f.ID 73 | } 74 | -------------------------------------------------------------------------------- /pkg/commands/global/global.go: -------------------------------------------------------------------------------- 1 | package global 2 | 3 | import ( 4 | "fmt" 5 | "path" 6 | "runtime" 7 | 8 | "github.com/sirupsen/logrus" 9 | "github.com/urfave/cli/v2" 10 | ) 11 | 12 | func Flags() []cli.Flag { 13 | globalFlags := []cli.Flag{ 14 | &cli.StringFlag{ 15 | Name: "log-level", 16 | Usage: "Log Level", 17 | Aliases: []string{"l"}, 18 | EnvVars: []string{"LOGLEVEL"}, 19 | Value: "info", 20 | }, 21 | &cli.BoolFlag{ 22 | Name: "log-caller", 23 | Usage: "log the caller (aka line number and file)", 24 | }, 25 | &cli.BoolFlag{ 26 | Name: "log-disable-color", 27 | Usage: "disable log coloring", 28 | }, 29 | &cli.BoolFlag{ 30 | Name: "log-full-timestamp", 31 | Usage: "force log output to always show full timestamp", 32 | }, 33 | } 34 | 35 | return globalFlags 36 | } 37 | 38 | func Before(c *cli.Context) error { 39 | formatter := &logrus.TextFormatter{ 40 | DisableColors: c.Bool("log-disable-color"), 41 | FullTimestamp: c.Bool("log-full-timestamp"), 42 | } 43 | if c.Bool("log-caller") { 44 | logrus.SetReportCaller(true) 45 | 46 | formatter.CallerPrettyfier = func(f *runtime.Frame) (string, string) { 47 | return "", fmt.Sprintf("%s:%d", path.Base(f.File), f.Line) 48 | } 49 | } 50 | 51 | logrus.SetFormatter(formatter) 52 | 53 | switch c.String("log-level") { 54 | case "trace": 55 | logrus.SetLevel(logrus.TraceLevel) 56 | case "debug": 57 | logrus.SetLevel(logrus.DebugLevel) 58 | case "info": 59 | logrus.SetLevel(logrus.InfoLevel) 60 | case "warn": 61 | logrus.SetLevel(logrus.WarnLevel) 62 | case "error": 63 | logrus.SetLevel(logrus.ErrorLevel) 64 | } 65 | 66 | return nil 67 | } 68 | -------------------------------------------------------------------------------- /resources/appstream-stacks.go: -------------------------------------------------------------------------------- 1 | package resources 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/aws/aws-sdk-go/service/appstream" 7 | 8 | "github.com/ekristen/aws-nuke/v3/pkg/nuke" 9 | "github.com/ekristen/libnuke/pkg/registry" 10 | "github.com/ekristen/libnuke/pkg/resource" 11 | ) 12 | 13 | type AppStreamStack struct { 14 | svc *appstream.AppStream 15 | name *string 16 | } 17 | 18 | const AppStreamStackResource = "AppStreamStack" 19 | 20 | func init() { 21 | registry.Register(®istry.Registration{ 22 | Name: AppStreamStackResource, 23 | Scope: nuke.Account, 24 | Lister: &AppStreamStackLister{}, 25 | }) 26 | } 27 | 28 | type AppStreamStackLister struct{} 29 | 30 | func (l *AppStreamStackLister) List(_ context.Context, o interface{}) ([]resource.Resource, error) { 31 | opts := o.(*nuke.ListerOpts) 32 | 33 | svc := appstream.New(opts.Session) 34 | resources := make([]resource.Resource, 0) 35 | 36 | params := &appstream.DescribeStacksInput{} 37 | 38 | for { 39 | output, err := svc.DescribeStacks(params) 40 | if err != nil { 41 | return nil, err 42 | } 43 | 44 | for _, stack := range output.Stacks { 45 | resources = append(resources, &AppStreamStack{ 46 | svc: svc, 47 | name: stack.Name, 48 | }) 49 | } 50 | 51 | if output.NextToken == nil { 52 | break 53 | } 54 | 55 | params.NextToken = output.NextToken 56 | } 57 | 58 | return resources, nil 59 | } 60 | 61 | func (f *AppStreamStack) Remove(_ context.Context) error { 62 | _, err := f.svc.DeleteStack(&appstream.DeleteStackInput{ 63 | Name: f.name, 64 | }) 65 | 66 | return err 67 | } 68 | 69 | func (f *AppStreamStack) String() string { 70 | return *f.name 71 | } 72 | -------------------------------------------------------------------------------- /resources/mq-broker.go: -------------------------------------------------------------------------------- 1 | package resources 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/aws/aws-sdk-go/aws" 7 | "github.com/aws/aws-sdk-go/service/mq" 8 | 9 | "github.com/ekristen/libnuke/pkg/registry" 10 | "github.com/ekristen/libnuke/pkg/resource" 11 | 12 | "github.com/ekristen/aws-nuke/v3/pkg/nuke" 13 | ) 14 | 15 | const MQBrokerResource = "MQBroker" 16 | 17 | func init() { 18 | registry.Register(®istry.Registration{ 19 | Name: MQBrokerResource, 20 | Scope: nuke.Account, 21 | Lister: &MQBrokerLister{}, 22 | }) 23 | } 24 | 25 | type MQBrokerLister struct{} 26 | 27 | func (l *MQBrokerLister) List(_ context.Context, o interface{}) ([]resource.Resource, error) { 28 | opts := o.(*nuke.ListerOpts) 29 | 30 | svc := mq.New(opts.Session) 31 | resources := make([]resource.Resource, 0) 32 | 33 | params := &mq.ListBrokersInput{ 34 | MaxResults: aws.Int64(100), 35 | } 36 | 37 | for { 38 | resp, err := svc.ListBrokers(params) 39 | if err != nil { 40 | return nil, err 41 | } 42 | 43 | for _, broker := range resp.BrokerSummaries { 44 | resources = append(resources, &MQBroker{ 45 | svc: svc, 46 | brokerID: broker.BrokerId, 47 | }) 48 | } 49 | if resp.NextToken == nil { 50 | break 51 | } 52 | 53 | params.NextToken = resp.NextToken 54 | } 55 | return resources, nil 56 | } 57 | 58 | type MQBroker struct { 59 | svc *mq.MQ 60 | brokerID *string 61 | } 62 | 63 | func (f *MQBroker) Remove(_ context.Context) error { 64 | _, err := f.svc.DeleteBroker(&mq.DeleteBrokerInput{ 65 | BrokerId: f.brokerID, 66 | }) 67 | 68 | return err 69 | } 70 | 71 | func (f *MQBroker) String() string { 72 | return *f.brokerID 73 | } 74 | -------------------------------------------------------------------------------- /resources/inspector-assessment-targets.go: -------------------------------------------------------------------------------- 1 | package resources 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/aws/aws-sdk-go/service/inspector" 7 | 8 | "github.com/ekristen/libnuke/pkg/registry" 9 | "github.com/ekristen/libnuke/pkg/resource" 10 | 11 | "github.com/ekristen/aws-nuke/v3/pkg/nuke" 12 | ) 13 | 14 | const InspectorAssessmentTargetResource = "InspectorAssessmentTarget" 15 | 16 | func init() { 17 | registry.Register(®istry.Registration{ 18 | Name: InspectorAssessmentTargetResource, 19 | Scope: nuke.Account, 20 | Lister: &InspectorAssessmentTargetLister{}, 21 | }) 22 | } 23 | 24 | type InspectorAssessmentTargetLister struct{} 25 | 26 | func (l *InspectorAssessmentTargetLister) List(_ context.Context, o interface{}) ([]resource.Resource, error) { 27 | opts := o.(*nuke.ListerOpts) 28 | 29 | svc := inspector.New(opts.Session) 30 | 31 | resp, err := svc.ListAssessmentTargets(nil) 32 | if err != nil { 33 | return nil, err 34 | } 35 | 36 | resources := make([]resource.Resource, 0) 37 | for _, out := range resp.AssessmentTargetArns { 38 | resources = append(resources, &InspectorAssessmentTarget{ 39 | svc: svc, 40 | arn: *out, 41 | }) 42 | } 43 | 44 | return resources, nil 45 | } 46 | 47 | type InspectorAssessmentTarget struct { 48 | svc *inspector.Inspector 49 | arn string 50 | } 51 | 52 | func (e *InspectorAssessmentTarget) Remove(_ context.Context) error { 53 | _, err := e.svc.DeleteAssessmentTarget(&inspector.DeleteAssessmentTargetInput{ 54 | AssessmentTargetArn: &e.arn, 55 | }) 56 | if err != nil { 57 | return err 58 | } 59 | 60 | return nil 61 | } 62 | 63 | func (e *InspectorAssessmentTarget) String() string { 64 | return e.arn 65 | } 66 | -------------------------------------------------------------------------------- /resources/kms-key_test.go: -------------------------------------------------------------------------------- 1 | //go:build integration 2 | 3 | package resources 4 | 5 | import ( 6 | "context" 7 | "fmt" 8 | "testing" 9 | 10 | "github.com/gotidy/ptr" 11 | "github.com/pkg/errors" 12 | "github.com/stretchr/testify/assert" 13 | 14 | "github.com/aws/aws-sdk-go/aws" 15 | "github.com/aws/aws-sdk-go/aws/awserr" 16 | "github.com/aws/aws-sdk-go/aws/session" 17 | "github.com/aws/aws-sdk-go/service/kms" 18 | "github.com/aws/aws-sdk-go/service/sts" 19 | ) 20 | 21 | func Test_KMSKey_Remove(t *testing.T) { 22 | cfg := aws.NewConfig() 23 | cfg.Region = ptr.String("us-east-1") 24 | 25 | sess := session.Must(session.NewSession(cfg)) 26 | svc := kms.New(sess) 27 | 28 | stsSvc := sts.New(sess) 29 | ident, err := stsSvc.GetCallerIdentity(&sts.GetCallerIdentityInput{}) 30 | assert.NoError(t, err) 31 | 32 | createInput := &kms.CreateKeyInput{ 33 | Policy: aws.String(fmt.Sprintf(`{ 34 | "Version": "2012-10-17", 35 | "Statement": [ 36 | { 37 | "Effect": "Allow", 38 | "Principal": { 39 | "AWS": "arn:aws:iam::%s:root" 40 | }, 41 | "Action": "kms:*", 42 | "Resource": "*" 43 | } 44 | ] 45 | }`, *ident.Account)), 46 | } 47 | 48 | out, err := svc.CreateKey(createInput) 49 | assert.NoError(t, err) 50 | assert.NotNil(t, out) 51 | 52 | kmsKey := KMSKey{ 53 | svc: svc, 54 | ID: out.KeyMetadata.KeyId, 55 | } 56 | 57 | removeError := kmsKey.Remove(context.TODO()) 58 | assert.NoError(t, removeError) 59 | 60 | _, err = svc.DescribeKey(&kms.DescribeKeyInput{ 61 | KeyId: kmsKey.ID, 62 | }) 63 | var awsError awserr.Error 64 | if errors.As(err, &awsError) { 65 | assert.Equal(t, "NoSuchEntity", awsError.Code()) 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /resources/lightsail-disks.go: -------------------------------------------------------------------------------- 1 | package resources 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/aws/aws-sdk-go/service/lightsail" 7 | 8 | "github.com/ekristen/libnuke/pkg/registry" 9 | "github.com/ekristen/libnuke/pkg/resource" 10 | 11 | "github.com/ekristen/aws-nuke/v3/pkg/nuke" 12 | ) 13 | 14 | const LightsailDiskResource = "LightsailDisk" 15 | 16 | func init() { 17 | registry.Register(®istry.Registration{ 18 | Name: LightsailDiskResource, 19 | Scope: nuke.Account, 20 | Lister: &LightsailDiskLister{}, 21 | }) 22 | } 23 | 24 | type LightsailDiskLister struct{} 25 | 26 | func (l *LightsailDiskLister) List(_ context.Context, o interface{}) ([]resource.Resource, error) { 27 | opts := o.(*nuke.ListerOpts) 28 | 29 | svc := lightsail.New(opts.Session) 30 | resources := make([]resource.Resource, 0) 31 | 32 | params := &lightsail.GetDisksInput{} 33 | 34 | for { 35 | output, err := svc.GetDisks(params) 36 | if err != nil { 37 | return nil, err 38 | } 39 | 40 | for _, disk := range output.Disks { 41 | resources = append(resources, &LightsailDisk{ 42 | svc: svc, 43 | diskName: disk.Name, 44 | }) 45 | } 46 | 47 | if output.NextPageToken == nil { 48 | break 49 | } 50 | 51 | params.PageToken = output.NextPageToken 52 | } 53 | 54 | return resources, nil 55 | } 56 | 57 | type LightsailDisk struct { 58 | svc *lightsail.Lightsail 59 | diskName *string 60 | } 61 | 62 | func (f *LightsailDisk) Remove(_ context.Context) error { 63 | _, err := f.svc.DeleteDisk(&lightsail.DeleteDiskInput{ 64 | DiskName: f.diskName, 65 | }) 66 | 67 | return err 68 | } 69 | 70 | func (f *LightsailDisk) String() string { 71 | return *f.diskName 72 | } 73 | -------------------------------------------------------------------------------- /resources/cloudtrail-trails.go: -------------------------------------------------------------------------------- 1 | package resources 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/aws/aws-sdk-go/service/cloudtrail" 7 | 8 | "github.com/ekristen/libnuke/pkg/registry" 9 | "github.com/ekristen/libnuke/pkg/resource" 10 | "github.com/ekristen/libnuke/pkg/types" 11 | 12 | "github.com/ekristen/aws-nuke/v3/pkg/nuke" 13 | ) 14 | 15 | const CloudTrailTrailResource = "CloudTrailTrail" 16 | 17 | func init() { 18 | registry.Register(®istry.Registration{ 19 | Name: CloudTrailTrailResource, 20 | Scope: nuke.Account, 21 | Lister: &CloudTrailTrailLister{}, 22 | }) 23 | } 24 | 25 | type CloudTrailTrailLister struct{} 26 | 27 | func (l *CloudTrailTrailLister) List(_ context.Context, o interface{}) ([]resource.Resource, error) { 28 | opts := o.(*nuke.ListerOpts) 29 | 30 | svc := cloudtrail.New(opts.Session) 31 | 32 | resp, err := svc.DescribeTrails(nil) 33 | if err != nil { 34 | return nil, err 35 | } 36 | 37 | resources := make([]resource.Resource, 0) 38 | for _, trail := range resp.TrailList { 39 | resources = append(resources, &CloudTrailTrail{ 40 | svc: svc, 41 | name: trail.Name, 42 | }) 43 | } 44 | 45 | return resources, nil 46 | } 47 | 48 | type CloudTrailTrail struct { 49 | svc *cloudtrail.CloudTrail 50 | name *string 51 | } 52 | 53 | func (trail *CloudTrailTrail) Remove(_ context.Context) error { 54 | _, err := trail.svc.DeleteTrail(&cloudtrail.DeleteTrailInput{ 55 | Name: trail.name, 56 | }) 57 | return err 58 | } 59 | 60 | func (trail *CloudTrailTrail) Properties() types.Properties { 61 | return types.NewProperties(). 62 | Set("Name", trail.name) 63 | } 64 | 65 | func (trail *CloudTrailTrail) String() string { 66 | return *trail.name 67 | } 68 | -------------------------------------------------------------------------------- /resources/glue-crawlers.go: -------------------------------------------------------------------------------- 1 | package resources 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/aws/aws-sdk-go/aws" 7 | "github.com/aws/aws-sdk-go/service/glue" 8 | 9 | "github.com/ekristen/libnuke/pkg/registry" 10 | "github.com/ekristen/libnuke/pkg/resource" 11 | 12 | "github.com/ekristen/aws-nuke/v3/pkg/nuke" 13 | ) 14 | 15 | const GlueCrawlerResource = "GlueCrawler" 16 | 17 | func init() { 18 | registry.Register(®istry.Registration{ 19 | Name: GlueCrawlerResource, 20 | Scope: nuke.Account, 21 | Lister: &GlueCrawlerLister{}, 22 | }) 23 | } 24 | 25 | type GlueCrawlerLister struct{} 26 | 27 | func (l *GlueCrawlerLister) List(_ context.Context, o interface{}) ([]resource.Resource, error) { 28 | opts := o.(*nuke.ListerOpts) 29 | 30 | svc := glue.New(opts.Session) 31 | resources := make([]resource.Resource, 0) 32 | 33 | params := &glue.GetCrawlersInput{ 34 | MaxResults: aws.Int64(100), 35 | } 36 | 37 | for { 38 | output, err := svc.GetCrawlers(params) 39 | if err != nil { 40 | return nil, err 41 | } 42 | 43 | for _, crawler := range output.Crawlers { 44 | resources = append(resources, &GlueCrawler{ 45 | svc: svc, 46 | name: crawler.Name, 47 | }) 48 | } 49 | 50 | if output.NextToken == nil { 51 | break 52 | } 53 | 54 | params.NextToken = output.NextToken 55 | } 56 | 57 | return resources, nil 58 | } 59 | 60 | type GlueCrawler struct { 61 | svc *glue.Glue 62 | name *string 63 | } 64 | 65 | func (f *GlueCrawler) Remove(_ context.Context) error { 66 | _, err := f.svc.DeleteCrawler(&glue.DeleteCrawlerInput{ 67 | Name: f.name, 68 | }) 69 | 70 | return err 71 | } 72 | 73 | func (f *GlueCrawler) String() string { 74 | return *f.name 75 | } 76 | -------------------------------------------------------------------------------- /resources/glue-triggers.go: -------------------------------------------------------------------------------- 1 | package resources 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/aws/aws-sdk-go/aws" 7 | "github.com/aws/aws-sdk-go/service/glue" 8 | 9 | "github.com/ekristen/libnuke/pkg/registry" 10 | "github.com/ekristen/libnuke/pkg/resource" 11 | 12 | "github.com/ekristen/aws-nuke/v3/pkg/nuke" 13 | ) 14 | 15 | const GlueTriggerResource = "GlueTrigger" 16 | 17 | func init() { 18 | registry.Register(®istry.Registration{ 19 | Name: GlueTriggerResource, 20 | Scope: nuke.Account, 21 | Lister: &GlueTriggerLister{}, 22 | }) 23 | } 24 | 25 | type GlueTriggerLister struct{} 26 | 27 | func (l *GlueTriggerLister) List(_ context.Context, o interface{}) ([]resource.Resource, error) { 28 | opts := o.(*nuke.ListerOpts) 29 | 30 | svc := glue.New(opts.Session) 31 | resources := make([]resource.Resource, 0) 32 | 33 | params := &glue.GetTriggersInput{ 34 | MaxResults: aws.Int64(100), 35 | } 36 | 37 | for { 38 | output, err := svc.GetTriggers(params) 39 | if err != nil { 40 | return nil, err 41 | } 42 | 43 | for _, trigger := range output.Triggers { 44 | resources = append(resources, &GlueTrigger{ 45 | svc: svc, 46 | name: trigger.Name, 47 | }) 48 | } 49 | 50 | if output.NextToken == nil { 51 | break 52 | } 53 | 54 | params.NextToken = output.NextToken 55 | } 56 | 57 | return resources, nil 58 | } 59 | 60 | type GlueTrigger struct { 61 | svc *glue.Glue 62 | name *string 63 | } 64 | 65 | func (f *GlueTrigger) Remove(_ context.Context) error { 66 | _, err := f.svc.DeleteTrigger(&glue.DeleteTriggerInput{ 67 | Name: f.name, 68 | }) 69 | 70 | return err 71 | } 72 | 73 | func (f *GlueTrigger) String() string { 74 | return *f.name 75 | } 76 | -------------------------------------------------------------------------------- /resources/iot-jobs.go: -------------------------------------------------------------------------------- 1 | package resources 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/aws/aws-sdk-go/aws" 7 | "github.com/aws/aws-sdk-go/service/iot" 8 | 9 | "github.com/ekristen/libnuke/pkg/registry" 10 | "github.com/ekristen/libnuke/pkg/resource" 11 | 12 | "github.com/ekristen/aws-nuke/v3/pkg/nuke" 13 | ) 14 | 15 | const IoTJobResource = "IoTJob" 16 | 17 | func init() { 18 | registry.Register(®istry.Registration{ 19 | Name: IoTJobResource, 20 | Scope: nuke.Account, 21 | Lister: &IoTJobLister{}, 22 | }) 23 | } 24 | 25 | type IoTJobLister struct{} 26 | 27 | func (l *IoTJobLister) List(_ context.Context, o interface{}) ([]resource.Resource, error) { 28 | opts := o.(*nuke.ListerOpts) 29 | 30 | svc := iot.New(opts.Session) 31 | resources := make([]resource.Resource, 0) 32 | 33 | params := &iot.ListJobsInput{ 34 | MaxResults: aws.Int64(100), 35 | Status: aws.String("IN_PROGRESS"), 36 | } 37 | for { 38 | output, err := svc.ListJobs(params) 39 | if err != nil { 40 | return nil, err 41 | } 42 | 43 | for _, job := range output.Jobs { 44 | resources = append(resources, &IoTJob{ 45 | svc: svc, 46 | ID: job.JobId, 47 | status: job.Status, 48 | }) 49 | } 50 | if output.NextToken == nil { 51 | break 52 | } 53 | 54 | params.NextToken = output.NextToken 55 | } 56 | 57 | return resources, nil 58 | } 59 | 60 | type IoTJob struct { 61 | svc *iot.IoT 62 | ID *string 63 | status *string 64 | } 65 | 66 | func (f *IoTJob) Remove(_ context.Context) error { 67 | _, err := f.svc.CancelJob(&iot.CancelJobInput{ 68 | JobId: f.ID, 69 | }) 70 | 71 | return err 72 | } 73 | 74 | func (f *IoTJob) String() string { 75 | return *f.ID 76 | } 77 | -------------------------------------------------------------------------------- /resources/iot-topicrules.go: -------------------------------------------------------------------------------- 1 | package resources 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/aws/aws-sdk-go/aws" 7 | "github.com/aws/aws-sdk-go/service/iot" 8 | 9 | "github.com/ekristen/libnuke/pkg/registry" 10 | "github.com/ekristen/libnuke/pkg/resource" 11 | 12 | "github.com/ekristen/aws-nuke/v3/pkg/nuke" 13 | ) 14 | 15 | const IoTTopicRuleResource = "IoTTopicRule" 16 | 17 | func init() { 18 | registry.Register(®istry.Registration{ 19 | Name: IoTTopicRuleResource, 20 | Scope: nuke.Account, 21 | Lister: &IoTTopicRuleLister{}, 22 | }) 23 | } 24 | 25 | type IoTTopicRuleLister struct{} 26 | 27 | func (l *IoTTopicRuleLister) List(_ context.Context, o interface{}) ([]resource.Resource, error) { 28 | opts := o.(*nuke.ListerOpts) 29 | 30 | svc := iot.New(opts.Session) 31 | resources := make([]resource.Resource, 0) 32 | 33 | params := &iot.ListTopicRulesInput{ 34 | MaxResults: aws.Int64(100), 35 | } 36 | for { 37 | output, err := svc.ListTopicRules(params) 38 | if err != nil { 39 | return nil, err 40 | } 41 | 42 | for _, rule := range output.Rules { 43 | resources = append(resources, &IoTTopicRule{ 44 | svc: svc, 45 | name: rule.RuleName, 46 | }) 47 | } 48 | if output.NextToken == nil { 49 | break 50 | } 51 | 52 | params.NextToken = output.NextToken 53 | } 54 | 55 | return resources, nil 56 | } 57 | 58 | type IoTTopicRule struct { 59 | svc *iot.IoT 60 | name *string 61 | } 62 | 63 | func (f *IoTTopicRule) Remove(_ context.Context) error { 64 | _, err := f.svc.DeleteTopicRule(&iot.DeleteTopicRuleInput{ 65 | RuleName: f.name, 66 | }) 67 | 68 | return err 69 | } 70 | 71 | func (f *IoTTopicRule) String() string { 72 | return *f.name 73 | } 74 | -------------------------------------------------------------------------------- /resources/devicefarm-projects.go: -------------------------------------------------------------------------------- 1 | package resources 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/aws/aws-sdk-go/service/devicefarm" 7 | 8 | "github.com/ekristen/libnuke/pkg/registry" 9 | "github.com/ekristen/libnuke/pkg/resource" 10 | 11 | "github.com/ekristen/aws-nuke/v3/pkg/nuke" 12 | ) 13 | 14 | const DeviceFarmProjectResource = "DeviceFarmProject" 15 | 16 | func init() { 17 | registry.Register(®istry.Registration{ 18 | Name: DeviceFarmProjectResource, 19 | Scope: nuke.Account, 20 | Lister: &DeviceFarmProjectLister{}, 21 | }) 22 | } 23 | 24 | type DeviceFarmProjectLister struct{} 25 | 26 | func (l *DeviceFarmProjectLister) List(_ context.Context, o interface{}) ([]resource.Resource, error) { 27 | opts := o.(*nuke.ListerOpts) 28 | 29 | svc := devicefarm.New(opts.Session) 30 | resources := make([]resource.Resource, 0) 31 | 32 | params := &devicefarm.ListProjectsInput{} 33 | 34 | for { 35 | output, err := svc.ListProjects(params) 36 | if err != nil { 37 | return nil, err 38 | } 39 | 40 | for _, project := range output.Projects { 41 | resources = append(resources, &DeviceFarmProject{ 42 | svc: svc, 43 | ARN: project.Arn, 44 | }) 45 | } 46 | 47 | if output.NextToken == nil { 48 | break 49 | } 50 | 51 | params.NextToken = output.NextToken 52 | } 53 | 54 | return resources, nil 55 | } 56 | 57 | type DeviceFarmProject struct { 58 | svc *devicefarm.DeviceFarm 59 | ARN *string 60 | } 61 | 62 | func (f *DeviceFarmProject) Remove(_ context.Context) error { 63 | _, err := f.svc.DeleteProject(&devicefarm.DeleteProjectInput{ 64 | Arn: f.ARN, 65 | }) 66 | 67 | return err 68 | } 69 | 70 | func (f *DeviceFarmProject) String() string { 71 | return *f.ARN 72 | } 73 | -------------------------------------------------------------------------------- /resources/inspector-assessment-templates.go: -------------------------------------------------------------------------------- 1 | package resources 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/aws/aws-sdk-go/service/inspector" 7 | 8 | "github.com/ekristen/libnuke/pkg/registry" 9 | "github.com/ekristen/libnuke/pkg/resource" 10 | 11 | "github.com/ekristen/aws-nuke/v3/pkg/nuke" 12 | ) 13 | 14 | const InspectorAssessmentTemplateResource = "InspectorAssessmentTemplate" 15 | 16 | func init() { 17 | registry.Register(®istry.Registration{ 18 | Name: InspectorAssessmentTemplateResource, 19 | Scope: nuke.Account, 20 | Lister: &InspectorAssessmentTemplateLister{}, 21 | }) 22 | } 23 | 24 | type InspectorAssessmentTemplateLister struct{} 25 | 26 | func (l *InspectorAssessmentTemplateLister) List(_ context.Context, o interface{}) ([]resource.Resource, error) { 27 | opts := o.(*nuke.ListerOpts) 28 | 29 | svc := inspector.New(opts.Session) 30 | 31 | resp, err := svc.ListAssessmentTemplates(nil) 32 | if err != nil { 33 | return nil, err 34 | } 35 | 36 | resources := make([]resource.Resource, 0) 37 | for _, out := range resp.AssessmentTemplateArns { 38 | resources = append(resources, &InspectorAssessmentTemplate{ 39 | svc: svc, 40 | arn: *out, 41 | }) 42 | } 43 | 44 | return resources, nil 45 | } 46 | 47 | type InspectorAssessmentTemplate struct { 48 | svc *inspector.Inspector 49 | arn string 50 | } 51 | 52 | func (e *InspectorAssessmentTemplate) Remove(_ context.Context) error { 53 | _, err := e.svc.DeleteAssessmentTemplate(&inspector.DeleteAssessmentTemplateInput{ 54 | AssessmentTemplateArn: &e.arn, 55 | }) 56 | if err != nil { 57 | return err 58 | } 59 | 60 | return nil 61 | } 62 | 63 | func (e *InspectorAssessmentTemplate) String() string { 64 | return e.arn 65 | } 66 | -------------------------------------------------------------------------------- /resources/iot-otaupdates.go: -------------------------------------------------------------------------------- 1 | package resources 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/aws/aws-sdk-go/aws" 7 | "github.com/aws/aws-sdk-go/service/iot" 8 | 9 | "github.com/ekristen/libnuke/pkg/registry" 10 | "github.com/ekristen/libnuke/pkg/resource" 11 | 12 | "github.com/ekristen/aws-nuke/v3/pkg/nuke" 13 | ) 14 | 15 | const IoTOTAUpdateResource = "IoTOTAUpdate" 16 | 17 | func init() { 18 | registry.Register(®istry.Registration{ 19 | Name: IoTOTAUpdateResource, 20 | Scope: nuke.Account, 21 | Lister: &IoTOTAUpdateLister{}, 22 | }) 23 | } 24 | 25 | type IoTOTAUpdateLister struct{} 26 | 27 | func (l *IoTOTAUpdateLister) List(_ context.Context, o interface{}) ([]resource.Resource, error) { 28 | opts := o.(*nuke.ListerOpts) 29 | 30 | svc := iot.New(opts.Session) 31 | resources := make([]resource.Resource, 0) 32 | 33 | params := &iot.ListOTAUpdatesInput{ 34 | MaxResults: aws.Int64(100), 35 | } 36 | for { 37 | output, err := svc.ListOTAUpdates(params) 38 | if err != nil { 39 | return nil, err 40 | } 41 | 42 | for _, otaUpdate := range output.OtaUpdates { 43 | resources = append(resources, &IoTOTAUpdate{ 44 | svc: svc, 45 | ID: otaUpdate.OtaUpdateId, 46 | }) 47 | } 48 | if output.NextToken == nil { 49 | break 50 | } 51 | 52 | params.NextToken = output.NextToken 53 | } 54 | 55 | return resources, nil 56 | } 57 | 58 | type IoTOTAUpdate struct { 59 | svc *iot.IoT 60 | ID *string 61 | } 62 | 63 | func (f *IoTOTAUpdate) Remove(_ context.Context) error { 64 | _, err := f.svc.DeleteOTAUpdate(&iot.DeleteOTAUpdateInput{ 65 | OtaUpdateId: f.ID, 66 | }) 67 | 68 | return err 69 | } 70 | 71 | func (f *IoTOTAUpdate) String() string { 72 | return *f.ID 73 | } 74 | -------------------------------------------------------------------------------- /resources/glue-databases.go: -------------------------------------------------------------------------------- 1 | package resources 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/aws/aws-sdk-go/aws" 7 | "github.com/aws/aws-sdk-go/service/glue" 8 | 9 | "github.com/ekristen/libnuke/pkg/registry" 10 | "github.com/ekristen/libnuke/pkg/resource" 11 | 12 | "github.com/ekristen/aws-nuke/v3/pkg/nuke" 13 | ) 14 | 15 | const GlueDatabaseResource = "GlueDatabase" 16 | 17 | func init() { 18 | registry.Register(®istry.Registration{ 19 | Name: GlueDatabaseResource, 20 | Scope: nuke.Account, 21 | Lister: &GlueDatabaseLister{}, 22 | }) 23 | } 24 | 25 | type GlueDatabaseLister struct{} 26 | 27 | func (l *GlueDatabaseLister) List(_ context.Context, o interface{}) ([]resource.Resource, error) { 28 | opts := o.(*nuke.ListerOpts) 29 | 30 | svc := glue.New(opts.Session) 31 | resources := make([]resource.Resource, 0) 32 | 33 | params := &glue.GetDatabasesInput{ 34 | MaxResults: aws.Int64(100), 35 | } 36 | 37 | for { 38 | output, err := svc.GetDatabases(params) 39 | if err != nil { 40 | return nil, err 41 | } 42 | 43 | for _, database := range output.DatabaseList { 44 | resources = append(resources, &GlueDatabase{ 45 | svc: svc, 46 | name: database.Name, 47 | }) 48 | } 49 | 50 | if output.NextToken == nil { 51 | break 52 | } 53 | 54 | params.NextToken = output.NextToken 55 | } 56 | 57 | return resources, nil 58 | } 59 | 60 | type GlueDatabase struct { 61 | svc *glue.Glue 62 | name *string 63 | } 64 | 65 | func (f *GlueDatabase) Remove(_ context.Context) error { 66 | _, err := f.svc.DeleteDatabase(&glue.DeleteDatabaseInput{ 67 | Name: f.name, 68 | }) 69 | 70 | return err 71 | } 72 | 73 | func (f *GlueDatabase) String() string { 74 | return *f.name 75 | } 76 | -------------------------------------------------------------------------------- /resources/inspector2.go: -------------------------------------------------------------------------------- 1 | package resources 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/aws/aws-sdk-go/aws" 7 | "github.com/aws/aws-sdk-go/service/inspector2" 8 | 9 | "github.com/ekristen/libnuke/pkg/registry" 10 | "github.com/ekristen/libnuke/pkg/resource" 11 | 12 | "github.com/ekristen/aws-nuke/v3/pkg/nuke" 13 | ) 14 | 15 | const Inspector2Resource = "Inspector2" 16 | 17 | func init() { 18 | registry.Register(®istry.Registration{ 19 | Name: Inspector2Resource, 20 | Scope: nuke.Account, 21 | Lister: &Inspector2Lister{}, 22 | }) 23 | } 24 | 25 | type Inspector2Lister struct{} 26 | 27 | func (l *Inspector2Lister) List(_ context.Context, o interface{}) ([]resource.Resource, error) { 28 | opts := o.(*nuke.ListerOpts) 29 | 30 | svc := inspector2.New(opts.Session) 31 | 32 | resources := make([]resource.Resource, 0) 33 | 34 | resp, err := svc.BatchGetAccountStatus(nil) 35 | if err != nil { 36 | return resources, err 37 | } 38 | for _, a := range resp.Accounts { 39 | if *a.State.Status != inspector2.StatusDisabled { 40 | resources = append(resources, &Inspector2{ 41 | svc: svc, 42 | accountID: a.AccountId, 43 | }) 44 | } 45 | } 46 | 47 | return resources, nil 48 | } 49 | 50 | type Inspector2 struct { 51 | svc *inspector2.Inspector2 52 | accountID *string 53 | } 54 | 55 | func (e *Inspector2) Remove(_ context.Context) error { 56 | _, err := e.svc.Disable(&inspector2.DisableInput{ 57 | AccountIds: []*string{e.accountID}, 58 | ResourceTypes: aws.StringSlice(inspector2.ResourceScanType_Values()), 59 | }) 60 | if err != nil { 61 | return err 62 | } 63 | 64 | return nil 65 | } 66 | 67 | func (e *Inspector2) String() string { 68 | return *e.accountID 69 | } 70 | -------------------------------------------------------------------------------- /resources/iot-thingtypes.go: -------------------------------------------------------------------------------- 1 | package resources 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/aws/aws-sdk-go/aws" 7 | "github.com/aws/aws-sdk-go/service/iot" 8 | 9 | "github.com/ekristen/libnuke/pkg/registry" 10 | "github.com/ekristen/libnuke/pkg/resource" 11 | 12 | "github.com/ekristen/aws-nuke/v3/pkg/nuke" 13 | ) 14 | 15 | const IoTThingTypeResource = "IoTThingType" 16 | 17 | func init() { 18 | registry.Register(®istry.Registration{ 19 | Name: IoTThingTypeResource, 20 | Scope: nuke.Account, 21 | Lister: &IoTThingTypeLister{}, 22 | }) 23 | } 24 | 25 | type IoTThingTypeLister struct{} 26 | 27 | func (l *IoTThingTypeLister) List(_ context.Context, o interface{}) ([]resource.Resource, error) { 28 | opts := o.(*nuke.ListerOpts) 29 | 30 | svc := iot.New(opts.Session) 31 | resources := make([]resource.Resource, 0) 32 | 33 | params := &iot.ListThingTypesInput{ 34 | MaxResults: aws.Int64(100), 35 | } 36 | for { 37 | output, err := svc.ListThingTypes(params) 38 | if err != nil { 39 | return nil, err 40 | } 41 | 42 | for _, thingType := range output.ThingTypes { 43 | resources = append(resources, &IoTThingType{ 44 | svc: svc, 45 | name: thingType.ThingTypeName, 46 | }) 47 | } 48 | if output.NextToken == nil { 49 | break 50 | } 51 | 52 | params.NextToken = output.NextToken 53 | } 54 | 55 | return resources, nil 56 | } 57 | 58 | type IoTThingType struct { 59 | svc *iot.IoT 60 | name *string 61 | } 62 | 63 | func (f *IoTThingType) Remove(_ context.Context) error { 64 | _, err := f.svc.DeleteThingType(&iot.DeleteThingTypeInput{ 65 | ThingTypeName: f.name, 66 | }) 67 | 68 | return err 69 | } 70 | 71 | func (f *IoTThingType) String() string { 72 | return *f.name 73 | } 74 | -------------------------------------------------------------------------------- /resources/ses-identities.go: -------------------------------------------------------------------------------- 1 | package resources 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/aws/aws-sdk-go/aws" 7 | "github.com/aws/aws-sdk-go/service/ses" 8 | 9 | "github.com/ekristen/libnuke/pkg/registry" 10 | "github.com/ekristen/libnuke/pkg/resource" 11 | 12 | "github.com/ekristen/aws-nuke/v3/pkg/nuke" 13 | ) 14 | 15 | const SESIdentityResource = "SESIdentity" 16 | 17 | func init() { 18 | registry.Register(®istry.Registration{ 19 | Name: SESIdentityResource, 20 | Scope: nuke.Account, 21 | Lister: &SESIdentityLister{}, 22 | }) 23 | } 24 | 25 | type SESIdentityLister struct{} 26 | 27 | func (l *SESIdentityLister) List(_ context.Context, o interface{}) ([]resource.Resource, error) { 28 | opts := o.(*nuke.ListerOpts) 29 | 30 | svc := ses.New(opts.Session) 31 | resources := make([]resource.Resource, 0) 32 | 33 | params := &ses.ListIdentitiesInput{ 34 | MaxItems: aws.Int64(100), 35 | } 36 | 37 | for { 38 | output, err := svc.ListIdentities(params) 39 | if err != nil { 40 | return nil, err 41 | } 42 | 43 | for _, identity := range output.Identities { 44 | resources = append(resources, &SESIdentity{ 45 | svc: svc, 46 | identity: identity, 47 | }) 48 | } 49 | 50 | if output.NextToken == nil { 51 | break 52 | } 53 | 54 | params.NextToken = output.NextToken 55 | } 56 | 57 | return resources, nil 58 | } 59 | 60 | type SESIdentity struct { 61 | svc *ses.SES 62 | identity *string 63 | } 64 | 65 | func (f *SESIdentity) Remove(_ context.Context) error { 66 | _, err := f.svc.DeleteIdentity(&ses.DeleteIdentityInput{ 67 | Identity: f.identity, 68 | }) 69 | 70 | return err 71 | } 72 | 73 | func (f *SESIdentity) String() string { 74 | return *f.identity 75 | } 76 | -------------------------------------------------------------------------------- /resources/ses-templates.go: -------------------------------------------------------------------------------- 1 | package resources 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/aws/aws-sdk-go/aws" 7 | "github.com/aws/aws-sdk-go/service/ses" 8 | 9 | "github.com/ekristen/libnuke/pkg/registry" 10 | "github.com/ekristen/libnuke/pkg/resource" 11 | 12 | "github.com/ekristen/aws-nuke/v3/pkg/nuke" 13 | ) 14 | 15 | const SESTemplateResource = "SESTemplate" 16 | 17 | func init() { 18 | registry.Register(®istry.Registration{ 19 | Name: SESTemplateResource, 20 | Scope: nuke.Account, 21 | Lister: &SESTemplateLister{}, 22 | }) 23 | } 24 | 25 | type SESTemplateLister struct{} 26 | 27 | func (l *SESTemplateLister) List(_ context.Context, o interface{}) ([]resource.Resource, error) { 28 | opts := o.(*nuke.ListerOpts) 29 | 30 | svc := ses.New(opts.Session) 31 | resources := make([]resource.Resource, 0) 32 | 33 | params := &ses.ListTemplatesInput{ 34 | MaxItems: aws.Int64(100), 35 | } 36 | 37 | for { 38 | output, err := svc.ListTemplates(params) 39 | if err != nil { 40 | return nil, err 41 | } 42 | 43 | for _, templateMetadata := range output.TemplatesMetadata { 44 | resources = append(resources, &SESTemplate{ 45 | svc: svc, 46 | name: templateMetadata.Name, 47 | }) 48 | } 49 | 50 | if output.NextToken == nil { 51 | break 52 | } 53 | 54 | params.NextToken = output.NextToken 55 | } 56 | 57 | return resources, nil 58 | } 59 | 60 | type SESTemplate struct { 61 | svc *ses.SES 62 | name *string 63 | } 64 | 65 | func (f *SESTemplate) Remove(_ context.Context) error { 66 | _, err := f.svc.DeleteTemplate(&ses.DeleteTemplateInput{ 67 | TemplateName: f.name, 68 | }) 69 | 70 | return err 71 | } 72 | 73 | func (f *SESTemplate) String() string { 74 | return *f.name 75 | } 76 | -------------------------------------------------------------------------------- /resources/iot-rolealiases.go: -------------------------------------------------------------------------------- 1 | package resources 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/aws/aws-sdk-go/aws" 7 | "github.com/aws/aws-sdk-go/service/iot" 8 | 9 | "github.com/ekristen/libnuke/pkg/registry" 10 | "github.com/ekristen/libnuke/pkg/resource" 11 | 12 | "github.com/ekristen/aws-nuke/v3/pkg/nuke" 13 | ) 14 | 15 | const IoTRoleAliasResource = "IoTRoleAlias" 16 | 17 | func init() { 18 | registry.Register(®istry.Registration{ 19 | Name: IoTRoleAliasResource, 20 | Scope: nuke.Account, 21 | Lister: &IoTRoleAliasLister{}, 22 | }) 23 | } 24 | 25 | type IoTRoleAliasLister struct{} 26 | 27 | func (l *IoTRoleAliasLister) List(_ context.Context, o interface{}) ([]resource.Resource, error) { 28 | opts := o.(*nuke.ListerOpts) 29 | 30 | svc := iot.New(opts.Session) 31 | resources := make([]resource.Resource, 0) 32 | 33 | params := &iot.ListRoleAliasesInput{ 34 | PageSize: aws.Int64(25), 35 | } 36 | for { 37 | output, err := svc.ListRoleAliases(params) 38 | if err != nil { 39 | return nil, err 40 | } 41 | 42 | for _, roleAlias := range output.RoleAliases { 43 | resources = append(resources, &IoTRoleAlias{ 44 | svc: svc, 45 | roleAlias: roleAlias, 46 | }) 47 | } 48 | if output.NextMarker == nil { 49 | break 50 | } 51 | 52 | params.Marker = output.NextMarker 53 | } 54 | 55 | return resources, nil 56 | } 57 | 58 | type IoTRoleAlias struct { 59 | svc *iot.IoT 60 | roleAlias *string 61 | } 62 | 63 | func (f *IoTRoleAlias) Remove(_ context.Context) error { 64 | _, err := f.svc.DeleteRoleAlias(&iot.DeleteRoleAliasInput{ 65 | RoleAlias: f.roleAlias, 66 | }) 67 | 68 | return err 69 | } 70 | 71 | func (f *IoTRoleAlias) String() string { 72 | return *f.roleAlias 73 | } 74 | -------------------------------------------------------------------------------- /resources/medialive-inputs.go: -------------------------------------------------------------------------------- 1 | package resources 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/aws/aws-sdk-go/aws" 7 | "github.com/aws/aws-sdk-go/service/medialive" 8 | 9 | "github.com/ekristen/libnuke/pkg/registry" 10 | "github.com/ekristen/libnuke/pkg/resource" 11 | 12 | "github.com/ekristen/aws-nuke/v3/pkg/nuke" 13 | ) 14 | 15 | const MediaLiveInputResource = "MediaLiveInput" 16 | 17 | func init() { 18 | registry.Register(®istry.Registration{ 19 | Name: MediaLiveInputResource, 20 | Scope: nuke.Account, 21 | Lister: &MediaLiveInputLister{}, 22 | }) 23 | } 24 | 25 | type MediaLiveInputLister struct{} 26 | 27 | func (l *MediaLiveInputLister) List(_ context.Context, o interface{}) ([]resource.Resource, error) { 28 | opts := o.(*nuke.ListerOpts) 29 | 30 | svc := medialive.New(opts.Session) 31 | resources := make([]resource.Resource, 0) 32 | 33 | params := &medialive.ListInputsInput{ 34 | MaxResults: aws.Int64(20), 35 | } 36 | 37 | for { 38 | output, err := svc.ListInputs(params) 39 | if err != nil { 40 | return nil, err 41 | } 42 | 43 | for _, input := range output.Inputs { 44 | resources = append(resources, &MediaLiveInput{ 45 | svc: svc, 46 | ID: input.Id, 47 | }) 48 | } 49 | 50 | if output.NextToken == nil { 51 | break 52 | } 53 | 54 | params.NextToken = output.NextToken 55 | } 56 | 57 | return resources, nil 58 | } 59 | 60 | type MediaLiveInput struct { 61 | svc *medialive.MediaLive 62 | ID *string 63 | } 64 | 65 | func (f *MediaLiveInput) Remove(_ context.Context) error { 66 | _, err := f.svc.DeleteInput(&medialive.DeleteInputInput{ 67 | InputId: f.ID, 68 | }) 69 | 70 | return err 71 | } 72 | 73 | func (f *MediaLiveInput) String() string { 74 | return *f.ID 75 | } 76 | -------------------------------------------------------------------------------- /resources/cloudwatchevents-buses.go: -------------------------------------------------------------------------------- 1 | package resources 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/gotidy/ptr" 7 | 8 | "github.com/aws/aws-sdk-go/service/cloudwatchevents" 9 | 10 | "github.com/ekristen/libnuke/pkg/registry" 11 | "github.com/ekristen/libnuke/pkg/resource" 12 | 13 | "github.com/ekristen/aws-nuke/v3/pkg/awsutil" 14 | "github.com/ekristen/aws-nuke/v3/pkg/nuke" 15 | ) 16 | 17 | const CloudWatchEventsBusesResource = "CloudWatchEventsBuses" 18 | 19 | func init() { 20 | registry.Register(®istry.Registration{ 21 | Name: CloudWatchEventsBusesResource, 22 | Scope: nuke.Account, 23 | Lister: &CloudWatchEventsBusesLister{}, 24 | }) 25 | } 26 | 27 | type CloudWatchEventsBusesLister struct{} 28 | 29 | func (l *CloudWatchEventsBusesLister) List(_ context.Context, o interface{}) ([]resource.Resource, error) { 30 | opts := o.(*nuke.ListerOpts) 31 | 32 | svc := cloudwatchevents.New(opts.Session) 33 | 34 | resp, err := svc.ListEventBuses(nil) 35 | if err != nil { 36 | return nil, err 37 | } 38 | 39 | resources := make([]resource.Resource, 0) 40 | for _, bus := range resp.EventBuses { 41 | if ptr.ToString(bus.Name) == awsutil.Default { 42 | continue 43 | } 44 | 45 | resources = append(resources, &CloudWatchEventsBus{ 46 | svc: svc, 47 | name: bus.Name, 48 | }) 49 | } 50 | return resources, nil 51 | } 52 | 53 | type CloudWatchEventsBus struct { 54 | svc *cloudwatchevents.CloudWatchEvents 55 | name *string 56 | } 57 | 58 | func (bus *CloudWatchEventsBus) Remove(_ context.Context) error { 59 | _, err := bus.svc.DeleteEventBus(&cloudwatchevents.DeleteEventBusInput{ 60 | Name: bus.name, 61 | }) 62 | return err 63 | } 64 | 65 | func (bus *CloudWatchEventsBus) String() string { 66 | return *bus.name 67 | } 68 | -------------------------------------------------------------------------------- /resources/opsworks-apps.go: -------------------------------------------------------------------------------- 1 | package resources 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/aws/aws-sdk-go/service/opsworks" 7 | 8 | "github.com/ekristen/libnuke/pkg/registry" 9 | "github.com/ekristen/libnuke/pkg/resource" 10 | 11 | "github.com/ekristen/aws-nuke/v3/pkg/nuke" 12 | ) 13 | 14 | const OpsWorksAppResource = "OpsWorksApp" 15 | 16 | func init() { 17 | registry.Register(®istry.Registration{ 18 | Name: OpsWorksAppResource, 19 | Scope: nuke.Account, 20 | Lister: &OpsWorksAppLister{}, 21 | }) 22 | } 23 | 24 | type OpsWorksAppLister struct{} 25 | 26 | func (l *OpsWorksAppLister) List(_ context.Context, o interface{}) ([]resource.Resource, error) { 27 | opts := o.(*nuke.ListerOpts) 28 | 29 | svc := opsworks.New(opts.Session) 30 | resources := make([]resource.Resource, 0) 31 | 32 | stackParams := &opsworks.DescribeStacksInput{} 33 | 34 | resp, err := svc.DescribeStacks(stackParams) 35 | if err != nil { 36 | return nil, err 37 | } 38 | 39 | appsParams := &opsworks.DescribeAppsInput{} 40 | 41 | for _, stack := range resp.Stacks { 42 | appsParams.StackId = stack.StackId 43 | output, err := svc.DescribeApps(appsParams) 44 | if err != nil { 45 | return nil, err 46 | } 47 | 48 | for _, app := range output.Apps { 49 | resources = append(resources, &OpsWorksApp{ 50 | svc: svc, 51 | ID: app.AppId, 52 | }) 53 | } 54 | } 55 | 56 | return resources, nil 57 | } 58 | 59 | type OpsWorksApp struct { 60 | svc *opsworks.OpsWorks 61 | ID *string 62 | } 63 | 64 | func (f *OpsWorksApp) Remove(_ context.Context) error { 65 | _, err := f.svc.DeleteApp(&opsworks.DeleteAppInput{ 66 | AppId: f.ID, 67 | }) 68 | 69 | return err 70 | } 71 | 72 | func (f *OpsWorksApp) String() string { 73 | return *f.ID 74 | } 75 | -------------------------------------------------------------------------------- /resources/securityhub-hub.go: -------------------------------------------------------------------------------- 1 | package resources 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/aws/aws-sdk-go/service/securityhub" 7 | 8 | "github.com/ekristen/libnuke/pkg/registry" 9 | "github.com/ekristen/libnuke/pkg/resource" 10 | "github.com/ekristen/libnuke/pkg/types" 11 | 12 | "github.com/ekristen/aws-nuke/v3/pkg/awsutil" 13 | "github.com/ekristen/aws-nuke/v3/pkg/nuke" 14 | ) 15 | 16 | const SecurityHubResource = "SecurityHub" 17 | 18 | func init() { 19 | registry.Register(®istry.Registration{ 20 | Name: SecurityHubResource, 21 | Scope: nuke.Account, 22 | Lister: &SecurityHubLister{}, 23 | }) 24 | } 25 | 26 | type SecurityHubLister struct{} 27 | 28 | func (l *SecurityHubLister) List(_ context.Context, o interface{}) ([]resource.Resource, error) { 29 | opts := o.(*nuke.ListerOpts) 30 | 31 | svc := securityhub.New(opts.Session) 32 | 33 | resources := make([]resource.Resource, 0) 34 | 35 | resp, err := svc.DescribeHub(nil) 36 | 37 | if err != nil { 38 | if awsutil.IsAWSError(err, securityhub.ErrCodeInvalidAccessException) { 39 | // Security SecurityHub is not enabled for this region 40 | return resources, nil 41 | } 42 | return nil, err 43 | } 44 | 45 | resources = append(resources, &SecurityHub{ 46 | svc: svc, 47 | id: resp.HubArn, 48 | }) 49 | return resources, nil 50 | } 51 | 52 | type SecurityHub struct { 53 | svc *securityhub.SecurityHub 54 | id *string 55 | } 56 | 57 | func (hub *SecurityHub) Properties() types.Properties { 58 | properties := types.NewProperties() 59 | properties.Set("Arn", hub.id) 60 | return properties 61 | } 62 | 63 | func (hub *SecurityHub) Remove(_ context.Context) error { 64 | _, err := hub.svc.DisableSecurityHub(&securityhub.DisableSecurityHubInput{}) 65 | return err 66 | } 67 | -------------------------------------------------------------------------------- /resources/lightsail-keypairs.go: -------------------------------------------------------------------------------- 1 | package resources 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/aws/aws-sdk-go/service/lightsail" 7 | 8 | "github.com/ekristen/libnuke/pkg/registry" 9 | "github.com/ekristen/libnuke/pkg/resource" 10 | 11 | "github.com/ekristen/aws-nuke/v3/pkg/nuke" 12 | ) 13 | 14 | const LightsailKeyPairResource = "LightsailKeyPair" 15 | 16 | func init() { 17 | registry.Register(®istry.Registration{ 18 | Name: LightsailKeyPairResource, 19 | Scope: nuke.Account, 20 | Lister: &LightsailKeyPairLister{}, 21 | }) 22 | } 23 | 24 | type LightsailKeyPairLister struct{} 25 | 26 | func (l *LightsailKeyPairLister) List(_ context.Context, o interface{}) ([]resource.Resource, error) { 27 | opts := o.(*nuke.ListerOpts) 28 | 29 | svc := lightsail.New(opts.Session) 30 | resources := make([]resource.Resource, 0) 31 | 32 | params := &lightsail.GetKeyPairsInput{} 33 | 34 | for { 35 | output, err := svc.GetKeyPairs(params) 36 | if err != nil { 37 | return nil, err 38 | } 39 | 40 | for _, keyPair := range output.KeyPairs { 41 | resources = append(resources, &LightsailKeyPair{ 42 | svc: svc, 43 | keyPairName: keyPair.Name, 44 | }) 45 | } 46 | 47 | if output.NextPageToken == nil { 48 | break 49 | } 50 | 51 | params.PageToken = output.NextPageToken 52 | } 53 | 54 | return resources, nil 55 | } 56 | 57 | type LightsailKeyPair struct { 58 | svc *lightsail.Lightsail 59 | keyPairName *string 60 | } 61 | 62 | func (f *LightsailKeyPair) Remove(_ context.Context) error { 63 | _, err := f.svc.DeleteKeyPair(&lightsail.DeleteKeyPairInput{ 64 | KeyPairName: f.keyPairName, 65 | }) 66 | 67 | return err 68 | } 69 | 70 | func (f *LightsailKeyPair) String() string { 71 | return *f.keyPairName 72 | } 73 | -------------------------------------------------------------------------------- /resources/ssm-activations.go: -------------------------------------------------------------------------------- 1 | package resources 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/aws/aws-sdk-go/aws" 7 | 8 | "github.com/aws/aws-sdk-go/service/ssm" 9 | 10 | "github.com/ekristen/libnuke/pkg/registry" 11 | "github.com/ekristen/libnuke/pkg/resource" 12 | 13 | "github.com/ekristen/aws-nuke/v3/pkg/nuke" 14 | ) 15 | 16 | const SSMActivationResource = "SSMActivation" 17 | 18 | func init() { 19 | registry.Register(®istry.Registration{ 20 | Name: SSMActivationResource, 21 | Scope: nuke.Account, 22 | Lister: &SSMActivationLister{}, 23 | }) 24 | } 25 | 26 | type SSMActivationLister struct{} 27 | 28 | func (l *SSMActivationLister) List(_ context.Context, o interface{}) ([]resource.Resource, error) { 29 | opts := o.(*nuke.ListerOpts) 30 | 31 | svc := ssm.New(opts.Session) 32 | resources := make([]resource.Resource, 0) 33 | 34 | params := &ssm.DescribeActivationsInput{ 35 | MaxResults: aws.Int64(50), 36 | } 37 | 38 | for { 39 | output, err := svc.DescribeActivations(params) 40 | if err != nil { 41 | return nil, err 42 | } 43 | 44 | for _, activation := range output.ActivationList { 45 | resources = append(resources, &SSMActivation{ 46 | svc: svc, 47 | ID: activation.ActivationId, 48 | }) 49 | } 50 | 51 | if output.NextToken == nil { 52 | break 53 | } 54 | 55 | params.NextToken = output.NextToken 56 | } 57 | 58 | return resources, nil 59 | } 60 | 61 | type SSMActivation struct { 62 | svc *ssm.SSM 63 | ID *string 64 | } 65 | 66 | func (f *SSMActivation) Remove(_ context.Context) error { 67 | _, err := f.svc.DeleteActivation(&ssm.DeleteActivationInput{ 68 | ActivationId: f.ID, 69 | }) 70 | 71 | return err 72 | } 73 | 74 | func (f *SSMActivation) String() string { 75 | return *f.ID 76 | } 77 | -------------------------------------------------------------------------------- /resources/codestar-projects.go: -------------------------------------------------------------------------------- 1 | package resources 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/aws/aws-sdk-go/aws" 7 | "github.com/aws/aws-sdk-go/service/codestar" 8 | 9 | "github.com/ekristen/libnuke/pkg/registry" 10 | "github.com/ekristen/libnuke/pkg/resource" 11 | 12 | "github.com/ekristen/aws-nuke/v3/pkg/nuke" 13 | ) 14 | 15 | const CodeStarProjectResource = "CodeStarProject" 16 | 17 | func init() { 18 | registry.Register(®istry.Registration{ 19 | Name: CodeStarProjectResource, 20 | Scope: nuke.Account, 21 | Lister: &CodeStarProjectLister{}, 22 | }) 23 | } 24 | 25 | type CodeStarProjectLister struct{} 26 | 27 | func (l *CodeStarProjectLister) List(_ context.Context, o interface{}) ([]resource.Resource, error) { 28 | opts := o.(*nuke.ListerOpts) 29 | 30 | svc := codestar.New(opts.Session) 31 | resources := make([]resource.Resource, 0) 32 | 33 | params := &codestar.ListProjectsInput{ 34 | MaxResults: aws.Int64(100), 35 | } 36 | 37 | for { 38 | output, err := svc.ListProjects(params) 39 | if err != nil { 40 | return nil, err 41 | } 42 | 43 | for _, project := range output.Projects { 44 | resources = append(resources, &CodeStarProject{ 45 | svc: svc, 46 | id: project.ProjectId, 47 | }) 48 | } 49 | 50 | if output.NextToken == nil { 51 | break 52 | } 53 | 54 | params.NextToken = output.NextToken 55 | } 56 | 57 | return resources, nil 58 | } 59 | 60 | type CodeStarProject struct { 61 | svc *codestar.CodeStar 62 | id *string 63 | } 64 | 65 | func (f *CodeStarProject) Remove(_ context.Context) error { 66 | _, err := f.svc.DeleteProject(&codestar.DeleteProjectInput{ 67 | Id: f.id, 68 | }) 69 | 70 | return err 71 | } 72 | 73 | func (f *CodeStarProject) String() string { 74 | return *f.id 75 | } 76 | -------------------------------------------------------------------------------- /resources/batch-job-queues.go: -------------------------------------------------------------------------------- 1 | package resources 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/aws/aws-sdk-go/aws" 7 | "github.com/aws/aws-sdk-go/service/batch" 8 | 9 | "github.com/ekristen/libnuke/pkg/registry" 10 | "github.com/ekristen/libnuke/pkg/resource" 11 | 12 | "github.com/ekristen/aws-nuke/v3/pkg/nuke" 13 | ) 14 | 15 | const BatchJobQueueResource = "BatchJobQueue" 16 | 17 | func init() { 18 | registry.Register(®istry.Registration{ 19 | Name: BatchJobQueueResource, 20 | Scope: nuke.Account, 21 | Lister: &BatchJobQueueLister{}, 22 | }) 23 | } 24 | 25 | type BatchJobQueueLister struct{} 26 | 27 | func (l *BatchJobQueueLister) List(_ context.Context, o interface{}) ([]resource.Resource, error) { 28 | opts := o.(*nuke.ListerOpts) 29 | 30 | svc := batch.New(opts.Session) 31 | resources := make([]resource.Resource, 0) 32 | 33 | params := &batch.DescribeJobQueuesInput{ 34 | MaxResults: aws.Int64(100), 35 | } 36 | 37 | for { 38 | output, err := svc.DescribeJobQueues(params) 39 | if err != nil { 40 | return nil, err 41 | } 42 | 43 | for _, queue := range output.JobQueues { 44 | resources = append(resources, &BatchJobQueue{ 45 | svc: svc, 46 | jobQueue: queue.JobQueueName, 47 | }) 48 | } 49 | 50 | if output.NextToken == nil { 51 | break 52 | } 53 | 54 | params.NextToken = output.NextToken 55 | } 56 | 57 | return resources, nil 58 | } 59 | 60 | type BatchJobQueue struct { 61 | svc *batch.Batch 62 | jobQueue *string 63 | } 64 | 65 | func (f *BatchJobQueue) Remove(_ context.Context) error { 66 | _, err := f.svc.DeleteJobQueue(&batch.DeleteJobQueueInput{ 67 | JobQueue: f.jobQueue, 68 | }) 69 | 70 | return err 71 | } 72 | 73 | func (f *BatchJobQueue) String() string { 74 | return *f.jobQueue 75 | } 76 | -------------------------------------------------------------------------------- /resources/gluedatabrew-jobs.go: -------------------------------------------------------------------------------- 1 | package resources 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/aws/aws-sdk-go/aws" 7 | "github.com/aws/aws-sdk-go/service/gluedatabrew" 8 | 9 | "github.com/ekristen/libnuke/pkg/registry" 10 | "github.com/ekristen/libnuke/pkg/resource" 11 | 12 | "github.com/ekristen/aws-nuke/v3/pkg/nuke" 13 | ) 14 | 15 | const GlueDataBrewJobsResource = "GlueDataBrewJobs" 16 | 17 | func init() { 18 | registry.Register(®istry.Registration{ 19 | Name: GlueDataBrewJobsResource, 20 | Scope: nuke.Account, 21 | Lister: &GlueDataBrewJobsLister{}, 22 | }) 23 | } 24 | 25 | type GlueDataBrewJobsLister struct{} 26 | 27 | func (l *GlueDataBrewJobsLister) List(_ context.Context, o interface{}) ([]resource.Resource, error) { 28 | opts := o.(*nuke.ListerOpts) 29 | 30 | svc := gluedatabrew.New(opts.Session) 31 | resources := make([]resource.Resource, 0) 32 | 33 | params := &gluedatabrew.ListJobsInput{ 34 | MaxResults: aws.Int64(100), 35 | } 36 | 37 | for { 38 | output, err := svc.ListJobs(params) 39 | if err != nil { 40 | return nil, err 41 | } 42 | 43 | for _, jobs := range output.Jobs { 44 | resources = append(resources, &GlueDataBrewJobs{ 45 | svc: svc, 46 | name: jobs.Name, 47 | }) 48 | } 49 | 50 | if output.NextToken == nil { 51 | break 52 | } 53 | 54 | params.NextToken = output.NextToken 55 | } 56 | 57 | return resources, nil 58 | } 59 | 60 | type GlueDataBrewJobs struct { 61 | svc *gluedatabrew.GlueDataBrew 62 | name *string 63 | } 64 | 65 | func (f *GlueDataBrewJobs) Remove(_ context.Context) error { 66 | _, err := f.svc.DeleteJob(&gluedatabrew.DeleteJobInput{ 67 | Name: f.name, 68 | }) 69 | 70 | return err 71 | } 72 | 73 | func (f *GlueDataBrewJobs) String() string { 74 | return *f.name 75 | } 76 | -------------------------------------------------------------------------------- /resources/medialive-channels.go: -------------------------------------------------------------------------------- 1 | package resources 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/aws/aws-sdk-go/aws" 7 | "github.com/aws/aws-sdk-go/service/medialive" 8 | 9 | "github.com/ekristen/libnuke/pkg/registry" 10 | "github.com/ekristen/libnuke/pkg/resource" 11 | 12 | "github.com/ekristen/aws-nuke/v3/pkg/nuke" 13 | ) 14 | 15 | const MediaLiveChannelResource = "MediaLiveChannel" 16 | 17 | func init() { 18 | registry.Register(®istry.Registration{ 19 | Name: MediaLiveChannelResource, 20 | Scope: nuke.Account, 21 | Lister: &MediaLiveChannelLister{}, 22 | }) 23 | } 24 | 25 | type MediaLiveChannelLister struct{} 26 | 27 | func (l *MediaLiveChannelLister) List(_ context.Context, o interface{}) ([]resource.Resource, error) { 28 | opts := o.(*nuke.ListerOpts) 29 | 30 | svc := medialive.New(opts.Session) 31 | resources := make([]resource.Resource, 0) 32 | 33 | params := &medialive.ListChannelsInput{ 34 | MaxResults: aws.Int64(20), 35 | } 36 | 37 | for { 38 | output, err := svc.ListChannels(params) 39 | if err != nil { 40 | return nil, err 41 | } 42 | 43 | for _, channel := range output.Channels { 44 | resources = append(resources, &MediaLiveChannel{ 45 | svc: svc, 46 | ID: channel.Id, 47 | }) 48 | } 49 | 50 | if output.NextToken == nil { 51 | break 52 | } 53 | 54 | params.NextToken = output.NextToken 55 | } 56 | 57 | return resources, nil 58 | } 59 | 60 | type MediaLiveChannel struct { 61 | svc *medialive.MediaLive 62 | ID *string 63 | } 64 | 65 | func (f *MediaLiveChannel) Remove(_ context.Context) error { 66 | _, err := f.svc.DeleteChannel(&medialive.DeleteChannelInput{ 67 | ChannelId: f.ID, 68 | }) 69 | 70 | return err 71 | } 72 | 73 | func (f *MediaLiveChannel) String() string { 74 | return *f.ID 75 | } 76 | -------------------------------------------------------------------------------- /resources/sagemaker-models.go: -------------------------------------------------------------------------------- 1 | package resources 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/aws/aws-sdk-go/aws" 7 | "github.com/aws/aws-sdk-go/service/sagemaker" 8 | 9 | "github.com/ekristen/libnuke/pkg/registry" 10 | "github.com/ekristen/libnuke/pkg/resource" 11 | 12 | "github.com/ekristen/aws-nuke/v3/pkg/nuke" 13 | ) 14 | 15 | const SageMakerModelResource = "SageMakerModel" 16 | 17 | func init() { 18 | registry.Register(®istry.Registration{ 19 | Name: SageMakerModelResource, 20 | Scope: nuke.Account, 21 | Lister: &SageMakerModelLister{}, 22 | }) 23 | } 24 | 25 | type SageMakerModelLister struct{} 26 | 27 | func (l *SageMakerModelLister) List(_ context.Context, o interface{}) ([]resource.Resource, error) { 28 | opts := o.(*nuke.ListerOpts) 29 | 30 | svc := sagemaker.New(opts.Session) 31 | resources := make([]resource.Resource, 0) 32 | 33 | params := &sagemaker.ListModelsInput{ 34 | MaxResults: aws.Int64(30), 35 | } 36 | 37 | for { 38 | resp, err := svc.ListModels(params) 39 | if err != nil { 40 | return nil, err 41 | } 42 | 43 | for _, model := range resp.Models { 44 | resources = append(resources, &SageMakerModel{ 45 | svc: svc, 46 | modelName: model.ModelName, 47 | }) 48 | } 49 | 50 | if resp.NextToken == nil { 51 | break 52 | } 53 | 54 | params.NextToken = resp.NextToken 55 | } 56 | 57 | return resources, nil 58 | } 59 | 60 | type SageMakerModel struct { 61 | svc *sagemaker.SageMaker 62 | modelName *string 63 | } 64 | 65 | func (f *SageMakerModel) Remove(_ context.Context) error { 66 | _, err := f.svc.DeleteModel(&sagemaker.DeleteModelInput{ 67 | ModelName: f.modelName, 68 | }) 69 | 70 | return err 71 | } 72 | 73 | func (f *SageMakerModel) String() string { 74 | return *f.modelName 75 | } 76 | -------------------------------------------------------------------------------- /resources/elasticbeanstalk-applications.go: -------------------------------------------------------------------------------- 1 | package resources 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/aws/aws-sdk-go/service/elasticbeanstalk" 7 | 8 | "github.com/ekristen/libnuke/pkg/registry" 9 | "github.com/ekristen/libnuke/pkg/resource" 10 | 11 | "github.com/ekristen/aws-nuke/v3/pkg/nuke" 12 | ) 13 | 14 | const ElasticBeanstalkApplicationResource = "ElasticBeanstalkApplication" 15 | 16 | func init() { 17 | registry.Register(®istry.Registration{ 18 | Name: ElasticBeanstalkApplicationResource, 19 | Scope: nuke.Account, 20 | Lister: &ElasticBeanstalkApplicationLister{}, 21 | }) 22 | } 23 | 24 | type ElasticBeanstalkApplicationLister struct{} 25 | 26 | func (l *ElasticBeanstalkApplicationLister) List(_ context.Context, o interface{}) ([]resource.Resource, error) { 27 | opts := o.(*nuke.ListerOpts) 28 | 29 | svc := elasticbeanstalk.New(opts.Session) 30 | resources := make([]resource.Resource, 0) 31 | 32 | params := &elasticbeanstalk.DescribeApplicationsInput{} 33 | 34 | output, err := svc.DescribeApplications(params) 35 | if err != nil { 36 | return nil, err 37 | } 38 | 39 | for _, application := range output.Applications { 40 | resources = append(resources, &ElasticBeanstalkApplication{ 41 | svc: svc, 42 | name: application.ApplicationName, 43 | }) 44 | } 45 | 46 | return resources, nil 47 | } 48 | 49 | type ElasticBeanstalkApplication struct { 50 | svc *elasticbeanstalk.ElasticBeanstalk 51 | name *string 52 | } 53 | 54 | func (f *ElasticBeanstalkApplication) Remove(_ context.Context) error { 55 | _, err := f.svc.DeleteApplication(&elasticbeanstalk.DeleteApplicationInput{ 56 | ApplicationName: f.name, 57 | }) 58 | 59 | return err 60 | } 61 | 62 | func (f *ElasticBeanstalkApplication) String() string { 63 | return *f.name 64 | } 65 | -------------------------------------------------------------------------------- /resources/iam-server-certificate.go: -------------------------------------------------------------------------------- 1 | package resources 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/aws/aws-sdk-go/service/iam" 7 | "github.com/aws/aws-sdk-go/service/iam/iamiface" 8 | 9 | "github.com/ekristen/libnuke/pkg/registry" 10 | "github.com/ekristen/libnuke/pkg/resource" 11 | 12 | "github.com/ekristen/aws-nuke/v3/pkg/nuke" 13 | ) 14 | 15 | const IAMServerCertificateResource = "IAMServerCertificate" 16 | 17 | func init() { 18 | registry.Register(®istry.Registration{ 19 | Name: IAMServerCertificateResource, 20 | Scope: nuke.Account, 21 | Lister: &IAMServerCertificateLister{}, 22 | DeprecatedAliases: []string{ 23 | "IamServerCertificate", 24 | }, 25 | }) 26 | } 27 | 28 | type IAMServerCertificateLister struct{} 29 | 30 | func (l *IAMServerCertificateLister) List(_ context.Context, o interface{}) ([]resource.Resource, error) { 31 | opts := o.(*nuke.ListerOpts) 32 | 33 | svc := iam.New(opts.Session) 34 | 35 | resp, err := svc.ListServerCertificates(nil) 36 | if err != nil { 37 | return nil, err 38 | } 39 | 40 | resources := make([]resource.Resource, 0) 41 | for _, meta := range resp.ServerCertificateMetadataList { 42 | resources = append(resources, &IAMServerCertificate{ 43 | svc: svc, 44 | name: *meta.ServerCertificateName, 45 | }) 46 | } 47 | 48 | return resources, nil 49 | } 50 | 51 | type IAMServerCertificate struct { 52 | svc iamiface.IAMAPI 53 | name string 54 | } 55 | 56 | func (e *IAMServerCertificate) Remove(_ context.Context) error { 57 | _, err := e.svc.DeleteServerCertificate(&iam.DeleteServerCertificateInput{ 58 | ServerCertificateName: &e.name, 59 | }) 60 | if err != nil { 61 | return err 62 | } 63 | 64 | return nil 65 | } 66 | 67 | func (e *IAMServerCertificate) String() string { 68 | return e.name 69 | } 70 | -------------------------------------------------------------------------------- /resources/iot-authorizers.go: -------------------------------------------------------------------------------- 1 | package resources 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/gotidy/ptr" 7 | 8 | "github.com/aws/aws-sdk-go/service/iot" 9 | 10 | "github.com/ekristen/libnuke/pkg/registry" 11 | "github.com/ekristen/libnuke/pkg/resource" 12 | 13 | "github.com/ekristen/aws-nuke/v3/pkg/nuke" 14 | ) 15 | 16 | const IoTAuthorizerResource = "IoTAuthorizer" 17 | 18 | func init() { 19 | registry.Register(®istry.Registration{ 20 | Name: IoTAuthorizerResource, 21 | Scope: nuke.Account, 22 | Lister: &IoTAuthorizerLister{}, 23 | }) 24 | } 25 | 26 | type IoTAuthorizerLister struct{} 27 | 28 | func (l *IoTAuthorizerLister) List(_ context.Context, o interface{}) ([]resource.Resource, error) { 29 | opts := o.(*nuke.ListerOpts) 30 | 31 | svc := iot.New(opts.Session) 32 | resources := make([]resource.Resource, 0) 33 | 34 | params := &iot.ListAuthorizersInput{} 35 | 36 | output, err := svc.ListAuthorizers(params) 37 | if err != nil { 38 | return nil, err 39 | } 40 | 41 | for _, authorizer := range output.Authorizers { 42 | resources = append(resources, &IoTAuthorizer{ 43 | svc: svc, 44 | name: authorizer.AuthorizerName, 45 | }) 46 | } 47 | 48 | return resources, nil 49 | } 50 | 51 | type IoTAuthorizer struct { 52 | svc *iot.IoT 53 | name *string 54 | } 55 | 56 | func (f *IoTAuthorizer) Remove(_ context.Context) error { 57 | if _, err := f.svc.UpdateAuthorizer(&iot.UpdateAuthorizerInput{ 58 | AuthorizerName: f.name, 59 | Status: ptr.String(iot.AuthorizerStatusInactive), 60 | }); err != nil { 61 | return err 62 | } 63 | 64 | _, err := f.svc.DeleteAuthorizer(&iot.DeleteAuthorizerInput{ 65 | AuthorizerName: f.name, 66 | }) 67 | 68 | return err 69 | } 70 | 71 | func (f *IoTAuthorizer) String() string { 72 | return *f.name 73 | } 74 | -------------------------------------------------------------------------------- /resources/lightsail-staticips.go: -------------------------------------------------------------------------------- 1 | package resources 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/aws/aws-sdk-go/service/lightsail" 7 | 8 | "github.com/ekristen/libnuke/pkg/registry" 9 | "github.com/ekristen/libnuke/pkg/resource" 10 | 11 | "github.com/ekristen/aws-nuke/v3/pkg/nuke" 12 | ) 13 | 14 | const LightsailStaticIPResource = "LightsailStaticIP" 15 | 16 | func init() { 17 | registry.Register(®istry.Registration{ 18 | Name: LightsailStaticIPResource, 19 | Scope: nuke.Account, 20 | Lister: &LightsailStaticIPLister{}, 21 | }) 22 | } 23 | 24 | type LightsailStaticIPLister struct{} 25 | 26 | func (l *LightsailStaticIPLister) List(_ context.Context, o interface{}) ([]resource.Resource, error) { 27 | opts := o.(*nuke.ListerOpts) 28 | 29 | svc := lightsail.New(opts.Session) 30 | resources := make([]resource.Resource, 0) 31 | 32 | params := &lightsail.GetStaticIpsInput{} 33 | 34 | for { 35 | output, err := svc.GetStaticIps(params) 36 | if err != nil { 37 | return nil, err 38 | } 39 | 40 | for _, staticIP := range output.StaticIps { 41 | resources = append(resources, &LightsailStaticIP{ 42 | svc: svc, 43 | staticIPName: staticIP.Name, 44 | }) 45 | } 46 | 47 | if output.NextPageToken == nil { 48 | break 49 | } 50 | 51 | params.PageToken = output.NextPageToken 52 | } 53 | 54 | return resources, nil 55 | } 56 | 57 | type LightsailStaticIP struct { 58 | svc *lightsail.Lightsail 59 | staticIPName *string 60 | } 61 | 62 | func (f *LightsailStaticIP) Remove(_ context.Context) error { 63 | _, err := f.svc.ReleaseStaticIp(&lightsail.ReleaseStaticIpInput{ 64 | StaticIpName: f.staticIPName, 65 | }) 66 | 67 | return err 68 | } 69 | 70 | func (f *LightsailStaticIP) String() string { 71 | return *f.staticIPName 72 | } 73 | -------------------------------------------------------------------------------- /resources/sfn-statemachines.go: -------------------------------------------------------------------------------- 1 | package resources 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/aws/aws-sdk-go/aws" 7 | "github.com/aws/aws-sdk-go/service/sfn" 8 | 9 | "github.com/ekristen/libnuke/pkg/registry" 10 | "github.com/ekristen/libnuke/pkg/resource" 11 | 12 | "github.com/ekristen/aws-nuke/v3/pkg/nuke" 13 | ) 14 | 15 | const SFNStateMachineResource = "SFNStateMachine" 16 | 17 | func init() { 18 | registry.Register(®istry.Registration{ 19 | Name: SFNStateMachineResource, 20 | Scope: nuke.Account, 21 | Lister: &SFNStateMachineLister{}, 22 | }) 23 | } 24 | 25 | type SFNStateMachineLister struct{} 26 | 27 | func (l *SFNStateMachineLister) List(_ context.Context, o interface{}) ([]resource.Resource, error) { 28 | opts := o.(*nuke.ListerOpts) 29 | 30 | svc := sfn.New(opts.Session) 31 | resources := make([]resource.Resource, 0) 32 | 33 | params := &sfn.ListStateMachinesInput{ 34 | MaxResults: aws.Int64(100), 35 | } 36 | 37 | for { 38 | output, err := svc.ListStateMachines(params) 39 | if err != nil { 40 | return nil, err 41 | } 42 | 43 | for _, stateMachine := range output.StateMachines { 44 | resources = append(resources, &SFNStateMachine{ 45 | svc: svc, 46 | ARN: stateMachine.StateMachineArn, 47 | }) 48 | } 49 | 50 | if output.NextToken == nil { 51 | break 52 | } 53 | 54 | params.NextToken = output.NextToken 55 | } 56 | 57 | return resources, nil 58 | } 59 | 60 | type SFNStateMachine struct { 61 | svc *sfn.SFN 62 | ARN *string 63 | } 64 | 65 | func (f *SFNStateMachine) Remove(_ context.Context) error { 66 | _, err := f.svc.DeleteStateMachine(&sfn.DeleteStateMachineInput{ 67 | StateMachineArn: f.ARN, 68 | }) 69 | 70 | return err 71 | } 72 | 73 | func (f *SFNStateMachine) String() string { 74 | return *f.ARN 75 | } 76 | -------------------------------------------------------------------------------- /resources/opsworks-layers.go: -------------------------------------------------------------------------------- 1 | package resources 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/aws/aws-sdk-go/service/opsworks" 7 | 8 | "github.com/ekristen/libnuke/pkg/registry" 9 | "github.com/ekristen/libnuke/pkg/resource" 10 | 11 | "github.com/ekristen/aws-nuke/v3/pkg/nuke" 12 | ) 13 | 14 | const OpsWorksLayerResource = "OpsWorksLayer" 15 | 16 | func init() { 17 | registry.Register(®istry.Registration{ 18 | Name: OpsWorksLayerResource, 19 | Scope: nuke.Account, 20 | Lister: &OpsWorksLayerLister{}, 21 | }) 22 | } 23 | 24 | type OpsWorksLayerLister struct{} 25 | 26 | func (l *OpsWorksLayerLister) List(_ context.Context, o interface{}) ([]resource.Resource, error) { 27 | opts := o.(*nuke.ListerOpts) 28 | 29 | svc := opsworks.New(opts.Session) 30 | resources := make([]resource.Resource, 0) 31 | 32 | stackParams := &opsworks.DescribeStacksInput{} 33 | 34 | resp, err := svc.DescribeStacks(stackParams) 35 | if err != nil { 36 | return nil, err 37 | } 38 | 39 | layerParams := &opsworks.DescribeLayersInput{} 40 | 41 | for _, stack := range resp.Stacks { 42 | layerParams.StackId = stack.StackId 43 | output, err := svc.DescribeLayers(layerParams) 44 | if err != nil { 45 | return nil, err 46 | } 47 | 48 | for _, layer := range output.Layers { 49 | resources = append(resources, &OpsWorksLayer{ 50 | svc: svc, 51 | ID: layer.LayerId, 52 | }) 53 | } 54 | } 55 | 56 | return resources, nil 57 | } 58 | 59 | type OpsWorksLayer struct { 60 | svc *opsworks.OpsWorks 61 | ID *string 62 | } 63 | 64 | func (f *OpsWorksLayer) Remove(_ context.Context) error { 65 | _, err := f.svc.DeleteLayer(&opsworks.DeleteLayerInput{ 66 | LayerId: f.ID, 67 | }) 68 | 69 | return err 70 | } 71 | 72 | func (f *OpsWorksLayer) String() string { 73 | return *f.ID 74 | } 75 | -------------------------------------------------------------------------------- /resources/opsworkscm-serverstates.go: -------------------------------------------------------------------------------- 1 | package resources 2 | 3 | import ( 4 | "context" 5 | 6 | "fmt" 7 | 8 | "github.com/aws/aws-sdk-go/service/opsworkscm" 9 | 10 | "github.com/ekristen/libnuke/pkg/registry" 11 | "github.com/ekristen/libnuke/pkg/resource" 12 | 13 | "github.com/ekristen/aws-nuke/v3/pkg/nuke" 14 | ) 15 | 16 | const OpsWorksCMServerStateResource = "OpsWorksCMServerState" 17 | 18 | func init() { 19 | registry.Register(®istry.Registration{ 20 | Name: OpsWorksCMServerStateResource, 21 | Scope: nuke.Account, 22 | Lister: &OpsWorksCMServerStateLister{}, 23 | }) 24 | } 25 | 26 | type OpsWorksCMServerStateLister struct{} 27 | 28 | func (l *OpsWorksCMServerStateLister) List(_ context.Context, o interface{}) ([]resource.Resource, error) { 29 | opts := o.(*nuke.ListerOpts) 30 | 31 | svc := opsworkscm.New(opts.Session) 32 | resources := make([]resource.Resource, 0) 33 | 34 | params := &opsworkscm.DescribeServersInput{} 35 | 36 | output, err := svc.DescribeServers(params) 37 | if err != nil { 38 | return nil, err 39 | } 40 | 41 | for _, server := range output.Servers { 42 | resources = append(resources, &OpsWorksCMServerState{ 43 | svc: svc, 44 | name: server.ServerName, 45 | status: server.Status, 46 | }) 47 | } 48 | 49 | return resources, nil 50 | } 51 | 52 | type OpsWorksCMServerState struct { 53 | svc *opsworkscm.OpsWorksCM 54 | name *string 55 | status *string 56 | } 57 | 58 | func (f *OpsWorksCMServerState) Remove(_ context.Context) error { 59 | return nil 60 | } 61 | 62 | func (f *OpsWorksCMServerState) String() string { 63 | return *f.name 64 | } 65 | 66 | func (f *OpsWorksCMServerState) Filter() error { 67 | if *f.status == "CREATING" { 68 | return nil 69 | } else { 70 | return fmt.Errorf("available for transition") 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /resources/datapipeline-pipelines.go: -------------------------------------------------------------------------------- 1 | package resources 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/aws/aws-sdk-go/service/datapipeline" 7 | 8 | "github.com/ekristen/libnuke/pkg/registry" 9 | "github.com/ekristen/libnuke/pkg/resource" 10 | 11 | "github.com/ekristen/aws-nuke/v3/pkg/nuke" 12 | ) 13 | 14 | const DataPipelinePipelineResource = "DataPipelinePipeline" 15 | 16 | func init() { 17 | registry.Register(®istry.Registration{ 18 | Name: DataPipelinePipelineResource, 19 | Scope: nuke.Account, 20 | Lister: &DataPipelinePipelineLister{}, 21 | }) 22 | } 23 | 24 | type DataPipelinePipelineLister struct{} 25 | 26 | func (l *DataPipelinePipelineLister) List(_ context.Context, o interface{}) ([]resource.Resource, error) { 27 | opts := o.(*nuke.ListerOpts) 28 | 29 | svc := datapipeline.New(opts.Session) 30 | resources := make([]resource.Resource, 0) 31 | 32 | params := &datapipeline.ListPipelinesInput{} 33 | 34 | for { 35 | resp, err := svc.ListPipelines(params) 36 | if err != nil { 37 | return nil, err 38 | } 39 | 40 | for _, pipeline := range resp.PipelineIdList { 41 | resources = append(resources, &DataPipelinePipeline{ 42 | svc: svc, 43 | pipelineID: pipeline.Id, 44 | }) 45 | } 46 | 47 | if resp.Marker == nil { 48 | break 49 | } 50 | 51 | params.Marker = resp.Marker 52 | } 53 | 54 | return resources, nil 55 | } 56 | 57 | type DataPipelinePipeline struct { 58 | svc *datapipeline.DataPipeline 59 | pipelineID *string 60 | } 61 | 62 | func (f *DataPipelinePipeline) Remove(_ context.Context) error { 63 | _, err := f.svc.DeletePipeline(&datapipeline.DeletePipelineInput{ 64 | PipelineId: f.pipelineID, 65 | }) 66 | 67 | return err 68 | } 69 | 70 | func (f *DataPipelinePipeline) String() string { 71 | return *f.pipelineID 72 | } 73 | -------------------------------------------------------------------------------- /resources/simpledb-domains.go: -------------------------------------------------------------------------------- 1 | package resources 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/aws/aws-sdk-go/aws" 7 | "github.com/aws/aws-sdk-go/service/simpledb" 8 | 9 | "github.com/ekristen/libnuke/pkg/registry" 10 | "github.com/ekristen/libnuke/pkg/resource" 11 | 12 | "github.com/ekristen/aws-nuke/v3/pkg/nuke" 13 | ) 14 | 15 | const SimpleDBDomainResource = "SimpleDBDomain" 16 | 17 | func init() { 18 | registry.Register(®istry.Registration{ 19 | Name: SimpleDBDomainResource, 20 | Scope: nuke.Account, 21 | Lister: &SimpleDBDomainLister{}, 22 | }) 23 | } 24 | 25 | type SimpleDBDomainLister struct{} 26 | 27 | func (l *SimpleDBDomainLister) List(_ context.Context, o interface{}) ([]resource.Resource, error) { 28 | opts := o.(*nuke.ListerOpts) 29 | 30 | svc := simpledb.New(opts.Session) 31 | resources := make([]resource.Resource, 0) 32 | 33 | params := &simpledb.ListDomainsInput{ 34 | MaxNumberOfDomains: aws.Int64(100), 35 | } 36 | 37 | for { 38 | output, err := svc.ListDomains(params) 39 | if err != nil { 40 | return nil, err 41 | } 42 | 43 | for _, domainName := range output.DomainNames { 44 | resources = append(resources, &SimpleDBDomain{ 45 | svc: svc, 46 | domainName: domainName, 47 | }) 48 | } 49 | 50 | if output.NextToken == nil { 51 | break 52 | } 53 | 54 | params.NextToken = output.NextToken 55 | } 56 | 57 | return resources, nil 58 | } 59 | 60 | type SimpleDBDomain struct { 61 | svc *simpledb.SimpleDB 62 | domainName *string 63 | } 64 | 65 | func (f *SimpleDBDomain) Remove(_ context.Context) error { 66 | _, err := f.svc.DeleteDomain(&simpledb.DeleteDomainInput{ 67 | DomainName: f.domainName, 68 | }) 69 | 70 | return err 71 | } 72 | 73 | func (f *SimpleDBDomain) String() string { 74 | return *f.domainName 75 | } 76 | -------------------------------------------------------------------------------- /resources/sqs-queues_mock_test.go: -------------------------------------------------------------------------------- 1 | package resources 2 | 3 | import ( 4 | "context" 5 | "testing" 6 | 7 | "github.com/golang/mock/gomock" 8 | "github.com/gotidy/ptr" 9 | "github.com/stretchr/testify/assert" 10 | 11 | "github.com/aws/aws-sdk-go/service/sqs" 12 | 13 | "github.com/ekristen/aws-nuke/v3/mocks/mock_sqsiface" 14 | 15 | "github.com/ekristen/aws-nuke/v3/pkg/nuke" 16 | ) 17 | 18 | func Test_Mock_SQSQueues_List(t *testing.T) { 19 | a := assert.New(t) 20 | ctrl := gomock.NewController(t) 21 | defer ctrl.Finish() 22 | 23 | mockSQS := mock_sqsiface.NewMockSQSAPI(ctrl) 24 | 25 | sqsQueueLister := SQSQueueLister{ 26 | mockSvc: mockSQS, 27 | } 28 | 29 | mockSQS.EXPECT().ListQueues(gomock.Any()).Return(&sqs.ListQueuesOutput{ 30 | QueueUrls: []*string{ 31 | ptr.String("foobar"), 32 | }, 33 | }, nil) 34 | 35 | mockSQS.EXPECT().ListQueueTags(gomock.Any()).Return(&sqs.ListQueueTagsOutput{ 36 | Tags: map[string]*string{ 37 | "Name": ptr.String("foobar"), 38 | }, 39 | }, nil) 40 | 41 | resources, err := sqsQueueLister.List(context.TODO(), &nuke.ListerOpts{}) 42 | a.Nil(err) 43 | a.Len(resources, 1) 44 | 45 | sqsQueue := resources[0].(*SQSQueue) 46 | a.Equal("foobar", sqsQueue.String()) 47 | a.Equal("foobar", sqsQueue.Properties().Get("tag:Name")) 48 | } 49 | 50 | func Test_Mock_SQSQueue_Remove(t *testing.T) { 51 | a := assert.New(t) 52 | ctrl := gomock.NewController(t) 53 | defer ctrl.Finish() 54 | 55 | mockSQS := mock_sqsiface.NewMockSQSAPI(ctrl) 56 | 57 | sqsQueue := SQSQueue{ 58 | svc: mockSQS, 59 | queueURL: ptr.String("foobar"), 60 | } 61 | 62 | mockSQS.EXPECT().DeleteQueue(gomock.Eq(&sqs.DeleteQueueInput{ 63 | QueueUrl: sqsQueue.queueURL, 64 | })).Return(&sqs.DeleteQueueOutput{}, nil) 65 | 66 | err := sqsQueue.Remove(context.TODO()) 67 | a.Nil(err) 68 | } 69 | -------------------------------------------------------------------------------- /resources/codepipeline-pipelines.go: -------------------------------------------------------------------------------- 1 | package resources 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/aws/aws-sdk-go/service/codepipeline" 7 | 8 | "github.com/ekristen/libnuke/pkg/registry" 9 | "github.com/ekristen/libnuke/pkg/resource" 10 | 11 | "github.com/ekristen/aws-nuke/v3/pkg/nuke" 12 | ) 13 | 14 | const CodePipelinePipelineResource = "CodePipelinePipeline" 15 | 16 | func init() { 17 | registry.Register(®istry.Registration{ 18 | Name: CodePipelinePipelineResource, 19 | Scope: nuke.Account, 20 | Lister: &CodePipelinePipelineLister{}, 21 | }) 22 | } 23 | 24 | type CodePipelinePipelineLister struct{} 25 | 26 | func (l *CodePipelinePipelineLister) List(_ context.Context, o interface{}) ([]resource.Resource, error) { 27 | opts := o.(*nuke.ListerOpts) 28 | 29 | svc := codepipeline.New(opts.Session) 30 | resources := make([]resource.Resource, 0) 31 | 32 | params := &codepipeline.ListPipelinesInput{} 33 | 34 | for { 35 | resp, err := svc.ListPipelines(params) 36 | if err != nil { 37 | return nil, err 38 | } 39 | 40 | for _, pipeline := range resp.Pipelines { 41 | resources = append(resources, &CodePipelinePipeline{ 42 | svc: svc, 43 | pipelineName: pipeline.Name, 44 | }) 45 | } 46 | 47 | if resp.NextToken == nil { 48 | break 49 | } 50 | 51 | params.NextToken = resp.NextToken 52 | } 53 | 54 | return resources, nil 55 | } 56 | 57 | type CodePipelinePipeline struct { 58 | svc *codepipeline.CodePipeline 59 | pipelineName *string 60 | } 61 | 62 | func (f *CodePipelinePipeline) Remove(_ context.Context) error { 63 | _, err := f.svc.DeletePipeline(&codepipeline.DeletePipelineInput{ 64 | Name: f.pipelineName, 65 | }) 66 | 67 | return err 68 | } 69 | 70 | func (f *CodePipelinePipeline) String() string { 71 | return *f.pipelineName 72 | } 73 | -------------------------------------------------------------------------------- /resources/appstream-fleets.go: -------------------------------------------------------------------------------- 1 | package resources 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/aws/aws-sdk-go/service/appstream" 7 | 8 | "github.com/ekristen/aws-nuke/v3/pkg/nuke" 9 | "github.com/ekristen/libnuke/pkg/registry" 10 | "github.com/ekristen/libnuke/pkg/resource" 11 | ) 12 | 13 | type AppStreamFleet struct { 14 | svc *appstream.AppStream 15 | name *string 16 | } 17 | 18 | const AppStreamFleetResource = "AppStreamFleet" 19 | 20 | func init() { 21 | registry.Register(®istry.Registration{ 22 | Name: AppStreamFleetResource, 23 | Scope: nuke.Account, 24 | Lister: &AppStreamFleetLister{}, 25 | }) 26 | } 27 | 28 | type AppStreamFleetLister struct{} 29 | 30 | func (l *AppStreamFleetLister) List(_ context.Context, o interface{}) ([]resource.Resource, error) { 31 | opts := o.(*nuke.ListerOpts) 32 | 33 | svc := appstream.New(opts.Session) 34 | resources := make([]resource.Resource, 0) 35 | 36 | params := &appstream.DescribeFleetsInput{} 37 | 38 | for { 39 | output, err := svc.DescribeFleets(params) 40 | if err != nil { 41 | return nil, err 42 | } 43 | 44 | for _, fleet := range output.Fleets { 45 | resources = append(resources, &AppStreamFleet{ 46 | svc: svc, 47 | name: fleet.Name, 48 | }) 49 | } 50 | 51 | if output.NextToken == nil { 52 | break 53 | } 54 | 55 | params.NextToken = output.NextToken 56 | } 57 | 58 | return resources, nil 59 | } 60 | 61 | func (f *AppStreamFleet) Remove(_ context.Context) error { 62 | _, err := f.svc.StopFleet(&appstream.StopFleetInput{ 63 | Name: f.name, 64 | }) 65 | 66 | if err != nil { 67 | return err 68 | } 69 | 70 | _, err = f.svc.DeleteFleet(&appstream.DeleteFleetInput{ 71 | Name: f.name, 72 | }) 73 | 74 | return err 75 | } 76 | 77 | func (f *AppStreamFleet) String() string { 78 | return *f.name 79 | } 80 | -------------------------------------------------------------------------------- /resources/iot-cacertificates.go: -------------------------------------------------------------------------------- 1 | package resources 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/aws/aws-sdk-go/aws" 7 | "github.com/aws/aws-sdk-go/service/iot" 8 | 9 | "github.com/ekristen/libnuke/pkg/registry" 10 | "github.com/ekristen/libnuke/pkg/resource" 11 | 12 | "github.com/ekristen/aws-nuke/v3/pkg/nuke" 13 | ) 14 | 15 | const IoTCACertificateResource = "IoTCACertificate" 16 | 17 | func init() { 18 | registry.Register(®istry.Registration{ 19 | Name: IoTCACertificateResource, 20 | Scope: nuke.Account, 21 | Lister: &IoTCACertificateLister{}, 22 | }) 23 | } 24 | 25 | type IoTCACertificateLister struct{} 26 | 27 | func (l *IoTCACertificateLister) List(_ context.Context, o interface{}) ([]resource.Resource, error) { 28 | opts := o.(*nuke.ListerOpts) 29 | 30 | svc := iot.New(opts.Session) 31 | resources := make([]resource.Resource, 0) 32 | 33 | params := &iot.ListCACertificatesInput{} 34 | 35 | output, err := svc.ListCACertificates(params) 36 | if err != nil { 37 | return nil, err 38 | } 39 | 40 | for _, certificate := range output.Certificates { 41 | resources = append(resources, &IoTCACertificate{ 42 | svc: svc, 43 | ID: certificate.CertificateId, 44 | }) 45 | } 46 | 47 | return resources, nil 48 | } 49 | 50 | type IoTCACertificate struct { 51 | svc *iot.IoT 52 | ID *string 53 | } 54 | 55 | func (f *IoTCACertificate) Remove(_ context.Context) error { 56 | _, err := f.svc.UpdateCACertificate(&iot.UpdateCACertificateInput{ 57 | CertificateId: f.ID, 58 | NewStatus: aws.String("INACTIVE"), 59 | }) 60 | if err != nil { 61 | return err 62 | } 63 | 64 | _, err = f.svc.DeleteCACertificate(&iot.DeleteCACertificateInput{ 65 | CertificateId: f.ID, 66 | }) 67 | 68 | return err 69 | } 70 | 71 | func (f *IoTCACertificate) String() string { 72 | return *f.ID 73 | } 74 | -------------------------------------------------------------------------------- /resources/mediaconvert-presets.go: -------------------------------------------------------------------------------- 1 | package resources 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/aws/aws-sdk-go/aws" 7 | "github.com/aws/aws-sdk-go/service/mediaconvert" 8 | 9 | "github.com/ekristen/libnuke/pkg/registry" 10 | "github.com/ekristen/libnuke/pkg/resource" 11 | 12 | "github.com/ekristen/aws-nuke/v3/pkg/nuke" 13 | ) 14 | 15 | const MediaConvertPresetResource = "MediaConvertPreset" 16 | 17 | func init() { 18 | registry.Register(®istry.Registration{ 19 | Name: MediaConvertPresetResource, 20 | Scope: nuke.Account, 21 | Lister: &MediaConvertPresetLister{}, 22 | }) 23 | } 24 | 25 | type MediaConvertPresetLister struct{} 26 | 27 | func (l *MediaConvertPresetLister) List(_ context.Context, o interface{}) ([]resource.Resource, error) { 28 | opts := o.(*nuke.ListerOpts) 29 | 30 | svc := mediaconvert.New(opts.Session) 31 | resources := make([]resource.Resource, 0) 32 | 33 | params := &mediaconvert.ListPresetsInput{ 34 | MaxResults: aws.Int64(20), 35 | } 36 | 37 | for { 38 | output, err := svc.ListPresets(params) 39 | if err != nil { 40 | return nil, err 41 | } 42 | 43 | for _, preset := range output.Presets { 44 | resources = append(resources, &MediaConvertPreset{ 45 | svc: svc, 46 | name: preset.Name, 47 | }) 48 | } 49 | 50 | if output.NextToken == nil { 51 | break 52 | } 53 | 54 | params.NextToken = output.NextToken 55 | } 56 | 57 | return resources, nil 58 | } 59 | 60 | type MediaConvertPreset struct { 61 | svc *mediaconvert.MediaConvert 62 | name *string 63 | } 64 | 65 | func (f *MediaConvertPreset) Remove(_ context.Context) error { 66 | _, err := f.svc.DeletePreset(&mediaconvert.DeletePresetInput{ 67 | Name: f.name, 68 | }) 69 | 70 | return err 71 | } 72 | 73 | func (f *MediaConvertPreset) String() string { 74 | return *f.name 75 | } 76 | -------------------------------------------------------------------------------- /resources/codebuild-report.go: -------------------------------------------------------------------------------- 1 | package resources 2 | 3 | import ( 4 | "context" 5 | "strings" 6 | 7 | "github.com/aws/aws-sdk-go/service/codebuild" 8 | 9 | "github.com/ekristen/libnuke/pkg/registry" 10 | "github.com/ekristen/libnuke/pkg/resource" 11 | "github.com/ekristen/libnuke/pkg/types" 12 | 13 | "github.com/ekristen/aws-nuke/v3/pkg/nuke" 14 | ) 15 | 16 | const CodeBuildReportResource = "CodeBuildReport" 17 | 18 | func init() { 19 | registry.Register(®istry.Registration{ 20 | Name: CodeBuildReportResource, 21 | Scope: nuke.Account, 22 | Lister: &CodeBuildReportLister{}, 23 | }) 24 | } 25 | 26 | type CodeBuildReportLister struct{} 27 | 28 | func (l *CodeBuildReportLister) List(_ context.Context, o interface{}) ([]resource.Resource, error) { 29 | opts := o.(*nuke.ListerOpts) 30 | svc := codebuild.New(opts.Session) 31 | var resources []resource.Resource 32 | 33 | res, err := svc.ListReports(&codebuild.ListReportsInput{}) 34 | if err != nil { 35 | return nil, err 36 | } 37 | 38 | for _, arn := range res.Reports { 39 | resources = append(resources, &CodeBuildReport{ 40 | svc: svc, 41 | arn: arn, 42 | }) 43 | } 44 | 45 | return resources, nil 46 | } 47 | 48 | type CodeBuildReport struct { 49 | svc *codebuild.CodeBuild 50 | arn *string 51 | } 52 | 53 | func (r *CodeBuildReport) Name() string { 54 | return strings.Split(*r.arn, "report/")[1] 55 | } 56 | 57 | func (r *CodeBuildReport) Remove(_ context.Context) error { 58 | _, err := r.svc.DeleteReport(&codebuild.DeleteReportInput{ 59 | Arn: r.arn, 60 | }) 61 | return err 62 | } 63 | 64 | func (r *CodeBuildReport) Properties() types.Properties { 65 | properties := types.NewProperties() 66 | properties.Set("Name", r.Name()) 67 | return properties 68 | } 69 | 70 | func (r *CodeBuildReport) String() string { 71 | return r.Name() 72 | } 73 | -------------------------------------------------------------------------------- /resources/ecs-taskdefinitions.go: -------------------------------------------------------------------------------- 1 | package resources 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/aws/aws-sdk-go/aws" 7 | "github.com/aws/aws-sdk-go/service/ecs" 8 | 9 | "github.com/ekristen/libnuke/pkg/registry" 10 | "github.com/ekristen/libnuke/pkg/resource" 11 | 12 | "github.com/ekristen/aws-nuke/v3/pkg/nuke" 13 | ) 14 | 15 | const ECSTaskDefinitionResource = "ECSTaskDefinition" 16 | 17 | func init() { 18 | registry.Register(®istry.Registration{ 19 | Name: ECSTaskDefinitionResource, 20 | Scope: nuke.Account, 21 | Lister: &ECSTaskDefinitionLister{}, 22 | }) 23 | } 24 | 25 | type ECSTaskDefinitionLister struct{} 26 | 27 | func (l *ECSTaskDefinitionLister) List(_ context.Context, o interface{}) ([]resource.Resource, error) { 28 | opts := o.(*nuke.ListerOpts) 29 | 30 | svc := ecs.New(opts.Session) 31 | resources := make([]resource.Resource, 0) 32 | 33 | params := &ecs.ListTaskDefinitionsInput{ 34 | MaxResults: aws.Int64(100), 35 | } 36 | 37 | for { 38 | output, err := svc.ListTaskDefinitions(params) 39 | if err != nil { 40 | return nil, err 41 | } 42 | 43 | for _, taskDefinitionARN := range output.TaskDefinitionArns { 44 | resources = append(resources, &ECSTaskDefinition{ 45 | svc: svc, 46 | ARN: taskDefinitionARN, 47 | }) 48 | } 49 | 50 | if output.NextToken == nil { 51 | break 52 | } 53 | 54 | params.NextToken = output.NextToken 55 | } 56 | 57 | return resources, nil 58 | } 59 | 60 | type ECSTaskDefinition struct { 61 | svc *ecs.ECS 62 | ARN *string 63 | } 64 | 65 | func (f *ECSTaskDefinition) Remove(_ context.Context) error { 66 | _, err := f.svc.DeregisterTaskDefinition(&ecs.DeregisterTaskDefinitionInput{ 67 | TaskDefinition: f.ARN, 68 | }) 69 | 70 | return err 71 | } 72 | 73 | func (f *ECSTaskDefinition) String() string { 74 | return *f.ARN 75 | } 76 | -------------------------------------------------------------------------------- /resources/glue-connections.go: -------------------------------------------------------------------------------- 1 | package resources 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/aws/aws-sdk-go/aws" 7 | "github.com/aws/aws-sdk-go/service/glue" 8 | 9 | "github.com/ekristen/libnuke/pkg/registry" 10 | "github.com/ekristen/libnuke/pkg/resource" 11 | 12 | "github.com/ekristen/aws-nuke/v3/pkg/nuke" 13 | ) 14 | 15 | const GlueConnectionResource = "GlueConnection" 16 | 17 | func init() { 18 | registry.Register(®istry.Registration{ 19 | Name: GlueConnectionResource, 20 | Scope: nuke.Account, 21 | Lister: &GlueConnectionLister{}, 22 | }) 23 | } 24 | 25 | type GlueConnectionLister struct{} 26 | 27 | func (l *GlueConnectionLister) List(_ context.Context, o interface{}) ([]resource.Resource, error) { 28 | opts := o.(*nuke.ListerOpts) 29 | 30 | svc := glue.New(opts.Session) 31 | resources := make([]resource.Resource, 0) 32 | 33 | params := &glue.GetConnectionsInput{ 34 | MaxResults: aws.Int64(100), 35 | } 36 | 37 | for { 38 | output, err := svc.GetConnections(params) 39 | if err != nil { 40 | return nil, err 41 | } 42 | 43 | for _, connection := range output.ConnectionList { 44 | resources = append(resources, &GlueConnection{ 45 | svc: svc, 46 | connectionName: connection.Name, 47 | }) 48 | } 49 | 50 | if output.NextToken == nil { 51 | break 52 | } 53 | 54 | params.NextToken = output.NextToken 55 | } 56 | 57 | return resources, nil 58 | } 59 | 60 | type GlueConnection struct { 61 | svc *glue.Glue 62 | connectionName *string 63 | } 64 | 65 | func (f *GlueConnection) Remove(_ context.Context) error { 66 | _, err := f.svc.DeleteConnection(&glue.DeleteConnectionInput{ 67 | ConnectionName: f.connectionName, 68 | }) 69 | 70 | return err 71 | } 72 | 73 | func (f *GlueConnection) String() string { 74 | return *f.connectionName 75 | } 76 | -------------------------------------------------------------------------------- /resources/mediapackage-channels.go: -------------------------------------------------------------------------------- 1 | package resources 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/aws/aws-sdk-go/aws" 7 | "github.com/aws/aws-sdk-go/service/mediapackage" 8 | 9 | "github.com/ekristen/libnuke/pkg/registry" 10 | "github.com/ekristen/libnuke/pkg/resource" 11 | 12 | "github.com/ekristen/aws-nuke/v3/pkg/nuke" 13 | ) 14 | 15 | const MediaPackageChannelResource = "MediaPackageChannel" 16 | 17 | func init() { 18 | registry.Register(®istry.Registration{ 19 | Name: MediaPackageChannelResource, 20 | Scope: nuke.Account, 21 | Lister: &MediaPackageChannelLister{}, 22 | }) 23 | } 24 | 25 | type MediaPackageChannelLister struct{} 26 | 27 | func (l *MediaPackageChannelLister) List(_ context.Context, o interface{}) ([]resource.Resource, error) { 28 | opts := o.(*nuke.ListerOpts) 29 | 30 | svc := mediapackage.New(opts.Session) 31 | resources := make([]resource.Resource, 0) 32 | 33 | params := &mediapackage.ListChannelsInput{ 34 | MaxResults: aws.Int64(50), 35 | } 36 | 37 | for { 38 | output, err := svc.ListChannels(params) 39 | if err != nil { 40 | return nil, err 41 | } 42 | 43 | for _, channel := range output.Channels { 44 | resources = append(resources, &MediaPackageChannel{ 45 | svc: svc, 46 | ID: channel.Id, 47 | }) 48 | } 49 | 50 | if output.NextToken == nil { 51 | break 52 | } 53 | 54 | params.NextToken = output.NextToken 55 | } 56 | 57 | return resources, nil 58 | } 59 | 60 | type MediaPackageChannel struct { 61 | svc *mediapackage.MediaPackage 62 | ID *string 63 | } 64 | 65 | func (f *MediaPackageChannel) Remove(_ context.Context) error { 66 | _, err := f.svc.DeleteChannel(&mediapackage.DeleteChannelInput{ 67 | Id: f.ID, 68 | }) 69 | 70 | return err 71 | } 72 | 73 | func (f *MediaPackageChannel) String() string { 74 | return *f.ID 75 | } 76 | -------------------------------------------------------------------------------- /resources/mobile-projects.go: -------------------------------------------------------------------------------- 1 | package resources 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/aws/aws-sdk-go/aws" 7 | "github.com/aws/aws-sdk-go/service/mobile" 8 | 9 | "github.com/ekristen/libnuke/pkg/registry" 10 | "github.com/ekristen/libnuke/pkg/resource" 11 | 12 | "github.com/ekristen/aws-nuke/v3/pkg/nuke" 13 | ) 14 | 15 | const MobileProjectResource = "MobileProject" 16 | 17 | func init() { 18 | registry.Register(®istry.Registration{ 19 | Name: MobileProjectResource, 20 | Scope: nuke.Account, 21 | Lister: &MobileProjectLister{}, 22 | }) 23 | } 24 | 25 | type MobileProjectLister struct{} 26 | 27 | func (l *MobileProjectLister) List(_ context.Context, o interface{}) ([]resource.Resource, error) { 28 | opts := o.(*nuke.ListerOpts) 29 | 30 | svc := mobile.New(opts.Session) 31 | svc.ClientInfo.SigningName = "AWSMobileHubService" 32 | resources := make([]resource.Resource, 0) 33 | 34 | params := &mobile.ListProjectsInput{ 35 | MaxResults: aws.Int64(100), 36 | } 37 | 38 | for { 39 | output, err := svc.ListProjects(params) 40 | if err != nil { 41 | return nil, err 42 | } 43 | 44 | for _, project := range output.Projects { 45 | resources = append(resources, &MobileProject{ 46 | svc: svc, 47 | projectID: project.ProjectId, 48 | }) 49 | } 50 | 51 | if output.NextToken == nil { 52 | break 53 | } 54 | 55 | params.NextToken = output.NextToken 56 | } 57 | 58 | return resources, nil 59 | } 60 | 61 | type MobileProject struct { 62 | svc *mobile.Mobile 63 | projectID *string 64 | } 65 | 66 | func (f *MobileProject) Remove(_ context.Context) error { 67 | _, err := f.svc.DeleteProject(&mobile.DeleteProjectInput{ 68 | ProjectId: f.projectID, 69 | }) 70 | 71 | return err 72 | } 73 | 74 | func (f *MobileProject) String() string { 75 | return *f.projectID 76 | } 77 | -------------------------------------------------------------------------------- /resources/neptune-clusters.go: -------------------------------------------------------------------------------- 1 | package resources 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/aws/aws-sdk-go/aws" 7 | "github.com/aws/aws-sdk-go/service/neptune" 8 | 9 | "github.com/ekristen/libnuke/pkg/registry" 10 | "github.com/ekristen/libnuke/pkg/resource" 11 | 12 | "github.com/ekristen/aws-nuke/v3/pkg/nuke" 13 | ) 14 | 15 | const NeptuneClusterResource = "NeptuneCluster" 16 | 17 | func init() { 18 | registry.Register(®istry.Registration{ 19 | Name: NeptuneClusterResource, 20 | Scope: nuke.Account, 21 | Lister: &NeptuneClusterLister{}, 22 | }) 23 | } 24 | 25 | type NeptuneClusterLister struct{} 26 | 27 | func (l *NeptuneClusterLister) List(_ context.Context, o interface{}) ([]resource.Resource, error) { 28 | opts := o.(*nuke.ListerOpts) 29 | 30 | svc := neptune.New(opts.Session) 31 | resources := make([]resource.Resource, 0) 32 | 33 | params := &neptune.DescribeDBClustersInput{ 34 | MaxRecords: aws.Int64(100), 35 | } 36 | 37 | for { 38 | output, err := svc.DescribeDBClusters(params) 39 | if err != nil { 40 | return nil, err 41 | } 42 | 43 | for _, dbCluster := range output.DBClusters { 44 | resources = append(resources, &NeptuneCluster{ 45 | svc: svc, 46 | ID: dbCluster.DBClusterIdentifier, 47 | }) 48 | } 49 | 50 | if output.Marker == nil { 51 | break 52 | } 53 | 54 | params.Marker = output.Marker 55 | } 56 | 57 | return resources, nil 58 | } 59 | 60 | type NeptuneCluster struct { 61 | svc *neptune.Neptune 62 | ID *string 63 | } 64 | 65 | func (f *NeptuneCluster) Remove(_ context.Context) error { 66 | _, err := f.svc.DeleteDBCluster(&neptune.DeleteDBClusterInput{ 67 | DBClusterIdentifier: f.ID, 68 | SkipFinalSnapshot: aws.Bool(true), 69 | }) 70 | 71 | return err 72 | } 73 | 74 | func (f *NeptuneCluster) String() string { 75 | return *f.ID 76 | } 77 | -------------------------------------------------------------------------------- /resources/waf-webacls.go: -------------------------------------------------------------------------------- 1 | package resources 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/aws/aws-sdk-go/aws" 7 | "github.com/aws/aws-sdk-go/service/waf" 8 | 9 | "github.com/ekristen/libnuke/pkg/registry" 10 | "github.com/ekristen/libnuke/pkg/resource" 11 | 12 | "github.com/ekristen/aws-nuke/v3/pkg/nuke" 13 | ) 14 | 15 | const WAFWebACLResource = "WAFWebACL" 16 | 17 | func init() { 18 | registry.Register(®istry.Registration{ 19 | Name: WAFWebACLResource, 20 | Scope: nuke.Account, 21 | Lister: &WAFWebACLLister{}, 22 | }) 23 | } 24 | 25 | type WAFWebACLLister struct{} 26 | 27 | func (l *WAFWebACLLister) List(_ context.Context, o interface{}) ([]resource.Resource, error) { 28 | opts := o.(*nuke.ListerOpts) 29 | 30 | svc := waf.New(opts.Session) 31 | resources := make([]resource.Resource, 0) 32 | 33 | params := &waf.ListWebACLsInput{ 34 | Limit: aws.Int64(50), 35 | } 36 | 37 | for { 38 | resp, err := svc.ListWebACLs(params) 39 | if err != nil { 40 | return nil, err 41 | } 42 | 43 | for _, webACL := range resp.WebACLs { 44 | resources = append(resources, &WAFWebACL{ 45 | svc: svc, 46 | ID: webACL.WebACLId, 47 | }) 48 | } 49 | 50 | if resp.NextMarker == nil { 51 | break 52 | } 53 | 54 | params.NextMarker = resp.NextMarker 55 | } 56 | 57 | return resources, nil 58 | } 59 | 60 | type WAFWebACL struct { 61 | svc *waf.WAF 62 | ID *string 63 | } 64 | 65 | func (f *WAFWebACL) Remove(_ context.Context) error { 66 | tokenOutput, err := f.svc.GetChangeToken(&waf.GetChangeTokenInput{}) 67 | if err != nil { 68 | return err 69 | } 70 | 71 | _, err = f.svc.DeleteWebACL(&waf.DeleteWebACLInput{ 72 | WebACLId: f.ID, 73 | ChangeToken: tokenOutput.ChangeToken, 74 | }) 75 | 76 | return err 77 | } 78 | 79 | func (f *WAFWebACL) String() string { 80 | return *f.ID 81 | } 82 | -------------------------------------------------------------------------------- /resources/resource-explorer2-views.go: -------------------------------------------------------------------------------- 1 | package resources 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/aws/aws-sdk-go/aws" 7 | "github.com/aws/aws-sdk-go/service/resourceexplorer2" 8 | "github.com/ekristen/aws-nuke/v3/pkg/nuke" 9 | "github.com/ekristen/libnuke/pkg/registry" 10 | "github.com/ekristen/libnuke/pkg/resource" 11 | ) 12 | 13 | const ResourceExplorer2ViewResource = "ResourceExplorer2View" 14 | 15 | func init() { 16 | registry.Register(®istry.Registration{ 17 | Name: ResourceExplorer2ViewResource, 18 | Scope: nuke.Account, 19 | Lister: &ResourceExplorer2ViewLister{}, 20 | }) 21 | } 22 | 23 | type ResourceExplorer2ViewLister struct{} 24 | 25 | type ResourceExplorer2View struct { 26 | svc *resourceexplorer2.ResourceExplorer2 27 | viewArn *string 28 | } 29 | 30 | func (l *ResourceExplorer2ViewLister) List(_ context.Context, o interface{}) ([]resource.Resource, error) { 31 | opts := o.(*nuke.ListerOpts) 32 | svc := resourceexplorer2.New(opts.Session) 33 | var resources []resource.Resource 34 | 35 | params := &resourceexplorer2.ListViewsInput{} 36 | 37 | for { 38 | output, err := svc.ListViews(params) 39 | if err != nil { 40 | return nil, err 41 | } 42 | 43 | for _, view := range output.Views { 44 | resources = append(resources, &ResourceExplorer2View{ 45 | svc: svc, 46 | viewArn: view, 47 | }) 48 | } 49 | 50 | if output.NextToken == nil { 51 | break 52 | } 53 | 54 | params.SetNextToken(aws.StringValue(output.NextToken)) 55 | } 56 | 57 | return resources, nil 58 | } 59 | 60 | func (f *ResourceExplorer2View) Remove(_ context.Context) error { 61 | _, err := f.svc.DeleteView(&resourceexplorer2.DeleteViewInput{ 62 | ViewArn: f.viewArn, 63 | }) 64 | 65 | return err 66 | } 67 | 68 | func (f *ResourceExplorer2View) String() string { 69 | return *f.viewArn 70 | } 71 | -------------------------------------------------------------------------------- /resources/cloudhsmv2-cluster.go: -------------------------------------------------------------------------------- 1 | package resources 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/aws/aws-sdk-go/aws" 7 | "github.com/aws/aws-sdk-go/service/cloudhsmv2" 8 | 9 | "github.com/ekristen/libnuke/pkg/registry" 10 | "github.com/ekristen/libnuke/pkg/resource" 11 | 12 | "github.com/ekristen/aws-nuke/v3/pkg/nuke" 13 | ) 14 | 15 | const CloudHSMV2ClusterResource = "CloudHSMV2Cluster" 16 | 17 | func init() { 18 | registry.Register(®istry.Registration{ 19 | Name: CloudHSMV2ClusterResource, 20 | Scope: nuke.Account, 21 | Lister: &CloudHSMV2ClusterLister{}, 22 | }) 23 | } 24 | 25 | type CloudHSMV2ClusterLister struct{} 26 | 27 | func (l *CloudHSMV2ClusterLister) List(_ context.Context, o interface{}) ([]resource.Resource, error) { 28 | opts := o.(*nuke.ListerOpts) 29 | 30 | svc := cloudhsmv2.New(opts.Session) 31 | resources := make([]resource.Resource, 0) 32 | 33 | params := &cloudhsmv2.DescribeClustersInput{ 34 | MaxResults: aws.Int64(25), 35 | } 36 | 37 | for { 38 | resp, err := svc.DescribeClusters(params) 39 | if err != nil { 40 | return nil, err 41 | } 42 | 43 | for _, cluster := range resp.Clusters { 44 | resources = append(resources, &CloudHSMV2Cluster{ 45 | svc: svc, 46 | clusterID: cluster.ClusterId, 47 | }) 48 | } 49 | 50 | if resp.NextToken == nil { 51 | break 52 | } 53 | 54 | params.NextToken = resp.NextToken 55 | } 56 | 57 | return resources, nil 58 | } 59 | 60 | type CloudHSMV2Cluster struct { 61 | svc *cloudhsmv2.CloudHSMV2 62 | clusterID *string 63 | } 64 | 65 | func (f *CloudHSMV2Cluster) Remove(_ context.Context) error { 66 | _, err := f.svc.DeleteCluster(&cloudhsmv2.DeleteClusterInput{ 67 | ClusterId: f.clusterID, 68 | }) 69 | 70 | return err 71 | } 72 | 73 | func (f *CloudHSMV2Cluster) String() string { 74 | return *f.clusterID 75 | } 76 | -------------------------------------------------------------------------------- /resources/ec2-volume.go: -------------------------------------------------------------------------------- 1 | package resources 2 | 3 | import ( 4 | "context" 5 | "time" 6 | 7 | "github.com/aws/aws-sdk-go/service/ec2" 8 | 9 | "github.com/ekristen/libnuke/pkg/registry" 10 | "github.com/ekristen/libnuke/pkg/resource" 11 | "github.com/ekristen/libnuke/pkg/types" 12 | 13 | "github.com/ekristen/aws-nuke/v3/pkg/nuke" 14 | ) 15 | 16 | const EC2VolumeResource = "EC2Volume" 17 | 18 | func init() { 19 | registry.Register(®istry.Registration{ 20 | Name: EC2VolumeResource, 21 | Scope: nuke.Account, 22 | Lister: &EC2VolumeLister{}, 23 | }) 24 | } 25 | 26 | type EC2Volume struct { 27 | svc *ec2.EC2 28 | volume *ec2.Volume 29 | } 30 | 31 | type EC2VolumeLister struct{} 32 | 33 | func (l *EC2VolumeLister) List(_ context.Context, o interface{}) ([]resource.Resource, error) { 34 | opts := o.(*nuke.ListerOpts) 35 | 36 | svc := ec2.New(opts.Session) 37 | 38 | resp, err := svc.DescribeVolumes(nil) 39 | if err != nil { 40 | return nil, err 41 | } 42 | 43 | resources := make([]resource.Resource, 0) 44 | for _, out := range resp.Volumes { 45 | resources = append(resources, &EC2Volume{ 46 | svc: svc, 47 | volume: out, 48 | }) 49 | } 50 | 51 | return resources, nil 52 | } 53 | 54 | func (e *EC2Volume) Remove(_ context.Context) error { 55 | _, err := e.svc.DeleteVolume(&ec2.DeleteVolumeInput{ 56 | VolumeId: e.volume.VolumeId, 57 | }) 58 | return err 59 | } 60 | 61 | func (e *EC2Volume) Properties() types.Properties { 62 | properties := types.NewProperties() 63 | properties.Set("State", e.volume.State) 64 | properties.Set("CreateTime", e.volume.CreateTime.Format(time.RFC3339)) 65 | for _, tagValue := range e.volume.Tags { 66 | properties.SetTag(tagValue.Key, tagValue.Value) 67 | } 68 | return properties 69 | } 70 | 71 | func (e *EC2Volume) String() string { 72 | return *e.volume.VolumeId 73 | } 74 | -------------------------------------------------------------------------------- /.github/workflows/docs.yaml: -------------------------------------------------------------------------------- 1 | name: docs 2 | 3 | on: 4 | workflow_dispatch: 5 | push: 6 | branches: 7 | - main 8 | paths: 9 | - docs/** 10 | 11 | # Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages 12 | permissions: 13 | contents: read 14 | pages: write 15 | id-token: write 16 | 17 | # Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued. 18 | # However, do NOT cancel in-progress runs as we want to allow these production deployments to complete. 19 | concurrency: 20 | group: "pages" 21 | cancel-in-progress: false 22 | 23 | jobs: 24 | deploy: 25 | runs-on: ubuntu-latest 26 | environment: 27 | name: github-pages 28 | url: ${{ steps.deployment.outputs.page_url }} 29 | steps: 30 | - uses: actions/checkout@v4 31 | - name: setup pages 32 | uses: actions/configure-pages@v5 33 | - name: setup python 34 | uses: actions/setup-python@v5 35 | with: 36 | python-version: 3.x 37 | - name: setup cache 38 | run: | 39 | echo "cache_id=$(date --utc '+%V')" >> $GITHUB_ENV 40 | - name: handle cache 41 | uses: actions/cache@v4 42 | with: 43 | key: mkdocs-material-${{ env.cache_id }} 44 | path: .cache 45 | restore-keys: | 46 | mkdocs-material- 47 | - name: install mkdocs material 48 | run: | 49 | pip install mkdocs-material 50 | - name: run mkdocs material 51 | run: | 52 | mkdocs build 53 | - name: upload artifact 54 | uses: actions/upload-pages-artifact@v3 55 | with: 56 | # Upload entire repository 57 | path: public/ 58 | - name: deploy to GitHub Pages 59 | id: deployment 60 | uses: actions/deploy-pages@v4 61 | -------------------------------------------------------------------------------- /resources/gluedatabrew-datasets.go: -------------------------------------------------------------------------------- 1 | package resources 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/aws/aws-sdk-go/aws" 7 | "github.com/aws/aws-sdk-go/service/gluedatabrew" 8 | 9 | "github.com/ekristen/libnuke/pkg/registry" 10 | "github.com/ekristen/libnuke/pkg/resource" 11 | 12 | "github.com/ekristen/aws-nuke/v3/pkg/nuke" 13 | ) 14 | 15 | const GlueDataBrewDatasetsResource = "GlueDataBrewDatasets" 16 | 17 | func init() { 18 | registry.Register(®istry.Registration{ 19 | Name: GlueDataBrewDatasetsResource, 20 | Scope: nuke.Account, 21 | Lister: &GlueDataBrewDatasetsLister{}, 22 | }) 23 | } 24 | 25 | type GlueDataBrewDatasetsLister struct{} 26 | 27 | func (l *GlueDataBrewDatasetsLister) List(_ context.Context, o interface{}) ([]resource.Resource, error) { 28 | opts := o.(*nuke.ListerOpts) 29 | 30 | svc := gluedatabrew.New(opts.Session) 31 | resources := make([]resource.Resource, 0) 32 | 33 | params := &gluedatabrew.ListDatasetsInput{ 34 | MaxResults: aws.Int64(100), 35 | } 36 | 37 | for { 38 | output, err := svc.ListDatasets(params) 39 | if err != nil { 40 | return nil, err 41 | } 42 | 43 | for _, dataset := range output.Datasets { 44 | resources = append(resources, &GlueDataBrewDatasets{ 45 | svc: svc, 46 | name: dataset.Name, 47 | }) 48 | } 49 | 50 | if output.NextToken == nil { 51 | break 52 | } 53 | 54 | params.NextToken = output.NextToken 55 | } 56 | 57 | return resources, nil 58 | } 59 | 60 | type GlueDataBrewDatasets struct { 61 | svc *gluedatabrew.GlueDataBrew 62 | name *string 63 | } 64 | 65 | func (f *GlueDataBrewDatasets) Remove(_ context.Context) error { 66 | _, err := f.svc.DeleteDataset(&gluedatabrew.DeleteDatasetInput{ 67 | Name: f.name, 68 | }) 69 | 70 | return err 71 | } 72 | 73 | func (f *GlueDataBrewDatasets) String() string { 74 | return *f.name 75 | } 76 | -------------------------------------------------------------------------------- /resources/gluedatabrew-projects.go: -------------------------------------------------------------------------------- 1 | package resources 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/aws/aws-sdk-go/aws" 7 | "github.com/aws/aws-sdk-go/service/gluedatabrew" 8 | 9 | "github.com/ekristen/libnuke/pkg/registry" 10 | "github.com/ekristen/libnuke/pkg/resource" 11 | 12 | "github.com/ekristen/aws-nuke/v3/pkg/nuke" 13 | ) 14 | 15 | const GlueDataBrewProjectsResource = "GlueDataBrewProjects" 16 | 17 | func init() { 18 | registry.Register(®istry.Registration{ 19 | Name: GlueDataBrewProjectsResource, 20 | Scope: nuke.Account, 21 | Lister: &GlueDataBrewProjectsLister{}, 22 | }) 23 | } 24 | 25 | type GlueDataBrewProjectsLister struct{} 26 | 27 | func (l *GlueDataBrewProjectsLister) List(_ context.Context, o interface{}) ([]resource.Resource, error) { 28 | opts := o.(*nuke.ListerOpts) 29 | 30 | svc := gluedatabrew.New(opts.Session) 31 | resources := make([]resource.Resource, 0) 32 | 33 | params := &gluedatabrew.ListProjectsInput{ 34 | MaxResults: aws.Int64(100), 35 | } 36 | 37 | for { 38 | output, err := svc.ListProjects(params) 39 | if err != nil { 40 | return nil, err 41 | } 42 | 43 | for _, project := range output.Projects { 44 | resources = append(resources, &GlueDataBrewProjects{ 45 | svc: svc, 46 | name: project.Name, 47 | }) 48 | } 49 | 50 | if output.NextToken == nil { 51 | break 52 | } 53 | 54 | params.NextToken = output.NextToken 55 | } 56 | 57 | return resources, nil 58 | } 59 | 60 | type GlueDataBrewProjects struct { 61 | svc *gluedatabrew.GlueDataBrew 62 | name *string 63 | } 64 | 65 | func (f *GlueDataBrewProjects) Remove(_ context.Context) error { 66 | _, err := f.svc.DeleteProject(&gluedatabrew.DeleteProjectInput{ 67 | Name: f.name, 68 | }) 69 | 70 | return err 71 | } 72 | 73 | func (f *GlueDataBrewProjects) String() string { 74 | return *f.name 75 | } 76 | -------------------------------------------------------------------------------- /resources/gluedatabrew-rulesets.go: -------------------------------------------------------------------------------- 1 | package resources 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/aws/aws-sdk-go/aws" 7 | "github.com/aws/aws-sdk-go/service/gluedatabrew" 8 | 9 | "github.com/ekristen/libnuke/pkg/registry" 10 | "github.com/ekristen/libnuke/pkg/resource" 11 | 12 | "github.com/ekristen/aws-nuke/v3/pkg/nuke" 13 | ) 14 | 15 | const GlueDataBrewRulesetsResource = "GlueDataBrewRulesets" 16 | 17 | func init() { 18 | registry.Register(®istry.Registration{ 19 | Name: GlueDataBrewRulesetsResource, 20 | Scope: nuke.Account, 21 | Lister: &GlueDataBrewRulesetsLister{}, 22 | }) 23 | } 24 | 25 | type GlueDataBrewRulesetsLister struct{} 26 | 27 | func (l *GlueDataBrewRulesetsLister) List(_ context.Context, o interface{}) ([]resource.Resource, error) { 28 | opts := o.(*nuke.ListerOpts) 29 | 30 | svc := gluedatabrew.New(opts.Session) 31 | resources := make([]resource.Resource, 0) 32 | 33 | params := &gluedatabrew.ListRulesetsInput{ 34 | MaxResults: aws.Int64(100), 35 | } 36 | 37 | for { 38 | output, err := svc.ListRulesets(params) 39 | if err != nil { 40 | return nil, err 41 | } 42 | 43 | for _, ruleset := range output.Rulesets { 44 | resources = append(resources, &GlueDataBrewRulesets{ 45 | svc: svc, 46 | name: ruleset.Name, 47 | }) 48 | } 49 | 50 | if output.NextToken == nil { 51 | break 52 | } 53 | 54 | params.NextToken = output.NextToken 55 | } 56 | 57 | return resources, nil 58 | } 59 | 60 | type GlueDataBrewRulesets struct { 61 | svc *gluedatabrew.GlueDataBrew 62 | name *string 63 | } 64 | 65 | func (f *GlueDataBrewRulesets) Remove(_ context.Context) error { 66 | _, err := f.svc.DeleteRuleset(&gluedatabrew.DeleteRulesetInput{ 67 | Name: f.name, 68 | }) 69 | 70 | return err 71 | } 72 | 73 | func (f *GlueDataBrewRulesets) String() string { 74 | return *f.name 75 | } 76 | -------------------------------------------------------------------------------- /resources/mediastore-containers.go: -------------------------------------------------------------------------------- 1 | package resources 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/aws/aws-sdk-go/aws" 7 | "github.com/aws/aws-sdk-go/service/mediastore" 8 | 9 | "github.com/ekristen/libnuke/pkg/registry" 10 | "github.com/ekristen/libnuke/pkg/resource" 11 | 12 | "github.com/ekristen/aws-nuke/v3/pkg/nuke" 13 | ) 14 | 15 | const MediaStoreContainerResource = "MediaStoreContainer" 16 | 17 | func init() { 18 | registry.Register(®istry.Registration{ 19 | Name: MediaStoreContainerResource, 20 | Scope: nuke.Account, 21 | Lister: &MediaStoreContainerLister{}, 22 | }) 23 | } 24 | 25 | type MediaStoreContainerLister struct{} 26 | 27 | func (l *MediaStoreContainerLister) List(_ context.Context, o interface{}) ([]resource.Resource, error) { 28 | opts := o.(*nuke.ListerOpts) 29 | 30 | svc := mediastore.New(opts.Session) 31 | resources := make([]resource.Resource, 0) 32 | 33 | params := &mediastore.ListContainersInput{ 34 | MaxResults: aws.Int64(100), 35 | } 36 | 37 | for { 38 | output, err := svc.ListContainers(params) 39 | if err != nil { 40 | return nil, err 41 | } 42 | 43 | for _, container := range output.Containers { 44 | resources = append(resources, &MediaStoreContainer{ 45 | svc: svc, 46 | name: container.Name, 47 | }) 48 | } 49 | 50 | if output.NextToken == nil { 51 | break 52 | } 53 | 54 | params.NextToken = output.NextToken 55 | } 56 | 57 | return resources, nil 58 | } 59 | 60 | type MediaStoreContainer struct { 61 | svc *mediastore.MediaStore 62 | name *string 63 | } 64 | 65 | func (f *MediaStoreContainer) Remove(_ context.Context) error { 66 | _, err := f.svc.DeleteContainer(&mediastore.DeleteContainerInput{ 67 | ContainerName: f.name, 68 | }) 69 | 70 | return err 71 | } 72 | 73 | func (f *MediaStoreContainer) String() string { 74 | return *f.name 75 | } 76 | -------------------------------------------------------------------------------- /resources/neptune-instances.go: -------------------------------------------------------------------------------- 1 | package resources 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/aws/aws-sdk-go/aws" 7 | "github.com/aws/aws-sdk-go/service/neptune" 8 | 9 | "github.com/ekristen/libnuke/pkg/registry" 10 | "github.com/ekristen/libnuke/pkg/resource" 11 | 12 | "github.com/ekristen/aws-nuke/v3/pkg/nuke" 13 | ) 14 | 15 | const NeptuneInstanceResource = "NeptuneInstance" 16 | 17 | func init() { 18 | registry.Register(®istry.Registration{ 19 | Name: NeptuneInstanceResource, 20 | Scope: nuke.Account, 21 | Lister: &NeptuneInstanceLister{}, 22 | }) 23 | } 24 | 25 | type NeptuneInstanceLister struct{} 26 | 27 | func (l *NeptuneInstanceLister) List(_ context.Context, o interface{}) ([]resource.Resource, error) { 28 | opts := o.(*nuke.ListerOpts) 29 | 30 | svc := neptune.New(opts.Session) 31 | resources := make([]resource.Resource, 0) 32 | 33 | params := &neptune.DescribeDBInstancesInput{ 34 | MaxRecords: aws.Int64(100), 35 | } 36 | 37 | for { 38 | output, err := svc.DescribeDBInstances(params) 39 | if err != nil { 40 | return nil, err 41 | } 42 | 43 | for _, dbInstance := range output.DBInstances { 44 | resources = append(resources, &NeptuneInstance{ 45 | svc: svc, 46 | ID: dbInstance.DBInstanceIdentifier, 47 | }) 48 | } 49 | 50 | if output.Marker == nil { 51 | break 52 | } 53 | 54 | params.Marker = output.Marker 55 | } 56 | 57 | return resources, nil 58 | } 59 | 60 | type NeptuneInstance struct { 61 | svc *neptune.Neptune 62 | ID *string 63 | } 64 | 65 | func (f *NeptuneInstance) Remove(_ context.Context) error { 66 | _, err := f.svc.DeleteDBInstance(&neptune.DeleteDBInstanceInput{ 67 | DBInstanceIdentifier: f.ID, 68 | SkipFinalSnapshot: aws.Bool(true), 69 | }) 70 | 71 | return err 72 | } 73 | 74 | func (f *NeptuneInstance) String() string { 75 | return *f.ID 76 | } 77 | -------------------------------------------------------------------------------- /resources/storagegateway-volumes.go: -------------------------------------------------------------------------------- 1 | package resources 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/aws/aws-sdk-go/aws" 7 | "github.com/aws/aws-sdk-go/service/storagegateway" 8 | 9 | "github.com/ekristen/libnuke/pkg/registry" 10 | "github.com/ekristen/libnuke/pkg/resource" 11 | 12 | "github.com/ekristen/aws-nuke/v3/pkg/nuke" 13 | ) 14 | 15 | const StorageGatewayVolumeResource = "StorageGatewayVolume" 16 | 17 | func init() { 18 | registry.Register(®istry.Registration{ 19 | Name: StorageGatewayVolumeResource, 20 | Scope: nuke.Account, 21 | Lister: &StorageGatewayVolumeLister{}, 22 | }) 23 | } 24 | 25 | type StorageGatewayVolumeLister struct{} 26 | 27 | func (l *StorageGatewayVolumeLister) List(_ context.Context, o interface{}) ([]resource.Resource, error) { 28 | opts := o.(*nuke.ListerOpts) 29 | 30 | svc := storagegateway.New(opts.Session) 31 | resources := make([]resource.Resource, 0) 32 | 33 | params := &storagegateway.ListVolumesInput{ 34 | Limit: aws.Int64(25), 35 | } 36 | 37 | for { 38 | output, err := svc.ListVolumes(params) 39 | if err != nil { 40 | return nil, err 41 | } 42 | 43 | for _, volumeInfo := range output.VolumeInfos { 44 | resources = append(resources, &StorageGatewayVolume{ 45 | svc: svc, 46 | ARN: volumeInfo.VolumeARN, 47 | }) 48 | } 49 | 50 | if output.Marker == nil { 51 | break 52 | } 53 | 54 | params.Marker = output.Marker 55 | } 56 | 57 | return resources, nil 58 | } 59 | 60 | type StorageGatewayVolume struct { 61 | svc *storagegateway.StorageGateway 62 | ARN *string 63 | } 64 | 65 | func (f *StorageGatewayVolume) Remove(_ context.Context) error { 66 | _, err := f.svc.DeleteVolume(&storagegateway.DeleteVolumeInput{ 67 | VolumeARN: f.ARN, 68 | }) 69 | 70 | return err 71 | } 72 | 73 | func (f *StorageGatewayVolume) String() string { 74 | return *f.ARN 75 | } 76 | -------------------------------------------------------------------------------- /resources/cloud9-environments.go: -------------------------------------------------------------------------------- 1 | package resources 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/aws/aws-sdk-go/aws" 7 | "github.com/aws/aws-sdk-go/service/cloud9" 8 | 9 | "github.com/ekristen/libnuke/pkg/registry" 10 | "github.com/ekristen/libnuke/pkg/resource" 11 | 12 | "github.com/ekristen/aws-nuke/v3/pkg/nuke" 13 | ) 14 | 15 | type Cloud9Environment struct { 16 | svc *cloud9.Cloud9 17 | environmentID *string 18 | } 19 | 20 | const Cloud9EnvironmentResource = "Cloud9Environment" 21 | 22 | func init() { 23 | registry.Register(®istry.Registration{ 24 | Name: Cloud9EnvironmentResource, 25 | Scope: nuke.Account, 26 | Lister: &Cloud9EnvironmentLister{}, 27 | }) 28 | } 29 | 30 | type Cloud9EnvironmentLister struct{} 31 | 32 | func (l *Cloud9EnvironmentLister) List(_ context.Context, o interface{}) ([]resource.Resource, error) { 33 | opts := o.(*nuke.ListerOpts) 34 | 35 | svc := cloud9.New(opts.Session) 36 | resources := make([]resource.Resource, 0) 37 | 38 | params := &cloud9.ListEnvironmentsInput{ 39 | MaxResults: aws.Int64(25), 40 | } 41 | 42 | for { 43 | resp, err := svc.ListEnvironments(params) 44 | if err != nil { 45 | return nil, err 46 | } 47 | 48 | for _, environmentID := range resp.EnvironmentIds { 49 | resources = append(resources, &Cloud9Environment{ 50 | svc: svc, 51 | environmentID: environmentID, 52 | }) 53 | } 54 | 55 | if resp.NextToken == nil { 56 | break 57 | } 58 | 59 | params.NextToken = resp.NextToken 60 | } 61 | 62 | return resources, nil 63 | } 64 | 65 | func (f *Cloud9Environment) Remove(_ context.Context) error { 66 | _, err := f.svc.DeleteEnvironment(&cloud9.DeleteEnvironmentInput{ 67 | EnvironmentId: f.environmentID, 68 | }) 69 | 70 | return err 71 | } 72 | 73 | func (f *Cloud9Environment) String() string { 74 | return *f.environmentID 75 | } 76 | -------------------------------------------------------------------------------- /resources/cloudwatch-dashboards.go: -------------------------------------------------------------------------------- 1 | package resources 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/aws/aws-sdk-go/service/cloudwatch" 7 | 8 | "github.com/ekristen/libnuke/pkg/registry" 9 | "github.com/ekristen/libnuke/pkg/resource" 10 | 11 | "github.com/ekristen/aws-nuke/v3/pkg/nuke" 12 | ) 13 | 14 | const CloudWatchDashboardResource = "CloudWatchDashboard" 15 | 16 | func init() { 17 | registry.Register(®istry.Registration{ 18 | Name: CloudWatchDashboardResource, 19 | Scope: nuke.Account, 20 | Lister: &CloudWatchDashboardLister{}, 21 | }) 22 | } 23 | 24 | type CloudWatchDashboardLister struct{} 25 | 26 | func (l *CloudWatchDashboardLister) List(_ context.Context, o interface{}) ([]resource.Resource, error) { 27 | opts := o.(*nuke.ListerOpts) 28 | 29 | svc := cloudwatch.New(opts.Session) 30 | resources := make([]resource.Resource, 0) 31 | 32 | params := &cloudwatch.ListDashboardsInput{} 33 | 34 | for { 35 | output, err := svc.ListDashboards(params) 36 | if err != nil { 37 | return nil, err 38 | } 39 | 40 | for _, dashboardEntry := range output.DashboardEntries { 41 | resources = append(resources, &CloudWatchDashboard{ 42 | svc: svc, 43 | dashboardName: dashboardEntry.DashboardName, 44 | }) 45 | } 46 | 47 | if output.NextToken == nil { 48 | break 49 | } 50 | 51 | params.NextToken = output.NextToken 52 | } 53 | 54 | return resources, nil 55 | } 56 | 57 | type CloudWatchDashboard struct { 58 | svc *cloudwatch.CloudWatch 59 | dashboardName *string 60 | } 61 | 62 | func (f *CloudWatchDashboard) Remove(_ context.Context) error { 63 | _, err := f.svc.DeleteDashboards(&cloudwatch.DeleteDashboardsInput{ 64 | DashboardNames: []*string{f.dashboardName}, 65 | }) 66 | 67 | return err 68 | } 69 | 70 | func (f *CloudWatchDashboard) String() string { 71 | return *f.dashboardName 72 | } 73 | -------------------------------------------------------------------------------- /resources/codedeploy-applications.go: -------------------------------------------------------------------------------- 1 | package resources 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/aws/aws-sdk-go/service/codedeploy" 7 | 8 | "github.com/ekristen/libnuke/pkg/registry" 9 | "github.com/ekristen/libnuke/pkg/resource" 10 | 11 | "github.com/ekristen/aws-nuke/v3/pkg/nuke" 12 | ) 13 | 14 | const CodeDeployApplicationResource = "CodeDeployApplication" 15 | 16 | func init() { 17 | registry.Register(®istry.Registration{ 18 | Name: CodeDeployApplicationResource, 19 | Scope: nuke.Account, 20 | Lister: &CodeDeployApplicationLister{}, 21 | }) 22 | } 23 | 24 | type CodeDeployApplicationLister struct{} 25 | 26 | func (l *CodeDeployApplicationLister) List(_ context.Context, o interface{}) ([]resource.Resource, error) { 27 | opts := o.(*nuke.ListerOpts) 28 | 29 | svc := codedeploy.New(opts.Session) 30 | resources := make([]resource.Resource, 0) 31 | 32 | params := &codedeploy.ListApplicationsInput{} 33 | 34 | for { 35 | resp, err := svc.ListApplications(params) 36 | if err != nil { 37 | return nil, err 38 | } 39 | 40 | for _, application := range resp.Applications { 41 | resources = append(resources, &CodeDeployApplication{ 42 | svc: svc, 43 | applicationName: application, 44 | }) 45 | } 46 | 47 | if resp.NextToken == nil { 48 | break 49 | } 50 | 51 | params.NextToken = resp.NextToken 52 | } 53 | 54 | return resources, nil 55 | } 56 | 57 | type CodeDeployApplication struct { 58 | svc *codedeploy.CodeDeploy 59 | applicationName *string 60 | } 61 | 62 | func (f *CodeDeployApplication) Remove(_ context.Context) error { 63 | _, err := f.svc.DeleteApplication(&codedeploy.DeleteApplicationInput{ 64 | ApplicationName: f.applicationName, 65 | }) 66 | 67 | return err 68 | } 69 | 70 | func (f *CodeDeployApplication) String() string { 71 | return *f.applicationName 72 | } 73 | -------------------------------------------------------------------------------- /resources/opsworks-instances.go: -------------------------------------------------------------------------------- 1 | package resources 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/aws/aws-sdk-go/service/opsworks" 7 | 8 | "github.com/ekristen/libnuke/pkg/registry" 9 | "github.com/ekristen/libnuke/pkg/resource" 10 | 11 | "github.com/ekristen/aws-nuke/v3/pkg/nuke" 12 | ) 13 | 14 | const OpsWorksInstanceResource = "OpsWorksInstance" 15 | 16 | func init() { 17 | registry.Register(®istry.Registration{ 18 | Name: OpsWorksInstanceResource, 19 | Scope: nuke.Account, 20 | Lister: &OpsWorksInstanceLister{}, 21 | }) 22 | } 23 | 24 | type OpsWorksInstanceLister struct{} 25 | 26 | func (l *OpsWorksInstanceLister) List(_ context.Context, o interface{}) ([]resource.Resource, error) { 27 | opts := o.(*nuke.ListerOpts) 28 | 29 | svc := opsworks.New(opts.Session) 30 | resources := make([]resource.Resource, 0) 31 | 32 | stackParams := &opsworks.DescribeStacksInput{} 33 | 34 | resp, err := svc.DescribeStacks(stackParams) 35 | if err != nil { 36 | return nil, err 37 | } 38 | 39 | instanceParams := &opsworks.DescribeInstancesInput{} 40 | for _, stack := range resp.Stacks { 41 | instanceParams.StackId = stack.StackId 42 | output, err := svc.DescribeInstances(instanceParams) 43 | if err != nil { 44 | return nil, err 45 | } 46 | 47 | for _, instance := range output.Instances { 48 | resources = append(resources, &OpsWorksInstance{ 49 | svc: svc, 50 | ID: instance.InstanceId, 51 | }) 52 | } 53 | } 54 | 55 | return resources, nil 56 | } 57 | 58 | type OpsWorksInstance struct { 59 | svc *opsworks.OpsWorks 60 | ID *string 61 | } 62 | 63 | func (f *OpsWorksInstance) Remove(_ context.Context) error { 64 | _, err := f.svc.DeleteInstance(&opsworks.DeleteInstanceInput{ 65 | InstanceId: f.ID, 66 | }) 67 | 68 | return err 69 | } 70 | 71 | func (f *OpsWorksInstance) String() string { 72 | return *f.ID 73 | } 74 | -------------------------------------------------------------------------------- /resources/sagemaker-endpoints.go: -------------------------------------------------------------------------------- 1 | package resources 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/aws/aws-sdk-go/aws" 7 | "github.com/aws/aws-sdk-go/service/sagemaker" 8 | 9 | "github.com/ekristen/libnuke/pkg/registry" 10 | "github.com/ekristen/libnuke/pkg/resource" 11 | 12 | "github.com/ekristen/aws-nuke/v3/pkg/nuke" 13 | ) 14 | 15 | const SageMakerEndpointResource = "SageMakerEndpoint" 16 | 17 | func init() { 18 | registry.Register(®istry.Registration{ 19 | Name: SageMakerEndpointResource, 20 | Scope: nuke.Account, 21 | Lister: &SageMakerEndpointLister{}, 22 | }) 23 | } 24 | 25 | type SageMakerEndpointLister struct{} 26 | 27 | func (l *SageMakerEndpointLister) List(_ context.Context, o interface{}) ([]resource.Resource, error) { 28 | opts := o.(*nuke.ListerOpts) 29 | 30 | svc := sagemaker.New(opts.Session) 31 | resources := make([]resource.Resource, 0) 32 | 33 | params := &sagemaker.ListEndpointsInput{ 34 | MaxResults: aws.Int64(30), 35 | } 36 | 37 | for { 38 | resp, err := svc.ListEndpoints(params) 39 | if err != nil { 40 | return nil, err 41 | } 42 | 43 | for _, endpoint := range resp.Endpoints { 44 | resources = append(resources, &SageMakerEndpoint{ 45 | svc: svc, 46 | endpointName: endpoint.EndpointName, 47 | }) 48 | } 49 | 50 | if resp.NextToken == nil { 51 | break 52 | } 53 | 54 | params.NextToken = resp.NextToken 55 | } 56 | 57 | return resources, nil 58 | } 59 | 60 | type SageMakerEndpoint struct { 61 | svc *sagemaker.SageMaker 62 | endpointName *string 63 | } 64 | 65 | func (f *SageMakerEndpoint) Remove(_ context.Context) error { 66 | _, err := f.svc.DeleteEndpoint(&sagemaker.DeleteEndpointInput{ 67 | EndpointName: f.endpointName, 68 | }) 69 | 70 | return err 71 | } 72 | 73 | func (f *SageMakerEndpoint) String() string { 74 | return *f.endpointName 75 | } 76 | -------------------------------------------------------------------------------- /resources/ses-configurationsets.go: -------------------------------------------------------------------------------- 1 | package resources 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/aws/aws-sdk-go/aws" 7 | "github.com/aws/aws-sdk-go/service/ses" 8 | 9 | "github.com/ekristen/libnuke/pkg/registry" 10 | "github.com/ekristen/libnuke/pkg/resource" 11 | 12 | "github.com/ekristen/aws-nuke/v3/pkg/nuke" 13 | ) 14 | 15 | const SESConfigurationSetResource = "SESConfigurationSet" 16 | 17 | func init() { 18 | registry.Register(®istry.Registration{ 19 | Name: SESConfigurationSetResource, 20 | Scope: nuke.Account, 21 | Lister: &SESConfigurationSetLister{}, 22 | }) 23 | } 24 | 25 | type SESConfigurationSetLister struct{} 26 | 27 | func (l *SESConfigurationSetLister) List(_ context.Context, o interface{}) ([]resource.Resource, error) { 28 | opts := o.(*nuke.ListerOpts) 29 | 30 | svc := ses.New(opts.Session) 31 | resources := make([]resource.Resource, 0) 32 | 33 | params := &ses.ListConfigurationSetsInput{ 34 | MaxItems: aws.Int64(100), 35 | } 36 | 37 | for { 38 | output, err := svc.ListConfigurationSets(params) 39 | if err != nil { 40 | return nil, err 41 | } 42 | 43 | for _, configurationSet := range output.ConfigurationSets { 44 | resources = append(resources, &SESConfigurationSet{ 45 | svc: svc, 46 | name: configurationSet.Name, 47 | }) 48 | } 49 | 50 | if output.NextToken == nil { 51 | break 52 | } 53 | 54 | params.NextToken = output.NextToken 55 | } 56 | 57 | return resources, nil 58 | } 59 | 60 | type SESConfigurationSet struct { 61 | svc *ses.SES 62 | name *string 63 | } 64 | 65 | func (f *SESConfigurationSet) Remove(_ context.Context) error { 66 | _, err := f.svc.DeleteConfigurationSet(&ses.DeleteConfigurationSetInput{ 67 | ConfigurationSetName: f.name, 68 | }) 69 | 70 | return err 71 | } 72 | 73 | func (f *SESConfigurationSet) String() string { 74 | return *f.name 75 | } 76 | -------------------------------------------------------------------------------- /resources/storagegateway-gateways.go: -------------------------------------------------------------------------------- 1 | package resources 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/aws/aws-sdk-go/aws" 7 | "github.com/aws/aws-sdk-go/service/storagegateway" 8 | 9 | "github.com/ekristen/libnuke/pkg/registry" 10 | "github.com/ekristen/libnuke/pkg/resource" 11 | 12 | "github.com/ekristen/aws-nuke/v3/pkg/nuke" 13 | ) 14 | 15 | const StorageGatewayGatewayResource = "StorageGatewayGateway" 16 | 17 | func init() { 18 | registry.Register(®istry.Registration{ 19 | Name: StorageGatewayGatewayResource, 20 | Scope: nuke.Account, 21 | Lister: &StorageGatewayGatewayLister{}, 22 | }) 23 | } 24 | 25 | type StorageGatewayGatewayLister struct{} 26 | 27 | func (l *StorageGatewayGatewayLister) List(_ context.Context, o interface{}) ([]resource.Resource, error) { 28 | opts := o.(*nuke.ListerOpts) 29 | 30 | svc := storagegateway.New(opts.Session) 31 | resources := make([]resource.Resource, 0) 32 | 33 | params := &storagegateway.ListGatewaysInput{ 34 | Limit: aws.Int64(25), 35 | } 36 | 37 | for { 38 | output, err := svc.ListGateways(params) 39 | if err != nil { 40 | return nil, err 41 | } 42 | 43 | for _, gateway := range output.Gateways { 44 | resources = append(resources, &StorageGatewayGateway{ 45 | svc: svc, 46 | ARN: gateway.GatewayARN, 47 | }) 48 | } 49 | 50 | if output.Marker == nil { 51 | break 52 | } 53 | 54 | params.Marker = output.Marker 55 | } 56 | 57 | return resources, nil 58 | } 59 | 60 | type StorageGatewayGateway struct { 61 | svc *storagegateway.StorageGateway 62 | ARN *string 63 | } 64 | 65 | func (f *StorageGatewayGateway) Remove(_ context.Context) error { 66 | _, err := f.svc.DeleteGateway(&storagegateway.DeleteGatewayInput{ 67 | GatewayARN: f.ARN, 68 | }) 69 | 70 | return err 71 | } 72 | 73 | func (f *StorageGatewayGateway) String() string { 74 | return *f.ARN 75 | } 76 | -------------------------------------------------------------------------------- /resources/apigateway-apikeys.go: -------------------------------------------------------------------------------- 1 | package resources 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/aws/aws-sdk-go/aws" 7 | "github.com/aws/aws-sdk-go/service/apigateway" 8 | 9 | "github.com/ekristen/libnuke/pkg/registry" 10 | "github.com/ekristen/libnuke/pkg/resource" 11 | 12 | "github.com/ekristen/aws-nuke/v3/pkg/nuke" 13 | ) 14 | 15 | const APIGatewayAPIKeyResource = "APIGatewayAPIKey" 16 | 17 | func init() { 18 | registry.Register(®istry.Registration{ 19 | Name: APIGatewayAPIKeyResource, 20 | Scope: nuke.Account, 21 | Lister: &APIGatewayAPIKeyLister{}, 22 | AlternativeResource: "AWS::ApiGateway::ApiKey", 23 | }) 24 | } 25 | 26 | type APIGatewayAPIKeyLister struct{} 27 | 28 | func (l *APIGatewayAPIKeyLister) List(_ context.Context, o interface{}) ([]resource.Resource, error) { 29 | opts := o.(*nuke.ListerOpts) 30 | svc := apigateway.New(opts.Session) 31 | 32 | var resources []resource.Resource 33 | 34 | params := &apigateway.GetApiKeysInput{ 35 | Limit: aws.Int64(100), 36 | } 37 | 38 | for { 39 | output, err := svc.GetApiKeys(params) 40 | if err != nil { 41 | return nil, err 42 | } 43 | 44 | for _, item := range output.Items { 45 | resources = append(resources, &APIGatewayAPIKey{ 46 | svc: svc, 47 | APIKey: item.Id, 48 | }) 49 | } 50 | 51 | if output.Position == nil { 52 | break 53 | } 54 | 55 | params.Position = output.Position 56 | } 57 | 58 | return resources, nil 59 | } 60 | 61 | type APIGatewayAPIKey struct { 62 | svc *apigateway.APIGateway 63 | APIKey *string 64 | } 65 | 66 | func (f *APIGatewayAPIKey) Remove(_ context.Context) error { 67 | _, err := f.svc.DeleteApiKey(&apigateway.DeleteApiKeyInput{ 68 | ApiKey: f.APIKey, 69 | }) 70 | 71 | return err 72 | } 73 | 74 | func (f *APIGatewayAPIKey) String() string { 75 | return *f.APIKey 76 | } 77 | -------------------------------------------------------------------------------- /resources/apigateway-domainnames.go: -------------------------------------------------------------------------------- 1 | package resources 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/aws/aws-sdk-go/aws" 7 | "github.com/aws/aws-sdk-go/service/apigateway" 8 | 9 | "github.com/ekristen/libnuke/pkg/registry" 10 | "github.com/ekristen/libnuke/pkg/resource" 11 | 12 | "github.com/ekristen/aws-nuke/v3/pkg/nuke" 13 | ) 14 | 15 | const APIGatewayDomainNameResource = "APIGatewayDomainName" 16 | 17 | func init() { 18 | registry.Register(®istry.Registration{ 19 | Name: APIGatewayDomainNameResource, 20 | Scope: nuke.Account, 21 | Lister: &APIGatewayDomainNameLister{}, 22 | }) 23 | } 24 | 25 | type APIGatewayDomainNameLister struct{} 26 | 27 | func (l *APIGatewayDomainNameLister) List(_ context.Context, o interface{}) ([]resource.Resource, error) { 28 | opts := o.(*nuke.ListerOpts) 29 | svc := apigateway.New(opts.Session) 30 | var resources []resource.Resource 31 | 32 | params := &apigateway.GetDomainNamesInput{ 33 | Limit: aws.Int64(100), 34 | } 35 | 36 | for { 37 | output, err := svc.GetDomainNames(params) 38 | if err != nil { 39 | return nil, err 40 | } 41 | 42 | for _, item := range output.Items { 43 | resources = append(resources, &APIGatewayDomainName{ 44 | svc: svc, 45 | domainName: item.DomainName, 46 | }) 47 | } 48 | 49 | if output.Position == nil { 50 | break 51 | } 52 | 53 | params.Position = output.Position 54 | } 55 | 56 | return resources, nil 57 | } 58 | 59 | type APIGatewayDomainName struct { 60 | svc *apigateway.APIGateway 61 | domainName *string 62 | } 63 | 64 | func (f *APIGatewayDomainName) Remove(_ context.Context) error { 65 | _, err := f.svc.DeleteDomainName(&apigateway.DeleteDomainNameInput{ 66 | DomainName: f.domainName, 67 | }) 68 | 69 | return err 70 | } 71 | 72 | func (f *APIGatewayDomainName) String() string { 73 | return *f.domainName 74 | } 75 | -------------------------------------------------------------------------------- /resources/ec2-key-pair.go: -------------------------------------------------------------------------------- 1 | package resources 2 | 3 | import ( 4 | "context" 5 | "time" 6 | 7 | "github.com/aws/aws-sdk-go/service/ec2" 8 | 9 | "github.com/ekristen/libnuke/pkg/registry" 10 | "github.com/ekristen/libnuke/pkg/resource" 11 | "github.com/ekristen/libnuke/pkg/types" 12 | 13 | "github.com/ekristen/aws-nuke/v3/pkg/nuke" 14 | ) 15 | 16 | const EC2KeyPairResource = "EC2KeyPair" 17 | 18 | func init() { 19 | registry.Register(®istry.Registration{ 20 | Name: EC2KeyPairResource, 21 | Scope: nuke.Account, 22 | Lister: &EC2KeyPairLister{}, 23 | }) 24 | } 25 | 26 | type EC2KeyPairLister struct{} 27 | 28 | func (l *EC2KeyPairLister) List(_ context.Context, o interface{}) ([]resource.Resource, error) { 29 | opts := o.(*nuke.ListerOpts) 30 | 31 | svc := ec2.New(opts.Session) 32 | 33 | resp, err := svc.DescribeKeyPairs(nil) 34 | if err != nil { 35 | return nil, err 36 | } 37 | 38 | resources := make([]resource.Resource, 0) 39 | for _, out := range resp.KeyPairs { 40 | resources = append(resources, &EC2KeyPair{ 41 | svc: svc, 42 | Name: out.KeyName, 43 | Tags: out.Tags, 44 | KeyType: out.KeyType, 45 | CreateTime: out.CreateTime, 46 | }) 47 | } 48 | 49 | return resources, nil 50 | } 51 | 52 | type EC2KeyPair struct { 53 | svc *ec2.EC2 54 | Name *string 55 | Tags []*ec2.Tag 56 | KeyType *string 57 | CreateTime *time.Time 58 | } 59 | 60 | func (r *EC2KeyPair) Remove(_ context.Context) error { 61 | params := &ec2.DeleteKeyPairInput{ 62 | KeyName: r.Name, 63 | } 64 | 65 | _, err := r.svc.DeleteKeyPair(params) 66 | if err != nil { 67 | return err 68 | } 69 | 70 | return nil 71 | } 72 | 73 | func (r *EC2KeyPair) Properties() types.Properties { 74 | return types.NewPropertiesFromStruct(r) 75 | } 76 | 77 | func (r *EC2KeyPair) String() string { 78 | return *r.Name 79 | } 80 | -------------------------------------------------------------------------------- /resources/gluedatabrew-schedules.go: -------------------------------------------------------------------------------- 1 | package resources 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/aws/aws-sdk-go/aws" 7 | "github.com/aws/aws-sdk-go/service/gluedatabrew" 8 | 9 | "github.com/ekristen/libnuke/pkg/registry" 10 | "github.com/ekristen/libnuke/pkg/resource" 11 | 12 | "github.com/ekristen/aws-nuke/v3/pkg/nuke" 13 | ) 14 | 15 | const GlueDataBrewSchedulesResource = "GlueDataBrewSchedules" 16 | 17 | func init() { 18 | registry.Register(®istry.Registration{ 19 | Name: GlueDataBrewSchedulesResource, 20 | Scope: nuke.Account, 21 | Lister: &GlueDataBrewSchedulesLister{}, 22 | }) 23 | } 24 | 25 | type GlueDataBrewSchedulesLister struct{} 26 | 27 | func (l *GlueDataBrewSchedulesLister) List(_ context.Context, o interface{}) ([]resource.Resource, error) { 28 | opts := o.(*nuke.ListerOpts) 29 | 30 | svc := gluedatabrew.New(opts.Session) 31 | resources := make([]resource.Resource, 0) 32 | 33 | params := &gluedatabrew.ListSchedulesInput{ 34 | MaxResults: aws.Int64(100), 35 | } 36 | 37 | for { 38 | output, err := svc.ListSchedules(params) 39 | if err != nil { 40 | return nil, err 41 | } 42 | 43 | for _, schedule := range output.Schedules { 44 | resources = append(resources, &GlueDataBrewSchedules{ 45 | svc: svc, 46 | name: schedule.Name, 47 | }) 48 | } 49 | 50 | if output.NextToken == nil { 51 | break 52 | } 53 | 54 | params.NextToken = output.NextToken 55 | } 56 | 57 | return resources, nil 58 | } 59 | 60 | type GlueDataBrewSchedules struct { 61 | svc *gluedatabrew.GlueDataBrew 62 | name *string 63 | } 64 | 65 | func (f *GlueDataBrewSchedules) Remove(_ context.Context) error { 66 | _, err := f.svc.DeleteSchedule(&gluedatabrew.DeleteScheduleInput{ 67 | Name: f.name, 68 | }) 69 | 70 | return err 71 | } 72 | 73 | func (f *GlueDataBrewSchedules) String() string { 74 | return *f.name 75 | } 76 | -------------------------------------------------------------------------------- /resources/guardduty.go: -------------------------------------------------------------------------------- 1 | package resources 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/aws/aws-sdk-go/service/guardduty" 7 | 8 | "github.com/ekristen/libnuke/pkg/registry" 9 | "github.com/ekristen/libnuke/pkg/resource" 10 | "github.com/ekristen/libnuke/pkg/types" 11 | 12 | "github.com/ekristen/aws-nuke/v3/pkg/nuke" 13 | ) 14 | 15 | const GuardDutyDetectorResource = "GuardDutyDetector" 16 | 17 | func init() { 18 | registry.Register(®istry.Registration{ 19 | Name: GuardDutyDetectorResource, 20 | Scope: nuke.Account, 21 | Lister: &GuardDutyDetectorLister{}, 22 | }) 23 | } 24 | 25 | type GuardDutyDetectorLister struct{} 26 | 27 | func (l *GuardDutyDetectorLister) List(_ context.Context, o interface{}) ([]resource.Resource, error) { 28 | opts := o.(*nuke.ListerOpts) 29 | 30 | svc := guardduty.New(opts.Session) 31 | 32 | detectors := make([]resource.Resource, 0) 33 | 34 | params := &guardduty.ListDetectorsInput{} 35 | 36 | err := svc.ListDetectorsPages(params, func(page *guardduty.ListDetectorsOutput, lastPage bool) bool { 37 | for _, out := range page.DetectorIds { 38 | detectors = append(detectors, &GuardDutyDetector{ 39 | svc: svc, 40 | id: out, 41 | }) 42 | } 43 | return true 44 | }) 45 | if err != nil { 46 | return nil, err 47 | } 48 | return detectors, nil 49 | } 50 | 51 | type GuardDutyDetector struct { 52 | svc *guardduty.GuardDuty 53 | id *string 54 | } 55 | 56 | func (r *GuardDutyDetector) Remove(_ context.Context) error { 57 | _, err := r.svc.DeleteDetector(&guardduty.DeleteDetectorInput{ 58 | DetectorId: r.id, 59 | }) 60 | return err 61 | } 62 | 63 | func (r *GuardDutyDetector) Properties() types.Properties { 64 | properties := types.NewProperties() 65 | properties.Set("DetectorID", r.id) 66 | return properties 67 | } 68 | 69 | func (r *GuardDutyDetector) String() string { 70 | return *r.id 71 | } 72 | -------------------------------------------------------------------------------- /resources/lightsail-loadbalancers.go: -------------------------------------------------------------------------------- 1 | package resources 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/aws/aws-sdk-go/service/lightsail" 7 | 8 | "github.com/ekristen/libnuke/pkg/registry" 9 | "github.com/ekristen/libnuke/pkg/resource" 10 | 11 | "github.com/ekristen/aws-nuke/v3/pkg/nuke" 12 | ) 13 | 14 | const LightsailLoadBalancerResource = "LightsailLoadBalancer" 15 | 16 | func init() { 17 | registry.Register(®istry.Registration{ 18 | Name: LightsailLoadBalancerResource, 19 | Scope: nuke.Account, 20 | Lister: &LightsailLoadBalancerLister{}, 21 | }) 22 | } 23 | 24 | type LightsailLoadBalancerLister struct{} 25 | 26 | func (l *LightsailLoadBalancerLister) List(_ context.Context, o interface{}) ([]resource.Resource, error) { 27 | opts := o.(*nuke.ListerOpts) 28 | 29 | svc := lightsail.New(opts.Session) 30 | resources := make([]resource.Resource, 0) 31 | 32 | params := &lightsail.GetLoadBalancersInput{} 33 | 34 | for { 35 | output, err := svc.GetLoadBalancers(params) 36 | if err != nil { 37 | return nil, err 38 | } 39 | 40 | for _, lb := range output.LoadBalancers { 41 | resources = append(resources, &LightsailLoadBalancer{ 42 | svc: svc, 43 | loadBalancerName: lb.Name, 44 | }) 45 | } 46 | 47 | if output.NextPageToken == nil { 48 | break 49 | } 50 | 51 | params.PageToken = output.NextPageToken 52 | } 53 | 54 | return resources, nil 55 | } 56 | 57 | type LightsailLoadBalancer struct { 58 | svc *lightsail.Lightsail 59 | loadBalancerName *string 60 | } 61 | 62 | func (f *LightsailLoadBalancer) Remove(_ context.Context) error { 63 | _, err := f.svc.DeleteLoadBalancer(&lightsail.DeleteLoadBalancerInput{ 64 | LoadBalancerName: f.loadBalancerName, 65 | }) 66 | 67 | return err 68 | } 69 | 70 | func (f *LightsailLoadBalancer) String() string { 71 | return *f.loadBalancerName 72 | } 73 | -------------------------------------------------------------------------------- /resources/resource-explorer2-indexes.go: -------------------------------------------------------------------------------- 1 | package resources 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/aws/aws-sdk-go/aws" 7 | "github.com/aws/aws-sdk-go/service/resourceexplorer2" 8 | "github.com/ekristen/aws-nuke/v3/pkg/nuke" 9 | "github.com/ekristen/libnuke/pkg/registry" 10 | "github.com/ekristen/libnuke/pkg/resource" 11 | ) 12 | 13 | const ResourceExplorer2IndexResource = "ResourceExplorer2Index" 14 | 15 | func init() { 16 | registry.Register(®istry.Registration{ 17 | Name: ResourceExplorer2IndexResource, 18 | Scope: nuke.Account, 19 | Lister: &ResourceExplorer2IndexLister{}, 20 | }) 21 | } 22 | 23 | type ResourceExplorer2IndexLister struct{} 24 | 25 | type ResourceExplorer2Index struct { 26 | svc *resourceexplorer2.ResourceExplorer2 27 | indexArn *string 28 | } 29 | 30 | func (l *ResourceExplorer2IndexLister) List(_ context.Context, o interface{}) ([]resource.Resource, error) { 31 | opts := o.(*nuke.ListerOpts) 32 | svc := resourceexplorer2.New(opts.Session) 33 | var resources []resource.Resource 34 | 35 | params := &resourceexplorer2.ListIndexesInput{} 36 | 37 | for { 38 | output, err := svc.ListIndexes(params) 39 | if err != nil { 40 | return nil, err 41 | } 42 | 43 | for _, index := range output.Indexes { 44 | resources = append(resources, &ResourceExplorer2Index{ 45 | svc: svc, 46 | indexArn: index.Arn, 47 | }) 48 | } 49 | 50 | if output.NextToken == nil { 51 | break 52 | } 53 | 54 | params.SetNextToken(aws.StringValue(output.NextToken)) 55 | } 56 | 57 | return resources, nil 58 | } 59 | 60 | func (f *ResourceExplorer2Index) Remove(_ context.Context) error { 61 | _, err := f.svc.DeleteIndex(&resourceexplorer2.DeleteIndexInput{ 62 | Arn: f.indexArn, 63 | }) 64 | 65 | return err 66 | } 67 | 68 | func (f *ResourceExplorer2Index) String() string { 69 | return *f.indexArn 70 | } 71 | -------------------------------------------------------------------------------- /resources/ssm-maintenancewindows.go: -------------------------------------------------------------------------------- 1 | package resources 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/aws/aws-sdk-go/aws" 7 | "github.com/aws/aws-sdk-go/service/ssm" 8 | 9 | "github.com/ekristen/libnuke/pkg/registry" 10 | "github.com/ekristen/libnuke/pkg/resource" 11 | 12 | "github.com/ekristen/aws-nuke/v3/pkg/nuke" 13 | ) 14 | 15 | const SSMMaintenanceWindowResource = "SSMMaintenanceWindow" 16 | 17 | func init() { 18 | registry.Register(®istry.Registration{ 19 | Name: SSMMaintenanceWindowResource, 20 | Scope: nuke.Account, 21 | Lister: &SSMMaintenanceWindowLister{}, 22 | }) 23 | } 24 | 25 | type SSMMaintenanceWindowLister struct{} 26 | 27 | func (l *SSMMaintenanceWindowLister) List(_ context.Context, o interface{}) ([]resource.Resource, error) { 28 | opts := o.(*nuke.ListerOpts) 29 | 30 | svc := ssm.New(opts.Session) 31 | resources := make([]resource.Resource, 0) 32 | 33 | params := &ssm.DescribeMaintenanceWindowsInput{ 34 | MaxResults: aws.Int64(50), 35 | } 36 | 37 | for { 38 | output, err := svc.DescribeMaintenanceWindows(params) 39 | if err != nil { 40 | return nil, err 41 | } 42 | 43 | for _, windowIdentity := range output.WindowIdentities { 44 | resources = append(resources, &SSMMaintenanceWindow{ 45 | svc: svc, 46 | ID: windowIdentity.WindowId, 47 | }) 48 | } 49 | 50 | if output.NextToken == nil { 51 | break 52 | } 53 | 54 | params.NextToken = output.NextToken 55 | } 56 | 57 | return resources, nil 58 | } 59 | 60 | type SSMMaintenanceWindow struct { 61 | svc *ssm.SSM 62 | ID *string 63 | } 64 | 65 | func (f *SSMMaintenanceWindow) Remove(_ context.Context) error { 66 | _, err := f.svc.DeleteMaintenanceWindow(&ssm.DeleteMaintenanceWindowInput{ 67 | WindowId: f.ID, 68 | }) 69 | 70 | return err 71 | } 72 | 73 | func (f *SSMMaintenanceWindow) String() string { 74 | return *f.ID 75 | } 76 | --------------------------------------------------------------------------------