Add additional configuration to an s3 bucket with a dynamic name

I tried @mfrankwork’s solution but am getting a cryptic error:

An error occurred: DiyBucket - Unable to validate the following destination configurations (Service: Amazon S3; Status Code: 400; Error Code: InvalidArgument; Request ID: 6516C03FC6506837; S3 Extended Request ID: RD1gHlYOOA+DRL7J8vg1MIf6xnPkDQ28p+lAkZOzgJijzalp/z6i1u1CaXUslLIzrmZ6Y4glYFE=).

My complete serverless.yml:

service: vg-diy-bucket

plugins:
  - serverless-dotenv-plugin
    
provider:
  name: aws
  stage: ${{opt:stage, 'dev'}}
  region: ${{opt:region, 'us-east-1'}}
  
  # use ${{}} to access serverless variables
  # this is necessary because cloudformation uses ${} syntax
  variableSyntax: "\\${{([ ~:a-zA-Z0-9._\\'\",\\-\\/\\(\\)]+?)}}"

  runtime: nodejs8.10
  memorySize: 512

custom:
  userFolderName: alpha

functions:
  transformOnBucketUpload:
    handler: dist/transform.onBucketUpload
    reservedConcurrency: 100
    # events:
    #   - s3:
    #     bucket: vg-diy-bucket-dev-diybucket-14aa5jo8lpn0j # fixme
    #     event: s3:ObjectCreated:*
    #     # rules:
    #     # - prefix: input/
    #     # - suffix: .sketch
    # environment:
    #   sloppy: true
    #   outputBucketArn:
    #     Fn::GetAtt: [DiyBucket, Arn]
    # iamRoleStatements:
    #   - Effect: Allow
    #     Action:
    #       - s3:*
    #     Resource:
    #       - Fn::GetAtt: [DiyBucket, Arn]
    #       - Fn::Join: ['', [Fn::GetAtt: [DiyBucket, Arn], '/*']]
          
resources:
   
  Resources:

    # lambda permission for the function to be invoked by the s3 bucket
    ResizeLambdaPermissionPhotosS3:
      Type: AWS::Lambda::Permission
      Properties:
        FunctionName:
          Fn::GetAtt: [TransformOnBucketUploadLambdaFunction, Arn]
        Principal: s3.amazonaws.com
        Action: lambda:*
        # SourceAccount:
        #   Ref: AWS::AccountId
        SourceArn:
          Fn::GetAtt: [DiyBucket, Arn]

    # the s3 bucket to store sketch files and receive applications
    DiyBucket:
      Type: AWS::S3::Bucket
      Properties:
        NotificationConfiguration:
          LambdaConfigurations:
            - Event: "s3:ObjectCreated:*"
              Function:
                Fn::GetAtt: [TransformOnBucketUploadLambdaFunction, Arn]

    # the admin user that can create bucket users
    DiyBucketAdminUser:
      Type: AWS::IAM::User
      Properties:
        LoginProfile:
          Password: ${{env:DIY_BUCKET_ADMIN_PASSWORD}}
          PasswordResetRequired: false
        Groups:
          - Ref: DiyBucketAdminUserGroup

    # the policy group that bucket admin users should be assigned to
    DiyBucketAdminUserGroup:
      Type: AWS::IAM::Group
      Properties:
        Policies:
          - PolicyName: DiyBucketAdminUserGroupPolicy
            PolicyDocument:
              Version: '2012-10-17'
              Statement:

                # required for user to use AWS S3 Console web ui
                - Sid: AllowGroupToSeeBucketListInTheConsole
                  Action:
                    - s3:ListAllMyBuckets
                    - s3:GetBucketLocation
                  Effect: Allow
                  Resource:
                    - arn:aws:s3:::*

                - Sid: AllowFullDiyBucketS3Access
                  Action:
                    - s3:*
                  Effect: Allow
                  Resource:
                    - Fn::GetAtt: [DiyBucket, Arn]
                    - Fn::Join: ['', [Fn::GetAtt: [DiyBucket, Arn], '/*']]

                - Sid: AllowFullIAMAccess
                  Action:
                    - iam:*
                  Effect: Allow
                  Resource: '*'
    
    # the policy group that bucket users should be assigned to
    # see https://aws.amazon.com/blogs/security/writing-iam-policies-grant-access-to-user-specific-folders-in-an-amazon-s3-bucket/
    DiyBucketUserGroup:
      Type: AWS::IAM::Group
      Properties:
        Policies:
          - PolicyName: DiyBucketUserGroupPolicy
            PolicyDocument:
              Version: '2012-10-17'
              Statement:

              # required for user to use AWS S3 Console web ui
              - Sid: AllowGroupToSeeBucketListInTheConsole
                Action:
                  - s3:ListAllMyBuckets
                  - s3:GetBucketLocation
                Effect: Allow
                Resource:
                  - arn:aws:s3:::*

              - Sid: AllowRootAndHomeListingOfCompanyBucket
                Action:
                  - s3:ListBucket
                Effect: Allow
                Resource:
                  - Fn::GetAtt: [DiyBucket, Arn]
                Condition:
                  StringEquals:
                    s3:prefix:
                      - ''
                      - '${{self:custom.userFolderName}}/'
                    s3:delimiter:
                      - '/'

              - Sid: AllowListingOfUserFolder
                Action:
                  - s3:ListBucket
                Effect: Allow
                Resource:
                  - Fn::GetAtt: [DiyBucket, Arn]
                Condition:
                  StringLike:
                    s3:prefix:
                      - '${{self:custom.userFolderName}}/${aws:username}/*'
                      - '${{self:custom.userFolderName}}/${aws:username}'

              - Sid: AllowInputSketch
                Action:
                  - s3:GetObject
                  - s3:PutObject
                  - s3:DeleteObject
                Effect: Allow
                Resource:
                  - Fn::Join: ['', [Fn::GetAtt: [DiyBucket, Arn], '/${{self:custom.userFolderName}}/${aws:username}/input/*.sketch']]

              - Sid: AllowDownloadOutput
                Action:
                  - s3:GetObject
                  - s3:DeleteObject
                Effect: Allow
                Resource:
                  - Fn::Join: ['', [Fn::GetAtt: [DiyBucket, Arn], '/${{self:custom.userFolderName}}/${aws:username}/output/*']]

              - Sid: DenyInputOutputFolderDeletion
                Effect: Deny
                Action:
                  - s3:DeleteObject
                Resource:
                  - Fn::Join: ['', [Fn::GetAtt: [DiyBucket, Arn], '/${{self:custom.userFolderName}}/${aws:username}/input/']]
                  - Fn::Join: ['', [Fn::GetAtt: [DiyBucket, Arn], '/${{self:custom.userFolderName}}/${aws:username}/output/']]