Skip to content

Commit 5621d42

Browse files
authored
Merge pull request #2 from terraform-linters/migrate_api_rules
Migrate API rules from TFLint core
2 parents 21a3144 + 30e8069 commit 5621d42

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

54 files changed

+54820
-36
lines changed

aws/api.go

Lines changed: 218 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,218 @@
1+
package aws
2+
3+
import (
4+
"github.com/aws/aws-sdk-go/service/ec2"
5+
"github.com/aws/aws-sdk-go/service/elasticache"
6+
"github.com/aws/aws-sdk-go/service/iam"
7+
"github.com/aws/aws-sdk-go/service/rds"
8+
)
9+
10+
// DescribeSecurityGroups is a wrapper of DescribeSecurityGroups
11+
func (c *Client) DescribeSecurityGroups() (map[string]bool, error) {
12+
ret := map[string]bool{}
13+
resp, err := c.EC2.DescribeSecurityGroups(&ec2.DescribeSecurityGroupsInput{})
14+
if err != nil {
15+
return ret, err
16+
}
17+
for _, sg := range resp.SecurityGroups {
18+
ret[*sg.GroupId] = true
19+
}
20+
return ret, err
21+
}
22+
23+
// DescribeSubnets is a wrapper of DescribeSubnets
24+
func (c *Client) DescribeSubnets() (map[string]bool, error) {
25+
ret := map[string]bool{}
26+
resp, err := c.EC2.DescribeSubnets(&ec2.DescribeSubnetsInput{})
27+
if err != nil {
28+
return ret, err
29+
}
30+
for _, subnet := range resp.Subnets {
31+
ret[*subnet.SubnetId] = true
32+
}
33+
return ret, err
34+
}
35+
36+
// DescribeDBSubnetGroups is a wrapper of DescribeDBSubnetGroups
37+
func (c *Client) DescribeDBSubnetGroups() (map[string]bool, error) {
38+
ret := map[string]bool{}
39+
resp, err := c.RDS.DescribeDBSubnetGroups(&rds.DescribeDBSubnetGroupsInput{})
40+
if err != nil {
41+
return ret, err
42+
}
43+
for _, subnetGroup := range resp.DBSubnetGroups {
44+
ret[*subnetGroup.DBSubnetGroupName] = true
45+
}
46+
return ret, err
47+
}
48+
49+
// DescribeOptionGroups is a wrapper of DescribeOptionGroups
50+
func (c *Client) DescribeOptionGroups() (map[string]bool, error) {
51+
ret := map[string]bool{}
52+
resp, err := c.RDS.DescribeOptionGroups(&rds.DescribeOptionGroupsInput{})
53+
if err != nil {
54+
return ret, err
55+
}
56+
for _, optionGroup := range resp.OptionGroupsList {
57+
ret[*optionGroup.OptionGroupName] = true
58+
}
59+
return ret, err
60+
}
61+
62+
// DescribeDBParameterGroups is a wrapper of DescribeDBParameterGroups
63+
func (c *Client) DescribeDBParameterGroups() (map[string]bool, error) {
64+
ret := map[string]bool{}
65+
resp, err := c.RDS.DescribeDBParameterGroups(&rds.DescribeDBParameterGroupsInput{})
66+
if err != nil {
67+
return ret, err
68+
}
69+
for _, parameterGroup := range resp.DBParameterGroups {
70+
ret[*parameterGroup.DBParameterGroupName] = true
71+
}
72+
return ret, err
73+
}
74+
75+
// DescribeCacheParameterGroups is a wrapper of DescribeCacheParameterGroups
76+
func (c *Client) DescribeCacheParameterGroups() (map[string]bool, error) {
77+
ret := map[string]bool{}
78+
resp, err := c.ElastiCache.DescribeCacheParameterGroups(&elasticache.DescribeCacheParameterGroupsInput{})
79+
if err != nil {
80+
return ret, err
81+
}
82+
for _, parameterGroup := range resp.CacheParameterGroups {
83+
ret[*parameterGroup.CacheParameterGroupName] = true
84+
}
85+
return ret, err
86+
}
87+
88+
// DescribeCacheSubnetGroups is a wrapper of DescribeCacheSubnetGroups
89+
func (c *Client) DescribeCacheSubnetGroups() (map[string]bool, error) {
90+
ret := map[string]bool{}
91+
resp, err := c.ElastiCache.DescribeCacheSubnetGroups(&elasticache.DescribeCacheSubnetGroupsInput{})
92+
if err != nil {
93+
return ret, err
94+
}
95+
for _, subnetGroup := range resp.CacheSubnetGroups {
96+
ret[*subnetGroup.CacheSubnetGroupName] = true
97+
}
98+
return ret, err
99+
}
100+
101+
// DescribeInstances is a wrapper of DescribeInstances
102+
func (c *Client) DescribeInstances() (map[string]bool, error) {
103+
ret := map[string]bool{}
104+
resp, err := c.EC2.DescribeInstances(&ec2.DescribeInstancesInput{})
105+
if err != nil {
106+
return ret, err
107+
}
108+
for _, reservation := range resp.Reservations {
109+
for _, instance := range reservation.Instances {
110+
ret[*instance.InstanceId] = true
111+
}
112+
}
113+
return ret, err
114+
}
115+
116+
// ListInstanceProfiles is a wrapper of ListInstanceProfiles
117+
func (c *Client) ListInstanceProfiles() (map[string]bool, error) {
118+
ret := map[string]bool{}
119+
resp, err := c.IAM.ListInstanceProfiles(&iam.ListInstanceProfilesInput{})
120+
if err != nil {
121+
return ret, err
122+
}
123+
for _, iamProfile := range resp.InstanceProfiles {
124+
ret[*iamProfile.InstanceProfileName] = true
125+
}
126+
return ret, err
127+
}
128+
129+
// DescribeKeyPairs is a wrapper of DescribeKeyPairs
130+
func (c *Client) DescribeKeyPairs() (map[string]bool, error) {
131+
ret := map[string]bool{}
132+
resp, err := c.EC2.DescribeKeyPairs(&ec2.DescribeKeyPairsInput{})
133+
if err != nil {
134+
return ret, err
135+
}
136+
for _, keyPair := range resp.KeyPairs {
137+
ret[*keyPair.KeyName] = true
138+
}
139+
return ret, err
140+
}
141+
142+
// DescribeEgressOnlyInternetGateways is wrapper of DescribeEgressOnlyInternetGateways
143+
func (c *Client) DescribeEgressOnlyInternetGateways() (map[string]bool, error) {
144+
ret := map[string]bool{}
145+
resp, err := c.EC2.DescribeEgressOnlyInternetGateways(&ec2.DescribeEgressOnlyInternetGatewaysInput{})
146+
if err != nil {
147+
return ret, err
148+
}
149+
for _, egateway := range resp.EgressOnlyInternetGateways {
150+
ret[*egateway.EgressOnlyInternetGatewayId] = true
151+
}
152+
return ret, err
153+
}
154+
155+
// DescribeInternetGateways is a wrapper of DescribeInternetGateways
156+
func (c *Client) DescribeInternetGateways() (map[string]bool, error) {
157+
ret := map[string]bool{}
158+
resp, err := c.EC2.DescribeInternetGateways(&ec2.DescribeInternetGatewaysInput{})
159+
if err != nil {
160+
return ret, err
161+
}
162+
for _, gateway := range resp.InternetGateways {
163+
ret[*gateway.InternetGatewayId] = true
164+
}
165+
return ret, err
166+
}
167+
168+
// DescribeNatGateways is a wrapper of DescribeNatGateways
169+
func (c *Client) DescribeNatGateways() (map[string]bool, error) {
170+
ret := map[string]bool{}
171+
resp, err := c.EC2.DescribeNatGateways(&ec2.DescribeNatGatewaysInput{})
172+
if err != nil {
173+
return ret, err
174+
}
175+
for _, ngateway := range resp.NatGateways {
176+
ret[*ngateway.NatGatewayId] = true
177+
}
178+
return ret, err
179+
}
180+
181+
// DescribeNetworkInterfaces is a wrapper of DescribeNetworkInterfaces
182+
func (c *Client) DescribeNetworkInterfaces() (map[string]bool, error) {
183+
ret := map[string]bool{}
184+
resp, err := c.EC2.DescribeNetworkInterfaces(&ec2.DescribeNetworkInterfacesInput{})
185+
if err != nil {
186+
return ret, err
187+
}
188+
for _, networkInterface := range resp.NetworkInterfaces {
189+
ret[*networkInterface.NetworkInterfaceId] = true
190+
}
191+
return ret, err
192+
}
193+
194+
// DescribeRouteTables is a wrapper of DescribeRouteTables
195+
func (c *Client) DescribeRouteTables() (map[string]bool, error) {
196+
ret := map[string]bool{}
197+
resp, err := c.EC2.DescribeRouteTables(&ec2.DescribeRouteTablesInput{})
198+
if err != nil {
199+
return ret, err
200+
}
201+
for _, routeTable := range resp.RouteTables {
202+
ret[*routeTable.RouteTableId] = true
203+
}
204+
return ret, err
205+
}
206+
207+
// DescribeVpcPeeringConnections is a wrapper of DescribeVpcPeeringConnections
208+
func (c *Client) DescribeVpcPeeringConnections() (map[string]bool, error) {
209+
ret := map[string]bool{}
210+
resp, err := c.EC2.DescribeVpcPeeringConnections(&ec2.DescribeVpcPeeringConnectionsInput{})
211+
if err != nil {
212+
return ret, err
213+
}
214+
for _, vpcPeeringConnection := range resp.VpcPeeringConnections {
215+
ret[*vpcPeeringConnection.VpcPeeringConnectionId] = true
216+
}
217+
return ret, err
218+
}

