13

I would like to know how to import security group defined in another stack, and then use in current stack.

I have tried this so far..

class relayStack extends cdk.Stack {
    public sg_relay: ec2.SecurityGroupRefProps

    constructor(parent: cdk.App, name: string, props: VPCProps) {
        super(parent, name, props);

        //#IMPORT VPC PROPS
        const vpc = ec2.VpcNetwork.import(this, 'VPC-Hottest100', props.infra.vpc);
        //#AUTOSCALING GROUP
        const asg_relayServer = new ec2.AutoScalingGroup(this, 'ASG_Relay', {
            vpc,
            instanceType: new ec2.InstanceTypePair(ec2.InstanceClass.T2, ec2.InstanceSize.Small),
            minSize: 1,
            maxSize: 3,
            desiredCapacity: 1,
            machineImage: new ec2.GenericLinuxImage({
                "ap-southeast-2": "ami-dc361ebf",
            }),
            keyName: 'icecast-poc',
            allowAllOutbound: false,
            vpcPlacement: {
                usePublicSubnets: false
            }
        });

        //#SECURITY Group
        const sg_relay = new ec2.SecurityGroup(this, 'SG_RELAY', {
            vpc,
            description: "Relay stack security group",
            groupName: 'relay-sg'
        })


        this.sg_relay = sg_relay
    }
}

And then from another stack I would like to access the exported security group sg_relay

I have tried following

//#SECURITY GROUP
const sg_nginx = new ec2.SecurityGroup(this, "SG_NGINX", {
    vpc,
    description: "NGINX stack security group",
    groupName: 'nginx-sg'
})

const sg_relayImp = new ec2.SecurityGroupRef(this, "SG_RELAY_IMP", {
    securityGroupId: new ec2.SecurityGroupId('SG_RELAY')
})

And then use as following

sg_nginx.addIngressRule(sg_relayImp, wowzaPort, 'asg_RelyToNgn_8000')

Obviously its not working for me.

I could not find any import function for security group between stacks, like vpc has one.

Could anyone please help me with this situation?

Romain
  • 12,679
  • 3
  • 41
  • 54
Rumman Ahmed
  • 189
  • 1
  • 1
  • 11

4 Answers4

27

You can directly refer the cross-stack resources in an app.

Below is a code snippet,

export class InfraCdkStack extends cdk.Stack {
  // Create a readonly property to reference on an instance.
  readonly vpc: ec2.IVpc;

  constructor(scope: cdk.Construct, id: string, props?: cdk.StackProps) {
    super(scope, id, props);

    // The code that defines your stack goes here.
    // Assign your vpc to your previously created property.
    // Creates a vpc in two AZs.
    this.vpc = new ec2.Vpc(this, 'MyVPC');
  }
}

// Create an interface to hold the vpc information.
interface ECSStackProps extends cdk.StackProps {
  vpc: ec2.IVpc;
}

