Использование ключей 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

Ответ 1

Выключается при использовании Ubuntu, ssh_config неверен. Вам нужно добавить

RUN  echo "    IdentityFile ~/.ssh/id_rsa" >> /etc/ssh/ssh_config

в ваш файл Docker, чтобы узнать, как распознать ваш ключ ssh.

Ответ 2

Это сложнее, если вам нужно использовать 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.

Ответ 3

Примечание: используйте этот подход только для изображений, которые являются частными и всегда будут !

Ключ 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

Ответ 4

Если вы используете 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

Ответ 5

Чтобы ввести ключ ssh в контейнер, у вас есть несколько решений:

  • Используя файл Docker с инструкцией ADD, вы можете вставлять его во время процесса сборки

  • Просто делайте что-то вроде cat id_rsa | docker run -i <image> sh -c 'cat > /root/.ssh/id_rsa'

  • Использование команды docker cp, которая позволяет вам вводить файлы во время работы контейнера.

Ответ 6

Расширяя ответ питера Грейнджера, я смог использовать многоэтапную сборку, доступную с 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 на конечном изображении.

Ответ 7

Эта строка является проблемой:

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

Ответ 8

Контейнеры-докеры должны рассматриваться как "службы". Чтобы разделить проблемы, вы должны разделить функциональные возможности:

1) Данные должны быть в контейнере данных: используйте связанный том для клонирования репо. Затем этот контейнер данных можно связать с сервисом, которому он нужен.

2) Используйте контейнер для запуска задачи клонирования git (т.е. это только клонирование задания), связывая контейнер данных с ним при его запуске.

3) То же самое для ssh-ключа: поместите это тома (как было предложено выше) и связать его с сервисом клона git, когда вам это нужно

Таким образом, и задача клонирования, и ключ являются эфемерными и только активны, когда это необходимо.

Теперь, если ваше приложение является интерфейсом git, вам может потребоваться прямое использование API-интерфейса REST API-интерфейса github или bitbucket для выполнения вашей работы: для чего они предназначены.

Ответ 9

У нас была аналогичная проблема при установке 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

Ответ 10

Одним из кроссплатформенных решений является использование bind mount для совместного использования папки хоста .ssh с контейнером:

docker run -v /home/<host user>/.ssh:/home/<docker user>/.ssh <image>

Подобно переадресации агента, этот подход сделает открытые ключи доступными для контейнера. Дополнительным преимуществом является то, что он работает и с пользователем без полномочий root и подключит вас к GitHub. Однако следует учитывать, что все содержимое (включая закрытые ключи) из папки .ssh будет общим, поэтому этот подход желателен только для разработки и только для доверенных образов контейнеров.

Ответ 11

Переслать в контейнер 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>, чтобы установить правильное владение, прежде чем покинуть контейнер, чтобы файлы были доступны внекорневому пользователю вне контейнера.

Ответ 12

Эта проблема действительно раздражает. Поскольку вы не можете добавить/скопировать любой файл вне контекста dockerfile, это означает, что невозможно просто связать ~/.ssh/id_rsa с изображением /root/.ssh/id_rsa, и когда вам определенно нужен ключ для выполнения некоторых вещей sshed как git клон из частной ссылки репо... во время создания вашего изображения докеров.

В любом случае, я нашел решение обходного пути, не так убедительно, но работал у меня.

  • в файле docker:

    • добавить этот файл как /root/.ssh/id_rsa
    • делать то, что вы хотите, например git clone, composer...
    • rm/root/.ssh/id_rsa в конце
  • a script сделать за один раз:

    • cp ваш ключ к папке, содержащей файл dockerfile
    • docker build
    • rm скопированный ключ
  • В любое время, когда вы должны запускать контейнер из этого изображения с некоторыми требованиями ssh, просто добавьте -v для команды запуска, например:

    docker run -v ~/.ssh/id_rsa:/root/.ssh/id_rsa - имя файла образа контейнера

Это решение не приводит к закрытому ключу как для источника проекта, так и для встроенного изображения докеров, поэтому больше не нужно беспокоиться о безопасности.

