Skip to content

feat(CG-1343): add ssm service support #135

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 4 commits into
base: alpha
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
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
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,9 @@ CloudGraph AWS Provider will ask you what regions you would like to crawl and wi
| sns | kms, cloudtrail, cloudwatch, s3 |
| sqs | elasticBeanstalkEnv, s3 |
| 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 |
| systemsManagerActivation | |
| systemsManagerAssociation | systemsManagerInstance |
| systemsManagerInstance | ec2, iamRole, systemManagerAssociation
| systemsManagerDocument | |
| systemsManagerParameter | |
| transitGateway | transitGatewayAttachment, transitGatewayRouteTable, vpnConnection |
Expand Down
3 changes: 3 additions & 0 deletions src/enums/resources.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,9 @@ export default {
networkInterface: 'aws_network_interface',
ecsTaskDefinition: 'aws_ecs_task_definition',
apiGatewayRestApi: 'aws_api_gateway_rest_api',
systemsManagerActivation: 'aws_ssm_activation',
systemsManagerAssociation: 'aws_ssm_association',
systemsManagerDocument: 'aws_ssm_document',
clientVpnEndpoint: 'aws_ec2_client_vpn_endpoint',
apiGatewayResource: 'aws_api_gateway_resource',
elastiCacheCluster: 'aws_elasticache_cluster',
Expand Down
4 changes: 3 additions & 1 deletion src/enums/schemasMap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -111,8 +111,10 @@ export default {
[services.sesEmail]: 'awsSesEmail',
[services.sesDomain]: 'awsSesDomain',
[services.sns]: 'awsSns',
[services.systemsManagerInstance]: 'awsSystemsManagerInstance',
[services.systemsManagerActivation]: 'awsSystemsManagerActivation',
[services.systemsManagerAssociation]: 'awsSystemsManagerAssociation',
[services.systemsManagerDocument]: 'awsSystemsManagerDocument',
[services.systemsManagerInstance]: 'awsSystemsManagerInstance',
[services.systemsManagerParameter]: 'awsSystemsManagerParameter',
[services.transitGateway]: 'awsTransitGateway',
[services.transitGatewayAttachment]: 'awsTransitGatewayAttachment',
Expand Down
2 changes: 2 additions & 0 deletions src/enums/serviceAliases.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,8 @@ export default {
[services.securityHubStandardSubscription]:
'securityHubStandardSubscriptions',
[services.subnet]: 'subnets',
[services.systemsManagerActivation]: 'systemsManagerActivations',
[services.systemsManagerAssociation]: 'systemsManagerAssociations',
[services.systemsManagerDocument]: 'systemsManagerDocuments',
[services.systemsManagerInstance]: 'systemsManagerInstances',
[services.systemsManagerParameter]: 'systemsManagerParameters',
Expand Down
22 changes: 13 additions & 9 deletions src/enums/serviceMap.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
import Account from '../services/account'
import ACM from '../services/acm'
import ALB from '../services/alb'
import APIGatewayApiKey from '../services/apiGatewayApiKey'
import APIGatewayDomainName from '../services/apiGateway2DomainName'
import APIGatewayV2HttpApi from '../services/apiGateway2HttpApi'
import APIGatewayV2VpcLink from '../services/apiGateway2VpcLink'
import APIGatewayApiKey from '../services/apiGatewayApiKey'
import APIGatewayResource from '../services/apiGatewayResource'
import APIGatewayRestApi from '../services/apiGatewayRestApi'
import APIGatewayStage from '../services/apiGatewayStage'
import APIGatewayUsagePlan from '../services/apiGatewayUsagePlan'
import APIGatewayVpcLink from '../services/apiGatewayVpcLink'
import APIGatewayV2VpcLink from '../services/apiGateway2VpcLink'
import AppSync from '../services/appSync'
import ASG from '../services/asg'
import AthenaDataCatalog from '../services/athenaDataCatalog'
Expand All @@ -25,15 +25,18 @@ import CloudWatchDashboard from '../services/cloudwatchDashboards'
import CloudWatchEventRule from '../services/cloudwatchEventRules'
import CloudWatchLog from '../services/cloudwatchLogs'
import CodeBuild from '../services/codeBuild'
import CodeCommitRepository from '../services/codeCommitRepository'
import CodePipeline from '../services/codePipeline'
import CodePipelineWebhook from '../services/codePipelineWebhook'
import CognitoIdentityPool from '../services/cognitoIdentityPool'
import CognitoUserPool from '../services/cognitoUserPool'
import ConfigurationDeliveryChannel from '../services/configurationDeliveryChannel'
import ConfigurationRecorder from '../services/configurationRecorder'
import ConfigurationRule from '../services/configurationRule'
import CustomerGateway from '../services/customerGateway'
import DmsReplicationInstance from '../services/dmsReplicationInstance'
import DynamoDB from '../services/dynamodb'
import DocDBCluster from '../services/docdbCluster'
import DynamoDB from '../services/dynamodb'
import EBS from '../services/ebs'
import EBSSnapshot from '../services/ebsSnapshot'
import EC2 from '../services/ec2'
Expand Down Expand Up @@ -108,12 +111,14 @@ import SecurityHub from '../services/securityHub'
import SecurityHubMember from '../services/securityHubMember'
import SecurityHubStandardSubscription from '../services/securityHubStandardSubscription'
import SES from '../services/ses'
import SESReceiptRuleSet from '../services/sesReceiptRuleSet'
import SESEmail from '../services/sesEmail'
import SESDomain from '../services/sesDomain'
import SESEmail from '../services/sesEmail'
import SESReceiptRuleSet from '../services/sesReceiptRuleSet'
import SNS from '../services/sns'
import SQS from '../services/sqs'
import AwsSubnet from '../services/subnet'
import SystemsManagerActivation from '../services/systemsManagerActivation'
import SystemsManagerAssociation from '../services/systemsManagerAssociation'
import SystemsManagerDocument from '../services/systemsManagerDocument'
import SystemsManagerInstance from '../services/systemsManagerInstance'
import SystemsManagerParameter from '../services/systemsManagerParameter'
Expand All @@ -124,13 +129,10 @@ import TransitGatewayRouteTable from '../services/transitGatewayRouteTable'
import VPC from '../services/vpc'
import VpcEndpoint from '../services/vpcEndpoint'
import VpcPeeringConnection from '../services/vpcPeeringConnection'
import CodeCommitRepository from '../services/codeCommitRepository'
import VpnConnection from '../services/vpnConnection'
import VpnGateway from '../services/vpnGateway'
import WafV2WebAcl from '../services/wafV2WebAcl'
import services from './services'
import CodePipeline from '../services/codePipeline'
import CodePipelineWebhook from '../services/codePipelineWebhook'

/**
* serviceMap is an object that contains all currently supported services for AWS
Expand Down Expand Up @@ -265,8 +267,10 @@ export default {
[services.vpnConnection]: VpnConnection,
[services.organization]: Organization,
[services.wafV2WebAcl]: WafV2WebAcl,
[services.systemsManagerInstance]: SystemsManagerInstance,
[services.systemsManagerActivation]: SystemsManagerActivation,
[services.systemsManagerAssociation]: SystemsManagerAssociation,
[services.systemsManagerDocument]: SystemsManagerDocument,
[services.systemsManagerInstance]: SystemsManagerInstance,
[services.systemsManagerParameter]: SystemsManagerParameter,
tag: AwsTag,
}
4 changes: 3 additions & 1 deletion src/enums/services.ts
Original file line number Diff line number Diff line change
Expand Up @@ -117,8 +117,10 @@ export default {
sns: 'sns',
sqs: 'sqs',
subnet: 'subnet',
systemsManagerInstance: 'systemsManagerInstance',
systemsManagerActivation: 'systemsManagerActivation',
systemsManagerAssociation: 'systemsManagerAssociation',
systemsManagerDocument: 'systemsManagerDocument',
systemsManagerInstance: 'systemsManagerInstance',
systemsManagerParameter: 'systemsManagerParameter',
transitGateway: 'transitGateway',
transitGatewayAttachment: 'transitGatewayAttachment',
Expand Down
10 changes: 9 additions & 1 deletion src/properties/logger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -789,5 +789,13 @@ export default {
/**
* Msk
*/
fetchedMskClusters: (num: number): string => `Fetched ${num} Msk clusters`,
fetchedMskClusters: (num: number): string =>
`Fetched ${num} Msk clusters`,
/**
* SSM
*/
fetchedSystemManagersActivations: (num: number): string =>
`Fetched ${num} SSM Activations`,
fetchedSystemManagersAssociations: (num: number): string =>
`Fetched ${num} SSM Associations`,
}
130 changes: 130 additions & 0 deletions src/services/systemsManagerActivation/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 = 'systemsManagerDocumentActivations'
const errorLog = new AwsErrorLog(serviceName)
const endpoint = initTestEndpoint(serviceName)
const customRetrySettings = setAwsRetryOptions({
baseDelay: API_GATEWAY_CUSTOM_DELAY,
})

/**
* SystemsManagerActivation
*/

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.fetchedSystemManagersActivations(items.length))

activationList.push(...items)

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

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

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

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

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

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

resolveSystemManagerActivationData()
})
})

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

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

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

const arn = systemManagerActivationArn({ 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/systemsManagerActivation/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 SystemManagerActivation extends BaseService implements Service {
format = format.bind(this)

getData = getData.bind(this)

mutation = mutation
}
5 changes: 5 additions & 0 deletions src/services/systemsManagerActivation/mutation.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export default `mutation($input: [AddawsSystemManagerActivationInput!]!) {
addawsSystemManagerActivation(input: $input, upsert: true) {
numUids
}
}`
12 changes: 12 additions & 0 deletions src/services/systemsManagerActivation/schema.graphql
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
type awsSystemManagerActivation 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