// Have your class constructor accept the interface.
export class ECSCdkStack extends cdk.Stack {
  constructor(scope: cdk.Construct, id: string, props: ECSStackProps) {
    super(scope, id, props);
}

const app = new cdk.App();
const infraStack = new InfraCdkStack(app, 'InfraCdkStack');
// Pass the infraStack.vpc property to the ECSCdkStack class.
const gameECSStack = new ECSCdkStack(app, 'ECSCdkStack', {
    vpc: infraStack.vpc
});

There is an example in official doc to demonstrate how sharing s3 bucket.

Kane
  • 8,035
  • 7
  • 46
  • 75
  • 2
    Thanks. I am wondering if there is any support or example for cross-repo value import? – Ivan Wang Apr 25 '20 at 16:53
  • 1
    See static methods [fromBucketXxx](https://docs.aws.amazon.com/cdk/api/latest/typescript/api/aws-s3/bucket.html#aws_s3_Bucket_fromBucketAttributes). Note, the imported resources mostly are readonly. – Kane Apr 26 '20 at 00:23
10

Assuming that the Stacks in question are both under your CDK Application, you can use Stack Outputs to share resources.

Docs here: https://docs.aws.amazon.com/cdk/api/latest/docs/core-readme.html#stack-outputs

I found this blog post to be useful as an example (not written by me)

It should work for any resource you might want to reference between stacks.

EDIT: This is what I'm working with at the moment.

// I have a resource which is a cloudfront dist id in StackA
new cdk.CfnOutput(this, 'cloudfront-dist-id-output', {
      description: 'cloudfront-dist-id-output',
      exportName: 'cloudfront-dist-id-output',
      value: cloudFrontDistribution.distributionId
    });

// Stack B needs the DistributionId (it's dynamic), so I pass it in as a parameter.
new StackB(app, 'StackB', Fn.importValue('cloudfront-dist-id-output'));

The only 'known' thing ahead of time is the name of the parameter that you're outputting.

This is effectively the same thing you've provided in your other answer, but the CDK writes the Fn.importValue for you.

Warning: Does not work with resources in stacks that are in different regions. The limitation is imposed by CloudFormation and will also happen in @Kane's answer.

charlybones
  • 309
  • 4
  • 12
  • 1
    Could you update answer with an example to demonstrate how to use outputs and imports? – Kane Aug 21 '19 at 05:27
  • @Kane I've updated the answer. Please note that there is a limitation on Fn.importValue imposed by CloudFormation. You can't reference things that are in stacks deployed in different regions. – charlybones Aug 21 '19 at 13:46
  • @charlybones so it has to be passed as a parameter? cant we not import directly in a constructor in the stack? and how is it different from the other answer above? since the other answer, we need not do explicit export and import – PCB Jan 26 '20 at 18:51
  • This was a super helpful answer. I had previously passing a reference from one stack into the other, but that caused both to be deployed every time I wanted to update the second stack. Using this stack export method allowed me to import the Arn I needed into the other stack without a huge dependency. Great tip. – MarkC Apr 15 '20 at 21:41
2

Create a sample security group like this in STACK A.

const sampleSecurityGroup = new ec2.SecurityGroup(this, 'security-group', { vpc: vpc, allowAllOutbound: true, description: 'Security Group Sample', securityGroupName: "SAMPLE-SG" });

Export the SG using below in STACK A.

const myoutput = new cdk.CfnOutput(this, 'Security-group-id-output', { description: 'Security group in Stack A', exportName: 'security-id-output', value: sampleSecurityGroup.securityGroupId });

Check the Cloud formation service in in UI you should see the Exports by the name "security-id-output".

In STACK B import the value using

cdk.Fn.importValue("security-id-output");
kish
  • 41
  • 3
  • 2
    This didn't work for me :(. Do the two stacks have to be under the same cdk.App? Or is it enough for the two stacks to be in the same account & region? – morgler Apr 04 '21 at 14:32
0

You could use SecurityGroup.export in the stack that defines the security group initially, and this will create a stack Output with a generated export name, and return the data that you need to pass to SecurityGroupRef.import in order to obtain a reference to the security group in the other stack.

You'll need to be sure to deploy the stack that defines the security group first, as otherwise the other stack will not be able to import from that stack's outputs.

Romain
  • 12,679
  • 3
  • 41
  • 54
  • Is there a general solution for this? I mean, what if the Output is something else, let's say, the ARN of a DynamoDB table? – Otavio Macedo Apr 23 '19 at 13:09
  • 7
    export/import has been removed in latest CDK versions. It won't work any more. – Kane Aug 21 '19 at 02:54
  • While this isn't an option any more, it is still a good answer for folks not using the CDK, as this is pretty much what you have to do with regular CloudFormation. CDK makes life easy by allowing you to avoid doing exports/imports in this way. – trademark Jul 08 '21 at 20:24