This is an automated email from the ASF dual-hosted git repository.
vincbeck pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/airflow.git
The following commit(s) were added to refs/heads/main by this push:
new ddf1ebc0fe7 fix: EksPodOperator 401 with cross-account AssumeRole via
aws_conn_id (#65335)
ddf1ebc0fe7 is described below
commit ddf1ebc0fe7e509e323b46d938600b31c82e679c
Author: Anmol Mishra <[email protected]>
AuthorDate: Fri May 22 00:29:01 2026 +0530
fix: EksPodOperator 401 with cross-account AssumeRole via aws_conn_id
(#65335)
---
.../src/airflow/providers/amazon/aws/hooks/eks.py | 24 +++++++++++++--
.../amazon/tests/unit/amazon/aws/hooks/test_eks.py | 35 ++++++++++++++++++++++
2 files changed, 57 insertions(+), 2 deletions(-)
diff --git a/providers/amazon/src/airflow/providers/amazon/aws/hooks/eks.py
b/providers/amazon/src/airflow/providers/amazon/aws/hooks/eks.py
index fd0dd09876c..032d7e16833 100644
--- a/providers/amazon/src/airflow/providers/amazon/aws/hooks/eks.py
+++ b/providers/amazon/src/airflow/providers/amazon/aws/hooks/eks.py
@@ -82,8 +82,14 @@ COMMAND = """
# Load credentials from secure file using (POSIX-compliant dot
operator)
. {credentials_file}
+ # Redirect stderr to a temporary file to prevent Python warnings,
+ # deprecation notices, or other log output from contaminating
stdout.
+ # The token output must be the ONLY thing on stdout for bash token
+ # parsing to work, but stderr should still be reported on failure.
+ stderr_file=$(mktemp)
+ trap 'rm -f "$stderr_file"' EXIT
output=$({python_executable} -m
airflow.providers.amazon.aws.utils.eks_get_token \
- --cluster-name {eks_cluster_name} --sts-url '{sts_url}' {args}
2>&1)
+ --cluster-name {eks_cluster_name} --sts-url '{sts_url}' {args}
2>"$stderr_file")
status=$?
@@ -91,11 +97,16 @@ COMMAND = """
unset AWS_ACCESS_KEY_ID AWS_SECRET_ACCESS_KEY AWS_SESSION_TOKEN
if [ "$status" -ne 0 ]; then
- printf '%s' "$output" >&2
+ printf 'eks_get_token failed with exit code %s.' "$status" >&2
+ if [ -s "$stderr_file" ]; then
+ printf ' Stderr was: ' >&2
+ cat "$stderr_file" >&2
+ fi
exit "$status"
fi
# Use pure bash below to parse so that it's posix compliant
+ # Only the token line should be on stdout (stderr captured above)
last_line=${{output##*$'\\n'}} # strip everything up to the last
newline
@@ -104,6 +115,15 @@ COMMAND = """
token=${{last_line##*, token: }} # text after ", token: "
+ # Validate that token was extracted — empty token means parsing
failed
+ # or eks_get_token produced unexpected output. Without this check,
a
+ # malformed ExecCredential is sent to the API server, resulting in
a
+ # 401 with an empty user identity in the audit logs.
+ if [ -z "$token" ]; then
+ printf 'Failed to extract token from eks_get_token output.' >&2
+ exit 1
+ fi
+
json_string=$(printf '{{"kind": "ExecCredential","apiVersion": \
"{authentication_api_version}","spec": {{}},"status": \
{{"expirationTimestamp": "%s","token": "%s"}}}}' "$timestamp"
"$token")
diff --git a/providers/amazon/tests/unit/amazon/aws/hooks/test_eks.py
b/providers/amazon/tests/unit/amazon/aws/hooks/test_eks.py
index c0da40e7c03..521005a19ed 100644
--- a/providers/amazon/tests/unit/amazon/aws/hooks/test_eks.py
+++ b/providers/amazon/tests/unit/amazon/aws/hooks/test_eks.py
@@ -1273,6 +1273,41 @@ class TestEksHook:
if expected_region_args:
assert expected_region_args in command_arg
+ def test_command_template_captures_stderr_separately(self):
+ """Verify COMMAND keeps stderr out of stdout while preserving
errors."""
+ from airflow.providers.amazon.aws.hooks.eks import COMMAND
+
+ # Verify stderr is not merged with stdout (the core correctness
requirement)
+ assert "2>&1" not in COMMAND, (
+ "COMMAND must not use 2>&1 — merging stderr with stdout breaks
bash token parsing"
+ )
+ assert "stderr_file=$(mktemp)" in COMMAND
+ assert '2>"$stderr_file"' in COMMAND
+ assert 'cat "$stderr_file" >&2' in COMMAND
+ assert "2>/dev/null" not in COMMAND
+
+ def test_command_template_does_not_print_token_output_on_error(self):
+ """Verify the error path does not echo stdout, which can contain a
token."""
+ from airflow.providers.amazon.aws.hooks.eks import COMMAND
+
+ failure_block = COMMAND.split('if [ "$status" -ne 0 ]; then',
1)[1].split("fi", 1)[0]
+ assert '"$output"' not in failure_block
+
+ def test_command_template_validates_token(self):
+ """Verify COMMAND template validates that the token was successfully
+ extracted before producing the ExecCredential JSON. Without this check,
+ a malformed ExecCredential with an empty token is sent to the API
server,
+ resulting in 401 Unauthorized with an empty user identity in audit
logs.
+ """
+ from airflow.providers.amazon.aws.hooks.eks import COMMAND
+
+ # Verify token validation check exists
+ assert 'if [ -z "$token" ]' in COMMAND, (
+ "COMMAND must validate that token is non-empty before producing
ExecCredential JSON"
+ )
+ # Verify the empty-token validation block exits with an error
+ assert "exit 1" in COMMAND, "COMMAND must exit with error when token
extraction fails"
+
# Helper methods for repeated assert combinations.
def assert_all_arn_values_are_valid(expected_arn_values, pattern,
arn_under_test) -> None: