Make. Build. Break. Reflect. – Telegram
Make. Build. Break. Reflect.
1.04K subscribers
124 photos
1 video
1 file
133 links
Полезные советы, всратые истории, странные шутки и заметки на полях от @kruchkov_alexandr
Download Telegram
#longread #grafana #kubernetes #troubleshooting #одинденьизжизни

Три дашборда на границе Grafana
Часть 3 из 3.

Жду 30 секунд (updateIntervalSeconds в provisioning конфиге).

Проверяю:
kubectl exec -n grafana pg-monitoring-2 -c postgres -- psql -U postgres -d grafana -c "SELECT id, uid, noscript FROM dashboard WHERE uid LIKE '%service-metrics%';"


  id  |            uid              |                   noscript                    
------+-----------------------------+--------------------------------------------
3838 | service-metrics-overview | Service Metrics Overview [VictoriaLogs]


Одна запись. Правильный noscript. Правильный UID.

Иду в UI - работает. Никаких дублей, никаких "Draft", никакого Loki.
Победа! 🎉

Если provisioning не срабатывает автоматически, можно вызвать reload через API (выше был пример курлом) или перезапустить pod Grafana (не мой вариант).
Подробнее про provisioning: https://grafana.com/docs/grafana/latest/administration/provisioning/

На всё ушло часа два.
Могло бы - минут пятнадцать, если бы сразу глянул в логи.

Выводы, а куда без них.
- Grafana provisioning не перезаписывает существующие записи в БД, если они созданы из другого источника. Он кидает ошибку в лог и оставляет старую версию.
- ошибка "A dashboard with the same uid already exists" - это про запись в PostgreSQL, не про файл. Файл может быть идеальным, но если в базе мусор - ничего не заработает.
- логи первым делом. Там обычно всё написано. Но не во всех версиях Grafana логи достаточно информативны.
- удаление из БД работает, но это неофициальный подход. Я не нашёл другого способа. Для provisioned dashboards безопасно - они автоматически пересоздаются из файлов. Главное - делать на primary ноде PostgreSQL и иметь бэкап.
- миграции дашбордов - это не "поменять пару строк". Особенно если UID менялся несколько раз. Особенно, если я баран.

Как избежать этой проблемы (предполагаю):
- не меняйте UID после первого деплоя. Если нужна миграция - создайте новый дашборд с новым UID, а старый удалите полностью (включая запись в БД).
- используйте стабильные UID с префиксами:
myteam-service-metrics-overview
myteam-app-logs-dashboard

- не используйте один UID для дашбордов в разных папках - это создаёт race condition.
- документируйте миграции в changelog или README.
- используйте allowUiUpdates: false в provisioning конфиге - это предотвращает дрейф конфигурации.
Пример конфигурации провижининга
apiVersion: 1
providers:
- name: 'sidecarProvider'
orgId: 1
type: file
disableDeletion: false
allowUiUpdates: false # запрет редактирования в UI
updateIntervalSeconds: 30 # интервал сканирования файлов
options:
foldersFromFilesStructure: true
path: /tmp/dashboards


Альтернативный подход, без прямого доступа к БД - когда его нет или страшно (предполагаю, что это правильный путь, но я не проверял):
- временно переименовать ConfigMap (например добавить суффикс -old)
- дождаться, пока Grafana удалит дашборды (если disableDeletion: false)
- вернуть ConfigMap с правильным именем и новым UID
- provisioning создаст дашборды заново
Этот способ медленнее, но безопаснее.

Для зануд:
Прямое изменение базы данных Grafana - неофициальная практика!
Это не является моим советом или рекомендацией!
Просто поделился своей историей.


- - -
- https://github.com/grafana/grafana/issues/12411
- https://github.com/grafana/grafana/issues/41085
- https://github.com/grafana/grafana/issues/73043
🔥81
#kubernetes

Пока я спал там взломали все инторнеты и все кубернетисы.

