web-dev-qa-db-ja.com

Dockerコンテナ内でSSHキーを使う

私はGitでさまざまな楽しいもの(git clone&git Pushの実行など)を実行するアプリを持っていて、それをドッカー化しようとしています。

私は私が問題に遭遇していますが、私はコンテナ「ユーザー」が使うためにコンテナに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.jsgit pullのようなgitコマンドを実行します

252
ebensing

Ubuntuを使用しているときに判明、ssh_configは正しくありません。追加する必要があります

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

あなたのsshキーを認識させるためにあなたのDockerfileに。

79
ebensing

構築時にSSHを使用する必要がある場合、それはより難しい問題です。例えばgit cloneを使用している場合、または私の場合はpipnpmをプライベートリポジトリからダウンロードする場合です。

私が見つけた解決策は--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を使っていて実験的な機能を持っている場合は、buildコマンドに--squashを追加してレイヤーを結合し、SSHキーを削除してdocker historyから隠すことができます。

92

:このアプローチは、 非公開で常に !になるイメージに対してのみ使用してください。

追加した後にlayerコマンドでキーを削除しても、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
74
yellowcap

docker compose を使用している場合、SSHエージェントを転送するのが簡単な選択です。

something:
    container_name: something
    volumes:
        - $SSH_AUTH_SOCK:/ssh-agent # Forward local machine SSH key to docker
    environment:
        SSH_AUTH_SOCK: /ssh-agent
49
Aistis

Sshキーをコンテナ内に注入するには、複数の解決策があります。

  1. ADD命令でDockerfileを使用すると、ビルドプロセス中にそれを挿入できます。

  2. 単にcat id_rsa | docker run -i <image> sh -c 'cat > /root/.ssh/id_rsa'のようなことをするだけです

  3. コンテナの実行中にファイルを注入することを可能にするdocker cpコマンドを使用します。

40
creack

拡大{ Peter Grainger's answer 私はDocker 17.05から利用可能な マルチステージビルド を使うことができました。公式ページには次のように記載されています。

マルチステージビルドでは、Dockerfileで複数のFROMステートメントを使用します。それぞれのFROM命令は異なるベースを使用することができ、それらはそれぞれビルドの新しい段階を開始します。成果物をあるステージから別のステージに選択的にコピーし、不要なものはすべて最終イメージに残しておくことができます。

これを念頭に置いているのは、3つのビルド段階を含むDockerfileの例です。クライアントWebアプリケーションの本番用イメージを作成するためのものです。

# 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.jsonyarn.lockファイル、およびSSH秘密鍵のみがsourcesという名前の最初の中間イメージにコピーされます。 SSH鍵のパスフレーズプロンプトがさらに表示されないようにするために、自動的にssh-agentに追加されます。最後にyarnコマンドは、NPMから必要なすべての依存関係をインストールし、SSH経由でBitbucketからプライベートgitリポジトリを複製します。

2)。第2段階では、Webアプリケーションのソースコードをビルドおよび縮小し、それをdistという名前の次の中間イメージのproductionディレクトリに配置します。インストールされたnode_modulesのソースコードは、この行によって最初の段階で生成されたsourcesという名前のイメージからコピーされます。

COPY --from=sources /app/ /app/

おそらくそれはまた次の行になるでしょう:

COPY --from=sources /app/node_modules/ /app/node_modules/

ここには最初の中間イメージからのnode_modulesディレクトリしかなく、SSH_KEYSSH_KEY_PASSPHRASE引数はもうありません。ビルドに必要な残りはすべて私たちのプロジェクトディレクトリからコピーされます。

3)。 3番目の段階では、distという2番目の中間イメージからproductionディレクトリのみを含め、Webサーバーを起動するためにNode Expressをインストールすることによって、ezze/geoport:0.6.0としてタグ付けされる最終イメージのサイズを縮小します。

画像を一覧表示すると、次のような出力が得られます。

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

タグ付けされていないイメージは、1番目と2番目の中間ビルドステージに対応します。

走れば

$ docker history ezze/geoport:0.6.0 --no-trunc

最終的な画像にSSH_KEYSSH_KEY_PASSPHRASEの言及はありません。

29
Ezze

この行は問題です。

ADD ../../home/ubuntu/.ssh/id_rsa /root/.ssh/id_rsa

画像にコピーしたいファイルを指定するときは、相対パス(Dockerfileがあるディレクトリからの相対パス)しか使用できません。だから代わりに使用する必要があります:

ADD id_rsa /root/.ssh/id_rsa

そしてid_rsaファイルをDockerfileと同じディレクトリに置きます。

詳細については、こちらをご覧ください。 http://docs.docker.io/reference/builder/#add

15
Dan Keder

