UNPKG

mira

Version:

NearForm Accelerator for Cloud Native Serverless AWS

115 lines (107 loc) 4.27 kB
import * as cdk from '@aws-cdk/core' import { PolicyStatement, CfnManagedPolicy, CfnPolicy, ManagedPolicyProps } from '@aws-cdk/aws-iam' import { CfnQueuePolicy } from '@aws-cdk/aws-sqs' import { CfnBucketPolicy } from '@aws-cdk/aws-s3' import { CfnVPCEndpoint } from '@aws-cdk/aws-ec2' import { CfnTopicPolicy } from '@aws-cdk/aws-sns' interface HasPolicyDocument extends cdk.IConstruct { policyDocument: ManagedPolicyProps cfnResourceType: string }; /** * The Policy class is used by Mira to validate policy aspects of various cloud services. */ export class Policies implements cdk.IAspect { constructor (customList?: string[]) { if (customList) { this.allowedServices = customList } } /** * reasons why to exclude some actions from validation: * * https://docs.aws.amazon.com/IAM/latest/UserGuide/list_amazonmobileanalytics.html * https://github.com/aws/aws-cdk/blob/master/packages/%40aws-cdk/aws-certificatemanager/lib/dns-validated-certificate.ts * * @ignore - Excluded from documentation generation. */ private allowedServices: string[] = [ 'mobileanalytics:PutEvents', 'cognito-idp:CreateUserPool', 'secretsmanager:GetRandomPassword', 'ec2:AllocateAddress', 'ec2:AssociateRouteTable', 'ec2:AttachInternetGateway', 'ec2:CreateInternetGateway', 'ec2:CreateNatGateway', 'ec2:CreateRoute', 'ec2:CreateRouteTable', 'ec2:CreateSecurityGroup', 'ec2:CreateSubnet', 'ec2:CreateVpc', 'ec2:DeleteNatGateway', 'ec2:DeleteSubnet', 'ec2:DeleteVpc', 'ec2:Describe*', 'ec2:DetachInternetGateway', 'ec2:DisassociateAddress', 'ec2:DisassociateRouteTable', 'ec2:ModifySubnetAttribute', 'ec2:ModifyVpcAttribute', 'ec2:ReleaseAddress', 'ecr:GetAuthorizationToken', 'acm:RequestCertificate', 'acm:DescribeCertificate', 'acm:DeleteCertificate', 'acm:ListCertificates', 'route53:GetChange', 'route53:ListResourceRecordSets', 'cloudfront:GetInvalidation', 'cloudfront:CreateInvalidation', 'personalize:CreateSchema', 'personalize:DeleteSchema', 'personalize:CreateDatasetGroup', 'personalize:DeleteDatasetGroup', 'personalize:CreateDataset', 'personalize:DeleteDataset', 'personalize:CreateDatasetImportJob' ] /** * The list of services that supports policyDocument * * @ignore - Excluded from documentation generation. */ private readonly policiesResourceType: string[] = [ CfnQueuePolicy.CFN_RESOURCE_TYPE_NAME, CfnBucketPolicy.CFN_RESOURCE_TYPE_NAME, CfnManagedPolicy.CFN_RESOURCE_TYPE_NAME, CfnPolicy.CFN_RESOURCE_TYPE_NAME, CfnVPCEndpoint.CFN_RESOURCE_TYPE_NAME, CfnTopicPolicy.CFN_RESOURCE_TYPE_NAME ] /** * * @ignore - Excluded from documentation generation. */ private actionsAllowed (actions: string[]): boolean { return actions.filter((action: string) => !this.allowedServices.includes(action)).length === 0 } public visit (node: cdk.IConstruct | HasPolicyDocument): void { // The check is done using the `cfnResourceType`. // NOTE: The original check was done with a `instanceof CfnPolicy`. That check always returned false, // probably caused by a conflict with the import of the file from 2 different `node_module` places if ('cfnResourceType' in node && this.policiesResourceType.includes(node.cfnResourceType) && node.policyDocument?.statements) { const statements: PolicyStatement[] = node.policyDocument.statements statements.forEach(statement => { const statementJson = statement.toJSON() const resource = Array.isArray(statementJson.Resource) ? statementJson.Resource : [statementJson.Resource] const action = Array.isArray(statementJson.Action) ? statementJson.Action : [statementJson.Action] resource.forEach((resource: string) => { if (resource === '*' && !this.actionsAllowed(action)) { node.node.addError('Unqualified asterisks are not allowed in resource specification for policies') } }) }) } } }