mcpField
S
s3-bucket-policy

s3-bucket-policy

github.com/dengineproblem安全65 次安装
代码仓库

关于 s3-bucket-policy

s3-bucket-policy 是用于编写、审查和改进 AWS S3 存储桶策略的指导 skill,涵盖访问控制模式、安全条件、策略验证与故障排查。

主要功能

  1. 01最小权限策略指导
  2. 02公共访问与跨账户模式
  3. 03CloudFront 和 CloudTrail 策略示例
  4. 04加密、IP、VPC 和 MFA 限制
  5. 05条件键参考
  6. 06策略验证与故障排查

适用场景

  1. 01为静态网站编写存储桶策略
  2. 02配置跨账户存储桶访问
  3. 03按 IP 或 VPC 端点限制访问
  4. 04排查 S3 AccessDenied 错误

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/dengineproblem/agents-monorepo --skill s3-bucket-policy

安装后在 Claude Code 中输入/s3-bucket-policy确认已加载。

详细介绍

AWS S3 存储桶策略专家

提供有关创建、分析和优化 AWS S3 存储桶策略的专业指导,重点关注安全性、访问控制和合规性。

策略结构

{
  "Version": "2012-10-17",
  "Id": "PolicyIdentifier",
  "Statement": [
    {
      "Sid": "StatementIdentifier",
      "Effect": "Allow | Deny",
      "Principal": {
        "AWS": "arn:aws:iam::account-id:root"
      },
      "Action": [
        "s3:GetObject",
        "s3:PutObject"
      ],
      "Resource": [
        "arn:aws:s3:::bucket-name",
        "arn:aws:s3:::bucket-name/*"
      ],
      "Condition": {
        "StringEquals": {
          "s3:x-amz-acl": "bucket-owner-full-control"
        }
      }
    }
  ]
}

核心原则

security_principles:
  least_privilege:
    description: "Grant only minimum necessary permissions"
    practice: "Start with deny all, add specific allows"

  explicit_deny:
    description: "Deny always overrides Allow"
    practice: "Use Deny for security guardrails"

  defense_in_depth:
    description: "Multiple layers of security"
    practice: "Combine bucket policy + IAM + ACL + encryption"

  avoid_wildcards:
    bad: '"Principal": "*"'
    better: '"Principal": {"AWS": "arn:aws:iam::123456789012:root"}'

common_mistakes:
  - "Using Principal: * without conditions"
  - "Missing resource ARN for objects (/*)"
  - "Forgetting to block public access"
  - "Not enabling versioning before policies"

常见策略模式

