AWSTemplateFormatVersion: '2010-09-09' Description: 'This AWS solution automates the generation of Seekable OCI (SOCI) index artifacts and stores them in Amazon ECR. It provides an easy way for customers to try SOCI technology to lazily load container images. CFN AWS SOCI Index Builder asynchronously generates SOCI index artifacts triggered by image pushes to designated Amazon ECR repositories and stores them in the repository by the images they reference. (qs-1tsurulid)' Parameters: SociRepositoryImageTagFilters: Description: > Comma-separated list of SOCI repository image tag filters. Each filter is a repository name followed by a colon, ":" and followed by a tag. Both repository names and tags may contain wildcards denoted by an asterisk, "*". For example, "prod*:latest" matches all images tagged with "latest" that are pushed to any repositories that start with "prod", while "dev:*" matches all images pushed to the "dev" repository. Use "*:*" to match all images pushed to all repositories in your private registry. This stack builds a SOCI index for any images that are pushed to your private registry after this stack is created and match at least one filter. Empty values are NOT accepted. Type: CommaDelimitedList Default: '*:*' AllowedPattern: '^(?:[a-z0-9\*]+(?:[._-][a-z0-9\*]+)*\/)*[a-z0-9\*]+(?:[._-][a-z0-9\*]+)*(?::[a-z0-9\*]+(?:[._-][a-z0-9\*]+)*)$' QSS3BucketName: AllowedPattern: ^[0-9a-z]+([0-9a-z-\.]*[0-9a-z])*$ ConstraintDescription: >- The S3 bucket name can include numbers, lowercase letters, and hyphens (-), but it cannot start or end with a hyphen. Default: aws-quickstart Description: >- Name of the S3 bucket for your copy of the deployment assets. Keep the default name unless you are customizing the template. Changing the name updates code references to point to a new location. MinLength: 3 MaxLength: 63 Type: String QSS3KeyPrefix: AllowedPattern: ^([0-9a-zA-Z!-_\.\*'\(\)/]+/)*$ ConstraintDescription: >- The S3 key prefix can include numbers, lowercase letters, uppercase letters, hyphens (-), underscores (_), periods (.), asterisks (*), single quotes ('), open parenthesis ((), close parenthesis ()), and forward slashes (/). End the prefix with a forward slash. Default: cfn-ecr-aws-soci-index-builder/ Description: >- S3 key prefix that is used to simulate a folder for your copy of the deployment assets. Keep the default prefix unless you are customizing the template. Changing the prefix updates code references to point to a new location. Type: String Metadata: AWS::CloudFormation::Interface: ParameterGroups: - Label: default: SOCI Index Builder configuration Parameters: - SociRepositoryImageTagFilters - Label: default: AWS Partner Solution configuration Parameters: - QSS3BucketName - QSS3KeyPrefix ParameterLabels: SociRepositoryImageTagFilters: default: SOCI repository image tag filters QSS3BucketName: default: Partner Solution S3 bucket name QSS3KeyPrefix: default: Partner Solution S3 key prefix Conditions: UsingDefaultBucket: !Equals [!Ref QSS3BucketName, "aws-quickstart"] Resources: ECRImageActionEventFilteringLambda: Type: AWS::Lambda::Function Properties: Description: > Given an Amazon ECR image action event from EventBridge, matches event detail.repository-name and detail.image-tag against one or more known patterns and invokes Executor Lambda with the same event on a match. Handler: ecr_image_action_event_filtering_lambda_function.lambda_handler Runtime: python3.9 Role: !GetAtt ECRImageActionEventFilteringLambdaRole.Arn Timeout: 900 Code: S3Bucket: !If [ UsingDefaultBucket, !Sub "${QSS3BucketName}-${AWS::Region}", !Ref QSS3BucketName, ] S3Key: !Sub "${QSS3KeyPrefix}functions/packages/ecr-image-action-event-filtering/lambda.zip" Environment: Variables: soci_repository_image_tag_filters: !Join [ ",", !Ref SociRepositoryImageTagFilters ] soci_index_generator_lambda_arn: !GetAtt SociIndexGeneratorLambda.Arn ECRImageActionEventFilteringLambdaRole: Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Version: "2012-10-17" Statement: - Effect: "Allow" Action: "sts:AssumeRole" Principal: Service: "lambda.amazonaws.com" ECRImageActionEventFilteringLambdaCloudwatchPolicy: Type: AWS::IAM::Policy Properties: PolicyName: ECRImageActionEventFilteringLambdaCloudwatchPolicy PolicyDocument: Version: "2012-10-17" Statement: - Effect: Allow Action: - "logs:CreateLogGroup" - "logs:CreateLogStream" - "logs:PutLogEvents" Resource: !Sub - "arn:${AWS::Partition}:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/lambda/${ImageActionEventFilteringLambdaId}:*" - ImageActionEventFilteringLambdaId: !Ref ECRImageActionEventFilteringLambda Roles: - Ref: "ECRImageActionEventFilteringLambdaRole" ECRImageActionEventFilteringLambdaInvokeSociIndexGeneratorLambdaPolicy: Type: AWS::IAM::Policy Properties: PolicyName: ECRImageActionEventFilteringLambdaInvokeSociIndexGeneratorLambdaPolicy PolicyDocument: Version: "2012-10-17" Statement: - Effect: Allow Action: - "lambda:InvokeFunction" - "lambda:InvokeAsync" Resource: - !GetAtt SociIndexGeneratorLambda.Arn Roles: - Ref: "ECRImageActionEventFilteringLambdaRole" ECRImageActionEventBridgeRule: Type: AWS::Events::Rule Properties: Description: "Invokes Amazon ECR image action event filtering Lambda function when image is successfully pushed to ECR." EventPattern: source: ["aws.ecr"] detail-type: ["ECR Image Action"] detail: action-type: [ "PUSH" ] result: [ "SUCCESS" ] region: - !Sub ${AWS::Region} Name: "ECRImageActionEventBridgeRule" State: "ENABLED" Targets: - Id: "ecr-image-action-lambda-target" Arn: !GetAtt ECRImageActionEventFilteringLambda.Arn ECRImageActionEventFilteringLambdaInvokePermission: Type: "AWS::Lambda::Permission" Properties: Action: "lambda:InvokeFunction" FunctionName: !Ref ECRImageActionEventFilteringLambda Principal: "events.amazonaws.com" SourceArn: !GetAtt ECRImageActionEventBridgeRule.Arn SociIndexGeneratorLambda: Type: AWS::Lambda::Function Properties: Description: > Given an Amazon ECR container repository and image, Lambda generates image SOCI artifacts and pushes to repository. Handler: main Runtime: go1.x Role: !GetAtt SociIndexGeneratorLambdaRole.Arn Timeout: 900 Code: S3Bucket: !If [ UsingDefaultBucket, !Sub "${QSS3BucketName}-${AWS::Region}", !Ref QSS3BucketName, ] S3Key: !Sub "${QSS3KeyPrefix}functions/packages/soci-index-generator-lambda/soci_index_generator_lambda.zip" EphemeralStorage: Size: 10240 # 10GB - default is 512MB MemorySize: 1024 SociIndexGeneratorLambdaCloudwatchPolicy: Type: AWS::IAM::Policy Properties: PolicyName: SociIndexGeneratorLambdaCloudwatchPolicy PolicyDocument: Version: "2012-10-17" Statement: - Effect: Allow Action: - "logs:CreateLogGroup" - "logs:CreateLogStream" - "logs:PutLogEvents" Resource: - !Sub - "arn:${AWS::Partition}:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/lambda/${SociIndexGeneratorLambdaId}:*" - SociIndexGeneratorLambdaId: !Ref SociIndexGeneratorLambda Roles: - Ref: "SociIndexGeneratorLambdaRole" RepositoryNameParsingLambdaRole: Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Version: "2012-10-17" Statement: - Effect: "Allow" Action: "sts:AssumeRole" Principal: Service: "lambda.amazonaws.com" RepositoryNameParsingLambda: Type: "AWS::Lambda::Function" Properties: FunctionName: RepositoryNameParsingLambda Handler: index.handler Runtime: python3.9 Role: !GetAtt RepositoryNameParsingLambdaRole.Arn Code: ZipFile: !Sub | import json import cfnresponse def handler(event, context): filters = event['ResourceProperties']['filters'] REPO_PREFIX = 'arn:${AWS::Partition}:ecr:${AWS::Region}:${AWS::AccountId}:repository/' repository_arns = [] response = {} try: repositories = [filter.split(':')[0] for filter in filters] for repository in repositories: if repository == '*': repository_arns = [REPO_PREFIX + '*'] break repository_arns.append(REPO_PREFIX + repository) response['repository_arns'] = repository_arns cfnresponse.send(event, context, cfnresponse.SUCCESS, response) except Exception: cfnresponse.send(event, context, cfnresponse.FAILED, response) InvokeRepositoryNameParsingLambda: DependsOn: RepositoryNameParsingLambda Type: Custom::MyCustomResource Properties: ServiceToken: !GetAtt RepositoryNameParsingLambda.Arn filters: !Ref SociRepositoryImageTagFilters SociIndexGeneratorLambdaECRRepositoryPolicy: Type: AWS::IAM::Policy Properties: PolicyName: SociIndexGeneratorLambdaECRRepositoryPolicy PolicyDocument: Version: "2012-10-17" Statement: - Effect: "Allow" Action: - "ecr:BatchGetImage" - "ecr:GetDownloadUrlForLayer" - "ecr:CompleteLayerUpload" - "ecr:UploadLayerPart" - "ecr:InitiateLayerUpload" - "ecr:BatchCheckLayerAvailability" - "ecr:PutImage" Resource: !GetAtt InvokeRepositoryNameParsingLambda.repository_arns Roles: - Ref: "SociIndexGeneratorLambdaRole" SociIndexGeneratorLambdaRole: Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Version: "2012-10-17" Statement: - Effect: "Allow" Action: "sts:AssumeRole" Principal: Service: "lambda.amazonaws.com" Policies: - PolicyName: "AllowEcrGetAuthorizationToken" PolicyDocument: Version: "2012-10-17" Statement: - Effect: "Allow" Action: [ "ecr:GetAuthorizationToken" ] Resource: "*" Outputs: ExportsStackName: Value: !Ref 'AWS::StackName' Export: Name: !Sub 'ExportsStackName-${AWS::StackName}'