Как обновляются учетные данные с помощью кэшированного клиента boto3 и параллелизма с поддержкой Lambda?

#amazon-web-services #caching #aws-lambda #boto3 #credentials

Вопрос:

Следуя рекомендациям по использованию преимуществ повторного использования среды выполнения для повышения производительности вашей функции, я изучаю, оказывает ли кэширование boto3 клиента какой-либо негативный эффект при использовании параллелизма с поддержкой Лямбда. boto3 Клиент кэшируется через @lru_cache декоратор и инициализируется с задержкой. Теперь проблема заключается в том, что базовые учетные boto3 данные клиента не обновляются, поскольку предусмотренный параллелизм сохранит среду выполнения в течение неизвестного периода времени. Этот срок службы может быть больше, чем срок действия временных учетных данных, введенных лямбда-средой.

Я не смог найти ни одного документа, объясняющего, как ведется это дело. Кто-нибудь знает, как лямбда-среда обрабатывает обновление учетных данных в приведенном выше случае?

Комментарии:

1. Вы имеете в виду «лямбда-слой», как в лямбда-слоях или в лямбда-среде выполнения?

2. Среда выполнения. Я отредактировал вопрос. Спасибо!

Ответ №1:

Если вы используете жестко закодированные учетные данные:

У вас есть более серьезная проблема с безопасностью, чем «повторно используемые» учетные данные, и вам следует немедленно удалить их.

Из документации:

Не помещайте буквальные ключи доступа в файлы приложений. Если вы это сделаете, вы создадите риск случайного раскрытия ваших учетных данных, если, например, вы загрузите проект в общедоступное хранилище.

Не включайте файлы, содержащие учетные данные, в область вашего проекта.

Замените их ролью исполнителя.


Если вы используете роль выполнения:

Вы не предоставляете никаких учетных данных вручную для любых вызовов AWS SDK. Учетные данные для SDK автоматически поступают из роли выполнения лямбда-функции.

Даже если учетные данные роли Boto3 совместно используются при вызовах под капотом для обеспечения параллелизма (никто не уверен), в чем будет проблема?

Позвольте Amazon разобраться с учетными данными ролей — вы вообще не несете ответственности за управление этим.


Я бы больше беспокоился о том, что код приложения имеет недостатки в безопасности, в отличие от автоматической аутентификации запросов SDK Amazon с учетными данными роли выполнения.

Комментарии:

1. 1 к вопросу о безопасности. На самом деле, я использую роль исполнителя. Я хотел получить подтверждение того, что вы сказали. Уверены ли мы, что лямбда-система принимает меры по уничтожению и воссозданию среды exe с истекшими учетными данными?

2. Если срок их действия истекает, у них должно быть что- то внутреннее во время выполнения, чтобы обновить их, так как в противном случае, как бы они работали после истечения срока действия? Их реализация будет настолько безопасной, насколько это возможно, поскольку они обеспечивают безопасность облака. Используйте роли, и вам не нужно будет беспокоиться о какой — либо форме учетных данных-это ненужная головная боль, чтобы пытаться думать о внутренних реализациях 🙂

3. На самом деле важно знать, как они меняют эти временные учетные данные, чтобы избежать «сюрпризов» в производстве. У вас есть какие-нибудь рекомендации, которыми вы могли бы поделиться по поводу того, что вы сказали?

4. Нет никаких сюрпризов при использовании ролей выполнения в соответствии с рекомендациями AWS — я не против, попробуйте поддержку AWS. Все, что я сказал, соответствует действительности в соответствии с документами AWS

Ответ №2:

Это не так.

Документация для Boto3 не очень хорошо описывает цепочку учетных данных, но в документации CLI показаны различные источники учетных данных (и, поскольку CLI написан на Python, он предоставляет авторитетную документацию).

В отличие от EC2 и ECS, которые извлекают учетные данные на основе ролей из метаданных экземпляра, Lambda предоставляет учетные данные в переменных среды. Среда выполнения Lambda устанавливает эти переменные среды при запуске, и каждый вызов этой среды выполнения Lambda использует одни и те же значения.

Параллельные лямбды получают отдельные наборы учетных данных, точно так же, как если бы вы одновременно выполняли явные вызовы STS AssumeRole .

