Cloudformation circular dependancy with elasticsearch

amazon-cloudformationamazon-web-serviceselasticsearch

I'm trying to create a cloudformation template that will have, among other things, an ec2 instance with and EIP and an elasticsearch domain. The issue is that I'm creating a circular dependancy that I'm unable to figure out how to uncouple. Here it is.

The ec2 instance needs the address of the elasticsearch domain, so I'm adding it to a file in the UserData.

The elasticsearch AccessPolicies need the public IP of the EC2 instance to allow access from that server.

So there it is. Elasticsearch depends on the EIP of an ec2 instance, and the ec2 instance depends on the address of the elasticsearch domain. So what I'm trying to do is use the EIPAssociation to delay the need to create the EC2Instance until after the ElasticSearch domain has been created. But still no luck.

Does anyone have a good solution to this issue? I know I can have an AccessPolicy that is IAM based, but I'd much rather use the IP.

Thanks in advance.

Here is the code:

"MyEIP" : {
  "Type" : "AWS::EC2::EIP"
},
"ElasticsearchDomain": {
  "Type": "AWS::Elasticsearch::Domain",
  "Properties": {
    "ElasticsearchClusterConfig": {
      "DedicatedMasterEnabled": "false",
      "InstanceCount": "1",
      "ZoneAwarenessEnabled": "false",
      "InstanceType": "t2.micro.elasticsearch"
    },
    "EBSOptions": {
      "EBSEnabled": true,
      "Iops": 0,
      "VolumeSize": 10,
      "VolumeType": "gp2"
    },
    "SnapshotOptions": {
      "AutomatedSnapshotStartHour": "0"
    },
    "AccessPolicies":{
      "Version": "2012-10-17",
      "Statement": [
        {
          "Sid": "",
          "Effect": "Allow",
          "Principal": {
            "AWS": "*"
          },
          "Action": "es:*",
          "Resource": { "Fn::Join" : [ "", [
            "arn:aws:es:us-east-1:00000000000:domain/",
            { "Ref" : "ElasticsearchDomain" },
            "/*"
          ]]},
          "Condition": {
            "IpAddress": {
              "aws:SourceIp": { "Ref" : "MyEIP" }
            }
          }
        }
      ]
    },
    "AdvancedOptions": {
      "rest.action.multi.allow_explicit_index": "true"
    }
  }
},
"Ec2Instance" : {
  "Type" : "AWS::EC2::Instance",
  "Properties" : {
    "ImageId" : { "Fn::FindInMap" : [ "RegionMap", { "Ref" : "AWS::Region" }, "64"]},
    "KeyName" : { "Ref" : "KeyName" },
    "InstanceType" : { "Ref": "ServerInstanceType" },
    "SecurityGroups" : [ { "Ref" : "InstanceSecurityGroup" } ],
    "Tags": [{
      "Key" : "Name",
      "Value" : {
        "Fn::Join" : [ "", [
          { "Ref" : "AWS::StackName" }
        ]]
      }
    }],
      "UserData" : { "Fn::Base64" : { "Fn::Join" : [ "", [
      "#!/bin/bash -ex\n",
      "echo \"",
      "STACK_NAME=", { "Ref" : "AWS::StackName"}, "\n",
      "ELASTICSEARCH_CLIENT=https://", { "Fn::GetAtt": [ "ElasticsearchDomain", "DomainEndpoint" ] }, "/\n",
  "\n",
      "\" > /etc/uni_creds\n"
    ]]}}
  }
},
"EIPAssociation" : {
   "Type": "AWS::EC2::EIPAssociation",
   "Properties": {
      "EIP": { "Ref" : "MyEIP" },
      "InstanceId": { "Ref" : "Ec2Instance" }
   }
}

Best Answer

I think I've solved my issue. Although I was getting an error that was saying there was a circular dependancy between the EC2 instance, elasticsearch domain, and the EIP or EIPAssociation, the actual error was that I was referencing my elasticsearch domain in my elasticsearch domain.

"ElasticsearchDomain": {
  "Type": "AWS::Elasticsearch::Domain"
  ...
  { "Ref" : "ElasticsearchDomain" },
}

Which would obviously cause an issue. The error message was what got me running up he wrong tree. Anyway, dumb mistake. Hopefully no one else runs into this.

Related Topic