在 VPC 上创建子网时如何确定 AWS Cloudformation 中的 ipv6 CIDR 块前缀

How to determine ipv6 CIDR block prefix in AWS Cloudformation when creating subnets on a VPC

AWS 为 VPC 生成 ipv6 CIDR 块,因此无法提前确定。生成的 CIDR 块类似于:2a05:d018:84c:c500::/56 并且大小始终为 56。

创建子网时,您必须使用完整前缀值指定大小为 64 的块。例如。 2a05:d018:84c:c501::/64.

可以在 cloudformation 中查找 VPC 的 ipv6 CIDR 块,但这 returns 是完整值,而不仅仅是前缀。要创建一个子网,我们需要能够在前缀上附加一些东西 01::/64 来为子网创建 64 大小的块。

我见过使用 lambda 函数的解决方案,但这使模板变得非常复杂。我想仅使用模板中可用的内置内部函数来执行此操作。

在同一堆栈中部署具有 ipv6 子网的 VPC 时,如何为子网生成有效的 ipv6 CIDR 块?

您可以通过组合使用 Fn::Split(在 00::/56 上)和 Fn::Select 来获取前缀来确定前缀。然后您可以附加您自己的值以使用 Fn::Join 创建子网 CIDR 块。以下示例假设您有一个 VPC,其中关联了一个或多个 Ipv6 CIDR 块。

将此值用于子网上的 Ipv6CidrBlock 属性。

{
    "Fn::Join": [
        "",
        [
            {
                "Fn::Select": [
                    0,
                    {
                        "Fn::Split": [
                            "00::/56",
                            {
                                "Fn::Select": [
                                    0,
                                    {
                                        "Fn::GetAtt": [
                                            "Vpc",
                                            "Ipv6CidrBlocks"
                                        ]
                                    }
                                ]
                            }
                        ]
                    }
                ]
            },
            "01::/64"
        ]
    ]
}

这是一种在 YAML 中计算第一个子网的方法:

Fn::Sub:
    - "${VpcPart}${SubnetPart}"
    - SubnetPart: 01::/64
      VpcPart: !Select [0, !Split ['00::/56', !Select [0,!GetAtt YourVpc.Ipv6CidrBlocks]]]

这是一个使用 Fn::Cidr intrinsic function.

做同样事情的单行本
!Select [1, !Cidr [!Select [0, !GetAtt 'Vpc.Ipv6CidrBlocks'], 256, 64]]

对于给定的块 2a05:d018:84c:c500::/56 这会给你 2a05:d018:84c:c501::/64

增加第一个索引以获得下一个块。

!Select [2, !Cidr [!Select [0, !GetAtt 'Vpc.Ipv6CidrBlocks'], 256, 64]]

会给你2a05:d018:84c:c502::/64

这里还有一个完整的最小示例,包括使用 AWS::EC2::VPCCidrBlock 资源将 IPv6 块附加到 VPC 并使用 DependsOn 属性 确保在创建子网之前附加 VPCCIdrBlock。

Resources:
  Vpc:
    Type: AWS::EC2::VPC
    Properties:
      CidrBlock: !Sub '10.255.0.0/16'

  VpcCidrBlockIpv6:
    Type: 'AWS::EC2::VPCCidrBlock'
    Properties:
      VpcId: !Ref 'Vpc'
      AmazonProvidedIpv6CidrBlock: true

  PrivateSubnet:
    Type: AWS::EC2::Subnet
    DependsOn: VpcCidrBlockIpv6 # Wait for IPv6 CIDR to be attached to VPC before creating subnet
    Properties:
      AvailabilityZone: !Select [ 0, !GetAZs '' ]
      VpcId: !Ref 'Vpc'
      AssignIpv6AddressOnCreation: true
      CidrBlock: !Sub '10.255.0.0/20'
      Ipv6CidrBlock: !Select [1, !Cidr [!Select [0, !GetAtt 'Vpc.Ipv6CidrBlocks'], 256, 64]]

AWS VPC 服务允许我们创建 VPC 并关联亚马逊提供的 /56 IPv6 CIDR 块 [我们无法提供自己的 CIDR]。 每个子网都可以有一个 /64 的 IP 块。这意味着理论上可以有 2^(64-56) 个子网,即 2^8 = 256 个子网。

为了计算 IPv6 CIDR 块的子网,Cloudformation 提供了一个内部函数 !Cidr 供我们执行此操作。

CIDR 块的语法如下:

!Cidr [ ipBlock, count, cidrBits ]

哪里

count --> 要生成的 CIDR 的数量。有效范围在 1 到 256 之间。

cidrBits --> CIDR 的子网位数。例如,为此参数指定值“8”将创建一个掩码为“/24”的 CIDR。

所以我们的语句变成:

!Select [0, !Cidr [!Select [0, !GetAtt 'Vpc.Ipv6CidrBlocks'], 256, 64]]

因此,创建 VPC 的示例模板具有 2 个附加了 IPv6 的子网,如下所示:

AWSTemplateFormatVersion: "2010-09-09"
    Resources:
        Vpc:
            Type: AWS::EC2::VPC
            Properties:
                CidrBlock: !Sub '10.255.0.0/16'

        VpcCidrBlockIpv6:
            Type: 'AWS::EC2::VPCCidrBlock'
            Properties:
                VpcId: !Ref 'Vpc'
                AmazonProvidedIpv6CidrBlock: true

        Subnet1:
            Type: AWS::EC2::Subnet
            Properties:
                AvailabilityZone: !Select [ 0, !GetAZs '' ]
                VpcId: !Ref 'Vpc'
                AssignIpv6AddressOnCreation: true
                CidrBlock: !Sub '${PrivateSubnetCIDR1}'
                Ipv6CidrBlock: !Select [0, !Cidr [!Select [0, !GetAtt 'Vpc.Ipv6CidrBlocks'], 256, 64]]

        Subnet2:
            Type: AWS::EC2::Subnet
            Properties:
                VpcId: !Ref 'Vpc'
                AssignIpv6AddressOnCreation: true
                CidrBlock: !Sub '${PrivateSubnetCIDR2}'
                Ipv6CidrBlock: !Select [1, !Cidr [!Select [0, !GetAtt 'Vpc.Ipv6CidrBlocks'], 256, 64]]