Стендап Сьогодні

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

Підписатись на RSS
📢 Канал в Telegram @stendap_sogodni
🦣 @stendap_sogodni@shevtsov.me в Федиверсі

21.08.2023

Основи безпеки AWS: ролі та політики

Продовження: початок тут, тут та тут.

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

Політики можна привʼязати або до користувача, або до ролі. Роль завжди краще, оскільки не має ключів. У коду, який виконується на AWS, є доступ до ролі з оточення. Через це додатку на AWS не потрібні ключі до AWS. Коли немає ключів, то їх не вкрадуть. А це найбільший ризик для безпеки.

(До речі, технічно ролі працюють через генерацію тимчасових ключів, які можна отримати через відповідний API. Інколи це корисно — наприклад, щоб вручну підписати запит до AWS. Роблю відсилання до свого стародавнього поста про завантаження на S3 з браузера.)

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


20.08.2023

Основи безпеки AWS: групи безпеки

Продовження: початок тут та тут.

Групи безпеки виконують функцію фаєрволу. А саме, обмежують, куди, звідки, та через які порти дозволені підключення. Це найточніший та найнадійніший апарат захисту в AWS, тому на них потрібно звертати максимум уваги. Вони настільки надійні, що в деяких випадках можуть заміняти авторизацію (бо, якщо, скажімо, сервіс Elasticache не доступний нікому, окрім контейнерів додатка, то авторизація мало що додає.)

Група безпеки призначається кожному ресурсу, що існує в VPC (бази даних, машини, балансувальники й так далі.) Основа дуже проста: не треба робити груп з необмеженим входом (ingress). Натомість дозволяти вхід тільки з тих ресурсів (груп), яким дійсно потрібний доступ.

Вихід (egress) обмежувати теж варто, але це на мою думку не так важливо. Окреме питання — чи дозволяти вихід в інтернет — але без нього сервіси, особливо додатки, схильні ламатись. Причому обмежити доступ за доменом неможливо — тільки за набором IP адрес — отже, виходить непрактично. А всередині VPC групи взагалі утворюють пари “вхід-вихід”, тому накладення явних обмежень на вихід тільки повторює симетричне обмеження на вхід. В цілому, мені спокійно, якщо у кожного сервісу щільно обмежений вхід.

Звернемо увагу, що у ресурсу може бути більше одної групи безпеки. Тому можна утворити, наприклад, групу “клієнти бази даних” замість того, щоб плодити однакове правило у групі кожного зі споживачів.

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


19.08.2023

Основи безпеки AWS: підмережі — приватні та публічні

Продовження: початок тут.

Наступне, з чим доведеться стикнутись — це підмережі (subnet.) Напевно, всі помічають, що багато сервісів вимагають не одну, а декілька підмереж. Чому так та навіщо нам взагалі вони потрібні?

Головна функція підмереж — використання зон доступності (availability zone.) Кожний регіон AWS далі поділений на зони, які є фізичними сегментами, ізольованими від ризиків (до деякого ступеня.) Тому для утворення високої доступності наші сервіси повинні мати копії в різних зонах. Так що варто мати по одній підмережі на кожну зону. Підмережа це більше як налаштування, ніж реальний ресурс, тому не коштує вона нічого.

Не забуваємо виділити підмережам достатній діапазон адрес. Взагалі про підмережі варто добре подумати заздалегідь, бо міняти їх складно та це потребує створення ресурсів наново. Я б починав з діапазонів /22 (на 1024 адреси.)

Та другий аспект підмережі — це контроль доступу з зовнішнього інтернету. Тут маємо публічні та приватні підмережі. Різниця між ними дуже проста: публічна має прямий маршрут до інтернету, а приватна — тільки через NAT. (Тобто різниця виключно в побудові таблиці маршрутів). Це значить, що до ресурсів в публічній мережі є (теоретична) можливість під’єднатися ззовні, а в приватній — взагалі ні. (NAT можна й не підключати, тоді ресурси будуть зовсім ізольовані від інтернету.) Підмережі не обмежують доступ до ресурсів з середини того ж VPC - ресурси з всіх підмереж можуть комунікувати один з одним.

Треба зазначити, що сама по собі публічна підмережа не відкриває доступу з інтернету, а тільки уможливлює. Це лише один з шарів безпеки. Ще потрібно принаймні виділити публічну адресу та додати відповідне правило в групу безпеки. (До речі, взагалі, якщо у машини в публічній мережі не буде публічної адреси, то вона не матиме доступу в інтернет — дізнався про це довгим шляхом.)

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

