Ответ 1
Выключается при использовании Ubuntu, ssh_config неверен. Вам нужно добавить
RUN echo " IdentityFile ~/.ssh/id_rsa" >> /etc/ssh/ssh_config
в ваш файл Docker, чтобы узнать, как распознать ваш ключ ssh.
У меня есть приложение, которое выполняет различные забавные вещи с помощью Git (например, запуск git clone & git push), и я пытаюсь сделать это в docker-ize.
Однако я сталкиваюсь с проблемой, когда мне нужно иметь возможность добавить ключ SSH в контейнер для использования контейнером "пользователь".
Я попытался скопировать его в /root/.ssh/
, изменить $HOME
, создать оболочку git ssh, но все равно не повезло.
Вот Dockerfile для справки:
#DOCKER-VERSION 0.3.4
from ubuntu:12.04
RUN apt-get update
RUN apt-get install python-software-properties python g++ make git-core openssh-server -y
RUN add-apt-repository ppa:chris-lea/node.js
RUN echo "deb http://archive.ubuntu.com/ubuntu precise universe" >> /etc/apt/sources.list
RUN apt-get update
RUN apt-get install nodejs -y
ADD . /src
ADD ../../home/ubuntu/.ssh/id_rsa /root/.ssh/id_rsa
RUN cd /src; npm install
EXPOSE 808:808
CMD [ "node", "/src/app.js"]
app.js
запускает команды git pull
такие как git pull
Выключается при использовании Ubuntu, ssh_config неверен. Вам нужно добавить
RUN echo " IdentityFile ~/.ssh/id_rsa" >> /etc/ssh/ssh_config
в ваш файл Docker, чтобы узнать, как распознать ваш ключ ssh.
Это сложнее, если вам нужно использовать SSH во время сборки. Например, если вы используете git clone
или в моем случае pip
и npm
для загрузки из частного репозитория.
Я нашел решение, чтобы добавить ваши ключи, используя флаг --build-arg
. Затем вы можете использовать новую экспериментальную команду --squash
(добавлено 1.13), чтобы объединить слои, чтобы ключи больше не были доступны после удаления. Здесь мое решение:
Команда сборки
$ docker build -t example --build-arg ssh_prv_key="$(cat ~/.ssh/id_rsa)" --build-arg ssh_pub_key="$(cat ~/.ssh/id_rsa.pub)" --squash .
Dockerfile
FROM python:3.6-slim
ARG ssh_prv_key
ARG ssh_pub_key
RUN apt-get update && \
apt-get install -y \
git \
openssh-server \
libmysqlclient-dev
# Authorize SSH Host
RUN mkdir -p /root/.ssh && \
chmod 0700 /root/.ssh && \
ssh-keyscan github.com > /root/.ssh/known_hosts
# Add the keys and set permissions
RUN echo "$ssh_prv_key" > /root/.ssh/id_rsa && \
echo "$ssh_pub_key" > /root/.ssh/id_rsa.pub && \
chmod 600 /root/.ssh/id_rsa && \
chmod 600 /root/.ssh/id_rsa.pub
# Avoid cache purge by adding requirements first
ADD ./requirements.txt /app/requirements.txt
WORKDIR /app/
RUN pip install -r requirements.txt
# Remove SSH keys
RUN rm -rf /root/.ssh/
# Add the rest of the files
ADD . .
CMD python manage.py runserver
Обновление: Если вы используете Docker 1.13 и имеете экспериментальные функции, вы можете добавить --squash
в команду сборки, которая объединит слои, удалив ключи SSH и сокрыв их из docker history
.
Примечание: используйте этот подход только для изображений, которые являются частными и всегда будут !
Ключ ssh остается в пределах изображения, даже если вы удалите ключ в команде слоя после добавления его (см. Комментарии в этом посте).
В моем случае это нормально, вот что я использую:
# Setup for ssh onto github
RUN mkdir -p /root/.ssh
ADD id_rsa /root/.ssh/id_rsa
RUN chmod 700 /root/.ssh/id_rsa
RUN echo "Host github.com\n\tStrictHostKeyChecking no\n" >> /root/.ssh/config
Если вы используете docker comp, вам будет проще переслать SSH-агент следующим образом:
something:
container_name: something
volumes:
- $SSH_AUTH_SOCK:/ssh-agent # Forward local machine SSH key to docker
environment:
SSH_AUTH_SOCK: /ssh-agent
Чтобы ввести ключ ssh в контейнер, у вас есть несколько решений:
Используя файл Docker с инструкцией ADD
, вы можете вставлять его во время процесса сборки
Просто делайте что-то вроде cat id_rsa | docker run -i <image> sh -c 'cat > /root/.ssh/id_rsa'
Использование команды docker cp
, которая позволяет вам вводить файлы во время работы контейнера.
Расширяя ответ питера Грейнджера, я смог использовать многоэтапную сборку, доступную с Docker 17.05. Официальная страница гласит:
В многоэтапных сборках вы используете несколько операторов
FROM
в вашем Dockerfile. Каждая инструкцияFROM
может использовать различную базу, и каждая из них начинает новый этап сборки. Вы можете выборочно копировать артефакты с одного этапа на другой, оставляя после себя все, что вам не нужно, в конечном изображении.
Имея это в виду, вот мой пример Dockerfile
, включающий три этапа сборки. Это означало создание производственного образа клиентского веб-приложения.
# Stage 1: get sources from npm and git over ssh
FROM node:carbon AS sources
ARG SSH_KEY
ARG SSH_KEY_PASSPHRASE
RUN mkdir -p /root/.ssh && \
chmod 0700 /root/.ssh && \
ssh-keyscan bitbucket.org > /root/.ssh/known_hosts && \
echo "${SSH_KEY}" > /root/.ssh/id_rsa && \
chmod 600 /root/.ssh/id_rsa
WORKDIR /app/
COPY package*.json yarn.lock /app/
RUN eval 'ssh-agent -s' && \
printf "${SSH_KEY_PASSPHRASE}\n" | ssh-add $HOME/.ssh/id_rsa && \
yarn --pure-lockfile --mutex file --network-concurrency 1 && \
rm -rf /root/.ssh/
# Stage 2: build minified production code
FROM node:carbon AS production
WORKDIR /app/
COPY --from=sources /app/ /app/
COPY . /app/
RUN yarn build:prod
# Stage 3: include only built production files and host them with Node Express server
FROM node:carbon
WORKDIR /app/
RUN yarn add express
COPY --from=production /app/dist/ /app/dist/
COPY server.js /app/
EXPOSE 33330
CMD ["node", "server.js"]
.dockerignore
повторяет содержимое файла .gitignore
(это предотвращает копирование node_modules
и результирующих каталогов dist
проекта):
.idea
dist
node_modules
*.log
Пример команды для создания изображения:
$ docker build -t ezze/geoport:0.6.0 \
--build-arg SSH_KEY="$(cat ~/.ssh/id_rsa)" \
--build-arg SSH_KEY_PASSPHRASE="my_super_secret" \
./
Если ваш закрытый ключ SSH не имеет парольной фразы, просто укажите пустой аргумент SSH_KEY_PASSPHRASE
.
Вот как это работает:
1). На первом этапе только файлы package.json
, yarn.lock
и закрытый ключ SSH копируются в первое промежуточное изображение с именем sources
. Чтобы избежать дальнейших запросов парольной фразы ключа SSH, она автоматически добавляется в ssh-agent
. Наконец, команда yarn
устанавливает все необходимые зависимости от NPM и клонирует частные репозитории git из Bitbucket через SSH.
2). Второй этап создает и минимизирует исходный код веб-приложения и помещает его в каталог dist
следующего промежуточного изображения с именем production
. Обратите внимание, что исходный код установленного node_modules
скопирован из образа с именем sources
, созданного на первом этапе этой строкой:
COPY --from=sources /app/ /app/
Вероятно, это также может быть следующая строка:
COPY --from=sources /app/node_modules/ /app/node_modules/
Здесь у нас есть только каталог node_modules
из первого промежуточного изображения, больше нет аргументов SSH_KEY
и SSH_KEY_PASSPHRASE
. Все остальное, необходимое для сборки, скопировано из каталога нашего проекта.
3). На третьем этапе мы уменьшаем размер конечного изображения, которое будет помечено как ezze/geoport:0.6.0
, путем включения только каталога dist
из второго промежуточного изображения с именем production
и установки Node Express для запуска веб-сервера.
Вывод списка изображений дает следующий вывод:
REPOSITORY TAG IMAGE ID CREATED SIZE
ezze/geoport 0.6.0 8e8809c4e996 3 hours ago 717MB
<none> <none> 1f6518644324 3 hours ago 1.1GB
<none> <none> fa00f1182917 4 hours ago 1.63GB
node carbon b87c2ad8344d 4 weeks ago 676MB
где немаркированные изображения соответствуют первому и второму промежуточным этапам сборки.
Если вы запускаете
$ docker history ezze/geoport:0.6.0 --no-trunc
вы не увидите упоминаний о SSH_KEY
и SSH_KEY_PASSPHRASE
на конечном изображении.
Эта строка является проблемой:
ADD ../../home/ubuntu/.ssh/id_rsa /root/.ssh/id_rsa
При указании файлов, которые вы хотите скопировать в изображение, вы можете использовать только относительные пути - относительно каталога, в котором находится ваш файл Docker. Поэтому вы должны использовать:
ADD id_rsa /root/.ssh/id_rsa
И поместите файл id_rsa в тот же каталог, где находится ваш файл Docker.
Проверьте это для более подробной информации: http://docs.docker.io/reference/builder/#add
Контейнеры-докеры должны рассматриваться как "службы". Чтобы разделить проблемы, вы должны разделить функциональные возможности:
1) Данные должны быть в контейнере данных: используйте связанный том для клонирования репо. Затем этот контейнер данных можно связать с сервисом, которому он нужен.
2) Используйте контейнер для запуска задачи клонирования git (т.е. это только клонирование задания), связывая контейнер данных с ним при его запуске.
3) То же самое для ssh-ключа: поместите это тома (как было предложено выше) и связать его с сервисом клона git, когда вам это нужно
Таким образом, и задача клонирования, и ключ являются эфемерными и только активны, когда это необходимо.
Теперь, если ваше приложение является интерфейсом git, вам может потребоваться прямое использование API-интерфейса REST API-интерфейса github или bitbucket для выполнения вашей работы: для чего они предназначены.
У нас была аналогичная проблема при установке npm в время сборки докеров.
Вдохновленный из решения Daniel van Flymen и объединив его с git url rewrite, мы обнаружили немного более простой метод для аутентификации установки npm из частных репозиториев github - мы использовали токены oauth2 вместо ключей.
В нашем случае зависимости npm были указаны как "git + https://github.com/..."
Для аутентификации в контейнере URL-адреса должны быть переписаны либо подходящими для аутентификации ssh (ssh:// git @github.com/), либо аутентификацией токена (https://${GITHUB_TOKEN} @github. com/)
Команда сборки:
docker build -t sometag --build-arg GITHUB_TOKEN=$GITHUB_TOKEN .
К сожалению, я на docker 1.9, поэтому опция -squash еще не существует, в конце концов ее нужно добавить
Dockerfile:
FROM node:5.10.0
ARG GITHUB_TOKEN
#Install dependencies
COPY package.json ./
# add rewrite rule to authenticate github user
RUN git config --global url."https://${GITHUB_TOKEN}@github.com/".insteadOf "https://github.com/"
RUN npm install
# remove the secret token from the git config file, remember to use --squash option for docker build, when it becomes available in docker 1.13
RUN git config --global --unset url."https://${GITHUB_TOKEN}@github.com/".insteadOf
# Expose the ports that the app uses
EXPOSE 8000
#Copy server and client code
COPY server /server
COPY clients /clients
Одним из кроссплатформенных решений является использование bind mount для совместного использования папки хоста .ssh
с контейнером:
docker run -v /home/<host user>/.ssh:/home/<docker user>/.ssh <image>
Подобно переадресации агента, этот подход сделает открытые ключи доступными для контейнера. Дополнительным преимуществом является то, что он работает и с пользователем без полномочий root и подключит вас к GitHub. Однако следует учитывать, что все содержимое (включая закрытые ключи) из папки .ssh
будет общим, поэтому этот подход желателен только для разработки и только для доверенных образов контейнеров.
Переслать в контейнер ssh-аутентификацию:
docker run --rm -ti \
-v $SSH_AUTH_SOCK:/tmp/ssh_auth.sock \
-e SSH_AUTH_SOCK=/tmp/ssh_auth.sock \
-w /src \
my_image
Ваш script сможет выполнить git clone
.
Дополнительно: Если вы хотите, чтобы клонированные файлы принадлежали определенному пользователю, вам нужно использовать chown
, поскольку использование другого пользователя, кроме root внутри контейнера, приведет к ошибке git
.
Вы можете сделать это публикацию в среде контейнера некоторыми дополнительными переменными:
docker run ...
-e OWNER_USER=$(id -u) \
-e OWNER_GROUP=$(id -g) \
...
После того, как вы клонируете, вы должны выполнить chown $OWNER_USER:$OWNER_GROUP -R <source_folder>
, чтобы установить правильное владение, прежде чем покинуть контейнер, чтобы файлы были доступны внекорневому пользователю вне контейнера.
Эта проблема действительно раздражает. Поскольку вы не можете добавить/скопировать любой файл вне контекста dockerfile, это означает, что невозможно просто связать ~/.ssh/id_rsa с изображением /root/.ssh/id_rsa, и когда вам определенно нужен ключ для выполнения некоторых вещей sshed как git клон из частной ссылки репо... во время создания вашего изображения докеров.
В любом случае, я нашел решение обходного пути, не так убедительно, но работал у меня.
в файле docker:
a script сделать за один раз:
В любое время, когда вы должны запускать контейнер из этого изображения с некоторыми требованиями ssh, просто добавьте -v для команды запуска, например:
docker run -v ~/.ssh/id_rsa:/root/.ssh/id_rsa - имя файла образа контейнера
Это решение не приводит к закрытому ключу как для источника проекта, так и для встроенного изображения докеров, поэтому больше не нужно беспокоиться о безопасности.
'вы можете выборочно разрешать удаленным серверам доступ к локальному ssh-агенту, как если бы он выполнялся на сервере
https://developer.github.com/guides/using-ssh-agent-forwarding/
Сегодня я столкнулся с той же проблемой и немного модифицированной версией с предыдущими сообщениями. Я нашел этот подход более полезным для меня.
docker run -it -v ~/.ssh/id_rsa:/root/.my-key:ro image /bin/bash
(Обратите внимание, что флаг readonly, чтобы контейнер не испортил мой ssh-ключ в любом случае.)
Внутренний контейнер теперь можно запустить:
ssh-agent bash -c "ssh-add ~/.my-key; git clone <gitrepourl> <target>"
Таким образом, я не получаю ошибку Bad owner or permissions on /root/.ssh/..
, отмеченную @kross
Вы также можете связать свой .ssh-каталог между хостом и контейнером, я не знаю, имеет ли этот метод какие-либо последствия для безопасности, но это может быть самый простой способ. Что-то вроде этого должно работать:
$ sudo docker run -it -v /root/.ssh:/root/.ssh someimage bash
Помните, что docker работает с sudo (если вы этого не сделаете), если это так, вы будете использовать корневые ssh-ключи.
Как уже прокомментировал eczajk в ответе Дэниела ван Флаймена, кажется, что небезопасно удалять ключи и использовать --squash
, так как они все еще будут видны в истории (docker history --no-trunc
).
Вместо этого с Docker 18.09 теперь вы можете использовать функцию "строить секреты". В моем случае я клонировал частное репозиторий git, используя мой SSH-ключ hosts, со следующим в моем Dockerfile:
# syntax=docker/dockerfile:experimental
[...]
RUN --mount=type=ssh git clone [...]
[...]
Чтобы использовать это, вам нужно включить новый бэкэнд BuildKit перед запуском docker build
:
export DOCKER_BUILDKIT=1
И вам нужно добавить параметр --ssh default
в docker build
.
Подробнее об этом здесь: https://medium.com/@tonistiigi/build-secrets-and-ssh-forwarding-in-docker-18-09-ae8161d066
В более поздних версиях Docker (17.05) вы можете использовать многоэтапные сборки. Какой самый безопасный вариант, так как предыдущие сборки могут быть использованы только последующей сборкой, а затем уничтожаются
См. fooobar.com/questions/2417758/... для получения дополнительной информации
Простой и безопасный способ добиться этого без сохранения ключа в слое изображения Docker или прохождения гимнастики ssh_agent:
В качестве одного из шагов в вашем Dockerfile
создайте .ssh
, добавив:
RUN mkdir -p/root/.ssh
Ниже указано, что вы хотите смонтировать каталог ssh как том:
VOLUME [ "/root/.ssh" ]
Убедитесь, что ваш контейнер ssh_config
знает, где найти открытые ключи, добавив ssh_config
строку:
RUN echo " IdentityFile/root/.ssh/id_rsa" >>/etc/ssh/ssh_config
Представьте свой локальный пользовательский .ssh
контейнеру во время выполнения:
docker run -v ~/.ssh: /root/.ssh -it image_name
Или в вашем dockerCompose.yml
добавьте это под ключом громкости обслуживания:
- "~/.ssh: /root/.ssh"
Ваш окончательный Dockerfile
должен содержать что-то вроде:
FROM node:6.9.1
RUN mkdir -p /root/.ssh
RUN echo " IdentityFile /root/.ssh/id_rsa" >> /etc/ssh/ssh_config
VOLUME [ "/root/.ssh" ]
EXPOSE 3000
CMD [ "launch" ]
Я пытаюсь решить проблему по-другому: добавление открытого ключа ssh к изображению. Но в моих испытаниях я обнаружил, что "docker cp" предназначен для копирования из контейнера в хост. Пункт 3 в ответе на скрип, похоже, говорит, что вы можете использовать docker cp для вставки файлов в контейнер. См. https://docs.docker.com/engine/reference/commandline/cp/
Отрывок
Скопировать файлы/папки из файловой системы контейнера в хост-путь. Пути относятся к корню файловой системы.
Usage: docker cp CONTAINER:PATH HOSTPATH Copy files/folders from the PATH to the HOSTPATH
Вы можете передать авторизованные ключи в свой контейнер с помощью общей папки и установить разрешения с помощью файла докеров:
FROM ubuntu:16.04
RUN apt-get install -y openssh-server
RUN mkdir /var/run/sshd
EXPOSE 22
RUN cp /root/auth/id_rsa.pub /root/.ssh/authorized_keys
RUN rm -f /root/auth
RUN chmod 700 /root/.ssh
RUN chmod 400 /root/.ssh/authorized_keys
RUN chown root. /root/.ssh/authorized_keys
CMD /usr/sbin/sshd -D
И ваш запуск docker содержит что-то вроде следующего, чтобы разделить каталог auth на хосте (удерживая authorized_keys) с контейнером, затем откройте порт ssh, доступ к которому будет доступен через порт 7001 на хосте.
-d -v /home/thatsme/dockerfiles/auth:/root/auth -–publish=127.0.0.1:7001:22
Вы можете посмотреть https://github.com/jpetazzo/nsenter, который, как представляется, является другим способом открыть оболочку в контейнере и выполнить команды в пределах контейнер.
Если вы не заботитесь о безопасности своих SSH-ключей, здесь есть много хороших ответов. Если вы это сделаете, лучший ответ, который я нашел, был связан с ссылкой в комментарии выше на этот комментарий GitHub от diegocsandrim. Так что другие чаще видят это, и на всякий случай, когда репо когда-либо уходит, вот отредактированная версия этого ответа:
Большинство решений здесь оставляют закрытый ключ в изображении. Это плохо, так как любой, у кого есть доступ к изображению, имеет доступ к вашему закрытому ключу. Поскольку мы не знаем достаточно о поведении squash
, это может быть и так, даже если вы удалите ключ и сквош этот слой.
Мы создаем URL-адрес предварительного знака для доступа к ключу с помощью aws s3 cli и ограничиваем доступ примерно на 5 минут, мы сохраняем этот URL-адрес предварительного знака в файл в каталоге репо, а затем в файле докере добавляем его в изображение.
В файле dockerfile у нас есть команда RUN, которая выполняет все эти шаги: используйте URL-адрес предварительного вызова, чтобы получить ключ ssh, запустите npm install и удалите ssh-ключ.
Выполняя это в одной команде, ключ ssh не будет сохранен ни на одном уровне, но будет сохранен URL-адрес предварительной подписки, и это не проблема, потому что URL-адрес не будет действителен через 5 минут.
Конструкция script выглядит так:
# build.sh
aws s3 presign s3://my_bucket/my_key --expires-in 300 > ./pre_sign_url
docker build -t my-service .
Dockerfile выглядит следующим образом:
FROM node
COPY . .
RUN eval "$(ssh-agent -s)" && \
wget -i ./pre_sign_url -q -O - > ./my_key && \
chmod 700 ./my_key && \
ssh-add ./my_key && \
ssh -o StrictHostKeyChecking=no [email protected] || true && \
npm install --production && \
rm ./my_key && \
rm -rf ~/.ssh/*
ENTRYPOINT ["npm", "run"]
CMD ["start"]
По общему признанию стороны, как на счет этого, что сделает ключи операционной системы вашего хоста доступными для root внутри контейнера, на лету:
docker run -v ~/.ssh:/mnt -it my_image /bin/bash -c "ln -s /mnt /root/.ssh; ssh [email protected]"
Я не одобряю использование Dockerfile для установки ключей, так как итерации вашего контейнера могут оставить закрытые ключи позади.
Вы можете использовать секреты для управления любыми конфиденциальными данными, которые нужны контейнеру во время выполнения, но вы не хотите хранить их в изображении или в управлении исходным кодом, например:
- Имена пользователей и пароли
- TLS сертификаты и ключи
- SSH ключи
- Другие важные данные, такие как имя базы данных или внутреннего сервера
- Общие строки или двоичное содержимое (размером до 500 КБ)
Я пытался выяснить, как добавить ключи подписи в контейнер для использования во время выполнения (не сборки), и наткнулся на этот вопрос. Секреты докера, похоже, являются решением для моего варианта использования, и, поскольку никто еще не упомянул об этом, я добавлю его.
Для debian/root/authorized_keys:
RUN set -x && apt-get install -y openssh-server
RUN mkdir /var/run/sshd
RUN mkdir -p /root/.ssh
RUN sed -i 's/#PermitRootLogin prohibit-password/PermitRootLogin yes/' /etc/ssh/sshd_config
RUN echo "ssh-rsa AAAA....yP3w== rsa-key-project01" >> /root/.ssh/authorized_keys
RUN chmod -R go= /root/.ssh
Краткий обзор проблем SSH внутри контейнеров Docker подробно описан здесь. Для подключения к доверенным удаленным устройствам из контейнера без утечки секретов существует несколько способов:
~/.ssh
в контейнер. (Только разработка, потенциально небезопасно)Помимо этого, существует также возможность использования хранилища ключей в отдельном контейнере Docker, доступном во время выполнения при использовании Compose. Недостатком здесь является дополнительная сложность из-за механизма, необходимого для создания и управления хранилищем ключей, такого как Vault by HashiCorp.
Для использования ключа SSH в автономном контейнере Docker см. методы, приведенные выше, и рассмотрите недостатки каждого из них в зависимости от ваших конкретных потребностей. Однако, если вы работаете внутри Compose и хотите поделиться ключом к приложению во время выполнения (отражая практические возможности OP), попробуйте следующее:
docker-compose.env
и добавьте его в свой файл .gitignore
.docker-compose.yml
и добавьте env_file
для службы, для которой требуется ключ.process.node.DEPLOYER_RSA_PUBKEY
в случае приложения Node.js.Вышеуказанный подход идеален для разработки и тестирования, и, хотя он может удовлетворить производственные требования, в процессе работы лучше использовать один из других методов, указанных выше.
Дополнительные ресурсы:
Простейший способ получить учетную запись для запуска и использовать: ssh-import-id
В запущенном контейнере докеров вы можете отправить ssh-keygen с помощью опции docker -i (interactive). Это перенаправляет подсказки контейнера для создания ключа внутри контейнера докера.