def add_security_group(family) -> None: """ Creates a new EC2 SecurityGroup and assigns to ecs_service.network_settings Adds the security group to the family template resources. :param ecs_composex.ecs.ecs_family.ComposeFamily family: """ family.service_networking.security_group = SecurityGroup( SG_T, GroupDescription=Sub( f"SG for ${{{SERVICE_NAME.title}}} - ${{STACK_NAME}}", STACK_NAME=define_stack_name(), ), Tags=Tags({ "Name": Sub( f"${{{SERVICE_NAME.title}}}-${{STACK_NAME}}", STACK_NAME=define_stack_name(), ), "StackName": StackName, "MicroserviceName": Ref(SERVICE_NAME), }), VpcId=Ref(VPC_ID), ) add_resource(family.template, family.service_networking.security_group)
def handle_key_settings(self, template): """ Method to add to the template for additional KMS key related resources. :param troposphere.Template template: """ if self.parameters and keyisset("Alias", self.parameters): alias_name = self.parameters["Alias"] if not (alias_name.startswith("alias/") or alias_name.startswith("aws")): alias_name = Sub( f"alias/${{STACK_NAME}}/{alias_name}", STACK_NAME=define_stack_name(template), ) elif alias_name.startswith("alias/aws") or alias_name.startswith( "aws"): raise ValueError( f"Alias {alias_name} cannot start with alias/aws.") Alias( f"{self.logical_name}Alias", template=template, AliasName=alias_name, TargetKeyId=Ref(self.cfn_resource), Metadata=metadata, )
def define_kms_key(self): """ Method to set the KMS Key """ if not self.properties: props = { "Description": Sub( f"{self.name} created in ${{STACK_NAME}}", STACK_NAME=define_stack_name(), ), "Enabled": True, "EnableKeyRotation": True, "KeyUsage": "ENCRYPT_DECRYPT", "PendingWindowInDays": 7, } else: props = import_record_properties(self.properties, Key) if not keyisset("KeyPolicy", props): props.update({"KeyPolicy": define_default_key_policy()}) props.update({"Metadata": metadata}) LOG.debug(props) self.cfn_resource = Key(self.logical_name, **props)
def define_export_name(self, output_definition, attribute_parameter): """ Method to define the export name for the resource :return: """ if len(output_definition) == 5 and output_definition[4]: LOG.debug(f"Adding portback output for {self.name}") export = Export( Sub( f"${{STACK_NAME}}{DELIM}{self.name}{DELIM}{output_definition[4]}", STACK_NAME=define_stack_name(), )) else: export = Export( Sub( f"${{STACK_NAME}}{DELIM}{self.logical_name}{DELIM}{attribute_parameter.title}", STACK_NAME=define_stack_name(), ), ) return export
def __init__( self, family: ComposeFamily, ): self._family = family self.logging_group_name = Sub( f"${{STACK_NAME}}/svc/ecs/${{{CLUSTER_NAME_T}}}/{family.logical_name}", STACK_NAME=define_stack_name( family.template if family.template else None), ) self._family_log_group: LogGroup = create_log_group( self.family, group_name=self.logging_group_name, grant_task_role_access=True) self.firelens_service = None self.firelens_config_service = None self.services_logging: dict = {} self.firelens_advanced_config = None
def define_domain_security_group(domain, stack): """ Create a new Security Group for the Domain :param ecs_composex.opensearch.opensearch_stack.OpenSearchDomain domain: :param ecs_composex.common.stacks.ComposeXStack stack: :return: The security Group """ add_parameters(stack.stack_template, [VPC_ID]) sg = SecurityGroup( f"{domain.logical_name}VPCSecurityGroup", GroupDescription=Sub( f"{domain.logical_name} OpenSearch SG in ${{STACK_NAME}}", STACK_NAME=define_stack_name(stack.stack_template), ), VpcId=Ref(VPC_ID), Tags=Tags(OsDomainName=domain.name), ) stack.stack_template.add_resource(sg) return sg
def __init__(self, resource, linked_service_name): self._resource = resource self.iam_modules_policies = OrderedDict() self.permissions_boundary = NoValue if ( resource.parameters and keyisset("x-iam", resource.parameters) and keyisset("PermissionsBoundary", resource.parameters["x-iam"]) ): self.permissions_boundarypermissions_boundary = define_iam_policy( resource.parameters["x-iam"]["PermissionsBoundary"] ) self.service_linked_role = IamRole( f"{resource.logical_name}IamRole", AssumeRolePolicyDocument=service_role_trust_policy(linked_service_name), Description=Sub( f"Firehose IAM Service Role for {resource.logical_name} - ${{STACK_NAME}}", STACK_NAME=define_stack_name(), ), PermissionsBoundary=self.permissions_boundary, )
def create_dashboards(settings: ComposeXSettings, x_stack: ComposeXStack, module: XResourceModule) -> None: """ Loop to iterate over dashboards definitions :param ecs_composex.common.settings.ComposeXSettings settings: :param ecs_composex.common.stacks.ComposeXStack x_stack: :param ModManager module: """ if not keyisset(module.res_key, settings.compose_content): LOG.error(f"No {module.res_key} defined") dashboards = settings.compose_content[module.res_key] for name, dashboard in dashboards.items(): widgets = [] if keyisset("Services", dashboard): service_params = retrieve_services(settings, dashboard["Services"], x_stack) y_index = 0 for param in service_params: service_ecs_widgets = ServiceEcsWidget(param[0], param[1], CLUSTER_NAME, y_index=y_index) widgets += service_ecs_widgets.widgets y_index += service_ecs_widgets.height + 1 dashboard_body_header = {"start": "-PT12H", "widgets": widgets} dashboard_body = Sub(json.dumps(dashboard_body_header)) cfn_dashboard = CWDashboard( NONALPHANUM.sub("", name), DashboardBody=dashboard_body, DashboardName=Sub( f"${{StackName}}--{name}", StackName=define_stack_name(x_stack.template), ), ) x_stack.stack_template.add_resource(cfn_dashboard)
def add_ecs_execution_role_managed_policy( template: Template, ) -> ManagedPolicy | AWSObject: """ Creates a blanket IAM Managed policy to use for the ECS Execution roles :param troposphere.Template template: :return: The managed policy :rtype: ManagedPolicy """ policy_logical_id = "ECSExecutionRoleCommonRequirements" if policy_logical_id not in template.resources: managed_policy = template.add_resource( ManagedPolicy( policy_logical_id, Description=Sub( r"Managed policy for ECS Execution role in ${STACK_NAME})", STACK_NAME=define_stack_name(), ), Roles=[], PolicyDocument={ "Version": "2012-10-17", "Statement": [ { "Sid": "AllowsForEcrPullFromEcsAgent", "Effect": "Allow", "Action": [ "ecr:GetAuthorizationToken", "ecr:BatchCheckLayerAvailability", "ecr:GetDownloadUrlForLayer", "ecr:GetRepositoryPolicy", "ecr:DescribeRepositories", "ecr:ListImages", "ecr:DescribeImages", "ecr:BatchGetImage", ], "Resource": ["*"], }, { "Sid": "AllowEcsAgentOrientedTasks", "Effect": "Allow", "Action": [ "ecs:DiscoverPollEndpoint", "ecs:Poll", "ecs:Submit*", ], "Resource": ["*"], }, { "Sid": "AllowElbv2Actions", "Effect": "Allow", "Action": [ "elasticloadbalancing:DeregisterInstancesFromLoadBalancer", "elasticloadbalancing:DeregisterTargets", "elasticloadbalancing:Describe*", "elasticloadbalancing:RegisterInstancesWithLoadBalancer", "elasticloadbalancing:RegisterTargets", ], "Resource": ["*"], }, { "Sid": "AllowsEC2Actions", "Effect": "Allow", "Action": [ "ec2:AttachNetworkInterface", "ec2:CreateNetworkInterface", "ec2:CreateNetworkInterfacePermission", "ec2:DeleteNetworkInterface", "ec2:DeleteNetworkInterfacePermission", "ec2:Describe*", "ec2:DetachNetworkInterface", ], "Resource": ["*"], }, ], }, )) return managed_policy else: return template.resources[policy_logical_id]
def create_log_groups(domain, stack, props): """ :param ecs_composex.opensearch.opensearch_stack.OpenSearchDomain domain: :param ecs_composex.common.stacks.ComposeXStack stack: :param dict props: :return: """ opts = {} all_opts = [ "SEARCH_SLOW_LOGS", "ES_APPLICATION_LOGS", "INDEX_SLOW_LOGS", "AUDIT_LOGS", ] opts_to_add = (domain.parameters["CreateLogGroups"] if isinstance( domain.parameters["CreateLogGroups"], list) else all_opts) groups = [] for option in opts_to_add: group_name = Sub( f"opensearch/${{STACK_NAME}}/{domain.logical_name}/{option}", STACK_NAME=define_stack_name(stack.stack_template), ) log_group = LogGroup( f"{domain.logical_name}{NONALPHANUM.sub('', option)}LogGroup", LogGroupName=group_name, RetentionInDays=30 if not keyisset("RetentionInDays", domain.parameters) else get_closest_valid_log_retention_period( domain.parameters["RetentionInDays"]), ) stack.stack_template.add_resource(log_group) groups.append(log_group) opts[option] = { "Enabled": True, "CloudWatchLogsLogGroupArn": Sub(f"arn:${{{AWS_PARTITION}}}:logs:${{{AWS_REGION}}}:${{{AWS_ACCOUNT_ID}}}:" f"log-group:${{{log_group.title}}}"), } if keyisset("CreateLogGroupsResourcePolicy", domain.parameters): logs_policy = ResourcePolicy( "OpenSearchLogGroupResourcePolicy", DeletionPolicy="Retain", PolicyName="ComposeXOpenSearchAccessToCWLogs", PolicyDocument=Sub( json.dumps({ "Version": "2012-10-17", "Statement": [{ "Sid": "AllowESDomainsToAccessLogGroupsInAllRegions", "Effect": "Allow", "Principal": { "Service": f"es.${{{AWS_URL_SUFFIX}}}" }, "Action": ["logs:PutLogEvents", "logs:CreateLogStream"], "Resource": [ f"arn:${{{AWS_PARTITION}}}:logs:*:${{{AWS_ACCOUNT_ID}}}:log-group:opensearch/*" ], }], })), ) stack.stack_template.add_resource(logs_policy) props["LogPublishingOptions"] = opts