Dockerコンテナーは、それ自体の「サービス」と見なすべきです。懸念を分けるには、機能を分けるべきです:

1)データはデータコンテナに格納する必要があります。レポジトリのクローンを作成するには、リンクされたボリュームを使用します。そのデータコンテナは、それを必要とするサービスにリンクすることができます。

2)コンテナーを使用して、gitクローン作成タスクを実行します(つまり、実行するときにデータコンテナーをリンクするのはジョブのみがクローン作成です)。

3)ssh-keyについても同じです。(上記のように)ボリュームにして、必要なときにgit cloneサービスにリンクします。

このようにして、クローン作成タスクとキーの両方が一時的であり、必要なときにのみアクティブになります。

アプリ自体がgitインターフェースの場合は、githubまたはbitbucket REST AP​​Iを直接使用して作業を行うことをお勧めします。それがそれらのために設計されたものです。

13
MrE

Docker build timeでnpm installを実行したときにも同様の問題がありました。

Daniel van Flymen からの解決策にインスパイアされ、 git url rewrite と組み合わせることで、プライベートgithubリポジトリからnpm installを認証するための少し簡単な方法が見つかりました。

私たちの場合、npm依存関係は "git + https://github.com/ ..."として指定されています。

コンテナでの認証の場合、URLはssh認証(ssh://[email protected]/)またはトークン認証(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
12
Markko Paas

この問題は本当に面倒なものです。 dockerfileのコンテキストの外にファイルを追加/コピーすることはできないので、〜/ .ssh/id_rsaをimageの/root/.ssh/id_rsaにリンクすることは不可能であり、あなたが間違いなく何かをするためにキーが必要なときDockerイメージの作成中に、プライベートレポジトリリンクからGitクローンを作成するのと同じです。

とにかく、私は回避策の解決策を見つけました、それほど説得力はありませんでしたが、私のために働きました。

  1. あなたのdockerfileで:

    • このファイルを/root/.ssh/id_rsaとして追加します。
    • git clone、composerなど、やりたいことをやってください。
    • 最後にrm /root/.ssh/id_rsa
  2. 1回の撮影で実行するスクリプト

    • dockerfileを保持しているフォルダへのキーのcp
    • ドッカービルド
    • コピーしたキーをrm
  3. sshの要件を満たしながらこのイメージからコンテナを実行する必要があるときはいつでも、runコマンドに-vを追加するだけです。

    docker run -v〜/ .ssh/id_rsa:/root/.ssh/id_rsa --nameコンテナイメージコマンド

このソリューションでは、プロジェクトのソースと構築されたdockerイメージの両方に秘密鍵が存在しないため、セキュリティ上の問題がなくなります。

10
ImLeo

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

あなたのスクリプトはgit cloneを実行することができるでしょう。

Extra:クローンファイルを特定のユーザに所属させたい場合は、コンテナ内でroot以外のユーザを使用するとchownが失敗するため、gitを使用する必要があります。

あなたはコンテナの環境にいくつかの追加の変数を公開することができます:

docker run ...
        -e OWNER_USER=$(id -u) \
        -e OWNER_GROUP=$(id -g) \
        ...

クローンを作成したら、コンテナを離れる前にchown $OWNER_USER:$OWNER_GROUP -R <source_folder>を実行して適切な所有権を設定する必要があります。これにより、コンテナの外部にいるroot以外のユーザがファイルにアクセスできるようになります。

10
edupo

「リモートサーバーからローカルのssh-agentに、サーバー上で実行されているかのように選択的にアクセスさせることができます。」

https://developer.github.com/guides/using-ssh-agent-forwarding/ /

7
arreche

1つの解決策は、以下のオプションでHostのsshキーをdockerにマウントすることです。

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

上記の解決方法に似ています。しかし、root以外のユーザーでも動作します。 githubと完璧に連携します。

7
Mohammad Azim

私は今日同じ問題に遭遇しました、そして私はこのアプローチが私にとってより有用であると以前の記事で少し修正したバージョン

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>"

そのため、@ krossが指摘したBad owner or permissions on /root/.ssh/..エラーは発生しません。

6
tojo

.sshディレクトリをホストとコンテナの間でリンクすることもできます。この方法にセキュリティ上の影響があるかどうかはわかりませんが、最も簡単な方法の可能性があります。このようなものでうまくいくはずです。

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

DockerはSudoで動作します(あなたがそうでない限り)、その場合はrootのsshキーを使うことになるでしょう。

6
Luis Elizondo

Docker(17.05)のそれ以降のバージョンでは マルチステージビルド を使うことができます。これまでのビルドは後続のビルドでしか使用できず、その後破棄されるため、最も安全な方法です。

私のstackoverflowの質問に対する答え を参照してください。

2
Peter Grainger

EczajkはすでにDaniel van Flymenの回答でコメントしていたように、それらはまだ歴史の中に見られるので(--squash)、キーを削除してdocker history --no-truncを使用するのは安全ではないようです。

代わりにDocker 18.09では、 "build secrets"機能を使うことができます。私の場合は、私のDockerfileに次のように私のホストのSSHキーを使用してプライベートGitリポジトリを複製しました。

# syntax=docker/dockerfile:experimental

[...]

RUN --mount=type=ssh git clone [...]

[...]

これを使用するには、docker buildを実行する前に新しいBuildKitバックエンドを有効にする必要があります。

export DOCKER_BUILDKIT=1

そして--ssh defaultパラメータをdocker buildに追加する必要があります。

これについてのより多くの情報はここに: https://medium.com/@tonistiigi/build-secrets-and-ssh-forwarding-in-docker-18-09-ae8161d066

1
frsc

共有フォルダを使用して認証済みのキーをコンテナに渡したり、次のようなdockerファイルを使用して権限を設定したりできます。

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ディレクトリ(authorised_keysを保持している)をコンテナと共有するための次のようなものが含まれています。そして、ホスト上のポート7001を通してアクセスできるsshポートを開きます。

-d -v /home/thatsme/dockerfiles/auth:/root/auth -–publish=127.0.0.1:7001:22

https://github.com/jpetazzo/nsenter を見るとよいでしょう。これは、コンテナ上でシェルを開いてコンテナ内でコマンドを実行するための別の方法のようです。

1
andrew pate

確かにパーティーに遅れて、その場でオンザフライであなたのホストオペレーティングシステムのキーがrootで利用できるようになるでしょうこれについてはどうですか:

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

私はDockerfileを使ってキーをインストールすることに賛成していません。あなたのコンテナを繰り返すと秘密キーが残ってしまうかもしれないからです。

1
Jepper

SSH鍵のセキュリティを気にしないのであれば、ここにたくさんの良い答えがあります。もしそうなら、私が見つけた最良の答えは このGitHubのコメント by diegocsandrim への上のコメントのリンクからでした。他の人がそれを見る可能性が高くなるように、そしてレポがこれまでになくなった場合のために、ここにその答えの編集版があります:

ここでのほとんどの解決策は、イメージに秘密鍵を残すことになります。画像にアクセスできる人なら誰でもあなたの秘密鍵にアクセスできるので、これは悪いことです。 squashの振る舞いについては十分にわかっていないので、キーを削除してそのレイヤーを隠したとしても、これは当てはまります。

Aws s3 cliでキーにアクセスするための事前署名URLを生成し、アクセスを約5分間制限します。この事前署名URLをrepoディレクトリ内のファイルに保存し、次にそれを画像に追加します。

Dockerfileには、これらすべての手順を実行するRUNコマンドがあります。事前に歌うURLを使用してsshキーを取得し、npm installを実行してsshキーを削除します。

これを1回のコマンドで実行すると、sshキーはどのレイヤにも格納されませんが、署名前のURLは格納されます。5分後にはURLが有効にならないため、これは問題になりません。

ビルドスクリプトは次のようになります。

# 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"]
1
Sam H.

私は他の方法で問題を解決しようとしています:公開SSHキーを画像に追加します。しかし、私の試験で、私は "docker cp"がコンテナからホストへコピーするためのものであることを発見しました。 creakによる回答の項目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
1
EricGreg

秘密を使用して、実行時にコンテナが必要とする機密データを管理できますが、画像やソース管理には保存したくありません。

  • ユーザー名とパスワード
  • TLS証明書とキー
  • SSHキー
  • データベースや内部サーバーの名前など、その他の重要なデータ
  • 一般的な文字列またはバイナリコンテンツ(最大500 kb)

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

実行時に使用する(ビルドではない)コンテナに署名キーを追加する方法を見つけようとしていたところ、この問題に遭遇しました。 Dockerの秘密は私のユースケースの解決策のように思われます、そして誰もまだそれを言及していないので私はそれを追加します。

0
Travis Britz

最も簡単な方法は、ランチパッドアカウントを取得して使用することです: ssh-import-id

0
Sam Saffron

Dockerイメージレイヤーにキーを保存したり、ssh_agent体操をしたりせずにこれを実現するための簡単で安全な方法は次のとおりです。

  1. Dockerfileの手順の1つとして、以下を追加して.sshディレクトリを作成します。

    RUN mkdir -p /root/.ssh

  2. その下にsshディレクトリをボリュームとしてマウントしたいことを示します。

    VOLUME [ "/root/.ssh" ]

  3. 次の行を追加して、コンテナの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" ]
0
Buchanora

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
0
StanislavKo