aws / aws/aws-cdk

(opensearch): Trying to define an Opensearch domain in one stack and reference it in another causes cyclic reference errors

Open
#20,256 6 comments 0 reactions 1 assignee Claimed by @kaizencc View on GitHub
@aws-cdk/aws-opensearch bug p3
Dominant language
TypeScript
Stars
12.9k
Forks
4.6k
Avg merge
1d 19h
Merged PRs (30d)
71

Description

### Describe the bug

I want to use the classic pattern where you have an infrastructure stack and a code stack.

I define an Opensearch domain in my infrastructure stack in a VPC. I then define a code stack, and attempt to wire up a Lambda that uses that domain.

This works when all the resources are in one stack; or if the code stack is nested in the infrastructure stack. But if they're peer stacks I get a cyclic reference stack.

For the reproduction provided below, the error is:

```
'InfrastructureStack' depends on 'CodeStack' (InfrastructureStack -> CodeStack/LambdaFunction/SecurityGroup/Resource.GroupId). Adding this dependency (CodeStack -> InfrastructureStack/OpensearchDomain/Resource.Arn) would create a cyclic reference.
```

### Expected Behavior

For all the resources related to my Lambda to be defined in the Code stack, so there's no cyclic references. That's what I'd do if I was writing the Cloudformation directly.

### Current Behavior

The lambda function itself is defined in the code stack Cloudformation. However, the AWS::EC2::SecurityGroupIngress allowing the lambda function ingress to the Opensearch domain is defined in the infrastructure stack Cloudformation.

### Reproduction Steps

The simplest reproduction I could come up with is to generate a new python application using `cdk init app --language python`, and then update app.py to be:

```
#!/usr/bin/env python3

import aws_cdk as cdk
from aws_cdk import aws_opensearchservice, aws_lambda, aws_ec2
from constructs import Construct

class InfrastructureStack(cdk.Stack):
def __init__(self, scope: Construct, construct_id: str, **kwargs) -> None:
super().__init__(scope, construct_id, **kwargs)

self._vpc = aws_ec2.Vpc(
scope=self,
id="Vpc",
cidr="10.64.0.0/16",
)

self._domain = aws_opensearchservice.Domain(
scope=self,
id="OpensearchDomain",
version=aws_opensearchservice.EngineVersion.OPENSEARCH_1_2,
vpc=self._vpc,
)

@property
def domain(self) -> aws_opensearchservice.Domain:
return self._domain

@property
def vpc(self) -> aws_ec2.IVpc:
return self._vpc

class CodeStack(cdk.Stack):
def __init__(self,
scope: Construct,
construct_id: str,
domain: aws_opensearchservice.Domain,
vpc: aws_ec2.IVpc,
**kwargs) -> None:
super().__init__(scope, construct_id, **kwargs)

self._lambda_function = aws_lambda.Function(
scope=self,
id="LambdaFunction",
handler="index.handler",
runtime=aws_lambda.Runtime.PYTHON_3_9,
code=aws_lambda.Code.from_inline("handler code goes here"),
environment={
"OPENSEARCH_ENDPOINT": domain.domain_endpoint,
},
vpc=vpc,
)

domain.connections.allow_from(self._lambda_function, aws_ec2.Port.tcp(443))
domain.grant_read_write(self._lambda_function)

app = cdk.App()

infrastructure_stack = InfrastructureStack(app, "InfrastructureStack")
CodeStack(app, "CodeStack", infrastructure_stack.domain, infrastructure_stack.vpc)

app.synth()
```

### Possible Solution

For all the resources related to my Lambda to be defined in the Code stack, so there's no cyclic references. That's what I'd do if I was writing the Cloudformation directly.

### Additional Information/Context

_No response_

### CDK CLI Version

2.23.0 (build 50444aa)

### Framework Version

2.24.0

### Node.js Version

14.17.0

### OS

Ubuntu (Windows Subsystem for Linux)

### Language

Python

### Language Version

3.9.7

### Other information

_No response_

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.