2017-01-30 5 views
0

Я отправляю json в AWS elasticsearch, используя функцию лямбда java.Почему я получаю 403 запрещенную ошибку при отправке json в конечную точку elasticsearch на AWS?

public Object handleRequest(DynamodbEvent dynamodbEvent, Context context) { 

      //code to general the json document  
      AmazonDynamoDBClient amazonDynamoDBClient = new AmazonDynamoDBClient(); 

    List<DynamodbEvent.DynamodbStreamRecord> dynamodbStreamRecordlist = dynamodbEvent.getRecords(); 

    if (!dynamodbStreamRecordlist.isEmpty()) { 
     DynamodbEvent.DynamodbStreamRecord record = dynamodbStreamRecordlist.get(0); 
     if(record.getEventSource().equalsIgnoreCase("aws:dynamodb")) 
      tableName = getTableNameFromARN(record.getEventSourceARN()); 
    } 
    LaneAnnotation laneAnnotation = new LaneAnnotation(); 

    ScanRequest scanRequest = new ScanRequest().withTableName(tableName); 
    ScanResult result = amazonDynamoDBClient.scan(scanRequest); 

    List<Lines> linesFinalList = new ArrayList<Lines>(); 

    if(result != null) { 
     for (Map<String, AttributeValue> item : result.getItems()) {  

     //code for looping through the table items and generating a json  object for the elastic search model 
     }  

      //Code to post the json below - 
      RestTemplate restTemplate = new RestTemplate(); 
      SimpleClientHttpRequestFactory clientHttpRequestFactory = (SimpleClientHttpRequestFactory)restTemplate.getRequestFactory(); 
      clientHttpRequestFactory.setConnectTimeout(10000); 
      clientHttpRequestFactory.setReadTimeout(10000); 

      HttpEntity<String> entity = new HttpEntity<String>(<json goes here>, headers); 

      try{ 
       restTemplate.exchange(endpoint, HttpMethod.POST, entity, String.class); 
      }catch(Exception e){ 
       e.printStackTrace(); 
      } 
} 

Однако, я вижу следующее сообщение об ошибке, когда я проверить свою функцию лямбда-AWS -

org.springframework.web.client.HttpClientErrorException: 403 Forbidden 
    at org.springframework.web.client.DefaultResponseErrorHandler.handleError(DefaultResponseErrorHandler.java:91) 
    at org.springframework.web.client.RestTemplate.handleResponse(RestTemplate.java:700) 
    at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:653) 
    at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:613) 
    at org.springframework.web.client.RestTemplate.exchange(RestTemplate.java:531) 
    at com.here.aws.LambdaApplication.handleRequest(LambdaApplication.java:166) 
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) 
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) 
    at java.lang.reflect.Method.invoke(Method.java:498) 
    at lambdainternal.EventHandlerLoader$PojoMethodRequestHandler.handleRequest(EventHandlerLoader.java:456) 
    at lambdainternal.EventHandlerLoader$PojoHandlerAsStreamHandler.handleRequest(EventHandlerLoader.java:375) 
    at lambdainternal.EventHandlerLoader$2.call(EventHandlerLoader.java:1139) 
    at lambdainternal.AWSLambda.startRuntime(AWSLambda.java:285) 
    at lambdainternal.AWSLambda.<clinit>(AWSLambda.java:57) 
    at java.lang.Class.forName0(Native Method) 
    at java.lang.Class.forName(Class.java:348) 
    at lambdainternal.LambdaRTEntry.main(LambdaRTEntry.java:94) 

Я даже изменил политику доступа и добавил свой IP-адрес. Неужели другие тоже сталкиваются с этим? Как вы его разрешили?> Любая помощь будет оценена.

EDIT1: Я сейчас пытаюсь включить подписание запроса, как указано здесь - https://aws.amazon.com/blogs/security/how-to-control-access-to-your-amazon-elasticsearch-service-domain/
доложит, если она идет хорошо.

EDIT2:

Вот второй способ отправки запроса, который я пытался со ссылкой на ссылку выше-

