AWS Bedrock Knowledge Base S3 IAM

AWS Bedrock Knowledge Base - błąd Access Denied przy synchronizacji z S3

Naprawa błędu Access Denied w Bedrock Knowledge Base sync: weryfikacja IAM role trust, KMS key policy, S3 bucket policy i VPC endpoint policy.

·
Bedrock Knowledge Base ingestion job kończy się natychmiast z błędem Access Denied przy próbie odczytu obiektów z S3. Embeddingi nie są aktualizowane, co oznacza że odpowiedzi RAG bazują na nieaktualnych danych. Problem pojawia się mimo pozornie poprawnej konfiguracji IAM role - przyczyna leży często w trust policy, KMS key policy lub bucket policy z explicit deny.

Ten runbook opisuje rozwiązywanie błędu Access Denied podczas synchronizacji Bedrock Knowledge Base z S3. Pełny przewodnik po architekturze RAG na AWS znajdziesz w artykule Architektura RAG na AWS - S3, OpenSearch, Bedrock: wzorce infrastruktury i koszty. W kwestii projektowania pipeline’ów RAG i konfiguracji Knowledge Base umów konsultacje.

Objaw

Bedrock console pokazuje status synchronizacji jako „Failed”. Ingestion job kończy się z błędem Access Denied bez przetworzenia jakichkolwiek dokumentów:

# Typowe komunikaty błędów:
# "The knowledge base storage configuration is invalid... Access Denied"
# "Failed to access S3 bucket: Access Denied (Service: Amazon S3; Status Code: 403)"
# "The data source sync failed because Bedrock could not access objects in the S3 bucket"

# Sprawdź status ostatniego ingestion job
aws bedrock-agent get-ingestion-job \
  --knowledge-base-id KBXXXXXXXX \
  --data-source-id DSXXXXXXXX \
  --ingestion-job-id IJXXXXXXXX \
  --query '{status:ingestionJob.status, failureReasons:ingestionJob.failureReasons, statistics:ingestionJob.statistics}'

# Lista ostatnich ingestion jobs dla data source
aws bedrock-agent list-ingestion-jobs \
  --knowledge-base-id KBXXXXXXXX \
  --data-source-id DSXXXXXXXX \
  --sort-by attribute=STARTED_AT,order=DESCENDING \
  --max-results 5 \
  --query 'ingestionJobSummaries[].{id:ingestionJobId, status:status, started:startedAt, docs:statistics.numberOfDocumentsScanned}'

# Sprawdź CloudTrail pod kątem błędów Access Denied z Bedrock
aws cloudtrail lookup-events \
  --lookup-attributes AttributeKey=EventSource,AttributeValue=s3.amazonaws.com \
  --start-time $(date -u -d '1 hour ago' +%Y-%m-%dT%H:%M:%S) \
  --query 'Events[?contains(CloudTrailEvent, `AccessDenied`) && contains(CloudTrailEvent, `bedrock`)].{time:EventTime, event:EventName, user:Username}' \
  -o table

# Szczegółowy event z CloudTrail (znajdź konkretny errorCode)
aws cloudtrail lookup-events \
  --lookup-attributes AttributeKey=EventSource,AttributeValue=s3.amazonaws.com \
  --start-time $(date -u -d '1 hour ago' +%Y-%m-%dT%H:%M:%S) \
  --max-results 10 \
  --query 'Events[?contains(CloudTrailEvent, `AccessDenied`)].[CloudTrailEvent]' \
  --output text | jq -r '. | select(.errorCode == "AccessDenied") | {eventTime, eventName, errorCode, errorMessage, requestParameters, userIdentity}'

Status ingestion job to „FAILED” z failureReasons wskazującym na Access Denied. Statystyki pokazują 0 przetworzonych dokumentów.

Przyczyna

