How to conditionally create an AWS::Events::Connection resource based on if a secret key is defined or not

Viewed 13

I currently have this cloud formation template that is supposed to create an event bridge resource with all the necessary configurations, but I can't get it to create because I can't get cloud formation to verify if a key exists in the secrets manager or not.

to be more clear, I want my event-bridge.yml template resource to only be created if my key ${Stage}/${SubDomain}/django-events-api-key is already defined in the secrets manager and has a valid value(meaning it does not only have an empty string or a AWS::NoValue); this because I need to create the key after the stack is created and deployed, before the stack is not deployed, so I can't execute my command to generate the key

I have this:

event-bridge.yml

AWSTemplateFormatVersion: "2010-09-09"
Description: "Event scheduling for sending the email digest"
Parameters:
  SubDomain:
    Description: The part of a website address before your DomainName - e.g. www or img
    Type: String
  DomainName:
    Description: The part of a website address after your SubDomain - e.g. example.com
    Type: String
  Stage:
    Description: Stage name (e.g. dev, test, prod)
    Type: String
  DjangoApiKey:
    Description: Api key for events bridge communication
    Type: String

Conditions:
  DjangoApiKeyExists: !Or [ !Not [ !Equals [ !Ref DjangoApiKey,  !Ref AWS::NoValue ] ], !Not [ !Equals [ !Ref DjangoApiKey,  "" ] ] ]

Outputs:
  DjangoEventsConnection:
    Description: Connection to the Django backend for Event Bridge
    Value: !Ref DjangoEventsConnection

Resources:
  MessageDigestEventsRule:
    Type: AWS::Events::Rule
    Properties:
      Name: !Sub "${SubDomain}-chat-digest"
      Description: "Send out email digests for a chat"
      ScheduleExpression: "rate(15 minutes)"
      State: "ENABLED"
      Targets:
        - Arn: !GetAtt MessageDigestEventsApiDestination.Arn
          HttpParameters:
            HeaderParameters: { }
            QueryStringParameters: { }
          Id: !Sub "${SubDomain}-chat-digest-api-target"
          RoleArn: !GetAtt MessageDigestEventsRole.Arn
      EventBusName: "default"

  DjangoEventsConnection:
    Type: AWS::Events::Connection
    Properties:
      Name: !Sub "${SubDomain}-django"
      AuthorizationType: "API_KEY"
      AuthParameters:
        ApiKeyAuthParameters:
          ApiKeyName: "Authorization"
          ApiKeyValue: !Ref DjangoApiKey

in a main.yml template I pass the key variable like this:

  EventBridge:
    DependsOn: [ VpcStack, DjangoEventBridgeApiKey ]
    Type: AWS::CloudFormation::Stack
    Properties:
      TemplateURL: ./event-bridge.yaml
      Parameters:
        SubDomain: !Ref SubDomain
        DomainName: !Ref DomainName
        Stage: !Ref Stage
        DjangoApiKey: !Sub '{{resolve:secretsmanager:arn:aws:secretsmanager:${AWS::Region}:${AWS::AccountId}:secret:${SubDomain}/django-events-api-key}}' <--

but that will always fail because the key is not defined, I would like to pass an empty string or something I can use as a conditional

I have also tried defining the secret, so it exists:

Resources:
  DjangoEventBridgeApiKey:
    Type: AWS::SecretsManager::Secret
    Properties:
      Name: !Sub ${Stage}/${SubDomain}/django-events-api-key
      Description: !Sub Credentials for the event bridge integration https://api.${SubDomain}.circular.co
      Tags:
        - Key: Name
          Value: django-events-api-key
  EventBridge:
    DependsOn: [ VpcStack, DjangoEventBridgeApiKey ]
    Type: AWS::CloudFormation::Stack
    Properties:
      TemplateURL: ./event-bridge.yaml
      Parameters:
        SubDomain: !Ref SubDomain
        DomainName: !Ref DomainName
        Stage: !Ref Stage
        DjangoApiKey: !Sub '{{resolve:secretsmanager:${DjangoEventBridgeApiKey}}}'

But that for some reason, is still making my condition above fail, making the stack attempt to execute, I still cant figure out why is my condition not working

Any ideas on how to make this better? any help provided will be super useful to me

1 Answers

Okay found out the biggest problem with my implementation, on event-bridge.yml:

AWSTemplateFormatVersion: "2010-09-09"
Description: "Event scheduling for sending the email digest of chat messages"
Parameters:
  SubDomain:
    Description: The part of a website address before your DomainName - e.g. www or img
    Type: String
  DomainName:
    Description: The part of a website address after your SubDomain - e.g. example.com
    Type: String
  Stage:
    Description: Stage name (e.g. dev, test, prod)
    Type: String
  DjangoApiKey:
    Description: Api key for events bridge communication
    Type: String

Conditions:
  DjangoApiKeyExists: !Not [ !Equals [ !Ref DjangoApiKey,  "" ] ] # <-- this works

Outputs:
  DjangoEventsConnection:
    Condition: DjangoApiKeyExists
    Description: Connection to the django backend for Event Bridge
    Value: !Ref DjangoEventsConnection

Resources:
  DjangoEventsConnection:
    Type: AWS::Events::Connection
    Condition: DjangoApiKeyExists
    Properties:
      Name: !Sub "${SubDomain}-django"
      AuthorizationType: "API_KEY"
      AuthParameters:
        ApiKeyAuthParameters:
          ApiKeyName: "Authorization"
          ApiKeyValue: !Ref DjangoApiKey
          # This does not update when we change the secret - so we need to force an update - need a more permanent solution
          # ApiKeyValue: pop

  MessageDigestEventsApiDestination:
    Type: AWS::Events::ApiDestination
    Condition: DjangoApiKeyExists
    DependsOn: DjangoEventsConnection

on main.yml

...
  DjangoEventBridgeApiKey:
    Type: AWS::SecretsManager::Secret
    Properties:
      Name: !Sub ${Stage}/${SubDomain}/django-events-api-key # <- this was missing ${Stage}
      SecretString: " "
      Tags:
        - Key: Name
          Value: django-events-api-key
  EventBridge:
    DependsOn: DjangoEventBridgeApiKey
    Type: AWS::CloudFormation::Stack
    Properties:
      TemplateURL: ./event-bridge.yaml
      Parameters:
        SubDomain: !Ref SubDomain
        DomainName: !Ref DomainName
        Stage: !Ref Stage
        DjangoApiKey: !Sub '{{resolve:secretsmanager:arn:aws:secretsmanager:${AWS::Region}:${AWS::AccountId}:secret:${Stage}/${SubDomain}/django-events-api-key}}'
      Tags:
        - Key: Stage
          Value: !Ref Stage
        - Key: SubDomain
          Value: !Ref SubDomain
        - Key: SecretKeyName
          Value: !Ref DjangoEventBridgeApiKey
Related