Lambda, HTML і трохи болю: пригоди мамкіного архітектора в AWS

💡 Усі статті, обговорення, новини про DevOps — в одному місці. Приєднуйтесь до DevOps спільноти!

Привіт! Я Сергій, автор каналу Мамкін Архітектор, і хочу поділитись з вами одним з дописів про те, як ми весело проводили час із сервісами AWS. В коментах написали, шо це може бути цікаво читачам DOU — і давайте це перевіримо :)

Якось мені залетіла задача: зробити веб сторінку, яка в залежності від країни відвідувача робить різні штуки. Причому логіка має конфігуруватись на бекенді, а сторінка має містити усе (розмітку, код, стилі) в одному файлі. Не питайте чого так, от треба і все.

Як людина, вихована серверелесом, я намалював в голові діаграмку з лямбдою і api gateway, і швиденько накидав інфру в CDK і логіку на python, яка дивиться в header на країну, підшаманює html шаблон і віддає його в браузер вдячного юзера.

План вогонь, але де взяти країну? Виявляється, що, якщо виставити API Gateway через CloudFront, то там пододаються різні хедери, включаючи країну, місто і багато інших. Окей, за допомогою solution construct aws-cloudfront-apigateway-lambda за пару рядків додаємо СloudFront і очікуємо, шо все працює (чого звісно ж не відбулось).

Насамперед перестав працювати javascript на сторінці. Якщо заходити напряму на apigateway, все працює, а через CloudFront — ніфіга. Браузер пише, що бачить певний хедер, який буквально забороняє виконувати embedded скрипти.

Так я познайомився з Content Security Policy. Вищезгаданий construct застосував best practices, в які входять обмеження контенту. Пофіксити це можна через додавання nonce в цей хедер (не буду зупинятись, хоча це цікаво). Я написав код, але таке враження, що CloudFrontу мої зміни по барабану — на браузер прилітало не те, що я наконфігурячив.

Виявилось, той construct не просто сетапить CSP хедер, а робить це, використовуючи edge function. І, незважаючи на те, що в налаштуваннях я вказав опцію «прокидувати CSP header, який повертає лямбда», функція в кінці просто його перезатирала.

Добрі новини в тому, що це можна вимкнути просто виставивши insertHttpSecurityHeaders=false. Я це зробив і мій джава скрипт запрацював. Проте намалювалась інша проблема...

Розвиток нашого проекту пройшов по колу і вивів до 403 помилки. Ми думали, шо позбулись її, але ніт — прийдеться розбиратись. І цього разу на зміні в ChatGPT був більш прошарений вуйко і він одразу підказав у чому причина.

Виявляється, API Gateway дозволяє до себе лише запити, де заголовок Host співпадає з доменом, на якому цей самий API Gateway працює. По дефолту це шось типу xyz.execute-api.us-east-1.amazonaws.com. Якщо там буде інше значення, то у запиті буде відмовлено. Саме тому CloudFront перезаписує цей хедер на значення, яке задовільняє API Gateway. Це дуже мило з його боку звісно, але нам треба якось прокинути хост, на який заходить користувач.

Щоб це зробити є декілька варіантів (і всі погані). Перший — прописати кастомні домени на API Gateway. Наче круто, проте треба буде додавати сертифікати і тд, і там ще можуть бути обмеження на їх кількість. Другий варіант — прокинути хоста через інший, кастомний хедер (X-Host). Ми обрали другий.

Зробити це можна відносно просто — написати ще одну лямбду на 2 рядки і додати її в якості edge funtion на CloudFront. Звісно на дорозі від плану до реалізації повилазили нʼюанси — ця лямбда має бути лише в сакральному регіоні us-east-1, і шоб зробити таке через CDK, треба окремий стек, який буде деплоїтись в цей регіон, і подумати, як передати посилання на цю функцію в інший стек... Проте насправді це все техніка, і рішення займає пару рядків (ну може десятків, бо форматування переносить аргумент на новий рядок — anyway).

В результаті Host прокинувся, логіка запрацювала, а ми вийшли переможцями з чергового двобою з клауд провайдером мрії.

Якщо це все перечитати, то здається, що все переускладнено. Проте в процесі вирішення всіх проблем я прийшов до висновку, що це все має сенс. І справа не в замороченості, а в skill issues.

Є також інший аспект. Наше рішення насправді доволі нестандартне. Бо API Gateway не дуже призначений для віддачі HTML, а HTML не полюбляє inline срипти та стилі і так далі. Тому і виявилось, що для здавалось би простого кейсу ми з розмаху увірвались в advanced аспекти.

Проте це було пізнавально, цікаво і в кінці все запрацювало. Один тих моментів, що радують розробників.

(Якщо ви дочитали до цього місця, то знайте, що нам насправді не потрібен був API Gateway. Можна просто було виставити лямбду через HTTP і можливо це спростило б багато речей. Перевіряти ми цього звісно не стали, бо наше гасло: «працює — не чіпай». А воно працює)

👍ПодобаєтьсяСподобалось5
До обраногоВ обраному2
LinkedIn
Ctrl + Enter
Ctrl + Enter

Lambda підтримується як CloudFront Origin вже як майже рік

Підписатись на коментарі