Export CDK Generated InternetGateway Resource [AWS Cloudformation] - amazon-web-services

So I have a basic VPC setup on CDK, after running cdk synth I see that an AWS::EC2::InternetGateway construct has been generated in my template under cdk.out. The problem is that I need to export this resource to another stack, but I can't reference this.vpc.internetGatewayId in my main .ts cdk file to export.
I know that this resource has been created, so I won't use CfnInternetGateway to create another, but at the same time this.vpc.internetGatewayId seems to have returned undefined even though I have a public subnet created and the resulting resource is in the template file.
Below is my VPC construct:
this.vpc = new ec2.Vpc(this, 'VPC', {
cidr: CONFIG.REGIONAL_CONFIG[region].VPC_CIDR,
maxAzs: CONFIG.REGIONAL_CONFIG[region].AVAILABILITY_ZONES,
subnetConfiguration: [
{
name: 'public',
subnetType: ec2.SubnetType.PUBLIC,
},
{
name: 'private',
subnetType: ec2.SubnetType.PRIVATE_WITH_NAT,
},
{
name: 'isolated',
subnetType: ec2.SubnetType.PRIVATE_ISOLATED,
},
],
});

Create a CloudFormation output on the exporting stack with with a CfnOutput:
// MyExportingStack.ts
// Cause the synth to fail if the ID is undefined. Alternatively, throw an error.
if (!vpc.internetGatewayId)
cdk.Annotations.of(this).addError('An Internet Gateway ID is required!');
// Create the CloudFormation Output
new cdk.CfnOutput(this, 'IgwId', { value: vpc.internetGatewayId ?? 'MISSING', exportName: 'my-igw-id',});

Related

Could not find a value associated with JSONKey in SecretString

I want to make RDS and proxy with credential
However, I bumped into this error.
14:32:32 | CREATE_FAILED | AWS::RDS::DBCluster | DatabaseB269D8BB
Could not find a value associated with JSONKey in SecretString
My script is like this below.
const rdsCredentials: rds.Credentials = rds.Credentials.fromGeneratedSecret(dbInfos['user'],{secretName:`cdk-st-${targetEnv}-db-secret`});
const dbCluster = new rds.DatabaseCluster(this, 'Database', {
parameterGroup,
engine: rds.DatabaseClusterEngine.auroraMysql({ version: rds.AuroraMysqlEngineVersion.VER_2_08_1 }),
credentials: rdsCredentials,
cloudwatchLogsExports:['slowquery','general','error','audit'],
backup: backupProps,
instances:2,
removalPolicy: cdk.RemovalPolicy.DESTROY,
clusterIdentifier: dbInfos['cluster'], //clusterIdentifier,
defaultDatabaseName :dbInfos['database'], //defaultDatabaseName,
instanceProps: {
// optional , defaults to t3.medium
instanceType: ec2.InstanceType.of(ec2.InstanceClass.BURSTABLE2, ec2.InstanceSize.SMALL),
vpcSubnets: {
subnetType: ec2.SubnetType.PRIVATE_ISOLATED,
},
vpc,
securityGroups:[dbSecurityGroup],
},
});
const proxy = new rds.DatabaseProxy(this, 'Proxy', {
proxyTarget: rds.ProxyTarget.fromCluster(dbCluster),
secrets: [dbCluster.secret!],
vpc,
});
I guess this error is related to secrets: [dbCluster.secret!] maybe.
I googled around and found this error happens when secrets are deleted.
However I want to use credential which is just generated for RDS
Is it impossible?
how can I fix this?
More Test
I tried another way but this comes the error below
/node_modules/aws-cdk-lib/aws-rds/lib/proxy.ts:239
secret.grantRead(role);
my code is here
dbCluster.addProxy('testProxy',{
secrets: [rdsCredentials.secret!],
vpc
});

How to get rid of the BootstrapVersion parameter with cdk synth?

