def add_service_actions(alarm, alarms_stack, target, scaling_in_policy, scaling_out_policy): """ Function to update the alarm properties with OKActions and AlarmActions :param ecs_composex.alarms.alarms_stack.Alarm alarm: :param ecs_composex.common.stacks.ComposeXStack alarms_stack: :param tuple target: :param scaling_in_policy: :param scaling_out_policy: """ setattr( alarm, "Threshold", float(scaling_out_policy.StepScalingPolicyConfiguration. StepAdjustments[0].MetricIntervalLowerBound), ) if not alarm.cfn_resource: raise AttributeError( f"Alarm {alarm.logical_name} has no CFN object associated") service_scaling_in_policy_param = Parameter( f"{target[0].logical_name}ScaleInPolicy", Type="String") service_scaling_out_policy_param = Parameter( f"{target[0].logical_name}ScaleOutPolicy", Type="String") add_parameters( alarms_stack.stack_template, [service_scaling_in_policy_param, service_scaling_out_policy_param], ) add_outputs( target[0].template, [ Output( f"{target[0].logical_name}ScaleInPolicy", Value=Ref(scaling_in_policy), ), Output( f"{target[0].logical_name}ScaleOutPolicy", Value=Ref(scaling_out_policy), ), ], ) alarms_stack.Parameters.update({ service_scaling_in_policy_param.title: GetAtt( target[0].logical_name, f"Outputs.{target[0].logical_name}ScaleInPolicy", ), service_scaling_out_policy_param.title: GetAtt( target[0].logical_name, f"Outputs.{target[0].logical_name}ScaleOutPolicy", ), }) actions = get_alarm_actions(alarm) actions[0].append(Ref(service_scaling_in_policy_param)) actions[1].append(Ref(service_scaling_out_policy_param))
def generate_outputs(self): for ( attribute_parameter, output_definition, ) in self.output_properties.items(): output_name = f"{self.title}{attribute_parameter.title}" value = self.set_new_resource_outputs(output_definition) self.attributes_outputs[attribute_parameter] = { "Name": output_name, "Output": Output(output_name, Value=value), "ImportParameter": Parameter( output_name, return_value=attribute_parameter.return_value, Type=attribute_parameter.Type, ), "ImportValue": GetAtt( self.stack, f"Outputs.{output_name}", ), "Original": attribute_parameter, } for attr in self.attributes_outputs.values(): if keyisset("Output", attr): self.outputs.append(attr["Output"])
def __init__(self, service: ComposeService, image_param: Parameter = None): if not keyisset("image", service.definition): raise KeyError(service.name, "You must define ``image``") self._service = service self._image = None self.image_uri = service.definition["image"] if not image_param: self._image_param = Parameter( f"{self.service.logical_name}ImageUrl", Type="String") self.image = service.definition["image"] else: self._image_param = image_param self.image = image_param
def set_ecs_cluster_logging_cw_access( settings: ComposeXSettings, policy, role_stack: ComposeXStack ) -> None: """ Based on ECS Cluster settings / configurations, grant permissions to CW Log defined to log ECS Execute command feature :param ecs_composex.common.settings.ComposeXSettings settings: :param policy: :param ecs_composex.common.stacks.ComposeXStack role_stack: """ if settings.ecs_cluster.log_group and settings.ecs_cluster.log_group != NoValue: parameter = Parameter("EcsExecuteLoggingGroup", Type="String") add_parameters(role_stack.stack_template, [parameter]) if isinstance(settings.ecs_cluster.log_group, FindInMap): role_stack.Parameters.update( {parameter.title: settings.ecs_cluster.log_group} ) arn_value = Sub( f"arn:${{{AWS_PARTITION}}}:logs:${{{AWS_REGION}}}:" f"${{{AWS_ACCOUNT_ID}}}:${{{parameter.title}}}:*" ) else: role_stack.Parameters.update( {parameter.title: GetAtt(settings.ecs_cluster.log_group, "Arn")} ) arn_value = Ref(parameter) policy.PolicyDocument["Statement"].append( { "Sid": "AllowDescribingAllCWLogGroupsForSSMClient", "Action": ["logs:DescribeLogGroups"], "Resource": ["*"], "Effect": "Allow", } ) policy.PolicyDocument["Statement"].append( { "Action": [ "logs:CreateLogStream", "logs:DescribeLogStreams", "logs:PutLogEvents", ], "Resource": [arn_value], "Effect": "Allow", } )
def set_ecs_cluster_logging_s3_access( settings: ComposeXSettings, policy, role_stack: ComposeXStack ): """ Based on ECS Cluster settings / configurations, grant permissions to put logs to S3 Bucket for logs defined to log ECS Execute command feature :param ecs_composex.common.settings.ComposeXSettings settings: :param policy: :param ecs_composex.common.stacks.ComposeXStack role_stack: """ if settings.ecs_cluster.log_bucket and settings.ecs_cluster.log_bucket != NoValue: parameter = Parameter("EcsExecuteLoggingBucket", Type="String") add_parameters(role_stack.stack_template, [parameter]) if isinstance(settings.ecs_cluster.log_bucket, FindInMap): role_stack.Parameters.update( {parameter.title: settings.ecs_cluster.log_bucket} ) else: role_stack.Parameters.update( {parameter.title: Ref(settings.ecs_cluster.log_bucket.cfn_resource)} ) policy.PolicyDocument["Statement"].append( { "Sid": "AllowDescribeS3Bucket", "Action": ["s3:GetEncryptionConfiguration"], "Resource": [ Sub(f"arn:${{{AWS_PARTITION}}}:s3:::${{{parameter.title}}}") ], "Effect": "Allow", } ) policy.PolicyDocument["Statement"].append( { "Sid": "AllowS3BucketObjectWrite", "Action": ["s3:PutObject"], "Resource": [ Sub(f"arn:${{{AWS_PARTITION}}}:s3:::${{{parameter.title}}}/*") ], "Effect": "Allow", } )
def create_vpc_mappings(self, vpc_settings): """ Generates the VPC CFN Mappings :param vpc_settings: :param ecs_composex.common.settings.ComposeXSettings settings: :return: """ self.mappings = { VPC_ID.title: { VPC_ID.title: vpc_settings[VPC_ID.title] }, APP_SUBNETS.title: { "Ids": vpc_settings[APP_SUBNETS.title] }, STORAGE_SUBNETS.title: { "Ids": vpc_settings[STORAGE_SUBNETS.title] }, PUBLIC_SUBNETS.title: { "Ids": vpc_settings[PUBLIC_SUBNETS.title] }, } ignored_keys = ["RoleArn", "session"] self.subnets_parameters.append(APP_SUBNETS) self.subnets_parameters.append(PUBLIC_SUBNETS) self.subnets_parameters.append(STORAGE_SUBNETS) for setting_name in vpc_settings: if (setting_name not in self.mappings.keys() and setting_name not in ignored_keys): self.mappings[setting_name] = { "Ids": vpc_settings[setting_name] } param = Parameter(setting_name, Type=SUBNETS_TYPE) self.subnets_parameters.append(param) self.set_azs_from_vpc_import( vpc_settings, session=vpc_settings["session"] if keyisset( "session", vpc_settings) else None, )
def set_ecs_cluster_logging_kms_access( settings: ComposeXSettings, policy, role_stack: ComposeXStack ): """ Based on ECS Cluster settings / configurations, grant permissions to KMS key encrypting Log defined to log ECS Execute command feature :param ecs_composex.common.settings.ComposeXSettings settings: :param policy: :param ecs_composex.common.stacks.ComposeXStack role_stack: """ if settings.ecs_cluster.log_key and settings.ecs_cluster.log_key != NoValue: parameter = Parameter("EcsExecuteLoggingEncryptionKey", Type="String") add_parameters(role_stack.stack_template, [parameter]) if isinstance(settings.ecs_cluster.log_key, FindInMap): role_stack.Parameters.update( {parameter.title: settings.ecs_cluster.log_key} ) else: role_stack.Parameters.update( { parameter.title: GetAtt( settings.ecs_cluster.log_key.cfn_resource, "Arn" ) } ) policy.PolicyDocument["Statement"].append( { "Action": [ "kms:Encrypt*", "kms:Decrypt*", "kms:ReEncrypt*", "kms:GenerateDataKey*", "kms:Describe*", ], "Resource": [Ref(parameter)], "Effect": "Allow", } )
def generate_tags_parameters(tags): """ Function to generate a list of parameters used for the tags values :return: list of parameters and tags to add to objects :rtype: tuple """ parameters = [] for tag in tags: parameters.append( Parameter( define_tag_parameter_title(tag["Key"]) if isinstance( tags, list) else define_tag_parameter_title(tag), group_label="Tagging", Type="String", MinLength=2, MaxLength=128, AllowedPattern=r"[\x20-\x7E]+", ConstraintDescription="Must be ASCII", Default=tag["Value"] if isinstance(tags, list) else tags[tag], )) return parameters
def generate_outputs(self): """ Method to create the outputs for XResources """ if self.stack and not self.stack.is_void: root_stack = self.stack.title else: root_stack = self.mapping_key for ( attribute_parameter, output_definition, ) in self.output_properties.items(): output_name = f"{self.logical_name}{attribute_parameter.title}" value = self.set_new_resource_outputs(output_definition) self.attributes_outputs[attribute_parameter] = { "Name": output_name, "Output": Output(output_name, Value=value), "ImportParameter": Parameter( output_name, group_label="ECS IAM Settings", return_value=attribute_parameter.return_value, Type=attribute_parameter.Type, ), "ImportValue": GetAtt( root_stack, f"Outputs.{output_name}", ), "Original": attribute_parameter, } for attr in self.attributes_outputs.values(): if keyisset("Output", attr): self.outputs.append(attr["Output"])
def set_compose_services_ingress(root_stack, dst_family: ComposeFamily, families: list, settings: ComposeXSettings) -> None: """ Function to crate SG Ingress between two families / services. Presently, the ingress rules are set after all services have been created :param ecs_composex.common.stacks.ComposeXStack root_stack: :param ecs_composex.ecs.ecs_family.ComposeFamily dst_family: :param list families: The list of family names. :param ecs_composex.common.settings.ComposeXSettings settings: """ for service in dst_family.service_networking.ingress.services: service_name = service["Name"] if service_name not in families: raise KeyError( f"The service {service_name} is not among the services created together. Valid services are", families, ) if not keypresent("DependsOn", service): add_independent_rules(dst_family, service_name, root_stack) else: src_family = settings.families[service_name] if dst_family.stack.title not in src_family.stack.DependsOn: src_family.stack.DependsOn.append(dst_family.stack.title) dst_family_sg_param = Parameter(f"{dst_family.stack.title}GroupId", Type=SG_ID_TYPE) add_parameters(src_family.template, [dst_family_sg_param]) src_family.stack.Parameters.update({ dst_family_sg_param.title: GetAtt( dst_family.stack.title, f"Outputs.{dst_family.logical_name}GroupId", ), }) add_dependant_ingress_rules(dst_family, dst_family_sg_param, src_family)
""" Module for DNS Route53 parameters """ import re from ecs_composex.common.cfn_params import Parameter TAGGING_API_ID = "route53" ZONES_PATTERN = re.compile(r"^Z[0-9A-Z]+$") LAST_DOT_RE = re.compile(r"(\.{1}$)") PUBLIC_DNS_ZONE_ID_T = "PublicDnsZoneId" PUBLIC_DNS_ZONE_ID = Parameter( PUBLIC_DNS_ZONE_ID_T, return_value="Id", Type="String", AllowedPattern=ZONES_PATTERN.pattern, ) PUBLIC_DNS_ZONE_ARN_T = "PublicDnsZoneArn" PUBLIC_DNS_ZONE_ARN = Parameter( PUBLIC_DNS_ZONE_ARN_T, Type="String", ) PUBLIC_DNS_ZONE_NAME_T = "HostedZoneName" PUBLIC_DNS_ZONE_NAME = Parameter(PUBLIC_DNS_ZONE_NAME_T, Type="String") def validate_domain_name(new_record, base_domain): """
# SPDX-License-Identifier: MPL-2.0 # Copyright 2020-2022 John Mille <*****@*****.**> from os import path from ecs_composex.common import NONALPHANUM from ecs_composex.common.cfn_params import Parameter from ecs_composex.common.ecs_composex import X_KEY MOD_KEY = path.basename(path.dirname(path.abspath(__file__))) RES_KEY = f"{X_KEY}{MOD_KEY}" MAPPINGS_KEY = NONALPHANUM.sub("", MOD_KEY) SSM_PARAM_NAME_T = "ParameterName" SSM_PARAM_NAME = Parameter(SSM_PARAM_NAME_T, Type="String") SSM_PARAM_ARN_T = "ParameterArn" SSM_PARAM_ARN = Parameter(SSM_PARAM_ARN_T, Type="String") SSM_PARAM_TYPE_T = "ParameterType" SSM_PARAM_TYPE = Parameter( SSM_PARAM_TYPE_T, return_value="Type", Type="String", AllowedValues=["String", "StringList", "SecureString"], ) SSM_PARAM_KMS_KEY_T = "ParameterKeyId" SSM_PARAM_KMS_KEY = Parameter(SSM_PARAM_KMS_KEY_T, return_value="KeyId", Type="String")
# SPDX-License-Identifier: MPL-2.0 # Copyright 2020-2022 John Mille <*****@*****.**> from ecs_composex.common.cfn_params import Parameter STREAM_ID_T = "StreamId" STREAM_ARN_T = "Arn" STREAM_KMS_KEY_ID_T = "KmsKeyId" GROUP_LABEL = "Kinesis Data Stream" STREAM_ID = Parameter(STREAM_ID_T, group_label=GROUP_LABEL, Type="String") STREAM_ARN = Parameter( STREAM_ARN_T, group_label=GROUP_LABEL, return_value="Arn", Type="String" ) STREAM_KMS_KEY_ID = Parameter( STREAM_KMS_KEY_ID_T, group_label=GROUP_LABEL, Type="String" )
# SPDX-License-Identifier: MPL-2.0 # Copyright 2020-2022 John Mille <*****@*****.**> from ecs_composex.common.cfn_params import Parameter TAGGING_API_ID = "sqs" SQS_SETTINGS = "SQS Settings" SQS_URL_T = "Url" SQS_URL = Parameter(SQS_URL_T, group_label=SQS_SETTINGS, Type="String") SQS_ARN_T = "Arn" SQS_ARN = Parameter(SQS_ARN_T, group_label=SQS_SETTINGS, return_value="Arn", Type="String") SQS_NAME_T = "QueueName" SQS_NAME = Parameter(SQS_NAME_T, group_label=SQS_SETTINGS, return_value="QueueName", Type="String") DLQ_NAME_T = "DeadLetterQueueName" DLQ_NAME = Parameter(DLQ_NAME_T, group_label=SQS_SETTINGS, Type="String") DLQ_ARN_T = "DeadLetterQueueArn" DLQ_ARN = Parameter(DLQ_ARN_T, group_label=SQS_SETTINGS, Type="String") SQS_KMS_KEY_T = "QueueKmsKey"
AZS_TYPE = "List<AWS::EC2::AvailabilityZone::Name>" SG_ID_TYPE = "AWS::EC2::SecurityGroup::Id" SG_NAME_TYPE = "AWS::EC2::SecurityGroup::GroupName" DEFAULT_VPC_CIDR = "100.64.72.0/24" DEFAULT_SINGLE_NAT = True VPC_SETTINGS = "VPC Settings" VPC_T = "Vpc" IGW_T = "InternetGatewayV4" RES_KEY = "x-vpc" MOD_KEY = "vpc" VPC_ID_T = "VpcId" VPC_ID = Parameter(VPC_ID_T, group_label=VPC_SETTINGS, Type=VPC_TYPE) VPC_CIDR_T = "VpcCidr" VPC_CIDR = Parameter(VPC_CIDR_T, group_label=VPC_SETTINGS, Type="String", Default=DEFAULT_VPC_CIDR) VPC_SINGLE_NAT_T = "SingleNat" VPC_SINGLE_NAT = Parameter(VPC_SINGLE_NAT_T, group_label=VPC_SETTINGS, Type="String", Default="True") STORAGE_SUBNETS_CIDR_T = "StorageSubnetsCidr" STORAGE_SUBNETS_CIDR = Parameter(STORAGE_SUBNETS_CIDR_T,
# SPDX-License-Identifier: MPL-2.0 # Copyright 2020-2022 John Mille <*****@*****.**> from os import path from ecs_composex.common.cfn_params import Parameter from ecs_composex.common.ecs_composex import X_KEY RES_KEY = f"{X_KEY}{path.basename(path.dirname(path.abspath(__file__)))}" LABEL = "CloudWatch Alarms" ALARM_NAME_T = "AlarmName" ALARM_NAME = Parameter(ALARM_NAME_T, group_label=LABEL, Type="String") ALARM_ARN_T = "AlarmArn" ALARM_ARN = Parameter(ALARM_ARN_T, group_label=LABEL, return_value="Arn", Type="String")
# SPDX-License-Identifier: MPL-2.0 # Copyright 2020-2022 John Mille <*****@*****.**> from ecs_composex.common.cfn_params import Parameter S3_ARN_REGEX = r"arn:(aws|aws-gov|aws-cn):s3:::([a-zA-Z0-9-.]+$)" GROUP_LABEL = "S3" S3_BUCKET_ARN_T = "BucketArn" S3_BUCKET_ARN = Parameter( S3_BUCKET_ARN_T, group_label=GROUP_LABEL, return_value="Arn", Type="String", AllowedPattern=S3_ARN_REGEX, ) S3_BUCKET_NAME_T = "BucketName" S3_BUCKET_NAME = Parameter( S3_BUCKET_NAME_T, group_label=GROUP_LABEL, Type="String", AllowedPattern=r"^[a-z0-9-.]+$", ) S3_BUCKET_DOMAIN_NAME_T = "BucketDomainName" S3_BUCKET_DOMAIN_NAME = Parameter( S3_BUCKET_DOMAIN_NAME_T, group_label=GROUP_LABEL, return_value="DomainName", Type="String", )
from ecs_composex.ecs.ecs_family import ComposeFamily from itertools import chain from compose_x_common.compose_x_common import keyisset from troposphere import If, NoValue, Ref, Sub from troposphere.ecs import FirelensConfiguration from ecs_composex.common import LOG, add_parameters from ecs_composex.common.cfn_params import Parameter from ecs_composex.ecs.ecs_conditions import USE_FARGATE_CON_T from ecs_composex.ecs.managed_sidecars import ManagedSidecar FLUENT_BIT_IMAGE_PARAMETER = Parameter( "FluentBitAwsImage", Type="AWS::SSM::Parameter::Value<String>", Default="/aws/service/aws-for-fluent-bit/latest", ) FLUENT_BIT_AGENT_NAME = "log_router" DEFAULT_LIMIT = 64 def render_agent_config( family: ComposeFamily, api_health_enabled: bool = False, enable_prometheus: bool = False, memory_limits: int = DEFAULT_LIMIT, ) -> dict: if memory_limits > 512: LOG.error(
def generate_outputs(self): """ Method to create the outputs for XResources """ if self.stack and not self.stack.is_void: root_stack = self.stack.title else: root_stack = self.module.mapping_key if self.lookup_properties: for attribute_parameter, value in self.lookup_properties.items(): output_name = f"{self.logical_name}{attribute_parameter.title}" self.attributes_outputs[attribute_parameter] = { "Name": output_name, "ImportValue": self.set_attributes_from_mapping(attribute_parameter), "ImportParameter": Parameter( output_name, group_label=attribute_parameter.group_label if attribute_parameter.group_label else self.module.mod_key, return_value=attribute_parameter.return_value, Type=attribute_parameter.Type, ), } elif self.output_properties and not self.lookup_properties: for ( attribute_parameter, output_definition, ) in self.output_properties.items(): output_name = NONALPHANUM.sub("", output_definition[0]) settings = self.set_new_resource_outputs( output_definition, attribute_parameter) value = settings[0] export = settings[1] self.attributes_outputs[attribute_parameter] = { "Name": output_name, "Output": Output(output_name, Value=value, Export=export), "ImportParameter": Parameter( output_name, group_label=attribute_parameter.group_label if attribute_parameter.group_label else self.module.mod_key, return_value=attribute_parameter.return_value, Type=attribute_parameter.Type, ), "ImportValue": GetAtt( root_stack, f"Outputs.{output_name}", ), "Original": attribute_parameter, } for attr in self.attributes_outputs.values(): if keyisset("Output", attr): self.outputs.append(attr["Output"])
# SPDX-License-Identifier: MPL-2.0 # Copyright 2020-2022 John Mille <*****@*****.**> import re from os import path from ecs_composex.common.cfn_params import Parameter from ecs_composex.common.ecs_composex import X_KEY MOD_KEY = path.basename(path.dirname(path.abspath(__file__))) RES_KEY = f"{X_KEY}{MOD_KEY}" TOPIC_ARN_RE = re.compile(r"(^arn:aws(?:-[a-z]+)?:sns:[\S]+:[0-9]+:[\S]+)$") TOPIC_ARN_T = "TopicArn" TOPIC_NAME_T = "TopicName" TOPIC_KMS_KEY_T = "TopicKmsKey" TOPIC_ARN = Parameter(TOPIC_ARN_T, Type="String") TOPIC_NAME = Parameter(TOPIC_NAME_T, return_value="TopicName", Type="String") TOPIC_KMS_KEY = Parameter(TOPIC_KMS_KEY_T, return_value="KmsMasterKeyId", Type="String")
# SPDX-License-Identifier: MPL-2.0 # Copyright 2020-2022 John Mille <*****@*****.**> """ Simple class to manage AWS XRay sidecar """ from ecs_composex.common.cfn_params import Parameter from ecs_composex.ecs.managed_sidecars import ManagedSidecar CW_IMAGE_PARAMETER = Parameter( "CloudwatchAgentImage", Type="String", Default="public.ecr.aws/cloudwatch-agent/cloudwatch-agent:latest", ) CW_AGENT_NAME = "cloudwatch-agent" CW_AGENT_DEFINITION = { "image": CW_IMAGE_PARAMETER.Default, "deploy": { "resources": { "limits": { "cpus": 0.1, "memory": "256M" } }, }, "labels": { "container_name": "cw-agent" }, }
from os import path from ecs_composex.common import NONALPHANUM from ecs_composex.common.cfn_params import Parameter from ecs_composex.common.ecs_composex import X_KEY MOD_KEY = path.basename(path.dirname(path.abspath(__file__))) RES_KEY = f"{X_KEY}{MOD_KEY}" MAPPINGS_KEY = NONALPHANUM.sub("", MOD_KEY) ROLE_ID_RE = re.compile(r"^[A-Z0-9]+$") POLICY_RE = re.compile( r"((^([a-zA-Z0-9-_./]+)$)|(^(arn:aws:iam::(aws|\d{12}):policy/)[a-zA-Z0-9-_./]+$))" ) IAM_ROLE_T = "IamRoleName" IAM_ROLE = Parameter(IAM_ROLE_T, return_value=None, Type="String") IAM_ROLE_ARN_T = "IamRoleArn" IAM_ROLE_ARN = Parameter(IAM_ROLE_ARN_T, return_value="Arn", Type="String") IAM_ROLE_ID_T = "IamRoleId" IAM_ROLE_ID = Parameter( IAM_ROLE_ID_T, return_value="RoleId", Type="String", AllowedPattern=ROLE_ID_RE.pattern, )
from ecs_composex.common import NONALPHANUM from ecs_composex.common.cfn_params import Parameter from ecs_composex.common.ecs_composex import X_KEY from ecs_composex.vpc.vpc_params import SG_ID_TYPE MOD_KEY = path.basename(path.dirname(path.abspath(__file__))) RES_KEY = f"{X_KEY}{MOD_KEY}" MAPPINGS_KEY = NONALPHANUM.sub("", MOD_KEY) LB_ID_T = "elbv2Id" LB_ARN_T = "elbv2Arn" LB_SG_ID_T = "elbv2SecurityGroupId" LB_DNS_NAME_T = "DNSName" LB_DNS_ZONE_ID_T = "CanonicalHostedZoneID" LB_ID = Parameter(LB_ID_T, Type="String") LB_ARN = Parameter(LB_ARN_T, Type="String") LB_SG_ID = Parameter(LB_SG_ID_T, return_value="GroupId", Type=SG_ID_TYPE) LB_DNS_NAME = Parameter(LB_DNS_NAME_T, return_value="DNSName", Type="String") LB_DNS_ZONE_ID = Parameter( LB_DNS_ZONE_ID_T, return_value="CanonicalHostedZoneID", Type="String", AllowedPattern=r"^Z[0-9A-Z]+$", ) LB_NAME_T = "LoadBalancerName" LB_NAME = Parameter(LB_NAME_T, return_value="LoadBalancerName", Type="String") LB_FULL_NAME_T = "LoadBalancerFullName" LB_FULL_NAME = Parameter(LB_FULL_NAME_T, return_value="LoadBalancerFullName", Type="String")
# SPDX-License-Identifier: MPL-2.0 # Copyright 2020-2022 John Mille <*****@*****.**> """ Module for Secrets parameters """ from ecs_composex.common.cfn_params import Parameter RES_KEY = "secrets" XRES_KEY = "x-secrets" PASSWORD_LENGTH_T = "PasswordLength" PASSWORD_LENGTH = Parameter(PASSWORD_LENGTH_T, Type="Number", MinValue=8, MaxValue=32, Default=16) USERNAME_T = "Username" USERNAME = Parameter(USERNAME_T, Type="String", MinLength=3, MaxLength=16, Default="dbadmin")
# SPDX-License-Identifier: MPL-2.0 # Copyright 2020-2022 John Mille <*****@*****.**> import re from os import path from ecs_composex.common import NONALPHANUM from ecs_composex.common.cfn_params import Parameter from ecs_composex.common.ecs_composex import X_KEY MOD_KEY = path.basename(path.dirname(path.abspath(__file__))) RES_KEY = f"{X_KEY}{MOD_KEY}" MAPPINGS_KEY = NONALPHANUM.sub("", MOD_KEY) KMS_KEY_ARN_RE = re.compile( r"(?:^arn:aws(?:-[a-z]+)?:kms:[\S]+:[0-9]+:)((key/)([\S]+))$") KMS_ALIAS_ARN_RE = re.compile( r"(?:^arn:aws(?:-[a-z]+)?:kms:[\S]+:[0-9]+:)((alias/)([\S]+))$") KMS_KEY_ARN_T = "KmsKeyArn" KMS_KEY_ID_T = "KmsKeyId" KMS_KEY_ALIAS_NAME_T = "KmsKeyAliasName" KMS_KEY_ALIAS_ARN_T = "KmsKeyAliasArn" KMS_KEY_ID = Parameter(KMS_KEY_ID_T, return_value="KeyId", Type="String") KMS_KEY_ARN = Parameter(KMS_KEY_ARN_T, return_value="Arn", Type="String") KMS_KEY_ALIAS_NAME = Parameter(KMS_KEY_ALIAS_NAME_T, Type="String")
# SPDX-License-Identifier: MPL-2.0 # Copyright 2020-2022 John Mille <*****@*****.**> from ecs_composex.common.cfn_params import Parameter from ecs_composex.rds.rds_params import ( DB_ENDPOINT_ADDRESS_T, DB_ENDPOINT_PORT_T, DB_RO_ENDPOINT_ADDRESS_T, ) DB_CLUSTER_RESOURCES_ARN_T = "DBClusterResources" DB_CLUSTER_RESOURCES_ARN = Parameter(DB_CLUSTER_RESOURCES_ARN_T, Type="String") DB_RESOURCE_ID_T = "ClusterResourceId" DB_RESOURCE_ID = Parameter(DB_RESOURCE_ID_T, return_value=DB_RESOURCE_ID_T, Type="String") DB_ENDPOINT = Parameter(DB_ENDPOINT_ADDRESS_T, return_value="Endpoint", Type="String") DB_READ_ENDPOINT = Parameter(DB_RO_ENDPOINT_ADDRESS_T, return_value="ReadEndpoint", Type="String") DB_PORT = Parameter( DB_ENDPOINT_PORT_T, return_value="Port", Type="Number", MinValue=1, MaxValue=((2 ^ 16) - 1), )
from os import path from ecs_composex.common import NONALPHANUM from ecs_composex.common.cfn_params import Parameter from ecs_composex.common.ecs_composex import X_KEY MOD_KEY = f"{path.basename(path.dirname(path.abspath(__file__)))}" RES_KEY = f"{X_KEY}{MOD_KEY}" MAPPINGS_KEY = NONALPHANUM.sub("", MOD_KEY) VALIDATION_DOMAIN_NAME_T = "ValidationDomainName" VALIDATION_DOMAIN_NAME = Parameter( VALIDATION_DOMAIN_NAME_T, Type="String", Default="none", AllowedPattern=r"(^none$|^(\*\.)?(((?!-)[A-Za-z0-9-]{0,62}[A-Za-z0-9])\.)+((?!-)[A-Za-z0-9-]{1,62}[A-Za-z0-9])$)", ) VALIDATION_DOMAIN_ZONE_ID_T = "ValidationZoneId" VALIDATION_DOMAIN_ZONE_ID = Parameter( VALIDATION_DOMAIN_ZONE_ID_T, Type="String", AllowedPattern=r"(none|^Z[A-Z0-9]+$)", Default="none", ) CERT_CN_T = "CertificateCn" CERT_CN = Parameter( CERT_CN_T, Type="String",
# SPDX-License-Identifier: MPL-2.0 # Copyright 2020-2022 John Mille <*****@*****.**> """ OpenSearch parameters """ import re from ecs_composex.common.cfn_params import Parameter from ecs_composex.vpc.vpc_params import SG_ID_TYPE OS_DOMAIN_ID_T = "DomainId" OS_DOMAIN_ID = Parameter(OS_DOMAIN_ID_T, Type="String") OS_DOMAIN_ARN_T = "DomainArn" OS_DOMAIN_ARN = Parameter(OS_DOMAIN_ARN_T, return_value="Arn", Type="String") OS_DOMAIN_ENDPOINT_T = "DomainEndpoint" OS_DOMAIN_ENDPOINT = Parameter( OS_DOMAIN_ENDPOINT_T, return_value="DomainEndpoint", Type="String" ) OS_DOMAIN_SG_T = "DomainSg" OS_DOMAIN_SG = Parameter(OS_DOMAIN_SG_T, return_value="GroupId", Type=SG_ID_TYPE) OS_DOMAIN_PORT_T = "DomainPort" OS_DOMAIN_PORT = Parameter( OS_DOMAIN_PORT_T, Type="Number", Default=443, MinValue=0, MaxValue=(pow(2, 16) - 1) ) OS_DOMAIN_ARN_RE = re.compile(
def define_service_targets(stack, rule, cluster_arn): """ Function to define the targets for service. :param ecs_composex.events.events_stack.XStack stack: :param ecs_composex.events.events_stack.Rule rule: :param troposphere.Sub cluster_arn: :return: """ for service in rule.families_targets: service_sg_param = Parameter(f"{service[0].logical_name}GroupId", Type=SG_ID_TYPE) service_task_def_param = Parameter( f"{service[0].logical_name}{TASK_T}", Type="String") service_subnets_param = Parameter( f"{service[0].logical_name}{APP_SUBNETS.title}", Type=SUBNETS_TYPE) events_policy_doc = { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": ["ecs:RunTask"], "Resource": [Ref(service_task_def_param)], "Condition": { "ArnLike": { "ecs:cluster": cluster_arn } }, }, { "Effect": "Allow", "Action": "iam:PassRole", "Resource": ["*"], "Condition": { "StringLike": { "iam:PassedToService": Sub(f"ecs-tasks.${{{AWS_URL_SUFFIX}}}") } }, }, ], } task_events_policy_doc = { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": ["ecs:RunTask"], "Resource": [Ref(service[0].template.resources[TASK_T])], "Condition": { "ArnLike": { "ecs:cluster": cluster_arn } }, }, { "Effect": "Allow", "Action": "iam:PassRole", "Resource": ["*"], "Condition": { "StringLike": { "iam:PassedToService": Sub(f"ecs-tasks.${{{AWS_URL_SUFFIX}}}") } }, }, ], } events_policy = Policy(PolicyName="EventsAccess", PolicyDocument=events_policy_doc) if "EventsAccessPolicy" not in service[0].template.resources: service[0].template.add_resource( PolicyType( "EventsAccessPolicy", PolicyName="EventsAccess", PolicyDocument=task_events_policy_doc, Roles=[ service[0].iam_manager.task_role.name, service[0].iam_manager.exec_role.name, ], )) role_name = f"{rule.logical_name}IamRoleToTrigger{service[0].logical_name}" if role_name not in stack.stack_template.resources: role = stack.stack_template.add_resource( Role( f"{rule.logical_name}IamRoleToTrigger{service[0].logical_name}", AssumeRolePolicyDocument={ "Version": "2012-10-17", "Statement": [{ "Sid": "TrustPolicy", "Effect": "Allow", "Principal": { "Service": Sub(f"events.${{{AWS_URL_SUFFIX}}}") }, "Action": "sts:AssumeRole", }], }, ManagedPolicyArns=[], Policies=[events_policy], PermissionsBoundary=Ref(AWS_NO_VALUE), )) if service[0].iam_manager.permissions_boundary: role.PermissionsBoundary = service[ 0].iam_manager.permissions_boundary else: role = stack.stack_template.resources[role_name] add_parameters( stack.stack_template, [service_sg_param, service_task_def_param, service_subnets_param], ) stack.Parameters.update({ service_sg_param.title: GetAtt( service[0].logical_name, f"Outputs.{service[0].logical_name}GroupId", ), service_task_def_param.title: GetAtt( service[0].logical_name, f"Outputs.{service[0].task_definition.title}", ), service_subnets_param.title: GetAtt( service[0].logical_name, f"Outputs.{SERVICE_SUBNETS.title}", ), }) target = Target( EcsParameters=EcsParameters( NetworkConfiguration=NetworkConfiguration( AwsVpcConfiguration=AwsVpcConfiguration( Subnets=Ref(service_subnets_param), SecurityGroups=[Ref(service_sg_param)], AssignPublicIp=service[0].service_networking. eip_assign, )), PlatformVersion=Ref(FARGATE_VERSION), TaskCount=service[3], TaskDefinitionArn=Ref(service_task_def_param), LaunchType="FARGATE", ), Arn=cluster_arn, Id=service[0].logical_name, RoleArn=GetAtt(role, "Arn"), ) rule.cfn_resource.Targets.append(target) if service[0].logical_name not in stack.DependsOn: stack.DependsOn.append(service[0].logical_name) if (keyisset("DeleteDefaultService", service[4]) and SERVICE_T in service[0].template.resources): LOG.info( f"Deleting ECS Service definition from stack for {service[0].name}" ) del service[0].template.resources[SERVICE_T] if SERVICE_SCALING_TARGET in service[0].template.resources: LOG.warning( f"Target for event {rule.logical_name} also had scaling rules. Deleting" ) delete_service_from_template(service)
# SPDX-License-Identifier: MPL-2.0 # Copyright 2020-2022 John Mille <*****@*****.**> from ecs_composex.common.cfn_params import Parameter from ecs_composex.rds.rds_params import ( DB_ENDPOINT_ADDRESS_T, DB_ENDPOINT_PORT_T, DB_RO_ENDPOINT_ADDRESS_T, ) DOCDB_NAME_T = "DBClusterName" DOCDB_ID_T = "ClusterResourceId" DOCDB_NAME = Parameter(DOCDB_NAME_T, Type="String") DOCDB_ID = Parameter(DOCDB_ID_T, return_value="ClusterResourceId", Type="String") DOCDBC_ENDPOINT = Parameter(DB_ENDPOINT_ADDRESS_T, return_value="Endpoint", Type="String") DOCDBC_READ_ENDPOINT = Parameter(DB_RO_ENDPOINT_ADDRESS_T, return_value="ReadEndpoint", Type="String") DOCDB_PORT = Parameter( DB_ENDPOINT_PORT_T, return_value="Port", Type="Number", MinValue=1, Default="27017", MaxValue=((2 ^ 16) - 1), )