diff --git a/src/services/cloudFormationStack/connections.ts b/src/services/cloudFormationStack/connections.ts index f9cd5a23..80bc057b 100644 --- a/src/services/cloudFormationStack/connections.ts +++ b/src/services/cloudFormationStack/connections.ts @@ -1,12 +1,10 @@ import { ServiceConnection } from '@cloudgraph/sdk' import { Stack } from 'aws-sdk/clients/cloudformation' import isEmpty from 'lodash/isEmpty' -import resources from '../../enums/resources' import services from '../../enums/services' import { RawAwsCloudFormationStack } from './data' import { RawAwsIamRole } from '../iamRole/data' import { TagMap } from '../../types' -import { getIamId } from '../../utils/ids' import { globalRegionName } from '../../enums/regions' /** @@ -84,14 +82,10 @@ export default ({ ) if (!isEmpty(dataAtRegion)) { for (const instance of dataAtRegion) { - const { RoleId: roleId, RoleName: roleName } = instance + const { Arn: arn }: RawAwsIamRole = instance connections.push({ - id: getIamId({ - resourceId: roleId, - resourceName: roleName, - resourceType: resources.iamRole, - }), + id: arn, resourceType: services.iamRole, relation: 'child', field: 'iamRole', diff --git a/src/services/cloudFormationStack/format.ts b/src/services/cloudFormationStack/format.ts index a53aeb31..15af402b 100644 --- a/src/services/cloudFormationStack/format.ts +++ b/src/services/cloudFormationStack/format.ts @@ -124,7 +124,7 @@ export default ({ timeoutInMinutes, capabilities, outputs: outputsList, - roleArn: roleArn || '', // TODO: create connection to IAM role if possible + roleArn: roleArn || '', tags: formatTagsFromMap(tags), enableTerminationProtection: enableTerminationProtection ? t.yes : t.no, parentId: parentId || '', diff --git a/src/services/cognitoUserPool/connections.ts b/src/services/cognitoUserPool/connections.ts index 32e81e66..1be0efbb 100644 --- a/src/services/cognitoUserPool/connections.ts +++ b/src/services/cognitoUserPool/connections.ts @@ -1,7 +1,47 @@ -import { UserPoolType } from 'aws-sdk/clients/cognitoidentityserviceprovider'; +import { UserPoolType, LambdaConfigType } from 'aws-sdk/clients/cognitoidentityserviceprovider' -import { ServiceConnection } from '@cloudgraph/sdk'; -import services from '../../enums/services'; +import { ServiceConnection } from '@cloudgraph/sdk' +import { isEmpty } from 'lodash' +import services from '../../enums/services' +import { sesArn } from '../../utils/generateArns' +import { RawAwsLambdaFunction } from '../lambda/data' +import { RawAwsSes } from '../ses/data' +import { RawAwsIamRole } from '../iamRole/data' +import { AwsKms } from '../kms/data' + +const getLambdasArn = ( + lambdaConfig?: LambdaConfigType +): string[] => { + if (isEmpty(lambdaConfig)) { + return [] + } + + const { + PreSignUp, + CustomMessage, + PostConfirmation, + PreAuthentication, + PostAuthentication, + DefineAuthChallenge, + CreateAuthChallenge, + VerifyAuthChallengeResponse, + PreTokenGeneration, + UserMigration, + } = lambdaConfig + + return [ + PreSignUp, + CustomMessage, + PostConfirmation, + PreAuthentication, + PostAuthentication, + DefineAuthChallenge, + CreateAuthChallenge, + VerifyAuthChallengeResponse, + PreTokenGeneration, + UserMigration, + ]?.filter(l => l) +} /** * Cognito User Pool @@ -11,7 +51,9 @@ export default ({ service: userPool, data, region, + account, }: { + account: string data: { name: string; data: { [property: string]: any[] } }[] service: UserPoolType & { region: string @@ -23,38 +65,104 @@ export default ({ const { Id: id, LambdaConfig: lambdaConfig, + EmailConfiguration: emailConfiguration, + SmsConfiguration: smsConfiguration, } = userPool - const defineAuthChallengeArn = lambdaConfig?.DefineAuthChallenge - /** * Find Lambda Functions - * related to this Auto Scaling Group + * related to this cognito user pool */ + const lambdasArn: string[] = getLambdasArn(lambdaConfig) const lambdas = data.find(({ name }) => name === services.lambda) - if (defineAuthChallengeArn && lambdas?.data?.[region]) { - const lambdaInRegion = lambdas.data[region].find(lambda => - defineAuthChallengeArn === lambda.FunctionArn) - - if (lambdaInRegion) { - const lambdaFunctionArn = lambdaInRegion.FunctionArn + if (lambdasArn?.length > 0 && lambdas?.data?.[region]) { + const lambdasInRegion: RawAwsLambdaFunction[] = lambdas.data[region].filter( + ({ FunctionArn }: RawAwsLambdaFunction) => + lambdasArn.includes(FunctionArn) + ) + if (!isEmpty(lambdasInRegion)) { + for (const lambda of lambdasInRegion) { + connections.push({ + id: lambda.FunctionArn, + resourceType: services.lambda, + relation: 'child', + field: 'lambdas', + }) + } + } + } + + /** + * Find MKS + * related to this cognito user pool + */ + const kmsKeyID = lambdaConfig?.KMSKeyID + const kms = data.find(({ name }) => name === services.kms) + + if (kmsKeyID && kms?.data?.[region]) { + const kmsInRegion: AwsKms = kms.data[region].find( + ({ KeyId }: AwsKms) => kmsKeyID === KeyId + ) + + if (kmsInRegion) { connections.push({ - id: lambdaFunctionArn, - resourceType: services.lambda, + id: kmsInRegion.KeyId, + resourceType: services.kms, relation: 'child', - field: 'lambda', + field: 'kms', }) } } - // TODO Email Sender + /** + * Find SES sender + * related to this cognito user pool + */ + const emailConfigSourceArn = emailConfiguration?.SourceArn + const emails = data.find(({ name }) => name === services.ses) - // TODO SMS Sender + if (emailConfigSourceArn && emails?.data?.[region]) { + const emailInRegion: RawAwsSes = emails.data[region].find( + ({ Identity }: RawAwsSes) => + emailConfigSourceArn === sesArn({ region, account, email: Identity }) + ) + + if (emailInRegion) { + connections.push({ + id: sesArn({ region, account, email: emailInRegion.Identity }), + resourceType: services.ses, + relation: 'child', + field: 'ses', + }) + } + } + + /** + * Find SNS caller + * related to this cognito user pool + */ + const smsConfigSnsCallerArn = smsConfiguration?.SnsCallerArn + const iamRoles = data.find(({ name }) => name === services.iamRole) + + if (smsConfigSnsCallerArn && iamRoles?.data?.[region]) { + const iamRoleInRegion: RawAwsIamRole = iamRoles.data[region].find( + ({ Arn }: RawAwsIamRole) => smsConfigSnsCallerArn === Arn + ) + + if (iamRoleInRegion) { + connections.push({ + id: iamRoleInRegion.Arn, + resourceType: services.iamRole, + relation: 'child', + field: 'iamRole', + }) + } + } const userPoolResult = { [id]: connections, } return userPoolResult -} +} \ No newline at end of file diff --git a/src/services/cognitoUserPool/schema.graphql b/src/services/cognitoUserPool/schema.graphql index 5746d749..3063d3f0 100644 --- a/src/services/cognitoUserPool/schema.graphql +++ b/src/services/cognitoUserPool/schema.graphql @@ -119,9 +119,9 @@ type awsCognitoUserPool implements awsBaseService @key(fields: "id") { usernameConfigurationCaseSensitive: String @search(by: [hash, regexp]) accountRecoverySettings: [awsAccountRecoverySetting] tags: [awsRawTag] - lambda: [awsLambda] @hasInverse(field: cognitoUserPool) #change to plural + lambdas: [awsLambda] @hasInverse(field: cognitoUserPools) appSync: [awsAppSync] @hasInverse(field: cognitoUserPool) -} - -# TODO: add connetion to kms -# TODO: add connection to iamRole using SmsConfiguration.SnsCallerArn + kms: [awsKms] @hasInverse(field: cognitoUserPools) + ses: [awsSes] @hasInverse(field: cognitoUserPools) + iamRole: [awsIamRole] @hasInverse(field: cognitoUserPools) +} \ No newline at end of file diff --git a/src/services/iamRole/schema.graphql b/src/services/iamRole/schema.graphql index c11be041..91b3c161 100644 --- a/src/services/iamRole/schema.graphql +++ b/src/services/iamRole/schema.graphql @@ -22,4 +22,5 @@ type awsIamRole implements awsBaseService @key(fields: "id") { systemsManagerInstances: [awsSystemsManagerInstance] @hasInverse(field: iamRole) iamInstanceProfiles: [awsIamInstanceProfile] @hasInverse(field: iamRole) + cognitoUserPools: [awsCognitoUserPool] @hasInverse(field: iamRole) } diff --git a/src/services/kms/schema.graphql b/src/services/kms/schema.graphql index 53d0ae5a..40b868c3 100644 --- a/src/services/kms/schema.graphql +++ b/src/services/kms/schema.graphql @@ -28,4 +28,5 @@ type awsKms implements awsBaseService @key(fields: "id") { sageMakerNotebookInstances: [awsSageMakerNotebookInstance] @hasInverse(field: kms) rdsClusterSnapshots: [awsRdsClusterSnapshot] @hasInverse(field: kms) + cognitoUserPools: [awsCognitoUserPool] @hasInverse(field: kms) } diff --git a/src/services/lambda/schema.graphql b/src/services/lambda/schema.graphql index c3d03d0d..432c0ae6 100644 --- a/src/services/lambda/schema.graphql +++ b/src/services/lambda/schema.graphql @@ -20,7 +20,7 @@ type awsLambda implements awsBaseService @key(fields: "arn") { securityGroups: [awsSecurityGroup] @hasInverse(field: lambda) subnet: [awsSubnet] @hasInverse(field: lambda) #change to plural vpc: [awsVpc] @hasInverse(field: lambda) - cognitoUserPool: [awsCognitoUserPool] @hasInverse(field: lambda) #change to plural + cognitoUserPools: [awsCognitoUserPool] @hasInverse(field: lambdas) appSync: [awsAppSync] @hasInverse(field: lambda) } diff --git a/src/services/ses/schema.graphql b/src/services/ses/schema.graphql index 087c9d83..5ae942f1 100644 --- a/src/services/ses/schema.graphql +++ b/src/services/ses/schema.graphql @@ -1,4 +1,5 @@ type awsSes implements awsBaseService @key(fields: "arn") { email: String @search(by: [hash, regexp]) verificationStatus: String @search(by: [hash, regexp]) + cognitoUserPools: [awsCognitoUserPool] @hasInverse(field: ses) } diff --git a/src/types/generated.ts b/src/types/generated.ts index ca9a2509..5333dd5d 100644 --- a/src/types/generated.ts +++ b/src/types/generated.ts @@ -1152,13 +1152,16 @@ export type AwsCognitoUserPool = AwsBaseService & { emailVerificationMessage?: Maybe; emailVerificationSubject?: Maybe; estimatedNumberOfUsers?: Maybe; - lambda?: Maybe>>; + iamRole?: Maybe>>; + kms?: Maybe>>; lambdaConfig?: Maybe; + lambdas?: Maybe>>; lastModifiedDate?: Maybe; mfaConfiguration?: Maybe; name?: Maybe; policies?: Maybe; schemaAttributes?: Maybe>>; + ses?: Maybe>>; smsAuthenticationMessage?: Maybe; smsConfigurationExternalId?: Maybe; smsConfigurationFailure?: Maybe; @@ -3011,6 +3014,7 @@ export type AwsIamRole = AwsBaseService & { assumeRolePolicy?: Maybe; cloudFormationStack?: Maybe>>; codebuilds?: Maybe>>; + cognitoUserPools?: Maybe>>; configurationRecorder?: Maybe>>; createdAt?: Maybe; description?: Maybe; @@ -3134,6 +3138,7 @@ export type AwsKms = AwsBaseService & { cloudtrail?: Maybe>>; cloudwatchLog?: Maybe>>; codebuilds?: Maybe>>; + cognitoUserPools?: Maybe>>; creationDate?: Maybe; customerMasterKeySpec?: Maybe; deletionDate?: Maybe; @@ -3162,7 +3167,7 @@ export type AwsKms = AwsBaseService & { export type AwsLambda = AwsBaseService & { appSync?: Maybe>>; - cognitoUserPool?: Maybe>>; + cognitoUserPools?: Maybe>>; description?: Maybe; environmentVariables?: Maybe>>; handler?: Maybe; @@ -3761,6 +3766,7 @@ export type AwsServiceBillingInfo = { }; export type AwsSes = AwsBaseService & { + cognitoUserPools?: Maybe>>; email?: Maybe; verificationStatus?: Maybe; };