Skip to content

Commit 3482db2

Browse files
authored
feat: add support for AWS Shield resources (#731)
1 parent c090577 commit 3482db2

File tree

9 files changed

+493
-4
lines changed

9 files changed

+493
-4
lines changed
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
---
2+
generated: true
3+
---
4+
5+
# ShieldProtectionGroup
6+
7+
8+
## Resource
9+
10+
```text
11+
ShieldProtectionGroup
12+
```
13+
14+
## Properties
15+
16+
17+
- `Aggregation`: The aggregation type for the protection group
18+
- `Members`: The list of resource ARNs that are members of the protection group
19+
- `Pattern`: The pattern for the protection group
20+
- `ProtectionGroupArn`: The ARN of the Shield protection group
21+
- `ProtectionGroupId`: The unique identifier of the Shield protection group
22+
- `ResourceType`: The resource type for the protection group
23+
- `tag:<key>:`: This resource has tags with property `Tags`. These are key/value pairs that are
24+
added as their own property with the prefix of `tag:` (e.g. [tag:example: "value"])
25+
26+
!!! note - Using Properties
27+
Properties are what [Filters](../config-filtering.md) are written against in your configuration. You use the property
28+
names to write filters for what you want to **keep** and omit from the nuke process.
29+
30+
### String Property
31+
32+
The string representation of a resource is generally the value of the Name, ID or ARN field of the resource. Not all
33+
resources support properties. To write a filter against the string representation, simply omit the `property` field in
34+
the filter.
35+
36+
The string value is always what is used in the output of the log format when a resource is identified.
37+
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
---
2+
generated: true
3+
---
4+
5+
# ShieldProtection
6+
7+
8+
## Resource
9+
10+
```text
11+
ShieldProtection
12+
```
13+
14+
## Properties
15+
16+
17+
- `ID`: The unique identifier of the Shield protection
18+
- `Name`: The name of the Shield protection
19+
- `ProtectionArn`: The ARN of the Shield protection
20+
- `ResourceArn`: The ARN of the AWS resource being protected
21+
- `tag:<key>:`: This resource has tags with property `Tags`. These are key/value pairs that are
22+
added as their own property with the prefix of `tag:` (e.g. [tag:example: "value"])
23+
24+
!!! note - Using Properties
25+
Properties are what [Filters](../config-filtering.md) are written against in your configuration. You use the property
26+
names to write filters for what you want to **keep** and omit from the nuke process.
27+
28+
### String Property
29+
30+
The string representation of a resource is generally the value of the Name, ID or ARN field of the resource. Not all
31+
resources support properties. To write a filter against the string representation, simply omit the `property` field in
32+
the filter.
33+
34+
The string value is always what is used in the output of the log format when a resource is identified.
35+

go.mod

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ toolchain go1.24.5
66

77
require (
88
github.com/aws/aws-sdk-go v1.55.7
9-
github.com/aws/aws-sdk-go-v2 v1.37.2
9+
github.com/aws/aws-sdk-go-v2 v1.38.3
1010
github.com/aws/aws-sdk-go-v2/config v1.28.11
1111
github.com/aws/aws-sdk-go-v2/credentials v1.17.68
1212
github.com/aws/aws-sdk-go-v2/service/apigateway v1.28.12
@@ -27,7 +27,7 @@ require (
2727
github.com/aws/aws-sdk-go-v2/service/ssmquicksetup v1.3.10
2828
github.com/aws/aws-sdk-go-v2/service/sts v1.33.20
2929
github.com/aws/aws-sdk-go-v2/service/transfer v1.55.5
30-
github.com/aws/smithy-go v1.22.5
30+
github.com/aws/smithy-go v1.23.0
3131
github.com/ekristen/libnuke v1.3.0
3232
github.com/fatih/color v1.18.0
3333
github.com/golang/mock v1.6.0
@@ -46,14 +46,15 @@ require (
4646
require (
4747
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.7 // indirect
4848
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.30 // indirect
49-
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.2 // indirect
50-
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.2 // indirect
49+
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.6 // indirect
50+
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.6 // indirect
5151
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1 // indirect
5252
github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.27 // indirect
5353
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.0 // indirect
5454
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.4.8 // indirect
5555
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.1 // indirect
5656
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.18.10 // indirect
57+
github.com/aws/aws-sdk-go-v2/service/shield v1.34.2 // indirect
5758
github.com/aws/aws-sdk-go-v2/service/sso v1.25.3 // indirect
5859
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.30.1 // indirect
5960
github.com/benbjohnson/clock v1.3.0 // indirect

go.sum

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ github.com/aws/aws-sdk-go v1.55.7 h1:UJrkFq7es5CShfBwlWAC8DA077vp8PyVbQd3lqLiztE
22
github.com/aws/aws-sdk-go v1.55.7/go.mod h1:eRwEWoyTWFMVYVQzKMNHWP5/RV4xIUGMQfXQHfHkpNU=
33
github.com/aws/aws-sdk-go-v2 v1.37.2 h1:xkW1iMYawzcmYFYEV0UCMxc8gSsjCGEhBXQkdQywVbo=
44
github.com/aws/aws-sdk-go-v2 v1.37.2/go.mod h1:9Q0OoGQoboYIAJyslFyF1f5K1Ryddop8gqMhWx/n4Wg=
5+
github.com/aws/aws-sdk-go-v2 v1.38.3 h1:B6cV4oxnMs45fql4yRH+/Po/YU+597zgWqvDpYMturk=
6+
github.com/aws/aws-sdk-go-v2 v1.38.3/go.mod h1:sDioUELIUO9Znk23YVmIk86/9DOpkbyyVb1i/gUNFXY=
57
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.7 h1:lL7IfaFzngfx0ZwUGOZdsFFnQ5uLvR0hWqqhyE7Q9M8=
68
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.7/go.mod h1:QraP0UcVlQJsmHfioCrveWOC1nbiWUl3ej08h4mXWoc=
79
github.com/aws/aws-sdk-go-v2/config v1.28.11 h1:7Ekru0IkRHRnSRWGQLnLN6i0o1Jncd0rHo2T130+tEQ=
@@ -12,8 +14,12 @@ github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.30 h1:x793wxmUWVDhshP8WW2mln
1214
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.30/go.mod h1:Jpne2tDnYiFascUEs2AWHJL9Yp7A5ZVy3TNyxaAjD6M=
1315
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.2 h1:sPiRHLVUIIQcoVZTNwqQcdtjkqkPopyYmIX0M5ElRf4=
1416
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.2/go.mod h1:ik86P3sgV+Bk7c1tBFCwI3VxMoSEwl4YkRB9xn1s340=
17+
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.6 h1:uF68eJA6+S9iVr9WgX1NaRGyQ/6MdIyc4JNUo6TN1FA=
18+
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.6/go.mod h1:qlPeVZCGPiobx8wb1ft0GHT5l+dc6ldnwInDFaMvC7Y=
1519
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.2 h1:ZdzDAg075H6stMZtbD2o+PyB933M/f20e9WmCBC17wA=
1620
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.2/go.mod h1:eE1IIzXG9sdZCB0pNNpMpsYTLl4YdOQD3njiVN1e/E4=
21+
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.6 h1:pa1DEC6JoI0zduhZePp3zmhWvk/xxm4NB8Hy/Tlsgos=
22+
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.6/go.mod h1:gxEjPebnhWGJoaDdtDkA0JX46VRg1wcTHYe63OfX5pE=
1723
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1 h1:VaRN3TlFdd6KxX1x3ILT5ynH6HvKgqdiXoTxAF4HQcQ=
1824
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1/go.mod h1:FbtygfRFze9usAadmnGJNc8KsP346kEe+y2/oyhGAGc=
1925
github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.27 h1:AmB5QxnD+fBFrg9LcqzkgF/CaYvMyU/BTlejG4t1S7Q=
@@ -56,6 +62,8 @@ github.com/aws/aws-sdk-go-v2/service/s3 v1.72.3 h1:WZOmJfCDV+4tYacLxpiojoAdT5sxT
5662
github.com/aws/aws-sdk-go-v2/service/s3 v1.72.3/go.mod h1:xMekrnhmJ5aqmyxtmALs7mlvXw5xRh+eYjOjvrIIFJ4=
5763
github.com/aws/aws-sdk-go-v2/service/s3control v1.52.7 h1:cewH1fJ35N26pujUo8pXtqngf0QZio0ko62rT1x2Uak=
5864
github.com/aws/aws-sdk-go-v2/service/s3control v1.52.7/go.mod h1:zZ6ah0Hp8TqLZERFcwSQ2T5A4lMkX5vujkDvSkFiXh8=
65+
github.com/aws/aws-sdk-go-v2/service/shield v1.34.2 h1:daAMTHVfwUaAOdyBlGNtl09xqkjB9k3X3/BgEVpmJD4=
66+
github.com/aws/aws-sdk-go-v2/service/shield v1.34.2/go.mod h1:TWtjIQVEyCP4M8JXZ/ePx3Zw2XHe1fC2arN6p44C2PI=
5967
github.com/aws/aws-sdk-go-v2/service/ssmquicksetup v1.3.10 h1:3e9ZvkZB5NsDellLxPuaCJSeA5Hg7SeHY+Godotzizc=
6068
github.com/aws/aws-sdk-go-v2/service/ssmquicksetup v1.3.10/go.mod h1:UKtH07HzEWvg7zZ6R2JixYlmGYa/3i2niz7Lz2zJoeM=
6169
github.com/aws/aws-sdk-go-v2/service/sso v1.25.3 h1:1Gw+9ajCV1jogloEv1RRnvfRFia2cL6c9cuKV2Ps+G8=
@@ -68,6 +76,8 @@ github.com/aws/aws-sdk-go-v2/service/transfer v1.55.5 h1:3CgAcyZciL7KG/8LCEWWoMJ
6876
github.com/aws/aws-sdk-go-v2/service/transfer v1.55.5/go.mod h1:NJBUE6GjnjqSvexXpU0pj/2w+VEhRk5XPL5rRZpj7bI=
6977
github.com/aws/smithy-go v1.22.5 h1:P9ATCXPMb2mPjYBgueqJNCA5S9UfktsW0tTxi+a7eqw=
7078
github.com/aws/smithy-go v1.22.5/go.mod h1:t1ufH5HMublsJYulve2RKmHDC15xu1f26kHCp/HgceI=
79+
github.com/aws/smithy-go v1.23.0 h1:8n6I3gXzWJB2DxBDnfxgBaSX6oe0d/t10qGz7OKqMCE=
80+
github.com/aws/smithy-go v1.23.0/go.mod h1:t1ufH5HMublsJYulve2RKmHDC15xu1f26kHCp/HgceI=
7181
github.com/benbjohnson/clock v1.3.0 h1:ip6w0uFQkncKQ979AypyG0ER7mqUSBdKLOgAle/AT8A=
7282
github.com/benbjohnson/clock v1.3.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
7383
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=

mkdocs.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -618,6 +618,8 @@ nav:
618618
- Ses Receipt Rule Set: resources/ses-receipt-rule-set.md
619619
- Ses Template: resources/ses-template.md
620620
- Sfn State Machine: resources/sfn-state-machine.md
621+
- Shield Protection Group: resources/shield-protection-group.md
622+
- Shield Protection: resources/shield-protection.md
621623
- Signer Signing Job: resources/signer-signing-job.md
622624
- Simple Db Domain: resources/simple-db-domain.md
623625
- Storage Gateway File Share: resources/storage-gateway-file-share.md
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
package resources
2+
3+
import (
4+
"context"
5+
6+
"github.com/aws/aws-sdk-go-v2/service/shield"
7+
shieldtypes "github.com/aws/aws-sdk-go-v2/service/shield/types"
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 ShieldProtectionGroupResource = "ShieldProtectionGroup"
17+
18+
func init() {
19+
registry.Register(&registry.Registration{
20+
Name: ShieldProtectionGroupResource,
21+
Scope: nuke.Account,
22+
Resource: &ShieldProtectionGroup{},
23+
Lister: &ShieldProtectionGroupLister{},
24+
})
25+
}
26+
27+
type ShieldProtectionGroupLister struct{}
28+
29+
func (l *ShieldProtectionGroupLister) List(ctx context.Context, o interface{}) ([]resource.Resource, error) {
30+
opts := o.(*nuke.ListerOpts)
31+
32+
svc := shield.NewFromConfig(*opts.Config)
33+
34+
params := &shield.ListProtectionGroupsInput{}
35+
resources := make([]resource.Resource, 0)
36+
37+
for {
38+
resp, err := svc.ListProtectionGroups(ctx, params)
39+
if err != nil {
40+
return nil, err
41+
}
42+
43+
for i := range resp.ProtectionGroups {
44+
group := &resp.ProtectionGroups[i]
45+
46+
tags, err := svc.ListTagsForResource(ctx, &shield.ListTagsForResourceInput{
47+
ResourceARN: group.ProtectionGroupArn,
48+
})
49+
if err != nil {
50+
return nil, err
51+
}
52+
53+
resources = append(resources, &ShieldProtectionGroup{
54+
svc: svc,
55+
ProtectionGroupId: group.ProtectionGroupId,
56+
Aggregation: &group.Aggregation,
57+
Pattern: &group.Pattern,
58+
ResourceType: &group.ResourceType,
59+
Members: &group.Members,
60+
ProtectionGroupArn: group.ProtectionGroupArn,
61+
Tags: &tags.Tags,
62+
})
63+
}
64+
65+
if resp.NextToken == nil {
66+
break
67+
}
68+
params.NextToken = resp.NextToken
69+
}
70+
71+
return resources, nil
72+
}
73+
74+
type ShieldProtectionGroup struct {
75+
svc *shield.Client
76+
ProtectionGroupId *string `description:"The unique identifier of the Shield protection group"`
77+
Aggregation *shieldtypes.ProtectionGroupAggregation `description:"The aggregation type for the protection group"`
78+
Pattern *shieldtypes.ProtectionGroupPattern `description:"The pattern for the protection group"`
79+
ResourceType *shieldtypes.ProtectedResourceType `description:"The resource type for the protection group"`
80+
Members *[]string `description:"The list of resource ARNs that are members of the protection group"` //nolint:lll
81+
ProtectionGroupArn *string `description:"The ARN of the Shield protection group"`
82+
Tags *[]shieldtypes.Tag `description:"The tags associated with the Shield protection group"`
83+
}
84+
85+
func (r *ShieldProtectionGroup) Remove(ctx context.Context) error {
86+
params := &shield.DeleteProtectionGroupInput{
87+
ProtectionGroupId: r.ProtectionGroupId,
88+
}
89+
90+
_, err := r.svc.DeleteProtectionGroup(ctx, params)
91+
return err
92+
}
93+
94+
func (r *ShieldProtectionGroup) Properties() types.Properties {
95+
return types.NewPropertiesFromStruct(r)
96+
}
97+
98+
func (r *ShieldProtectionGroup) String() string {
99+
return *r.ProtectionGroupId
100+
}
Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
package resources
2+
3+
import (
4+
"testing"
5+
6+
"github.com/aws/aws-sdk-go-v2/aws"
7+
shieldtypes "github.com/aws/aws-sdk-go-v2/service/shield/types"
8+
"github.com/gotidy/ptr"
9+
"github.com/stretchr/testify/assert"
10+
)
11+
12+
func Test_ShieldProtectionGroup_String(t *testing.T) {
13+
a := assert.New(t)
14+
15+
shieldProtectionGroup := ShieldProtectionGroup{
16+
ProtectionGroupId: ptr.String("protection-group-id"),
17+
}
18+
19+
a.Equal("protection-group-id", shieldProtectionGroup.String())
20+
}
21+
22+
func Test_ShieldProtectionGroup_Properties(t *testing.T) {
23+
a := assert.New(t)
24+
25+
aggregation := shieldtypes.ProtectionGroupAggregationSum
26+
pattern := shieldtypes.ProtectionGroupPatternAll
27+
resourceType := shieldtypes.ProtectedResourceTypeCloudfrontDistribution
28+
29+
shieldProtectionGroup := ShieldProtectionGroup{
30+
ProtectionGroupId: ptr.String("protection-group-id"),
31+
Aggregation: &aggregation,
32+
Pattern: &pattern,
33+
ResourceType: &resourceType,
34+
Members: &[]string{"arn:aws:cloudfront::123456789012:distribution/EXAMPLE123"},
35+
ProtectionGroupArn: ptr.String("arn:aws:shield::123456789012:protection-group/protection-group-id"),
36+
Tags: &[]shieldtypes.Tag{
37+
{
38+
Key: aws.String("Environment"),
39+
Value: aws.String("production"),
40+
},
41+
{
42+
Key: aws.String("Team"),
43+
Value: aws.String("security"),
44+
},
45+
},
46+
}
47+
48+
properties := shieldProtectionGroup.Properties()
49+
50+
a.Equal("protection-group-id", properties.Get("ProtectionGroupId"))
51+
a.Equal("SUM", properties.Get("Aggregation"))
52+
a.Equal("ALL", properties.Get("Pattern"))
53+
a.Equal("CLOUDFRONT_DISTRIBUTION", properties.Get("ResourceType"))
54+
a.Equal("arn:aws:shield::123456789012:protection-group/protection-group-id", properties.Get("ProtectionGroupArn"))
55+
a.Equal("production", properties.Get("tag:Environment"))
56+
a.Equal("security", properties.Get("tag:Team"))
57+
}
58+
59+
func Test_ShieldProtectionGroup_Properties_EmptyTags(t *testing.T) {
60+
a := assert.New(t)
61+
62+
aggregation := shieldtypes.ProtectionGroupAggregationSum
63+
pattern := shieldtypes.ProtectionGroupPatternAll
64+
65+
shieldProtectionGroup := ShieldProtectionGroup{
66+
ProtectionGroupId: ptr.String("protection-group-id"),
67+
Aggregation: &aggregation,
68+
Pattern: &pattern,
69+
Members: &[]string{},
70+
ProtectionGroupArn: ptr.String("arn:aws:shield::123456789012:protection-group/protection-group-id"),
71+
Tags: &[]shieldtypes.Tag{},
72+
}
73+
74+
properties := shieldProtectionGroup.Properties()
75+
76+
a.Equal("protection-group-id", properties.Get("ProtectionGroupId"))
77+
a.Equal("SUM", properties.Get("Aggregation"))
78+
a.Equal("ALL", properties.Get("Pattern"))
79+
a.Equal("arn:aws:shield::123456789012:protection-group/protection-group-id", properties.Get("ProtectionGroupArn"))
80+
}
81+
82+
func Test_ShieldProtectionGroup_Properties_SpecialCharactersInTags(t *testing.T) {
83+
a := assert.New(t)
84+
85+
aggregation := shieldtypes.ProtectionGroupAggregationSum
86+
pattern := shieldtypes.ProtectionGroupPatternAll
87+
88+
shieldProtectionGroup := ShieldProtectionGroup{
89+
ProtectionGroupId: ptr.String("protection-group-id"),
90+
Aggregation: &aggregation,
91+
Pattern: &pattern,
92+
Members: &[]string{"arn:aws:cloudfront::123456789012:distribution/EXAMPLE123"},
93+
ProtectionGroupArn: ptr.String("arn:aws:shield::123456789012:protection-group/protection-group-id"),
94+
Tags: &[]shieldtypes.Tag{
95+
{
96+
Key: aws.String("Environment:Stage"),
97+
Value: aws.String("prod/staging"),
98+
},
99+
{
100+
Key: aws.String("Cost-Center"),
101+
Value: aws.String("security-team"),
102+
},
103+
},
104+
}
105+
106+
properties := shieldProtectionGroup.Properties()
107+
108+
a.Equal("protection-group-id", properties.Get("ProtectionGroupId"))
109+
a.Equal("prod/staging", properties.Get("tag:Environment:Stage"))
110+
a.Equal("security-team", properties.Get("tag:Cost-Center"))
111+
}

0 commit comments

Comments
 (0)