Question
What/where is the definition of AWS Prefix?
Background
While looking for a way to list S3 endpoint CIDR, encountered the word AWS prefix list but not sure what it exactly means and where the terminology is defined.
Confusion
Prefix means a word placed in front. For S3, according to Listing Keys Hierarchically Using a Prefix and Delimiter, it should be the starting path to an object.
However, apparently it refers to a IP address range. How come prefix is used for IP ranges? What is the history or reason?
Terraform aws_prefix_list
This can be used both to validate a prefix list given in a variable and to obtain the CIDR blocks (IP address ranges) for the associated AWS service.
describe-prefix-lists
Describes available AWS services in a prefix list format, which includes the prefix list name and prefix list ID of the service and the IP address range for the service.
AWS IP Address Ranges
SERVICE="S3"
REGION="us-west-1"
$ curl -s https://ip-ranges.amazonaws.com/ip-ranges.json | \
jq -r --arg SERVICE "$SERVICE" --arg REGION "${REGION}" '.prefixes[] \
| select(.service==$SERVICE and .region==$REGION)'
{
"ip_prefix": "52.92.48.0/22",
"region": "us-west-1",
"service": "S3"
}
{
"ip_prefix": "54.231.232.0/21",
"region": "us-west-1",
"service": "S3"
}
{
"ip_prefix": "52.219.20.0/22",
"region": "us-west-1",
"service": "S3"
}
{
"ip_prefix": "52.219.24.0/21",
"region": "us-west-1",
"service": "S3"
}
Update
Gateway VPC Endpoints
Specify the VPC in which to create the endpoint, and the service to which you're connecting. A service is identified by a prefix list—the name and ID of a service for a Region. A prefix list ID uses the form pl-xxxxxxx and a prefix list name uses the form "com.amazonaws.region.service". Use the prefix list name (service name) to create an endpoint.
what is the meaning of Prefix ?
suppose you have a network like 10.5.10.0/24
so you will have the 10.5.10 prefix in that subnet from 1 to 255 and your network address will be 10.5.10.0
I suppose (10.0.0.0/24) means (Top 24 bit part of 32 bit IP) of a network that has
254 ip addresses from 1 to 254 (0 is network and 255 is broadcast). Prefix is top 24 bit and suffix (?) is last 8 bit. List of top N bit which identifies a network is a list of IP prefix.
If what you are looking for is prefix list id for vpc endpoint like dynamodb/s3, then it is not related to IP or CIDR. As it is mentioned in the documentation:
A prefix list ID is required for creating an outbound security group rule that allows traffic from a VPC to access an AWS service through a gateway VPC endpoint.
So if do not have prefix-list id in your security group outbout for ec2 or vpc-lambda, you will get time out when connecting to dynamodb or s3.
You can get the prefix-list by running
aws ec2 describe-prefix-lists
{
"PrefixLists": [
{
"Cidrs": [
"54.231.0.0/17",
"52.216.0.0/15"
],
"PrefixListId": "pl-63c5400k",
"PrefixListName": "com.amazonaws.us-east-1.s3"
},
{
"Cidrs": [
"52.94.0.0/22",
"52.119.224.0/20"
],
"PrefixListId": "pl-02ad2a6c",
"PrefixListName": "com.amazonaws.us-east-1.dynamodb"
}
]
}
Then you can put this PrefixListId into your security group outbound via aws web console. If you use terraform for different region, it could be something like:
resource "aws_security_group_rule" "MyService_to_DynamoDB_east" {
count = "${ lower(var.region) == "us-east-1" ? 1 : 0 }"
security_group_id = "${aws_security_group.MyService_Ext_Api.id}"
description = "DynamoDB"
type = "egress"
protocol = "tcp"
from_port = 443
to_port = 443
prefix_list_ids = ["pl-02ad2a6c"]
}
resource "aws_security_group_rule" "MyService_to_DynamoDB_west" {
count = "${ lower(var.region) == "us-west-2" ? 1 : 0 }"
security_group_id = "${aws_security_group.MyService_Ext_Api.id}"
description = "DynamoDB"
type = "egress"
protocol = "tcp"
from_port = 443
to_port = 443
prefix_list_ids = ["pl-0ca54061"]
}
The term prefix list comes from routing technology. An IP address in CIDR format has an IP prefix and a network prefix (10.1.0.0/16). The IP prefix is 10.1 and the network prefix is /16.
Therefore if you are using a list of IP addresses in CIDR format we call it an IP Prefix List.
What is Prefix List in AWS VPC context
Prefix List is the IP ranges in CIDR format which are assigned to the VPC Gateway Endpoint (S3 or DynamoDB) in a region. It is region-specific.
For example, as of 24/Feb, 2020, the prefix list for DynamoDB in the us-east-2 region is "52.94.4.0/24" where 52.94.4 is the IP prefix and the network prefix is /24 as explained by #John Hanley. The IPs the VPC Gateway endpoint for DynamoDB can take is within 52.94.4.1 - 52.94.4.254 (AWS may have reserved some IPs).
$ aws ec2 describe-prefix-lists
{
"PrefixLists": [
{
"Cidrs": [
"52.94.4.0/24"
],
"PrefixListId": "pl-4ca54025",
"PrefixListName": "com.amazonaws.us-east-2.dynamodb"
},
{
"Cidrs": [
"52.219.80.0/20",
"3.5.128.0/22",
"3.5.132.0/23",
"52.219.96.0/20",
"52.92.76.0/22"
],
"PrefixListId": "pl-7ba54012",
"PrefixListName": "com.amazonaws.us-east-2.s3"
}
]
}
Those prefix list has an ID and a name. We can specify prefix list ID in a VPC routing table and in a Security Group, but not in NACL. We need to use CIDR for NACL.
Gateway VPC Endpoints
You canNOT use a prefix list ID in an outbound rule in a network ACL to allow or deny outbound traffic to the service specified in an endpoint. If your network ACL rules restrict traffic, you must specify the CIDR block (IP address range) for the service instead. You can, however, use a prefix list ID in an outbound security group rule. For more information, see Security Groups.
Terraform examples
NACL
Data Source: aws_prefix_list
resource "aws_vpc_endpoint" "private_s3" {
vpc_id = "${aws_vpc.foo.id}"
service_name = "com.amazonaws.us-west-2.s3"
}
data "aws_prefix_list" "private_s3" {
prefix_list_id = "${aws_vpc_endpoint.private_s3.prefix_list_id}"
}
resource "aws_network_acl" "bar" {
vpc_id = "${aws_vpc.foo.id}"
}
resource "aws_network_acl_rule" "private_s3" {
network_acl_id = "${aws_network_acl.bar.id}"
rule_number = 200
egress = false
protocol = "tcp"
rule_action = "allow"
cidr_block = "${data.aws_prefix_list.private_s3.cidr_blocks[0]}"
from_port = 443
to_port = 443
}
Security Group as provided by #LeOn - Han Li in his answer.
resource "aws_security_group_rule" "MyService_to_DynamoDB_east" {
count = "${ lower(var.region) == "us-east-1" ? 1 : 0 }"
security_group_id = "${aws_security_group.MyService_Ext_Api.id}"
description = "DynamoDB"
type = "egress"
protocol = "tcp"
from_port = 443
to_port = 443
prefix_list_ids = ["pl-02ad2a6c"]
}
resource "aws_security_group_rule" "MyService_to_DynamoDB_west" {
count = "${ lower(var.region) == "us-west-2" ? 1 : 0 }"
security_group_id = "${aws_security_group.MyService_Ext_Api.id}"
description = "DynamoDB"
type = "egress"
protocol = "tcp"
from_port = 443
to_port = 443
prefix_list_ids = ["pl-0ca54061"]
}
Access Control
Why can’t I connect to an S3 bucket using a gateway VPC endpoint? layouts comprehensive list regarding S3 VPC Gateway Endpoint and the prefix list ID and CIDR would play parts there.
DNS settings in your VPC
Important: DNS resolution must be enabled in your VPC (see Gateway Endpoint Limitations). If you're using your own DNS server, be sure DNS requests to AWS services resolve to AWS-maintained IP addresses.
Route table settings to Amazon S3
Security group outbound rules
Network ACL rules
Gateway VPC endpoint policy
S3 bucket policy
IAM policy
References
Gateway VPC Endpoints
Specify the VPC in which to create the endpoint, and the service to which you're connecting. A service is identified by a prefix list—the name and ID of a service for a Region. A prefix list ID uses the form pl-xxxxxxx and a prefix list name uses the form "com.amazonaws.region.service". Use the prefix list name (service name) to create an endpoint.
Well even though question is answered regarding Prefix definition pertaining to VPC, I did not see answer to prefix definition related to S3 (beside CIDR related). Simply put in S3 if you have a folder Photos and it has yourpic.jpg file in it then it should look like this photos/yourpic.jpg. The part which is folder photos/ is called prefix in S3 Terminology. As mentioned in latest AWS Performance tuning guide for S3 we can use prefix to do parallelism and increase performance. Anyway I am still learning AWS so take it with a grain of salt. Check below link for reference.
https://docs.aws.amazon.com/AmazonS3/latest/user-guide/using-folders.html
An AWS-managed prefix list is a way to add a single rule in an AWS Security Group that represents all the IP ranges for that service instead of having to enter every single range in the AWS IP ranges here:
https://ip-ranges.amazonaws.com/ip-ranges.json
For example, if you want to provide outbound access to S3 you would have to enter every IP range in that JSON IP ranges list to access S3 (or the ones in the region you're in if you are restricting access to a single region.)
With a prefix list, you create a rule in the security group and assign the prefix list instead as the destination.
You can also create your own customer-managed prefix list for your own list of IP ranges. I just wrote a blog post on how to do that on my medium Cloud-Security blog.
Related
When I'm creating a Network ACL for AWS in Terraform I'm not able to configure the field "Type"
However if you configure the ACL via Portal the field type can be configured accordingly.
aws nacl ui
The Type field on the web console is just an easy way to select pre-configured combinations of protocols and ports. This field is not there in terraform templates, and you can simply specify the protocol and port separately as shown in #marcincuber's answer. It's the same in AWS CloudFormation as well.
The type field is "automatically defined" based on the information you use for the port/protocol.
For example, try to create a rule for port 25/tcp.
After you apply and the rule is created, the type will automatically be set to "SMTP(25)".
You are looking for the following terraform resources that support protocol argument:
resource "aws_network_acl" "bar" {
vpc_id = aws_vpc.foo.id
}
resource "aws_network_acl_rule" "bar" {
network_acl_id = aws_network_acl.bar.id
rule_number = 200
egress = false
protocol = "tcp"
rule_action = "allow"
cidr_block = aws_vpc.foo.cidr_block
from_port = 22
to_port = 22
}
The example was takes from https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/network_acl_rule
I got a microservice in an ECS instance in AWS behind a WAF, I want to create these rules:
Allow specific IPs (done)
Allow all connections from inside the VPN (done)
Deny all the other requests.
The first two IP set are created, but I can't make the last one to work. I tried creating the IP set with 0.0.0.0/0 and another combinations without success.
This is my code, I removed ipset 1 and 2 (that are working), this is the ipset 3:
resource "aws_wafv2_ip_set" "ipset" {
name = "${var.app_name}-${var.environment_name}-whitelist-ips"
scope = "REGIONAL"
ip_address_version = "IPV4"
addresses = ["0.0.0.0/0"]
}
module "alb_wafv2" {
source = "trussworks/wafv2/aws"
version = "~> 2.0"
name = "${var.app_name}-${var.environment_name}"
scope = "REGIONAL"
alb_arn = aws_lb.app_lb.arn
associate_alb = true
ip_sets_rule = [
{
name = "${var.app_name}-${var.environment_name}-ip-blacklist"
action = "deny"
priority = 1
ip_set_arn = aws_wafv2_ip_set.ipset.arn
}
]
}
{
RespMetadata: {
StatusCode: 400,
RequestID: "c98b2d3a-ebd0-44e0-a80a-702bc698598b"
},
Field: "IP_ADDRESS",
Message_: "Error reason: The parameter contains formatting that is not valid., field: IP_ADDRESS, parameter: 0.0.0.0/0",
Parameter: "0.0.0.0/0",
Reason: "The parameter contains formatting that is not valid."
}
Tried to create an IP Set from the AWS Console with the same error:
So I got two questions, first, how can I do this? And the second one, is this the best approach?
Thanks in advance
You don't need to block 0.0.0.0/0. After you created two IP rules, look "Default web ACL action for requests that don't match any rules" on WAF console and set Action to Block.
Consider using this trick to bypass the 0.0.0.0/0 limitation:
Divide the IPv4 address space into two chunks: 0.0.0.0/1 and 128.0.0.0/1
The following terraform snippet was accepted and the ip set was created by TF (Terraform 0.15.4 and aws provider version 3.42.0):
resource "aws_wafv2_ip_set" "ipset" {
name = "all_internet_kludge"
scope = "REGIONAL"
ip_address_version = "IPV4"
addresses = ["0.0.0.0/1", "128.0.0.0/1"]
}
You can't block all addresses (CIDR /0). It is not supported. From docs:
AWS WAF supports all IPv4 and IPv6 CIDR ranges except for /0.
Instead, you can use network ACL to deny all traffic, or security groups.
I am trying to setup AWS SFTP transfer in vpc endpoint mode but there is one think I can't manage with.
The problem I have is how to get target IPs for NLB target group.
The only output I found:
output "vpc_endpoint_transferserver_network_interface_ids" {
description = "One or more network interfaces for the VPC Endpoint for transferserver"
value = flatten(aws_vpc_endpoint.transfer_server.*.network_interface_ids)
}
gives network interface ids which cannot be used as targets:
Outputs:
api_url = https://12345.execute-api.eu-west-1.amazonaws.com/prod
vpc_endpoint_transferserver_network_interface_ids = [
"eni-12345",
"eni-67890",
"eni-abcde",
]
I went through:
terraform get subnet integration ips from vpc endpoint subnets tab
and
Terraform how to get IP address of aws_lb
but none of them seems to be working. The latter says:
on modules/sftp/main.tf line 134, in data "aws_network_interface" "ifs":
134: count = "${length(local.nlb_interface_ids)}"
The "count" value depends on resource attributes that cannot be determined
until apply, so Terraform cannot predict how many instances will be created.
To work around this, use the -target argument to first apply only the
resources that the count depends on.
You can create an Elastic IP
resource "aws_eip" "lb" {
instance = "${aws_instance.web.id}"
vpc = true
}
Then specify the Elastic IPs while creating Network LB
resource "aws_lb" "example" {
name = "example"
load_balancer_type = "network"
subnet_mapping {
subnet_id = "${aws_subnet.example1.id}"
allocation_id = "${aws_eip.example1.id}"
}
subnet_mapping {
subnet_id = "${aws_subnet.example2.id}"
allocation_id = "${aws_eip.example2.id}"
}
}
How can I create a target group for a network load balancer containing a VPC endpoint in Terraform?
In AWS console, I would have done following steps:
Create VPC Endpoint in two subnets to an endpoint service in another VPC
Create a target group of type IP and register the IP adresses of
the enpoints created in step 1
In terraform, I can create target groups and endpoints, but I don't know how to assign the enpoint's IPs to the target group. Where can I find instructions or an example how to do this? (Creating target groups for type instance is no problem, my question is specific for type IP).
Late to the party! But this is what I did.
Created a null resource that would get the IP addresses of the VPC endpoints and store it in a file
resource "null_resource" "nlb" {
triggers = {
always_run = "${timestamp()}"
}
provisioner "local-exec" {
command = "dig +short ${lookup(tomap(element(aws_vpc_endpoint.api-gw.dns_entry, 0)), "dns_name", "")} > /tmp/entry"
}
}
and then read the file entries
resource aws_lb_target_group_attachment nlb {
depends_on = [
null_resource.nlb
]
for_each = toset(slice(split("\n", file("/tmp/entry")), 0, 2))
target_group_arn = resource.aws_lb_target_group.nlb.arn
target_id = each.value
port = 443
}
I need to set up a VPC Endpoint for S3 via Terraform.
To do so, I need to add rules to my acl for all of the CIDR blocks used by S3 in the appropriate region.
I can get the CIDR blocks using the aws_prefix_list data source.
The problem is then adding the rules.
Rules need to be added one at a time via the aws_network_acl_rule resource.
However, without knowing in advance how many CIDR blocks will be returned, there is no way to enumerate through them (Terraform does not let us simply count the results).
I don't want to have to hardcode the number of results to expect (which differs between region and over time).
The following fails with the error * aws_network_acl_rule.private_s3: aws_network_acl_rule.private_s3: value of 'count' cannot be computed because it does not know at plan time how many results will be returned.
resource "aws_vpc_endpoint" "private_s3" {
vpc_id = "{var.vpc_id}"
service_name = "com.amazonaws.us-west-2.s3"
}
data "aws_prefix_list" "private_s3" {
prefix_list_id = "${aws_vpc_endpoint.private_s3.prefix_list_id}"
}
resource "aws_network_acl" "bar" {
vpc_id = "{var.vpc_id}"
}
resource "aws_network_acl_rule" "private_s3" {
count = "${length(data.aws_prefix_list.private_s3.cidr_blocks)}"
network_acl_id = "${aws_network_acl.bar.id}"
rule_number = 200
egress = false
protocol = "tcp"
rule_action = "allow"
cidr_block = "${data.aws_prefix_list.private_s3.cidr_blocks[count.index]}"
from_port = 443
to_port = 443
}
Any thoughts?