奇怪的AWS CDK循环引用错误,无法识别循环依赖的来源

问题描述 投票:0回答:1

为了简单起见,我有一个 VPC 堆栈、一个 RDS 堆栈和一个 Lambda 堆栈。

Lambda堆栈依赖于RDS堆栈,并且它们都依赖于VPC堆栈,这是独立的。然而,AWS 告诉我 RDS 和 Lambda 堆栈相互依赖。

这是它在主文件中的样子:

vpc_stack = VPCStack(
    app,
    "VPCStack",
    env=cdk.Environment(account=Cfg.ACCOUNT, region=Cfg.REGION),
)

rds_stack = RDSStack(
    app,
    "RDSStack",
    vpc=vpc_stack.vpc,
    env=cdk.Environment(account=Cfg.ACCOUNT, region=Cfg.REGION),
)

main_lambda_stack = MainLambdaStack(
    app,
    "MainLambdaStack",
    vpc=vpc_stack.vpc,
    rds_proxy=rds_stack.rds_proxy,
    image_deleter_queue=bid_lambda_stack.image_deleter_queue,
    redis_cluster=redis_stack.redis_cluster,
    packages_bucket=s3_stack.packages_bucket,
    sg_redis=redis_stack.sg_redis,
    sg_rds_proxy=rds_stack.sg_rds_proxy,
    images_bucket=s3_stack.user_images_bucket,
    env=cdk.Environment(account=Cfg.ACCOUNT, region=Cfg.REGION),
)

错误本身是:

    RuntimeError: Error: 'RDSStack' depends on 'MainLambdaStack' 
(RDSStack -> MainLambdaStack/LambdaSecurityGroup/Resource.GroupId). 
Adding this dependency (MainLambdaStack -> RDSStack/RDSProxy/Resource.Endpoint) 
would create a cyclic reference.

但我在 RDS 堆栈中找不到任何 Lambda 依赖项。

有关更多上下文,这里是整个 RDS 堆栈:

class RDSStack(Stack):
    def __init__(
        self, scope: Construct, construct_id: str, vpc: ec2.Vpc, **kwargs
    ) -> None:
        super().__init__(scope, construct_id, **kwargs)

        # RDS security group
        sg_rds = ec2.SecurityGroup(
            self,
            "RDSSecurityGroup",
            vpc=vpc,
            description="Security group for RDS",
            security_group_name="rds-sg",
        )

        # RDS Proxy security group
        self.sg_rds_proxy = ec2.SecurityGroup(
            self,
            "RDSProxySecurityGroup",
            vpc=vpc,
            description="Security group for RDS Proxy",
            security_group_name="rds-proxy-sg",
        )

        # RDS instance
        rds_instance = rds.DatabaseInstance(  # noqa: F841
            self,
            "RDSInstance",
            engine=rds.DatabaseInstanceEngine.postgres(
                version=rds.PostgresEngineVersion.VER_16_1
            ),
            instance_type=ec2.InstanceType.of(
                ec2.InstanceClass.BURSTABLE2, ec2.InstanceSize.MICRO
            ),
            vpc=vpc,
            vpc_subnets=ec2.SubnetSelection(
                subnet_type=ec2.SubnetType.PRIVATE_ISOLATED
            ),
            security_groups=[sg_rds],
            removal_policy=RemovalPolicy.RETAIN,
            allocated_storage=20,
            auto_minor_version_upgrade=True,
            enable_performance_insights=True,
            monitoring_interval=Duration.minutes(10),
            backup_retention=Duration.days(7),
        )

        # RDS Proxy
        self.rds_proxy = rds.DatabaseProxy(  # noqa: F841
            self,
            "RDSProxy",
            vpc=vpc,
            vpc_subnets=ec2.SubnetSelection(
                subnet_type=ec2.SubnetType.PRIVATE_ISOLATED
            ),
            security_groups=[self.sg_rds_proxy],
            db_proxy_name="rds-proxy",
            proxy_target=rds.ProxyTarget.from_instance(rds_instance),
            secrets=[rds_instance.secret],
        )

        # RDS ingress from RDS Proxy
        sg_rds.add_ingress_rule(
            ec2.Peer.security_group_id(self.sg_rds_proxy.security_group_id),
            ec2.Port.tcp(5432),
            "Allow PostgreSQL traffic from RDS Proxy security group",
        )

如有任何帮助,我们将不胜感激。

编辑:添加主 Lamba 堆栈以获得额外的上下文(它相当大,但我不知道要为 MRE 切断什么)