Источник на английском с глубоким разбором.
- https://grahamhelton.com/blog/nodes-proxy-rce

Хорошие ребята, кого не жалко репостнуть:
- https://news.1rj.ru/str/tech_b0lt_Genona/6101
- https://labs.iximiuz.com/tutorials/nodes-proxy-rce-c9e436a9

Хорошо, что все кубернетисы (кроме моих личных лабораторий) на предыдущих и нынешней работах это приватные сетки (что спасает от внешних негодяев, но не спасает от внутренних, но таких у нас нет).

Как проверить, подвержен ли ваш кластер/SA? А легко!
Копи-паст скрипта в своем кластере:
kubectl get serviceaccounts --all-namespaces -o json | \
jq -r '.items[] | "\(.metadata.namespace)\t\(.metadata.name)"' | \
while IFS=$'\t' read -r ns sa; do
if kubectl auth can-i get nodes/proxy --as="system:serviceaccount:${ns}:${sa}" -n "$ns" >/dev/null 2>&1; then
echo -e "${ns}\t${sa}\tyes"
fi
done

Да, такие дела. Ну и порт 10250 должен быть доступен.
🔥2
#kubernetes #golang #troubleshooting

Снова про операторы.

У ресурса Secret в Kubernetes есть два поля для данных:
- Data map[string][]byte - бинарные данные, в YAML выглядят как base64
- StringData map[string]string - строковые данные, plain text в YAML

Как это работает на самом деле:
StringData - write-only поле для удобства.
Когда ты создаёшь или обновляешь секрет, API-сервер мержит StringData в Data (ключи из StringData перезаписывают Data при совпадении).
В etcd хранилке и в ответе API сохраняется только Data.
При чтении секрета из кластера поле StringData всегда пустое - его там просто нет.
Поэтому StringData - для людей и YAML-манифестов, а Data - для кода операторов.


А теперь типичнейшая ошибка, на которую я снова попался. 😭

Код оператора с ошибкой:
func BuildCredentialsSecret(instance *v1alpha1.MyApp) *corev1.Secret {
return &corev1.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: instance.Name + "-credentials",
Namespace: instance.Namespace,
},
Type: corev1.SecretTypeOpaque,
StringData: map[string]string{
"API_HOST": instance.Spec.Config.API.Host,
"API_TOKEN": instance.Spec.Config.API.Token,
},
}
}

В реконсайлере проверка "изменился ли секрет?":
func secretDataEqual(a, b map[string][]byte) bool {
if len(a) != len(b) {
return false
}
for k, v := range a {
if !bytes.Equal(v, b[k]) {
return false
}
}
return true
}

// в reconcile:
if !secretDataEqual(found.Data, secret.Data) {
// обновляем секрет
found.Data = secret.Data // ВОТ ТУТ ПРОБЛЕМА
return r.Update(ctx, found)
}

Видите проблему?

При создании desired-секрета мы используем StringData.
Но в Go-структуре этого объекта поле Data равно nil, потому что мы его не заполняли!!!

Что происходит:
- оператор создаёт секрет с StringData > API сервер конвертирует в Data, в кластере всё ок
- при следующем reconcile оператор читает секрет - там Data заполнен
- оператор строит desired-секрет - там Data = nil, StringData заполнен
- сравнение видит разницу:
len(found.Data) != 0, а len(secret.Data) == 0 

(потому что nil)
- оператор решает обновить секрет и делает
found.Data = secret.Data

записывая nil в поле данных!
- теперь в кластере секрет с
data: {}

(0 ключей)
- в следующем reconcile сравнение
secretDataEqual(found.Data, nil)

оба пустые? Да!
(len(nil) == 0, len(map{}) == 0)

- оператор думает: "секрет актуален", и никогда не восстанавливает данные 🤡

Результат: секрет живёт, ownerReference на месте, лейблы есть, а данных - ноль.
Поды падают с:
MountVolume.SetUp failed for volume "credentials": 
references non-existent secret key: API_TOKEN

