AWS Elastic Search Policy, only allow lambda to access Elastic Search

Viewed 2020

I'm working on setting up an ElasticSearch instance on AWS. My goal is to only allow http request from my Lambda function to the ElasticSearch instance. I have created one policy, that gives the 'Lambdaaccess to theElasticSearchinstance. The part I'm struggling with is the inline resource policy forElasticSearchthat will deny all other request that aren't from the 'Lambda.

I have tried setting the ElasticSearch resource policy to Deny all request and then giving my Lambda a role with access to ElasticSearch. While the Lambda is using that role I am signing my http requests using axios and aws4 but the request are rejected with The request signature we calculated does not match the signature you provided. I don't think the issue is the actual signing of the request but instead the polices I created. If anyone can steer me in the right direction that would really help.

Lambda Policy

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "VisualEditor0",
            "Effect": "Allow",
            "Action": [
                "es:ESHttpGet",
                "es:CreateElasticsearchDomain",
                "es:DescribeElasticsearchDomainConfig",
                "es:ListTags",
                "es:ESHttpDelete",
                "es:GetUpgradeHistory",
                "es:AddTags",
                "es:ESHttpHead",
                "es:RemoveTags",
                "es:DeleteElasticsearchDomain",
                "es:DescribeElasticsearchDomain",
                "es:UpgradeElasticsearchDomain",
                "es:ESHttpPost",
                "es:UpdateElasticsearchDomainConfig",
                "es:GetUpgradeStatus",
                "es:ESHttpPut"
            ],
            "Resource": "arn:aws:es:us-east-1:,accountid>:domain/<es-instance>"
        },
        {
            "Sid": "VisualEditor1",
            "Effect": "Allow",
            "Action": [
                "es:PurchaseReservedElasticsearchInstance",
                "es:DeleteElasticsearchServiceRole"
            ],
            "Resource": "*"
        }
    ]
}

ElasticSearch Inline Policy

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Deny",
      "Principal": {
        "AWS": [
          "*"
        ]
      },
      "Action": [
        "es:*"
      ],
      "Resource": "arn:aws:es:us-east-1:<account-number>:domain/<es-instance>/*"
    }
  ]
}

Lambda Code Using Aws4 and Axios

//process.env.HOST = search-<es-instance>-<es-id>.us-east-1.es.amazonaws.com
function createRecipesIndex(url, resolve, reject){

         axios(aws4.sign({
            host: process.env.HOST,
            method: "PUT",
            url: "https://" + process.env.HOST,
            path: '/recipes/',
       }))
      .then(response => {
          console.log("----- SUCCESS INDEX CREATED -----");
        resolve();
      })
      .catch(error => {
          console.log("----- FAILED TO CREATE INDEX -----");
        console.log(error);
        reject();
      });
}

Note: I have tried creating my index with the inline policy on ElasticSearch set to allow *(all) and removing the aws4 library signature and it works fine. Right now I just want to secure access to this resource.

1 Answers

I found the solution to my issue and it was 2 fold. The first issue was my inline resource policy on my ElasticSearch instance. I needed to update it to allow the role that I have given to my Lambda. This was done by getting the role arn from IAM and then creating the below policy to be attached inline on the ElasticSearch instance.

My second issue was with aws4. the path and the url I set did not match. My path had /xxxx/ while my url was https://search-<es-instance>-<es-id>.us-east-1.es.amazonaws.com/xxxx. Since the path contained an extra forward slash not found in the url, the signing failed. For anyone else using the library make sure those values are consistent. I hope this helps someone else out in the future :D

Elastic Search Policy

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "AWS": "arn:aws:iam::<account-id>:role/service-role/<role-name>"
      },
      "Action": "es:*",
      "Resource": "arn:aws:es:us-east-1:<account-id>:domain/<es-instance>/*"
    }
  ]
}
Related