🛡 Docker для параноика: SSH-доступ без передачи приватного ключа
Приватный ключ внутри контейнера — это компрометация в квадрате. Даже монтирование ~/.ssh только для чтения не спасает: процесс читает ключ и уносит наружу. Замена на токен ничего не меняет, если токен доступен тому же процессу. Проблема не в выборе секрета, а в том, что процесс вообще не должен его видеть. В rootless Docker схема с ssh-agent усложняется: UID контейнера не совпадает с UID на хосте. Прямое монтирование SSH_AUTH_SOCK не работает — ssh-agent видит чужой UID и отклоняет соединение. По данным habr_infosec, решение — запустить отдельный ssh-agent с сопоставленным UID через setpriv.
UID 1000 внутри контейнера превращается в 100999 на хосте. Вычислить это можно через /etc/subuid и /proc/self/uid_map. Затем модуль systemd остаётся root, но сам ssh-agent запускается от 100999: setpriv --reuid=100999 --regid=100999 --clear-groups --inh-caps=-all --no-new-privs /usr/bin/ssh-agent. Ключ читает root через ExecStartPost, а контейнер получает только Unix-сокет. Так ключ физически отсутствует в пространстве имён контейнера. Дополнительно ssh_known_hosts проверяет подлинность сервера — StrictHostKeyChecking=no не нужен.
Схема не закрывает все риски. Если процесс получит доступ к сокету, он сможет использовать ssh-agent от имени этого UID. Поэтому права на сокет и каталог критичны. Ещё одно ограничение: менять /etc/subuid или UID внутри контейнера после создания файлов опасно — сменится их владелец, и контейнер перестанет их видеть.
Меня беспокоит, что такой подход почти не встречается в готовых образах и оркестраторах. Каждая команда изобретает велосипед с сопоставлением UID. Хотелось бы видеть это как встроенный флаг в docker run, а не набор костылей.
#Docker #rootless #sshAgent #DevSecOps
Post #905
12