There are a number of solutions to this problem:
- There are some services (such as cloudwatch, which we are successfully using; also neptune and dynamodb) which "just work";
- There are some services (such as SSM, the secrets manager) which have custom endpoints you can identify in your lambda code;
- It is possible to define a NAT gateway;
- It is possible to use AWS PrivateLink;
- It is possible to use IPv6 and an egress-only gateway.
It took AWS forever to implement IPv6. I forget why I first wanted to use IPv6 on AWS, but it was back in 2012 or 2013. I was amazed that it wasn't an option. I was even more amazed that it wasn't on their roadmap. If I read the histories correctly, it was only introduced in 2023.
I don't fully understand these things, but the reason you need a NAT gateway from a VPC is because you are using "local" IPv4 addresses. There are no "local" IPv6 addresses - they are all unique. As such, it is not necessary to translate them to global addresses, and hence no NAT gateway is needed. Instead, there is a component called an "egress-only" gateway which supports IPv6 only and has the significant advantage that it is completely free.
All of my VPC setup is off-camera, so I can just tell you that I created an egress only internet gateway and then enabled IPv6 on all the subnets in my VPC.
That's a good start, but it's not enough. In order for any of this to work, both the lambda and the API gateway also need to support IPv6. Each of them has an option to enable "dual stack" processing - that is, both IPv4 and IPv6. For the lambda, it is part of the VpcConfig setting:
VpcConfig <= aws.VPC.Config
DualStack <- true
Subnets <- vpc->subnets
SecurityGroups <- vpc->securityGroups
NEPTUNE_WATCH_LAMBDA:neptune/dply/infrastructure.dply
And for the API Gateway, we need to specify the IpAddressType at the top level:api.gatewayV2 "stock-watch"
@teardown delete
Protocol <- "websocket"
IpAddressType <- "dualstack"
RouteSelectionExpression <- "$request.body.action"
NEPTUNE_WATCH_LAMBDA:neptune/dply/infrastructure.dply
It may not be obvious why we need this in the API Gateway, but the IpAddressType property is really there to enable the gateway to provide its web services to IPv6 clients. We are not really doing that, but the mechanism is the same: you make an HTTP request to the gateway from within the lambda. Since that request is travelling "over" IPv6, we need the gateway to be listening to IPv6 traffic.I'm going to admit that much of this still confuses me. I think I understand IPv6 addressing reasonably enough, but I have always been confused by "multi-homed" machines with multiple network cards. How does it know which to choose? Particularly when there are so many (at least 6 - two protocols for each of three subnets). But it does, somehow, and it works. And doesn't require me to pay for a NAT gateway.
No comments:
Post a Comment