Фикс очевиден: использовать Data в коде оператора:
func BuildCredentialsSecret(instance *v1alpha1.MyApp) *corev1.Secret {
return &corev1.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: instance.Name + "-credentials",
Namespace: instance.Namespace,
},
Type: corev1.SecretTypeOpaque,
Data: map[string][]byte{
"API_HOST": []byte(instance.Spec.Config.API.Host),
"API_TOKEN": []byte(instance.Spec.Config.API.Token),
},
}
}


Теперь secret.Data заполнен, сравнение работает корректно, и ты случайно не затираешь данные nil-ом.
🎉🎉🎉

Мораль:
- stringData - для YAML и kubectl, где удобно писать plain text
- data - для кода операторов на Go
- в client-go структуре StringData и Data - разные поля; API сервер не синхронизирует их при чтении
- если используешь StringData в коде, помни: secret.Data == nil в этой структуре
- сравнивай и применяй то, что реально используешь

Потерял на этом баге часа два, пока не дошло. Сука.
Секрет создавался, лейблы были, ownerReference был, а данных - ноль.

Классика - симптомы в одном месте (падающие поды), причина в другом (nil вместо мапы в билдере).
Please open Telegram to view this post
VIEW IN TELEGRAM
6👍6
#kubernetes #aws #eks #helm

Тихо и незаметно вышла мажорная версия AWS Load Balancer Controller - 3.0.0.
https://github.com/kubernetes-sigs/aws-load-balancer-controller
Вместе с ней и Helm-чарт тоже прыгнул на 3.x.
https://github.com/aws/eks-charts/tree/master/stable/aws-load-balancer-controller

Как я понял по заявлению мейнтейнеров, breaking changes в пользовательском API (Ingress, Service, Gateway) они не предполагают.
Но issue на GitHub уже висят, так что посмотрим.

Что важного и интересного (для меня):
- Gateway API объявлен GA (production ready) - теперь можно смело использовать в бою, а не в тестовых проектах 🔥
​- Версия Helm-чарта выровнена с версией контроллера - раньше было 2.x контроллер с чартом 1.x, теперь 3.0.0 = 3.0.0. Наконец-то! ❤️
​- Новые фиксы NLB target groups, порядка сабнетов, AZ mismatch и webhook-сертификатов
​- CRD ListenerRuleConfiguration добавлен, но пока экспериментальный - не использовать в проде
- Минимальная версия Kubernetes - теперь официально требуется 1.24+ (интересно, кто ещё на таком старье сидит 😁)
​- IPv6 для internet-facing ALB/NLB - теперь нативно поддерживается без костылей, раньше были ограничения 🎉

Нюансы с апгрейдом:
- перед helm upgrade до 3.0.0 нужно вручную обновить CRD'ы. Issue #4555 прямо про это - люди натыкаются на проблемы, потому что в release notes это не очень явно прописано.
Но как по мне так это и очевидно, так как мы все знаем, что при хелм апгрейде​ CRD не обновляется никогда и ни у кого, архитектурная особенность самого хелма.
- для Gateway API нужны не только CRD самого контроллера, но и базовые Gateway API CRD (HTTPRoute, GatewayClass и т.д.), если их ещё нет в кластере

Сам, конечно же, я пока обновляться не буду.
Почитаю issues ещё недельку, потом с командой решим - стоит ли сразу или подождать патч-релиз.

Better safe than sorry, особенно с ингресс-контроллерами, которые держат весь трафик.
Please open Telegram to view this post
VIEW IN TELEGRAM
💯4🎃1
А вариантов отказаться и нет 😭
Please open Telegram to view this post
VIEW IN TELEGRAM
7🤣4🤯3💔2👍1
Там Daniele Polencic обновил статью про k8s API.
Прям с графиками, картиночками, наглядно.
В целом годно, как и многие его другие ресурсы/статьи. Никакого рокетсайнса и кишочков - просто база-дополнение к официальной документации.

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

