How do I resolve circular dependencies with AWS SAM templates in CloudFormation?

3 minute read
0

If I deploy an AWS Serverless Application Model (AWS SAM) template in AWS CloudFormation, then I get an error similar to the following: "Circular dependency between resources: [Function, Bucket, FunctionRole, FunctionUploadPermission]."

Short description

If you use the following AWS SAM template, then you get an error in CloudFormation:

AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: Circular Dependency
Resources:
  Bucket:
    Type: AWS::S3::Bucket
    Properties:
      BucketName: !Sub "{AWS::StackName}-${AWS::Region}-${AWS::AccountId}"
  Function:
    Type: AWS::Serverless::Function
    Properties:
      CodeUri: s3://mybucket/function.zip
      Runtime: nodejs12.x
      Handler: index.handler
      Policies:
        - Version: 2012-10-17
          Statement:
            - Effect: Allow
              Action: s3:GetObject*
              Resource: !Sub "arn:aws:s3:::${Bucket}*"
      Events:
        Upload:
          Properties:
            Bucket:
              Ref: Bucket
            Events: s3:ObjectCreated:*
          Type: S3

The template produces an error because it creates the following circular dependency:

  1. The Bucket resource depends on the FunctionUploadPermission.
  2. The FunctionUploadPermission depends on the Function.
  3. The Function depends on the FunctionRole.
  4. FunctionRole depends on the Bucket resource.

Note: In the error message, the FunctionUploadPermission resource is of type AWS::Lambda::Permission. This resource is generated by AWS SAM automatically when the Events property for AWS::Serverless::Function is specified. The FunctionRole resource is of type AWS::IAM::Role. This resource is generated by AWS SAM automatically when the Role property for AWS::Serverless::Function isn't specified.

To resolve the circular dependency, replace the dynamic reference to the bucket resource. The replacement breaks the loop.

Resolution

Replace the CloudFormation template that has a circular dependency with the following template:

Permission is hereby granted, free of charge, to any person obtaining a copy of this
software and associated documentation files (the "Software"), to deal in the Software
without restriction, including without limitation the rights to use, copy, modify,
merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: Circular Dependency
Resources:
  Bucket:
    Type: AWS::S3::Bucket
    Properties:
      BucketName: !Sub "${AWS::StackName}-${AWS::Region}-${AWS::AccountId}"
  Function:
    Type: AWS::Serverless::Function
    Properties:
      CodeUri: s3://mybucket/function.zip
      Runtime: nodejs12.x
      Handler: index.handler
      Policies:
        - Version: 2012-10-17
          Statement:
            - Effect: Allow
              Action: s3:GetObject*
              Resource: !Sub "arn:aws:s3:::${AWS::StackName}-${AWS::Region}-${AWS::AccountId}*"
      Events:
        Upload:
          Properties:
            Bucket:
              Ref: Bucket
            Events: s3:ObjectCreated:*
          Type: S3

In the template, the bucket name in the policy statement's Resources section uses the same pseudo-parameters used in the bucket resource's BucketName property. You pass the bucket name without a direct reference to that bucket.

The error is resolved because the circular dependency loop is broken. The CloudFormation stack isn't directly referencing the Bucket resource. The FunctionRole no longer depends on the Bucket resource.

Note: Replace s3://mybucket/function.zip with your file location.

Related information

Fn: :Sub
Ref
AWS::Serverless::Function
AWS::S3::Bucket

AWS OFFICIAL
AWS OFFICIALUpdated 22 days ago