Bedrock Knowledge Base używa IAM role do dostępu do S3 bucket z danymi źródłowymi. Access Denied pojawia się, gdy jakakolwiek warstwa autoryzacji blokuje dostęp:

  • Brak trust policy dla bedrock.amazonaws.com: IAM role przypisana do Knowledge Base nie ma w trust policy wpisu zezwalającego serwisowi bedrock.amazonaws.com na sts:AssumeRole. Bedrock nie może przyjąć roli i każda operacja S3 kończy się odmową dostępu.

  • KMS key policy nie uwzględnia roli Bedrock: Obiekty w S3 są zaszyfrowane kluczem KMS (customer-managed CMK), ale key policy nie zawiera grantu na kms:Decrypt i kms:GenerateDataKey dla roli Bedrock. Nawet jeśli IAM policy roli zezwala na S3 GetObject, brak uprawnień KMS skutkuje Access Denied.

  • S3 bucket policy z explicit deny: Bucket policy zawiera statement z "Effect": "Deny" który pasuje do żądań z roli Bedrock - np. deny all except specific VPC endpoint, deny all except specific source IP, lub deny bez konkretnego warunku. Explicit deny w bucket policy nadpisuje wszystkie Allow w IAM policy.

  • VPC endpoint policy ogranicza dostęp: Jeśli Bedrock operuje w VPC z S3 Gateway lub Interface endpoint, policy na endpoincie może ograniczać dostęp tylko do określonych bucketów lub principals. Żądania do bucketów spoza listy są blokowane na poziomie endpointu.

  • Obiekty zaszyfrowane customer-managed KMS bez odpowiednich grantów: Nawet jeśli bucket default encryption jest poprawnie skonfigurowany, poszczególne obiekty mogą być zaszyfrowane innym kluczem KMS (np. przesłane przez inny proces z własnym kluczem). Rola Bedrock nie ma uprawnień do tego konkretnego klucza.

Rozwiązanie

A) Naprawa IAM role trust policy:

# Sprawdź aktualną trust policy roli Bedrock Knowledge Base
aws iam get-role \
  --role-name AmazonBedrockExecutionRoleForKnowledgeBase_kb123 \
  --query 'Role.AssumeRolePolicyDocument' | jq .

# Trust policy MUSI zawierać bedrock.amazonaws.com jako trusted principal
# Jeśli brakuje - zaktualizuj trust policy:
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Service": "bedrock.amazonaws.com"
      },
      "Action": "sts:AssumeRole",
      "Condition": {
        "StringEquals": {
          "aws:SourceAccount": "123456789012"
        },
        "ArnLike": {
          "aws:SourceArn": "arn:aws:bedrock:eu-west-1:123456789012:knowledge-base/KBXXXXXXXX"
        }
      }
    }
  ]
}
# Zapisz powyższy JSON do pliku i zaktualizuj trust policy
aws iam update-assume-role-policy \
  --role-name AmazonBedrockExecutionRoleForKnowledgeBase_kb123 \
  --policy-document file://trust-policy.json

# Sprawdź też permissions policy roli - musi zawierać s3:GetObject i s3:ListBucket
aws iam list-attached-role-policies \
  --role-name AmazonBedrockExecutionRoleForKnowledgeBase_kb123

aws iam get-role-policy \
  --role-name AmazonBedrockExecutionRoleForKnowledgeBase_kb123 \
  --policy-name BedrockS3Access \
  --query 'PolicyDocument' | jq .

B) Aktualizacja KMS key policy:

# Znajdź jaki klucz KMS jest używany do szyfrowania bucket
aws s3api get-bucket-encryption \
  --bucket my-kb-documents \
  --query 'ServerSideEncryptionConfiguration.Rules[0].ApplyServerSideEncryptionByDefault.KMSMasterKeyID'

# Sprawdź aktualną key policy
aws kms get-key-policy \
  --key-id arn:aws:kms:eu-west-1:123456789012:key/mrk-1234abcd \
  --policy-name default \
  --query 'Policy' --output text | jq .

Dodaj statement do key policy zezwalający roli Bedrock na decrypt:

