diff --git a/.gitignore b/.gitignore index b402f4af..d85551bf 100644 --- a/.gitignore +++ b/.gitignore @@ -3,4 +3,5 @@ .vscode/ .env .venv +params.yml diff --git a/APIGateway/apigateway_lambda_integration.json b/APIGateway/apigateway_lambda_integration.json index ab312075..7ec674f3 100644 --- a/APIGateway/apigateway_lambda_integration.json +++ b/APIGateway/apigateway_lambda_integration.json @@ -1,291 +1,265 @@ { - "AWSTemplateFormatVersion": "2010-09-09", - "Parameters": { - "ApiType": { - "Description": "The Endpoint type for RESTApi", - "Type": "String", - "Default": "REGIONAL", - "AllowedValues": [ - "EDGE", - "REGIONAL", - "PRIVATE" - ] - }, - "ApigatewayTimeout": { - "Description": "ApiGateway Backend Integration timeout in milliseconds", - "Type": "Number", - "Default": "29000", - "MinValue": "50", - "MaxValue": "29000" - }, - "LambdaFunctionName": { - "Description": "The Name for the Lambda Function", - "Type": "String", - "Default": "My-Function" - } - }, - "Resources": { - "RestApi": { - "Type": "AWS::ApiGateway::RestApi", - "Properties": { - "Description": "My Rest API", - "Name": "MyApi", - "EndpointConfiguration": { - "Types": [ - { - "Ref": "ApiType" - } - ] - } - } - }, - "ApiResource": { - "Type": "AWS::ApiGateway::Resource", - "Properties": { - "ParentId": { - "Fn::GetAtt": [ - "RestApi", - "RootResourceId" - ] - }, - "RestApiId": { - "Ref": "RestApi" + "AWSTemplateFormatVersion": "2010-09-09", + "Parameters": { + "ApiType": { + "Description": "The Endpoint type for RESTApi", + "Type": "String", + "AllowedValues": [ + "EDGE", + "REGIONAL", + "PRIVATE" + ], + "Default": "REGIONAL" }, - "PathPart": "{city}" - } - }, - "RequestModel": { - "Type": "AWS::ApiGateway::Model", - "Properties": { - "ContentType": "application/json", - "Name": "MyModel", - "RestApiId": { - "Ref": "RestApi" + "ApigatewayTimeout": { + "Description": "ApiGateway Backend Integration timeout in milliseconds", + "Type": "Number", + "Default": "29000", + "MinValue": "50", + "MaxValue": "29000" }, - "Schema": { - "$schema": "http://json-schema.org/draft-04/schema#", - "title": "MyModel", - "type": "object", - "properties": { - "callerName": { - "type": "string" - } - } + "LambdaFunctionName": { + "Description": "The Name for the Lambda Function", + "Type": "String", + "Default": "My-APIGW-Integ-Function" } - } }, - "ApiMethod": { - "Type": "AWS::ApiGateway::Method", - "Properties": { - "HttpMethod": "ANY", - "AuthorizationType": "NONE", - "RequestParameters": { - "method.request.path.city": "true", - "method.request.querystring.time": "true", - "method.request.header.day": "true" + "Resources": { + "RestApi": { + "Type": "AWS::ApiGateway::RestApi", + "Properties": { + "Description": "My Rest API", + "Name": "MyApi", + "EndpointConfiguration": { + "Types": [ + { + "Ref": "ApiType" + } + ] + } + } }, - "MethodResponses": [ - { - "StatusCode": "200" - } - ], - "Integration": { - "IntegrationHttpMethod": "POST", - "Type": "AWS", - "TimeoutInMillis": { - "Ref": "ApigatewayTimeout" - }, - "Uri": { - "Fn::Join": [ - "", - [ - "arn:", - { - "Ref": "AWS::Partition" - }, - ":apigateway:", - { - "Ref": "AWS::Region" + "ApiResource": { + "Type": "AWS::ApiGateway::Resource", + "Properties": { + "ParentId": { + "Fn::GetAtt": [ + "RestApi", + "RootResourceId" + ] }, - ":lambda:path/2015-03-31/functions/", - { - "Fn::GetAtt": [ - "LambdaFunction", - "Arn" - ] + "RestApiId": { + "Ref": "RestApi" }, - "/invocations" - ] - ] - }, - "RequestTemplates": { - "application/json": { - "Fn::Join": [ - "", - [ - "\n #set($inputRoot = $input.path('$'))", - "\n{", - "\n \"city\": \"$input.params('city')\",", - "\n \"time\": \"$input.params('time')\",", - "\n \"day\": \"$input.params('day')\",", - "\n \"name\": \"$inputRoot.callerName\"", - "\n}" - ] - ] + "PathPart": "{city}" } - }, - "IntegrationResponses": [ - { - "StatusCode": "200" - } - ] - }, - "ResourceId": { - "Ref": "ApiResource" }, - "RestApiId": { - "Ref": "RestApi" + "RequestModel": { + "Type": "AWS::ApiGateway::Model", + "Properties": { + "ContentType": "application/json", + "Name": "MyModel", + "RestApiId": { + "Ref": "RestApi" + }, + "Schema": { + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "MyModel", + "type": "object", + "properties": { + "callerName": { + "type": "string" + } + } + } + } }, - "RequestModels": { - "application/json": { - "Ref": "RequestModel" - } - } - } - }, - "LambdaFunction": { - "Type": "AWS::Lambda::Function", - "Properties": { - "Code": { - "ZipFile": { - "Fn::Join": [ - "\n", - [ - "import json", - "days = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday']", - "times = ['morning', 'afternoon', 'evening', 'night', 'day']", - "def lambda_handler(event, context):", - " name = event.get(\"name\", \"you\")", - " city = event.get(\"city\", \"world\")", - " try:", - " if (times.index(event.get(\"time\", \"None\"))) >-1:", - " time = event.get(\"time\")", - " except ValueError:", - " time = \"day\"", - " try:", - " if (days.index(event.get(\"day\",\"None\"))) >-1:", - " day = event['day']", - " except ValueError:", - " day = None", - " greetings = \"Good {time}, {name} of {city}. \".format(time=time, name=name, city=city)", - " if day:", - " greetings += \"Happy {}\".format(day)", - " return {", - " 'statusCode': 200,", - " 'body': json.dumps(greetings)", - " }" - ] - ] - } + "ApiMethod": { + "Type": "AWS::ApiGateway::Method", + "Properties": { + "HttpMethod": "ANY", + "AuthorizationType": "NONE", + "RequestParameters": { + "method.request.path.city": "true", + "method.request.querystring.time": "true", + "method.request.header.day": "true" + }, + "MethodResponses": [ + { + "StatusCode": "200" + } + ], + "Integration": { + "IntegrationHttpMethod": "POST", + "Type": "AWS", + "TimeoutInMillis": { + "Ref": "ApigatewayTimeout" + }, + "Uri": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":apigateway:", + { + "Ref": "AWS::Region" + }, + ":lambda:path/2015-03-31/functions/", + { + "Fn::GetAtt": [ + "LambdaFunction", + "Arn" + ] + }, + "/invocations" + ] + ] + }, + "RequestTemplates": { + "application/json": "#set($inputRoot = $input.path('$'))\n {\n \"city\": \"$input.params('city')\",\n \"time\": \"$input.params('time')\",\n \"day\": \"$input.params('day')\",\n \"name\": \"$inputRoot.callerName\"\n }\n" + }, + "IntegrationResponses": [ + { + "StatusCode": "200" + } + ] + }, + "ResourceId": { + "Ref": "ApiResource" + }, + "RestApiId": { + "Ref": "RestApi" + }, + "RequestModels": { + "application/json": { + "Ref": "RequestModel" + } + } + } }, - "Handler": "index.lambda_handler", - "FunctionName": { - "Ref": "LambdaFunctionName" + "LambdaFunction": { + "Type": "AWS::Lambda::Function", + "Metadata": { + "cfn-lint": { + "config": { + "ignore_checks": [ + "E3012" + ] + } + }, + "guard": { + "SuppressedRules": [ + "LAMBDA_INSIDE_VPC" + ] + } + }, + "Properties": { + "Code": { + "ZipFile": { + "Rain::Embed": "handler.py" + } + }, + "Handler": "index.lambda_handler", + "FunctionName": { + "Ref": "LambdaFunctionName" + }, + "MemorySize": "128", + "Runtime": "python3.12", + "Timeout": "10", + "Role": { + "Fn::GetAtt": [ + "LambdaIamRole", + "Arn" + ] + } + } }, - "MemorySize": "128", - "Runtime": "python3.8", - "Timeout": "10", - "Role": { - "Fn::GetAtt": [ - "LambdaIamRole", - "Arn" - ] - } - } - }, - "LambdaIamRole": { - "Type": "AWS::IAM::Role", - "Properties": { - "AssumeRolePolicyDocument": { - "Version": "2012-10-17", - "Statement": [ - { - "Effect": "Allow", - "Principal": { - "Service": [ - "lambda.amazonaws.com" + "LambdaIamRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Effect": "Allow", + "Principal": { + "Service": [ + "lambda.amazonaws.com" + ] + }, + "Action": [ + "sts:AssumeRole" + ] + } + ] + }, + "RoleName": "LambdaRole", + "Policies": [ + { + "PolicyName": "LambdaApipolicy", + "PolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Effect": "Allow", + "Action": [ + "logs:CreateLogGroup" + ], + "Resource": { + "Fn::Sub": "arn:${AWS::Partition}:logs:${AWS::Region}:${AWS::AccountId}:*" + } + }, + { + "Effect": "Allow", + "Action": [ + "logs:CreateLogStream", + "logs:PutLogEvents" + ], + "Resource": { + "Fn::Sub": "arn:${AWS::Partition}:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/lambda/${LambdaFunctionName}:*" + } + } + ] + } + } ] - }, - "Action": [ - "sts:AssumeRole" - ] } - ] }, - "RoleName": "LambdaRole", - "Policies": [ - { - "PolicyName": "LambdaApipolicy", - "PolicyDocument": { - "Version": "2012-10-17", - "Statement": [ - { - "Effect": "Allow", - "Action": [ - "logs:CreateLogGroup" - ], - "Resource": { - "Fn::Sub": "arn:${AWS::Partition}:logs:${AWS::Region}:${AWS::AccountId}:*" - } + "LambdaApiGatewayInvoke": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "Action": "lambda:InvokeFunction", + "FunctionName": { + "Fn::GetAtt": [ + "LambdaFunction", + "Arn" + ] }, - { - "Effect": "Allow", - "Action": [ - "logs:CreateLogStream", - "logs:PutLogEvents" - ], - "Resource": { - "Fn::Sub": "arn:${AWS::Partition}:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/lambda/${LambdaFunctionName}:*" - } + "Principal": "apigateway.amazonaws.com", + "SourceArn": { + "Fn::Join": [ + "", + [ + "arn:aws:execute-api:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":", + { + "Ref": "RestApi" + }, + "/*/*/*" + ] + ] } - ] } - } - ] - } - }, - "LambdaApiGatewayInvoke": { - "Type": "AWS::Lambda::Permission", - "Properties": { - "Action": "lambda:InvokeFunction", - "FunctionName": { - "Fn::GetAtt": [ - "LambdaFunction", - "Arn" - ] - }, - "Principal": "apigateway.amazonaws.com", - "SourceArn": { - "Fn::Join": [ - "", - [ - "arn:aws:execute-api:", - { - "Ref": "AWS::Region" - }, - ":", - { - "Ref": "AWS::AccountId" - }, - ":", - { - "Ref": "RestApi" - }, - "/*/*/*" - ] - ] } - } } - } } diff --git a/APIGateway/apigateway_lambda_integration.yaml b/APIGateway/apigateway_lambda_integration.yaml new file mode 100644 index 00000000..4d4185aa --- /dev/null +++ b/APIGateway/apigateway_lambda_integration.yaml @@ -0,0 +1,158 @@ +AWSTemplateFormatVersion: "2010-09-09" + +Parameters: + ApiType: + Description: The Endpoint type for RESTApi + Type: String + AllowedValues: + - EDGE + - REGIONAL + - PRIVATE + Default: REGIONAL + + ApigatewayTimeout: + Description: ApiGateway Backend Integration timeout in milliseconds + Type: Number + Default: "29000" + MinValue: "50" + MaxValue: "29000" + + LambdaFunctionName: + Description: The Name for the Lambda Function + Type: String + Default: My-APIGW-Integ-Function + +Resources: + RestApi: + Type: AWS::ApiGateway::RestApi + Properties: + Description: My Rest API + Name: MyApi + EndpointConfiguration: + Types: + - !Ref ApiType + + ApiResource: + Type: AWS::ApiGateway::Resource + Properties: + ParentId: !GetAtt RestApi.RootResourceId + RestApiId: !Ref RestApi + PathPart: '{city}' + + RequestModel: + Type: AWS::ApiGateway::Model + Properties: + ContentType: application/json + Name: MyModel + RestApiId: !Ref RestApi + Schema: + $schema: http://json-schema.org/draft-04/schema# + title: MyModel + type: object + properties: + callerName: + type: string + + ApiMethod: + Type: AWS::ApiGateway::Method + Properties: + HttpMethod: ANY + AuthorizationType: NONE + RequestParameters: + method.request.path.city: "true" + method.request.querystring.time: "true" + method.request.header.day: "true" + MethodResponses: + - StatusCode: "200" + Integration: + IntegrationHttpMethod: POST + Type: AWS + TimeoutInMillis: !Ref ApigatewayTimeout + Uri: !Join + - "" + - - 'arn:' + - !Ref AWS::Partition + - ':apigateway:' + - !Ref AWS::Region + - :lambda:path/2015-03-31/functions/ + - !GetAtt LambdaFunction.Arn + - /invocations + RequestTemplates: + application/json: | + #set($inputRoot = $input.path('$')) + { + "city": "$input.params('city')", + "time": "$input.params('time')", + "day": "$input.params('day')", + "name": "$inputRoot.callerName" + } + IntegrationResponses: + - StatusCode: "200" + ResourceId: !Ref ApiResource + RestApiId: !Ref RestApi + RequestModels: + application/json: !Ref RequestModel + + LambdaFunction: + Type: AWS::Lambda::Function + Metadata: + cfn-lint: + config: + ignore_checks: + - E3012 + guard: + SuppressedRules: + - LAMBDA_INSIDE_VPC + Properties: + Code: + ZipFile: !Rain::Embed handler.py + Handler: index.lambda_handler + FunctionName: !Ref LambdaFunctionName + MemorySize: "128" + Runtime: python3.12 + Timeout: "10" + Role: !GetAtt LambdaIamRole.Arn + + LambdaIamRole: + Type: AWS::IAM::Role + Properties: + AssumeRolePolicyDocument: + Version: "2012-10-17" + Statement: + - Effect: Allow + Principal: + Service: + - lambda.amazonaws.com + Action: + - sts:AssumeRole + RoleName: LambdaRole + Policies: + - PolicyName: LambdaApipolicy + PolicyDocument: + Version: "2012-10-17" + Statement: + - Effect: Allow + Action: + - logs:CreateLogGroup + Resource: !Sub arn:${AWS::Partition}:logs:${AWS::Region}:${AWS::AccountId}:* + - Effect: Allow + Action: + - logs:CreateLogStream + - logs:PutLogEvents + Resource: !Sub arn:${AWS::Partition}:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/lambda/${LambdaFunctionName}:* + + LambdaApiGatewayInvoke: + Type: AWS::Lambda::Permission + Properties: + Action: lambda:InvokeFunction + FunctionName: !GetAtt LambdaFunction.Arn + Principal: apigateway.amazonaws.com + SourceArn: !Join + - "" + - - 'arn:aws:execute-api:' + - !Ref AWS::Region + - ':' + - !Ref AWS::AccountId + - ':' + - !Ref RestApi + - /*/*/* diff --git a/APIGateway/handler.py b/APIGateway/handler.py new file mode 100644 index 00000000..64fb689f --- /dev/null +++ b/APIGateway/handler.py @@ -0,0 +1,30 @@ +"""Generate a greeting as a demo of an API""" + +import json + +DAYS = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'] +TIMES = ['morning', 'afternoon', 'evening', 'night', 'day'] + + +def lambda_handler(event, _): + """ + Lambda handler + """ + name = event.get("name", "you") + city = event.get("city", "world") + time = event.get("time", "day") + day = event.get("day", None) + + if time not in TIMES: + time = "day" + if day and day not in DAYS: + day = None + + greetings = f"Good {time}, {name} of {city}." + if day: + greetings += f" Happy {day}" + + return { + 'statusCode': 200, + 'body': json.dumps(greetings) + } diff --git a/AutoScaling/AutoScalingMultiAZWithNotifications.json b/AutoScaling/AutoScalingMultiAZWithNotifications.json index 9edcc8bd..6d521c1c 100644 --- a/AutoScaling/AutoScalingMultiAZWithNotifications.json +++ b/AutoScaling/AutoScalingMultiAZWithNotifications.json @@ -1,69 +1,11 @@ { "AWSTemplateFormatVersion": "2010-09-09", "Description": "AWS CloudFormation Sample Template AutoScalingMultiAZWithNotifications: Create a multi-az, load balanced and Auto Scaled sample web site running on an Apache Web Server. The application is configured to span all Availability Zones in the region and is Auto-Scaled based on the CPU utilization of the web servers. Notifications will be sent to the operator email address on scaling events. The instances are load balanced with a simple health check against the default web page. **WARNING** This template creates one or more Amazon EC2 instances and an Elastic Load Balancer. You will be billed for the AWS resources used if you create a stack from this template.", - "Metadata": { - "License": "Apache-2.0" - }, "Parameters": { "InstanceType": { "Description": "WebServer EC2 instance type", "Type": "String", - "AllowedValues": [ - "t1.micro", - "t2.nano", - "t2.micro", - "t2.small", - "t2.medium", - "t2.large", - "m1.small", - "m1.medium", - "m1.large", - "m1.xlarge", - "m2.xlarge", - "m2.2xlarge", - "m2.4xlarge", - "m3.medium", - "m3.large", - "m3.xlarge", - "m3.2xlarge", - "m4.large", - "m4.xlarge", - "m4.2xlarge", - "m4.4xlarge", - "m4.10xlarge", - "c1.medium", - "c1.xlarge", - "c3.large", - "c3.xlarge", - "c3.2xlarge", - "c3.4xlarge", - "c3.8xlarge", - "c4.large", - "c4.xlarge", - "c4.2xlarge", - "c4.4xlarge", - "c4.8xlarge", - "g2.2xlarge", - "g2.8xlarge", - "r3.large", - "r3.xlarge", - "r3.2xlarge", - "r3.4xlarge", - "r3.8xlarge", - "i2.xlarge", - "i2.2xlarge", - "i2.4xlarge", - "i2.8xlarge", - "d2.xlarge", - "d2.2xlarge", - "d2.4xlarge", - "d2.8xlarge", - "hs1.8xlarge", - "cr1.8xlarge", - "cc2.8xlarge" - ], - "Default": "t2.small", - "ConstraintDescription": "must be a valid EC2 instance type." + "Default": "t2.micro" }, "OperatorEMail": { "Description": "EMail address to notify if there are any scaling operations", @@ -84,6 +26,26 @@ "MaxLength": 18, "AllowedPattern": "(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})/(\\d{1,2})", "ConstraintDescription": "must be a valid IP CIDR range of the form x.x.x.x/x." + }, + "LatestAmiId": { + "Type": "AWS::SSM::Parameter::Value", + "Default": "/aws/service/ami-amazon-linux-latest/al2023-ami-kernel-6.1-arm64" + }, + "KmsKeyArn": { + "Description": "KMS Key ARN to encrypt data", + "Type": "String" + }, + "CertificateArn": { + "Description": "Certificate ARN for HTTPS", + "Type": "String" + }, + "SecurityGroups": { + "Description": "Security Groups to be used", + "Type": "List" + }, + "Subnets": { + "Description": "Subnets to be used", + "Type": "List" } }, "Mappings": { @@ -127,240 +89,15 @@ "cn-north-1": { "Examples": "https://s3.cn-north-1.amazonaws.com.cn/cloudformation-examples-cn-north-1" } - }, - "AWSInstanceType2Arch": { - "t1.micro": { - "Arch": "PV64" - }, - "t2.nano": { - "Arch": "HVM64" - }, - "t2.micro": { - "Arch": "HVM64" - }, - "t2.small": { - "Arch": "HVM64" - }, - "t2.medium": { - "Arch": "HVM64" - }, - "t2.large": { - "Arch": "HVM64" - }, - "m1.small": { - "Arch": "PV64" - }, - "m1.medium": { - "Arch": "PV64" - }, - "m1.large": { - "Arch": "PV64" - }, - "m1.xlarge": { - "Arch": "PV64" - }, - "m2.xlarge": { - "Arch": "PV64" - }, - "m2.2xlarge": { - "Arch": "PV64" - }, - "m2.4xlarge": { - "Arch": "PV64" - }, - "m3.medium": { - "Arch": "HVM64" - }, - "m3.large": { - "Arch": "HVM64" - }, - "m3.xlarge": { - "Arch": "HVM64" - }, - "m3.2xlarge": { - "Arch": "HVM64" - }, - "m4.large": { - "Arch": "HVM64" - }, - "m4.xlarge": { - "Arch": "HVM64" - }, - "m4.2xlarge": { - "Arch": "HVM64" - }, - "m4.4xlarge": { - "Arch": "HVM64" - }, - "m4.10xlarge": { - "Arch": "HVM64" - }, - "c1.medium": { - "Arch": "PV64" - }, - "c1.xlarge": { - "Arch": "PV64" - }, - "c3.large": { - "Arch": "HVM64" - }, - "c3.xlarge": { - "Arch": "HVM64" - }, - "c3.2xlarge": { - "Arch": "HVM64" - }, - "c3.4xlarge": { - "Arch": "HVM64" - }, - "c3.8xlarge": { - "Arch": "HVM64" - }, - "c4.large": { - "Arch": "HVM64" - }, - "c4.xlarge": { - "Arch": "HVM64" - }, - "c4.2xlarge": { - "Arch": "HVM64" - }, - "c4.4xlarge": { - "Arch": "HVM64" - }, - "c4.8xlarge": { - "Arch": "HVM64" - }, - "g2.2xlarge": { - "Arch": "HVMG2" - }, - "g2.8xlarge": { - "Arch": "HVMG2" - }, - "r3.large": { - "Arch": "HVM64" - }, - "r3.xlarge": { - "Arch": "HVM64" - }, - "r3.2xlarge": { - "Arch": "HVM64" - }, - "r3.4xlarge": { - "Arch": "HVM64" - }, - "r3.8xlarge": { - "Arch": "HVM64" - }, - "i2.xlarge": { - "Arch": "HVM64" - }, - "i2.2xlarge": { - "Arch": "HVM64" - }, - "i2.4xlarge": { - "Arch": "HVM64" - }, - "i2.8xlarge": { - "Arch": "HVM64" - }, - "d2.xlarge": { - "Arch": "HVM64" - }, - "d2.2xlarge": { - "Arch": "HVM64" - }, - "d2.4xlarge": { - "Arch": "HVM64" - }, - "d2.8xlarge": { - "Arch": "HVM64" - }, - "hi1.4xlarge": { - "Arch": "HVM64" - }, - "hs1.8xlarge": { - "Arch": "HVM64" - }, - "cr1.8xlarge": { - "Arch": "HVM64" - }, - "cc2.8xlarge": { - "Arch": "HVM64" - } - }, - "AWSRegionArch2AMI": { - "us-east-1": { - "PV64": "ami-2a69aa47", - "HVM64": "ami-6869aa05", - "HVMG2": "ami-50b4f047" - }, - "us-west-2": { - "PV64": "ami-7f77b31f", - "HVM64": "ami-7172b611", - "HVMG2": "ami-002bf460" - }, - "us-west-1": { - "PV64": "ami-a2490dc2", - "HVM64": "ami-31490d51", - "HVMG2": "ami-699ad409" - }, - "eu-west-1": { - "PV64": "ami-4cdd453f", - "HVM64": "ami-f9dd458a", - "HVMG2": "ami-f0e0a483" - }, - "eu-central-1": { - "PV64": "ami-6527cf0a", - "HVM64": "ami-ea26ce85", - "HVMG2": "ami-d9d62ab6" - }, - "ap-northeast-1": { - "PV64": "ami-3e42b65f", - "HVM64": "ami-374db956", - "HVMG2": "ami-78ba6619" - }, - "ap-northeast-2": { - "PV64": "NOT_SUPPORTED", - "HVM64": "ami-2b408b45", - "HVMG2": "NOT_SUPPORTED" - }, - "ap-southeast-1": { - "PV64": "ami-df9e4cbc", - "HVM64": "ami-a59b49c6", - "HVMG2": "ami-56e84c35" - }, - "ap-southeast-2": { - "PV64": "ami-63351d00", - "HVM64": "ami-dc361ebf", - "HVMG2": "ami-2589b946" - }, - "ap-south-1": { - "PV64": "NOT_SUPPORTED", - "HVM64": "ami-ffbdd790", - "HVMG2": "ami-f7354198" - }, - "us-east-2": { - "PV64": "NOT_SUPPORTED", - "HVM64": "ami-f6035893", - "HVMG2": "NOT_SUPPORTED" - }, - "sa-east-1": { - "PV64": "ami-1ad34676", - "HVM64": "ami-6dd04501", - "HVMG2": "NOT_SUPPORTED" - }, - "cn-north-1": { - "PV64": "ami-77559f1a", - "HVM64": "ami-8e6aa0e3", - "HVMG2": "NOT_SUPPORTED" - } } }, "Resources": { "NotificationTopic": { "Type": "AWS::SNS::Topic", "Properties": { + "DisplayName": { + "Fn::Sub": "${AWS::StackName}-NotificationTopic" + }, "Subscription": [ { "Endpoint": { @@ -368,58 +105,15 @@ }, "Protocol": "email" } - ] - } - }, - "WebServerGroup": { - "CreationPolicy": { - "ResourceSignal": { - "Timeout": "PT15M", - "Count": 1 - } - }, - "UpdatePolicy": { - "AutoScalingRollingUpdate": { - "MinInstancesInService": 1, - "MaxBatchSize": 1, - "PauseTime": "PT15M", - "WaitOnResourceSignals": true - } - }, - "Type": "AWS::AutoScaling::AutoScalingGroup", - "Properties": { - "AvailabilityZones": { - "Fn::GetAZs": null - }, - "LaunchConfigurationName": { - "Ref": "LaunchConfig" - }, - "MinSize": "1", - "MaxSize": "3", - "LoadBalancerNames": [ - { - "Ref": "ElasticLoadBalancer" - } ], - "NotificationConfigurations": [ - { - "TopicARN": { - "Ref": "NotificationTopic" - }, - "NotificationTypes": [ - "autoscaling:EC2_INSTANCE_LAUNCH", - "autoscaling:EC2_INSTANCE_LAUNCH_ERROR", - "autoscaling:EC2_INSTANCE_TERMINATE", - "autoscaling:EC2_INSTANCE_TERMINATE_ERROR" - ] - } - ] + "KmsMasterKeyId": { + "Ref": "KmsKeyArn" + } } }, - "LaunchConfig": { - "Type": "AWS::AutoScaling::LaunchConfiguration", + "LaunchTemplate": { + "Type": "AWS::EC2::LaunchTemplate", "Metadata": { - "Comment": "Install a simple application", "AWS::CloudFormation::Init": { "config": { "packages": { @@ -454,22 +148,7 @@ }, "/etc/cfn/cfn-hup.conf": { "content": { - "Fn::Join": [ - "", - [ - "[main] ", - "stack=", - { - "Ref": "AWS::StackId" - }, - " ", - "region=", - { - "Ref": "AWS::Region" - }, - " " - ] - ] + "Fn::Sub": "[main]\nstack=${AWS::StackId}\nregion=${AWS::Region}\n" }, "mode": "000400", "owner": "root", @@ -477,26 +156,7 @@ }, "/etc/cfn/hooks.d/cfn-auto-reloader.conf": { "content": { - "Fn::Join": [ - "", - [ - "[cfn-auto-reloader-hook] ", - "triggers=post.update ", - "path=Resources.LaunchConfig.Metadata.AWS::CloudFormation::Init ", - "action=/opt/aws/bin/cfn-init -v ", - " --stack ", - { - "Ref": "AWS::StackName" - }, - " --resource LaunchConfig ", - " --region ", - { - "Ref": "AWS::Region" - }, - " ", - "runas=root " - ] - ] + "Fn::Sub": "[cfn-auto-reloader-hook]\ntriggers=post.update\npath=Resources.LaunchConfig.Metadata.AWS::CloudFormation::Init\naction=/opt/aws/bin/cfn-init -v --stack ${AWS::StackName} --resource LaunchConfig --region ${AWS::Region}\nrunas=root\n" } } }, @@ -520,66 +180,114 @@ } }, "Properties": { - "KeyName": { - "Ref": "KeyName" + "LaunchTemplateName": { + "Fn::Sub": "${AWS::StackName}-LaunchTemplate" }, - "ImageId": { - "Fn::FindInMap": [ - "AWSRegionArch2AMI", + "LaunchTemplateData": { + "ImageId": { + "Ref": "LatestAmiId" + }, + "InstanceType": { + "Ref": "InstanceType" + }, + "SecurityGroupIds": { + "Ref": "SecurityGroups" + }, + "KeyName": { + "Ref": "KeyName" + }, + "BlockDeviceMappings": [ { - "Ref": "AWS::Region" - }, + "DeviceName": "/dev/sda1", + "Ebs": { + "VolumeSize": 32 + } + } + ], + "UserData": { + "Fn::Base64": { + "Fn::Sub": "#!/bin/bash\n/opt/aws/bin/cfn-init -v --stack ${AWS::StackName} --resource LaunchConfig --region ${AWS::Region}\n/opt/aws/bin/cfn-signal -e $? --stack ${AWS::StackName} --resource WebServerGroup --region ${AWS::Region}\n" + } + }, + "TagSpecifications": [ { - "Fn::FindInMap": [ - "AWSInstanceType2Arch", + "ResourceType": "instance", + "Tags": [ { - "Ref": "InstanceType" - }, - "Arch" + "Key": "Name", + "Value": { + "Fn::Sub": "${AWS::StackName}-Instance" + } + } ] } ] + } + } + }, + "WebServerGroup": { + "CreationPolicy": { + "ResourceSignal": { + "Timeout": "PT5M", + "Count": 1 + } + }, + "UpdatePolicy": { + "AutoScalingRollingUpdate": { + "MinInstancesInService": 1, + "MaxBatchSize": 1, + "PauseTime": "PT5M", + "WaitOnResourceSignals": true + } + }, + "Type": "AWS::AutoScaling::AutoScalingGroup", + "Metadata": { + "cfn-lint": { + "config": { + "ignore_checks": [ + "E3014" + ] + } + } + }, + "Properties": { + "AvailabilityZones": { + "Fn::GetAZs": null + }, + "LaunchTemplate": { + "LaunchTemplateId": { + "Ref": "LaunchTemplate" + }, + "Version": { + "Fn::GetAtt": [ + "LaunchTemplate", + "LatestVersionNumber" + ] + } }, - "SecurityGroups": [ + "MinSize": "1", + "MaxSize": "3", + "LoadBalancerNames": [ { - "Ref": "InstanceSecurityGroup" + "Ref": "ElasticLoadBalancer" } ], - "InstanceType": { - "Ref": "InstanceType" - }, - "UserData": { - "Fn::Base64": { - "Fn::Join": [ - "", - [ - "#!/bin/bash -xe ", - "yum update -y aws-cfn-bootstrap ", - "/opt/aws/bin/cfn-init -v ", - " --stack ", - { - "Ref": "AWS::StackName" - }, - " --resource LaunchConfig ", - " --region ", - { - "Ref": "AWS::Region" - }, - " ", - "/opt/aws/bin/cfn-signal -e $? ", - " --stack ", - { - "Ref": "AWS::StackName" - }, - " --resource WebServerGroup ", - " --region ", - { - "Ref": "AWS::Region" - }, - " " - ] + "NotificationConfigurations": [ + { + "TopicARN": { + "Ref": "NotificationTopic" + }, + "NotificationTypes": [ + "autoscaling:EC2_INSTANCE_LAUNCH", + "autoscaling:EC2_INSTANCE_LAUNCH_ERROR", + "autoscaling:EC2_INSTANCE_TERMINATE", + "autoscaling:EC2_INSTANCE_TERMINATE_ERROR" ] } + ], + "HealthCheckType": "ELB", + "VPCZoneIdentifier": { + "Ref": "Subnets" } } }, @@ -668,7 +376,10 @@ { "LoadBalancerPort": "80", "InstancePort": "80", - "Protocol": "HTTP" + "Protocol": "HTTP", + "SSLCertificateId": { + "Ref": "CertificateArn" + } } ], "HealthCheck": { @@ -728,7 +439,7 @@ "Fn::Join": [ "", [ - "http://", + "https://", { "Fn::GetAtt": [ "ElasticLoadBalancer", diff --git a/AutoScaling/AutoScalingMultiAZWithNotifications.yaml b/AutoScaling/AutoScalingMultiAZWithNotifications.yaml index 557fba8f..e14f32f5 100644 --- a/AutoScaling/AutoScalingMultiAZWithNotifications.yaml +++ b/AutoScaling/AutoScalingMultiAZWithNotifications.yaml @@ -2,68 +2,11 @@ AWSTemplateFormatVersion: "2010-09-09" Description: 'AWS CloudFormation Sample Template AutoScalingMultiAZWithNotifications: Create a multi-az, load balanced and Auto Scaled sample web site running on an Apache Web Server. The application is configured to span all Availability Zones in the region and is Auto-Scaled based on the CPU utilization of the web servers. Notifications will be sent to the operator email address on scaling events. The instances are load balanced with a simple health check against the default web page. **WARNING** This template creates one or more Amazon EC2 instances and an Elastic Load Balancer. You will be billed for the AWS resources used if you create a stack from this template.' -Metadata: - License: Apache-2.0 - Parameters: InstanceType: Description: WebServer EC2 instance type Type: String - AllowedValues: - - t1.micro - - t2.nano - - t2.micro - - t2.small - - t2.medium - - t2.large - - m1.small - - m1.medium - - m1.large - - m1.xlarge - - m2.xlarge - - m2.2xlarge - - m2.4xlarge - - m3.medium - - m3.large - - m3.xlarge - - m3.2xlarge - - m4.large - - m4.xlarge - - m4.2xlarge - - m4.4xlarge - - m4.10xlarge - - c1.medium - - c1.xlarge - - c3.large - - c3.xlarge - - c3.2xlarge - - c3.4xlarge - - c3.8xlarge - - c4.large - - c4.xlarge - - c4.2xlarge - - c4.4xlarge - - c4.8xlarge - - g2.2xlarge - - g2.8xlarge - - r3.large - - r3.xlarge - - r3.2xlarge - - r3.4xlarge - - r3.8xlarge - - i2.xlarge - - i2.2xlarge - - i2.4xlarge - - i2.8xlarge - - d2.xlarge - - d2.2xlarge - - d2.4xlarge - - d2.8xlarge - - hs1.8xlarge - - cr1.8xlarge - - cc2.8xlarge - Default: t2.small - ConstraintDescription: must be a valid EC2 instance type. + Default: t2.micro OperatorEMail: Description: EMail address to notify if there are any scaling operations @@ -85,6 +28,26 @@ Parameters: AllowedPattern: (\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})/(\d{1,2}) ConstraintDescription: must be a valid IP CIDR range of the form x.x.x.x/x. + LatestAmiId: + Type: AWS::SSM::Parameter::Value + Default: /aws/service/ami-amazon-linux-latest/al2023-ami-kernel-6.1-arm64 + + KmsKeyArn: + Description: KMS Key ARN to encrypt data + Type: String + + CertificateArn: + Description: Certificate ARN for HTTPS + Type: String + + SecurityGroups: + Description: Security Groups to be used + Type: List + + Subnets: + Description: Subnets to be used + Type: List + Mappings: Region2Examples: us-east-1: @@ -114,207 +77,19 @@ Mappings: cn-north-1: Examples: https://s3.cn-north-1.amazonaws.com.cn/cloudformation-examples-cn-north-1 - AWSInstanceType2Arch: - t1.micro: - Arch: PV64 - t2.nano: - Arch: HVM64 - t2.micro: - Arch: HVM64 - t2.small: - Arch: HVM64 - t2.medium: - Arch: HVM64 - t2.large: - Arch: HVM64 - m1.small: - Arch: PV64 - m1.medium: - Arch: PV64 - m1.large: - Arch: PV64 - m1.xlarge: - Arch: PV64 - m2.xlarge: - Arch: PV64 - m2.2xlarge: - Arch: PV64 - m2.4xlarge: - Arch: PV64 - m3.medium: - Arch: HVM64 - m3.large: - Arch: HVM64 - m3.xlarge: - Arch: HVM64 - m3.2xlarge: - Arch: HVM64 - m4.large: - Arch: HVM64 - m4.xlarge: - Arch: HVM64 - m4.2xlarge: - Arch: HVM64 - m4.4xlarge: - Arch: HVM64 - m4.10xlarge: - Arch: HVM64 - c1.medium: - Arch: PV64 - c1.xlarge: - Arch: PV64 - c3.large: - Arch: HVM64 - c3.xlarge: - Arch: HVM64 - c3.2xlarge: - Arch: HVM64 - c3.4xlarge: - Arch: HVM64 - c3.8xlarge: - Arch: HVM64 - c4.large: - Arch: HVM64 - c4.xlarge: - Arch: HVM64 - c4.2xlarge: - Arch: HVM64 - c4.4xlarge: - Arch: HVM64 - c4.8xlarge: - Arch: HVM64 - g2.2xlarge: - Arch: HVMG2 - g2.8xlarge: - Arch: HVMG2 - r3.large: - Arch: HVM64 - r3.xlarge: - Arch: HVM64 - r3.2xlarge: - Arch: HVM64 - r3.4xlarge: - Arch: HVM64 - r3.8xlarge: - Arch: HVM64 - i2.xlarge: - Arch: HVM64 - i2.2xlarge: - Arch: HVM64 - i2.4xlarge: - Arch: HVM64 - i2.8xlarge: - Arch: HVM64 - d2.xlarge: - Arch: HVM64 - d2.2xlarge: - Arch: HVM64 - d2.4xlarge: - Arch: HVM64 - d2.8xlarge: - Arch: HVM64 - hi1.4xlarge: - Arch: HVM64 - hs1.8xlarge: - Arch: HVM64 - cr1.8xlarge: - Arch: HVM64 - cc2.8xlarge: - Arch: HVM64 - - AWSRegionArch2AMI: - us-east-1: - PV64: ami-2a69aa47 - HVM64: ami-6869aa05 - HVMG2: ami-50b4f047 - us-west-2: - PV64: ami-7f77b31f - HVM64: ami-7172b611 - HVMG2: ami-002bf460 - us-west-1: - PV64: ami-a2490dc2 - HVM64: ami-31490d51 - HVMG2: ami-699ad409 - eu-west-1: - PV64: ami-4cdd453f - HVM64: ami-f9dd458a - HVMG2: ami-f0e0a483 - eu-central-1: - PV64: ami-6527cf0a - HVM64: ami-ea26ce85 - HVMG2: ami-d9d62ab6 - ap-northeast-1: - PV64: ami-3e42b65f - HVM64: ami-374db956 - HVMG2: ami-78ba6619 - ap-northeast-2: - PV64: NOT_SUPPORTED - HVM64: ami-2b408b45 - HVMG2: NOT_SUPPORTED - ap-southeast-1: - PV64: ami-df9e4cbc - HVM64: ami-a59b49c6 - HVMG2: ami-56e84c35 - ap-southeast-2: - PV64: ami-63351d00 - HVM64: ami-dc361ebf - HVMG2: ami-2589b946 - ap-south-1: - PV64: NOT_SUPPORTED - HVM64: ami-ffbdd790 - HVMG2: ami-f7354198 - us-east-2: - PV64: NOT_SUPPORTED - HVM64: ami-f6035893 - HVMG2: NOT_SUPPORTED - sa-east-1: - PV64: ami-1ad34676 - HVM64: ami-6dd04501 - HVMG2: NOT_SUPPORTED - cn-north-1: - PV64: ami-77559f1a - HVM64: ami-8e6aa0e3 - HVMG2: NOT_SUPPORTED - Resources: NotificationTopic: Type: AWS::SNS::Topic Properties: + DisplayName: !Sub ${AWS::StackName}-NotificationTopic Subscription: - Endpoint: !Ref OperatorEMail Protocol: email + KmsMasterKeyId: !Ref KmsKeyArn - WebServerGroup: - CreationPolicy: - ResourceSignal: - Timeout: PT15M - Count: 1 - UpdatePolicy: - AutoScalingRollingUpdate: - MinInstancesInService: 1 - MaxBatchSize: 1 - PauseTime: PT15M - WaitOnResourceSignals: true - Type: AWS::AutoScaling::AutoScalingGroup - Properties: - AvailabilityZones: !GetAZs - LaunchConfigurationName: !Ref LaunchConfig - MinSize: "1" - MaxSize: "3" - LoadBalancerNames: - - !Ref ElasticLoadBalancer - NotificationConfigurations: - - TopicARN: !Ref NotificationTopic - NotificationTypes: - - autoscaling:EC2_INSTANCE_LAUNCH - - autoscaling:EC2_INSTANCE_LAUNCH_ERROR - - autoscaling:EC2_INSTANCE_TERMINATE - - autoscaling:EC2_INSTANCE_TERMINATE_ERROR - - LaunchConfig: - Type: AWS::AutoScaling::LaunchConfiguration + LaunchTemplate: + Type: AWS::EC2::LaunchTemplate Metadata: - Comment: Install a simple application AWS::CloudFormation::Init: config: packages: @@ -335,32 +110,20 @@ Resources: owner: root group: root /etc/cfn/cfn-hup.conf: - content: !Join - - "" - - - '[main] ' - - stack= - - !Ref AWS::StackId - - ' ' - - region= - - !Ref AWS::Region - - ' ' + content: !Sub | + [main] + stack=${AWS::StackId} + region=${AWS::Region} mode: "000400" owner: root group: root /etc/cfn/hooks.d/cfn-auto-reloader.conf: - content: !Join - - "" - - - '[cfn-auto-reloader-hook] ' - - 'triggers=post.update ' - - 'path=Resources.LaunchConfig.Metadata.AWS::CloudFormation::Init ' - - 'action=/opt/aws/bin/cfn-init -v ' - - ' --stack ' - - !Ref AWS::StackName - - ' --resource LaunchConfig ' - - ' --region ' - - !Ref AWS::Region - - ' ' - - 'runas=root ' + content: !Sub | + [cfn-auto-reloader-hook] + triggers=post.update + path=Resources.LaunchConfig.Metadata.AWS::CloudFormation::Init + action=/opt/aws/bin/cfn-init -v --stack ${AWS::StackName} --resource LaunchConfig --region ${AWS::Region} + runas=root services: sysvinit: httpd: @@ -373,36 +136,62 @@ Resources: - /etc/cfn/cfn-hup.conf - /etc/cfn/hooks.d/cfn-auto-reloader.conf Properties: - KeyName: !Ref KeyName - ImageId: !FindInMap - - AWSRegionArch2AMI - - !Ref AWS::Region - - !FindInMap - - AWSInstanceType2Arch - - !Ref InstanceType - - Arch - SecurityGroups: - - !Ref InstanceSecurityGroup - InstanceType: !Ref InstanceType - UserData: !Base64 - Fn::Join: - - "" - - - '#!/bin/bash -xe ' - - 'yum update -y aws-cfn-bootstrap ' - - '/opt/aws/bin/cfn-init -v ' - - ' --stack ' - - !Ref AWS::StackName - - ' --resource LaunchConfig ' - - ' --region ' - - !Ref AWS::Region - - ' ' - - '/opt/aws/bin/cfn-signal -e $? ' - - ' --stack ' - - !Ref AWS::StackName - - ' --resource WebServerGroup ' - - ' --region ' - - !Ref AWS::Region - - ' ' + LaunchTemplateName: !Sub ${AWS::StackName}-LaunchTemplate + LaunchTemplateData: + ImageId: !Ref LatestAmiId + InstanceType: !Ref InstanceType + SecurityGroupIds: !Ref SecurityGroups + KeyName: !Ref KeyName + BlockDeviceMappings: + - DeviceName: /dev/sda1 + Ebs: + VolumeSize: 32 + UserData: !Base64 + Fn::Sub: | + #!/bin/bash + /opt/aws/bin/cfn-init -v --stack ${AWS::StackName} --resource LaunchConfig --region ${AWS::Region} + /opt/aws/bin/cfn-signal -e $? --stack ${AWS::StackName} --resource WebServerGroup --region ${AWS::Region} + TagSpecifications: + - ResourceType: instance + Tags: + - Key: Name + Value: !Sub ${AWS::StackName}-Instance + + WebServerGroup: + CreationPolicy: + ResourceSignal: + Timeout: PT5M + Count: 1 + UpdatePolicy: + AutoScalingRollingUpdate: + MinInstancesInService: 1 + MaxBatchSize: 1 + PauseTime: PT5M + WaitOnResourceSignals: true + Type: AWS::AutoScaling::AutoScalingGroup + Metadata: + cfn-lint: + config: + ignore_checks: + - E3014 + Properties: + AvailabilityZones: !GetAZs + LaunchTemplate: + LaunchTemplateId: !Ref LaunchTemplate + Version: !GetAtt LaunchTemplate.LatestVersionNumber + MinSize: "1" + MaxSize: "3" + LoadBalancerNames: + - !Ref ElasticLoadBalancer + NotificationConfigurations: + - TopicARN: !Ref NotificationTopic + NotificationTypes: + - autoscaling:EC2_INSTANCE_LAUNCH + - autoscaling:EC2_INSTANCE_LAUNCH_ERROR + - autoscaling:EC2_INSTANCE_TERMINATE + - autoscaling:EC2_INSTANCE_TERMINATE_ERROR + HealthCheckType: ELB + VPCZoneIdentifier: !Ref Subnets WebServerScaleUpPolicy: Type: AWS::AutoScaling::ScalingPolicy @@ -463,6 +252,7 @@ Resources: - LoadBalancerPort: "80" InstancePort: "80" Protocol: HTTP + SSLCertificateId: !Ref CertificateArn HealthCheck: Target: HTTP:80/ HealthyThreshold: "3" @@ -494,5 +284,5 @@ Outputs: Description: The URL of the website Value: !Join - "" - - - http:// + - - https:// - !GetAtt ElasticLoadBalancer.DNSName diff --git a/Config/Config.yaml b/Config/Config.yaml index 043d9666..0aa83b77 100644 --- a/Config/Config.yaml +++ b/Config/Config.yaml @@ -188,7 +188,7 @@ Resources: }); } Handler: index.handler - Runtime: nodejs16.x + Runtime: nodejs20.x Timeout: "30" Role: !GetAtt LambdaExecutionRole.Arn diff --git a/EC2/InstanceWithCfnInit.json b/EC2/InstanceWithCfnInit.json new file mode 100644 index 00000000..c0fdf9e9 --- /dev/null +++ b/EC2/InstanceWithCfnInit.json @@ -0,0 +1,85 @@ +{ + "AWSTemplateFormatVersion": "2010-09-09", + "Description": "AWS CloudFormation sample template. \nCreate an Amazon EC2 instance with cfn-init and cfn-signal.\n", + "Resources": { + "Instance": { + "CreationPolicy": { + "ResourceSignal": { + "Timeout": "PT5M" + } + }, + "Type": "AWS::EC2::Instance", + "Metadata": { + "guard": { + "SuppressedRules": [ + "EC2_INSTANCES_IN_VPC" + ] + }, + "AWS::CloudFormation::Init": { + "config": { + "packages": { + "yum": { + "httpd": [] + } + }, + "files": { + "/var/www/html/index.html": { + "content": "\n

Congratulations, you have successfully launched the AWS CloudFormation sample.

\n\n", + "mode": "000644", + "owner": "root", + "group": "root" + }, + "/etc/cfn/cfn-hup.conf": { + "content": { + "Fn::Sub": "[main]\nstack=${AWS::StackId}\nregion=${AWS::Region}\n" + }, + "mode": "000400", + "owner": "root", + "group": "root" + }, + "/etc/cfn/hooks.d/cfn-auto-reloader.conf": { + "content": { + "Fn::Sub": "[cfn-auto-reloader-hook]\ntriggers=post.update\npath=Resources.LaunchConfig.Metadata.AWS::CloudFormation::Init\naction=/opt/aws/bin/cfn-init -v --stack ${AWS::StackName} --resource Instance --region ${AWS::Region}\nrunas=root" + } + } + }, + "services": { + "sysvinit": { + "httpd": { + "enabled": true, + "ensureRunning": true + }, + "cfn-hup": { + "enabled": true, + "ensureRunning": true, + "files": [ + "/etc/cfn/cfn-hup.conf", + "/etc/cfn/hooks.d/cfn-auto-reloader.conf" + ] + } + } + } + } + } + }, + "Properties": { + "ImageId": "{{resolve:ssm:/aws/service/ami-amazon-linux-latest/al2023-ami-kernel-6.1-arm64}}", + "InstanceType": "t4g.nano", + "KeyName": "sample", + "BlockDeviceMappings": [ + { + "DeviceName": "/dev/sda1", + "Ebs": { + "VolumeSize": 32 + } + } + ], + "UserData": { + "Fn::Base64": { + "Fn::Sub": "#!/bin/bash\n/opt/aws/bin/cfn-signal -e $? --stack ${AWS::StackName} --resource Instance --region ${AWS::Region}" + } + } + } + } + } +} diff --git a/EC2/InstanceWithCfnInit.yaml b/EC2/InstanceWithCfnInit.yaml new file mode 100644 index 00000000..4378e019 --- /dev/null +++ b/EC2/InstanceWithCfnInit.yaml @@ -0,0 +1,66 @@ +AWSTemplateFormatVersion: "2010-09-09" + +Description: "AWS CloudFormation sample template. \nCreate an Amazon EC2 instance with cfn-init and cfn-signal.\n" + +Resources: + Instance: + CreationPolicy: + ResourceSignal: + Timeout: PT5M + Type: AWS::EC2::Instance + Metadata: + guard: + SuppressedRules: + - EC2_INSTANCES_IN_VPC + AWS::CloudFormation::Init: + config: + packages: + yum: + httpd: [] + files: + /var/www/html/index.html: + content: | + +

Congratulations, you have successfully launched the AWS CloudFormation sample.

+ + mode: "000644" + owner: root + group: root + /etc/cfn/cfn-hup.conf: + content: !Sub | + [main] + stack=${AWS::StackId} + region=${AWS::Region} + mode: "000400" + owner: root + group: root + /etc/cfn/hooks.d/cfn-auto-reloader.conf: + content: !Sub |- + [cfn-auto-reloader-hook] + triggers=post.update + path=Resources.LaunchConfig.Metadata.AWS::CloudFormation::Init + action=/opt/aws/bin/cfn-init -v --stack ${AWS::StackName} --resource Instance --region ${AWS::Region} + runas=root + services: + sysvinit: + httpd: + enabled: true + ensureRunning: true + cfn-hup: + enabled: true + ensureRunning: true + files: + - /etc/cfn/cfn-hup.conf + - /etc/cfn/hooks.d/cfn-auto-reloader.conf + Properties: + ImageId: '{{resolve:ssm:/aws/service/ami-amazon-linux-latest/al2023-ami-kernel-6.1-arm64}}' + InstanceType: t4g.nano + KeyName: sample + BlockDeviceMappings: + - DeviceName: /dev/sda1 + Ebs: + VolumeSize: 32 + UserData: !Base64 + Fn::Sub: |- + #!/bin/bash + /opt/aws/bin/cfn-signal -e $? --stack ${AWS::StackName} --resource Instance --region ${AWS::Region} diff --git a/scripts/guard-all.sh b/scripts/guard-all.sh index 48b5f3f3..eed01750 100755 --- a/scripts/guard-all.sh +++ b/scripts/guard-all.sh @@ -13,5 +13,3 @@ SCRIPT_DIR=$(dirname "$0") find . -name "*.yaml" | grep -v "\.env" | xargs -n 1 ${SCRIPT_DIR}/guard-single.sh - -echo "Success" diff --git a/scripts/guard-single.sh b/scripts/guard-single.sh index 390dae67..fa58062a 100755 --- a/scripts/guard-single.sh +++ b/scripts/guard-single.sh @@ -13,4 +13,3 @@ cfn-guard validate --data $1 \ --show-summary fail \ --type CFNTemplate -echo "Success" diff --git a/scripts/rules.guard b/scripts/rules.guard index e95ed661..5236f1f1 100644 --- a/scripts/rules.guard +++ b/scripts/rules.guard @@ -1693,3 +1693,33 @@ rule IAM_USER_NO_POLICIES_CHECK when %aws_iam_users_no_policies !empty { Fix: Remove the Policies list property from any IAM Users. >> } + +let lambda_functions = Resources.*[ + Type == "AWS::Lambda::Function" +] + +rule LAMBDA_DEPRECATED_RUNTIME when %lambda_functions !empty { + %lambda_functions { + Properties { + when Runtime exists { + Runtime !in ["dotnetcore3.1", "nodejs12.x", "python3.6", "python2.7", "dotnet5.0", "dotnetcore2.1", "ruby2.5", "nodejs10.x", "nodejs8.10", "nodejs4.3", "nodejs6.10", "dotnetcore1.0", "dotnetcore2.0", "nodejs4.3-edge", "nodejs"] + << + Lambda function is using a deprecated runtime. + >> + } + } + } +} + +rule LAMBDA_DEPRECATED_SOON_RUNTIME when %lambda_functions !empty { + %lambda_functions { + Properties { + when Runtime exists { + Runtime !in ["nodejs16.x", "nodejs14.x", "python3.7", "java8", "dotnet7", "go1.x", "ruby2.7", "provided"] + << + Lambda function is using a runtime that is targeted for deprecation. + >> + } + } + } +} diff --git a/scripts/test-all.sh b/scripts/test-all.sh index f5b7ce0b..399cc4f7 100755 --- a/scripts/test-all.sh +++ b/scripts/test-all.sh @@ -48,6 +48,5 @@ then pylint $RCFILE Solutions/ADConnector/src/adconnector_custom_resource.py pylint $RCFILE Solutions/DirectoryServiceSettings/src/directory_settings_custom_resource.py + pylint $RCFILE APIGateway/handler.py fi - -echo "Success"