https://learnkube.com/kubernetes-api-explained
🔥12👍2
#gitlab #troubleshooting #одинденьизжизни

Тихий убийца времени.


На новом проекте дали задачу: небольшие изменения в гошном операторе Kubernetes.
Секреты, cluster-scoped объекты, ничего космического.
Покрутил код, разобрался в архитектуре, поднял локальный kind-кластер, погонял тесты.
Makefile на месте, всё зелёное. Красота.

Коммичу, пушу MR.
Тесты падают. 🙃

Ну ладно, думаю. Я серьёзно менял логику, наверное поломал что-то. Бывает.
Возвращаюсь, перепроверяю. Локально гоняю - всё проходит.
Коммичу, пушу - снова падает.

Ок, уже интересно.

Открываю .gitlab-ci.yml, читаю джобу тестов строчка за строчкой.
Повторяю ровно то же самое локально - make test, всё зелёное.
В GitLab - красное.

Смотрю логи джобы внимательнее.
Один из тестов падает на скачивании image из container registry соседнего репозитория. Не хватает авторизации. Ага.

Проверяю:
- мой GitLab токен - валидный
- доступ в соседние репозитории (сайдкар-образы для тестов) - есть
- образы в registry - на месте
- пайплайн до моих изменений - зелёный, тесты проходили
Всё на месте, а не работает.🤡

Перепроверяю ещё тысячу раз.
Локально - 100% то же самое - работает.
В GitLab - нет.

Тут приходит мысль: а может дело не в коде, а в правах?
Пайплайн-то запускается от моего имени.
А у тех, кто запускал до меня, может быть что-то другое.

Иду смотреть настройки репозитория.
Settings - нет доступа.
Access Tokens - нет доступа.
Deploy Tokens - нет доступа.
У меня Developer, без права заглянуть хоть куда-то в настройки.

Пишу в личку коллеге, который точно Admin:
- Слушай, можешь по этой ссылке просто нажать Retry на джобе тестов?
Он жмёт.
Тесты проходят. Сука.

Я жму Retry.
Тесты падают. Сука.

Пишу главной команде DevOps (да, оксюморон - девопс пишет девопсам "спасити-памагити").
Объясняю ситуацию: так и так, тесты падают только когда пайплайн запускает мой юзер, предполагаю, что CI_JOB_TOKEN моего профиля не имеет нужных прав, он передаётся в кубер как image pull secret, а там авторизация не проходит.

Ну, после некоторых усилий удалось донести мысль. Ребята берут таймаут.

Через несколько дней/часов:
- Ретрай.
Ретраю.
Зелёное. 🎉

- А что было?
- Мы тоже долго дебажили, скормили все токены в Claude, но нашли.
У тебя в профиле GitLab стояла галочка External User.


External. User. Сука.
Галочка. В профиле. Которую я не ставил. Которую даже не видел (у меня нет доступа к админ-панели). Которую кто-то когда-то поставил при создании моего аккаунта. Или не снял. Или поставил по дефолту в LDAP/SAML/SCIM-маппинге. Или просто потому что.

Что делает External User в GitLab:
- https://docs.gitlab.com/administration/external_users/
- внешний пользователь не имеет доступа к internal-репозиториям
- CI_JOB_TOKEN наследует ограничения профиля
- даже если у тебя есть явный Developer-доступ к проекту, некоторые internal-ресурсы (включая container registry соседних проектов) могут быть недоступны
- в логах пайплайна это выглядит как обычная 401/403 при pull image - ни слова про external user

Всё работает. Везде. Кроме одного места.
И это место - галочка в чужой админ-панели, которую ты даже увидеть не можешь.

Потрачено:
- ~6-7 часов моего времени на дебаг
- N часов времени DevOps-команды
- массу нервных клеток
- массу токенов в Claude

