EFS File System Not Publicly Accessible
Overview
This check verifies that your Amazon Elastic File System (EFS) file systems have properly restrictive policies that prevent excessive access. It flags file systems with policies that allow any client within the VPC to mount without proper conditions, or file systems with no policy at all (which AWS treats as open to VPC clients by default).
Risk
Without a restrictive file system policy, your EFS data may be accessible to any workload in your VPC:
- Data exfiltration: Any compromised workload or malicious insider in your VPC can mount the file system and copy sensitive data
- Unauthorized modifications: Attackers can alter or encrypt your data (ransomware attacks)
- Data deletion: Overly permissive policies may allow complete data destruction
- Lateral movement: Attackers who compromise one system can use open EFS shares to pivot to other workloads
- Compliance violations: Many security frameworks require least-privilege access controls on storage
Remediation Steps
Prerequisites
You need:
- AWS Console access with permissions to manage EFS file systems
- Knowledge of which applications and IAM roles should access each file system
Required IAM permissions (for administrators)
Your IAM user or role needs these permissions:
elasticfilesystem:DescribeFileSystemselasticfilesystem:DescribeFileSystemPolicyelasticfilesystem:PutFileSystemPolicyelasticfilesystem:DeleteFileSystemPolicy
AWS Console Method
-
Open the EFS Console
- Go to EFS Console in us-east-1
-
Select your file system
- Click on the file system ID that failed the check
-
View the current policy
- Click the File system policy tab
- Review the current policy (if empty, your file system is open to all VPC clients)
-
Edit the file system policy
- Click Edit
- You have two options:
- Use the Policy editor for a guided experience
- Use JSON for direct policy editing
-
Apply a restrictive policy
- At minimum, require mount target access by adding this condition:
- Check Prevent anonymous access (adds
aws:PrincipalArnrequirement) - Check Enforce read-only access by default if appropriate
- Check Prevent anonymous access (adds
- For stricter security, also restrict by:
- Specific IAM roles or users
- Source VPC or VPC endpoint
- At minimum, require mount target access by adding this condition:
-
Save the policy
- Click Save
-
Enable Block Public Access (recommended)
- Go back to the EFS Console main page
- Click Block public access settings in the left sidebar
- Click Edit
- Check Block public access to file systems
- Click Save
AWS CLI (optional)
View current file system policy
aws efs describe-file-system-policy \
--file-system-id fs-1234567890abcdef0 \
--region us-east-1
If no policy exists, you'll receive an error indicating the policy doesn't exist.
Apply a restrictive policy
Create a policy that requires mount target access:
aws efs put-file-system-policy \
--file-system-id fs-1234567890abcdef0 \
--policy '{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "RequireMountTargetAccess",
"Effect": "Allow",
"Principal": {
"AWS": "*"
},
"Action": [
"elasticfilesystem:ClientMount",
"elasticfilesystem:ClientWrite"
],
"Condition": {
"Bool": {
"elasticfilesystem:AccessedViaMountTarget": "true"
}
}
}
]
}' \
--region us-east-1
Apply a more restrictive policy (specific IAM roles)
For production workloads, restrict to specific IAM roles:
aws efs put-file-system-policy \
--file-system-id fs-1234567890abcdef0 \
--policy '{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowSpecificRoles",
"Effect": "Allow",
"Principal": {
"AWS": [
"arn:aws:iam::111122223333:role/MyApplicationRole",
"arn:aws:iam::111122223333:role/MyBackupRole"
]
},
"Action": [
"elasticfilesystem:ClientMount",
"elasticfilesystem:ClientWrite"
],
"Condition": {
"Bool": {
"elasticfilesystem:AccessedViaMountTarget": "true"
}
}
}
]
}' \
--region us-east-1
Replace:
fs-1234567890abcdef0with your file system ID111122223333with your AWS account ID- Role ARNs with your actual application roles
List all file systems to review
aws efs describe-file-systems \
--region us-east-1 \
--query 'FileSystems[*].[FileSystemId,Name]' \
--output table
CloudFormation (optional)
AWSTemplateFormatVersion: '2010-09-09'
Description: EFS file system with restrictive policy
Parameters:
FileSystemName:
Type: String
Default: my-secure-efs
Description: Name tag for the EFS file system
AllowedRoleArn:
Type: String
Description: ARN of the IAM role allowed to access this file system
Default: ''
Conditions:
HasSpecificRole: !Not [!Equals [!Ref AllowedRoleArn, '']]
Resources:
SecureFileSystem:
Type: AWS::EFS::FileSystem
Properties:
Encrypted: true
PerformanceMode: generalPurpose
ThroughputMode: bursting
FileSystemTags:
- Key: Name
Value: !Ref FileSystemName
FileSystemPolicy:
Type: AWS::EFS::FileSystemPolicy
Properties:
FileSystemId: !Ref SecureFileSystem
FileSystemPolicy:
Version: '2012-10-17'
Statement:
- Sid: RequireMountTargetAndTLS
Effect: Allow
Principal:
AWS: !If
- HasSpecificRole
- !Ref AllowedRoleArn
- '*'
Action:
- elasticfilesystem:ClientMount
- elasticfilesystem:ClientWrite
Condition:
Bool:
elasticfilesystem:AccessedViaMountTarget: 'true'
aws:SecureTransport: 'true'
- Sid: DenyNonSecureTransport
Effect: Deny
Principal:
AWS: '*'
Action: '*'
Condition:
Bool:
aws:SecureTransport: 'false'
Outputs:
FileSystemId:
Description: The EFS file system ID
Value: !Ref SecureFileSystem
FileSystemArn:
Description: The EFS file system ARN
Value: !GetAtt SecureFileSystem.Arn
Deploy with:
aws cloudformation deploy \
--template-file efs-secure.yaml \
--stack-name secure-efs-stack \
--parameter-overrides \
FileSystemName=my-secure-efs \
AllowedRoleArn=arn:aws:iam::111122223333:role/MyApplicationRole \
--region us-east-1
Terraform (optional)
# EFS file system with restrictive policy
resource "aws_efs_file_system" "secure" {
encrypted = true
performance_mode = "generalPurpose"
throughput_mode = "bursting"
tags = {
Name = var.file_system_name
}
}
# Restrictive file system policy
resource "aws_efs_file_system_policy" "secure" {
file_system_id = aws_efs_file_system.secure.id
policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Sid = "RequireMountTargetAndTLS"
Effect = "Allow"
Principal = {
AWS = var.allowed_role_arns
}
Action = [
"elasticfilesystem:ClientMount",
"elasticfilesystem:ClientWrite"
]
Condition = {
Bool = {
"elasticfilesystem:AccessedViaMountTarget" = "true"
"aws:SecureTransport" = "true"
}
}
},
{
Sid = "DenyNonSecureTransport"
Effect = "Deny"
Principal = { AWS = "*" }
Action = "*"
Condition = {
Bool = {
"aws:SecureTransport" = "false"
}
}
}
]
})
}
# Mount target in a subnet
resource "aws_efs_mount_target" "main" {
for_each = toset(var.subnet_ids)
file_system_id = aws_efs_file_system.secure.id
subnet_id = each.value
security_groups = [aws_security_group.efs.id]
}
# Security group for EFS
resource "aws_security_group" "efs" {
name = "${var.file_system_name}-efs-sg"
description = "Security group for EFS mount targets"
vpc_id = var.vpc_id
ingress {
description = "NFS from allowed security groups"
from_port = 2049
to_port = 2049
protocol = "tcp"
security_groups = var.allowed_security_group_ids
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
tags = {
Name = "${var.file_system_name}-efs-sg"
}
}
# Variables
variable "file_system_name" {
description = "Name for the EFS file system"
type = string
default = "secure-efs"
}
variable "vpc_id" {
description = "VPC ID for the EFS mount targets"
type = string
}
variable "subnet_ids" {
description = "Subnet IDs for EFS mount targets"
type = list(string)
}
variable "allowed_role_arns" {
description = "IAM role ARNs allowed to access the file system"
type = list(string)
default = ["*"]
}
variable "allowed_security_group_ids" {
description = "Security group IDs allowed to connect to EFS"
type = list(string)
}
# Outputs
output "file_system_id" {
description = "The EFS file system ID"
value = aws_efs_file_system.secure.id
}
output "file_system_arn" {
description = "The EFS file system ARN"
value = aws_efs_file_system.secure.arn
}
Deploy with:
terraform init
terraform plan -var="vpc_id=vpc-12345" -var='subnet_ids=["subnet-abc","subnet-def"]' -var='allowed_security_group_ids=["sg-12345"]'
terraform apply
Verification
After applying a restrictive policy, verify the configuration:
-
In the AWS Console:
- Go to EFS > File systems
- Click on your file system
- Click the File system policy tab
- Verify the policy includes the
elasticfilesystem:AccessedViaMountTargetcondition - Check that Block public access is enabled (EFS Console > Block public access settings)
-
Test access:
- Verify your applications can still mount the file system
- Confirm that unauthorized workloads cannot mount it
CLI verification commands
Check the file system policy:
aws efs describe-file-system-policy \
--file-system-id fs-1234567890abcdef0 \
--region us-east-1
The output should show a policy with restrictive conditions.
Check all file systems for missing or permissive policies:
for fs in $(aws efs describe-file-systems --region us-east-1 --query 'FileSystems[*].FileSystemId' --output text); do
echo "=== File System: $fs ==="
aws efs describe-file-system-policy --file-system-id "$fs" --region us-east-1 2>&1 || echo "No policy (open to VPC)"
done
Additional Resources
- AWS Documentation: EFS File System Policies
- AWS Documentation: EFS Block Public Access
- AWS Documentation: EFS Access Points
- AWS Blog: Securing Amazon EFS
Notes
- Default behavior: An EFS file system with no policy allows any client in the VPC to mount it. This is why the check flags file systems without policies or with overly permissive policies.
- AccessedViaMountTarget condition: This condition ensures that access only comes through an EFS mount target in your VPC, preventing direct API access that bypasses network controls.
- Existing applications: Before applying restrictive policies, inventory all applications that access the file system. Restricting to specific IAM roles may break applications that haven't been configured with the proper IAM roles.
- EFS Access Points: For fine-grained access control, consider using EFS access points. Each access point can enforce a specific POSIX user/group and restrict clients to a specific directory.
- Encryption in transit: The policy examples above also enforce TLS (encryption in transit) via the
aws:SecureTransportcondition. This is a security best practice. - Block Public Access: Enable EFS Block Public Access at the account level to prevent any EFS file system from being made public, even if someone applies an overly permissive policy.
- No service disruption: Applying a file system policy does not disconnect existing mounts, but new mount attempts will be evaluated against the policy.