Мой интерфейс с AWS Lambda и аутентификацией IAM завершается ошибкой аутентификации PAM

#java #postgresql #aws-lambda #mybatis #pam

Вопрос:

Я пытаюсь подключиться к экземпляру RDS Aurora Postgres с помощью IAM auth и MyBatis-Guice для запуска некоторых операторов вставки. Изначально настройка работает нормально. Однако через некоторое время вызов lambda завершается ошибкой с FATAL: PAM authentication failed for user "xxx" . Обычно это происходит при одновременных вызовах. Но затем следующие вызовы завершаются успешно.

Это мой метод ДАО:

 @Transactional(executorType=ExecutorType.BATCH, isolationType=Isolation.READ_COMMITTED)
public void insertEntities(List<Entity> entities) {
    for(Entity entity: entities) {
        myMapper.insert(entity);
    }
}
 

Эта ошибка не должна возникать, поскольку токен IAM и Лямбда имеют ограничение по времени 15 минут.
Кроме того, просматривая исходный код, я вижу, что dataSourceProvider привязан к источнику данных в одноэлементной области в MyBatisModule. Я предполагаю, что какой-то параллельный getAuthToken() вызов лямбды изменяет ожидаемый токен для роли postgres, и когда вызывается любая другая «теплая» параллельная лямбда (вместе с лямбдой, которая изменила пароль) и открывает новый управляемый сеанс с источником данных, настроенным на более старый токен, он получает сообщение об PAM authentication ошибке.

Как я мог бы смягчить это?

Ответ №1:

Я устанавливал пароль каждый раз, когда вызывалась лямбда — функция. Я внес несколько изменений в свой метод DAO и использовал SqlSession вместо картографов. Это делается для того, чтобы избежать кэширования SqlSession, которое выполняет базовый SqlSessionManager при использовании методов сопоставления непосредственно в mybatis-guice @Transactional . Используемый здесь SqlSessionFactory находится в одноэлементной области и вводится в экземпляр DAO.

 public void insertEntities(List<Entity> entites) {
  try(SqlSession session = sqlSessionFactory.openSession(ExecutorType.BATCH, TransactionIsolationLevel.READ_COMMITTED) {
    try {
      MyMapper myMapper = session.getMapper(MyMapper.class);
      // do something
      session.commit();
    } catch(Exception e) {
      session.rollback();
      throw e;
    }
  }
}
 

И при каждом вызове я устанавливаю пароль в качестве маркера аутентификации IAM в источнике данных.

 MyDataSource dataSource = (MyDataSource) sqlSessionFactory.getConfiguration().getEnvironment().getDataSource();
dataSource.setPassword(generator.getAuthToken(request));
 

Теперь всякий раз, когда вызывается функция Lambda, источник данных будет иметь новый токен аутентификации и сможет подключаться к базе данных.