Перейти к содержимому

core.url

← Каталог модулей

soul-sidesoulstack.networknetworkroot требуется

Загрузка файла по https-URL с checksum-верификацией и SSRF-guard.

core.url.fetched скачивает файл по url в path и приводит mode/owner/group к декларации. Работает secure-by-default: только https://, SSRF-guard по резолвнутому IP, проверка TLS-цепочки и checksum-верификация во временном файле до atomic rename — неверный хэш не материализуется никогда. Идемпотентность идёт по checksum, а без него — по SHA-256; каждый контур безопасности снимается отдельным opt-out-флагом. Без shell.

Требования

  • Rootтребуется
  • Сторонаsoul-side
  • Коллекцияsoulstack.network
  • Категорияnetwork
Capabilitiesnetwork_outboundfs_write_root

Состояния

core.url.fetched — Файл по url материализован в path с заданными mode/owner/group.

Меняется, когда

Контент скачан заново либо правился атрибут (mode/owner/group). Ветвление — в таблице «Поведение fetched по веткам».

Не меняется, когда

Совпадение по checksum/SHA-256 без правки атрибутов.

Параметры

ПараметрТипОбяз. / дефолтОписание
urlstringrequiredИсточник (только https://; SSRF-guard на резолвнутый IP).
pathstringrequiredЦелевой путь файла.
checksumstringoptionalОжидаемый хэш в форме "sha256:<hex>"/"sha1:<hex>" (supply-chain).
modestringoptionalПрава в восьмеричной форме, напр. "0644".
ownerstringoptionalВладелец (имя пользователя).
groupstringoptionalГруппа-владелец (имя группы).
headersmap<string>optionalHTTP-заголовки запроса (значения секретны, в output не попадают). If-None-Match/If-Modified-Since здесь же дают conditional-GET (304 → no-op).
timeoutstringoptionalТаймаут запроса (Soul Stack duration, напр. "300s").
allow_httpbooloptional · falseРазрешить http:// (downgrade-риск). НЕ открывает SSRF — dial-guard держится отдельно (allow_private).
insecure_skip_verifybooloptional · falseНе проверять TLS-цепочку (self-signed / internal CA). MITM-риск.
allow_privatebooloptional · falseСнять SSRF-guard: разрешить dial в metadata/loopback/RFC1918 (легитимный internal endpoint).

Пример — Скачать релиз с GitHub с проверкой checksum

- name: Fetch node_exporter tarball with checksum
module: core.url.fetched
params:
url: "https://github.com/prometheus/node_exporter/releases/download/v1.9.0/node_exporter-1.9.0.linux-amd64.tar.gz"
path: /tmp/node_exporter-1.9.0.tar.gz
checksum: "sha256:abc...def"
mode: "0644"

Output

ПолеТипОписание
pathstring
urlstring (эхо без headers)
sha256string (SHA-256 записанного/совпавшего содержимого)
sizeint (байты)
changedbool
fetchedtrue

Справочник

Поведение fetched по веткам

Логика зависит от того, задан ли checksum и совпадает ли уже лежащий по path файл.

УсловиеДействиеchanged
checksum задан + файл есть и совпал по хэшуконтент не качается; mode/owner/group приводятся к декларации (convergence)true только если правился атрибут
checksum задан, файла нет / хэш не совпалскачать во temp → verify по checksum → atomic rename; mismatch → failed, temp удаляется, целевой путь не трогаетсяtrue
checksum не задан + файл есть и совпал по SHA-256скачать во temp → сравнить SHA-256 → записи нет; mode/owner/group сверяютсяtrue только если правился атрибут
checksum не задан + содержимое отличается / файла нетскачать во temp → atomic renametrue

Заметки

  • Условный GET: If-None-Match / If-Modified-Since в headers дают conditional-GET — сервер может ответить 304 Not Modified (тело не передаётся). 304 при существующем локальном файле → no-op (mode/owner/group приводятся к декларации, output по существующему файлу); 304 без локального файла → failed (stale-валидатор без кэша, скачивать нечего). 304 проверяется раньше общей проверки 2xx.
  • Права зависят от целевого path: запись в системный каталог требует root, в user-writable путь (напр. /tmp) — нет. Манифест объявляет network_outbound + fs_write_root.
  • checksum: поддержаны sha256 и sha1; md5 сознательно не поддержан (слаб для supply-chain). В output.sha256 всегда SHA-256, даже если checksum задавался по sha1.
  • Снятие любого opt-out-флага (allow_http / allow_private / insecure_skip_verify) кладёт строку в output warnings — только host, без полного URL и headers (query/path и заголовки могут нести секреты).
  • Не выполняет подпроцессов: скачивание, хэширование и запись — in-process, без shell.

Безопасность и умолчания

  • По умолчанию только https:// — http://, file:// и трюки вида https://\nhttp://evil отвергаются (схема сверяется регистронезависимо через url.Parse). allow_http допускает http://, но file:// / ftp:// остаются запрещены и SSRF-guard не ослабляется.
  • SSRF-guard: dial в metadata (169.254.169.254), loopback, RFC1918, link-local/CGNAT заблокирован по фактически резолвнутому IP — закрывает прямой SSRF (кража cloud-metadata IAM-кредов) и DNS-rebind (dial по уже проверенному IP, без второго резолва). Хост с парой A-записей «публичный + metadata» блокируется целиком. Снимается только allow_private.
  • Checksum verify ДО публикации: скачивание всегда идёт во временный файл в каталоге path, хэш считается на лету, verify против checksum — до rename. При mismatch temp удаляется, целевой путь не трогается — неверный хэш не материализуется никогда.
  • TLS — системный trust store по умолчанию; снимается insecure_skip_verify (self-signed / internal CA, MITM-риск). Редиректы: downgrade https→http отвергается (допускается только при allow_http; редирект на не-http(s) схему блокируется всегда, как и dial в приватные адреса на hop'е без allow_private).
  • headers sensitive-by-construction (ADR-010 §7.4): значения никогда не логируются и не попадают в output/register, в том числе в эхо-поле url.

См. также