Ошибка AccessDenied не всегда означает отсутствие одной галочки. Итоговое решение доступа складывается из личности запроса, IAM-policy, bucket policy, resource path, условий, временной сессии и иногда прав на ключ шифрования.
Сначала выясните, от имени какого principal реально выполняется запрос. Затем проверьте конкретное действие над конкретным ARN/ресурсом и явные Deny. Не выдавайте администраторские права приложению ради проверки: используйте симуляцию и минимальную тестовую policy.
Что проверить в первую очередь
Сначала зафиксируйте точный сценарий, время ошибки и последнее известное рабочее состояние. Не меняйте несколько настроек одновременно: один контролируемый шаг должен подтверждать или исключать одну гипотезу. Перед работой с данными и конфигурацией подготовьте резервную копию и понятный способ отката.
- Получите identity/assumed role текущего процесса, account/project и срок временных credentials.
- Зафиксируйте действие: ListBucket, GetObject, PutObject, DeleteObject или multipart.
- Сравните bucket, prefix, регион/endpoint и фактический ключ объекта.
- Проверьте явные Deny в IAM, bucket policy, organization policy и KMS.
Почему возникает проблема
Внешний симптом обычно появляется на границе нескольких компонентов: интерфейса, backend, базы, фоновой очереди или внешнего сервиса. Поэтому важно найти первое место, где состояние становится неверным, а не исправлять последнее сообщение об ошибке.
- Приложение ожидает одну роль, но runtime использует instance/service role другого проекта.
- Policy разрешает object ARN, но не bucket ARN для ListBucket или наоборот.
- Условие prefix, source VPC, IP или principal не совпадает с запросом.
- Объект зашифрован KMS-ключом, к которому роль не имеет Encrypt/Decrypt.
- Временные credentials истекли или не обновляются процессом.
Пошаговая диагностика
Диагностику проводите на тестовой записи или отдельном окружении. В журналах скрывайте токены, пароли и персональные данные. Для каждого шага сохраняйте измеримый результат: идентификатор события, код ответа, версию записи, состояние процесса или контрольную сумму.
- Выполните безопасный identity call из того же контейнера/процесса.
- Повторите одну минимальную операцию CLI/SDK с debug metadata без вывода секретов.
- Проверьте policy simulator или audit log для точного action/resource.
- Сравните разрешения ListBucket и Get/PutObject отдельно.
- Проверьте session policy, permission boundary и organization-level restrictions.
Как складывается решение IAM
Разрешение в одной policy не перекрывает явный Deny и не предоставляет доступ к связанному KMS-ключу. Нужно проверить всю цепочку.
- Principal — пользователь, сервисная учетная запись или assumed role, фактически подписавшая запрос.
- Action должен точно соответствовать операции SDK, включая multipart и list.
- Resource различается для самого bucket и объектов внутри него.
- Conditions ограничивают prefix, теги, сеть, шифрование и другие параметры.
- KMS key policy и IAM должны совместно разрешать криптографическую операцию.
Как исправить проблему
Исправление лучше разбить на небольшие обратимые изменения. Сначала устраните подтвержденную причину, затем повторите исходный сценарий и проверьте соседние функции. Массовую обработку данных запускайте на ограниченной выборке с отчетом и только после сверки расширяйте на весь объем.
- Назначьте приложению правильную runtime role вместо статических ключей.
- Добавьте только нужные actions и prefixes для bucket/object ресурсов.
- Исправьте bucket policy, сохраняя public access block и явные ограничения.
- Предоставьте минимальные права на KMS-ключ либо используйте согласованный ключ хранилища.
- Настройте автоматическое обновление временных credentials и обработку их истечения.
Безопасный порядок внедрения
- Сохраните затрагиваемые данные, конфигурацию и текущие журналы, заранее проверив способ отката.
- Повторите проблему на тестовом объекте без реальных списаний, рассылок и изменений клиентских данных.
- Внесите одно логическое изменение и зафиксируйте его в системе контроля версий или журнале работ.
- Не отключайте авторизацию, валидацию, шифрование и другие защитные механизмы ради быстрого исчезновения ошибки.
- После выкладки контролируйте логи, метрики и полный пользовательский сценарий, а не только один успешный запрос.
Как проверить результат
Разовый успешный тест недостаточен. Повторите операцию, проверьте крайние значения, параллельные действия и восстановление после перезапуска или временного сбоя. Для важного сценария сохраните автоматический тест либо короткий регрессионный чек-лист.
- Приложение выполняет необходимые List/Get/Put и не может обращаться к соседнему prefix.
- Доступ работает после ротации/истечения временной сессии.
- Публичный анонимный запрос остается запрещенным.
- Audit log показывает ожидаемый principal, action и resource без AccessDenied.
Типичные ошибки при исправлении
- Выдавать AdministratorAccess и оставлять его после диагностики.
- Хранить access key в репозитории или образе контейнера.
- Разрешать s3:* на все ресурсы ради одной папки.
- Игнорировать KMS и organization policy, бесконечно расширяя bucket policy.
Как предотвратить повторение
Профилактика строится вокруг явных контрактов, повторяемых релизов и наблюдаемости. Система должна не только работать сейчас, но и позволять быстро увидеть нарушение инварианта при следующем обновлении, росте нагрузки или сбое внешнего сервиса.
- Управляйте IAM как кодом и проверяйте изменения review.
- Используйте короткоживущие роли workload identity вместо постоянных ключей.
- Добавьте тест положительных и отрицательных действий для каждого сервиса.
- Мониторьте AccessDenied, неожиданные principals и изменения policy.
Что подготовить для технического разбора
- Описание ожидаемого и фактического поведения, а также точную последовательность действий.
- Время проблемы, идентификатор тестового объекта и версии затронутых компонентов.
- Фрагменты журналов до и после ошибки без секретов и персональных данных.
- Перечень последних изменений и уже выполненных проверок.
- Безопасный доступ к тестовой среде или способ воспроизвести сбой без влияния на клиентов.
Частые вопросы
Почему GetObject разрешен, а список файлов нет?
GetObject действует на объект, а ListBucket — на ресурс bucket и часто требует отдельного разрешения с условием prefix.
Может ли bucket policy запретить разрешение IAM?
Да. Явный Deny имеет приоритет, а cross-account доступ обычно требует согласованного разрешения с обеих сторон.
Когда нужна помощь специалиста
Если приложение получает AccessDenied и непонятно, какая роль работает, я могу проследить principal, action и resource, исправить IAM/bucket/KMS policy по принципу минимальных прав и проверить отрицательные сценарии.