Я - великий прихильник безcерверних (serverless) технологій, і майже завжди надаю їм перевагу в порівнянні з більш традиційними методами. Cloud Run замість GKE, Fargate замість EKS, Pub/Sub замість Кафки та Aurora замість RDS. Це дешевше, цим легше управляти, менше інфраструктури... Але як щодо безпеки? Чи можливо насправді пересвідчитись, що ваші безсерверні процеси (та дані) захищені?

Міф 1: Та я просто запущу свій таск в хмарі, що може піти не так?

Зізнавайтесь, бували такі думки? В хмарі дуже легко експериментувати, особливо - коли будь-який код можна упакувати в контейнер та запустити в якомусь ECS чи Cloud Run.

Безсерверні технології - тобто, ті, в яких ми не маємо конкретної інфраструктури в традиційному сенсі - ще більше полегшують життя розробникам. Для будь-якого юз-кейса існує спеціалізований сервіс, тільки бери та використовуй. Давайте подивимось, чим загрожує ця легкість в використанні, з точки зору безпеки.

Одного грудневого ранку резиденти Австралійського штату Вікторія отримати електронний лист від свого уряду. Лист повідомляв їх про те, що після зламу місцевої компанії Optus вони отримають нові посвідчення водія…

В штаті Вікторія всього декілька мільйонів жителів, і цілий мільйон із них має отримати нові посвідчення водія, тому що найпопулярнішого оператора мобільного звʼязку - Optus - хакнули. Як це відбулося? Мабуть, якась серйозна хакерська група, можливо, спонсорована урядом недружньої країни, хакнула цю компанію Optus?

Виявляється, зовсім ні. Це була одна (1) людина, що знайшла відкритий API та завантажила дані всіх клієнтів. Просто endpoint в інтернеті.

Переписка між журналістом Джеремі Кьорком та хакером на форумі підтверджує, що ніякої автентифікації на цьому API не було. Просто зайшов, просто скачав дані десяти мільйонів австралійців.

Мабуть, хтось подумав, ну, я просто тестую API, воно ні до чого не приєднано, не потрібна автентифікація. А потім про цей API забули.

Ми не знаємо, яка технологія стояла за цим API компанії Optus в Австралії, але не важко уявити, що такі ситуації відбуваються, коли ми хочемо щось якнайшвидше запустити, використавши найлегшу можливу технологію. Цією технологією все частіше стають безсерверні продукти. Лямбда, Fargate, Cloud Run, Cloud Functions - все це дуже легко використовувати, але й дуже легко залишити відкритим.

Коли ми говоримо про традиційні системи і їх захист, зазвичай більшість уваги приділяється захисту мереж: відкриті порти, Security Groups, Firewall rules. Проте, у випадку безсерверних технологій, мережі у нас, як такової, немає. Складові захисту цих безсерверних технологій - інші.

  • доступ до цього сервісу: хто може запустити цю функцію, хто може запустити цей контейнер, хто може активувати API.
  • до чого має доступ сам сервіс: які дані може зчитувати та писати цей контейнер чи функція, куди пишуться логи, тощо.
  • внутрішні механізми безпеки: вбудовані всередні коду.

Розгляньмо деталі налаштування цих доступів.

Міф 2: Мій безсерверний таск ні до чого не приєднаний

Почнемо з того, до чого має доступ наш сервіс, на прикладах Cloud Run і Lambda. До прикладу, скажімо, наш сервіс буде зчитувати повідомлення з одного топіка, писати повідомлення в інший топік, а також читати і писати дані в базі даних. Ці топіки та бази даних – це те, до чого має доступ цей сервіс.

serverless security what service can access

В хмарних провайдерах існують дефолтні опції, які частіше за все лежать на поверхні і є найлегшим шляхом виконання. В Гуглі – це Default Service Accounts. Вони будуть використані за замовчуванням вашими сервісами, якщо не налаштувати по-іншому. Мінус цих акаунтів в тому, що вони мають занадто широкі привілеї на рівні всього проекта: наприклад, Compute Service Account має роль Editor, тобто, він може читати і модифікувати всі ресурси в цьому проекті.

serverless security run default SA

Як це виправляти? Треба створювати спеціальні Service Accounts. Краще за все їх створювати для кожного сервісу, тобто для кожного контейнеру, який ви запускаєте, і давати least privileged роль. Наприклад, не зчитувати і записувати дані у всі топики PubSub, які є в цьому проєкті, а в якийсь конкретний, до якого цей конкретний сервіс має мати доступ.

serverless security run dedicated SA

В AWS така ж сама ситуація. Ви знаєте, що в AWS кожен сервіс матиме певну роль, і до цієї ролі приєднані специфічні полісі. Так от, існує більше тисячі стандартних IAM полісі, які AWS створює для вас, і в яких зазвичай занадто відкриті доступи. Так, наприклад, стандартна роль AWS Lambda Execute містить дозвіл S3 Read-Write на всіх бакетах.

AWS Lambda Execute role

Це багато, чи не так? Створюйте, будь ласка, конкретні полісі для конкретної функції, що надають доступ до конкретних дій лише на тих ресурсах, які потрібні.

Ще один надважливий момент в розділі IAM, нічний жах всіх security operations, це статичні токени. Статичні токени – це ключі до вашої інфраструктури, які дуже легко створити і почати використовувати, і дуже легко вкрасти.

