diff --git a/.buildspec.yaml b/.buildspec.yaml index 9a617d9..337d44e 100644 --- a/.buildspec.yaml +++ b/.buildspec.yaml @@ -1,18 +1,13 @@ --- version: 0.2 -env: - variables: - LAMBDA_BUCKET_PREFIX: binxio-public - LAMBDA_BUCKET_REGION: eu-central-1 - MAKE_TARGET: deploy phases: install: runtime-versions: - docker: 18 - python: 3.7 + docker: 20 + python: 3.9 build: commands: - > echo '{"registry-mirrors": ["https://mirror.gcr.io"]}' > /etc/docker/daemon.json - pkill -1 dockerd - - make S3_BUCKET_PREFIX=${LAMBDA_BUCKET_PREFIX} AWS_REGION=${LAMBDA_BUCKET_REGION} ${MAKE_TARGET:-deploy} + - make deploy diff --git a/.make-release-support b/.make-release-support index 6915974..20887ea 100644 --- a/.make-release-support +++ b/.make-release-support @@ -1,5 +1,3 @@ -#!/bin/bash -# # Copyright 2015 Xebia Nederland B.V. # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -15,7 +13,21 @@ # limitations under the License. # function hasChanges() { - test -n "$(git status -s .)" + test -n "$(showChanges)" +} + +function showChanges() { + git status -s -- $(getTagOnChangesIn) +} + +function getTagOnChangesIn() { + result=$(awk -F= '/^tag_on_changes_in=/{print $2}' .release) + if egrep -q -e '^\.$' -e '^\./?[ ]' -e '[ ]\./?[ ]' <<< "$result" ; then + echo "$result" + else + echo ". $result" + fi + return 0 } function getRelease() { @@ -36,8 +48,8 @@ function getTag() { function setRelease() { if [ -n "$1" ] ; then - sed -i.x -e "s/^tag=.*/tag=$(getTag $1)/" .release - sed -i.x -e "s/^release=.*/release=$1/g" .release + sed -i.x -e "s~^tag=.*~tag=$(getTag $1)~" .release + sed -i.x -e "s~^release=.*~release=$1~g" .release rm -f .release.x runPreTagCommand "$1" else @@ -63,16 +75,20 @@ function tagExists() { test -n "$tag" && test -n "$(git tag | grep "^$tag\$")" } +function showDiffFromRelease() { + git diff --compact-summary -r $tag -- $(getTagOnChangesIn) +} + function differsFromRelease() { tag=$(getTag) - ! tagExists $tag || test -n "$(git diff --shortstat -r $tag .)" + ! tagExists $tag || test -n "$(showDiffFromRelease)" } function getVersion() { result=$(getRelease) if differsFromRelease; then - result="$result-$(git rev-parse --short HEAD)" + result="$result-$(git log -n 1 --format=%h $(getTagOnChangesIn))" fi if hasChanges ; then diff --git a/.release b/.release index 011f795..182f0da 100644 --- a/.release +++ b/.release @@ -1,3 +1,3 @@ release=2.0.1 tag=v2.0.1 -pre_tag_command=sed -i '' -e 's^lambdas/cfn-secret-provider-[0-9]*\.[0-9]*\.[0-9]*[^\.]*\.^lambdas/cfn-secret-provider-@@RELEASE@@.^' README.md cloudformation/cfn-resource-provider.yaml +pre_tag_command=sed -i '' -e 's^lambdas/cfn-secret-provider:[0-9]*\.[0-9]*\.[0-9]*[^\.]*\.^lambdas/cfn-secret-provider:@@RELEASE@@.^' README.md cloudformation/cfn-resource-provider.yaml diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..c503dd2 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,12 @@ +FROM --platform=linux/amd64 public.ecr.aws/lambda/python:3.9 + +WORKDIR ${LAMBDA_TASK_ROOT} + +COPY requirements.txt . + +RUN pip install -r requirements.txt + +RUN find . -type d -print0 | xargs -0 chmod ugo+rx && \ + find . -type f -print0 | xargs -0 chmod ugo+r + +CMD [ "secrets.handler" ] diff --git a/Dockerfile.lambda b/Dockerfile.lambda deleted file mode 100644 index 63e461b..0000000 --- a/Dockerfile.lambda +++ /dev/null @@ -1,19 +0,0 @@ -FROM public.ecr.aws/lambda/python:3.9 -RUN yum install -y zip -WORKDIR /lambda - -ADD requirements.txt /tmp -RUN pip install --quiet -t /lambda -r /tmp/requirements.txt -ADD src/ /lambda/ - -RUN find /lambda -type d -print0 | xargs -0 chmod ugo+rx && \ - find /lambda -type f -print0 | xargs -0 chmod ugo+r - -RUN python -m compileall -q /lambda - -ARG ZIPFILE=lambda.zip -RUN zip --quiet -9r /${ZIPFILE} . - -FROM scratch -ARG ZIPFILE -COPY --from=0 /${ZIPFILE} / diff --git a/Makefile b/Makefile index f683aff..d1a4d66 100644 --- a/Makefile +++ b/Makefile @@ -1,80 +1,29 @@ include Makefile.mk - +USERNAME=xebia NAME=cfn-secret-provider + S3_BUCKET_PREFIX=binxio-public AWS_REGION=eu-central-1 S3_BUCKET=$(S3_BUCKET_PREFIX)-$(AWS_REGION) +AWS_ACCOUNT=$(shell aws sts get-caller-identity --query Account --output text) ALL_REGIONS=$(shell aws --region $(AWS_REGION) \ ec2 describe-regions \ --query 'join(`\n`, Regions[?RegionName != `$(AWS_REGION)`].RegionName)' \ --output text) +REGISTRY_HOST=$(AWS_ACCOUNT).dkr.ecr.$(AWS_REGION).amazonaws.com +IMAGE=$(REGISTRY_HOST)/$(USERNAME)/$(NAME) +TAG_WITH_LATEST=never -help: - @echo 'make - builds a zip file to target/.' - @echo 'make release - builds a zip file and deploys it to s3.' - @echo 'make clean - the workspace.' - @echo 'make test - execute the tests, requires a working AWS connection.' - @echo 'make deploy-provider - deploys the provider.' - @echo 'make delete-provider - deletes the provider.' - @echo 'make demo - deploys the provider and the demo cloudformation stack.' - @echo 'make delete-demo - deletes the demo cloudformation stack.' - - -deploy: target/$(NAME)-$(VERSION).zip - aws s3 --region $(AWS_REGION) \ - cp --acl public-read \ - cloudformation/cfn-resource-provider.yaml \ - s3://$(S3_BUCKET)/lambdas/$(NAME)-$(VERSION).yaml - aws s3 --region $(AWS_REGION) \ - cp --acl public-read \ - target/$(NAME)-$(VERSION).zip \ - s3://$(S3_BUCKET)/lambdas/$(NAME)-$(VERSION).zip - aws s3 --region $(AWS_REGION) \ - cp --acl public-read \ - s3://$(S3_BUCKET)/lambdas/$(NAME)-$(VERSION).zip \ - s3://$(S3_BUCKET)/lambdas/$(NAME)-latest.zip - -deploy-all-regions: deploy - @for REGION in $(ALL_REGIONS); do \ - echo "copying to region $$REGION.." ; \ - aws s3 --region $$REGION \ - cp --acl public-read \ - s3://$(S3_BUCKET)/lambdas/$(NAME)-$(VERSION).zip \ - s3://$(S3_BUCKET_PREFIX)-$$REGION/lambdas/$(NAME)-$(VERSION).zip; \ - aws s3 --region $$REGION \ - cp --acl public-read \ - s3://$(S3_BUCKET)/lambdas/$(NAME)-$(VERSION).zip \ - s3://$(S3_BUCKET_PREFIX)-$$REGION/lambdas/$(NAME)-latest.zip; \ - done - -undeploy: - @for REGION in $(ALL_REGIONS); do \ - echo "removing lamdba from region $$REGION.." ; \ - aws s3 --region $(AWS_REGION) \ - rm \ - s3://$(S3_BUCKET_PREFIX)-$$REGION/lambdas/$(NAME)-$(VERSION).zip; \ - done - - -do-push: deploy - -do-build: target/$(NAME)-$(VERSION).zip - -target/$(NAME)-$(VERSION).zip: src/*.py requirements.txt - mkdir -p target/content - docker build --build-arg ZIPFILE=$(NAME)-$(VERSION).zip -t $(NAME)-lambda:$(VERSION) -f Dockerfile.lambda . && \ - ID=$$(docker create $(NAME)-lambda:$(VERSION) /bin/true) && \ - docker export $$ID | (cd target && tar -xvf - $(NAME)-$(VERSION).zip) && \ - docker rm -f $$ID && \ - chmod ugo+r target/$(NAME)-$(VERSION).zip - -clean: - rm -rf target src/*.pyc tests/*.pyc Pipfile.lock: Pipfile requirements.txt test-requirements.txt - pipenv install -r requirements.txt - pipenv install -d -r test-requirements.txt + +requirements.txt test-requirements.txt: Pipfile + pipenv requirements > requirements.txt + pipenv requirements --dev-only > test-requirements.txt + +Pipfile.lock: Pipfile + pipenv update test: Pipfile.lock for n in ./cloudformation/*.yaml ; do aws cloudformation validate-template --template-body file://$$n ; done @@ -83,26 +32,24 @@ test: Pipfile.lock fmt: black src/*.py tests/*.py -deploy-provider: target/$(NAME)-$(VERSION).zip +deploy-provider: ## deploy the provider to the current account + sed -i '' -e 's^cfn-secret-provider:[0-9]*\.[0-9]*\.[0-9]*[^\.]*^cfn-secret-provider:$(VERSION)^' cloudformation/cfn-resource-provider.yaml aws cloudformation deploy \ --capabilities CAPABILITY_IAM \ --stack-name $(NAME) \ --template-file ./cloudformation/cfn-resource-provider.yaml \ - --parameter-overrides \ - S3BucketPrefix=$(S3_BUCKET_PREFIX) \ - CFNCustomProviderZipFileName=lambdas/$(NAME)-$(VERSION).zip delete-provider: aws cloudformation delete-stack --stack-name $(NAME) aws cloudformation wait stack-delete-complete --stack-name $(NAME) + + deploy-pipeline: aws cloudformation deploy \ --capabilities CAPABILITY_IAM \ --stack-name $(NAME)-pipeline \ - --template-file ./cloudformation/cicd-pipeline.yaml \ - --parameter-overrides \ - S3BucketPrefix=$(S3_BUCKET_PREFIX) + --template-file ./cloudformation/cicd-pipeline.yaml delete-pipeline: aws cloudformation delete-stack --stack-name $(NAME)-pipeline diff --git a/Makefile.mk b/Makefile.mk index 14cd3f5..51ec0be 100644 --- a/Makefile.mk +++ b/Makefile.mk @@ -1,5 +1,5 @@ # -# Copyright 2015 Xebia Nederland B.V. +# Copyright 2015-2024 Xebia Nederland B.V. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -15,20 +15,27 @@ # REGISTRY_HOST=docker.io USERNAME=$(USER) -NAME=$(shell basename $(PWD)) +NAME=$(shell basename $(CURDIR)) RELEASE_SUPPORT := $(shell dirname $(abspath $(lastword $(MAKEFILE_LIST))))/.make-release-support IMAGE=$(REGISTRY_HOST)/$(USERNAME)/$(NAME) + VERSION=$(shell . $(RELEASE_SUPPORT) ; getVersion) +BASE_RELEASE=$(shell . $(RELEASE_SUPPORT) ; getRelease) + TAG=$(shell . $(RELEASE_SUPPORT); getTag) +TAG_WITH_LATEST=always SHELL=/bin/bash -.PHONY: pre-build do-build post-build build release patch-release minor-release major-release tag check-status check-release showver \ - push do-push post-push +DOCKER_BUILD_CONTEXT=. +DOCKER_FILE_PATH=Dockerfile + +.PHONY: pre-build docker-build post-build build release patch-release minor-release major-release tag check-status check-release showver \ + push pre-push do-push post-push showimage -build: pre-build do-build post-build +build: pre-build docker-build post-build ## builds a new version of your container image pre-build: @@ -36,28 +43,26 @@ pre-build: post-build: +pre-push: + + post-push: -do-build: .release - @if [[ -f Dockerfile ]]; then docker build -t $(IMAGE):$(VERSION) . ; else echo "INFO: No Dockerfile found." >/dev/null ; fi - @if [[ -f Dockerfile ]]; then \ - DOCKER_MAJOR=$(shell docker -v | sed -e 's/.*version //' -e 's/,.*//' | cut -d\. -f1) ; \ - DOCKER_MINOR=$(shell docker -v | sed -e 's/.*version //' -e 's/,.*//' | cut -d\. -f2) ; \ - if [ $$DOCKER_MAJOR -eq 1 ] && [ $$DOCKER_MINOR -lt 10 ] ; then \ - echo docker tag -f $(IMAGE):$(VERSION) $(IMAGE):latest ;\ - docker tag -f $(IMAGE):$(VERSION) $(IMAGE):latest ;\ - else \ - echo docker tag $(IMAGE):$(VERSION) $(IMAGE):latest ;\ - docker tag $(IMAGE):$(VERSION) $(IMAGE):latest ; \ - fi ; \ +docker-build: .release + docker build $(DOCKER_BUILD_ARGS) -t $(IMAGE):$(VERSION) $(DOCKER_BUILD_CONTEXT) -f $(DOCKER_FILE_PATH) + @if [[ $(TAG_WITH_LATEST) != never ]] && ([[ $(TAG_WITH_LATEST) == always ]] || [[ $(BASE_RELEASE) == $(VERSION) ]]); then \ + echo docker tag $(IMAGE):$(VERSION) $(IMAGE):latest >&2; \ + docker tag $(IMAGE):$(VERSION) $(IMAGE):latest; \ else \ - echo 'No Dockerfile found.' > /dev/null ;\ + echo docker rmi --force --no-prune $(IMAGE):latest >&2; \ + docker rmi --force --no-prune $(IMAGE):latest 2>/dev/null; \ fi .release: @echo "release=0.0.0" > .release @echo "tag=$(NAME)-0.0.0" >> .release + @echo "tag_on_changes_in=." >> .release @echo INFO: .release created @cat .release @@ -65,37 +70,40 @@ do-build: .release release: check-status check-release build push -push: do-push post-push +push: pre-push do-push post-push -do-push: - @if [[ -f Dockerfile ]]; then \ - docker push $(IMAGE):$(VERSION) ; \ - docker push $(IMAGE):latest ; \ - else \ - echo > /dev/null ; \ +do-push: IMAGE_EXISTS=$(shell docker manifest inspect $(IMAGE):$(VERSION) 2>/dev/null) +do-push: + docker push $(IMAGE):$(VERSION) + @if [[ $(TAG_WITH_LATEST) != never ]] && ([[ $(TAG_WITH_LATEST) == always ]] || [[ $(BASE_RELEASE) == $(VERSION) ]]); then \ + echo docker push $(IMAGE):latest >&2; \ + docker push $(IMAGE):latest; \ fi -snapshot: build push +snapshot: build push ## builds a new version of your container image, and pushes it to the registry -showver: .release +showver: .release ## shows the current release tag based on the workspace @. $(RELEASE_SUPPORT); getVersion +showimage: .release ## shows the container image name based on the workspace + @echo $(IMAGE):$(VERSION) + tag-patch-release: VERSION := $(shell . $(RELEASE_SUPPORT); nextPatchLevel) -tag-patch-release: .release tag +tag-patch-release: .release tag ## increments the patch release level and create the tag without build tag-minor-release: VERSION := $(shell . $(RELEASE_SUPPORT); nextMinorLevel) -tag-minor-release: .release tag +tag-minor-release: .release tag ## increments the minor release level and create the tag without build tag-major-release: VERSION := $(shell . $(RELEASE_SUPPORT); nextMajorLevel) -tag-major-release: .release tag +tag-major-release: .release tag ## increments the major release level and create the tag without build -patch-release: tag-patch-release release +patch-release: tag-patch-release release ## increments the patch release level, build and push to registry @echo $(VERSION) -minor-release: tag-minor-release release +minor-release: tag-minor-release release ## increments the minor release level, build and push to registry @echo $(VERSION) -major-release: tag-major-release release +major-release: tag-major-release release ## increments the major release level, build and push to registry @echo $(VERSION) @@ -106,11 +114,15 @@ tag: check-status git add . git commit -m "bumped to version $(VERSION)" ; git tag $(TAG) ; - @if [ -n "$(shell git remote -v)" ] ; then git push --tags ; fi + @ if [ -n "$(shell git remote -v)" ] ; then git push --tags ; else echo 'no remote to push tags to' ; fi -check-status: - @. $(RELEASE_SUPPORT) ; ! hasChanges || (echo "ERROR: there are still outstanding changes" >&2 && exit 1) ; +check-status: ## checks whether there are outstanding changes + @. $(RELEASE_SUPPORT) ; ! hasChanges || (echo "ERROR: there are still outstanding changes" >&2 && showChanges >&2 && exit 1) ; -check-release: .release +check-release: .release ## checks whether the workspace matches the tagged release in git @. $(RELEASE_SUPPORT) ; tagExists $(TAG) || (echo "ERROR: version not yet tagged in git. make [minor,major,patch]-release." >&2 && exit 1) ; - @. $(RELEASE_SUPPORT) ; ! differsFromRelease $(TAG) || (echo "ERROR: current directory differs from tagged $(TAG). make [minor,major,patch]-release." ; exit 1) + @. $(RELEASE_SUPPORT) ; ! differsFromRelease $(TAG) || (echo "ERROR: current directory differs from tagged $(TAG). make [minor,major,patch]-release." && showDiffFromRelease >&2 ; exit 1) + + +help: ## show this help. + @fgrep -h "##" $(MAKEFILE_LIST) | grep -v fgrep | sed -e 's/\([^:]*\):[^#]*##\(.*\)/printf '"'%-20s - %s\\\\n' '\1' '\2'"'/' |bash diff --git a/README.md b/README.md index 7474eb4..c1ccd21 100644 --- a/README.md +++ b/README.md @@ -74,9 +74,7 @@ aws cloudformation create-stack \ aws cloudformation wait stack-create-complete --stack-name cfn-secret-provider ``` -This CloudFormation template will use our pre-packaged provider from `s3://binxio-public-${AWS_REGION}/lambdas/cfn-secret-provider-2.0.1.zip`. - -or use [![](https://s3.amazonaws.com/cloudformation-examples/cloudformation-launch-stack.png)](https://console.aws.amazon.com/cloudformation/home?region=eu-central-1#/stacks/new?stackName=cfn-secret-provider&templateURL=https://binxio-public-eu-central-1.s3.amazonaws.com/lambdas/cfn-secret-provider-2.0.1.yaml) +This CloudFormation template will use our pre-packaged provider from `444093529715.dkr.ecr.eu-central-1.amazonaws.com/xebia/cfn-secret-provider:2.0.1-b39b00b-dirty` ## Demo To install the simple sample of the Custom Resource, type: diff --git a/cloudformation/cfn-resource-provider.yaml b/cloudformation/cfn-resource-provider.yaml index 8b472af..dade277 100644 --- a/cloudformation/cfn-resource-provider.yaml +++ b/cloudformation/cfn-resource-provider.yaml @@ -2,12 +2,6 @@ AWSTemplateFormatVersion: '2010-09-09' Description: CloudFormation Secret Provider Parameters: - S3BucketPrefix: - Type: String - Default: 'binxio-public' - CFNCustomProviderZipFileName: - Type: String - Default: 'lambdas/cfn-secret-provider-2.0.1.zip' IAMPermissionBoundaryARN: Type: String Default: '' @@ -16,8 +10,6 @@ Conditions: Resources: LambdaPolicy: Type: AWS::IAM::Policy - DependsOn: - - LambdaRole Properties: PolicyName: CFNCustomSecretProviderPolicy PolicyDocument: @@ -87,16 +79,14 @@ Resources: CFNSecretProvider: Type: AWS::Lambda::Function - DependsOn: - - LambdaRole Properties: Description: CloudFormation Custom:Secret implementation + PackageType: Image Code: - S3Bucket: !Sub '${S3BucketPrefix}-${AWS::Region}' - S3Key: !Ref 'CFNCustomProviderZipFileName' + ImageUri: 444093529715.dkr.ecr.eu-central-1.amazonaws.com/xebia/cfn-secret-provider:2.0.1-fe1363a-dirty + Architectures: + - x86_64 FunctionName: 'binxio-cfn-secret-provider' - Handler: secrets.handler MemorySize: 128 Timeout: 30 Role: !GetAtt 'LambdaRole.Arn' - Runtime: python3.9 diff --git a/cloudformation/cicd-pipeline.yaml b/cloudformation/cicd-pipeline.yaml index 057e2d2..b779d8f 100644 --- a/cloudformation/cicd-pipeline.yaml +++ b/cloudformation/cicd-pipeline.yaml @@ -1,42 +1,30 @@ AWSTemplateFormatVersion: '2010-09-09' -Parameters: - S3BucketPrefix: - Type: String - Default: binxio-public - Resources: - Project: - Type: AWS::CodeBuild::Project - Properties: - Name: cfn-secret-provider - Description: 'cfn-secret-provider builder' - ServiceRole: !Ref 'ProjectRole' - Artifacts: - Type: no_artifacts - Environment: - Type: LINUX_CONTAINER - ComputeType: BUILD_GENERAL1_SMALL - Image: aws/codebuild/standard:2.0 - PrivilegedMode: true - EnvironmentVariables: - - Name: LAMBDA_BUCKET_PREFIX - Value: !Ref S3BucketPrefix - Type: PLAINTEXT - - Name: MAKE_TARGET - Value: deploy-all-regions - Type: PLAINTEXT - Source: - Type: GITHUB - Location: https://github.com/binxio/cfn-secret-provider.git - BuildSpec: .buildspec.yaml - GitCloneDepth: 0 - Triggers: - FilterGroups: - - - Type: EVENT - Pattern: PUSH - - Type: HEAD_REF - Pattern: "refs/tags/.*" - Webhook: true +# Project: +# Type: AWS::CodeBuild::Project +# Properties: +# Name: cfn-secret-provider +# Description: 'cfn-secret-provider builder' +# ServiceRole: !Ref 'ProjectRole' +# Artifacts: +# Type: NO_ARTIFACTS +# Environment: +# Type: LINUX_CONTAINER +# ComputeType: BUILD_GENERAL1_SMALL +# Image: aws/codebuild/standard:7.0 +# PrivilegedMode: true +# Source: +# Type: GITHUB +# Location: https://github.com/binxio/cfn-secret-provider.git +# BuildSpec: .buildspec.yaml +# GitCloneDepth: 0 +# Triggers: +# FilterGroups: +# - - Type: EVENT +# Pattern: PUSH +# - Type: HEAD_REF +# Pattern: "refs/tags/.*" +# Webhook: true ProjectRole: Type: AWS::IAM::Role @@ -50,27 +38,27 @@ Resources: Condition: {} Path: / Policies: - - PolicyName: CFNSecretProviderBuilder + - PolicyName: LambdaBuilder PolicyDocument: Statement: - Effect: Allow Action: - - s3:ListObjects - - s3:GetBucketLocation - Resource: - - !Sub 'arn:aws:s3:::${S3BucketPrefix}-*' - - Effect: Allow - Action: - - s3:GetObject - - s3:PutObject - - s3:PutObjectAcl + - ec2:DescribeRegions Resource: - - !Sub 'arn:aws:s3:::${S3BucketPrefix}-*/lambdas/cfn-secret-provider-*' + - '*' + - Effect: Allow Action: - - ec2:DescribeRegions + - ecr:GetDownloadUrlForLayer + - ecr:BatchGetImage + - ecr:BatchCheckLayerAvailability + - ecr:PutImage + - ecr:InitiateLayerUpload + - ecr:UploadLayerPart + - ecr:CompleteLayerUpload Resource: - - '*' + - !Sub 'arn:aws:ecr:${AWS::Region}:${AWS::AccountId}:repository/xebia/cfn-secret-provider' + - Sid: CloudWatchLogsPolicy Effect: Allow Action: @@ -80,9 +68,40 @@ Resources: Resource: - '*' - LogGroup: - Type: AWS::Logs::LogGroup + Repository: + Type: AWS::ECR::Repository Properties: - LogGroupName: !Sub '/aws/codebuild/${Project}' - RetentionInDays: 7 + RepositoryName: xebia/cfn-secret-provider + ImageTagMutability: IMMUTABLE + RepositoryPolicyText: + Version: '2012-10-17' + Statement: + - Sid: read only access + Effect: Allow + Principal: + AWS: + - '*' + Action: + - ecr:GetDownloadUrlForLayer + - ecr:BatchGetImage + - ecr:BatchCheckLayerAvailability + + - Sid: write to owner account + Effect: Allow + Principal: + AWS: !Sub 'arn:aws:iam::${AWS::AccountId}:root' + Action: + - ecr:GetDownloadUrlForLayer + - ecr:BatchGetImage + - ecr:BatchCheckLayerAvailability + - ecr:PutImage + - ecr:InitiateLayerUpload + - ecr:UploadLayerPart + - ecr:CompleteLayerUpload + +# LogGroup: +# Type: AWS::Logs::LogGroup +# Properties: +# LogGroupName: !Sub '/aws/codebuild/${Project}' +# RetentionInDays: 7