{
  "Sid": "AllowBedrockKnowledgeBaseDecrypt",
  "Effect": "Allow",
  "Principal": {
    "AWS": "arn:aws:iam::123456789012:role/AmazonBedrockExecutionRoleForKnowledgeBase_kb123"
  },
  "Action": [
    "kms:Decrypt",
    "kms:DescribeKey",
    "kms:GenerateDataKey"
  ],
  "Resource": "*"
}
# Zaktualizuj key policy (pobierz aktualną, dodaj statement, zapisz)
aws kms get-key-policy \
  --key-id mrk-1234abcd \
  --policy-name default \
  --query 'Policy' --output text > kms-policy.json

# Edytuj kms-policy.json - dodaj powyższy statement do tablicy Statement

aws kms put-key-policy \
  --key-id mrk-1234abcd \
  --policy-name default \
  --policy file://kms-policy.json

C) Naprawa S3 bucket policy:

# Sprawdź bucket policy
aws s3api get-bucket-policy \
  --bucket my-kb-documents \
  --query 'Policy' --output text | jq .

Jeśli bucket policy zawiera explicit deny - dodaj warunek wyłączający rolę Bedrock z deny:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "AllowBedrockKnowledgeBase",
      "Effect": "Allow",
      "Principal": {
        "AWS": "arn:aws:iam::123456789012:role/AmazonBedrockExecutionRoleForKnowledgeBase_kb123"
      },
      "Action": [
        "s3:GetObject",
        "s3:ListBucket"
      ],
      "Resource": [
        "arn:aws:s3:::my-kb-documents",
        "arn:aws:s3:::my-kb-documents/*"
      ]
    },
    {
      "Sid": "DenyNonVpcAccess",
      "Effect": "Deny",
      "Principal": "*",
      "Action": "s3:*",
      "Resource": [
        "arn:aws:s3:::my-kb-documents",
        "arn:aws:s3:::my-kb-documents/*"
      ],
      "Condition": {
        "StringNotEquals": {
          "aws:sourceVpce": "vpce-0abc1234def56789"
        },
        "ArnNotLike": {
          "aws:PrincipalArn": "arn:aws:iam::123456789012:role/AmazonBedrockExecutionRoleForKnowledgeBase_kb123"
        }
      }
    }
  ]
}
# Zastosuj poprawioną bucket policy
aws s3api put-bucket-policy \
  --bucket my-kb-documents \
  --policy file://bucket-policy.json

D) Aktualizacja VPC endpoint policy:

# Znajdź S3 VPC endpoint
aws ec2 describe-vpc-endpoints \
  --filters "Name=service-name,Values=com.amazonaws.eu-west-1.s3" \
  --query 'VpcEndpoints[].{id:VpcEndpointId, policy:PolicyDocument, vpcId:VpcId}' | jq .

Dodaj bucket i rolę Bedrock do endpoint policy:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "AllowBedrockS3Access",
      "Effect": "Allow",
      "Principal": {
        "AWS": "arn:aws:iam::123456789012:role/AmazonBedrockExecutionRoleForKnowledgeBase_kb123"
      },
      "Action": [
        "s3:GetObject",
        "s3:ListBucket"
      ],
      "Resource": [
        "arn:aws:s3:::my-kb-documents",
        "arn:aws:s3:::my-kb-documents/*"
      ]
    }
  ]
}
# Zaktualizuj VPC endpoint policy
aws ec2 modify-vpc-endpoint \
  --vpc-endpoint-id vpce-0abc1234def56789 \
  --policy-document file://vpce-policy.json

E) Weryfikacja szyfrowania na poziomie obiektów:

# Sprawdź szyfrowanie poszczególnych obiektów w bucket
aws s3api head-object \
  --bucket my-kb-documents \
  --key documents/handbook.pdf \
  --query '{encryption:ServerSideEncryption, kmsKeyId:SSEKMSKeyId}'

# Lista obiektów z różnym szyfrowaniem niż bucket default
aws s3api list-objects-v2 \
  --bucket my-kb-documents \
  --prefix documents/ \
  --max-items 20 \
  --query 'Contents[].Key' --output text | \
  xargs -I {} aws s3api head-object \
    --bucket my-kb-documents \
    --key {} \
    --query '{key: "{}",  kmsKey:SSEKMSKeyId}' 2>/dev/null

