4

I create a DynamoDb table conditionally:

 MyDynamoTable:
    Type: AWS::DynamoDB::Table
    Condition: IsDevAccount

and this is how IsDevAccount is defined using an input parameter:

Conditions:
  IsDevAccount: !Equals [ !Ref Stage, dev ]

Now I'm creating a Lambda function that accepts the table's name (amongst other things) as input through environment variables. This is done conditionally, too. Within the function's code, I'd check if the table name is passed (pass empty if condition isn't met). If so, I'd put some items into it.

However, I'm not sure how to apply policy templates to the function's role conditionally. Normally I do it like this:

MyFunction:
    Type: AWS::Serverless::Function
    Properties:
       Policies:
       - DynamoDBWritePolicy:
          TableName: !Ref MyDynamoTable

What happens to the function's execution role if the table isn't created because the condition isn't met (e.g.: in another account)? Can I apply this policy template conditionally, as well?

What I don't want to do is to blindly give write permission to all DynamoDB tables within the account.

Amir Keibi
  • 1,991
  • 28
  • 45

1 Answers1

1

Yes, you could add the condition to the DB write policy so that only when the condition is met, it will allow the write policy.

You're creating the table only if the environment is staging or development, you could apply a condition on the policy to check for your table name then apply the write policy. Example below

MyDynamoTable:
    Type: AWS::DynamoDB::Table
    Condition: IsDevAccount

Conditions:
  IsDevAccount: !Equals [ !Ref Stage, dev ]
       
MyFunction:
    Type: AWS::Serverless::Function
    Properties:
       Policies:
       - DynamoDBWritePolicy:
          Condition: !Equals [ !Ref MyDynamoTable, "myTableName" ],
          TableName: !Ref MyDynamoTable

Update in response to comments:

!Ref returns the value of the specified parameter or resource. We need parameters with allowed values for the environment and DBtable for the condition.

Parameters:
    Environment:
        Type: String
        Default: dev
        AllowedValues:
          - dev
          - stage
          - prod 

  MyDynamoTable: 
    Description: table name for the db
    Type: String
    AllowedValues:
       - tableOne
       - tableTwo
       - myTableName

 Conditions:
      IsDevAccount: !Equals [ !Ref Environment, "dev" ]
      TableExists:  !Equals [ !Ref MyDynamoTable, "myTableName" ]

MyFunction:
    Type: AWS::Serverless::Function
    Properties:
       Policies:
       - DynamoDBWritePolicy:
          Condition: !And [IsDevAccount, TableExists] // Only with TableExists condition, it'll work fine with the added parameters
          TableName: !Ref MyDynamoTable

Ref:- https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/parameters-section-structure.html

https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/conditions-section-structure.html

Update 2:

Agreed, I researched and confirmed, there is no way to check for resources created in the same stack template (That's why suggested parameter). Conditions are all parameter based.

However if the resource was created already in other stack, you could do this through Resource import. I don't think, resource import will be of help in your requirement.

However, a workaround would be to have Boolean parameters for TableExists condition and can pass the value through AWS CLI on the run like below,

MyDynamoTable: 
    Description: dynamo db table
    Type: String
    AllowedValues:
       - true
       - false
       
 Conditions:
      TableExists:  !Equals [ !Ref MyDynamoTable, "true" ]

 MyFunction:
    Type: AWS::Serverless::Function
    Properties:
       Policies:
       - DynamoDBWritePolicy:
          Condition: !Ref TableExists 
          TableName: !Ref MyDynamoTable

AWS CLI on deploy pass required parameters

aws cloudformation deploy --template templateName.yml --parameter-overrides MyDynamoTable="true" dynamoDBtableName="myTableName" (any parameter required)
dee
  • 2,244
  • 3
  • 13
  • 33
  • 1
    Thanks, this is what I was looking for. – Amir Keibi Jul 05 '21 at 16:16
  • Actually, when I tested this, it didn't work in a non-dev environment. I got an error from Cloud Formation: FAILED. Reason: Template format error: Unresolved resource dependencies [MyDynamoTable] in the Resources block of the template – Amir Keibi Aug 20 '21 at 21:41
  • @AmirKeibi The first line of your question says, creating DynamoDb table conditionally. The condition is the environment has to be "dev" or "stage". When you say, tested in non-dev environment. Was it staging env? The error says the resource MyDynamoTable is unresolved, the question was to apply a write policy on a "resource created" conditionally but the table is unresolved. You need to ensure the table is created. Verify the env name (stage/staging/dev/development), remove policy then check to ensure table exists. – dee Aug 25 '21 at 06:35
  • Well, that was the whole question. That is, if I create a resource conditionally, how can I apply the policy conditionally. In other words, when I use the template in dev env (condition = true), resource is created and policy is applied. If I use the template in non-dev env (condition = false), resource should not be created and policy should not apply. – Amir Keibi Aug 25 '21 at 17:24
  • @AmirKeibi can you try the updated answer? – dee Aug 26 '21 at 10:35
  • Are you suggesting that the table name to be a stack parameter? If so, this is not really a viable solution for a couple of reasons. 1- We're now passing the responsibility of naming a resource to something other than CF 2- I avoid statically names resources as much as possible because changing the resource in future would mean changing its name. – Amir Keibi Aug 31 '21 at 19:26
  • @AmirKeibi Ran out of characters, updated my response in the answer. Thanks – dee Aug 31 '21 at 21:44