AWS Managed Prefix Lists
Some time ago AWS released a new feature called Customer Managed Prefix Lists.
The concept isn't new, they already exist for services like S3 Gateway or DynamoDB Endpoints. You can use the Prefix list ID within your Security Group rules to follow the practice of least privilege when crafting rules.
To allow access to only S3 from my instance, I create a rule as follows instead of just allowing the default outbound any.
Behind the scenes, the Prefix list ID contains a list of CIDR blocks that cover all the IP address ranges for the S3 service in the target region.
With this release, we can now create our own Managed Prefix Lists with a few of caveats.
- Can't change the address family once created
- Max CIDR entries must be defined on creation and can't be modified
- When referenced in a Security Group, the value of max is consumed from the rule limit
Why should I care
In my career I've been sad enough to learn the IP addresses of BIND servers or Wiki sites but most people don't retain that sort of thing and just find it tedious. If you are wanting to provide a common way to consume known CIDR ranges they are extremely useful. They can also be tagged with appropriate values to provide more context to the person consuming them.
Creating a structure
We don't want to just blindly start creating these things or else it's going to get messy very quickly!
At my company, we are a heavy user of Cloudformation StackSets to provide base configuration across all accounts from Cloudtrail through to setting up SAML Authentication.
Using this new feature, we can provide common managed prefix lists for services that our customers can consume either manually or through automation using the SSM Parameter Store hierarchy.
In the above structure, we will have many service names for all our managed service endpoints.
Querying the following /Cloud/ServiceName/PrefixListId will provide the customer the managed prefix for that service.
The following extract shows example code for our service endpoints deployed through Cloudformation.
CloudServiceNameCIDR1:
Type: AWS::SSM::Parameter
Properties:
Name: "/Cloud/ServiceName/CIDR1"
Type: String
Value: '10.130.1.0/24'
Description: Cloud ServiceName CIDR1
AllowedPattern: ^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(\/(1[0-9]|2[0-9]|3[0-2]))$
CloudServiceNameCIDR2:
Type: AWS::SSM::Parameter
Properties:
Name: "/Cloud/ServiceName/CIDR2"
Type: String
Value: '10.130.2.0/24'
Description: Cloud ServiceName CIDR2
AllowedPattern: ^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(\/(1[0-9]|2[0-9]|3[0-2]))$
CloudServiceNameCIDR3:
Type: AWS::SSM::Parameter
Properties:
Name: "/Cloud/ServiceName/CIDR3"
Type: String
Value: '10.130.3.0/24'
Description: Cloud ServiceName CIDR3
AllowedPattern: ^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(\/(1[0-9]|2[0-9]|3[0-2]))$
CloudServiceNamePrefixList:
Type: AWS::EC2::PrefixList
Properties:
PrefixListName: !Join ["-", ["Cloud", "ServiceName"]]
AddressFamily: "IPv4"
MaxEntries: 3
Entries:
- Cidr: !GetAtt "CloudServiceNameCIDR1.Value"
Description: "Cloud ServiceName CIDR1"
- Cidr: !GetAtt "CloudServiceNameCIDR2.Value"
Description: "Cloud ServiceName CIDR2"
- Cidr: !GetAtt "CloudServiceNameCIDR3.Value"
Description: "Cloud ServiceName CIDR3"
CloudServiceNamePrefixListId:
Type: AWS::SSM::Parameter
Properties:
Name: "/Cloud/ServiceName/PrefixListId"
Type: String
Value: !GetAtt "CloudServiceNamePrefixList.PrefixListId"
Description: Cloud ServiceName
CloudServiceNamePrefixListId:
Description: Cloud ServiceName
Value: !GetAtt "CloudServiceNamePrefixList.PrefixListId"
Export:
Name: "CloudServiceNamePrefixListId"
Infrastructure as Code
With the above in place, customers can now reference this value within Cloudformation using the AWS::SSM::Parameter Type
CloudServiceNamePrefixListId:
Type: "AWS::SSM::Parameter::Value<String>"
Description: "Retrieve the Managed Prefix from SSM for use in Cloudformation template"
Default: "/Cloud/ServiceName/PrefixListId"
Or if Terraform is your preference use the aws_ssm_parameter data source
data "aws_ssm_parameter" "CloudServiceNamePrefixListId" {
name = "/Cloud/ServiceName/PrefixListId"
}
Summary
While not the most exciting release, this feature is very helpful in our environment to provide the following to our customers.
- A managed prefix that can be used within Security Groups for services available across our hybrid cloud infrastructure
- A managed prefix that can be consumed easily via automation
- A managed prefix that can be managed and updated by our operations teams via cloudformation at scale
There's always a catch....
When you hit that max limit of CIDRs per prefix list, you will have to remove and re-create if you need to add additional CIDR values. You can either add a bit of fat initially or just accept a change of the ID value. You will have to audit your Security Groups to see if they are being referenced.
Hope someone else finds this useful.
Cheers!
For more articles on AWS VPC click here!](https://sjramblings.io/tag/vpc)