aws/client.go

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
package aws
2+
3+
import (
4+
"errors"
5+
"log"
6+
"strings"
7+
8+
"github.com/aws/aws-sdk-go/service/ec2"
9+
"github.com/aws/aws-sdk-go/service/ec2/ec2iface"
10+
"github.com/aws/aws-sdk-go/service/ecs"
11+
"github.com/aws/aws-sdk-go/service/ecs/ecsiface"
12+
"github.com/aws/aws-sdk-go/service/elasticache"
13+
"github.com/aws/aws-sdk-go/service/elasticache/elasticacheiface"
14+
"github.com/aws/aws-sdk-go/service/elb"
15+
"github.com/aws/aws-sdk-go/service/elb/elbiface"
16+
"github.com/aws/aws-sdk-go/service/elbv2"
17+
"github.com/aws/aws-sdk-go/service/elbv2/elbv2iface"
18+
"github.com/aws/aws-sdk-go/service/iam"
19+
"github.com/aws/aws-sdk-go/service/iam/iamiface"
20+
"github.com/aws/aws-sdk-go/service/rds"
21+
"github.com/aws/aws-sdk-go/service/rds/rdsiface"
22+
awsbase "github.com/hashicorp/aws-sdk-go-base"
23+
"github.com/mitchellh/go-homedir"
24+
)
25+
26+
//go:generate go run github.com/golang/mock/mockgen -destination mock/ec2.go -package mock github.com/aws/aws-sdk-go/service/ec2/ec2iface EC2API
27+
//go:generate go run github.com/golang/mock/mockgen -destination mock/elasticache.go -package mock github.com/aws/aws-sdk-go/service/elasticache/elasticacheiface ElastiCacheAPI
28+
//go:generate go run github.com/golang/mock/mockgen -destination mock/elb.go -package mock github.com/aws/aws-sdk-go/service/elb/elbiface ELBAPI
29+
//go:generate go run github.com/golang/mock/mockgen -destination mock/elbv2.go -package mock github.com/aws/aws-sdk-go/service/elbv2/elbv2iface ELBV2API
30+
//go:generate go run github.com/golang/mock/mockgen -destination mock/iam.go -package mock github.com/aws/aws-sdk-go/service/iam/iamiface IAMAPI
31+
//go:generate go run github.com/golang/mock/mockgen -destination mock/rds.go -package mock github.com/aws/aws-sdk-go/service/rds/rdsiface RDSAPI
32+
//go:generate go run github.com/golang/mock/mockgen -destination mock/ecs.go -package mock github.com/aws/aws-sdk-go/service/ecs/ecsiface ECSAPI
33+
34+
// Client is a wrapper of the AWS SDK client
35+
// It has interfaces for each services to make testing easier
36+
type Client struct {
37+
IAM iamiface.IAMAPI
38+
EC2 ec2iface.EC2API
39+
RDS rdsiface.RDSAPI
40+
ElastiCache elasticacheiface.ElastiCacheAPI
41+
ELB elbiface.ELBAPI
42+
ELBV2 elbv2iface.ELBV2API
43+
ECS ecsiface.ECSAPI
44+
}
45+
46+
// Credentials is credentials for AWS used in deep check mode
47+
type Credentials struct {
48+
AccessKey string
49+
SecretKey string
50+
Profile string
51+
CredsFile string
52+
AssumeRoleARN string
53+
AssumeRoleExternalID string
54+
AssumeRolePolicy string
55+
AssumeRoleSessionName string
56+
Region string
57+
}
58+
59+
// NewClient returns a new Client with configured session
60+
func NewClient(creds Credentials) (*Client, error) {
61+
log.Print("[INFO] Initialize AWS Client")
62+
63+
config, err := getBaseConfig(creds)
64+
if err != nil {
65+
return nil, err
66+
}
67+
68+
s, err := awsbase.GetSession(config)
69+
if err != nil {
70+
return nil, formatBaseConfigError(err)
71+
}
72+
73+
return &Client{
74+
IAM: iam.New(s),
75+
EC2: ec2.New(s),
76+
RDS: rds.New(s),
77+
ElastiCache: elasticache.New(s),
78+
ELB: elb.New(s),
79+
ELBV2: elbv2.New(s),
80+
ECS: ecs.New(s),
81+
}, nil
82+
}
83+
84+
func getBaseConfig(creds Credentials) (*awsbase.Config, error) {
85+
expandedCredsFile, err := homedir.Expand(creds.CredsFile)
86+
if err != nil {
87+
return nil, err
88+
}
89+
90+
return &awsbase.Config{
91+
AccessKey: creds.AccessKey,
92+
AssumeRoleARN: creds.AssumeRoleARN,
93+
AssumeRoleExternalID: creds.AssumeRoleExternalID,
94+
AssumeRolePolicy: creds.AssumeRolePolicy,
95+
AssumeRoleSessionName: creds.AssumeRoleSessionName,
96+
SecretKey: creds.SecretKey,
97+
Profile: creds.Profile,
98+
CredsFilename: expandedCredsFile,
99+
Region: creds.Region,
100+
}, nil
101+
}
102+
103+
// @see https://github.com/hashicorp/aws-sdk-go-base/blob/v0.3.0/session.go#L87
104+
func formatBaseConfigError(err error) error {
105+
if strings.Contains(err.Error(), "No valid credential sources found for AWS Provider") {
106+
return errors.New("No valid credential sources found")
107+
}
108+
return err
109+
}

