Коротко. Ключи и аккаунт созданы, бакет существует, GUI зелёный — а клиент получает 403 AccessDenied уже на листинге. Причина в правах: у ресурса нет resource policy, которая разрешает этому аккаунту доступ. Штатный путь — выдать политику через iamd (PutResourcePolicy), а не обходить проверку системным ключом.
Симптом
- Клиент получает
403 AccessDeniedнаListBucket,GET,PUT— иногда на всё сразу. - Тело ответа — код
AccessDenied, а неSignatureDoesNotMatchи не текст про разницу времени. - Ключи заведомо верные: тот же аккаунт работает из консоли продукта, либо ключи только что созданы и проверены.
- Аккаунта нет в
/model/— и это норма: аккаунты и ключи живут в iamd, а не в модели. - В GUI ошибок по узлам, дискам и службам нет; S3-фронт отвечает (например
307на корень). - Отдельно похожий, но другой случай:
403на запрос с неподписаннымx-amz-meta-*— это штатное правило S3 («заголовкиx-amz-*надо подписывать»), а не отсутствие политики.
Что проверить первым (read-only)
Проверки — через консоль продукта: sudo -i; sherpa -c "<одна строка>". gRPC-вызовы iamd требуют
явных аргументов, поэтому поля перечисляются все.
-
Есть ли аккаунт и пользователь:
python from google.protobuf.json_format import MessageToDict iam = cli._connection_factory.create_iamd_connection() MessageToDict(iam.ListAccounts(marker='', onlyIfQuotaExceeded=False, nameOrEmailRegex='', maxItems=100, allowDisabled=True)) MessageToDict(iam.ListUsers(accountEmail='<ACCOUNT_EMAIL>', maxItems=100, marker='', pathPrefix='', allowDisabled=True, nameOrEmailRegex='', accountCanonicalId=''))Ожидается: аккаунт в списке, пользователь активен, ключ существует. Если аккаунта нет — это другой класс проблемы (учётку не создали), а не права на ресурс. -
Проверка вендорским путём, без внешнего клиента (
cli.s3_connectсам берёт секрет из iamd):python conn = cli.s3_connect('<ACCESS_KEY_ID>') b = conn.get_bucket('<BUCKET>', validate=False) # validate=False обязателен print b.get_all_keys()Ожидается список объектов.S3ResponseError: 403 AccessDenied— подтверждение, что дело в правах на ресурс, а не в ключах или сети. -
Что говорит политика бакета (подписанным запросом валидными ключами):
bash aws --endpoint-url https://<DOMAIN> s3api get-bucket-policy --bucket <BUCKET>Ожидается документ политики с нужным principal и действиями. Пустой ответ / отсутствие политики — причина найдена. У продукта bucket policy API есть:PUT ?policyотвечает204,GET ?policyотдаёт политику. -
Доступен ли IAM по имени, а не по адресу: IAM вызывается по IAM-домену; обращение «по IP» не работает. Проверяется резолвом домена и тем, что
ListAccountsиз п.1 отвечает, а не висит. -
Отвечает ли фронт вообще (чтобы исключить TLS/DNS):
bash curl -sS -o /dev/null -w '%{http_code}\n' https://<DOMAIN>/Ожидается307иServer: Quantum-ActiveScale.
Причина
Права проверяются после подписи
Шлюз принимает запрос, проверяет подпись SigV4, затем — права. Аккаунт с валидными ключами, но без
разрешения на конкретный ресурс, получает AccessDenied. Это не ошибка ключей: подпись сошлась,
иначе клиент увидел бы SignatureDoesNotMatch.
Почему «аккаунт есть» не означает «доступ есть»
Создание аккаунта и ключа не создаёт разрешений на бакеты. Разрешение — отдельный документ
resource policy, привязанный к ARN ресурса (arn:aws:s3:::<BUCKET>), где перечислены principal и
действия. Пока документа нет, шлюз по умолчанию закрывает доступ даже на листинг. Продукт ведёт
себя как S3: «запрещено, пока не разрешено явно».
Где путаются
- Аккаунты не в модели. Поиск аккаунта в
/model/даёт пусто и рождает ложную гипотезу «аккаунт потерялся». Аккаунты — в iamd (gRPC), проверяются черезListAccounts. Principal: "*"не открывает анонимный доступ. Политика бакета сPrincipal: "*"и{"AWS": "*"}на практике отдаёт анонимным запросам403 AccessDenied; анонимов пускает ACLpublic-read-write, но при анонимной записи шлюз молча выбрасываетx-amz-meta-*. Это другой сценарий и другая статья; для доступа по ключам нужен principal конкретного аккаунта.- Системный foos-ключ. Обход прав «служебным ключом» — не ремонт, а дыра; так делать нельзя.
Что здесь гипотеза
Механизм «нет resource policy» подтверждён живыми вызовами. Если политика есть и разрешает нужные
действия, а 403 AccessDenied остаётся — гипотеза: не совпал principal (canonical id аккаунта
против указанного в документе) либо ARN указывает не на тот ресурс. Проверяется сверкой документа
политики с canonical id аккаунта и точным именем бакета.
Решение (штатное)
-
Зафиксировать текущее состояние: список аккаунтов/пользователей (п.1) и документ политики, если он есть (п.3). Скопировать документ в файл вне каталога продукта — это основа отката.
-
Подготовить документ политики под конкретный аккаунт и бакет: principal — аккаунт, действия — минимум необходимого (
s3:ListBucket,s3:GetObject,s3:PutObject— по задаче), ресурсы — бакет иarn:aws:s3:::<BUCKET>/*. -
Выдать политику штатным путём через iamd:
python iam = cli._connection_factory.create_iamd_connection() iam.PutResourcePolicy(resourceArn='arn:aws:s3:::<BUCKET>', resourcePolicyDocument=<JSON_DOC>, expectedResourceId='')Ожидается пустой ответ{}= успех. Имя поля — именноresourcePolicyDocument; другое имя даёт ошибку вызова, а не «политика не применилась». -
Проверить доступ тем же вендорским путём (п.2):
get_bucket(..., validate=False)иget_all_keys()без исключения. -
Проверить внешним клиентом:
aws s3 ls, затем PUT/GET небольшого объекта. Ожидается200и совпадающее тело. -
Записать, что именно выдано (ресурс, principal, действия) — в реестр доступа; это пригодится при аудите и при следующем
AccessDenied.
Если штатный путь недоступен
- Нет доступа к
sherpa(L1 без прав root): собрать факты (код ответа, ключ, бакет, время), передать инженеру. Временная мера «дать полный доступ всем» недопустима. - Нужен доступ сегодня, а политику согласуют долго: временная мера — отдельный аккаунт с минимальной политикой под конкретную задачу; пометка не штатно в смысле «обход процесса согласования», план замены — штатная политика на основной аккаунт.
- Обход системным ключом/отключение проверки прав — запрещено: это не решение, а неконтролируемый доступ.
Проверка
PutResourcePolicy→{}(успех).cli.s3_connect('<ACCESS_KEY_ID>')→get_bucket('<BUCKET>', validate=False)без ошибки;get_all_keys()возвращает список.aws s3 ls→ листинг;PUT/GETобъекта →200, тело совпадает.GET ?policy→ документ содержит нужный principal и действия.403с кодомAccessDeniedв логах шлюза по этому аккаунту больше не появляется.- Контроль:
403на запрос с неподписаннымx-amz-meta-*остаётся — это норма, не регресс.
Профилактика
- Выдавать политику вместе с аккаунтом — в одном чек-листе провижининга, а не «потом».
- Проверять доступ вендорским путём (
cli.s3_connect) сразу после создания ключей: дешевле, чем ждать клиента. - Различать коды:
AccessDenied— права;SignatureDoesNotMatch— секрет/подпись; текст про разницу времени — часы; TLS-ошибка — сертификат и DNS. Лечение у них разное. - Не искать аккаунты в модели — они в iamd.
- Реестр доступов: кто, к какому бакету, какие действия. При аудите и разборе
403это первое, что спрашивают.
Источники и дата
- Вендор: Управление системой (GUI) (дата доступа 2026-11-07)
- Вендор: Software Documentation Center 7.3 (дата доступа 2026-11-07)
- Наша практика (обезличено): класс «S3
AccessDenied— нет resource policy у аккаунта»; выдача через iamd, проверка вендорским S3-подключением. - Обновлено: 2026-11-07.