예제 #1
0
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)
예제 #2
0
    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,
            )
예제 #3
0
 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)
예제 #4
0
 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
예제 #5
0
 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
예제 #6
0
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
예제 #7
0
 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)
예제 #9
0
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]
예제 #10
0
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