-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
11 changed files
with
900 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,11 @@ | ||
# Changelog | ||
|
||
## v6.2.0 (07/01/2019) | ||
|
||
**New** | ||
|
||
* Added `aws-dump` | ||
|
||
## v6.1.0 (21/12/2018) | ||
|
||
**New** | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,100 @@ | ||
# aws-dump | ||
|
||
Dumps AWS resources to JSON and optionally check if they are managed by Terraform | ||
|
||
``` | ||
usage: aws-dump --accounts-config=ACCOUNTS-CONFIG --output=OUTPUT [<flags>] | ||
Dump AWS resources | ||
Flags: | ||
--help Show context-sensitive help (also try --help-long and --help-man). | ||
--assume-role-arn=ASSUME-ROLE-ARN | ||
Role to assume | ||
--assume-role-external-id=ASSUME-ROLE-EXTERNAL-ID | ||
External ID of the role to assume | ||
--assume-role-session-name=ASSUME-ROLE-SESSION-NAME | ||
Role session name | ||
--region=REGION AWS Region | ||
--mfa-serial-number=MFA-SERIAL-NUMBER | ||
MFA Serial Number | ||
--mfa-token-code=MFA-TOKEN-CODE | ||
MFA Token Code | ||
-v, --version Display the version | ||
-c, --accounts-config=ACCOUNTS-CONFIG | ||
Configuration file with the accounts to list resources for. | ||
-t, --terraform-backends-config=TERRAFORM-BACKENDS-CONFIG | ||
Configuration file with the terraform backends to compare with. | ||
-o, --output=OUTPUT Filename to store the results in. | ||
--only-unmanaged Only return resources not managed by terraform. | ||
``` | ||
|
||
## Supported resources | ||
|
||
* EC2 | ||
* VPC | ||
* Security Groups | ||
* IAM (Does not include attachments) | ||
* Users | ||
* Access keys | ||
* Roles | ||
* Policies | ||
* S3 | ||
* Buckets | ||
|
||
## Configuration | ||
|
||
### AWS Accounts | ||
|
||
Create a JSON file with the following structure | ||
|
||
```js | ||
{ | ||
"accounts": [ | ||
{ | ||
"role_arn": "arn:aws:iam::123456789012:role/Role", | ||
"regions": ["us-east-1", "us-east-2", "eu-west-1"] | ||
}, | ||
{ | ||
"role_arn": "arn:aws:iam::234567890123:role/Role", | ||
"regions": ["us-east-1"] | ||
} | ||
] | ||
} | ||
``` | ||
|
||
Then pass the filename to the `--accounts-config` flag. | ||
|
||
### Terraform | ||
|
||
Currently only S3 backends are supported. | ||
|
||
#### s3 backends | ||
|
||
Create a JSON file with the following structure | ||
|
||
``` | ||
{ | ||
"destination": "./terraform-states/", | ||
"options": { | ||
"path_substitutions": [ | ||
{ | ||
"old": "/", | ||
"new": "-" | ||
} | ||
], | ||
"overwrite": false | ||
}, | ||
"s3":[ | ||
{ | ||
"bucket":"terraform-bucket", | ||
"keys":[ | ||
"test.tfstate", | ||
"prod.tfstate" | ||
], | ||
"region":"eu-west-1", | ||
"role_arn":"arn:aws:iam::123456789012:role/Role" | ||
} | ||
] | ||
} | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
package main | ||
|
||
import ( | ||
"encoding/json" | ||
"io/ioutil" | ||
|
||
"github.com/aws/aws-sdk-go/aws" | ||
"github.com/aws/aws-sdk-go/aws/session" | ||
"github.com/aws/aws-sdk-go/service/sts" | ||
"github.com/hamstah/awstools/common" | ||
) | ||
|
||
type Account struct { | ||
Regions []string `json:"regions"` | ||
RoleARN string `json:"role_arn"` | ||
ExternalID string `json:"external_id"` | ||
SessionName string `json:"session_name"` | ||
} | ||
|
||
type Accounts struct { | ||
Accounts []*Account `json:"accounts"` | ||
Sessions []*Session | ||
} | ||
|
||
type Session struct { | ||
Session *session.Session | ||
Config *aws.Config | ||
AccountID string | ||
} | ||
|
||
func NewAccounts(filename string) (*Accounts, error) { | ||
data, err := ioutil.ReadFile(filename) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
result := &Accounts{} | ||
err = json.Unmarshal(data, result) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
for _, account := range result.Accounts { | ||
for _, region := range account.Regions { | ||
sess, conf := common.OpenSession(&common.SessionFlags{ | ||
RoleArn: &account.RoleARN, | ||
RoleExternalID: &account.ExternalID, | ||
Region: ®ion, | ||
RoleSessionName: &account.SessionName, | ||
|
||
MFASerialNumber: aws.String(""), | ||
MFATokenCode: aws.String(""), | ||
}) | ||
|
||
stsClient := sts.New(sess, conf) | ||
identity, err := stsClient.GetCallerIdentity(&sts.GetCallerIdentityInput{}) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
result.Sessions = append(result.Sessions, &Session{ | ||
Session: sess, | ||
Config: conf, | ||
AccountID: *identity.Account, | ||
}) | ||
} | ||
} | ||
|
||
return result, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
package main | ||
|
||
import ( | ||
"fmt" | ||
|
||
"github.com/aws/aws-sdk-go/service/ec2" | ||
) | ||
|
||
func EC2ListVpcs(session *Session) *FetchResult { | ||
client := ec2.New(session.Session, session.Config) | ||
|
||
vpcs := []Resource{} | ||
|
||
res, err := client.DescribeVpcs(&ec2.DescribeVpcsInput{}) | ||
if err != nil { | ||
return &FetchResult{nil, err} | ||
} | ||
|
||
for _, vpc := range res.Vpcs { | ||
if *vpc.IsDefault { | ||
continue | ||
} | ||
vpcs = append(vpcs, Resource{ | ||
ID: *vpc.VpcId, | ||
// ARN | ||
Service: "ec2", | ||
Type: "vpc", | ||
AccountID: *vpc.OwnerId, | ||
Region: *session.Config.Region, | ||
}) | ||
} | ||
|
||
return &FetchResult{vpcs, err} | ||
} | ||
|
||
func EC2ListSecurityGroups(session *Session) *FetchResult { | ||
client := ec2.New(session.Session, session.Config) | ||
|
||
securityGroups := []Resource{} | ||
err := client.DescribeSecurityGroupsPages(&ec2.DescribeSecurityGroupsInput{}, | ||
func(page *ec2.DescribeSecurityGroupsOutput, lastPage bool) bool { | ||
for _, securityGroup := range page.SecurityGroups { | ||
resource := Resource{ | ||
ID: *securityGroup.GroupId, | ||
ARN: fmt.Sprintf("arn:aws:ec2:%s:%s:security-group/%s", | ||
*session.Config.Region, | ||
*securityGroup.OwnerId, | ||
*securityGroup.GroupId, | ||
), | ||
Service: "ec2", | ||
Type: "security-group", | ||
AccountID: *securityGroup.OwnerId, | ||
Region: *session.Config.Region, | ||
Metadata: map[string]string{ | ||
"GroupName": *securityGroup.GroupName, | ||
"Description": *securityGroup.Description, | ||
}, | ||
} | ||
if securityGroup.VpcId != nil { | ||
resource.Metadata["VpcId"] = *securityGroup.VpcId | ||
} | ||
securityGroups = append(securityGroups, resource) | ||
} | ||
|
||
return true | ||
}) | ||
|
||
return &FetchResult{securityGroups, err} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,124 @@ | ||
package main | ||
|
||
import ( | ||
"github.com/aws/aws-sdk-go/aws" | ||
"github.com/aws/aws-sdk-go/service/iam" | ||
) | ||
|
||
func IAMListUsersAndAccessKeys(session *Session) *FetchResult { | ||
client := iam.New(session.Session, session.Config) | ||
|
||
result := &FetchResult{} | ||
result.Error = client.ListUsersPages(&iam.ListUsersInput{}, | ||
func(page *iam.ListUsersOutput, lastPage bool) bool { | ||
for _, user := range page.Users { | ||
resource, err := NewResource(*user.Arn) | ||
if err != nil { | ||
result.Error = err | ||
return false | ||
} | ||
result.Resources = append(result.Resources, *resource) | ||
|
||
keysResult := IAMListAccessKeys(session, *user.UserName) | ||
if keysResult.Error != nil { | ||
result.Error = keysResult.Error | ||
return false | ||
} | ||
result.Resources = append(result.Resources, keysResult.Resources...) | ||
} | ||
|
||
return true | ||
}) | ||
|
||
return result | ||
} | ||
|
||
func IAMListGroups(session *Session) *FetchResult { | ||
client := iam.New(session.Session, session.Config) | ||
|
||
result := &FetchResult{} | ||
result.Error = client.ListGroupsPages(&iam.ListGroupsInput{}, | ||
func(page *iam.ListGroupsOutput, lastPage bool) bool { | ||
for _, group := range page.Groups { | ||
|
||
resource, err := NewResource(*group.Arn) | ||
if err != nil { | ||
result.Error = err | ||
return false | ||
} | ||
result.Resources = append(result.Resources, *resource) | ||
} | ||
|
||
return true | ||
}) | ||
|
||
return result | ||
} | ||
|
||
func IAMListRoles(session *Session) *FetchResult { | ||
client := iam.New(session.Session, session.Config) | ||
|
||
result := &FetchResult{} | ||
result.Error = client.ListRolesPages(&iam.ListRolesInput{}, | ||
func(page *iam.ListRolesOutput, lastPage bool) bool { | ||
for _, role := range page.Roles { | ||
resource, err := NewResource(*role.Arn) | ||
if err != nil { | ||
result.Error = err | ||
return false | ||
} | ||
result.Resources = append(result.Resources, *resource) | ||
} | ||
|
||
return true | ||
}) | ||
|
||
return result | ||
} | ||
|
||
func IAMListPolicies(session *Session) *FetchResult { | ||
client := iam.New(session.Session, session.Config) | ||
|
||
result := &FetchResult{} | ||
result.Error = client.ListPoliciesPages(&iam.ListPoliciesInput{Scope: aws.String("Local")}, | ||
func(page *iam.ListPoliciesOutput, lastPage bool) bool { | ||
for _, policy := range page.Policies { | ||
resource, err := NewResource(*policy.Arn) | ||
if err != nil { | ||
result.Error = err | ||
return false | ||
} | ||
result.Resources = append(result.Resources, *resource) | ||
} | ||
|
||
return true | ||
}) | ||
|
||
return result | ||
} | ||
|
||
func IAMListAccessKeys(session *Session, username string) *FetchResult { | ||
client := iam.New(session.Session, session.Config) | ||
|
||
result := &FetchResult{} | ||
result.Error = client.ListAccessKeysPages(&iam.ListAccessKeysInput{ | ||
UserName: aws.String(username), | ||
}, | ||
func(page *iam.ListAccessKeysOutput, lastPage bool) bool { | ||
for _, accessKey := range page.AccessKeyMetadata { | ||
result.Resources = append(result.Resources, Resource{ | ||
ID: *accessKey.AccessKeyId, | ||
AccountID: session.AccountID, | ||
Service: "iam", | ||
Type: "access-key", | ||
Metadata: map[string]string{ | ||
"UserName": *accessKey.UserName, | ||
}, | ||
}) | ||
} | ||
|
||
return true | ||
}) | ||
|
||
return result | ||
} |
Oops, something went wrong.