AWS S3 Endpoint Access Control
Overview
From last post https://cloudjourney.medium.com/aws-s3-private-link-f3c7f4ba55a9, we explored the interface endpoint and compared the private link feature with Azure storage.
In this article, we will focus on VPC interface endpoint policy for S3, region limitation and assess Azure corresponding functionality.
We will utilize the sample policy from AWS official doc, test the policy and compare with Azure functionality.
AWS S3 VPC endpoint is not at individual S3 bucket level, it’s a resource which is tied to subnet, through this private endpoint, you may reach to AWS S3. Of course, you will have to have sufficient IAM permission, if endpoint policy, bucket policy or bucket ACL blocks the access, you won’t be able to access.
Lab Environment
We build the lab environment form last post, including
- S3 interface endpoint in us-east-1
- EC2 in us-west-1
- us-west-1 default VPC is peered to a test VPC in us-east-1
To accommodate policy test, let’s created three S3 buckets, two in us-east-1 and one in us-west-1.
Restricting access to a specific bucket from a VPC endpoint
Overview
First we will validate the access to two S3 buckets via interface endpoint, both should work.
Then we apply a policy to the endpoint to allow access to one bucket only and validate the access.
Lab
Connect to EC2 via session manager, and then list objects from S3 via interface endpoint
sh-4.2$ aws s3 --region us-east-1 --endpoint-url https://bucket.vpce-0e787478ce3b1998c-hvc8qoxf.s3.us-east-1.vpce.amazonaws.com ls s3://ronniepersonaluseast1/
2021-05-16 14:47:44 131112 test.pdf
sh-4.2$ aws s3 --region us-west-1 --endpoint-url https://bucket.vpce-0e787478ce3b1998c-hvc8qoxf.s3.us-east-1.vpce.amazonaws.com ls s3://ronniepersonaluswest1/
2021-05-16 14:49:37 164 test1.ps1
sh-4.2$
Off course, the access to the public endpoint is in place as well.
sh-4.2$ aws s3 --region us-east-1 ls s3://ronniepersonaluseast1/
2021-05-16 14:47:44 131112 test.pdf
sh-4.2$ aws s3 --region us-west-1 ls s3://ronniepersonaluswest1/
2021-05-16 14:49:37 164 test1.ps1
Now add a policy to endpoint to limit the access to ronniepersonalxyzuseast1 bucket only.
We are not able to list the object from ronniepersonaluseast1 any more via endpoint.
But why uswest1 bucket still responds when we have endpoint option in the CLI command? This does not necessarily mean the private link is working for the bucket. AWS interface endpoint does not support service from other region or in other words it’s not effective.
[ec2-user@ip-172-31-11-119 ~]$ aws s3 --region us-east-1 --endpoint-url https://bucket.vpce-0e787478ce3b1998c-hvc8qoxf.s3.us-east-1.vpce.amazonaws.com ls s3://ronniepersonaluswest1/
2021-05-16 14:49:37 164 test1.ps1
[ec2-user@ip-172-31-11-119 ~]$ aws s3 --region us-east-1 --endpoint-url https://bucket.vpce-0e787478ce3b1998c-hvc8qoxf.s3.us-east-1.vpce.amazonaws.com ls s3://ronniepersonaluseast1/An error occurred (AccessDenied) when calling the ListObjectsV2 operation: Access Denied
[ec2-user@ip-172-31-11-119 ~]$ aws s3 --region us-east-1 ls s3://ronniepersonaluseast1/
2021-05-16 14:47:44 131112 test.pdf
[ec2-user@ip-172-31-11-119 ~]$ aws s3 --region us-west-1 ls s3://ronniepersonaluswest1/
2021-05-16 14:49:37 164 test1.ps1
Compare With Azure
So what’s the equivalent from Azure side?
Azure private link is designed differently, each storage account has its own private endpoint configuration, and is assigned a distinct private IP, within private network, storage account FQDN is resolved to the private IP. When access to the storage account, network traffic doesn’t traverse the public internet.
I would say Azure does not need to configure limiting access to a specific storage account for the endpoint, because by design the endpoint is scoped to a resource.
Restricting access to buckets in a specific account from a VPC endpoint
Lab
All three test buckets reside in AWS account 91200xxxxxxx, now let’s update VPC endpoint policy to only allow access from account 26478xxxxxxx.
{ "Version": "2012-10-17",
"Id": "Policy1415115909152",
"Statement": [
{ "Sid": "Access-to-specific-VPCE-only", "Principal": "*", "Action": "s3:*", "Effect": "Deny", "Resource": ["arn:aws:s3:::DOC-EXAMPLE-BUCKET2", "arn:aws:s3:::DOC-EXAMPLE-BUCKET2/*"], "Condition": {"StringNotEquals": {"aws:sourceVpce": "vpce-1a2b3c4d"}} } ] }
We are not able to access any us-east-1 buckets via endpoint anymore.
[ec2-user@ip-172–31–11–119 ~]$ aws s3 — region us-east-1 — endpoint-url https://bucket.vpce-0e787478ce3b1998c-hvc8qoxf.s3.us-east-1.vpce.amazonaws.com ls s3://ronniepersonaluseast1/An error occurred (AccessDenied) when calling the ListObjectsV2 operation: Access Denied
[ec2-user@ip-172–31–11–119 ~]$ aws s3 — region us-east-1 — endpoint-url https://bucket.vpce-0e787478ce3b1998c-hvc8qoxf.s3.us-east-1.vpce.amazonaws.com ls s3://ronniepersonalxyzuseast1/An error occurred (AccessDenied) when calling the ListObjectsV2 operation: Access Denied
[ec2-user@ip-172–31–11–119 ~]$ aws s3 — region us-east-1 — endpoint-url https://bucket.vpce-0e787478ce3b1998c-hvc8qoxf.s3.us-east-1.vpce.amazonaws.com ls s3://ronniepersonaluswest1/
2021–05–16 14:49:37 164 test1.ps1
Compare With Azure
Once again Azure storage private endpoint is scoped a specific resource, network access control can be done through Azure network security group rules, authentication can be done via storage account access key or AAD integrated RBAC and ABAC.
Restricting access to a specific VPC endpoint in the S3 bucket policy
Lab
Before test the bucket policy, you may want to revert back endpoint policy to default allow, because we want to test the bucket policy alone to confirm the deny works, we don’t want the deny from other policy.
Then add following bucket policy to S3 ronniepersonaluseast1. This bucket policy effectively denies any access via public network.
From my home PC, when list object from bucket ronniepersonaluseast1, got access denied error. While it still works for other S3, since the policy is applied to bucket ronniepersonaluseast1 only.
From EC2, we are still able to access ronniepersonaluseast1 via interface endpoint, but failed to access without endpoint.
[ec2-user@ip-172–31–11–119 ~]$ aws s3 — region us-east-1 — endpoint-url https://bucket.vpce-0e787478ce3b1998c-hvc8qoxf.s3.us-east-1.vpce.amazonaws.com ls s3://ronniepersonaluseast1/
2021–05–16 14:47:44 131112 test.pdf
[ec2-user@ip-172–31–11–119 ~]$ aws s3 — region us-east-1 ls s3://ronniepersonaluseast1/An error occurred (AccessDenied) when calling the ListObjectsV2 operation: Access Denied
The access does not change for other bucket, e.g ronniepersonalxyzuseast1 still works with or without endpoint.
[ec2-user@ip-172–31–11–119 ~]$ aws s3 — region us-east-1 — endpoint-url https://bucket.vpce-0e787478ce3b1998c-hvc8qoxf.s3.us-east-1.vpce.amazonaws.com ls s3://ronniepersonalxyzuseast1/
2021–05–16 19:08:08 19971 Untitled 1.odg
[ec2-user@ip-172–31–11–119 ~]$ aws s3 — region us-east-1 ls s3://ronniepersonalxyzuseast1/
2021–05–16 19:08:08 19971 Untitled 1.odg
TCP Connectivity
Keep in mind, bucket policy does not stop TCP connectivity. When access to bucket object is denied, TCP connectivity is still there.
C:\Users\rquan>aws s3 --region us-east-1 ls s3://ronniepersonaluseast1/
2021-05-21 15:52:17 164 test1.ps1C:\Users\rquan>aws s3 --region us-east-1 ls s3://ronniepersonaluseast1/An error occurred (AccessDenied) when calling the ListObjectsV2 operation: Access DeniedC:\Users\rquan>curl https://ronniepersonaluseast1.s3.amazonaws.com/test1.ps1
<?xml version="1.0" encoding="UTF-8"?>
<Error><Code>AccessDenied</Code><Message>Access Denied</Message><RequestId>8G1YMEGDFFSYKYTH</RequestId><HostId>qhPjoQj0aVBz/kHgMHFtNKRLEXLeuiZ12nhuNCb2a4yYNiDqZtKwCjjLFom0LHTopFU7PCOcZpc=</HostId></Error>
C:\Users\rquan>curl -v https://ronniepersonaluseast1.s3.amazonaws.com/test1.ps1
* Trying 52.216.153.252...
* TCP_NODELAY set
* Connected to ronniepersonaluseast1.s3.amazonaws.com (52.216.153.252) port 443 (#0)
* schannel: SSL/TLS connection with ronniepersonaluseast1.s3.amazonaws.com port 443 (step 1/3)
* schannel: checking server certificate revocation
* schannel: sending initial handshake data: sending 209 bytes...
* schannel: sent initial handshake data: sent 209 bytes
* schannel: SSL/TLS connection with ronniepersonaluseast1.s3.amazonaws.com port 443 (step 2/3)
* schannel: failed to receive handshake, need more data
* schannel: SSL/TLS connection with ronniepersonaluseast1.s3.amazonaws.com port 443 (step 2/3)
* schannel: encrypted data got 3225
* schannel: encrypted data buffer: offset 3225 length 4096
* schannel: sending next handshake data: sending 126 bytes...
* schannel: SSL/TLS connection with ronniepersonaluseast1.s3.amazonaws.com port 443 (step 2/3)
* schannel: encrypted data got 51
* schannel: encrypted data buffer: offset 51 length 4096
* schannel: SSL/TLS handshake complete
* schannel: SSL/TLS connection with ronniepersonaluseast1.s3.amazonaws.com port 443 (step 3/3)
* schannel: stored credential handle in session cache
> GET /test1.ps1 HTTP/1.1
> Host: ronniepersonaluseast1.s3.amazonaws.com
> User-Agent: curl/7.55.1
> Accept: */*
>
Compare With Azure
In Azure storage account networking blade, when don’t configure VNet and don’t configure allowed IP list and don’t configure trusted Microsoft service, effectively you deny storage account access from public network.
Conclusion
AWS has IAM user policy, VPC endpoint policy and AWS service-specific policy (e.g S3 bucket policy, and S3 ACL), all must grant necessary permission for access to succeed.
While it provides extensive flexibility and multiple layer fine grain control, it also adds operational cost.
Azure authentication is typically done via AAD integration, service key is not recommended, but still being widely used. Most of the services also provide resource level networking isolation configuration, e.g private endpoint or access from selected network via service endpoint or IP restriction.
References
Interface endpoint properties and limitations:
In case you lost access to storage account and are not able to clean up the lab resources, refer to following doc