export async function createRule()

in src/deployments/cdk/src/deployments/config/create.ts [47:251]


export async function createRule(props: CreateRuleProps) {
  const { acceleratorExecutionRoleName, config, accountStacks, accounts, outputs, defaultRegion } = props;
  const awsConfigConf = config['global-options']['aws-config'];
  if (!awsConfigConf) {
    return;
  }

  const configRules = awsConfigConf.rules;
  const configRuleDefaults = awsConfigConf.defaults;
  let configRuleArtifact: ConfigRuleArtifactsOutput | undefined;
  const configRuleArtifactOutputs: ConfigRuleArtifactsOutput[] = getStackJsonOutput(outputs, {
    accountKey: config.getMandatoryAccountKey('master'),
    outputType: 'ConfigRulesArtifactsOutput',
  });

  if (configRuleArtifactOutputs.length > 0) {
    configRuleArtifact = configRuleArtifactOutputs[0];
  }

  const customRules =
    config['global-options']['aws-config']?.rules
      .filter(r => r.type === 'custom')
      .map(r => r['runtime-path'] || r.name.toLowerCase())
      .map(r => (r.endsWith('.zip') ? r : r + '.zip')) || [];
  if (configRuleArtifact) {
    await downloadCustomRules(
      getAccountId(accounts, config.getMandatoryAccountKey('master'))!,
      acceleratorExecutionRoleName,
      customRules,
      configRuleArtifact.bucketName,
      configRuleArtifact.keyPrefix,
    );
  }

  for (const [ouKey, ouConfig] of config.getOrganizationalUnits()) {
    if (!ouConfig['aws-config']) {
      continue;
    }
    const ouAwsConfigRuleConfigs = ouConfig['aws-config'];
    for (const [accountKey, accountConfig] of config.getAccountConfigsForOu(ouKey)) {
      console.warn(`Creating config rules in account ${accountKey}`);
      const awsAccountConfigRuleConfig = accountConfig['aws-config'];
      for (const awsConfigRuleConfig of ouAwsConfigRuleConfigs) {
        for (const ruleName of awsConfigRuleConfig.rules) {
          console.log(`Creating config rule ${ruleName}`);
          const awsConfigRule = configRules.find(cr => cr.name === ruleName);
          if (!awsConfigRule) {
            console.warn(`Config rule ${ruleName} is not found in Accelerator Configuration global-options`);
            continue;
          }
          console.debug(`Config rule configuration`);
          console.debug(JSON.stringify(awsConfigRule, null, 2));

          const remediation =
            awsConfigRule.remediation === undefined ? configRuleDefaults.remediation : awsConfigRule.remediation;
          const remediationAttempts =
            awsConfigRule['remediation-attempts'] || configRuleDefaults['remediation-attempts'];
          const remediationRetrySeconds =
            awsConfigRule['remediation-retry-seconds'] || configRuleDefaults['remediation-retry-seconds'];
          const remediationConcurrency =
            awsConfigRule['remediation-concurrency'] || configRuleDefaults['remediation-concurrency'];
          for (const region of config['global-options']['supported-regions']) {
            console.warn(`Creating config rule ${ruleName} in region ${region}`);
            if (awsConfigRuleConfig['excl-regions'].includes(region)) {
              console.warn(`Skipping creation in excluded region ${region}`);
              continue;
            }
            const isRuleIgnored = awsAccountConfigRuleConfig.find(
              ac => ac['excl-rules'].includes(ruleName) && ac.regions.includes(region),
            );
            if (isRuleIgnored) {
              console.warn(`Skipping creation as config rule is excluded for region ${region}`);
              continue;
            }
            const accountStack = accountStacks.tryGetOrCreateAccountStack(accountKey, region);
            if (!accountStack) {
              console.warn(`Cannot find account stack ${accountKey} in region ${region}`);
              continue;
            }
            const configRuleName = createName({
              name: ruleName,
              suffixLength: 0,
            });
            const configParams = getConfigRuleParameters({
              ruleParams: awsConfigRule.parameters,
              config,
              outputs,
              accountKey,
              defaultRegion,
            });
            let configRule;
            if (awsConfigRule.type === 'managed') {
              console.warn(`Creating rule as managed rule`);
              configRule = new awsConfig.ManagedRule(accountStack, `ConfigRule-${ruleName}`, {
                identifier: ruleName,
                configRuleName,
                description: configRuleName,
                inputParameters: configParams,
              });
            } else {
              console.warn(`Creating rule as custom resource`);
              if (!configRuleArtifact) {
                console.error('ConfigRuleArtifact is not found to create Custom ConfigRule');
                continue;
              }
              const configRuleRuntime = awsConfigRule['runtime-path'] || awsConfigRule.name.toLowerCase();
              const ruleProps: CustomRuleProps = {
                roleArn: `arn:${cdk.Aws.PARTITION}:iam::${cdk.Aws.ACCOUNT_ID}:role/${acceleratorExecutionRoleName}`,
                configRuleName,
                description: configRuleName,
                inputParameters: configParams,
                ruleScope: {
                  resourceTypes: awsConfigRule['resource-types'].map(r => awsConfig.ResourceType.of(r)),
                },
                maximumExecutionFrequency: awsConfigRule['max-frequency']
                  ? (awsConfigRule['max-frequency'] as awsConfig.MaximumExecutionFrequency)
                  : undefined,
                periodic: !!awsConfigRule['max-frequency'],
                configurationChanges: !!awsConfigRule['resource-types'].length,
                runtimeFileLocation: path.join(configRulesTempDir, configRuleRuntime),
                lambdaRuntime: awsConfigRule.runtime!,
              };
              configRule = new CustomRule(accountStack, `ConfigRule-${ruleName}`, ruleProps).resource;
            }
            if (!awsConfigRuleConfig['remediate-regions']?.includes(region)) {
              continue;
            }

            if (!remediation || !awsConfigRule['remediation-action']) {
              continue;
            }
            const remediationAction = awsConfigRule['remediation-action'];

            const ssmDocumentsConfig = config['global-options']['ssm-automation'];
            const remediationActionName = createName({
              name: remediationAction,
              suffixLength: 0,
            });
            let targetId = remediationActionName;
            const ssmDocInGlobalOptions = ssmDocumentsConfig.find(
              d =>
                d.documents.find(dc => dc.name === remediationAction) &&
                d.regions.includes(region) &&
                d.accounts.includes(accountKey),
            );
            if (!ssmDocInGlobalOptions) {
              const ssmDocInAccount = accountConfig['ssm-automation'].find(d =>
                d.documents.includes(remediationAction),
              );
              if (ssmDocInAccount) {
                targetId = `arn:${cdk.Aws.PARTITION}:ssm:${cdk.Aws.REGION}:${getAccountId(
                  accounts,
                  ssmDocInAccount.account,
                )}:document/${remediationActionName}`;
              } else {
                const ssmDocInOu = ouConfig['ssm-automation'].find(d => d.documents.includes(remediationAction));
                if (ssmDocInOu) {
                  targetId = `arn:${cdk.Aws.PARTITION}:ssm:${cdk.Aws.REGION}:${getAccountId(
                    accounts,
                    ssmDocInOu.account,
                  )}:document/${remediationActionName}`;
                } else if (config['global-options']['default-ssm-documents'].includes(remediationAction)) {
                  targetId = remediationAction;
                } else {
                  console.warn(
                    `No Remediation "${remediationAction}"is Created in account "${accountKey}" and region "${region}"`,
                  );
                  continue;
                }
              }
            } else if (ssmDocInGlobalOptions) {
              targetId = remediationActionName;
            } else if (config['global-options']['default-ssm-documents'].includes(remediationAction)) {
              targetId = remediationAction;
            } else {
              console.warn(
                `Invalid SSM-Document given in "remediation-action" for AWS Config Rule ${awsConfigRule.name}, ${accountKey}`,
              );
              continue;
            }

            const remediationParams = getRemediationParameters({
              outputs,
              remediationParams: awsConfigRule['remediation-params'],
              roleName: acceleratorExecutionRoleName,
              config,
              accountKey,
              defaultRegion,
            });

            new awsConfig.CfnRemediationConfiguration(accountStack, `ConfigRuleRemediation-${ruleName}`, {
              configRuleName: configRule.configRuleName,
              targetId,
              targetType: 'SSM_DOCUMENT',
              parameters: remediationParams,
              automatic: true,
              maximumAutomaticAttempts: remediationAttempts,
              retryAttemptSeconds: remediationRetrySeconds,
            });
          }
        }
      }
    }
  }
}