diff --git a/README.md b/README.md index e8bd6612..d625fcef 100644 --- a/README.md +++ b/README.md @@ -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 | diff --git a/src/enums/resources.ts b/src/enums/resources.ts index baf9d9c3..0207b207 100644 --- a/src/enums/resources.ts +++ b/src/enums/resources.ts @@ -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', diff --git a/src/enums/schemasMap.ts b/src/enums/schemasMap.ts index f6dbc0af..e4c2ca48 100644 --- a/src/enums/schemasMap.ts +++ b/src/enums/schemasMap.ts @@ -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', diff --git a/src/enums/serviceAliases.ts b/src/enums/serviceAliases.ts index 48b4467e..df435b0b 100644 --- a/src/enums/serviceAliases.ts +++ b/src/enums/serviceAliases.ts @@ -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', diff --git a/src/enums/serviceMap.ts b/src/enums/serviceMap.ts index 90bc9d45..2e192250 100644 --- a/src/enums/serviceMap.ts +++ b/src/enums/serviceMap.ts @@ -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' @@ -25,6 +25,9 @@ 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' @@ -32,8 +35,8 @@ 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' @@ -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' @@ -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 @@ -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, } diff --git a/src/enums/services.ts b/src/enums/services.ts index a4c2a0be..2ceb6c23 100644 --- a/src/enums/services.ts +++ b/src/enums/services.ts @@ -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', diff --git a/src/properties/logger.ts b/src/properties/logger.ts index c4881b40..746f2e6e 100644 --- a/src/properties/logger.ts +++ b/src/properties/logger.ts @@ -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`, } diff --git a/src/services/systemsManagerActivation/data.ts b/src/services/systemsManagerActivation/data.ts new file mode 100644 index 00000000..e2239eba --- /dev/null +++ b/src/services/systemsManagerActivation/data.ts @@ -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 => + 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 { + 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(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')) + }) diff --git a/src/services/systemsManagerActivation/format.ts b/src/services/systemsManagerActivation/format.ts new file mode 100644 index 00000000..6467e6a7 --- /dev/null +++ b/src/services/systemsManagerActivation/format.ts @@ -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), + } +} diff --git a/src/services/systemsManagerActivation/index.ts b/src/services/systemsManagerActivation/index.ts new file mode 100644 index 00000000..21c18ac7 --- /dev/null +++ b/src/services/systemsManagerActivation/index.ts @@ -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 +} \ No newline at end of file diff --git a/src/services/systemsManagerActivation/mutation.ts b/src/services/systemsManagerActivation/mutation.ts new file mode 100644 index 00000000..bfbc27c6 --- /dev/null +++ b/src/services/systemsManagerActivation/mutation.ts @@ -0,0 +1,5 @@ +export default `mutation($input: [AddawsSystemManagerActivationInput!]!) { + addawsSystemManagerActivation(input: $input, upsert: true) { + numUids + } +}` \ No newline at end of file diff --git a/src/services/systemsManagerActivation/schema.graphql b/src/services/systemsManagerActivation/schema.graphql new file mode 100644 index 00000000..19944fa1 --- /dev/null +++ b/src/services/systemsManagerActivation/schema.graphql @@ -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] +} diff --git a/src/services/systemsManagerAssociation/connections.ts b/src/services/systemsManagerAssociation/connections.ts new file mode 100644 index 00000000..510f83fb --- /dev/null +++ b/src/services/systemsManagerAssociation/connections.ts @@ -0,0 +1,45 @@ +import { ServiceConnection } from '@cloudgraph/sdk' +import services from '../../enums/services' +import { RawAwsSystemManagerAssociation } from './data'; +import { RawAwsSystemsManagerInstance } from '../systemsManagerInstance/data'; + +export default ({ + service: systemsManagerAssociation, + data, + region, +}: { + service: RawAwsSystemManagerAssociation + data: Array<{ name: string; data: { [property: string]: any[] } }> + region: string +}): { + [property: string]: ServiceConnection[] +} => { + const { AssociationId, InstanceId } = systemsManagerAssociation + const connections: ServiceConnection[] = [] + + /** + * Find SystemManagerInstances used in SystemsManagerAssociation + */ + const instances: { + name: string + data: { [property: string]: any[] } + } = data.find(({ name }) => name === services.systemsManagerInstance) + if (instances?.data?.[region]) { + const systemsManagerInstanceInRegion: RawAwsSystemsManagerInstance[] = instances.data[region].find( + ({ InstanceId: iId }: RawAwsSystemsManagerInstance) => iId === InstanceId + ) + if (systemsManagerInstanceInRegion) { + connections.push({ + id: InstanceId, + resourceType: services.systemsManagerInstance, + relation: 'child', + field: 'systemsManagerInstances', + }) + } + } + + const result = { + [AssociationId]: connections, + } + return result +} diff --git a/src/services/systemsManagerAssociation/data.ts b/src/services/systemsManagerAssociation/data.ts new file mode 100644 index 00000000..1af83649 --- /dev/null +++ b/src/services/systemsManagerAssociation/data.ts @@ -0,0 +1,126 @@ +import CloudGraph from '@cloudgraph/sdk' +import SSM, { Association, ListAssociationsRequest, ListAssociationsResult } 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' + +const lt = { ...awsLoggerText } +const { logger } = CloudGraph +const MAX_ACTIVATIONS = 50 +const serviceName = 'systemsManagerDocumentAssociations' +const errorLog = new AwsErrorLog(serviceName) +const endpoint = initTestEndpoint(serviceName) +const customRetrySettings = setAwsRetryOptions({ + baseDelay: API_GATEWAY_CUSTOM_DELAY, +}) + +/** + * SystemsManagerAssociation + */ + +export const getAssociationsForRegion = async ( + ssm: SSM +): Promise => + new Promise(async resolve => { + const associationList: Association[] = [] + + const listAssociationsOpts: ListAssociationsRequest = {} + const listAllAssociations = (token?: string): void => { + listAssociationsOpts.MaxResults = MAX_ACTIVATIONS + if (token) { + listAssociationsOpts.NextToken = token + } + try { + ssm.listAssociations( + listAssociationsOpts, + (err: AWSError, data: ListAssociationsResult) => { + if (err) { + errorLog.generateAwsErrorLog({ + functionName: 'ssm:listAssociations', + err, + }) + } + + if (isEmpty(data)) { + return resolve([]) + } + + const { NextToken: nextToken, Associations: items = [] } = data || {} + + if (isEmpty(items)) { + return resolve([]) + } + + logger.debug(lt.fetchedSystemManagersAssociations(items.length)) + + associationList.push(...items) + + if (nextToken) { + listAllAssociations(nextToken) + } else { + resolve(associationList) + } + } + ) + } catch (error) { + resolve([]) + } + } + listAllAssociations() + }) + +export interface RawAwsSystemManagerAssociation extends Association { + region: string + account +} + +export default async ({ + regions, + config, + account, +}: { + account: string + regions: string + config: Config +}): Promise<{ + [region: string]: RawAwsSystemManagerAssociation[] +}> => + new Promise(async resolve => { + const associationsResult: RawAwsSystemManagerAssociation[] = [] + + const regionPromises = regions.split(',').map(region => { + const ssm = new SSM({ + ...config, + region, + endpoint, + ...customRetrySettings, + }) + + return new Promise(async resolveSystemManagerAssociationData => { + // Get SystemManager Association + const associations = await getAssociationsForRegion(ssm) + + if (!isEmpty(associations)) { + associationsResult.push( + ...associations.map((association) => ({ + ...association, + region, + account, + })) + ) + } + + resolveSystemManagerAssociationData() + }) + }) + + await Promise.all(regionPromises) + errorLog.reset() + + resolve(groupBy(associationsResult, 'region')) + }) diff --git a/src/services/systemsManagerAssociation/format.ts b/src/services/systemsManagerAssociation/format.ts new file mode 100644 index 00000000..89cde2f9 --- /dev/null +++ b/src/services/systemsManagerAssociation/format.ts @@ -0,0 +1,76 @@ +import { RawAwsSystemManagerAssociation } from './data' +import { AwsSystemManagerAssociation } from '../../types/generated' +import { systemManagerAssociationArn } from '../../utils/generateArns' +import { AssociationStatusAggregatedCount, TargetMaps } from 'aws-sdk/clients/ssm' + +export default ({ + service, + account, + region, +}: { + service: RawAwsSystemManagerAssociation + account: string + region: string +}): AwsSystemManagerAssociation => { + const { + Name: documentArn, + InstanceId: instanceId, + AssociationId: associationId, + AssociationVersion: associationVersion, + DocumentVersion: documentVersion, + Targets: targets, + LastExecutionDate: lastExecutionDate, + Overview: overview, + ScheduleExpression: scheduleExpression, + AssociationName: associationName, + ScheduleOffset: scheduleOffset, + TargetMaps: targetMaps, + } = service + + const arn = systemManagerAssociationArn({ region, account, id: associationId }) + + const formatStatusAggregatedCount = (aggregatedCount: AssociationStatusAggregatedCount): {id: string, key: string, count: number}[] => { + const result: {id: string, key: string, count: number}[] = [] + for (const [key, value] of Object.entries(aggregatedCount)) { + result.push({ id: `${key}:${value}`, key, count: value }) + } + return result + } + + const formatTargetMap = (targetMaps: TargetMaps): {id: string, key: string, values: string[]}[] => { + const result: {id: string, key: string, values: string[]}[] = [] + targetMaps.forEach(tm => { + for (const [key, value] of Object.entries(tm)) { + result.push({ id: `${key}:${value}`, key, values: value}) + } + }); + return result + } + + return { + id: arn, + accountId: account, + arn, + region, + documentArn, + instanceId, + associationId, + associationVersion, + documentVersion, + targets: targets?.map(t => ({ + id: `${t.Key}:${t.Values.join(':')}`, + key: t.Key, + value: t.Values + })) || [], + lastExecutionDate: lastExecutionDate?.toISOString(), + overview: { + status: overview?.Status, + detailedStatus: overview?.DetailedStatus, + associationStatusAggregatedCount: overview?.AssociationStatusAggregatedCount?formatStatusAggregatedCount(overview?.AssociationStatusAggregatedCount):[], + }, + scheduleExpression, + associationName, + scheduleOffset, + targetMaps: targetMaps? formatTargetMap(targetMaps) : [], + } +} diff --git a/src/services/systemsManagerAssociation/index.ts b/src/services/systemsManagerAssociation/index.ts new file mode 100644 index 00000000..36d81c45 --- /dev/null +++ b/src/services/systemsManagerAssociation/index.ts @@ -0,0 +1,16 @@ +import { Service } from '@cloudgraph/sdk' +import BaseService from '../base' +import format from './format' +import getConnections from '../systemsManagerAssociation/connections'; +import getData from './data' +import mutation from './mutation' + +export default class SystemManagerAssociation extends BaseService implements Service { + format = format.bind(this) + + getConnections = getConnections.bind(this) + + getData = getData.bind(this) + + mutation = mutation +} \ No newline at end of file diff --git a/src/services/systemsManagerAssociation/mutation.ts b/src/services/systemsManagerAssociation/mutation.ts new file mode 100644 index 00000000..72cc16e0 --- /dev/null +++ b/src/services/systemsManagerAssociation/mutation.ts @@ -0,0 +1,5 @@ +export default `mutation($input: [AddawsSystemManagerAssociationInput!]!) { + addawsSystemManagerAssociation(input: $input, upsert: true) { + numUids + } +}` \ No newline at end of file diff --git a/src/services/systemsManagerAssociation/schema.graphql b/src/services/systemsManagerAssociation/schema.graphql new file mode 100644 index 00000000..0b9ca680 --- /dev/null +++ b/src/services/systemsManagerAssociation/schema.graphql @@ -0,0 +1,59 @@ +type awsSystemManagerAssociationTargets + @generate( + query: { get: false, query: true, aggregate: false } + mutation: { add: false, delete: false } + subscription: false + ) { + id: String! @id + key: String @search(by: [hash, regexp]) + value: [String] @search(by: [hash, regexp]) +} + +type awsSystemManagerAssociationOverviewStatusAggregatedCount + @generate( + query: { get: false, query: true, aggregate: false } + mutation: { add: false, delete: false } + subscription: false + ) { + id: String! @id + key: String @search(by: [hash, regexp]) + value: Int @search +} + +type awsSystemManagerAssociationOverview + @generate( + query: { get: false, query: true, aggregate: false } + mutation: { add: false, delete: false } + subscription: false + ) { + status: String @search(by: [hash, regexp]) + detailedStatus: String @search(by: [hash, regexp]) + associationStatusAggregatedCount: [awsSystemManagerAssociationOverviewStatusAggregatedCount] +} + +type awsSystemManagerAssociationTargetMaps + @generate( + query: { get: false, query: true, aggregate: false } + mutation: { add: false, delete: false } + subscription: false + ) { + id: String! @id + key: String @search(by: [hash, regexp]) + value: [String] @search(by: [hash, regexp]) +} + +type awsSystemManagerAssociation implements awsBaseService @key(fields: "arn") { + documentArn: String @search(by: [hash, regexp]) + instanceId: String @search(by: [hash, regexp]) + associationId: String @search(by: [hash, regexp]) + associationVersion: String @search(by: [hash, regexp]) + documentVersion: String @search(by: [hash, regexp]) + targets: [awsSystemManagerAssociationTargets] + lastExecutionDate: DateTime @search(by: [day]) + overview: awsSystemManagerAssociationOverview + scheduleExpression: String @search(by: [hash, regexp]) + associationName: String @search(by: [hash, regexp]) + scheduleOffset: Int @search + targetMaps: [awsSystemManagerAssociationTargetMaps] + systemsManagerInstances: [awsSystemsManagerInstance] @hasInverse(field: systemManagerAssociations) +} diff --git a/src/services/systemsManagerInstance/index.ts b/src/services/systemsManagerInstance/index.ts index 8e2b63d1..00cb6e33 100644 --- a/src/services/systemsManagerInstance/index.ts +++ b/src/services/systemsManagerInstance/index.ts @@ -1,14 +1,14 @@ import { Service } from '@cloudgraph/sdk' - import BaseService from '../base' - import format from './format' - import getData from './data' - import mutation from './mutation' +import BaseService from '../base' +import format from './format' +import getData from './data' +import mutation from './mutation' - export default class SystemsManagerInstance extends BaseService implements Service { - format = format.bind(this) - - getData = getData.bind(this) - - mutation = mutation - } +export default class SystemsManagerInstance extends BaseService implements Service { + format = format.bind(this) + + getData = getData.bind(this) + + mutation = mutation +} \ No newline at end of file diff --git a/src/services/systemsManagerInstance/schema.graphql b/src/services/systemsManagerInstance/schema.graphql index e4ff5624..c1ff45cd 100644 --- a/src/services/systemsManagerInstance/schema.graphql +++ b/src/services/systemsManagerInstance/schema.graphql @@ -22,6 +22,7 @@ type awsSystemsManagerInstance implements awsBaseService @key(fields: "arn") { sourceType: String @search(by: [hash, regexp]) iamRole: [awsIamRole] @hasInverse(field: systemsManagerInstances) ec2Instance: [awsEc2] @hasInverse(field: systemsManagerInstance) + systemManagerAssociations: [awsSystemManagerAssociation] @hasInverse(field: systemsManagerInstances) } type systemsManagerInstanceAssociationOverview { diff --git a/src/types/generated.ts b/src/types/generated.ts index 5ce30c20..c4f7c487 100644 --- a/src/types/generated.ts +++ b/src/types/generated.ts @@ -4930,6 +4930,59 @@ export type AwsSuspendedProcess = { suspensionReason?: Maybe; }; +export type AwsSystemManagerActivation = AwsBaseService & { + activationId?: Maybe; + createdDate?: Maybe; + defaultInstanceName?: Maybe; + description?: Maybe; + expirationDate?: Maybe; + expired?: Maybe; + iamRole?: Maybe; + registrationLimit?: Maybe; + registrationsCount?: Maybe; + tags?: Maybe>>; +}; + +export type AwsSystemManagerAssociation = AwsBaseService & { + associationId?: Maybe; + associationName?: Maybe; + associationVersion?: Maybe; + documentArn?: Maybe; + documentVersion?: Maybe; + instanceId?: Maybe; + lastExecutionDate?: Maybe; + overview?: Maybe; + scheduleExpression?: Maybe; + scheduleOffset?: Maybe; + systemsManagerInstances?: Maybe>>; + targetMaps?: Maybe>>; + targets?: Maybe>>; +}; + +export type AwsSystemManagerAssociationOverview = { + associationStatusAggregatedCount?: Maybe>>; + detailedStatus?: Maybe; + status?: Maybe; +}; + +export type AwsSystemManagerAssociationOverviewStatusAggregatedCount = { + id: Scalars['String']; + key?: Maybe; + value?: Maybe; +}; + +export type AwsSystemManagerAssociationTargetMaps = { + id: Scalars['String']; + key?: Maybe; + value?: Maybe>>; +}; + +export type AwsSystemManagerAssociationTargets = { + id: Scalars['String']; + key?: Maybe; + value?: Maybe>>; +}; + export type AwsSystemsManagerDocument = AwsBaseService & { createdDate?: Maybe; documentFormat?: Maybe; @@ -4979,6 +5032,7 @@ export type AwsSystemsManagerInstance = AwsBaseService & { resourceType?: Maybe; sourceId?: Maybe; sourceType?: Maybe; + systemManagerAssociations?: Maybe>>; }; export type AwsSystemsManagerParameter = AwsBaseService & { diff --git a/src/utils/generateArns.ts b/src/utils/generateArns.ts index 4867396a..104c72e2 100644 --- a/src/utils/generateArns.ts +++ b/src/utils/generateArns.ts @@ -414,3 +414,23 @@ export const codePipelineArn = ({ account: string name: string }): string => `arn:aws:codepipeline:${region}:${account}:pipeline/${name}` + +export const systemManagerActivationArn = ({ + region, + account, + id, +}: { + region: string + account: string + id: string +}): string => `arn:aws:ssm:${region}:${account}:activation/${id}` + +export const systemManagerAssociationArn = ({ + region, + account, + id, +}: { + region: string + account: string + id: string +}): string => `arn:aws:ssm:${region}:${account}:association/${id}`