AWS cloud formation (Fn::ForEach - AWS CloudFormation ) how to use with Parameter store

0

I am working to build CFT where I will pass IP addresses in the code (yaml) to build resolver rules. I have stored IPs in aws parameter store as comma separated strings as 10.10.0.200,10.10.0.201. Now I am trying to refer these IPs one by one in my code . How can i do that ?

Code snippet given below but when i am using this - IP: "{{resolve:ssm:/core/bmas-ip-address:1}}", Its actually fetching the whole string value as IP address and cft ,and of-course failing, My question is can i run it in loop with ForEach CFN function ? Does anyone has any similar solution developed ? Please let me know if any questions.

(BindResolverRule: Type: AWS::Route53Resolver::ResolverRule Properties: DomainName: !Ref DomainName Name: !Ref OutBoundRuleName1 ResolverEndpointId: !Ref OutboundResolverEp RuleType: !Ref RuleType Tags: - Key: Name Value: core-network-forward-all - TargetIp - IP: "{{resolve:ssm:/core/bmas-ip-address:1}}" Port: 53)

1 Antwort
1
Akzeptierte Antwort

You can use a Lambda-backed custom resource. During the Stack creation, the Lambda goes to the Parameter Store, gets a list of strings, parses it and returns back to the CloudFormation

Parameters:
  ParameterPath:
    Type: String
    Default: /core/bmas-ip-address
    Description: Parameter path containing comma-separated list of IP addresses

Resources:
  CustomResolverRuleUpdaterFunction:
    Type: AWS::Lambda::Function
    Properties:
      Code:
        ZipFile: |

          import json
          import logging
          import signal
          import urllib3
          import boto3
          
          LOGGER = logging.getLogger()
          LOGGER.setLevel(logging.INFO)
          
          def handler(event, context):
              try:
                  LOGGER.info('REQUEST RECEIVED:\n %s', event)
                  LOGGER.info('REQUEST RECEIVED:\n %s', context)
                  if event['RequestType'] == 'Create':
                      LOGGER.info('CREATE!')
          
                      ssm_parameter_path = event['ResourceProperties']['ParameterPath']
                      ssm_client = boto3.client('ssm')
                      response = ssm_client.get_parameter(Name=ssm_parameter_path, WithDecryption=True)
                      ip_list = response['Parameter']['Value'].split(',')
                        
                      response_data = {
                          'TargetIps': [{'Ip': ip, 'Port': "53"} for ip in ip_list]
                      }    
          
                      send_response(event, context, "SUCCESS", response_data)
          
          
                  elif event['RequestType'] == 'Update':
                      LOGGER.info('UPDATE!')
                      send_response(event, context, "SUCCESS",
                                    {"Message": "Resource update successful!"})
                  elif event['RequestType'] == 'Delete':
                      LOGGER.info('DELETE!')
                      send_response(event, context, "SUCCESS",
                                    {"Message": "Resource deletion successful!"})
                  else:
                      LOGGER.info('FAILED!')
                      send_response(event, context, "FAILED",
                                    {"Message": "Unexpected event received from CloudFormation"})
              except Exception as e:
                  LOGGER.info('FAILED!')
                  send_response(event, context, "FAILED", {"Message": "Exception during processing: {}".format(str(e))})
          
          
          def send_response(event, context, response_status, response_data):
              '''Send a resource manipulation status response to CloudFormation'''
              response_body = json.dumps({
                  "Status": response_status,
                  "Reason": "See the details in CloudWatch Log Stream: " + context.log_stream_name,
                  "PhysicalResourceId": context.log_stream_name,
                  "StackId": event['StackId'],
                  "RequestId": event['RequestId'],
                  "LogicalResourceId": event['LogicalResourceId'],
                  "Data": response_data
              })
          
              LOGGER.info('ResponseURL: %s', event['ResponseURL'])
              LOGGER.info('ResponseBody: %s', response_body)
          
              http = urllib3.PoolManager()
              response = http.request('PUT', event['ResponseURL'], body=response_body, headers={'Content-Type': ''})
              LOGGER.info("Status code: %s", response.status)
              LOGGER.info("Status message: %s", response.reason)
          
          
          def timeout_handler(_signal, _frame):
              '''Handle SIGALRM'''
              raise Exception('Time exceeded')
          
          
          signal.signal(signal.SIGALRM, timeout_handler)

      Handler: index.handler
      Role: !GetAtt CustomResolverRuleUpdaterRole.Arn
      Runtime: python3.8

  CustomResolverRuleUpdaterRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: "2012-10-17"
        Statement:
          - Effect: Allow
            Principal:
              Service: lambda.amazonaws.com
            Action: sts:AssumeRole
      Policies:
        - PolicyName: CustomResolverRuleTargetIpPolicy
          PolicyDocument:
            Version: "2012-10-17"
            Statement:
              - Effect: Allow
                Action:
                  - ssm:GetParameter
                Resource: "*"
        - PolicyName: WriteLogs
          PolicyDocument:
            Version: '2012-10-17'
            Statement:
              - Effect: Allow
                Action:
                - logs:*
                Resource: arn:aws:logs:*:*:*

  CustomResolverRuleUpdater:
    Type: Custom::ResolverRuleUpdater
    Properties:
      ServiceToken: !GetAtt CustomResolverRuleUpdaterFunction.Arn
      ParameterPath: !Ref ParameterPath

  MyResolverRule:
    Type: AWS::Route53Resolver::ResolverRule
    Properties:
      DomainName: demo1.com
      RuleType: FORWARD
      ResolverEndpointId: rslvr-out-ce*****4ca
      TargetIps: !GetAtt CustomResolverRuleUpdater.TargetIps

Outputs:
  ResolverRuleId:
    Value: !GetAtt MyResolverRule.ResolverRuleId
profile picture
EXPERTE
beantwortet vor 2 Monaten
profile picture
EXPERTE
Artem
überprüft vor 2 Monaten

Du bist nicht angemeldet. Anmelden um eine Antwort zu veröffentlichen.

Eine gute Antwort beantwortet die Frage klar, gibt konstruktives Feedback und fördert die berufliche Weiterentwicklung des Fragenstellers.

Richtlinien für die Beantwortung von Fragen