Networks not so scary with Amazon VPC Lattice

by Adam Świątkowski
15 mins read
Amazon VPC Lattice

Amazon VPC Lattice is a newly released service which should make easier connecting, securing and monitoring different services inside the AWS cloud. Will this service make life easier for both developers and network administrators/Sys Admins? Let’s check!

Amazon VPC Lattice description

Before we start

This topic was covered by me during AWS Community Day 2023 in Warsaw on 1st of June. I’d like to thank all of the organizers and great audience ♥️. People like you drives me to do more great stuff. 🚀

AWS Community Day 2023 Warsaw

What is Amazon VPC Lattice?

Amazon VPC Lattice is a service that, in principle, should facilitate the connection between services. This is another layer imposed on VPC, thanks to which aspects such as, already mentioned, connection between services, authorization and monitoring, should not be so problematic. The service should relieve developers from the need to be network magicians in terms of connecting services within the organization and to allow them to focus on the actual increase in features.

Service-to-service connectivity with Amazon VPC Lattice
Service-to-service connectivity with Amazon VPC Lattice

CDK Project with Amazon VPC Lattice

I am the type of person who believes in practice over theory. In order to check what the new service allows, I’ve prepared an architecture project described in Python and AWS CDK. You can find it here. Please read the Readme file carefully before deploying the project to your AWS account. The architecture design looks as follows:

Amazon VPC Lattice CDK project
Amazon VPC Lattice CDK project

We have here 3 services with ECS Fargate cluster, EC2 and Lambda function. Each service simply returns “Hello World” when invoked. The important part is not how applications work, but how they connect with each other. Imagine the whole system is a simple shop where EC2 is a web server, ECS has ERP things and Lambda is an order processor.

ECS (ERP) needs to have an access to the EC2 (web server) to read order details, EC2 (web server) needs to have an access to the Lambda function to process new order and ECS (ERP) to get customer details. This is a fake, sample situation, don’t judge! 🙂

Now it’s time for the task, we need to allow communication flow as described above.

Dummy developer made dummy networks

If you are observant you will notice that in the diagram someone made different VPCs with the same addressation (10.0.0.0/16)! This limits us to several approaches to connecting the services that are in these VPCs.

We can’t use VPC peering, hence it require us to have non-overlapping CIDR (eng. Classless Inter-Domain Routing) blocks. We can use Transit Gateway hence there are strategies described here which allows connecting networks with overlapping CIDRs, but it might be problematic and time consuming.

Third option is the one I’ve used, that is using Amazon VPC Lattice. I know Lattice is nos as cheap as it should be, but we can save planty of time when we’ll create network using that service. There’re more pros for Lattice which is built-in monitoring of network flows and also authorization between services.

Amazon VPC Lattice Logo

Nomenclature

Let’s now focus on understanding what constitutes the Lattice service:

  • Service network – Think of this like of our application holistically. This is a group of services that make up our application,
  • Service – is a piece of your application doing its job,
  • Target group – is a collection of units such as EC2 instances, Lambda functions, IP addresses, Application Load Balancers or Kubernetes comprising the service,
  • Auth policy – AWS IAM policy which defines access to selected services or service networks.
Unit testing Lambda functions built with AWS CDK

Amazon VPC Lattice CDK project

Knowing the above let’s jump to the CDK project (you can find it here).

Creating Service Network

We need to create the service network to group our resources (in our case EC2, Lambda and ECS cluster).

    def _build_service_network(self) -> aws_vpclattice.CfnServiceNetwork:
        return aws_vpclattice.CfnServiceNetwork(
            self,
            "LatticeNetwork",
            name="latticenetwork",
        )

As you see it’s rather simple, we only have to pass the name of the network which we want to create.

Creating Services

For each of our resources (in our case EC2 web app, Lambda function which processes new orders and ERP which reads orders and collects customers details) we need to have separate services. Let’s see how to make them:

    def _build_service_for_lambda_function(self) -> aws_vpclattice.CfnService:
        return aws_vpclattice.CfnService(self, "lambdaservice", auth_type='AWS_IAM')

Another rather simple step. We need to pass the name of our service and Auth type if we want to use Auth policy for our service. You need to create similar services for 2 other elements (EC2, ECS).

Creating Target Groups

