为 Bucket Policy 和 RAM Policy 中的 Statement 设置有效期

更新时间:
复制为 MD 格式

OSS Bucket Policy 和 RAM Policy 都支持在 Statement 中通过 Condition 引入 acs:CurrentTime 时间条件,实现策略语句到期自动失效。本文介绍如何为临时封禁、限时授权等场景配置带有效期的 Statement,并提供清理过期 Statement 的参考实现。

使用场景

在以下场景中,可以通过在 Statement 中引入时间条件,让策略语句到期后自动失效,避免手工撤销操作的滞后和疏漏:

  • 临时封禁:在指定日期之前禁止一切访问,到达日期后自动恢复访问。

  • 限时授权:仅允许在指定的时间窗口内访问资源,过期后权限自动失效。

实现方式:在 Statement 的 Condition 块中使用 acs:CurrentTime 条件键和日期类比较操作符,将语句的生效与否绑定到系统时间。

Bucket Policy 配置示例

以下 Bucket Policy 表示:在 2026 年 8 月 12 日 17:00:00(北京时间)之前,允许(Allow)所有用户对 mytestbucket 中的任意 Object 执行 oss:GetObject 操作;到期后该 Statement 自动失效,访问失败。

{
    "Version": "1",
    "Statement": [
        {
            "Action": [
                "oss:GetObject"
            ],
            "Effect": "Allow",
            "Resource": [
                "acs:oss:*:*:mytestbucket/*"
            ],
            "Condition": {
                "DateLessThan": {
                    "acs:CurrentTime": [
                        "2026-08-12T17:00:00+08:00"
                    ]
                }
            }
        }
    ]
}

生效逻辑

  • 失效前(当前时间 < 2026-08-12 17:00):DateLessThan 条件为真(True),Allow 语句生效,用户 GetObject 成功。

  • 失效后(当前时间 ≥ 2026-08-12 17:00):DateLessThan 条件为假(False),该 Statement 不再生效,用户访问失败。

RAM Policy 配置示例

以下 RAM Policy 表示:被授予此策略的 RAM 用户只能在 2026 年 8 月 12 日 17:00:00(北京时间)之前对 mytestbucket 中的任意 Object 访问 OSS 中的 Bucket。

{
  "Version": "1",
  "Statement": [
    {
      "Action": "oss:*",
      "Effect": "Allow",
      "Resource": [
        "acs:oss:*:*:mytestbucket/*"
      ],
      "Condition": {
        "DateLessThan": {
          "acs:CurrentTime": "2026-08-12T17:00:00+08:00"
        }
      }
    }
  ]
}

关于 RAM Policy 中时间条件的更多说明,请参见 在指定的时间段访问阿里云

Condition 条件键与操作符

OSS Bucket Policy 与 RAM Policy 支持的 Condition 条件键和操作符完全一致。设置 Statement 有效期时常用以下组合:

条件键

条件键

说明

acs:CurrentTime

请求到达 OSS 服务端时的系统时间,需要使用 ISO 8601 格式。

日期类操作符

acs:CurrentTime 属于日期类型,支持以下 6 个操作符:

操作符

含义

DateEquals

当前时间等于指定时间。

DateNotEquals

当前时间不等于指定时间。

DateLessThan

当前时间早于指定时间。常用于"到期前 Allow / 到期前 Deny"场景。

DateLessThanEquals

当前时间早于或等于指定时间。

DateGreaterThan

当前时间晚于指定时间。常用于"生效后 Allow"场景。

DateGreaterThanEquals

当前时间晚于或等于指定时间。

完整的 Bucket Policy 元素与条件,请参考Condition

定期清理过期 Statement

带时间条件的 Statement 到期后不会自动从 Bucket Policy 中移除。如果长期累积,可能触发以下问题:

  • 大小上限:Bucket Policy JSON 文本上限为 16 KB,累积过多过期 Statement 会导致无法添加新策略。

  • 管理与排查:冗余 Statement 会干扰管理员审阅当前生效的权限边界。

  • 合规要求:及时清理过期的 Allow 或 Deny 条目,符合权限最小化原则。

建议定期清理过期 Statement,可手动通过 Sid 识别后删除,或将自动化脚本部署到函数计算(FC)并配置定时触发器(例如每周一次)。以下为建议的过期 Statement 清理方式,供参考。具体的清理请结合业务逻辑和实际需要进行制定。

清理流程

  1. 调用 GetBucketPolicy 获取完整的 Policy JSON 文本。

  2. 解析 JSON,遍历每一条 Statement。

  3. 查找 Condition 中的 DateLessThanDateGreaterThan,提取 acs:CurrentTime 对应的时间字符串。

  4. 将时间字符串解析为 datetime 对象,与当前系统时间对比。

  5. 如果时间条件已经永远不会再触发(例如 DateLessThan 的指定时间早于当前时间),则将该 Statement 标记为过期并从列表中移除。

  6. 调用 PutBucketPolicy 将剔除过期条目后的 Statement 列表重新提交。