静态网站的公开读取权限
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "PublicReadGetObject",
      "Effect": "Allow",
      "Principal": "*",
      "Action": "s3:GetObject",
      "Resource": "arn:aws:s3:::my-website-bucket/*",
      "Condition": {
        "StringEquals": {
          "s3:ExistingObjectTag/public": "true"
        }
      }
    }
  ]
}
跨账户访问
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "CrossAccountAccess",
      "Effect": "Allow",
      "Principal": {
        "AWS": "arn:aws:iam::987654321098:root"
      },
      "Action": [
        "s3:GetObject",
        "s3:PutObject",
        "s3:ListBucket"
      ],
      "Resource": [
        "arn:aws:s3:::shared-bucket",
        "arn:aws:s3:::shared-bucket/*"
      ],
      "Condition": {
        "StringEquals": {
          "s3:x-amz-acl": "bucket-owner-full-control"
        }
      }
    }
  ]
}
CloudFront 源访问控制
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "AllowCloudFrontServicePrincipal",
      "Effect": "Allow",
      "Principal": {
        "Service": "cloudfront.amazonaws.com"
      },
      "Action": "s3:GetObject",
      "Resource": "arn:aws:s3:::my-cdn-bucket/*",
      "Condition": {
        "StringEquals": {
          "AWS:SourceArn": "arn:aws:cloudfront::123456789012:distribution/EDFDVBD6EXAMPLE"
        }
      }
    }
  ]
}
强制加密
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "DenyUnencryptedUploads",
      "Effect": "Deny",
      "Principal": "*",
      "Action": "s3:PutObject",
      "Resource": "arn:aws:s3:::secure-bucket/*",
      "Condition": {
        "StringNotEquals": {
          "s3:x-amz-server-side-encryption": "aws:kms"
        }
      }
    },
    {
      "Sid": "DenyIncorrectKMSKey",
      "Effect": "Deny",
      "Principal": "*",
      "Action": "s3:PutObject",
      "Resource": "arn:aws:s3:::secure-bucket/*",
      "Condition": {
        "StringNotEquals": {
          "s3:x-amz-server-side-encryption-aws-kms-key-id": "arn:aws:kms:us-east-1:123456789012:key/12345678-1234-1234-1234-123456789012"
        }
      }
    }
  ]
}
基于 IP 的限制
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "AllowFromCorporateNetwork",
      "Effect": "Allow",
      "Principal": "*",
      "Action": [
        "s3:GetObject",
        "s3:PutObject"
      ],
      "Resource": "arn:aws:s3:::internal-bucket/*",
      "Condition": {
        "IpAddress": {
          "aws:SourceIp": [
            "192.0.2.0/24",
            "203.0.113.0/24"
          ]
        }
      }
    },
    {
      "Sid": "DenyFromOtherIPs",
      "Effect": "Deny",
      "Principal": "*",
      "Action": "s3:*",
      "Resource": [
        "arn:aws:s3:::internal-bucket",
        "arn:aws:s3:::internal-bucket/*"
      ],
      "Condition": {
        "NotIpAddress": {
          "aws:SourceIp": [
            "192.0.2.0/24",
            "203.0.113.0/24"
          ]
        }
      }
    }
  ]
}
仅允许通过 VPC 端点访问
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "DenyNonVPCAccess",
      "Effect": "Deny",
      "Principal": "*",
      "Action": "s3:*",
      "Resource": [
        "arn:aws:s3:::private-bucket",
        "arn:aws:s3:::private-bucket/*"
      ],
      "Condition": {
        "StringNotEquals": {
          "aws:SourceVpce": "vpce-1234567890abcdef0"
        }
      }
    }
  ]
}
MFA 删除保护
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "RequireMFAForDelete",
      "Effect": "Deny",
      "Principal": "*",
      "Action": [
        "s3:DeleteObject",
        "s3:DeleteObjectVersion"
      ],
      "Resource": "arn:aws:s3:::critical-bucket/*",
      "Condition": {
        "Bool": {
          "aws:MultiFactorAuthPresent": "false"
        }
      }
    }
  ]
}
基于时间的访问
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "BusinessHoursOnly",
      "Effect": "Deny",
      "Principal": "*",
      "Action": "s3:*",
      "Resource": [
        "arn:aws:s3:::business-bucket",
        "arn:aws:s3:::business-bucket/*"
      ],
      "Condition": {
        "DateGreaterThan": {
          "aws:CurrentTime": "2024-01-01T18:00:00Z"
        },
        "DateLessThan": {
          "aws:CurrentTime": "2024-01-02T09:00:00Z"
        }
      }
    }
  ]
}
CloudTrail 日志记录
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "AWSCloudTrailAclCheck",
      "Effect": "Allow",
      "Principal": {
        "Service": "cloudtrail.amazonaws.com"
      },
      "Action": "s3:GetBucketAcl",
      "Resource": "arn:aws:s3:::cloudtrail-logs-bucket",
      "Condition": {
        "StringEquals": {
          "AWS:SourceArn": "arn:aws:cloudtrail:us-east-1:123456789012:trail/mytrail"
        }
      }
    },
    {
      "Sid": "AWSCloudTrailWrite",
      "Effect": "Allow",
      "Principal": {
        "Service": "cloudtrail.amazonaws.com"
      },
      "Action": "s3:PutObject",
      "Resource": "arn:aws:s3:::cloudtrail-logs-bucket/AWSLogs/123456789012/*",
      "Condition": {
        "StringEquals": {
          "s3:x-amz-acl": "bucket-owner-full-control",
          "AWS:SourceArn": "arn:aws:cloudtrail:us-east-1:123456789012:trail/mytrail"
        }
      }
    }
  ]
}

条件键参考

condition_keys:
  global:
    aws:SourceIp: "IP address or CIDR"
    aws:SourceVpc: "VPC ID"
    aws:SourceVpce: "VPC endpoint ID"
    aws:PrincipalOrgID: "AWS Organization ID"
    aws:CurrentTime: "ISO 8601 datetime"
    aws:MultiFactorAuthPresent: "true/false"
    aws:SecureTransport: "true/false"

  s3_specific:
    s3:x-amz-acl: "ACL to apply"
    s3:x-amz-server-side-encryption: "AES256 or aws:kms"
    s3:x-amz-server-side-encryption-aws-kms-key-id: "KMS key ARN"
    s3:ExistingObjectTag/<key>: "Object tag value"
    s3:RequestObjectTagKeys: "Tags being set"
    s3:prefix: "Object key prefix"
    s3:max-keys: "Max keys in ListBucket"
    s3:object-lock-mode: "GOVERNANCE or COMPLIANCE"

  operators:
    StringEquals: "Exact match"
    StringNotEquals: "Not equal"
    StringLike: "Wildcard match (*)"
    IpAddress: "IP in CIDR"
    NotIpAddress: "IP not in CIDR"
    DateGreaterThan: "After date"
    DateLessThan: "Before date"
    Bool: "Boolean check"
    Null: "Key exists/not exists"

