in packages/aws-cdk-lib/aws-ec2/lib/vpn.ts [284:370]
constructor(scope: Construct, id: string, props: VpnConnectionProps) {
super(scope, id);
// Enhanced CDK Analytics Telemetry
addConstructMetadata(this, props);
if (!props.vpc.vpnGatewayId) {
props.vpc.enableVpnGateway({
type: 'ipsec.1',
amazonSideAsn: props.asn,
});
}
if (!Token.isUnresolved(props.ip) && !net.isIPv4(props.ip)) {
throw new ValidationError(`The \`ip\` ${props.ip} is not a valid IPv4 address.`, this);
}
const type = VpnConnectionType.IPSEC_1;
const bgpAsn = props.asn || 65000;
const customerGateway = new CfnCustomerGateway(this, 'CustomerGateway', {
bgpAsn,
ipAddress: props.ip,
type,
});
this.customerGatewayId = customerGateway.ref;
this.customerGatewayAsn = bgpAsn;
this.customerGatewayIp = props.ip;
// Validate tunnel options
if (props.tunnelOptions) {
if (props.tunnelOptions.length > 2) {
throw new ValidationError('Cannot specify more than two `tunnelOptions`', this);
}
if (props.tunnelOptions.length === 2 &&
props.tunnelOptions[0].tunnelInsideCidr === props.tunnelOptions[1].tunnelInsideCidr &&
props.tunnelOptions[0].tunnelInsideCidr !== undefined) {
throw new ValidationError(`Same ${props.tunnelOptions[0].tunnelInsideCidr} \`tunnelInsideCidr\` cannot be used for both tunnels.`, this);
}
props.tunnelOptions.forEach((options, index) => {
if (options.preSharedKey && options.preSharedKeySecret) {
throw new ValidationError("Specify at most one of 'preSharedKey' and 'preSharedKeySecret'.", this);
}
if (options.preSharedKey && !Token.isUnresolved(options.preSharedKey) && !/^[a-zA-Z1-9._][a-zA-Z\d._]{7,63}$/.test(options.preSharedKey)) {
/* eslint-disable max-len */
throw new ValidationError(`The \`preSharedKey\` ${options.preSharedKey} for tunnel ${index + 1} is invalid. Allowed characters are alphanumeric characters and ._. Must be between 8 and 64 characters in length and cannot start with zero (0).`, this);
/* eslint-enable max-len */
}
if (options.tunnelInsideCidr) {
if (RESERVED_TUNNEL_INSIDE_CIDR.includes(options.tunnelInsideCidr)) {
throw new ValidationError(`The \`tunnelInsideCidr\` ${options.tunnelInsideCidr} for tunnel ${index + 1} is a reserved inside CIDR.`, this);
}
if (!/^169\.254\.\d{1,3}\.\d{1,3}\/30$/.test(options.tunnelInsideCidr)) {
/* eslint-disable-next-line max-len */
throw new ValidationError(`The \`tunnelInsideCidr\` ${options.tunnelInsideCidr} for tunnel ${index + 1} is not a size /30 CIDR block from the 169.254.0.0/16 range.`, this);
}
}
});
}
const vpnConnection = new CfnVPNConnection(this, 'Resource', {
type,
customerGatewayId: customerGateway.ref,
staticRoutesOnly: props.staticRoutes ? true : false,
vpnGatewayId: props.vpc.vpnGatewayId,
vpnTunnelOptionsSpecifications: props.tunnelOptions?.map(t => ({
preSharedKey: t.preSharedKeySecret?.unsafeUnwrap() ?? t.preSharedKey,
tunnelInsideCidr: t.tunnelInsideCidr,
})),
});
this.vpnId = vpnConnection.ref;
if (props.staticRoutes) {
props.staticRoutes.forEach(route => {
new CfnVPNConnectionRoute(this, `Route${route.replace(/[^\d]/g, '')}`, {
destinationCidrBlock: route,
vpnConnectionId: this.vpnId,
});
});
}
}