diff --git a/README.md b/README.md index 0a56341e..9964f8aa 100644 --- a/README.md +++ b/README.md @@ -81,7 +81,7 @@ CloudGraph AWS Provider will ask you what regions you would like to crawl and wi | cloudfront | elb, s3 | | cloudtrail | cloudwatch, cloudwatchLog, kms, s3, sns | | cloudwatch | cloudtrail, cloudwatchLog, sns | -| cloudwatchLog | cloudtrail, cloudwatch, kms | +| cloudwatchLog | cloudtrail, cloudwatch, ecsCluster, kms | | codebuild | iamRole, kms, vpc, securityGroup, subnet | | cognitoIdentityPool | | | cognitoUserPool | appSync, lambda | @@ -92,7 +92,7 @@ CloudGraph AWS Provider will ask you what regions you would like to crawl and wi | ebs | asg, ec2, emrInstance | | ec2 | alb, asg, ebs, eip, emrInstance, eksCluster, elasticBeanstalkEnv, iamInstanceProfile, iamRole, networkInterface, securityGroup, subnet, systemsManagerInstance, vpc, ecsContainer | | ecr | | -| ecsCluster | ecsService, ecsTask, ecsTaskSet | +| ecsCluster | cloudwatchLog, ecsService, ecsTask, ecsTaskSet, kms, s3 | | ecsContainer | ecsTask, ec2 | | ecsService | ecsCluster, ecsTaskDefinition, ecsTaskSet, elb, iamRole, securityGroup, subnet, vpc | | ecsTask | ecsContainer, ecsCluster, ecsTaskDefinition | @@ -128,7 +128,7 @@ CloudGraph AWS Provider will ask you what regions you would like to crawl and wi | iot | | | kinesisFirehose | kinesisStream, s3 | | kinesisStream | kinesisFirehose | -| kms | cloudtrail, cloudwatchLog, codebuild, dynamodb, efs, eksCluster, elastiCacheReplicationGroup, elasticSearchDomain, emrCluster, lambda, rdsClusterSnapshot, sns, sageMakerNotebookInstance, dmsReplicationInstance, redshiftCluster | +| kms | cloudtrail, cloudwatchLog, codebuild, ecsCluster, efs, eksCluster, elastiCacheReplicationGroup, elasticSearchDomain, emrCluster, lambda, rdsClusterSnapshot, sns, sageMakerNotebookInstance, dmsReplicationInstance, redshiftCluster | | lambda | appSync, cognitoUserPool, kms, securityGroup, subnet, vpc | | managedAirflow | iamRole, securityGroups, subnet, s3 | | nacl | vpc | @@ -145,7 +145,7 @@ CloudGraph AWS Provider will ask you what regions you would like to crawl and wi | sageMakerExperiment | | | sageMakerNotebookInstance | iamRole, kms, networkInterface, subnet, securityGroup | | sageMakerProject | | -| s3 | cloudfront, cloudtrail, kinesisFirehose, managedAirflow | +| s3 | cloudfront, cloudtrail, ecsCluster, kinesisFirehose, managedAirflow | | secretsManager | | | securityGroup | alb, asg, clientVpnEndpoint, codebuild, dmsReplicationInstance, ecsService, lambda, ec2, elasticSearchDomain, elb, rdsCluster, rdsDbInstance, eksCluster, elastiCacheCluster, managedAirflow, sageMakerNotebookInstance | | ses | | diff --git a/src/services/cloudwatchLogs/schema.graphql b/src/services/cloudwatchLogs/schema.graphql index b18c4c68..79110649 100644 --- a/src/services/cloudwatchLogs/schema.graphql +++ b/src/services/cloudwatchLogs/schema.graphql @@ -13,6 +13,7 @@ type awsCloudwatchLog @key(fields: "arn") { kms: [awsKms] @hasInverse(field: cloudwatchLog) cloudwatch: [awsCloudwatch] @hasInverse(field: cloudwatchLog) cloudtrail: [awsCloudtrail] @hasInverse(field: cloudwatchLog) + ecsCluster: [awsEcsCluster] @hasInverse(field: cloudwatchLog) } type awsMetricFilter diff --git a/src/services/cognitoUserPool/connections.ts b/src/services/cognitoUserPool/connections.ts index 1be0efbb..29a26b2c 100644 --- a/src/services/cognitoUserPool/connections.ts +++ b/src/services/cognitoUserPool/connections.ts @@ -103,7 +103,7 @@ export default ({ if (kmsKeyID && kms?.data?.[region]) { const kmsInRegion: AwsKms = kms.data[region].find( - ({ KeyId }: AwsKms) => kmsKeyID === KeyId + ({ KeyArn }: AwsKms) => kmsKeyID === KeyArn ) if (kmsInRegion) { diff --git a/src/services/ecsCluster/connections.ts b/src/services/ecsCluster/connections.ts new file mode 100644 index 00000000..4349e013 --- /dev/null +++ b/src/services/ecsCluster/connections.ts @@ -0,0 +1,97 @@ +import { ServiceConnection } from '@cloudgraph/sdk' + +import { isEmpty } from 'lodash' +import services from '../../enums/services' +import { RawAwsEcsCluster } from '../ecsCluster/data' +import { RawAwsS3 } from '../s3/data' +import { RawAwsLogGroup } from '../cloudwatchLogs/data' +import { AwsKms } from '../kms/data' +import { gets3BucketId } from '../../utils/ids' + +export default ({ + service: ecsCluster, + data, + region, +}: { + service: RawAwsEcsCluster + data: Array<{ name: string; data: { [property: string]: any[] } }> + region: string +}): { + [property: string]: ServiceConnection[] +} => { + const { + clusterArn: arn, + configuration: { + executeCommandConfiguration: { logConfiguration, kmsKeyId } = {}, + } = {}, + } = ecsCluster + const connections: ServiceConnection[] = [] + + /** + * Find S3 + * related to this ecs cluster + */ + const buckets = data.find(({ name }) => name === services.s3) + if (buckets?.data?.[region]) { + const dataAtRegion: RawAwsS3[] = buckets.data[region].filter( + ({ Name: name }: RawAwsS3) => name === logConfiguration?.s3BucketName + ) + for (const bucket of dataAtRegion) { + connections.push({ + id: gets3BucketId(bucket.Name), + resourceType: services.s3, + relation: 'child', + field: 's3', + }) + } + } + + /** + * Find Cloudwatch Log Group + * related to this ecs cluster + */ + const logGroups = data.find(({ name }) => name === services.cloudwatchLog) + let logGroupsInRegion: RawAwsLogGroup[] = [] + if (logGroups?.data?.[region]) { + logGroupsInRegion = logGroups.data[region].filter( + ({ logGroupName }: RawAwsLogGroup) => + logGroupName === logConfiguration?.cloudWatchLogGroupName + ) + } + + if (!isEmpty(logGroupsInRegion)) { + for (const logGroup of logGroupsInRegion) { + connections.push({ + id: logGroup.logGroupName, + resourceType: services.cloudwatchLog, + relation: 'child', + field: 'cloudwatchLog', + }) + } + } + + /** + * Find MKS + * related to this ecs cluster + */ + const kms = data.find(({ name }) => name === services.kms) + if (kms?.data?.[region]) { + const kmsInRegion: AwsKms = kms.data[region].find( + ({ KeyArn }: AwsKms) => KeyArn === kmsKeyId + ) + + if (kmsInRegion) { + connections.push({ + id: kmsInRegion.KeyId, + resourceType: services.kms, + relation: 'child', + field: 'kms', + }) + } + } + + const natResult = { + [arn]: connections, + } + return natResult +} diff --git a/src/services/ecsCluster/index.ts b/src/services/ecsCluster/index.ts index 8e25a7a2..dbdaa3f2 100644 --- a/src/services/ecsCluster/index.ts +++ b/src/services/ecsCluster/index.ts @@ -2,6 +2,7 @@ import {Service} from '@cloudgraph/sdk' import BaseService from '../base' import format from './format' import getData from './data' +import getConnections from './connections' import mutation from './mutation' export default class EcsCluster extends BaseService implements Service { @@ -9,5 +10,7 @@ export default class EcsCluster extends BaseService implements Service { getData = getData.bind(this) + getConnections = getConnections.bind(this) + mutation = mutation } \ No newline at end of file diff --git a/src/services/ecsCluster/schema.graphql b/src/services/ecsCluster/schema.graphql index 70a8d77e..1a3e1a61 100644 --- a/src/services/ecsCluster/schema.graphql +++ b/src/services/ecsCluster/schema.graphql @@ -16,10 +16,11 @@ type awsEcsCluster implements awsBaseService @key(fields: "arn") { ecsService: [awsEcsService] @hasInverse(field: ecsCluster) ecsTask: [awsEcsTask] @hasInverse(field: ecsCluster) ecsTaskSet: [awsEcsTaskSet] @hasInverse(field: ecsCluster) + s3: [awsS3] @hasInverse(field: ecsCluster) + cloudwatchLog: [awsCloudwatchLog] @hasInverse(field: ecsCluster) + kms: [awsKms] @hasInverse(field: ecsCluster) } -#TODO: add connections to cloudwatchLog, s3, - type AwsEcsExecuteCommandLogConfiguration @generate( query: { get: false, query: true, aggregate: false } diff --git a/src/services/kms/schema.graphql b/src/services/kms/schema.graphql index 53023cf2..56b22ac8 100644 --- a/src/services/kms/schema.graphql +++ b/src/services/kms/schema.graphql @@ -28,6 +28,7 @@ type awsKms implements awsBaseService @key(fields: "id") { sageMakerNotebookInstances: [awsSageMakerNotebookInstance] @hasInverse(field: kms) rdsClusterSnapshots: [awsRdsClusterSnapshot] @hasInverse(field: kms) + ecsCluster: [awsEcsCluster] @hasInverse(field: kms) dynamodb: [awsDynamoDbTable] @hasInverse(field: kms) cognitoUserPools: [awsCognitoUserPool] @hasInverse(field: kms) } diff --git a/src/services/s3/schema.graphql b/src/services/s3/schema.graphql index 535d64a4..edc266f0 100644 --- a/src/services/s3/schema.graphql +++ b/src/services/s3/schema.graphql @@ -23,6 +23,7 @@ type awsS3 implements awsBaseService @key(fields: "arn") { cloudfrontDistribution: [awsCloudfront] @hasInverse(field: s3) #change to plural cloudtrail: [awsCloudtrail] @hasInverse(field: s3) #change to plural managedAirflows: [awsManagedAirflow] @hasInverse(field: s3) + ecsCluster: [awsEcsCluster] @hasInverse(field: s3) } # TODO: use getBucketReplication and getBucketNotificationConfiguration to make connections to lambda, sns, iamRole, SQS diff --git a/src/types/generated.ts b/src/types/generated.ts index d8443681..7c712625 100644 --- a/src/types/generated.ts +++ b/src/types/generated.ts @@ -914,6 +914,7 @@ export type AwsCloudwatchLog = { cloudtrail?: Maybe>>; cloudwatch?: Maybe>>; creationTime?: Maybe; + ecsCluster?: Maybe>>; id: Scalars['String']; kms?: Maybe>>; kmsKeyId?: Maybe; @@ -1595,15 +1596,18 @@ export type AwsEcsCluster = AwsBaseService & { attachments?: Maybe>>; attachmentsStatus?: Maybe; capacityProviders?: Maybe>>; + cloudwatchLog?: Maybe>>; clusterName?: Maybe; configuration?: Maybe; defaultCapacityProviderStrategy?: Maybe>>; ecsService?: Maybe>>; ecsTask?: Maybe>>; ecsTaskSet?: Maybe>>; + kms?: Maybe>>; pendingTasksCount?: Maybe; registeredContainerInstancesCount?: Maybe; runningTasksCount?: Maybe; + s3?: Maybe>>; settings?: Maybe>>; statistics?: Maybe>>; status?: Maybe; @@ -3179,6 +3183,7 @@ export type AwsKms = AwsBaseService & { description?: Maybe; dmsReplicationInstances?: Maybe>>; dynamodb?: Maybe>>; + ecsCluster?: Maybe>>; efs?: Maybe>>; eksCluster?: Maybe>>; elastiCacheReplicationGroup?: Maybe>>; @@ -3676,6 +3681,7 @@ export type AwsS3 = AwsBaseService & { cloudtrail?: Maybe>>; corsConfiguration?: Maybe; crossRegionReplication?: Maybe; + ecsCluster?: Maybe>>; encrypted?: Maybe; ignorePublicAcls?: Maybe; kinesisFirehose?: Maybe>>;