Skip to content

Commit 0042518

Browse files
author
Harish Senthilkumar
committed
Grant CloudWatch Logs export permission on the release artifacts bucket
The LogsPuller CodeBuild project exports build logs to the release artifacts bucket via `aws logs create-export-task`. That call is made by the CloudWatch Logs service (not the CodeBuild role), so the destination bucket must grant the logs service principal s3:GetBucketAcl and s3:PutObject via a bucket policy. The (externally-managed) release bucket had no such policy, so every export failed with "AccessDeniedException ... CreateExportTask: GetBucketAcl call on the given bucket failed." Add an AWS::S3::BucketPolicy for the release artifacts bucket granting the CloudWatch Logs service principal GetBucketAcl + PutObject, scoped with aws:SourceAccount and aws:SourceArn (the CodeBuild log group). The bucket has ACLs disabled (BucketOwnerEnforced), so no s3:x-amz-acl condition is used. Also harden buildspecs/pull-logs.yml: fail the build when a log export task cannot be created (empty task id) or ends FAILED/CANCELLED. Previously these errors were swallowed and the build reported SUCCEEDED while exporting zero logs. Signed-off-by: Harish Senthilkumar <harishxr@amazon.com>
1 parent 6cda0b4 commit 0042518

2 files changed

Lines changed: 53 additions & 1 deletion

File tree

build-infrastructure/release-pipeline-stack.yml

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -899,6 +899,43 @@ Resources:
899899
Status: ENABLED
900900
StreamName: !Ref CopyCodeBuildProjectName
901901

902+
# CloudWatch Logs exports (LogsPuller, via `aws logs create-export-task`) to the
903+
# release artifacts bucket are performed by the CloudWatch Logs *service*, not the
904+
# CodeBuild role. So the (externally-managed) release bucket must grant the logs
905+
# service principal s3:GetBucketAcl + s3:PutObject via a bucket policy; without it
906+
# the export fails with "AccessDeniedException ... GetBucketAcl call on the given
907+
# bucket failed". The bucket has ACLs disabled (BucketOwnerEnforced), so no
908+
# s3:x-amz-acl condition is used.
909+
ReleaseArtifactsBucketLogExportPolicy:
910+
Type: AWS::S3::BucketPolicy
911+
Properties:
912+
Bucket: !Ref ReleaseArtifactsBucketName
913+
PolicyDocument:
914+
Version: 2012-10-17
915+
Statement:
916+
- Sid: AllowCloudWatchLogsExportGetBucketAcl
917+
Effect: Allow
918+
Principal:
919+
Service: !Sub 'logs.${AWS::Region}.amazonaws.com'
920+
Action: s3:GetBucketAcl
921+
Resource: !Ref ReleaseArtifactsBucketArn
922+
Condition:
923+
StringEquals:
924+
aws:SourceAccount: !Ref 'AWS::AccountId'
925+
ArnLike:
926+
aws:SourceArn: !GetAtt CodeBuildLogGroup.Arn
927+
- Sid: AllowCloudWatchLogsExportPutObject
928+
Effect: Allow
929+
Principal:
930+
Service: !Sub 'logs.${AWS::Region}.amazonaws.com'
931+
Action: s3:PutObject
932+
Resource: !Sub '${ReleaseArtifactsBucketArn}/*'
933+
Condition:
934+
StringEquals:
935+
aws:SourceAccount: !Ref 'AWS::AccountId'
936+
ArnLike:
937+
aws:SourceArn: !GetAtt CodeBuildLogGroup.Arn
938+
902939
BuildAndSignCodePipelineServiceRole:
903940
Type: AWS::IAM::Role
904941
Properties:

buildspecs/pull-logs.yml

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,13 +57,28 @@ phases:
5757
--destination $RELEASE_BUCKET_NAME \
5858
--destination-prefix "$GIT_COMMIT_SHA/logs" | jq -r '.taskId')
5959
60+
# Fail loudly if the export task was not created (e.g. the destination
61+
# bucket is missing the CloudWatch Logs service bucket policy). Previously
62+
# this was swallowed and the build reported SUCCEEDED while exporting no logs.
63+
if [ -z "$export_task_id" ] || [ "$export_task_id" = "null" ]; then
64+
echo "ERROR: failed to create log export task for $build_id" >&2
65+
return 1
66+
fi
67+
6068
echo "log export task for $build_id started with $export_task_id"
6169
echo "wait for export to finish..." && sleep $DEFAULT_SLEEP_DURATION_IN_SECONDS
6270
6371
# use the given task id to look up the status, log the status later
6472
local export_task_status=$(aws logs describe-export-tasks --task-id $export_task_id | jq -r '.exportTasks[] | .status | .code')
6573
6674
echo "log export task for $build_id (task $export_task_id) has status $export_task_status after $DEFAULT_SLEEP_DURATION_IN_SECONDS seconds"
75+
76+
# RUNNING/PENDING/COMPLETED are fine; a terminal failure is a hard error.
77+
if [ "$export_task_status" = "FAILED" ] || [ "$export_task_status" = "CANCELLED" ]; then
78+
echo "ERROR: log export task $export_task_id for $build_id ended in status $export_task_status" >&2
79+
return 1
80+
fi
81+
6782
echo "wait so we don't get throttled..." && sleep $DEFAULT_SLEEP_DURATION_IN_SECONDS
6883
echo -e "-------------------------------------------------\n"
6984
}
@@ -82,5 +97,5 @@ phases:
8297
# CodeBuild project to the same string in the CloudFormation template
8398
- |
8499
source /tmp/functions.sh && for build_id in $EXTRACT_BUILD_ID $AMD_BUILD_ID $ARM_BUILD_ID $SIGNING_BUILD_ID $COPY_BUILD_ID; do
85-
export_and_describe $(echo $build_id | sed -r 's/:/\//g')
100+
export_and_describe $(echo $build_id | sed -r 's/:/\//g') || exit 1
86101
done

0 commit comments

Comments
 (0)