Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,9 @@ CloudGraph AWS Provider will ask you what regions you would like to crawl and wi
| ses | |
| sns | kms, cloudtrail, cloudwatch, s3 |
| sqs | elasticBeanstalkEnv, s3 |
| ssmActivation | |
| ssmAssociation | |
| ssmDocument | |
Comment thread
m-pizarro marked this conversation as resolved.
Outdated
| subnet | alb, asg, codebuild, dmsReplicationInstance, ec2, ecsService, efsMountTarget, elastiCacheCluster, elasticSearchDomain, elb, lambda, managedAirflow, natGateway, networkInterface, rdsCluster, sageMakerNotebookInstance, routeTable, vpc, vpcEndpoint, eksCluster, emrCluster, flowLog, mskCluster |
| systemsManagerInstance | ec2, iamRole |
| systemsManagerDocument | |
Expand Down
3 changes: 3 additions & 0 deletions src/enums/resources.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@ export default {
ec2Instance: 'aws_instance',
iamPolicies: 'aws_iam_polocies', // Not a real TF resource, used to organize all the policies
route53Zone: 'aws_route53_zone',
ssmActivation: 'aws_ssm_activation',
ssmAssociation: 'aws_ssm_association',
ssmDocument: 'aws_ssm_document',
organization: 'aws_organizations_organization',
vpnConnection: 'aws_vpn_connection',
ecrRepository: 'aws_ecr_repository',
Expand Down
3 changes: 3 additions & 0 deletions src/enums/schemasMap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -110,5 +110,8 @@ export default {
[services.vpnConnection]: 'awsVpnConnection',
[services.organization]: 'awsOrganization',
[services.wafV2WebAcl]: 'awsWafV2WebAcl',
[services.ssmActivation]: 'awsSsmActivation',
[services.ssmAssociation]: 'awsSsmAssociation',
[services.ssmDocument]: 'awsSsmDocument',
tag: 'awsTag',
}
3 changes: 3 additions & 0 deletions src/enums/serviceAliases.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,4 +80,7 @@ export default {
[services.vpcEndpoint]: 'vpcEndpoints',
[services.vpnConnection]: 'vpnConnections',
[services.vpcPeeringConnection]: 'vpcPeeringConnections',
[services.ssmActivation]: 'ssmActivations',
[services.ssmAssociation]: 'ssmAssociations',
[services.ssmDocument]: 'ssmDocuments',
}
6 changes: 6 additions & 0 deletions src/enums/serviceMap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,9 @@ import ManagedPrefixList from '../services/managedPrefixList'
import MskCluster from '../services/msk'
import TransitGatewayRouteTable from '../services/transitGatewayRouteTable'
import VpcPeeringConnection from '../services/vpcPeeringConnection'
import SsmActivation from '../services/ssmActivation'
import SsmAssociation from '../services/ssmAssociation'
import SsmDocument from '../services/ssmDocument'

/**
* serviceMap is an object that contains all currently supported services for AWS
Expand Down Expand Up @@ -218,5 +221,8 @@ export default {
[services.wafV2WebAcl]: WafV2WebAcl,
[services.systemsManagerInstance]: SystemsManagerInstance,
[services.systemsManagerDocument]: SystemsManagerDocument,
[services.ssmActivation]: SsmActivation,
[services.ssmAssociation]: SsmAssociation,
[services.ssmDocument]: SsmDocument,
tag: AwsTag,
}
3 changes: 3 additions & 0 deletions src/enums/services.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,9 @@ export default {
sg: 'sg',
sns: 'sns',
sqs: 'sqs',
ssmActivation: 'ssmActivation',
ssmAssociation: 'ssmAssociation',
ssmDocument: 'ssmDocument',
subnet: 'subnet',
systemsManagerInstance: 'systemsManagerInstance',
systemsManagerDocument: 'systemsManagerDocument',
Expand Down
9 changes: 9 additions & 0 deletions src/properties/logger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -712,4 +712,13 @@ export default {
*/
fetchedMskClusters: (num: number): string =>
`Fetched ${num} Msk clusters`,
/**
* SSM
*/
fetchedSsmActivations: (num: number): string =>
`Fetched ${num} SSM Activations`,
fetchedSsmAssociations: (num: number): string =>
`Fetched ${num} SSM Associations`,
fetchedSsmDocuments: (num: number): string =>
`Fetched ${num} SSM Documents`,
}
130 changes: 130 additions & 0 deletions src/services/ssmActivation/data.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
import CloudGraph from '@cloudgraph/sdk'
import SSM, { Activation, DescribeActivationsRequest, DescribeActivationsResult } from 'aws-sdk/clients/ssm'
import { AWSError } from 'aws-sdk/lib/error'
import { Config } from 'aws-sdk/lib/config'
import isEmpty from 'lodash/isEmpty'
import groupBy from 'lodash/groupBy'
import awsLoggerText from '../../properties/logger'
import { initTestEndpoint, setAwsRetryOptions } from '../../utils'
import AwsErrorLog from '../../utils/errorLog'
import { API_GATEWAY_CUSTOM_DELAY } from '../../config/constants'
import { AwsTag, TagMap } from '../../types'
import { convertAwsTagsToTagMap } from '../../utils/format'

