title: UserData script with Resource Attribute CloudFormation
body: <p><strong>The main question:</strong> How to I reference dependent resource attributes in a cloud formation template to build out a user data script.</p>
  
  <p><strong>What I have tried</strong>:</p>
  
  <ol>
  <li>Approach listed <a href="https://github.com/awslabs/aws-cloudformation-templates/blob/master/aws/services/CloudFormation/FindInMap_Inside_Sub.yaml" rel="noreferrer">here</a>. </li>
  <li>Examples from <a href="https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference-sub.html" rel="noreferrer">sub function</a></li>
  </ol>
  
  <p>I am building a CloudFormation template for a three node Kafka cluster. </p>
  
  <p>The approach I am taking here is configuring Zookeeper and Kafka on each node of the cluster using a UserData script on the EC2 instance.</p>
  
  <p>I am using the <a href="https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference-sub.html" rel="noreferrer">Sub</a> and <a href="https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference-base64.html" rel="noreferrer">Base64</a> functions to populate my user data script with the <code>PrimaryPrivateIpAddress</code> of my NetworkInterface but they are coming across as empty strings instead of the actual values. I know that the values are being populated correctly because they are part of my output in the template. </p>
  
  <p>I have included the resource block of my template below as a reference. I omitted some uninteresting parts for the sake of succinctness. I also am illustrating a couple different approaches that I have tried to the EC2 resource blocks are not consistent.</p>
  
  <pre><code>EC2I8MWW:
    Type: 'AWS::EC2::Instance'
    DependsOn:
      - EC2NI2E8ES
      - EC2NI2PFST
      - EC2NI54B66
    Properties:
      KeyName: !Ref DesiredKeyName
      InstanceType: !Ref InstanceType
      NetworkInterfaces:
        - NetworkInterfaceId: !Ref EC2NI54B66
          DeviceIndex: "0"
      UserData:
        Fn::Base64:
          Fn::Sub:
            - |
              #!/bin/bash
              CONF="/etc/zookeeper/conf.dist/zoo.cfg"
              PRIVATE_1=${Private1}
              PRIVATE_2=${Private2}
              PRIVATE_3=${Private3}
              echo "# Zookeeper configuration for Talentreef" &gt; "$CONF"
              cat &lt;&lt;EOT &gt;&gt; "$CONF"
              maxClientCnxns=50
              tickTime=2000
              initLimit=10
              syncLimit=5
              EOT
              echo "server.1=$PRIVATE_1:2888:3888" &gt;&gt; $CONF
              echo "server.2=$PRIVATE_2:2888:3888" &gt;&gt; $CONF
              echo "server.3=$PRIVATE_3:2888:3888" &gt;&gt; $CONF
              service zookeeper-server init --myid=$NODE_ID
              chkconfig zookeeper-server on
            - {
              Private1: !GetAtt EC2NI2E8ES.PrimaryPrivateIpAddress,
              Private2: !GetAtt EC2NI2PFST.PrimaryPrivateIpAddress,
              Private3: !GetAtt EC2NI54B66.PrimaryPrivateIpAddress
              }
  EC2I2JVJI:
    Type: 'AWS::EC2::Instance'
    DependsOn: EC2NI54B66
    Properties:
      KeyName: !Ref DesiredKeyName
      InstanceType: !Ref InstanceType
      BlockDeviceMappings:
        - DeviceName: /dev/xvdb
          Ebs:
            VolumeType: st1
            DeleteOnTermination: 'true'
            VolumeSize: '500'
        - DeviceName: /dev/xvda
          Ebs:
            VolumeType: gp2
            DeleteOnTermination: 'true'
            VolumeSize: '8'
      ImageId: !FindInMap
        - AWSRegionArch2AMI
        - !Ref 'AWS::Region'
        - !FindInMap
          - AWSInstanceType2Arch
          - !Ref InstanceType
          - Arch
      NetworkInterfaces:
        - NetworkInterfaceId: !Ref EC2NI2PFST
          DeviceIndex: "0"
      UserData:
        Fn::Base64: !Sub |
          #!/bin/bash
          CONF="/etc/zookeeper/conf.dist/zoo.cfg"
          cp $CONF /etc/zookeeper/conf.dist/zoo.cfg.bak-$(date +%s)
          echo "# Zookeeper configuration for Talentreef" &gt; "$CONF"
          cat &lt;&lt;EOT &gt;&gt; "$CONF"
          maxClientCnxns=50
          tickTime=2000
          initLimit=10
          syncLimit=5
          server.1=${EC2NI2E8ES.PrimaryPrivateIpAddress}:2888:3888
          server.2=${EC2NI2PFST.PrimaryPrivateIpAddress}:2888:3888
          server.3=${EC2NI54B66.PrimaryPrivateIpAddress}:2888:3888
          EOT
          service zookeeper-server init --myid=$NODE_ID
          chkconfig zookeeper-server on
          service zookeeper-server start
  EC2I56LVQ:
    Type: 'AWS::EC2::Instance'
    DependsOn: EC2NI54B66
    Properties:
      KeyName: !Ref DesiredKeyName
      InstanceType: !Ref InstanceType
      BlockDeviceMappings:
        - DeviceName: /dev/xvdb
          Ebs:
            VolumeType: st1
            DeleteOnTermination: 'true'
            VolumeSize: '500'
        - DeviceName: /dev/xvda
          Ebs:
            VolumeType: gp2
            DeleteOnTermination: 'true'
            VolumeSize: '8'
      ImageId: !FindInMap
        - AWSRegionArch2AMI
        - !Ref 'AWS::Region'
        - !FindInMap
          - AWSInstanceType2Arch
          - !Ref InstanceType
          - Arch
      NetworkInterfaces:
        - NetworkInterfaceId: !Ref EC2NI2E8ES
          DeviceIndex: "0"
      UserData:
        Fn::Base64:
          Fn::Sub:
            - |
              CONF="/etc/zookeeper/conf.dist/zoo.cfg"
              cp $CONF /etc/zookeeper/conf.dist/zoo.cfg.bak-$(date +%s)
              echo "# Zookeeper configuration for Talentreef" &gt; "$CONF"
              cat &lt;&lt;EOT &gt;&gt; "$CONF"
              maxClientCnxns=50
              tickTime=2000
              initLimit=10
              syncLimit=5
              EOT
              echo "server.1=${Private1}:2888:3888" &gt;&gt; $CONF
              echo "server.2=${Private2}:2888:3888" &gt;&gt; $CONF
              echo "server.3=${Private3}:2888:3888" &gt;&gt; $CONF
              service zookeeper-server init --myid=$NODE_ID
              chkconfig zookeeper-server on
            - {
              Private1: !GetAtt EC2NI2E8ES.PrimaryPrivateIpAddress,
              Private2: !GetAtt EC2NI2PFST.PrimaryPrivateIpAddress,
              Private3: !GetAtt EC2NI54B66.PrimaryPrivateIpAddress
              }
  EC2NI54B66:
    Type: 'AWS::EC2::NetworkInterface'
    DependsOn: EC2NI2PFST
    Properties: {}
  EC2NI2PFST:
    Type: 'AWS::EC2::NetworkInterface'
    DependsOn: EC2NI2E8ES
    Properties {}
  EC2NI2E8ES:
    Type: 'AWS::EC2::NetworkInterface'
    Properties: {}
  </code></pre>
  
  <p>When this script runs I get the following output in the <code>zoo.cfg</code> file:</p>
  
  <pre><code>maxClientCnxns=50
  tickTime=2000
  initLimit=10
  syncLimit=5
  server.1=:2888:3888
  server.2=:2888:3888
  server.3=:2888:3888
  </code></pre>
  
  <p>Please let me know if I'm doing something wrong here or if I have to change my approach. Thank you for the help.</p>