如何识别"过期"

清理脚本判定过期时,需要结合 Condition 操作符和 Effect 综合理解业务意图:

条件组合

业务含义

清理建议

DateLessThan + Deny

在指定日期之前禁止访问,到期后自动解除封禁。

指定日期早于当前时间后可安全删除,删除后不再有拦截,符合业务预期。

DateLessThan + Allow

在指定日期之前限时授权,到期后权限自动失效。

指定日期早于当前时间后可安全删除。

DateGreaterThan + Allow

指定日期之后才允许访问。当前时间晚于该日期后条件永远为真。

如果业务希望该权限永久化,可移除 Condition 部分但保留 Statement;否则建议配合 DateLessThan 一起使用。

Python 自动化脚本示例

以下示例脚本基于 oss2 SDK,演示如何识别并清理仅含 DateLessThan 时间条件的过期 Statement。请根据实际业务逻辑调整识别和清理规则。

重要

该脚本会修改 Bucket Policy,请务必先在测试 Bucket 上验证后再用于生产环境。建议安装 python-dateutil 以便解析带时区的 ISO 8601 时间字符串。

import json
import alibabacloud_oss_v2 as oss
from datetime import datetime, timezone
import dateutil.parser  # 建议安装 python-dateutil 库来完美解析 ISO8601 格式

# 配置信息
access_key = '您的AccessKey'
secret_key = '您的SecretKey'
region = 'cn-hangzhou'
bucket_name = '您的Bucket名称'

cfg = oss.config.load_default()
cfg.credentials_provider = oss.credentials.StaticCredentialsProvider(access_key, secret_key)
cfg.region = region
client = oss.Client(cfg)

def clean_expired_policy():
    try:
        # 1. 获取当前 Bucket Policy
        result = client.get_bucket_policy(oss.models.GetBucketPolicyRequest(bucket=bucket_name))
        policy_data = json.loads(result.body)

        statements = policy_data.get('Statement', [])
        now = datetime.now(timezone.utc)  # 使用 UTC 时间进行对比

        new_statements = []
        removed_count = 0

        # 2. 遍历并检查
        for stmt in statements:
            is_expired = False

            # 检查是否有时间限制条件 (以 DateLessThan 为例)
            condition = stmt.get('Condition', {})
            date_less_than = condition.get('DateLessThan', {}).get('acs:CurrentTime')

            if date_less_than:
                # 提取策略里的时间 (例如 "2026-08-12T17:00:00+08:00")
                # dateutil.parser 可以自动处理 +08:00 等时区信息
                expiry_time = dateutil.parser.isoparse(date_less_than[0])

                # 如果设定时间早于当前时间,说明该 Deny/Allow 已经再也不会触发了
                if expiry_time < now:
                    is_expired = True
                    print(f"发现失效 Statement [Sid: {stmt.get('Sid', 'N/A')}]: 设定时间 {date_less_than[0]} 已过期。")

            if not is_expired:
                new_statements.append(stmt)
            else:
                removed_count += 1

        # 3. 写回 Policy
        if removed_count > 0:
            if not new_statements:
                # 如果删空了,直接删除整个 Policy
                client.delete_bucket_policy(oss.models.DeleteBucketPolicyRequest(bucket=bucket_name))
                print("所有 Statement 已过期,已清空 Bucket Policy。")
            else:
                policy_data['Statement'] = new_statements
                client.put_bucket_policy(oss.models.PutBucketPolicyRequest(
                    bucket=bucket_name,
                    body=json.dumps(policy_data),
                ))
                print(f"清理完成,共移除 {removed_count} 条过期条目。")
        else:
            print("未发现过期条目。")

    except oss.exceptions.OperationError as e:
        cause = e.unwrap() if hasattr(e, 'unwrap') else None
        if isinstance(cause, oss.exceptions.ServiceError) and cause.code == 'NoSuchBucketPolicy':
            print("该 Bucket 没有配置 Policy。")
        else:
            print(f"发生错误: {e}")
    except Exception as e:
        print(f"发生错误: {e}")

if __name__ == "__main__":
    clean_expired_policy()

注意事项

  • 时间格式:时间字符串必须符合 ISO 8601 格式,建议显式带上时区(如 +08:00),否则可能因服务端时区解析差异导致 Statement 失效时间不符合预期。

  • 操作符匹配:请根据业务场景设置合理的时间和操作符,以满足不同业务场景需求。

  • 测试先行:变更生产 Bucket Policy 前,请先在测试 Bucket 上验证配置和清理脚本的行为符合预期。