Стендап Сьогодні
Що я зробив, що я хочу зробити, і що це все значить.
Повсякденні здобутки в форматі стендапу.
Детальніше в статті
Підписатись на RSS
📢
Канал в Telegram @stendap_sogodni
🦣
@stendap_sogodni@shevtsov.me в Федиверсі
27.08.2023
Розширення парсера Remark
Останній раз я писав про Remark з точки зору споживача. Проте, довелося також його й дописувати. Документації тут бракує, а екосистема складна, тому не так вже воно й легко.
Мені, власне, потрібно впровадити підтримку знайомого по GitHub синтаксису задач - [ ] To do
. Для такого вже є рішення. Проте є нюанс: в Obsidian дозволено ставити статусом задачі не тільки хрестик, але й інші символи (наприклад, -
для скасованих задач.) А всі плагіни, що існують, мають семантику “пробіл або хрестик”. Тому взяв за основу gfm-task-list-item та модифікував його так, щоб інші символи теж були дозволені.
Перший сюрприз - Remark використовує парсер micromark. Нестандартний синтаксис майже напевно потребує особливої обробки токенів, тому доведеться робити розширення для Micromark, що мене здивувало, бо це ціла окрема бібліотека (збирався робити на Remark, а опинився в Micromark). Micromark це взагалі повноцінний парсер, але Remark бере від нього саме токенізатор.
Доповнення для токенізатора складається з символу-тригера та логіки, яка споживає символи та генерує токени власних типів. Так, доповнення gfm-task-list-item
споживало маркер задачі та перевіряло, чи то пробіл або хрестик. Якщо так, то генерувало токен “задача зроблена/не зроблена”, а в протилежному чині — відмовлялася від обробки. Я поміняв це на простішу логіку, що просто зберігає символ між квадратними дужками в токен taskListItemValue
.
Щоб перетворити ці токени на елементи дерева AST, потрібне друге доповнення для іншого етапу, яке називається тут fromMarkdownExtension
. Таке доповнення реагує на потік токенів та будує дерево. Відповідно, в моєму випадку воно слухає вихід з taskListItemValue
(тобто коли вже відомо, що токен прочитаний повністю) та переносить символ маркера з токена в атрибут вузла listItem
.
Все це треба робити тому, що без особливої обробки рядок [ ]
не є вірним Markown - це посилання без адреси. Тому не можна просто шукати його в тексті вже по готовому дереву.
26.08.2023
Починай з простого
Хочу звернути увагу на одну професійну ваду, яку за собою помічаю. Коли переді мною стоїть великий проєкт, але більш-менш зрозуміло, що має вийти в кінці, то я починаю робити його, скажімо, від початку та до кінця. А мав би робити від простого до складного.
Проілюструю. Для розробки дерева задач для Obsidian потрібно з документів витягати задачі. Кожна задача має назву — це, власне, той текст, яким вона підписана. Поки все ясно.
Але… тексту може бути більше одного рядка. Або не бути зовсім. Або це не текст, а блок коду, чи заголовок, чи зображення. А також в тексті може бути форматування, посилання, ті ж самі зображення… Markdown все це дозволяє.
Підхід, який я вважаю вадою, це відразу намагатись покрити всі можливі комбінації синтаксису. Їх же ж вигадувати не треба — все відомо. От тільки вигадати код, який все покриває, непросто, та й взагалі, незрозуміло, як підступитись. Навіть маленький шматок (такий, як обхід дерева в пошуці задач) - складна задача, якщо вона має покривати всі можливі варіанти.
Краще, на мою думку, взяти найпростішу ситуацію: коли в документі є тільки список задач, та кожна задача має тільки один рядок опису з чистого тексту. Далі — потроху ускладнювати (наприклад, дозволити більше одного рядку тексту.)
Мені це здається контрінтуїтивним: якщо я знаю майбутні умови, навіщо мені свідомо ігнорувати їх та писати код, який гарантовано доведеться переписувати? Чи не зайва то робота? В тому й справа, що поступовий рефакторинг дає кращий код, ніж спроби відразу передбачити все.
Наступного разу пропоную планувати роботу від найпростішої реалізації до повної.
(Так, я розумію, що це приблизно те, що радить TDD.)
25.08.2023
Трохи про периферію
З мого останнього поста про клавіатури багато чого помінялось. Я шукав клавіатуру з підключенням по радіо — а натомість отримав багато розуміння… та пару нових клавіатур.
Epomaker TH80 - непогана клавіатура, яку псують ніжки. Вони не точкові, а широкі. Через це вона хиталася на моєму столі (до того я й не здогадувався, що він кривий… або то клавіатура крива?) А ще, для неї абсолютно неможливо зробити так, щоб функціональні клавіші під macOS були функціональними, а не мультимедійними.
Keychron Q1 Pro - за якістю просто супер. До того ж відкрита для модифікацій під свій смак. Мені не сподобався профіль клавіш — надто високі, а поверхня завузька. Поки що знайшов (на німецькому Амазоні) такі приємні клавіші профілю MSA - нижчі та ширші. Профіль клавіш клавіатури — це такий аспект, про не здогадуєшся, поки не побачиш різницю. (Я знаю, бо колись купив пару прикольних клавіш на свою клавіатуру та по отриманню дізнався, що вони абсолютно не підходять.)
Підставка для запʼястя — просто перегорнула мені життя. Рукам набагато зручніше, коли на них не давить край клавіатури. (Це працює навіть з ноутбуком.) Свою я знайшов на Реддіті. Рекомендую перед покупкою переконатись, що підставка не з сосни (як підставки Keychron), а з твердої породи деревини. Різниця в гладкості дуже помітна.
Миша XTRFY M42 Wireless - обирав мишу для fingertip grip, ця сподобалась розміром та вагою. Мій попередній вибір була Logitech MX Anywhere, яка ще менша та теж дуже хороша. Але після випробувань залишив M42 через те, що вона легша та ц
А щодо Vortex Race 3 - все ще дуже її люблю, у цій клавіатурі чудовий мінімалістичний розмір та приємні клавіші. Єдине, що перемикачі не змінні — зате вона дуже низько сидить для повноцінної механічної клавіатури.
24.08.2023
Ролапи в OpenSearch
Є така функція в OpenSearch - ролап (rollup). Це така собі передагрегація. Вона дозволяє робити обмежений набір агрегацій, маючи тільки стисле відображення оригінальних даних — тобто заощадити на місці, коли крім статистики нічого не потрібно.
Я коли її побачив, то дуже зрадів, бо підхід мені добре знайомий. В Redshift (або PostgreSQL) таке доводилось робити вручну. Як я писав, з PostgreSQL можна взагалі зробити майже будь-що — тільки на особливу оптимізацію не треба розраховувати.
Як воно працює: ми визначаємо найменшу можливу комірку агрегації та групуємо по ньому. Наприклад, якщо нам потрібна кількість по даті та користувачу:
CREATE TABLE stats AS
SELECT DATE(created_at) as date, user_id, COUNT(*) as cnt
FROM events
GROUP BY date, user_id
Тепер таблицю можна використати для агрегації за більшими комірками:
-- статистика по даті
SELECT date, SUM(cnt) FROM stats WHERE user_id=123 GROUP BY date
-- статистика по користувачам
SELECT user_id, SUM(cnt) FROM stats WHERE date>'2023-01-01' AND date<'2023-08-24' GROUP BY user_id
Залишається питання — як цю таблицю оновляти? Добре, якщо агрегація відбувається за поточною датою, тобто дані за вчора вже не поміняються. (Це й з боку розуміння користувачами краще.) Проте цей підхід до передагрегації не підведе навіть коли в майбутньому можуть зʼявиться нові дані для комірки, що вже існує: два чи більше рядків з однаковим ключем будуть просто підсумовані.
Приблизно так само воно й працює в OpenSearch, тільки в напівавтоматичному режимі. Зокрема, можна робити агрегацію разом по ролапах та по звичайних індексах — зручна абстракція.
23.08.2023
Основи безпеки AWS: це ти
На завершення серії, хочу розказати про те, як можна витратити $10,000 на стрес-тест. Це повчальна історія про те, що ніяких шахраїв не треба, щоб створити собі величезні витрати.
Хмарний хостинг — це зручно, оскільки ми можемо створювати ресурси, абстрагуючись від витрат. Ми майже ніколи не знаємо наперед, скільки витратимо. По-перше, завжди є витрати за використання — наприклад, за трафік. А по-друге, фактично, всі витрати є витратами “за використання”, бо вимірюються в годинах, та ми не знаємо, чи буде машина працювати постійно, чи ми її потушимо за пів години через автомасштабування.
Ми не хочемо, щоб наш продукт раптом припинив роботу, бо на рахунку закінчились гроші. Тому в хмарних хостингах немає ніякої жорсткої межі на використання. Є тільки попередження — які можна не помітити, а можна взагалі не налаштувати. Тобто всі створені нами ресурси будуть витрачати гроші, аж допоки ми не побачимо величезний рахунок. А ще скоріше, величезне зняття на своєму банківському рахунку.
Так і сталося з цим стрес-тестом: машини бази даних, які були підготовані, коштували близько $10 на годину; помнож це на чотири машини та маємо близько $1,000 на день. Протримай такий кластер один робочий тиждень, та підеш в мінус на пʼять тисяч доларів. Додай до цього витрати на IOPS та на сховище, які залежать від обсягів, та вже непомітно нагуляв рахунок на $10,000. (До речі, мова йде про AWS Aurora, а багато IOPS пішло на реплікацію, а навіть не на сам тест.)
Теоретично, такі витрати можна передбачити та мінімізувати (запускати кластер тільки під час активного тестування, наприклад.) Проблема в тому, що абсолютно нічого тобі в цьому не допоможе — витрати не помітні в інтерфейсі. І цей приклад тільки найбільш очевидний — в меншому масштабі непомітні зайві витрати присутні в будь-якому продукті. Будьте пильними.
До речі, історія має добрий кінець - AWS повернули гроші. Але зроблено то було надзвичайними зусиллями нашого керівництва. Не раджу пробувати це повторити.
22.08.2023
Основи безпеки AWS: захист ключів IAM
Продовження: початок тут, тут, тут та тут.
Як я писав вчора, більшість споживачів API AWS повинні авторизуватись через роль, а не користувача. Різниця в тому, що у ролі немає ключів, тому щоб отримати доступ до неї, потрібно запустити код у відповідному середовищі. А в користувача є ключі. Якщо отримати ключі, то доступ відкритий будь-звідки.
Це особливо небезпечно для адміністративних користувачів, оскільки вони мають широкі права доступу — часто необмежені. З такими правами можна не тільки отримати дані користувачів. Окремим вектором атаки є використання крадених ключів AWS для придбання обчислювальних ресурсів за ваші гроші. AWS тут ніяк, абсолютно ніяк не зупиняє шахраїв, тому навіть на маленькому проєкті можна влетіти на значну суму грошей — аж поки не помітиш, що щось пішло не так (для чого, до речі, конче необхідно мати монітор білінгу).
Я вже писав, що ключі AWS можна сховати в 1Password. Це підходить до ключів, якими користуються люди (бо є ще ключі для сервісів поза межами AWS, до яких ролі не застосовуються.) Звісно, абсолютного захисту таке рішення не дає, а являє собою один з шарів захисту.
Інший підхід — впровадження двофакторної автентифікації для запитів до API. Для цього є ключ MultiFactorAuthPresent в політиках доступу. На практиці це накладає додаткову умову на дію.
А для сервісних користувачів є умова за IP адресою. Це теж добре захищає… якщо у вас є стала IP адреса, звісно.
Взагалі в тих умовах багато всього цікавого — можна за User-Agent обмежити, наприклад. Це вже зупинить найбільш поширений вид шахрайства, коли ключі отримують через загальні вразливості та без знання вашого проєкту.
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, яка дозволяє підʼєднатись до деяких ресурсів “напряму”, що, як я розумію, просто спрощує маршрутизацію.