Next we need to define Target Groups for our Services. Let’s see how to do it:

    def _build_target_group_for_ec2(self) -> aws_vpclattice.CfnTargetGroup:
        return aws_vpclattice.CfnTargetGroup(
            self, "ec2targetgroup", type="INSTANCE", name="ec2targetgroup", config=aws_vpclattice.CfnTargetGroup.TargetGroupConfigProperty(
                port=80,
                protocol="HTTP",
                vpc_identifier=self.scope.ec2_instance.ec2_vpc.vpc_id,
            ), targets=[aws_vpclattice.CfnTargetGroup.TargetProperty(id=self.scope.ec2_instance.ec2_instance.instance_id, port=80)])

    def _build_target_group_for_ecs(self) -> aws_vpclattice.CfnTargetGroup:
        return aws_vpclattice.CfnTargetGroup(
            self, "ecstargetgroup", type="ALB", name="ecstargetgroup", config=aws_vpclattice.CfnTargetGroup.TargetGroupConfigProperty(
                port=80,
                protocol="HTTP",
                vpc_identifier=self.scope.ecs_cluster.ecs_vpc.vpc_id,
            ), targets=[aws_vpclattice.CfnTargetGroup.TargetProperty(id=self.scope.ecs_cluster.alb.load_balancer_arn, port=80)])

    def _build_target_group_for_lambda(self) -> aws_vpclattice.CfnTargetGroup:
        return aws_vpclattice.CfnTargetGroup(
            self, "lambdatargetgroup", type="LAMBDA", name="lambdatargetgroup",
            targets=[aws_vpclattice.CfnTargetGroup.TargetProperty(id=self.scope.lambda_function.lambda_function.function_arn)])

This might be problematic in CDK, hence we need to pass the config property for ECS (and more specifically for the ALB which is in front of the cluster) and for EC2. For Lambda we need to only pass the ARN of the function, for other types we need to pass also port, protocol and VPC ID in which targeting service resides. Read carefully how it was achieved in above example.

Creating Listeners

For each Service we need also to add the Listener which is a Target Group which correspond to specific Service.

    def _build_listener_for_lambda(self) -> aws_vpclattice.CfnListener:
        return aws_vpclattice.CfnListener(
            self,
            "lambdalistener",
            default_action=aws_vpclattice.CfnListener.DefaultActionProperty(
                forward=aws_vpclattice.CfnListener.ForwardProperty(target_groups=[
                    aws_vpclattice.CfnListener.WeightedTargetGroupProperty(target_group_identifier=self.target_group_for_lambda.attr_arn,
                                                                           weight=100)
                ])),
            protocol="HTTP",
            port=80,
            service_identifier=self.service_for_lambda_function.attr_arn,
        )

Having above example try to create similar listeners for ECS and EC2 (protocol and port will be the same on both).

Adding Auth Policy to the Lambda Service

We want to restrict access to Lambda Service only to request originating from the VPC in which EC2 resides, in other words, we want to allow connecting to the Lambda function only from our web app (EC2). To fulfill this, we need to add Auth Policy to the Lambda service which will allow traffic only from EC2 VPC.

    def _add_auth_policy_for_lambda(self):
        # Allow calls to this Lambda only from the EC2
        aws_vpclattice.CfnAuthPolicy(
            self, "lambdaserviceauthpolicy", policy={
                "Version":
                    "2012-10-17",
                "Statement": [{
                    "Effect": "Allow",
                    "Principal": "*",
                    "Action": "vpc-lattice-svcs:Invoke",
                    "Resource": "*",
                    "Condition": {
                        "StringEquals": {
                            "vpc-lattice-svcs:SourceVpc": f'{self.scope.ec2_instance.ec2_vpc.vpc_id}'
                        }
                    }
                }]
            }, resource_identifier=self.service_for_lambda_function.attr_arn)
Assign Services with Service network

Having all of the above resources created we need to assign Services with Lattice Service Network.

    def _associate_ecs_service_with_lattice_network(self) -> None:
        aws_vpclattice.CfnServiceNetworkServiceAssociation(self, "ecsserviceenetworkassociation",
                                                           service_identifier=self.service_for_ecs_cluster.attr_arn,
                                                           service_network_identifier=self.service_network.attr_arn)

Try to achieve the same with other two Services (EC2, ECS).

Assign Service Network with VPCs

Last step needs to connect the VPCs in which Services resources reside. We need to pass VPC identifiers to the appropriate method.

    def _associate_lattice_network_with_lambda_vpc(self) -> None:
        aws_vpclattice.CfnServiceNetworkVpcAssociation(self, "lambdavpcassociation",
                                                       service_network_identifier=self.service_network.attr_arn,
                                                       vpc_identifier=self.scope.lambda_function.lambda_vpc.vpc_id)

Try to assign other two VPCs (EC2, ECS).

Checking if everything works

Amazon VPC Lattice Services
Amazon VPC Lattice Services

Let’s connect via SSH to the EC2 instance which was created after deployment of the CDK project and make simple GET requests to the Lattice Services of web app (EC2), order processor (Lambda function) and ERP (ECS).

Testing Amazon VPC Lattice Services
Testing Amazon VPC Lattice Services

Yeaah! It works 🙂

Summarize

Thank you for reaching out to that place. If you want to know more about AWS and the cloud, check the below posts:

Related Articles

This website uses cookies to improve your experience. I'll assume you're ok with this, but you can opt-out if you wish. Read Privacy Policy. Accept