def build_cluster_endpoints()

in source/idea/idea-administrator/src/ideaadministrator/app/cdk/stacks/cluster_stack.py [0:0]


    def build_cluster_endpoints(self):
        lambda_name = 'cluster-endpoints'

        cluster_endpoints_policy = Policy(
            context=self.context,
            name=f'{lambda_name}-policy',
            scope=self.stack,
            policy_template_name='custom-resource-cluster-endpoints.yml'
        )
        cluster_endpoints_role = Role(
            context=self.context,
            name=f'{lambda_name}-role',
            scope=self.stack,
            description=f'Role for cluster endpoints lambda function for Cluster: {self.cluster_name}',
            assumed_by=['lambda'])

        cluster_endpoints_role.attach_inline_policy(cluster_endpoints_policy)

        self.cluster_endpoints_lambda = LambdaFunction(
            context=self.context,
            name=lambda_name,
            scope=self.stack,
            idea_code_asset=IdeaCodeAsset(
                lambda_package_name='idea_custom_resource_cluster_endpoints',
                lambda_platform=SupportedLambdaPlatforms.PYTHON
            ),
            description='Manage cluster endpoints exposed via internal and external ALB',
            timeout_seconds=600,
            role=cluster_endpoints_role,
            log_retention_role=self.roles[app_constants.LOG_RETENTION_ROLE_NAME]
        )
        self.cluster_endpoints_lambda.node.add_dependency(cluster_endpoints_policy)
        self.cluster_endpoints_lambda.node.add_dependency(cluster_endpoints_role)

        # external ALB - can be deployed in public or private subnets
        is_public = self.context.config().get_bool('cluster.load_balancers.external_alb.public', default=True)
        external_alb_subnets = self.public_subnets(SubnetFilterKeys.LOAD_BALANCER_SUBNETS) if is_public is True else self.private_subnets(SubnetFilterKeys.LOAD_BALANCER_SUBNETS)
        self.external_alb = elbv2.ApplicationLoadBalancer(
            self.stack,
            f'{self.cluster_name}-external-alb',
            load_balancer_name=f'{self.cluster_name}-external-alb',
            security_group=self.security_groups['external-load-balancer'],
            http2_enabled=True,
            vpc=self.vpc,
            vpc_subnets=ec2.SubnetSelection(subnets=external_alb_subnets),
            internet_facing=is_public
        )
        if self.external_certificate is not None:
            self.external_alb.node.add_dependency(self.external_certificate)

        # internal ALB - will always be deployed in private subnets
        self.internal_alb = elbv2.ApplicationLoadBalancer(
            self.stack,
            f'{self.cluster_name}-internal-alb',
            load_balancer_name=f'{self.cluster_name}-internal-alb',
            security_group=self.security_groups['internal-load-balancer'],
            http2_enabled=True,
            vpc=self.vpc,
            vpc_subnets=ec2.SubnetSelection(subnets=self.private_subnets()),
            internet_facing=False
        )

        # Manage Access Logs for external/internal Application Load Balancer
        # https://docs.aws.amazon.com/elasticloadbalancing/latest/application/load-balancer-access-logs.html
        external_alb_enable_access_log = self.context.config().get_bool('cluster.load_balancers.external_alb.access_logs', default=False)
        internal_alb_enable_access_log = self.context.config().get_bool('cluster.load_balancers.internal_alb.access_logs', default=False)

        cluster_s3_bucket = None
        if external_alb_enable_access_log or internal_alb_enable_access_log:
            cluster_s3_bucket = s3.Bucket.from_bucket_name(scope=self.stack, id='cluster-s3-bucket', bucket_name=self.context.config().get_string('cluster.cluster_s3_bucket', required=True))

        if external_alb_enable_access_log:
            self.external_alb.log_access_logs(cluster_s3_bucket, f'logs/{self.module_id}/alb-access-logs/external-alb')
        if internal_alb_enable_access_log:
            self.internal_alb.log_access_logs(cluster_s3_bucket, f'logs/{self.module_id}/alb-access-logs/internal-alb')

        # Drop invalid headers from requests to the ALB as a security measure
        self.external_alb.set_attribute('routing.http.drop_invalid_header_fields.enabled', 'true')
        self.internal_alb.set_attribute('routing.http.drop_invalid_header_fields.enabled', 'true')

        elbv2.CfnListener(
            self.external_alb,
            'http-listener',
            port=80,
            load_balancer_arn=self.external_alb.load_balancer_arn,
            protocol='HTTP',
            default_actions=[
                elbv2.CfnListener.ActionProperty(
                    type='redirect',
                    redirect_config=elbv2.CfnListener.RedirectConfigProperty(
                        host='#{host}',
                        path='/#{path}',
                        port='443',
                        protocol='HTTPS',
                        query='#{query}',
                        status_code='HTTP_301'
                    )
                )
            ]
        )

        # ALB listener must be created with a default action.
        # after the cluster stack is deployed, the cluster manager stack can update the default action to point to web portal
        # to avoid replacing the default action set for web-portal, fetch the default actions if the listener exists
        external_alb_listener_arn = self.context.config().get_string('cluster.load_balancers.external_alb.https_listener_arn')
        external_alb_default_actions = self.get_alb_listener_default_actions(external_alb_listener_arn)

        if self.external_certificate is None:
            external_acm_certificate_arn = self.context.config().get_string('cluster.load_balancers.external_alb.certificates.acm_certificate_arn', required=True)
        else:
            external_acm_certificate_arn = self.external_certificate.get_att_string('acm_certificate_arn')

        self.external_alb_https_listener = elbv2.CfnListener(
            self.external_alb,
            'https-listener',
            port=443,
            ssl_policy=self.context.config().get_string('cluster.load_balancers.external_alb.ssl_policy', default='ELBSecurityPolicy-TLS13-1-2-2021-06'),
            load_balancer_arn=self.external_alb.load_balancer_arn,
            protocol='HTTPS',
            certificates=[
                elbv2.CfnListener.CertificateProperty(
                    certificate_arn=external_acm_certificate_arn
                )
            ],
            default_actions=external_alb_default_actions
        )
        if self.external_certificate is not None:
            self.external_alb_https_listener.node.add_dependency(self.external_certificate)

        self.internal_alb.node.add_dependency(self.internal_certificate)

        internal_acm_certificate_arn = self.internal_certificate.get_att_string('acm_certificate_arn')
        self.internal_alb_https_listener = elbv2.CfnListener(
            self.internal_alb,
            'https-listener',
            port=443,
            ssl_policy=self.context.config().get_string('cluster.load_balancers.internal_alb.ssl_policy', default='ELBSecurityPolicy-TLS13-1-2-2021-06'),
            load_balancer_arn=self.internal_alb.load_balancer_arn,
            protocol='HTTPS',
            certificates=[
                elbv2.CfnListener.CertificateProperty(
                    certificate_arn=internal_acm_certificate_arn
                )
            ],
            default_actions=[
                elbv2.CfnListener.ActionProperty(
                    type='fixed-response',
                    fixed_response_config=elbv2.CfnListener.FixedResponseConfigProperty(
                        status_code='200',
                        content_type='application/json',
                        message_body=Utils.to_json({
                            'success': True,
                            'message': 'OK'
                        })
                    )
                )
            ]
        )
        self.internal_alb_https_listener.node.add_dependency(self.internal_certificate)
        if self.aws_region in Utils.get_value_as_list('ROUTE53_CROSS_ZONE_ALIAS_RESTRICTED_REGION_LIST', constants.CAVEATS, []):
            self.internal_alb_dns_record_set = route53.CnameRecord(
                self.stack,
                'internal-alb-dns-record',
                record_name=f'internal-alb.{self.private_hosted_zone.zone_name}',
                zone=self.private_hosted_zone,
                domain_name=self.internal_alb.load_balancer_dns_name,
                ttl=cdk.Duration.minutes(5)
            )
        else:
            self.internal_alb_dns_record_set = route53.RecordSet(
                self.stack,
                'internal-alb-dns-record',
                record_type=route53.RecordType.A,
                target=route53.RecordTarget.from_alias(route53_targets.LoadBalancerTarget(self.internal_alb)),
                ttl=cdk.Duration.minutes(5),
                record_name=f'internal-alb.{self.private_hosted_zone.zone_name}',
                zone=self.private_hosted_zone
            )

        if self.context.config().is_module_enabled(constants.MODULE_VIRTUAL_DESKTOP_CONTROLLER):
            dcv_broker_client_listener_arn = self.context.config().get_string('cluster.external_alb.dcv_broker_client_listener_arn')
            dcv_broker_client_listener_default_actions = self.get_alb_listener_default_actions(dcv_broker_client_listener_arn)
            dcv_broker_client_communication_port = self.context.config().get_int('virtual-desktop-controller.dcv_broker.client_communication_port', required=True)
            self.internal_alb_dcv_broker_client_listener = elbv2.CfnListener(
                self.internal_alb,
                'dcv-broker-client-listener',
                port=dcv_broker_client_communication_port,
                ssl_policy=self.context.config().get_string('virtual-desktop-controller.dcv_broker.ssl_policy', default='ELBSecurityPolicy-TLS13-1-2-2021-06'),
                load_balancer_arn=self.internal_alb.load_balancer_arn,
                protocol='HTTPS',
                certificates=[
                    elbv2.CfnListener.CertificateProperty(
                        certificate_arn=internal_acm_certificate_arn
                    )
                ],
                default_actions=dcv_broker_client_listener_default_actions
            )
            self.internal_alb_dcv_broker_client_listener.node.add_dependency(self.internal_certificate)
            self.security_groups['internal-load-balancer'].add_ingress_rule(
                ec2.Peer.ipv4(self.vpc.vpc_cidr_block),
                ec2.Port.tcp(dcv_broker_client_communication_port),
                description='Allow HTTPS traffic from DCV Clients to DCV Broker'
            )

            dcv_broker_agent_listener_arn = self.context.config().get_string('cluster.external_alb.dcv_broker_agent_listener_arn')
            dcv_broker_agent_listener_default_actions = self.get_alb_listener_default_actions(dcv_broker_agent_listener_arn)
            dcv_broker_agent_communication_port = self.context.config().get_int('virtual-desktop-controller.dcv_broker.agent_communication_port', required=True)
            self.internal_alb_dcv_broker_agent_listener = elbv2.CfnListener(
                self.internal_alb,
                'dcv-broker-agent-listener',
                port=dcv_broker_agent_communication_port,
                ssl_policy=self.context.config().get_string('virtual-desktop-controller.dcv_broker.ssl_policy', default='ELBSecurityPolicy-TLS13-1-2-2021-06'),
                load_balancer_arn=self.internal_alb.load_balancer_arn,
                protocol='HTTPS',
                certificates=[
                    elbv2.CfnListener.CertificateProperty(
                        certificate_arn=internal_acm_certificate_arn
                    )
                ],
                default_actions=dcv_broker_agent_listener_default_actions
            )
            self.internal_alb_dcv_broker_agent_listener.node.add_dependency(self.internal_certificate)
            self.security_groups['internal-load-balancer'].add_ingress_rule(
                ec2.Peer.ipv4(self.vpc.vpc_cidr_block),
                ec2.Port.tcp(dcv_broker_agent_communication_port),
                description='Allow HTTPS traffic from DCV Agents to DCV Broker'
            )

            dcv_broker_gateway_listener_arn = self.context.config().get_string('cluster.external_alb.dcv_broker_gateway_listener_arn')
            dcv_broker_gateway_listener_default_actions = self.get_alb_listener_default_actions(dcv_broker_gateway_listener_arn)
            dcv_broker_gateway_communication_port = self.context.config().get_int('virtual-desktop-controller.dcv_broker.gateway_communication_port', required=True)
            self.internal_alb_dcv_broker_gateway_listener = elbv2.CfnListener(
                self.internal_alb,
                'dcv-broker-gateway-listener',
                port=dcv_broker_gateway_communication_port,
                ssl_policy=self.context.config().get_string('virtual-desktop-controller.dcv_broker.ssl_policy', default='ELBSecurityPolicy-TLS13-1-2-2021-06'),
                load_balancer_arn=self.internal_alb.load_balancer_arn,
                protocol='HTTPS',
                certificates=[
                    elbv2.CfnListener.CertificateProperty(
                        certificate_arn=internal_acm_certificate_arn
                    )
                ],

                default_actions=dcv_broker_gateway_listener_default_actions
            )
            self.internal_alb_dcv_broker_gateway_listener.node.add_dependency(self.internal_certificate)
            self.security_groups['internal-load-balancer'].add_ingress_rule(
                ec2.Peer.ipv4(self.vpc.vpc_cidr_block),
                ec2.Port.tcp(dcv_broker_gateway_communication_port),
                description='Allow HTTPS traffic from DCV Connection Gateway to DCV Broker'
            )