When generating the cloudformation template with aws cdk:
cdk synth
I always get:
"Parameters": {
"BootstrapVersion": {
"Type": "AWS::SSM::Parameter::Value<String>",
...
Here the code:
import * as cdk from 'aws-cdk-lib';
import { Stack } from 'aws-cdk-lib';
import { Construct } from 'constructs';
import * as sqs from 'aws-cdk-lib/aws-sqs';
export class MyStack extends Stack {
constructor(scope: Construct, id: string) {
super(scope, id);
const queue = new sqs.Queue(this, 'Example', {
visibilityTimeout: cdk.Duration.seconds(300)
});
}
};
const app = new cdk.App();
new MyStack(app, 'MyStack');
Full output (some shortening ...):
$ cdk synth
Resources:
ExampleA925490C:
Type: AWS::SQS::Queue
Properties:
VisibilityTimeout: 300
UpdateReplacePolicy: Delete
DeletionPolicy: Delete
Metadata:
aws:cdk:path: MyStack/Example/Resource
CDKMetadata:
Type: AWS::CDK::Metadata
Properties:
Analytics: v2:deflate64:H4sIAAAAAAAA/zPSM9EzUEwsL9ZNTsnWzclM0qsOLklMztYBCsUXFxbrVQeWppam6jin5YEZtSBWUGpxfmlRMljUOT8vJbMkMz+vVicvPyVVL6tYv8zQTM8YaGpWcWamblFpXklmbqpeEIQGAChZc6twAAAA
Metadata:
aws:cdk:path: MyStack/CDKMetadata/Default
Condition: CDKMetadataAvailable
Conditions:
CDKMetadataAvailable:
Fn::Or:
- Fn::Or:
- Fn::Equals:
- Ref: AWS::Region
- af-south-1
...
- Fn::Or:
- Fn::Equals:
- Ref: AWS::Region
- us-west-1
...
Parameters:
BootstrapVersion:
Type: AWS::SSM::Parameter::Value<String>
Default: /cdk-bootstrap/hnb659fds/version
Description: Version of the CDK Bootstrap resources in this environment, automatically retrieved from SSM Parameter Store. [cdk:skip]
Rules:
CheckBootstrapVersion:
Assertions:
- Assert:
Fn::Not:
- Fn::Contains:
- - "1"
- "2"
- "3"
- "4"
- "5"
- Ref: BootstrapVersion
AssertDescription: CDK bootstrap stack version 6 required. Please run 'cdk bootstrap' with a recent version of the CDK CLI.
Here the environment:
$ cdk doctor
ℹ️ CDK Version: 2.8.0 (build 8a5eb49)
ℹ️ AWS environment variables:
- AWS_PAGER =
- AWS_DEFAULT_PROFILE = sbxb.admin
- AWS_STS_REGIONAL_ENDPOINTS = regional
- AWS_NODEJS_CONNECTION_REUSE_ENABLED = 1
- AWS_SDK_LOAD_CONFIG = 1
ℹ️ No CDK environment variables
How to get rid of that cloudformation parameter?
I just want to use CDK to create a cloudformation template.
Later I want to use that template with the service catalog and don't want the BootstrapVersion parameter to be exposed nor do I need it.
Here the modified code which works:
import * as cdk from 'aws-cdk-lib';
import { DefaultStackSynthesizer, Stack } from 'aws-cdk-lib';
import { Construct } from 'constructs';
import * as sqs from 'aws-cdk-lib/aws-sqs';
export class MyStack extends Stack {
constructor(scope: Construct, id: string, props?: cdk.StackProps) {
super(scope, id, props);
const queue = new sqs.Queue(this, 'Example', {
visibilityTimeout: cdk.Duration.seconds(300)
});
}
};
const app = new cdk.App();
new MyStack(app, 'MyStack' , {
synthesizer: new DefaultStackSynthesizer({
generateBootstrapVersionRule: false
})
});
As mentioned by the other answer one has to override the DefaultStackSynthesizer with generateBootstrapVersionRule: false.
Edit: updated the answer to mention the generateBootstrapVersionRule parameter. See #Felix's answer for code.
By default, the following is included in all templates when using DefaultStackSynthesizer:
"Parameters": {
"BootstrapVersion": {
"Type": "AWS::SSM::Parameter::Value<String>",
"Default": "/cdk-bootstrap/hnb659fds/version",
"Description": "Version of the CDK Bootstrap resources in this environment, automatically retrieved from SSM Parameter Store. [cdk:skip]"
}
},
"Rules": {
"CheckBootstrapVersion": {
"Assertions": [
{
"Assert": {
"Fn::Not": [
{
"Fn::Contains": [
[
"1",
"2",
"3",
"4",
"5"
],
{
"Ref": "BootstrapVersion"
}
]
}
]
},
"AssertDescription": "CDK bootstrap stack version 6 required. Please run 'cdk bootstrap' with a recent version of the CDK CLI."
}
]
}
}
The BootstrapVersion parameter and the associated rule are used by CDK to check the version of the Bootstrap stack which is deployed in your environment. You can remove it if you are confident that your stack doesn't require bootstrapping or you have the correct BootstrapVersion. The parameter isn't used anywhere else in stack.
By default, CDK v2 uses the DefaultStackSynthesizer so this parameter will always be included. One way of avoid this is to create a custom object with generateBootstrapVersionRule parameter with a value of false (see Felix's answer for code). Alternatively can also specify the LegacyStackSynthesizer when instantiating the CDK to avoid creating the parameter, however this makes a few changes in the way your stack is synthesized and how you use the bootstrap stack. A table of differences is given in the v1 documentation link below.
CDK v1 is the opposite and uses the LegacyStackSynthesizer by default.
References
https://github.com/aws/aws-cdk/issues/17942#issuecomment-992295898
https://docs.aws.amazon.com/cdk/v2/guide/bootstrapping.html#bootstrapping-synthesizers (v2 documentation)
https://docs.aws.amazon.com/cdk/v1/guide/bootstrapping.html#bootstrapping-synthesizers (v1 documentation)

AWS Subnet is out of IP Addresses (using CDK)

I've been trying de deploy a RestApiGateway with 20 lambda functions since a while now, and I keep getting the error message Subnet is out of IP addresses every time I try to deploy. Any idea why this may be happening?
Here's how my Vpc stack looks like:
this.vpc = new ec2.Vpc(this, 'vpc', {
cidr: '10.0.0.0/21',
maxAzs: this.azs,
natGateways: this.azs,
subnetConfiguration: [
{
subnetType: ec2.SubnetType.PUBLIC,
name: `${APP_PREFIX}-public-subnet`,
cidrMask: 24,
},
{
subnetType: ec2.SubnetType.PRIVATE,
name: `${APP_PREFIX}-private-subnet`,
cidrMask: 28,
},
],
});
...and here's the gateway:
const interfaceVpcEndpoint = vpc.addInterfaceEndpoint(`${APP_PREFIX}-endpoint`, {
service: ec2.InterfaceVpcEndpointAwsService.APIGATEWAY,
subnets: { subnetType: ec2.SubnetType.PRIVATE },
});
const restApiLogGroup = new logs.LogGroup(stack, `${APP_PREFIX}-log-group`, {
logGroupName: `${APP_PREFIX}-log-group`,
});
return new gateway.RestApi(stack, `${APP_PREFIX}-rest-api`, {
restApiName: `${APP_PREFIX}-rest-api`,
endpointConfiguration: {
types: [gateway.EndpointType.PRIVATE],
vpcEndpoints: [interfaceVpcEndpoint],
},
retainDeployments: true,
deployOptions: {
stageName: 'v2',
loggingLevel: gateway.MethodLoggingLevel.INFO,
dataTraceEnabled: true,
accessLogDestination: new gateway.LogGroupLogDestination(restApiLogGroup),
accessLogFormat: gateway.AccessLogFormat.jsonWithStandardFields(),
},
policy: new iam.PolicyDocument({
statements: [
new iam.PolicyStatement({
effect: iam.Effect.DENY,
principals: [new iam.AnyPrincipal()],
actions: ['execute-api:Invoke'],
resources: ['execute-api:/*/POST/*'],
conditions: {
StringNotEquals: {
'aws:sourceVpc': vpc.vpcId,
},
},
}),
new iam.PolicyStatement({
effect: iam.Effect.ALLOW,
principals: [new iam.AnyPrincipal()],
actions: ['execute-api:Invoke'],
resources: ['execute-api:/*/POST/*'],
}),
],
}),
});
The idea is that the lambda functions should not be accessible from the internet, only from a Fargate service that I will deploy via another stack.
I think this is the problem:
cidrMask: 28
A /28 network allows 16 IP addresses, and AWS takes 3 of those addresses for itself.
I'm not familiar with the CDK classes to create a subnet, so can't say whether the overall approach that you're using is correct. I'm assuming that it's smart enough to break the VPC CIDR into subnet blocks based on what you provide for a mask.
I recommend giving at least a /24 allocation to each subnet; I prefer a /20. And a /16 to the VPC. Network configuration is free when you start, extremely expensive to correct later.
I ended up explicitly adding the default security group created by the VPC Construct to each Lambda and that worked.

Get existing VPC for use within a Pulumi stack

I'm trying to use Pulumi within a somewhat restricted AWS environment.
This sandbox requires that I use a specific VPC, and there is no default VPC.
I have tried the examples showing how to reference an existing VPC, but they all fail with some variant of "invoking aws:ec2/getVpc:getVpc: no matching VPC found"
#pulumi/awsx, using code referenced from: https://github.com/pulumi/pulumi-awsx/issues/522:
const vpc = awsx.ec2.Vpc.fromExistingIds('name', {
vpcId: 'id',
publicSubnetIds: ['a', 'b'],
privateSubnetIds: ['a', 'b']
})
#pulumi/aws, using code referenced from https://www.pulumi.com/docs/reference/pkg/aws/ec2/getvpc/:
const vpc = aws.ec2.Vpc.get('vpc-1', 'vpc-1')
Question: what is the correct and complete syntax for referencing an existing VPC within a Pulumi stack?
Note that I would rather not "adopt" this resource as it is shared and the user running the pulumi up command does not have permission to delete VPC resources.
There is a subtle difference between getVpc() that you linked to and Vpc.get() that you tried using. You should use the former:
const vpc = aws.ec2.getVpc({ id: yourVpcId });
This is what worked in the end:
const vpc = aws.ec2.Vpc.get('vpc-123', 'vpc-123')
I don't think I had saved my file correctly before pulumi up after making the above change.
Note that I also had to add subnets manually to my ALB to get this working, as below:
const vpc = aws.ec2.Vpc.get('vpc-123', 'vpc-123')
const clusterName = nameResource('graphQlServiceCluster')
const ecsCluster = new awsx.ecs.Cluster(clusterName, {
name: clusterName,
vpc
})
const PublicSubnet1a = 'subnet-123'
const PublicSubnet1b = 'subnet-123'
const alb = new awsx.lb.ApplicationLoadBalancer(nameResource('graphQlServiceElb'), {
name: nameResource('graphQlServiceElb'),
external: true,
vpc,
subnets: [
PublicSubnet1a,
PublicSubnet1b
]
})
const listener = alb.createListener(nameResource('graphqlServiceListener'), {
name: nameResource('graphqlServiceListener'),
port: 80,
external: true,
vpc
})
Pulumi has multiple Vpc types. You probably want to use the awsx VPC as it's higher level (and required to use other awsx infrastructure).
There's two ways to do this:
Creating a new VPC
const vpc = new awsx.ec2.Vpc(config.vpcName, {
cidrBlock: "10.0.0.0/16",
subnets: [
{
name: "public",
type: "public",
location: {
cidrBlock: "10.0.0.0/24",
availabilityZone: "us-east-2a",
},
},
{
name: "private-a",
type: "private",
location: {
cidrBlock: "10.0.1.0/24",
availabilityZone: "us-east-2a",
},
},
{
name: "private-b",
type: "private",
location: {
cidrBlock: "10.0.2.0/24",
availabilityZone: "us-east-2b",
},
},
],
});
Using an existing VPC
Borrowing from this GitHub thread with the Pulumi CTO produced a correct result:
const vpc = awsx.ec2.Vpc.fromExistingIds("mycompany", {
vpcId: "vpc-myvpcid",
});
// Create an ECS Fargate cluster.
const ecsCluster = new awsx.ecs.Cluster("mycompany-pulumi-cluster", {
vpc,
});

How to give particular/full access to Elastic beanstalk using aws CDK?

I have created aws pipeline to deploy my dot net framework app to elastic beanstalk using CDK typescript code.
But in deploy step it fails with below error
Insufficient permissions
The provided role does not have the elasticbeanstalk:CreateApplicationVersion permission
I am not sure how to assign permissions using aws cdk.
How should I add permissions in below code
Below is my deploy stage code
const appName = "SampleDotNetMVCWebApp";
const newRole = new iam.Role(this, "Role", {
assumedBy: new iam.ServicePrincipal("elasticbeanstalk.amazonaws.com")
});
newRole.addToPolicy(
new iam.PolicyStatement({
resources: ["*"],
actions: ["elasticbeanstalk:CreateApplicationVersion"]
})
);
const app = new elasticbeanstalk.CfnApplication(this, "EBApplication", {
applicationName: appName
});
const elbEnv = new elasticbeanstalk.CfnEnvironment(this, "Environment", {
environmentName: "SampleMVCEBEnvironment",
applicationName: appName,
platformArn: platform,
solutionStackName: "64bit Windows Server 2012 R2 v2.5.0 running IIS 8.5"
});
pipeline.addStage({
stageName: "Deploy",
actions: [
new ElasticBeanStalkDeployAction({
actionName: "DeployToEB",
applicationName: appName,
environmentName: "SampleMVCEBEnvironment",
input: cdkBuildOutput,
role: newRole
})
]
});
NOTE: In above code aws pipeline action "ElasticBeanStalkDeployAction" is custom action as aws cdk has not release this deploy to eb action feature yet.
You can check the issue and code for implementation of IAction here
https://github.com/aws/aws-cdk/issues/2516
You need to add permissions to ElasticBeanStalkDeployAction to create CreateApplicationVersion, Use .addToPolicy
These policies will be created with the role, whereas those added by
addToPolicy are added using a separate CloudFormation resource
(allowing a way around circular dependencies that could otherwise be
introduced).
const elasticBeanStalkDeployAction = new ElasticBeanStalkDeployAction({
actionName: 'DeployToEB',
applicationName: appName,
environmentName: 'SampleMVCEBEnvironment',
input: cdkBuildOutput
})
elasticBeanStalkDeployAction.addToRolePolicy(new PolicyStatement({
effect: Effect.ALLOW,
resources: ['*'],
actions: ['elasticbeanstalk:*']
}));
Later, use the object you created and pass it into the action:
pipeline.addStage({
stageName: 'Deploy',
actions: [elasticBeanStalkDeployAction]
});
Alternatively as suggested here - https://github.com/aws/aws-cdk/issues/2516
This issue can be resolved by adding policy in bind method of ElasticBeanStalkDeployAction
public bind(scope: Construct, stage: codepipeline.IStage, options: codepipeline.ActionBindOptions):
codepipeline.ActionConfig {
options.role.addManagedPolicy(
iam.ManagedPolicy.fromAwsManagedPolicyName(
"AWSElasticBeanstalkFullAccess"
));
}