Выводы:
- если пайплайн падает только у вашего юзера, а у коллег - нет, проблема не всегда в коде.
Проблема иногда в правах. Не в правах репозитория, а в правах профиля.
- External User в GitLab - это тихий убийца. Никаких предупреждений в UI, никаких баннеров "вы external". Просто CI_JOB_TOKEN молча получает урезанные права.
- вы не увидите эту галочку сами - она в Admin Area, доступ только у администраторов GitLab.
- при онбординге на новый проект спросите: "А мой аккаунт точно не external?" Серьёзно. Одна галочка - полдня жизни.
- локальные тесты != CI тесты. Даже если команды идентичны. Контекст авторизации разный.
- и как обычно: во всём виноваты девопсы. Даже когда девопс - это ты сам. 😢
Please open Telegram to view this post
VIEW IN TELEGRAM
👍23🤡2💔1
#longread #troubleshooting #operators #kubectl #kubernetes #одинденьизжизни

Внезапный и незапланированный лонгрид.

Разбирал по работе задачу, узнал новое про фичу kubectl cache discovery.
Теперь делюсь историей и знаниями с вами.
Приятного прочтения.

https://teletype.in/@kruchkov_alexandr/wWa-INvQvJH
15👍27🔥1
#devops

Просто делюсь последними находками.

- https://system-design.space/
Нечто типа русскоязычного справочника по system design.
Большой и объёмный. Начал почитывать, весьма годно.
За один присест всё не осилить, буду продолжать как книгу читать ближайшие месяцы.
Достойный аналог известному https://github.com/donnemartin/system-design-primer

Оцениваю как 9.5/10.

- https://endoflife.date/
А где-же, а где-же я смотрю когда что протухнет?
Не руками/глазами же смотрю на сайте каждого облака/ продукта/ компонента/ девайс/ операционка/ имадж/ фремворка/ либы.
Если надо глазами глянуть, то этот сайт просто топ.
Для обычных библиотек софта есть dependabot/Renovatebot (кстати, кто-то из них с этого же сайта берёт инфо).
А для всего остального этот ресурс.
Может даже у него MCP есть, но я не искал, я быстрее глазами найду, чем заряжать на это LLM.

Оцениваю как 9/10 (есть не всё).

- https://thenewstack.io/
Невероятно захватывающие и очень интересные мне истории, случаи, опыт, рассказы, postmortems.
DevOps, k8s, cloud и вот это вот всё.
Читаю те топики, что мне интересны, часть пропускаю (есть и маркетинг буллшит).

Оцениваю в 8.5/10.

- https://awesome-llmops.inftyai.com/
- https://github.com/InftyAI/Awesome-LLMOps
Неплохая таблица как у https://landscape.cncf.io/, но по LLM/LLMOps.
Курируемый список (awesome list) инструментов для LLMOps, он охватывает инференс, оркестрацию, RAG, агентов, fine-tuning и мониторинг LLM.
​Короче очередной неплохой awesome список.
В мире AI, когда каждый день всё меняется, это неплохой источник.
А надо быть в курсе всего этого, иначе уволят будешь не в теме.

Оценка 8/10.

- https://resources.anthropic.com/hubfs/The-Complete-Guide-to-Building-Skill-for-Claude.pdf?hsLang=en
Крутой мануал по скиллам. Сразу запилил себе кучу всего полезного.
Нет смысла рассказывать, что себе сделал, так как эта инфа устареет уже завтра, когда выйдет очередная новая модель и обновление курсора с новыми фичами.
Имеет смысл ознакомится и попробовать либо сейчас, либо сразу скипнуть.

- https://agentsmd.io/agents-md-best-practices
Бест практисы с AGENTS.md файлом.
Ровно как и предыдущая ссылка будет актуально лишь короткое время.
Имеет смысл ознакомится и попробовать либо сейчас, либо сразу скипнуть.