Цитуючи Google: “To bad actors, service account keys can be more valuable than a leaked password”. Тобто, паролі користувачів менш корисні для хакерів, ніж токени. Чому так? Часто ці ключі створюються для пайплайнів, для управління системами, для автоматизації процесів. Ці речі вимагають elevated privileges, часто - доступ рівня адмін чи root. Так і виходить, що, використовуючи токени, ми залишаємо високо привілейовані ключі “валятися” навколо.

А як щодо мереж? Це безсерверні технології, але невже нічого не можна зробити?

Давайте подивимось, знову ж, на прикладах AWS Lambda та GCP Cloud Run.

Міф 3: Та це лише експеримент, натицяю вручну

В англійській є такий термін - clickops. Він означає ручні дії в консолі хмарного провайдера, і зазвичай має дерогативний зміст. В роботі з безсерверними технологіями ризик клікопсу вищий, особливо в плані запуску інтерактивних аплікацій.

Одне з основних призначень AWS Lambda та GCP Cloud Run - це веб аплікації. Хто каже веб - каже DNS, і тут заховані великі можливості для помилок.

Якщо ви спитаєте у своїх друзів, чи вони мали колись data leak, або порушення периметрів доступу саме в Lambda, то найчастіша причина - вони забули сховати функцію за API gateway. Замість API gateway тепер існують Lambda Function URLs, які замінюють Gateway і створюють DNS адресу для функції.

У Lambda Function URLs маємо 2 моменти безпеки, на які варто звернути увагу: тип аутентифікації на самій URL, та resource policy функції. За замовчанням, тип аутентифікації - None. А дефолтова полісі у Lambda Invoke Function URL теж зазначає автентифікацію типу None, тобто, будь-хто, знаючи DNS адресу функції, може її запустити.

"lambda-invoke" resource policy: { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": "*", "Action": "lambda:InvokeFunctionUrl", "Resource": "arn:aws:lambda:us-east-1:123456789012:function:my-function", "Condition": { "StringEquals": { "lambda:FunctionUrlAuthType": "NONE" } } } ] }

Звісно, іноді саме відкритий доступ і потрібен - наприклад, якщо це API, який ви надаєте вашим партнерам. В такому випадку, варто забезпечити авторизацію всередині коду функції Lambda, і залишати відкритий доступ в policy.

У випадку з GCP Cloud Run найлегший спосіб підʼєднати автентифікацію до сервісу - це Identity Aware Proxy. Для її використання потрібен також Load Balancer, що також дозволяє створити юзер-френдлі DNS адресу для сервісу, та підʼєднати сертифікат.

Питання в тому, як проконтролювати, що користувачі комунікують з сервісом саме через цю спеціальну адресу serviceName.example.com, а не через автоматичну адресу, що створена Гуглом автоматично і має формат

https://<serviceName>-<projectHash>-<region>.run.app

В безсерверних технологій немає мережі, але деякі речі можна все-таки контролювати. І одна з них в GCP Cloud Run – це Ingress, або контроль вхідного трафіку.

    Існує 3 варіанти контролю вхідного трафіку в Cloud Run:
  • INGRESS_TRAFFIC_ALL <- вибір за замовчуванням
  • INGRESS_TRAFFIC_INTERNAL_ONLY
  • INGRESS_TRAFFIC_INTERNAL_LOAD_BALANCER

По дефолту, інгрес полісі у Cloud Run – це allow traffic all. Весь трафік дозволений. Це дозволить комунікацію з сервісом, що запущений в Cloud Run, в обзід налаштованих Identity-Aware Proxy, Load Balancer, та сертифікату.

Тому важливо переключити цей контроль на Internal Load Balancer. В цьому випадку, лише трафік, що надходить з внутрішніх мереж або з Load Balancer, буде дозволений.

Які ще є варіанти захисту безсерверних технологій на рівні мереж?

Serverless is not really serverless, тобто мережа, все ж, десь є - але ви її не контролюєте. Що робити, якщо є необхідність надати фунції Lambda або сервісу Cloud Run приватну ІР адресу всередині вашої мережі?

В GCP для цього існує Serverless VPC connectors. Connector – це окремий ресурс, який ви деплоїте всередині вашої мережі, що дозволяє приєднати безсерверні compute сервіси до вашої приватної мережі.

Завдяки коннектору, функція my-func1 має приватний IP у вашій мережі, і може комунікувати з іншими сервісами - наприклад, BigQuery, приватно. В Cloud Run тепер є нативний VPC Egress, тобто нам більше не треба запускати serverless VPC connectors в Cloud Run.

В AWS еквівалент – це VPC endpoints. Вони дозволяють перенаправити трафік між безсерверними Lambda, S3, Cloudwatch тощо - до приватної мережі, яку контролюєте саме ви.

Безсерверні технології залишаються моїми улюбленими через легкість використання,а тепер і ви знаєте, як правильно їх налаштувати в AWS та Google Cloud. Може здатися, що ці сервіси в порівнянні з більш традиційними - більш ризиковані, не готові до продакшену. Але насправді вони часто навіть безпечніші - просто треба памʼятати певні моменти в конфігурації.

Sign in
Or by mail
Sign in
Or by mail
Register with email
Register with email
Forgot password?