Clone
6
S3 Vector Bucket Security
Chris Lu edited this page 2026-11-04 08:14:29 -08:00

S3 Vector Bucket Security

Who may call the S3 Vectors API, and how to grant access with a vector bucket policy. Vector bucket policies use the same policy evaluation as S3 Tables Security, with s3vectors: actions.

Authentication

Requests are signed with SigV4 for the service s3vectors, with an identity from the S3 configuration (-s3.config, see S3 Credentials). An unknown access key is refused with 403 AccessDenied: authentication failed.

On a SeaweedFS without identities, every request is accepted whatever its access key, and weed-vector needs no credentials (see S3 Vector Bucket#quick-start). Configure identities for anything beyond a trial.

Who can do what

Access comes from two places: the actions listed for the identity in the S3 configuration, and the bucket's policy.

Caller Access
An identity with the Admin action in the admin account: the identity named admin, or one configured with "account": {"id": "admin"} Everything on every vector bucket. Bucket policies do not apply to it, not even a Deny.
Any other identity with the Admin action, or with s3vectors:* Can create vector buckets and use every vector bucket, unless a bucket policy denies it.
An identity with specific actions such as s3vectors:QueryVectors Those operations on every vector bucket, unless a bucket policy denies them. s3vectors:CreateVectorBucket lets it create buckets.
An identity with actions scoped to one bucket, such as s3vectors:QueryVectors:team-a or s3vectors:*:team-a Those operations on that bucket and its indexes only, unless its policy denies them. A scoped action never lets it create a bucket.
The bucket's owner: the account that created it Everything on that bucket, unless its policy denies it. An identity without an account is its own account; every identity in the creating account owns the bucket.
Any other identity Only what the bucket's policy allows.

Identity actions look like this in the -s3.config file:

{
  "identities": [
    {"name": "search", "credentials": [{"accessKey": "search", "secretKey": "search-secret"}],
     "actions": ["s3vectors:GetVectors", "s3vectors:QueryVectors"]}
  ]
}

search can then call GetVectors and QueryVectors on every vector bucket, and nothing else.

  • The Read, Write and List actions do not grant anything on vector buckets. An identity with only those got AccessDeniedException for every vector operation, including CreateVectorBucket.
  • ListVectorBuckets returns only the buckets on which the caller has s3vectors:ListVectorBuckets or s3vectors:GetVectorBucket, scoped ones included: an identity with s3vectors:*:team-b lists team-b. The search identity above can query every bucket but lists none.

Vector bucket policies

Attach a policy with PutVectorBucketPolicy. The caller needs s3vectors:PutVectorBucketPolicy: an admin identity has it, and so does an identity the bucket's current policy grants it.

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {"AWS": "reader"},
      "Action": [
        "s3vectors:GetVectorBucket",
        "s3vectors:ListIndexes",
        "s3vectors:GetIndex",
        "s3vectors:GetVectors",
        "s3vectors:ListVectors",
        "s3vectors:QueryVectors"
      ],
      "Resource": [
        "arn:aws:s3vectors:us-east-1:000000000000:bucket/team-a",
        "arn:aws:s3vectors:us-east-1:000000000000:bucket/team-a/index/*"
      ]
    }
  ]
}
s3v.put_vector_bucket_policy(vectorBucketName="team-a", policy=json.dumps(policy))