Обеспеченный параллелизм немного сложнее. Вы можете подумать, что одна и та же среда выполнения Lambda живет «вечно», но на самом деле это не так: если вы неоднократно вызываете Lambda с предоставленным параллелизмом, вы увидите, что в какой-то момент она создает новый поток журнала CloudWatch. Это указывает на то, что Lambda запустила новую среду выполнения. Lambda завершит инициализацию новой среды выполнения до того, как прекратит отправку запросов в старую среду выполнения, поэтому вы не получите задержку холодного запуска.


Обновить:

Вот Лямбда Питона, которая демонстрирует то, что я сказал выше. Как часть своего кода инициализации (вне обработчика) он записывает, когда он был впервые инициализирован, а затем сообщает об этой отметке времени всякий раз, когда он вызывается. Он также регистрирует текущее содержимое переменных среды «AWS», чтобы вы могли видеть, изменяется ли какая-либо из них.

 import json
import os
from datetime import datetime

print("initializing environment")
init_timestamp = datetime.utcnow()

def lambda_handler(event, context):
    print(f"environment was initialized at {init_timestamp.isoformat()}")
    print("")
    print("**** env ****")
    keys = list(os.environ.keys())
    keys.sort()
    for k in keys:
        if k.startswith("AWS_"):
            print(f"{k}: {os.environ[k]}")
 

Настройте его для обеспечения параллелизма, а затем используйте эту команду командной оболочки, чтобы вызывать его каждые 45 секунд:

 while true ; do date ; aws lambda invoke --function-name InvocationExplorer:2 --invocation-type Event --payload '{"foo": "irrelevant"}' /tmp/$ ; sleep 45 ; done
 

Оставьте его включенным на час или больше, и вы получите два потока журналов. Первый поток выглядит так (показывает начало и конец с пропущенными несколькими сотнями сообщений):

 2021-10-19T16:19:32.699-04:00   initializing environment
2021-10-19T16:30:57.240-04:00   START RequestId: a27f6802-c7e6-4f70-b890-2e0172d46780 Version: 2
2021-10-19T16:30:57.243-04:00   environment was initialized at 2021-10-19T16:19:32.699455 
...
2021-10-19T17:07:24.853-04:00   END RequestId: dd9a356f-7928-4bf9-be56-86f4c5e1bb64
2021-10-19T17:07:24.853-04:00   REPORT RequestId: dd9a356f-7928-4bf9-be56-86f4c5e1bb64 Duration: 1.00 ms Billed Duration: 2 ms Memory Size: 128 MB Max Memory Used: 39 MB 
 

Как вы можете видеть, Лямбда-код был инициализирован в 16:19:32, когда я включил параллелизм подготовки. Первый запрос был обработан в 16:30:57.

Но то, что я хочу вызвать, — это последний запрос в этом потоке журналов, в 17:07:24, или примерно через 48 минут после инициализации Лямбды.

Второй поток журналов начинается следующим образом:

 2021-10-19T17:04:08.739-04:00   initializing environment
2021-10-19T17:08:10.276-04:00   START RequestId: 6b15ba7c-91e2-4f91-bb6c-99b9877f1ebf Version: 2
2021-10-19T17:08:10.279-04:00   environment was initialized at 2021-10-19T17:04:08.739398 
 

Как вы можете видеть, он был инициализирован за несколько минут до окончательного запроса в первом потоке, но начал обрабатывать вызовы после первого потока.

Это, конечно, не гарантированное поведение. Именно так работает Лямбда сегодня и может измениться в будущем. Но изменения маловероятны: текущая имплантация ведет себя так, как задокументировано, и любое изменение чревато нарушением кода клиента.

Комментарии:

1. Можете ли вы поделиться какой-либо ссылкой на то, что вы сказали?

2. @GiulioMicheloni — За использование переменных окружения или поведение при перезапуске? Первое описано в документации, на которую я ссылался. У меня нет авторитетной документации (AWS) по последнему, но я провел обширные тесты, чтобы убедиться, что это так. Я отредактировал свой вопрос, чтобы показать вам код, который я использовал для запуска этих тестов, чтобы вы могли их воспроизвести.