mirror of
https://github.com/BishopFox/cloudfox.git
synced 2026-11-07 09:56:01 -10:00
initial draft of the orgs command
This commit is contained in:
5 files changed
+232
-5
No files matched your search
+179
@@ -0,0 +1,179 @@
|
||||
package aws
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
|
||||
"github.com/BishopFox/cloudfox/internal"
|
||||
"github.com/aws/aws-sdk-go-v2/aws"
|
||||
"github.com/aws/aws-sdk-go-v2/service/organizations"
|
||||
"github.com/aws/aws-sdk-go-v2/service/organizations/types"
|
||||
"github.com/aws/aws-sdk-go-v2/service/sts"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
type OrgModule struct {
|
||||
OrganizationsClient *organizations.Client
|
||||
Caller sts.GetCallerIdentityOutput
|
||||
AWSRegions []string
|
||||
OutputFormat string
|
||||
Goroutines int
|
||||
AWSProfile string
|
||||
SkipAdminCheck bool
|
||||
WrapTable bool
|
||||
|
||||
// Main module data
|
||||
Accounts []Account
|
||||
CommandCounter internal.CommandCounter
|
||||
// Used to store output data for pretty printing
|
||||
output internal.OutputData2
|
||||
modLog *logrus.Entry
|
||||
}
|
||||
|
||||
type OrganizationsClientInterface interface {
|
||||
ListAccounts(ctx context.Context, params *organizations.ListAccountsInput, optFns ...func(*organizations.Options)) (*organizations.ListAccountsOutput, error)
|
||||
}
|
||||
|
||||
type Account struct {
|
||||
isManagementAccount bool
|
||||
Name string
|
||||
Id string
|
||||
Email string
|
||||
Arn string
|
||||
Status string
|
||||
}
|
||||
|
||||
func (m *OrgModule) PrintOrgAccounts(outputFormat string, outputDirectory string, verbosity int) {
|
||||
// These stuct values are used by the output module
|
||||
m.output.Verbosity = verbosity
|
||||
m.output.Directory = outputDirectory
|
||||
m.output.CallingModule = "org"
|
||||
|
||||
m.modLog = internal.TxtLog.WithFields(logrus.Fields{
|
||||
"module": m.output.CallingModule,
|
||||
})
|
||||
if m.AWSProfile == "" {
|
||||
m.AWSProfile = internal.BuildAWSPath(m.Caller)
|
||||
}
|
||||
|
||||
fmt.Printf("[%s][%s] Checking if account %s is the management account in an organization %s.\n", cyan(m.output.CallingModule), cyan(m.AWSProfile), aws.ToString(m.Caller.Account))
|
||||
|
||||
// wg := new(sync.WaitGroup)
|
||||
// semaphore := make(chan struct{}, m.Goroutines)
|
||||
|
||||
// // Create a channel to signal the spinner aka task status goroutine to finish
|
||||
// spinnerDone := make(chan bool)
|
||||
// //fire up the the task status spinner/updated
|
||||
// go internal.SpinUntil(m.output.CallingModule, &m.CommandCounter, spinnerDone, "tasks")
|
||||
|
||||
// //create a channel to receive the objects
|
||||
// dataReceiver := make(chan Project)
|
||||
|
||||
// // Create a channel to signal to stop
|
||||
// receiverDone := make(chan bool)
|
||||
|
||||
// go m.Receiver(dataReceiver, receiverDone)
|
||||
|
||||
// // for _, region := range m.AWSRegions {
|
||||
// // wg.Add(1)
|
||||
// // m.CommandCounter.Pending++
|
||||
// // go m.executeChecks(region, wg, semaphore, dataReceiver)
|
||||
|
||||
// // }
|
||||
|
||||
// wg.Wait()
|
||||
|
||||
// // Send a message to the spinner goroutine to close the channel and stop
|
||||
// spinnerDone <- true
|
||||
// <-spinnerDone
|
||||
// receiverDone <- true
|
||||
// <-receiverDone
|
||||
|
||||
m.addOrgAccounts()
|
||||
|
||||
m.output.Headers = []string{
|
||||
"Name",
|
||||
"ID",
|
||||
"isManagementAccount?",
|
||||
"Status",
|
||||
"Email",
|
||||
}
|
||||
|
||||
// Table rows
|
||||
|
||||
for i := range m.Accounts {
|
||||
m.output.Body = append(
|
||||
m.output.Body,
|
||||
[]string{
|
||||
m.Accounts[i].Name,
|
||||
m.Accounts[i].Id,
|
||||
strconv.FormatBool(m.Accounts[i].isManagementAccount),
|
||||
m.Accounts[i].Status,
|
||||
m.Accounts[i].Email,
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
if len(m.output.Body) > 0 {
|
||||
m.output.FilePath = filepath.Join(outputDirectory, "cloudfox-output", "aws", m.AWSProfile)
|
||||
internal.OutputSelector(verbosity, outputFormat, m.output.Headers, m.output.Body, m.output.FilePath, m.output.CallingModule, m.output.CallingModule, m.WrapTable, m.AWSProfile)
|
||||
//m.writeLoot(m.output.FilePath, verbosity)
|
||||
fmt.Printf("[%s][%s] %d accounts found.\n", cyan(m.output.CallingModule), cyan(m.AWSProfile), len(m.output.Body))
|
||||
fmt.Printf("[%s][%s] For context and next steps: https://github.com/BishopFox/cloudfox/wiki/AWS-Commands#%s\n", cyan(m.output.CallingModule), cyan(m.AWSProfile), m.output.CallingModule)
|
||||
|
||||
} else {
|
||||
fmt.Printf("[%s][%s] No accounts found, skipping the creation of an output file.\n", cyan(m.output.CallingModule), cyan(m.AWSProfile))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func (m *OrgModule) addOrgAccounts() {
|
||||
accounts, err := m.listAccounts()
|
||||
if err != nil {
|
||||
m.modLog.Errorf("Failed to list accounts: %s", err)
|
||||
return
|
||||
}
|
||||
for _, account := range accounts {
|
||||
m.Accounts = append(m.Accounts, Account{
|
||||
isManagementAccount: false,
|
||||
Name: aws.ToString(account.Name),
|
||||
Id: aws.ToString(account.Id),
|
||||
Email: aws.ToString(account.Email),
|
||||
Arn: aws.ToString(account.Arn),
|
||||
Status: string(account.Status),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func (m *OrgModule) listAccounts() ([]types.Account, error) {
|
||||
// "PaginationMarker" is a control variable used for output continuity, as AWS return the output in pages.
|
||||
var PaginationControl *string
|
||||
var accounts []types.Account
|
||||
|
||||
for {
|
||||
ListAccounts, err := m.OrganizationsClient.ListAccounts(
|
||||
context.TODO(),
|
||||
&organizations.ListAccountsInput{
|
||||
NextToken: PaginationControl,
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
m.modLog.Error(err.Error())
|
||||
m.CommandCounter.Error++
|
||||
break
|
||||
}
|
||||
|
||||
accounts = append(accounts, ListAccounts.Accounts...)
|
||||
|
||||
if ListAccounts.NextToken != nil {
|
||||
PaginationControl = ListAccounts.NextToken
|
||||
} else {
|
||||
PaginationControl = nil
|
||||
break
|
||||
}
|
||||
|
||||
}
|
||||
return accounts, nil
|
||||
}
|
||||
+29
@@ -31,6 +31,7 @@ import (
|
||||
"github.com/aws/aws-sdk-go-v2/service/lightsail"
|
||||
"github.com/aws/aws-sdk-go-v2/service/mq"
|
||||
"github.com/aws/aws-sdk-go-v2/service/opensearch"
|
||||
"github.com/aws/aws-sdk-go-v2/service/organizations"
|
||||
"github.com/aws/aws-sdk-go-v2/service/ram"
|
||||
"github.com/aws/aws-sdk-go-v2/service/rds"
|
||||
"github.com/aws/aws-sdk-go-v2/service/redshift"
|
||||
@@ -272,6 +273,16 @@ var (
|
||||
Run: runOutboundAssumedRolesCommand,
|
||||
}
|
||||
|
||||
OrgsCommand = &cobra.Command{
|
||||
Use: "orgs",
|
||||
Aliases: []string{"org", "organizations", "accounts", "account"},
|
||||
Short: "Enumerate accounts in an organization",
|
||||
Long: "\nUse case examples:\n" +
|
||||
os.Args[0] + " aws orgs --profile readonly_profile",
|
||||
PreRun: awsPreRun,
|
||||
Run: runOrgsCommand,
|
||||
}
|
||||
|
||||
PermissionsPrincipal string
|
||||
PermissionsCommand = &cobra.Command{
|
||||
Use: "permissions",
|
||||
@@ -457,6 +468,7 @@ func init() {
|
||||
NetworkPortsCommand,
|
||||
PmapperCommand,
|
||||
ResourceTrustsCommand,
|
||||
OrgsCommand,
|
||||
)
|
||||
|
||||
}
|
||||
@@ -864,6 +876,23 @@ func runOutboundAssumedRolesCommand(cmd *cobra.Command, args []string) {
|
||||
}
|
||||
}
|
||||
|
||||
func runOrgsCommand(cmd *cobra.Command, args []string) {
|
||||
for _, profile := range AWSProfiles {
|
||||
var AWSConfig = internal.AWSConfigFileLoader(profile, cmd.Root().Version)
|
||||
caller, err := internal.AWSWhoami(profile, cmd.Root().Version)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
m := aws.OrgModule{
|
||||
OrganizationsClient: organizations.NewFromConfig(AWSConfig),
|
||||
Caller: *caller,
|
||||
AWSProfile: profile,
|
||||
WrapTable: AWSWrapTable,
|
||||
}
|
||||
m.PrintOrgAccounts(AWSOutputFormat, AWSOutputDirectory, Verbosity)
|
||||
}
|
||||
}
|
||||
|
||||
func runPermissionsCommand(cmd *cobra.Command, args []string) {
|
||||
for _, profile := range AWSProfiles {
|
||||
var AWSConfig = internal.AWSConfigFileLoader(profile, cmd.Root().Version)
|
||||
|
||||
@@ -10,7 +10,7 @@ require (
|
||||
github.com/Azure/go-autorest/autorest v0.11.28
|
||||
github.com/Azure/go-autorest/autorest/azure/auth v0.5.11
|
||||
github.com/aquasecurity/table v1.8.0
|
||||
github.com/aws/aws-sdk-go-v2 v1.17.5
|
||||
github.com/aws/aws-sdk-go-v2 v1.17.7
|
||||
github.com/aws/aws-sdk-go-v2/config v1.18.3
|
||||
github.com/aws/aws-sdk-go-v2/service/apigateway v1.15.25
|
||||
github.com/aws/aws-sdk-go-v2/service/apigatewayv2 v1.12.23
|
||||
@@ -75,8 +75,8 @@ require (
|
||||
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.9 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.13.3 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.19 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.29 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.23 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.31 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.25 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/ini v1.3.26 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/v4a v1.0.16 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/codebuild v1.20.5 // indirect
|
||||
@@ -85,6 +85,7 @@ require (
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/endpoint-discovery v1.7.19 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.19 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.13.19 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/organizations v1.19.2 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.11.25 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.13.8 // indirect
|
||||
github.com/dimchansky/utfbom v1.1.1 // indirect
|
||||
|
||||
@@ -88,6 +88,8 @@ github.com/aws/aws-sdk-go-v2 v1.17.3 h1:shN7NlnVzvDUgPQ+1rLMSxY8OWRNDRYtiqe0p/Pg
|
||||
github.com/aws/aws-sdk-go-v2 v1.17.3/go.mod h1:uzbQtefpm44goOPmdKyAlXSNcwlRgF3ePWVW6EtJvvw=
|
||||
github.com/aws/aws-sdk-go-v2 v1.17.5 h1:TzCUW1Nq4H8Xscph5M/skINUitxM5UBAyvm2s7XBzL4=
|
||||
github.com/aws/aws-sdk-go-v2 v1.17.5/go.mod h1:uzbQtefpm44goOPmdKyAlXSNcwlRgF3ePWVW6EtJvvw=
|
||||
github.com/aws/aws-sdk-go-v2 v1.17.7 h1:CLSjnhJSTSogvqUGhIC6LqFKATMRexcxLZ0i/Nzk9Eg=
|
||||
github.com/aws/aws-sdk-go-v2 v1.17.7/go.mod h1:uzbQtefpm44goOPmdKyAlXSNcwlRgF3ePWVW6EtJvvw=
|
||||
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.9 h1:RKci2D7tMwpvGpDNZnGQw9wk6v7o/xSwFcUAuNPoB8k=
|
||||
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.9/go.mod h1:vCmV1q1VK8eoQJ5+aYE7PkK1K6v41qJ5pJdK3ggCDvg=
|
||||
github.com/aws/aws-sdk-go-v2/config v1.18.3 h1:3kfBKcX3votFX84dm00U8RGA1sCCh3eRMOGzg5dCWfU=
|
||||
@@ -101,11 +103,15 @@ github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.27 h1:I3cakv2Uy1vNmmhRQ
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.27/go.mod h1:a1/UpzeyBBerajpnP5nGZa9mGzsBn5cOKxm6NWQsvoI=
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.29 h1:9/aKwwus0TQxppPXFmf010DFrE+ssSbzroLVYINA+xE=
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.29/go.mod h1:Dip3sIGv485+xerzVv24emnjX5Sg88utCL8fwGmCeWg=
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.31 h1:sJLYcS+eZn5EeNINGHSCRAwUJMFVqklwkH36Vbyai7M=
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.31/go.mod h1:QT0BqUvX1Bh2ABdTGnjqEjvjzrCfIniM9Sc8zn9Yndo=
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.19/go.mod h1:6Q0546uHDp421okhmmGfbxzq2hBqbXFNpi4k+Q1JnQA=
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.21 h1:5NbbMrIzmUn/TXFqAle6mgrH5m9cOvMLRGL7pnG8tRE=
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.21/go.mod h1:+Gxn8jYn5k9ebfHEqlhrMirFjSW0v0C9fI+KN5vk2kE=
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.23 h1:b/Vn141DBuLVgXbhRWIrl9g+ww7G+ScV5SzniWR13jQ=
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.23/go.mod h1:mr6c4cHC+S/MMkrjtSlG4QA36kOznDep+0fga5L/fGQ=
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.25 h1:1mnRASEKnkqsntcxHaysxwgVoUUp5dkiB+l3llKnqyg=
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.25/go.mod h1:zBHOPwhBc3FlQjQJE/D3IfPWiWaQmT06Vq9aNukDo0k=
|
||||
github.com/aws/aws-sdk-go-v2/internal/ini v1.3.26 h1:Mza+vlnZr+fPKFKRq/lKGVvM6B/8ZZmNdEopOwSQLms=
|
||||
github.com/aws/aws-sdk-go-v2/internal/ini v1.3.26/go.mod h1:Y2OJ+P+MC1u1VKnavT+PshiEuGPyh/7DqxoDNij4/bg=
|
||||
github.com/aws/aws-sdk-go-v2/internal/v4a v1.0.16 h1:2EXB7dtGwRYIN3XQ9qwIW504DVbKIw3r89xQnonGdsQ=
|
||||
@@ -168,6 +174,8 @@ github.com/aws/aws-sdk-go-v2/service/mq v1.13.15 h1:K0UbxNfaPHoIXo0T4L4jrbE+TKcV
|
||||
github.com/aws/aws-sdk-go-v2/service/mq v1.13.15/go.mod h1:ycghPMXYItx5Y74iehFgGwDNUMXdq0xCxLaYC5uYZO0=
|
||||
github.com/aws/aws-sdk-go-v2/service/opensearch v1.11.3 h1:ViGcWux+UbkS/JBLxPILq/Mevlf9RXSycGlPaVQON5Y=
|
||||
github.com/aws/aws-sdk-go-v2/service/opensearch v1.11.3/go.mod h1:7mh4ks7MsQUuhHFCr10LIF9gKVS+0yylPUmCEM/kzJE=
|
||||
github.com/aws/aws-sdk-go-v2/service/organizations v1.19.2 h1:8tikveMqrEqTIyMcevyeFNASIkffCuwuV+DAkMiXm8g=
|
||||
github.com/aws/aws-sdk-go-v2/service/organizations v1.19.2/go.mod h1:MTKfY5PMwGkG9+tK451UCUpDm5jo1uyJwUkkvn7G1p4=
|
||||
github.com/aws/aws-sdk-go-v2/service/ram v1.16.24 h1:pzB33ZEhd1szVKHkgYe4cXQ+kSLJEFGBLy+IpbAKY9Y=
|
||||
github.com/aws/aws-sdk-go-v2/service/ram v1.16.24/go.mod h1:el3+/AiwdwKk5qZEcCQqm+t3b1A5QLZI2nr/OkhM/gc=
|
||||
github.com/aws/aws-sdk-go-v2/service/rds v1.31.0 h1:lx8pflhN7oogISvAorwqPGFHN7eiVlGEwk21ThYcyoA=
|
||||
|
||||
@@ -11,6 +11,9 @@
|
||||
"cloudformation:ListStacks",
|
||||
"cloudtrail:LookupEvents",
|
||||
"cloudfront:ListDistributions",
|
||||
"codebuild:ListProjects",
|
||||
"codebuild:BatchGetProjects",
|
||||
"codebuild:GetResourcePolicy",
|
||||
"dynamodb:ListTables",
|
||||
"ec2:DescribeInstanceAttribute",
|
||||
"ec2:DescribeInstances",
|
||||
@@ -21,7 +24,7 @@
|
||||
"ecs:DescribeTaskDefinition",
|
||||
"ecs:ListClusters",
|
||||
"ecs:ListTaskDefinitions",
|
||||
"ecs:ListTasks",
|
||||
"ecs:ListTasks",
|
||||
"eks:DescribeCluster",
|
||||
"eks:DescribeNodegroup",
|
||||
"eks:ListClusters",
|
||||
@@ -47,11 +50,13 @@
|
||||
"iam:ListRoles",
|
||||
"iam:SimulatePrincipalPolicy",
|
||||
"lambda:GetFunctionUrlConfig",
|
||||
"lambda:ListFunctions",
|
||||
"lambda:ListFunctions",
|
||||
"lambda:GetPolicy",
|
||||
"lightsail:GetContainerServices",
|
||||
"lightsail:GetInstances",
|
||||
"mq:DescribeBroker",
|
||||
"mq:ListBrokers",
|
||||
"organizations:ListAccounts",
|
||||
"es:DescribeDomain",
|
||||
"es:ListDomainNames",
|
||||
"ram:GetResourceShares",
|
||||
@@ -63,6 +68,9 @@
|
||||
"s3:GetBucketPolicyStatus",
|
||||
"s3:GetBucketWebsite",
|
||||
"s3:ListAllMyBuckets",
|
||||
"s3:GetAccountPublicAccessBlock",
|
||||
"s3:GetBucketLocation",
|
||||
"s3:GetBucketPolicy",
|
||||
"ssm:DescribeParameters",
|
||||
"sagemaker:ListProcessingJobs",
|
||||
"sagemaker:DescribeProcessingJob",
|
||||
@@ -74,7 +82,9 @@
|
||||
"sagemaker:DescribeModel",
|
||||
"secretsmanager:ListSecrets",
|
||||
"sns:ListTopics",
|
||||
"sns:GetTopicAttributes",
|
||||
"sqs:ListQueues",
|
||||
"sqs:GetQueueAttributes",
|
||||
"tag:GetResources"
|
||||
|
||||
],
|
||||
|
||||
Reference in new issue
Block a user