# Jeśli obiekty używają innego klucza KMS - dodaj grant dla roli Bedrock
aws kms create-grant \
  --key-id arn:aws:kms:eu-west-1:123456789012:key/other-key-5678efgh \
  --grantee-principal arn:aws:iam::123456789012:role/AmazonBedrockExecutionRoleForKnowledgeBase_kb123 \
  --operations Decrypt DescribeKey \
  --name "BedrockKBAccessGrant"

# Alternatywnie - re-encrypt obiekty kluczem bucket default
aws s3 cp \
  s3://my-kb-documents/documents/handbook.pdf \
  s3://my-kb-documents/documents/handbook.pdf \
  --sse aws:kms \
  --sse-kms-key-id arn:aws:kms:eu-west-1:123456789012:key/mrk-1234abcd

Walidacja

# 1. Uruchom nowy sync (ingestion job)
aws bedrock-agent start-ingestion-job \
  --knowledge-base-id KBXXXXXXXX \
  --data-source-id DSXXXXXXXX

# 2. Poczekaj 1-2 minuty i sprawdź status
aws bedrock-agent get-ingestion-job \
  --knowledge-base-id KBXXXXXXXX \
  --data-source-id DSXXXXXXXX \
  --ingestion-job-id $(aws bedrock-agent list-ingestion-jobs \
    --knowledge-base-id KBXXXXXXXX \
    --data-source-id DSXXXXXXXX \
    --sort-by attribute=STARTED_AT,order=DESCENDING \
    --max-results 1 \
    --query 'ingestionJobSummaries[0].ingestionJobId' --output text) \
  --query '{status:ingestionJob.status, stats:ingestionJob.statistics}'
# Expected: status = "COMPLETE", numberOfDocumentsScanned > 0

# 3. Zweryfikuj że dokumenty są zaindeksowane w vector store
aws bedrock-agent-runtime retrieve \
  --knowledge-base-id KBXXXXXXXX \
  --retrieval-query '{"text": "test query relevant to your documents"}' \
  --retrieval-configuration '{"vectorSearchConfiguration": {"numberOfResults": 3}}' \
  --query 'retrievalResults[].{score:score, uri:location.s3Location.uri}'
# Expected: wyniki z dokumentów S3, score > 0

# 4. Sprawdź CloudTrail - brak nowych Access Denied
aws cloudtrail lookup-events \
  --lookup-attributes AttributeKey=EventSource,AttributeValue=s3.amazonaws.com \
  --start-time $(date -u -d '10 minutes ago' +%Y-%m-%dT%H:%M:%S) \
  --query 'Events[?contains(CloudTrailEvent, `AccessDenied`) && contains(CloudTrailEvent, `bedrock`)]' \
  --output text
# Expected: brak wyników (pusty output)

Jeśli ingestion job zakończył się statusem „COMPLETE”, dokumenty są dostępne w retrieve i brak nowych błędów Access Denied w CloudTrail - problem jest rozwiązany. Uruchom pełny sync jeśli poprzednie częściowe próby mogły pominąć dokumenty.

Nieudany sync Knowledge Base oznacza, że embeddingi w vector store są nieaktualne. Użytkownicy końcowi otrzymują odpowiedzi bazujące na starych danych - lub nie otrzymują odpowiedzi wcale, jeśli Knowledge Base nigdy nie została poprawnie zsynchronizowana. W aplikacjach RAG produkcyjnych to cichy błąd: system odpowiada pewnie, ale na podstawie nieaktualnych lub niekompletnych danych. Im dłużej sync jest zepsuty, tym bardziej odpowiedzi oddalają się od rzeczywistości.

 

Jerzy Kopaczewski

Bedrock Knowledge Base nie synchronizuje się z S3?

Umów bezpłatną 30-minutową rozmowę. Przejrzymy konfigurację IAM, KMS i bucket policy, aby odblokować sync i przywrócić aktualne odpowiedzi RAG.