-
Notifications
You must be signed in to change notification settings - Fork 5
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix IPV6 cidr blocks #197
Fix IPV6 cidr blocks #197
Changes from 3 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
name: pulumi-aws-ec2 | ||
runtime: nodejs | ||
description: ec2 integration test |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,127 @@ | ||
import * as aws from '@pulumi/aws'; | ||
import * as iam from 'aws-cdk-lib/aws-iam'; | ||
import * as ec2 from 'aws-cdk-lib/aws-ec2'; | ||
import * as elbv2 from 'aws-cdk-lib/aws-elasticloadbalancingv2'; | ||
import * as pulumicdk from '@pulumi/cdk'; | ||
import { SecretValue } from 'aws-cdk-lib/core'; | ||
|
||
class Ec2Stack extends pulumicdk.Stack { | ||
constructor(app: pulumicdk.App, id: string, options?: pulumicdk.StackOptions) { | ||
super(app, id, options); | ||
const vpc = new ec2.Vpc(this, 'Vpc', { | ||
maxAzs: 2, | ||
ipProtocol: ec2.IpProtocol.DUAL_STACK, | ||
vpnGateway: true, | ||
ipAddresses: ec2.IpAddresses.cidr('10.0.0.0/16'), | ||
natGateways: 1, | ||
vpnConnections: { | ||
dynamic: { | ||
ip: '1.2.3.4', | ||
tunnelOptions: [ | ||
{ | ||
preSharedKeySecret: SecretValue.unsafePlainText('secretkey1234'), | ||
}, | ||
{ | ||
preSharedKeySecret: SecretValue.unsafePlainText('secretkey5678'), | ||
}, | ||
], | ||
}, | ||
static: { | ||
ip: '4.5.6.7', | ||
staticRoutes: ['192.168.10.0/24', '192.168.20.0/24'], | ||
}, | ||
}, | ||
subnetConfiguration: [ | ||
{ | ||
name: 'Public', | ||
subnetType: ec2.SubnetType.PUBLIC, | ||
}, | ||
{ | ||
name: 'Private', | ||
subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS, | ||
}, | ||
{ | ||
name: 'Isolated', | ||
subnetType: ec2.SubnetType.PRIVATE_ISOLATED, | ||
}, | ||
], | ||
restrictDefaultSecurityGroup: false, | ||
}); | ||
|
||
vpc.addFlowLog('FlowLogs', { | ||
destination: ec2.FlowLogDestination.toCloudWatchLogs(), | ||
}); | ||
|
||
vpc.addGatewayEndpoint('Dynamo', { | ||
service: ec2.GatewayVpcEndpointAwsService.DYNAMODB, | ||
}); | ||
vpc.addInterfaceEndpoint('ecr', { | ||
service: ec2.InterfaceVpcEndpointAwsService.ECR_DOCKER, | ||
}); | ||
|
||
new ec2.PrefixList(this, 'PrefixList', {}); | ||
const nacl = new ec2.NetworkAcl(this, 'NetworkAcl', { | ||
vpc, | ||
subnetSelection: { subnetType: ec2.SubnetType.PUBLIC }, | ||
}); | ||
nacl.addEntry('AllowAll', { | ||
cidr: ec2.AclCidr.anyIpv4(), | ||
ruleAction: ec2.Action.ALLOW, | ||
ruleNumber: 100, | ||
traffic: ec2.AclTraffic.allTraffic(), | ||
}); | ||
new ec2.KeyPair(this, 'KeyPair'); | ||
|
||
const nlb = new elbv2.NetworkLoadBalancer(this, 'NLB1', { vpc }); | ||
new ec2.VpcEndpointService(this, 'EndpointService', { | ||
vpcEndpointServiceLoadBalancers: [nlb], | ||
allowedPrincipals: [new iam.ArnPrincipal('ec2.amazonaws.com')], | ||
}); | ||
} | ||
} | ||
|
||
new pulumicdk.App( | ||
'app', | ||
(scope: pulumicdk.App) => { | ||
new Ec2Stack(scope, 'teststack'); | ||
}, | ||
{ | ||
appOptions: { | ||
remapCloudControlResource: (logicalId, typeName, props, options) => { | ||
if (typeName === 'AWS::EC2::VPNGatewayRoutePropagation') { | ||
const tableIds: string[] = props.RouteTableIds; | ||
return tableIds.flatMap((tableId, i) => { | ||
const id = i === 0 ? logicalId : `${logicalId}-${i}`; | ||
return { | ||
logicalId: id, | ||
resource: new aws.ec2.VpnGatewayRoutePropagation( | ||
id, | ||
{ | ||
routeTableId: tableId, | ||
vpnGatewayId: props.VpnGatewayId, | ||
}, | ||
options, | ||
), | ||
}; | ||
}); | ||
} | ||
if (typeName === 'AWS::EC2::NetworkAclEntry') { | ||
return new aws.ec2.NetworkAclRule(logicalId, { | ||
egress: props.Egress, | ||
toPort: props.PortRange?.To, | ||
fromPort: props.PortRange?.From, | ||
protocol: props.Protocol, | ||
ruleNumber: props.RuleNumber, | ||
networkAclId: props.NetworkAclId, | ||
ruleAction: props.RuleAction, | ||
cidrBlock: props.CidrBlock, | ||
ipv6CidrBlock: props.Ipv6CidrBlock, | ||
icmpCode: props.Icmp?.Code, | ||
icmpType: props.Icmp?.Type, | ||
}); | ||
} | ||
return undefined; | ||
}, | ||
}, | ||
}, | ||
); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
{ | ||
"name": "pulumi-aws-cdk", | ||
"devDependencies": { | ||
"@types/node": "^10.0.0" | ||
}, | ||
"dependencies": { | ||
"@pulumi/aws": "^6.0.0", | ||
"@pulumi/aws-native": "^1.6.0", | ||
"@pulumi/cdk": "^0.5.0", | ||
"@pulumi/pulumi": "^3.0.0", | ||
"aws-cdk-lib": "2.149.0", | ||
"constructs": "10.3.0", | ||
"esbuild": "^0.24.0" | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
{ | ||
"compilerOptions": { | ||
"strict": true, | ||
"outDir": "bin", | ||
"target": "es2019", | ||
"module": "commonjs", | ||
"moduleResolution": "node", | ||
"sourceMap": true, | ||
"experimentalDecorators": true, | ||
"pretty": true, | ||
"noFallthroughCasesInSwitch": true, | ||
"noImplicitReturns": true, | ||
"forceConsistentCasingInFileNames": true | ||
}, | ||
"include": [ | ||
"./*.ts" | ||
] | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -115,15 +115,19 @@ | |
// Map of resource logicalId to GraphNode. Allows for easy lookup by logicalId | ||
cfnElementNodes: Map<string, GraphNode>; | ||
|
||
// If the app has a VpcCidrBlock resource, this will be set to the GraphNode representing it | ||
vpcCidrBlockNode?: GraphNode; | ||
// If the app has a Vpc resource, this will be set to the GraphNode representing it | ||
vpcNode?: GraphNode; | ||
|
||
constructor(private readonly stack: StackManifest) { | ||
this.constructNodes = new Map<ConstructInfo, GraphNode>(); | ||
this.cfnElementNodes = new Map<string, GraphNode>(); | ||
} | ||
|
||
// build constructs a dependency graph from the adapter and returns its nodes sorted in topological order. | ||
public static build(stack: StackManifest): GraphNode[] { | ||
const b = new GraphBuilder(stack); | ||
return b._build(); | ||
public build(): GraphNode[] { | ||
return this._build(); | ||
} | ||
|
||
/** | ||
|
@@ -163,6 +167,12 @@ | |
`Something went wrong: resourceType ${resource.Type} does not equal CfnType ${cfnType}`, | ||
); | ||
} | ||
if (resource.Type === 'AWS::EC2::VPCCidrBlock') { | ||
this.vpcCidrBlockNode = node; | ||
} | ||
if (resource.Type === 'AWS::EC2::VPC') { | ||
this.vpcNode = node; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can a stack only have a single VPC? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think that case would be exceedingly rare, but I should be able to update this to handle that case |
||
} | ||
} | ||
this.constructNodes.set(construct, node); | ||
if (tree.children) { | ||
|
@@ -224,7 +234,7 @@ | |
sorted.push(node); | ||
} | ||
|
||
for (const [_, node] of this.constructNodes) { | ||
sort(node); | ||
} | ||
|
||
|
@@ -285,9 +295,25 @@ | |
|
||
private addEdgesForIntrinsic(fn: string, params: any, source: GraphNode) { | ||
switch (fn) { | ||
case 'Fn::GetAtt': | ||
this.addEdgeForRef(params[0], source); | ||
case 'Fn::GetAtt': { | ||
let logicalId = params[0]; | ||
const attributeName = params[1]; | ||
// Special case for VPC Ipv6CidrBlocks | ||
// Ipv6 cidr blocks are added to the VPC through a separate VpcCidrBlock resource | ||
// Due to [pulumi/pulumi-aws-native#1798] the `Ipv6CidrBlocks` attribute will always be empty | ||
// and we need to instead pull the `Ipv6CidrBlock` attribute from the VpcCidrBlock resource. | ||
// Here we switching the dependency to be on the `VpcCidrBlock` resource (since that will also have a dependency | ||
// on the VPC resource) | ||
if ( | ||
logicalId === this.vpcNode?.logicalId && | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Along the lines of my earlier Q, what happens if the stack has multiple VPCs? |
||
attributeName === 'Ipv6CidrBlocks' && | ||
this.vpcCidrBlockNode?.logicalId | ||
) { | ||
logicalId = this.vpcCidrBlockNode.logicalId; | ||
} | ||
this.addEdgeForRef(logicalId, source); | ||
break; | ||
} | ||
case 'Fn::Sub': | ||
{ | ||
const [template, vars] = | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: I'd prefer if we'd save that in the result of
GraphBuilder::build
. E.g. turn this into aGraphResult
struct that has the necessary params we need.I wouldn't expect a
Builder
to store state beyond what's needed to build