Skip to content

IAM Permissions

S3 Vectors uses the s3vectors: action prefix — separate from s3:.

{
"Sid": "S3VectorsAccess",
"Effect": "Allow",
"Action": [
"s3vectors:PutVectors",
"s3vectors:QueryVectors",
"s3vectors:GetVectors",
"s3vectors:DeleteVectors",
"s3vectors:ListIndexes"
],
"Resource": "${vector_bucket_arn}/*"
}

Scope permissions to {vector_bucket_arn}/* — the bucket ARN with wildcard covers all indexes within it.

In Terraform:

Resource = "${aws_s3vectors_vector_bucket.this.vector_bucket_arn}/*"

This demo uses separate IAM roles for each Lambda:

LambdaS3 Vectors permissionsRationale
IngestPutVectors, QueryVectors, GetVectors, DeleteVectors, ListIndexesFull CRUD — needs to write and manage vectors
QueryQueryVectors, GetVectors, ListIndexesRead-only + search — never modifies vectors
lambda_ingest.tf
resource "aws_iam_role_policy" "ingest_lambda" {
name = "${var.project_name}-${var.environment}-ingest-lambda"
role = aws_iam_role.ingest_lambda.id
policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Sid = "CloudWatchLogs"
Effect = "Allow"
Action = ["logs:CreateLogGroup", "logs:CreateLogStream", "logs:PutLogEvents"]
Resource = "arn:aws:logs:${data.aws_region.current.region}:${data.aws_caller_identity.current.account_id}:log-group:/aws/lambda/...:*"
},
{
Sid = "S3SourceBucketAccess"
Effect = "Allow"
Action = ["s3:GetObject", "s3:PutObject", "s3:ListBucket"]
Resource = [aws_s3_bucket.source_documents.arn, "${aws_s3_bucket.source_documents.arn}/*"]
},
{
Sid = "S3VectorsAccess"
Effect = "Allow"
Action = ["s3vectors:PutVectors", "s3vectors:QueryVectors", "s3vectors:GetVectors", "s3vectors:DeleteVectors", "s3vectors:ListIndexes"]
Resource = "${aws_s3vectors_vector_bucket.this.vector_bucket_arn}/*"
},
{
Sid = "BedrockInvokeModel"
Effect = "Allow"
Action = "bedrock:InvokeModel"
Resource = ["arn:aws:bedrock:${data.aws_region.current.region}::foundation-model/${var.embedding_model_id}"]
}
]
})
}