- https://github.com/metalbear-co/mirrord
Очень интересная задумка. Конечно же у него есть аналоги, но мне понравилась эта реализация.
Потыкал на лабораторном кластере с go-шным и php стеком - прикольно!
В отличии от telepresence/gefyra/nocalhost невероятно низкий входной порог и буквально в три клика развернуть.
Простота в наше переусложнённое время дорогого стоит.
Однозначно лайк, надеюсь они не умрут через полгода.

Оценка 10/10.


Было ещё много прочитанного, изученного, но в общем и целом это, скорее, белый шум, чем что-то, чем хочется поделится.
10👍20🔥16
Перешёл на Ask every time в Cursor IDE.

Устал разгребать дерьмо от агента.
Прям утомился и устал.

Реалии февраля 2026:
- игнорирует allow list в README.md
- игнорирует allow list в настройках Cursor IDE
- игнорирует файл(ы) rules Cursor IDE
- игнорирует allow для MCP серверов
- игнорирует явные запреты в AGENTS.md
- игнорирует рут сандбокс (может легко выходить из песочницы)
- при моих запретах средствами операционной системы начинает писать питон скрипты, чтобы обойти запреты доступа к файловой системе и просить аппрув на выполнение🤨

Каждый раз без зазрения совести использует опасные команды без аппрува, если ему захотелось
- terraform apply -target -auto-approve
- kubectl delete/apply
- terragrunt run-all -auto-approve
- aws .. modify ..
и многое другое. Печаль.

Модели:
- Claude-4.5-sonnet
- 4.6 Opus

Четырёх сильных ошибок мне хватило.
Благо git всё помнит и можно ревертнуть руками, а косяк был без персистент даты.

Мне нравится этот новый поезд LLM и агентов.
Однако слишком быстро стремящийся поезд.
Предпочитаю быть за рулем, или хотя бы быть в вагоне с кабиной управления, а не ехать в заднем вагоне с закрытыми глазами.

- - -
На скрине часть моей драмы-переписки.
В итоге у меня сейчас 0 MCP серверов, пустые allow list, пару костыль-ограничений средствами операционки и Ask every time.
Печаль.
Please open Telegram to view this post
VIEW IN TELEGRAM
😁195👍5🥴2😢1
Ямлоделие

О, дивный мир, на работе я узнал об ограничении GitLab на парсинг YAML файла с пайплайном.

Проскочила ошибка, уронила всё.
Unable to run pipeline
`gitlab-ci.yml`: The parsed YAML is too big

Документация привела к
https://docs.gitlab.com/administration/instance_limits/#maximum-size-and-depth-of-cicd-configuration-yaml-files

Интереса ради спуллил их репу https://gitlab.com/gitlab-org/gitlab
Аригато, кстати, что git репозиторий весит всего 2.79 GiB, просто невероятное удобство😊.

Затем спросил нейронку сколько памяти/ресурсов экономится при парсинге 2 или 4 мегабайтных файлов и какие причины такого ограничения.

Самое интересное - max_yaml_size_bytes это не физический размер файла, а память, выделяемая на объекты при парсинге.
То есть 2 MB YAML может жрать больше 2 MB RAM в зависимости от структуры.

Зачем вообще лимит?
Погуглил, почитал документацию, посмотрел код.
- DoS защита
один огромный YAML может положить весь Sidekiq (классная архитектура 😀)
- OOM превенция
память пре-аллоцируется, условно 100 пайплайнов по 100 MB = изда RIP серверу
- производительность
парсинг гигантских YAML тормозит всех (чужие проекты, пайплайны)
- code smell детектор (это я/мы)
если у вас 2+ MB YAML, что-то пошло не так в архитектуре

Ну штош, значит пора оптимизировать содержимое пайплайнов.😭
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5👌21
#aws #rds #troubleshooting