安全最佳实践

security_checklist:
  block_public_access:
    setting: "Block all public access"
    how: |
      aws s3api put-public-access-block \
        --bucket my-bucket \
        --public-access-block-configuration \
        "BlockPublicAcls=true,IgnorePublicAcls=true,BlockPublicPolicy=true,RestrictPublicBuckets=true"

  enable_versioning:
    purpose: "Protect against accidental deletion"
    how: |
      aws s3api put-bucket-versioning \
        --bucket my-bucket \
        --versioning-configuration Status=Enabled

  enable_logging:
    purpose: "Audit access"
    how: |
      aws s3api put-bucket-logging \
        --bucket my-bucket \
        --bucket-logging-status '{"LoggingEnabled":{"TargetBucket":"log-bucket","TargetPrefix":"s3-access/"}}'

  default_encryption:
    purpose: "Encrypt at rest"
    how: |
      aws s3api put-bucket-encryption \
        --bucket my-bucket \
        --server-side-encryption-configuration \
        '{"Rules":[{"ApplyServerSideEncryptionByDefault":{"SSEAlgorithm":"aws:kms","KMSMasterKeyID":"alias/s3-key"}}]}'

  lifecycle_policy:
    purpose: "Manage object lifecycle"
    example: "Transition to Glacier after 90 days, delete after 365"

故障排除

common_issues:
  access_denied:
    symptoms: "403 AccessDenied error"
    checks:
      - "Verify IAM user/role permissions"
      - "Check bucket policy allows action"
      - "Verify resource ARN is correct"
      - "Check for explicit Deny statements"
      - "Verify bucket block public access settings"
    debug: |
      # Check effective policy
      aws s3api get-bucket-policy --bucket my-bucket

      # Test access
      aws s3api head-object --bucket my-bucket --key test.txt

  policy_too_large:
    limit: "20 KB maximum"
    solutions:
      - "Use IAM policies instead"
      - "Consolidate statements"
      - "Use conditions instead of listing principals"
      - "Reference IAM roles instead of users"

  invalid_principal:
    symptoms: "MalformedPolicy error"
    common_causes:
      - "Account ID doesn't exist"
      - "Role/user doesn't exist"
      - "Typo in ARN format"
    format: "arn:aws:iam::ACCOUNT-ID:root/role/user"

  condition_not_working:
    checks:
      - "Verify condition key spelling"
      - "Check operator type matches value type"
      - "Ensure condition applies to correct action"

策略验证

# Validate policy syntax
aws iam simulate-custom-policy \
  --policy-input-list file://policy.json \
  --action-names s3:GetObject \
  --resource-arns arn:aws:s3:::my-bucket/test.txt

# Test policy with IAM Policy Simulator
# Console: https://policysim.aws.amazon.com/

# Check for public access
aws s3api get-bucket-policy-status --bucket my-bucket

# List bucket policies
aws s3api get-bucket-policy --bucket my-bucket --output text

Terraform 示例

resource "aws_s3_bucket" "example" {
  bucket = "my-secure-bucket"
}

resource "aws_s3_bucket_public_access_block" "example" {
  bucket = aws_s3_bucket.example.id

  block_public_acls       = true
  block_public_policy     = true
  ignore_public_acls      = true
  restrict_public_buckets = true
}

resource "aws_s3_bucket_policy" "example" {
  bucket = aws_s3_bucket.example.id
  policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        Sid       = "EnforceSSL"
        Effect    = "Deny"
        Principal = "*"
        Action    = "s3:*"
        Resource = [
          aws_s3_bucket.example.arn,
          "${aws_s3_bucket.example.arn}/*"
        ]
        Condition = {
          Bool = {
            "aws:SecureTransport" = "false"
          }
        }
      }
    ]
  })
}

最佳实践

  1. 最小权限 — 仅授予必要的权限
  2. 阻止公开访问 — 默认阻止公开访问
  3. 使用条件 — 添加条件以增强保护
  4. 启用日志记录 — 记录对存储桶的所有访问
  5. 版本控制 — 将策略存储在 git 中
  6. 定期审计 — 定期检查策略

评论

支持 Markdown