@Override 
    public Object handleRequest(DynamodbEvent dynamodbEvent, Context context) { 

     AmazonDynamoDBClient amazonDynamoDBClient = new AmazonDynamoDBClient(); 

     List<DynamodbEvent.DynamodbStreamRecord> dynamodbStreamRecordlist = dynamodbEvent.getRecords(); 

     if (!dynamodbStreamRecordlist.isEmpty()) { 
      DynamodbEvent.DynamodbStreamRecord record = dynamodbStreamRecordlist.get(0); 
      if(record.getEventSource().equalsIgnoreCase("aws:dynamodb")) 
       tableName = getTableNameFromARN(record.getEventSourceARN()); 
     } 
     LaneAnnotation laneAnnotation = new LaneAnnotation(); 

     ScanRequest scanRequest = new ScanRequest().withTableName(tableName); 
     ScanResult result = amazonDynamoDBClient.scan(scanRequest); 

     List<Lines> linesFinalList = new ArrayList<Lines>(); 

     if(result != null) { 
      for (Map<String, AttributeValue> item : result.getItems()) { 
      //Generate the json object that needs to be sent in the request 

     } 

     HttpHeaders headers = new HttpHeaders(); 
     headers.setContentType(MediaType.APPLICATION_JSON_UTF8); 

     Request<?> request = new DefaultRequest<Void>(SERVICE_NAME); 
     request.setContent(new ByteArrayInputStream(elasticSearchModel.toString().getBytes())); 
     request.setEndpoint(URI.create(endpoint)); 
     request.setHttpMethod(HttpMethodName.POST); 

     AWS4Signer signer = new AWS4Signer(); 
     signer.setServiceName(SERVICE_NAME); 
     signer.setRegionName(Regions.US_EAST_1.getName()); 

     AWSCredentialsProvider credsProvider = 
       new DefaultAWSCredentialsProviderChain(); 

     AWSCredentials creds = credsProvider.getCredentials(); 

     // Sign request with supplied creds 
     signer.sign(request, creds); 
     log.info("Request signed"); 

     ExecutionContext executionContext = new ExecutionContext(true); 

     ClientConfiguration clientConfiguration = new ClientConfiguration(); 
     AmazonHttpClient client = new AmazonHttpClient(clientConfiguration); 

     MyHttpResponseHandler<Void> responseHandler = new MyHttpResponseHandler<Void>(); 
     MyErrorHandler errorHandler = new MyErrorHandler(); 

     Response<Void> response = 
       client.execute(request, responseHandler, errorHandler, executionContext); 

     return dynamodbEvent; 
    } 

Однако, я получаю следующее сообщение об ошибке -

Check the signature you provided. Check your AWS Secret Access Key and signing method. Consult the service documentation for details. 

    The Canonical String for this request should have been 
    'GET 
    /

    host:somehostname-XXXXXXXXXXXXXXXX.us-east-1.es.amazonaws.com 
    x-amz-date:20170130T105736Z 
    x-amz-security-token:FQoDYXdzEG4aDJJ4ryjXXXXXXXXXXXXXXXX/auMHooYENY6YXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX 

    host;x-amz-date;x-amz-security-token 
    e3b0c4429XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX' 

    The String-to-Sign should have been 
    'AWS4-HMAC-SHA256 
    20170130T105736Z 
    20170130/us-east-1/es/aws4_request 
    9a5b4c92ec121c333f8cdXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX' 
    "}" 

10:57:36.818 [main] DEBUG org.apache.http.headers - http-outgoing-1 << HTTP/1.1 403 Forbidden 
+0

Может быть несколько вещей, которые могут вызвать это. Индекс ors устанавливается только для чтения (то есть когда ES сам возвращает 403), или если вы используете прокси перед ним или у вас нет доступа к записи в этот индекс. – chaos

+0

Это потому, что мне нужно добавить аутентификацию в запрос? Я просто загружаю свою банку лямбды на s3 и использую ее url для проверки моей лямбда-функции. Я добавил еще один код выше, чтобы показать, как я извлекаю элементы из своей таблицы. –

+0

Просто нашел это - https://aws.amazon.com/blogs/security/how-to-control-access-to-your-amazon-elasticsearch -service-domain/Позвольте мне попробовать, и я обновляю здесь, как это произошло. –

ответ

0

AWS Elastic Search имеет шлюз безопасности, который обеспечивает аутентификацию. Параметры аутентификации настраиваются в консоли AWS Elastic Search.

Вы получаете ошибку проверки подлинности 403, потому что ваша политика доступа к ресурсу AWS не позволяет IP-адрес шлюза NAT, который использует ваша Лямбда.

http://docs.aws.amazon.com/elasticsearch-service/latest/developerguide/es-createupdatedomains.html#es-createdomain-configure-access-policies

Вот шаблон политики доступа, которые можно использовать для проверки подлинности на основе IP.

{ 
    "Version": "2012-10-17", 
    "Statement": [ 
     { 
      "Effect": "Allow", 
      "Principal": { 
       "AWS": "*" 
      }, 
      "Action": "es:*", 
      "Resource": "arn:aws:es:us-east-1:YOUR-AWS-ACCOUNT-ID:domain/YOUR-ELASTICSEARCH-DOMAIN-NAME/*", 
      "Condition": { 
       "IpAddress": { 
        "aws:SourceIp": [ 
         "YOUR-NAT-GATEWAY-PUBLIC-IP/32" 
        ] 
       } 
      } 
     } 
    ] 
}