Ответ 14

Сегодня я столкнулся с той же проблемой и немного модифицированной версией с предыдущими сообщениями. Я нашел этот подход более полезным для меня.

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

Ответ 15

Вы также можете связать свой .ssh-каталог между хостом и контейнером, я не знаю, имеет ли этот метод какие-либо последствия для безопасности, но это может быть самый простой способ. Что-то вроде этого должно работать:

$ sudo docker run -it -v /root/.ssh:/root/.ssh someimage bash

Помните, что docker работает с sudo (если вы этого не сделаете), если это так, вы будете использовать корневые ssh-ключи.

Ответ 16

Как уже прокомментировал 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

Ответ 17

В более поздних версиях Docker (17.05) вы можете использовать многоэтапные сборки. Какой самый безопасный вариант, так как предыдущие сборки могут быть использованы только последующей сборкой, а затем уничтожаются

См. fooobar.com/questions/2417758/... для получения дополнительной информации

Ответ 18

Простой и безопасный способ добиться этого без сохранения ключа в слое изображения Docker или прохождения гимнастики ssh_agent:

  1. В качестве одного из шагов в вашем Dockerfile создайте .ssh, добавив:

    RUN mkdir -p/root/.ssh

  2. Ниже указано, что вы хотите смонтировать каталог ssh как том:

    VOLUME [ "/root/.ssh" ]

  3. Убедитесь, что ваш контейнер ssh_config знает, где найти открытые ключи, добавив ssh_config строку:

    RUN echo " IdentityFile/root/.ssh/id_rsa" >>/etc/ssh/ssh_config

  4. Представьте свой локальный пользовательский .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" ]

Ответ 19

Я пытаюсь решить проблему по-другому: добавление открытого ключа 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

Ответ 20

Вы можете передать авторизованные ключи в свой контейнер с помощью общей папки и установить разрешения с помощью файла докеров:

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, который, как представляется, является другим способом открыть оболочку в контейнере и выполнить команды в пределах контейнер.

Ответ 21

Если вы не заботитесь о безопасности своих 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"]

Ответ 22

По общему признанию стороны, как на счет этого, что сделает ключи операционной системы вашего хоста доступными для root внутри контейнера, на лету:

docker run -v ~/.ssh:/mnt -it my_image /bin/bash -c "ln -s /mnt /root/.ssh; ssh [email protected]"

Я не одобряю использование Dockerfile для установки ключей, так как итерации вашего контейнера могут оставить закрытые ключи позади.

Ответ 23

Вы можете использовать секреты для управления любыми конфиденциальными данными, которые нужны контейнеру во время выполнения, но вы не хотите хранить их в изображении или в управлении исходным кодом, например:

  • Имена пользователей и пароли
  • TLS сертификаты и ключи
  • SSH ключи
  • Другие важные данные, такие как имя базы данных или внутреннего сервера
  • Общие строки или двоичное содержимое (размером до 500 КБ)

https://docs.docker.com/engine/swarm/secrets/

Я пытался выяснить, как добавить ключи подписи в контейнер для использования во время выполнения (не сборки), и наткнулся на этот вопрос. Секреты докера, похоже, являются решением для моего варианта использования, и, поскольку никто еще не упомянул об этом, я добавлю его.

Ответ 24

Для 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

Ответ 25

Краткий обзор проблем SSH внутри контейнеров Docker подробно описан здесь. Для подключения к доверенным удаленным устройствам из контейнера без утечки секретов существует несколько способов:

Помимо этого, существует также возможность использования хранилища ключей в отдельном контейнере 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.

Вышеуказанный подход идеален для разработки и тестирования, и, хотя он может удовлетворить производственные требования, в процессе работы лучше использовать один из других методов, указанных выше.

Дополнительные ресурсы:

Ответ 26

Простейший способ получить учетную запись для запуска и использовать: ssh-import-id

Ответ 27

В запущенном контейнере докеров вы можете отправить ssh-keygen с помощью опции docker -i (interactive). Это перенаправляет подсказки контейнера для создания ключа внутри контейнера докера.