47

I am trying to create a VPC controlled Elastic Search Service on AWS. The problem is I keep getting the error when I run the following code: 'ValidationException: Before you can proceed, you must enable a service-linked role to give Amazon ES permissions to access your VPC'.

const AWS = require('aws-sdk');
AWS.config.update({region:'<aws-datacenter>'});
const accessPolicies = {
  Statement: [{
    Effect: "Allow",
    Principal: {
      AWS: "*"
    },
    Action: "es:*",
    Resource: "arn:aws:es:<dc>:<accountid>:domain/<domain-name/*"
  }]
};
const params = {
  DomainName: '<domain>',
  /* required */
  AccessPolicies: JSON.stringify(accessPolicies),
  AdvancedOptions: {
    EBSEnabled: "true",
    VolumeType: "io1",
    VolumeSize: "100",
    Iops: "1000"
  },
  EBSOptions: {
    EBSEnabled: true,
    Iops: 1000,
    VolumeSize: 100,
    VolumeType: "io1"
  },
  ElasticsearchClusterConfig: {
    DedicatedMasterCount: 3,
    DedicatedMasterEnabled: true,
    DedicatedMasterType: "m4.large.elasticsearch",
    InstanceCount: 2,
    InstanceType: 'm4.xlarge.elasticsearch',
    ZoneAwarenessEnabled: true
  },
  ElasticsearchVersion: '5.5',
  SnapshotOptions: {
    AutomatedSnapshotStartHour: 3
  },
  VPCOptions: {
    SubnetIds: [
      '<redacted>',
      '<redacted>'
    ],
    SecurityGroupIds: [
      '<redacted>'
    ]
  }
};

const es = new AWS.ES();
es.createElasticsearchDomain(params, function (err, data) {
  if (err) {
    console.log(err, err.stack); // an error occurred
  } else {
    console.log(JSON.stringify(data, null, 4)); // successful response
  }
});

The problem is I get this error: ValidationException: Before you can proceed, you must enable a service-linked role to give Amazon ES permissions to access your VPC. I cannot seem to figure out how to create this service linked role for the elastic search service. In the aws.amazon.com IAM console I cannot select that service for a role. I believe it is supposed to be created automatically.

Has anybody ran into this or know the way to fix it?

Michael Young
  • 650
  • 1
  • 6
  • 8
  • I am also getting the same error while creating `elasticsearch` domain in a VPC using `aws-cloudformation` templates. Looks like there is no way to set service linked role in [VPCOptions](http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-elasticsearch-domain-vpcoptions.html#aws-properties-elasticsearch-domain-vpcoptions-seealso). Amazon ES requires a service-linked role to access your VPC, create the domain endpoint, and place network interfaces in a subnet of your VPC. – Rishikesh Darandale Nov 28 '17 at 12:40

5 Answers5

74

The service-linked role can be created using the AWS CLI.

aws iam create-service-linked-role --aws-service-name opensearchservice.amazonaws.com

Previous answer: before the service was renamed, you would do the following:

aws iam create-service-linked-role --aws-service-name es.amazonaws.com
Oscar Barrett
  • 3,135
  • 31
  • 36
  • 2
    Since the AWS move to OpenSearch it is now `aws iam create-service-linked-role --aws-service-name opensearchservice.amazonaws.com` – Dan-Dev May 19 '22 at 10:11
  • after 2 hours of debugging, I don't know how to be calm and answer how great this solution is! Sometimes, I just miss GCP :( – confiq Oct 17 '22 at 13:57
25

You can now create a service-linked role in a CloudFormation template, similar to the Terraform answer by @htaccess. See the documentation for the CloudFormation syntax for Service-Linked Roles for more details

YourRoleNameHere:
  Type: 'AWS::IAM::ServiceLinkedRole'
  Properties:
    AWSServiceName: es.amazonaws.com
    Description: 'Role for ES to access resources in my VPC'
tryinHard
  • 566
  • 8
  • 8
  • 2
    Maybe it was something wrong with my config, but even with a "DependsOn" between the service linked role and the ES Domain I still got the same error message. It *did* however work if I launched a CF template that did what you describe, *followed by* another template that had the ES Domain, but unfortunately that wasn't very useful for me. – Ocelot20 Mar 08 '19 at 06:55
  • 1
    I was creating other things in my template, so I used additional `DependsOn`s to let the role create first, create other things, then create the ES Domain as late as possible. Guessing it's due to IAM's eventual consistency. – Nate Fox May 28 '19 at 23:51
  • This did not work when I had the ServiceLinkedRole in the same CF-script as creating the elasticsearch-domain. Is there any handy ways of waiting? Tried with depends on and that did not work. Worked when I create the role independently with aws cli, but would prefer to have all config in CF. – olovholm Jan 06 '21 at 11:01
22

For terraform users who hit this error, you can use the aws_iam_service_linked_role resource to create a service linked role for the ES service:

resource "aws_iam_service_linked_role" "es" {
    aws_service_name = "es.amazonaws.com"
    description      = "Allows Amazon ES to manage AWS resources for a domain on your behalf."
}

This resource was added in Release 1.15.0 (April 18, 2018) of the AWS Provider.

htaccess
  • 2,800
  • 26
  • 31
  • 1
    I did that but now I cannot delete it. I get an error in the console that says: 'At least one domain is using service linked role' ? How do I fix it? – atom88 Nov 30 '21 at 23:39
19

Creating a elasticsearch domain with VPC and using aws-sdk/cloudformation is currently not supported. The elasticsearch service requires a special service linked role to create the network interfaces in the specified VPC. This currently possible using console / cli(@Oscar Barrett's answer below).

However, there is a workaround to get this working and it is described as follows:

  • Create a test elasticsearch domain with VPC access using console.
  • This will create a service linked role named AWSServiceRoleForAmazonElasticsearchService [Note: You can not create the role with specified name manually or through thr console]
  • Once this role is created, use aws-sdk or cloudformation to create elasticsearch domain with VPC.
  • You can delete the test elasticsearch domain later

Update: The more correct way to create the service role is described in @Oscar Barrett's answer. I was thinking to delete my answer; but the other facts about the actual issue is still more relevant, thus keeping my answer here.

Rishikesh Darandale
  • 3,222
  • 4
  • 17
  • 35
6

Do it yourself in CDK:

const serviceLinkedRole = new cdk.CfnResource(this, "es-service-linked-role", {
  type: "AWS::IAM::ServiceLinkedRole",
  properties: {
    AWSServiceName: "es.amazonaws.com",
    Description: "Role for ES to access resources in my VPC"
  }
});

const esDomain = new es.CfnDomain(this, "es", { ... });

esDomain.node.addDependency(serviceLinkedRole);
Otto
  • 1,787
  • 1
  • 17
  • 25
  • 1
    AWS CDK issue ref https://github.com/aws/aws-cdk/issues/3734 – Wingjam May 18 '22 at 19:27
  • the result of this is still "Cannot find Service Linked Role template for opensearch.amazonaws.com (Service: AmazonIdentityManagement; Status Code: 403;" in my case I use opensearch name – ses Mar 01 '23 at 14:11