Тож з підмережами все просто: робимо по одній публічній на кожну зону доступності, та за потребою створюємо приватні.


18.08.2023

Основи безпеки AWS: VPC - ваша локальна мережа

Розпочну короткий курс з безпеки в AWS та що я про неї встиг дізнатись.

З чого все починається — це VPC, “віртуальна приватна хмара”, а фактично — локальна мережа. Існує вона зрозуміло для чого — щоб провести чітку межу між ресурсами проєкту та зовнішнім світом. Раніше використання VPC було за бажанням, але на цей час всі нові ресурси створюються тільки так, бодай в VPC за замовчуванням.

Існування VPC уможливлює всі функції, про які я писатиму далі. Бо з локальною мережею ми точно знаємо, де наші ресурси: віртуальні машини, контейнери ECS, бази даних і так далі — а де чужі. Це саме логічне угрупування, а не фізичне, бо ресурси можуть розташовуватись будь-де в регіоні. Щодо безпеки, то VPC на неї прямо не впливає; шифрування трафіку відбувається в будь-якому разі.

Зазвичай компанія матиме один VPC. Більше має сенс, якщо у вас більше одного продукту (але тоді може бути доцільніше зробити окремі облікові записи AWS). Або якщо ви використовуєте більш одного регіону.

Різні VPC одна до одної — чужі. Якщо плануєте більше однієї VPC, важливо призначити їм різні простори адрес. Бо тоді можна в майбутньому залучити VPC Peering - поєднання двох VPC в одну. А от якщо адреси збігаються… тоді ніякого Peering не вийде. Але також раджу не робити окремих VPC, якщо не має пекучої потреби повного розділення ресурсів.

Не всі сервіси AWS підтримують VPC; як найбільш знайомий — то S3. Такі сервіси стосовно VPC будуть зовнішніми. Проте існує свіжа технологія PrivateLink, яка дозволяє підʼєднатись до деяких ресурсів “напряму”, що, як я розумію, просто спрощує маршрутизацію.


17.08.2023

Де взяти IP адресу?

У всього, до чого ми звертаємось в інтернеті, обовʼязково є IP адреса. Але що вони значать? Та де їх взяти? Про це ми не думаємо.

Взагалі IP адреса — суто віртуальний вказівник. Сам по собі він майже нічого не значить. IP адреси працюють в сукупності з таблицями маршрутів. Така таблиця міститься на кожному вузлі в Інтернеті та попросту каже, якому з локальних вузлів передавати пакети, призначені той чи іншій IP адресі. Бо інтернет працює за “естафетою” - саме її ми бачимо командою traceroute.

Тому з IP адресами в інтернеті відбувається багато цікавих подій, які ми не помічаємо. Наприклад: технологія Anycast дозволяє мати одну та ту саму IP адресу для різних серверів в різних місцях інтернету. Так DNS-сервіс 1.1.1.1 насправді має сервер десь поруч з тобою, а не один на всіх. (Мені показує Нідерланди. А, до речі, 8.8.8.8 веде аж до Каліфорнії.)

Нам адреси видає провайдер - потроху, бо кількість адрес обмежена. А що, якщо хочеться більше адрес? Може, ми придумали видавати кожному клієнтові по DNS серверу? Або просто створити власний хостинг?

Тоді можемо взяти в оренду цілий блок IP адрес. От, наприклад через компанію LIR Services (на правах досвіду, не реклами.) Коштує це від $1K за 256 адрес — найменший діапазон для оренди. Купити не можна, бо розподілом IP адрес у світі керують 5 великих агенцій - RIR.

Але що взагалі значить — володіти IP адресами? Далі треба, щоб хтось оголошував їх (щоб всі знали, куди передавати “естафету” до цих адрес) та маршрутизував до конкретних серверів. Хочеш робити це сам — треба реєструвати автономну систему - це ще витрати — на ліцензію та на підтримку. Тому гарно, що хмарні провайдери, наприклад, AWS, почали пропонувати сервіс BYOIP - тобто обслуговування діапазону, який ти заорендував в іншому місці. В них є своя автономна система, до якої буде доданий діапазон. Далі клієнти знатимуть, що твоя IP адреса мешкає на Амазоні — а AWS вже знатиме, як дістатися до конкретної віртуальної машини всередині.

Все це складно для розуміння, але цілком доступно кожному з бюджетом. Сервісу приватного DNS - бути!


16.08.2023

Чому Кафка обмежує розмір пачки в байтах?

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