Приходят как-то коллеги, говорят - нет прав включить Enhanced Logging на RDS Proxy.
Для дебага очень надо на пару часов.
Ок, смотрю политику, а там rds:* на Resource = "*".
Говорю - всё есть, всё должно работать.
Хоть дропайте всё к херам (stage account).

Возвращаются - нет, всё равно не работает.
Проверяю глазами ещё раз полиси.
Да вроде всё ок.
Говорю сделайте релогин и попробуйте ещё, все права есть.

Снова возвращаются, сделав релогин.
Говорят "включаем, а оно не включается".
Делаю невозмутимое лицо, хотя внутри уже кривлюсь как хурма: описание проблемы уровня "включаем, а не включается, ошибок нет" звучит слишком уныло, чтобы воспринимать его всерьёз.

Прошу объяснить подробнее.
Мне показывают по шагам:
- зашли в консоль
- зашли в RDS
- нашли нужный proxy
- нажали Edit/Modify (я не помню название кнопки)
- поставили галочку "Activate enhanced logging"
- нажали "Modify proxy"
- видят надпись "Modifying proxy ..."
- видят зелёный баннер "Successfully modified proxy ..."
- выходят, заходят снова - галочки нет

Нигде ни одной ошибки.
Всё выглядит как успех.
Но изменение не применяется.
В ивентах пусто.

Повторяю сам под своим admin пермишнсетом - у меня работает, галочка стоит.
В ивентах изменения появились.

Ладно, добавляю себя временно в эту группу и начинаю воспроизводить.
Захожу под их пермишнсетом, повторяю их действия.
Та же история - "Successfully modified", а галочка не стоит.

Думаю что не так.
Выхожу из SSO, захожу снова - галочки нет.
Сбрасываю кеш браузера - галочки нет.
Пробую другой браузер - галочки нет.
Смотрю в developer tools в браузере - никаких ошибок, никаких 403, всё 200.
Смотрю в сам UI консоли - ни единого красного баннера, ни единого намёка на проблему.
Само собой инкогнито мод браузера не помог.
Ивентов нет.

Потратил на это ещё чуть времени, пока до меня наконец не дошло.
Дурачок, - думаю я, - а CloudTrail-то ты проверил?

Иду в CloudTrail, фильтрую по ModifyDBProxy.
Нахожу событие. И там:
"errorCode": "AccessDenied",
"errorMessage": "User: ... is not authorized to perform: iam:PassRole
on resource: arn:aws:iam::ACCOUNT_ID:role/rds-proxy-wanker
because no identity-based policy allows the iam:PassRole action"

Вот оно.

AWS при вызове ModifyDBProxy передаёт IAM роль прокси в Secrets Manager.
Для этого нужно право передать (PassRole) именно эту роль.
rds:* тут ни при чём - это отдельное действие на отдельный ресурс.

В политике группы iam:PassRole был разрешён только для одной конкретной роли.
Про rds-proxy-* никто не подумал.

Добавляем в политику:
{
"Effect": "Allow",
"Action": "iam:PassRole",
"Resource": "arn:aws:iam::ACCOUNT_ID:role/rds-proxy-*"
}

Применяем, перелогиниваемся.
Галочка встаёт и остаётся стоять.
Ивенты пишутся.

Итоги:
- "Successfully modified" в AWS консоли не гарантирует, что изменение применилось 🥲
- AccessDenied может прилетать не на само действие, а на зависимое - в данном случае на iam:PassRole
- Консоль эту ошибку не показывает совсем. Молча глотает. Никакого красного баннера. Никаких ошибок. Никаких ивентов. 😎
- CloudTrail - первое место, куда надо смотреть, когда "всё работает, но не работает"
- rds:* не равно "всё для RDS". Некоторые операции тащат за собой зависимости на другие сервисы
- нехер снова кривить свою морду, коллеги всё же солнышки-зайчики и правы, даже если пояснение проблемы тупорылое
Please open Telegram to view this post
VIEW IN TELEGRAM
🤯162😭1