This is an automated email from the ASF dual-hosted git repository.
ChenSammi pushed a commit to branch HDDS-13323-sts
in repository https://gitbox.apache.org/repos/asf/ozone.git
The following commit(s) were added to refs/heads/HDDS-13323-sts by this push:
new 5000f2835c5 HDDS-16186. Move sts robot tests out of misc suite (#11042)
5000f2835c5 is described below
commit 5000f2835c5940a82b8135c9db16b82cc3a4f1ce
Author: fmorg-git <[email protected]>
AuthorDate: Sun Aug 23 21:02:10 2026 -0700
HDDS-16186. Move sts robot tests out of misc suite (#11042)
---
.../main/compose/ozonesecure-ha/ranger-testlib.sh | 111 +++++++++++++++++++++
.../src/main/compose/ozonesecure-ha/ranger.yaml | 2 +-
.../src/main/compose/ozonesecure-ha/test-ranger.sh | 90 +----------------
.../src/main/compose/ozonesecure-ha/test-sts.sh | 30 ++++++
.../smoketest/security/ozone-secure-sts.resource | 57 +++++++++++
.../main/smoketest/security/ozone-secure-sts.robot | 43 ++++++++
6 files changed, 244 insertions(+), 89 deletions(-)
diff --git
a/hadoop-ozone/dist/src/main/compose/ozonesecure-ha/ranger-testlib.sh
b/hadoop-ozone/dist/src/main/compose/ozonesecure-ha/ranger-testlib.sh
new file mode 100644
index 00000000000..1046a412b24
--- /dev/null
+++ b/hadoop-ozone/dist/src/main/compose/ozonesecure-ha/ranger-testlib.sh
@@ -0,0 +1,111 @@
+#!/usr/bin/env bash
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+_ranger_testlib_dir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1
&& pwd )"
+: "${COMPOSE_DIR:=$_ranger_testlib_dir}"
+export COMPOSE_DIR
+
+# shellcheck source=/dev/null
+source "$COMPOSE_DIR/../testlib.sh"
+
+setup_ranger_acceptance_env() {
+ # Load FF_ENABLE_OZONE_ACTION_MATCHES_CONDITION from .env without overriding
other env.
+ # Ranger reads this value from install.properties (not process env), but we
allow
+ # controlling the mounted install.properties via .env.
+ if [[ -z "${FF_ENABLE_OZONE_ACTION_MATCHES_CONDITION:-}" ]] && [[ -f
"${COMPOSE_DIR}/.env" ]]; then
+ local ff_from_dotenv
+ ff_from_dotenv="$(
+ (
+ set -a
+ # shellcheck source=/dev/null
+ source "${COMPOSE_DIR}/.env" || true
+ echo "${FF_ENABLE_OZONE_ACTION_MATCHES_CONDITION:-}"
+ ) 2>/dev/null
+ )"
+ if [[ -n "${ff_from_dotenv}" ]]; then
+ export FF_ENABLE_OZONE_ACTION_MATCHES_CONDITION="${ff_from_dotenv}"
+ fi
+ fi
+
+ if [[ -z "${RANGER_VERSION:-}" ]]; then
+ export RANGER_VERSION="${ranger.version}"
+ fi
+
+ : "${DOWNLOAD_DIR:=${TEMP_DIR:-/tmp}}"
+
+ export COMPOSE_FILE=docker-compose.yaml:ranger.yaml:../common/ranger.yaml
+ export OM_SERVICE_ID="omservice"
+ export SCM=scm1.org
+ export SECURITY_ENABLED=true
+
+ if [[ "${SKIP_APACHE_VERIFY_DOWNLOAD}" != "true" ]]; then
+ curl -LO https://downloads.apache.org/ranger/KEYS
+ gpg --import KEYS
+ fi
+
+ download_and_verify_apache_release
"ranger/${RANGER_VERSION}/apache-ranger-${RANGER_VERSION}.tar.gz"
+ tar -C "${DOWNLOAD_DIR}" -x -z -f
"${DOWNLOAD_DIR}/apache-ranger-${RANGER_VERSION}.tar.gz"
+ export RANGER_SOURCE_DIR="${DOWNLOAD_DIR}/apache-ranger-${RANGER_VERSION}"
+ chmod -R a+rX "${RANGER_SOURCE_DIR}"
+ export
RANGER_INIT_POSTGRES_SH="${RANGER_SOURCE_DIR}/dev-support/ranger-docker/scripts/rdbms/init_postgres.sh"
+
+ # Create a temp install.properties so we can override feature flags from
.env.
+ local ranger_admin_install_properties_src
+
ranger_admin_install_properties_src="${RANGER_SOURCE_DIR}/dev-support/ranger-docker/scripts/admin/ranger-admin-install-postgres.properties"
+ RANGER_ADMIN_INSTALL_PROPERTIES="$(mktemp
"${DOWNLOAD_DIR%/}/ranger-admin-install-postgres.XXXXXX")"
+ cp -f "${ranger_admin_install_properties_src}"
"${RANGER_ADMIN_INSTALL_PROPERTIES}"
+ chmod a+r "${RANGER_ADMIN_INSTALL_PROPERTIES}"
+
+ local ff
+ ff="$(echo "${FF_ENABLE_OZONE_ACTION_MATCHES_CONDITION:-false}" | tr
'[:upper:]' '[:lower:]')"
+ if [[ "${ff}" != "true" ]]; then
+ ff="false"
+ fi
+ if grep -Eq
'^[[:space:]]*#?[[:space:]]*FF_ENABLE_OZONE_ACTION_MATCHES_CONDITION='
"${RANGER_ADMIN_INSTALL_PROPERTIES}"; then
+ perl -pi -e
"s@^[[:space:]]*#?[[:space:]]*FF_ENABLE_OZONE_ACTION_MATCHES_CONDITION=.*@FF_ENABLE_OZONE_ACTION_MATCHES_CONDITION=${ff}@g"
\
+ "${RANGER_ADMIN_INSTALL_PROPERTIES}"
+ else
+ printf '\nFF_ENABLE_OZONE_ACTION_MATCHES_CONDITION=%s\n' "${ff}" >>
"${RANGER_ADMIN_INSTALL_PROPERTIES}"
+ fi
+
+ export RANGER_ADMIN_INSTALL_PROPERTIES
+
+ # Ranger docker support scripts moved between releases (eg: from config/*.sh
to scripts/**).
+ # Ensure we don't fail if a glob doesn't match, but still make init scripts
executable when present.
+ if [[ -d "${RANGER_SOURCE_DIR}/dev-support/ranger-docker" ]]; then
+ find "${RANGER_SOURCE_DIR}/dev-support/ranger-docker" -type f -name '*.sh'
-exec chmod a+x {} +
+ fi
+ download_and_verify_apache_release
"ranger/${RANGER_VERSION}/plugins/ozone/ranger-${RANGER_VERSION}-ozone-plugin.tar.gz"
+ tar -C "${DOWNLOAD_DIR}" -x -z -f
"${DOWNLOAD_DIR}/ranger-${RANGER_VERSION}-ozone-plugin.tar.gz"
+ export
RANGER_OZONE_PLUGIN_DIR="${DOWNLOAD_DIR}/ranger-${RANGER_VERSION}-ozone-plugin"
+ chmod -R a+rX "${RANGER_OZONE_PLUGIN_DIR}"
+ chmod a+x "${RANGER_OZONE_PLUGIN_DIR}"/*.sh
+
+ # customizations before install
+ perl -wpl -i \
+ -e 's@^POLICY_MGR_URL=.*@POLICY_MGR_URL=http://ranger:6080@;' \
+ -e 's@^REPOSITORY_NAME=.*@REPOSITORY_NAME=dev_ozone@;' \
+ -e 's@^CUSTOM_USER=ozone@CUSTOM_USER=hadoop@;' \
+ -e 's@^[email protected]=false@;' \
+ -e
's@^XAAUDIT.LOG4J.DESTINATION.LOG4J=true@XAAUDIT.LOG4J.DESTINATION.LOG4J=false@;'
\
+ "${RANGER_OZONE_PLUGIN_DIR}/install.properties"
+
+ echo 'machine ranger login admin password rangerR0cks!' >
"${COMPOSE_DIR}/../../.netrc"
+
+ start_docker_env
+ wait_for_port ranger 6080 120
+}
diff --git a/hadoop-ozone/dist/src/main/compose/ozonesecure-ha/ranger.yaml
b/hadoop-ozone/dist/src/main/compose/ozonesecure-ha/ranger.yaml
index 579dbfc0cc1..2dad84dbb5f 100644
--- a/hadoop-ozone/dist/src/main/compose/ozonesecure-ha/ranger.yaml
+++ b/hadoop-ozone/dist/src/main/compose/ozonesecure-ha/ranger.yaml
@@ -42,7 +42,7 @@ x-om-ranger-config:
# JDK17+ no longer ships javax.annotation, but the Ranger Ozone plugin's
Jersey2
# client needs javax.annotation.Priority. Copy the jar into the plugin
impl dir
# so the isolated RangerPluginClassLoader can find it.
- command: bash -c 'sudo mkdir -p
/opt/ranger/ozone-plugin/lib/libext/ranger-ozone-plugin-impl && for j in
/opt/hadoop/share/ozone/lib/javax.annotation-api-*.jar; do [ -e "$$j" ] ||
continue; sudo cp -n "$$j"
/opt/ranger/ozone-plugin/lib/libext/ranger-ozone-plugin-impl/; done && sudo
--preserve-env /opt/ranger/ozone-plugin/enable-ozone-plugin.sh && exec
/opt/hadoop/bin/ozone om'
+ command: bash -c 'sudo mkdir -p
/opt/ranger/ozone-plugin/lib/libext/ranger-ozone-plugin-impl && for j in
/opt/hadoop/share/ozone/lib/javax.annotation-api-*.jar; do [ -e "$$j" ] ||
continue;
dest="/opt/ranger/ozone-plugin/lib/libext/ranger-ozone-plugin-impl/$$(basename
"$$j")"; sudo test -e "$$dest" || sudo cp -n "$$j" "$$dest" || sudo test -e
"$$dest"; done && sudo --preserve-env
/opt/ranger/ozone-plugin/enable-ozone-plugin.sh && exec /opt/hadoop/bin/ozone
om'
services:
om1:
diff --git a/hadoop-ozone/dist/src/main/compose/ozonesecure-ha/test-ranger.sh
b/hadoop-ozone/dist/src/main/compose/ozonesecure-ha/test-ranger.sh
index 4940e782da5..7d6950ccaa7 100755
--- a/hadoop-ozone/dist/src/main/compose/ozonesecure-ha/test-ranger.sh
+++ b/hadoop-ozone/dist/src/main/compose/ozonesecure-ha/test-ranger.sh
@@ -20,99 +20,13 @@
COMPOSE_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
export COMPOSE_DIR
-# Load FF_ENABLE_OZONE_ACTION_MATCHES_CONDITION from .env without overriding
other env.
-# Ranger reads this value from install.properties (not process env), but we
allow
-# controlling the mounted install.properties via .env.
-if [[ -z "${FF_ENABLE_OZONE_ACTION_MATCHES_CONDITION:-}" ]] && [[ -f
"${COMPOSE_DIR}/.env" ]]; then
- _ff_from_dotenv="$(
- (
- set -a
- # shellcheck source=/dev/null
- source "${COMPOSE_DIR}/.env"
- echo "${FF_ENABLE_OZONE_ACTION_MATCHES_CONDITION:-}"
- ) 2>/dev/null
- )"
- if [[ -n "${_ff_from_dotenv}" ]]; then
- export FF_ENABLE_OZONE_ACTION_MATCHES_CONDITION="${_ff_from_dotenv}"
- fi
- unset _ff_from_dotenv
-fi
-
-if [[ -z "${RANGER_VERSION:-}" ]]; then
- export RANGER_VERSION="${ranger.version}"
-fi
-
-: "${DOWNLOAD_DIR:=${TEMP_DIR:-/tmp}}"
-
# shellcheck source=/dev/null
-source "$COMPOSE_DIR/../testlib.sh"
-
-export COMPOSE_FILE=docker-compose.yaml:ranger.yaml:../common/ranger.yaml
-export OM_SERVICE_ID="omservice"
-export SCM=scm1.org
-export SECURITY_ENABLED=true
-
-if [[ "${SKIP_APACHE_VERIFY_DOWNLOAD}" != "true" ]]; then
- curl -LO https://downloads.apache.org/ranger/KEYS
- gpg --import KEYS
-fi
-
-download_and_verify_apache_release
"ranger/${RANGER_VERSION}/apache-ranger-${RANGER_VERSION}.tar.gz"
-tar -C "${DOWNLOAD_DIR}" -x -z -f
"${DOWNLOAD_DIR}/apache-ranger-${RANGER_VERSION}.tar.gz"
-export RANGER_SOURCE_DIR="${DOWNLOAD_DIR}/apache-ranger-${RANGER_VERSION}"
-chmod -R a+rX "${RANGER_SOURCE_DIR}"
-export
RANGER_INIT_POSTGRES_SH="${RANGER_SOURCE_DIR}/dev-support/ranger-docker/scripts/rdbms/init_postgres.sh"
-
-# Create a temp install.properties so we can override feature flags from .env.
-RANGER_ADMIN_INSTALL_PROPERTIES_SRC="${RANGER_SOURCE_DIR}/dev-support/ranger-docker/scripts/admin/ranger-admin-install-postgres.properties"
-RANGER_ADMIN_INSTALL_PROPERTIES="$(mktemp
"${DOWNLOAD_DIR%/}/ranger-admin-install-postgres.XXXXXX")"
-cp -f "${RANGER_ADMIN_INSTALL_PROPERTIES_SRC}"
"${RANGER_ADMIN_INSTALL_PROPERTIES}"
-chmod a+r "${RANGER_ADMIN_INSTALL_PROPERTIES}"
-
-_ff="$(echo "${FF_ENABLE_OZONE_ACTION_MATCHES_CONDITION:-false}" | tr
'[:upper:]' '[:lower:]')"
-if [[ "${_ff}" != "true" ]]; then
- _ff="false"
-fi
-if grep -Eq
'^[[:space:]]*#?[[:space:]]*FF_ENABLE_OZONE_ACTION_MATCHES_CONDITION='
"${RANGER_ADMIN_INSTALL_PROPERTIES}"; then
- perl -pi -e
"s@^[[:space:]]*#?[[:space:]]*FF_ENABLE_OZONE_ACTION_MATCHES_CONDITION=.*@FF_ENABLE_OZONE_ACTION_MATCHES_CONDITION=${_ff}@g"
\
- "${RANGER_ADMIN_INSTALL_PROPERTIES}"
-else
- printf '\nFF_ENABLE_OZONE_ACTION_MATCHES_CONDITION=%s\n' "${_ff}" >>
"${RANGER_ADMIN_INSTALL_PROPERTIES}"
-fi
-unset _ff
-
-export RANGER_ADMIN_INSTALL_PROPERTIES
-
-# Ranger docker support scripts moved between releases (eg: from config/*.sh
to scripts/**).
-# Ensure we don't fail if a glob doesn't match, but still make init scripts
executable when present.
-if [[ -d "${RANGER_SOURCE_DIR}/dev-support/ranger-docker" ]]; then
- find "${RANGER_SOURCE_DIR}/dev-support/ranger-docker" -type f -name '*.sh'
-exec chmod a+x {} +
-fi
-download_and_verify_apache_release
"ranger/${RANGER_VERSION}/plugins/ozone/ranger-${RANGER_VERSION}-ozone-plugin.tar.gz"
-tar -C "${DOWNLOAD_DIR}" -x -z -f
"${DOWNLOAD_DIR}/ranger-${RANGER_VERSION}-ozone-plugin.tar.gz"
-export
RANGER_OZONE_PLUGIN_DIR="${DOWNLOAD_DIR}/ranger-${RANGER_VERSION}-ozone-plugin"
-chmod -R a+rX "${RANGER_OZONE_PLUGIN_DIR}"
-chmod a+x "${RANGER_OZONE_PLUGIN_DIR}"/*.sh
-
-# customizations before install
-perl -wpl -i \
- -e 's@^POLICY_MGR_URL=.*@POLICY_MGR_URL=http://ranger:6080@;' \
- -e 's@^REPOSITORY_NAME=.*@REPOSITORY_NAME=dev_ozone@;' \
- -e 's@^CUSTOM_USER=ozone@CUSTOM_USER=hadoop@;' \
- -e 's@^[email protected]=false@;' \
- -e
's@^XAAUDIT.LOG4J.DESTINATION.LOG4J=true@XAAUDIT.LOG4J.DESTINATION.LOG4J=false@;'
\
- "${RANGER_OZONE_PLUGIN_DIR}/install.properties"
-
-echo 'machine ranger login admin password rangerR0cks!' > ../../.netrc
+source "$COMPOSE_DIR/ranger-testlib.sh"
-start_docker_env
-wait_for_port ranger 6080 120
+setup_ranger_acceptance_env
execute_robot_test s3g -v USER:hdfs kinit.robot
execute_robot_test s3g freon/generate.robot
execute_robot_test s3g freon/validate.robot
execute_robot_test s3g -v RANGER_ENDPOINT_URL:"http://ranger:6080" -v
USER:hdfs security/ozone-secure-tenant.robot
-execute_robot_test s3g -v RANGER_ENDPOINT_URL:"http://ranger:6080" -v
USER:hdfs security/ozone-secure-sts.robot
-execute_robot_test s3g -v RANGER_ENDPOINT_URL:"http://ranger:6080" -v
USER:hdfs security/ozone-secure-sts-multitenant.robot
-"${COMPOSE_DIR}/polaris-smoketest.sh"
diff --git a/hadoop-ozone/dist/src/main/compose/ozonesecure-ha/test-sts.sh
b/hadoop-ozone/dist/src/main/compose/ozonesecure-ha/test-sts.sh
new file mode 100755
index 00000000000..879dd1b5851
--- /dev/null
+++ b/hadoop-ozone/dist/src/main/compose/ozonesecure-ha/test-sts.sh
@@ -0,0 +1,30 @@
+#!/usr/bin/env bash
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+#suite:sts
+
+COMPOSE_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
+export COMPOSE_DIR
+
+# shellcheck source=/dev/null
+source "$COMPOSE_DIR/ranger-testlib.sh"
+
+setup_ranger_acceptance_env
+
+execute_robot_test s3g -v RANGER_ENDPOINT_URL:"http://ranger:6080" -v
USER:hdfs security/ozone-secure-sts.robot
+execute_robot_test s3g -v RANGER_ENDPOINT_URL:"http://ranger:6080" -v
USER:hdfs security/ozone-secure-sts-multitenant.robot
+"${COMPOSE_DIR}/polaris-smoketest.sh"
diff --git
a/hadoop-ozone/dist/src/main/smoketest/security/ozone-secure-sts.resource
b/hadoop-ozone/dist/src/main/smoketest/security/ozone-secure-sts.resource
index dd697b1598e..19cb6f4e202 100644
--- a/hadoop-ozone/dist/src/main/smoketest/security/ozone-secure-sts.resource
+++ b/hadoop-ozone/dist/src/main/smoketest/security/ozone-secure-sts.resource
@@ -27,6 +27,11 @@ ${RANGER_ENDPOINT_URL} ${EMPTY}
${STS_ENDPOINT_URL} http://s3g:9880
${S3G_ENDPOINT_URL} http://s3g:9878
${ROLE_SESSION_NAME} sts-session-name
+${EXPIRED_STS_TOKEN_PROFILE} expired_sts_token
+${EXPIRED_STS_TOKEN_ACCESS_KEY_ID} ${EMPTY}
+${EXPIRED_STS_TOKEN_SECRET_ACCESS_KEY} ${EMPTY}
+${EXPIRED_STS_TOKEN_SESSION_TOKEN} ${EMPTY}
+${EXPIRED_STS_TOKEN_EXPIRATION} ${EMPTY}
*** Keywords ***
Configure AWS Profile
@@ -115,6 +120,58 @@ Assume Role And Get Temporary Credentials
Should Be True ${time_diff} >= ${minimum_expected}
Expected expiration to be at least ${minimum_expected}s in the future, but was
${time_diff}s
Should Be True ${time_diff} <= ${maximum_expected}
Expected expiration to be at most ${maximum_expected}s in the future, but was
${time_diff}s
+Assume Role And Store Expired STS Token Credentials
+ # Issue a 900s STS credential and store it in EXPIRED_STS_TOKEN_* globals
only (it should never be used/modified until the "Expired STS temporary
credentials return ExpiredToken on S3 APIs" test).
+ [Arguments] ${perm_access_key_id} ${perm_secret_key}
${role_arn} ${duration_seconds}=900
+ Configure AWS Profile permanent ${perm_access_key_id}
${perm_secret_key}
+ ${suffix} = Generate Random String 8 [LOWER]
+ ${role_session_name} = Set Variable
expired-sts-token-${suffix}
+
+ ${cmd} = Set Variable aws sts
assume-role --endpoint-url ${STS_ENDPOINT_URL} --role-arn ${role_arn}
--role-session-name ${role_session_name} --duration-seconds ${duration_seconds}
--output json --profile permanent
+
+ ${json} = Execute ${cmd}
+ Should Contain ${json} Credentials
+
+ ${expiredStsAccessKeyId} = Execute printf '%s'
'${json}' | jq -r '.Credentials.AccessKeyId'
+ ${expiredStsSecretKey} = Execute printf '%s'
'${json}' | jq -r '.Credentials.SecretAccessKey'
+ ${expiredStsSessionToken} = Execute printf '%s'
'${json}' | jq -r '.Credentials.SessionToken'
+ ${expiration} = Execute printf '%s'
'${json}' | jq -r '.Credentials.Expiration'
+ Should Start With ${expiredStsAccessKeyId} ASIA
+ Set Global Variable ${EXPIRED_STS_TOKEN_ACCESS_KEY_ID}
${expiredStsAccessKeyId}
+ Set Global Variable ${EXPIRED_STS_TOKEN_SECRET_ACCESS_KEY}
${expiredStsSecretKey}
+ Set Global Variable ${EXPIRED_STS_TOKEN_SESSION_TOKEN}
${expiredStsSessionToken}
+ Set Global Variable ${EXPIRED_STS_TOKEN_EXPIRATION}
${expiration}
+
+Expired STS Token Credentials Should Be Available
+ Skip If '${EXPIRED_STS_TOKEN_EXPIRATION}' ==
'${EMPTY}' Expired STS token credentials are unavailable. Run the prerequisite
AssumeRole test before expired-token checks.
+ Should Not Be Empty ${EXPIRED_STS_TOKEN_ACCESS_KEY_ID}
Expired STS token access key ID is unavailable.
+ Should Not Be Empty ${EXPIRED_STS_TOKEN_SECRET_ACCESS_KEY}
Expired STS token secret key is unavailable.
+ Should Not Be Empty ${EXPIRED_STS_TOKEN_SESSION_TOKEN}
Expired STS token session token is unavailable.
+
+Wait Until Expired STS Token Expiration Elapsed
+ # Matches the +/-2s skew tolerance used for AssumeRole duration checks.
+ Expired STS Token Credentials Should Be Available
+ ${now} = Get Current Date time_zone=UTC
+ ${secondsUntilExpiration} = Subtract Date From Date
${EXPIRED_STS_TOKEN_EXPIRATION} ${now}
+ ${remaining} = Evaluate
${secondsUntilExpiration} + 2
+ Run Keyword If ${remaining} > 0 Sleep
${remaining}
+
+Configure Expired STS Token S3 Profile
+ Expired STS Token Credentials Should Be Available
+ Configure AWS Profile ${EXPIRED_STS_TOKEN_PROFILE}
${EXPIRED_STS_TOKEN_ACCESS_KEY_ID} ${EXPIRED_STS_TOKEN_SECRET_ACCESS_KEY}
${EXPIRED_STS_TOKEN_SESSION_TOKEN}
+
+Execute S3api Expect Expired Token
+ [Arguments] ${command_tail}
+ ${output} = Execute And Ignore Error aws s3api
--endpoint-url ${S3G_ENDPOINT_URL} ${command_tail} --profile
${EXPIRED_STS_TOKEN_PROFILE}
+ Should Contain ${output} ExpiredToken
+
+Execute S3api Expect Expired Token Head Operation
+ [Arguments] ${command_tail}
${expected_aws_operation_name}
+ [Documentation] head-bucket and head-object omit S3 XML
error bodies so we can't check for ExpiredToken in the body. awscli surfaces
HTTP 400 and the operation label (HeadBucket / HeadObject) instead of
ExpiredToken. Assert status and operation together to avoid matching unrelated
400s.
+ ${output} = Execute And Ignore Error aws s3api
--endpoint-url ${S3G_ENDPOINT_URL} ${command_tail} --profile
${EXPIRED_STS_TOKEN_PROFILE}
+ Should Contain ${output} (400)
+ Should Contain ${output}
${expected_aws_operation_name}
+
Assume Role And Configure STS Profile
[Arguments] ${perm_access_key_id} ${perm_secret_key}
${policy_json}=${EMPTY} ${role_arn}=${ROLE_ARN_OBS}
${role_session_name}=${ROLE_SESSION_NAME} ${duration_seconds}=900
Assume Role And Get Temporary Credentials
perm_access_key_id=${perm_access_key_id} perm_secret_key=${perm_secret_key}
policy_json=${policy_json} role_arn=${role_arn}
role_session_name=${role_session_name} duration_seconds=${duration_seconds}
diff --git
a/hadoop-ozone/dist/src/main/smoketest/security/ozone-secure-sts.robot
b/hadoop-ozone/dist/src/main/smoketest/security/ozone-secure-sts.robot
index a1f34e818b7..c0362d74704 100644
--- a/hadoop-ozone/dist/src/main/smoketest/security/ozone-secure-sts.robot
+++ b/hadoop-ozone/dist/src/main/smoketest/security/ozone-secure-sts.robot
@@ -408,6 +408,9 @@ Get S3 Credentials for Service Catalog Principal, Create
Iceberg Buckets, and Up
# Switch back to the service catalog principal for running S3/STS requests.
Kinit test user ${ICEBERG_SVC_CATALOG_USER}
${ICEBERG_SVC_CATALOG_USER}.keytab
+ # Long-lived 15-minute STS credential to test STS token expiration and
proper error message
+ Assume Role And Store Expired STS Token Credentials
perm_access_key_id=${PERMANENT_ACCESS_KEY_ID}
perm_secret_key=${PERMANENT_SECRET_KEY}
role_arn=${ICEBERG_ALL_ACCESS_ROLE_OBS_ARN}
+
Assume Role for Limited-Scope Token
# All access role is limited to read-only via session policy
FOR ${bucket} ${role_arn} IN
@@ -1237,6 +1240,46 @@ STS session policy containing only GetObject must deny
DeleteObjects
${output} = Execute aws s3api
--endpoint-url ${S3G_ENDPOINT_URL} delete-bucket --bucket ${bucket} --profile
sts
Should Not Contain ${output} AccessDenied
+Expired STS temporary credentials must return ExpiredToken on S3 APIs
+ # Increase timeout to account for 15 minute STS token expiration plus the
time to execute the api calls
+ [Timeout] 25 minutes
+ ${dummy_mpu_upload_id} = Set Variable
dummyExpiredStsMpuUploadId01
+
+ Wait Until Expired STS Token Expiration Elapsed
+ Configure Expired STS Token S3 Profile
+
+ Execute S3api Expect Expired Token list-buckets
--output json
+ Execute S3api Expect Expired Token Head Operation head-bucket
--bucket ${ICEBERG_BUCKET_OBS} HeadBucket
+ Execute S3api Expect Expired Token
list-objects-v2 --bucket ${ICEBERG_BUCKET_OBS} --output json
+ Execute S3api Expect Expired Token list-objects
--bucket ${ICEBERG_BUCKET_OBS} --output json
+ Execute S3api Expect Expired Token get-object
--bucket ${ICEBERG_BUCKET_OBS} --key ${ICEBERG_BUCKET_TESTFILE}
${TEMP_DIR}/expired-sts-token-get-object.out
+
+ Create File
${TEMP_DIR}/expired-sts-token-put-object-body.txt expired sts token put body
+
+ Execute S3api Expect Expired Token put-object
--bucket ${ICEBERG_BUCKET_OBS} --key sts-expired-sts-token-put.txt --body
${TEMP_DIR}/expired-sts-token-put-object-body.txt
+ Execute S3api Expect Expired Token Head Operation head-object
--bucket ${ICEBERG_BUCKET_OBS} --key ${ICEBERG_BUCKET_TESTFILE} HeadObject
+ Execute S3api Expect Expired Token delete-object
--bucket ${ICEBERG_BUCKET_OBS} --key sts-expired-sts-token-delete-marker.txt
+ Execute S3api Expect Expired Token delete-objects
--bucket ${ICEBERG_BUCKET_OBS} --delete
'Objects=[{Key=sts-expired-sts-token-delete-objects-marker.txt}],Quiet=false'
+
+ ${bucket_suffix} = Generate Random String 8 [LOWER]
+ ${exp_bucket} = Set Variable
sts-bucket-expired-sts-token-${bucket_suffix}
+
+ Execute S3api Expect Expired Token create-bucket
--bucket ${exp_bucket}
+ Execute S3api Expect Expired Token delete-bucket
--bucket ${exp_bucket}
+ Execute S3api Expect Expired Token get-bucket-acl
--bucket ${ICEBERG_BUCKET_OBS}
+ Execute S3api Expect Expired Token put-bucket-acl
--bucket ${ICEBERG_BUCKET_OBS} --grant-read ''
+ Execute S3api Expect Expired Token
list-multipart-uploads --bucket ${ICEBERG_BUCKET_OBS}
+ Execute S3api Expect Expired Token
create-multipart-upload --bucket ${ICEBERG_BUCKET_OBS} --key
sts-expired-sts-token-mpu.txt
+ Execute S3api Expect Expired Token upload-part
--bucket ${ICEBERG_BUCKET_OBS} --key sts-expired-sts-token-mpu.txt
--part-number 1 --body ${TEMP_DIR}/expired-sts-token-put-object-body.txt
--upload-id ${dummy_mpu_upload_id}
+ Execute S3api Expect Expired Token
upload-part-copy --bucket ${ICEBERG_BUCKET_OBS} --key
sts-expired-sts-token-mpu-copy.txt --part-number 1 --upload-id
${dummy_mpu_upload_id} --copy-source
${ICEBERG_BUCKET_OBS}/${ICEBERG_BUCKET_TESTFILE}
+ Execute S3api Expect Expired Token list-parts
--bucket ${ICEBERG_BUCKET_OBS} --key sts-expired-sts-token-mpu.txt --upload-id
${dummy_mpu_upload_id}
+ Execute S3api Expect Expired Token
abort-multipart-upload --bucket ${ICEBERG_BUCKET_OBS} --key
sts-expired-sts-token-mpu.txt --upload-id ${dummy_mpu_upload_id}
+ Execute S3api Expect Expired Token
complete-multipart-upload --bucket ${ICEBERG_BUCKET_OBS} --key
sts-expired-sts-token-mpu.txt --upload-id ${dummy_mpu_upload_id}
--multipart-upload
'{"Parts":[{"ETag":"d41d8cd98f00b204e9800998ecf8427e","PartNumber":1}]}'
+ Execute S3api Expect Expired Token copy-object
--bucket ${ICEBERG_BUCKET_OBS} --copy-source
${ICEBERG_BUCKET_OBS}/${ICEBERG_BUCKET_TESTFILE} --key
sts-expired-sts-token-copy-dest.txt
+ Execute S3api Expect Expired Token
get-object-tagging --bucket ${ICEBERG_BUCKET_OBS} --key
${ICEBERG_BUCKET_TESTFILE}
+ Execute S3api Expect Expired Token
put-object-tagging --bucket ${ICEBERG_BUCKET_OBS} --key
${ICEBERG_BUCKET_TESTFILE} --tagging
'{"TagSet":[{"Key":"tag-key-expired-sts-token","Value":"tag-value-expired-sts-token"}]}'
+ Execute S3api Expect Expired Token
delete-object-tagging --bucket ${ICEBERG_BUCKET_OBS} --key
${ICEBERG_BUCKET_TESTFILE}
+
Revoking Permanent User Must Revoke Existing Session Token
# Create session tokens for both buckets, verify they work, then revoke
permanent user secret and verify both fail.
Assume Role And Get Temporary Credentials
perm_access_key_id=${PERMANENT_ACCESS_KEY_ID}
perm_secret_key=${PERMANENT_SECRET_KEY}
role_arn=${ICEBERG_ALL_ACCESS_ROLE_OBS_ARN}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]