Dockerコンテナ内でGCPの証明書エラーと戦ってみた


Docker for Macで作成したコンテナ内にgcloudコマンドの環境を構築したところ、社内プロキシ関連の証明書でエラーが出たので回避策をまとめておきます

結論

gcloud config set auth/disable_ssl_validation True

で証明書のチェックを無効化する。

あるいは、ホストマシンにインストールされた証明書をコンテナ内に持って行って、以下のコマンドで証明書を指定する

gcloud config set core/custom_ca_certs_file /path/to/ca_certs

動作環境

macOS Mojave

version 10.14.5

$ docker --version
Docker version 18.09.2, build 6247962
$ code --version
1.35.1
c7d83e57cd18f18026a8162d042843bda1bcf21f
x64

事象

gcloud auth loginコマンドでログイン処理を行なったところ、以下のエラーが発生しました

ERROR: gcloud crashed (SSLHandshakeError): [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed (_ssl.c:727)

SSL: CERTIFICATE_VERIFY_FAILEDということで証明書のエラーとのことです。

対策方法

調べた感じ対策は2種類かな、という感じでした。

  1. gcloudコマンドのSSLのチェックを無効化する
  2. ホスト(Mac)にインストールされている証明書をコンテナ側にインストールする

この2つの方法を試してみました。

gcloudコマンドのSSLのチェックを無効化する

こちらは簡単で、コマンド1発で設定するだけです。

gcloud config set auth/disable_ssl_validation True

これでSSLのエラーが出ても無視するようになります。

ホスト(Mac)にインストールされている証明書をコンテナ側にインストールする

完全無視の方法は楽なんですがちゃんとした証明書でやる方法も欲しいということでやってみました。

プロキシ配下の場合にDockerコンテナ内でエラーが出るのは、プロキシのルート証明書がコンテナ内のOSにはインストールされていないからです。これによって、

  • ホストマシン(Mac)には社内プロキシ用の証明書がインストールされているので、ブラウザでみた場合は問題なし
  • コンテナや仮想マシンの場合は一般的な証明書しか入っていないのでエラーが出る

というような動きになります。

ということはホストマシンの証明書をコンテナ側にも設定してあげれば良い、ということになるのでやってみました
(逆に言うと、証明書が古いとかの原因でホスト側からもアクセスできないようなサイトの場合は無理なので、その場合は諦めます。)

手順はざっくり以下です。

  1. キーチェーン アプリからルート証明書のファイルをエクスポートする
  2. コンテナ内のLinuxに証明書のファイルをコピーする
  3. gcloudコマンドで証明書を指定する

細かい手順は次から

キーチェーンから証明書をエクスポートする

Macのキーチェーンアプリを開きます

以下のように、キーチェーンはシステム、分類は証明書を選ぶとインストールされている証明書の一覧が確認できます。

この中から該当するルート証明書を選びます。
複数あってどれかわからないと言う場合は備考:ルート証明書の確認の方法で確認できます。

必要となる証明書を右クリックして***を書き出すというメニューからファイルに書き出します。

ファイル形式はpemとして、説明の為にファイル名はroot.pemとします。

このroot.pemができればホスト側の作業は終わりです。

試してみる

本当にちゃんと通信できるか試してみました。

まず、以下のDockerfileでgcloudコマンドがインストールされたUbuntuイメージを作成します。

こんな構成でファイルを配置して、docker-compose.ymlで立ち上げます。
root.pemは上記で書き出したファイルです。

./Dockerfile
./certificates
./certificates/root.pem
./docker-compose.yml
FROM ubuntu:18.04

RUN apt update && apt install -y lsb-release
RUN apt install -y curl gnupg
RUN export CLOUD_SDK_REPO="cloud-sdk-$(lsb_release -c -s)" && \
    echo "deb http://packages.cloud.google.com/apt $CLOUD_SDK_REPO main" | tee -a /etc/apt/sources.list.d/google-cloud-sdk.list && \
    curl -k https://packages.cloud.google.com/apt/doc/apt-key.gpg | apt-key add - && \
    apt-get update -y && apt-get install google-cloud-sdk -y
docker-compose.yml
version: '3.3'

services:
  main:
    build: .
    tty: true
    volumes:
      - ./certificates:/certificates

docker-compose立ち上げて、コンテナに接続します

docker-compose up -d
docker-compose exec main bash

コンテナ内からgcloud auth loginで認証をしてみますが、まだ何も設定していないので当然ながらエラーが出ました。

$ gcloud auth login
Go to the following link in your browser:

    https://accounts.google.com/o/oauth2/auth?***********************

Enter verification code: 
ERROR: gcloud crashed (SSLHandshakeError): [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed (_ssl.c:727)

gcloud's default CA certificates failed to verify your connection, which can happen if you are behind a proxy or firewall.
To use a custom CA certificates file, please run the following command:
  gcloud config set core/custom_ca_certs_file /path/to/ca_certs

If you would like to report this issue, please run the following command:
  gcloud feedback

To check gcloud for common problems, please run the following command:
  gcloud info --run-diagnostics

gcloud setコマンドで証明書を指定する

エラーメッセージにもあるように、gcloud config set core/custom_ca_certs_file /path/to/ca_certsで証明書のファイル指定すれば良いということなのでやってみます。

証明書のマウント先は/certificates/root.pemになります

$ gcloud config set core/custom_ca_certs_file /certificates/root.pem 
Updated property [core/custom_ca_certs_file].

To take a quick anonymous survey, run:
  $ gcloud alpha survey

gcloud alpha surveyは何?と思いましたが、ただのアンケートのようなので無視します

この状態でもう一度ログイン処理を走らせます

$ gcloud auth login
Go to the following link in your browser:
    https://accounts.google.com/o/oauth2/auth?***********************

Enter verification code: 
WARNING: `gcloud auth login` no longer writes application default credentials.
If you need to use ADC, see:
  gcloud auth application-default --help

You are now logged in as [********].
Your current project is [None].  You can change this setting by running:

無事にログインできました。

この状態からプロジェクトを設定して、GCPのAPIなども叩けたので問題ないかなと思います。

備考:ルート証明書の確認

Webブラウザでサイトにアクセスすると、どの証明書で認証したかが確認できます。
ChromeでVisual Studio Marketplaceを開いた場合は以下のような感じです。

URLの左側の鍵をクリックするとこんなダイアログが出るので

証明書を選択すれば使われているルート証明書が確認できます。この中の一番上のものを選んでおけば大丈夫かと思います

おわりに

gcloudの証明書エラーと戦ってみました。
社内プロキシがあるとどうしても出てくる問題なので仕方ないような、無駄な時間のような...

ちなみに独自のルートCA証明書を追加する方法(Ubuntu, CentOS 7) | cloudpack.media の方法を使えばOS自体の証明書にも追加できるので、その他のツール周りでエラーが出る場合でもいけるはずです。

参考

Adding a custom CA Root certificate to GCloud utility (or Python generally) on Windows - Stack Overflow