diff --git a/hadoop-ozone/dist/src/main/compose/common/init-kdc.sh b/hadoop-ozone/dist/src/main/compose/common/init-kdc.sh index 3fd00a2b4f36..665d3da8264c 100755 --- a/hadoop-ozone/dist/src/main/compose/common/init-kdc.sh +++ b/hadoop-ozone/dist/src/main/compose/common/init-kdc.sh @@ -37,6 +37,9 @@ export_keytab testuser/om testuser export_keytab testuser/recon testuser export_keytab testuser/s3g testuser export_keytab testuser/scm testuser +export_keytab svc-iceberg-rest-catalog/s3g svc-iceberg-rest-catalog +export_keytab svc-iceberg-userA/s3g svc-iceberg-userA +export_keytab svc-iceberg-userB/s3g svc-iceberg-userB export_keytab testuser2/dn testuser2 export_keytab testuser2/httpfs testuser2 diff --git a/hadoop-ozone/dist/src/main/compose/common/ranger.yaml b/hadoop-ozone/dist/src/main/compose/common/ranger.yaml index ab3676f3ba7b..8a61f67149fd 100644 --- a/hadoop-ozone/dist/src/main/compose/common/ranger.yaml +++ b/hadoop-ozone/dist/src/main/compose/common/ranger.yaml @@ -26,7 +26,7 @@ services: environment: POSTGRES_PASSWORD: "rangerR0cks!" volumes: - - ${RANGER_SOURCE_DIR}/dev-support/ranger-docker/config/init_postgres.sh:/docker-entrypoint-initdb.d/init_postgres.sh + - ${RANGER_SOURCE_DIR}/dev-support/ranger-docker/scripts/rdbms/init_postgres.sh:${RANGER_SOURCE_DIR}/dev-support/ranger-docker/config/init_postgres.sh:/docker-entrypoint-initdb.d/init_postgres.sh healthcheck: test: 'su -c "pg_isready -q" postgres' interval: 10s diff --git a/hadoop-ozone/dist/src/main/compose/ozonesecure-ha/.env b/hadoop-ozone/dist/src/main/compose/ozonesecure-ha/.env index 1571c3aa8249..7796361788b4 100644 --- a/hadoop-ozone/dist/src/main/compose/ozonesecure-ha/.env +++ b/hadoop-ozone/dist/src/main/compose/ozonesecure-ha/.env @@ -24,7 +24,7 @@ OZONE_VOLUME=./data OZONE_OPTS= RANGER_DB_IMAGE=postgres RANGER_DB_IMAGE_VERSION=12 -RANGER_IMAGE=ghcr.io/adoroszlai/ranger-admin -RANGER_IMAGE_VERSION=0ae34250d3af672776fca6a53047699adf3afce5-${ranger.version}-8 +RANGER_IMAGE=ghcr.io/fmorg-git/ranger-admin +RANGER_IMAGE_VERSION=84bcfcf5a322aa97bf8b7264357cfeb377072e6c-${ranger.version}-8 RANGER_VERSION=${ranger.version} WAITFOR_TIMEOUT=3000 diff --git a/hadoop-ozone/dist/src/main/compose/ozonesecure-ha/docker-config b/hadoop-ozone/dist/src/main/compose/ozonesecure-ha/docker-config index 4fabf7b8cc77..b5d108b3c53c 100644 --- a/hadoop-ozone/dist/src/main/compose/ozonesecure-ha/docker-config +++ b/hadoop-ozone/dist/src/main/compose/ozonesecure-ha/docker-config @@ -101,6 +101,9 @@ OZONE-SITE.XML_ozone.security.http.kerberos.enabled=true OZONE-SITE.XML_ozone.s3g.secret.http.enabled=true OZONE-SITE.XML_ozone.http.filter.initializers=org.apache.hadoop.security.AuthenticationFilterInitializer +# Enable S3 Gateway STS (AWS STS compatible) endpoint on s3g (http://s3g:9880/sts) +OZONE-SITE.XML_ozone.s3g.sts.http.enabled=true + OZONE-SITE.XML_ozone.om.http.auth.type=kerberos OZONE-SITE.XML_hdds.scm.http.auth.type=kerberos OZONE-SITE.XML_hdds.datanode.http.auth.type=kerberos 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 0b5ca66b77da..d241743ef1c1 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,7 +20,7 @@ COMPOSE_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" export COMPOSE_DIR -: "${RANGER_VERSION:=2.6.0}" +: "${RANGER_VERSION:=2.8.0-SNAPSHOT}" : "${DOWNLOAD_DIR:=${TEMP_DIR:-/tmp}}" # shellcheck source=/dev/null @@ -31,20 +31,79 @@ export OM_SERVICE_ID="omservice" export SCM=scm1.org export SECURITY_ENABLED=true -if [[ "${SKIP_APACHE_VERIFY_DOWNLOAD}" != "true" ]]; then +# Check if we are using a snapshot version +if [[ "${RANGER_VERSION}" =~ [0-9]+\.[0-9]+\.[0-9]+-[0-9]{8}\.[0-9]{6}-[0-9]+ ]] || [[ "${RANGER_VERSION}" == *"SNAPSHOT"* ]]; then + IS_SNAPSHOT=true +else + IS_SNAPSHOT=false +fi + +if [[ "${SKIP_APACHE_VERIFY_DOWNLOAD}" != "true" ]] && [[ "${IS_SNAPSHOT}" == "false" ]]; 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}" +if [[ "${IS_SNAPSHOT}" == "true" ]]; then + # Snapshot download logic + RANGER_BASE_VERSION=$(echo "${RANGER_VERSION}" | sed -E 's/-[0-9]{8}\.[0-9]{6}-[0-9]+//') + if [[ "${RANGER_BASE_VERSION}" == "${RANGER_VERSION}" ]]; then + RANGER_BASE_VERSION="${RANGER_VERSION}" + else + RANGER_BASE_VERSION="${RANGER_BASE_VERSION}-SNAPSHOT" + fi + SNAPSHOT_REPO="https://repository.apache.org/content/groups/snapshots/org/apache/ranger/ranger-distro/${RANGER_BASE_VERSION}" + + if [[ "${RANGER_VERSION}" == *"SNAPSHOT"* ]]; then + # If RANGER_VERSION is a snapshot (e.g. 2.8.0-SNAPSHOT), resolve it to the latest timestamped version + download_if_not_exists "${SNAPSHOT_REPO}/maven-metadata.xml" "${DOWNLOAD_DIR}/maven-metadata.xml" + TIMESTAMP=$(grep "" "${DOWNLOAD_DIR}/maven-metadata.xml" | head -1 | sed -e 's/.*\(.*\)<\/timestamp>.*/\1/') + BUILDNUM=$(grep "" "${DOWNLOAD_DIR}/maven-metadata.xml" | head -1 | sed -e 's/.*\(.*\)<\/buildNumber>.*/\1/') + if [[ -n "${TIMESTAMP}" ]] && [[ -n "${BUILDNUM}" ]]; then + RANGER_VERSION="${RANGER_BASE_VERSION%-SNAPSHOT}-${TIMESTAMP}-${BUILDNUM}" + echo "Resolved RANGER_VERSION to ${RANGER_VERSION}" + fi + fi + + SRC_TAR="ranger-distro-${RANGER_VERSION}-src.tar.gz" + download_if_not_exists "${SNAPSHOT_REPO}/${SRC_TAR}" "${DOWNLOAD_DIR}/${SRC_TAR}" + tar -C "${DOWNLOAD_DIR}" -x -z -f "${DOWNLOAD_DIR}/${SRC_TAR}" + + # Find the extracted directory name + EXTRACTED_DIR=$(tar -tf "${DOWNLOAD_DIR}/${SRC_TAR}" | grep -o '^[^/]*' | sort | uniq | head -1) + export RANGER_SOURCE_DIR="${DOWNLOAD_DIR}/${EXTRACTED_DIR}" +else + # Release download logic + 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}" +fi + chmod -R a+rX "${RANGER_SOURCE_DIR}" -chmod a+x "${RANGER_SOURCE_DIR}"/dev-support/ranger-docker/config/*.sh -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" +# 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. +shopt -s nullglob +chmod_targets=( + "${RANGER_SOURCE_DIR}"/dev-support/ranger-docker/config/*.sh + "${RANGER_SOURCE_DIR}"/dev-support/ranger-docker/scripts/rdbms/*.sh +) +shopt -u nullglob +if (( ${#chmod_targets[@]} > 0 )); then + chmod a+x "${chmod_targets[@]}" +fi + +if [[ "${IS_SNAPSHOT}" == "true" ]]; then + PLUGIN_TAR="ranger-distro-${RANGER_VERSION}-ozone-plugin.tar.gz" + download_if_not_exists "${SNAPSHOT_REPO}/${PLUGIN_TAR}" "${DOWNLOAD_DIR}/${PLUGIN_TAR}" + tar -C "${DOWNLOAD_DIR}" -x -z -f "${DOWNLOAD_DIR}/${PLUGIN_TAR}" + EXTRACTED_PLUGIN_DIR=$(tar -tf "${DOWNLOAD_DIR}/${PLUGIN_TAR}" | grep -o '^[^/]*' | sort | uniq | head -1) + export RANGER_OZONE_PLUGIN_DIR="${DOWNLOAD_DIR}/${EXTRACTED_PLUGIN_DIR}" +else + 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" +fi + chmod -R a+rX "${RANGER_OZONE_PLUGIN_DIR}" chmod a+x "${RANGER_OZONE_PLUGIN_DIR}"/*.sh @@ -53,6 +112,8 @@ 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@^XAAUDIT.LOG4J.ENABLE=.*@XAAUDIT.LOG4J.ENABLE=false@;' \ + -e 's@^XAAUDIT.LOG4J.DESTINATION.LOG4J=.*@XAAUDIT.LOG4J.DESTINATION.LOG4J=false@;' \ "${RANGER_OZONE_PLUGIN_DIR}/install.properties" echo 'machine ranger login admin password rangerR0cks!' > ../../.netrc @@ -65,3 +126,5 @@ 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 diff --git a/hadoop-ozone/dist/src/main/compose/testlib.sh b/hadoop-ozone/dist/src/main/compose/testlib.sh index 040d9c1db1c6..0dc67bff490e 100755 --- a/hadoop-ozone/dist/src/main/compose/testlib.sh +++ b/hadoop-ozone/dist/src/main/compose/testlib.sh @@ -251,7 +251,7 @@ execute_robot_test(){ -v OM_SERVICE_ID:"${OM_SERVICE_ID:-om}" \ -v OZONE_DIR:"${OZONE_DIR}" \ -v SCM:"${SCM}" \ - ${ARGUMENTS[@]} --log NONE --report NONE --output "$OUTPUT_PATH" \ + ${ARGUMENTS[@]-} --log NONE --report NONE --output "$OUTPUT_PATH" \ "$SMOKETEST_DIR_INSIDE/$TEST" local -i rc=$? diff --git a/hadoop-ozone/dist/src/main/k8s/examples/testlib.sh b/hadoop-ozone/dist/src/main/k8s/examples/testlib.sh index 1ae4dd98485f..75a8da55e5e2 100644 --- a/hadoop-ozone/dist/src/main/k8s/examples/testlib.sh +++ b/hadoop-ozone/dist/src/main/k8s/examples/testlib.sh @@ -163,7 +163,7 @@ execute_robot_test() { kubectl exec -it "${CONTAINER}" -- bash -c 'rm -rf /tmp/report' kubectl exec -it "${CONTAINER}" -- bash -c 'mkdir -p /tmp/report' - kubectl exec -it "${CONTAINER}" -- robot --nostatusrc -d /tmp/report ${ARGUMENTS[@]} || true + kubectl exec -it "${CONTAINER}" -- robot --nostatusrc -d /tmp/report ${ARGUMENTS[@]-} || true kubectl cp "${CONTAINER}":/tmp/report/output.xml "result/$CONTAINER-$RANDOM.xml" || true } diff --git a/hadoop-ozone/dist/src/main/smoketest/security/ozone-secure-sts-multitenant.robot b/hadoop-ozone/dist/src/main/smoketest/security/ozone-secure-sts-multitenant.robot new file mode 100644 index 000000000000..5fd94b7465d4 --- /dev/null +++ b/hadoop-ozone/dist/src/main/smoketest/security/ozone-secure-sts-multitenant.robot @@ -0,0 +1,338 @@ +# 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. + +*** Settings *** +Documentation Smoke test for S3 STS AssumeRole + Temp Creds (Multi-Tenant Scenario) +Resource ./ozone-secure-sts.resource +Resource ../admincli/lib.resource +Test Timeout 10 minutes + +*** Variables *** +${TENANT_ONE} sts-tenant-one +${TENANT_TWO} sts-tenant-two +${TENANT_THREE} sts-tenant-three +${USER_A} svc-iceberg-userA +${USER_B} svc-iceberg-userB +${TENANT_ONE_ROLE} sts-tenant-one-role +${TENANT_TWO_ROLE} sts-tenant-two-role +${TENANT_THREE_ROLE} sts-tenant-three-role +${TENANT_ONE_ICEBERG_BUCKET} iceberg-tenant-one-bucket +${TENANT_TWO_ICEBERG_BUCKET} iceberg-tenant-two-bucket +${TENANT_THREE_ICEBERG_BUCKET} iceberg-tenant-three-bucket +${TENANT_TWO_ANOTHER_BUCKET} tenant-two-another-bucket +${TENANT_ONE_LINKED_BUCKET} tenant-one-a-linked-bucket +${ICEBERG_BUCKET_TESTFILE} testfile23 +${ANOTHER_BUCKET_TESTFILE} testfile00 +${OM_ADMIN_USER} hdfs + +*** Keywords *** +Update Resource Policy + [Arguments] ${policy_name} ${tenant_id} ${policy_item_json} + # Fetch the existing policy json created from the ozone tenant commands + ${policy} = Execute curl --fail --silent --show-error --location --netrc --request GET --header "accept: application/json" "${RANGER_ENDPOINT_URL}/service/public/v2/api/service/dev_ozone/policy/${policy_name}" + # Get policy id, then update by id + ${policy_id} = Execute printf '%s' '${policy}' | jq -r '.id' + # Update the policyItem with the supplied ${policy_item_json} + ${updated} = Execute printf '%s' '${policy}' | jq '.policyItems += ${policy_item_json}' + ${result} = Execute curl --fail --include --location --netrc -X PUT -H "Content-Type: application/json" -H "accept: application/json" --data '${updated}' "${RANGER_ENDPOINT_URL}/service/public/v2/api/policy/${policy_id}" + Should Contain ${result} HTTP/1.1 200 + +*** Test Cases *** +Create Users in Ranger + ${user_json} = Set Variable { "loginId": "${USER_A}", "name": "${USER_A}", "password": "Password123", "firstName": "User A Iceberg REST", "lastName": "Catalog", "emailAddress": "${USER_A}@example.com", "userRoleList": ["ROLE_USER"], "userPermList": [ { "moduleId": 1, "isAllowed": 1 }, { "moduleId": 3, "isAllowed": 1 }, { "moduleId": 7, "isAllowed": 1 } ] } + Create Ranger User ${user_json} + ${user_json} = Set Variable { "loginId": "${USER_B}", "name": "${USER_B}", "password": "Password123", "firstName": "User B Iceberg REST", "lastName": "Catalog", "emailAddress": "${USER_B}@example.com", "userRoleList": ["ROLE_USER"], "userPermList": [ { "moduleId": 1, "isAllowed": 1 }, { "moduleId": 3, "isAllowed": 1 }, { "moduleId": 7, "isAllowed": 1 } ] } + Create Ranger User ${user_json} + +Create Tenants + Kinit test user ${OM_ADMIN_USER} ${OM_ADMIN_USER}.keytab + ${output} = Execute ozone tenant --verbose create ${TENANT_ONE} + Should contain ${output} "tenantId" : "${TENANT_ONE}" + ${output} = Execute ozone tenant --verbose create ${TENANT_TWO} + Should contain ${output} "tenantId" : "${TENANT_TWO}" + ${output} = Execute ozone tenant --verbose create ${TENANT_THREE} + Should contain ${output} "tenantId" : "${TENANT_THREE}" + +Assign Users to Tenants + ${output} = Execute ozone tenant --verbose user assign ${USER_A} --tenant=${TENANT_ONE} + Should contain ${output} Assigned '${USER_A}' to '${TENANT_ONE}' + ${accessKeyId} = Get Regexp Matches ${output} (?<=export AWS_ACCESS_KEY_ID=).* + ${secretKey} = Get Regexp Matches ${output} (?<=export AWS_SECRET_ACCESS_KEY=).* + ${accessKeyId} = Set Variable ${accessKeyId[0]} + ${secretKey} = Set Variable ${secretKey[0]} + Set Global Variable ${USER_A_T1_PERM_ACCESS_KEY_ID} ${accessKeyId} + Set Global Variable ${USER_A_T1_PERM_SECRET_KEY} ${secretKey} + + ${output} = Execute ozone tenant --verbose user assign ${USER_A} --tenant=${TENANT_TWO} + Should contain ${output} Assigned '${USER_A}' to '${TENANT_TWO}' + ${accessKeyId} = Get Regexp Matches ${output} (?<=export AWS_ACCESS_KEY_ID=).* + ${secretKey} = Get Regexp Matches ${output} (?<=export AWS_SECRET_ACCESS_KEY=).* + ${accessKeyId} = Set Variable ${accessKeyId[0]} + ${secretKey} = Set Variable ${secretKey[0]} + Set Global Variable ${USER_A_T2_PERM_ACCESS_KEY_ID} ${accessKeyId} + Set Global Variable ${USER_A_T2_PERM_SECRET_KEY} ${secretKey} + + ${output} = Execute ozone tenant --verbose user assign ${USER_B} --tenant=${TENANT_THREE} + Should contain ${output} Assigned '${USER_B}' to '${TENANT_THREE}' + ${accessKeyId} = Get Regexp Matches ${output} (?<=export AWS_ACCESS_KEY_ID=).* + ${secretKey} = Get Regexp Matches ${output} (?<=export AWS_SECRET_ACCESS_KEY=).* + ${accessKeyId} = Set Variable ${accessKeyId[0]} + ${secretKey} = Set Variable ${secretKey[0]} + Set Global Variable ${USER_B_T3_PERM_ACCESS_KEY_ID} ${accessKeyId} + Set Global Variable ${USER_B_T3_PERM_SECRET_KEY} ${secretKey} + +Create Roles in Ranger + ${role_json} = Set Variable { "name": "${TENANT_ONE_ROLE}", "description": "Tenant One Role" } + Create Ranger Role ${role_json} + ${role_json} = Set Variable { "name": "${TENANT_TWO_ROLE}", "description": "Tenant Two Role" } + Create Ranger Role ${role_json} + ${role_json} = Set Variable { "name": "${TENANT_THREE_ROLE}", "description": "Tenant Three Role" } + Create Ranger Role ${role_json} + +Create Assume Role Policies + # This policy gives '${USER_A}' user ASSUME_ROLE permission on role '${TENANT_ONE_ROLE}' + ${policy_json} = Set Variable { "isEnabled": true, "service": "dev_ozone", "name": "${TENANT_ONE_ROLE} assume role policy", "policyType": 0, "policyPriority": 0, "isAuditEnabled": true, "resources": { "role": { "values": ["${TENANT_ONE_ROLE}"],"isExcludes": false, "isRecursive": false } }, "policyItems": [ { "accesses": [ { "type": "assume_role", "isAllowed": true } ], "users": [ "${USER_A}" ], "delegateAdmin": false } ], "serviceType": "ozone", "isDenyAllElse": false } + Create Ranger Policy ${policy_json} + + # This policy gives '${USER_A}' user ASSUME_ROLE permission on role '${TENANT_TWO_ROLE}' + ${policy_json} = Set Variable { "isEnabled": true, "service": "dev_ozone", "name": "${TENANT_TWO_ROLE} assume role policy", "policyType": 0, "policyPriority": 0, "isAuditEnabled": true, "resources": { "role": { "values": ["${TENANT_TWO_ROLE}"],"isExcludes": false, "isRecursive": false } }, "policyItems": [ { "accesses": [ { "type": "assume_role", "isAllowed": true } ], "users": [ "${USER_A}" ], "delegateAdmin": false } ], "serviceType": "ozone", "isDenyAllElse": false } + Create Ranger Policy ${policy_json} + + # This policy gives '${USER_B}' user ASSUME_ROLE permission on role '${TENANT_THREE_ROLE}' + ${policy_json} = Set Variable { "isEnabled": true, "service": "dev_ozone", "name": "${TENANT_THREE_ROLE} assume role policy", "policyType": 0, "policyPriority": 0, "isAuditEnabled": true, "resources": { "role": { "values": ["${TENANT_THREE_ROLE}"],"isExcludes": false, "isRecursive": false } }, "policyItems": [ { "accesses": [ { "type": "assume_role", "isAllowed": true } ], "users": [ "${USER_B}" ], "delegateAdmin": false } ], "serviceType": "ozone", "isDenyAllElse": false } + Create Ranger Policy ${policy_json} + +Update Tenant Volume Access policies + # This policy gives '${TENANT_ONE_ROLE}' role READ,LIST permission on volume ${TENANT_ONE}. + # It also gives '${USER_A}' user READ permission on volume ${TENANT_ONE}. + ${policy_item_json} = Set Variable [ { "accesses": [ { "type": "read", "isAllowed": true }, { "type": "list", "isAllowed": true } ], "roles": [ "${TENANT_ONE_ROLE}" ], "delegateAdmin": false }, { "accesses": [ { "type": "read", "isAllowed": true } ], "users": [ "${USER_A}" ], "delegateAdmin": false } ] + Update Resource Policy ${TENANT_ONE}-VolumeAccess ${TENANT_ONE} ${policy_item_json} + + # This policy gives '${TENANT_TWO_ROLE}' role READ,LIST permission on volume ${TENANT_TWO}. + # It also gives '${USER_A}' user READ permission on volume ${TENANT_TWO}. + # It also gives '${TENANT_ONE_ROLE}' role READ permission on volume ${TENANT_TWO} so it can access ${TENANT_ONE}/${TENANT_ONE_LINKED_BUCKET}. + ${policy_item_json} = Set Variable [ { "accesses": [ { "type": "read", "isAllowed": true }, { "type": "list", "isAllowed": true } ], "roles": [ "${TENANT_TWO_ROLE}" ], "delegateAdmin": false }, { "accesses": [ { "type": "read", "isAllowed": true } ], "users": [ "${USER_A}" ], "delegateAdmin": false }, { "accesses": [ { "type": "read", "isAllowed": true } ], "roles": [ "${TENANT_ONE_ROLE}" ], "delegateAdmin": false } ] + Update Resource Policy ${TENANT_TWO}-VolumeAccess ${TENANT_TWO} ${policy_item_json} + + # This policy gives '${TENANT_THREE_ROLE}' role READ,LIST permission on volume ${TENANT_THREE}. + # It also gives '${USER_B}' user READ permission on volume ${TENANT_THREE}. + ${policy_item_json} = Set Variable [ { "accesses": [ { "type": "read", "isAllowed": true }, { "type": "list", "isAllowed": true } ], "roles": [ "${TENANT_THREE_ROLE}" ], "delegateAdmin": false }, { "accesses": [ { "type": "read", "isAllowed": true } ], "users": [ "${USER_B}" ], "delegateAdmin": false } ] + Update Resource Policy ${TENANT_THREE}-VolumeAccess ${TENANT_THREE} ${policy_item_json} + +Create Bucket Access policies + # This policy gives '${TENANT_ONE_ROLE}' role ALL permission on buckets ${TENANT_ONE}/${TENANT_ONE_ICEBERG_BUCKET} + # and ${TENANT_ONE}/${TENANT_ONE_LINKED_BUCKET}. + # It also gives '${USER_A}' user READ, CREATE permissions on bucket ${TENANT_ONE}/${TENANT_ONE_ICEBERG_BUCKET}. + ${policy_json} = Set Variable { "isEnabled": true, "service": "dev_ozone", "name": "${TENANT_ONE} ${TENANT_ONE_ICEBERG_BUCKET} and ${TENANT_ONE_LINKED_BUCKET} access", "policyType": 0, "policyPriority": 0, "isAuditEnabled": true, "resources": { "volume": { "values": [ "${TENANT_ONE}" ], "isExcludes": false, "isRecursive": false }, "bucket": { "values": [ "${TENANT_ONE_ICEBERG_BUCKET}", "${TENANT_ONE_LINKED_BUCKET}" ], "isExcludes": false, "isRecursive": false } }, "policyItems": [ { "accesses": [ { "type": "all", "isAllowed": true } ], "roles": [ "${TENANT_ONE_ROLE}" ], "delegateAdmin": false }, { "accesses": [ { "type": "read", "isAllowed": true }, { "type": "create", "isAllowed": true } ], "users": [ "${USER_A}" ], "delegateAdmin": false } ], "serviceType": "ozone", "isDenyAllElse": false } + Create Ranger Policy ${policy_json} + + # This policy gives '${TENANT_TWO_ROLE}' role ALL permission on bucket ${TENANT_TWO}/${TENANT_TWO_ICEBERG_BUCKET}. + # It also gives '${USER_A}' user READ, CREATE permissions on bucket ${TENANT_TWO}/${TENANT_TWO_ICEBERG_BUCKET}. + ${policy_json} = Set Variable { "isEnabled": true, "service": "dev_ozone", "name": "${TENANT_TWO} ${TENANT_TWO_ICEBERG_BUCKET} access", "policyType": 0, "policyPriority": 0, "isAuditEnabled": true, "resources": { "volume": { "values": [ "${TENANT_TWO}" ], "isExcludes": false, "isRecursive": false }, "bucket": { "values": [ "${TENANT_TWO_ICEBERG_BUCKET}" ], "isExcludes": false, "isRecursive": false } }, "policyItems": [ { "accesses": [ { "type": "all", "isAllowed": true } ], "roles": [ "${TENANT_TWO_ROLE}" ], "delegateAdmin": false }, { "accesses": [ { "type": "read", "isAllowed": true }, { "type": "create", "isAllowed": true } ], "users": [ "${USER_A}" ], "delegateAdmin": false } ], "serviceType": "ozone", "isDenyAllElse": false } + Create Ranger Policy ${policy_json} + + # This policy gives '${TENANT_THREE_ROLE}' role ALL permission on bucket ${TENANT_THREE}/${TENANT_THREE_ICEBERG_BUCKET}. + # It also gives '${USER_B}' user READ, CREATE permissions on bucket ${TENANT_THREE}/${TENANT_THREE_ICEBERG_BUCKET}. + ${policy_json} = Set Variable { "isEnabled": true, "service": "dev_ozone", "name": "${TENANT_THREE} ${TENANT_THREE_ICEBERG_BUCKET} access", "policyType": 0, "policyPriority": 0, "isAuditEnabled": true, "resources": { "volume": { "values": [ "${TENANT_THREE}" ], "isExcludes": false, "isRecursive": false }, "bucket": { "values": [ "${TENANT_THREE_ICEBERG_BUCKET}" ], "isExcludes": false, "isRecursive": false } }, "policyItems": [ { "accesses": [ { "type": "all", "isAllowed": true } ], "roles": [ "${TENANT_THREE_ROLE}" ], "delegateAdmin": false }, { "accesses": [ { "type": "read", "isAllowed": true }, { "type": "create", "isAllowed": true } ], "users": [ "${USER_B}" ], "delegateAdmin": false } ], "serviceType": "ozone", "isDenyAllElse": false } + Create Ranger Policy ${policy_json} + + # This policy gives '${TENANT_ONE_ROLE}' role ALL permission on bucket ${TENANT_TWO}/${TENANT_TWO_ANOTHER_BUCKET}. + # It also gives '${USER_A}' user READ, CREATE permissions on bucket ${TENANT_TWO}/${TENANT_TWO_ANOTHER_BUCKET}. + ${policy_json} = Set Variable { "isEnabled": true, "service": "dev_ozone", "name": "${TENANT_TWO} ${TENANT_TWO_ANOTHER_BUCKET} access", "policyType": 0, "policyPriority": 0, "isAuditEnabled": true, "resources": { "volume": { "values": [ "${TENANT_TWO}" ], "isExcludes": false, "isRecursive": false }, "bucket": { "values": [ "${TENANT_TWO_ANOTHER_BUCKET}" ], "isExcludes": false, "isRecursive": false } }, "policyItems": [ { "accesses": [ { "type": "all", "isAllowed": true } ], "roles": [ "${TENANT_ONE_ROLE}" ], "delegateAdmin": false }, { "accesses": [ { "type": "read", "isAllowed": true }, { "type": "create", "isAllowed": true } ], "users": [ "${USER_A}" ], "delegateAdmin": false } ], "serviceType": "ozone", "isDenyAllElse": false } + Create Ranger Policy ${policy_json} + +Create Iceberg Bucket and Another Bucket Table Access policies + # This policy gives '${TENANT_ONE_ROLE}' role ALL permission on keys ${TENANT_ONE}/${TENANT_ONE_ICEBERG_BUCKET}/* + # and keys ${TENANT_ONE}/${TENANT_ONE_LINKED_BUCKET}/*. + ${policy_json} = Set Variable { "isEnabled": true, "service": "dev_ozone", "name": "${TENANT_ONE} ${TENANT_ONE_ICEBERG_BUCKET} and ${TENANT_ONE_LINKED_BUCKET} table access", "policyType": 0, "policyPriority": 0, "isAuditEnabled": true, "resources": { "volume": { "values": [ "${TENANT_ONE}" ], "isExcludes": false, "isRecursive": false }, "bucket": { "values": [ "${TENANT_ONE_ICEBERG_BUCKET}", "${TENANT_ONE_LINKED_BUCKET}" ], "isExcludes": false, "isRecursive": false }, "key": { "values": [ "*" ], "isExcludes": false, "isRecursive": true } }, "policyItems": [ { "accesses": [ { "type": "all", "isAllowed": true } ], "roles": [ "${TENANT_ONE_ROLE}" ], "delegateAdmin": false } ], "serviceType": "ozone", "isDenyAllElse": false } + Create Ranger Policy ${policy_json} + + # This policy gives '${TENANT_TWO_ROLE}' role ALL permission on keys ${TENANT_TWO}/${TENANT_TWO_ICEBERG_BUCKET}/*. + ${policy_json} = Set Variable { "isEnabled": true, "service": "dev_ozone", "name": "${TENANT_TWO} ${TENANT_TWO_ICEBERG_BUCKET} table access", "policyType": 0, "policyPriority": 0, "isAuditEnabled": true, "resources": { "volume": { "values": [ "${TENANT_TWO}" ], "isExcludes": false, "isRecursive": false }, "bucket": { "values": [ "${TENANT_TWO_ICEBERG_BUCKET}" ], "isExcludes": false, "isRecursive": false }, "key": { "values": [ "*" ], "isExcludes": false, "isRecursive": true } }, "policyItems": [ { "accesses": [ { "type": "all", "isAllowed": true } ], "roles": [ "${TENANT_TWO_ROLE}" ], "delegateAdmin": false } ], "serviceType": "ozone", "isDenyAllElse": false } + Create Ranger Policy ${policy_json} + + # This policy gives '${TENANT_THREE_ROLE}' role ALL permission on keys ${TENANT_THREE}/${TENANT_THREE_ICEBERG_BUCKET}/*. + ${policy_json} = Set Variable { "isEnabled": true, "service": "dev_ozone", "name": "${TENANT_THREE} ${TENANT_THREE_ICEBERG_BUCKET} table access", "policyType": 0, "policyPriority": 0, "isAuditEnabled": true, "resources": { "volume": { "values": [ "${TENANT_THREE}" ], "isExcludes": false, "isRecursive": false }, "bucket": { "values": [ "${TENANT_THREE_ICEBERG_BUCKET}" ], "isExcludes": false, "isRecursive": false }, "key": { "values": [ "*" ], "isExcludes": false, "isRecursive": true } }, "policyItems": [ { "accesses": [ { "type": "all", "isAllowed": true } ], "roles": [ "${TENANT_THREE_ROLE}" ], "delegateAdmin": false } ], "serviceType": "ozone", "isDenyAllElse": false } + Create Ranger Policy ${policy_json} + + # This policy gives '${TENANT_ONE_ROLE}' role ALL permission on keys ${TENANT_TWO}/${TENANT_TWO_ANOTHER_BUCKET}/*. + ${policy_json} = Set Variable { "isEnabled": true, "service": "dev_ozone", "name": "${TENANT_TWO} ${TENANT_TWO_ANOTHER_BUCKET} table access", "policyType": 0, "policyPriority": 0, "isAuditEnabled": true, "resources": { "volume": { "values": [ "${TENANT_TWO}" ], "isExcludes": false, "isRecursive": false }, "bucket": { "values": [ "${TENANT_TWO_ANOTHER_BUCKET}" ], "isExcludes": false, "isRecursive": false }, "key": { "values": [ "*" ], "isExcludes": false, "isRecursive": true } }, "policyItems": [ { "accesses": [ { "type": "all", "isAllowed": true } ], "roles": [ "${TENANT_ONE_ROLE}" ], "delegateAdmin": false } ], "serviceType": "ozone", "isDenyAllElse": false } + Create Ranger Policy ${policy_json} + + # Update Ranger policy cache + Kinit test user ${OM_ADMIN_USER} ${OM_ADMIN_USER}.keytab + ${om_param} = Get OM Service Param + ${output} = Execute ozone admin om updateranger ${om_param} + Should contain ${output} Operation completed successfully + +Get S3 Credentials for Principals, Create Buckets, and Upload Files to Buckets + Kinit test user ${USER_A} ${USER_A}.keytab + + # Waiting for Ranger policy cache refresh - ${USER_A} needs to be able to read ${TENANT_ONE} volume + Wait Until Keyword Succeeds 30s 5s Execute ozone sh volume info ${TENANT_ONE} + + # Kinit OM_ADMIN_USER that has access to all volumes/buckets per Ranger default policies + Kinit test user ${OM_ADMIN_USER} ${OM_ADMIN_USER}.keytab + + # Tenant 1 data + Execute ozone sh bucket create /${TENANT_ONE}/${TENANT_ONE_ICEBERG_BUCKET} + Create File ${TEMP_DIR}/${ICEBERG_BUCKET_TESTFILE} + Execute ozone sh key put /${TENANT_ONE}/${TENANT_ONE_ICEBERG_BUCKET}/${ICEBERG_BUCKET_TESTFILE} ${TEMP_DIR}/${ICEBERG_BUCKET_TESTFILE} + + # Tenant 2 data and linked bucket + Execute ozone sh bucket create /${TENANT_TWO}/${TENANT_TWO_ICEBERG_BUCKET} + Execute ozone sh key put /${TENANT_TWO}/${TENANT_TWO_ICEBERG_BUCKET}/${ICEBERG_BUCKET_TESTFILE} ${TEMP_DIR}/${ICEBERG_BUCKET_TESTFILE} + Execute ozone sh bucket create /${TENANT_TWO}/${TENANT_TWO_ANOTHER_BUCKET} + Create File ${TEMP_DIR}/${ANOTHER_BUCKET_TESTFILE} + Execute ozone sh key put /${TENANT_TWO}/${TENANT_TWO_ANOTHER_BUCKET}/${ANOTHER_BUCKET_TESTFILE} ${TEMP_DIR}/${ANOTHER_BUCKET_TESTFILE} + # Link ${TENANT_ONE}/${TENANT_ONE_LINKED_BUCKET} to ${TENANT_TWO}/${TENANT_TWO_ANOTHER_BUCKET} + Execute ozone sh bucket link /${TENANT_TWO}/${TENANT_TWO_ANOTHER_BUCKET} /${TENANT_ONE}/${TENANT_ONE_LINKED_BUCKET} + Execute ozone sh key put /${TENANT_ONE}/${TENANT_ONE_LINKED_BUCKET}/${ANOTHER_BUCKET_TESTFILE} ${TEMP_DIR}/${ANOTHER_BUCKET_TESTFILE} + + # Tenant 3 data + Execute ozone sh bucket create /${TENANT_THREE}/${TENANT_THREE_ICEBERG_BUCKET} + Execute ozone sh key put /${TENANT_THREE}/${TENANT_THREE_ICEBERG_BUCKET}/${ICEBERG_BUCKET_TESTFILE} ${TEMP_DIR}/${ICEBERG_BUCKET_TESTFILE} + +Create Role-Scoped Tokens for All Three Tenants + Set Global Variable ${ROLE_ARN} arn:aws:iam::123456789012:role/${TENANT_ONE_ROLE} + Assume Role And Get Temporary Credentials perm_access_key_id=${USER_A_T1_PERM_ACCESS_KEY_ID} perm_secret_key=${USER_A_T1_PERM_SECRET_KEY} + Set Global Variable ${USER_A_T1_STS_ACCESS_KEY_ID} ${STS_ACCESS_KEY_ID} + Set Global Variable ${USER_A_T1_STS_SECRET_KEY} ${STS_SECRET_KEY} + Set Global Variable ${USER_A_T1_STS_SESSION_TOKEN} ${STS_SESSION_TOKEN} + + Set Global Variable ${ROLE_ARN} arn:aws:iam::123456789012:role/${TENANT_TWO_ROLE} + Assume Role And Get Temporary Credentials perm_access_key_id=${USER_A_T2_PERM_ACCESS_KEY_ID} perm_secret_key=${USER_A_T2_PERM_SECRET_KEY} + Set Global Variable ${USER_A_T2_STS_ACCESS_KEY_ID} ${STS_ACCESS_KEY_ID} + Set Global Variable ${USER_A_T2_STS_SECRET_KEY} ${STS_SECRET_KEY} + Set Global Variable ${USER_A_T2_STS_SESSION_TOKEN} ${STS_SESSION_TOKEN} + + Set Global Variable ${ROLE_ARN} arn:aws:iam::123456789012:role/${TENANT_THREE_ROLE} + Assume Role And Get Temporary Credentials perm_access_key_id=${USER_B_T3_PERM_ACCESS_KEY_ID} perm_secret_key=${USER_B_T3_PERM_SECRET_KEY} + Set Global Variable ${USER_B_T3_STS_ACCESS_KEY_ID} ${STS_ACCESS_KEY_ID} + Set Global Variable ${USER_B_T3_STS_SECRET_KEY} ${STS_SECRET_KEY} + Set Global Variable ${USER_B_T3_STS_SESSION_TOKEN} ${STS_SESSION_TOKEN} + +Verify Role-Scoped Token Accesses + Configure STS Profile ${USER_A_T1_STS_ACCESS_KEY_ID} ${USER_A_T1_STS_SECRET_KEY} ${USER_A_T1_STS_SESSION_TOKEN} + + # This token should be able to read from ${TENANT_ONE}/${TENANT_ONE_ICEBERG_BUCKET} but not ${TENANT_TWO}/${TENANT_TWO_ICEBERG_BUCKET} + # nor ${TENANT_THREE}/${TENANT_THREE_ICEBERG_BUCKET}. Also verify that it can write to ${TENANT_ONE}/${TENANT_ONE_ICEBERG_BUCKET}. + Get Object Should Succeed ${TENANT_ONE_ICEBERG_BUCKET} ${ICEBERG_BUCKET_TESTFILE} + Get Object Should Fail ${TENANT_TWO_ICEBERG_BUCKET} ${ICEBERG_BUCKET_TESTFILE} NoSuchBucket + Get Object Should Fail ${TENANT_THREE_ICEBERG_BUCKET} ${ICEBERG_BUCKET_TESTFILE} NoSuchBucket + Put Object Should Succeed ${TENANT_ONE_ICEBERG_BUCKET} ${ICEBERG_BUCKET_TESTFILE} + + # This token should be able to read from/write to ${TENANT_ONE}/${TENANT_ONE_LINKED_BUCKET} which is linked to + # ${TENANT_TWO}/${TENANT_TWO_ANOTHER_BUCKET}. It should NOT be able to read from/write to ${TENANT_TWO}/${TENANT_TWO_ANOTHER_BUCKET} + # even though the ${TENANT_ONE_ROLE} has access because the permanent credential only has access to ${TENANT_ONE} volume. + Get Object Should Succeed ${TENANT_ONE_LINKED_BUCKET} ${ANOTHER_BUCKET_TESTFILE} + Put Object Should Succeed ${TENANT_ONE_LINKED_BUCKET} ${ANOTHER_BUCKET_TESTFILE} + Get Object Should Fail ${TENANT_TWO_ANOTHER_BUCKET} ${ANOTHER_BUCKET_TESTFILE} NoSuchBucket + Put Object Should Fail ${TENANT_TWO_ANOTHER_BUCKET} ${ANOTHER_BUCKET_TESTFILE} NoSuchBucket + + Configure STS Profile ${USER_A_T2_STS_ACCESS_KEY_ID} ${USER_A_T2_STS_SECRET_KEY} ${USER_A_T2_STS_SESSION_TOKEN} + + # This token should be able to read from ${TENANT_TWO}/${TENANT_TWO_ICEBERG_BUCKET} but not ${TENANT_ONE}/${TENANT_ONE_ICEBERG_BUCKET} + # nor ${TENANT_TWO}/${TENANT_TWO_ANOTHER_BUCKET} nor ${TENANT_THREE}/${TENANT_THREE_ICEBERG_BUCKET} + # nor ${TENANT_ONE}/${TENANT_ONE_LINKED_BUCKET}. + # Also verify that it can write to ${TENANT_TWO}/${TENANT_TWO_ICEBERG_BUCKET}. + Get Object Should Succeed ${TENANT_TWO_ICEBERG_BUCKET} ${ICEBERG_BUCKET_TESTFILE} + Get Object Should Fail ${TENANT_ONE_ICEBERG_BUCKET} ${ICEBERG_BUCKET_TESTFILE} NoSuchBucket + Get Object Should Fail ${TENANT_TWO_ANOTHER_BUCKET} ${ANOTHER_BUCKET_TESTFILE} AccessDenied + Get Object Should Fail ${TENANT_THREE_ICEBERG_BUCKET} ${ICEBERG_BUCKET_TESTFILE} NoSuchBucket + Get Object Should Fail ${TENANT_ONE_LINKED_BUCKET} ${ANOTHER_BUCKET_TESTFILE} NoSuchBucket + Put Object Should Succeed ${TENANT_TWO_ICEBERG_BUCKET} ${ICEBERG_BUCKET_TESTFILE} + + Configure STS Profile ${USER_B_T3_STS_ACCESS_KEY_ID} ${USER_B_T3_STS_SECRET_KEY} ${USER_B_T3_STS_SESSION_TOKEN} + + # This token should be able to read from ${TENANT_THREE}/${TENANT_THREE_ICEBERG_BUCKET} but not ${TENANT_ONE}/${TENANT_ONE_ICEBERG_BUCKET} + # nor ${TENANT_TWO}/${TENANT_TWO_ICEBERG_BUCKET} nor ${TENANT_TWO}/${TENANT_TWO_ANOTHER_BUCKET} + # nor ${TENANT_ONE}/${TENANT_ONE_LINKED_BUCKET}. + # Also verify that it can write to ${TENANT_THREE}/${TENANT_THREE_ICEBERG_BUCKET}. + Get Object Should Succeed ${TENANT_THREE_ICEBERG_BUCKET} ${ICEBERG_BUCKET_TESTFILE} + Get Object Should Fail ${TENANT_ONE_ICEBERG_BUCKET} ${ICEBERG_BUCKET_TESTFILE} NoSuchBucket + Get Object Should Fail ${TENANT_TWO_ICEBERG_BUCKET} ${ICEBERG_BUCKET_TESTFILE} NoSuchBucket + Get Object Should Fail ${TENANT_TWO_ANOTHER_BUCKET} ${ANOTHER_BUCKET_TESTFILE} NoSuchBucket + Get Object Should Fail ${TENANT_ONE_LINKED_BUCKET} ${ANOTHER_BUCKET_TESTFILE} NoSuchBucket + Put Object Should Succeed ${TENANT_THREE_ICEBERG_BUCKET} ${ICEBERG_BUCKET_TESTFILE} + +Create Limited-Scoped Tokens for All Three Tenants + # Limit scope to read-only for keys in ${TENANT_ONE_ICEBERG_BUCKET} (note ${TENANT_ONE_LINKED_BUCKET} is excluded) + ${session_policy} = Set Variable {"Version":"2012-10-17","Statement":[{"Effect":"Allow","Action":"s3:GetObject","Resource": "arn:aws:s3:::${TENANT_ONE_ICEBERG_BUCKET}/*" }]} + Set Global Variable ${ROLE_ARN} arn:aws:iam::123456789012:role/${TENANT_ONE_ROLE} + Assume Role And Get Temporary Credentials policy_json=${session_policy} perm_access_key_id=${USER_A_T1_PERM_ACCESS_KEY_ID} perm_secret_key=${USER_A_T1_PERM_SECRET_KEY} + Set Global Variable ${USER_A_T1_STS_ACCESS_KEY_ID} ${STS_ACCESS_KEY_ID} + Set Global Variable ${USER_A_T1_STS_SECRET_KEY} ${STS_SECRET_KEY} + Set Global Variable ${USER_A_T1_STS_SESSION_TOKEN} ${STS_SESSION_TOKEN} + + # Limit scope to read-only for keys in ${TENANT_TWO_ICEBERG_BUCKET} + ${session_policy} = Set Variable {"Version":"2012-10-17","Statement":[{"Effect":"Allow","Action":"s3:GetObject","Resource":"arn:aws:s3:::${TENANT_TWO_ICEBERG_BUCKET}/*"}]} + Set Global Variable ${ROLE_ARN} arn:aws:iam::123456789012:role/${TENANT_TWO_ROLE} + Assume Role And Get Temporary Credentials policy_json=${session_policy} perm_access_key_id=${USER_A_T2_PERM_ACCESS_KEY_ID} perm_secret_key=${USER_A_T2_PERM_SECRET_KEY} + Set Global Variable ${USER_A_T2_STS_ACCESS_KEY_ID} ${STS_ACCESS_KEY_ID} + Set Global Variable ${USER_A_T2_STS_SECRET_KEY} ${STS_SECRET_KEY} + Set Global Variable ${USER_A_T2_STS_SESSION_TOKEN} ${STS_SESSION_TOKEN} + + # Limit scope to read-only for ${TENANT_THREE_ICEBERG_BUCKET} keys + ${session_policy} = Set Variable {"Version":"2012-10-17","Statement":[{"Effect":"Allow","Action":"s3:GetObject","Resource":"arn:aws:s3:::${TENANT_THREE_ICEBERG_BUCKET}/*"}]} + Set Global Variable ${ROLE_ARN} arn:aws:iam::123456789012:role/${TENANT_THREE_ROLE} + Assume Role And Get Temporary Credentials policy_json=${session_policy} perm_access_key_id=${USER_B_T3_PERM_ACCESS_KEY_ID} perm_secret_key=${USER_B_T3_PERM_SECRET_KEY} + Set Global Variable ${USER_B_T3_STS_ACCESS_KEY_ID} ${STS_ACCESS_KEY_ID} + Set Global Variable ${USER_B_T3_STS_SECRET_KEY} ${STS_SECRET_KEY} + Set Global Variable ${USER_B_T3_STS_SESSION_TOKEN} ${STS_SESSION_TOKEN} + +Verify Limited-Scoped Token Accesses + Configure STS Profile ${USER_A_T1_STS_ACCESS_KEY_ID} ${USER_A_T1_STS_SECRET_KEY} ${USER_A_T1_STS_SESSION_TOKEN} + + # This token should be able to read from ${TENANT_ONE}/${TENANT_ONE_ICEBERG_BUCKET} but not ${TENANT_TWO}/${TENANT_TWO_ICEBERG_BUCKET} + # nor ${TENANT_THREE}/${TENANT_THREE_ICEBERG_BUCKET}. Also verify that it CANNOT write to ${TENANT_ONE}/${TENANT_ONE_ICEBERG_BUCKET}. + Get Object Should Succeed ${TENANT_ONE_ICEBERG_BUCKET} ${ICEBERG_BUCKET_TESTFILE} + Get Object Should Fail ${TENANT_TWO_ICEBERG_BUCKET} ${ICEBERG_BUCKET_TESTFILE} NoSuchBucket + Get Object Should Fail ${TENANT_THREE_ICEBERG_BUCKET} ${ICEBERG_BUCKET_TESTFILE} NoSuchBucket + Put Object Should Fail ${TENANT_ONE_ICEBERG_BUCKET} ${ICEBERG_BUCKET_TESTFILE} AccessDenied + + # This token should NOT be able to read from/write to ${TENANT_ONE}/${TENANT_ONE_LINKED_BUCKET} (because of the session policy) which is linked to + # ${TENANT_TWO}/${TENANT_TWO_ANOTHER_BUCKET}. It should not be able to read from/write to ${TENANT_TWO}/${TENANT_TWO_ANOTHER_BUCKET} + # even though the ${TENANT_ONE_ROLE} has access because the permanent credential only has access to ${TENANT_ONE}. + Get Object Should Fail ${TENANT_ONE_LINKED_BUCKET} ${ANOTHER_BUCKET_TESTFILE} AccessDenied + Put Object Should Fail ${TENANT_ONE_LINKED_BUCKET} ${ANOTHER_BUCKET_TESTFILE} AccessDenied + Get Object Should Fail ${TENANT_TWO_ANOTHER_BUCKET} ${ANOTHER_BUCKET_TESTFILE} NoSuchBucket + Put Object Should Fail ${TENANT_TWO_ANOTHER_BUCKET} ${ANOTHER_BUCKET_TESTFILE} NoSuchBucket + + Configure STS Profile ${USER_A_T2_STS_ACCESS_KEY_ID} ${USER_A_T2_STS_SECRET_KEY} ${USER_A_T2_STS_SESSION_TOKEN} + + # This token should be able to read from ${TENANT_TWO}/${TENANT_TWO_ICEBERG_BUCKET} but not ${TENANT_ONE}/${TENANT_ONE_ICEBERG_BUCKET} + # nor ${TENANT_TWO}/${TENANT_TWO_ANOTHER_BUCKET} nor ${TENANT_THREE}/${TENANT_THREE_ICEBERG_BUCKET} + # nor ${TENANT_ONE}/${TENANT_ONE_LINKED_BUCKET}. + # Also verify that it CANNOT write to ${TENANT_TWO}/${TENANT_TWO_ICEBERG_BUCKET}. + Get Object Should Succeed ${TENANT_TWO_ICEBERG_BUCKET} ${ICEBERG_BUCKET_TESTFILE} + Get Object Should Fail ${TENANT_ONE_ICEBERG_BUCKET} ${ICEBERG_BUCKET_TESTFILE} NoSuchBucket + Get Object Should Fail ${TENANT_TWO_ANOTHER_BUCKET} ${ANOTHER_BUCKET_TESTFILE} AccessDenied + Get Object Should Fail ${TENANT_THREE_ICEBERG_BUCKET} ${ICEBERG_BUCKET_TESTFILE} NoSuchBucket + Get Object Should Fail ${TENANT_ONE_LINKED_BUCKET} ${ANOTHER_BUCKET_TESTFILE} NoSuchBucket + Put Object Should Fail ${TENANT_TWO_ICEBERG_BUCKET} ${ICEBERG_BUCKET_TESTFILE} AccessDenied + + Configure STS Profile ${USER_B_T3_STS_ACCESS_KEY_ID} ${USER_B_T3_STS_SECRET_KEY} ${USER_B_T3_STS_SESSION_TOKEN} + + # This token should be able to read from ${TENANT_THREE}/${TENANT_THREE_ICEBERG_BUCKET} but not ${TENANT_ONE}/${TENANT_ONE_ICEBERG_BUCKET} + # nor ${TENANT_TWO}/${TENANT_TWO_ICEBERG_BUCKET} nor ${TENANT_TWO}/${TENANT_TWO_ANOTHER_BUCKET} + # nor ${TENANT_ONE}/${TENANT_ONE_LINKED_BUCKET}. + # Also verify that it CANNOT write to ${TENANT_THREE}/${TENANT_THREE_ICEBERG_BUCKET}. + Get Object Should Succeed ${TENANT_THREE_ICEBERG_BUCKET} ${ICEBERG_BUCKET_TESTFILE} + Get Object Should Fail ${TENANT_ONE_ICEBERG_BUCKET} ${ICEBERG_BUCKET_TESTFILE} NoSuchBucket + Get Object Should Fail ${TENANT_TWO_ICEBERG_BUCKET} ${ICEBERG_BUCKET_TESTFILE} NoSuchBucket + Get Object Should Fail ${TENANT_TWO_ANOTHER_BUCKET} ${ANOTHER_BUCKET_TESTFILE} NoSuchBucket + Get Object Should Fail ${TENANT_ONE_LINKED_BUCKET} ${ANOTHER_BUCKET_TESTFILE} NoSuchBucket + Put Object Should Fail ${TENANT_THREE_ICEBERG_BUCKET} ${ICEBERG_BUCKET_TESTFILE} AccessDenied 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 new file mode 100644 index 000000000000..04bb9c5b5869 --- /dev/null +++ b/hadoop-ozone/dist/src/main/smoketest/security/ozone-secure-sts.resource @@ -0,0 +1,112 @@ +# 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. + +*** Settings *** +Library OperatingSystem +Library String +Library BuiltIn +Library DateTime +Resource ../commonlib.robot +Resource ../s3/commonawslib.robot + +*** Variables *** +${RANGER_ENDPOINT_URL} ${EMPTY} +${STS_ENDPOINT_URL} http://s3g:9880/sts +${S3G_ENDPOINT_URL} http://s3g:9878 +${ROLE_SESSION_NAME} sts-session-name + +*** Keywords *** +Configure AWS Profile + [Arguments] ${profile} ${access_key} ${secret_key} ${session_token}=${EMPTY} ${region}=us-east-1 + Run Keyword Install aws cli + Execute aws configure set aws_access_key_id ${access_key} --profile ${profile} + Execute aws configure set aws_secret_access_key ${secret_key} --profile ${profile} + Execute aws configure set region ${region} --profile ${profile} + Run Keyword If '${session_token}' != '${EMPTY}' Execute aws configure set aws_session_token ${session_token} --profile ${profile} + +Configure STS Profile + [Arguments] ${access_key} ${secret_key} ${session_token} + Configure AWS Profile sts ${access_key} ${secret_key} ${session_token} + +Create Ranger Artifact + [Arguments] ${json} ${endpoint_url} + Pass Execution If '${RANGER_ENDPOINT_URL}' == '' No Ranger + ${result} = Execute curl --fail --include --location --netrc --request POST --header "Content-Type: application/json" --header "accept: application/json" --data '${json}' '${endpoint_url}' + Should Contain ${result} HTTP/1.1 200 + +Create Ranger User + [Arguments] ${user_json} + # Note: the /service/xusers/secure/users endpoint must be used below so that the userPermList can be set. Without + # the userPermList being set, the user cannot be added to a Ranger policy. + Create Ranger Artifact ${user_json} '${RANGER_ENDPOINT_URL}/service/xusers/secure/users' + +Create Ranger Role + [Arguments] ${role_json} + Create Ranger Artifact ${role_json} '${RANGER_ENDPOINT_URL}/service/roles/roles' + +Create Ranger Policy + [Arguments] ${policy_json} + Create Ranger Artifact ${policy_json} '${RANGER_ENDPOINT_URL}/service/public/v2/api/policy' + +Assume Role And Get Temporary Credentials + [Arguments] ${perm_access_key_id} ${perm_secret_key} ${policy_json}=${EMPTY} + Configure AWS Profile permanent ${perm_access_key_id} ${perm_secret_key} + + ${now} = Get Current Date time_zone=UTC + + ${cmd} = Set Variable aws sts assume-role --endpoint-url ${STS_ENDPOINT_URL} --role-arn ${ROLE_ARN} --role-session-name ${ROLE_SESSION_NAME} --duration-seconds 900 --output json --profile permanent + ${cmd} = Set Variable If '${policy_json}' != '${EMPTY}' ${cmd} --policy '${policy_json}' ${cmd} + + ${json} = Execute ${cmd} + Should contain ${json} Credentials + + ${stsAccessKeyId} = Execute echo '${json}' | jq -r '.Credentials.AccessKeyId' + ${stsSecretKey} = Execute echo '${json}' | jq -r '.Credentials.SecretAccessKey' + ${stsSessionToken} = Execute echo '${json}' | jq -r '.Credentials.SessionToken' + Should Start With ${stsAccessKeyId} ASIA + Set Global Variable ${STS_ACCESS_KEY_ID} ${stsAccessKeyId} + Set Global Variable ${STS_SECRET_KEY} ${stsSecretKey} + Set Global Variable ${STS_SESSION_TOKEN} ${stsSessionToken} + + # Verify Expiration is at least 900 seconds in the future, but allow 2 second grace on both sides for clock skew + ${expiration} = Execute echo '${json}' | jq -r '.Credentials.Expiration' + ${time_diff} = Subtract Date From Date ${expiration} ${now} + Should Be True ${time_diff} >= 898 Expected expiration to be at least 898s in the future, but was ${time_diff}s + Should Be True ${time_diff} <= 902 Expected expiration to be at most 902s in the future, but was ${time_diff}s + +Get Object Should Succeed + [Arguments] ${bucket} ${key} ${destination}=./${key} ${profile}=sts + ${output} = Execute And Ignore Error aws s3api --endpoint-url ${S3G_ENDPOINT_URL} get-object --bucket ${bucket} --key ${key} ${destination} --profile ${profile} + Should Contain ${output} "AcceptRanges": "bytes" + +Get Object Should Fail + [Arguments] ${bucket} ${key} ${expectedFailureMessage} ${destination}=./${key} ${profile}=sts + ${output} = Execute And Ignore Error aws s3api --endpoint-url ${S3G_ENDPOINT_URL} get-object --bucket ${bucket} --key ${key} ${destination} --profile ${profile} + Should Contain ${output} ${expectedFailureMessage} + +Put Object Should Succeed + [Arguments] ${bucket} ${key} ${body}=./${key} ${profile}=sts + ${output} = Execute And Ignore Error aws s3api --endpoint-url ${S3G_ENDPOINT_URL} put-object --bucket ${bucket} --key ${key} --body ${body} --profile ${profile} + Should Contain ${output} "ETag" + +Put Object Should Fail + [Arguments] ${bucket} ${key} ${expectedFailureMessage} ${body}=./${key} ${profile}=sts + ${output} = Execute And Ignore Error aws s3api --endpoint-url ${S3G_ENDPOINT_URL} put-object --bucket ${bucket} --key ${key} --body ${body} --profile ${profile} + Should Contain ${output} ${expectedFailureMessage} + +Create Bucket Should Fail + [Arguments] ${bucket} ${expectedFailureMessage}=AccessDenied ${profile}=sts + ${output} = Execute And Ignore Error aws s3api --endpoint-url ${S3G_ENDPOINT_URL} create-bucket --bucket ${bucket} --profile ${profile} + Should Contain ${output} ${expectedFailureMessage} 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 new file mode 100644 index 000000000000..fdc74ebe51f9 --- /dev/null +++ b/hadoop-ozone/dist/src/main/smoketest/security/ozone-secure-sts.robot @@ -0,0 +1,158 @@ +# 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. + +*** Settings *** +Documentation Smoke test for S3 STS AssumeRole + Temp Creds +Library OperatingSystem +Library String +Library BuiltIn +Library DateTime +Resource ../commonlib.robot +Resource ../s3/commonawslib.robot +Test Timeout 10 minutes + +*** Variables *** +${RANGER_ENDPOINT_URL} ${EMPTY} +${STS_ENDPOINT_URL} http://s3g:9880/sts +${S3G_ENDPOINT_URL} http://s3g:9878 + +${ICEBERG_SVC_CATALOG_USER} svc-iceberg-rest-catalog +${ICEBERG_ALL_ACCESS_ROLE} iceberg-data-all-access +${ICEBERG_BUCKET} iceberg +${ICEBERG_BUCKET_TESTFILE} testfile55 +${ROLE_ARN} arn:aws:iam::123456789012:role/${ICEBERG_ALL_ACCESS_ROLE} +${ROLE_SESSION_NAME} sts-session-name + +*** Keywords *** +Create Ranger Policy + [Arguments] ${policy_json} + ${result} = Execute curl --fail --include --location --netrc --request POST --header "Content-Type: application/json" --header "accept: application/json" --data '${policy_json}' '${RANGER_ENDPOINT_URL}/service/public/v2/api/policy' + Should Contain ${result} HTTP/1.1 200 + +Assume Role And Get Temporary Credentials + [Arguments] ${policy_json}=${EMPTY} + Run Keyword Install aws cli + Execute aws configure set aws_access_key_id ${PERMANENT_ACCESS_ID} --profile permanent + Execute aws configure set aws_secret_access_key ${PERMANENT_SECRET_KEY} --profile permanent + Execute aws configure set region us-east-1 --profile permanent + + ${now} = Get Current Date time_zone=UTC + + ${cmd} = Set Variable aws sts assume-role --endpoint-url ${STS_ENDPOINT_URL} --role-arn ${ROLE_ARN} --role-session-name ${ROLE_SESSION_NAME} --duration-seconds 900 --output json --profile permanent + ${cmd} = Set Variable If '${policy_json}' != '${EMPTY}' ${cmd} --policy '${policy_json}' ${cmd} + + ${json} = Execute ${cmd} + Should contain ${json} Credentials + ${stsAccessId} = Execute echo '${json}' | jq -r '.Credentials.AccessKeyId' + ${stsSecretKey} = Execute echo '${json}' | jq -r '.Credentials.SecretAccessKey' + ${stsSessionToken} = Execute echo '${json}' | jq -r '.Credentials.SessionToken' + Should Start With ${stsAccessId} ASIA + Set Global Variable ${STS_ACCESS_ID} ${stsAccessId} + Set Global Variable ${STS_SECRET_KEY} ${stsSecretKey} + Set Global Variable ${STS_SESSION_TOKEN} ${stsSessionToken} + + # Verify Expiration is at least 900 seconds in the future, but allow 2 second grace for clock skew + ${expiration} = Execute echo '${json}' | jq -r '.Credentials.Expiration' + ${time_diff} = Subtract Date From Date ${expiration} ${now} + Should Be True ${time_diff} >= 898 Expected expiration to be at least 898s in the future, but was ${time_diff}s + +Configure STS Profile + Execute aws configure set aws_access_key_id ${STS_ACCESS_ID} --profile sts + Execute aws configure set aws_secret_access_key ${STS_SECRET_KEY} --profile sts + Execute aws configure set aws_session_token ${STS_SESSION_TOKEN} --profile sts + +*** Test Cases *** +Create Users in Ranger + Pass Execution If '${RANGER_ENDPOINT_URL}' == '' No Ranger + # Note: the /service/xusers/secure/users endpoint must be used below so that the userPermList can be set. Without + # the userPermList being set, the user cannot be added to a Ranger policy. + Execute curl --fail --include --location --netrc --request POST --header "Content-Type: application/json" --header "accept: application/json" --data '{ "loginId": "${ICEBERG_SVC_CATALOG_USER}", "name": "${ICEBERG_SVC_CATALOG_USER}", "password": "Password123", "firstName": "Iceberg REST", "lastName": "Catalog", "emailAddress": "${ICEBERG_SVC_CATALOG_USER}@example.com", "userRoleList": ["ROLE_USER"], "userPermList": [ { "moduleId": 1, "isAllowed": 1 }, { "moduleId": 3, "isAllowed": 1 }, { "moduleId": 7, "isAllowed": 1 } ] }' '${RANGER_ENDPOINT_URL}/service/xusers/secure/users' + +Create Role in Ranger + Pass Execution If '${RANGER_ENDPOINT_URL}' == '' No Ranger + Execute curl --fail --include --location --netrc --request POST --header "Content-Type: application/json" --header "accept: application/json" --data '{"name": "${ICEBERG_ALL_ACCESS_ROLE}", "description": "Iceberg data all access"}' '${RANGER_ENDPOINT_URL}/service/roles/roles' + +Create Assume Role Policy + # This policy gives '${ICEBERG_SVC_CATALOG_USER}' user ASSUME_ROLE permission on role '${ICEBERG_ALL_ACCESS_ROLE}' + ${policy_json} = Set Variable { "isEnabled": true, "service": "dev_ozone", "name": "iceberg role policy", "policyType": 0, "policyPriority": 0, "isAuditEnabled": true, "resources": { "role": { "values": ["${ICEBERG_ALL_ACCESS_ROLE}"],"isExcludes": false, "isRecursive": false } }, "policyItems": [ { "accesses": [ { "type": "assume_role", "isAllowed": true } ], "users": [ "${ICEBERG_SVC_CATALOG_USER}" ], "delegateAdmin": false } ], "serviceType": "ozone", "isDenyAllElse": false } + Create Ranger Policy ${policy_json} + +Create Iceberg Volume Access policy + # This policy gives '${ICEBERG_ALL_ACCESS_ROLE}' role READ,LIST permission on volume s3v. + # It also gives '${ICEBERG_SVC_CATALOG_USER}' user READ permission on volume s3v. + ${policy_json} = Set Variable { "isEnabled": true, "service": "dev_ozone", "name": "iceberg volume access", "policyType": 0, "policyPriority": 0, "isAuditEnabled": true, "resources": { "volume": { "values": [ "s3v" ], "isExcludes": false, "isRecursive": false } }, "policyItems": [ { "accesses": [ { "type": "read", "isAllowed": true }, { "type": "list", "isAllowed": true } ], "roles": [ "${ICEBERG_ALL_ACCESS_ROLE}" ], "delegateAdmin": false }, { "accesses": [ { "type": "read", "isAllowed": true } ], "users": [ "${ICEBERG_SVC_CATALOG_USER}" ], "delegateAdmin": false } ], "serviceType": "ozone", "isDenyAllElse": false } + Create Ranger Policy ${policy_json} + +Create Iceberg Bucket Access policy + # This policy gives '${ICEBERG_ALL_ACCESS_ROLE}' role ALL permission on bucket s3v/${ICEBERG_BUCKET}. + # It also gives '${ICEBERG_SVC_CATALOG_USER}' user READ permission on bucket s3v/${ICEBERG_BUCKET}. + ${policy_json} = Set Variable { "isEnabled": true, "service": "dev_ozone", "name": "iceberg bucket access", "policyType": 0, "policyPriority": 0, "isAuditEnabled": true, "resources": { "volume": { "values": [ "s3v" ], "isExcludes": false, "isRecursive": false }, "bucket": { "values": [ "${ICEBERG_BUCKET}" ], "isExcludes": false, "isRecursive": false } }, "policyItems": [ { "accesses": [ { "type": "all", "isAllowed": true } ], "roles": [ "${ICEBERG_ALL_ACCESS_ROLE}" ], "delegateAdmin": false }, { "accesses": [ { "type": "read", "isAllowed": true }, { "type": "create", "isAllowed": true } ], "users": [ "${ICEBERG_SVC_CATALOG_USER}" ], "delegateAdmin": false } ], "serviceType": "ozone", "isDenyAllElse": false } + Create Ranger Policy ${policy_json} + +Create Iceberg Table Access policy + # This policy gives '${ICEBERG_ALL_ACCESS_ROLE}' role ALL permission on keys s3v/${ICEBERG_BUCKET}/*. + ${policy_json} = Set Variable { "isEnabled": true, "service": "dev_ozone", "name": "iceberg table access", "policyType": 0, "policyPriority": 0, "isAuditEnabled": true, "resources": { "volume": { "values": [ "s3v" ], "isExcludes": false, "isRecursive": false }, "bucket": { "values": [ "${ICEBERG_BUCKET}" ], "isExcludes": false, "isRecursive": false }, "key": { "values": [ "*" ], "isExcludes": false, "isRecursive": true } }, "policyItems": [ { "accesses": [ { "type": "all", "isAllowed": true } ], "roles": [ "${ICEBERG_ALL_ACCESS_ROLE}" ], "delegateAdmin": false } ], "serviceType": "ozone", "isDenyAllElse": false } + Create Ranger Policy ${policy_json} + +Get S3 Credentials for Service Catalog Principal, Create Iceberg Bucket, and Upload File to Bucket + Kinit test user ${ICEBERG_SVC_CATALOG_USER} ${ICEBERG_SVC_CATALOG_USER}.keytab + # Waiting for Ranger policy cache refresh - ${ICEBERG_SVC_CATALOG_USER} needs to be able to read s3v volume + Wait Until Keyword Succeeds 30s 5s Execute ozone sh volume info s3v + ${output} = Execute ozone s3 getsecret + ${accessId} = Get Regexp Matches ${output} (?<=awsAccessKey=).* + ${secretKey} = Get Regexp Matches ${output} (?<=awsSecret=).* + ${accessId} = Set Variable ${accessId[0]} + ${secretKey} = Set Variable ${secretKey[0]} + Set Global Variable ${PERMANENT_ACCESS_ID} ${accessId} + Set Global Variable ${PERMANENT_SECRET_KEY} ${secretKey} + Execute ozone sh bucket create /s3v/${ICEBERG_BUCKET} + Create File ${TEMP_DIR}/${ICEBERG_BUCKET_TESTFILE} + Execute ozone sh key put /s3v/${ICEBERG_BUCKET}/${ICEBERG_BUCKET_TESTFILE} ${TEMP_DIR}/${ICEBERG_BUCKET_TESTFILE} + +AssumeRole for Limited-Scope Token + ${session_policy} = Set Variable {"Version":"2012-10-17","Statement":[{"Effect":"Allow","Action":"s3:GetObject","Resource":"arn:aws:s3:::iceberg/*"}]} + Assume Role And Get Temporary Credentials policy_json=${session_policy} + +Verify Limited-Scope Token Access + Configure STS Profile + ${bucketSuffix} = Generate Random String 8 [LOWER] + ${bucket} = Set Variable sts-bucket-${bucketSuffix} + ${output} = Execute And Ignore Error aws s3api --endpoint-url ${S3G_ENDPOINT_URL} create-bucket --bucket ${bucket} --profile sts + Should contain ${output} AccessDenied + ${output} = Execute aws s3api --endpoint-url ${S3G_ENDPOINT_URL} get-object --bucket ${ICEBERG_BUCKET} --key ${ICEBERG_BUCKET_TESTFILE} ./${ICEBERG_BUCKET_TESTFILE} --profile sts + Should contain ${output} "AcceptRanges": "bytes" + ${output} = Execute And Ignore Error aws s3api --endpoint-url ${S3G_ENDPOINT_URL} put-object --bucket ${ICEBERG_BUCKET} --key ${ICEBERG_BUCKET_TESTFILE} --body ./${ICEBERG_BUCKET_TESTFILE} --profile sts + Should contain ${output} AccessDenied + +AssumeRole for Role-Scoped Token + Assume Role And Get Temporary Credentials + +Verify Role-Scoped Token Access + Configure STS Profile + ${bucketSuffix} = Generate Random String 8 [LOWER] + ${bucket} = Set Variable sts-bucket-${bucketSuffix} + ${output} = Execute And Ignore Error aws s3api --endpoint-url ${S3G_ENDPOINT_URL} create-bucket --bucket ${bucket} --profile sts + Should contain ${output} AccessDenied + ${output} = Execute aws s3api --endpoint-url ${S3G_ENDPOINT_URL} get-object --bucket ${ICEBERG_BUCKET} --key ${ICEBERG_BUCKET_TESTFILE} ./${ICEBERG_BUCKET_TESTFILE} --profile sts + Should contain ${output} "AcceptRanges": "bytes" + ${output} = Execute aws s3api --endpoint-url ${S3G_ENDPOINT_URL} put-object --bucket ${ICEBERG_BUCKET} --key ${ICEBERG_BUCKET_TESTFILE} --body ./${ICEBERG_BUCKET_TESTFILE} --profile sts + Should contain ${output} "ETag" + +Verify Token Revocation + ${output} = Execute ozone s3 revokeststoken -t ${STS_SESSION_TOKEN} -y ${OM_HA_PARAM} + Should contain ${output} STS token revoked for sessionToken + # Trying to use the token for even get-object should now fail + ${output} = Execute And Ignore Error aws s3api --endpoint-url ${S3G_ENDPOINT_URL} get-object --bucket ${ICEBERG_BUCKET} --key ${ICEBERG_BUCKET_TESTFILE} ./${ICEBERG_BUCKET_TESTFILE} --profile sts + Should contain ${output} AccessDenied diff --git a/pom.xml b/pom.xml index 843122c36ade..f86ae2fca252 100644 --- a/pom.xml +++ b/pom.xml @@ -197,7 +197,7 @@ 0.6.1 2.5.0 3.25.8 - 2.6.0 + 2.8.0-SNAPSHOT 1.75.0 4.1.127.Final @@ -2518,7 +2518,7 @@ never - false + true never apache.snapshots @@ -2530,7 +2530,7 @@ never - false + true never apache.snapshots.https