aws/client_test.go

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
package aws
2+
3+
import (
4+
"path/filepath"
5+
"testing"
6+
7+
"github.com/google/go-cmp/cmp"
8+
awsbase "github.com/hashicorp/aws-sdk-go-base"
9+
"github.com/mitchellh/go-homedir"
10+
)
11+
12+
func Test_getBaseConfig(t *testing.T) {
13+
home, err := homedir.Expand("~/")
14+
if err != nil {
15+
t.Fatal(err)
16+
}
17+
18+
cases := []struct {
19+
Name string
20+
Creds Credentials
21+
Expected *awsbase.Config
22+
}{
23+
{
24+
Name: "static credentials",
25+
Creds: Credentials{
26+
AccessKey: "AWS_ACCESS_KEY",
27+
SecretKey: "AWS_SECRET_KEY",
28+
Region: "us-east-1",
29+
},
30+
Expected: &awsbase.Config{
31+
AccessKey: "AWS_ACCESS_KEY",
32+
SecretKey: "AWS_SECRET_KEY",
33+
Region: "us-east-1",
34+
},
35+
},
36+
{
37+
Name: "shared credentials",
38+
Creds: Credentials{
39+
Profile: "default",
40+
CredsFile: "~/.aws/creds",
41+
Region: "us-east-1",
42+
},
43+
Expected: &awsbase.Config{
44+
Profile: "default",
45+
CredsFilename: filepath.Join(home, ".aws", "creds"),
46+
Region: "us-east-1",
47+
},
48+
},
49+
}
50+
51+
for _, tc := range cases {
52+
base, err := getBaseConfig(tc.Creds)
53+
if err != nil {
54+
t.Fatalf("Failed `%s` test: Unexpected error occurred: %s", tc.Name, err)
55+
}
56+
if !cmp.Equal(tc.Expected, base) {
57+
t.Fatalf("Failed `%s` test: Diff=%s", tc.Name, cmp.Diff(tc.Expected, base))
58+
}
59+
}
60+
}

0 commit comments

Comments
 (0)