const lt = { ...awsLoggerText }
const { logger } = CloudGraph
const MAX_ACTIVATIONS = 50
const serviceName = 'ssmActivations'
const errorLog = new AwsErrorLog(serviceName)
const endpoint = initTestEndpoint(serviceName)
const customRetrySettings = setAwsRetryOptions({
baseDelay: API_GATEWAY_CUSTOM_DELAY,
})

/**
* SSM Activation
*/

export const getActivationsForRegion = async (
ssm: SSM
): Promise<Activation[]> =>
new Promise(async resolve => {
const activationList: Activation[] = []

const describeActivationsOpts: DescribeActivationsRequest = {}
const listAllActivations = (token?: string): void => {
describeActivationsOpts.MaxResults = MAX_ACTIVATIONS
if (token) {
describeActivationsOpts.NextToken = token
}
try {
ssm.describeActivations(
describeActivationsOpts,
(err: AWSError, data: DescribeActivationsResult) => {
if (err) {
errorLog.generateAwsErrorLog({
functionName: 'ssm:describeActivations',
err,
})
}

if (isEmpty(data)) {
return resolve([])
}

const { NextToken: nextToken, ActivationList: items = [] } = data || {}

if (isEmpty(items)) {
return resolve([])
}

logger.debug(lt.fetchedSsmActivations(items.length))

activationList.push(...items)

if (nextToken) {
listAllActivations(nextToken)
} else {
resolve(activationList)
}
}
)
} catch (error) {
resolve([])
}
}
listAllActivations()
})

export interface RawAwsSsmActivation extends Omit<Activation, 'Tags'> {
Tags: TagMap
region: string
account
}

export default async ({
regions,
config,
account,
}: {
account: string
regions: string
config: Config
}): Promise<{
[region: string]: RawAwsSsmActivation[]
}> =>
new Promise(async resolve => {
const activationResult: RawAwsSsmActivation[] = []

const regionPromises = regions.split(',').map(region => {
const ssm = new SSM({
...config,
region,
endpoint,
...customRetrySettings,
})

return new Promise<void>(async resolveSsmActivationData => {
// Get SSM Activations
const activations = await getActivationsForRegion(ssm)

if (!isEmpty(activations)) {
activationResult.push(
...activations.map(({Tags, ...activation}) => ({
...activation,
region,
account,
Tags: convertAwsTagsToTagMap(Tags as AwsTag[]),
}))
)
}

resolveSsmActivationData()
})
})

await Promise.all(regionPromises)
errorLog.reset()

resolve(groupBy(activationResult, 'region'))
})
45 changes: 45 additions & 0 deletions src/services/ssmActivation/format.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { RawAwsSsmActivation } from './data'
import { AwsSsmActivation } from '../../types/generated'
import { formatTagsFromMap } from '../../utils/format'
import { ssmActivationArn } from '../../utils/generateArns'

export default ({
service,
account,
region,
}: {
service: RawAwsSsmActivation
account: string
region: string
}): AwsSsmActivation => {
const {
ActivationId: activationId,
Description: description,
DefaultInstanceName: defaultInstanceName,
IamRole: iamRole,
RegistrationLimit: registrationLimit,
RegistrationsCount: registrationsCount,
ExpirationDate: expirationDate,
Expired: expired,
CreatedDate: createdDate,
Tags: tags,
} = service

const arn = ssmActivationArn({ region, account, id: activationId })

return {
id: activationId,
accountId: account,
arn,
region,
description,
defaultInstanceName,
iamRole,
registrationLimit,
registrationsCount,
expirationDate: expirationDate?.toISOString(),
expired,
createdDate: createdDate?.toISOString(),
tags: formatTagsFromMap(tags),
}
}
13 changes: 13 additions & 0 deletions src/services/ssmActivation/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { Service } from '@cloudgraph/sdk'
import BaseService from '../base'
import format from './format'
import getData from './data'
import mutation from './mutation'

export default class Acm extends BaseService implements Service {
format = format.bind(this)

getData = getData.bind(this)

mutation = mutation
}
5 changes: 5 additions & 0 deletions src/services/ssmActivation/mutation.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export default `mutation($input: [AddawsSsmActivationInput!]!) {
addawsSsmActivation(input: $input, upsert: true) {
numUids
}
}`
12 changes: 12 additions & 0 deletions src/services/ssmActivation/schema.graphql
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
type awsSsmActivation implements awsBaseService @key(fields: "arn") {
activationId: String @search(by: [hash, regexp])
description: String @search(by: [hash, regexp])
defaultInstanceName: String @search(by: [hash, regexp])
iamRole: String @search(by: [hash, regexp])
registrationLimit: Int @search
registrationsCount: Int @search
expirationDate: DateTime @search(by: [day])
expired: Boolean@search
createdDate: DateTime @search(by: [day])
tags: [awsRawTag]
}
Loading