├── .devcontainer.json ├── .eslintrc.json ├── .gitattributes ├── .github ├── ISSUE_TEMPLATE │ ├── bug.yml │ ├── doc.yml │ ├── feature-request.yml │ └── general-issue.yml ├── pull_request_template.md └── workflows │ ├── auto-approve.yml │ ├── build.yml │ ├── pull-request-lint.yml │ ├── release.yml │ └── upgrade-main.yml ├── .gitignore ├── .mergify.yml ├── .npmignore ├── .pre-commit-config.yaml ├── .projen ├── deps.json ├── files.json └── tasks.json ├── .projenrc.js ├── API.md ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── Dockerfile ├── LICENSE ├── NOTICE ├── README.md ├── RULES.md ├── cdk_nag.gif ├── docs ├── IgnoreSuppressionConditions.md ├── NagLogger.md ├── NagPack.md └── RuleCreation.md ├── package.json ├── src ├── ignore-suppression-conditions.ts ├── index.ts ├── models │ └── nag-suppression.ts ├── nag-logger.ts ├── nag-pack.ts ├── nag-rules.ts ├── nag-suppressions.ts ├── packs │ ├── aws-solutions.ts │ ├── hipaa-security.ts │ ├── nist-800-53-r4.ts │ ├── nist-800-53-r5.ts │ ├── pci-dss-321.ts │ └── serverless.ts ├── rules │ ├── apigw │ │ ├── APIGWAccessLogging.ts │ │ ├── APIGWAssociatedWithWAF.ts │ │ ├── APIGWAuthorization.ts │ │ ├── APIGWCacheEnabledAndEncrypted.ts │ │ ├── APIGWDefaultThrottling.ts │ │ ├── APIGWExecutionLoggingEnabled.ts │ │ ├── APIGWRequestValidation.ts │ │ ├── APIGWSSLEnabled.ts │ │ ├── APIGWStructuredLogging.ts │ │ ├── APIGWXrayEnabled.ts │ │ └── index.ts │ ├── appsync │ │ ├── AppSyncGraphQLRequestLogging.ts │ │ ├── AppSyncTracing.ts │ │ └── index.ts │ ├── autoscaling │ │ ├── AutoScalingGroupCooldownPeriod.ts │ │ ├── AutoScalingGroupELBHealthCheckRequired.ts │ │ ├── AutoScalingGroupHealthCheck.ts │ │ ├── AutoScalingGroupScalingNotifications.ts │ │ ├── AutoScalingLaunchConfigPublicIpDisabled.ts │ │ └── index.ts │ ├── cloud9 │ │ ├── Cloud9InstanceNoIngressSystemsManager.ts │ │ └── index.ts │ ├── cloudfront │ │ ├── CloudFrontDistributionAccessLogging.ts │ │ ├── CloudFrontDistributionGeoRestrictions.ts │ │ ├── CloudFrontDistributionHttpsViewerNoOutdatedSSL.ts │ │ ├── CloudFrontDistributionNoOutdatedSSL.ts │ │ ├── CloudFrontDistributionS3OriginAccessControl.ts │ │ ├── CloudFrontDistributionS3OriginAccessIdentity.ts │ │ ├── CloudFrontDistributionWAFIntegration.ts │ │ └── index.ts │ ├── cloudtrail │ │ ├── CloudTrailCloudWatchLogsEnabled.ts │ │ ├── CloudTrailEncryptionEnabled.ts │ │ ├── CloudTrailLogFileValidationEnabled.ts │ │ └── index.ts │ ├── cloudwatch │ │ ├── CloudWatchAlarmAction.ts │ │ ├── CloudWatchLogGroupEncrypted.ts │ │ ├── CloudWatchLogGroupRetentionPeriod.ts │ │ └── index.ts │ ├── codebuild │ │ ├── CodeBuildProjectEnvVarAwsCred.ts │ │ ├── CodeBuildProjectKMSEncryptedArtifacts.ts │ │ ├── CodeBuildProjectManagedImages.ts │ │ ├── CodeBuildProjectSourceRepoUrl.ts │ │ └── index.ts │ ├── cognito │ │ ├── CognitoUserPoolAPIGWAuthorizer.ts │ │ ├── CognitoUserPoolAdvancedSecurityModeEnforced.ts │ │ ├── CognitoUserPoolMFA.ts │ │ ├── CognitoUserPoolNoUnauthenticatedLogins.ts │ │ ├── CognitoUserPoolStrongPasswordPolicy.ts │ │ └── index.ts │ ├── dms │ │ ├── DMSReplicationNotPublic.ts │ │ └── index.ts │ ├── documentdb │ │ ├── DocumentDBClusterBackupRetentionPeriod.ts │ │ ├── DocumentDBClusterEncryptionAtRest.ts │ │ ├── DocumentDBClusterLogExports.ts │ │ ├── DocumentDBClusterNonDefaultPort.ts │ │ ├── DocumentDBCredentialsInSecretsManager.ts │ │ └── index.ts │ ├── dynamodb │ │ ├── DAXEncrypted.ts │ │ ├── DynamoDBAutoScalingEnabled.ts │ │ ├── DynamoDBInBackupPlan.ts │ │ ├── DynamoDBPITREnabled.ts │ │ └── index.ts │ ├── ec2 │ │ ├── EC2EBSInBackupPlan.ts │ │ ├── EC2EBSOptimizedInstance.ts │ │ ├── EC2EBSVolumeEncrypted.ts │ │ ├── EC2IMDSv2Enabled.ts │ │ ├── EC2InstanceDetailedMonitoringEnabled.ts │ │ ├── EC2InstanceNoPublicIp.ts │ │ ├── EC2InstanceProfileAttached.ts │ │ ├── EC2InstanceTerminationProtection.ts │ │ ├── EC2InstancesInVPC.ts │ │ ├── EC2RestrictedCommonPorts.ts │ │ ├── EC2RestrictedInbound.ts │ │ ├── EC2RestrictedSSH.ts │ │ ├── EC2SecurityGroupDescription.ts │ │ └── index.ts │ ├── ecr │ │ ├── ECROpenAccess.ts │ │ └── index.ts │ ├── ecs │ │ ├── ECSClusterCloudWatchContainerInsights.ts │ │ ├── ECSTaskDefinitionContainerLogging.ts │ │ ├── ECSTaskDefinitionNoEnvironmentVariables.ts │ │ ├── ECSTaskDefinitionUserForHostMode.ts │ │ └── index.ts │ ├── efs │ │ ├── EFSEncrypted.ts │ │ ├── EFSInBackupPlan.ts │ │ └── index.ts │ ├── eks │ │ ├── EKSClusterControlPlaneLogs.ts │ │ ├── EKSClusterNoEndpointPublicAccess.ts │ │ └── index.ts │ ├── elasticache │ │ ├── ElastiCacheClusterInVPC.ts │ │ ├── ElastiCacheClusterNonDefaultPort.ts │ │ ├── ElastiCacheRedisClusterAutomaticBackup.ts │ │ ├── ElastiCacheRedisClusterEncryption.ts │ │ ├── ElastiCacheRedisClusterMultiAZ.ts │ │ ├── ElastiCacheRedisClusterRedisAuth.ts │ │ └── index.ts │ ├── elasticbeanstalk │ │ ├── ElasticBeanstalkEC2InstanceLogsToS3.ts │ │ ├── ElasticBeanstalkEnhancedHealthReportingEnabled.ts │ │ ├── ElasticBeanstalkManagedUpdatesEnabled.ts │ │ ├── ElasticBeanstalkVPCSpecified.ts │ │ └── index.ts │ ├── elb │ │ ├── ALBHttpDropInvalidHeaderEnabled.ts │ │ ├── ALBHttpToHttpsRedirection.ts │ │ ├── ALBWAFEnabled.ts │ │ ├── CLBConnectionDraining.ts │ │ ├── CLBNoInboundHttpHttps.ts │ │ ├── ELBACMCertificateRequired.ts │ │ ├── ELBCrossZoneLoadBalancingEnabled.ts │ │ ├── ELBDeletionProtectionEnabled.ts │ │ ├── ELBLoggingEnabled.ts │ │ ├── ELBTlsHttpsListenersOnly.ts │ │ ├── ELBv2ACMCertificateRequired.ts │ │ └── index.ts │ ├── emr │ │ ├── EMRAuthEC2KeyPairOrKerberos.ts │ │ ├── EMREncryptionInTransit.ts │ │ ├── EMRKerberosEnabled.ts │ │ ├── EMRLocalDiskEncryption.ts │ │ ├── EMRS3AccessLogging.ts │ │ └── index.ts │ ├── eventbridge │ │ ├── EventBusDLQ.ts │ │ ├── EventBusOpenAccess.ts │ │ └── index.ts │ ├── glue │ │ ├── GlueEncryptedCloudWatchLogs.ts │ │ ├── GlueJobBookmarkEncrypted.ts │ │ └── index.ts │ ├── iam │ │ ├── IAMGroupHasUsers.ts │ │ ├── IAMNoInlinePolicy.ts │ │ ├── IAMNoManagedPolicies.ts │ │ ├── IAMNoWildcardPermissions.ts │ │ ├── IAMPolicyNoStatementsWithAdminAccess.ts │ │ ├── IAMPolicyNoStatementsWithFullAccess.ts │ │ ├── IAMUserGroupMembership.ts │ │ ├── IAMUserNoPolicies.ts │ │ └── index.ts │ ├── index.ts │ ├── kinesis │ │ ├── KinesisDataAnalyticsFlinkCheckpointing.ts │ │ ├── KinesisDataFirehoseSSE.ts │ │ ├── KinesisDataStreamDefaultKeyWhenSSE.ts │ │ ├── KinesisDataStreamSSE.ts │ │ └── index.ts │ ├── kms │ │ ├── KMSBackingKeyRotationEnabled.ts │ │ └── index.ts │ ├── lambda │ │ ├── LambdaAsyncFailureDestination.ts │ │ ├── LambdaConcurrency.ts │ │ ├── LambdaDLQ.ts │ │ ├── LambdaDefaultMemorySize.ts │ │ ├── LambdaDefaultTimeout.ts │ │ ├── LambdaEventSourceMappingDestination.ts │ │ ├── LambdaEventSourceSQSVisibilityTimeout.ts │ │ ├── LambdaFunctionPublicAccessProhibited.ts │ │ ├── LambdaFunctionUrlAuth.ts │ │ ├── LambdaInsideVPC.ts │ │ ├── LambdaLatestVersion.ts │ │ ├── LambdaLogLevel.ts │ │ ├── LambdaLogging.ts │ │ ├── LambdaStarPermissions.ts │ │ ├── LambdaTracing.ts │ │ └── index.ts │ ├── lex │ │ ├── LexBotAliasEncryptedConversationLogs.ts │ │ └── index.ts │ ├── mediastore │ │ ├── MediaStoreCloudWatchMetricPolicy.ts │ │ ├── MediaStoreContainerAccessLogging.ts │ │ ├── MediaStoreContainerCORSPolicy.ts │ │ ├── MediaStoreContainerHasContainerPolicy.ts │ │ ├── MediaStoreContainerLifecyclePolicy.ts │ │ ├── MediaStoreContainerSSLRequestsOnly.ts │ │ └── index.ts │ ├── msk │ │ ├── MSKBrokerLogging.ts │ │ ├── MSKBrokerToBrokerTLS.ts │ │ ├── MSKClientToBrokerTLS.ts │ │ └── index.ts │ ├── neptune │ │ ├── NeptuneClusterAutomaticMinorVersionUpgrade.ts │ │ ├── NeptuneClusterBackupRetentionPeriod.ts │ │ ├── NeptuneClusterEncryptionAtRest.ts │ │ ├── NeptuneClusterIAMAuth.ts │ │ ├── NeptuneClusterMultiAZ.ts │ │ └── index.ts │ ├── opensearch │ │ ├── OpenSearchAllowlistedIPs.ts │ │ ├── OpenSearchDedicatedMasterNode.ts │ │ ├── OpenSearchEncryptedAtRest.ts │ │ ├── OpenSearchErrorLogsToCloudWatch.ts │ │ ├── OpenSearchInVPCOnly.ts │ │ ├── OpenSearchNoUnsignedOrAnonymousAccess.ts │ │ ├── OpenSearchNodeToNodeEncryption.ts │ │ ├── OpenSearchSlowLogsToCloudWatch.ts │ │ ├── OpenSearchZoneAwareness.ts │ │ └── index.ts │ ├── quicksight │ │ ├── QuicksightSSLConnections.ts │ │ └── index.ts │ ├── rds │ │ ├── AuroraMySQLBacktrack.ts │ │ ├── AuroraMySQLLogging.ts │ │ ├── AuroraMySQLPostgresIAMAuth.ts │ │ ├── RDSAutomaticMinorVersionUpgradeEnabled.ts │ │ ├── RDSEnhancedMonitoringEnabled.ts │ │ ├── RDSInBackupPlan.ts │ │ ├── RDSInstanceBackupEnabled.ts │ │ ├── RDSInstanceDeletionProtectionEnabled.ts │ │ ├── RDSInstancePublicAccess.ts │ │ ├── RDSLoggingEnabled.ts │ │ ├── RDSMultiAZSupport.ts │ │ ├── RDSNonDefaultPort.ts │ │ ├── RDSRestrictedInbound.ts │ │ ├── RDSStorageEncrypted.ts │ │ └── index.ts │ ├── redshift │ │ ├── RedshiftBackupEnabled.ts │ │ ├── RedshiftClusterAuditLogging.ts │ │ ├── RedshiftClusterConfiguration.ts │ │ ├── RedshiftClusterEncryptionAtRest.ts │ │ ├── RedshiftClusterInVPC.ts │ │ ├── RedshiftClusterMaintenanceSettings.ts │ │ ├── RedshiftClusterNonDefaultPort.ts │ │ ├── RedshiftClusterNonDefaultUsername.ts │ │ ├── RedshiftClusterPublicAccess.ts │ │ ├── RedshiftClusterUserActivityLogging.ts │ │ ├── RedshiftClusterVersionUpgrade.ts │ │ ├── RedshiftEnhancedVPCRoutingEnabled.ts │ │ ├── RedshiftRequireTlsSSL.ts │ │ └── index.ts │ ├── s3 │ │ ├── S3BucketDefaultLockEnabled.ts │ │ ├── S3BucketLevelPublicAccessProhibited.ts │ │ ├── S3BucketLoggingEnabled.ts │ │ ├── S3BucketPublicReadProhibited.ts │ │ ├── S3BucketPublicWriteProhibited.ts │ │ ├── S3BucketReplicationEnabled.ts │ │ ├── S3BucketSSLRequestsOnly.ts │ │ ├── S3BucketVersioningEnabled.ts │ │ ├── S3DefaultEncryptionKMS.ts │ │ ├── S3WebBucketOAIAccess.ts │ │ └── index.ts │ ├── sagemaker │ │ ├── SageMakerEndpointConfigurationKMSKeyConfigured.ts │ │ ├── SageMakerNotebookInVPC.ts │ │ ├── SageMakerNotebookInstanceKMSKeyConfigured.ts │ │ ├── SageMakerNotebookNoDirectInternetAccess.ts │ │ └── index.ts │ ├── secretsmanager │ │ ├── SecretsManagerRotationEnabled.ts │ │ ├── SecretsManagerUsingKMSKey.ts │ │ └── index.ts │ ├── sns │ │ ├── SNSEncryptedKMS.ts │ │ ├── SNSRedrivePolicy.ts │ │ ├── SNSTopicSSLPublishOnly.ts │ │ └── index.ts │ ├── sqs │ │ ├── SQSQueueDLQ.ts │ │ ├── SQSQueueSSE.ts │ │ ├── SQSQueueSSLRequestsOnly.ts │ │ ├── SQSRedrivePolicy.ts │ │ └── index.ts │ ├── stepfunctions │ │ ├── StepFunctionStateMachineAllLogsToCloudWatch.ts │ │ ├── StepFunctionStateMachineXray.ts │ │ └── index.ts │ ├── timestream │ │ ├── TimestreamDatabaseCustomerManagedKey.ts │ │ └── index.ts │ ├── vpc │ │ ├── VPCDefaultSecurityGroupClosed.ts │ │ ├── VPCFlowLogsEnabled.ts │ │ ├── VPCNoNACLs.ts │ │ ├── VPCNoUnrestrictedRouteToIGW.ts │ │ ├── VPCSubnetAutoAssignPublicIpDisabled.ts │ │ └── index.ts │ └── waf │ │ ├── WAFv2LoggingEnabled.ts │ │ └── index.ts └── utils │ ├── flatten-cfn-reference.ts │ └── nag-suppression-helper.ts ├── test ├── Conditions.test.ts ├── Engine.test.ts ├── Loggers.test.ts ├── Packs.test.ts ├── rules │ ├── APIGW.test.ts │ ├── AppSync.test.ts │ ├── AutoScaling.test.ts │ ├── Cloud9.test.ts │ ├── CloudFront.test.ts │ ├── CloudTrail.test.ts │ ├── CloudWatch.test.ts │ ├── CodeBuild.test.ts │ ├── Cognito.test.ts │ ├── DMS.test.ts │ ├── DocumentDB.test.ts │ ├── DynamoDB.test.ts │ ├── EC2.test.ts │ ├── ECR.test.ts │ ├── ECS.test.ts │ ├── EFS.test.ts │ ├── EKS.test.ts │ ├── ELB.test.ts │ ├── EMR.test.ts │ ├── ElastiCache.test.ts │ ├── ElasticBeanstalk.test.ts │ ├── EventBridge.test.ts │ ├── Glue.test.ts │ ├── IAM.test.ts │ ├── KMS.test.ts │ ├── Kinesis.test.ts │ ├── Lambda.test.ts │ ├── Lex.test.ts │ ├── MSK.test.ts │ ├── MediaStore.test.ts │ ├── Neptune.test.ts │ ├── OpenSearch.test.ts │ ├── QuickSight.test.ts │ ├── RDS.test.ts │ ├── Redshift.test.ts │ ├── S3.test.ts │ ├── SNS.test.ts │ ├── SQS.test.ts │ ├── SageMaker.test.ts │ ├── SecretsManager.test.ts │ ├── StepFunctions.test.ts │ ├── Timestream.test.ts │ ├── VPC.test.ts │ ├── WAF.test.ts │ └── utils.ts ├── test-utils.ts └── utils │ └── flatten-cfn-reference.test.ts ├── tsconfig.dev.json └── yarn.lock /.devcontainer.json: -------------------------------------------------------------------------------- 1 | { 2 | "build": { 3 | "dockerfile": "./Dockerfile" 4 | }, 5 | "postCreateCommand": "( npx projen dev-container-setup ) && ( npx projen default )", 6 | "features": { 7 | "docker-in-docker": { 8 | "version": "latest" 9 | }, 10 | "ghcr.io/devcontainers/features/github-cli": { 11 | "version": "latest" 12 | } 13 | }, 14 | "//": "~~ Generated by projen. To modify, edit .projenrc.js and run \"npx projen\"." 15 | } 16 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # ~~ Generated by projen. To modify, edit .projenrc.js and run "npx projen". 2 | 3 | * text=auto eol=lf 4 | *.snap linguist-generated 5 | /.devcontainer.json linguist-generated 6 | /.eslintrc.json linguist-generated 7 | /.gitattributes linguist-generated 8 | /.github/pull_request_template.md linguist-generated 9 | /.github/workflows/auto-approve.yml linguist-generated 10 | /.github/workflows/build.yml linguist-generated 11 | /.github/workflows/pull-request-lint.yml linguist-generated 12 | /.github/workflows/release.yml linguist-generated 13 | /.github/workflows/upgrade-main.yml linguist-generated 14 | /.gitignore linguist-generated 15 | /.mergify.yml linguist-generated 16 | /.npmignore linguist-generated 17 | /.projen/** linguist-generated 18 | /.projen/deps.json linguist-generated 19 | /.projen/files.json linguist-generated 20 | /.projen/tasks.json linguist-generated 21 | /API.md linguist-generated 22 | /LICENSE linguist-generated 23 | /package.json linguist-generated 24 | /tsconfig.dev.json linguist-generated 25 | /yarn.lock linguist-generated -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/doc.yml: -------------------------------------------------------------------------------- 1 | name: Documentation Issue 2 | description: Issue in the reference documentation or developer guide 3 | title: 'doc: short issue description' 4 | labels: [documentation, needs-triage] 5 | body: 6 | - type: textarea 7 | id: issue 8 | attributes: 9 | label: Describe your issue? 10 | validations: 11 | required: true 12 | 13 | - type: markdown 14 | attributes: 15 | value: | 16 | --- 17 | 18 | This is a 📕 documentation issue 19 | -------------------------------------------------------------------------------- /.github/pull_request_template.md: -------------------------------------------------------------------------------- 1 | Fixes # -------------------------------------------------------------------------------- /.github/workflows/auto-approve.yml: -------------------------------------------------------------------------------- 1 | # ~~ Generated by projen. To modify, edit .projenrc.js and run "npx projen". 2 | 3 | name: auto-approve 4 | on: 5 | pull_request_target: 6 | types: 7 | - labeled 8 | - opened 9 | - synchronize 10 | - reopened 11 | - ready_for_review 12 | jobs: 13 | approve: 14 | runs-on: ubuntu-latest 15 | permissions: 16 | pull-requests: write 17 | if: contains(github.event.pull_request.labels.*.name, 'auto-approve') && (github.event.pull_request.user.login == 'cdklabs-automation' || github.event.pull_request.user.login == 'dontirun') 18 | steps: 19 | - uses: hmarr/auto-approve-action@f0939ea97e9205ef24d872e76833fa908a770363 20 | with: 21 | github-token: ${{ secrets.GITHUB_TOKEN }} 22 | -------------------------------------------------------------------------------- /.github/workflows/pull-request-lint.yml: -------------------------------------------------------------------------------- 1 | # ~~ Generated by projen. To modify, edit .projenrc.js and run "npx projen". 2 | 3 | name: pull-request-lint 4 | on: 5 | pull_request_target: 6 | types: 7 | - labeled 8 | - opened 9 | - synchronize 10 | - reopened 11 | - ready_for_review 12 | - edited 13 | merge_group: {} 14 | jobs: 15 | validate: 16 | name: Validate PR title 17 | runs-on: ubuntu-latest 18 | permissions: 19 | pull-requests: write 20 | if: (github.event_name == 'pull_request' || github.event_name == 'pull_request_target') 21 | steps: 22 | - uses: amannn/action-semantic-pull-request@v6 23 | env: 24 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 25 | with: 26 | types: |- 27 | feat 28 | fix 29 | chore 30 | requireScope: false 31 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # ~~ Generated by projen. To modify, edit .projenrc.js and run "npx projen". 2 | !/.gitattributes 3 | !/.projen/tasks.json 4 | !/.projen/deps.json 5 | !/.projen/files.json 6 | !/.github/workflows/pull-request-lint.yml 7 | !/.github/workflows/auto-approve.yml 8 | !/package.json 9 | !/LICENSE 10 | !/.npmignore 11 | logs 12 | *.log 13 | npm-debug.log* 14 | yarn-debug.log* 15 | yarn-error.log* 16 | lerna-debug.log* 17 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 18 | pids 19 | *.pid 20 | *.seed 21 | *.pid.lock 22 | lib-cov 23 | coverage 24 | *.lcov 25 | .nyc_output 26 | build/Release 27 | node_modules/ 28 | jspm_packages/ 29 | *.tsbuildinfo 30 | .eslintcache 31 | *.tgz 32 | .yarn-integrity 33 | .cache 34 | .vscode 35 | **/.DS_Store 36 | /test-reports/ 37 | junit.xml 38 | /coverage/ 39 | !/.github/workflows/build.yml 40 | /dist/changelog.md 41 | /dist/version.txt 42 | !/.github/workflows/release.yml 43 | !/.mergify.yml 44 | !/.github/workflows/upgrade-main.yml 45 | !/.github/pull_request_template.md 46 | !/test/ 47 | !/tsconfig.dev.json 48 | !/src/ 49 | /lib 50 | /dist/ 51 | !/.eslintrc.json 52 | .jsii 53 | tsconfig.json 54 | !/API.md 55 | !/.devcontainer.json 56 | !/.projenrc.js 57 | -------------------------------------------------------------------------------- /.mergify.yml: -------------------------------------------------------------------------------- 1 | # ~~ Generated by projen. To modify, edit .projenrc.js and run "npx projen". 2 | 3 | queue_rules: 4 | - name: default 5 | update_method: merge 6 | queue_conditions: 7 | - "#approved-reviews-by>=1" 8 | - -label~=(do-not-merge) 9 | - status-success=build 10 | - status-success=package-js 11 | - status-success=package-java 12 | - status-success=package-python 13 | - status-success=package-dotnet 14 | - status-success=package-go 15 | merge_method: squash 16 | commit_message_template: |- 17 | {{ title }} (#{{ number }}) 18 | 19 | {{ body }} 20 | pull_request_rules: 21 | - name: Automatic merge on approval and successful build 22 | actions: 23 | delete_head_branch: {} 24 | queue: 25 | name: default 26 | conditions: 27 | - "#approved-reviews-by>=1" 28 | - -label~=(do-not-merge) 29 | - status-success=build 30 | - status-success=package-js 31 | - status-success=package-java 32 | - status-success=package-python 33 | - status-success=package-dotnet 34 | - status-success=package-go 35 | merge_queue: 36 | max_parallel_checks: 1 37 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | # ~~ Generated by projen. To modify, edit .projenrc.js and run "npx projen". 2 | /.projen/ 3 | /test-reports/ 4 | junit.xml 5 | /coverage/ 6 | permissions-backup.acl 7 | /dist/changelog.md 8 | /dist/version.txt 9 | /.mergify.yml 10 | /test/ 11 | /tsconfig.dev.json 12 | /src/ 13 | !/lib/ 14 | !/lib/**/*.js 15 | !/lib/**/*.d.ts 16 | dist 17 | /tsconfig.json 18 | /.github/ 19 | /.vscode/ 20 | /.idea/ 21 | /.projenrc.js 22 | tsconfig.tsbuildinfo 23 | /.eslintrc.json 24 | !.jsii 25 | /.gitattributes 26 | -------------------------------------------------------------------------------- /.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | # Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | # SPDX-License-Identifier: Apache-2.0 3 | repos: 4 | - repo: https://github.com/pre-commit/pre-commit-hooks 5 | rev: v4.0.1 6 | hooks: 7 | - id: check-json 8 | - id: trailing-whitespace 9 | exclude: ^API.md||.github/$ 10 | - repo: https://github.com/pre-commit/mirrors-eslint 11 | rev: v8.56.0 12 | hooks: 13 | - id: eslint 14 | files: \.[jt]sx?$ 15 | types: [file] 16 | - repo: https://github.com/pre-commit/mirrors-prettier 17 | rev: 'v2.3.2' 18 | hooks: 19 | - id: prettier 20 | exclude: | 21 | (?x)( 22 | ^.github/| 23 | ^.projen/| 24 | ^.mergify.yml| 25 | ^.*.json | 26 | ^API.md 27 | ) 28 | - repo: https://github.com/dontirun/text-prepender 29 | rev: v0.1.0 30 | hooks: 31 | - id: text-prepender 32 | exclude: | 33 | (?x)( 34 | ^.github/| 35 | ^.projen/| 36 | ^.mergify.yml| 37 | ^.*.json | 38 | ^API.md 39 | ) 40 | -------------------------------------------------------------------------------- /.projen/files.json: -------------------------------------------------------------------------------- 1 | { 2 | "files": [ 3 | ".devcontainer.json", 4 | ".eslintrc.json", 5 | ".gitattributes", 6 | ".github/pull_request_template.md", 7 | ".github/workflows/auto-approve.yml", 8 | ".github/workflows/build.yml", 9 | ".github/workflows/pull-request-lint.yml", 10 | ".github/workflows/release.yml", 11 | ".github/workflows/upgrade-main.yml", 12 | ".gitignore", 13 | ".mergify.yml", 14 | ".projen/deps.json", 15 | ".projen/files.json", 16 | ".projen/tasks.json", 17 | "LICENSE", 18 | "tsconfig.dev.json" 19 | ], 20 | "//": "~~ Generated by projen. To modify, edit .projenrc.js and run \"npx projen\"." 21 | } 22 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | 5 | 6 | ## Code of Conduct 7 | 8 | This project has adopted the [Amazon Open Source Code of Conduct](https://aws.github.io/code-of-conduct). 9 | For more information see the [Code of Conduct FAQ](https://aws.github.io/code-of-conduct-faq) or contact 10 | opensource-codeofconduct@amazon.com with any additional questions or comments. 11 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM jsii/superchain:1-buster-slim-node20 2 | 3 | USER root 4 | 5 | # Change uid/guid of superchain so it can work with the docker-in-docker feature 6 | RUN groupmod --gid 1000 superchain \ 7 | && usermod --uid 1000 --gid 1000 superchain \ 8 | && chown -R 1000:1000 /home/superchain 9 | 10 | # Setup dependencies 11 | RUN yarn install 12 | RUN chmod -R 777 node_modules 13 | 14 | # Setup pre-commit 15 | RUN python3 -m pip install pre-commit 16 | 17 | USER superchain 18 | 19 | # Setup oh-my-zsh 20 | RUN sudo apt-get update && export DEBIAN_FRONTEND=noninteractive \ 21 | && sudo apt-get -y install --no-install-recommends zsh vim git-all \ 22 | && sudo rm -rf /var/lib/apt/lists/* \ 23 | && sudo chsh -s $(which zsh) $(whoami) 24 | RUN sh -c "$(curl -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh)" "" --unattended \ 25 | && sudo sh -c 'echo "[oh-my-zsh]\n hide-dirty = 1" > /etc/gitconfig' -------------------------------------------------------------------------------- /NOTICE: -------------------------------------------------------------------------------- 1 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | SPDX-License-Identifier: Apache-2.0 3 | -------------------------------------------------------------------------------- /cdk_nag.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cdklabs/cdk-nag/160aa75e794ad9e371620e2512e471d3f79a57d3/cdk_nag.gif -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | export * from './ignore-suppression-conditions'; 6 | export * from './models/nag-suppression'; 7 | export * from './nag-logger'; 8 | export * from './nag-pack'; 9 | export * from './nag-rules'; 10 | export * from './nag-suppressions'; 11 | export * from './packs/aws-solutions'; 12 | export * from './packs/hipaa-security'; 13 | export * from './packs/nist-800-53-r4'; 14 | export * from './packs/nist-800-53-r5'; 15 | export * from './packs/pci-dss-321'; 16 | export * from './packs/serverless'; 17 | export * as rules from './rules'; 18 | -------------------------------------------------------------------------------- /src/models/nag-suppression.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | 6 | /** 7 | * Interface for creating a rule suppression 8 | */ 9 | export interface NagPackSuppression { 10 | /** 11 | * The id of the rule to ignore 12 | */ 13 | readonly id: string; 14 | /** 15 | * The reason to ignore the rule (minimum 10 characters) 16 | */ 17 | readonly reason: string; 18 | /** 19 | * Rule specific granular suppressions 20 | */ 21 | readonly appliesTo?: NagPackSuppressionAppliesTo[]; 22 | } 23 | 24 | /** 25 | * A granular suppression 26 | */ 27 | export type NagPackSuppressionAppliesTo = string | RegexAppliesTo; 28 | 29 | /** 30 | * A regular expression to apply to matching findings 31 | */ 32 | export interface RegexAppliesTo { 33 | /** 34 | * An ECMA-262 regex string 35 | */ 36 | readonly regex: string; 37 | } 38 | -------------------------------------------------------------------------------- /src/rules/apigw/APIGWCacheEnabledAndEncrypted.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { parse } from 'path'; 6 | import { CfnResource, Stack } from 'aws-cdk-lib'; 7 | import { CfnStage } from 'aws-cdk-lib/aws-apigateway'; 8 | import { NagRuleCompliance } from '../../nag-rules'; 9 | 10 | /** 11 | * All methods in API Gateway stages have caching enabled and encrypted 12 | * @param node the CfnResource to check 13 | */ 14 | export default Object.defineProperty( 15 | (node: CfnResource): NagRuleCompliance => { 16 | if (node instanceof CfnStage) { 17 | if (node.methodSettings == undefined) { 18 | return NagRuleCompliance.NON_COMPLIANT; 19 | } 20 | const methodSettings = Stack.of(node).resolve(node.methodSettings); 21 | let found = false; 22 | for (const setting of methodSettings) { 23 | const resolvedSetting = Stack.of(node).resolve(setting); 24 | if ( 25 | resolvedSetting?.httpMethod == '*' && 26 | resolvedSetting?.resourcePath == '/*' && 27 | resolvedSetting?.cacheDataEncrypted && 28 | resolvedSetting?.cachingEnabled 29 | ) { 30 | found = true; 31 | break; 32 | } 33 | } 34 | if (!found) { 35 | return NagRuleCompliance.NON_COMPLIANT; 36 | } 37 | return NagRuleCompliance.COMPLIANT; 38 | } else { 39 | return NagRuleCompliance.NOT_APPLICABLE; 40 | } 41 | }, 42 | 'name', 43 | { value: parse(__filename).name } 44 | ); 45 | -------------------------------------------------------------------------------- /src/rules/apigw/APIGWExecutionLoggingEnabled.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { parse } from 'path'; 6 | import { CfnResource, Stack } from 'aws-cdk-lib'; 7 | import { CfnStage, MethodLoggingLevel } from 'aws-cdk-lib/aws-apigateway'; 8 | import { NagRuleCompliance } from '../../nag-rules'; 9 | 10 | /** 11 | * API Gateway stages have logging enabled 12 | * @param node the CfnResource to check 13 | */ 14 | export default Object.defineProperty( 15 | (node: CfnResource): NagRuleCompliance => { 16 | if (node instanceof CfnStage) { 17 | if (node.methodSettings == undefined) { 18 | return NagRuleCompliance.NON_COMPLIANT; 19 | } 20 | const methodSettings = Stack.of(node).resolve(node.methodSettings); 21 | let found = false; 22 | for (const setting of methodSettings) { 23 | const resolvedSetting = Stack.of(node).resolve(setting); 24 | if ( 25 | resolvedSetting?.httpMethod == '*' && 26 | resolvedSetting?.resourcePath == '/*' && 27 | (resolvedSetting?.loggingLevel == MethodLoggingLevel.ERROR || 28 | resolvedSetting?.loggingLevel == MethodLoggingLevel.INFO) 29 | ) { 30 | found = true; 31 | break; 32 | } 33 | } 34 | if (!found) { 35 | return NagRuleCompliance.NON_COMPLIANT; 36 | } 37 | return NagRuleCompliance.COMPLIANT; 38 | } else { 39 | return NagRuleCompliance.NOT_APPLICABLE; 40 | } 41 | }, 42 | 'name', 43 | { value: parse(__filename).name } 44 | ); 45 | -------------------------------------------------------------------------------- /src/rules/apigw/APIGWSSLEnabled.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { parse } from 'path'; 6 | import { CfnResource } from 'aws-cdk-lib'; 7 | import { CfnStage } from 'aws-cdk-lib/aws-apigateway'; 8 | import { NagRuleCompliance } from '../../nag-rules'; 9 | 10 | /** 11 | * API Gateway REST API stages are configured with SSL certificates 12 | * @param node the CfnResource to check 13 | */ 14 | export default Object.defineProperty( 15 | (node: CfnResource): NagRuleCompliance => { 16 | if (node instanceof CfnStage) { 17 | if (node.clientCertificateId == undefined) { 18 | return NagRuleCompliance.NON_COMPLIANT; 19 | } 20 | return NagRuleCompliance.COMPLIANT; 21 | } else { 22 | return NagRuleCompliance.NOT_APPLICABLE; 23 | } 24 | }, 25 | 'name', 26 | { value: parse(__filename).name } 27 | ); 28 | -------------------------------------------------------------------------------- /src/rules/apigw/APIGWXrayEnabled.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { parse } from 'path'; 6 | import { CfnResource } from 'aws-cdk-lib'; 7 | import { CfnStage } from 'aws-cdk-lib/aws-apigateway'; 8 | import { NagRuleCompliance, NagRules } from '../../nag-rules'; 9 | /** 10 | * API Gateway REST API stages have X-Ray tracing enabled 11 | * @param node the CfnResource to check 12 | */ 13 | export default Object.defineProperty( 14 | (node: CfnResource): NagRuleCompliance => { 15 | if (node instanceof CfnStage) { 16 | const tracingEnabled = NagRules.resolveIfPrimitive( 17 | node, 18 | node.tracingEnabled 19 | ); 20 | if (tracingEnabled !== true) { 21 | return NagRuleCompliance.NON_COMPLIANT; 22 | } 23 | return NagRuleCompliance.COMPLIANT; 24 | } else { 25 | return NagRuleCompliance.NOT_APPLICABLE; 26 | } 27 | }, 28 | 'name', 29 | { value: parse(__filename).name } 30 | ); 31 | -------------------------------------------------------------------------------- /src/rules/apigw/index.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | export { default as APIGWAccessLogging } from './APIGWAccessLogging'; 6 | export { default as APIGWAssociatedWithWAF } from './APIGWAssociatedWithWAF'; 7 | export { default as APIGWAuthorization } from './APIGWAuthorization'; 8 | export { default as APIGWCacheEnabledAndEncrypted } from './APIGWCacheEnabledAndEncrypted'; 9 | export { default as APIGWExecutionLoggingEnabled } from './APIGWExecutionLoggingEnabled'; 10 | export { default as APIGWRequestValidation } from './APIGWRequestValidation'; 11 | export { default as APIGWSSLEnabled } from './APIGWSSLEnabled'; 12 | export { default as APIGWXrayEnabled } from './APIGWXrayEnabled'; 13 | export { default as APIGWStructuredLogging } from './APIGWStructuredLogging'; 14 | export { default as APIGWDefaultThrottling } from './APIGWDefaultThrottling'; 15 | -------------------------------------------------------------------------------- /src/rules/appsync/AppSyncGraphQLRequestLogging.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { parse } from 'path'; 6 | import { CfnResource, Stack } from 'aws-cdk-lib'; 7 | import { CfnGraphQLApi } from 'aws-cdk-lib/aws-appsync'; 8 | import { NagRuleCompliance, NagRules } from '../../nag-rules'; 9 | 10 | /** 11 | * GraphQL APIs have request leveling logging enabled 12 | * @param node the CfnResource to check 13 | */ 14 | export default Object.defineProperty( 15 | (node: CfnResource): NagRuleCompliance => { 16 | if (node instanceof CfnGraphQLApi) { 17 | const logConfig = Stack.of(node).resolve(node.logConfig); 18 | if (logConfig === undefined) { 19 | return NagRuleCompliance.NON_COMPLIANT; 20 | } 21 | const excludeVerboseContent = NagRules.resolveIfPrimitive( 22 | node, 23 | logConfig.excludeVerboseContent 24 | ); 25 | if ( 26 | logConfig.cloudWatchLogsRoleArn === undefined || 27 | excludeVerboseContent === true 28 | ) { 29 | return NagRuleCompliance.NON_COMPLIANT; 30 | } 31 | return NagRuleCompliance.COMPLIANT; 32 | } else { 33 | return NagRuleCompliance.NOT_APPLICABLE; 34 | } 35 | }, 36 | 'name', 37 | { value: parse(__filename).name } 38 | ); 39 | -------------------------------------------------------------------------------- /src/rules/appsync/AppSyncTracing.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { parse } from 'path'; 6 | import { CfnResource, Stack } from 'aws-cdk-lib'; 7 | import { CfnGraphQLApi } from 'aws-cdk-lib/aws-appsync'; 8 | import { NagRuleCompliance } from '../../nag-rules'; 9 | 10 | /** 11 | * AppSync APIs have tracing enabled 12 | * @param node the CfnResource to check 13 | */ 14 | export default Object.defineProperty( 15 | (node: CfnResource): NagRuleCompliance => { 16 | if (node instanceof CfnGraphQLApi) { 17 | const isXrayEnabled = Stack.of(node).resolve(node.xrayEnabled); 18 | if (isXrayEnabled) return NagRuleCompliance.COMPLIANT; 19 | return NagRuleCompliance.NON_COMPLIANT; 20 | } 21 | return NagRuleCompliance.NOT_APPLICABLE; 22 | }, 23 | 'name', 24 | { value: parse(__filename).name } 25 | ); 26 | -------------------------------------------------------------------------------- /src/rules/appsync/index.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | export { default as AppSyncGraphQLRequestLogging } from './AppSyncGraphQLRequestLogging'; 6 | export { default as AppSyncTracing } from './AppSyncTracing'; 7 | -------------------------------------------------------------------------------- /src/rules/autoscaling/AutoScalingGroupCooldownPeriod.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { parse } from 'path'; 6 | import { CfnResource } from 'aws-cdk-lib'; 7 | import { CfnAutoScalingGroup } from 'aws-cdk-lib/aws-autoscaling'; 8 | import { NagRuleCompliance, NagRules } from '../../nag-rules'; 9 | 10 | /** 11 | * Auto Scaling Groups have configured cooldown periods 12 | * @param node the CfnResource to check 13 | */ 14 | export default Object.defineProperty( 15 | (node: CfnResource): NagRuleCompliance => { 16 | if (node instanceof CfnAutoScalingGroup) { 17 | const cooldown = NagRules.resolveIfPrimitive(node, node.cooldown); 18 | if (cooldown != undefined && parseInt(cooldown) == 0) { 19 | return NagRuleCompliance.NON_COMPLIANT; 20 | } 21 | return NagRuleCompliance.COMPLIANT; 22 | } else { 23 | return NagRuleCompliance.NOT_APPLICABLE; 24 | } 25 | }, 26 | 'name', 27 | { value: parse(__filename).name } 28 | ); 29 | -------------------------------------------------------------------------------- /src/rules/autoscaling/AutoScalingGroupELBHealthCheckRequired.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { parse } from 'path'; 6 | import { CfnResource, Stack } from 'aws-cdk-lib'; 7 | import { CfnAutoScalingGroup } from 'aws-cdk-lib/aws-autoscaling'; 8 | import { NagRuleCompliance, NagRules } from '../../nag-rules'; 9 | /** 10 | * Auto Scaling groups which are associated with load balancers utilize ELB health checks 11 | * @param node the CfnResource to check 12 | */ 13 | export default Object.defineProperty( 14 | (node: CfnResource): NagRuleCompliance => { 15 | if (node instanceof CfnAutoScalingGroup) { 16 | const classicLBs = Stack.of(node).resolve(node.loadBalancerNames); 17 | const otherLBs = Stack.of(node).resolve(node.targetGroupArns); 18 | if ( 19 | (otherLBs != undefined && otherLBs.length > 0) || 20 | (classicLBs != undefined && classicLBs.length > 0) 21 | ) { 22 | const healthCheckType = NagRules.resolveIfPrimitive( 23 | node, 24 | node.healthCheckType 25 | ); 26 | if (healthCheckType != undefined) { 27 | if (healthCheckType != 'ELB') { 28 | return NagRuleCompliance.NON_COMPLIANT; 29 | } 30 | } else { 31 | return NagRuleCompliance.NON_COMPLIANT; 32 | } 33 | } 34 | return NagRuleCompliance.COMPLIANT; 35 | } else { 36 | return NagRuleCompliance.NOT_APPLICABLE; 37 | } 38 | }, 39 | 'name', 40 | { value: parse(__filename).name } 41 | ); 42 | -------------------------------------------------------------------------------- /src/rules/autoscaling/AutoScalingGroupHealthCheck.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { parse } from 'path'; 6 | import { CfnResource } from 'aws-cdk-lib'; 7 | import { CfnAutoScalingGroup } from 'aws-cdk-lib/aws-autoscaling'; 8 | import { NagRuleCompliance, NagRules } from '../../nag-rules'; 9 | 10 | /** 11 | * Auto Scaling Groups have properly configured health checks 12 | * @param node the CfnResource to check 13 | */ 14 | export default Object.defineProperty( 15 | (node: CfnResource): NagRuleCompliance => { 16 | if (node instanceof CfnAutoScalingGroup) { 17 | const healthCheckType = NagRules.resolveIfPrimitive( 18 | node, 19 | node.healthCheckType 20 | ); 21 | const healthCheckGracePeriod = NagRules.resolveIfPrimitive( 22 | node, 23 | node.healthCheckGracePeriod 24 | ); 25 | if ( 26 | healthCheckType != undefined && 27 | healthCheckType == 'ELB' && 28 | healthCheckGracePeriod == undefined 29 | ) { 30 | return NagRuleCompliance.NON_COMPLIANT; 31 | } 32 | return NagRuleCompliance.COMPLIANT; 33 | } else { 34 | return NagRuleCompliance.NOT_APPLICABLE; 35 | } 36 | }, 37 | 'name', 38 | { value: parse(__filename).name } 39 | ); 40 | -------------------------------------------------------------------------------- /src/rules/autoscaling/AutoScalingLaunchConfigPublicIpDisabled.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { parse } from 'path'; 6 | import { CfnResource } from 'aws-cdk-lib'; 7 | import { CfnLaunchConfiguration } from 'aws-cdk-lib/aws-autoscaling'; 8 | import { NagRuleCompliance, NagRules } from '../../nag-rules'; 9 | /** 10 | * Auto Scaling launch configurations have public IP addresses disabled 11 | * @param node the CfnResource to check 12 | */ 13 | export default Object.defineProperty( 14 | (node: CfnResource): NagRuleCompliance => { 15 | if (node instanceof CfnLaunchConfiguration) { 16 | const associatePublicIpAddress = NagRules.resolveIfPrimitive( 17 | node, 18 | node.associatePublicIpAddress 19 | ); 20 | if (associatePublicIpAddress !== false) { 21 | return NagRuleCompliance.NON_COMPLIANT; 22 | } 23 | return NagRuleCompliance.COMPLIANT; 24 | } else { 25 | return NagRuleCompliance.NOT_APPLICABLE; 26 | } 27 | }, 28 | 'name', 29 | { value: parse(__filename).name } 30 | ); 31 | -------------------------------------------------------------------------------- /src/rules/autoscaling/index.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | export { default as AutoScalingGroupCooldownPeriod } from './AutoScalingGroupCooldownPeriod'; 6 | export { default as AutoScalingGroupELBHealthCheckRequired } from './AutoScalingGroupELBHealthCheckRequired'; 7 | export { default as AutoScalingGroupHealthCheck } from './AutoScalingGroupHealthCheck'; 8 | export { default as AutoScalingGroupScalingNotifications } from './AutoScalingGroupScalingNotifications'; 9 | export { default as AutoScalingLaunchConfigPublicIpDisabled } from './AutoScalingLaunchConfigPublicIpDisabled'; 10 | -------------------------------------------------------------------------------- /src/rules/cloud9/Cloud9InstanceNoIngressSystemsManager.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { parse } from 'path'; 6 | import { CfnResource } from 'aws-cdk-lib'; 7 | import { CfnEnvironmentEC2 } from 'aws-cdk-lib/aws-cloud9'; 8 | import { NagRuleCompliance, NagRules } from '../../nag-rules'; 9 | 10 | /** 11 | * Cloud9 instances use no-ingress EC2 instances with AWS Systems Manager 12 | * @param node the CfnResource to check 13 | */ 14 | export default Object.defineProperty( 15 | (node: CfnResource): NagRuleCompliance => { 16 | if (node instanceof CfnEnvironmentEC2) { 17 | const connectionType = NagRules.resolveIfPrimitive( 18 | node, 19 | node.connectionType 20 | ); 21 | if (connectionType == undefined || connectionType != 'CONNECT_SSM') { 22 | return NagRuleCompliance.NON_COMPLIANT; 23 | } 24 | return NagRuleCompliance.COMPLIANT; 25 | } else { 26 | return NagRuleCompliance.NOT_APPLICABLE; 27 | } 28 | }, 29 | 'name', 30 | { value: parse(__filename).name } 31 | ); 32 | -------------------------------------------------------------------------------- /src/rules/cloud9/index.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | export { default as Cloud9InstanceNoIngressSystemsManager } from './Cloud9InstanceNoIngressSystemsManager'; 6 | -------------------------------------------------------------------------------- /src/rules/cloudfront/CloudFrontDistributionGeoRestrictions.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { parse } from 'path'; 6 | import { CfnResource, Stack } from 'aws-cdk-lib'; 7 | import { CfnDistribution } from 'aws-cdk-lib/aws-cloudfront'; 8 | import { NagRuleCompliance, NagRules } from '../../nag-rules'; 9 | 10 | /** 11 | * CloudFront distributions may require Geo restrictions 12 | * @param node the CfnResource to check 13 | */ 14 | export default Object.defineProperty( 15 | (node: CfnResource): NagRuleCompliance => { 16 | if (node instanceof CfnDistribution) { 17 | const distributionConfig = Stack.of(node).resolve( 18 | node.distributionConfig 19 | ); 20 | if (distributionConfig.restrictions == undefined) { 21 | return NagRuleCompliance.NON_COMPLIANT; 22 | } else { 23 | const restrictions = Stack.of(node).resolve( 24 | distributionConfig.restrictions 25 | ); 26 | const geoRestrictions = Stack.of(node).resolve( 27 | restrictions.geoRestriction 28 | ); 29 | const restrictionType = NagRules.resolveIfPrimitive( 30 | node, 31 | geoRestrictions.restrictionType 32 | ); 33 | if (restrictionType == 'none') { 34 | return NagRuleCompliance.NON_COMPLIANT; 35 | } 36 | } 37 | return NagRuleCompliance.COMPLIANT; 38 | } else { 39 | return NagRuleCompliance.NOT_APPLICABLE; 40 | } 41 | }, 42 | 'name', 43 | { value: parse(__filename).name } 44 | ); 45 | -------------------------------------------------------------------------------- /src/rules/cloudfront/CloudFrontDistributionS3OriginAccessIdentity.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { parse } from 'path'; 6 | import { CfnResource, Stack } from 'aws-cdk-lib'; 7 | import { CfnStreamingDistribution } from 'aws-cdk-lib/aws-cloudfront'; 8 | import { NagRuleCompliance } from '../../nag-rules'; 9 | 10 | /** 11 | * CloudFront Streaming distributions use an origin access identity for S3 origins 12 | * Only applying to CloudFront Streaming distributions because CloudFront distributions should use origin access control instead 13 | * @param node the CfnResource to check 14 | */ 15 | export default Object.defineProperty( 16 | (node: CfnResource): NagRuleCompliance => { 17 | if (node instanceof CfnStreamingDistribution) { 18 | const distributionConfig = Stack.of(node).resolve( 19 | node.streamingDistributionConfig 20 | ); 21 | const resolvedOrigin = Stack.of(node).resolve( 22 | distributionConfig.s3Origin 23 | ); 24 | if (resolvedOrigin.originAccessIdentity.replace(/\s/g, '').length == 0) { 25 | return NagRuleCompliance.NON_COMPLIANT; 26 | } 27 | return NagRuleCompliance.COMPLIANT; 28 | } else { 29 | return NagRuleCompliance.NOT_APPLICABLE; 30 | } 31 | }, 32 | 'name', 33 | { value: parse(__filename).name } 34 | ); 35 | -------------------------------------------------------------------------------- /src/rules/cloudfront/CloudFrontDistributionWAFIntegration.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { parse } from 'path'; 6 | import { CfnResource, Stack } from 'aws-cdk-lib'; 7 | import { CfnDistribution } from 'aws-cdk-lib/aws-cloudfront'; 8 | import { NagRuleCompliance } from '../../nag-rules'; 9 | 10 | /** 11 | * CloudFront distributions may require integration with AWS WAF 12 | * @param node the CfnResource to check 13 | */ 14 | export default Object.defineProperty( 15 | (node: CfnResource): NagRuleCompliance => { 16 | if (node instanceof CfnDistribution) { 17 | const distributionConfig = Stack.of(node).resolve( 18 | node.distributionConfig 19 | ); 20 | if (distributionConfig.webAclId == undefined) { 21 | return NagRuleCompliance.NON_COMPLIANT; 22 | } 23 | return NagRuleCompliance.COMPLIANT; 24 | } else { 25 | return NagRuleCompliance.NOT_APPLICABLE; 26 | } 27 | }, 28 | 'name', 29 | { value: parse(__filename).name } 30 | ); 31 | -------------------------------------------------------------------------------- /src/rules/cloudfront/index.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | export { default as CloudFrontDistributionAccessLogging } from './CloudFrontDistributionAccessLogging'; 6 | export { default as CloudFrontDistributionGeoRestrictions } from './CloudFrontDistributionGeoRestrictions'; 7 | export { default as CloudFrontDistributionHttpsViewerNoOutdatedSSL } from './CloudFrontDistributionHttpsViewerNoOutdatedSSL'; 8 | export { default as CloudFrontDistributionNoOutdatedSSL } from './CloudFrontDistributionNoOutdatedSSL'; 9 | export { default as CloudFrontDistributionS3OriginAccessIdentity } from './CloudFrontDistributionS3OriginAccessIdentity'; 10 | export { default as CloudFrontDistributionWAFIntegration } from './CloudFrontDistributionWAFIntegration'; 11 | export { default as CloudFrontDistributionS3OriginAccessControl } from './CloudFrontDistributionS3OriginAccessControl'; 12 | -------------------------------------------------------------------------------- /src/rules/cloudtrail/CloudTrailCloudWatchLogsEnabled.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { parse } from 'path'; 6 | import { CfnResource, Stack } from 'aws-cdk-lib'; 7 | import { CfnTrail } from 'aws-cdk-lib/aws-cloudtrail'; 8 | import { NagRuleCompliance } from '../../nag-rules'; 9 | 10 | /** 11 | * CloudTrail trails have CloudWatch logs enabled 12 | * @param node the CfnResource to check 13 | */ 14 | export default Object.defineProperty( 15 | (node: CfnResource): NagRuleCompliance => { 16 | if (node instanceof CfnTrail) { 17 | const cloudWatch = Stack.of(node).resolve(node.cloudWatchLogsLogGroupArn); 18 | 19 | if (cloudWatch == undefined) { 20 | return NagRuleCompliance.NON_COMPLIANT; 21 | } 22 | return NagRuleCompliance.COMPLIANT; 23 | } else { 24 | return NagRuleCompliance.NOT_APPLICABLE; 25 | } 26 | }, 27 | 'name', 28 | { value: parse(__filename).name } 29 | ); 30 | -------------------------------------------------------------------------------- /src/rules/cloudtrail/CloudTrailEncryptionEnabled.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { parse } from 'path'; 6 | import { CfnResource, Stack } from 'aws-cdk-lib'; 7 | import { CfnTrail } from 'aws-cdk-lib/aws-cloudtrail'; 8 | import { NagRuleCompliance } from '../../nag-rules'; 9 | 10 | /** 11 | * CloudTrail trails have encryption enabled 12 | * @param node the CfnResource to check 13 | */ 14 | export default Object.defineProperty( 15 | (node: CfnResource): NagRuleCompliance => { 16 | if (node instanceof CfnTrail) { 17 | const keyID = Stack.of(node).resolve(node.kmsKeyId); 18 | 19 | if (keyID == undefined) { 20 | return NagRuleCompliance.NON_COMPLIANT; 21 | } 22 | return NagRuleCompliance.COMPLIANT; 23 | } else { 24 | return NagRuleCompliance.NOT_APPLICABLE; 25 | } 26 | }, 27 | 'name', 28 | { value: parse(__filename).name } 29 | ); 30 | -------------------------------------------------------------------------------- /src/rules/cloudtrail/CloudTrailLogFileValidationEnabled.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { parse } from 'path'; 6 | import { CfnResource } from 'aws-cdk-lib'; 7 | import { CfnTrail } from 'aws-cdk-lib/aws-cloudtrail'; 8 | import { NagRuleCompliance, NagRules } from '../../nag-rules'; 9 | /** 10 | * CloudTrail trails have log file validation enabled 11 | * @param node the CfnResource to check 12 | */ 13 | export default Object.defineProperty( 14 | (node: CfnResource): NagRuleCompliance => { 15 | if (node instanceof CfnTrail) { 16 | const enabled = NagRules.resolveIfPrimitive( 17 | node, 18 | node.enableLogFileValidation 19 | ); 20 | 21 | if (enabled != true) { 22 | return NagRuleCompliance.NON_COMPLIANT; 23 | } 24 | return NagRuleCompliance.COMPLIANT; 25 | } else { 26 | return NagRuleCompliance.NOT_APPLICABLE; 27 | } 28 | }, 29 | 'name', 30 | { value: parse(__filename).name } 31 | ); 32 | -------------------------------------------------------------------------------- /src/rules/cloudtrail/index.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | export { default as CloudTrailCloudWatchLogsEnabled } from './CloudTrailCloudWatchLogsEnabled'; 6 | export { default as CloudTrailEncryptionEnabled } from './CloudTrailEncryptionEnabled'; 7 | export { default as CloudTrailLogFileValidationEnabled } from './CloudTrailLogFileValidationEnabled'; 8 | -------------------------------------------------------------------------------- /src/rules/cloudwatch/CloudWatchLogGroupEncrypted.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { parse } from 'path'; 6 | import { CfnResource } from 'aws-cdk-lib'; 7 | import { CfnLogGroup } from 'aws-cdk-lib/aws-logs'; 8 | import { NagRuleCompliance } from '../../nag-rules'; 9 | 10 | /** 11 | * CloudWatch Log Groups are encrypted with customer managed keys 12 | * @param node the CfnResource to check 13 | */ 14 | export default Object.defineProperty( 15 | (node: CfnResource): NagRuleCompliance => { 16 | if (node instanceof CfnLogGroup) { 17 | if (node.kmsKeyId == undefined) { 18 | return NagRuleCompliance.NON_COMPLIANT; 19 | } 20 | return NagRuleCompliance.COMPLIANT; 21 | } else { 22 | return NagRuleCompliance.NOT_APPLICABLE; 23 | } 24 | }, 25 | 'name', 26 | { value: parse(__filename).name } 27 | ); 28 | -------------------------------------------------------------------------------- /src/rules/cloudwatch/CloudWatchLogGroupRetentionPeriod.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { parse } from 'path'; 6 | import { CfnResource } from 'aws-cdk-lib'; 7 | import { CfnLogGroup } from 'aws-cdk-lib/aws-logs'; 8 | import { NagRuleCompliance } from '../../nag-rules'; 9 | 10 | /** 11 | * CloudWatch Log Groups have an explicit retention period configured 12 | * @param node the CfnResource to check 13 | */ 14 | export default Object.defineProperty( 15 | (node: CfnResource): NagRuleCompliance => { 16 | if (node instanceof CfnLogGroup) { 17 | if (node.retentionInDays == undefined) { 18 | return NagRuleCompliance.NON_COMPLIANT; 19 | } 20 | return NagRuleCompliance.COMPLIANT; 21 | } else { 22 | return NagRuleCompliance.NOT_APPLICABLE; 23 | } 24 | }, 25 | 'name', 26 | { value: parse(__filename).name } 27 | ); 28 | -------------------------------------------------------------------------------- /src/rules/cloudwatch/index.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | export { default as CloudWatchAlarmAction } from './CloudWatchAlarmAction'; 6 | export { default as CloudWatchLogGroupEncrypted } from './CloudWatchLogGroupEncrypted'; 7 | export { default as CloudWatchLogGroupRetentionPeriod } from './CloudWatchLogGroupRetentionPeriod'; 8 | -------------------------------------------------------------------------------- /src/rules/codebuild/CodeBuildProjectKMSEncryptedArtifacts.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { parse } from 'path'; 6 | import { CfnResource, Stack } from 'aws-cdk-lib'; 7 | import { CfnProject } from 'aws-cdk-lib/aws-codebuild'; 8 | import { NagRuleCompliance } from '../../nag-rules'; 9 | 10 | /** 11 | * Codebuild projects use an AWS KMS key for encryption 12 | * @param node the CfnResource to check 13 | */ 14 | export default Object.defineProperty( 15 | (node: CfnResource): NagRuleCompliance => { 16 | if (node instanceof CfnProject) { 17 | const encryptionKey = Stack.of(node).resolve(node.encryptionKey); 18 | if (encryptionKey === undefined || encryptionKey === 'alias/aws/s3') { 19 | return NagRuleCompliance.NON_COMPLIANT; 20 | } 21 | return NagRuleCompliance.COMPLIANT; 22 | } else { 23 | return NagRuleCompliance.NOT_APPLICABLE; 24 | } 25 | }, 26 | 'name', 27 | { value: parse(__filename).name } 28 | ); 29 | -------------------------------------------------------------------------------- /src/rules/codebuild/CodeBuildProjectManagedImages.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { parse } from 'path'; 6 | import { CfnResource, Stack } from 'aws-cdk-lib'; 7 | import { CfnProject } from 'aws-cdk-lib/aws-codebuild'; 8 | import { NagRuleCompliance, NagRules } from '../../nag-rules'; 9 | 10 | /** 11 | * Codebuild projects use images provided by the CodeBuild service or have a cdk-nag suppression rule explaining the need for a custom image 12 | * @param node the CfnResource to check 13 | */ 14 | export default Object.defineProperty( 15 | (node: CfnResource): NagRuleCompliance => { 16 | if (node instanceof CfnProject) { 17 | const environment = Stack.of(node).resolve(node.environment); 18 | const image = NagRules.resolveIfPrimitive(node, environment.image); 19 | if (!image.startsWith('aws/codebuild/')) { 20 | return NagRuleCompliance.NON_COMPLIANT; 21 | } 22 | return NagRuleCompliance.COMPLIANT; 23 | } else { 24 | return NagRuleCompliance.NOT_APPLICABLE; 25 | } 26 | }, 27 | 'name', 28 | { value: parse(__filename).name } 29 | ); 30 | -------------------------------------------------------------------------------- /src/rules/codebuild/CodeBuildProjectSourceRepoUrl.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { parse } from 'path'; 6 | import { CfnResource, Stack } from 'aws-cdk-lib'; 7 | import { CfnProject } from 'aws-cdk-lib/aws-codebuild'; 8 | import { NagRuleCompliance, NagRules } from '../../nag-rules'; 9 | 10 | /** 11 | * Codebuild projects with a GitHub or BitBucket source repository utilize OAUTH 12 | * @param node the CfnResource to check 13 | */ 14 | export default Object.defineProperty( 15 | (node: CfnResource): NagRuleCompliance => { 16 | if (node instanceof CfnProject) { 17 | //Check for the presence of OAUTH 18 | const projectSource = Stack.of(node).resolve(node.source); 19 | const projectAuth = Stack.of(node).resolve(projectSource.auth); 20 | if (projectAuth == undefined) { 21 | return NagRuleCompliance.NON_COMPLIANT; 22 | } else { 23 | const projectAuthType = NagRules.resolveIfPrimitive( 24 | node, 25 | projectAuth.type 26 | ); 27 | if (projectAuthType != 'OAUTH') { 28 | return NagRuleCompliance.NON_COMPLIANT; 29 | } 30 | } 31 | return NagRuleCompliance.COMPLIANT; 32 | } else { 33 | return NagRuleCompliance.NOT_APPLICABLE; 34 | } 35 | }, 36 | 'name', 37 | { value: parse(__filename).name } 38 | ); 39 | -------------------------------------------------------------------------------- /src/rules/codebuild/index.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | export { default as CodeBuildProjectEnvVarAwsCred } from './CodeBuildProjectEnvVarAwsCred'; 6 | export { default as CodeBuildProjectKMSEncryptedArtifacts } from './CodeBuildProjectKMSEncryptedArtifacts'; 7 | export { default as CodeBuildProjectManagedImages } from './CodeBuildProjectManagedImages'; 8 | export { default as CodeBuildProjectSourceRepoUrl } from './CodeBuildProjectSourceRepoUrl'; 9 | -------------------------------------------------------------------------------- /src/rules/cognito/CognitoUserPoolAPIGWAuthorizer.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { parse } from 'path'; 6 | import { CfnResource } from 'aws-cdk-lib'; 7 | import { CfnMethod } from 'aws-cdk-lib/aws-apigateway'; 8 | import { NagRuleCompliance, NagRules } from '../../nag-rules'; 9 | 10 | /** 11 | * Rest API methods use Cognito User Pool Authorizers 12 | * @param node the CfnResource to check 13 | */ 14 | export default Object.defineProperty( 15 | (node: CfnResource): NagRuleCompliance => { 16 | if (node instanceof CfnMethod) { 17 | const httpMethod = NagRules.resolveIfPrimitive(node, node.httpMethod); 18 | if (httpMethod === 'OPTIONS') { 19 | return NagRuleCompliance.NOT_APPLICABLE; 20 | } 21 | if (node.authorizationType !== 'COGNITO_USER_POOLS') { 22 | return NagRuleCompliance.NON_COMPLIANT; 23 | } 24 | return NagRuleCompliance.COMPLIANT; 25 | } else { 26 | return NagRuleCompliance.NOT_APPLICABLE; 27 | } 28 | }, 29 | 'name', 30 | { value: parse(__filename).name } 31 | ); 32 | -------------------------------------------------------------------------------- /src/rules/cognito/CognitoUserPoolAdvancedSecurityModeEnforced.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { parse } from 'path'; 6 | import { CfnResource, Stack } from 'aws-cdk-lib'; 7 | import { CfnUserPool } from 'aws-cdk-lib/aws-cognito'; 8 | import { NagRuleCompliance, NagRules } from '../../nag-rules'; 9 | 10 | /** 11 | * Cognito user pools have AdvancedSecurityMode set to ENFORCED 12 | * @param node the CfnResource to check 13 | */ 14 | export default Object.defineProperty( 15 | (node: CfnResource): NagRuleCompliance => { 16 | if (node instanceof CfnUserPool) { 17 | const userPoolAddOns = Stack.of(node).resolve(node.userPoolAddOns); 18 | if (userPoolAddOns == undefined) { 19 | return NagRuleCompliance.NON_COMPLIANT; 20 | } 21 | const advancedSecurityMode = NagRules.resolveIfPrimitive( 22 | node, 23 | userPoolAddOns.advancedSecurityMode 24 | ); 25 | if ( 26 | advancedSecurityMode == undefined || 27 | advancedSecurityMode != 'ENFORCED' 28 | ) { 29 | return NagRuleCompliance.NON_COMPLIANT; 30 | } 31 | return NagRuleCompliance.COMPLIANT; 32 | } else { 33 | return NagRuleCompliance.NOT_APPLICABLE; 34 | } 35 | }, 36 | 'name', 37 | { value: parse(__filename).name } 38 | ); 39 | -------------------------------------------------------------------------------- /src/rules/cognito/CognitoUserPoolMFA.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { parse } from 'path'; 6 | import { CfnResource } from 'aws-cdk-lib'; 7 | import { CfnUserPool, Mfa } from 'aws-cdk-lib/aws-cognito'; 8 | import { NagRuleCompliance, NagRules } from '../../nag-rules'; 9 | 10 | /** 11 | * Cognito user pools require MFA 12 | * @param node the CfnResource to check 13 | */ 14 | export default Object.defineProperty( 15 | (node: CfnResource): NagRuleCompliance => { 16 | if (node instanceof CfnUserPool) { 17 | const mfaConfiguration = NagRules.resolveIfPrimitive( 18 | node, 19 | node.mfaConfiguration 20 | ); 21 | if (mfaConfiguration == undefined || mfaConfiguration != Mfa.REQUIRED) { 22 | return NagRuleCompliance.NON_COMPLIANT; 23 | } 24 | return NagRuleCompliance.COMPLIANT; 25 | } else { 26 | return NagRuleCompliance.NOT_APPLICABLE; 27 | } 28 | }, 29 | 'name', 30 | { value: parse(__filename).name } 31 | ); 32 | -------------------------------------------------------------------------------- /src/rules/cognito/CognitoUserPoolNoUnauthenticatedLogins.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { parse } from 'path'; 6 | import { CfnResource } from 'aws-cdk-lib'; 7 | import { CfnIdentityPool } from 'aws-cdk-lib/aws-cognito'; 8 | import { NagRuleCompliance, NagRules } from '../../nag-rules'; 9 | 10 | /** 11 | * Cognito identity pools do not allow for unauthenticated logins without a valid reason 12 | * @param node the CfnResource to check 13 | */ 14 | export default Object.defineProperty( 15 | (node: CfnResource): NagRuleCompliance => { 16 | if (node instanceof CfnIdentityPool) { 17 | const allowUnauthenticatedIdentities = NagRules.resolveIfPrimitive( 18 | node, 19 | node.allowUnauthenticatedIdentities 20 | ); 21 | if (allowUnauthenticatedIdentities) { 22 | return NagRuleCompliance.NON_COMPLIANT; 23 | } 24 | return NagRuleCompliance.COMPLIANT; 25 | } else { 26 | return NagRuleCompliance.NOT_APPLICABLE; 27 | } 28 | }, 29 | 'name', 30 | { value: parse(__filename).name } 31 | ); 32 | -------------------------------------------------------------------------------- /src/rules/cognito/index.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | export { default as CognitoUserPoolAdvancedSecurityModeEnforced } from './CognitoUserPoolAdvancedSecurityModeEnforced'; 6 | export { default as CognitoUserPoolAPIGWAuthorizer } from './CognitoUserPoolAPIGWAuthorizer'; 7 | export { default as CognitoUserPoolMFA } from './CognitoUserPoolMFA'; 8 | export { default as CognitoUserPoolNoUnauthenticatedLogins } from './CognitoUserPoolNoUnauthenticatedLogins'; 9 | export { default as CognitoUserPoolStrongPasswordPolicy } from './CognitoUserPoolStrongPasswordPolicy'; 10 | -------------------------------------------------------------------------------- /src/rules/dms/DMSReplicationNotPublic.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { parse } from 'path'; 6 | import { CfnResource } from 'aws-cdk-lib'; 7 | import { CfnReplicationInstance } from 'aws-cdk-lib/aws-dms'; 8 | import { NagRuleCompliance, NagRules } from '../../nag-rules'; 9 | 10 | /** 11 | * DMS replication instances are not public 12 | * @param node the CfnResource to check 13 | */ 14 | export default Object.defineProperty( 15 | (node: CfnResource): NagRuleCompliance => { 16 | if (node instanceof CfnReplicationInstance) { 17 | const publicAccess = NagRules.resolveIfPrimitive( 18 | node, 19 | node.publiclyAccessible 20 | ); 21 | if (publicAccess !== false) { 22 | return NagRuleCompliance.NON_COMPLIANT; 23 | } 24 | return NagRuleCompliance.COMPLIANT; 25 | } else { 26 | return NagRuleCompliance.NOT_APPLICABLE; 27 | } 28 | }, 29 | 'name', 30 | { value: parse(__filename).name } 31 | ); 32 | -------------------------------------------------------------------------------- /src/rules/dms/index.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | export { default as DMSReplicationNotPublic } from './DMSReplicationNotPublic'; 6 | -------------------------------------------------------------------------------- /src/rules/documentdb/DocumentDBClusterBackupRetentionPeriod.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { parse } from 'path'; 6 | import { CfnResource } from 'aws-cdk-lib'; 7 | import { CfnDBCluster } from 'aws-cdk-lib/aws-docdb'; 8 | import { NagRuleCompliance, NagRules } from '../../nag-rules'; 9 | 10 | /** 11 | * Document DB clusters have a reasonable minimum backup retention period configured 12 | * @param node the CfnResource to check 13 | */ 14 | export default Object.defineProperty( 15 | (node: CfnResource): NagRuleCompliance => { 16 | if (node instanceof CfnDBCluster) { 17 | const backupRetentionPeriod = NagRules.resolveIfPrimitive( 18 | node, 19 | node.backupRetentionPeriod 20 | ); 21 | if (backupRetentionPeriod == undefined || backupRetentionPeriod < 7) { 22 | return NagRuleCompliance.NON_COMPLIANT; 23 | } 24 | return NagRuleCompliance.COMPLIANT; 25 | } else { 26 | return NagRuleCompliance.NOT_APPLICABLE; 27 | } 28 | }, 29 | 'name', 30 | { value: parse(__filename).name } 31 | ); 32 | -------------------------------------------------------------------------------- /src/rules/documentdb/DocumentDBClusterEncryptionAtRest.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { parse } from 'path'; 6 | import { CfnResource } from 'aws-cdk-lib'; 7 | import { CfnDBCluster } from 'aws-cdk-lib/aws-docdb'; 8 | import { NagRuleCompliance, NagRules } from '../../nag-rules'; 9 | 10 | /** 11 | * Document DB clusters have encryption at rest enabled 12 | * @param node the CfnResource to check 13 | */ 14 | export default Object.defineProperty( 15 | (node: CfnResource): NagRuleCompliance => { 16 | if (node instanceof CfnDBCluster) { 17 | if (node.storageEncrypted == undefined) { 18 | return NagRuleCompliance.NON_COMPLIANT; 19 | } 20 | const storageEncrypted = NagRules.resolveIfPrimitive( 21 | node, 22 | node.storageEncrypted 23 | ); 24 | if (!storageEncrypted) { 25 | return NagRuleCompliance.NON_COMPLIANT; 26 | } 27 | return NagRuleCompliance.COMPLIANT; 28 | } else { 29 | return NagRuleCompliance.NOT_APPLICABLE; 30 | } 31 | }, 32 | 'name', 33 | { value: parse(__filename).name } 34 | ); 35 | -------------------------------------------------------------------------------- /src/rules/documentdb/DocumentDBClusterLogExports.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { parse } from 'path'; 6 | import { CfnResource } from 'aws-cdk-lib'; 7 | import { CfnDBCluster } from 'aws-cdk-lib/aws-docdb'; 8 | import { 9 | NagRuleCompliance, 10 | NagRuleFindings, 11 | NagRuleResult, 12 | } from '../../nag-rules'; 13 | 14 | /** 15 | * Document DB clusters have authenticate, createIndex, and dropCollection Log Exports enabled 16 | * @param node the CfnResource to check 17 | */ 18 | export default Object.defineProperty( 19 | (node: CfnResource): NagRuleResult => { 20 | if (node instanceof CfnDBCluster) { 21 | const needed = ['authenticate', 'createIndex', 'dropCollection']; 22 | const exports = node.enableCloudwatchLogsExports ?? []; 23 | const findings: NagRuleFindings = needed 24 | .filter((log) => !exports.includes(log)) 25 | .map((log) => `LogExport::${log}`); 26 | return findings.length ? findings : NagRuleCompliance.COMPLIANT; 27 | } else { 28 | return NagRuleCompliance.NOT_APPLICABLE; 29 | } 30 | }, 31 | 'name', 32 | { value: parse(__filename).name } 33 | ); 34 | -------------------------------------------------------------------------------- /src/rules/documentdb/DocumentDBClusterNonDefaultPort.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { parse } from 'path'; 6 | import { CfnResource } from 'aws-cdk-lib'; 7 | import { CfnDBCluster } from 'aws-cdk-lib/aws-docdb'; 8 | import { NagRuleCompliance, NagRules } from '../../nag-rules'; 9 | 10 | /** 11 | * Document DB clusters do not use the default endpoint port 12 | * @param node the CfnResource to check 13 | */ 14 | export default Object.defineProperty( 15 | (node: CfnResource): NagRuleCompliance => { 16 | if (node instanceof CfnDBCluster) { 17 | const port = NagRules.resolveIfPrimitive(node, node.port); 18 | if (port == undefined || port == 27017) { 19 | return NagRuleCompliance.NON_COMPLIANT; 20 | } 21 | return NagRuleCompliance.COMPLIANT; 22 | } else { 23 | return NagRuleCompliance.NOT_APPLICABLE; 24 | } 25 | }, 26 | 'name', 27 | { value: parse(__filename).name } 28 | ); 29 | -------------------------------------------------------------------------------- /src/rules/documentdb/DocumentDBCredentialsInSecretsManager.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { parse } from 'path'; 6 | import { CfnResource } from 'aws-cdk-lib'; 7 | import { CfnDBCluster } from 'aws-cdk-lib/aws-docdb'; 8 | import { NagRuleCompliance, NagRules } from '../../nag-rules'; 9 | 10 | /** 11 | * Document DB clusters have the username and password stored in Secrets Manager 12 | * @param node the CfnResource to check 13 | */ 14 | export default Object.defineProperty( 15 | (node: CfnResource): NagRuleCompliance => { 16 | if (node instanceof CfnDBCluster) { 17 | const masterUsername = NagRules.resolveIfPrimitive( 18 | node, 19 | node.masterUsername 20 | ); 21 | const masterUserPassword = NagRules.resolveIfPrimitive( 22 | node, 23 | node.masterUserPassword 24 | ); 25 | if ( 26 | masterUsername.includes('{{resolve:secretsmanager') == false || 27 | masterUserPassword.includes('{{resolve:secretsmanager') == false 28 | ) { 29 | return NagRuleCompliance.NON_COMPLIANT; 30 | } 31 | return NagRuleCompliance.COMPLIANT; 32 | } else { 33 | return NagRuleCompliance.NOT_APPLICABLE; 34 | } 35 | }, 36 | 'name', 37 | { value: parse(__filename).name } 38 | ); 39 | -------------------------------------------------------------------------------- /src/rules/documentdb/index.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | export { default as DocumentDBClusterBackupRetentionPeriod } from './DocumentDBClusterBackupRetentionPeriod'; 6 | export { default as DocumentDBClusterEncryptionAtRest } from './DocumentDBClusterEncryptionAtRest'; 7 | export { default as DocumentDBClusterLogExports } from './DocumentDBClusterLogExports'; 8 | export { default as DocumentDBClusterNonDefaultPort } from './DocumentDBClusterNonDefaultPort'; 9 | export { default as DocumentDBCredentialsInSecretsManager } from './DocumentDBCredentialsInSecretsManager'; 10 | -------------------------------------------------------------------------------- /src/rules/dynamodb/DAXEncrypted.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { parse } from 'path'; 6 | import { CfnResource, Stack } from 'aws-cdk-lib'; 7 | import { CfnCluster } from 'aws-cdk-lib/aws-dax'; 8 | import { NagRuleCompliance, NagRules } from '../../nag-rules'; 9 | 10 | /** 11 | * DAX clusters have server-side encryption enabled 12 | * @param node the CfnResource to check 13 | */ 14 | export default Object.defineProperty( 15 | (node: CfnResource): NagRuleCompliance => { 16 | if (node instanceof CfnCluster) { 17 | if (node.sseSpecification == undefined) { 18 | return NagRuleCompliance.NON_COMPLIANT; 19 | } 20 | const sseSpecification = Stack.of(node).resolve(node.sseSpecification); 21 | const enabled = NagRules.resolveIfPrimitive( 22 | node, 23 | sseSpecification.sseEnabled 24 | ); 25 | if (!enabled) { 26 | return NagRuleCompliance.NON_COMPLIANT; 27 | } 28 | return NagRuleCompliance.COMPLIANT; 29 | } else { 30 | return NagRuleCompliance.NOT_APPLICABLE; 31 | } 32 | }, 33 | 'name', 34 | { value: parse(__filename).name } 35 | ); 36 | -------------------------------------------------------------------------------- /src/rules/dynamodb/DynamoDBPITREnabled.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { parse } from 'path'; 6 | import { CfnResource, Stack } from 'aws-cdk-lib'; 7 | import { CfnTable } from 'aws-cdk-lib/aws-dynamodb'; 8 | import { NagRuleCompliance, NagRules } from '../../nag-rules'; 9 | 10 | /** 11 | * DynamoDB tables have Point-in-time Recovery enabled 12 | * @param node the CfnResource to check 13 | */ 14 | 15 | export default Object.defineProperty( 16 | (node: CfnResource): NagRuleCompliance => { 17 | if (node instanceof CfnTable) { 18 | if (node.pointInTimeRecoverySpecification == undefined) { 19 | return NagRuleCompliance.NON_COMPLIANT; 20 | } 21 | const pitr = Stack.of(node).resolve( 22 | node.pointInTimeRecoverySpecification 23 | ); 24 | const enabled = NagRules.resolveIfPrimitive( 25 | node, 26 | pitr.pointInTimeRecoveryEnabled 27 | ); 28 | if (!enabled) { 29 | return NagRuleCompliance.NON_COMPLIANT; 30 | } 31 | return NagRuleCompliance.COMPLIANT; 32 | } else { 33 | return NagRuleCompliance.NOT_APPLICABLE; 34 | } 35 | }, 36 | 'name', 37 | { value: parse(__filename).name } 38 | ); 39 | -------------------------------------------------------------------------------- /src/rules/dynamodb/index.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | export { default as DAXEncrypted } from './DAXEncrypted'; 6 | export { default as DynamoDBAutoScalingEnabled } from './DynamoDBAutoScalingEnabled'; 7 | export { default as DynamoDBInBackupPlan } from './DynamoDBInBackupPlan'; 8 | export { default as DynamoDBPITREnabled } from './DynamoDBPITREnabled'; 9 | -------------------------------------------------------------------------------- /src/rules/ec2/EC2InstanceDetailedMonitoringEnabled.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { parse } from 'path'; 6 | import { CfnResource } from 'aws-cdk-lib'; 7 | import { CfnLaunchConfiguration } from 'aws-cdk-lib/aws-autoscaling'; 8 | import { CfnInstance } from 'aws-cdk-lib/aws-ec2'; 9 | import { NagRuleCompliance, NagRules } from '../../nag-rules'; 10 | 11 | /** 12 | * EC2 instances have detailed monitoring enabled 13 | * @param node the CfnResource to check 14 | */ 15 | export default Object.defineProperty( 16 | (node: CfnResource): NagRuleCompliance => { 17 | if (node instanceof CfnInstance) { 18 | const monitoring = NagRules.resolveIfPrimitive(node, node.monitoring); 19 | if (monitoring == undefined || monitoring == false) { 20 | return NagRuleCompliance.NON_COMPLIANT; 21 | } 22 | return NagRuleCompliance.COMPLIANT; 23 | } else if (node instanceof CfnLaunchConfiguration) { 24 | const monitoring = NagRules.resolveIfPrimitive( 25 | node, 26 | node.instanceMonitoring 27 | ); 28 | if (monitoring != undefined && monitoring == false) { 29 | return NagRuleCompliance.NON_COMPLIANT; 30 | } 31 | return NagRuleCompliance.COMPLIANT; 32 | } else { 33 | return NagRuleCompliance.NOT_APPLICABLE; 34 | } 35 | }, 36 | 'name', 37 | { value: parse(__filename).name } 38 | ); 39 | -------------------------------------------------------------------------------- /src/rules/ec2/EC2InstanceNoPublicIp.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { parse } from 'path'; 6 | import { CfnResource, Stack } from 'aws-cdk-lib'; 7 | import { CfnInstance } from 'aws-cdk-lib/aws-ec2'; 8 | import { NagRuleCompliance, NagRules } from '../../nag-rules'; 9 | 10 | /** 11 | * EC2 instances do not have public IPs 12 | * @param node the CfnResource to check 13 | */ 14 | export default Object.defineProperty( 15 | (node: CfnResource): NagRuleCompliance => { 16 | if (node instanceof CfnInstance) { 17 | const networkInterfaces = Stack.of(node).resolve(node.networkInterfaces); 18 | if (networkInterfaces != undefined) { 19 | //Iterate through network interfaces, checking if public IPs are enabled 20 | for (const networkInterface of networkInterfaces) { 21 | const resolvedInterface = Stack.of(node).resolve(networkInterface); 22 | const associatePublicIpAddress = NagRules.resolveIfPrimitive( 23 | node, 24 | resolvedInterface.associatePublicIpAddress 25 | ); 26 | if (associatePublicIpAddress === true) { 27 | return NagRuleCompliance.NON_COMPLIANT; 28 | } 29 | } 30 | } 31 | return NagRuleCompliance.COMPLIANT; 32 | } else { 33 | return NagRuleCompliance.NOT_APPLICABLE; 34 | } 35 | }, 36 | 'name', 37 | { value: parse(__filename).name } 38 | ); 39 | -------------------------------------------------------------------------------- /src/rules/ec2/EC2InstanceProfileAttached.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { parse } from 'path'; 6 | import { CfnResource } from 'aws-cdk-lib'; 7 | import { CfnInstance } from 'aws-cdk-lib/aws-ec2'; 8 | import { NagRuleCompliance } from '../../nag-rules'; 9 | 10 | /** 11 | * EC2 instances have an instance profile attached 12 | * @param node the CfnResource to check 13 | */ 14 | export default Object.defineProperty( 15 | (node: CfnResource): NagRuleCompliance => { 16 | if (node instanceof CfnInstance) { 17 | if (node.iamInstanceProfile == undefined) { 18 | return NagRuleCompliance.NON_COMPLIANT; 19 | } 20 | return NagRuleCompliance.COMPLIANT; 21 | } else { 22 | return NagRuleCompliance.NOT_APPLICABLE; 23 | } 24 | }, 25 | 'name', 26 | { value: parse(__filename).name } 27 | ); 28 | -------------------------------------------------------------------------------- /src/rules/ec2/EC2InstanceTerminationProtection.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { parse } from 'path'; 6 | import { CfnResource } from 'aws-cdk-lib'; 7 | import { CfnInstance } from 'aws-cdk-lib/aws-ec2'; 8 | import { NagRuleCompliance, NagRules } from '../../nag-rules'; 9 | 10 | /** 11 | * EC2 Instances outside of an ASG have Termination Protection enabled 12 | * @param node the CfnResource to check 13 | */ 14 | export default Object.defineProperty( 15 | (node: CfnResource): NagRuleCompliance => { 16 | if (node instanceof CfnInstance) { 17 | const disableApiTermination = NagRules.resolveIfPrimitive( 18 | node, 19 | node.disableApiTermination 20 | ); 21 | if (disableApiTermination !== true) { 22 | return NagRuleCompliance.NON_COMPLIANT; 23 | } 24 | return NagRuleCompliance.COMPLIANT; 25 | } else { 26 | return NagRuleCompliance.NOT_APPLICABLE; 27 | } 28 | }, 29 | 'name', 30 | { value: parse(__filename).name } 31 | ); 32 | -------------------------------------------------------------------------------- /src/rules/ec2/EC2InstancesInVPC.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { parse } from 'path'; 6 | import { CfnResource, Stack } from 'aws-cdk-lib'; 7 | import { CfnInstance } from 'aws-cdk-lib/aws-ec2'; 8 | import { NagRuleCompliance } from '../../nag-rules'; 9 | 10 | /** 11 | * EC2 instances are created within VPCs 12 | * @param node the CfnResource to check 13 | */ 14 | export default Object.defineProperty( 15 | (node: CfnResource): NagRuleCompliance => { 16 | if (node instanceof CfnInstance) { 17 | //If we are in a VPC, then we'll have a subnet 18 | const subnetId = Stack.of(node).resolve(node.subnetId); 19 | if (subnetId == undefined) { 20 | return NagRuleCompliance.NON_COMPLIANT; 21 | } 22 | return NagRuleCompliance.COMPLIANT; 23 | } else { 24 | return NagRuleCompliance.NOT_APPLICABLE; 25 | } 26 | }, 27 | 'name', 28 | { value: parse(__filename).name } 29 | ); 30 | -------------------------------------------------------------------------------- /src/rules/ec2/EC2SecurityGroupDescription.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { parse } from 'path'; 6 | import { CfnResource } from 'aws-cdk-lib'; 7 | import { CfnSecurityGroup } from 'aws-cdk-lib/aws-ec2'; 8 | import { NagRuleCompliance, NagRules } from '../../nag-rules'; 9 | 10 | /** 11 | * Security Groups have descriptions 12 | * @param node the CfnResource to check 13 | */ 14 | export default Object.defineProperty( 15 | (node: CfnResource): NagRuleCompliance => { 16 | if (node instanceof CfnSecurityGroup) { 17 | const description = NagRules.resolveIfPrimitive( 18 | node, 19 | node.groupDescription 20 | ); 21 | if (description.length < 2) { 22 | return NagRuleCompliance.NON_COMPLIANT; 23 | } 24 | return NagRuleCompliance.COMPLIANT; 25 | } else { 26 | return NagRuleCompliance.NOT_APPLICABLE; 27 | } 28 | }, 29 | 'name', 30 | { value: parse(__filename).name } 31 | ); 32 | -------------------------------------------------------------------------------- /src/rules/ec2/index.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | export { default as EC2EBSInBackupPlan } from './EC2EBSInBackupPlan'; 6 | export { default as EC2EBSOptimizedInstance } from './EC2EBSOptimizedInstance'; 7 | export { default as EC2EBSVolumeEncrypted } from './EC2EBSVolumeEncrypted'; 8 | export { default as EC2IMDSv2Enabled } from './EC2IMDSv2Enabled'; 9 | export { default as EC2InstanceDetailedMonitoringEnabled } from './EC2InstanceDetailedMonitoringEnabled'; 10 | export { default as EC2InstanceNoPublicIp } from './EC2InstanceNoPublicIp'; 11 | export { default as EC2InstanceProfileAttached } from './EC2InstanceProfileAttached'; 12 | export { default as EC2InstanceTerminationProtection } from './EC2InstanceTerminationProtection'; 13 | export { default as EC2InstancesInVPC } from './EC2InstancesInVPC'; 14 | export { default as EC2RestrictedCommonPorts } from './EC2RestrictedCommonPorts'; 15 | export { default as EC2RestrictedInbound } from './EC2RestrictedInbound'; 16 | export { default as EC2RestrictedSSH } from './EC2RestrictedSSH'; 17 | export { default as EC2SecurityGroupDescription } from './EC2SecurityGroupDescription'; 18 | -------------------------------------------------------------------------------- /src/rules/ecr/index.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | export { default as ECROpenAccess } from './ECROpenAccess'; 6 | -------------------------------------------------------------------------------- /src/rules/ecs/ECSClusterCloudWatchContainerInsights.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { parse } from 'path'; 6 | import { CfnResource, Stack } from 'aws-cdk-lib'; 7 | import { CfnCluster } from 'aws-cdk-lib/aws-ecs'; 8 | import { NagRuleCompliance } from '../../nag-rules'; 9 | 10 | /** 11 | * ECS Clusters have CloudWatch Container Insights Enabled 12 | * @param node the CfnResource to check 13 | */ 14 | export default Object.defineProperty( 15 | (node: CfnResource): NagRuleCompliance => { 16 | if (node instanceof CfnCluster) { 17 | if (node.clusterSettings == undefined) { 18 | return NagRuleCompliance.NON_COMPLIANT; 19 | } 20 | const clusterSettings = Stack.of(node).resolve(node.clusterSettings); 21 | let found = false; 22 | for (const setting of clusterSettings) { 23 | const resolvedSetting = Stack.of(node).resolve(setting); 24 | if ( 25 | resolvedSetting.name && 26 | resolvedSetting.name == 'containerInsights' && 27 | resolvedSetting.value && 28 | (resolvedSetting.value == 'enabled' || 29 | resolvedSetting.value == 'enhanced') 30 | ) { 31 | found = true; 32 | break; 33 | } 34 | } 35 | if (!found) { 36 | return NagRuleCompliance.NON_COMPLIANT; 37 | } 38 | return NagRuleCompliance.COMPLIANT; 39 | } else { 40 | return NagRuleCompliance.NOT_APPLICABLE; 41 | } 42 | }, 43 | 'name', 44 | { value: parse(__filename).name } 45 | ); 46 | -------------------------------------------------------------------------------- /src/rules/ecs/ECSTaskDefinitionContainerLogging.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { parse } from 'path'; 6 | import { CfnResource, Stack } from 'aws-cdk-lib'; 7 | import { CfnTaskDefinition } from 'aws-cdk-lib/aws-ecs'; 8 | import { NagRuleCompliance } from '../../nag-rules'; 9 | 10 | /** 11 | * Containers in ECS Task Definitions have logging enabled 12 | * @param node the CfnResource to check 13 | */ 14 | export default Object.defineProperty( 15 | (node: CfnResource): NagRuleCompliance => { 16 | if (node instanceof CfnTaskDefinition) { 17 | const containerDefinitions = Stack.of(node).resolve( 18 | node.containerDefinitions 19 | ); 20 | if (containerDefinitions !== undefined) { 21 | for (const containerDefinition of containerDefinitions) { 22 | const resolvedDefinition = 23 | Stack.of(node).resolve(containerDefinition); 24 | const logConfiguration = Stack.of(node).resolve( 25 | resolvedDefinition.logConfiguration 26 | ); 27 | if (logConfiguration?.logDriver === undefined) { 28 | return NagRuleCompliance.NON_COMPLIANT; 29 | } 30 | } 31 | } 32 | return NagRuleCompliance.COMPLIANT; 33 | } else { 34 | return NagRuleCompliance.NOT_APPLICABLE; 35 | } 36 | }, 37 | 'name', 38 | { value: parse(__filename).name } 39 | ); 40 | -------------------------------------------------------------------------------- /src/rules/ecs/ECSTaskDefinitionNoEnvironmentVariables.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { parse } from 'path'; 6 | import { CfnResource, Stack } from 'aws-cdk-lib'; 7 | import { CfnTaskDefinition } from 'aws-cdk-lib/aws-ecs'; 8 | import { NagRuleCompliance } from '../../nag-rules'; 9 | 10 | /** 11 | * Containers in ECS task definitions do not directly specify environment variables 12 | * @param node the CfnResource to check 13 | */ 14 | export default Object.defineProperty( 15 | (node: CfnResource): NagRuleCompliance => { 16 | if (node instanceof CfnTaskDefinition) { 17 | const containerDefinitions = Stack.of(node).resolve( 18 | node.containerDefinitions 19 | ); 20 | if (containerDefinitions !== undefined) { 21 | for (const containerDefinition of containerDefinitions) { 22 | const resolvedDefinition = 23 | Stack.of(node).resolve(containerDefinition); 24 | const environment = Stack.of(node).resolve( 25 | resolvedDefinition.environment 26 | ); 27 | if (environment !== undefined) { 28 | return NagRuleCompliance.NON_COMPLIANT; 29 | } 30 | } 31 | } 32 | return NagRuleCompliance.COMPLIANT; 33 | } else { 34 | return NagRuleCompliance.NOT_APPLICABLE; 35 | } 36 | }, 37 | 'name', 38 | { value: parse(__filename).name } 39 | ); 40 | -------------------------------------------------------------------------------- /src/rules/ecs/index.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | export { default as ECSClusterCloudWatchContainerInsights } from './ECSClusterCloudWatchContainerInsights'; 6 | export { default as ECSTaskDefinitionContainerLogging } from './ECSTaskDefinitionContainerLogging'; 7 | export { default as ECSTaskDefinitionNoEnvironmentVariables } from './ECSTaskDefinitionNoEnvironmentVariables'; 8 | export { default as ECSTaskDefinitionUserForHostMode } from './ECSTaskDefinitionUserForHostMode'; 9 | -------------------------------------------------------------------------------- /src/rules/efs/EFSEncrypted.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { parse } from 'path'; 6 | import { CfnResource } from 'aws-cdk-lib'; 7 | import { CfnFileSystem } from 'aws-cdk-lib/aws-efs'; 8 | import { NagRuleCompliance, NagRules } from '../../nag-rules'; 9 | 10 | /** 11 | * Elastic File Systems are configured for encryption at rest 12 | * @param node the CfnResource to check 13 | */ 14 | export default Object.defineProperty( 15 | (node: CfnResource): NagRuleCompliance => { 16 | if (node instanceof CfnFileSystem) { 17 | const encrypted = NagRules.resolveIfPrimitive(node, node.encrypted); 18 | if (encrypted === false) { 19 | return NagRuleCompliance.NON_COMPLIANT; 20 | } 21 | return NagRuleCompliance.COMPLIANT; 22 | } else { 23 | return NagRuleCompliance.NOT_APPLICABLE; 24 | } 25 | }, 26 | 'name', 27 | { value: parse(__filename).name } 28 | ); 29 | -------------------------------------------------------------------------------- /src/rules/efs/index.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | export { default as EFSInBackupPlan } from './EFSInBackupPlan'; 6 | export { default as EFSEncrypted } from './EFSEncrypted'; 7 | -------------------------------------------------------------------------------- /src/rules/eks/index.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | export { default as EKSClusterControlPlaneLogs } from './EKSClusterControlPlaneLogs'; 6 | export { default as EKSClusterNoEndpointPublicAccess } from './EKSClusterNoEndpointPublicAccess'; 7 | -------------------------------------------------------------------------------- /src/rules/elasticache/ElastiCacheClusterInVPC.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { parse } from 'path'; 6 | import { CfnResource } from 'aws-cdk-lib'; 7 | import { 8 | CfnCacheCluster, 9 | CfnReplicationGroup, 10 | } from 'aws-cdk-lib/aws-elasticache'; 11 | import { NagRuleCompliance } from '../../nag-rules'; 12 | 13 | /** 14 | * ElastiCache clusters are provisioned in a VPC 15 | * @param node the CfnResource to check 16 | */ 17 | export default Object.defineProperty( 18 | (node: CfnResource): NagRuleCompliance => { 19 | if ( 20 | node instanceof CfnCacheCluster || 21 | node instanceof CfnReplicationGroup 22 | ) { 23 | if ( 24 | node.cacheSubnetGroupName == undefined || 25 | node.cacheSubnetGroupName.length == 0 26 | ) { 27 | return NagRuleCompliance.NON_COMPLIANT; 28 | } 29 | return NagRuleCompliance.COMPLIANT; 30 | } else { 31 | return NagRuleCompliance.NOT_APPLICABLE; 32 | } 33 | }, 34 | 'name', 35 | { value: parse(__filename).name } 36 | ); 37 | -------------------------------------------------------------------------------- /src/rules/elasticache/ElastiCacheRedisClusterAutomaticBackup.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { parse } from 'path'; 6 | import { CfnResource } from 'aws-cdk-lib'; 7 | import { 8 | CfnCacheCluster, 9 | CfnReplicationGroup, 10 | } from 'aws-cdk-lib/aws-elasticache'; 11 | import { NagRuleCompliance, NagRules } from '../../nag-rules'; 12 | 13 | /** 14 | * ElastiCache Redis clusters retain automatic backups for at least 15 days 15 | * @param node the CfnResource to check 16 | */ 17 | export default Object.defineProperty( 18 | (node: CfnResource): NagRuleCompliance => { 19 | if (node instanceof CfnCacheCluster) { 20 | const engine = NagRules.resolveIfPrimitive( 21 | node, 22 | node.engine.toLowerCase() 23 | ); 24 | const retention = NagRules.resolveIfPrimitive( 25 | node, 26 | node.snapshotRetentionLimit 27 | ); 28 | if (engine == 'redis' && (retention == undefined || retention < 15)) { 29 | return NagRuleCompliance.NON_COMPLIANT; 30 | } 31 | return NagRuleCompliance.COMPLIANT; 32 | } else if (node instanceof CfnReplicationGroup) { 33 | const retention = NagRules.resolveIfPrimitive( 34 | node, 35 | node.snapshotRetentionLimit 36 | ); 37 | if (retention == undefined || retention < 15) { 38 | return NagRuleCompliance.NON_COMPLIANT; 39 | } 40 | return NagRuleCompliance.COMPLIANT; 41 | } else { 42 | return NagRuleCompliance.NOT_APPLICABLE; 43 | } 44 | }, 45 | 'name', 46 | { value: parse(__filename).name } 47 | ); 48 | -------------------------------------------------------------------------------- /src/rules/elasticache/ElastiCacheRedisClusterEncryption.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { parse } from 'path'; 6 | import { CfnResource } from 'aws-cdk-lib'; 7 | import { CfnReplicationGroup } from 'aws-cdk-lib/aws-elasticache'; 8 | import { NagRuleCompliance, NagRules } from '../../nag-rules'; 9 | 10 | /** 11 | * ElastiCache Redis clusters have both encryption in transit and at rest enabled 12 | * @param node the CfnResource to check 13 | */ 14 | export default Object.defineProperty( 15 | (node: CfnResource): NagRuleCompliance => { 16 | if (node instanceof CfnReplicationGroup) { 17 | if ( 18 | node.atRestEncryptionEnabled == undefined || 19 | node.transitEncryptionEnabled == undefined 20 | ) { 21 | return NagRuleCompliance.NON_COMPLIANT; 22 | } 23 | const rest = NagRules.resolveIfPrimitive( 24 | node, 25 | node.atRestEncryptionEnabled 26 | ); 27 | const transit = NagRules.resolveIfPrimitive( 28 | node, 29 | node.transitEncryptionEnabled 30 | ); 31 | if (rest == false || transit == false) { 32 | return NagRuleCompliance.NON_COMPLIANT; 33 | } 34 | return NagRuleCompliance.COMPLIANT; 35 | } else { 36 | return NagRuleCompliance.NOT_APPLICABLE; 37 | } 38 | }, 39 | 'name', 40 | { value: parse(__filename).name } 41 | ); 42 | -------------------------------------------------------------------------------- /src/rules/elasticache/ElastiCacheRedisClusterMultiAZ.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { parse } from 'path'; 6 | import { CfnResource } from 'aws-cdk-lib'; 7 | import { CfnReplicationGroup } from 'aws-cdk-lib/aws-elasticache'; 8 | import { NagRuleCompliance, NagRules } from '../../nag-rules'; 9 | 10 | /** 11 | * ElastiCache Redis clusters are deployed in a Multi-AZ configuration 12 | * @param node the CfnResource to check 13 | */ 14 | export default Object.defineProperty( 15 | (node: CfnResource): NagRuleCompliance => { 16 | if (node instanceof CfnReplicationGroup) { 17 | if (node.multiAzEnabled == undefined) { 18 | return NagRuleCompliance.NON_COMPLIANT; 19 | } 20 | const multiAz = NagRules.resolveIfPrimitive(node, node.multiAzEnabled); 21 | if (!multiAz) { 22 | return NagRuleCompliance.NON_COMPLIANT; 23 | } 24 | return NagRuleCompliance.COMPLIANT; 25 | } else { 26 | return NagRuleCompliance.NOT_APPLICABLE; 27 | } 28 | }, 29 | 'name', 30 | { value: parse(__filename).name } 31 | ); 32 | -------------------------------------------------------------------------------- /src/rules/elasticache/ElastiCacheRedisClusterRedisAuth.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { parse } from 'path'; 6 | import { CfnResource } from 'aws-cdk-lib'; 7 | import { CfnReplicationGroup } from 'aws-cdk-lib/aws-elasticache'; 8 | import { NagRuleCompliance } from '../../nag-rules'; 9 | 10 | /** 11 | * ElastiCache Redis clusters use Redis AUTH for user authentication 12 | * @param node the CfnResource to check 13 | */ 14 | export default Object.defineProperty( 15 | (node: CfnResource): NagRuleCompliance => { 16 | if (node instanceof CfnReplicationGroup) { 17 | if (node.authToken == undefined || node.authToken.length == 0) { 18 | return NagRuleCompliance.NON_COMPLIANT; 19 | } 20 | return NagRuleCompliance.COMPLIANT; 21 | } else { 22 | return NagRuleCompliance.NOT_APPLICABLE; 23 | } 24 | }, 25 | 'name', 26 | { value: parse(__filename).name } 27 | ); 28 | -------------------------------------------------------------------------------- /src/rules/elasticache/index.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | export { default as ElastiCacheClusterInVPC } from './ElastiCacheClusterInVPC'; 6 | export { default as ElastiCacheClusterNonDefaultPort } from './ElastiCacheClusterNonDefaultPort'; 7 | export { default as ElastiCacheRedisClusterAutomaticBackup } from './ElastiCacheRedisClusterAutomaticBackup'; 8 | export { default as ElastiCacheRedisClusterEncryption } from '././ElastiCacheRedisClusterEncryption'; 9 | export { default as ElastiCacheRedisClusterMultiAZ } from './ElastiCacheRedisClusterMultiAZ'; 10 | export { default as ElastiCacheRedisClusterRedisAuth } from './ElastiCacheRedisClusterRedisAuth'; 11 | -------------------------------------------------------------------------------- /src/rules/elasticbeanstalk/index.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | export { default as ElasticBeanstalkEC2InstanceLogsToS3 } from './ElasticBeanstalkEC2InstanceLogsToS3'; 6 | export { default as ElasticBeanstalkEnhancedHealthReportingEnabled } from './ElasticBeanstalkEnhancedHealthReportingEnabled'; 7 | export { default as ElasticBeanstalkManagedUpdatesEnabled } from './ElasticBeanstalkManagedUpdatesEnabled'; 8 | export { default as ElasticBeanstalkVPCSpecified } from './ElasticBeanstalkVPCSpecified'; 9 | -------------------------------------------------------------------------------- /src/rules/elb/ALBHttpDropInvalidHeaderEnabled.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { parse } from 'path'; 6 | import { CfnResource, Stack } from 'aws-cdk-lib'; 7 | import { CfnLoadBalancer } from 'aws-cdk-lib/aws-elasticloadbalancingv2'; 8 | import { NagRuleCompliance, NagRules } from '../../nag-rules'; 9 | 10 | /** 11 | * Application Load Balancers are enabled to drop invalid headers 12 | * @param node the CfnResource to check 13 | */ 14 | export default Object.defineProperty( 15 | (node: CfnResource): NagRuleCompliance => { 16 | if (node instanceof CfnLoadBalancer) { 17 | const type = NagRules.resolveIfPrimitive(node, node.type); 18 | if (type == undefined || type == 'application') { 19 | const attributes = Stack.of(node).resolve(node.loadBalancerAttributes); 20 | if (attributes != undefined) { 21 | const reg = 22 | /"routing\.http\.drop_invalid_header_fields\.enabled","value":"true"/gm; 23 | if (JSON.stringify(attributes).search(reg) == -1) { 24 | return NagRuleCompliance.NON_COMPLIANT; 25 | } 26 | } else { 27 | return NagRuleCompliance.NON_COMPLIANT; 28 | } 29 | } 30 | return NagRuleCompliance.COMPLIANT; 31 | } else { 32 | return NagRuleCompliance.NOT_APPLICABLE; 33 | } 34 | }, 35 | 'name', 36 | { value: parse(__filename).name } 37 | ); 38 | -------------------------------------------------------------------------------- /src/rules/elb/ALBHttpToHttpsRedirection.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { parse } from 'path'; 6 | import { CfnResource, Stack } from 'aws-cdk-lib'; 7 | import { CfnListener } from 'aws-cdk-lib/aws-elasticloadbalancingv2'; 8 | import { NagRuleCompliance, NagRules } from '../../nag-rules'; 9 | 10 | /** 11 | * ALB HTTP listeners are configured to redirect to HTTPS 12 | * @param node the CfnResource to check 13 | */ 14 | export default Object.defineProperty( 15 | (node: CfnResource): NagRuleCompliance => { 16 | if (node instanceof CfnListener) { 17 | let found = false; 18 | const protocol = NagRules.resolveIfPrimitive(node, node.protocol); 19 | const actions = Stack.of(node).resolve(node.defaultActions); 20 | 21 | if (protocol == 'HTTP') { 22 | for (const action of actions) { 23 | if ( 24 | action.type == 'redirect' && 25 | action.redirectConfig.protocol == 'HTTPS' 26 | ) { 27 | found = true; 28 | } 29 | } 30 | if (!found) return NagRuleCompliance.NON_COMPLIANT; 31 | } 32 | return NagRuleCompliance.COMPLIANT; 33 | } else { 34 | return NagRuleCompliance.NOT_APPLICABLE; 35 | } 36 | }, 37 | 'name', 38 | { value: parse(__filename).name } 39 | ); 40 | -------------------------------------------------------------------------------- /src/rules/elb/CLBConnectionDraining.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { parse } from 'path'; 6 | import { CfnResource, Stack } from 'aws-cdk-lib'; 7 | import { CfnLoadBalancer } from 'aws-cdk-lib/aws-elasticloadbalancing'; 8 | import { NagRuleCompliance, NagRules } from '../../nag-rules'; 9 | 10 | /** 11 | * CLBs have connection draining enabled. 12 | * @param node the CfnResource to check 13 | */ 14 | export default Object.defineProperty( 15 | (node: CfnResource): NagRuleCompliance => { 16 | if (node instanceof CfnLoadBalancer) { 17 | if (node.connectionDrainingPolicy == undefined) { 18 | return NagRuleCompliance.NON_COMPLIANT; 19 | } 20 | const draining = Stack.of(node).resolve(node.connectionDrainingPolicy); 21 | const resolvedDraining = Stack.of(node).resolve(draining); 22 | const enabled = NagRules.resolveIfPrimitive( 23 | node, 24 | resolvedDraining.enabled 25 | ); 26 | if (enabled !== true) { 27 | return NagRuleCompliance.NON_COMPLIANT; 28 | } 29 | return NagRuleCompliance.COMPLIANT; 30 | } else { 31 | return NagRuleCompliance.NOT_APPLICABLE; 32 | } 33 | }, 34 | 'name', 35 | { value: parse(__filename).name } 36 | ); 37 | -------------------------------------------------------------------------------- /src/rules/elb/CLBNoInboundHttpHttps.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { parse } from 'path'; 6 | import { CfnResource, Stack } from 'aws-cdk-lib'; 7 | import { CfnLoadBalancer } from 'aws-cdk-lib/aws-elasticloadbalancing'; 8 | import { NagRuleCompliance, NagRules } from '../../nag-rules'; 9 | 10 | /** 11 | * CLBs are not used for incoming HTTP/HTTPS traffic. Use ALBs instead. 12 | * @param node the CfnResource to check 13 | */ 14 | export default Object.defineProperty( 15 | (node: CfnResource): NagRuleCompliance => { 16 | if (node instanceof CfnLoadBalancer) { 17 | const listeners = Stack.of(node).resolve(node.listeners); 18 | for (const listener of listeners) { 19 | const resolvedListener = Stack.of(node).resolve(listener); 20 | const protocol = NagRules.resolveIfPrimitive( 21 | node, 22 | resolvedListener.protocol 23 | ); 24 | if ( 25 | protocol.toLowerCase() == 'http' || 26 | protocol.toLowerCase() == 'https' 27 | ) { 28 | return NagRuleCompliance.NON_COMPLIANT; 29 | } 30 | } 31 | return NagRuleCompliance.COMPLIANT; 32 | } else { 33 | return NagRuleCompliance.NOT_APPLICABLE; 34 | } 35 | }, 36 | 'name', 37 | { value: parse(__filename).name } 38 | ); 39 | -------------------------------------------------------------------------------- /src/rules/elb/ELBCrossZoneLoadBalancingEnabled.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { parse } from 'path'; 6 | import { CfnResource } from 'aws-cdk-lib'; 7 | import { CfnLoadBalancer } from 'aws-cdk-lib/aws-elasticloadbalancing'; 8 | import { NagRuleCompliance, NagRules } from '../../nag-rules'; 9 | 10 | /** 11 | * CLBs use at least two AZs with the Cross-Zone Load Balancing feature enabled 12 | * @param node the CfnResource to check 13 | */ 14 | export default Object.defineProperty( 15 | (node: CfnResource): NagRuleCompliance => { 16 | if (node instanceof CfnLoadBalancer) { 17 | if (node.crossZone == undefined) { 18 | return NagRuleCompliance.NON_COMPLIANT; 19 | } 20 | if (node.subnets == undefined) { 21 | if ( 22 | node.availabilityZones == undefined || 23 | node.availabilityZones.length < 2 24 | ) { 25 | return NagRuleCompliance.NON_COMPLIANT; 26 | } 27 | } else if (node.subnets.length < 2) { 28 | return NagRuleCompliance.NON_COMPLIANT; 29 | } 30 | const crossZone = NagRules.resolveIfPrimitive(node, node.crossZone); 31 | if (crossZone != true) { 32 | return NagRuleCompliance.NON_COMPLIANT; 33 | } 34 | return NagRuleCompliance.COMPLIANT; 35 | } else { 36 | return NagRuleCompliance.NOT_APPLICABLE; 37 | } 38 | }, 39 | 'name', 40 | { value: parse(__filename).name } 41 | ); 42 | -------------------------------------------------------------------------------- /src/rules/elb/ELBDeletionProtectionEnabled.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { parse } from 'path'; 6 | import { CfnResource, Stack } from 'aws-cdk-lib'; 7 | import { CfnLoadBalancer } from 'aws-cdk-lib/aws-elasticloadbalancingv2'; 8 | import { NagRuleCompliance } from '../../nag-rules'; 9 | 10 | /** 11 | * ALBs, NLBs, and GLBs have deletion protection enabled 12 | * @param node the CfnResource to check 13 | */ 14 | export default Object.defineProperty( 15 | (node: CfnResource): NagRuleCompliance => { 16 | if (node instanceof CfnLoadBalancer) { 17 | const attributes = Stack.of(node).resolve(node.loadBalancerAttributes); 18 | if (attributes != undefined) { 19 | var deletionProtectionEnabled = false; 20 | for (const attr of attributes) { 21 | const resolvedAttr = Stack.of(node).resolve(attr); 22 | if ( 23 | resolvedAttr.key != undefined && 24 | resolvedAttr.key == 'deletion_protection.enabled' 25 | ) { 26 | if (resolvedAttr.value == 'true') { 27 | deletionProtectionEnabled = true; 28 | } 29 | } 30 | } 31 | if (!deletionProtectionEnabled) { 32 | return NagRuleCompliance.NON_COMPLIANT; 33 | } 34 | } else { 35 | return NagRuleCompliance.NON_COMPLIANT; 36 | } 37 | return NagRuleCompliance.COMPLIANT; 38 | } else { 39 | return NagRuleCompliance.NOT_APPLICABLE; 40 | } 41 | }, 42 | 'name', 43 | { value: parse(__filename).name } 44 | ); 45 | -------------------------------------------------------------------------------- /src/rules/elb/ELBv2ACMCertificateRequired.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { parse } from 'path'; 6 | import { CfnResource, Stack } from 'aws-cdk-lib'; 7 | import { CfnListener } from 'aws-cdk-lib/aws-elasticloadbalancingv2'; 8 | import { NagRuleCompliance } from '../../nag-rules'; 9 | 10 | /** 11 | * ALB, NLB, and GLB listeners use ACM-managed certificates 12 | * @param node the CfnResource to check 13 | */ 14 | export default Object.defineProperty( 15 | (node: CfnResource): NagRuleCompliance => { 16 | if (node instanceof CfnListener) { 17 | const certificates = Stack.of(node).resolve(node.certificates); 18 | if (certificates == undefined) { 19 | return NagRuleCompliance.NON_COMPLIANT; 20 | } 21 | let found = false; 22 | for (const certificate of certificates) { 23 | const resolvedCertificate = Stack.of(node).resolve(certificate); 24 | if (resolvedCertificate.certificateArn != undefined) { 25 | found = true; 26 | break; 27 | } 28 | } 29 | if (!found) { 30 | return NagRuleCompliance.NON_COMPLIANT; 31 | } 32 | return NagRuleCompliance.COMPLIANT; 33 | } else { 34 | return NagRuleCompliance.NOT_APPLICABLE; 35 | } 36 | }, 37 | 'name', 38 | { value: parse(__filename).name } 39 | ); 40 | -------------------------------------------------------------------------------- /src/rules/elb/index.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | export { default as ALBHttpDropInvalidHeaderEnabled } from './ALBHttpDropInvalidHeaderEnabled'; 6 | export { default as ALBHttpToHttpsRedirection } from './ALBHttpToHttpsRedirection'; 7 | export { default as ALBWAFEnabled } from './ALBWAFEnabled'; 8 | export { default as CLBNoInboundHttpHttps } from './CLBNoInboundHttpHttps'; 9 | export { default as CLBConnectionDraining } from './CLBConnectionDraining'; 10 | export { default as ELBACMCertificateRequired } from './ELBACMCertificateRequired'; 11 | export { default as ELBCrossZoneLoadBalancingEnabled } from './ELBCrossZoneLoadBalancingEnabled'; 12 | export { default as ELBDeletionProtectionEnabled } from './ELBDeletionProtectionEnabled'; 13 | export { default as ELBLoggingEnabled } from './ELBLoggingEnabled'; 14 | export { default as ELBTlsHttpsListenersOnly } from './ELBTlsHttpsListenersOnly'; 15 | export { default as ELBv2ACMCertificateRequired } from './ELBv2ACMCertificateRequired'; 16 | -------------------------------------------------------------------------------- /src/rules/emr/EMRAuthEC2KeyPairOrKerberos.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { parse } from 'path'; 6 | import { CfnResource, Stack } from 'aws-cdk-lib'; 7 | import { CfnCluster } from 'aws-cdk-lib/aws-emr'; 8 | import { NagRuleCompliance } from '../../nag-rules'; 9 | 10 | /** 11 | * EMR clusters implement authentication via an EC2 Key Pair or Kerberos 12 | * @param node the CfnResource to check 13 | */ 14 | export default Object.defineProperty( 15 | (node: CfnResource): NagRuleCompliance => { 16 | if (node instanceof CfnCluster) { 17 | const kerberosAttributes = Stack.of(node).resolve( 18 | node.kerberosAttributes 19 | ); 20 | if (kerberosAttributes == undefined) { 21 | const instanceConfig = Stack.of(node).resolve(node.instances); 22 | if (instanceConfig.ec2KeyName == undefined) { 23 | return NagRuleCompliance.NON_COMPLIANT; 24 | } 25 | } 26 | return NagRuleCompliance.COMPLIANT; 27 | } else { 28 | return NagRuleCompliance.NOT_APPLICABLE; 29 | } 30 | }, 31 | 'name', 32 | { value: parse(__filename).name } 33 | ); 34 | -------------------------------------------------------------------------------- /src/rules/emr/EMRKerberosEnabled.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { parse } from 'path'; 6 | import { CfnResource, Stack } from 'aws-cdk-lib'; 7 | import { CfnCluster } from 'aws-cdk-lib/aws-emr'; 8 | import { NagRuleCompliance } from '../../nag-rules'; 9 | 10 | /** 11 | * EMR clusters have Kerberos enabled 12 | * @param node the CfnResource to check 13 | */ 14 | export default Object.defineProperty( 15 | (node: CfnResource): NagRuleCompliance => { 16 | if (node instanceof CfnCluster) { 17 | const kerberosAttributes = Stack.of(node).resolve( 18 | node.kerberosAttributes 19 | ); 20 | if (kerberosAttributes == undefined) { 21 | return NagRuleCompliance.NON_COMPLIANT; 22 | } 23 | return NagRuleCompliance.COMPLIANT; 24 | } else { 25 | return NagRuleCompliance.NOT_APPLICABLE; 26 | } 27 | }, 28 | 'name', 29 | { value: parse(__filename).name } 30 | ); 31 | -------------------------------------------------------------------------------- /src/rules/emr/EMRS3AccessLogging.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { parse } from 'path'; 6 | import { CfnResource, Stack } from 'aws-cdk-lib'; 7 | import { CfnCluster } from 'aws-cdk-lib/aws-emr'; 8 | import { NagRuleCompliance } from '../../nag-rules'; 9 | 10 | /** 11 | * EMR clusters have S3 logging enabled 12 | * @param node the CfnResource to check 13 | */ 14 | export default Object.defineProperty( 15 | (node: CfnResource): NagRuleCompliance => { 16 | if (node instanceof CfnCluster) { 17 | const logUri = Stack.of(node).resolve(node.logUri); 18 | if (logUri == undefined) { 19 | return NagRuleCompliance.NON_COMPLIANT; 20 | } 21 | return NagRuleCompliance.COMPLIANT; 22 | } else { 23 | return NagRuleCompliance.NOT_APPLICABLE; 24 | } 25 | }, 26 | 'name', 27 | { value: parse(__filename).name } 28 | ); 29 | -------------------------------------------------------------------------------- /src/rules/emr/index.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | export { default as EMRAuthEC2KeyPairOrKerberos } from './EMRAuthEC2KeyPairOrKerberos'; 6 | export { default as EMREncryptionInTransit } from './EMREncryptionInTransit'; 7 | export { default as EMRKerberosEnabled } from './EMRKerberosEnabled'; 8 | export { default as EMRLocalDiskEncryption } from './EMRLocalDiskEncryption'; 9 | export { default as EMRS3AccessLogging } from './EMRS3AccessLogging'; 10 | -------------------------------------------------------------------------------- /src/rules/eventbridge/EventBusDLQ.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { parse } from 'path'; 6 | import { CfnResource, Stack } from 'aws-cdk-lib'; 7 | import { CfnRule } from 'aws-cdk-lib/aws-events'; 8 | import { NagRuleCompliance } from '../../nag-rules'; 9 | 10 | /** 11 | * EventBridge targets have a Dead Letter Queue configured. 12 | * @param node the CfnResource to check 13 | */ 14 | export default Object.defineProperty( 15 | (node: CfnResource): NagRuleCompliance => { 16 | if (node instanceof CfnRule) { 17 | const targets: CfnRule.TargetProperty[] = Stack.of(node).resolve( 18 | node.targets 19 | ); 20 | if (targets.every((target) => target.deadLetterConfig !== undefined)) { 21 | return NagRuleCompliance.COMPLIANT; 22 | } 23 | return NagRuleCompliance.NON_COMPLIANT; 24 | } 25 | return NagRuleCompliance.NOT_APPLICABLE; 26 | }, 27 | 'name', 28 | { value: parse(__filename).name } 29 | ); 30 | -------------------------------------------------------------------------------- /src/rules/eventbridge/index.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | export { default as EventBusOpenAccess } from './EventBusOpenAccess'; 6 | export { default as EventBusDLQ } from './EventBusDLQ'; 7 | -------------------------------------------------------------------------------- /src/rules/glue/index.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | export { default as GlueEncryptedCloudWatchLogs } from './GlueEncryptedCloudWatchLogs'; 6 | export { default as GlueJobBookmarkEncrypted } from './GlueJobBookmarkEncrypted'; 7 | -------------------------------------------------------------------------------- /src/rules/iam/IAMNoInlinePolicy.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { parse } from 'path'; 6 | import { CfnResource, Stack } from 'aws-cdk-lib'; 7 | import { CfnRole, CfnUser, CfnGroup, CfnPolicy } from 'aws-cdk-lib/aws-iam'; 8 | import { NagRuleCompliance } from '../../nag-rules'; 9 | 10 | /** 11 | * IAM Groups, Users, and Roles do not contain inline policies 12 | * @param node the CfnResource to check 13 | */ 14 | export default Object.defineProperty( 15 | (node: CfnResource): NagRuleCompliance => { 16 | if ( 17 | node instanceof CfnGroup || 18 | node instanceof CfnUser || 19 | node instanceof CfnRole 20 | ) { 21 | const inlinePolicies = Stack.of(node).resolve(node.policies); 22 | if (inlinePolicies != undefined) { 23 | return NagRuleCompliance.NON_COMPLIANT; 24 | } 25 | return NagRuleCompliance.COMPLIANT; 26 | } else if (node instanceof CfnPolicy) { 27 | return NagRuleCompliance.NON_COMPLIANT; 28 | } else { 29 | return NagRuleCompliance.NOT_APPLICABLE; 30 | } 31 | }, 32 | 'name', 33 | { value: parse(__filename).name } 34 | ); 35 | -------------------------------------------------------------------------------- /src/rules/iam/IAMNoManagedPolicies.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { parse } from 'path'; 6 | import { CfnResource, Stack } from 'aws-cdk-lib'; 7 | import { CfnRole, CfnUser, CfnGroup } from 'aws-cdk-lib/aws-iam'; 8 | import { 9 | NagRuleCompliance, 10 | NagRuleFinding, 11 | NagRuleResult, 12 | } from '../../nag-rules'; 13 | import { flattenCfnReference } from '../../utils/flatten-cfn-reference'; 14 | 15 | /** 16 | * IAM users, roles, and groups do not use AWS managed policies 17 | * @param node the CfnResource to check 18 | */ 19 | export default Object.defineProperty( 20 | (node: CfnResource): NagRuleResult => { 21 | if ( 22 | node instanceof CfnGroup || 23 | node instanceof CfnUser || 24 | node instanceof CfnRole 25 | ) { 26 | const managedPolicyArns = ( 27 | Stack.of(node).resolve(node.managedPolicyArns) 28 | ); 29 | const findings = new Set(); 30 | if (managedPolicyArns !== undefined) { 31 | managedPolicyArns 32 | .map((policy) => flattenCfnReference(Stack.of(node).resolve(policy))) 33 | .filter((policy) => policy.includes(':iam::aws:')) 34 | .forEach((policy) => findings.add(`Policy::${policy}`)); 35 | } 36 | return findings.size ? [...findings] : NagRuleCompliance.COMPLIANT; 37 | } else { 38 | return NagRuleCompliance.NOT_APPLICABLE; 39 | } 40 | }, 41 | 'name', 42 | { value: parse(__filename).name } 43 | ); 44 | -------------------------------------------------------------------------------- /src/rules/iam/IAMUserGroupMembership.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { parse } from 'path'; 6 | import { CfnResource, Stack } from 'aws-cdk-lib'; 7 | import { CfnUser } from 'aws-cdk-lib/aws-iam'; 8 | import { NagRuleCompliance } from '../../nag-rules'; 9 | 10 | /** 11 | * IAM users are assigned to at least one group 12 | * @param node the CfnResource to check 13 | */ 14 | export default Object.defineProperty( 15 | (node: CfnResource): NagRuleCompliance => { 16 | if (node instanceof CfnUser) { 17 | const userGroup = Stack.of(node).resolve(node.groups); 18 | if (userGroup == undefined) { 19 | return NagRuleCompliance.NON_COMPLIANT; 20 | } 21 | return NagRuleCompliance.COMPLIANT; 22 | } else { 23 | return NagRuleCompliance.NOT_APPLICABLE; 24 | } 25 | }, 26 | 'name', 27 | { value: parse(__filename).name } 28 | ); 29 | -------------------------------------------------------------------------------- /src/rules/iam/IAMUserNoPolicies.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { parse } from 'path'; 6 | import { CfnResource, Stack } from 'aws-cdk-lib'; 7 | import { CfnPolicy, CfnManagedPolicy, CfnUser } from 'aws-cdk-lib/aws-iam'; 8 | import { NagRuleCompliance } from '../../nag-rules'; 9 | /** 10 | * IAM policies are not attached at the user level 11 | * @param node the CfnResource to check 12 | */ 13 | export default Object.defineProperty( 14 | (node: CfnResource): NagRuleCompliance => { 15 | if (node instanceof CfnPolicy || node instanceof CfnManagedPolicy) { 16 | const policyUsers = Stack.of(node).resolve(node.users); 17 | if (policyUsers != undefined) { 18 | return NagRuleCompliance.NON_COMPLIANT; 19 | } 20 | return NagRuleCompliance.COMPLIANT; 21 | } else if (node instanceof CfnUser) { 22 | const policies = Stack.of(node).resolve(node.policies); 23 | const managedPolicyArns = Stack.of(node).resolve(node.managedPolicyArns); 24 | if (policies != undefined || managedPolicyArns != undefined) { 25 | return NagRuleCompliance.NON_COMPLIANT; 26 | } 27 | return NagRuleCompliance.COMPLIANT; 28 | } else { 29 | return NagRuleCompliance.NOT_APPLICABLE; 30 | } 31 | }, 32 | 'name', 33 | { value: parse(__filename).name } 34 | ); 35 | -------------------------------------------------------------------------------- /src/rules/iam/index.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | export { default as IAMGroupHasUsers } from './IAMGroupHasUsers'; 6 | export { default as IAMNoInlinePolicy } from './IAMNoInlinePolicy'; 7 | export { default as IAMNoManagedPolicies } from './IAMNoManagedPolicies'; 8 | export { default as IAMNoWildcardPermissions } from './IAMNoWildcardPermissions'; 9 | export { default as IAMPolicyNoStatementsWithAdminAccess } from './IAMPolicyNoStatementsWithAdminAccess'; 10 | export { default as IAMPolicyNoStatementsWithFullAccess } from './IAMPolicyNoStatementsWithFullAccess'; 11 | export { default as IAMUserGroupMembership } from './IAMUserGroupMembership'; 12 | export { default as IAMUserNoPolicies } from './IAMUserNoPolicies'; 13 | -------------------------------------------------------------------------------- /src/rules/kinesis/KinesisDataFirehoseSSE.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { parse } from 'path'; 6 | import { CfnResource, Stack } from 'aws-cdk-lib'; 7 | import { CfnDeliveryStream } from 'aws-cdk-lib/aws-kinesisfirehose'; 8 | import { NagRuleCompliance } from '../../nag-rules'; 9 | 10 | /** 11 | * Kinesis Data Firehose delivery stream have server-side encryption enabled 12 | * @param node the CfnResource to check 13 | */ 14 | export default Object.defineProperty( 15 | (node: CfnResource): NagRuleCompliance => { 16 | if (node instanceof CfnDeliveryStream) { 17 | const deliveryStreamEncryptionConfigurationInput = Stack.of(node).resolve( 18 | node.deliveryStreamEncryptionConfigurationInput 19 | ); 20 | if (deliveryStreamEncryptionConfigurationInput == undefined) { 21 | return NagRuleCompliance.NON_COMPLIANT; 22 | } 23 | return NagRuleCompliance.COMPLIANT; 24 | } else { 25 | return NagRuleCompliance.NOT_APPLICABLE; 26 | } 27 | }, 28 | 'name', 29 | { value: parse(__filename).name } 30 | ); 31 | -------------------------------------------------------------------------------- /src/rules/kinesis/KinesisDataStreamDefaultKeyWhenSSE.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { parse } from 'path'; 6 | import { CfnResource, Stack } from 'aws-cdk-lib'; 7 | import { CfnStream } from 'aws-cdk-lib/aws-kinesis'; 8 | import { NagRuleCompliance } from '../../nag-rules'; 9 | 10 | /** 11 | * Kinesis Data Streams use the "aws/kinesis" key when server-sided encryption is enabled 12 | * @param node the CfnResource to check 13 | */ 14 | export default Object.defineProperty( 15 | (node: CfnResource): NagRuleCompliance => { 16 | if (node instanceof CfnStream) { 17 | const streamEncryption = Stack.of(node).resolve(node.streamEncryption); 18 | if (streamEncryption !== undefined) { 19 | if (streamEncryption.keyId !== 'alias/aws/kinesis') { 20 | return NagRuleCompliance.NON_COMPLIANT; 21 | } 22 | } 23 | return NagRuleCompliance.COMPLIANT; 24 | } else { 25 | return NagRuleCompliance.NOT_APPLICABLE; 26 | } 27 | }, 28 | 'name', 29 | { value: parse(__filename).name } 30 | ); 31 | -------------------------------------------------------------------------------- /src/rules/kinesis/KinesisDataStreamSSE.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { parse } from 'path'; 6 | import { CfnResource, Stack } from 'aws-cdk-lib'; 7 | import { CfnStream } from 'aws-cdk-lib/aws-kinesis'; 8 | import { NagRuleCompliance } from '../../nag-rules'; 9 | 10 | /** 11 | * Kinesis Data Streams have server-side encryption enabled 12 | * @param node the CfnResource to check 13 | */ 14 | export default Object.defineProperty( 15 | (node: CfnResource): NagRuleCompliance => { 16 | if (node instanceof CfnStream) { 17 | const streamEncryption = Stack.of(node).resolve(node.streamEncryption); 18 | if (streamEncryption == undefined) { 19 | return NagRuleCompliance.NON_COMPLIANT; 20 | } 21 | return NagRuleCompliance.COMPLIANT; 22 | } else { 23 | return NagRuleCompliance.NOT_APPLICABLE; 24 | } 25 | }, 26 | 'name', 27 | { value: parse(__filename).name } 28 | ); 29 | -------------------------------------------------------------------------------- /src/rules/kinesis/index.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | export { default as KinesisDataAnalyticsFlinkCheckpointing } from './KinesisDataAnalyticsFlinkCheckpointing'; 6 | export { default as KinesisDataFirehoseSSE } from './KinesisDataFirehoseSSE'; 7 | export { default as KinesisDataStreamDefaultKeyWhenSSE } from './KinesisDataStreamDefaultKeyWhenSSE'; 8 | export { default as KinesisDataStreamSSE } from './KinesisDataStreamSSE'; 9 | -------------------------------------------------------------------------------- /src/rules/kms/KMSBackingKeyRotationEnabled.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { parse } from 'path'; 6 | import { CfnResource, Stack } from 'aws-cdk-lib'; 7 | import { CfnKey, KeySpec } from 'aws-cdk-lib/aws-kms'; 8 | import { NagRuleCompliance, NagRules } from '../../nag-rules'; 9 | 10 | /** 11 | * KMS Symmetric keys have automatic key rotation enabled 12 | * @param node the CfnResource to check 13 | */ 14 | export default Object.defineProperty( 15 | (node: CfnResource): NagRuleCompliance => { 16 | if (node instanceof CfnKey) { 17 | const keySpec = Stack.of(node).resolve(node.keySpec); 18 | if (keySpec == undefined || keySpec == KeySpec.SYMMETRIC_DEFAULT) { 19 | const enableKeyRotation = NagRules.resolveIfPrimitive( 20 | node, 21 | node.enableKeyRotation 22 | ); 23 | if (enableKeyRotation !== true) { 24 | return NagRuleCompliance.NON_COMPLIANT; 25 | } 26 | } 27 | return NagRuleCompliance.COMPLIANT; 28 | } else { 29 | return NagRuleCompliance.NOT_APPLICABLE; 30 | } 31 | }, 32 | 'name', 33 | { value: parse(__filename).name } 34 | ); 35 | -------------------------------------------------------------------------------- /src/rules/kms/index.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | export { default as KMSBackingKeyRotationEnabled } from './KMSBackingKeyRotationEnabled'; 6 | -------------------------------------------------------------------------------- /src/rules/lambda/LambdaAsyncFailureDestination.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { parse } from 'path'; 6 | import { CfnResource, Stack } from 'aws-cdk-lib'; 7 | import { CfnEventInvokeConfig } from 'aws-cdk-lib/aws-lambda'; 8 | import { NagRuleCompliance } from '../../nag-rules'; 9 | 10 | /** 11 | * Lambda functions with asynchronous invocations should have a failure destination 12 | * @param node the CfnResource to check 13 | */ 14 | export default Object.defineProperty( 15 | (node: CfnResource): NagRuleCompliance => { 16 | if (node instanceof CfnEventInvokeConfig) { 17 | const destinationConfig = Stack.of(node).resolve(node.destinationConfig); 18 | if (destinationConfig?.onFailure?.destination) { 19 | return NagRuleCompliance.COMPLIANT; 20 | } 21 | return NagRuleCompliance.NON_COMPLIANT; 22 | } 23 | return NagRuleCompliance.NOT_APPLICABLE; 24 | }, 25 | 'name', 26 | { value: parse(__filename).name } 27 | ); 28 | -------------------------------------------------------------------------------- /src/rules/lambda/LambdaConcurrency.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { parse } from 'path'; 6 | import { CfnResource } from 'aws-cdk-lib'; 7 | import { CfnFunction } from 'aws-cdk-lib/aws-lambda'; 8 | import { NagRuleCompliance, NagRules } from '../../nag-rules'; 9 | 10 | /** 11 | * Lambda functions are configured with function-level concurrent execution limits 12 | * @param node the CfnResource to check 13 | */ 14 | export default Object.defineProperty( 15 | (node: CfnResource): NagRuleCompliance => { 16 | if (node instanceof CfnFunction) { 17 | const reservedConcurrentExecutions = NagRules.resolveIfPrimitive( 18 | node, 19 | node.reservedConcurrentExecutions 20 | ); 21 | if ( 22 | reservedConcurrentExecutions == undefined || 23 | reservedConcurrentExecutions === 0 24 | ) { 25 | return NagRuleCompliance.NON_COMPLIANT; 26 | } 27 | return NagRuleCompliance.COMPLIANT; 28 | } else { 29 | return NagRuleCompliance.NOT_APPLICABLE; 30 | } 31 | }, 32 | 'name', 33 | { value: parse(__filename).name } 34 | ); 35 | -------------------------------------------------------------------------------- /src/rules/lambda/LambdaDLQ.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { parse } from 'path'; 6 | import { CfnResource, Stack } from 'aws-cdk-lib'; 7 | import { CfnFunction } from 'aws-cdk-lib/aws-lambda'; 8 | import { NagRuleCompliance } from '../../nag-rules'; 9 | 10 | /** 11 | * Lambda functions are configured with a dead-letter configuration 12 | * @param node the CfnResource to check 13 | */ 14 | export default Object.defineProperty( 15 | (node: CfnResource): NagRuleCompliance => { 16 | if (node instanceof CfnFunction) { 17 | const deadLetterConfig = Stack.of(node).resolve(node.deadLetterConfig); 18 | if ( 19 | deadLetterConfig == undefined || 20 | deadLetterConfig.targetArn == undefined 21 | ) { 22 | return NagRuleCompliance.NON_COMPLIANT; 23 | } 24 | return NagRuleCompliance.COMPLIANT; 25 | } else { 26 | return NagRuleCompliance.NOT_APPLICABLE; 27 | } 28 | }, 29 | 'name', 30 | { value: parse(__filename).name } 31 | ); 32 | -------------------------------------------------------------------------------- /src/rules/lambda/LambdaDefaultMemorySize.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { parse } from 'path'; 6 | import { CfnResource, Stack } from 'aws-cdk-lib'; 7 | import { CfnFunction } from 'aws-cdk-lib/aws-lambda'; 8 | import { NagRuleCompliance } from '../../nag-rules'; 9 | 10 | /** 11 | * Lambda functions should have an explicitly defined amount of memory configured. 12 | * @param node the CfnResource to check 13 | */ 14 | export default Object.defineProperty( 15 | (node: CfnResource): NagRuleCompliance => { 16 | if (node instanceof CfnFunction) { 17 | const memorySize = Stack.of(node).resolve(node.memorySize); 18 | if (memorySize) { 19 | return NagRuleCompliance.COMPLIANT; 20 | } 21 | return NagRuleCompliance.NON_COMPLIANT; 22 | } 23 | return NagRuleCompliance.NOT_APPLICABLE; 24 | }, 25 | 'name', 26 | { value: parse(__filename).name } 27 | ); 28 | -------------------------------------------------------------------------------- /src/rules/lambda/LambdaDefaultTimeout.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { parse } from 'path'; 6 | import { CfnResource, Stack } from 'aws-cdk-lib'; 7 | import { CfnFunction } from 'aws-cdk-lib/aws-lambda'; 8 | import { NagRuleCompliance } from '../../nag-rules'; 9 | 10 | /** 11 | * Lambda functions must have an explicitly defined timeout value. 12 | * @param node the CfnResource to check 13 | */ 14 | export default Object.defineProperty( 15 | (node: CfnResource): NagRuleCompliance => { 16 | if (node instanceof CfnFunction) { 17 | const timeout = Stack.of(node).resolve(node.timeout); 18 | if (timeout) { 19 | return NagRuleCompliance.COMPLIANT; 20 | } 21 | return NagRuleCompliance.NON_COMPLIANT; 22 | } 23 | return NagRuleCompliance.NOT_APPLICABLE; 24 | }, 25 | 'name', 26 | { value: parse(__filename).name } 27 | ); 28 | -------------------------------------------------------------------------------- /src/rules/lambda/LambdaEventSourceMappingDestination.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { CfnResource, Stack } from 'aws-cdk-lib'; 6 | import { CfnEventSourceMapping } from 'aws-cdk-lib/aws-lambda'; 7 | import { NagRuleCompliance } from '../../nag-rules'; 8 | 9 | /** 10 | * Lambda Event Source Mappings must have a destination configured for failed invocations. 11 | * 12 | * @param node - The CfnResource to check 13 | */ 14 | export default function LambdaEventSourceMappingDestination( 15 | node: CfnResource 16 | ): NagRuleCompliance { 17 | if (node instanceof CfnEventSourceMapping) { 18 | const destinationConfig = Stack.of(node).resolve(node.destinationConfig); 19 | if ( 20 | destinationConfig?.onFailure && 21 | destinationConfig?.onFailure?.destination 22 | ) { 23 | return NagRuleCompliance.COMPLIANT; 24 | } 25 | return NagRuleCompliance.NON_COMPLIANT; 26 | } 27 | return NagRuleCompliance.NOT_APPLICABLE; 28 | } 29 | -------------------------------------------------------------------------------- /src/rules/lambda/LambdaFunctionPublicAccessProhibited.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { parse } from 'path'; 6 | import { CfnResource, Stack } from 'aws-cdk-lib'; 7 | import { CfnPermission } from 'aws-cdk-lib/aws-lambda'; 8 | import { NagRuleCompliance } from '../../nag-rules'; 9 | 10 | /** 11 | * Lambda function permissions do not grant public access 12 | * @param node the CfnResource to check 13 | */ 14 | export default Object.defineProperty( 15 | (node: CfnResource): NagRuleCompliance => { 16 | if (node instanceof CfnPermission) { 17 | if ( 18 | Stack.of(node).resolve(node.principal) === '*' && 19 | node.principalOrgId === undefined && 20 | node.sourceAccount === undefined && 21 | node.sourceArn === undefined 22 | ) { 23 | return NagRuleCompliance.NON_COMPLIANT; 24 | } 25 | return NagRuleCompliance.COMPLIANT; 26 | } else { 27 | return NagRuleCompliance.NOT_APPLICABLE; 28 | } 29 | }, 30 | 'name', 31 | { value: parse(__filename).name } 32 | ); 33 | -------------------------------------------------------------------------------- /src/rules/lambda/LambdaFunctionUrlAuth.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { parse } from 'path'; 6 | import { CfnResource } from 'aws-cdk-lib'; 7 | import { CfnUrl, FunctionUrlAuthType } from 'aws-cdk-lib/aws-lambda'; 8 | import { NagRuleCompliance } from '../../nag-rules'; 9 | 10 | /** 11 | * Lambda function URLs require Auth 12 | * @param node the CfnResource to check 13 | */ 14 | export default Object.defineProperty( 15 | (node: CfnResource): NagRuleCompliance => { 16 | if (node instanceof CfnUrl) { 17 | if (node.authType === FunctionUrlAuthType.NONE) { 18 | return NagRuleCompliance.NON_COMPLIANT; 19 | } 20 | return NagRuleCompliance.COMPLIANT; 21 | } else { 22 | return NagRuleCompliance.NOT_APPLICABLE; 23 | } 24 | }, 25 | 'name', 26 | { value: parse(__filename).name } 27 | ); 28 | -------------------------------------------------------------------------------- /src/rules/lambda/LambdaInsideVPC.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { parse } from 'path'; 6 | import { CfnResource, Stack } from 'aws-cdk-lib'; 7 | import { CfnFunction } from 'aws-cdk-lib/aws-lambda'; 8 | import { NagRuleCompliance } from '../../nag-rules'; 9 | 10 | /** 11 | * Lambda functions are VPC enabled 12 | * @param node the CfnResource to check 13 | */ 14 | export default Object.defineProperty( 15 | (node: CfnResource): NagRuleCompliance => { 16 | if (node instanceof CfnFunction) { 17 | const vpcConfig = Stack.of(node).resolve(node.vpcConfig); 18 | if (vpcConfig == undefined) { 19 | return NagRuleCompliance.NON_COMPLIANT; 20 | } else { 21 | const secgroups = Stack.of(node).resolve(vpcConfig.securityGroupIds); 22 | const subnets = Stack.of(node).resolve(vpcConfig.subnetIds); 23 | if (secgroups == undefined || secgroups.length == 0) { 24 | if (subnets == undefined || subnets.length == 0) { 25 | return NagRuleCompliance.NON_COMPLIANT; 26 | } 27 | } 28 | } 29 | return NagRuleCompliance.COMPLIANT; 30 | } else { 31 | return NagRuleCompliance.NOT_APPLICABLE; 32 | } 33 | }, 34 | 'name', 35 | { value: parse(__filename).name } 36 | ); 37 | -------------------------------------------------------------------------------- /src/rules/lambda/LambdaLogLevel.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { parse } from 'path'; 6 | import { CfnResource, Stack } from 'aws-cdk-lib'; 7 | import { CfnFunction } from 'aws-cdk-lib/aws-lambda'; 8 | import { NagRuleCompliance } from '../../nag-rules'; 9 | 10 | /** 11 | * Ensure that Lambda functions have a corresponding Log Group with an explicit retention period configured. 12 | * @param node the CfnResource to check 13 | */ 14 | export default Object.defineProperty( 15 | (node: CfnResource): NagRuleCompliance => { 16 | if (node instanceof CfnFunction) { 17 | const loggingConfig = Stack.of(node).resolve(node.loggingConfig); 18 | if (loggingConfig && loggingConfig.logGroup && loggingConfig.retention) { 19 | return NagRuleCompliance.COMPLIANT; 20 | } 21 | return NagRuleCompliance.NON_COMPLIANT; 22 | } 23 | return NagRuleCompliance.NOT_APPLICABLE; 24 | }, 25 | 'name', 26 | { value: parse(__filename).name } 27 | ); 28 | -------------------------------------------------------------------------------- /src/rules/lambda/LambdaLogging.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { parse } from 'path'; 6 | import { CfnResource, Stack } from 'aws-cdk-lib'; 7 | import { CfnFunction } from 'aws-cdk-lib/aws-lambda'; 8 | import { NagRuleCompliance } from '../../nag-rules'; 9 | 10 | /** 11 | * Ensure that Lambda functions have a corresponding Log Group 12 | * @param node the CfnResource to check 13 | */ 14 | export default Object.defineProperty( 15 | (node: CfnResource): NagRuleCompliance => { 16 | if (node instanceof CfnFunction) { 17 | const loggingConfig = Stack.of(node).resolve(node.loggingConfig); 18 | if (loggingConfig) return NagRuleCompliance.COMPLIANT; 19 | return NagRuleCompliance.NON_COMPLIANT; 20 | } 21 | return NagRuleCompliance.NOT_APPLICABLE; 22 | }, 23 | 'name', 24 | { value: parse(__filename).name } 25 | ); 26 | -------------------------------------------------------------------------------- /src/rules/lambda/LambdaTracing.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { parse } from 'path'; 6 | import { CfnResource, Stack } from 'aws-cdk-lib'; 7 | import { CfnFunction } from 'aws-cdk-lib/aws-lambda'; 8 | import { NagRuleCompliance } from '../../nag-rules'; 9 | 10 | /** 11 | * Ensure Lambda functions have tracing enabled 12 | * @param node the CfnResource to check 13 | */ 14 | export default Object.defineProperty( 15 | (node: CfnResource): NagRuleCompliance => { 16 | if (node instanceof CfnFunction) { 17 | const tracingConfig = Stack.of(node).resolve(node.tracingConfig) as 18 | | CfnFunction.TracingConfigProperty 19 | | undefined; 20 | if (tracingConfig?.mode === 'Active') return NagRuleCompliance.COMPLIANT; 21 | return NagRuleCompliance.NON_COMPLIANT; 22 | } 23 | return NagRuleCompliance.NOT_APPLICABLE; 24 | }, 25 | 'name', 26 | { value: parse(__filename).name } 27 | ); 28 | -------------------------------------------------------------------------------- /src/rules/lambda/index.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | 6 | export { default as LambdaAsyncFailureDestination } from './LambdaAsyncFailureDestination'; 7 | export { default as LambdaConcurrency } from './LambdaConcurrency'; 8 | export { default as LambdaDefaultMemorySize } from './LambdaDefaultMemorySize'; 9 | export { default as LambdaDefaultTimeout } from './LambdaDefaultTimeout'; 10 | export { default as LambdaDLQ } from './LambdaDLQ'; 11 | export { default as LambdaEventSourceMappingDestination } from './LambdaEventSourceMappingDestination'; 12 | export { default as LambdaEventSourceSQSVisibilityTimeout } from './LambdaEventSourceSQSVisibilityTimeout'; 13 | export { default as LambdaFunctionPublicAccessProhibited } from './LambdaFunctionPublicAccessProhibited'; 14 | export { default as LambdaFunctionUrlAuth } from './LambdaFunctionUrlAuth'; 15 | export { default as LambdaInsideVPC } from './LambdaInsideVPC'; 16 | export { default as LambdaLatestVersion } from './LambdaLatestVersion'; 17 | export { default as LambdaStarPermissions } from './LambdaStarPermissions'; 18 | export { default as LambdaTracing } from './LambdaTracing'; 19 | -------------------------------------------------------------------------------- /src/rules/lex/index.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | export { default as LexBotAliasEncryptedConversationLogs } from './LexBotAliasEncryptedConversationLogs'; 6 | -------------------------------------------------------------------------------- /src/rules/mediastore/MediaStoreCloudWatchMetricPolicy.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { parse } from 'path'; 6 | import { CfnResource, Stack } from 'aws-cdk-lib'; 7 | import { CfnContainer } from 'aws-cdk-lib/aws-mediastore'; 8 | import { NagRuleCompliance, NagRules } from '../../nag-rules'; 9 | 10 | /** 11 | * Media Store containers define metric policies to send metrics to CloudWatch 12 | * @param node the CfnResource to check 13 | */ 14 | export default Object.defineProperty( 15 | (node: CfnResource): NagRuleCompliance => { 16 | if (node instanceof CfnContainer) { 17 | const metricPolicy = Stack.of(node).resolve(node.metricPolicy); 18 | if (metricPolicy == undefined) { 19 | return NagRuleCompliance.NON_COMPLIANT; 20 | } 21 | const containerLevelMetrics = NagRules.resolveIfPrimitive( 22 | node, 23 | metricPolicy.containerLevelMetrics 24 | ); 25 | if (containerLevelMetrics != 'ENABLED') { 26 | return NagRuleCompliance.NON_COMPLIANT; 27 | } 28 | return NagRuleCompliance.COMPLIANT; 29 | } else { 30 | return NagRuleCompliance.NOT_APPLICABLE; 31 | } 32 | }, 33 | 'name', 34 | { value: parse(__filename).name } 35 | ); 36 | -------------------------------------------------------------------------------- /src/rules/mediastore/MediaStoreContainerAccessLogging.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { parse } from 'path'; 6 | import { CfnResource } from 'aws-cdk-lib'; 7 | import { CfnContainer } from 'aws-cdk-lib/aws-mediastore'; 8 | import { NagRuleCompliance, NagRules } from '../../nag-rules'; 9 | 10 | /** 11 | * Media Store containers have container access logging enabled 12 | * @param node the CfnResource to check 13 | */ 14 | export default Object.defineProperty( 15 | (node: CfnResource): NagRuleCompliance => { 16 | if (node instanceof CfnContainer) { 17 | const accessLoggingEnabled = NagRules.resolveIfPrimitive( 18 | node, 19 | node.accessLoggingEnabled 20 | ); 21 | if (accessLoggingEnabled !== true) { 22 | return NagRuleCompliance.NON_COMPLIANT; 23 | } 24 | return NagRuleCompliance.COMPLIANT; 25 | } else { 26 | return NagRuleCompliance.NOT_APPLICABLE; 27 | } 28 | }, 29 | 'name', 30 | { value: parse(__filename).name } 31 | ); 32 | -------------------------------------------------------------------------------- /src/rules/mediastore/MediaStoreContainerCORSPolicy.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { parse } from 'path'; 6 | import { CfnResource, Stack } from 'aws-cdk-lib'; 7 | import { CfnContainer } from 'aws-cdk-lib/aws-mediastore'; 8 | import { NagRuleCompliance } from '../../nag-rules'; 9 | 10 | /** 11 | * Media Store containers define CORS policies 12 | * @param node the CfnResource to check 13 | */ 14 | export default Object.defineProperty( 15 | (node: CfnResource): NagRuleCompliance => { 16 | if (node instanceof CfnContainer) { 17 | const corsPolicy = Stack.of(node).resolve(node.corsPolicy); 18 | if (corsPolicy == undefined || corsPolicy.length == 0) { 19 | return NagRuleCompliance.NON_COMPLIANT; 20 | } 21 | return NagRuleCompliance.COMPLIANT; 22 | } else { 23 | return NagRuleCompliance.NOT_APPLICABLE; 24 | } 25 | }, 26 | 'name', 27 | { value: parse(__filename).name } 28 | ); 29 | -------------------------------------------------------------------------------- /src/rules/mediastore/MediaStoreContainerHasContainerPolicy.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { parse } from 'path'; 6 | import { CfnResource, Stack } from 'aws-cdk-lib'; 7 | import { CfnContainer } from 'aws-cdk-lib/aws-mediastore'; 8 | import { NagRuleCompliance } from '../../nag-rules'; 9 | 10 | /** 11 | * Media Store containers define container policies 12 | * @param node the CfnResource to check 13 | */ 14 | export default Object.defineProperty( 15 | (node: CfnResource): NagRuleCompliance => { 16 | if (node instanceof CfnContainer) { 17 | const policy = Stack.of(node).resolve(node.policy); 18 | if (policy == undefined) { 19 | return NagRuleCompliance.NON_COMPLIANT; 20 | } 21 | return NagRuleCompliance.COMPLIANT; 22 | } else { 23 | return NagRuleCompliance.NOT_APPLICABLE; 24 | } 25 | }, 26 | 'name', 27 | { value: parse(__filename).name } 28 | ); 29 | -------------------------------------------------------------------------------- /src/rules/mediastore/MediaStoreContainerLifecyclePolicy.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { parse } from 'path'; 6 | import { CfnResource, Stack } from 'aws-cdk-lib'; 7 | import { CfnContainer } from 'aws-cdk-lib/aws-mediastore'; 8 | import { NagRuleCompliance } from '../../nag-rules'; 9 | 10 | /** 11 | * Media Store containers define lifecycle policies 12 | * @param node the CfnResource to check 13 | */ 14 | export default Object.defineProperty( 15 | (node: CfnResource): NagRuleCompliance => { 16 | if (node instanceof CfnContainer) { 17 | const lifecyclePolicy = Stack.of(node).resolve(node.lifecyclePolicy); 18 | if (lifecyclePolicy == undefined) { 19 | return NagRuleCompliance.NON_COMPLIANT; 20 | } 21 | return NagRuleCompliance.COMPLIANT; 22 | } else { 23 | return NagRuleCompliance.NOT_APPLICABLE; 24 | } 25 | }, 26 | 'name', 27 | { value: parse(__filename).name } 28 | ); 29 | -------------------------------------------------------------------------------- /src/rules/mediastore/index.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | export { default as MediaStoreCloudWatchMetricPolicy } from './MediaStoreCloudWatchMetricPolicy'; 6 | export { default as MediaStoreContainerAccessLogging } from './MediaStoreContainerAccessLogging'; 7 | export { default as MediaStoreContainerCORSPolicy } from './MediaStoreContainerCORSPolicy'; 8 | export { default as MediaStoreContainerHasContainerPolicy } from './MediaStoreContainerHasContainerPolicy'; 9 | export { default as MediaStoreContainerLifecyclePolicy } from './MediaStoreContainerLifecyclePolicy'; 10 | export { default as MediaStoreContainerSSLRequestsOnly } from './MediaStoreContainerSSLRequestsOnly'; 11 | -------------------------------------------------------------------------------- /src/rules/msk/MSKBrokerToBrokerTLS.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { parse } from 'path'; 6 | import { CfnResource, Stack } from 'aws-cdk-lib'; 7 | import { CfnCluster } from 'aws-cdk-lib/aws-msk'; 8 | import { NagRuleCompliance, NagRules } from '../../nag-rules'; 9 | 10 | /** 11 | * MSK clusters use TLS communication between brokers 12 | * @param node the CfnResource to check 13 | */ 14 | export default Object.defineProperty( 15 | (node: CfnResource): NagRuleCompliance => { 16 | if (node instanceof CfnCluster) { 17 | const encryptionInfo = Stack.of(node).resolve(node.encryptionInfo); 18 | if (encryptionInfo != undefined) { 19 | const encryptionInTransit = Stack.of(node).resolve( 20 | encryptionInfo.encryptionInTransit 21 | ); 22 | if (encryptionInTransit != undefined) { 23 | const inCluster = NagRules.resolveIfPrimitive( 24 | node, 25 | encryptionInTransit.inCluster 26 | ); 27 | if (inCluster === false) { 28 | return NagRuleCompliance.NON_COMPLIANT; 29 | } 30 | } 31 | } 32 | return NagRuleCompliance.COMPLIANT; 33 | } else { 34 | return NagRuleCompliance.NOT_APPLICABLE; 35 | } 36 | }, 37 | 'name', 38 | { value: parse(__filename).name } 39 | ); 40 | -------------------------------------------------------------------------------- /src/rules/msk/MSKClientToBrokerTLS.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { parse } from 'path'; 6 | import { CfnResource, Stack } from 'aws-cdk-lib'; 7 | import { CfnCluster } from 'aws-cdk-lib/aws-msk'; 8 | import { NagRuleCompliance, NagRules } from '../../nag-rules'; 9 | 10 | /** 11 | * MSK clusters only uses TLS communication between clients and brokers 12 | * @param node the CfnResource to check 13 | */ 14 | export default Object.defineProperty( 15 | (node: CfnResource): NagRuleCompliance => { 16 | if (node instanceof CfnCluster) { 17 | const encryptionInfo = Stack.of(node).resolve(node.encryptionInfo); 18 | if (encryptionInfo != undefined) { 19 | const encryptionInTransit = Stack.of(node).resolve( 20 | encryptionInfo.encryptionInTransit 21 | ); 22 | if (encryptionInTransit != undefined) { 23 | const clientBroker = NagRules.resolveIfPrimitive( 24 | node, 25 | encryptionInTransit.clientBroker 26 | ); 27 | if (clientBroker != undefined && clientBroker != 'TLS') { 28 | return NagRuleCompliance.NON_COMPLIANT; 29 | } 30 | } 31 | } 32 | return NagRuleCompliance.COMPLIANT; 33 | } else { 34 | return NagRuleCompliance.NOT_APPLICABLE; 35 | } 36 | }, 37 | 'name', 38 | { value: parse(__filename).name } 39 | ); 40 | -------------------------------------------------------------------------------- /src/rules/msk/index.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | export { default as MSKBrokerLogging } from './MSKBrokerLogging'; 6 | export { default as MSKBrokerToBrokerTLS } from './MSKBrokerToBrokerTLS'; 7 | export { default as MSKClientToBrokerTLS } from './MSKClientToBrokerTLS'; 8 | -------------------------------------------------------------------------------- /src/rules/neptune/NeptuneClusterAutomaticMinorVersionUpgrade.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { parse } from 'path'; 6 | import { CfnResource } from 'aws-cdk-lib'; 7 | import { CfnDBInstance } from 'aws-cdk-lib/aws-neptune'; 8 | import { NagRuleCompliance, NagRules } from '../../nag-rules'; 9 | 10 | /** 11 | * Neptune DB instances have Auto Minor Version Upgrade enabled 12 | * @param node the CfnResource to check 13 | */ 14 | export default Object.defineProperty( 15 | (node: CfnResource): NagRuleCompliance => { 16 | if (node instanceof CfnDBInstance) { 17 | if (node.autoMinorVersionUpgrade == undefined) { 18 | return NagRuleCompliance.NON_COMPLIANT; 19 | } 20 | const autoMinorVersionUpgrade = NagRules.resolveIfPrimitive( 21 | node, 22 | node.autoMinorVersionUpgrade 23 | ); 24 | if (!autoMinorVersionUpgrade) { 25 | return NagRuleCompliance.NON_COMPLIANT; 26 | } 27 | return NagRuleCompliance.COMPLIANT; 28 | } else { 29 | return NagRuleCompliance.NOT_APPLICABLE; 30 | } 31 | }, 32 | 'name', 33 | { value: parse(__filename).name } 34 | ); 35 | -------------------------------------------------------------------------------- /src/rules/neptune/NeptuneClusterBackupRetentionPeriod.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { parse } from 'path'; 6 | import { CfnResource } from 'aws-cdk-lib'; 7 | import { CfnDBCluster } from 'aws-cdk-lib/aws-neptune'; 8 | import { NagRuleCompliance, NagRules } from '../../nag-rules'; 9 | 10 | /** 11 | * Neptune DB clusters have a reasonable minimum backup retention period configured 12 | * @param node the CfnResource to check 13 | */ 14 | export default Object.defineProperty( 15 | (node: CfnResource): NagRuleCompliance => { 16 | if (node instanceof CfnDBCluster) { 17 | const backupRetentionPeriod = NagRules.resolveIfPrimitive( 18 | node, 19 | node.backupRetentionPeriod 20 | ); 21 | if (backupRetentionPeriod == undefined || backupRetentionPeriod < 7) { 22 | return NagRuleCompliance.NON_COMPLIANT; 23 | } 24 | return NagRuleCompliance.COMPLIANT; 25 | } else { 26 | return NagRuleCompliance.NOT_APPLICABLE; 27 | } 28 | }, 29 | 'name', 30 | { value: parse(__filename).name } 31 | ); 32 | -------------------------------------------------------------------------------- /src/rules/neptune/NeptuneClusterEncryptionAtRest.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { parse } from 'path'; 6 | import { CfnResource } from 'aws-cdk-lib'; 7 | import { CfnDBCluster } from 'aws-cdk-lib/aws-neptune'; 8 | import { NagRuleCompliance, NagRules } from '../../nag-rules'; 9 | 10 | /** 11 | * Neptune DB clusters have encryption at rest enabled 12 | * @param node the CfnResource to check 13 | */ 14 | export default Object.defineProperty( 15 | (node: CfnResource): NagRuleCompliance => { 16 | if (node instanceof CfnDBCluster) { 17 | if (node.storageEncrypted == undefined) { 18 | return NagRuleCompliance.NON_COMPLIANT; 19 | } 20 | const storageEncrypted = NagRules.resolveIfPrimitive( 21 | node, 22 | node.storageEncrypted 23 | ); 24 | if (!storageEncrypted) { 25 | return NagRuleCompliance.NON_COMPLIANT; 26 | } 27 | return NagRuleCompliance.COMPLIANT; 28 | } else { 29 | return NagRuleCompliance.NOT_APPLICABLE; 30 | } 31 | }, 32 | 'name', 33 | { value: parse(__filename).name } 34 | ); 35 | -------------------------------------------------------------------------------- /src/rules/neptune/NeptuneClusterIAMAuth.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { parse } from 'path'; 6 | import { CfnResource } from 'aws-cdk-lib'; 7 | import { CfnDBCluster } from 'aws-cdk-lib/aws-neptune'; 8 | import { NagRuleCompliance, NagRules } from '../../nag-rules'; 9 | 10 | /** 11 | * Neptune DB clusters have IAM Database Authentication enabled 12 | * @param node the CfnResource to check 13 | */ 14 | export default Object.defineProperty( 15 | (node: CfnResource): NagRuleCompliance => { 16 | if (node instanceof CfnDBCluster) { 17 | if (node.iamAuthEnabled == undefined) { 18 | return NagRuleCompliance.NON_COMPLIANT; 19 | } 20 | const iamAuthEnabled = NagRules.resolveIfPrimitive( 21 | node, 22 | node.iamAuthEnabled 23 | ); 24 | if (!iamAuthEnabled) { 25 | return NagRuleCompliance.NON_COMPLIANT; 26 | } 27 | return NagRuleCompliance.COMPLIANT; 28 | } else { 29 | return NagRuleCompliance.NOT_APPLICABLE; 30 | } 31 | }, 32 | 'name', 33 | { value: parse(__filename).name } 34 | ); 35 | -------------------------------------------------------------------------------- /src/rules/neptune/NeptuneClusterMultiAZ.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { parse } from 'path'; 6 | import { CfnResource } from 'aws-cdk-lib'; 7 | import { CfnDBCluster } from 'aws-cdk-lib/aws-neptune'; 8 | import { NagRuleCompliance } from '../../nag-rules'; 9 | 10 | /** 11 | * Neptune DB clusters are deployed in a Multi-AZ configuration 12 | * @param node the CfnResource to check 13 | */ 14 | export default Object.defineProperty( 15 | (node: CfnResource): NagRuleCompliance => { 16 | if (node instanceof CfnDBCluster) { 17 | if (node.dbSubnetGroupName == undefined) { 18 | return NagRuleCompliance.NON_COMPLIANT; 19 | } 20 | if ( 21 | node.availabilityZones != undefined && 22 | node.availabilityZones.length < 2 23 | ) { 24 | return NagRuleCompliance.NON_COMPLIANT; 25 | } 26 | return NagRuleCompliance.COMPLIANT; 27 | } else { 28 | return NagRuleCompliance.NOT_APPLICABLE; 29 | } 30 | }, 31 | 'name', 32 | { value: parse(__filename).name } 33 | ); 34 | -------------------------------------------------------------------------------- /src/rules/neptune/index.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | export { default as NeptuneClusterMultiAZ } from './NeptuneClusterMultiAZ'; 6 | export { default as NeptuneClusterAutomaticMinorVersionUpgrade } from './NeptuneClusterAutomaticMinorVersionUpgrade'; 7 | export { default as NeptuneClusterBackupRetentionPeriod } from './NeptuneClusterBackupRetentionPeriod'; 8 | export { default as NeptuneClusterEncryptionAtRest } from './NeptuneClusterEncryptionAtRest'; 9 | export { default as NeptuneClusterIAMAuth } from './NeptuneClusterIAMAuth'; 10 | -------------------------------------------------------------------------------- /src/rules/opensearch/OpenSearchEncryptedAtRest.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { parse } from 'path'; 6 | import { CfnResource, Stack } from 'aws-cdk-lib'; 7 | import { CfnDomain as LegacyCfnDomain } from 'aws-cdk-lib/aws-elasticsearch'; 8 | import { CfnDomain } from 'aws-cdk-lib/aws-opensearchservice'; 9 | import { NagRuleCompliance, NagRules } from '../../nag-rules'; 10 | 11 | /** 12 | * OpenSearch Service domains have encryption at rest enabled 13 | * @param node the CfnResource to check 14 | */ 15 | export default Object.defineProperty( 16 | (node: CfnResource): NagRuleCompliance => { 17 | if (node instanceof LegacyCfnDomain || node instanceof CfnDomain) { 18 | const encryptionAtRestOptions = Stack.of(node).resolve( 19 | node.encryptionAtRestOptions 20 | ); 21 | if (encryptionAtRestOptions !== undefined) { 22 | const enabled = NagRules.resolveIfPrimitive( 23 | node, 24 | encryptionAtRestOptions.enabled 25 | ); 26 | if (enabled !== true) { 27 | return NagRuleCompliance.NON_COMPLIANT; 28 | } 29 | } else { 30 | return NagRuleCompliance.NON_COMPLIANT; 31 | } 32 | return NagRuleCompliance.COMPLIANT; 33 | } else { 34 | return NagRuleCompliance.NOT_APPLICABLE; 35 | } 36 | }, 37 | 'name', 38 | { value: parse(__filename).name } 39 | ); 40 | -------------------------------------------------------------------------------- /src/rules/opensearch/OpenSearchErrorLogsToCloudWatch.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { parse } from 'path'; 6 | import { CfnResource, Stack } from 'aws-cdk-lib'; 7 | import { CfnDomain as LegacyCfnDomain } from 'aws-cdk-lib/aws-elasticsearch'; 8 | import { CfnDomain } from 'aws-cdk-lib/aws-opensearchservice'; 9 | import { NagRuleCompliance } from '../../nag-rules'; 10 | 11 | /** 12 | * OpenSearch Service domains stream error logs to CloudWatch Logs 13 | * @param node the CfnResource to check 14 | */ 15 | export default Object.defineProperty( 16 | (node: CfnResource): NagRuleCompliance => { 17 | if (node instanceof LegacyCfnDomain || node instanceof CfnDomain) { 18 | const logPublishingOptions = Stack.of(node).resolve( 19 | node.logPublishingOptions 20 | ); 21 | if (logPublishingOptions === undefined) { 22 | return NagRuleCompliance.NON_COMPLIANT; 23 | } 24 | const resolvedLog = Stack.of(node).resolve( 25 | logPublishingOptions?.ES_APPLICATION_LOGS 26 | ); 27 | if (resolvedLog === undefined) { 28 | return NagRuleCompliance.NON_COMPLIANT; 29 | } 30 | return NagRuleCompliance.COMPLIANT; 31 | } else { 32 | return NagRuleCompliance.NOT_APPLICABLE; 33 | } 34 | }, 35 | 'name', 36 | { value: parse(__filename).name } 37 | ); 38 | -------------------------------------------------------------------------------- /src/rules/opensearch/OpenSearchInVPCOnly.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { parse } from 'path'; 6 | import { CfnResource, Stack } from 'aws-cdk-lib'; 7 | import { CfnDomain as LegacyCfnDomain } from 'aws-cdk-lib/aws-elasticsearch'; 8 | import { CfnDomain } from 'aws-cdk-lib/aws-opensearchservice'; 9 | import { NagRuleCompliance } from '../../nag-rules'; 10 | 11 | /** 12 | * OpenSearch Service domains are within VPCs 13 | * @param node the CfnResource to check 14 | */ 15 | export default Object.defineProperty( 16 | (node: CfnResource): NagRuleCompliance => { 17 | if (node instanceof LegacyCfnDomain || node instanceof CfnDomain) { 18 | const vpcOptions = Stack.of(node).resolve(node.vpcOptions); 19 | if (vpcOptions === undefined) { 20 | return NagRuleCompliance.NON_COMPLIANT; 21 | } 22 | const subnetIds = Stack.of(node).resolve(vpcOptions.subnetIds); 23 | if (subnetIds === undefined || subnetIds.length === 0) { 24 | return NagRuleCompliance.NON_COMPLIANT; 25 | } 26 | return NagRuleCompliance.COMPLIANT; 27 | } else { 28 | return NagRuleCompliance.NOT_APPLICABLE; 29 | } 30 | }, 31 | 'name', 32 | { value: parse(__filename).name } 33 | ); 34 | -------------------------------------------------------------------------------- /src/rules/opensearch/OpenSearchNodeToNodeEncryption.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { parse } from 'path'; 6 | import { CfnResource, Stack } from 'aws-cdk-lib'; 7 | import { CfnDomain as LegacyCfnDomain } from 'aws-cdk-lib/aws-elasticsearch'; 8 | import { CfnDomain } from 'aws-cdk-lib/aws-opensearchservice'; 9 | import { NagRuleCompliance, NagRules } from '../../nag-rules'; 10 | 11 | /** 12 | * OpenSearch Service domains are node-to-node encrypted 13 | * @param node the CfnResource to check 14 | */ 15 | export default Object.defineProperty( 16 | (node: CfnResource): NagRuleCompliance => { 17 | if (node instanceof LegacyCfnDomain || node instanceof CfnDomain) { 18 | const encryptedNodeToNode = Stack.of(node).resolve( 19 | node.nodeToNodeEncryptionOptions 20 | ); 21 | if (encryptedNodeToNode != undefined) { 22 | const enabled = NagRules.resolveIfPrimitive( 23 | node, 24 | encryptedNodeToNode.enabled 25 | ); 26 | if (enabled !== true) { 27 | return NagRuleCompliance.NON_COMPLIANT; 28 | } 29 | } else { 30 | return NagRuleCompliance.NON_COMPLIANT; 31 | } 32 | return NagRuleCompliance.COMPLIANT; 33 | } else { 34 | return NagRuleCompliance.NOT_APPLICABLE; 35 | } 36 | }, 37 | 'name', 38 | { value: parse(__filename).name } 39 | ); 40 | -------------------------------------------------------------------------------- /src/rules/opensearch/OpenSearchSlowLogsToCloudWatch.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { parse } from 'path'; 6 | import { CfnResource, Stack } from 'aws-cdk-lib'; 7 | import { CfnDomain as LegacyCfnDomain } from 'aws-cdk-lib/aws-elasticsearch'; 8 | import { CfnDomain } from 'aws-cdk-lib/aws-opensearchservice'; 9 | import { 10 | NagRuleCompliance, 11 | NagRuleFindings, 12 | NagRuleResult, 13 | NagRules, 14 | } from '../../nag-rules'; 15 | 16 | /** 17 | * OpenSearch Service domains minimally publish SEARCH_SLOW_LOGS and INDEX_SLOW_LOGS to CloudWatch Logs 18 | * @param node the CfnResource to check 19 | */ 20 | export default Object.defineProperty( 21 | (node: CfnResource): NagRuleResult => { 22 | if (node instanceof LegacyCfnDomain || node instanceof CfnDomain) { 23 | const logPublishingOptions = Stack.of(node).resolve( 24 | node.logPublishingOptions 25 | ); 26 | const requiredSlowLogs = ['SEARCH_SLOW_LOGS', 'INDEX_SLOW_LOGS']; 27 | const findings: NagRuleFindings = []; 28 | for (const log of requiredSlowLogs) { 29 | const resolvedLog = Stack.of(node).resolve(logPublishingOptions?.[log]); 30 | const enabled = NagRules.resolveIfPrimitive(node, resolvedLog?.enabled); 31 | if (!enabled) { 32 | findings.push(`LogExport::${log}`); 33 | } 34 | } 35 | return findings.length ? findings : NagRuleCompliance.COMPLIANT; 36 | } else { 37 | return NagRuleCompliance.NOT_APPLICABLE; 38 | } 39 | }, 40 | 'name', 41 | { value: parse(__filename).name } 42 | ); 43 | -------------------------------------------------------------------------------- /src/rules/opensearch/index.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | export { default as OpenSearchAllowlistedIPs } from './OpenSearchAllowlistedIPs'; 6 | export { default as OpenSearchDedicatedMasterNode } from './OpenSearchDedicatedMasterNode'; 7 | export { default as OpenSearchEncryptedAtRest } from './OpenSearchEncryptedAtRest'; 8 | export { default as OpenSearchErrorLogsToCloudWatch } from './OpenSearchErrorLogsToCloudWatch'; 9 | export { default as OpenSearchInVPCOnly } from './OpenSearchInVPCOnly'; 10 | export { default as OpenSearchNodeToNodeEncryption } from './OpenSearchNodeToNodeEncryption'; 11 | export { default as OpenSearchNoUnsignedOrAnonymousAccess } from './OpenSearchNoUnsignedOrAnonymousAccess'; 12 | export { default as OpenSearchSlowLogsToCloudWatch } from './OpenSearchSlowLogsToCloudWatch'; 13 | export { default as OpenSearchZoneAwareness } from './OpenSearchZoneAwareness'; 14 | -------------------------------------------------------------------------------- /src/rules/quicksight/QuicksightSSLConnections.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { parse } from 'path'; 6 | import { CfnResource, Stack } from 'aws-cdk-lib'; 7 | import { CfnDataSource } from 'aws-cdk-lib/aws-quicksight'; 8 | import { NagRuleCompliance, NagRules } from '../../nag-rules'; 9 | 10 | /** 11 | * Quicksight uses SSL when connecting to a data source 12 | * @param node the CfnResource to check 13 | */ 14 | export default Object.defineProperty( 15 | (node: CfnResource): NagRuleCompliance => { 16 | if (node instanceof CfnDataSource) { 17 | const sslProperties = Stack.of(node).resolve(node.sslProperties); 18 | if (sslProperties != undefined) { 19 | const disableSsl = NagRules.resolveIfPrimitive( 20 | node, 21 | sslProperties.disableSsl 22 | ); 23 | if (disableSsl === true) { 24 | return NagRuleCompliance.NON_COMPLIANT; 25 | } 26 | } 27 | return NagRuleCompliance.COMPLIANT; 28 | } else { 29 | return NagRuleCompliance.NOT_APPLICABLE; 30 | } 31 | }, 32 | 'name', 33 | { value: parse(__filename).name } 34 | ); 35 | -------------------------------------------------------------------------------- /src/rules/quicksight/index.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | export { default as QuicksightSSLConnections } from './QuicksightSSLConnections'; 6 | -------------------------------------------------------------------------------- /src/rules/rds/AuroraMySQLBacktrack.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { parse } from 'path'; 6 | import { CfnResource } from 'aws-cdk-lib'; 7 | import { CfnDBCluster } from 'aws-cdk-lib/aws-rds'; 8 | import { NagRuleCompliance, NagRules } from '../../nag-rules'; 9 | 10 | /** 11 | * RDS Aurora serverless clusters have Log Exports enabled 12 | * @param node the CfnResource to check 13 | */ 14 | export default Object.defineProperty( 15 | (node: CfnResource): NagRuleCompliance => { 16 | if (node instanceof CfnDBCluster) { 17 | const engine = NagRules.resolveIfPrimitive( 18 | node, 19 | node.engine 20 | ).toLowerCase(); 21 | const backtrackWindow = NagRules.resolveIfPrimitive( 22 | node, 23 | node.backtrackWindow 24 | ); 25 | if (engine == 'aurora' || engine == 'aurora-mysql') { 26 | if (backtrackWindow == undefined || backtrackWindow == 0) { 27 | return NagRuleCompliance.NON_COMPLIANT; 28 | } 29 | } 30 | return NagRuleCompliance.COMPLIANT; 31 | } else { 32 | return NagRuleCompliance.NOT_APPLICABLE; 33 | } 34 | }, 35 | 'name', 36 | { value: parse(__filename).name } 37 | ); 38 | -------------------------------------------------------------------------------- /src/rules/rds/AuroraMySQLPostgresIAMAuth.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { parse } from 'path'; 6 | import { CfnResource } from 'aws-cdk-lib'; 7 | import { CfnDBCluster } from 'aws-cdk-lib/aws-rds'; 8 | import { NagRuleCompliance, NagRules } from '../../nag-rules'; 9 | 10 | /** 11 | * RDS Aurora MySQL/PostgresSQL clusters have IAM Database Authentication enabled 12 | * @param node the CfnResource to check 13 | */ 14 | export default Object.defineProperty( 15 | (node: CfnResource): NagRuleCompliance => { 16 | if (node instanceof CfnDBCluster) { 17 | if (!node.engine) return NagRuleCompliance.NOT_APPLICABLE; 18 | if (node.engine.toLowerCase().includes('aurora')) { 19 | if (node.enableIamDatabaseAuthentication == undefined) { 20 | return NagRuleCompliance.NON_COMPLIANT; 21 | } 22 | const iamAuth = NagRules.resolveIfPrimitive( 23 | node, 24 | node.enableIamDatabaseAuthentication 25 | ); 26 | if (iamAuth == false) { 27 | return NagRuleCompliance.NON_COMPLIANT; 28 | } 29 | } 30 | return NagRuleCompliance.COMPLIANT; 31 | } else { 32 | return NagRuleCompliance.NOT_APPLICABLE; 33 | } 34 | }, 35 | 'name', 36 | { value: parse(__filename).name } 37 | ); 38 | -------------------------------------------------------------------------------- /src/rules/rds/RDSAutomaticMinorVersionUpgradeEnabled.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { parse } from 'path'; 6 | import { CfnResource } from 'aws-cdk-lib'; 7 | import { CfnDBInstance } from 'aws-cdk-lib/aws-rds'; 8 | import { NagRuleCompliance, NagRules } from '../../nag-rules'; 9 | 10 | /** 11 | * RDS DB instances have automatic minor version upgrades enabled 12 | * @param node the CfnResource to check 13 | */ 14 | export default Object.defineProperty( 15 | (node: CfnResource): NagRuleCompliance => { 16 | if (node instanceof CfnDBInstance) { 17 | const autoMinorVersionUpgrade = NagRules.resolveIfPrimitive( 18 | node, 19 | node.autoMinorVersionUpgrade 20 | ); 21 | if (autoMinorVersionUpgrade === false) { 22 | return NagRuleCompliance.NON_COMPLIANT; 23 | } 24 | return NagRuleCompliance.COMPLIANT; 25 | } else { 26 | return NagRuleCompliance.NOT_APPLICABLE; 27 | } 28 | }, 29 | 'name', 30 | { value: parse(__filename).name } 31 | ); 32 | -------------------------------------------------------------------------------- /src/rules/rds/RDSEnhancedMonitoringEnabled.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { parse } from 'path'; 6 | import { CfnResource } from 'aws-cdk-lib'; 7 | import { CfnDBInstance } from 'aws-cdk-lib/aws-rds'; 8 | import { NagRuleCompliance, NagRules } from '../../nag-rules'; 9 | 10 | /** 11 | * RDS DB instances have enhanced monitoring enabled 12 | * @param node the CfnResource to check 13 | */ 14 | export default Object.defineProperty( 15 | (node: CfnResource): NagRuleCompliance => { 16 | if (node instanceof CfnDBInstance) { 17 | const enhancedMonitoring = NagRules.resolveIfPrimitive( 18 | node, 19 | node.monitoringInterval 20 | ); 21 | if (enhancedMonitoring == undefined || enhancedMonitoring <= 0) { 22 | return NagRuleCompliance.NON_COMPLIANT; 23 | } 24 | return NagRuleCompliance.COMPLIANT; 25 | } else { 26 | return NagRuleCompliance.NOT_APPLICABLE; 27 | } 28 | }, 29 | 'name', 30 | { value: parse(__filename).name } 31 | ); 32 | -------------------------------------------------------------------------------- /src/rules/rds/RDSInstanceBackupEnabled.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { parse } from 'path'; 6 | import { CfnResource } from 'aws-cdk-lib'; 7 | import { CfnDBInstance } from 'aws-cdk-lib/aws-rds'; 8 | import { NagRuleCompliance, NagRules } from '../../nag-rules'; 9 | 10 | /** 11 | * RDS DB instances have backup enabled 12 | * @param node the CfnResource to check 13 | */ 14 | export default Object.defineProperty( 15 | (node: CfnResource): NagRuleCompliance => { 16 | if (node instanceof CfnDBInstance) { 17 | const backup = NagRules.resolveIfPrimitive( 18 | node, 19 | node.backupRetentionPeriod 20 | ); 21 | if (backup !== undefined && backup <= 0) { 22 | return NagRuleCompliance.NON_COMPLIANT; 23 | } 24 | return NagRuleCompliance.COMPLIANT; 25 | } else { 26 | return NagRuleCompliance.NOT_APPLICABLE; 27 | } 28 | }, 29 | 'name', 30 | { value: parse(__filename).name } 31 | ); 32 | -------------------------------------------------------------------------------- /src/rules/rds/RDSInstancePublicAccess.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { parse } from 'path'; 6 | import { CfnResource } from 'aws-cdk-lib'; 7 | import { CfnDBInstance } from 'aws-cdk-lib/aws-rds'; 8 | import { NagRuleCompliance, NagRules } from '../../nag-rules'; 9 | 10 | /** 11 | * RDS DB instances are not publicly accessible 12 | * @param node the CfnResource to check 13 | */ 14 | export default Object.defineProperty( 15 | (node: CfnResource): NagRuleCompliance => { 16 | if (node instanceof CfnDBInstance) { 17 | const publicAccess = NagRules.resolveIfPrimitive( 18 | node, 19 | node.publiclyAccessible 20 | ); 21 | if (publicAccess !== false) { 22 | return NagRuleCompliance.NON_COMPLIANT; 23 | } 24 | return NagRuleCompliance.COMPLIANT; 25 | } else { 26 | return NagRuleCompliance.NOT_APPLICABLE; 27 | } 28 | }, 29 | 'name', 30 | { value: parse(__filename).name } 31 | ); 32 | -------------------------------------------------------------------------------- /src/rules/rds/RDSMultiAZSupport.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { parse } from 'path'; 6 | import { CfnResource } from 'aws-cdk-lib'; 7 | import { CfnDBInstance } from 'aws-cdk-lib/aws-rds'; 8 | import { NagRuleCompliance, NagRules } from '../../nag-rules'; 9 | 10 | /** 11 | * Non-Aurora RDS DB instances have multi-AZ support enabled 12 | * @param node the CfnResource to check 13 | */ 14 | export default Object.defineProperty( 15 | (node: CfnResource): NagRuleCompliance => { 16 | if (node instanceof CfnDBInstance) { 17 | const multiAz = NagRules.resolveIfPrimitive(node, node.multiAz); 18 | const engine = NagRules.resolveIfPrimitive(node, node.engine); 19 | if ( 20 | !multiAz && 21 | (engine == undefined || !engine.toLowerCase().includes('aurora')) 22 | ) { 23 | return NagRuleCompliance.NON_COMPLIANT; 24 | } 25 | return NagRuleCompliance.COMPLIANT; 26 | } else { 27 | return NagRuleCompliance.NOT_APPLICABLE; 28 | } 29 | }, 30 | 'name', 31 | { value: parse(__filename).name } 32 | ); 33 | -------------------------------------------------------------------------------- /src/rules/rds/index.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | export { default as AuroraMySQLBacktrack } from './AuroraMySQLBacktrack'; 6 | export { default as AuroraMySQLLogging } from './AuroraMySQLLogging'; 7 | export { default as AuroraMySQLPostgresIAMAuth } from './AuroraMySQLPostgresIAMAuth'; 8 | export { default as RDSAutomaticMinorVersionUpgradeEnabled } from './RDSAutomaticMinorVersionUpgradeEnabled'; 9 | export { default as RDSEnhancedMonitoringEnabled } from './RDSEnhancedMonitoringEnabled'; 10 | export { default as RDSInBackupPlan } from './RDSInBackupPlan'; 11 | export { default as RDSInstanceBackupEnabled } from './RDSInstanceBackupEnabled'; 12 | export { default as RDSInstanceDeletionProtectionEnabled } from './RDSInstanceDeletionProtectionEnabled'; 13 | export { default as RDSInstancePublicAccess } from './RDSInstancePublicAccess'; 14 | export { default as RDSLoggingEnabled } from './RDSLoggingEnabled'; 15 | export { default as RDSMultiAZSupport } from './RDSMultiAZSupport'; 16 | export { default as RDSNonDefaultPort } from './RDSNonDefaultPort'; 17 | export { default as RDSRestrictedInbound } from './RDSRestrictedInbound'; 18 | export { default as RDSStorageEncrypted } from './RDSStorageEncrypted'; 19 | -------------------------------------------------------------------------------- /src/rules/redshift/RedshiftBackupEnabled.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { parse } from 'path'; 6 | import { CfnResource } from 'aws-cdk-lib'; 7 | import { CfnCluster } from 'aws-cdk-lib/aws-redshift'; 8 | import { NagRuleCompliance, NagRules } from '../../nag-rules'; 9 | 10 | /** 11 | * Redshift clusters have automated snapshots enabled and the retention period is between 1 and 35 days 12 | * @param node the CfnResource to check 13 | */ 14 | export default Object.defineProperty( 15 | (node: CfnResource): NagRuleCompliance => { 16 | if (node instanceof CfnCluster) { 17 | const automatedSnapshotRetentionPeriod = NagRules.resolveIfPrimitive( 18 | node, 19 | node.automatedSnapshotRetentionPeriod 20 | ); 21 | if ( 22 | automatedSnapshotRetentionPeriod != undefined && 23 | automatedSnapshotRetentionPeriod == 0 24 | ) { 25 | return NagRuleCompliance.NON_COMPLIANT; 26 | } 27 | return NagRuleCompliance.COMPLIANT; 28 | } else { 29 | return NagRuleCompliance.NOT_APPLICABLE; 30 | } 31 | }, 32 | 'name', 33 | { value: parse(__filename).name } 34 | ); 35 | -------------------------------------------------------------------------------- /src/rules/redshift/RedshiftClusterAuditLogging.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { parse } from 'path'; 6 | import { CfnResource, Stack } from 'aws-cdk-lib'; 7 | import { CfnCluster } from 'aws-cdk-lib/aws-redshift'; 8 | import { NagRuleCompliance } from '../../nag-rules'; 9 | 10 | /** 11 | * Redshift clusters have audit logging enabled 12 | * @param node the CfnResource to check 13 | */ 14 | export default Object.defineProperty( 15 | (node: CfnResource): NagRuleCompliance => { 16 | if (node instanceof CfnCluster) { 17 | const loggingProperties = Stack.of(node).resolve(node.loggingProperties); 18 | if (loggingProperties == undefined) { 19 | return NagRuleCompliance.NON_COMPLIANT; 20 | } 21 | return NagRuleCompliance.COMPLIANT; 22 | } else { 23 | return NagRuleCompliance.NOT_APPLICABLE; 24 | } 25 | }, 26 | 'name', 27 | { value: parse(__filename).name } 28 | ); 29 | -------------------------------------------------------------------------------- /src/rules/redshift/RedshiftClusterConfiguration.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { parse } from 'path'; 6 | import { CfnResource, Stack } from 'aws-cdk-lib'; 7 | import { CfnCluster } from 'aws-cdk-lib/aws-redshift'; 8 | import { NagRuleCompliance, NagRules } from '../../nag-rules'; 9 | 10 | /** 11 | * Redshift clusters have encryption and audit logging enabled 12 | * @param node the CfnResource to check 13 | */ 14 | export default Object.defineProperty( 15 | (node: CfnResource): NagRuleCompliance => { 16 | if (node instanceof CfnCluster) { 17 | const encrypted = NagRules.resolveIfPrimitive(node, node.encrypted); 18 | const loggingProperties = Stack.of(node).resolve(node.loggingProperties); 19 | if (!encrypted || loggingProperties == undefined) { 20 | return NagRuleCompliance.NON_COMPLIANT; 21 | } 22 | return NagRuleCompliance.COMPLIANT; 23 | } else { 24 | return NagRuleCompliance.NOT_APPLICABLE; 25 | } 26 | }, 27 | 'name', 28 | { value: parse(__filename).name } 29 | ); 30 | -------------------------------------------------------------------------------- /src/rules/redshift/RedshiftClusterEncryptionAtRest.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { parse } from 'path'; 6 | import { CfnResource } from 'aws-cdk-lib'; 7 | import { CfnCluster } from 'aws-cdk-lib/aws-redshift'; 8 | import { NagRuleCompliance, NagRules } from '../../nag-rules'; 9 | 10 | /** 11 | * Redshift clusters have encryption at rest enabled 12 | * @param node the CfnResource to check 13 | */ 14 | export default Object.defineProperty( 15 | (node: CfnResource): NagRuleCompliance => { 16 | if (node instanceof CfnCluster) { 17 | if (node.encrypted == undefined) { 18 | return NagRuleCompliance.NON_COMPLIANT; 19 | } 20 | const encrypted = NagRules.resolveIfPrimitive(node, node.encrypted); 21 | if (!encrypted) { 22 | return NagRuleCompliance.NON_COMPLIANT; 23 | } 24 | return NagRuleCompliance.COMPLIANT; 25 | } else { 26 | return NagRuleCompliance.NOT_APPLICABLE; 27 | } 28 | }, 29 | 'name', 30 | { value: parse(__filename).name } 31 | ); 32 | -------------------------------------------------------------------------------- /src/rules/redshift/RedshiftClusterInVPC.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { parse } from 'path'; 6 | import { CfnResource } from 'aws-cdk-lib'; 7 | import { CfnCluster } from 'aws-cdk-lib/aws-redshift'; 8 | import { NagRuleCompliance } from '../../nag-rules'; 9 | 10 | /** 11 | * Redshift clusters are provisioned in a VPC 12 | * @param node the CfnResource to check 13 | */ 14 | export default Object.defineProperty( 15 | (node: CfnResource): NagRuleCompliance => { 16 | if (node instanceof CfnCluster) { 17 | if ( 18 | node.clusterSubnetGroupName == undefined || 19 | node.clusterSubnetGroupName.length == 0 20 | ) { 21 | return NagRuleCompliance.NON_COMPLIANT; 22 | } 23 | return NagRuleCompliance.COMPLIANT; 24 | } else { 25 | return NagRuleCompliance.NOT_APPLICABLE; 26 | } 27 | }, 28 | 'name', 29 | { value: parse(__filename).name } 30 | ); 31 | -------------------------------------------------------------------------------- /src/rules/redshift/RedshiftClusterMaintenanceSettings.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { parse } from 'path'; 6 | import { CfnResource } from 'aws-cdk-lib'; 7 | import { CfnCluster } from 'aws-cdk-lib/aws-redshift'; 8 | import { NagRuleCompliance, NagRules } from '../../nag-rules'; 9 | 10 | /** 11 | * Redshift clusters have version upgrades enabled, automated snapshot retention periods enabled, and explicit maintenance windows configured 12 | * @param node the CfnResource to check 13 | */ 14 | export default Object.defineProperty( 15 | (node: CfnResource): NagRuleCompliance => { 16 | if (node instanceof CfnCluster) { 17 | const allowVersionUpgrade = NagRules.resolveIfPrimitive( 18 | node, 19 | node.allowVersionUpgrade 20 | ); 21 | const automatedSnapshotRetentionPeriod = NagRules.resolveIfPrimitive( 22 | node, 23 | node.automatedSnapshotRetentionPeriod 24 | ); 25 | if ( 26 | (automatedSnapshotRetentionPeriod != undefined && 27 | automatedSnapshotRetentionPeriod == 0) || 28 | node.preferredMaintenanceWindow == undefined || 29 | allowVersionUpgrade === false 30 | ) { 31 | return NagRuleCompliance.NON_COMPLIANT; 32 | } 33 | return NagRuleCompliance.COMPLIANT; 34 | } else { 35 | return NagRuleCompliance.NOT_APPLICABLE; 36 | } 37 | }, 38 | 'name', 39 | { value: parse(__filename).name } 40 | ); 41 | -------------------------------------------------------------------------------- /src/rules/redshift/RedshiftClusterNonDefaultPort.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { parse } from 'path'; 6 | import { CfnResource } from 'aws-cdk-lib'; 7 | import { CfnCluster } from 'aws-cdk-lib/aws-redshift'; 8 | import { NagRuleCompliance, NagRules } from '../../nag-rules'; 9 | 10 | /** 11 | * Redshift clusters do not use the default endpoint port 12 | * @param node the CfnResource to check 13 | */ 14 | export default Object.defineProperty( 15 | (node: CfnResource): NagRuleCompliance => { 16 | if (node instanceof CfnCluster) { 17 | const port = NagRules.resolveIfPrimitive(node, node.port); 18 | if (port == undefined || port == 5439) { 19 | return NagRuleCompliance.NON_COMPLIANT; 20 | } 21 | return NagRuleCompliance.COMPLIANT; 22 | } else { 23 | return NagRuleCompliance.NOT_APPLICABLE; 24 | } 25 | }, 26 | 'name', 27 | { value: parse(__filename).name } 28 | ); 29 | -------------------------------------------------------------------------------- /src/rules/redshift/RedshiftClusterNonDefaultUsername.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { parse } from 'path'; 6 | import { CfnResource } from 'aws-cdk-lib'; 7 | import { CfnCluster } from 'aws-cdk-lib/aws-redshift'; 8 | import { NagRuleCompliance, NagRules } from '../../nag-rules'; 9 | 10 | /** 11 | * Redshift clusters use custom user names vice the default (awsuser) 12 | * @param node the CfnResource to check 13 | */ 14 | export default Object.defineProperty( 15 | (node: CfnResource): NagRuleCompliance => { 16 | if (node instanceof CfnCluster) { 17 | const masterUsername = NagRules.resolveIfPrimitive( 18 | node, 19 | node.masterUsername 20 | ); 21 | if (masterUsername == 'awsuser') { 22 | return NagRuleCompliance.NON_COMPLIANT; 23 | } 24 | return NagRuleCompliance.COMPLIANT; 25 | } else { 26 | return NagRuleCompliance.NOT_APPLICABLE; 27 | } 28 | }, 29 | 'name', 30 | { value: parse(__filename).name } 31 | ); 32 | -------------------------------------------------------------------------------- /src/rules/redshift/RedshiftClusterPublicAccess.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { parse } from 'path'; 6 | import { CfnResource } from 'aws-cdk-lib'; 7 | import { CfnCluster } from 'aws-cdk-lib/aws-redshift'; 8 | import { NagRuleCompliance, NagRules } from '../../nag-rules'; 9 | 10 | /** 11 | * Redshift clusters do not allow public access 12 | * @param node the CfnResource to check 13 | */ 14 | export default Object.defineProperty( 15 | (node: CfnResource): NagRuleCompliance => { 16 | if (node instanceof CfnCluster) { 17 | const publicAccess = NagRules.resolveIfPrimitive( 18 | node, 19 | node.publiclyAccessible 20 | ); 21 | if (publicAccess === true) { 22 | return NagRuleCompliance.NON_COMPLIANT; 23 | } 24 | return NagRuleCompliance.COMPLIANT; 25 | } else { 26 | return NagRuleCompliance.NOT_APPLICABLE; 27 | } 28 | }, 29 | 'name', 30 | { value: parse(__filename).name } 31 | ); 32 | -------------------------------------------------------------------------------- /src/rules/redshift/RedshiftClusterVersionUpgrade.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { parse } from 'path'; 6 | import { CfnResource } from 'aws-cdk-lib'; 7 | import { CfnCluster } from 'aws-cdk-lib/aws-redshift'; 8 | import { NagRuleCompliance, NagRules } from '../../nag-rules'; 9 | 10 | /** 11 | * Redshift clusters have version upgrade enabled 12 | * @param node the CfnResource to check 13 | */ 14 | export default Object.defineProperty( 15 | (node: CfnResource): NagRuleCompliance => { 16 | if (node instanceof CfnCluster) { 17 | const allowVersionUpgrade = NagRules.resolveIfPrimitive( 18 | node, 19 | node.allowVersionUpgrade 20 | ); 21 | if (allowVersionUpgrade === false) { 22 | return NagRuleCompliance.NON_COMPLIANT; 23 | } 24 | return NagRuleCompliance.COMPLIANT; 25 | } else { 26 | return NagRuleCompliance.NOT_APPLICABLE; 27 | } 28 | }, 29 | 'name', 30 | { value: parse(__filename).name } 31 | ); 32 | -------------------------------------------------------------------------------- /src/rules/redshift/RedshiftEnhancedVPCRoutingEnabled.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { parse } from 'path'; 6 | import { CfnResource } from 'aws-cdk-lib'; 7 | import { CfnCluster } from 'aws-cdk-lib/aws-redshift'; 8 | import { NagRuleCompliance, NagRules } from '../../nag-rules'; 9 | 10 | /** 11 | * Redshift clusters have enhanced VPC routing enabled 12 | * @param node the CfnResource to check 13 | */ 14 | export default Object.defineProperty( 15 | (node: CfnResource): NagRuleCompliance => { 16 | if (node instanceof CfnCluster) { 17 | const enhancedVpcRouting = NagRules.resolveIfPrimitive( 18 | node, 19 | node.enhancedVpcRouting 20 | ); 21 | if (enhancedVpcRouting !== true) { 22 | return NagRuleCompliance.NON_COMPLIANT; 23 | } 24 | return NagRuleCompliance.COMPLIANT; 25 | } else { 26 | return NagRuleCompliance.NOT_APPLICABLE; 27 | } 28 | }, 29 | 'name', 30 | { value: parse(__filename).name } 31 | ); 32 | -------------------------------------------------------------------------------- /src/rules/redshift/index.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | export { default as RedshiftBackupEnabled } from './RedshiftBackupEnabled'; 6 | export { default as RedshiftClusterAuditLogging } from './RedshiftClusterAuditLogging'; 7 | export { default as RedshiftClusterConfiguration } from './RedshiftClusterConfiguration'; 8 | export { default as RedshiftClusterEncryptionAtRest } from './RedshiftClusterEncryptionAtRest'; 9 | export { default as RedshiftClusterInVPC } from './RedshiftClusterInVPC'; 10 | export { default as RedshiftClusterNonDefaultPort } from './RedshiftClusterNonDefaultPort'; 11 | export { default as RedshiftClusterMaintenanceSettings } from './RedshiftClusterMaintenanceSettings'; 12 | export { default as RedshiftClusterNonDefaultUsername } from './RedshiftClusterNonDefaultUsername'; 13 | export { default as RedshiftClusterPublicAccess } from './RedshiftClusterPublicAccess'; 14 | export { default as RedshiftClusterUserActivityLogging } from './RedshiftClusterUserActivityLogging'; 15 | export { default as RedshiftClusterVersionUpgrade } from './RedshiftClusterVersionUpgrade'; 16 | export { default as RedshiftEnhancedVPCRoutingEnabled } from './RedshiftEnhancedVPCRoutingEnabled'; 17 | export { default as RedshiftRequireTlsSSL } from './RedshiftRequireTlsSSL'; 18 | -------------------------------------------------------------------------------- /src/rules/s3/S3BucketDefaultLockEnabled.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { parse } from 'path'; 6 | import { CfnResource, Stack } from 'aws-cdk-lib'; 7 | import { CfnBucket } from 'aws-cdk-lib/aws-s3'; 8 | import { NagRuleCompliance, NagRules } from '../../nag-rules'; 9 | 10 | /** 11 | * S3 Buckets have object lock enabled 12 | * @param node the CfnResource to check 13 | */ 14 | export default Object.defineProperty( 15 | (node: CfnResource): NagRuleCompliance => { 16 | if (node instanceof CfnBucket) { 17 | const objectLockEnabled = NagRules.resolveIfPrimitive( 18 | node, 19 | node.objectLockEnabled 20 | ); 21 | const objectLockConfiguration = Stack.of(node).resolve( 22 | node.objectLockConfiguration 23 | ); 24 | if ( 25 | objectLockEnabled !== true || 26 | objectLockConfiguration === undefined || 27 | NagRules.resolveIfPrimitive( 28 | node, 29 | objectLockConfiguration.objectLockEnabled 30 | ) !== 'Enabled' 31 | ) { 32 | return NagRuleCompliance.NON_COMPLIANT; 33 | } 34 | return NagRuleCompliance.COMPLIANT; 35 | } else { 36 | return NagRuleCompliance.NOT_APPLICABLE; 37 | } 38 | }, 39 | 'name', 40 | { value: parse(__filename).name } 41 | ); 42 | -------------------------------------------------------------------------------- /src/rules/s3/S3BucketReplicationEnabled.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { parse } from 'path'; 6 | import { CfnResource, Stack } from 'aws-cdk-lib'; 7 | import { CfnBucket } from 'aws-cdk-lib/aws-s3'; 8 | import { NagRuleCompliance } from '../../nag-rules'; 9 | 10 | /** 11 | * S3 Buckets have replication enabled 12 | * @param node the CfnResource to check 13 | */ 14 | export default Object.defineProperty( 15 | (node: CfnResource): NagRuleCompliance => { 16 | if (node instanceof CfnBucket) { 17 | const replication = Stack.of(node).resolve(node.replicationConfiguration); 18 | if (replication === undefined) { 19 | return NagRuleCompliance.NON_COMPLIANT; 20 | } 21 | const rules = Stack.of(node).resolve(replication.rules); 22 | let found = false; 23 | for (const rule of rules) { 24 | const resolvedRule = Stack.of(node).resolve(rule); 25 | if (resolvedRule.status === 'Enabled') { 26 | found = true; 27 | break; 28 | } 29 | } 30 | if (!found) { 31 | return NagRuleCompliance.NON_COMPLIANT; 32 | } 33 | return NagRuleCompliance.COMPLIANT; 34 | } else { 35 | return NagRuleCompliance.NOT_APPLICABLE; 36 | } 37 | }, 38 | 'name', 39 | { value: parse(__filename).name } 40 | ); 41 | -------------------------------------------------------------------------------- /src/rules/s3/S3BucketVersioningEnabled.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { parse } from 'path'; 6 | import { CfnResource, Stack } from 'aws-cdk-lib'; 7 | import { CfnBucket } from 'aws-cdk-lib/aws-s3'; 8 | import { NagRuleCompliance, NagRules } from '../../nag-rules'; 9 | 10 | /** 11 | * S3 Buckets have versioningConfiguration enabled 12 | * @param node the CfnResource to check 13 | */ 14 | export default Object.defineProperty( 15 | (node: CfnResource): NagRuleCompliance => { 16 | if (node instanceof CfnBucket) { 17 | const versioningConfiguration = Stack.of(node).resolve( 18 | node.versioningConfiguration 19 | ); 20 | if ( 21 | versioningConfiguration === undefined || 22 | NagRules.resolveIfPrimitive(node, versioningConfiguration.status) === 23 | 'Suspended' 24 | ) { 25 | return NagRuleCompliance.NON_COMPLIANT; 26 | } 27 | return NagRuleCompliance.COMPLIANT; 28 | } else { 29 | return NagRuleCompliance.NOT_APPLICABLE; 30 | } 31 | }, 32 | 'name', 33 | { value: parse(__filename).name } 34 | ); 35 | -------------------------------------------------------------------------------- /src/rules/s3/index.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | export { default as S3BucketDefaultLockEnabled } from './S3BucketDefaultLockEnabled'; 6 | export { default as S3BucketLevelPublicAccessProhibited } from './S3BucketLevelPublicAccessProhibited'; 7 | export { default as S3BucketLoggingEnabled } from './S3BucketLoggingEnabled'; 8 | export { default as S3BucketPublicReadProhibited } from './S3BucketPublicReadProhibited'; 9 | export { default as S3BucketPublicWriteProhibited } from './S3BucketPublicWriteProhibited'; 10 | export { default as S3BucketReplicationEnabled } from './S3BucketReplicationEnabled'; 11 | export { default as S3BucketSSLRequestsOnly } from './S3BucketSSLRequestsOnly'; 12 | export { default as S3BucketVersioningEnabled } from './S3BucketVersioningEnabled'; 13 | export { default as S3DefaultEncryptionKMS } from './S3DefaultEncryptionKMS'; 14 | export { default as S3WebBucketOAIAccess } from './S3WebBucketOAIAccess'; 15 | -------------------------------------------------------------------------------- /src/rules/sagemaker/SageMakerEndpointConfigurationKMSKeyConfigured.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { parse } from 'path'; 6 | import { CfnResource, Stack } from 'aws-cdk-lib'; 7 | import { CfnEndpointConfig } from 'aws-cdk-lib/aws-sagemaker'; 8 | import { NagRuleCompliance } from '../../nag-rules'; 9 | 10 | /** 11 | * SageMaker endpoints utilize a KMS key 12 | * @param node the CfnResource to check 13 | */ 14 | export default Object.defineProperty( 15 | (node: CfnResource): NagRuleCompliance => { 16 | if (node instanceof CfnEndpointConfig) { 17 | const kmsKey = Stack.of(node).resolve(node.kmsKeyId); 18 | if (kmsKey == undefined) { 19 | return NagRuleCompliance.NON_COMPLIANT; 20 | } 21 | return NagRuleCompliance.COMPLIANT; 22 | } else { 23 | return NagRuleCompliance.NOT_APPLICABLE; 24 | } 25 | }, 26 | 'name', 27 | { value: parse(__filename).name } 28 | ); 29 | -------------------------------------------------------------------------------- /src/rules/sagemaker/SageMakerNotebookInVPC.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { parse } from 'path'; 6 | import { CfnResource, Stack } from 'aws-cdk-lib'; 7 | import { CfnNotebookInstance } from 'aws-cdk-lib/aws-sagemaker'; 8 | import { NagRuleCompliance } from '../../nag-rules'; 9 | 10 | /** 11 | * SageMaker notebook instances are provisioned inside a VPC 12 | * @param node the CfnResource to check 13 | */ 14 | export default Object.defineProperty( 15 | (node: CfnResource): NagRuleCompliance => { 16 | if (node instanceof CfnNotebookInstance) { 17 | const subnetId = Stack.of(node).resolve(node.subnetId); 18 | if (subnetId == undefined) { 19 | return NagRuleCompliance.NON_COMPLIANT; 20 | } 21 | return NagRuleCompliance.COMPLIANT; 22 | } else { 23 | return NagRuleCompliance.NOT_APPLICABLE; 24 | } 25 | }, 26 | 'name', 27 | { value: parse(__filename).name } 28 | ); 29 | -------------------------------------------------------------------------------- /src/rules/sagemaker/SageMakerNotebookInstanceKMSKeyConfigured.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { parse } from 'path'; 6 | import { CfnResource, Stack } from 'aws-cdk-lib'; 7 | import { CfnNotebookInstance } from 'aws-cdk-lib/aws-sagemaker'; 8 | import { NagRuleCompliance } from '../../nag-rules'; 9 | 10 | /** 11 | * SageMaker notebook instances utilize KMS keys for encryption at rest 12 | * @param node the CfnResource to check 13 | */ 14 | export default Object.defineProperty( 15 | (node: CfnResource): NagRuleCompliance => { 16 | if (node instanceof CfnNotebookInstance) { 17 | const kmsKey = Stack.of(node).resolve(node.kmsKeyId); 18 | if (kmsKey == undefined) { 19 | return NagRuleCompliance.NON_COMPLIANT; 20 | } 21 | return NagRuleCompliance.COMPLIANT; 22 | } else { 23 | return NagRuleCompliance.NOT_APPLICABLE; 24 | } 25 | }, 26 | 'name', 27 | { value: parse(__filename).name } 28 | ); 29 | -------------------------------------------------------------------------------- /src/rules/sagemaker/SageMakerNotebookNoDirectInternetAccess.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { parse } from 'path'; 6 | import { CfnResource } from 'aws-cdk-lib'; 7 | import { CfnNotebookInstance } from 'aws-cdk-lib/aws-sagemaker'; 8 | import { NagRuleCompliance, NagRules } from '../../nag-rules'; 9 | 10 | /** 11 | * SageMaker notebook instances have direct internet access disabled 12 | * @param node the CfnResource to check 13 | */ 14 | export default Object.defineProperty( 15 | (node: CfnResource): NagRuleCompliance => { 16 | if (node instanceof CfnNotebookInstance) { 17 | const directInternetAccess = NagRules.resolveIfPrimitive( 18 | node, 19 | node.directInternetAccess 20 | ); 21 | if ( 22 | directInternetAccess == undefined || 23 | directInternetAccess != 'Disabled' 24 | ) { 25 | return NagRuleCompliance.NON_COMPLIANT; 26 | } 27 | return NagRuleCompliance.COMPLIANT; 28 | } else { 29 | return NagRuleCompliance.NOT_APPLICABLE; 30 | } 31 | }, 32 | 'name', 33 | { value: parse(__filename).name } 34 | ); 35 | -------------------------------------------------------------------------------- /src/rules/sagemaker/index.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | 6 | export { default as SageMakerEndpointConfigurationKMSKeyConfigured } from './SageMakerEndpointConfigurationKMSKeyConfigured'; 7 | export { default as SageMakerNotebookNoDirectInternetAccess } from './SageMakerNotebookNoDirectInternetAccess'; 8 | export { default as SageMakerNotebookInVPC } from './SageMakerNotebookInVPC'; 9 | export { default as SageMakerNotebookInstanceKMSKeyConfigured } from './SageMakerNotebookInstanceKMSKeyConfigured'; 10 | -------------------------------------------------------------------------------- /src/rules/secretsmanager/SecretsManagerUsingKMSKey.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { parse } from 'path'; 6 | import { CfnResource, Stack } from 'aws-cdk-lib'; 7 | import { CfnSecret } from 'aws-cdk-lib/aws-secretsmanager'; 8 | import { NagRuleCompliance } from '../../nag-rules'; 9 | 10 | /** 11 | * Secrets are encrypted with KMS Customer managed keys 12 | * @param node the CfnResource to check 13 | */ 14 | export default Object.defineProperty( 15 | (node: CfnResource): NagRuleCompliance => { 16 | if (node instanceof CfnSecret) { 17 | const kmsKeyId = Stack.of(node).resolve(node.kmsKeyId); 18 | if (kmsKeyId === undefined || kmsKeyId === 'aws/secretsmanager') { 19 | return NagRuleCompliance.NON_COMPLIANT; 20 | } 21 | return NagRuleCompliance.COMPLIANT; 22 | } else { 23 | return NagRuleCompliance.NOT_APPLICABLE; 24 | } 25 | }, 26 | 'name', 27 | { value: parse(__filename).name } 28 | ); 29 | -------------------------------------------------------------------------------- /src/rules/secretsmanager/index.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | export { default as SecretsManagerRotationEnabled } from './SecretsManagerRotationEnabled'; 6 | export { default as SecretsManagerUsingKMSKey } from './SecretsManagerUsingKMSKey'; 7 | -------------------------------------------------------------------------------- /src/rules/sns/SNSEncryptedKMS.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { parse } from 'path'; 6 | import { CfnResource, Stack } from 'aws-cdk-lib'; 7 | import { CfnTopic } from 'aws-cdk-lib/aws-sns'; 8 | import { NagRuleCompliance } from '../../nag-rules'; 9 | 10 | /** 11 | * SNS topics are encrypted via KMS 12 | * @param node the CfnResource to check 13 | */ 14 | export default Object.defineProperty( 15 | (node: CfnResource): NagRuleCompliance => { 16 | if (node instanceof CfnTopic) { 17 | const topicKey = Stack.of(node).resolve(node.kmsMasterKeyId); 18 | if (topicKey == undefined) { 19 | return NagRuleCompliance.NON_COMPLIANT; 20 | } 21 | return NagRuleCompliance.COMPLIANT; 22 | } else { 23 | return NagRuleCompliance.NOT_APPLICABLE; 24 | } 25 | }, 26 | 'name', 27 | { value: parse(__filename).name } 28 | ); 29 | -------------------------------------------------------------------------------- /src/rules/sns/SNSRedrivePolicy.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { parse } from 'path'; 6 | import { CfnResource } from 'aws-cdk-lib'; 7 | import { CfnSubscription } from 'aws-cdk-lib/aws-sns'; 8 | import { NagRuleCompliance } from '../../nag-rules'; 9 | 10 | /** 11 | * SNS subscriptions have a redrive policy configured. 12 | * 13 | * @see https://docs.aws.amazon.com/sns/latest/dg/sns-dead-letter-queues.html 14 | */ 15 | export default Object.defineProperty( 16 | (node: CfnResource): NagRuleCompliance => { 17 | if (node instanceof CfnSubscription) { 18 | if (node.redrivePolicy === undefined) { 19 | return NagRuleCompliance.NON_COMPLIANT; 20 | } 21 | return NagRuleCompliance.COMPLIANT; 22 | } 23 | return NagRuleCompliance.NOT_APPLICABLE; 24 | }, 25 | 'name', 26 | { value: parse(__filename).name } 27 | ); 28 | -------------------------------------------------------------------------------- /src/rules/sns/index.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | export { default as SNSEncryptedKMS } from './SNSEncryptedKMS'; 6 | export { default as SNSRedrivePolicy } from './SNSRedrivePolicy'; 7 | export { default as SNSTopicSSLPublishOnly } from './SNSTopicSSLPublishOnly'; 8 | -------------------------------------------------------------------------------- /src/rules/sqs/SQSQueueSSE.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { parse } from 'path'; 6 | import { CfnResource, Stack } from 'aws-cdk-lib'; 7 | import { CfnQueue } from 'aws-cdk-lib/aws-sqs'; 8 | import { NagRuleCompliance } from '../../nag-rules'; 9 | 10 | /** 11 | * SQS queues have server-side encryption enabled 12 | * @param node the CfnResource to check 13 | */ 14 | export default Object.defineProperty( 15 | (node: CfnResource): NagRuleCompliance => { 16 | if (node instanceof CfnQueue) { 17 | const kmsMasterKeyId = Stack.of(node).resolve(node.kmsMasterKeyId); 18 | const sqsManagedSseEnabled = Stack.of(node).resolve( 19 | node.sqsManagedSseEnabled 20 | ); 21 | if (kmsMasterKeyId === undefined && sqsManagedSseEnabled === false) { 22 | return NagRuleCompliance.NON_COMPLIANT; 23 | } 24 | return NagRuleCompliance.COMPLIANT; 25 | } else { 26 | return NagRuleCompliance.NOT_APPLICABLE; 27 | } 28 | }, 29 | 'name', 30 | { value: parse(__filename).name } 31 | ); 32 | -------------------------------------------------------------------------------- /src/rules/sqs/SQSRedrivePolicy.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { CfnResource, Stack } from 'aws-cdk-lib'; 6 | import { CfnQueue } from 'aws-cdk-lib/aws-sqs'; 7 | import { NagRuleCompliance } from '../../nag-rules'; 8 | 9 | /** 10 | * SQS queues have a redrive policy configured 11 | * 12 | * @param node - the CfnResource to check 13 | */ 14 | export default function SQSRedrivePolicy(node: CfnResource): NagRuleCompliance { 15 | if (node instanceof CfnQueue) { 16 | const redrivePolicy = Stack.of(node).resolve(node.redrivePolicy); 17 | if (redrivePolicy !== undefined) { 18 | return NagRuleCompliance.COMPLIANT; 19 | } 20 | return NagRuleCompliance.NON_COMPLIANT; 21 | } 22 | return NagRuleCompliance.NOT_APPLICABLE; 23 | } 24 | -------------------------------------------------------------------------------- /src/rules/sqs/index.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | export { default as SQSQueueDLQ } from './SQSQueueDLQ'; 6 | export { default as SQSQueueSSE } from './SQSQueueSSE'; 7 | export { default as SQSQueueSSLRequestsOnly } from './SQSQueueSSLRequestsOnly'; 8 | export { default as SQSRedrivePolicy } from './SQSRedrivePolicy'; 9 | -------------------------------------------------------------------------------- /src/rules/stepfunctions/StepFunctionStateMachineAllLogsToCloudWatch.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { parse } from 'path'; 6 | import { CfnResource, Stack } from 'aws-cdk-lib'; 7 | import { CfnStateMachine, LogLevel } from 'aws-cdk-lib/aws-stepfunctions'; 8 | import { NagRuleCompliance, NagRules } from '../../nag-rules'; 9 | 10 | /** 11 | * Step Function log "ALL" events to CloudWatch Logs 12 | * @param node the CfnResource to check 13 | */ 14 | export default Object.defineProperty( 15 | (node: CfnResource): NagRuleCompliance => { 16 | if (node instanceof CfnStateMachine) { 17 | const loggingConfiguration = Stack.of(node).resolve( 18 | node.loggingConfiguration 19 | ); 20 | if (loggingConfiguration == undefined) { 21 | return NagRuleCompliance.NON_COMPLIANT; 22 | } 23 | const level = NagRules.resolveIfPrimitive( 24 | node, 25 | loggingConfiguration.level 26 | ); 27 | if (level == undefined || level != LogLevel.ALL) { 28 | return NagRuleCompliance.NON_COMPLIANT; 29 | } 30 | return NagRuleCompliance.COMPLIANT; 31 | } else { 32 | return NagRuleCompliance.NOT_APPLICABLE; 33 | } 34 | }, 35 | 'name', 36 | { value: parse(__filename).name } 37 | ); 38 | -------------------------------------------------------------------------------- /src/rules/stepfunctions/StepFunctionStateMachineXray.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { parse } from 'path'; 6 | import { CfnResource, Stack } from 'aws-cdk-lib'; 7 | import { CfnStateMachine } from 'aws-cdk-lib/aws-stepfunctions'; 8 | import { NagRuleCompliance, NagRules } from '../../nag-rules'; 9 | 10 | /** 11 | * Step Function have X-Ray tracing enabled 12 | * @param node the CfnResource to check 13 | */ 14 | export default Object.defineProperty( 15 | (node: CfnResource): NagRuleCompliance => { 16 | if (node instanceof CfnStateMachine) { 17 | const tracingConfiguration = Stack.of(node).resolve( 18 | node.tracingConfiguration 19 | ); 20 | if (tracingConfiguration == undefined) { 21 | return NagRuleCompliance.NON_COMPLIANT; 22 | } 23 | const enabled = NagRules.resolveIfPrimitive( 24 | node, 25 | tracingConfiguration.enabled 26 | ); 27 | if (!enabled) { 28 | return NagRuleCompliance.NON_COMPLIANT; 29 | } 30 | return NagRuleCompliance.COMPLIANT; 31 | } else { 32 | return NagRuleCompliance.NOT_APPLICABLE; 33 | } 34 | }, 35 | 'name', 36 | { value: parse(__filename).name } 37 | ); 38 | -------------------------------------------------------------------------------- /src/rules/stepfunctions/index.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | export { default as StepFunctionStateMachineAllLogsToCloudWatch } from './StepFunctionStateMachineAllLogsToCloudWatch'; 6 | export { default as StepFunctionStateMachineXray } from './StepFunctionStateMachineXray'; 7 | -------------------------------------------------------------------------------- /src/rules/timestream/TimestreamDatabaseCustomerManagedKey.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { parse } from 'path'; 6 | import { CfnResource } from 'aws-cdk-lib'; 7 | import { CfnDatabase } from 'aws-cdk-lib/aws-timestream'; 8 | import { NagRuleCompliance } from '../../nag-rules'; 9 | 10 | /** 11 | * Timestream databases use Customer Managed KMS Keys 12 | * @param node the CfnResource to check 13 | */ 14 | export default Object.defineProperty( 15 | (node: CfnResource): NagRuleCompliance => { 16 | if (node instanceof CfnDatabase) { 17 | if (node.kmsKeyId === undefined) { 18 | return NagRuleCompliance.NON_COMPLIANT; 19 | } 20 | return NagRuleCompliance.COMPLIANT; 21 | } else { 22 | return NagRuleCompliance.NOT_APPLICABLE; 23 | } 24 | }, 25 | 'name', 26 | { value: parse(__filename).name } 27 | ); 28 | -------------------------------------------------------------------------------- /src/rules/timestream/index.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | export { default as TimestreamDatabaseCustomerManagedKey } from './TimestreamDatabaseCustomerManagedKey'; 6 | -------------------------------------------------------------------------------- /src/rules/vpc/VPCNoNACLs.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { parse } from 'path'; 6 | import { CfnResource } from 'aws-cdk-lib'; 7 | import { CfnNetworkAcl, CfnNetworkAclEntry } from 'aws-cdk-lib/aws-ec2'; 8 | import { NagRuleCompliance } from '../../nag-rules'; 9 | 10 | /** 11 | * VPCs do not implement network ACLs 12 | * @param node the CfnResource to check 13 | */ 14 | export default Object.defineProperty( 15 | (node: CfnResource): NagRuleCompliance => { 16 | if (node instanceof CfnNetworkAcl || node instanceof CfnNetworkAclEntry) { 17 | return NagRuleCompliance.NON_COMPLIANT; 18 | } else { 19 | return NagRuleCompliance.NOT_APPLICABLE; 20 | } 21 | }, 22 | 'name', 23 | { value: parse(__filename).name } 24 | ); 25 | -------------------------------------------------------------------------------- /src/rules/vpc/VPCNoUnrestrictedRouteToIGW.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { parse } from 'path'; 6 | import { CfnResource } from 'aws-cdk-lib'; 7 | import { CfnRoute } from 'aws-cdk-lib/aws-ec2'; 8 | import { NagRuleCompliance, NagRules } from '../../nag-rules'; 9 | 10 | /** 11 | * Route tables do not have unrestricted routes ('0.0.0.0/0' or '::/0') to IGWs 12 | * @param node the CfnResource to check 13 | */ 14 | export default Object.defineProperty( 15 | (node: CfnResource): NagRuleCompliance => { 16 | if (node instanceof CfnRoute) { 17 | if (node.gatewayId != undefined) { 18 | const destinationCidrBlock = NagRules.resolveIfPrimitive( 19 | node, 20 | node.destinationCidrBlock 21 | ); 22 | const destinationIpv6CidrBlock = NagRules.resolveIfPrimitive( 23 | node, 24 | node.destinationIpv6CidrBlock 25 | ); 26 | if ( 27 | destinationCidrBlock != undefined && 28 | destinationCidrBlock.includes('/0') 29 | ) { 30 | return NagRuleCompliance.NON_COMPLIANT; 31 | } 32 | if ( 33 | destinationIpv6CidrBlock != undefined && 34 | destinationIpv6CidrBlock.includes('/0') 35 | ) { 36 | return NagRuleCompliance.NON_COMPLIANT; 37 | } 38 | } 39 | return NagRuleCompliance.COMPLIANT; 40 | } else { 41 | return NagRuleCompliance.NOT_APPLICABLE; 42 | } 43 | }, 44 | 'name', 45 | { value: parse(__filename).name } 46 | ); 47 | -------------------------------------------------------------------------------- /src/rules/vpc/VPCSubnetAutoAssignPublicIpDisabled.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { parse } from 'path'; 6 | import { CfnResource } from 'aws-cdk-lib'; 7 | import { CfnSubnet } from 'aws-cdk-lib/aws-ec2'; 8 | import { NagRuleCompliance, NagRules } from '../../nag-rules'; 9 | 10 | /** 11 | * Subnets do not auto-assign public IP addresses 12 | * @param node the CfnResource to check 13 | */ 14 | export default Object.defineProperty( 15 | (node: CfnResource): NagRuleCompliance => { 16 | if (node instanceof CfnSubnet) { 17 | const mapPublicIpOnLaunch = NagRules.resolveIfPrimitive( 18 | node, 19 | node.mapPublicIpOnLaunch 20 | ); 21 | const assignIpv6AddressOnCreation = NagRules.resolveIfPrimitive( 22 | node, 23 | node.assignIpv6AddressOnCreation 24 | ); 25 | if ( 26 | mapPublicIpOnLaunch === true || 27 | assignIpv6AddressOnCreation === true 28 | ) { 29 | return NagRuleCompliance.NON_COMPLIANT; 30 | } 31 | return NagRuleCompliance.COMPLIANT; 32 | } else { 33 | return NagRuleCompliance.NOT_APPLICABLE; 34 | } 35 | }, 36 | 'name', 37 | { value: parse(__filename).name } 38 | ); 39 | -------------------------------------------------------------------------------- /src/rules/vpc/index.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | export { default as VPCDefaultSecurityGroupClosed } from './VPCDefaultSecurityGroupClosed'; 6 | export { default as VPCFlowLogsEnabled } from './VPCFlowLogsEnabled'; 7 | export { default as VPCNoNACLs } from './VPCNoNACLs'; 8 | export { default as VPCNoUnrestrictedRouteToIGW } from './VPCNoUnrestrictedRouteToIGW'; 9 | export { default as VPCSubnetAutoAssignPublicIpDisabled } from './VPCSubnetAutoAssignPublicIpDisabled'; 10 | -------------------------------------------------------------------------------- /src/rules/waf/index.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | export { default as WAFv2LoggingEnabled } from './WAFv2LoggingEnabled'; 6 | -------------------------------------------------------------------------------- /test/rules/DMS.test.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { CfnReplicationInstance } from 'aws-cdk-lib/aws-dms'; 6 | import { Aspects, Stack } from 'aws-cdk-lib/core'; 7 | import { validateStack, TestType, TestPack } from './utils'; 8 | import { DMSReplicationNotPublic } from '../../src/rules/dms'; 9 | 10 | const testPack = new TestPack([DMSReplicationNotPublic]); 11 | let stack: Stack; 12 | 13 | beforeEach(() => { 14 | stack = new Stack(); 15 | Aspects.of(stack).add(testPack); 16 | }); 17 | 18 | describe('AWS Database Migration Service (AWS DMS)', () => { 19 | describe('DMSReplicationNotPublic: DMS replication instances are not public', () => { 20 | const ruleId = 'DMSReplicationNotPublic'; 21 | test('Noncompliance 1', () => { 22 | new CfnReplicationInstance(stack, 'rInstance', { 23 | replicationInstanceClass: 'dms.t2.micro', 24 | }); 25 | validateStack(stack, ruleId, TestType.NON_COMPLIANCE); 26 | }); 27 | test('Compliance', () => { 28 | new CfnReplicationInstance(stack, 'rInstance', { 29 | replicationInstanceClass: 'dms.t2.micro', 30 | publiclyAccessible: false, 31 | }); 32 | validateStack(stack, ruleId, TestType.COMPLIANCE); 33 | }); 34 | }); 35 | }); 36 | -------------------------------------------------------------------------------- /test/rules/ECR.test.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { Repository } from 'aws-cdk-lib/aws-ecr'; 6 | import { 7 | PolicyStatement, 8 | Effect, 9 | AccountPrincipal, 10 | AccountRootPrincipal, 11 | } from 'aws-cdk-lib/aws-iam'; 12 | import { Aspects, Stack } from 'aws-cdk-lib/core'; 13 | import { validateStack, TestType, TestPack } from './utils'; 14 | import { ECROpenAccess } from '../../src/rules/ecr'; 15 | 16 | const testPack = new TestPack([ECROpenAccess]); 17 | let stack: Stack; 18 | 19 | beforeEach(() => { 20 | stack = new Stack(); 21 | Aspects.of(stack).add(testPack); 22 | }); 23 | 24 | describe('Amazon Elastic Container Registry (ECR)', () => { 25 | describe('ECROpenAccess: ECR Repositories do not allow open access', () => { 26 | const ruleId = 'ECROpenAccess'; 27 | test('Noncompliance 1', () => { 28 | const repo = new Repository(stack, 'rRepo'); 29 | repo.addToResourcePolicy( 30 | new PolicyStatement({ 31 | effect: Effect.ALLOW, 32 | actions: ['*'], 33 | principals: [new AccountPrincipal('*'), new AccountRootPrincipal()], 34 | }) 35 | ); 36 | validateStack(stack, ruleId, TestType.NON_COMPLIANCE); 37 | }); 38 | test('Compliance', () => { 39 | new Repository(stack, 'rRepo'); 40 | validateStack(stack, ruleId, TestType.COMPLIANCE); 41 | }); 42 | }); 43 | }); 44 | -------------------------------------------------------------------------------- /test/rules/KMS.test.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { Key, KeySpec } from 'aws-cdk-lib/aws-kms'; 6 | import { Aspects, Stack } from 'aws-cdk-lib/core'; 7 | import { validateStack, TestType, TestPack } from './utils'; 8 | import { KMSBackingKeyRotationEnabled } from '../../src/rules/kms'; 9 | 10 | const testPack = new TestPack([KMSBackingKeyRotationEnabled]); 11 | let stack: Stack; 12 | 13 | beforeEach(() => { 14 | stack = new Stack(); 15 | Aspects.of(stack).add(testPack); 16 | }); 17 | 18 | describe('AWS Key Management Service (KMS)', () => { 19 | describe('KMSBackingKeyRotationEnabled: KMS Symmetric keys have automatic key rotation enabled', () => { 20 | const ruleId = 'KMSBackingKeyRotationEnabled'; 21 | test('Noncompliance 1', () => { 22 | new Key(stack, 'rSymmetricKey'); 23 | validateStack(stack, ruleId, TestType.NON_COMPLIANCE); 24 | }); 25 | test('Compliance', () => { 26 | new Key(stack, 'rSymmetricKey', { enableKeyRotation: true }); 27 | new Key(stack, 'rAsymmetricKey', { keySpec: KeySpec.RSA_4096 }); 28 | validateStack(stack, ruleId, TestType.COMPLIANCE); 29 | }); 30 | }); 31 | }); 32 | -------------------------------------------------------------------------------- /test/rules/QuickSight.test.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { CfnDataSource } from 'aws-cdk-lib/aws-quicksight'; 6 | import { Aspects, Stack } from 'aws-cdk-lib/core'; 7 | import { validateStack, TestType, TestPack } from './utils'; 8 | import { QuicksightSSLConnections } from '../../src/rules/quicksight'; 9 | 10 | const testPack = new TestPack([QuicksightSSLConnections]); 11 | let stack: Stack; 12 | 13 | beforeEach(() => { 14 | stack = new Stack(); 15 | Aspects.of(stack).add(testPack); 16 | }); 17 | 18 | describe('Amazon QuickSight', () => { 19 | describe('QuicksightSSLConnections: Quicksight data sources connections are configured to use SSL', () => { 20 | const ruleId = 'QuicksightSSLConnections'; 21 | test('Noncompliance 1', () => { 22 | new CfnDataSource(stack, 'Dashboard', { 23 | name: 'datasource', 24 | type: 'AMAZON_ELASTICSEARCH', 25 | sslProperties: { disableSsl: true }, 26 | }); 27 | validateStack(stack, ruleId, TestType.NON_COMPLIANCE); 28 | }); 29 | test('Compliance', () => { 30 | new CfnDataSource(stack, 'Dashboard', { 31 | name: 'datasource', 32 | type: 'AMAZON_ELASTICSEARCH', 33 | sslProperties: { disableSsl: false }, 34 | }); 35 | new CfnDataSource(stack, 'Dashboard2', { 36 | name: 'datasource', 37 | type: 'AMAZON_ELASTICSEARCH', 38 | sslProperties: {}, 39 | }); 40 | validateStack(stack, ruleId, TestType.COMPLIANCE); 41 | }); 42 | }); 43 | }); 44 | -------------------------------------------------------------------------------- /test/rules/Timestream.test.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { CfnDatabase } from 'aws-cdk-lib/aws-timestream'; 6 | import { Aspects, Stack } from 'aws-cdk-lib/core'; 7 | import { validateStack, TestType, TestPack } from './utils'; 8 | import { TimestreamDatabaseCustomerManagedKey } from '../../src/rules/timestream'; 9 | 10 | const testPack = new TestPack([TimestreamDatabaseCustomerManagedKey]); 11 | let stack: Stack; 12 | 13 | beforeEach(() => { 14 | stack = new Stack(); 15 | Aspects.of(stack).add(testPack); 16 | }); 17 | 18 | describe('Amazon Timestream', () => { 19 | describe('TimestreamDatabaseCustomerManagedKey: Timestream databases use Customer Managed KMS Keys', () => { 20 | const ruleId = 'TimestreamDatabaseCustomerManagedKey'; 21 | test('Noncompliance 1', () => { 22 | new CfnDatabase(stack, 'rTimestreamDb'); 23 | validateStack(stack, ruleId, TestType.NON_COMPLIANCE); 24 | }); 25 | test('Compliance', () => { 26 | new CfnDatabase(stack, 'rTimestreamDb', { 27 | kmsKeyId: 'foo', 28 | }); 29 | validateStack(stack, ruleId, TestType.COMPLIANCE); 30 | }); 31 | }); 32 | }); 33 | -------------------------------------------------------------------------------- /test/test-utils.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { SynthesisMessage } from 'aws-cdk-lib/cx-api'; 6 | 7 | interface ExpectMessageConditions { 8 | readonly containing?: string[]; 9 | readonly notContaining?: string[]; 10 | readonly length?: number; 11 | } 12 | export function expectMessages( 13 | messages: SynthesisMessage[], 14 | conditions: ExpectMessageConditions 15 | ) { 16 | if (conditions.containing) { 17 | for (const condition of conditions.containing) { 18 | expect(messages).toContainEqual( 19 | expect.objectContaining({ 20 | entry: expect.objectContaining({ 21 | data: expect.stringContaining(condition), 22 | }), 23 | }) 24 | ); 25 | } 26 | } 27 | if (conditions.notContaining) { 28 | for (const condition of conditions.notContaining) { 29 | expect(messages).not.toContainEqual( 30 | expect.objectContaining({ 31 | entry: expect.objectContaining({ 32 | data: expect.stringContaining(condition), 33 | }), 34 | }) 35 | ); 36 | } 37 | } 38 | if (conditions.length) { 39 | expect(messages.length).toEqual(conditions.length); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /tsconfig.dev.json: -------------------------------------------------------------------------------- 1 | // ~~ Generated by projen. To modify, edit .projenrc.js and run "npx projen". 2 | { 3 | "compilerOptions": { 4 | "alwaysStrict": true, 5 | "declaration": true, 6 | "esModuleInterop": true, 7 | "experimentalDecorators": true, 8 | "inlineSourceMap": true, 9 | "inlineSources": true, 10 | "lib": [ 11 | "es2020" 12 | ], 13 | "module": "CommonJS", 14 | "noEmitOnError": false, 15 | "noFallthroughCasesInSwitch": true, 16 | "noImplicitAny": true, 17 | "noImplicitReturns": true, 18 | "noImplicitThis": true, 19 | "noUnusedLocals": true, 20 | "noUnusedParameters": true, 21 | "resolveJsonModule": true, 22 | "strict": true, 23 | "strictNullChecks": true, 24 | "strictPropertyInitialization": true, 25 | "stripInternal": true, 26 | "target": "ES2020" 27 | }, 28 | "include": [ 29 | "src/**/*.ts", 30 | "test/**/*.ts", 31 | ".projenrc.js" 32 | ], 33 | "exclude": [ 34 | "node_modules" 35 | ] 36 | } 37 | --------------------------------------------------------------------------------