How to determine ipv6 CIDR block prefix in AWS Clo

2019-06-04 13:19发布

问题:

AWS generates the ipv6 CIDR block for VPCs so its not possible to determine ahead of time. The generated CIDR block looks something like: 2a05:d018:84c:c500::/56 and is always size 56.

When creating a subnet you have to specify a size 64 block using the full prefixed value. E.g. 2a05:d018:84c:c501::/64.

It's possible to look up the ipv6 CIDR blocks for a VPC in cloudformation, but this returns the full value, not just the prefix. To create a subnet we need to be able to append something 01::/64 to the prefix to create the 64 sized block for the subnet.

I've seen solutions that use a lambda function, but this greatly complicated the templates. I'd like to do this using just the built-in intrinsic functions available in the templates.

When deploying a VPC with ipv6 subnets in the same stack, how can you generate valid ipv6 CIDR blocks for the subnets?

回答1:

Here is a one liner that does the same thing using the Fn::Cidr intrinsic function.

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

For a given block 2a05:d018:84c:c500::/56 this will give you 2a05:d018:84c:c501::/64

Increment the first index to get the next block.

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

will give you 2a05:d018:84c:c502::/64

Also here is a full minimal example including the crucial steps of using an AWS::EC2::VPCCidrBlock resource to attach the IPv6 block to the VPC and using the DependsOn property to make sure that the VPCCidrBlock is attached before the Subnet is created.

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]]


回答2:

Here's a way to calculate the first subnet in YAML:

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


回答3:

You can determine the prefix by using a combination of Fn::Split (on 00::/56) and Fn::Select to get the prefix. Then you can append your own value to create the subnet CIDR blocks using Fn::Join. The following example assumes you have a VPC with one or more Ipv6 CIDR blocks associated with it.

Use this value for the Ipv6CidrBlock property on the subnet.

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