class MainLambdaStack(Stack):

    def __init__(
        self,
        scope: Construct,
        construct_id: str,
        vpc: ec2.Vpc,
        rds_proxy: rds.DatabaseProxy,
        image_deleter_queue: sqs.Queue,
        redis_cluster: elasticache.CfnCacheCluster,
        packages_bucket: s3.Bucket,
        sg_redis: ec2.SecurityGroup,
        sg_rds_proxy: ec2.SecurityGroup,
        images_bucket: s3.Bucket,
        **kwargs,
    ) -> None:
        super().__init__(scope, construct_id, **kwargs)

        # company lambda security group
        sg_company_lambda = ec2.SecurityGroup(
            self,
            "companyLambdaSecurityGroup",
            vpc=vpc,
            description="Security group for company Lambda",
            security_group_name="company-lambda-sg",
        )

        # company lambda environment variables
        DB_HOST = rds_proxy.endpoint
        IMAGE_DELETER_QUEUE_URL = image_deleter_queue.queue_url
        REDIS_HOST = redis_cluster.attr_redis_endpoint_address

        env_vars = {
            "DB_FORCE_ROLLBACK": "False",
            "DB_HOST": DB_HOST,
            "DB_PORT": "5432",
            "DB_SCHEMA": "companyMVP_DEV",
            "ENV_STATE": "DEV",
            "IMAGE_DELETER_QUEUE_URL": IMAGE_DELETER_QUEUE_URL,
            "LOG_LEVEL": "DEBUG",
            "REDIS_HOST": REDIS_HOST,
            "REDIS_PORT": "6379",
        }

        # Execution role
        multi_service_role = iam.Role(
            self,
            "LambdaMultiServiceRole",
            assumed_by=iam.ServicePrincipal("lambda.amazonaws.com"),
            managed_policies=[
                iam.ManagedPolicy.from_aws_managed_policy_name(
                    "AmazonElastiCacheFullAccess"
                ),
                iam.ManagedPolicy.from_aws_managed_policy_name("AmazonS3FullAccess"),
                iam.ManagedPolicy.from_aws_managed_policy_name("AmazonSESFullAccess"),
                iam.ManagedPolicy.from_aws_managed_policy_name("AmazonSQSFullAccess"),
                iam.ManagedPolicy.from_aws_managed_policy_name("AWSLambdaExecute"),
                iam.ManagedPolicy.from_aws_managed_policy_name(
                    "SecretsManagerReadWrite"
                ),
            ],
            role_name="lambda-multi-service-role",
        )

        # Add logs policy
        multi_service_role.add_to_policy(
            statement=iam.PolicyStatement(
                actions=[
                    "logs:CreateLogGroup",
                    "logs:CreateLogStream",
                    "logs:PutLogEvents",
                ],
                resources=[f"arn:aws:logs:us-east-1:{Cfg.ACCOUNT}:*"],
                effect=iam.Effect.ALLOW,
            )
        )

        # Add Cognito policy
        multi_service_role.add_to_policy(
            statement=iam.PolicyStatement(
                actions=[
                    "cognito-identity:GetOpenIdTokenForDeveloperIdentity",
                    "cognito-identity:GetId",
                    "cognito-identity:GetCredentialsForIdentity",
                ],
                resources=["*"],
                effect=iam.Effect.ALLOW,
            )
        )

        # Add RDS Proxy policy
        multi_service_role.add_to_policy(
            statement=iam.PolicyStatement(
                actions=[
                    "rds-db:connect",
                ],
                # CHECK HERE IF SHIT DONT WORK
                resources=[f"arn:aws:rds-db:us-east-1:{Cfg.ACCOUNT}:*/*"],
                effect=iam.Effect.ALLOW,
            )
        )

        # Add X-ray policy
        multi_service_role.add_to_policy(
            statement=iam.PolicyStatement(
                actions=[
                    "xray:PutTraceSegments",
                    "xray:PutTelemetryRecords",
                ],
                resources=["*"],
                effect=iam.Effect.ALLOW,
            )
        )

        # Add VPC Access policy
        multi_service_role.add_to_policy(
            statement=iam.PolicyStatement(
                actions=[
                    "ec2:CreateNetworkInterface",
                    "ec2:DeleteNetworkInterface",
                    "ec2:DescribeNetworkInterfaces",
                ],
                resources=["*"],
                effect=iam.Effect.ALLOW,
            )
        )

        # company lambda function
        lambda_fn = _lambda.Function(
            self,
            "companyLambda",
            runtime=_lambda.Runtime.PYTHON_3_12,
            handler="main.handler",
            memory_size=1024,
            vpc=vpc,
            security_groups=[sg_company_lambda],
            vpc_subnets=ec2.SubnetSelection(
                subnet_type=ec2.SubnetType.PRIVATE_ISOLATED
            ),
            environment=env_vars,
            timeout=Duration.seconds(30),
            role=multi_service_role,
            code=_lambda.Code.from_bucket(packages_bucket, "main_lambda.zip"),
        )

        # Add alias
        self.lambda_alias = _lambda.Alias(
            self,
            "MainLambdaAlias",
            alias_name="DEV",
            version=lambda_fn.current_version,
            provisioned_concurrent_executions=1,
        )

        # Add alias ARN to parameter store
        ssm.StringParameter(
            self,
            "main_lambda_alias_arn",
            parameter_name="/cdk/main_lambda/alias_arn",
            string_value=self.lambda_alias.function_arn,
        )

        # Parameter extension layer
        parameters_layer = _lambda.LayerVersion.from_layer_version_arn(
            self,
            "ParametersLayer",
            layer_version_arn="arn:aws:lambda:us-east-1:177933569100:layer:AWS-Parameters-and-Secrets-Lambda-Extension:11",
        )
        # Add parameter extension layer to lambda function
        lambda_fn.add_layers(parameters_layer)

        # Redis ingress from company Lambda
        sg_redis.add_ingress_rule(
            ec2.Peer.security_group_id(sg_company_lambda.security_group_id),
            ec2.Port.tcp(6379),
            "Allow Redis traffic from company Lambda security group",
        )

        # RDS Proxy ingress from company Lambda
        sg_rds_proxy.add_ingress_rule(
            ec2.Peer.security_group_id(sg_company_lambda.security_group_id),
            ec2.Port.tcp(5432),
            "Allow PostgreSQL traffic from company Lambda security group",
        )

        # Create a new SES domain identity
        domain_identity = ses.EmailIdentity(  # noqa F841
            self, "DomainIdentity", identity=ses.Identity.domain("company.io")
        )

        # Create cognito identity pool provider
        cognito_identity_pool = cognito.CfnIdentityPool(  # noqa F841
            self,
            "CognitoIdentityPool",
            allow_unauthenticated_identities=False,
            identity_pool_name="company-verified-users",
            developer_provider_name="company.io",
        )

        # Create cognito identity pool role
        cognito_identity_pool_role = iam.Role(  # noqa F841
            self,
            "CognitoIdentityPoolRole",
            assumed_by=iam.FederatedPrincipal(
                federated="cognito-identity.amazonaws.com",
                conditions={
                    "StringEquals": {
                        "cognito-identity.amazonaws.com:aud": cognito_identity_pool.ref
                    }
                },
                assume_role_action="sts:AssumeRoleWithWebIdentity",
            ),
        )

        # Add get credentialts for identity policy
        cognito_identity_pool_role.add_to_policy(
            statement=iam.PolicyStatement(
                actions=["cognito-identity:GetCredentialsForIdentity"],
                resources=["*"],
                effect=iam.Effect.ALLOW,
            )
        )

        images_bucket_name = images_bucket.bucket_name

        # Add S3 get object policy
        cognito_identity_pool_role.add_to_policy(
            statement=iam.PolicyStatement(
                actions=["s3:GetObject"],
                resources=[f"arn:aws:s3:::{images_bucket_name}/*"],
                effect=iam.Effect.ALLOW,
            )
        )
python python-3.x amazon-web-services aws-cdk circular-dependency
1个回答
0
投票

我想说这些命令将 RDS 堆栈的引用添加到 lambda 堆栈

# Redis ingress from company Lambda
        sg_redis.add_ingress_rule(
            ec2.Peer.security_group_id(sg_company_lambda.security_group_id),
            ec2.Port.tcp(6379),
            "Allow Redis traffic from company Lambda security group",
        )

        # RDS Proxy ingress from company Lambda
        sg_rds_proxy.add_ingress_rule(
            ec2.Peer.security_group_id(sg_company_lambda.security_group_id),
            ec2.Port.tcp(5432),
            "Allow PostgreSQL traffic from company Lambda security group",
        )

有时,CDK 构造源代码会以其他方式产生依赖关系,而不是您的代码在堆栈之间进行构造函数注入。

我建议使用 CDK 合成器并研究跨堆栈使用的输出导出的输出 CloudFormation 模板。

您还可以在 GitHub 中查看 CDK 构造的源代码。

© www.soinside.com 2019 - 2024. All rights reserved.