При использовании аутентификации по базе данных IAM срок действия пароля истекает примерно через 15 минут. Поэтому в идеале мне нужно обновить соединение с базой данных до истечения срока действия пароля. Я устанавливаю таймер при первой инициализации базы данных и запрашиваю прошедшее время по каждому запросу. Как я могу обновить пароль соединения до истечения срока действия пароля? Или как я могу уничтожить старый объект базы данных и при необходимости обновить объект?

Сообщение об ошибке: «Аутентификация PAM не удалась для пользователя iam_user».

Код для получения IAM пароля:

const pgp = require('pg-promise')();
const AWS = require('aws-sdk');
const ca =
  '-----BEGIN CERTIFICATE-----\nMIID9DCCAtyg...
   ...wZfTUU=\n-----END CERTIFICATE-----\n';

const signer = new AWS.RDS.Signer({
  region: process.env.REGION,
  username: process.env.DATABASE_USER,
  hostname: process.env.DATABASE_HOST,
  port: parseInt(`${process.env.DATABASE_PORT}`, 10),
});

module.exports = pgp({
  host: process.env.DATABASE_HOST,
  port: process.env.DATABASE_PORT,
  database: process.env.DATABASE_NAME,
  user: process.env.DATABASE_USER,
  ssl: { ca },
  dialectOptions: { ssl: { require: true } },
  password: signer.getAuthToken(),
});

Вставка объекта db в graphql:

const db = require('../db/init');
server.use(
    mount(
      '/graphql',
      graphqlHTTP( () => ({
        schema: schema,
        context: { startTime: Date.now(), db },
        graphiql: true
      })),
    ),
  );

Использование базы данных в резолверах.

Я мог запросить время создания соединения с базой данных. Есть ли возможность обновить пароль при необходимости? Или как лучше всего уничтожить старый объект базы данных и создать новый объект базы данных?

const resolvers = {
Query: {
    Post: (root, args, {db}) => {
      console.log(args.id);
      console.log(db.$config.options)
      const postQuery = new PQ({
        text:
          'SELECT post_id as id FROM tbl_post where post_id = $1',
        values: [parseInt(args.id, 10)],
      });
      return db.one(postQuery).catch((err) => console.log(err));
    }
}
1
Florat 1 Ноя 2019 в 19:16
Каково отношение подключения к базе данных к истечению срока действия вашего пароля?
 – 
vitaly-t
2 Ноя 2019 в 08:31
Привет, Виталий-т, прежде всего я хотел бы поблагодарить вас за вашу прекрасную библиотеку и за то, что вы чрезвычайно полезны для всех, кто обращается за помощью. Насколько я понял из документации, я могу получить доступ (только для чтения) к настройкам подключения с помощью database.$cn. Но я не могу обновить пароль в соединении с базой данных. Поэтому я попытался завершить пулы с помощью pgp.end() / db.$pool.end() и воссоздать пул. Но затем при стресс-тестировании я получаю тайм-ауты соединения. Поэтому мне было интересно, есть ли лучший способ изменить пароль только в объекте открытой базы данных, который я обновляю с помощью signer.getAuthToken().
 – 
Florat
2 Ноя 2019 в 12:21
1
Почему нельзя просто использовать функцию для пароля? Это то, что он делает, предоставляет динамический пароль.
 – 
vitaly-t
2 Ноя 2019 в 13:14
1
Пароль-функция вызывается только для новых подключений. Идея состоит в том, что когда срок действия пароля базы данных истекает, соединение становится недействительным, т. е. разрывается, и в этом случае соединение прерывается, а затем автоматически выделяется при получении нового пароля. Пароль-функция не должна вызываться без какой-либо причины, так как вы работаете с пулом соединений, который кэширует живые соединения. Поскольку вы используете GraphQL, возможно, мне следует проконсультироваться в вашем случае.
 – 
vitaly-t
2 Ноя 2019 в 16:15
1
Если я подключаюсь повторно с интервалом менее 10 секунд, то пароль не обновляется с помощью функции, но соединение остается открытым. Если я повторно подключаюсь с интервалом более 10 секунд, функция обновления пароля вызывается при каждом вызове. В любом случае это работает. Спасибо за помощь.
 – 
Florat
2 Ноя 2019 в 18:09

1 ответ

Как предложил Виталий-т, я использовал функцию пароля. Чтобы избежать увеличения задержки, эта функция обновляет пароль только каждые 15 минут. Если пул постоянно используется с интервалами менее 10 секунд, то соединение остается открытым без вызова функции пароля вообще. По моим тестам новых подключений к БД вообще не открывается.

const ca = '-----BEGIN CERTIFICATE-----\9DC...-----END CERTIFICATE-----\n';

const signer = new AWS.RDS.Signer({
    region: process.env.REGION,
    username: process.env.DATABASE_USER,
    hostname: process.env.DATABASE_HOST,
    port: parseInt(`${process.env.DATABASE_PORT}`, 10),
});

const SIGNER = { time: 0, password: undefined};

function getSignedPassword() {
    const time = Date.now();
    if (time - SIGNER.time > 900000) {
        SIGNER.time = new Date().getTime();
        SIGNER.password = signer.getAuthToken();
        return SIGNER.password;
    }
  return SIGNER.password;
}

module.exports = pgp({
    host: process.env.DATABASE_HOST,
    port: process.env.DATABASE_PORT,
    database: process.env.DATABASE_NAME,
    user: process.env.DATABASE_USER,
    ssl: { ca },
    password: getSignedPassword,
});
1
Florat 8 Ноя 2019 в 11:34