diff --git a/templates/00-main.yaml b/templates/00-main.yaml index e432b7e..c05325b 100644 --- a/templates/00-main.yaml +++ b/templates/00-main.yaml @@ -1,7 +1,6 @@ --- AWSTemplateFormatVersion: 2010-09-09 - -Description: Stack to deploy a highly available, elastic, scalable Moodle environment. This master stack launches multiple nested stacks for different tiers. !! This can only be run in certain AWS Regions - 'us-east-1', 'us-east-2', 'us-west-2', 'eu-west-1'. +Description: Moodle Metadata: AWS::CloudFormation::Interface: @@ -10,8 +9,6 @@ Metadata: default: General AWS Parameters: - DeploymentLocation - - EC2KeyName - - SshAccessCidr - HostedZoneName - DomainName - NotifyEmailAddress @@ -33,7 +30,6 @@ Metadata: - Label: default: Shared File Storage Parameters: - - SharedStorageEncryptionBoolean - SharedStorageEncryptionCmk - Label: default: Database Tier @@ -43,7 +39,6 @@ Metadata: - DatabaseMinCapacity - DatabaseMaxCapacity - DatabaseInstanceType - - DatabaseEncryptedBoolean - DatabaseCmk - DatabaseMasterUsername # - DatabaseMasterPassword @@ -53,16 +48,13 @@ Metadata: Parameters: - CacheEngineType - UseSessionCacheBoolean + - UseServerlessSessionCache - SessionCacheNodeType - UseApplicationCacheBoolean + - UseServerlessApplicationCache - ApplicationCacheNodeType - UseCloudFrontBoolean - CloudFrontAcmCertificate - - Label: - default: Bastion Tier - Parameters: - - NeedBastionHost - - BastionInstanceType - Label: default: Web Tier Parameters: @@ -77,16 +69,10 @@ Metadata: ParameterLabels: DeploymentLocation: default: "Location to deploy from (S3 URL without trailing slash, e.g.: https://.s3..amazonaws.com)" - BastionInstanceType: - default: Bastion Instance Type - NeedBastionHost: - default: Need Bastion Host? CloudFrontAcmCertificate: default: CloudFront Certificate ARN DatabaseCmk: default: AWS KMS CMK for RDS - DatabaseEncryptedBoolean: - default: Encrypted DB Cluster DatabaseUseServerless: default: Should the database use Serverless engines? DatabaseMinCapacity: @@ -99,16 +85,10 @@ Metadata: default: DB Master Username DatabaseName: default: DB Name - SharedStorageEncryptionBoolean: - default: Shared File Storage Encrypted? SharedStorageEncryptionCmk: default: (Optional) Shared File Storage Encryption Key ARN (AWS KMS CMK) - EC2KeyName: - default: EC2 Key Pair PublicAlbAcmCertificate: default: ALB Certificate ARN - SshAccessCidr: - default: SSH Access From UseApplicationCacheBoolean: default: Use Application Cache ApplicationCacheNodeType: @@ -158,118 +138,11 @@ Metadata: UseCloudFrontBoolean: default: Use CloudFront - Parameters: DeploymentLocation: - Description: Location to deploy from (S3 URL), Keep it as is unless you created your own S3 bucket - Type: String - Default: https://s3.amazonaws.com/aws-refarch/moodle/al2023/templates - BastionInstanceType: - AllowedValues: - - t3.nano - - t3.micro - - t3.small - - t3.medium - - t3.large - - t3.xlarge - - t3.2xlarge - - m5.large - - m5.xlarge - - m5.2xlarge - - m5.4xlarge - - m5.8xlarge - - m5.12xlarge - - m5.16xlarge - - m5.24xlarge - - c5.large - - c5.xlarge - - c5.2xlarge - - c5.4xlarge - - c5.9xlarge - - c5.12xlarge - - c5.18xlarge - - c5.24xlarge - - r5.large - - r5.xlarge - - r5.2xlarge - - r5.4xlarge - - r5.8xlarge - - r5.12xlarge - - r5.16xlarge - - r5.24xlarge - - t3a.nano - - t3a.micro - - t3a.small - - t3a.medium - - t3a.large - - t3a.xlarge - - t3a.2xlarge - - m5a.large - - m5a.xlarge - - m5a.2xlarge - - m5a.4xlarge - - m5a.8xlarge - - m5a.12xlarge - - m5a.16xlarge - - m5a.24xlarge - - c5a.large - - c5a.xlarge - - c5a.2xlarge - - c5a.4xlarge - - c5a.9xlarge - - c5a.12xlarge - - c5a.18xlarge - - c5a.24xlarge - - r5a.large - - r5a.xlarge - - r5a.2xlarge - - r5a.4xlarge - - r5a.8xlarge - - r5a.12xlarge - - r5a.16xlarge - - r5a.24xlarge - - t4g.nano - - t4g.micro - - t4g.small - - t4g.medium - - t4g.large - - t4g.xlarge - - t4g.2xlarge - - m6g.large - - m6g.xlarge - - m6g.2xlarge - - m6g.4xlarge - - m6g.8xlarge - - m6g.12xlarge - - m6g.16xlarge - - m6g.24xlarge - - c6g.large - - c6g.xlarge - - c6g.2xlarge - - c6g.4xlarge - - c6g.9xlarge - - c6g.12xlarge - - c6g.18xlarge - - c6g.24xlarge - - r6g.large - - r6g.xlarge - - r6g.2xlarge - - r6g.4xlarge - - r6g.8xlarge - - r6g.12xlarge - - r6g.16xlarge - - r6g.24xlarge - ConstraintDescription: Must be a valid Amazon EC2 instance type. - Default: t4g.nano - Description: Bastion EC2 instance type. - Type: String - NeedBastionHost: - AllowedValues: - - false - - true - Default: false - Description: Whether you need Bastion host to access machines, else you can use SSM agent by default. + Description: Templates location (S3 URL). By default, uses AWS provided templates. Type: String + Default: https://s3.amazonaws.com/aws-refarch/moodle/4.4/templates PublicAlbAcmCertificate: AllowedPattern: ^$|(arn:aws:acm:)([a-z0-9/:-])*([a-z0-9])$ Description: '[ Optional ] The AWS Certification Manager certificate ARN for the ALB certificate - this certificate should be created in the region you wish to run the ALB and must reference the domain name you use below.' @@ -288,13 +161,6 @@ Parameters: Default: PostgreSQL Description: Indicates whether to use Aurora MySQL or PostgreSQL. Type: String - DatabaseEncryptedBoolean: - AllowedValues: - - true - - false - Default: true - Description: Indicates whether the DB instances in the cluster are encrypted. - Type: String DatabaseUseServerless: AllowedValues: - true @@ -334,6 +200,8 @@ Parameters: AllowedValues: - db.t3.medium - db.t3.large + - db.t4g.medium + - db.t4g.large - db.r5.large - db.r5.xlarge - db.r5.2xlarge @@ -348,6 +216,21 @@ Parameters: - db.r6g.8xlarge - db.r6g.12xlarge - db.r6g.16xlarge + - db.r6i.large + - db.r6i.xlarge + - db.r6i.2xlarge + - db.r6i.4xlarge + - db.r6i.8xlarge + - db.r6i.12xlarge + - db.r6i.16xlarge + - db.r6i.24xlarge + - db.r6i.32xlarge + - db.r6gd.xlarge + - db.r6gd.2xlarge + - db.r6gd.4xlarge + - db.r6gd.8xlarge + - db.r6gd.12xlarge + - db.r6gd.16xlarge ConstraintDescription: Must be a valid Aurora RDS instance type. Default: db.r6g.large Description: Amazon RDS database instance type (only used if non-serverless) @@ -365,13 +248,6 @@ Parameters: Description: Aurora RDS database name Type: String Default: moodle - SharedStorageEncryptionBoolean: - AllowedValues: - - true - - false - Default: true - Description: Do you want encrypted Shared file storage? - Type: String SharedStorageEncryptionCmk: AllowedPattern: ^$|(arn:aws:kms:)([a-z0-9/:-])*([a-z0-9])$ ConstraintDescription: Must be an existing ARN for an AWS KMS CMK. @@ -389,14 +265,32 @@ Parameters: AllowedValues: - true - false - Default: false - Description: Specifies whether an ElastiCache Cache Cluster should be created for sessions. This will not be used at first and will be integrated only after IsMoodleSetupComplete parameter changes to 'Yes'. + Default: true + Description: Set to true to deploy ElastiCache session cache. This will not be used at first and will be integrated only after IsMoodleSetupComplete parameter changes to 'Yes'. + Type: String + UseServerlessSessionCache: + AllowedValues: + - true + - false + Default: true + Description: Set to true to deploy ElastiCache session cache using serverless approach. Set to false to use instances instead. Type: String SessionCacheNodeType: AllowedValues: + - cache.t2.micro + - cache.t2.small + - cache.t2.medium - cache.t3.micro - cache.t3.small - cache.t3.medium + - cache.t4g.micro + - cache.t4g.small + - cache.t4g.medium + - cache.m4.large + - cache.m4.xlarge + - cache.m4.2xlarge + - cache.m4.4xlarge + - cache.m4.10xlarge - cache.m5.large - cache.m5.xlarge - cache.m5.2xlarge @@ -410,8 +304,33 @@ Parameters: - cache.m6g.8xlarge - cache.m6g.12xlarge - cache.m6g.16xlarge + - cache.r4.large + - cache.r4.xlarge + - cache.r4.2xlarge + - cache.r4.4xlarge + - cache.r4.8xlarge + - cache.r4.16xlarge + - cache.r5.large + - cache.r5.xlarge + - cache.r5.2xlarge + - cache.r5.4xlarge + - cache.r5.12xlarge + - cache.r5.24xlarge + - cache.r6g.large + - cache.r6g.xlarge + - cache.r6g.2xlarge + - cache.r6g.4xlarge + - cache.r6g.8xlarge + - cache.r6g.12xlarge + - cache.r6g.16xlarge + - cache.r6gd.xlarge + - cache.r6gd.2xlarge + - cache.r6gd.4xlarge + - cache.r6gd.8xlarge + - cache.r6gd.12xlarge + - cache.r6gd.16xlarge ConstraintDescription: Must be a valid Amazon ElastiCache node type. - Default: cache.m6g.large + Default: cache.r6g.large Description: The Amazon ElastiCache cluster node type. Type: String UseApplicationCacheBoolean: @@ -421,11 +340,29 @@ Parameters: Default: false Description: Specifies whether an ElastiCache Cache Cluster should be created to cache application content. Type: String + UseServerlessApplicationCache: + AllowedValues: + - true + - false + Default: true + Description: Indicates whether to use serverless ElastiCache for application. + Type: String ApplicationCacheNodeType: AllowedValues: + - cache.t2.micro + - cache.t2.small + - cache.t2.medium - cache.t3.micro - cache.t3.small - cache.t3.medium + - cache.t4g.micro + - cache.t4g.small + - cache.t4g.medium + - cache.m4.large + - cache.m4.xlarge + - cache.m4.2xlarge + - cache.m4.4xlarge + - cache.m4.10xlarge - cache.m5.large - cache.m5.xlarge - cache.m5.2xlarge @@ -439,19 +376,35 @@ Parameters: - cache.m6g.8xlarge - cache.m6g.12xlarge - cache.m6g.16xlarge + - cache.r4.large + - cache.r4.xlarge + - cache.r4.2xlarge + - cache.r4.4xlarge + - cache.r4.8xlarge + - cache.r4.16xlarge + - cache.r5.large + - cache.r5.xlarge + - cache.r5.2xlarge + - cache.r5.4xlarge + - cache.r5.12xlarge + - cache.r5.24xlarge + - cache.r6g.large + - cache.r6g.xlarge + - cache.r6g.2xlarge + - cache.r6g.4xlarge + - cache.r6g.8xlarge + - cache.r6g.12xlarge + - cache.r6g.16xlarge + - cache.r6gd.xlarge + - cache.r6gd.2xlarge + - cache.r6gd.4xlarge + - cache.r6gd.8xlarge + - cache.r6gd.12xlarge + - cache.r6gd.16xlarge ConstraintDescription: Must be a valid Amazon ElastiCache node type. - Default: cache.m6g.large + Default: cache.r6g.large Description: The Amazon ElastiCache cluster node type. Type: String - EC2KeyName: - ConstraintDescription: Must be letters (upper or lower), numbers, and special characters. - Description: Name of an EC2 KeyPair. Your bastion & Web instances will launch with this KeyPair. - Type: AWS::EC2::KeyPair::KeyName - SshAccessCidr: - AllowedPattern: ^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(\/([0-9]|[1-2][0-9]|3[0-2]))$ - Description: The CIDR IP range that is permitted to SSH to bastion instance. Note - a value of 0.0.0.0/0 will allow access from ANY IP address. You could also use /32 to restrict to your own public IP address. - Type: String - Default: 0.0.0.0/0 WebAsgMax: AllowedPattern: ^((?!0$)[1-2]?[0-9]|30)$ ConstraintDescription: Must be a number between 1 and 30. @@ -542,7 +495,15 @@ Parameters: - m6g.8xlarge - m6g.12xlarge - m6g.16xlarge - - m6g.24xlarge + - m6g.24xlarge + - m7g.medium + - m7g.large + - m7g.xlarge + - m7g.2xlarge + - m7g.4xlarge + - m7g.8xlarge + - m7g.12xlarge + - m7g.16xlarge - c6g.large - c6g.xlarge - c6g.2xlarge @@ -559,8 +520,16 @@ Parameters: - r6g.12xlarge - r6g.16xlarge - r6g.24xlarge + - c7g.medium + - c7g.large + - c7g.xlarge + - c7g.2xlarge + - c7g.4xlarge + - c7g.8xlarge + - c7g.12xlarge + - c7g.16xlarge ConstraintDescription: Must be a valid Amazon EC2 instance type. - Default: m6g.large + Default: c7g.xlarge Description: The Amazon EC2 instance type for your web instances. Type: String HostedZoneName: @@ -576,8 +545,7 @@ Parameters: Type: String Default: en AvailabilityZones: - Description: 'List of Availability Zones to use for the subnets in the VPC. Note: - The logical order is preserved.' + Description: 'List of Availability Zones to use for the subnets in the VPC. Note: The logical order is preserved.' Type: List NumberOfAZs: AllowedValues: @@ -670,8 +638,12 @@ Conditions: !Equals [ false, !Ref UseSessionCacheBoolean ] DeployWithSessionCache: !Equals [ true, !Ref UseSessionCacheBoolean ] + DeployWithServerlessSessionCache: + !Equals [ true, !Ref UseServerlessSessionCache ] DeployApplicationCache: !Equals [ true, !Ref UseApplicationCacheBoolean ] + DeployWithServerlessApplicationCache: + !Equals [ true, !Ref UseServerlessApplicationCache ] DeployRoute53: !And [ !Not [!Equals ['', !Ref DomainName ] ], @@ -702,8 +674,6 @@ Conditions: !Equals [ true, !Ref UseCloudFrontBoolean ] ] ] - DeployWithBastionHost: - !Equals [true, !Ref NeedBastionHost ] SharedStorageEFS: !Equals ['EFS', 'EFS' ] DeployUsingRDSServerless: @@ -801,32 +771,14 @@ Resources: Type: AWS::CloudFormation::Stack Properties: Parameters: - SshAccessCidr: - !Ref SshAccessCidr Vpc: !GetAtt [ vpc, Outputs.Vpc ] DatabaseType: !Ref DatabaseType + ElastiCacheType: + !Ref CacheEngineType TemplateURL: !Sub '${DeploymentLocation}/02-securitygroups.yaml' - bastion: - Condition: DeployWithBastionHost - DependsOn: securitygroups - Type: AWS::CloudFormation::Stack - Properties: - Parameters: - BastionInstanceType: - !Ref BastionInstanceType - BastionSecurityGroup: - !GetAtt [ securitygroups, Outputs.BastionSecurityGroup ] - EC2KeyName: - !Ref EC2KeyName - NumberOfSubnets: - !Ref NumberOfAZs - Subnet: - !GetAtt [ vpc, Outputs.PublicSubnet ] - TemplateURL: !Sub '${DeploymentLocation}/03-bastion.yaml' - publicalb: DependsOn: securitygroups Type: AWS::CloudFormation::Stack @@ -862,8 +814,6 @@ Resources: !Ref rdsInstanceSecret DatabaseName: !Ref DatabaseName - DatabaseEncryptedBoolean: - !Ref DatabaseEncryptedBoolean DatabaseCmk: !Ref DatabaseCmk DatabaseSecurityGroup: @@ -892,8 +842,6 @@ Resources: !Ref DatabaseMinCapacity DatabaseMaxCapacity: !Ref DatabaseMaxCapacity - DatabaseEncryptedBoolean: - !Ref DatabaseEncryptedBoolean DatabaseCmk: !Ref DatabaseCmk DatabaseSecurityGroup: @@ -912,8 +860,6 @@ Resources: Type: AWS::CloudFormation::Stack Properties: Parameters: - EncryptedBoolean: - !Ref SharedStorageEncryptionBoolean Cmk: !Ref SharedStorageEncryptionCmk SecurityGroup: @@ -931,10 +877,8 @@ Resources: Type: AWS::CloudFormation::Stack Properties: Parameters: - EC2KeyName: - !Ref EC2KeyName PipelineSecurityGroup: - !GetAtt [ securitygroups, Outputs.EfsSecurityGroup ] + !GetAtt [ securitygroups, Outputs.WebSecurityGroup ] NumberOfSubnets: !Ref NumberOfAZs PipelineSubnet: @@ -963,19 +907,14 @@ Resources: Parameters: CacheEngineType: !Ref CacheEngineType CacheUsageType: 'session' - Subnet: - !GetAtt [ vpc, Outputs.DataSubnet ] - ElastiCacheClusterName: - !Sub '${AWS::StackName}session' - ElastiCacheNodeType: - !Ref SessionCacheNodeType - ElastiCacheSecurityGroup: - !GetAtt [ securitygroups, Outputs.ElastiCacheSecurityGroup ] - NumberOfSubnets: - !Ref NumberOfAZs - ProjectName: - !Sub '${AWS::StackName}' - TemplateURL: !Sub '${DeploymentLocation}/03-elasticache.yaml' + Subnet: !GetAtt [ vpc, Outputs.DataSubnet ] + ElastiCacheClusterName: !Sub '${AWS::StackName}session' + ElastiCacheNodeType: !Ref SessionCacheNodeType + ElastiCacheSecurityGroup: !GetAtt [ securitygroups, Outputs.ElastiCacheSecurityGroup ] + NumberOfSubnets: !Ref NumberOfAZs + ProjectName: !Sub '${AWS::StackName}' + TemplateURL: !If [ DeployWithServerlessSessionCache, !Sub '${DeploymentLocation}/03-elasticacheserverless.yaml', !Sub '${DeploymentLocation}/03-elasticache.yaml' ] + applicationcache: Condition: DeployApplicationCache DependsOn: securitygroups @@ -984,19 +923,14 @@ Resources: Parameters: CacheEngineType: !Ref CacheEngineType CacheUsageType: 'application' - Subnet: - !GetAtt [ vpc, Outputs.DataSubnet ] - ElastiCacheClusterName: - !Sub '${AWS::StackName}application' - ElastiCacheNodeType: - !Ref ApplicationCacheNodeType - ElastiCacheSecurityGroup: - !GetAtt [ securitygroups, Outputs.ElastiCacheSecurityGroup ] - NumberOfSubnets: - !Ref NumberOfAZs - ProjectName: - !Sub '${AWS::StackName}' - TemplateURL: !Sub '${DeploymentLocation}/03-elasticache.yaml' + Subnet: !GetAtt [ vpc, Outputs.DataSubnet ] + ElastiCacheClusterName: !Sub '${AWS::StackName}application' + ElastiCacheNodeType: !Ref ApplicationCacheNodeType + ElastiCacheSecurityGroup: !GetAtt [ securitygroups, Outputs.ElastiCacheSecurityGroup ] + NumberOfSubnets: !Ref NumberOfAZs + ProjectName: !Sub '${AWS::StackName}' + TemplateURL: !If [ DeployWithServerlessApplicationCache, !Sub '${DeploymentLocation}/03-elasticacheserverless.yaml', !Sub '${DeploymentLocation}/03-elasticache.yaml' ] + webapp: DependsOn: [ publicalb, pipelineHelper ] Type: AWS::CloudFormation::Stack @@ -1004,8 +938,6 @@ Resources: Parameters: RDSInstanceSecretArn: !Ref rdsInstanceSecret - EC2KeyName: - !Ref EC2KeyName NumberOfSubnets: !Ref NumberOfAZs Subnet: diff --git a/templates/01-newvpc.yaml b/templates/01-newvpc.yaml index 91da615..b376964 100644 --- a/templates/01-newvpc.yaml +++ b/templates/01-newvpc.yaml @@ -1,60 +1,10 @@ --- AWSTemplateFormatVersion: 2010-09-09 +Description: Moodle network (VPC) -Description: Reference Architecture to host Moodle on AWS - Creates New VPC - -Metadata: - - AWS::CloudFormation::Interface: - - ParameterGroups: - - Label: - default: Amazon VPC Parameters - Parameters: - - NumberOfAZs - - AvailabilityZones - - VpcCidr - - PublicSubnet0Cidr - - PublicSubnet1Cidr - - PublicSubnet2Cidr - - AppSubnet0Cidr - - AppSubnet1Cidr - - AppSubnet2Cidr - - DataSubnet0Cidr - - DataSubnet1Cidr - - DataSubnet2Cidr - - ParameterLabels: - AvailabilityZones: - default: Availability Zones - NumberOfAZs: - default: Number of Availability Zones - VpcCidr: - default: VpcCidr - PublicSubnet0Cidr: - default: Public Subnet 0 - PublicSubnet1Cidr: - default: Public Subnet 1 - PublicSubnet2Cidr: - default: Public Subnet 2 - AppSubnet0Cidr: - default: App Subnet 0 - AppSubnet1Cidr: - default: App Subnet 1 - AppSubnet2Cidr: - default: App Subnet 2 - DataSubnet0Cidr: - default: Data Subnet 0 - DataSubnet1Cidr: - default: Data Subnet 1 - DataSubnet2Cidr: - default: Data Subnet 2 - Parameters: - AvailabilityZones: - Description: 'List of Availability Zones to use for the subnets in the VPC. Note: - The logical order is preserved.' + Description: 'List of Availability Zones to use for the subnets in the VPC. Note: The logical order is preserved.' Type: List NumberOfAZs: AllowedValues: @@ -62,8 +12,7 @@ Parameters: - 2 - 3 Default: 2 - Description: Number of Availability Zones to use in the VPC. This must match your - selections in the list of Availability Zones parameter. + Description: Number of Availability Zones to use in the VPC. This must match your selections in the list of Availability Zones parameter. Type: Number VpcCidr: AllowedPattern: "^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(\\/(1[6-9]|2[0-8]))$" @@ -127,13 +76,9 @@ Parameters: Type: String Conditions: - - NumberOfAZs1: - !Equals [ '1', !Ref NumberOfAZs ] - NumberOfAZs2: - !Equals [ '2', !Ref NumberOfAZs ] - NumberOfAZs3: - !Equals [ '3', !Ref NumberOfAZs ] + NumberOfAZs1: !Equals [ '1', !Ref NumberOfAZs ] + NumberOfAZs2: !Equals [ '2', !Ref NumberOfAZs ] + NumberOfAZs3: !Equals [ '3', !Ref NumberOfAZs ] AZ0: !Or - !Condition NumberOfAZs1 - !Condition NumberOfAZs2 @@ -144,7 +89,6 @@ Conditions: AZ2: !Condition NumberOfAZs3 Resources: - AppSubnet0: Condition: AZ0 Type: AWS::EC2::Subnet @@ -158,6 +102,7 @@ Resources: - Key: SubnetType Value: Private VpcId: !Ref Vpc + AppSubnet1: Condition: AZ1 Type: AWS::EC2::Subnet @@ -171,6 +116,7 @@ Resources: - Key: SubnetType Value: Private VpcId: !Ref Vpc + AppSubnet2: Condition: AZ2 Type: AWS::EC2::Subnet @@ -191,12 +137,14 @@ Resources: Properties: RouteTableId: !Ref NatRouteTable0 SubnetId: !Ref AppSubnet0 + AppSubnetRouteTableAssociation1: Condition: AZ1 Type: AWS::EC2::SubnetRouteTableAssociation Properties: RouteTableId: !Ref NatRouteTable1 SubnetId: !Ref AppSubnet1 + AppSubnetRouteTableAssociation2: Condition: AZ2 Type: AWS::EC2::SubnetRouteTableAssociation @@ -217,6 +165,7 @@ Resources: - Key: SubnetType Value: Private VpcId: !Ref Vpc + DataSubnet1: Condition: AZ1 Type: AWS::EC2::Subnet @@ -230,6 +179,7 @@ Resources: - Key: SubnetType Value: Private VpcId: !Ref Vpc + DataSubnet2: Condition: AZ2 Type: AWS::EC2::Subnet @@ -250,25 +200,28 @@ Resources: Properties: RouteTableId: !Ref NatRouteTable0 SubnetId: !Ref DataSubnet0 + DataSubnetRouteTableAssociation1: Condition: AZ1 Type: AWS::EC2::SubnetRouteTableAssociation Properties: RouteTableId: !Ref NatRouteTable1 SubnetId: !Ref DataSubnet1 + DataSubnetRouteTableAssociation2: Condition: AZ2 Type: AWS::EC2::SubnetRouteTableAssociation Properties: RouteTableId: !Ref NatRouteTable2 SubnetId: !Ref DataSubnet2 - + InternetGateway: Type: AWS::EC2::InternetGateway Properties: Tags: - Key: Name Value: !Join [ '', [ 'InternetGateway / ', !Ref 'AWS::StackName' ] ] + AttachInternetGateway: Type: AWS::EC2::VPCGatewayAttachment Properties: @@ -280,6 +233,7 @@ Resources: Type: AWS::EC2::EIP Properties: Domain: vpc + NatGateway0: Condition: AZ0 Type: AWS::EC2::NatGateway @@ -287,6 +241,7 @@ Resources: Properties: AllocationId: !GetAtt NatEIP0.AllocationId SubnetId: !Ref PublicSubnet0 + NatRoute0: Condition: AZ0 Type: AWS::EC2::Route @@ -294,6 +249,7 @@ Resources: RouteTableId: !Ref NatRouteTable0 DestinationCidrBlock: 0.0.0.0/0 NatGatewayId: !Ref NatGateway0 + NatRouteTable0: Condition: AZ0 Type: AWS::EC2::RouteTable @@ -310,6 +266,7 @@ Resources: Type: AWS::EC2::EIP Properties: Domain: vpc + NatGateway1: Condition: AZ1 Type: AWS::EC2::NatGateway @@ -317,6 +274,7 @@ Resources: Properties: AllocationId: !GetAtt NatEIP1.AllocationId SubnetId: !Ref PublicSubnet1 + NatRoute1: Condition: AZ1 Type: AWS::EC2::Route @@ -324,6 +282,7 @@ Resources: RouteTableId: !Ref NatRouteTable1 DestinationCidrBlock: 0.0.0.0/0 NatGatewayId: !Ref NatGateway1 + NatRouteTable1: Condition: AZ1 Type: AWS::EC2::RouteTable @@ -340,6 +299,7 @@ Resources: Type: AWS::EC2::EIP Properties: Domain: vpc + NatGateway2: Condition: AZ2 Type: AWS::EC2::NatGateway @@ -347,6 +307,7 @@ Resources: Properties: AllocationId: !GetAtt NatEIP2.AllocationId SubnetId: !Ref PublicSubnet2 + NatRoute2: Condition: AZ2 Type: AWS::EC2::Route @@ -354,6 +315,7 @@ Resources: RouteTableId: !Ref NatRouteTable2 DestinationCidrBlock: 0.0.0.0/0 NatGatewayId: !Ref NatGateway2 + NatRouteTable2: Condition: AZ2 Type: AWS::EC2::RouteTable @@ -372,6 +334,7 @@ Resources: RouteTableId: !Ref PublicRouteTable DestinationCidrBlock: 0.0.0.0/0 GatewayId: !Ref InternetGateway + PublicRouteTable: Type: AWS::EC2::RouteTable Properties: @@ -381,65 +344,70 @@ Resources: - Key: Network Value: Public VpcId: !Ref Vpc + PublicRouteTableAssociation0: Condition: AZ0 Type: AWS::EC2::SubnetRouteTableAssociation Properties: SubnetId: !Ref PublicSubnet0 RouteTableId: !Ref PublicRouteTable + PublicRouteTableAssociation1: Condition: AZ1 Type: AWS::EC2::SubnetRouteTableAssociation Properties: SubnetId: !Ref PublicSubnet1 RouteTableId: !Ref PublicRouteTable + PublicRouteTableAssociation2: Condition: AZ2 Type: AWS::EC2::SubnetRouteTableAssociation Properties: SubnetId: !Ref PublicSubnet2 RouteTableId: !Ref PublicRouteTable - + PublicSubnet0: Condition: AZ0 Type: AWS::EC2::Subnet Properties: AvailabilityZone: !Select [ 0, !Ref AvailabilityZones ] CidrBlock: !Ref PublicSubnet0Cidr - MapPublicIpOnLaunch: true + MapPublicIpOnLaunch: false Tags: - Key: Name Value: !Join [ '', [ 'PublicSubnet0 / ', !Ref 'AWS::StackName' ] ] - Key: SubnetType Value: Public VpcId: !Ref Vpc + PublicSubnet1: Condition: AZ1 Type: AWS::EC2::Subnet Properties: AvailabilityZone: !Select [ 1, !Ref AvailabilityZones ] CidrBlock: !Ref PublicSubnet1Cidr - MapPublicIpOnLaunch: true + MapPublicIpOnLaunch: false Tags: - Key: Name Value: !Join [ '', [ 'PublicSubnet1 / ', !Ref 'AWS::StackName' ] ] - Key: SubnetType Value: Public VpcId: !Ref Vpc + PublicSubnet2: Condition: AZ2 Type: AWS::EC2::Subnet Properties: AvailabilityZone: !Select [ 2, !Ref AvailabilityZones ] CidrBlock: !Ref PublicSubnet2Cidr - MapPublicIpOnLaunch: true + MapPublicIpOnLaunch: false Tags: - Key: Name Value: !Join [ '', [ 'PublicSubnet2 / ', !Ref 'AWS::StackName' ] ] - Key: SubnetType Value: Public VpcId: !Ref Vpc - + Vpc: Type: AWS::EC2::VPC Properties: @@ -449,6 +417,7 @@ Resources: Tags: - Key: Name Value: !Join [ '', [ 'Vpc / ', !Ref 'AWS::StackName' ] ] + VpcFlowLog: Type: AWS::EC2::FlowLog Properties: @@ -457,6 +426,7 @@ Resources: ResourceId: !Ref Vpc ResourceType: VPC TrafficType: ALL + VpcFlowLogsRole: Type: AWS::IAM::Role Properties: @@ -476,16 +446,20 @@ Resources: Version: 2012-10-17 Statement: - Action: - - logs:CreateLogGroup - logs:CreateLogStream - logs:DescribeLogGroups - logs:DescribeLogStreams - logs:PutLogEvents Effect: Allow - Resource: '*' + Resource: !GetAtt VpcFlowLogsGroup.Arn + + VpcFlowLogsGroup: + Type: AWS::Logs::LogGroup + DeletionPolicy: Delete + Properties: + RetentionInDays: 7 Outputs: - Vpc: Value: !Ref Vpc VpcCidr: @@ -550,4 +524,3 @@ Outputs: !Join [ ',', [ !Ref PublicSubnet0, !Ref PublicSubnet1, !Ref PublicSubnet2 ] ] ] ] - diff --git a/templates/02-securitygroups.yaml b/templates/02-securitygroups.yaml index 0704e69..abc7a88 100644 --- a/templates/02-securitygroups.yaml +++ b/templates/02-securitygroups.yaml @@ -1,101 +1,87 @@ --- AWSTemplateFormatVersion: 2010-09-09 - -Description: Reference Architecture to host Moodle on AWS - Creates VPC security groups - -Metadata: - AWS::CloudFormation::Interface: - ParameterGroups: - - Label: - default: AWS Parameters - Parameters: - - SshAccessCidr - - Vpc - ParameterLabels: - SshAccessCidr: - default: SSH Access From - Vpc: - default: Vpc Id +Description: Moodle security groups Parameters: - SshAccessCidr: - AllowedPattern: ^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(\/([0-9]|[1-2][0-9]|3[0-2]))$ - Description: The CIDR IP range that is permitted to SSH to bastion instance. Note - a value of 0.0.0.0/0 will allow access from ANY IP address. - Type: String - Default: 0.0.0.0/0 Vpc: AllowedPattern: ^(vpc-)([a-z0-9]{8}|[a-z0-9]{17})$ - Description: The Vpc Id of an existing Vpc. + Description: VPC Id of an existing VPC. Type: AWS::EC2::VPC::Id DatabaseType: AllowedValues: - MySQL - PostgreSQL Default: PostgreSQL - Description: Indicates whether to use Aurora MySQL or PostgreSQL. + Description: Database engine to use. + Type: String + ElastiCacheType: + AllowedValues: + - Redis + - Memcached + Default: Memcached + Description: Cache engine to use. Type: String + Conditions: UsePostgreSQL: - !Equals [!Ref DatabaseType, PostgreSQL] -Resources: - - BastionSecurityGroup: - Type: AWS::EC2::SecurityGroup - Properties: - GroupDescription: Security group for Bastion instances - SecurityGroupIngress: - - IpProtocol: tcp - FromPort: 22 - ToPort: 22 - CidrIp: !Ref SshAccessCidr - VpcId: - !Ref Vpc + !Equals [!Ref DatabaseType, PostgreSQL] + UseRedis: + !Equals [!Ref ElastiCacheType, Redis] +Resources: DatabaseSecurityGroup: Type: AWS::EC2::SecurityGroup Properties: - GroupDescription: Security group for Amazon RDS cluster + GroupDescription: Database Security Group SecurityGroupIngress: - IpProtocol: tcp + Description: "Allow database access from instances in the Web Security Group" FromPort: !If [ UsePostgreSQL, 5432, 3306 ] ToPort: !If [ UsePostgreSQL, 5432, 3306 ] SourceSecurityGroupId: !Ref WebSecurityGroup - VpcId: - !Ref Vpc + SecurityGroupEgress: + - IpProtocol: -1 + Description: "Block all egress" + CidrIp: 127.0.0.1/32 + VpcId: !Ref Vpc ElastiCacheSecurityGroup: Type: AWS::EC2::SecurityGroup Properties: - GroupDescription: Security group for ElastiCache cache cluster + GroupDescription: Cache Security Group SecurityGroupIngress: - IpProtocol: tcp - FromPort: 11211 - ToPort: 11211 - SourceSecurityGroupId: !Ref WebSecurityGroup - - IpProtocol: tcp - FromPort: 6379 - ToPort: 6379 + Description: "Allow cache engine access from instances in the Web Security Group" + FromPort: !If [ UseRedis, 6379, 11211 ] + ToPort: !If [ UseRedis, 6379, 11211 ] SourceSecurityGroupId: !Ref WebSecurityGroup - VpcId: - !Ref Vpc + SecurityGroupEgress: + - IpProtocol: -1 + Description: "Block all egress" + CidrIp: 127.0.0.1/32 + VpcId: !Ref Vpc + EfsSecurityGroup: Type: AWS::EC2::SecurityGroup Properties: - GroupDescription: Security group for EFS mount targets - VpcId: !Ref Vpc + GroupDescription: EFS Security Group SecurityGroupIngress: - IpProtocol: tcp + Description: "Allow NFS access from instances in the Web Security Group" FromPort: 2049 ToPort: 2049 SourceSecurityGroupId: !Ref WebSecurityGroup - - IpProtocol: tcp - FromPort: 22 - ToPort: 22 - SourceSecurityGroupId: !Ref BastionSecurityGroup + SecurityGroupEgress: + - IpProtocol: -1 + Description: "Block all egress" + CidrIp: 127.0.0.1/32 + VpcId: !Ref Vpc + EfsSecurityGroupIngress: Type: AWS::EC2::SecurityGroupIngress Properties: IpProtocol: tcp + Description: "Allow NFS access from instances in EFS Security Group" FromPort: 2049 ToPort: 2049 SourceSecurityGroupId: !GetAtt EfsSecurityGroup.GroupId @@ -104,42 +90,66 @@ Resources: PublicAlbSecurityGroup: Type: AWS::EC2::SecurityGroup Properties: - GroupDescription: Security group for ALB + GroupDescription: Load balancer Security Group SecurityGroupIngress: - IpProtocol: tcp + Description: "Allow https access from everywhere" FromPort: 443 ToPort: 443 CidrIp: 0.0.0.0/0 - IpProtocol: tcp + Description: "Allow http access from everywhere" FromPort: 80 ToPort: 80 CidrIp: 0.0.0.0/0 - VpcId: - !Ref Vpc + SecurityGroupEgress: + - IpProtocol: -1 + Description: "Block all egress" + CidrIp: 127.0.0.1/32 + VpcId: !Ref Vpc + + PublicAlbSecurityGroupEgressHttp: + Type: AWS::EC2::SecurityGroupEgress + Properties: + IpProtocol: tcp + Description: "Allow http access to Web security group" + FromPort: 80 + ToPort: 80 + DestinationSecurityGroupId: !GetAtt WebSecurityGroup.GroupId + GroupId: !GetAtt PublicAlbSecurityGroup.GroupId + + PublicAlbSecurityGroupEgressHttps: + Type: AWS::EC2::SecurityGroupEgress + Properties: + IpProtocol: tcp + Description: "Allow http access to Web security group" + FromPort: 443 + ToPort: 443 + DestinationSecurityGroupId: !GetAtt WebSecurityGroup.GroupId + GroupId: !GetAtt PublicAlbSecurityGroup.GroupId WebSecurityGroup: Type: AWS::EC2::SecurityGroup Properties: - GroupDescription: Security group for web instances + GroupDescription: Web instances Security Group SecurityGroupIngress: - IpProtocol: tcp + Description: "Allow http access from load balancer Security Group" FromPort: 80 ToPort: 80 SourceSecurityGroupId: !Ref PublicAlbSecurityGroup - IpProtocol: tcp + Description: "Allow https access from load balancer Security Group" FromPort: 443 ToPort: 443 SourceSecurityGroupId: !Ref PublicAlbSecurityGroup - - IpProtocol: tcp - FromPort: 22 - ToPort: 22 - SourceSecurityGroupId: !Ref BastionSecurityGroup - VpcId: - !Ref Vpc + SecurityGroupEgress: + - IpProtocol: "-1" + Description: "Allow outgoing access from web instances to Internet (download packages, updates)" + CidrIp: 0.0.0.0/0 + VpcId: !Ref Vpc Outputs: - BastionSecurityGroup: - Value: !Ref BastionSecurityGroup DatabaseSecurityGroup: Value: !Ref DatabaseSecurityGroup EfsSecurityGroup: diff --git a/templates/03-bastion.yaml b/templates/03-bastion.yaml deleted file mode 100644 index e076a23..0000000 --- a/templates/03-bastion.yaml +++ /dev/null @@ -1,260 +0,0 @@ ---- -AWSTemplateFormatVersion: 2010-09-09 - -Description: Reference Architecture to host Moodle on AWS - Creates bastion (desired:0; min:0; max:1) Auto Scaling group - -Metadata: - - AWS::CloudFormation::Interface: - ParameterGroups: - - Label: - default: AWS Parameters - Parameters: - - EC2KeyName - - BastionInstanceType - - BastionSecurityGroup - - NumberOfSubnets - - Subnet - ParameterLabels: - BastionSecurityGroup: - default: Bastion Security Group - BastionInstanceType: - default: Instance Type - EC2KeyName: - default: Existing Key Pair - NumberOfSubnets: - default: Number of subnets - Subnet: - default: Subnets - -Parameters: - - BastionSecurityGroup: - Description: Select the bastion security group. - Type: AWS::EC2::SecurityGroup::Id - BastionInstanceType: - AllowedValues: - - t3.nano - - t3.micro - - t3.small - - t3.medium - - t3.large - - t3.xlarge - - t3.2xlarge - - m5.large - - m5.xlarge - - m5.2xlarge - - m5.4xlarge - - m5.8xlarge - - m5.12xlarge - - m5.16xlarge - - m5.24xlarge - - c5.large - - c5.xlarge - - c5.2xlarge - - c5.4xlarge - - c5.9xlarge - - c5.12xlarge - - c5.18xlarge - - c5.24xlarge - - r5.large - - r5.xlarge - - r5.2xlarge - - r5.4xlarge - - r5.8xlarge - - r5.12xlarge - - r5.16xlarge - - r5.24xlarge - - t3a.nano - - t3a.micro - - t3a.small - - t3a.medium - - t3a.large - - t3a.xlarge - - t3a.2xlarge - - m5a.large - - m5a.xlarge - - m5a.2xlarge - - m5a.4xlarge - - m5a.8xlarge - - m5a.12xlarge - - m5a.16xlarge - - m5a.24xlarge - - c5a.large - - c5a.xlarge - - c5a.2xlarge - - c5a.4xlarge - - c5a.9xlarge - - c5a.12xlarge - - c5a.18xlarge - - c5a.24xlarge - - r5a.large - - r5a.xlarge - - r5a.2xlarge - - r5a.4xlarge - - r5a.8xlarge - - r5a.12xlarge - - r5a.16xlarge - - r5a.24xlarge - - t4g.nano - - t4g.micro - - t4g.small - - t4g.medium - - t4g.large - - t4g.xlarge - - t4g.2xlarge - - m6g.large - - m6g.xlarge - - m6g.2xlarge - - m6g.4xlarge - - m6g.8xlarge - - m6g.12xlarge - - m6g.16xlarge - - m6g.24xlarge - - c6g.large - - c6g.xlarge - - c6g.2xlarge - - c6g.4xlarge - - c6g.9xlarge - - c6g.12xlarge - - c6g.18xlarge - - c6g.24xlarge - - r6g.large - - r6g.xlarge - - r6g.2xlarge - - r6g.4xlarge - - r6g.8xlarge - - r6g.12xlarge - - r6g.16xlarge - - r6g.24xlarge - ConstraintDescription: Must be a valid Amazon EC2 instance type. - Default: t4g.nano - Description: Bastion EC2 instance type. - Type: String - EC2KeyName: - Description: Name of an EC2 KeyPair. Your bastion instances will launch with this KeyPair. - Type: AWS::EC2::KeyPair::KeyName - NumberOfSubnets: - AllowedValues: - - 1 - - 2 - - 3 - Default: 2 - Description: Number of subnets. This must match your selections in the list of subnets below. - Type: String - Subnet: - Description: Select existing subnets. The number selected must match the number of subnets above. Subnets selected must be in separate AZs. - Type: List - LatestAmiId : - Type : AWS::SSM::Parameter::Value - Default: /aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2 - LatestArmAmiId : - Type : AWS::SSM::Parameter::Value - Default: /aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-arm64-gp2 - - -Conditions: - - NumberOfSubnets1: - !Equals [ 1, !Ref NumberOfSubnets ] - NumberOfSubnets2: - !Equals [ 2, !Ref NumberOfSubnets ] - NumberOfSubnets3: - !Equals [ 3, !Ref NumberOfSubnets ] - Subnet0: !Or - - !Condition NumberOfSubnets1 - - !Condition NumberOfSubnets2 - - !Condition NumberOfSubnets3 - Subnet1: !Or - - !Condition NumberOfSubnets2 - - !Condition NumberOfSubnets3 - Subnet2: !Condition NumberOfSubnets3 - UsingGraviton2Ami: !Or - - !Equals ["t4",!Select [0, !Split [ "g.", !Ref BastionInstanceType]]] - - !Equals ["c6",!Select [0, !Split [ "g.", !Ref BastionInstanceType]]] - - !Equals ["m6",!Select [0, !Split [ "g.", !Ref BastionInstanceType]]] - - !Equals ["r6",!Select [0, !Split [ "g.", !Ref BastionInstanceType]]] - - -Resources: - - BastionAutoScalingGroup: - Type: AWS::AutoScaling::AutoScalingGroup - Properties: - Cooldown: 60 - HealthCheckGracePeriod: 120 - HealthCheckType: EC2 - LaunchTemplate: - LaunchTemplateId: !Ref BastionLaunchTemplate - Version: !GetAtt BastionLaunchTemplate.LatestVersionNumber - MaxSize: 1 - MinSize: 0 - Tags: - - Key: Name - Value: !Join [ '', [ 'Bastion / ', !Ref 'AWS::StackName' ] ] - PropagateAtLaunch: true - VPCZoneIdentifier: - !If - [ NumberOfSubnets1, - [ !Select [ 0, !Ref Subnet ] ], - !If - [ NumberOfSubnets2, - [ !Select [ 0, !Ref Subnet ], !Select [ 1, !Ref Subnet ] ], - [ !Select [ 0, !Ref Subnet ], !Select [ 1, !Ref Subnet ], !Select [ 2, !Ref Subnet ] ] - ] - ] - BastionLaunchTemplate: - Type: AWS::EC2::LaunchTemplate - Properties: - LaunchTemplateData: - IamInstanceProfile: - Arn: !GetAtt BastionInstanceProfile.Arn - ImageId: !If [UsingGraviton2Ami, !Ref LatestArmAmiId, !Ref LatestAmiId] - Monitoring: - Enabled: true - InstanceType: !Ref BastionInstanceType - KeyName: !Ref EC2KeyName - SecurityGroupIds: - - !Ref BastionSecurityGroup - UserData: - Fn::Base64: - !Sub | - #!/bin/bash -xe - sudo systemctl enable amazon-ssm-agent - sudo systemctl start amazon-ssm-agent - sudo systemctl status amazon-ssm-agent - - BastionInstanceProfile: - Type: AWS::IAM::InstanceProfile - Properties: - Path: '/' - Roles: - - !Ref BastionInstanceRole - BastionInstanceRole: - Type: AWS::IAM::Role - Properties: - AssumeRolePolicyDocument: - Version: 2012-10-17 - Statement: - - Effect: Allow - Principal: - Service: - - ec2.amazonaws.com - Action: - - sts:AssumeRole - ManagedPolicyArns: - - 'arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore' - Path: '/' - Policies: - - PolicyName: logs - PolicyDocument: - Version: 2012-10-17 - Statement: - - Effect: Allow - Action: - - logs:CreateLogGroup - - logs:CreateLogStream - - logs:PutLogEvents - - logs:DescribeLogStreams - Resource: - - arn:aws:logs:*:*:* diff --git a/templates/03-codecommit.yaml b/templates/03-codecommit.yaml deleted file mode 100644 index 1ecae81..0000000 --- a/templates/03-codecommit.yaml +++ /dev/null @@ -1,35 +0,0 @@ ---- -AWSTemplateFormatVersion: 2010-09-09 - -Description: Reference Architecture to host Moodle on AWS - Creates AWS CodeCommit repository - -Metadata: - AWS::CloudFormation::Interface: - ParameterGroups: - - Label: - default: CodeCommit Parameters - Parameters: - - RepoName - ParameterLabels: - RepoName: - default: CodeCommit Repo Name - -Parameters: - RepoName: - Description: The CodeCommit repo name. - Type: String - -Resources: - MoodleRepo: - Type: AWS::CodeCommit::Repository - Properties: - RepositoryName: !Ref RepoName - RepositoryDescription: This is a repository for my project with code from MySourceCodeBucket. - -Outputs: - RepoArn: - Value: !GetAtt MoodleRepo.Arn - RepoHTTP: - Value: !GetAtt MoodleRepo.CloneUrlHttp - RepoName: - Value: !GetAtt MoodleRepo.Name \ No newline at end of file diff --git a/templates/03-codedeploy.yaml b/templates/03-codedeploy.yaml deleted file mode 100644 index a30a062..0000000 --- a/templates/03-codedeploy.yaml +++ /dev/null @@ -1,28 +0,0 @@ ---- -AWSTemplateFormatVersion: 2010-09-09 - -Description: Reference Architecture to host Moodle on AWS - Creates CodePiple and CodeDeploy - -Metadata: - AWS::CloudFormation::Interface: - ParameterGroups: - - Label: - default: S3 Parameters - Parameters: - - S3BucketName - ParameterLabels: - S3BucketName: - default: S3 Bucket Name - -Parameters: - S3BucketName: - Description: The S3 Bucket name. - Type: String - -Resources: - S3Bucket: - Type: AWS::S3::Bucket - -Outputs: - BucketName: - Value: !Ref S3Bucket \ No newline at end of file diff --git a/templates/03-efsfilesystem.yaml b/templates/03-efsfilesystem.yaml index b70945d..daf1cf1 100644 --- a/templates/03-efsfilesystem.yaml +++ b/templates/03-efsfilesystem.yaml @@ -1,16 +1,8 @@ --- AWSTemplateFormatVersion: 2010-09-09 - -Description: Setting up EFS File System and Target mount points for each subnet +Description: Moodle EFS shared file system Parameters: - EncryptedBoolean: - AllowedValues: - - True - - False - Default: True - Description: Create an encrypted Amazon EFS file system. - Type: String Cmk: Description: An existing AWS KMS Customer Master Key (CMK) to encrypt file system Type: String @@ -56,14 +48,11 @@ Resources: ElasticFileSystem: Type: AWS::EFS::FileSystem Properties: - Encrypted: !Ref EncryptedBoolean - KmsKeyId: - !If [ UseAWS-ManagedCMK, !Ref 'AWS::NoValue', !Ref Cmk ] - FileSystemTags: - - Key: Name - Value: !Join [ '-', [ !Ref ProjectName, 'FileSystem'] ] + Encrypted: true + KmsKeyId: !If [ UseAWS-ManagedCMK, !Ref 'AWS::NoValue', !Ref Cmk ] PerformanceMode: generalPurpose ThroughputMode: elastic + ElasticFileSystemMountTarget0: Condition: Subnet0 Type: AWS::EFS::MountTarget @@ -72,6 +61,7 @@ Resources: SecurityGroups: - !Ref SecurityGroup SubnetId: !Select [ 0, !Ref Subnet ] + ElasticFileSystemMountTarget1: Condition: Subnet1 Type: AWS::EFS::MountTarget @@ -80,6 +70,7 @@ Resources: SecurityGroups: - !Ref SecurityGroup SubnetId: !Select [ 1, !Ref Subnet ] + ElasticFileSystemMountTarget2: Condition: Subnet2 Type: AWS::EFS::MountTarget @@ -88,17 +79,18 @@ Resources: SecurityGroups: - !Ref SecurityGroup SubnetId: !Select [ 2, !Ref Subnet ] + ElasticFileSystemParam: Type: AWS::SSM::Parameter Properties: Name: !Join [ '', [ '/Moodle/',!Ref ProjectName, '/SharedFile/ElasticFileSystem' ] ] Type: String Value: !Ref ElasticFileSystem - Description: SSM Parameter for Moodle EFS File System Id + Description: Moodle EFS File System Id Outputs: ElasticFileSystem: Value: !Ref ElasticFileSystem ElasticFileSystemDnsName: Description: DNS name for the Amazon EFS file system. - Value: !Join [ '.', [ !Ref ElasticFileSystem, 'efs', !Ref 'AWS::Region', 'amazonaws', 'com' ] ] \ No newline at end of file + Value: !Join [ '.', [ !Ref ElasticFileSystem, 'efs', !Ref 'AWS::Region', 'amazonaws', 'com' ] ] diff --git a/templates/03-elasticache.yaml b/templates/03-elasticache.yaml index 4302d77..12c4216 100644 --- a/templates/03-elasticache.yaml +++ b/templates/03-elasticache.yaml @@ -1,36 +1,6 @@ --- AWSTemplateFormatVersion: 2010-09-09 - -Description: Reference Architecture to host Moodle on AWS - Creates ElastiCache cache cluster - -Metadata: - AWS::CloudFormation::Interface: - ParameterGroups: - - Label: - default: Cache Parameters - Parameters: - - CacheUsageType - - CacheEngineType - - ElastiCacheNodeType - - ElastiCacheClusterName - - ElastiCacheSecurityGroup - - NumberOfSubnets - - Subnet - ParameterLabels: - CacheEngineType: - default: Cache Engine Type - CacheUsageType: - default: Cache Usage Type - ElastiCacheClusterName: - default: Cache Cluster Name - ElastiCacheNodeType: - default: Cache Cluster Node Type - ElastiCacheSecurityGroup: - default: ElastiCache Security Group - NumberOfSubnets: - default: Number of subnets - Subnet: - default: Subnets +Description: Moodle cache cluster Parameters: CacheEngineType: @@ -38,14 +8,14 @@ Parameters: - Redis - Memcached Default: Memcached - Description: Indicates whether to use ElastiCache Memcached or Redis. + Description: Cache engine to use. Type: String CacheUsageType: AllowedValues: - application - session Default: session - Description: Indicates whether to use ElastiCache for session or application caching. + Description: Session or application caching. Type: String ElastiCacheClusterName: AllowedPattern: ^([a-zA-Z0-9]*)$ @@ -53,9 +23,20 @@ Parameters: Type: String ElastiCacheNodeType: AllowedValues: + - cache.t2.micro + - cache.t2.small + - cache.t2.medium - cache.t3.micro - cache.t3.small - cache.t3.medium + - cache.t4g.micro + - cache.t4g.small + - cache.t4g.medium + - cache.m4.large + - cache.m4.xlarge + - cache.m4.2xlarge + - cache.m4.4xlarge + - cache.m4.10xlarge - cache.m5.large - cache.m5.xlarge - cache.m5.2xlarge @@ -69,12 +50,37 @@ Parameters: - cache.m6g.8xlarge - cache.m6g.12xlarge - cache.m6g.16xlarge + - cache.r4.large + - cache.r4.xlarge + - cache.r4.2xlarge + - cache.r4.4xlarge + - cache.r4.8xlarge + - cache.r4.16xlarge + - cache.r5.large + - cache.r5.xlarge + - cache.r5.2xlarge + - cache.r5.4xlarge + - cache.r5.12xlarge + - cache.r5.24xlarge + - cache.r6g.large + - cache.r6g.xlarge + - cache.r6g.2xlarge + - cache.r6g.4xlarge + - cache.r6g.8xlarge + - cache.r6g.12xlarge + - cache.r6g.16xlarge + - cache.r6gd.xlarge + - cache.r6gd.2xlarge + - cache.r6gd.4xlarge + - cache.r6gd.8xlarge + - cache.r6gd.12xlarge + - cache.r6gd.16xlarge ConstraintDescription: Must be a valid Amazon ElastiCache node type. - Default: cache.m6g.large + Default: cache.r6g.large Description: ElastiCache cluster node type. Type: String ElastiCacheSecurityGroup: - Description: Select the ElastiCache security group. + Description: ElastiCache Security Group. Type: AWS::EC2::SecurityGroup::Id NumberOfSubnets: AllowedValues: @@ -94,24 +100,10 @@ Parameters: Type: String Conditions: - UseRedis: - !Equals [!Ref CacheEngineType, Redis] - UseMemcached: - !Equals [!Ref CacheEngineType, Memcached] - NumberOfSubnets1: - !Equals [ 1, !Ref NumberOfSubnets ] - NumberOfSubnets2: - !Equals [ 2, !Ref NumberOfSubnets ] - NumberOfSubnets3: - !Equals [ 3, !Ref NumberOfSubnets ] - Subnet0: !Or - - !Condition NumberOfSubnets1 - - !Condition NumberOfSubnets2 - - !Condition NumberOfSubnets3 - Subnet1: !Or - - !Condition NumberOfSubnets2 - - !Condition NumberOfSubnets3 - Subnet2: !Condition NumberOfSubnets3 + UseRedis: !Equals [!Ref CacheEngineType, Redis] + UseMemcached: !Equals [!Ref CacheEngineType, Memcached] + NumberOfSubnets1: !Equals [ 1, !Ref NumberOfSubnets ] + NumberOfSubnets2: !Equals [ 2, !Ref NumberOfSubnets ] Resources: ElastiCacheClusterRedis: @@ -121,7 +113,7 @@ Resources: ReplicationGroupId: !Ref ElastiCacheClusterName ReplicationGroupDescription: !Ref ElastiCacheClusterName AtRestEncryptionEnabled: true - TransitEncryptionEnabled: false + TransitEncryptionEnabled: true AutoMinorVersionUpgrade: true MultiAZEnabled: true CacheNodeType: !Ref ElastiCacheNodeType @@ -129,8 +121,7 @@ Resources: SecurityGroupIds: - !Ref ElastiCacheSecurityGroup Engine: redis - NumCacheClusters: - !Ref NumberOfSubnets + NumCacheClusters: !Ref NumberOfSubnets ElastiCacheClusterMemcached: Condition: UseMemcached @@ -141,53 +132,37 @@ Resources: CacheSubnetGroupName: !Ref ElastiCacheSubnetGroup ClusterName: !Ref ElastiCacheClusterName Engine: memcached - NumCacheNodes: - !Ref NumberOfSubnets - Tags: - - Key: Name - Value: !Join [ '', [ 'Moodle / ', !Ref 'AWS::StackName' ] ] + NumCacheNodes: !Ref NumberOfSubnets VpcSecurityGroupIds: - - !Ref ElastiCacheSecurityGroup + - !Ref ElastiCacheSecurityGroup ElastiCacheSubnetGroup: Type: AWS::ElastiCache::SubnetGroup Properties: CacheSubnetGroupName: !Join [ '', [ !Ref ElastiCacheClusterName, SubnetGroup ] ] Description: ElastiCache Subnet Group for Moodle - SubnetIds: - !If - [ NumberOfSubnets1, - [ !Select [ 0, !Ref Subnet ] ], - !If - [ NumberOfSubnets2, - [ !Select [ 0, !Ref Subnet ], !Select [ 1, !Ref Subnet ] ], - [ !Select [ 0, !Ref Subnet ], !Select [ 1, !Ref Subnet ], !Select [ 2, !Ref Subnet ] ] - ] - ] + SubnetIds: !If [ NumberOfSubnets1, [ !Select [ 0, !Ref Subnet ] ], + !If [ NumberOfSubnets2, [ !Select [ 0, !Ref Subnet ], !Select [ 1, !Ref Subnet ] ], + [ !Select [ 0, !Ref Subnet ], !Select [ 1, !Ref Subnet ], !Select [ 2, !Ref Subnet ] ] ] ] ElastiCacheClusterEndpoint: Type: AWS::SSM::Parameter Properties: Name: !Join [ '', [ '/Moodle/',!Ref ProjectName, '/Cache/', !Ref CacheUsageType, '/ElastiCacheClusterEndpoint' ] ] + Description: ElastiCache Cluster Endpoint Type: String - Value: !If [UseRedis, - !Join [ ':', [!GetAtt ElastiCacheClusterRedis.PrimaryEndPoint.Address, !GetAtt ElastiCacheClusterRedis.PrimaryEndPoint.Port]], - !Join [ ':', [!GetAtt ElastiCacheClusterMemcached.ConfigurationEndpoint.Address, !GetAtt ElastiCacheClusterMemcached.ConfigurationEndpoint.Port]] - ] - Description: SSM Parameter for ElastiCache Cluster Endpoint + Value: !If [UseRedis, !Join [ ':', [!GetAtt ElastiCacheClusterRedis.PrimaryEndPoint.Address, !GetAtt ElastiCacheClusterRedis.PrimaryEndPoint.Port]], + !Join [ ':', [!GetAtt ElastiCacheClusterMemcached.ConfigurationEndpoint.Address, !GetAtt ElastiCacheClusterMemcached.ConfigurationEndpoint.Port]] ] ElastiCacheEngine: Type: AWS::SSM::Parameter Properties: Name: !Join [ '', [ '/Moodle/',!Ref ProjectName, '/Cache/', !Ref CacheUsageType, '/Engine' ] ] + Description: !Sub ElastiCache Engine Type (${CacheUsageType}) Type: String Value: !Ref CacheEngineType - Description: SSM Parameter for ElastiCache Engine Type Outputs: ElastiCacheClusterEndpointAddress: - Value: !If [UseRedis, - !Join [ ':', [!GetAtt ElastiCacheClusterRedis.PrimaryEndPoint.Address, !GetAtt ElastiCacheClusterRedis.PrimaryEndPoint.Port]], - !Join [ ':', [!GetAtt ElastiCacheClusterMemcached.ConfigurationEndpoint.Address, !GetAtt ElastiCacheClusterMemcached.ConfigurationEndpoint.Port]] - ] - \ No newline at end of file + Value: !If [UseRedis, !Join [ ':', [!GetAtt ElastiCacheClusterRedis.PrimaryEndPoint.Address, !GetAtt ElastiCacheClusterRedis.PrimaryEndPoint.Port]], + !Join [ ':', [!GetAtt ElastiCacheClusterMemcached.ConfigurationEndpoint.Address, !GetAtt ElastiCacheClusterMemcached.ConfigurationEndpoint.Port]] ] diff --git a/templates/03-elasticacheserverless.yaml b/templates/03-elasticacheserverless.yaml new file mode 100644 index 0000000..bc6b3e9 --- /dev/null +++ b/templates/03-elasticacheserverless.yaml @@ -0,0 +1,82 @@ +--- +AWSTemplateFormatVersion: 2010-09-09 +Description: Moodle serverless cache cluster + +Parameters: + CacheEngineType: + AllowedValues: + - Redis + - Memcached + Default: Memcached + Description: Cache engine to use. + Type: String + CacheUsageType: + AllowedValues: + - application + - session + Default: session + Description: Session or application caching. + Type: String + ElastiCacheClusterName: + AllowedPattern: ^([a-zA-Z0-9]*)$ + Description: ElastiCache cluster name. + Type: String + ElastiCacheNodeType: + Description: Unused, only kept for compatibility with the non-serverless template. + Type: String + Default: cache.t2.micro + ElastiCacheSecurityGroup: + Description: ElastiCache Security Group. + Type: AWS::EC2::SecurityGroup::Id + NumberOfSubnets: + AllowedValues: + - 1 + - 2 + - 3 + Default: 2 + Description: Number of subnets. This must match your selections in the list of subnets below. + Type: String + Subnet: + Description: Select existing subnets. The number selected must match the number of subnets above. Subnets selected must be in separate AZs. + Type: List + ProjectName: + AllowedPattern: ^([a-zA-Z0-9]*)$ + Default: App + Description: Moodle Project Name + Type: String + +Conditions: + NumberOfSubnets1: !Equals [ 1, !Ref NumberOfSubnets ] + NumberOfSubnets2: !Equals [ 2, !Ref NumberOfSubnets ] + +Resources: + ElastiCacheServerless: + Type: AWS::ElastiCache::ServerlessCache + Properties: + Engine: !Ref CacheEngineType + ServerlessCacheName: !Ref ElastiCacheClusterName + SecurityGroupIds: + - !Ref ElastiCacheSecurityGroup + SubnetIds: !If [ NumberOfSubnets1, [ !Select [ 0, !Ref Subnet ] ], + !If [ NumberOfSubnets2, [ !Select [ 0, !Ref Subnet ], !Select [ 1, !Ref Subnet ] ], + [ !Select [ 0, !Ref Subnet ], !Select [ 1, !Ref Subnet ], !Select [ 2, !Ref Subnet ] ] ] ] + + ElastiCacheClusterEndpoint: + Type: AWS::SSM::Parameter + Properties: + Name: !Join [ '', [ '/Moodle/',!Ref ProjectName, '/Cache/', !Ref CacheUsageType, '/ElastiCacheClusterEndpoint' ] ] + Description: ElastiCache Cluster Endpoint + Type: String + Value: !Join [ ':', [!GetAtt ElastiCacheServerless.Endpoint.Address, !GetAtt ElastiCacheServerless.Endpoint.Port]] + + ElastiCacheEngine: + Type: AWS::SSM::Parameter + Properties: + Name: !Join [ '', [ '/Moodle/',!Ref ProjectName, '/Cache/', !Ref CacheUsageType, '/Engine' ] ] + Description: !Sub ElastiCache Engine Type (${CacheUsageType}) + Type: String + Value: !Ref CacheEngineType + +Outputs: + ElastiCacheClusterEndpointAddress: + Value: !Join [ ':', [!GetAtt ElastiCacheServerless.Endpoint.Address, !GetAtt ElastiCacheServerless.Endpoint.Port]] diff --git a/templates/03-pipelinehelper.yaml b/templates/03-pipelinehelper.yaml index 226decd..71c0ce0 100644 --- a/templates/03-pipelinehelper.yaml +++ b/templates/03-pipelinehelper.yaml @@ -4,11 +4,6 @@ AWSTemplateFormatVersion: 2010-09-09 Description: This templates helps creating CodeCommit repo, S3 Bucket and update repo with Moodle code & configurations. Parameters: - - EC2KeyName: - Description: Name of an existing EC2 key pair - Type: AWS::EC2::KeyPair::KeyName - PipelineSecurityGroup: Description: Select the Pipeline security group Id Type: AWS::EC2::SecurityGroup::Id @@ -28,6 +23,13 @@ Parameters: InstanceType: AllowedValues: + - t3.nano + - t3.micro + - t3.small + - t3.medium + - t3.large + - t3.xlarge + - t3.2xlarge - m5.large - m5.xlarge - m5.2xlarge @@ -52,6 +54,13 @@ Parameters: - r5.12xlarge - r5.16xlarge - r5.24xlarge + - t3a.nano + - t3a.micro + - t3a.small + - t3a.medium + - t3a.large + - t3a.xlarge + - t3a.2xlarge - m5a.large - m5a.xlarge - m5a.2xlarge @@ -76,6 +85,13 @@ Parameters: - r5a.12xlarge - r5a.16xlarge - r5a.24xlarge + - t4g.nano + - t4g.micro + - t4g.small + - t4g.medium + - t4g.large + - t4g.xlarge + - t4g.2xlarge - m6g.large - m6g.xlarge - m6g.2xlarge @@ -83,7 +99,15 @@ Parameters: - m6g.8xlarge - m6g.12xlarge - m6g.16xlarge - - m6g.24xlarge + - m6g.24xlarge + - m7g.medium + - m7g.large + - m7g.xlarge + - m7g.2xlarge + - m7g.4xlarge + - m7g.8xlarge + - m7g.12xlarge + - m7g.16xlarge - c6g.large - c6g.xlarge - c6g.2xlarge @@ -100,8 +124,16 @@ Parameters: - r6g.12xlarge - r6g.16xlarge - r6g.24xlarge + - c7g.medium + - c7g.large + - c7g.xlarge + - c7g.2xlarge + - c7g.4xlarge + - c7g.8xlarge + - c7g.12xlarge + - c7g.16xlarge ConstraintDescription: Must be a valid Amazon EC2 instance type. - Default: m6g.large + Default: c7g.xlarge Description: The Amazon EC2 instance type that dynamically adjusts thresholds based on permitted throughput changes. Type: String @@ -165,10 +197,13 @@ Conditions: - !Condition NumberOfSubnets3 Subnet2: !Condition NumberOfSubnets3 UsingGraviton2Ami: !Or - - !Equals ["t4",!Select [0, !Split [ "g.", !Ref InstanceType]]] - - !Equals ["c6",!Select [0, !Split [ "g.", !Ref InstanceType]]] - - !Equals ["m6",!Select [0, !Split [ "g.", !Ref InstanceType]]] - - !Equals ["r6",!Select [0, !Split [ "g.", !Ref InstanceType]]] + - !Equals ["t4",!Select [0, !Split [ "g.", !Ref WebInstanceType]]] + - !Equals ["c6",!Select [0, !Split [ "g.", !Ref WebInstanceType]]] + - !Equals ["c7",!Select [0, !Split [ "g.", !Ref WebInstanceType]]] + - !Equals ["m6",!Select [0, !Split [ "g.", !Ref WebInstanceType]]] + - !Equals ["m7",!Select [0, !Split [ "g.", !Ref WebInstanceType]]] + - !Equals ["r6",!Select [0, !Split [ "g.", !Ref WebInstanceType]]] + - !Equals ["r7",!Select [0, !Split [ "g.", !Ref WebInstanceType]]] Resources: ########################### TODO put this in the codepipeline template @@ -182,6 +217,16 @@ Resources: CodeArtifactS3Bucket: Type: AWS::S3::Bucket DeletionPolicy: RetainExceptOnCreate + Properties: + PublicAccessBlockConfiguration: + BlockPublicAcls: true + BlockPublicPolicy: true + IgnorePublicAcls: true + RestrictPublicBuckets: true + BucketEncryption: + ServerSideEncryptionConfiguration: + - ServerSideEncryptionByDefault: + SSEAlgorithm: AES256 InstanceProfile: Type: AWS::IAM::InstanceProfile @@ -224,8 +269,19 @@ Resources: !Sub 'arn:aws:codepipeline:${AWS::Region}:${AWS::AccountId}:${ProjectName}-Pipeline' - Effect: Allow Action: + - codecommit:GitPull - codecommit:GitPush - Resource: !GetAtt MoodleRepo.Arn + - codecommit:CreateBranch + - codecommit:CreateCommit + - codecommit:GetRepository + - codecommit:Get* + - codecommit:List* + - codecommit:PutFile + - codecommit:UploadArchive + - codecommit:GetUploadArchiveStatus + Resource: + - !GetAtt MoodleRepo.Arn + - !Join [ "", [ !GetAtt MoodleRepo.Arn, "/*" ] ] PipelineHelperASGroup: Type: AWS::AutoScaling::AutoScalingGroup @@ -281,9 +337,6 @@ Resources: ApplicationStop: - location: .pipeline/stop_application.sh timeout: 300 - BeforeInstall: - - location: .pipeline/before_install.sh - timeout: 600 AfterInstall: - location: .pipeline/after_install.sh timeout: 300 @@ -511,14 +564,6 @@ Resources: mode: 000500 owner: root group: root - /tmp/before_install.sh: - content: - !Sub | - #!/bin/bash -xe - echo "Nothing to do" - mode: 000500 - owner: root - group: root /tmp/moodle-git-config.sh: content: !Sub | #!/bin/bash -x @@ -635,7 +680,6 @@ Resources: Arn: !GetAtt InstanceProfile.Arn ImageId: !If [UsingGraviton2Ami, !Ref LatestArmAmiId, !Ref LatestAmiId] InstanceType: !Ref InstanceType - KeyName: !Ref EC2KeyName SecurityGroupIds: - !Ref PipelineSecurityGroup UserData: diff --git a/templates/03-publicalb.yaml b/templates/03-publicalb.yaml index eedb302..5a487ca 100644 --- a/templates/03-publicalb.yaml +++ b/templates/03-publicalb.yaml @@ -1,30 +1,6 @@ AWSTemplateFormatVersion: 2010-09-09 - -Description: Reference Architecture to host Moodle on AWS - Creates Application Load Balancer - -Metadata: - AWS::CloudFormation::Interface: - ParameterGroups: - - Label: - default: ALB Parameters - Parameters: - - Vpc - - PublicAlbAcmCertificate - - PublicAlbSecurityGroup - - NumberOfSubnets - - Subnet - ParameterLabels: - Vpc: - default: Vpc Id - PublicAlbAcmCertificate: - default: ALB Certificate ARN - PublicAlbSecurityGroup: - default: Public ALB Security Group - NumberOfSubnets: - default: Number of subnets - Subnet: - default: Subnets +Description: Moodle Application Load Balancer Parameters: NumberOfSubnets: @@ -55,29 +31,63 @@ Parameters: Type: String Conditions: + SslCertificate: !Not [!Equals [ '', !Ref PublicAlbAcmCertificate ] ] + NoSslCertificate: !Equals [ '', !Ref PublicAlbAcmCertificate ] + NumberOfSubnets1: !Equals [ 1, !Ref NumberOfSubnets ] + NumberOfSubnets2: !Equals [ 2, !Ref NumberOfSubnets ] - SslCertificate: - !Not [!Equals [ '', !Ref PublicAlbAcmCertificate ] ] - NoSslCertificate: - !Equals [ '', !Ref PublicAlbAcmCertificate ] - NumberOfSubnets1: - !Equals [ 1, !Ref NumberOfSubnets ] - NumberOfSubnets2: - !Equals [ 2, !Ref NumberOfSubnets ] - NumberOfSubnets3: - !Equals [ 3, !Ref NumberOfSubnets ] - Subnet0: !Or - - !Condition NumberOfSubnets1 - - !Condition NumberOfSubnets2 - - !Condition NumberOfSubnets3 - Subnet1: !Or - - !Condition NumberOfSubnets2 - - !Condition NumberOfSubnets3 - Subnet2: !Condition NumberOfSubnets3 +Mappings: + # https://docs.aws.amazon.com/elasticloadbalancing/latest/application/enable-access-logging.html + RegionMap: + us-east-1: + "ELBAccountID": "127311923021" + us-east-2: + "ELBAccountID": "033677994240" + us-west-1: + "ELBAccountID": "027434742980" + us-west-2: + "ELBAccountID": "797873946194" + af-south-1: + "ELBAccountID": "098369216593" + ap-east-1: + "ELBAccountID": "754344448648" + ap-southeast-3: + "ELBAccountID": "589379963580" + ap-south-1: + "ELBAccountID": "718504428378" + ap-northeast-3: + "ELBAccountID": "383597477331" + ap-northeast-2: + "ELBAccountID": "600734575887" + ap-southeast-1: + "ELBAccountID": "114774131450" + ap-southeast-2: + "ELBAccountID": "783225319266" + ap-northeast-1: + "ELBAccountID": "582318560864" + ca-central-1: + "ELBAccountID": "985666609251" + eu-central-1: + "ELBAccountID": "054676820928" + eu-west-1: + "ELBAccountID": "156460612806" + eu-west-2: + "ELBAccountID": "652711504416" + eu-south-1: + "ELBAccountID": "635631232127" + eu-west-3: + "ELBAccountID": "009996457667" + eu-north-1: + "ELBAccountID": "897822967062" + me-south-1: + "ELBAccountID": "076674570225" + sa-east-1: + "ELBAccountID": "507241528517" Resources: PublicAlbListenerNoSslCertificate: Type : AWS::ElasticLoadBalancingV2::Listener + DependsOn: LoadBalancerAccessLogsBucketPolicy Properties: DefaultActions: - Type: forward @@ -89,6 +99,7 @@ Resources: PublicAlbListenerSslCertificate: Condition: SslCertificate Type : AWS::ElasticLoadBalancingV2::Listener + DependsOn: LoadBalancerAccessLogsBucketPolicy Properties: Certificates: - CertificateArn: !Ref PublicAlbAcmCertificate @@ -98,29 +109,66 @@ Resources: LoadBalancerArn: !Ref PublicApplicationLoadBalancer Port: 443 Protocol: HTTPS + SslPolicy: "ELBSecurityPolicy-TLS13-1-2-2021-06" + + LoadBalancerAccessLogsBucket: + Type: AWS::S3::Bucket + DeletionPolicy: RetainExceptOnCreate + Properties: + PublicAccessBlockConfiguration: + BlockPublicAcls: true + BlockPublicPolicy: true + IgnorePublicAcls: true + RestrictPublicBuckets: true + BucketEncryption: + ServerSideEncryptionConfiguration: + - ServerSideEncryptionByDefault: + SSEAlgorithm: AES256 + LifecycleConfiguration: + Rules: + - Id: DeleteOldLogs + Status: Enabled + ExpirationInDays: 7 + + LoadBalancerAccessLogsBucketPolicy: + Type: AWS::S3::BucketPolicy + Properties: + Bucket: !Ref LoadBalancerAccessLogsBucket + PolicyDocument: + Statement: + - Action: + - s3:PutObject + Effect: Allow + Resource: !Join [ "", [ !GetAtt LoadBalancerAccessLogsBucket.Arn, "/*" ] ] + Principal: + Service: logdelivery.elasticloadbalancing.amazonaws.com + # https://docs.aws.amazon.com/elasticloadbalancing/latest/application/enable-access-logging.html + - Action: + - s3:PutObject + Effect: Allow + Resource: !Join [ "", [ !GetAtt LoadBalancerAccessLogsBucket.Arn, "/*" ] ] + Principal: + AWS: !Join [ "", [ "arn:aws:iam::", !FindInMap [RegionMap, !Ref "AWS::Region", ELBAccountID], ":root" ] ] PublicApplicationLoadBalancer: Type: AWS::ElasticLoadBalancingV2::LoadBalancer Properties: Scheme: internet-facing - Subnets: - !If - [ NumberOfSubnets1, - [ !Select [ 0, !Ref Subnet ] ], - !If - [ NumberOfSubnets2, - [ !Select [ 0, !Ref Subnet ], !Select [ 1, !Ref Subnet ] ], - [ !Select [ 0, !Ref Subnet ], !Select [ 1, !Ref Subnet ], !Select [ 2, !Ref Subnet ] ] - ] - ] + Subnets: !If [ NumberOfSubnets1, [ !Select [ 0, !Ref Subnet ] ], + !If [ NumberOfSubnets2, [ !Select [ 0, !Ref Subnet ], !Select [ 1, !Ref Subnet ] ], + [ !Select [ 0, !Ref Subnet ], !Select [ 1, !Ref Subnet ], !Select [ 2, !Ref Subnet ] ] ] ] LoadBalancerAttributes: - Key: idle_timeout.timeout_seconds Value: '60' + - Key: access_logs.s3.enabled + Value: true + - Key: access_logs.s3.bucket + Value: !Ref LoadBalancerAccessLogsBucket + - Key: access_logs.s3.prefix + Value: !Join [ '', [ !Ref ProjectName, '-publicalb' ] ] SecurityGroups: - !Ref PublicAlbSecurityGroup - Tags: - - Key: Name - Value: !Join [ '-', [ 'Moodle',!Ref ProjectName,'alb' ] ] + PublicAlbTargetGroup: Type: AWS::ElasticLoadBalancingV2::TargetGroup Properties: @@ -130,34 +178,23 @@ Resources: Name: !Join [ '', [ 'PublicALB-', !Ref Vpc ] ] Port: 80 Protocol: HTTP - Tags: - - Key: Name - Value: !Join [ '-', [ 'Moodle',!Ref ProjectName,'alb-TG' ] ] UnhealthyThresholdCount: 5 VpcId: !Ref Vpc Outputs: PublicAlbTargetGroupArn: - Value: - !Ref PublicAlbTargetGroup + Value: !Ref PublicAlbTargetGroup PublicAlbTargetGroupName: - Value: - !GetAtt PublicAlbTargetGroup.TargetGroupName + Value: !GetAtt PublicAlbTargetGroup.TargetGroupName PublicAlbCanonicalHostedZoneId: - Value: - !GetAtt PublicApplicationLoadBalancer.CanonicalHostedZoneID + Value: !GetAtt PublicApplicationLoadBalancer.CanonicalHostedZoneID PublicAlbDnsName: - Value: - !GetAtt PublicApplicationLoadBalancer.DNSName + Value: !GetAtt PublicApplicationLoadBalancer.DNSName PublicAlbFullName: - Value: - !GetAtt PublicApplicationLoadBalancer.LoadBalancerFullName + Value: !GetAtt PublicApplicationLoadBalancer.LoadBalancerFullName PublicAlbName: - Value: - !GetAtt PublicApplicationLoadBalancer.LoadBalancerName + Value: !GetAtt PublicApplicationLoadBalancer.LoadBalancerName PublicAlbHostname: - Value: - !If [ NoSslCertificate, !Join [ '', [ 'http://', !GetAtt PublicApplicationLoadBalancer.DNSName ] ], !Join [ '', [ 'https://', !GetAtt PublicApplicationLoadBalancer.DNSName ] ] ] + Value: !If [ NoSslCertificate, !Join [ '', [ 'http://', !GetAtt PublicApplicationLoadBalancer.DNSName ] ], !Join [ '', [ 'https://', !GetAtt PublicApplicationLoadBalancer.DNSName ] ] ] SslCertificate: - Value: - !If [ SslCertificate, True, False ] + Value: !If [ SslCertificate, True, False ] diff --git a/templates/03-rds.yaml b/templates/03-rds.yaml index 541aae2..c13a7d8 100644 --- a/templates/03-rds.yaml +++ b/templates/03-rds.yaml @@ -1,45 +1,6 @@ --- AWSTemplateFormatVersion: 2010-09-09 - -Description: Reference Architecture to host Moodle on AWS - Creates RDS Aurora MySQL or PostgreSQL database cluster - -Metadata: - AWS::CloudFormation::Interface: - ParameterGroups: - - Label: - default: Database Parameters - Parameters: - - DatabaseType - - DatabaseInstanceType - # - DatabaseMasterUsername - # - DatabaseMasterPassword - - DatabaseName - - DatabaseEncryptedBoolean - - DatabaseCmk - - DatabaseSecurityGroup - - NumberOfSubnets - - Subnet - ParameterLabels: - DatabaseType: - default: Aurora database type - DatabaseEncryptedBoolean: - default: Encrypted DB Cluster - DatabaseCmk: - default: AWS KMS Customer Master Key (CMK) to encrypt DB - DatabaseInstanceType: - default: DB Instance Class - # DatabaseMasterUsername: - # default: DB Master Username - # DatabaseMasterPassword: - # default: DB Master Password - DatabaseName: - default: DB Name - DatabaseSecurityGroup: - default: DB Security Group - NumberOfSubnets: - default: Number of subnets - Subnet: - default: Subnets +Description: Moodle database Parameters: DatabaseType: @@ -47,14 +8,7 @@ Parameters: - MySQL - PostgreSQL Default: PostgreSQL - Description: Indicates whether to use Aurora MySQL or PostgreSQL. - Type: String - DatabaseEncryptedBoolean: - AllowedValues: - - true - - false - Default: True - Description: Indicates whether the DB instances in the cluster are encrypted. + Description: Database engine to use. Type: String DatabaseCmk: Description: AWS KMS Customer Master Key (CMK) to encrypt database cluster @@ -63,6 +17,8 @@ Parameters: AllowedValues: - db.t3.medium - db.t3.large + - db.t4g.medium + - db.t4g.large - db.r5.large - db.r5.xlarge - db.r5.2xlarge @@ -77,6 +33,21 @@ Parameters: - db.r6g.8xlarge - db.r6g.12xlarge - db.r6g.16xlarge + - db.r6i.large + - db.r6i.xlarge + - db.r6i.2xlarge + - db.r6i.4xlarge + - db.r6i.8xlarge + - db.r6i.12xlarge + - db.r6i.16xlarge + - db.r6i.24xlarge + - db.r6i.32xlarge + - db.r6gd.xlarge + - db.r6gd.2xlarge + - db.r6gd.4xlarge + - db.r6gd.8xlarge + - db.r6gd.12xlarge + - db.r6gd.16xlarge ConstraintDescription: Must be a valid Aurora RDS instance type. Default: db.r6g.large Description: Amazon Aurora RDS database instance type @@ -108,26 +79,11 @@ Parameters: Type: String Conditions: - UseMySQL: - !Equals [!Ref DatabaseType, MySQL] - UsePostgreSQL: - !Equals [!Ref DatabaseType, PostgreSQL] - NumberOfSubnets1: - !Equals [ 1, !Ref NumberOfSubnets ] - NumberOfSubnets2: - !Equals [ 2, !Ref NumberOfSubnets ] - NumberOfSubnets3: - !Equals [ 3, !Ref NumberOfSubnets ] - Subnet0: !Or - - !Condition NumberOfSubnets1 - - !Condition NumberOfSubnets2 - - !Condition NumberOfSubnets3 - Subnet1: !Or - - !Condition NumberOfSubnets2 - - !Condition NumberOfSubnets3 - Subnet2: !Condition NumberOfSubnets3 - UseAWS-ManagedCMK: - !Equals ['', !Ref DatabaseCmk] + UseMySQL: !Equals [!Ref DatabaseType, MySQL] + UsePostgreSQL: !Equals [!Ref DatabaseType, PostgreSQL] + NumberOfSubnets1: !Equals [ 1, !Ref NumberOfSubnets ] + NumberOfSubnets2: !Equals [ 2, !Ref NumberOfSubnets ] + UseAWS-ManagedCMK: !Equals ['', !Ref DatabaseCmk] Resources: DatabaseCluster: @@ -136,76 +92,55 @@ Resources: BackupRetentionPeriod: 30 DatabaseName: !Ref DatabaseName DBSubnetGroupName: !Ref DataSubnetGroup - Engine: - !If [ UsePostgreSQL, aurora-postgresql, aurora-mysql ] - DBClusterParameterGroupName: - !If [ UsePostgreSQL, default.aurora-postgresql13, default.aurora-mysql8.0 ] - EngineVersion: - !If [ UsePostgreSQL, '13.8', '8.0.mysql_aurora.3.02.1' ] - KmsKeyId: - !If [ UseAWS-ManagedCMK, !Ref 'AWS::NoValue', !Ref DatabaseCmk ] + PubliclyAccessible: false + Engine: !If [ UsePostgreSQL, aurora-postgresql, aurora-mysql ] + KmsKeyId: !If [ UseAWS-ManagedCMK, !Ref 'AWS::NoValue', !Ref DatabaseCmk ] MasterUsername: !Join ['', ['{{resolve:secretsmanager:', !Ref RDSInstanceSecretArn, ':SecretString:username}}' ]] MasterUserPassword: !Join ['', ['{{resolve:secretsmanager:', !Ref RDSInstanceSecretArn, ':SecretString:password}}' ]] - Port: - !If [ UsePostgreSQL, 5432, 3306 ] - StorageEncrypted: !Ref DatabaseEncryptedBoolean - Tags: - - Key: Name - Value: !Join [ '', [ 'Moodle / ', !Ref 'AWS::StackName' ] ] + Port: !If [ UsePostgreSQL, 5432, 3306 ] + StorageEncrypted: true VpcSecurityGroupIds: - !Ref DatabaseSecurityGroup + DatabaseInstance0: Type: AWS::RDS::DBInstance DeletionPolicy: Delete Properties: AllowMajorVersionUpgrade: false AutoMinorVersionUpgrade: true + PubliclyAccessible: false DBClusterIdentifier: !Ref DatabaseCluster DBInstanceClass: !Ref DatabaseInstanceType DBSubnetGroupName: !Ref DataSubnetGroup - Engine: - !If [ UsePostgreSQL, aurora-postgresql, aurora-mysql ] - Tags: - - Key: Name - Value: !Join [ '', [ 'Moodle / ', !Ref 'AWS::StackName' ] ] + Engine: !If [ UsePostgreSQL, aurora-postgresql, aurora-mysql ] + DatabaseInstance1: Type: AWS::RDS::DBInstance DeletionPolicy: Delete Properties: AllowMajorVersionUpgrade: false AutoMinorVersionUpgrade: true + PubliclyAccessible: false DBClusterIdentifier: !Ref DatabaseCluster DBInstanceClass: !Ref DatabaseInstanceType DBSubnetGroupName: !Ref DataSubnetGroup - Engine: - !If [ UsePostgreSQL, aurora-postgresql, aurora-mysql ] - Tags: - - Key: Name - Value: !Join [ '', [ 'Moodle / ', !Ref 'AWS::StackName' ] ] + Engine: !If [ UsePostgreSQL, aurora-postgresql, aurora-mysql ] + DataSubnetGroup: Type: AWS::RDS::DBSubnetGroup Properties: DBSubnetGroupDescription: RDS Database Subnet Group for Moodle - SubnetIds: - !If - [ NumberOfSubnets1, - [ !Select [ 0, !Ref Subnet ] ], - !If - [ NumberOfSubnets2, - [ !Select [ 0, !Ref Subnet ], !Select [ 1, !Ref Subnet ] ], - [ !Select [ 0, !Ref Subnet ], !Select [ 1, !Ref Subnet ], !Select [ 2, !Ref Subnet ] ] - ] - ] - Tags: - - Key: Name - Value: !Join [ '', [ 'Moodle / ', !Ref 'AWS::StackName' ] ] + SubnetIds: !If [ NumberOfSubnets1, [ !Select [ 0, !Ref Subnet ] ], + !If [ NumberOfSubnets2, [ !Select [ 0, !Ref Subnet ], !Select [ 1, !Ref Subnet ] ], + [ !Select [ 0, !Ref Subnet ], !Select [ 1, !Ref Subnet ], !Select [ 2, !Ref Subnet ] ] ] ] + DatabaseClusterParam: Type: AWS::SSM::Parameter Properties: Name: !Join [ '', [ '/Moodle/',!Ref ProjectName, '/DB/ClusterEndpoint' ] ] Type: String Value: !GetAtt DatabaseCluster.Endpoint.Address - Description: SSM Parameter for Moodle DB Cluster + Description: Moodle DB Cluster DatabaseClusterReadOnlyParam: Type: AWS::SSM::Parameter @@ -213,7 +148,7 @@ Resources: Name: !Join [ '', [ '/Moodle/',!Ref ProjectName, '/DB/ClusterReadOnlyEndpoint' ] ] Type: String Value: !GetAtt DatabaseCluster.ReadEndpoint.Address - Description: SSM Parameter for Moodle DB Cluster Read only + Description: Moodle DB Cluster Read only DatabaseNameParam: Type: AWS::SSM::Parameter @@ -221,7 +156,7 @@ Resources: Name: !Join [ '', [ '/Moodle/',!Ref ProjectName, '/DB/Name' ] ] Type: String Value: !Ref DatabaseName - Description: SSM Parameter for Moodle DB Name + Description: Moodle DB Name DatabaseTypeParam: Type: AWS::SSM::Parameter @@ -229,7 +164,7 @@ Resources: Name: !Join [ '', [ '/Moodle/',!Ref ProjectName, '/DB/Type' ] ] Type: String Value: !Ref DatabaseType - Description: SSM Parameter for Moodle DB Type + Description: Moodle DB Type Outputs: Database: @@ -248,4 +183,3 @@ Outputs: Value: !GetAtt DatabaseCluster.Endpoint.Port DatabaseClusterReadEndpointAddress: Value: !GetAtt DatabaseCluster.ReadEndpoint.Address - diff --git a/templates/03-rdsserverless.yaml b/templates/03-rdsserverless.yaml index 3dfe779..27c5928 100644 --- a/templates/03-rdsserverless.yaml +++ b/templates/03-rdsserverless.yaml @@ -1,42 +1,6 @@ --- AWSTemplateFormatVersion: 2010-09-09 - -Description: Reference Architecture to host Moodle on AWS - Creates RDS Aurora Serverless v2 MySQL or PostgreSQL database - -Metadata: - AWS::CloudFormation::Interface: - ParameterGroups: - - Label: - default: Database Parameters - Parameters: - - DatabaseType - - DatabaseMinCapacity - - DatabaseMaxCapacity - - DatabaseName - - DatabaseEncryptedBoolean - - DatabaseCmk - - DatabaseSecurityGroup - - NumberOfSubnets - - Subnet - ParameterLabels: - DatabaseType: - default: Aurora database type - DatabaseMinCapacity: - default: Minimum capacity for database - DatabaseMaxCapacity: - default: Maximum capacity for database - DatabaseEncryptedBoolean: - default: Encrypted DB Cluster - DatabaseCmk: - default: AWS KMS Customer Master Key (CMK) to encrypt DB - DatabaseName: - default: DB Name - DatabaseSecurityGroup: - default: DB Security Group - NumberOfSubnets: - default: Number of subnets - Subnet: - default: Subnets +Description: Moodle serverless database Parameters: DatabaseType: @@ -44,14 +8,7 @@ Parameters: - MySQL - PostgreSQL Default: PostgreSQL - Description: Indicates whether to use Aurora MySQL or PostgreSQL. - Type: String - DatabaseEncryptedBoolean: - AllowedValues: - - true - - false - Default: True - Description: Indicates whether the DB instances in the cluster are encrypted. + Description: Database engine to use. Type: String DatabaseCmk: Description: AWS KMS Customer Master Key (CMK) to encrypt database cluster @@ -111,26 +68,11 @@ Parameters: Type: String Conditions: - UseMySQL: - !Equals [!Ref DatabaseType, MySQL] - UsePostgreSQL: - !Equals [!Ref DatabaseType, PostgreSQL] - NumberOfSubnets1: - !Equals [ 1, !Ref NumberOfSubnets ] - NumberOfSubnets2: - !Equals [ 2, !Ref NumberOfSubnets ] - NumberOfSubnets3: - !Equals [ 3, !Ref NumberOfSubnets ] - Subnet0: !Or - - !Condition NumberOfSubnets1 - - !Condition NumberOfSubnets2 - - !Condition NumberOfSubnets3 - Subnet1: !Or - - !Condition NumberOfSubnets2 - - !Condition NumberOfSubnets3 - Subnet2: !Condition NumberOfSubnets3 - UseAWS-ManagedCMK: - !Equals ['', !Ref DatabaseCmk] + UseMySQL: !Equals [!Ref DatabaseType, MySQL] + UsePostgreSQL: !Equals [!Ref DatabaseType, PostgreSQL] + NumberOfSubnets1: !Equals [ 1, !Ref NumberOfSubnets ] + NumberOfSubnets2: !Equals [ 2, !Ref NumberOfSubnets ] + UseAWS-ManagedCMK: !Equals ['', !Ref DatabaseCmk] Resources: DatabaseCluster: @@ -139,22 +81,12 @@ Resources: BackupRetentionPeriod: 30 DatabaseName: !Ref DatabaseName DBSubnetGroupName: !Ref DataSubnetGroup - Engine: - !If [ UsePostgreSQL, aurora-postgresql, aurora-mysql ] - DBClusterParameterGroupName: - !If [ UsePostgreSQL, default.aurora-postgresql13, default.aurora-mysql8.0 ] - EngineVersion: - !If [ UsePostgreSQL, '13.8', '8.0.mysql_aurora.3.02.1' ] - KmsKeyId: - !If [ UseAWS-ManagedCMK, !Ref 'AWS::NoValue', !Ref DatabaseCmk ] + Engine: !If [ UsePostgreSQL, aurora-postgresql, aurora-mysql ] + Port: !If [ UsePostgreSQL, 5432, 3306 ] + KmsKeyId: !If [ UseAWS-ManagedCMK, !Ref 'AWS::NoValue', !Ref DatabaseCmk ] MasterUsername: !Join ['', ['{{resolve:secretsmanager:', !Ref RDSInstanceSecretArn, ':SecretString:username}}' ]] MasterUserPassword: !Join ['', ['{{resolve:secretsmanager:', !Ref RDSInstanceSecretArn, ':SecretString:password}}' ]] - Port: - !If [ UsePostgreSQL, 5432, 3306 ] - StorageEncrypted: !Ref DatabaseEncryptedBoolean - Tags: - - Key: Name - Value: !Join [ '', [ 'Moodle / ', !Ref 'AWS::StackName' ] ] + StorageEncrypted: true VpcSecurityGroupIds: - !Ref DatabaseSecurityGroup ServerlessV2ScalingConfiguration: @@ -170,29 +102,16 @@ Resources: DBClusterIdentifier: !Ref DatabaseCluster DBInstanceClass: 'db.serverless' DBSubnetGroupName: !Ref DataSubnetGroup - Engine: - !If [ UsePostgreSQL, aurora-postgresql, aurora-mysql ] - Tags: - - Key: Name - Value: !Join [ '', [ 'Moodle / ', !Ref 'AWS::StackName' ] ] + Engine: !If [ UsePostgreSQL, aurora-postgresql, aurora-mysql ] + PubliclyAccessible: false DataSubnetGroup: Type: AWS::RDS::DBSubnetGroup Properties: DBSubnetGroupDescription: RDS Database Subnet Group for Moodle - SubnetIds: - !If - [ NumberOfSubnets1, - [ !Select [ 0, !Ref Subnet ] ], - !If - [ NumberOfSubnets2, - [ !Select [ 0, !Ref Subnet ], !Select [ 1, !Ref Subnet ] ], - [ !Select [ 0, !Ref Subnet ], !Select [ 1, !Ref Subnet ], !Select [ 2, !Ref Subnet ] ] - ] - ] - Tags: - - Key: Name - Value: !Join [ '', [ 'Moodle / ', !Ref 'AWS::StackName' ] ] + SubnetIds: !If [ NumberOfSubnets1, [ !Select [ 0, !Ref Subnet ] ], + !If [ NumberOfSubnets2, [ !Select [ 0, !Ref Subnet ], !Select [ 1, !Ref Subnet ] ], + [ !Select [ 0, !Ref Subnet ], !Select [ 1, !Ref Subnet ], !Select [ 2, !Ref Subnet ] ] ] ] DatabaseClusterParam: Type: AWS::SSM::Parameter @@ -200,16 +119,15 @@ Resources: Name: !Join [ '', [ '/Moodle/',!Ref ProjectName, '/DB/ClusterEndpoint' ] ] Type: String Value: !GetAtt DatabaseCluster.Endpoint.Address - Description: SSM Parameter for Moodle DB Cluster + Description: Moodle DB Cluster Endpoint DatabaseClusterReadOnlyParam: Type: AWS::SSM::Parameter Properties: Name: !Join [ '', [ '/Moodle/',!Ref ProjectName, '/DB/ClusterReadOnlyEndpoint' ] ] Type: String - # Aurora Serverless v1 does not support Read-only replicas - Value: !GetAtt DatabaseCluster.Endpoint.Address - Description: SSM Parameter for Moodle DB Cluster Read only + Value: !GetAtt DatabaseCluster.ReadEndpoint.Address + Description: Moodle DB Cluster Read only Endpoint DatabaseNameParam: Type: AWS::SSM::Parameter @@ -217,7 +135,7 @@ Resources: Name: !Join [ '', [ '/Moodle/',!Ref ProjectName, '/DB/Name' ] ] Type: String Value: !Ref DatabaseName - Description: SSM Parameter for Moodle DB Name + Description: Moodle DB Name DatabaseTypeParam: Type: AWS::SSM::Parameter @@ -225,7 +143,7 @@ Resources: Name: !Join [ '', [ '/Moodle/',!Ref ProjectName, '/DB/Type' ] ] Type: String Value: !Ref DatabaseType - Description: SSM Parameter for Moodle DB Type + Description: for Moodle DB Type Outputs: Database: @@ -240,5 +158,3 @@ Outputs: Value: !GetAtt DatabaseCluster.Endpoint.Port DatabaseClusterReadEndpointAddress: Value: !GetAtt DatabaseCluster.ReadEndpoint.Address - - diff --git a/templates/03-s3.yaml b/templates/03-s3.yaml deleted file mode 100644 index 0f787ec..0000000 --- a/templates/03-s3.yaml +++ /dev/null @@ -1,28 +0,0 @@ ---- -AWSTemplateFormatVersion: 2010-09-09 - -Description: Reference Architecture to host Moodle on AWS - Creates S3 artifact bucket - -Metadata: - AWS::CloudFormation::Interface: - ParameterGroups: - - Label: - default: S3 Parameters - Parameters: - - S3BucketName - ParameterLabels: - S3BucketName: - default: S3 Bucket Name - -Parameters: - S3BucketName: - Description: The S3 Bucket name. - Type: String - -Resources: - S3Bucket: - Type: AWS::S3::Bucket - -Outputs: - BucketName: - Value: !Ref S3Bucket \ No newline at end of file diff --git a/templates/04-cloudfront.yaml b/templates/04-cloudfront.yaml index a80c99f..eb0e449 100644 --- a/templates/04-cloudfront.yaml +++ b/templates/04-cloudfront.yaml @@ -1,28 +1,8 @@ --- AWSTemplateFormatVersion: 2010-09-09 - -Description: Reference Architecture to host Moodle on AWS - Creates CloudFront distribution (if selected) - -Metadata: - - AWS::CloudFormation::Interface: - ParameterGroups: - - Label: - default: AWS Parameters - Parameters: - - CloudFrontAcmCertificate - - DomainName - - PublicAlbDnsName - ParameterLabels: - CloudFrontAcmCertificate: - default: CloudFront Certificate ARN - PublicAlbDnsName: - default: Public ALB DNS Name - DomainName: - default: Domain name of the Moodle site +Description: Moodle CloudFront distribution Parameters: - CloudFrontAcmCertificate: AllowedPattern: ^$|(arn:aws:acm:)([a-z0-9/:-])*([a-z0-9])$ Description: '[ Optional ] The AWS Certification Manager certificate ARN for the CloudFront distribution certificate - this certificate should be created in the us-east-1 (N. Virginia) region and must reference the Moodle domain name you use below.' @@ -36,18 +16,12 @@ Parameters: Type: String Conditions: - - SslCertificate: - !Not [ !Equals [ '', !Ref CloudFrontAcmCertificate ] ] - NoSslCertificate: - !Equals [ '', !Ref CloudFrontAcmCertificate ] - DomainName: - !Not [ !Equals [ '', !Ref DomainName ] ] - NoDomainName: - !Equals [ '', !Ref DomainName ] + SslCertificate: !Not [ !Equals [ '', !Ref CloudFrontAcmCertificate ] ] + NoSslCertificate: !Equals [ '', !Ref CloudFrontAcmCertificate ] + DomainName: !Not [ !Equals [ '', !Ref DomainName ] ] + NoDomainName: !Equals [ '', !Ref DomainName ] Resources: - CloudFrontDistributionNoSslCertificate: Type: AWS::CloudFront::Distribution Condition: NoSslCertificate @@ -85,6 +59,7 @@ Resources: HttpVersion: http2and3 ViewerCertificate: CloudFrontDefaultCertificate: true + MinimumProtocolVersion: TLSv1.2_2021 CloudFrontDistributionSslCertificate: Type: AWS::CloudFront::Distribution @@ -126,9 +101,8 @@ Resources: ViewerCertificate: AcmCertificateArn: !Ref CloudFrontAcmCertificate SslSupportMethod: sni-only - MinimumProtocolVersion: TLSv1.2_2019 + MinimumProtocolVersion: TLSv1.2_2021 Outputs: - DnsName: - Value: !If [ NoSslCertificate, !GetAtt CloudFrontDistributionNoSslCertificate.DomainName, !GetAtt CloudFrontDistributionSslCertificate.DomainName ] \ No newline at end of file + Value: !If [ NoSslCertificate, !GetAtt CloudFrontDistributionNoSslCertificate.DomainName, !GetAtt CloudFrontDistributionSslCertificate.DomainName ] diff --git a/templates/04-efsalarms.yaml b/templates/04-efsalarms.yaml deleted file mode 100644 index 205257d..0000000 --- a/templates/04-efsalarms.yaml +++ /dev/null @@ -1,512 +0,0 @@ ---- -AWSTemplateFormatVersion: 2010-09-09 - -Description: Reference Architecture to host Moodle on AWS - Creates EFS alarms - -Metadata: - - AWS::CloudFormation::Interface: - - ParameterGroups: - - Label: - default: Amazon EFS Parameters - Parameters: - - ElasticFileSystem - - WarningThreshold - - CriticalThreshold - - EmailAddress - - InstanceType - - EC2KeyName - - SecurityGroup - - NumberOfSubnets - - Subnet - ParameterLabels: - CriticalThreshold: - default: Burst Credit Balance Critical Threshold (Minutes) - ElasticFileSystem: - default: Amazon EFS File System - EmailAddress: - default: SNS Email Address - InstanceType: - default: Instance Type - EC2KeyName: - default: Existing Key Pair - NumberOfSubnets: - default: Number of subnets - SecurityGroup: - default: EFS Security Group - Subnet: - default: Subnets - WarningThreshold: - default: Burst Credit Balance Warning Threshold (Minutes) - -Parameters: - - CriticalThreshold: - AllowedPattern: ^[0-9]+$ - ConstraintDescription: Must be an integer. - Default: 60 - Description: Send critical alarm this minutes before burst credit balance is zero. - Type: String - SecurityGroup: - Description: Select the Amazon EFS security group. - Type: AWS::EC2::SecurityGroup::Id - ElasticFileSystem: - Description: The Amazon EFS file system id. - Type: String - EmailAddress: - Description: The email address for SNS notifications. - Type: String - InstanceType: - AllowedValues: - - t2.nano - - t2.micro - - t2.small - - t2.medium - - t2.large - - t2.xlarge - - t2.2xlarge - - m3.medium - - m3.large - - m3.xlarge - - m3.2xlarge - - m4.large - - m4.xlarge - - m4.2xlarge - - m4.4xlarge - - m4.10xlarge - - m4.16xlarge - - c3.large - - c3.xlarge - - c3.2xlarge - - c3.4xlarge - - c3.8xlarge - - c4.large - - c4.xlarge - - c4.2xlarge - - c4.4xlarge - - c4.8xlarge - - c5.large - - c5.xlarge - - c5.2xlarge - - c5.4xlarge - - c5.8xlarge - - r3.large - - r3.xlarge - - r3.2xlarge - - r3.4xlarge - - r3.8xlarge - - r4.large - - r4.xlarge - - r4.2xlarge - - r4.4xlarge - - r4.8xlarge - - r4.16xlarge - - i3.large - - i3.xlarge - - i3.2xlarge - - i3.4xlarge - - i3.8xlarge - - i3.16xlarge - - d2.xlarge - - d2.2xlarge - - d2.4xlarge - - d2.8xlarge - - p2.xlarge - - p2.8xlarage - - p2.16xlarge - - g3.4xlarge - - g3.8xlarge - - g3.16xlarge - - f1.2xlarge - - f1.16xlarge - - x1.16xlarge - - x1.32xlarge - ConstraintDescription: Must be a valid Amazon EC2 instance type. - Default: t2.nano - Description: The Amazon EC2 instance type that dynamically adjusts thresholds based on permitted throughput changes. - Type: String - EC2KeyName: - Description: Name of an existing EC2 key pair - Type: AWS::EC2::KeyPair::KeyName - NumberOfSubnets: - AllowedValues: - - 2 - - 3 - - 4 - - 5 - - 6 - Default: 3 - Description: Number of subnets. This must match your selections in the list of Subnets below. - Type: String - Subnet: - Description: Select existing subnets. - Type: List - WarningThreshold: - AllowedPattern: ^[0-9]+$ - ConstraintDescription: Must be an integer. - Default: 180 - Description: Send warning alarm this many minutes before burst credit balance is zero. - Type: String - LatestAmiId : - Type : AWS::SSM::Parameter::Value - Default: /aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2 - -Conditions: - - NumberOfSubnets1: - !Equals [ 1, !Ref NumberOfSubnets ] - NumberOfSubnets2: - !Equals [ 2, !Ref NumberOfSubnets ] - NumberOfSubnets3: - !Equals [ 3, !Ref NumberOfSubnets ] - NumberOfSubnets4: - !Equals [ 4, !Ref NumberOfSubnets ] - NumberOfSubnets5: - !Equals [ 5, !Ref NumberOfSubnets ] - NumberOfSubnets6: - !Equals [ 6, !Ref NumberOfSubnets ] - Subnet0: !Or - - !Condition NumberOfSubnets1 - - !Condition NumberOfSubnets2 - - !Condition NumberOfSubnets3 - - !Condition NumberOfSubnets4 - - !Condition NumberOfSubnets5 - - !Condition NumberOfSubnets6 - Subnet1: !Or - - !Condition NumberOfSubnets2 - - !Condition NumberOfSubnets3 - - !Condition NumberOfSubnets4 - - !Condition NumberOfSubnets5 - - !Condition NumberOfSubnets6 - Subnet2: !Or - - !Condition NumberOfSubnets3 - - !Condition NumberOfSubnets4 - - !Condition NumberOfSubnets5 - - !Condition NumberOfSubnets6 - Subnet3: !Or - - !Condition NumberOfSubnets4 - - !Condition NumberOfSubnets5 - - !Condition NumberOfSubnets6 - Subnet4: !Or - - !Condition NumberOfSubnets5 - - !Condition NumberOfSubnets6 - Subnet5: !Condition NumberOfSubnets6 - - -Resources: - - AutoScalingGroup: - Type: AWS::AutoScaling::AutoScalingGroup - Properties: - Cooldown: 60 - HealthCheckGracePeriod: 120 - HealthCheckType: EC2 - LaunchConfigurationName: !Ref LaunchConfiguration - MaxSize: 1 - MinSize: 0 - DesiredCapacity: 1 - Tags: - - Key: Name - Value: !Join [ '', [ 'Updating ', !Ref 'ElasticFileSystem', ' burst credit balance Cloudwatch alarms.. will auto terminate' ] ] - PropagateAtLaunch: true - VPCZoneIdentifier: - !If - [ NumberOfSubnets1, - [ !Select [ 0, !Ref Subnet ] ], - !If - [ NumberOfSubnets2, - [ !Select [ 0, !Ref Subnet ], !Select [ 1, !Ref Subnet ] ], - !If - [ NumberOfSubnets3, - [ !Select [ 0, !Ref Subnet ], !Select [ 1, !Ref Subnet ], !Select [ 2, !Ref Subnet ] ], - !If - [ NumberOfSubnets4, - [ !Select [ 0, !Ref Subnet ], !Select [ 1, !Ref Subnet ], !Select [ 2, !Ref Subnet ], !Select [ 3, !Ref Subnet ] ], - !If - [ NumberOfSubnets5, - [ !Select [ 0, !Ref Subnet ], !Select [ 1, !Ref Subnet ], !Select [ 2, !Ref Subnet ], !Select [ 3, !Ref Subnet ], !Select [ 4, !Ref Subnet ] ], - [ !Select [ 0, !Ref Subnet ], !Select [ 1, !Ref Subnet ], !Select [ 2, !Ref Subnet ], !Select [ 3, !Ref Subnet ], !Select [ 4, !Ref Subnet ], !Select [ 5, !Ref Subnet ] ] - ] - ] - ] - ] - ] - CreationPolicy: - ResourceSignal: - Count: 0 - Timeout: PT5M - AutoScalingPolicy: - Type: AWS::AutoScaling::ScalingPolicy - Properties: - AdjustmentType: ChangeInCapacity - AutoScalingGroupName: !Ref AutoScalingGroup - Cooldown: 60 - PolicyType: SimpleScaling - ScalingAdjustment: 1 - BurstCreditBalanceDecreaseAlarm: - Type: AWS::CloudWatch::Alarm - Properties: - AlarmActions: - - !Ref SNSTopic - - !Ref AutoScalingPolicy - AlarmDescription: !Join [ '', [ 'Set ', !Ref ElasticFileSystem, ' burst credit balance decrease threshold - ', !Ref 'AWS::StackName' ] ] - AlarmName: !Join [ '', [ 'Set ', !Ref ElasticFileSystem, ' burst credit balance decrease threshold - ', !Ref 'AWS::StackName' ] ] - ComparisonOperator: LessThanThreshold - Dimensions: - - Name: FileSystemId - Value: !Ref ElasticFileSystem - EvaluationPeriods: 10 - MetricName: PermittedThroughput - Namespace: AWS/EFS - Period: 60 - Statistic: Sum - Threshold: 0 - TreatMissingData: missing - BurstCreditBalanceIncreaseAlarm: - Type: AWS::CloudWatch::Alarm - Properties: - AlarmActions: - - !Ref SNSTopic - - !Ref AutoScalingPolicy - AlarmDescription: !Join [ '', [ 'Set ', !Ref ElasticFileSystem, ' burst credit balance increase threshold - ', !Ref 'AWS::StackName' ] ] - AlarmName: !Join [ '', [ 'Set ', !Ref ElasticFileSystem, ' burst credit balance increase threshold - ', !Ref 'AWS::StackName' ] ] - ComparisonOperator: LessThanThreshold - Dimensions: - - Name: FileSystemId - Value: !Ref ElasticFileSystem - EvaluationPeriods: 10 - MetricName: PermittedThroughput - Namespace: AWS/EFS - Period: 60 - Statistic: Sum - Threshold: 0 - TreatMissingData: missing - CriticalAlarm: - Type: AWS::CloudWatch::Alarm - Properties: - AlarmActions: - - !Ref SNSTopic - AlarmDescription: !Join [ '', [ !Ref ElasticFileSystem, ' burst credit balance - Critical - ', !Ref 'AWS::StackName' ] ] - AlarmName: !Join [ '', [ !Ref ElasticFileSystem, ' burst credit balance - Critical - ', !Ref 'AWS::StackName' ] ] - ComparisonOperator: LessThanThreshold - Dimensions: - - Name: FileSystemId - Value: !Ref ElasticFileSystem - EvaluationPeriods: 10 - MetricName: BurstCreditBalance - Namespace: AWS/EFS - Period: 60 - Statistic: Sum - Threshold: 0 - TreatMissingData: missing - InstanceProfile: - Type: AWS::IAM::InstanceProfile - Properties: - Path: / - Roles: - - !Ref InstanceRole - InstanceRole: - Type: AWS::IAM::Role - Properties: - AssumeRolePolicyDocument: - Version: 2012-10-17 - Statement: - - Effect: Allow - Principal: - Service: - - ec2.amazonaws.com - Action: - - sts:AssumeRole - Path: / - Policies: - - PolicyName: efs-burst-credit-balance-cloudwatch-alarms - PolicyDocument: - Version: 2012-10-17 - Statement: - - Effect: Allow - Action: - - cloudwatch:GetMetricStatistics - - cloudwatch:PutMetricAlarm - - autoscaling:DescribeAutoScalingGroups - - autoscaling:DescribeAutoScalingInstances - - autoscaling:DescribePolicies - - autoscaling:UpdateAutoScalingGroup - - elasticfilesystem:DescribeFileSystems - Resource: '*' - - Effect: Allow - Action: - - sns:Publish - Resource: !Ref SNSTopic - LaunchConfiguration: - Type: AWS::AutoScaling::LaunchConfiguration - Metadata: - AWS::CloudFormation::Init: - configSets: - set_cloudwatch_alarms: - - set-cloudwatch-alarms - set-cloudwatch-alarms: - files: - /tmp/set-cloudwatch-alarms.sh: - content: - !Join [ - "",[ - "#!/bin/bash -x\n", - "\n", - "FILE_SYSTEM_ID=$1\n", - "WARNING_THRESHOLD_MINUTES=$2\n", - "CRITICAL_THRESHOLD_MINUTES=$3\n", - "SNS_ARN=$4\n", - "\n", - "error=0\n", - "\n", - "# get region\n", - "availability_zone=$(curl -s http://169.254.169.254/latest/meta-data/placement/availability-zone)\n", - "region=${availability_zone:0:-1}\n", - "\n", - "# get instance id\n", - "instance_id=$(curl -s http://169.254.169.254/latest/meta-data/instance-id)\n", - "\n", - "# get autoscaling group name\n", - "asg_name=$(aws autoscaling describe-auto-scaling-instances --instance-ids ${instance_id} --region ${region} --output text --query 'AutoScalingInstances[0].AutoScalingGroupName')\n", - "\n", - "# get autoscaling policy arn\n", - "asg_policy_arn=$(aws autoscaling describe-policies --auto-scaling-group-name ${asg_name} --region ${region} --output text --query 'ScalingPolicies[0].PolicyARN')\n", - "\n", - "# validate FILE_SYSTEM_ID send notification and exit if doesn't exist\n", - "aws efs describe-file-systems --file-system-id ${FILE_SYSTEM_ID} --region ${region} --output text --query 'FileSystems[0].[FileSystemId]'\n", - "result=$?\n", - "if [ $result -ne 0 ]; then\n", - " aws sns publish --topic-arn ${SNS_ARN} --region ${region} --message 'Amazon EFS burst credit balance CloudWatch alarm error. File system '${FILE_SYSTEM_ID}' does not exist.'\n", - " exit\n", - "fi\n", - "\n", - "# get current permitted throughput\n", - "count=1\n", - "while [ -z ${permitted_throughput} ] || [ ${permitted_throughput} == null ] && [ ${count} -lt 60 ]; do\n", - " permitted_throughput=$(aws cloudwatch get-metric-statistics --namespace AWS/EFS --metric-name PermittedThroughput --dimensions Name=FileSystemId,Value=${FILE_SYSTEM_ID} --start-time $(date --utc +%FT%TZ -d '-120 seconds') --end-time $(date --utc +%FT%TZ -d '-60 seconds') --period 60 --statistics Sum --region ${region} --output json --query 'Datapoints[0].Sum')\n", - " sleep 2\n", - " count=$(expr ${count} + 1)\n", - "done\n", - "\n", - "# get current burst credit balance\n", - "count=1\n", - "while [ -z ${burst_credit_balance} ] || [ ${burst_credit_balance} == null ] && [ ${count} -lt 60 ]; do\n", - " burst_credit_balance=$(aws cloudwatch get-metric-statistics --namespace AWS/EFS --metric-name BurstCreditBalance --dimensions Name=FileSystemId,Value=${FILE_SYSTEM_ID} --start-time $(date --utc +%FT%TZ -d '-120 seconds') --end-time $(date --utc +%FT%TZ -d '-60 seconds') --period 60 --statistics Sum --region ${region} --output json --query 'Datapoints[0].Sum')\n", - " sleep 2\n", - " count=$(expr ${count} + 1)\n", - "done\n", - "\n", - "# calculate new burst credit balance warning threshold\n", - "burst_credit_balance_threshold_warning=$(( ${burst_credit_balance:0:-2} - ( ( ( ${burst_credit_balance:0:-2} / ( ${permitted_throughput:0:-2} * 60 ) ) - $WARNING_THRESHOLD_MINUTES ) * ( ${permitted_throughput:0:-2} * 60 ) ) ))\n", - "\n", - "# calculate new burst credit balance critical threshold\n", - "burst_credit_balance_threshold_critical=$(( ${burst_credit_balance:0:-2} - ( ( ( ${burst_credit_balance:0:-2} / ( ${permitted_throughput:0:-2} * 60 ) ) - $CRITICAL_THRESHOLD_MINUTES ) * ( ${permitted_throughput:0:-2} * 60 ) ) ))\n", - "\n", - "# update warning alarm with new burst credit balance warning threshold\n", - "aws cloudwatch put-metric-alarm --alarm-name ''${FILE_SYSTEM_ID}' burst credit balance - Warning - '", !Ref 'AWS::StackName', " --alarm-description ''${FILE_SYSTEM_ID}' burst credit balance - Warning - '", !Ref 'AWS::StackName', " --actions-enabled --alarm-actions ${SNS_ARN} --metric-name BurstCreditBalance --namespace AWS/EFS --statistic Sum --dimensions Name=FileSystemId,Value=${FILE_SYSTEM_ID} --period 60 --evaluation-periods 5 --threshold ${burst_credit_balance_threshold_warning} --comparison-operator LessThanThreshold --treat-missing-data missing --region ${region}\n", - "result=$?\n", - "if [ $result -ne 0 ]; then\n", - " aws sns publish --topic-arn ${SNS_ARN} --region ${region} --message 'Amazon EFS burst credit balance CloudWatch alarm error. Check CloudWatch alarms for file system '${FILE_SYSTEM_ID}'.'\n", - " error=$(expr ${error} + 1)\n", - "fi\n", - "\n", - "# update critical alarm with new burst credit balance critical threshold\n", - "aws cloudwatch put-metric-alarm --alarm-name ''${FILE_SYSTEM_ID}' burst credit balance - Critical - '", !Ref 'AWS::StackName', " --alarm-description ''${FILE_SYSTEM_ID}' burst credit balance - Critical - '", !Ref 'AWS::StackName', " --actions-enabled --alarm-actions ${SNS_ARN} --metric-name BurstCreditBalance --namespace AWS/EFS --statistic Sum --dimensions Name=FileSystemId,Value=${FILE_SYSTEM_ID} --period 60 --evaluation-periods 5 --threshold ${burst_credit_balance_threshold_critical} --comparison-operator LessThanThreshold --treat-missing-data missing --region ${region}\n", - "result=$?\n", - "if [ $result -ne 0 ]; then\n", - " aws sns publish --topic-arn ${SNS_ARN} --region ${region} --message 'Amazon EFS burst credit balance CloudWatch alarm error. Check CloudWatch alarms for file system '${FILE_SYSTEM_ID}'.'\n", - " error=$(expr ${error} + 1)\n", - "fi\n", - "\n", - "# update burst credit balance increase threshold based\n", - "aws cloudwatch put-metric-alarm --alarm-name 'Set '${FILE_SYSTEM_ID}' burst credit balance increase threshold - '", !Ref 'AWS::StackName', " --alarm-description 'Set '${FILE_SYSTEM_ID}' burst credit balance increase threshold - '", !Ref 'AWS::StackName', " --actions-enabled --alarm-actions ${SNS_ARN} ${asg_policy_arn} --metric-name PermittedThroughput --namespace AWS/EFS --statistic Sum --dimensions Name=FileSystemId,Value=${FILE_SYSTEM_ID} --period 60 --evaluation-periods 5 --threshold ${permitted_throughput:0:-2} --comparison-operator GreaterThanThreshold --treat-missing-data missing --region ${region}\n", - "result=$?\n", - "if [ $result -ne 0 ]; then\n", - " aws sns publish --topic-arn ${SNS_ARN} --region ${region} --message 'Amazon EFS burst credit balance CloudWatch alarm error. Check CloudWatch alarms for file system '${FILE_SYSTEM_ID}'.'\n", - " error=$(expr ${error} + 1)\n", - "fi\n", - "\n", - "# update burst credit balance decrease threshold based\n", - "aws cloudwatch put-metric-alarm --alarm-name 'Set '${FILE_SYSTEM_ID}' burst credit balance decrease threshold - '", !Ref 'AWS::StackName', " --alarm-description 'Set '${FILE_SYSTEM_ID}' burst credit balance decrease threshold - '", !Ref 'AWS::StackName', " --actions-enabled --alarm-actions ${SNS_ARN} ${asg_policy_arn} --metric-name PermittedThroughput --namespace AWS/EFS --statistic Sum --dimensions Name=FileSystemId,Value=${FILE_SYSTEM_ID} --period 60 --evaluation-periods 5 --threshold ${permitted_throughput:0:-2} --comparison-operator LessThanThreshold --treat-missing-data missing --region ${region}\n", - "result=$?\n", - "if [ $result -ne 0 ]; then\n", - " aws sns publish --topic-arn ${SNS_ARN} --region ${region} --message 'Amazon EFS burst credit balance CloudWatch alarm error. Check CloudWatch alarms for file system '${FILE_SYSTEM_ID}'.'\n", - " error=$(expr ${error} + 1)\n", - "fi\n", - "\n", - "# auto terminate instance - setting auto scaling group desired capacity 0\n", - "if [ $error -eq 0 ]; then\n", - " aws autoscaling update-auto-scaling-group --auto-scaling-group-name ${asg_name} --desired-capacity 0 --region ${region}\n", - " else\n", - " aws sns publish --topic-arn ${SNS_ARN} --region ${region} --message 'Amazon EFS burst credit balance CloudWatch alarm error. Check CloudWatch alarms for file system '${FILE_SYSTEM_ID}'.'\n", - "fi\n", - "\n" - ] - ] - mode: 000777 - owner: root - group: root - Properties: - BlockDeviceMappings: - - DeviceName: /dev/xvda - Ebs: - DeleteOnTermination: true - VolumeSize: 10 - VolumeType: gp2 - IamInstanceProfile: !Ref InstanceProfile - ImageId: !Ref LatestAmiId - InstanceMonitoring: true - InstanceType: !Ref InstanceType - KeyName: !Ref EC2KeyName - SecurityGroups: - - !Ref SecurityGroup - UserData: - "Fn::Base64": - !Sub | - #cloud-config - repo_update: true - repo_upgrade: all - - packages: - - runcmd: - - ntpstat - - /opt/aws/bin/cfn-init --configsets set_cloudwatch_alarms --verbose --stack ${AWS::StackName} --resource LaunchConfiguration --region ${AWS::Region} - - /tmp/set-cloudwatch-alarms.sh ${ElasticFileSystem} ${WarningThreshold} ${CriticalThreshold} ${SNSTopic} - SNSTopic: - Type: AWS::SNS::Topic - Properties: - DisplayName: !Join [ '', [ !Ref ElasticFileSystem, '-alarm-notification' ] ] - Subscription: - - Endpoint: !Ref EmailAddress - Protocol: "email" - TopicName: !Join [ '', [ !Ref ElasticFileSystem, '-alarm-notification' ] ] - WarningAlarm: - Type: AWS::CloudWatch::Alarm - Properties: - AlarmActions: - - !Ref SNSTopic - AlarmDescription: !Join [ '', [ !Ref ElasticFileSystem, ' burst credit balance - Warning - ', !Ref 'AWS::StackName' ] ] - AlarmName: !Join [ '', [ !Ref ElasticFileSystem, ' burst credit balance - Warning - ', !Ref 'AWS::StackName' ] ] - ComparisonOperator: LessThanThreshold - Dimensions: - - Name: FileSystemId - Value: !Ref ElasticFileSystem - EvaluationPeriods: 10 - MetricName: BurstCreditBalance - Namespace: AWS/EFS - Period: 60 - Statistic: Sum - Threshold: 0 - TreatMissingData: missing - -Outputs: - BurstCreditBalanceDecreaseAlarmArn: - Value: !GetAtt BurstCreditBalanceDecreaseAlarm.Arn - BurstCreditBalanceIncreaseAlarmArn: - Value: !GetAtt BurstCreditBalanceIncreaseAlarm.Arn - CriticalAlarmArn: - Value: !GetAtt CriticalAlarm.Arn - WarningAlarmArn: - Value: !GetAtt WarningAlarm.Arn \ No newline at end of file diff --git a/templates/04-efsfilegrowhelper.yaml b/templates/04-efsfilegrowhelper.yaml deleted file mode 100644 index 9d4dc78..0000000 --- a/templates/04-efsfilegrowhelper.yaml +++ /dev/null @@ -1,660 +0,0 @@ ---- -AWSTemplateFormatVersion: 2010-09-09 - -Description: Reference Architecture to host Moodle on AWS - Creates EFS alarms - -Parameters: - Growth: - ConstraintDescription: Must be an integer. - Default: 0 - Description: Amount of dummy data (GiB) to add to the file system (max 6144 GiB). Amazon EFS storage charges apply. - MaxValue: 6144 - MinValue: 0 - Type: Number - CriticalThreshold: - AllowedPattern: ^[0-9]+$ - ConstraintDescription: Must be an integer. - Default: 60 - Description: Send critical alarm this minutes before burst credit balance is zero. - Type: String - SecurityGroup: - Description: Select the Amazon EFS security group. - Type: AWS::EC2::SecurityGroup::Id - ElasticFileSystem: - Description: The Amazon EFS file system id. - Type: String - EmailAddress: - Description: The email address for SNS notifications. - Type: String - InstanceType: - AllowedValues: - - m5.large - - m5.xlarge - - m5.2xlarge - - m5.4xlarge - - m5.8xlarge - - m5.12xlarge - - m5.16xlarge - - m5.24xlarge - - c5.large - - c5.xlarge - - c5.2xlarge - - c5.4xlarge - - c5.9xlarge - - c5.12xlarge - - c5.18xlarge - - c5.24xlarge - - r5.large - - r5.xlarge - - r5.2xlarge - - r5.4xlarge - - r5.8xlarge - - r5.12xlarge - - r5.16xlarge - - r5.24xlarge - - m5a.large - - m5a.xlarge - - m5a.2xlarge - - m5a.4xlarge - - m5a.8xlarge - - m5a.12xlarge - - m5a.16xlarge - - m5a.24xlarge - - c5a.large - - c5a.xlarge - - c5a.2xlarge - - c5a.4xlarge - - c5a.9xlarge - - c5a.12xlarge - - c5a.18xlarge - - c5a.24xlarge - - r5a.large - - r5a.xlarge - - r5a.2xlarge - - r5a.4xlarge - - r5a.8xlarge - - r5a.12xlarge - - r5a.16xlarge - - r5a.24xlarge - - m6g.large - - m6g.xlarge - - m6g.2xlarge - - m6g.4xlarge - - m6g.8xlarge - - m6g.12xlarge - - m6g.16xlarge - - m6g.24xlarge - - c6g.large - - c6g.xlarge - - c6g.2xlarge - - c6g.4xlarge - - c6g.9xlarge - - c6g.12xlarge - - c6g.18xlarge - - c6g.24xlarge - - r6g.large - - r6g.xlarge - - r6g.2xlarge - - r6g.4xlarge - - r6g.8xlarge - - r6g.12xlarge - - r6g.16xlarge - - r6g.24xlarge - ConstraintDescription: Must be a valid Amazon EC2 instance type. - Default: m6g.large - Description: The Amazon EC2 instance type that dynamically adjusts thresholds based on permitted throughput changes. - Type: String - EC2KeyName: - Description: Name of an existing EC2 key pair - Type: AWS::EC2::KeyPair::KeyName - NumberOfSubnets: - AllowedValues: - - 1 - - 2 - - 3 - Default: 2 - Description: Number of subnets. This must match your selections in the list of Subnets below. - Type: String - Subnet: - Description: Select existing subnets. - Type: List - WarningThreshold: - AllowedPattern: ^[0-9]+$ - ConstraintDescription: Must be an integer. - Default: 180 - Description: Send warning alarm this many minutes before burst credit balance is zero. - Type: String - LatestAmiId : - Type : AWS::SSM::Parameter::Value - Default: /aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2 - LatestArmAmiId : - Type : AWS::SSM::Parameter::Value - Default: /aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-arm64-gp2 - -Conditions: - NumberOfSubnets1: - !Equals [ 1, !Ref NumberOfSubnets ] - NumberOfSubnets2: - !Equals [ 2, !Ref NumberOfSubnets ] - NumberOfSubnets3: - !Equals [ 3, !Ref NumberOfSubnets ] - Subnet0: !Or - - !Condition NumberOfSubnets1 - - !Condition NumberOfSubnets2 - - !Condition NumberOfSubnets3 - Subnet1: !Or - - !Condition NumberOfSubnets2 - - !Condition NumberOfSubnets3 - Subnet2: !Condition NumberOfSubnets3 - UsingGraviton2Ami: !Or - - !Equals ["t4",!Select [0, !Split [ "g.", !Ref InstanceType]]] - - !Equals ["c6",!Select [0, !Split [ "g.", !Ref InstanceType]]] - - !Equals ["m6",!Select [0, !Split [ "g.", !Ref InstanceType]]] - - !Equals ["r6",!Select [0, !Split [ "g.", !Ref InstanceType]]] - -Resources: - InstanceProfile: - Type: AWS::IAM::InstanceProfile - Properties: - Path: / - Roles: - - !Ref InstanceRole - - InstanceRole: - Type: AWS::IAM::Role - Properties: - AssumeRolePolicyDocument: - Version: 2012-10-17 - Statement: - - Effect: Allow - Principal: - Service: - - ec2.amazonaws.com - Action: - - sts:AssumeRole - ManagedPolicyArns: - - 'arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore' - Path: / - Policies: - - PolicyName: MoodleEFSFileHelperPolicy - PolicyDocument: - Version: 2012-10-17 - Statement: - - Effect: Allow - Action: - - autoscaling:DescribeAutoScalingGroups - - autoscaling:DescribeAutoScalingInstances - - autoscaling:DescribePolicies - - autoscaling:UpdateAutoScalingGroup - Resource: '*' - - Effect: Allow - Action: - - cloudwatch:GetMetricStatistics - - cloudwatch:PutMetricAlarm - - autoscaling:DescribeAutoScalingGroups - - autoscaling:DescribeAutoScalingInstances - - autoscaling:DescribePolicies - - autoscaling:UpdateAutoScalingGroup - - elasticfilesystem:DescribeFileSystems - Resource: '*' - - Effect: Allow - Action: - - sns:Publish - Resource: !Ref SNSTopic - - AutoScalingGroup: - Type: AWS::AutoScaling::AutoScalingGroup - Properties: - Cooldown: 60 - HealthCheckGracePeriod: 120 - HealthCheckType: EC2 - LaunchTemplate: - LaunchTemplateId: !Ref LaunchTemplate - Version: !GetAtt LaunchTemplate.LatestVersionNumber - MaxSize: 1 - MinSize: 0 - DesiredCapacity: 1 - Tags: - - Key: Name - Value: !Join [ '', [ 'Moodle EFS Helper ', !Ref 'ElasticFileSystem', ' ...will auto terminate' ] ] - PropagateAtLaunch: true - VPCZoneIdentifier: - !If - [ NumberOfSubnets1, - [ !Select [ 0, !Ref Subnet ] ], - !If - [ NumberOfSubnets2, - [ !Select [ 0, !Ref Subnet ], !Select [ 1, !Ref Subnet ] ], - [ !Select [ 0, !Ref Subnet ], !Select [ 1, !Ref Subnet ], !Select [ 2, !Ref Subnet ] ] - ] - ] - CreationPolicy: - ResourceSignal: - Count: 0 - Timeout: PT12H - UpdatePolicy: - AutoScalingReplacingUpdate: - WillReplace: true - - AutoScalingPolicy: - Type: AWS::AutoScaling::ScalingPolicy - Properties: - AdjustmentType: ChangeInCapacity - AutoScalingGroupName: !Ref AutoScalingGroup - Cooldown: 60 - PolicyType: SimpleScaling - ScalingAdjustment: 1 - - BurstCreditBalanceDecreaseAlarm: - Type: AWS::CloudWatch::Alarm - Properties: - AlarmActions: - - !Ref SNSTopic - - !Ref AutoScalingPolicy - AlarmDescription: !Join [ '', [ 'Set ', !Ref ElasticFileSystem, ' burst credit balance decrease threshold - ', !Ref 'AWS::StackName' ] ] - AlarmName: !Join [ '', [ 'Set ', !Ref ElasticFileSystem, ' burst credit balance decrease threshold - ', !Ref 'AWS::StackName' ] ] - ComparisonOperator: LessThanThreshold - Dimensions: - - Name: FileSystemId - Value: !Ref ElasticFileSystem - EvaluationPeriods: 10 - MetricName: PermittedThroughput - Namespace: AWS/EFS - Period: 60 - Statistic: Sum - Threshold: 0 - TreatMissingData: missing - - BurstCreditBalanceIncreaseAlarm: - Type: AWS::CloudWatch::Alarm - Properties: - AlarmActions: - - !Ref SNSTopic - - !Ref AutoScalingPolicy - AlarmDescription: !Join [ '', [ 'Set ', !Ref ElasticFileSystem, ' burst credit balance increase threshold - ', !Ref 'AWS::StackName' ] ] - AlarmName: !Join [ '', [ 'Set ', !Ref ElasticFileSystem, ' burst credit balance increase threshold - ', !Ref 'AWS::StackName' ] ] - ComparisonOperator: LessThanThreshold - Dimensions: - - Name: FileSystemId - Value: !Ref ElasticFileSystem - EvaluationPeriods: 10 - MetricName: PermittedThroughput - Namespace: AWS/EFS - Period: 60 - Statistic: Sum - Threshold: 0 - TreatMissingData: missing - - CriticalAlarm: - Type: AWS::CloudWatch::Alarm - Properties: - AlarmActions: - - !Ref SNSTopic - AlarmDescription: !Join [ '', [ !Ref ElasticFileSystem, ' burst credit balance - Critical - ', !Ref 'AWS::StackName' ] ] - AlarmName: !Join [ '', [ !Ref ElasticFileSystem, ' burst credit balance - Critical - ', !Ref 'AWS::StackName' ] ] - ComparisonOperator: LessThanThreshold - Dimensions: - - Name: FileSystemId - Value: !Ref ElasticFileSystem - EvaluationPeriods: 10 - MetricName: BurstCreditBalance - Namespace: AWS/EFS - Period: 60 - Statistic: Sum - Threshold: 0 - TreatMissingData: missing - - LaunchTemplate: - Type: AWS::EC2::LaunchTemplate - Metadata: - AWS::CloudFormation::Init: - configSets: - efs_add_storage: - - efs-add-storage - set_cloudwatch_alarms: - - set-cloudwatch-alarms - efs-add-storage: - packages: - yum: - #Only needed to set permissions on the moodle folder - httpd: [] - files: - /tmp/efs-add-storage.sh: - content: !Sub | - #!/bin/bash -x - - FILE_SYSTEM_ID=$1 - DATA_DIRECTORY=$2 - GROWTH=$3 - - if [ $# -lt 3 ]; then - echo "Invalid # of arguments. Require: file system id, data directory, file system growth (GiB) " - exit 0 - fi - - # get region from instance meta-data - availabilityzone=$(curl -s http://169.254.169.254/latest/meta-data/placement/availability-zone) - region=${!availabilityzone:0:-1} - - # get instance id - instance_id=$(curl -s http://169.254.169.254/latest/meta-data/instance-id) - - # get autoscaling group name - asg_name=$(aws autoscaling describe-auto-scaling-instances --instance-ids $instance_id --region $region --output text --query 'AutoScalingInstances[0].AutoScalingGroupName') - - # set the number of threads to the number of vcpus - threads=$(( $(nproc --all) * 8 )) - - # wait for file system DNS name to be propagated - results=1 - while [[ $results != 0 ]]; do - nslookup $FILE_SYSTEM_ID.efs.$region.amazonaws.com - results=$? - if [[ results = 1 ]]; then - sleep 30 - fi - done - - # mount file system - sudo mkdir -p /$FILE_SYSTEM_ID - sudo chown ec2-user:ec2-user /$FILE_SYSTEM_ID - sudo mountpoint -q /$FILE_SYSTEM_ID || sudo mount -t nfs4 -o nfsvers=4.1,rsize=1048576,wsize=1048576,hard,timeo=600,retrans=2 $FILE_SYSTEM_ID.efs.$region.amazonaws.com:/ /$FILE_SYSTEM_ID - - #Create directories for Moodle - sudo mkdir -p /$FILE_SYSTEM_ID/data - sudo mkdir -p /$FILE_SYSTEM_ID/cache - sudo mkdir -p /$FILE_SYSTEM_ID/temp - chown apache:apache /$FILE_SYSTEM_ID/data/ - chown apache:apache /$FILE_SYSTEM_ID/cache/ - chown apache:apache /$FILE_SYSTEM_ID/temp/ - - # create data directory if not exists - sudo mkdir -p /$FILE_SYSTEM_ID/$DATA_DIRECTORY - sudo chown ec2-user:ec2-user /$FILE_SYSTEM_ID/$DATA_DIRECTORY - - # dd 1GiB files to file system to match DATA_SIZE - files=$GROWTH - if [ $(( $files / $threads )) == 0 ]; - then - runs=0 - parallel_threads=$(( $files % $threads )) - else - runs=$(( $files / $threads )) - parallel_threads=$threads - fi - while [ $runs -ge 0 ]; do - if [ $runs == 0 ]; - then - parallel_threads=$(( $files % $threads )) - seq 0 $(( $parallel_threads - 1 )) | parallel --will-cite -j $parallel_threads --compress dd if=/dev/zero of=/$FILE_SYSTEM_ID/$DATA_DIRECTORY/1G-dd-$(date +%Y%m%d%H%M%S.%3N)-{} bs=1M count=1024 oflag=sync - runs=$(($runs-1)) - else - seq 0 $(( $parallel_threads - 1 )) | parallel --will-cite -j $parallel_threads --compress dd if=/dev/zero of=/$FILE_SYSTEM_ID/$DATA_DIRECTORY/1G-dd-$(date +%Y%m%d%H%M%S.%3N)-{} bs=1M count=1024 oflag=sync - runs=$(($runs-1)) - fi - done - - # set ASG to zero which terminates instance - # aws autoscaling update-auto-scaling-group --auto-scaling-group-name $asg_name --desired-capacity 0 --region $region - mode: 000777 - owner: root - group: root - set-cloudwatch-alarms: - files: - /tmp/set-cloudwatch-alarms.sh: - content: - !Join [ - "",[ - "#!/bin/bash -x\n", - "\n", - "FILE_SYSTEM_ID=$1\n", - "WARNING_THRESHOLD_MINUTES=$2\n", - "CRITICAL_THRESHOLD_MINUTES=$3\n", - "SNS_ARN=$4\n", - "\n", - "error=0\n", - "\n", - "# get region\n", - "availability_zone=$(curl -s http://169.254.169.254/latest/meta-data/placement/availability-zone)\n", - "region=${availability_zone:0:-1}\n", - "\n", - "# get instance id\n", - "instance_id=$(curl -s http://169.254.169.254/latest/meta-data/instance-id)\n", - "\n", - "# get autoscaling group name\n", - "asg_name=$(aws autoscaling describe-auto-scaling-instances --instance-ids ${instance_id} --region ${region} --output text --query 'AutoScalingInstances[0].AutoScalingGroupName')\n", - "\n", - "# get autoscaling policy arn\n", - "asg_policy_arn=$(aws autoscaling describe-policies --auto-scaling-group-name ${asg_name} --region ${region} --output text --query 'ScalingPolicies[0].PolicyARN')\n", - "\n", - "# validate FILE_SYSTEM_ID send notification and exit if doesn't exist\n", - "aws efs describe-file-systems --file-system-id ${FILE_SYSTEM_ID} --region ${region} --output text --query 'FileSystems[0].[FileSystemId]'\n", - "result=$?\n", - "if [ $result -ne 0 ]; then\n", - " aws sns publish --topic-arn ${SNS_ARN} --region ${region} --message 'Amazon EFS burst credit balance CloudWatch alarm error. File system '${FILE_SYSTEM_ID}' does not exist.'\n", - " exit\n", - "fi\n", - "\n", - "# get current permitted throughput\n", - "count=1\n", - "while [ -z ${permitted_throughput} ] || [ ${permitted_throughput} == null ] && [ ${count} -lt 60 ]; do\n", - " permitted_throughput=$(aws cloudwatch get-metric-statistics --namespace AWS/EFS --metric-name PermittedThroughput --dimensions Name=FileSystemId,Value=${FILE_SYSTEM_ID} --start-time $(date --utc +%FT%TZ -d '-120 seconds') --end-time $(date --utc +%FT%TZ -d '-60 seconds') --period 60 --statistics Sum --region ${region} --output json --query 'Datapoints[0].Sum')\n", - " sleep 2\n", - " count=$(expr ${count} + 1)\n", - "done\n", - "\n", - "# get current burst credit balance\n", - "count=1\n", - "while [ -z ${burst_credit_balance} ] || [ ${burst_credit_balance} == null ] && [ ${count} -lt 60 ]; do\n", - " burst_credit_balance=$(aws cloudwatch get-metric-statistics --namespace AWS/EFS --metric-name BurstCreditBalance --dimensions Name=FileSystemId,Value=${FILE_SYSTEM_ID} --start-time $(date --utc +%FT%TZ -d '-120 seconds') --end-time $(date --utc +%FT%TZ -d '-60 seconds') --period 60 --statistics Sum --region ${region} --output json --query 'Datapoints[0].Sum')\n", - " sleep 2\n", - " count=$(expr ${count} + 1)\n", - "done\n", - "\n", - "# calculate new burst credit balance warning threshold\n", - "burst_credit_balance_threshold_warning=$(( ${burst_credit_balance:0:-2} - ( ( ( ${burst_credit_balance:0:-2} / ( ${permitted_throughput:0:-2} * 60 ) ) - $WARNING_THRESHOLD_MINUTES ) * ( ${permitted_throughput:0:-2} * 60 ) ) ))\n", - "\n", - "# calculate new burst credit balance critical threshold\n", - "burst_credit_balance_threshold_critical=$(( ${burst_credit_balance:0:-2} - ( ( ( ${burst_credit_balance:0:-2} / ( ${permitted_throughput:0:-2} * 60 ) ) - $CRITICAL_THRESHOLD_MINUTES ) * ( ${permitted_throughput:0:-2} * 60 ) ) ))\n", - "\n", - "# update warning alarm with new burst credit balance warning threshold\n", - "aws cloudwatch put-metric-alarm --alarm-name ''${FILE_SYSTEM_ID}' burst credit balance - Warning - '", !Ref 'AWS::StackName', " --alarm-description ''${FILE_SYSTEM_ID}' burst credit balance - Warning - '", !Ref 'AWS::StackName', " --actions-enabled --alarm-actions ${SNS_ARN} --metric-name BurstCreditBalance --namespace AWS/EFS --statistic Sum --dimensions Name=FileSystemId,Value=${FILE_SYSTEM_ID} --period 60 --evaluation-periods 5 --threshold ${burst_credit_balance_threshold_warning} --comparison-operator LessThanThreshold --treat-missing-data missing --region ${region}\n", - "result=$?\n", - "if [ $result -ne 0 ]; then\n", - " aws sns publish --topic-arn ${SNS_ARN} --region ${region} --message 'Amazon EFS burst credit balance CloudWatch alarm error. Check CloudWatch alarms for file system '${FILE_SYSTEM_ID}'.'\n", - " error=$(expr ${error} + 1)\n", - "fi\n", - "\n", - "# update critical alarm with new burst credit balance critical threshold\n", - "aws cloudwatch put-metric-alarm --alarm-name ''${FILE_SYSTEM_ID}' burst credit balance - Critical - '", !Ref 'AWS::StackName', " --alarm-description ''${FILE_SYSTEM_ID}' burst credit balance - Critical - '", !Ref 'AWS::StackName', " --actions-enabled --alarm-actions ${SNS_ARN} --metric-name BurstCreditBalance --namespace AWS/EFS --statistic Sum --dimensions Name=FileSystemId,Value=${FILE_SYSTEM_ID} --period 60 --evaluation-periods 5 --threshold ${burst_credit_balance_threshold_critical} --comparison-operator LessThanThreshold --treat-missing-data missing --region ${region}\n", - "result=$?\n", - "if [ $result -ne 0 ]; then\n", - " aws sns publish --topic-arn ${SNS_ARN} --region ${region} --message 'Amazon EFS burst credit balance CloudWatch alarm error. Check CloudWatch alarms for file system '${FILE_SYSTEM_ID}'.'\n", - " error=$(expr ${error} + 1)\n", - "fi\n", - "\n", - "# update burst credit balance increase threshold based\n", - "aws cloudwatch put-metric-alarm --alarm-name 'Set '${FILE_SYSTEM_ID}' burst credit balance increase threshold - '", !Ref 'AWS::StackName', " --alarm-description 'Set '${FILE_SYSTEM_ID}' burst credit balance increase threshold - '", !Ref 'AWS::StackName', " --actions-enabled --alarm-actions ${SNS_ARN} ${asg_policy_arn} --metric-name PermittedThroughput --namespace AWS/EFS --statistic Sum --dimensions Name=FileSystemId,Value=${FILE_SYSTEM_ID} --period 60 --evaluation-periods 5 --threshold ${permitted_throughput:0:-2} --comparison-operator GreaterThanThreshold --treat-missing-data missing --region ${region}\n", - "result=$?\n", - "if [ $result -ne 0 ]; then\n", - " aws sns publish --topic-arn ${SNS_ARN} --region ${region} --message 'Amazon EFS burst credit balance CloudWatch alarm error. Check CloudWatch alarms for file system '${FILE_SYSTEM_ID}'.'\n", - " error=$(expr ${error} + 1)\n", - "fi\n", - "\n", - "# update burst credit balance decrease threshold based\n", - "aws cloudwatch put-metric-alarm --alarm-name 'Set '${FILE_SYSTEM_ID}' burst credit balance decrease threshold - '", !Ref 'AWS::StackName', " --alarm-description 'Set '${FILE_SYSTEM_ID}' burst credit balance decrease threshold - '", !Ref 'AWS::StackName', " --actions-enabled --alarm-actions ${SNS_ARN} ${asg_policy_arn} --metric-name PermittedThroughput --namespace AWS/EFS --statistic Sum --dimensions Name=FileSystemId,Value=${FILE_SYSTEM_ID} --period 60 --evaluation-periods 5 --threshold ${permitted_throughput:0:-2} --comparison-operator LessThanThreshold --treat-missing-data missing --region ${region}\n", - "result=$?\n", - "if [ $result -ne 0 ]; then\n", - " aws sns publish --topic-arn ${SNS_ARN} --region ${region} --message 'Amazon EFS burst credit balance CloudWatch alarm error. Check CloudWatch alarms for file system '${FILE_SYSTEM_ID}'.'\n", - " error=$(expr ${error} + 1)\n", - "fi\n", - "\n", - "# auto terminate instance - setting auto scaling group desired capacity 0\n", - "if [ $error -eq 0 ]; then\n", - " aws autoscaling update-auto-scaling-group --auto-scaling-group-name ${asg_name} --desired-capacity 0 --region ${region}\n", - " else\n", - " aws sns publish --topic-arn ${SNS_ARN} --region ${region} --message 'Amazon EFS burst credit balance CloudWatch alarm error. Check CloudWatch alarms for file system '${FILE_SYSTEM_ID}'.'\n", - "fi\n", - "\n" - ] - ] - mode: 000777 - owner: root - group: root - Properties: - LaunchTemplateData: - BlockDeviceMappings: - - DeviceName: /dev/xvda - Ebs: - DeleteOnTermination: true - VolumeSize: 10 - VolumeType: gp3 - IamInstanceProfile: - Arn: !GetAtt InstanceProfile.Arn - ImageId: !If [UsingGraviton2Ami, !Ref LatestArmAmiId, !Ref LatestAmiId] - Monitoring: - Enabled: true - InstanceType: !Ref InstanceType - KeyName: !Ref EC2KeyName - SecurityGroupIds: - - !Ref SecurityGroup - UserData: - "Fn::Base64": - !Sub | - #!/bin/bash -xe - sudo systemctl enable amazon-ssm-agent - sudo systemctl start amazon-ssm-agent - sudo systemctl status amazon-ssm-agent - - yum install -y https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm - yum-config-manager --enable epel - yum install -y parallel - /opt/aws/bin/cfn-init --configsets set_cloudwatch_alarms --verbose --stack ${AWS::StackName} --resource LaunchTemplate --region ${AWS::Region} - /opt/aws/bin/cfn-init --configsets efs_add_storage --verbose --stack ${AWS::StackName} --resource LaunchTemplate --region ${AWS::Region} - /tmp/efs-add-storage.sh ${ElasticFileSystem} throughput_data ${Growth} - /tmp/set-cloudwatch-alarms.sh ${ElasticFileSystem} ${WarningThreshold} ${CriticalThreshold} ${SNSTopic} - /opt/aws/bin/cfn-signal -e $? --stack ${AWS::StackName} --resource AutoScalingGroup --region ${AWS::Region} - - EfsSizeMonitorFunction: - DependsOn: LambdaRole - Type: AWS::Lambda::Function - Properties: - Code: - ZipFile: !Sub | - import boto3 - import os - import sys - - def handler(event, context): - if not os.environ.get('filesystemid'): - print "Unable to get the environment variable filesystemid" - sys.exit(1) - else: - filesystemid = os.environ.get('filesystemid') - - if not os.environ.get('region'): - print "Unable to get the environment variable region" - sys.exit(1) - else: - region = os.environ.get('region') - - def efs_get_size(): - client = boto3.client('efs') - response = client.describe_file_systems(FileSystemId=filesystemid) - k = response['FileSystems'][0]['SizeInBytes']['Value'] - return k - - def cloudwatch_put_metric(): - client = boto3.client('cloudwatch') - client.put_metric_data( - MetricData=[ - { - 'MetricName': 'SizeInBytes', - 'Dimensions': [ - { - 'Name': 'FileSystemId', - 'Value': filesystemid - }, - ], - 'Unit': 'None', - 'Value': efs_get_size() - }, - ], - Namespace='Custom/EFS' - ) - print('CloudWatch metric SizeInBytes sucessfully updated.') - - cloudwatch_put_metric() - Description: Lambda function to update the SizeInBytes EFS CloudWatch metric - Environment: - Variables: - filesystemid: !Ref ElasticFileSystem - region: !Ref 'AWS::Region' - FunctionName: !Join [ '', [ 'efs-', !Ref ElasticFileSystem, '-size-monitor' ] ] - Handler: index.handler - Role: !GetAtt LambdaRole.Arn - Runtime: python3.9 - Timeout: 60 - - LambdaRole: - Type: AWS::IAM::Role - Properties: - AssumeRolePolicyDocument: - Version: 2012-10-17 - Statement: - - Effect: Allow - Principal: - Service: - - lambda.amazonaws.com - Action: - - sts:AssumeRole - Path: / - ManagedPolicyArns: - - arn:aws:iam::aws:policy/CloudWatchFullAccess - - arn:aws:iam::aws:policy/AmazonElasticFileSystemReadOnlyAccess - # EfsLambdaPermission: - # Type: AWS::Lambda::Permission - # Properties: - # FunctionName: !Ref EfsSizeMonitorFunction - # Action: lambda:InvokeFunction - # Principal: events.amazonaws.com - # SourceArn: !GetAtt EfsSizeMonitorEvent.Arn - # EfsSizeMonitorEvent: - # Type: AWS::Events::Rule - # Properties: - # Description: Scheduled event to update SizeInBytes EFS CloudWatch metric - # Name: !Join [ '', [ 'efs-', !Ref ElasticFileSystem, '-size-monitor-scheduled-event' ] ] - # ScheduleExpression: rate(1 minute) - # State: ENABLED - # Targets: - # - Arn: !GetAtt EfsSizeMonitorFunction.Arn - # Id: '1' - - SNSTopic: - Type: AWS::SNS::Topic - Properties: - DisplayName: !Join [ '', [ !Ref ElasticFileSystem, '-alarm-notification' ] ] - Subscription: - - Endpoint: !Ref EmailAddress - Protocol: "email" - TopicName: !Join [ '', [ !Ref ElasticFileSystem, '-alarm-notification' ] ] - - WarningAlarm: - Type: AWS::CloudWatch::Alarm - Properties: - AlarmActions: - - !Ref SNSTopic - AlarmDescription: !Join [ '', [ !Ref ElasticFileSystem, ' burst credit balance - Warning - ', !Ref 'AWS::StackName' ] ] - AlarmName: !Join [ '', [ !Ref ElasticFileSystem, ' burst credit balance - Warning - ', !Ref 'AWS::StackName' ] ] - ComparisonOperator: LessThanThreshold - Dimensions: - - Name: FileSystemId - Value: !Ref ElasticFileSystem - EvaluationPeriods: 10 - MetricName: BurstCreditBalance - Namespace: AWS/EFS - Period: 60 - Statistic: Sum - Threshold: 0 - TreatMissingData: missing - diff --git a/templates/04-web.yaml b/templates/04-web.yaml index cbb7422..8d99b0f 100644 --- a/templates/04-web.yaml +++ b/templates/04-web.yaml @@ -1,17 +1,10 @@ --- AWSTemplateFormatVersion: 2010-09-09 +Description: Moodle web instances -Description: Reference Architecture to host Moodle on AWS - Creates Moodle web Auto Scaling group - Parameters: - RDSInstanceSecretArn: Type: String - EC2KeyName: - AllowedPattern: ^([a-zA-Z0-9 @.`~!#$%^&*()_+,\\-])*$ - ConstraintDescription: Must be letters (upper or lower), numbers, and special characters. - Description: Name of an EC2 KeyPair. Your bastion & Web instances will launch with this KeyPair. - Type: AWS::EC2::KeyPair::KeyName NumberOfSubnets: AllowedValues: - 1 @@ -116,7 +109,15 @@ Parameters: - m6g.8xlarge - m6g.12xlarge - m6g.16xlarge - - m6g.24xlarge + - m6g.24xlarge + - m7g.medium + - m7g.large + - m7g.xlarge + - m7g.2xlarge + - m7g.4xlarge + - m7g.8xlarge + - m7g.12xlarge + - m7g.16xlarge - c6g.large - c6g.xlarge - c6g.2xlarge @@ -133,8 +134,16 @@ Parameters: - r6g.12xlarge - r6g.16xlarge - r6g.24xlarge + - c7g.medium + - c7g.large + - c7g.xlarge + - c7g.2xlarge + - c7g.4xlarge + - c7g.8xlarge + - c7g.12xlarge + - c7g.16xlarge ConstraintDescription: Must be a valid Amazon EC2 instance type. - Default: m6g.large + Default: c7g.xlarge Description: The Amazon EC2 instance type for your web instances. Type: String WebSecurityGroup: @@ -156,25 +165,17 @@ Parameters: Type: String Conditions: - NumberOfSubnets1: - !Equals [ 1, !Ref NumberOfSubnets ] - NumberOfSubnets2: - !Equals [ 2, !Ref NumberOfSubnets ] - NumberOfSubnets3: - !Equals [ 3, !Ref NumberOfSubnets ] - Subnet0: !Or - - !Condition NumberOfSubnets1 - - !Condition NumberOfSubnets2 - - !Condition NumberOfSubnets3 - Subnet1: !Or - - !Condition NumberOfSubnets2 - - !Condition NumberOfSubnets3 - Subnet2: !Condition NumberOfSubnets3 + NumberOfSubnets1: !Equals [ 1, !Ref NumberOfSubnets ] + NumberOfSubnets2: !Equals [ 2, !Ref NumberOfSubnets ] + NumberOfSubnets3: !Equals [ 3, !Ref NumberOfSubnets ] UsingGraviton2Ami: !Or - !Equals ["t4",!Select [0, !Split [ "g.", !Ref WebInstanceType]]] - !Equals ["c6",!Select [0, !Split [ "g.", !Ref WebInstanceType]]] + - !Equals ["c7",!Select [0, !Split [ "g.", !Ref WebInstanceType]]] - !Equals ["m6",!Select [0, !Split [ "g.", !Ref WebInstanceType]]] + - !Equals ["m7",!Select [0, !Split [ "g.", !Ref WebInstanceType]]] - !Equals ["r6",!Select [0, !Split [ "g.", !Ref WebInstanceType]]] + - !Equals ["r7",!Select [0, !Split [ "g.", !Ref WebInstanceType]]] Resources: WebInstanceProfile: @@ -183,6 +184,7 @@ Resources: Path: / Roles: - !Ref WebInstanceRole + WebInstanceRole: Type: AWS::IAM::Role Properties: @@ -206,19 +208,18 @@ Resources: Statement: - Effect: Allow Action: - - logs:CreateLogGroup - logs:CreateLogStream - logs:PutLogEvents - logs:DescribeLogStreams Resource: - - arn:aws:logs:*:*:* + - !GetAtt Logs.Arn - Effect: Allow Action: - autoscaling:CompleteLifecycleAction - autoscaling:DescribeAutoScalingInstances - autoscaling:DescribeLifecycleHooks Resource: - - arn:aws:autoscaling:*:*:* + - "*" - Effect: Allow Action: - secretsmanager:GetSecretValue @@ -226,7 +227,9 @@ Resources: - !Ref RDSInstanceSecretArn - Effect: Allow Action: - - s3:* + - s3:GetObject + - s3:ListBucket + - s3:GetBucketLocation Resource: - !Ref CodeArtifactS3BucketArn - !Join [ '', [ !Ref CodeArtifactS3BucketArn,'/*' ] ] @@ -239,7 +242,7 @@ Resources: Logs: Type: AWS::Logs::LogGroup - DeletionPolicy: Retain + DeletionPolicy: Delete Properties: RetentionInDays: 7 @@ -587,7 +590,6 @@ Resources: InstanceType: !Ref WebInstanceType Monitoring: Enabled: true - KeyName: !Ref EC2KeyName SecurityGroupIds: - !Ref WebSecurityGroup UserData: diff --git a/templates/05-codepipeline.yaml b/templates/05-codepipeline.yaml index 22f3af4..fea1dd0 100644 --- a/templates/05-codepipeline.yaml +++ b/templates/05-codepipeline.yaml @@ -1,3 +1,7 @@ +--- +AWSTemplateFormatVersion: 2010-09-09 +Description: Moodle deployment pipeline + Parameters: CodeCommitRepoName: Type: "String" @@ -9,7 +13,7 @@ Parameters: BranchName: Type: "String" Default: "main" - Description: repository's branch name + Description: Repository branch name AppAutoScalingGroupName: Type: "String" Description: Name of Autoscaling group for Moodle Web app. @@ -29,8 +33,6 @@ Parameters: Type: String Resources: - # AWS CodePipeline to deploy source code from CodeCommit repo to autoscaling groups for Moodle Web apps. - # This role is assumed by the CodePipeline service itself. MoodleCodeDeployServiceRole: Type: AWS::IAM::Role @@ -54,7 +56,6 @@ Resources: Statement: - Effect: Allow Action: - - iam:PassRole - ec2:CreateTags - ec2:RunInstances Resource: @@ -66,11 +67,10 @@ Resources: ApplicationName: !Sub '${ProjectName}-DeployApp' MoodleDeploymentGroup: - Type: 'AWS::CodeDeploy::DeploymentGroup' + Type: AWS::CodeDeploy::DeploymentGroup DependsOn: MoodleDeployApp Properties: ApplicationName: !Ref MoodleDeployApp - DeploymentGroupName: !Sub '${ProjectName}-AppDG' ServiceRoleArn: !GetAtt MoodleCodeDeployServiceRole.Arn DeploymentStyle: DeploymentOption: BLUE_GREEN #IN_PLACE @@ -90,7 +90,6 @@ Resources: Description: SSM Parameter for Moodle WebApp Auto scaling group #This role is for Moodle pipeline to perform ci-cd tasks. - # !TODO to limit this role from full access. MoodlePipelineRole: Type: AWS::IAM::Role Properties: @@ -104,6 +103,7 @@ Resources: Action: sts:AssumeRole ManagedPolicyArns: - 'arn:aws:iam::aws:policy/AWSCodePipeline_FullAccess' + - 'arn:aws:iam::aws:policy/AWSCodeDeployDeployerAccess' Path: / Policies: - PolicyName: MoodlePipelineCustomPolicy @@ -112,7 +112,14 @@ Resources: Statement: - Effect: Allow Action: - - codedeploy:* + - codedeploy:CreateDeployment + - codedeploy:CreateDeployment* + - codedeploy:StopDeployment + - codedeploy:Update* + - codedeploy:RegisterApplicationRevision + - codedeploy:Get* + - codedeploy:List* + - codedeploy:PutLifecycleEventHookExecutionStatus Resource: - arn:aws:codedeploy:*:*:application:* - arn:aws:codedeploy:*:*:deploymentgroup:*/* @@ -120,15 +127,25 @@ Resources: - arn:aws:codedeploy:*:*:deploymentconfig:* - Effect: Allow Action: - - s3:* + - s3:GetObject + - s3:ListBucket + - s3:GetBucketLocation + - s3:PutObject Resource: - !Ref CodeArtifactS3BucketArn - !Join [ '', [ !Ref CodeArtifactS3BucketArn,'/*' ] ] - Effect: Allow Action: - - codecommit:* + - codecommit:GetRepository + - codecommit:ListBranches + - codecommit:GitPull + - codecommit:GetBranch + - codecommit:GetCommit + - codecommit:UploadArchive + - codecommit:GetUploadArchiveStatus Resource: - !Ref CodeCommitRepoArn + - !Join [ '', [ !Ref CodeCommitRepoArn,'/*' ] ] # The CI/CD pipeline stitching the full mechanism together MoodleAppPipeline: @@ -173,4 +190,4 @@ Resources: ArtifactStore: Location: !Ref CodeArtifactS3BucketName Type: S3 - \ No newline at end of file + diff --git a/templates/05-route53.yaml b/templates/05-route53.yaml index ff5db23..bed2126 100644 --- a/templates/05-route53.yaml +++ b/templates/05-route53.yaml @@ -1,31 +1,8 @@ --- AWSTemplateFormatVersion: 2010-09-09 - -Description: Reference Architecture to host Moodle on AWS - Creates Route 53 record set (if selected) - -Metadata: - - AWS::CloudFormation::Interface: - ParameterGroups: - - Label: - default: Route 53 Parameters - Parameters: - - DomainName - - HostedZoneName - - DnsEndpoint - - DnsHostId - ParameterLabels: - DnsEndpoint: - default: DNS Endpoint - DnsHostId: - default: DNS Host Id - DomainName: - default: Domain Name of the Moodle site - HostedZoneName: - default: Hosted Zone Name +Description: Moodle DNS using Route 53 Parameters: - DnsEndpoint: AllowedPattern: ^(?!http)(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9\-]*[A-Za-z0-9])$ Description: The DNS endpoint - CloudFront DNS if using CloudFront else Public ALB DNS name. @@ -44,7 +21,6 @@ Parameters: Type: String Resources: - RecordSet: Type: AWS::Route53::RecordSetGroup Properties: @@ -55,4 +31,4 @@ Resources: AliasTarget: DNSName: !Ref DnsEndpoint EvaluateTargetHealth: True - HostedZoneId: !Ref DnsHostId \ No newline at end of file + HostedZoneId: !Ref DnsHostId