Причина найпростіша. Kafka не розглядає записи як окремі сутності. Всередині вони зберігаються саме як послідовність байтів. Коли ти робиш fetch, то Кафка відрізає шматок потрібного розміру та віддає. В протоколі навіть написано, що в кінці шматка може бути неповне повідомлення, яке треба проігнорувати. Тобто сервер навіть не шукає, де закінчується останнє повідомлення в пачці.

(Це неповне повідомлення — не така страшна справа. По-перше, поки йде активне споживання, дані не повинні накопичуватись, тож вони не сягнуть порогу пачки та не будуть обрізані. По-друге, якщо вже будуть, то пачка міститиме тисячі повідомлень чи більше — та швидше один раз відкинути решту, ніж тисячу раз додавати, поки не наберемо потрібний розмір.)

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

Рекомендую для прочитання опис протоколу Kafka, щоб краще зрозуміти ідеї, на яких вона побудована.

Примітка: є ще опція max.poll.records та можна подумати, що вона є альтернативою для fetch.max.bytes. Проте ні — обмеження за кількістю записів відбувається вже на боці клієнта, після того, як вони отримані. Така опція є зручною абстракцією для нашого коду, не більше.


15.08.2023

Дерево задач для Obsidian

В продовження теми з доповненням для Obsidian сьогодні розробляв структуру даних для задач.

В минулому пості я розповідав про синтаксичне дерево Markdown. Довгий час я планував працювати з цим деревом, як воно є, та просто доповнювати вузли потрібними мені атрибутами (наприклад, задачу — її статусом.) Проте це незручно: задачі губляться посеред інших елементів.

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

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

Щоб мати можливість відтворити зміни назад в документ, потрібно привʼязати задачі до відповідних їх місць документа, тобто вузлів синтаксичного дерева. Це можна було б робити за допомогою матеріалізованого шляху, тобто зберігати шлях до вузла. Але оскільки в JavaScript всі обʼєкти завжди передаються за посиланням, то можна просто зберігати сам вузол в атрибут задачі. Далі можна, скажімо, виконати певні перетворення задач (додати дати закінчення), поміняти вузли, та згенерувати з синтаксичного дерева новий документ.

А Obsidian Tasks мені перестав подобатись, не так він працює, як я хочу. Ідеї в них хороші, але можна їх дорозвинути.


14.08.2023

Kafka проти черг: події проти задач

Як цікаво: з першого погляду Kafka майже не відрізняється від черг, таких як SQS або RabbitMQ. Проте відмінності, на мою думку, починаються з того, як кожна система дивиться на повідомлення всередині.

Задача в черзі — це наказ на роботу. Значить, кожна задача витратить нетривіальний проміжок часу. А це, своєю чергою, значить, що задач буде не так вже й багато (порівняно з подіями.) Задачі цікавлять нас поодинці: кожну задачу ми робимо окремо, а коли зробили — підтверджуємо, що зроблено.

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

Така різниця інформує API Кафки: воно розроблене, щоб якнайшвидше отримувати події, яких буде багато. Реально багато — хоч мільйон на секунду. Коли отримали та обробили, відмічаємо події як оброблені. Не кожну окремо (бо кому то цікаво робити з мільйоном записів), а всі разом — за зсувом.

Отже, Кафку має сенс ставити там, де вам потрібно обробляти значний обсяг подій та продукувати стан, або якось реагувати на зміни стану. А про Кафку як чергу гарно написали на StackOverflow.


13.08.2023

Емоції дороги

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


12.08.2023

Мʼякість TypeScript

Мабуть, цікавий аспект, про який можна й не замислюватись — все, що робить TypeScript, робиться в момент компіляції. Далі залишається тільки код JavaScript. Більш за те, поки код TypeScript є синтаксично коректним, він буде працювати. Я хотів написати “працювати, але з багами”, але часто ситуація зворотна: це типи містять помилки, а код цілком вірний. Думаю, без такої можливості TypeScript далеко б не пішов, тому що багато бібліотек, що існують, не підходять для точної типізації.

Якщо ти з типізованих мов бачив тільки TypeScript, то навпаки, може скластися враження, що це стандартна система. Але ні: практично всі типізовані мови, що я знаю, не погодяться компілювати код без повністю вірних типів. (Не кажу про RBS для Ruby, бо він для мене надто сирий. Головним чином, аналог DefinitelyTyped поки не виріс.) Тож TypeScript являє особливу, “мʼяку” екосистему.

Мʼякість — це не тільки можливість виконати код без правильних типів. Це й розширення типів, про яке я писав вчора. І підхід типізації “за зразком” - тобто, замість жорстко заданих класів тип об’єкта перевіряється за наявними атрибутами.

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