With this policy, identity reader can list the bucket, its indexes and their vectors, and query them; PutVectors and DeleteIndex still get AccessDeniedException.

  • Principal: the caller's account, as {"AWS": "reader"} or a list, or "*" for every authenticated identity. An identity's account is its name when it has no account in the S3 configuration, and its account.id otherwise. A statement that names an identity with an account by its name does not match it, not even a Deny.
  • Action: s3vectors: followed by the operation name, e.g. s3vectors:QueryVectors, or s3vectors:*. Each operation of the S3 Vectors API checks the action of the same name. A CreateVectorBucket or CreateIndex with tags also needs s3vectors:TagResource.
  • Resource: the bucket ARN, an index ARN, or a wildcard such as arn:aws:s3vectors:us-east-1:000000000000:bucket/team-a/index/*. ARNs always use region us-east-1 and account 000000000000.
  • Deny wins: a matching Deny overrides any Allow, the owner's access and the identity's own actions. Only an identity with the Admin action in the admin account is exempt.

Example: let every identity query one index, but shut out writer entirely:

{
  "Version": "2012-10-17",
  "Statement": [
    {"Effect": "Allow", "Principal": "*", "Action": "s3vectors:QueryVectors",
     "Resource": "arn:aws:s3vectors:us-east-1:000000000000:bucket/team-a/index/idx"},
    {"Effect": "Deny", "Principal": {"AWS": "writer"}, "Action": "s3vectors:*", "Resource": "*"}
  ]
}

An identity with no vector grants of its own can then call QueryVectors on idx, but not GetVectors; writer gets AccessDeniedException even for QueryVectors.

GetVectorBucketPolicy returns the document as it was stored; with no policy it returns NotFoundException. DeleteVectorBucketPolicy removes it, and with it every access the policy granted.

Tag conditions

Tag conditions are on master since #12351 and not yet in a release: 4.52 rejects any Condition in a vector bucket policy with ValidationException.

A statement in a vector bucket policy can have a Condition on the S3 Vectors API#tags of the bucket or index, or on the tags a request sets:

Condition key Compared with
aws:ResourceTag/<key> The bucket's tag on a bucket request. On a request that names an index, the index's own tag.
s3vectors:VectorBucketTag/<key> The bucket's tag, on bucket and index requests alike.
aws:RequestTag/<key> The tag that TagResource or CreateIndex sets.
aws:TagKeys The keys that TagResource or CreateIndex sets, or that UntagResource removes.

Example, on bucket team-a tagged env=prod, whose index idx is tagged stage=live:

{
  "Version": "2012-10-17",
  "Statement": [
    {"Effect": "Allow", "Principal": {"AWS": "reader"}, "Action": "s3vectors:GetIndex",
     "Resource": "arn:aws:s3vectors:us-east-1:000000000000:bucket/team-a/index/*",
     "Condition": {"StringEquals": {"aws:ResourceTag/stage": "live"}}},
    {"Effect": "Allow", "Principal": {"AWS": "reader"}, "Action": "s3vectors:QueryVectors",
     "Resource": "arn:aws:s3vectors:us-east-1:000000000000:bucket/team-a/index/*",
     "Condition": {"StringEquals": {"s3vectors:VectorBucketTag/env": "prod"}}},
    {"Effect": "Allow", "Principal": {"AWS": "writer"}, "Action": "s3vectors:TagResource",
     "Resource": "arn:aws:s3vectors:us-east-1:000000000000:bucket/team-a/index/*",
     "Condition": {"StringEquals": {"aws:RequestTag/team": "search"},
                   "ForAllValues:StringEquals": {"aws:TagKeys": ["team"]}}}
  ]
}
  • reader can call GetIndex on idx. On an index without stage=live it gets AccessDeniedException.
  • reader can query every index in the bucket. Once the bucket is retagged env=dev, its next query gets AccessDeniedException.
  • writer can tag an index with {"team": "search"}. Tagging with {"team": "other"}, or with {"team": "search", "env": "dev"}, gets AccessDeniedException.

A Deny with a tag condition protects the resources carrying the tag. This statement keeps every index tagged protected=true from being deleted, by any identity except the admin described above:

{"Effect": "Deny", "Principal": "*", "Action": "s3vectors:DeleteIndex",
 "Resource": "arn:aws:s3vectors:us-east-1:000000000000:bucket/team-a/index/*",
 "Condition": {"StringEquals": {"aws:ResourceTag/protected": "true"}}}
  • Conditions apply in bucket policies only. The actions of an identity in the S3 configuration have no conditions.
  • CreateVectorBucket cannot be limited by tags, because a new bucket has no policy yet.
  • A tag that is not set matches no value. A statement that allows CreateIndex only with aws:RequestTag/team = search also refuses a CreateIndex without tags.
  • A tag change applies from the next request.
  • The operators are the ones in S3 Policy Conditions#supported-condition-operators, including the ForAllValues: and ForAnyValue: forms. The IfExists forms are rejected.
  • Condition keys are case-sensitive: aws:resourcetag/env is rejected.

The engine's identity

weed-vector reads and writes every index's files with the identity passed in its --storage-option flags, whoever called the API. Authorization happens in the gateway before the engine is called. In our tests the engine used an identity with the Admin action. On a SeaweedFS without identities it needs none.

Rejected policies

PutVectorBucketPolicy refuses, with ValidationException, a policy that it could not enforce:

Policy content Message
An action of another service, e.g. s3tables:GetTable or s3:GetObject action "s3:GetObject" is not enforceable in a vector bucket policy
A resource ARN of another service, e.g. arn:aws:s3tables:... resource "arn:aws:s3tables:..." is not enforceable in a vector bucket policy
NotAction NotAction is not supported
NotResource NotResource is not supported
A condition on a key other than those under Tag conditions, e.g. aws:SourceIp condition key "aws:SourceIp" is not supported in a vector bucket policy
An unsupported condition operator, e.g. StringEqualsIfExists condition operator "StringEqualsIfExists" is not supported
An operator with no keys, e.g. "StringEquals": {} condition StringEquals needs at least one key
A value the operator cannot read: null, an object, an empty list, NaN or ±Inf; a non-number for Numeric*, a non-RFC 3339 time for Date*, anything but true/false for Bool and Null, a non-IP/CIDR for IpAddress condition StringEquals on "aws:ResourceTag/env" needs values StringEquals can read (...)
An Allow whose Condition is null an Allow statement's Condition must not be null
Statement, Effect or Condition not spelled exactly that, e.g. condition condition must be spelled Condition
A Condition written twice in one statement a statement's Condition must be under one key

Policies stored by an earlier version that contain an unusable condition fail safe: an Allow statement with one never grants, and a Deny statement with one always applies.