def add_resources(self): self.runner_terminate_rule = self.template.add_resource( Rule( "RunnerTeminateRule", EventPattern={ "source": ["aws.autoscaling"], "detail-type": ["EC2 Instance-terminate Lifecycle Action"], }, State="ENABLED", Targets=[ Target( Arn=Ref(self.runner_unregister_function_arn), Id=Ref(self.runner_terminate_target_id), ) ], )) self.runner_unregister_permission = self.template.add_resource( Permission( "RunnerUnregisterPermission", Action="lambda:InvokeFunction", FunctionName=Ref(self.runner_unregister_function), Principal="events.amazonaws.com", SourceArn=GetAtt(self.runner_terminate_rule, "Arn"), )) self.runner_terminate_lifecyclehook = self.template.add_resource( LifecycleHook( "RunnerTerminateLifecycleHook", AutoScalingGroupName=Ref(self.runner_autoscaling_group), LifecycleTransition="autoscaling:EC2_INSTANCE_TERMINATING", ))
def create_cron_rule(self, schedule_expression, targets, state='ENABLED', name_prefix='', **kwargs): return self.template.add_resource( Rule('{0}Rule'.format(name_prefix), State=state, Targets=targets, ScheduleExpression=schedule_expression, **kwargs))
def create_lambda_fn_cron(name_prefix, lambda_fn, schedule_expression): rule = Rule( '{}EventRule'.format(name_prefix), ScheduleExpression=schedule_expression, Targets=[Target(Arn=GetAtt(lambda_fn, 'Arn'), Id=lambda_fn.name)]) permission = Permission('{}LambdaFunctionPermission'.format(name_prefix), Action="lambda:InvokeFunction", FunctionName=GetAtt(lambda_fn, 'Arn'), Principal='events.amazonaws.com', SourceArn=GetAtt(rule, 'Arn')) return (rule, permission)
def add_event_rule_demo(self): self.rule_demo = self.template.add_resource( Rule("SpotRuleDemo", Description= "Rule trigered when a spot termination notice is found", EventPattern={ "source": ["mARC_demo"], "detail-type": ["EC2 Spot Instance Interruption Warning"], "detail": { "instance-action": ["terminate"] } }, State="ENABLED", Targets=[self.lambda_target]))
def build_cw_event(template=Template, project_name=None, role=None): # Run either at 12 or 13:00 UTC, 04/05:00 PST hour = randrange(12, 14) project_target = Target(f"{project_name}Target", Arn=GetAtt(project_name, "Arn"), RoleArn=GetAtt(role, "Arn"), Id=f"{project_name}CWid") rule = template.add_resource( Rule( f"{project_name}Rule", Name=f"{project_name}Evernt", Description="scheduled run Build with CloudFormation", Targets=[project_target], State='ENABLED', # Run at the top of a random hour. ScheduleExpression=f"cron(0 {hour} * * ? *)", DependsOn=project_name)) return rule
def add_lambda_scheduler(*, template_res, cron, lambda_function_name, lambda_function_arn): lambda_function = ''.join( [a.title() for a in lambda_function_name.split('_')]) event_target = Target(f'{lambda_function}EventTarget', Arn=lambda_function_arn, Id=f'{lambda_function}FunctionEventTarget') scheduler = template_res.add_resource( Rule( f'ScheduledRule{lambda_function}', ScheduleExpression=cron, # http://docs.aws.amazon.com/AmazonCloudWatch/latest/events/ScheduledEvents.html Description=f'Scheduled Event for Lambda {lambda_function_name}', State="ENABLED", Targets=[event_target])) add_permission = template_res.add_resource( awslambda.Permission(f'AccessLambda{lambda_function}', Action='lambda:InvokeFunction', FunctionName=f'{lambda_function_name}', Principal='events.amazonaws.com', SourceArn=GetAtt(scheduler, 'Arn')))
def create_lambda_schedule(template, awslambda, schedule): """ Create Lambda function schedule :param template: Cloudformation template to add to :param awslambda: Lambda function to be scheduled :param schedule: Rate at which schedule should run """ trop_cw_rule = template.add_resource( Rule('CloudsploitRule', Name='CloudsploitReporter', ScheduleExpression=schedule, State='ENABLED', Targets=[ Target(Arn=GetAtt(awslambda, 'Arn'), Id='CloudsploitRule') ])) trop_cw_permission = template.add_resource( Permission('CloudsploitRulePermission', Action='lambda:InvokeFunction', FunctionName=GetAtt(awslambda, 'Arn'), Principal='events.amazonaws.com', SourceArn=GetAtt(trop_cw_rule, 'Arn')))
def build_cw_event(template=Template, project_name=None, role=None, target_job=None, hour=12, minute=0, input_json=None): """ Create a CloudWatch Event to run a CodeBuild Project. """ # CloudFormation doesn't allow underscores project_name = project_name.replace('_', '') # target_job is only expected in the case where multiple events are pointed at the same target. # Use the project name as the dependency otherwise. if not target_job: target_job = project_name # input_json is used to pass additional ENV variables to the codebuild job. if input_json: project_target = Target(f"{project_name}Target", Arn=GetAtt(target_job, "Arn"), RoleArn=GetAtt(role, "Arn"), Input=json.dumps(input_json), Id=f"{project_name}CWid") else: project_target = Target(f"{project_name}Target", Arn=GetAtt(target_job, "Arn"), RoleArn=GetAtt(role, "Arn"), Id=f"{project_name}CWid") Rule( f"{project_name}Rule", template=template, Name=f"{project_name}Event", Description="scheduled run Build with CloudFormation", Targets=[project_target], State='ENABLED', # Run at the top of hour. ScheduleExpression=f"cron({minute} {hour} * * ? *)", DependsOn=target_job)
def add_resources(self): """Create Resources to deploy Limit Monitor.""" template = self.template variables = self.get_variables() path = os.path.dirname(os.path.abspath(path=__file__)) stacker_dict = yaml.safe_load( open(path + '/' + '../01_limit_monitor_spoke_us-east-1.yaml')) service_item = '' for item in stacker_dict['stacks']['servicelimitmonitorspoke'][ 'variables']['SERVICES']: quoted_item = '"' + item + '"' service_item = service_item + quoted_item + ',' """Adding Mapping for AnonymousData""" template.add_mapping('MetricsMap', {'Send-Data': { 'SendAnonymousData': 'Yes' }}) """Adding Mapping for RefreshRate.""" template.add_mapping('RefreshRate', {'CronSchedule': { 'Default': 'rate(1 day)' }}) """Adding Mapping for SourceCode.""" template.add_mapping( 'SourceCode', { 'General': { 'S3Bucket': 'solutions', 'KeyPrefix': 'limit-monitor/v5.1.1' } }) # """Adding Mapping for EventsMap.""" # template.add_mapping( # 'EventsMap', { # 'Checks': { # 'Services': '"AutoScaling","CloudFormation","EBS","EC2","ELB","IAM","RDS","VPC"' # # } # } # ) s3_bucket = FindInMap('SourceCode', 'General', 'S3Bucket') s3_key = FindInMap('SourceCode', 'General', 'KeyPrefix') """TAOkRule Target Resource Definition.""" ta_ok_rule_target = Target( 'TAOkRuleTarget', Arn=Join(':', [ 'arn:aws:events', 'us-east-1', str(variables['MasterAccount'].value), 'event-bus/default' ]), Id='SpokeOkTarget', ) """CWR - Rule for TA OK events'.""" template.add_resource( Rule('TAOkRule', Description= 'Limit Monitor Solution - Spoke - Rule for TA OK events', EventPattern={ 'account': [Ref('AWS::AccountId')], 'source': ['aws.trustedadvisor'], 'detail-type': ['Trusted Advisor Check Item Refresh Notification'], 'detail': { 'status': ["OK"], 'check-item-detail': { 'Service': variables['SERVICES'].value } } }, State='ENABLED', Targets=[ ta_ok_rule_target, ])) """TAWarnRule Target Resource Definition.""" ta_warn_rule_target = Target( 'TAWarnRuleTarget', Arn=Join(':', [ 'arn:aws:events', 'us-east-1', str(variables['MasterAccount'].value), 'event-bus/default' ]), Id='SpokeWarnTarget', ) """CWR - Rule for TA WARN events'""" template.add_resource( Rule('TAWarnRule', Description= 'Limit Monitor Solution - Spoke - Rule for TA WARN events', EventPattern={ 'account': [Ref('AWS::AccountId')], 'source': ['aws.trustedadvisor'], 'detail-type': ['Trusted Advisor Check Item Refresh Notification'], 'detail': { 'status': ["WARN"], 'check-item-detail': { 'Service': variables['SERVICES'].value } } }, State='ENABLED', Targets=[ ta_warn_rule_target, ])) """TAErrorRule Target Resource Definition.""" ta_error_rule_target = Target( 'TAErrorRuleTarget', Arn=Join(':', [ 'arn:aws:events', 'us-east-1', str(variables['MasterAccount'].value), 'event-bus/default' ]), Id='SpokeErrorTarget', ) """CWR - Rule for TA Error events'""" template.add_resource( Rule('TAErrorRule', Description= 'Limit Monitor Solution - Spoke - Rule for TA WARN events', EventPattern={ 'account': [Ref('AWS::AccountId')], 'source': ['aws.trustedadvisor'], 'detail-type': ['Trusted Advisor Check Item Refresh Notification'], 'detail': { 'status': ["ERROR"], 'check-item-detail': { 'Service': variables['SERVICES'].value } } }, State='ENABLED', Targets=[ ta_error_rule_target, ])) """Create the IAM role for the TA Refresher Lambda Function""" ta_refresher_role = template.add_resource( Role('TARefresherRole', AssumeRolePolicyDocument=PolicyDocument(Statement=[ Statement(Effect=Allow, Action=[awacs.sts.AssumeRole], Principal=Principal('Service', ['lambda.amazonaws.com'])) ]), Path='/', Policies=[ Policy(PolicyDocument=PolicyDocument( Version='2012-10-17', Statement=[ Statement(Effect=Allow, Action=[ CreateLogGroup, CreateLogStream, PutLogEvents ], Resource=[ Join(':', [ 'arn:aws:logs', Ref('AWS::Region'), Ref('AWS::AccountId'), 'log-group', '/aws/lambda/*' ]) ]), Statement(Effect=Allow, Action=[awacs.support.Action('*')], Resource=['*']), ]), PolicyName=Join('-', [ 'Limit-Monitor-Refresher-Policy', Ref('AWS::StackName') ])) ])) """Create TA Refresher Lambda Function.""" ta_refresher = template.add_resource( Function( 'TARefresher', Description= 'Serverless Limit Monitor - Lambda function to summarize service limits', Environment=Environment( Variables={ # 'AWS_SERVICES': FindInMap('EventsMap', 'Checks', 'Services'), 'AWS_SERVICES': str(service_item[:-1]), 'LOG_LEVEL': 'ERROR' }), Handler='index.handler', Role=GetAtt(ta_refresher_role, 'Arn'), Code=Code(S3Bucket=Join( '-', [s3_bucket, Ref('AWS::Region')]), S3Key=Join('/', [s3_key, 'limtr-refresh-service.zip'])), Runtime='nodejs8.10', Timeout=300, DependsOn=[ta_refresher_role])) """Create the target for Refresh Schedule.""" ta_refresher_target = Target('TARefreshRate', Arn=GetAtt(ta_refresher, 'Arn'), Id='SqsPollRate') """Create the TARefreshSchedule Rule.""" ta_refresh_schedule = template.add_resource( Rule('TARefreshSchedule', Description= 'Limit Monitor Solution - Schedule to refresh TA checks', ScheduleExpression=FindInMap('RefreshRate', 'CronSchedule', 'Default'), State='ENABLED', Targets=[ta_refresher_target], DependsOn=[ta_refresher])) """Create the Ta Refresher Lambda Permission.""" template.add_resource( Permission('TARefresherInvokePermission', FunctionName=Ref(ta_refresher), Action='lambda:InvokeFunction', Principal='events.amazonaws.com', SourceArn=GetAtt(ta_refresh_schedule, 'Arn'), DependsOn=[ta_refresher])) """Create the Limtr Helper Role.""" limtr_helper_role = template.add_resource( Role('LimtrHelperRole', AssumeRolePolicyDocument=PolicyDocument( Version='2012-10-17', Statement=[ Statement(Effect=Allow, Action=[awacs.sts.AssumeRole], Principal=Principal( 'Service', ['lambda.amazonaws.com'])) ]), Path='/', Policies=[ Policy(PolicyDocument=PolicyDocument( Version='2012-10-17', Statement=[ Statement(Effect=Allow, Action=[ CreateLogGroup, CreateLogStream, PutLogEvents ], Resource=[ Join(':', [ 'arn:aws:logs', Ref('AWS::Region'), Ref('AWS::AccountId'), 'log-group', '/aws/lambda/*' ]) ]), Statement( Effect=Allow, Action=[PutPermission, RemovePermission], Resource=[ Join(':', [ 'arn:aws:events', Ref('AWS::Region'), Ref('AWS::AccountId'), 'event-bus/default' ]) ]), Statement( Effect=Allow, Action=[GetParameters, PutParameter], Resource=[ Join(':', [ 'arn:aws:ssm', Ref('AWS::Region'), Ref('AWS::AccountId'), 'parameter/*' ]) ]) ]), PolicyName='Custom_Limtr_Helper_Permissions') ])) """Create the Lambda Function for the Limtr Helper.""" limtr_helper = template.add_resource( Function( 'LimtrHelperFunction', Description= 'This function generates UUID, establishes cross account trust ' 'on CloudWatch Event Bus and sends anonymous metric', Handler='index.handler', Environment=Environment(Variables={'LOG_LEVEL': 'ERROR'}), Code=Code(S3Bucket=Join( '-', [s3_bucket, Ref('AWS::Region')]), S3Key=Join('/', [s3_key, 'limtr-helper-service.zip'])), Role=GetAtt(limtr_helper_role, 'Arn'), Runtime='nodejs8.10', Timeout=300, DependsOn=[limtr_helper_role])) """Create the Custom Resource UUID.""" create_uuid = template.add_resource( CustomUUID('CreateUUID', ServiceToken=GetAtt(limtr_helper, 'Arn'))) """Create the Custom Resource DeploymentData.""" template.add_resource( CustomDeploymentData('DeploymentData', ServiceToken=GetAtt(limtr_helper, 'Arn'), SOLUTION='SO0005', UUID=Ref(create_uuid), VERSION='v5.1.1', ANONYMOUS_DATA=FindInMap( 'MetricsMap', 'Send-Data', 'SendAnonymousData'))) """Output for Service Checks.""" template.add_output( Output('ServiceChecks', Description='Service limits monitored in the account', Value=str(service_item[:-1])))
def create_template(): t = Template(Description="Infrastructure for routezero") api_key = t.add_parameter(Parameter("ZerotierApiKey", Type="String", NoEcho=True)) network_id = t.add_parameter(Parameter("ZerotierNetworkId", Type="String")) role = t.add_resource( Role( "Role", AssumeRolePolicyDocument=get_lambda_assumerole_policy(), Policies=[ Policy( PolicyName="cloudformation-route53-update", PolicyDocument=PolicyDocument( Statement=[ Statement( Effect=Allow, Action=[ cloudformation.Action("*"), route53.Action("*"), ], Resource=["*"], ) ] ), ) ], ManagedPolicyArns=[ "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" ], ) ) function = t.add_resource( CLIFunction( "Function", MemorySize=256, Timeout=60 * 15, Handler=".".join([routezero.__name__, routezero.handler.__name__]), Runtime="python3.6", Code=create_bundle(), Role=GetAtt(role, "Arn"), Environment=Environment( Variables={ "ZEROTIER_API_KEY": Ref(api_key), "ZEROTIER_NETWORK_ID": Ref(network_id), "ROUTE53_RECORD_STACK_NAME": Sub("${AWS::StackName}Records"), } ), ) ) log_group = t.add_resource( LogGroup( "LogGroup", LogGroupName=Sub("/aws/lambda/${Function}"), RetentionInDays=30 ) ) permission = t.add_resource( Permission( "Permission", FunctionName=GetAtt(function, "Arn"), Principal="events.amazonaws.com", Action="lambda:InvokeFunction", SourceArn=Sub( "arn:${AWS::Partition}:events:${AWS::Region}:${AWS::AccountId}:rule/*" ), DependsOn=[log_group], ) ) rule = t.add_resource( Rule( "Rule", ScheduleExpression="rate(15 minutes)", Targets=[Target(Id=Ref(function), Arn=GetAtt(function, "Arn"))], DependsOn=[permission], ) ) return t
}, )) cw_rule_target = Target(Arn=Join('', [ "arn:aws:codepipeline:", Ref('regionparameter'), ':', Ref('accountparameter'), ':', Ref('pipeline') ]), Id='mlTargert1', RoleArn=GetAtt("CloudWatchEventExecutionRole", "Arn")) pipeline_cw_rule = t.add_resource( Rule('mlpipelinerule', Description='Triggers codepipeline', EventPattern=cw_event_pattern, State='ENABLED', Targets=[cw_rule_target])) # This role allows sagemaker to do things like use the kms key that was used to encrypt the contents of the input and # output buckets as well as pull docker container images from the ecr repo. SagemakerExecutionRole = t.add_resource( Role( "SagemakerExecutionRole", Path="/", Policies=[ Policy(PolicyName="SagemakerExecutionRole", PolicyDocument={ "Version": "2012-10-17", "Statement": [{
""" Python Script : cloud_watch/function_schedules.py This script creates the CloudWatch Events that will be used to schedule Lambda functions. Within each function definition we create a Target object. These objects need to be imported here and added to the correct scheduling definition. """ # REQUIRED MODULE IMPORTS from troposphere.events import Rule # IMPORT FUNCTION TARGETS from templates import lambda_template [function, target] = lambda_template.lambda_configuration('url_string_check') url_string_check_target = target print(url_string_check_target) # initiate empty list to add targets resources = [] """ SCHEDULE DEFINITIONS """ url_check_schedule = Rule('UrlCheckSchedule', Description='testing', Name='url-check-schedule', ScheduleExpression="cron(0/5 * * * ? *)", Targets=[url_string_check_target]) resources.append(url_check_schedule)
def __init__(self, title, template, dependencies, network_config, lambda_config): """ Amazonia lambda unit definition http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lambda-function.html https://github.com/cloudtools/troposphere/blob/master/troposphere/awslambda.py :param title: Title of the autoscaling application e.g 'webApp1', 'api2' or 'dataprocessing' :param template: Troposphere stack to append resources to :param dependencies: list of unit names this unit needs access to :param network_config: object containing network related variables :param lambda_config: object containing lambda related variables """ super(Lambda, self).__init__(vpc=network_config.vpc, title=title, template=template) self.title = title self.dependencies = dependencies if dependencies else [] self.function_name = Join( '', [Ref('AWS::StackName'), '-', lambda_config.lambda_function_name]) self.trop_lambda_function = template.add_resource( Function(self.title, Code=Code(S3Bucket=lambda_config.lambda_s3_bucket, S3Key=lambda_config.lambda_s3_key), Description=lambda_config.lambda_description, FunctionName=self.function_name, Handler=lambda_config.lambda_handler, MemorySize=lambda_config.lambda_memory_size, Role=lambda_config.lambda_role_arn, Runtime=lambda_config.lambda_runtime, Timeout=lambda_config.lambda_timeout, VpcConfig=VPCConfig( SubnetIds=network_config.private_subnets, SecurityGroupIds=[self.security_group]))) self.add_egress(receiver=network_config.public_cidr, port='-1') # All Traffic to Nat gateways if lambda_config.lambda_schedule: self.cwa_name = Join('', [ Ref('AWS::StackName'), '-', lambda_config.lambda_function_name + 'Rule' ]) self.trop_cw_rule = template.add_resource( Rule(self.title + 'Rule', Name=self.cwa_name, ScheduleExpression=lambda_config.lambda_schedule, State='ENABLED', Targets=[ Target(Arn=GetAtt(self.trop_lambda_function, 'Arn'), Id=title) ])) self.trop_cw_permission = template.add_resource( Permission(self.title + 'RulePermission', Action='lambda:InvokeFunction', FunctionName=GetAtt(self.trop_lambda_function, 'Arn'), Principal='events.amazonaws.com', SourceArn=GetAtt(self.trop_cw_rule, 'Arn')))
def scaffold(self): """ Create long lived stack resources for the cluster """ self.t.add_resource( Cluster("Cluster", ClusterName=self.cluster_vars['name'])) OUTPUT_SG = ["ALB", "DB", "Cache", "Aux"] for sg in OUTPUT_SG: tmpsg = SecurityGroup( "{}BadgeSg".format(sg), GroupDescription= "SG for {} to wear in order to talk to ecs instances".format( sg), VpcId=self.cluster_vars.get('vpc')) self.t.add_resource(tmpsg) self.t.add_output( Output("{}BadgeSg".format(sg), Description="{} Security Group Badge".format(sg), Export=Export(Sub("${AWS::StackName}:%sBadgeSg" % sg)), Value=GetAtt(tmpsg, "GroupId"))) # Refactor like this ### removing this because it's in the agent now add_asg_cleanup(self.t, sanitize_cfn_resource_name(self.cluster_vars['name'])) # add metric lambda self.t.add_resource( Function("ECSMetricLambda", Code=Code(S3Bucket=Sub("${S3Bucket}"), S3Key=Sub("${S3Prefix}/deployment.zip")), Handler="metrics.cluster_metrics.lambda_handler", Role=GetAtt("CronLambdaRole", "Arn"), Runtime="python3.7", MemorySize=128, Timeout=300, Environment=Environment( Variables={ "CLUSTER": Sub("${ClusterName}"), "ASGPREFIX": Sub("${ClusterName}-asg-"), "REGION": Ref("AWS::Region") }))) self.t.add_resource( Role("CronLambdaRole", AssumeRolePolicyDocument={ "Statement": [{ "Effect": "Allow", "Action": "sts:AssumeRole", "Principal": { "Service": "lambda.amazonaws.com" }, }] }, Policies=[ Policy(PolicyName="logs-and-stuff", PolicyDocument={ "Statement": [{ "Effect": "Allow", "Action": ["logs:*"], "Resource": "arn:aws:logs:*:*:*" }, { "Effect": "Allow", "Action": [ "ec2:DescribeAutoScalingGroups", "ec2:UpdateAutoScalingGroup", "ecs:*", "cloudwatch:PutMetricData" ], "Resource": "*" }] }) ])) # run metrics every minute self.t.add_resource( Rule( "CronStats", ScheduleExpression="rate(1 minute)", Description="Cron for cluster stats", Targets=[Target(Id="1", Arn=GetAtt("ECSMetricLambda", "Arn"))])) self.t.add_resource( Permission("StatPerm", Action="lambda:InvokeFunction", FunctionName=GetAtt("ECSMetricLambda", "Arn"), Principal="events.amazonaws.com", SourceArn=GetAtt("CronStats", "Arn")))
"Effect": "Allow", "Resource": [ Ref(video_step_function), ], }], }) ], )) template.add_resource( Rule('StartMetadataRule', Description= 'Routes start metadata events to the corresponding step functions', EventBusName=Ref(event_bus), EventPattern={"source": ["spunt.video.events"]}, Targets=[ Target( Arn=Ref(video_step_function), Id='VideoStepFunction', RoleArn=GetAtt(event_bridge_role, 'Arn'), ) ])) start_insights_role = template.add_resource( Role( 'StartInsightsLambdaRole', Path="/", AssumeRolePolicyDocument={ "Version": "2012-10-17", "Statement": [{ "Action": ["sts:AssumeRole"],
def create_template(): template = Template(Description=( "Static website hosted with S3 and CloudFront. " "https://github.com/schlarpc/overengineered-cloudfront-s3-static-website" )) partition_config = add_mapping( template, "PartitionConfig", { "aws": { # the region with the control plane for CloudFront, IAM, Route 53, etc "PrimaryRegion": "us-east-1", # assume that Lambda@Edge replicates to all default enabled regions, and that # future regions will be opt-in. generated with AWS CLI: # aws ec2 describe-regions --all-regions --query "Regions[?OptInStatus=='opt-in-not-required'].RegionName|sort(@)" "DefaultRegions": [ "ap-northeast-1", "ap-northeast-2", "ap-northeast-3", "ap-south-1", "ap-southeast-1", "ap-southeast-2", "ca-central-1", "eu-central-1", "eu-north-1", "eu-west-1", "eu-west-2", "eu-west-3", "sa-east-1", "us-east-1", "us-east-2", "us-west-1", "us-west-2", ], }, # this doesn't actually work, because Lambda@Edge isn't supported in aws-cn "aws-cn": { "PrimaryRegion": "cn-north-1", "DefaultRegions": ["cn-north-1", "cn-northwest-1"], }, }, ) acm_certificate_arn = template.add_parameter( Parameter( "AcmCertificateArn", Description= "Existing ACM certificate to use for serving TLS. Overrides HostedZoneId.", Type="String", AllowedPattern="(arn:[^:]+:acm:[^:]+:[^:]+:certificate/.+|)", Default="", )) hosted_zone_id = template.add_parameter( Parameter( "HostedZoneId", Description= "Existing Route 53 zone to use for validating a new TLS certificate.", Type="String", AllowedPattern="(Z[A-Z0-9]+|)", Default="", )) dns_names = template.add_parameter( Parameter( "DomainNames", Description= "Comma-separated list of additional domain names to serve.", Type="CommaDelimitedList", Default="", )) tls_protocol_version = template.add_parameter( Parameter( "TlsProtocolVersion", Description= "CloudFront TLS security policy; see https://amzn.to/2DR91Xq for details.", Type="String", Default="TLSv1.2_2019", )) log_retention_days = template.add_parameter( Parameter( "LogRetentionDays", Description= "Days to keep CloudFront, S3, and Lambda logs. 0 means indefinite retention.", Type="Number", AllowedValues=[0] + CLOUDWATCH_LOGS_RETENTION_OPTIONS, Default=365, )) default_ttl_seconds = template.add_parameter( Parameter( "DefaultTtlSeconds", Description="Cache time-to-live when not set by S3 object headers.", Type="Number", Default=int(datetime.timedelta(minutes=5).total_seconds()), )) enable_price_class_hack = template.add_parameter( Parameter( "EnablePriceClassHack", Description="Cut your bill in half with this one weird trick.", Type="String", Default="false", AllowedValues=["true", "false"], )) retention_defined = add_condition(template, "RetentionDefined", Not(Equals(Ref(log_retention_days), 0))) using_price_class_hack = add_condition( template, "UsingPriceClassHack", Equals(Ref(enable_price_class_hack), "true")) using_acm_certificate = add_condition( template, "UsingAcmCertificate", Not(Equals(Ref(acm_certificate_arn), ""))) using_hosted_zone = add_condition(template, "UsingHostedZone", Not(Equals(Ref(hosted_zone_id), ""))) using_certificate = add_condition( template, "UsingCertificate", Or(Condition(using_acm_certificate), Condition(using_hosted_zone)), ) should_create_certificate = add_condition( template, "ShouldCreateCertificate", And(Condition(using_hosted_zone), Not(Condition(using_acm_certificate))), ) using_dns_names = add_condition(template, "UsingDnsNames", Not(Equals(Select(0, Ref(dns_names)), ""))) is_primary_region = "IsPrimaryRegion" template.add_condition( is_primary_region, Equals(Region, FindInMap(partition_config, Partition, "PrimaryRegion")), ) precondition_region_is_primary = template.add_resource( WaitConditionHandle( "PreconditionIsPrimaryRegionForPartition", Condition=is_primary_region, )) log_ingester_dlq = template.add_resource( Queue( "LogIngesterDLQ", MessageRetentionPeriod=int( datetime.timedelta(days=14).total_seconds()), KmsMasterKeyId="alias/aws/sqs", )) log_ingester_role = template.add_resource( Role( "LogIngesterRole", AssumeRolePolicyDocument=PolicyDocument( Version="2012-10-17", Statement=[ Statement( Effect="Allow", Principal=Principal("Service", "lambda.amazonaws.com"), Action=[sts.AssumeRole], ) ], ), Policies=[ PolicyProperty( PolicyName="DLQPolicy", PolicyDocument=PolicyDocument( Version="2012-10-17", Statement=[ Statement( Effect=Allow, Action=[sqs.SendMessage], Resource=[GetAtt(log_ingester_dlq, "Arn")], ) ], ), ) ], )) log_ingester = template.add_resource( Function( "LogIngester", Runtime=PYTHON_RUNTIME, Handler="index.{}".format(log_ingest.handler.__name__), Code=Code(ZipFile=inspect.getsource(log_ingest)), MemorySize=256, Timeout=300, Role=GetAtt(log_ingester_role, "Arn"), DeadLetterConfig=DeadLetterConfig( TargetArn=GetAtt(log_ingester_dlq, "Arn")), )) log_ingester_permission = template.add_resource( Permission( "LogIngesterPermission", FunctionName=GetAtt(log_ingester, "Arn"), Action="lambda:InvokeFunction", Principal="s3.amazonaws.com", SourceAccount=AccountId, )) log_bucket = template.add_resource( Bucket( "LogBucket", # S3 requires this ACL (regardless of bucket policy) or s3:PutBucketLogging fails. # When the CloudFront distribution is created, it adds an additional bucket ACL. # That ACL is not possible to model in CloudFormation. AccessControl="LogDeliveryWrite", LifecycleConfiguration=LifecycleConfiguration(Rules=[ LifecycleRule(ExpirationInDays=1, Status="Enabled"), LifecycleRule( AbortIncompleteMultipartUpload= AbortIncompleteMultipartUpload(DaysAfterInitiation=1), Status="Enabled", ), ]), NotificationConfiguration=NotificationConfiguration( LambdaConfigurations=[ LambdaConfigurations(Event="s3:ObjectCreated:*", Function=GetAtt(log_ingester, "Arn")) ]), BucketEncryption=BucketEncryption( ServerSideEncryptionConfiguration=[ ServerSideEncryptionRule( ServerSideEncryptionByDefault= ServerSideEncryptionByDefault( # if we use KMS, we can't read the logs SSEAlgorithm="AES256")) ]), OwnershipControls=OwnershipControls(Rules=[ OwnershipControlsRule(ObjectOwnership="BucketOwnerPreferred") ], ), PublicAccessBlockConfiguration=PublicAccessBlockConfiguration( BlockPublicAcls=True, BlockPublicPolicy=True, IgnorePublicAcls=True, RestrictPublicBuckets=True, ), DependsOn=[log_ingester_permission], )) log_ingester_log_group = template.add_resource( LogGroup( "LogIngesterLogGroup", LogGroupName=Join( "", ["/aws/lambda/", Ref(log_ingester)]), RetentionInDays=If(retention_defined, Ref(log_retention_days), NoValue), )) log_ingester_policy = template.add_resource( PolicyType( "LogIngesterPolicy", Roles=[Ref(log_ingester_role)], PolicyName="IngestLogPolicy", PolicyDocument=PolicyDocument( Version="2012-10-17", Statement=[ Statement( Effect=Allow, Action=[logs.CreateLogStream, logs.PutLogEvents], Resource=[ Join( ":", [ "arn", Partition, "logs", Region, AccountId, "log-group", "/aws/cloudfront/*", ], ), Join( ":", [ "arn", Partition, "logs", Region, AccountId, "log-group", "/aws/s3/*", ], ), GetAtt(log_ingester_log_group, "Arn"), ], ), Statement( Effect=Allow, Action=[s3.GetObject], Resource=[Join("", [GetAtt(log_bucket, "Arn"), "/*"])], ), ], ), )) bucket = template.add_resource( Bucket( "ContentBucket", LifecycleConfiguration=LifecycleConfiguration(Rules=[ # not supported by CFN yet: # LifecycleRule( # Transitions=[ # LifecycleRuleTransition( # StorageClass='INTELLIGENT_TIERING', # TransitionInDays=1, # ), # ], # Status="Enabled", # ), LifecycleRule( AbortIncompleteMultipartUpload= AbortIncompleteMultipartUpload(DaysAfterInitiation=7), Status="Enabled", ) ]), LoggingConfiguration=LoggingConfiguration( DestinationBucketName=Ref(log_bucket), LogFilePrefix="s3/"), BucketEncryption=BucketEncryption( ServerSideEncryptionConfiguration=[ ServerSideEncryptionRule( ServerSideEncryptionByDefault= ServerSideEncryptionByDefault( # Origin Access Identities can't use KMS SSEAlgorithm="AES256")) ]), OwnershipControls=OwnershipControls(Rules=[ OwnershipControlsRule(ObjectOwnership="BucketOwnerPreferred") ], ), PublicAccessBlockConfiguration=PublicAccessBlockConfiguration( BlockPublicAcls=True, BlockPublicPolicy=True, IgnorePublicAcls=True, RestrictPublicBuckets=True, ), )) origin_access_identity = template.add_resource( CloudFrontOriginAccessIdentity( "CloudFrontIdentity", CloudFrontOriginAccessIdentityConfig= CloudFrontOriginAccessIdentityConfig( Comment=GetAtt(bucket, "Arn")), )) bucket_policy = template.add_resource( BucketPolicy( "ContentBucketPolicy", Bucket=Ref(bucket), PolicyDocument=PolicyDocument( Version="2012-10-17", Statement=[ Statement( Effect=Allow, Principal=Principal( "CanonicalUser", GetAtt(origin_access_identity, "S3CanonicalUserId"), ), Action=[s3.GetObject], Resource=[Join("", [GetAtt(bucket, "Arn"), "/*"])], ), ], ), )) # Not strictly necessary, as ACLs should take care of this access. However, CloudFront docs # state "In some circumstances [...] S3 resets permissions on the bucket to the default value", # and this allows logging to work without any ACLs in place. log_bucket_policy = template.add_resource( BucketPolicy( "LogBucketPolicy", Bucket=Ref(log_bucket), PolicyDocument=PolicyDocument( Version="2012-10-17", Statement=[ Statement( Effect=Allow, Principal=Principal("Service", "delivery.logs.amazonaws.com"), Action=[s3.PutObject], Resource=[ Join( "/", [GetAtt(log_bucket, "Arn"), "cloudfront", "*"]) ], ), Statement( Effect=Allow, Principal=Principal("Service", "delivery.logs.amazonaws.com"), Action=[s3.ListBucket], Resource=[Join("/", [GetAtt(log_bucket, "Arn")])], ), Statement( Effect=Allow, Principal=Principal("Service", "s3.amazonaws.com"), Action=[s3.PutObject], Resource=[ Join("/", [GetAtt(log_bucket, "Arn"), "s3", "*"]) ], ), ], ), )) certificate_validator_dlq = template.add_resource( Queue( "CertificateValidatorDLQ", MessageRetentionPeriod=int( datetime.timedelta(days=14).total_seconds()), KmsMasterKeyId="alias/aws/sqs", Condition=should_create_certificate, )) certificate_validator_role = template.add_resource( Role( "CertificateValidatorRole", AssumeRolePolicyDocument=PolicyDocument( Version="2012-10-17", Statement=[ Statement( Effect="Allow", Principal=Principal("Service", "lambda.amazonaws.com"), Action=[sts.AssumeRole], ) ], ), Policies=[ PolicyProperty( PolicyName="DLQPolicy", PolicyDocument=PolicyDocument( Version="2012-10-17", Statement=[ Statement( Effect=Allow, Action=[sqs.SendMessage], Resource=[ GetAtt(certificate_validator_dlq, "Arn") ], ) ], ), ) ], # TODO scope down ManagedPolicyArns=[ "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole", "arn:aws:iam::aws:policy/AmazonRoute53FullAccess", "arn:aws:iam::aws:policy/AWSCertificateManagerReadOnly", ], Condition=should_create_certificate, )) certificate_validator_function = template.add_resource( Function( "CertificateValidatorFunction", Runtime=PYTHON_RUNTIME, Handler="index.{}".format(certificate_validator.handler.__name__), Code=Code(ZipFile=inspect.getsource(certificate_validator)), MemorySize=256, Timeout=300, Role=GetAtt(certificate_validator_role, "Arn"), DeadLetterConfig=DeadLetterConfig( TargetArn=GetAtt(certificate_validator_dlq, "Arn")), Environment=Environment( Variables={ certificate_validator.EnvVars.HOSTED_ZONE_ID.name: Ref(hosted_zone_id) }), Condition=should_create_certificate, )) certificate_validator_log_group = template.add_resource( LogGroup( "CertificateValidatorLogGroup", LogGroupName=Join( "", ["/aws/lambda/", Ref(certificate_validator_function)]), RetentionInDays=If(retention_defined, Ref(log_retention_days), NoValue), Condition=should_create_certificate, )) certificate_validator_rule = template.add_resource( Rule( "CertificateValidatorRule", EventPattern={ "detail-type": ["AWS API Call via CloudTrail"], "detail": { "eventSource": ["acm.amazonaws.com"], "eventName": ["AddTagsToCertificate"], "requestParameters": { "tags": { "key": [certificate_validator_function.title], "value": [GetAtt(certificate_validator_function, "Arn")], } }, }, }, Targets=[ Target( Id="certificate-validator-lambda", Arn=GetAtt(certificate_validator_function, "Arn"), ) ], DependsOn=[certificate_validator_log_group], Condition=should_create_certificate, )) certificate_validator_permission = template.add_resource( Permission( "CertificateValidatorPermission", FunctionName=GetAtt(certificate_validator_function, "Arn"), Action="lambda:InvokeFunction", Principal="events.amazonaws.com", SourceArn=GetAtt(certificate_validator_rule, "Arn"), Condition=should_create_certificate, )) certificate = template.add_resource( Certificate( "Certificate", DomainName=Select(0, Ref(dns_names)), SubjectAlternativeNames=Ref( dns_names), # duplicate first name works fine ValidationMethod="DNS", Tags=Tags( **{ certificate_validator_function.title: GetAtt(certificate_validator_function, "Arn") }), DependsOn=[certificate_validator_permission], Condition=should_create_certificate, )) edge_hook_role = template.add_resource( Role( "EdgeHookRole", AssumeRolePolicyDocument=PolicyDocument( Version="2012-10-17", Statement=[ Statement( Effect="Allow", Principal=Principal( "Service", [ "lambda.amazonaws.com", "edgelambda.amazonaws.com" ], ), Action=[sts.AssumeRole], ) ], ), )) edge_hook_function = template.add_resource( Function( "EdgeHookFunction", Runtime=PYTHON_RUNTIME, Handler="index.handler", Code=Code(ZipFile=inspect.getsource(edge_hook)), MemorySize=128, Timeout=3, Role=GetAtt(edge_hook_role, "Arn"), )) edge_hook_function_hash = (hashlib.sha256( json.dumps(edge_hook_function.to_dict(), sort_keys=True).encode("utf-8")).hexdigest()[:10].upper()) edge_hook_version = template.add_resource( Version( "EdgeHookVersion" + edge_hook_function_hash, FunctionName=GetAtt(edge_hook_function, "Arn"), )) replica_log_group_name = Join( "/", [ "/aws/lambda", Join( ".", [ FindInMap(partition_config, Partition, "PrimaryRegion"), Ref(edge_hook_function), ], ), ], ) edge_hook_role_policy = template.add_resource( PolicyType( "EdgeHookRolePolicy", PolicyName="write-logs", PolicyDocument=PolicyDocument( Version="2012-10-17", Statement=[ Statement( Effect=Allow, Action=[logs.CreateLogStream, logs.PutLogEvents], Resource=[ Join( ":", [ "arn", Partition, "logs", "*", AccountId, "log-group", replica_log_group_name, "log-stream", "*", ], ), ], ), ], ), Roles=[Ref(edge_hook_role)], )) stack_set_administration_role = template.add_resource( Role( "StackSetAdministrationRole", AssumeRolePolicyDocument=PolicyDocument( Version="2012-10-17", Statement=[ Statement( Effect=Allow, Principal=Principal("Service", "cloudformation.amazonaws.com"), Action=[sts.AssumeRole], ), ], ), )) stack_set_execution_role = template.add_resource( Role( "StackSetExecutionRole", AssumeRolePolicyDocument=PolicyDocument( Version="2012-10-17", Statement=[ Statement( Effect=Allow, Principal=Principal( "AWS", GetAtt(stack_set_administration_role, "Arn")), Action=[sts.AssumeRole], ), ], ), Policies=[ PolicyProperty( PolicyName="create-stackset-instances", PolicyDocument=PolicyDocument( Version="2012-10-17", Statement=[ Statement( Effect=Allow, Action=[ cloudformation.DescribeStacks, logs.DescribeLogGroups, ], Resource=["*"], ), # stack instances communicate with the CFN service via SNS Statement( Effect=Allow, Action=[sns.Publish], NotResource=[ Join( ":", [ "arn", Partition, "sns", "*", AccountId, "*" ], ) ], ), Statement( Effect=Allow, Action=[ logs.CreateLogGroup, logs.DeleteLogGroup, logs.PutRetentionPolicy, logs.DeleteRetentionPolicy, ], Resource=[ Join( ":", [ "arn", Partition, "logs", "*", AccountId, "log-group", replica_log_group_name, "log-stream", "", ], ), ], ), Statement( Effect=Allow, Action=[ cloudformation.CreateStack, cloudformation.DeleteStack, cloudformation.UpdateStack, ], Resource=[ Join( ":", [ "arn", Partition, "cloudformation", "*", AccountId, Join( "/", [ "stack", Join( "-", [ "StackSet", StackName, "*" ], ), ], ), ], ) ], ), ], ), ), ], )) stack_set_administration_role_policy = template.add_resource( PolicyType( "StackSetAdministrationRolePolicy", PolicyName="assume-execution-role", PolicyDocument=PolicyDocument( Version="2012-10-17", Statement=[ Statement( Effect=Allow, Action=[sts.AssumeRole], Resource=[GetAtt(stack_set_execution_role, "Arn")], ), ], ), Roles=[Ref(stack_set_administration_role)], )) edge_log_groups = template.add_resource( StackSet( "EdgeLambdaLogGroupStackSet", AdministrationRoleARN=GetAtt(stack_set_administration_role, "Arn"), ExecutionRoleName=Ref(stack_set_execution_role), StackSetName=Join("-", [StackName, "EdgeLambdaLogGroup"]), PermissionModel="SELF_MANAGED", Description="Multi-region log groups for Lambda@Edge replicas", Parameters=[ StackSetParameter( ParameterKey="LogGroupName", ParameterValue=replica_log_group_name, ), StackSetParameter( ParameterKey="LogRetentionDays", ParameterValue=Ref(log_retention_days), ), ], OperationPreferences=OperationPreferences( FailureToleranceCount=0, MaxConcurrentPercentage=100, ), StackInstancesGroup=[ StackInstances( DeploymentTargets=DeploymentTargets(Accounts=[AccountId]), Regions=FindInMap(partition_config, Partition, "DefaultRegions"), ) ], TemplateBody=create_log_group_template().to_json(indent=None), DependsOn=[stack_set_administration_role_policy], )) price_class_distribution = template.add_resource( Distribution( "PriceClassDistribution", DistributionConfig=DistributionConfig( Comment="Dummy distribution used for price class hack", DefaultCacheBehavior=DefaultCacheBehavior( TargetOriginId="default", ViewerProtocolPolicy="allow-all", ForwardedValues=ForwardedValues(QueryString=False), ), Enabled=True, Origins=[ Origin(Id="default", DomainName=GetAtt(bucket, "DomainName")) ], IPV6Enabled=True, ViewerCertificate=ViewerCertificate( CloudFrontDefaultCertificate=True), PriceClass="PriceClass_All", ), Condition=using_price_class_hack, )) distribution = template.add_resource( Distribution( "ContentDistribution", DistributionConfig=DistributionConfig( Enabled=True, Aliases=If(using_dns_names, Ref(dns_names), NoValue), Logging=Logging(Bucket=GetAtt(log_bucket, "DomainName"), Prefix="cloudfront/"), DefaultRootObject="index.html", Origins=[ Origin( Id="default", DomainName=GetAtt(bucket, "DomainName"), S3OriginConfig=S3OriginConfig( OriginAccessIdentity=Join( "", [ "origin-access-identity/cloudfront/", Ref(origin_access_identity), ], )), ) ], DefaultCacheBehavior=DefaultCacheBehavior( TargetOriginId="default", Compress=True, ForwardedValues=ForwardedValues(QueryString=False), ViewerProtocolPolicy="redirect-to-https", DefaultTTL=Ref(default_ttl_seconds), LambdaFunctionAssociations=[ LambdaFunctionAssociation( EventType="origin-request", LambdaFunctionARN=Ref(edge_hook_version), ) ], ), HttpVersion="http2", IPV6Enabled=True, ViewerCertificate=ViewerCertificate( AcmCertificateArn=If( using_acm_certificate, Ref(acm_certificate_arn), If(using_hosted_zone, Ref(certificate), NoValue), ), SslSupportMethod=If(using_certificate, "sni-only", NoValue), CloudFrontDefaultCertificate=If(using_certificate, NoValue, True), MinimumProtocolVersion=Ref(tls_protocol_version), ), PriceClass=If(using_price_class_hack, "PriceClass_100", "PriceClass_All"), ), DependsOn=[ bucket_policy, log_ingester_policy, edge_log_groups, precondition_region_is_primary, ], )) distribution_log_group = template.add_resource( LogGroup( "DistributionLogGroup", LogGroupName=Join( "", ["/aws/cloudfront/", Ref(distribution)]), RetentionInDays=If(retention_defined, Ref(log_retention_days), NoValue), )) bucket_log_group = template.add_resource( LogGroup( "BucketLogGroup", LogGroupName=Join("", ["/aws/s3/", Ref(bucket)]), RetentionInDays=If(retention_defined, Ref(log_retention_days), NoValue), )) template.add_output(Output("DistributionId", Value=Ref(distribution))) template.add_output( Output("DistributionDomain", Value=GetAtt(distribution, "DomainName"))) template.add_output( Output( "DistributionDnsTarget", Value=If( using_price_class_hack, GetAtt(price_class_distribution, "DomainName"), GetAtt(distribution, "DomainName"), ), )) template.add_output( Output( "DistributionUrl", Value=Join("", ["https://", GetAtt(distribution, "DomainName"), "/"]), )) template.add_output(Output("ContentBucketArn", Value=GetAtt(bucket, "Arn"))) return template
EventRule = t.add_resource(Rule( "DockerStaticWebsiteEventRule", Name='codepipeline-DockerStaticWebsiteEventRule', State='ENABLED', Description='Amazon CloudWatch Events rule to automatically start your pipeline when a change occurs in the Amazon S3 object key or S3 folder. Deleting this may prevent changes from being detected in that pipeline. Read more: http://docs.aws.amazon.com/codepipeline/latest/userguide/pipelines-about-starting.html', EventPattern={ "source": [ "aws.s3" ], "detail-type": [ "AWS API Call via CloudTrail" ], "detail": { "eventSource": [ "s3.amazonaws.com" ], "eventName": [ "PutObject", "CompleteMultipartUpload", "CopyObject" ], "requestParameters": { "bucketName": [ {"Ref": S3_DELIVERY_BUCKET} ], "key": [ S3_OBJECT_Key ] } } }, Targets=[ Target( Arn=Join( "", ['arn:aws:codepipeline:', Region, ":", AccountId, ":", BUILD_NAME] ), Id='CodePipelineTarget', RoleArn=GetAtt(EventRole, "Arn"), ) ] ))
# Create the Lambda function foobar_function = t.add_resource( Function( "FoobarFunction", Code=Code(ZipFile=Join("", code)), Handler="index.handler", Role=GetAtt("LambdaExecutionRole", "Arn"), Runtime="nodejs", )) # Create the Event Target foobar_target = Target("FoobarTarget", Arn=GetAtt('FoobarFunction', 'Arn'), Id="FooBarFunction1") # Create the Event Rule rule = t.add_resource( Rule("FoobarRule", EventPattern={ "source": ["aws.ec2"], "detail-type": ["EC2 Instance State-change Notification"], "detail": { "state": ["stopping"] } }, Description="Foobar CloudWatch Event", State="ENABLED", Targets=[foobar_target])) print(t.to_json())
], Resource=["arn:aws:logs:*:*:*"]) ])) ])) # Create the Event Target GuardDutyEventTarget = Target("GuardDutyEventTarget", Arn=GetAtt('GuardDutyToSlackFunction', 'Arn'), Id="GuardDutyToSlackFunction") # Create the Event Rule GuardDutyEventRule = t.add_resource( Rule("GuardDutyEventRule", EventPattern={ "source": ["aws.guardduty"], "detail-type": ["GuardDuty Finding"] }, Description="GuardDuty CloudWatch Event Rule", State="ENABLED", Targets=[GuardDutyEventTarget])) # Create invoke Permission APILambdaPermission = t.add_resource( awslambda.Permission("APILambdaPermission", DependsOn="GuardDutyToSlackFunction", Action="lambda:InvokeFunction", FunctionName=GetAtt('GuardDutyToSlackFunction', 'Arn'), Principal="events.amazonaws.com", SourceArn=GetAtt('GuardDutyEventRule', 'Arn'))) print t.to_json()
"Function deletes volume snapshots basted on ec2 instance tags", Code=Code(S3Bucket=Ref(s3_bucket), S3Key="backup-manager.zip"), Handler="ebs-snapshot-manager.lambda_handler", Role=GetAtt("LambdaExecutionRole", "Arn"), Runtime="python2.7", MemorySize=Ref(memory_size), Timeout=Ref(timeout))) create_backup_target = Target("CreateBackupTarget", Arn=GetAtt(create_snapshots_function, 'Arn'), Id="CreateBackupFunction1") create_backup_rule = template.add_resource( Rule("CreateBackupRule", ScheduleExpression="cron(0 7 * * ? *)", Description="Create backups event rule", State="ENABLED", Targets=[create_backup_target])) manage_backup_target = Target("ManageBackupTarget", Arn=GetAtt(manage_snapshots_function, 'Arn'), Id="ManageBackupFunction1") manage_backup_rule = template.add_resource( Rule("ManageBackupRule", ScheduleExpression="cron(0 7 * * ? *)", Description="Create backups event rule", State="ENABLED", Targets=[manage_backup_target])) template.add_output([
def _deploy_service(self, service: ff.Service): context = self._context_map.get_context(service.name) if self._aws_config.get('image_uri') is None: self._package_and_deploy_code(context) template = Template() template.set_version('2010-09-09') memory_size = template.add_parameter( Parameter(f'{self._lambda_resource_name(service.name)}MemorySize', Type=NUMBER, Default=self._aws_config.get('memory_sync', '3008'))) timeout_gateway = template.add_parameter( Parameter( f'{self._lambda_resource_name(service.name)}GatewayTimeout', Type=NUMBER, Default='30')) timeout_async = template.add_parameter( Parameter( f'{self._lambda_resource_name(service.name)}AsyncTimeout', Type=NUMBER, Default='900')) role_title = f'{self._lambda_resource_name(service.name)}ExecutionRole' role = self._add_role(role_title, template) params = { 'FunctionName': f'{self._service_name(service.name)}Sync', 'Role': GetAtt(role_title, 'Arn'), 'MemorySize': Ref(memory_size), 'Timeout': Ref(timeout_gateway), 'Environment': self._lambda_environment(context) } image_uri = self._aws_config.get('image_uri') if image_uri is not None: params.update({ 'Code': Code(ImageUri=image_uri), 'PackageType': 'Image', }) else: params.update({ 'Code': Code(S3Bucket=self._bucket, S3Key=self._code_key), 'Runtime': 'python3.7', 'Handler': 'handlers.main', }) if self._security_group_ids and self._subnet_ids: params['VpcConfig'] = VPCConfig( SecurityGroupIds=self._security_group_ids, SubnetIds=self._subnet_ids) api_lambda = template.add_resource( Function(f'{self._lambda_resource_name(service.name)}Sync', **params)) route = inflection.dasherize(context.name) proxy_route = f'{route}/{{proxy+}}' template.add_resource( Permission( f'{self._lambda_resource_name(service.name)}SyncPermission', Action='lambda:InvokeFunction', FunctionName=f'{self._service_name(service.name)}Sync', Principal='apigateway.amazonaws.com', SourceArn=Join('', [ 'arn:aws:execute-api:', self._region, ':', self._account_id, ':', ImportValue( self._rest_api_reference()), '/*/*/', route, '*' ]), DependsOn=api_lambda)) if self._adaptive_memory: value = '3008' if not self._adaptive_memory else '256' try: value = int(self._aws_config.get('memory_async')) except ValueError: pass memory_size = template.add_parameter( Parameter( f'{self._lambda_resource_name(service.name)}MemorySizeAsync', Type=NUMBER, Default=value)) params = { 'FunctionName': self._lambda_function_name(service.name, 'Async'), 'Role': GetAtt(role_title, 'Arn'), 'MemorySize': Ref(memory_size), 'Timeout': Ref(timeout_async), 'Environment': self._lambda_environment(context) } if image_uri is not None: params.update({ 'Code': Code(ImageUri=image_uri), 'PackageType': 'Image', }) else: params.update({ 'Code': Code(S3Bucket=self._bucket, S3Key=self._code_key), 'Runtime': 'python3.7', 'Handler': 'handlers.main', }) if self._security_group_ids and self._subnet_ids: params['VpcConfig'] = VPCConfig( SecurityGroupIds=self._security_group_ids, SubnetIds=self._subnet_ids) async_lambda = template.add_resource( Function(self._lambda_resource_name(service.name, type_='Async'), **params)) if self._adaptive_memory: self._add_adaptive_memory_functions(template, context, timeout_async, role_title, async_lambda) # self._add_adaptive_memory_streams(template, context, async_lambda, role) # Timers for cls, _ in context.command_handlers.items(): if cls.has_timer(): timer = cls.get_timer() if timer.environment is not None and timer.environment != self._env: continue if isinstance(timer.command, str): timer_name = timer.command else: timer_name = timer.command.__name__ target = Target( f'{self._service_name(service.name)}AsyncTarget', Arn=GetAtt( self._lambda_resource_name(service.name, type_='Async'), 'Arn'), Id=self._lambda_resource_name(service.name, type_='Async'), Input= f'{{"_context": "{context.name}", "_type": "command", "_name": "{cls.__name__}"}}' ) rule = template.add_resource( Rule(f'{timer_name}TimerRule', ScheduleExpression=f'cron({timer.cron})', State='ENABLED', Targets=[target])) template.add_resource( Permission(f'{timer_name}TimerPermission', Action='lambda:invokeFunction', Principal='events.amazonaws.com', FunctionName=Ref(async_lambda), SourceArn=GetAtt(rule, 'Arn'))) integration = template.add_resource( Integration( self._integration_name(context.name), ApiId=ImportValue(self._rest_api_reference()), PayloadFormatVersion='2.0', IntegrationType='AWS_PROXY', IntegrationUri=Join('', [ 'arn:aws:lambda:', self._region, ':', self._account_id, ':function:', Ref(api_lambda), ]), )) template.add_resource( Route(f'{self._route_name(context.name)}Base', ApiId=ImportValue(self._rest_api_reference()), RouteKey=f'ANY /{route}', AuthorizationType='NONE', Target=Join( '/', ['integrations', Ref(integration)]), DependsOn=integration)) template.add_resource( Route(f'{self._route_name(context.name)}Proxy', ApiId=ImportValue(self._rest_api_reference()), RouteKey=f'ANY /{proxy_route}', AuthorizationType='NONE', Target=Join( '/', ['integrations', Ref(integration)]), DependsOn=integration)) # Error alarms / subscriptions if 'errors' in self._aws_config: alerts_topic = template.add_resource( Topic(self._alert_topic_name(service.name), TopicName=self._alert_topic_name(service.name))) if 'email' in self._aws_config.get('errors'): for address in self._aws_config.get('errors').get('email').get( 'recipients').split(','): template.add_resource( SubscriptionResource( self._alarm_subscription_name(context.name), Protocol='email', Endpoint=address, TopicArn=self._alert_topic_arn(context.name), DependsOn=[alerts_topic])) # Queues / Topics subscriptions = {} for subscription in self._get_subscriptions(context): if subscription['context'] not in subscriptions: subscriptions[subscription['context']] = [] subscriptions[subscription['context']].append(subscription) dlq = template.add_resource( Queue(f'{self._queue_name(context.name)}Dlq', QueueName=f'{self._queue_name(context.name)}Dlq', VisibilityTimeout=905, ReceiveMessageWaitTimeSeconds=20, MessageRetentionPeriod=1209600)) self._queue_policy(template, dlq, f'{self._queue_name(context.name)}Dlq', subscriptions) queue = template.add_resource( Queue(self._queue_name(context.name), QueueName=self._queue_name(context.name), VisibilityTimeout=905, ReceiveMessageWaitTimeSeconds=20, MessageRetentionPeriod=1209600, RedrivePolicy=RedrivePolicy(deadLetterTargetArn=GetAtt( dlq, 'Arn'), maxReceiveCount=1000), DependsOn=dlq)) self._queue_policy(template, queue, self._queue_name(context.name), subscriptions) template.add_resource( EventSourceMapping( f'{self._lambda_resource_name(context.name)}AsyncMapping', BatchSize=1, Enabled=True, EventSourceArn=GetAtt(queue, 'Arn'), FunctionName=self._lambda_function_name(service.name, 'Async'), DependsOn=[queue, async_lambda])) topic = template.add_resource( Topic(self._topic_name(context.name), TopicName=self._topic_name(context.name))) for context_name, list_ in subscriptions.items(): if context_name == context.name and len(list_) > 0: template.add_resource( SubscriptionResource( self._subscription_name(context_name), Protocol='sqs', Endpoint=GetAtt(queue, 'Arn'), TopicArn=self._topic_arn(context.name), FilterPolicy={ '_name': [x['name'] for x in list_], }, RedrivePolicy={ 'deadLetterTargetArn': GetAtt(dlq, 'Arn'), }, DependsOn=[queue, dlq, topic])) elif len(list_) > 0: if context_name not in self._context_map.contexts: self._find_or_create_topic(context_name) template.add_resource( SubscriptionResource( self._subscription_name(context.name, context_name), Protocol='sqs', Endpoint=GetAtt(queue, 'Arn'), TopicArn=self._topic_arn(context_name), FilterPolicy={'_name': [x['name'] for x in list_]}, RedrivePolicy={ 'deadLetterTargetArn': GetAtt(dlq, 'Arn'), }, DependsOn=[queue, dlq])) # DynamoDB Table ddb_table = template.add_resource( Table(self._ddb_resource_name(context.name), TableName=self._ddb_table_name(context.name), AttributeDefinitions=[ AttributeDefinition(AttributeName='pk', AttributeType='S'), AttributeDefinition(AttributeName='sk', AttributeType='S'), ], BillingMode='PAY_PER_REQUEST', KeySchema=[ KeySchema(AttributeName='pk', KeyType='HASH'), KeySchema(AttributeName='sk', KeyType='RANGE'), ], TimeToLiveSpecification=TimeToLiveSpecification( AttributeName='TimeToLive', Enabled=True))) template.add_output( Output("DDBTable", Value=Ref(ddb_table), Description="Document table")) for cb in self._pre_deployment_hooks: cb(template=template, context=context, env=self._env) self.info('Deploying stack') self._s3_client.put_object(Body=template.to_json(), Bucket=self._bucket, Key=self._template_key) url = self._s3_client.generate_presigned_url(ClientMethod='get_object', Params={ 'Bucket': self._bucket, 'Key': self._template_key }) stack_name = self._stack_name(context.name) try: self._cloudformation_client.describe_stacks(StackName=stack_name) self._update_stack(self._stack_name(context.name), url) except ClientError as e: if f'Stack with id {stack_name} does not exist' in str(e): self._create_stack(self._stack_name(context.name), url) else: raise e for cb in self._post_deployment_hooks: cb(template=template, context=context, env=self._env) self._migrate_schema(context) self.info('Done')
ContainerName=depend, )) definition.Links.append(depend) task.ContainerDefinitions.append(definition) t.add_resource(task) if schedule: target = Target( Id="{}-Schedule".format(name), Arn=GetAtt(netkan_ecs, 'Arn'), RoleArn=GetAtt(netkan_scheduler_role, 'Arn'), EcsParameters=EcsParameters(TaskDefinitionArn=Ref(task))) t.add_resource( Rule( '{}Rule'.format(name), Description='{} scheduled task'.format(name), ScheduleExpression=schedule, Targets=[target], )) continue t.add_resource( Service( '{}Service'.format(name), Cluster='NetKANCluster', DesiredCount=1, TaskDefinition=Ref(task), # Allow for in place service redeployments DeploymentConfiguration=DeploymentConfiguration( MaximumPercent=100, MinimumHealthyPercent=0), DependsOn=['NetKANCluster']))
"Timeout": 60 } )) custom_metric_target = Target( "CustomMetricTarget", Arn=GetAtt(custom_metric, 'Arn'), Id="CustomMetricFunction1", Input=Sub( '{"QueueUrl":"${QueueUrl}","AutoScalingGroupName":"${AGName}","MetricName":"${MetricName}"}', QueueUrl=Ref(start_events), AGName=Ref(processing_group), MetricName=custom_metric_name ) ) custom_metric_rule = t.add_resource(Rule( "CustomMetricSchedule", ScheduleExpression="rate(1 minute)", State="ENABLED", Targets=[custom_metric_target] )) PermissionForEventsToInvokeLambda = t.add_resource(Permission( "EventScheduleCustomMetricPermissions", FunctionName=Ref(custom_metric), Action="lambda:InvokeFunction", Principal="events.amazonaws.com", SourceArn=GetAtt(custom_metric_rule, "Arn") ))
#### CLOUDWATCH #### # Create the Event Target event_target = Target("pVideoDashboardEventTarget" + suffixcf, Arn=GetAtt('pVideoDashboardMetricsExtract' + suffixcf, 'Arn'), Id="lambdaTarget", Input="{" + " \"campaigns\": [] " + "\"}") event_rule = t.add_resource( Rule( "pVideoDashboardTrigger" + suffixcf, Name="pVideoDashboardTrigger" + suffixcf, ScheduleExpression="cron(0/5 8-17 ? * MON-FRI *)", # Run every 5 minutes Monday through Friday between 8:00 am and 19:55 pm (UTC) Description= "cron for trigger extraction metrics by lambda (pVideoDashboardMetricsExtract)", State=lambda_trigger_status, Targets=[event_target])) #### CLOUDWATCH ALARM #### alarm_topic = t.add_resource( Topic( "pVideoDashboardAlarmTopic" + suffixcf, TopicName="pVideoDashboardAlarmTopic" + suffixcf, Subscription=[ Subscription(Endpoint=alarm_email_1, Protocol="email"), Subscription(Endpoint=alarm_email_2, Protocol="email"), ],
def create_template(): template = Template( Description="Lambda VPC interface IP allocator utility") vpc_id = template.add_parameter(Parameter("VpcId", Type="String")) image_uri = template.add_parameter(Parameter( "ImageUri", Type="String", )) deployment_id = template.add_parameter( Parameter( "DeploymentId", Type="String", )) role = template.add_resource( Role( "Role", AssumeRolePolicyDocument=PolicyDocument( Version="2012-10-17", Statement=[ Statement( Effect=Allow, Action=[sts.AssumeRole], Principal=Principal("Service", "lambda.amazonaws.com"), ), ], ), )) function, alias = common.add_versioned_lambda( template, Ref(deployment_id), Function( "Function", MemorySize=256, Timeout=30, Role=GetAtt(role, "Arn"), PackageType="Image", Code=Code(ImageUri=Ref(image_uri), ), ImageConfig=ImageConfig(Command=[ Join(":", (handler.__module__, handler.__name__)), ], ), ), ) log_group = template.add_resource( LogGroup( "FunctionLogs", LogGroupName=Join("/", ["/aws/lambda", Ref(function)]), RetentionInDays=common.LOG_RETENTION_DAYS, )) policy = template.add_resource( PolicyType( "Policy", PolicyName=Ref(role), PolicyDocument=PolicyDocument( Version="2012-10-17", Statement=[ Statement( Effect=Allow, Action=[logs.PutLogEvents, logs.CreateLogStream], Resource=[GetAtt(log_group, "Arn")], ), # TODO scope down Statement( Effect=Allow, Action=[ ec2.AllocateAddress, ec2.ReleaseAddress, ec2.AssociateAddress, ec2.CreateTags, ], Resource=[ Join(":", [ "arn", Partition, "ec2", Region, AccountId, "*" ]) ], ), Statement( Effect=Allow, Action=[ ec2.DescribeAddresses, ], Resource=["*"], ), ], ), Roles=[Ref(role)], )) rule_create = template.add_resource( Rule( "RuleCreate", EventPattern={ "source": ["aws.ec2"], "detail-type": ["AWS API Call via CloudTrail"], "detail": { "eventSource": ["ec2.amazonaws.com"], "eventName": ["CreateNetworkInterface"], "responseElements": { "networkInterface": { "vpcId": [Ref(vpc_id)], "description": [{ "prefix": "AWS Lambda VPC ENI" }], }, }, "errorCode": [{ "exists": False }], }, }, Targets=[ Target( Id="default", Arn=Ref(alias), ), ], DependsOn=[policy], )) template.add_resource( Permission( "PermissionCreate", Principal="events.amazonaws.com", Action="lambda:InvokeFunction", FunctionName=Ref(alias), SourceArn=GetAtt(rule_create, "Arn"), )) rule_delete = template.add_resource( Rule( "RuleDelete", EventPattern={ "source": ["aws.ec2"], "detail-type": ["AWS API Call via CloudTrail"], "detail": { "eventSource": ["ec2.amazonaws.com"], "eventName": ["DeleteNetworkInterface"], "errorCode": [{ "exists": False }], }, }, Targets=[ Target( Id="default", Arn=Ref(alias), ), ], DependsOn=[policy], )) template.add_resource( Permission( "PermissionDelete", Principal="events.amazonaws.com", Action="lambda:InvokeFunction", FunctionName=Ref(alias), SourceArn=GetAtt(rule_delete, "Arn"), )) return template
Code=Code(ZipFile=Join("", code)), Handler="index.handler", Role=GetAtt("LambdaExecutionRole", "Arn"), Runtime="nodejs")) test_target = Target("TestTarget", Arn=GetAtt('TestFunction', 'Arn'), Id="TestFunction1") rule = t.add_resource( Rule("TestRule", EventPattern={ "source": ["aws.ec2"], "detail-type": ["test notification"], "detail": { "state": ["stopping"] } }, Description="Test Cloudwatch Event", State="DISABLED", Targets=[test_target])) permission = t.add_resource( Permission("TestPermission", Action='lambda:invokeFunction', Principal='events.amazonaws.com', FunctionName=Ref(test_function), SourceArn=GetAtt(rule, 'Arn'))) print(t.to_json())
StageName=stage_name, RestApiId=Ref(rest_api), DeploymentId=Ref(deployment))) t.add_output([ Output("ApiEndpoint", Value=Join("", [ "https://", Ref(rest_api), ".execute-api.", Ref('AWS::Region'), ".amazonaws.com/", stage_name ]), Description="Endpoint for this stage of the api") ]) #Event Target (for email scheduling) event_target_daily_emailer = Target("DailyEmailerTarget", Arn=GetAtt("EmailSendFunction", "Arn"), Id="DailyEmailerTargetFunction") # Schedule the emailer to run daily event_rule_daily_emailer = t.add_resource( Rule("DailyEmailsRule", ScheduleExpression="cron(0 23 * * ? *)", Name="DailyEmailListRule", State="ENABLED", Targets=[event_target_daily_emailer])) # Project wants yaml instead of json #print(t.to_json()) print(t.to_yaml())
InlineCode=inspect.getsource(post_crawler), Timeout=Ref(Timeout), ) ) Rule = T.add_resource(Rule( 'PostCrawlerRuleForETL', Name='PostCrawlerRuleForETL'.lower(), EventPattern={ "source": ["aws.glue"], "detail-type": ["Glue Crawler State Change"], "detail": { "state": [ "Succeeded" ] } }, Description="Post Crawler Rule for CloudWatch Event", State="ENABLED", Targets=[ Target( "PostCrawlerTarget", Arn= GetAtt("PostCrawlerFnForGlueJob", "Arn"), Id= "PostCrawlerTargetFunction1" ) ] )) # Prints the cf template file to console print(T.to_json())
Environment=Environment(Variables={ "probability": Ref(default_probability), "regions": Ref(regions), }), Handler=module_name + ".handler", MemorySize=128, Role=GetAtt(lambda_role, "Arn"), Runtime="python2.7", Timeout=30, )) chaos_lambda_rule = t.add_resource( Rule("ChaosLambdaRule", Description="Trigger Chaos Lambda according to a schedule", State="ENABLED", ScheduleExpression=Ref(chaos_schedule), Targets=[ Target(Arn=GetAtt(lambda_function, "Arn"), Id="ChaosLambdaRuleTarget") ])) t.add_resource( Permission("ChaosLambdaRulePermission", FunctionName=GetAtt(lambda_function, "Arn"), SourceArn=GetAtt(chaos_lambda_rule, "Arn"), Principal="events.amazonaws.com", Action="lambda:InvokeFunction")) t.add_output( Output("ChaosLambdaFunctionOutput", Value=Ref(lambda_function), Description="The Chaos Lambda Function")) t.add_output(
# Create the Event Rule EventRule = t.add_resource( Rule( "StaticWebsiteEventRule", Name='codepipeline-StaticWebsiteEventRule', State='ENABLED', Description= 'Amazon CloudWatch Events rule to automatically start your pipeline when a change occurs in CodeCommit', EventPattern={ "source": ["aws.codecommit"], "detail-type": ["CodeCommit Repository State Change"], "resources": [GetAtt(CodeCommit, "Arn")], "detail": { "event": ["referenceCreated", "referenceUpdated"], "referenceType": ["branch"], "referenceName": ["master"] } }, Targets=[ Target( Arn=Join("", [ 'arn:aws:codepipeline:', Region, ":", AccountId, ":", BUILD_NAME ]), Id='CodePipelineTarget', RoleArn=GetAtt(EventRole, "Arn"), ) ])) # Show cerated ressources t.add_output([