Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/stale.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -37,3 +37,4 @@ jobs:
with no activity. Feel free to reopen if this is still relevant.
exempt-issue-labels: pinned,security,bug
exempt-pr-labels: pinned,security

4 changes: 4 additions & 0 deletions CHANGELOG-3.x.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
# v3.2.0
- Use partition-aware DNS suffix for S3 Files for aws-cn
- Add regex for region mount option

# v3.1.3
- Rollback DNS Query Change

Expand Down
6 changes: 5 additions & 1 deletion amazon-efs-utils.spec
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@
%{?!include_vendor_tarball:%define include_vendor_tarball true}

Name : amazon-efs-utils
Version : 3.1.3
Version : 3.2.0
Release : 1%{platform}
Summary : This package provides utilities for simplifying the use of EFS file systems

Expand Down Expand Up @@ -215,6 +215,10 @@ fi
%clean

%changelog
* Wed Jul 8 2026 Samuel Hale <samuhale@amazon.com> - 3.2.0
- Use partition-aware DNS suffix for S3 Files for aws-cn
- Add regex for region mount option

* Tue Jun 9 2026 Samuel Hale <samuhale@amazon.com> - 3.1.3
- Rollback DNS Query Change

Expand Down
2 changes: 1 addition & 1 deletion build-deb.sh
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ set -ex

BASE_DIR=$(pwd)
BUILD_ROOT=${BASE_DIR}/build/debbuild
VERSION=3.1.3
VERSION=3.2.0
RELEASE=1
ARCH=$(dpkg --print-architecture)
DEB_SYSTEM_RELEASE_PATH=/etc/os-release
Expand Down
2 changes: 1 addition & 1 deletion config.ini
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,5 @@
#

[global]
version=3.1.3
version=3.2.0
release=1
6 changes: 4 additions & 2 deletions dist/s3files-utils.conf
Original file line number Diff line number Diff line change
Expand Up @@ -54,11 +54,13 @@ retry_nfs_mount_command_count = 3
retry_nfs_mount_command_timeout_sec = 15

[mount.cn-north-1]
dns_name_suffix = amazonaws.com.cn
# S3 Files mount target DNS is under "on.amazonwebservices.com.cn"
dns_name_suffix = on.amazonwebservices.com.cn


[mount.cn-northwest-1]
dns_name_suffix = amazonaws.com.cn
# S3 Files mount target DNS is under "on.amazonwebservices.com.cn"
dns_name_suffix = on.amazonwebservices.com.cn


[mount.eu-isoe-west-1]
Expand Down
4 changes: 4 additions & 0 deletions src/efs_utils_common/aws_credentials.py
Original file line number Diff line number Diff line change
Expand Up @@ -307,9 +307,13 @@ def get_aws_security_credentials_from_pod_identity(config, is_fatal=False):


def get_sts_endpoint_url(config, region):
# The dns_name_suffix from config may be an S3 Files "on.*" domain that
# doesn't match the STS endpoint domain. Map to the correct STS domain.
dns_name_suffix = get_dns_name_suffix(config, region)
if dns_name_suffix == "on.aws":
dns_name_suffix = "amazonaws.com"
elif dns_name_suffix == "on.amazonwebservices.com.cn":
dns_name_suffix = "amazonaws.com.cn"
return STS_ENDPOINT_URL_FORMAT.format(region, dns_name_suffix)


Expand Down
2 changes: 1 addition & 1 deletion src/efs_utils_common/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
import pwd
import re

VERSION = "3.1.3"
VERSION = "3.2.0"

AMAZON_LINUX_2_RELEASE_ID = "Amazon Linux release 2 (Karoo)"
AMAZON_LINUX_2_PRETTY_NAME = "Amazon Linux 2"
Expand Down
9 changes: 8 additions & 1 deletion src/efs_utils_common/metadata.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import logging
import os
import random
import re
import socket
import sys
import time
Expand Down Expand Up @@ -123,6 +124,9 @@
}


VALID_REGION_PATTERN = re.compile(r"[a-z0-9](?:[a-z0-9-]{0,30}[a-z0-9])?")


def get_target_region(config, options):
def _fatal_error(message):
fatal_error(
Expand All @@ -133,7 +137,10 @@ def _fatal_error(message):
)

if "region" in options:
return options.get("region")
region = options.get("region")
if not VALID_REGION_PATTERN.fullmatch(region):
fatal_error('Invalid "region" mount option specified: %r' % region)
return region

# Check environment variable
env_region = os.environ.get("AWS_REGION") or os.environ.get("AWS_DEFAULT_REGION")
Expand Down
11 changes: 11 additions & 0 deletions src/efs_utils_common/network_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,9 +80,20 @@ def get_ipv6_addresses(hostname):

def dns_name_can_be_resolved(dns_name):
try:
# Try resolution as-is first
addr_info = socket.getaddrinfo(dns_name, None, socket.AF_UNSPEC)
return len(addr_info) > 0
except socket.gaierror:
# If resolution fails and hostname is not already FQDN, retry with trailing
# dot to force absolute resolution and bypass VPC search domain suffixing
# (e.g. .compute.internal) which can cause transient NXDOMAIN failures.
if not dns_name.endswith("."):
try:
fqdn = dns_name + "."
addr_info = socket.getaddrinfo(fqdn, None, socket.AF_UNSPEC)
return len(addr_info) > 0
except socket.gaierror:
return False
return False


Expand Down
30 changes: 24 additions & 6 deletions src/mount_s3files/dns_resolver.py
Original file line number Diff line number Diff line change
Expand Up @@ -142,15 +142,33 @@ def match_device(config, device, options):
return remote, path, None

try:
# Try resolution as-is first
primary, secondaries, _ = socket.gethostbyname_ex(remote)
hostnames = list(filter(lambda e: e is not None, [primary] + secondaries))
except socket.gaierror:
create_default_cloudwatchlog_agent_if_not_exist(config, options)
fatal_error(
'Failed to resolve "%s" - check that the specified DNS name is a CNAME record resolving to a valid S3Files DNS '
"name" % remote,
'Failed to resolve "%s"' % remote,
)
# If resolution fails, retry with trailing dot to bypass VPC search domain
# suffixing (e.g. .compute.internal) which causes transient NXDOMAIN for S3Files.
if not remote.endswith("."):
try:
fqdn = remote + "."
primary, secondaries, _ = socket.gethostbyname_ex(fqdn)
hostnames = list(
filter(lambda e: e is not None, [primary] + secondaries)
)
except socket.gaierror:
create_default_cloudwatchlog_agent_if_not_exist(config, options)
fatal_error(
'Failed to resolve "%s" - check that the specified DNS name is a CNAME record resolving to a valid S3Files DNS '
"name" % remote,
'Failed to resolve "%s"' % remote,
)
else:
create_default_cloudwatchlog_agent_if_not_exist(config, options)
fatal_error(
'Failed to resolve "%s" - check that the specified DNS name is a CNAME record resolving to a valid S3Files DNS '
"name" % remote,
'Failed to resolve "%s"' % remote,
)

if not hostnames:
create_default_cloudwatchlog_agent_if_not_exist(config, options)
Expand Down
Loading
Loading