Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Deployment of servless app fails - Enable fine-grained access control or apply a restrictive access policy to your domain

I have a serverless app where I would like to deploy an elasticsearch cluster. I have configured it like this:

PostsSearch:
      Type: AWS::Elasticsearch::Domain
      Properties:
        ElasticsearchVersion: '6.3'
        DomainName: images-search-${self:provider.stage}
        ElasticsearchClusterConfig:
          DedicatedMasterEnabled: false
          InstanceCount: 1
          ZoneAwarenessEnabled: false
          InstanceType: t2.small.elasticsearch
        EBSOptions:
          EBSEnabled: true
          Iops: 0
          VolumeSize: 10
          VolumeType: 'gp2'
        AccessPolicies:
          Version: '2012-10-17'
          Statement:
            - Effect: Allow
              Principal:
                AWS: '*'
              Action: 'es:ESHttp*'
              Resource: '*'

But, I get an error:

An error occurred: PostsSearch - Enable fine-grained access control or apply a restrictive access policy to your domain (Service: AWSElasticsearch; Status Code: 400; Error Code: ValidationException; Request ID: be0eca95-23ae-4ac9-be81-67cab37ccd70; Proxy: null).

How should I fix this?

like image 314
Leff Avatar asked Oct 19 '20 11:10

Leff


People also ask

Which service is used to enable fine grained access control for users accessing your .NET applications and AWS resources?

Amazon Elasticsearch Service (Amazon ES) provides fine-grained access control, powered by the Open Distro for Elasticsearch security plugin.

What is fine grained access control AWS Elasticsearch?

Fine grained access control enables different teams to share an Amazon OpenSearch Service domain without being able to see or modify other teams' data, dashboards, or visualizations, enabling greater efficiency and centralizing management.

What is fine grained access control?

Fine-grained access control is a method of controlling who can access certain data. Compared to generalized data access control, also known as coarse-grained access control, fine-grained access control uses more nuanced and variable methods for allowing access.

What is an Elasticsearch domain?

Elasticsearch Service domains are Elasticsearch clusters created using the Elasticsearch Service console, CLI, or API. Each domain is the cluster in the cloud with the specified compute and storage resources. Enables you to create and delete domains, define infrastructure attributes, and control access and security.


1 Answers

Based on the extra discussion in the comments.

It is not possible to make an ES domain totally public. CloudFormation will not allow for that. Thus, there are three options to choose from. Below I present three of them with in a sample serverless application. This is just basic hello-world application, it does not use the ES domain in any capacity, but I use it to verify that each choice works and can be deployed using serverless framework without errors.

Apply IP-based condition

This will make your domain open for access to only individual IP address or IP CIDR range. The example below limits access to one, single IP address.

service: estest

provider:
  name: aws
  runtime: python3.8

  stage: ${opt:stage, 'dev'}
  region: ${opt:region, 'us-east-1'}  

functions:
  hello:
    handler: handler.hello

resources:
  Resources:
    PostsSearch:
      Type: AWS::Elasticsearch::Domain
      Properties:
        ElasticsearchVersion: '6.3'
        DomainName: images-search-${self:provider.stage}
        ElasticsearchClusterConfig:
          DedicatedMasterEnabled: false
          InstanceCount: 1
          ZoneAwarenessEnabled: false
          InstanceType: t2.small.elasticsearch
        EBSOptions:
          EBSEnabled: true
          Iops: 0
          VolumeSize: 10
          VolumeType: 'gp2'
        AccessPolicies:
          Version: '2012-10-17'
          Statement:
            - Effect: Allow
              Principal:
                AWS: '*'
              Action: 'es:ESHttp*'
              Resource: !Sub "arn:aws:es:${self:provider.region}:${AWS::AccountId}:domain/images-search-${self:provider.stage}/*"
              Condition:
                IpAddress:
                   aws:SourceIp: ["12.13.14.15"] 

Restrict principal

You can restrict access to your ES domain to selected IAM user or role. This way, only the given IAM user/role will be able to access the ES domain. In the below I use lambda existing IAM role as a principle. The function and its role must already exist.

service: estest

provider:
  name: aws
  runtime: python3.8

  stage: ${opt:stage, 'dev'}
  region: ${opt:region, 'us-east-1'}  

functions:
  hello:
    handler: handler.hello

resources:
  Resources:
    PostsSearch:
      Type: AWS::Elasticsearch::Domain
      Properties:
        ElasticsearchVersion: '6.3'
        DomainName: images-search-${self:provider.stage}
        ElasticsearchClusterConfig:
          DedicatedMasterEnabled: false
          InstanceCount: 1
          ZoneAwarenessEnabled: false
          InstanceType: t2.small.elasticsearch
        EBSOptions:
          EBSEnabled: true
          Iops: 0
          VolumeSize: 10
          VolumeType: 'gp2'
        AccessPolicies:
          Version: '2012-10-17'
          Statement:
            - Effect: Allow
              Action: 'es:ESHttp*'            
              Principal:
                AWS: !Sub "arn:aws:iam::${AWS::AccountId}:role/service-role/lambda-function-es-role-b44mvudf"
              Resource: !Sub "arn:aws:es:${self:provider.region}:${AWS::AccountId}:domain/images-search-${self:provider.stage}/*"


Use fine-grained access control

The example here creates publicly accessible ES domain with fine-grained controls that requires username and password. This does not work in free-tier. I also hard-coded username and password, which obviously would need to be modified and provided as a parameter from from SSM Parameter store in real application.

service: estest

provider:
  name: aws
  runtime: python3.8

  stage: ${opt:stage, 'dev'}
  region: ${opt:region, 'us-east-1'}  

functions:
  hello:
    handler: handler.hello

resources:
  Resources:
    PostsSearch:    
      Type: AWS::Elasticsearch::Domain
      Properties: 
        DomainName: images-search-${self:provider.stage}        
        AccessPolicies: !Sub |
          {
            "Version": "2012-10-17",
            "Statement": [
              {
                "Effect": "Allow",
                "Principal": {
                  "AWS": "*"
                },
                "Action": "es:*",
                "Resource": "*"
              }
            ]
          }
        AdvancedSecurityOptions:
            Enabled: true
            InternalUserDatabaseEnabled: true
            MasterUserOptions: 
              MasterUserName: admin
              MasterUserPassword: fD343sfdf!3rf
        EncryptionAtRestOptions: 
          Enabled: true
        NodeToNodeEncryptionOptions:
          Enabled: true
        DomainEndpointOptions:
          EnforceHTTPS: true
        EBSOptions: 
          EBSEnabled: true
          VolumeSize: 20
          VolumeType: gp2
        ElasticsearchClusterConfig: 
          DedicatedMasterEnabled: false
          InstanceCount: 1
          InstanceType: c4.large.elasticsearch
          ZoneAwarenessEnabled: false
        ElasticsearchVersion: 7.7
like image 160
Marcin Avatar answered Sep 20 '22 15:09

Marcin