constructor()

in packages/aws-cdk-lib/aws-ec2/lib/vpc.ts [1505:1705]


  constructor(scope: Construct, id: string, props: VpcProps = {}) {
    super(scope, id);
    // Enhanced CDK Analytics Telemetry
    addConstructMetadata(this, props);

    const stack = Stack.of(this);

    // Can't have enabledDnsHostnames without enableDnsSupport
    if (props.enableDnsHostnames && !props.enableDnsSupport) {
      throw new ValidationError('To use DNS Hostnames, DNS Support must be enabled, however, it was explicitly disabled.', this);
    }

    if (props.availabilityZones && props.maxAzs) {
      throw new ValidationError('Vpc supports \'availabilityZones\' or \'maxAzs\', but not both.', this);
    }

    const cidrBlock = ifUndefined(props.cidr, Vpc.DEFAULT_CIDR_RANGE);
    if (Token.isUnresolved(cidrBlock)) {
      throw new ValidationError('\'cidr\' property must be a concrete CIDR string, got a Token (we need to parse it for automatic subdivision)', this);
    }

    if (props.ipAddresses && props.cidr) {
      throw new ValidationError('supply at most one of ipAddresses or cidr', this);
    }

    const ipProtocol = props.ipProtocol ?? IpProtocol.IPV4_ONLY;
    // this property can be set to false if an IPv6_ONLY VPC is implemented in the future
    this.useIpv4 = ipProtocol === IpProtocol.IPV4_ONLY || ipProtocol === IpProtocol.DUAL_STACK;

    this.useIpv6 = ipProtocol === IpProtocol.DUAL_STACK;

    const ipv6OnlyProps: Array<keyof VpcProps> = ['ipv6Addresses'];
    if (!this.useIpv6) {
      for (const prop of ipv6OnlyProps) {
        if (props[prop] !== undefined) {
          throw new ValidationError(`${prop} can only be set if IPv6 is enabled. Set ipProtocol to DUAL_STACK`, this);
        }
      }
    }

    this.ipAddresses = props.ipAddresses ?? IpAddresses.cidr(cidrBlock);

    this.dnsHostnamesEnabled = props.enableDnsHostnames == null ? true : props.enableDnsHostnames;
    this.dnsSupportEnabled = props.enableDnsSupport == null ? true : props.enableDnsSupport;
    const instanceTenancy = props.defaultInstanceTenancy || 'default';
    this.internetConnectivityEstablished = this._internetConnectivityEstablished;

    const vpcIpAddressOptions = this.ipAddresses.allocateVpcCidr();

    // Define a VPC using the provided CIDR range
    this.resource = new CfnVPC(this, 'Resource', {
      cidrBlock: vpcIpAddressOptions.cidrBlock,
      ipv4IpamPoolId: vpcIpAddressOptions.ipv4IpamPoolId,
      ipv4NetmaskLength: vpcIpAddressOptions.ipv4NetmaskLength,
      enableDnsHostnames: this.dnsHostnamesEnabled,
      enableDnsSupport: this.dnsSupportEnabled,
      instanceTenancy,
    });

    this.vpcDefaultNetworkAcl = this.resource.attrDefaultNetworkAcl;
    this.vpcCidrBlockAssociations = this.resource.attrCidrBlockAssociations;
    this.vpcCidrBlock = this.resource.attrCidrBlock;
    this.vpcDefaultSecurityGroup = this.resource.attrDefaultSecurityGroup;
    this.vpcIpv6CidrBlocks = this.resource.attrIpv6CidrBlocks;

    Tags.of(this).add(NAME_TAG, props.vpcName || this.node.path);

    if (props.availabilityZones) {
      // If given AZs and stack AZs are both resolved, then validate their compatibility.
      const resolvedStackAzs = this.resolveStackAvailabilityZones(stack.availabilityZones);
      const areGivenAzsSubsetOfStack = resolvedStackAzs.length === 0 ||
        props.availabilityZones.every(az => Token.isUnresolved(az) ||resolvedStackAzs.includes(az));
      if (!areGivenAzsSubsetOfStack) {
        throw new ValidationError(`Given VPC 'availabilityZones' ${props.availabilityZones} must be a subset of the stack's availability zones ${resolvedStackAzs}`, this);
      }
      this.availabilityZones = props.availabilityZones;
    } else {
      const maxAZs = props.maxAzs ?? 3;
      this.availabilityZones = stack.availabilityZones.slice(0, maxAZs);
    }
    for (let i = 0; props.reservedAzs && i < props.reservedAzs; i++) {
      this.availabilityZones.push(FAKE_AZ_NAME);
    }

    this.vpcId = this.resource.ref;
    this.vpcArn = Arn.format({
      service: 'ec2',
      resource: 'vpc',
      resourceName: this.vpcId,
    }, stack);

    const defaultSubnet = props.natGateways === 0 ? Vpc.DEFAULT_SUBNETS_NO_NAT : Vpc.DEFAULT_SUBNETS;
    this.subnetConfiguration = ifUndefined(props.subnetConfiguration, defaultSubnet);

    const natGatewayPlacement = props.natGatewaySubnets || { subnetType: SubnetType.PUBLIC };
    const natGatewayCount = determineNatGatewayCount(props.natGateways, this.subnetConfiguration, this.availabilityZones.length);

    if (this.useIpv6) {
      this.ipv6Addresses = props.ipv6Addresses ?? Ipv6Addresses.amazonProvided();

      this.ipv6CidrBlock = this.ipv6Addresses.allocateVpcIpv6Cidr({
        scope: this,
        vpcId: this.vpcId,
      });

      this.ipv6SelectedCidr = Fn.select(0, this.resource.attrIpv6CidrBlocks);
    }

    // subnetConfiguration must be set before calling createSubnets
    this.createSubnets();

    const createInternetGateway = props.createInternetGateway ?? true;
    const allowOutbound = this.subnetConfiguration.filter(
      subnet => (subnet.subnetType !== SubnetType.PRIVATE_ISOLATED && subnet.subnetType !== SubnetType.ISOLATED && !subnet.reserved)).length > 0;

    // Create an Internet Gateway and attach it if necessary
    if (allowOutbound && createInternetGateway) {
      const igw = new CfnInternetGateway(this, 'IGW', {
      });

      this.internetGatewayId = igw.ref;

      this._internetConnectivityEstablished.add(igw);
      const att = new CfnVPCGatewayAttachment(this, 'VPCGW', {
        internetGatewayId: igw.ref,
        vpcId: this.resource.ref,
      });

      (this.publicSubnets as PublicSubnet[]).forEach(publicSubnet => {
        // configure IPv4 route
        if (this.useIpv4) {
          publicSubnet.addDefaultInternetRoute(igw.ref, att);
        }
        // configure IPv6 route if VPC is dual stack
        if (this.useIpv6) {
          publicSubnet.addIpv6DefaultInternetRoute(igw.ref);
        }
      });

      // if gateways are needed create them
      if (natGatewayCount > 0) {
        const provider = props.natGatewayProvider || NatProvider.gateway();
        this.createNatGateways(provider, natGatewayCount, natGatewayPlacement);
      }
    }

    // Create an Egress Only Internet Gateway and attach it if necessary
    if (this.useIpv6 && this.privateSubnets) {
      const eigw = new CfnEgressOnlyInternetGateway(this, 'EIGW6', {
        vpcId: this.vpcId,
      });

      (this.privateSubnets as PrivateSubnet[]).forEach(privateSubnet => {
        privateSubnet.addIpv6DefaultEgressOnlyInternetRoute(eigw.ref);
      });
    }

    if (props.vpnGateway && this.publicSubnets.length === 0 && this.privateSubnets.length === 0 && this.isolatedSubnets.length === 0) {
      throw new ValidationError('Can not enable the VPN gateway while the VPC has no subnets at all', this);
    }

    if ((props.vpnConnections || props.vpnGatewayAsn) && props.vpnGateway === false) {
      throw new ValidationError('Cannot specify `vpnConnections` or `vpnGatewayAsn` when `vpnGateway` is set to false.', this);
    }

    if (props.vpnGateway || props.vpnConnections || props.vpnGatewayAsn) {
      this.enableVpnGateway({
        amazonSideAsn: props.vpnGatewayAsn,
        type: VpnConnectionType.IPSEC_1,
        vpnRoutePropagation: props.vpnRoutePropagation,
      });

      const vpnConnections = props.vpnConnections || {};
      for (const [connectionId, connection] of Object.entries(vpnConnections)) {
        this.addVpnConnection(connectionId, connection);
      }
    }

    // Allow creation of gateway endpoints on VPC instantiation as those can be
    // immediately functional without further configuration. This is not the case
    // for interface endpoints where the security group must be configured.
    if (props.gatewayEndpoints) {
      const gatewayEndpoints = props.gatewayEndpoints || {};
      for (const [endpointId, endpoint] of Object.entries(gatewayEndpoints)) {
        this.addGatewayEndpoint(endpointId, endpoint);
      }
    }

    // Add flow logs to the VPC
    if (props.flowLogs) {
      const flowLogs = props.flowLogs || {};
      for (const [flowLogId, flowLog] of Object.entries(flowLogs)) {
        this.addFlowLog(flowLogId, flowLog);
      }
    }

    const restrictFlag = FeatureFlags.of(this).isEnabled(EC2_RESTRICT_DEFAULT_SECURITY_GROUP);
    if ((restrictFlag && props.restrictDefaultSecurityGroup !== false) || props.restrictDefaultSecurityGroup) {
      this.restrictDefaultSecurityGroup();
    }
  }