Featured image of post PrometheusをHTTPS化する

PrometheusをHTTPS化する

セキュリティは大事

やったことのまとめ

PrometheusはデフォルトだとHTTP(暗号化なし)で公開されるが, セキュリティの観点からどうしてもHTTPSで動かしたい場合がある.

今回はnginxを使ってリバースプロキシする方法とPrometheus自体をHTTPS化する方法の2通りの方法を試してみた.

HTTPS化したPrometheus

つかうもの

  • macOS Mojave 10.14
    • Dockerのホストとして使用, 動作確認用のブラウザもこちらで起動する
  • Google Chrome
    • バージョン: 88.0.4324.150(Official Build) (x86_64)
  • Docker Desktop for Mac
    • Version 3.1.0
    • Docker Engine Version 20.10.2
    • docker-compose version 1.27.4
  • Prometheus (Docker)
  • nginx (Docker)
  • openssl
    • version 1.1.1d

やったこと

秘密鍵とオレオレ証明書の作成

まずはHTTPSで通信を行うためにopensslで秘密鍵とSSL証明書(オレオレ証明書)を作成する.
(公的な証明書と鍵のペアがある場合は不要. 文中のhogehoge.comは適切なホスト名に置き換える.)

オレオレ証明書を作るときは以前のやり方に加えて,
ページをChromeで開いた場合も怒られないようにSANs(Subject Alternative Names)を設定するようにする.

今回の鍵と証明書の作成に使用するopensslnginxDocker imageに入っているものを使う.

# nginxコンテナの中で実行(カレントディレクトリをマウントしておく)
$ docker container run --rm -it -v="$PWD:/workdir" -w="/workdir" --entrypoint=/bin/bash nginx:1.18.0

## ここからコンテナ内
$ openssl version
OpenSSL 1.1.1d  10 Sep 2019

# 秘密鍵(private-key.pem)の作成
$ openssl genpkey -algorithm RSA -out private-key.pem

# オレオレ証明書(cert.pem)の作成(CSRの作成と署名)
# SANsの設定もやっておく(Chrome対応)
$ openssl req -x509 -key private-key.pem -out cert.pem -addext 'subjectAltName = DNS:hogehoge.com,DNS:fugafuga.com'
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [AU]:
State or Province Name (full name) [Some-State]:
Locality Name (eg, city) []:
Organization Name (eg, company) [Internet Widgits Pty Ltd]:
Organizational Unit Name (eg, section) []:
Common Name (e.g. server FQDN or YOUR name) []:hogehoge.com
Email Address []:

# 証明書の中身を確認(SANsが追加されている)
$ openssl x509 -in cert.pem -noout -text
Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number:
            24:4c:ec:40:cc:94:5c:a2:af:30:6a:e9:7d:5c:17:28:5e:fb:ec:fc
        Signature Algorithm: sha256WithRSAEncryption
        Issuer: C = AU, ST = Some-State, O = Internet Widgits Pty Ltd, CN = hogehoge.com
        Validity
            Not Before: Feb 10 16:13:01 2021 GMT
            Not After : Mar 12 16:13:01 2021 GMT
        Subject: C = AU, ST = Some-State, O = Internet Widgits Pty Ltd, CN = hogehoge.com
        ...
        X509v3 extensions:
            ...
            X509v3 Subject Alternative Name:
                DNS:hogehoge.com, DNS:fugafuga.com

# コンテナから出る
$ exit 

## ここからホストOS(Mac)

# 秘密鍵と証明書ができている
$ ls
cert.pem
private-key.pem

次にSANsに指定したhogehoge.comlocalhost(127.0.0.1)にアクセスできるよう,
Mac(Prometheusを起動するマシン)の名前解決設定(/etc/hosts)を編集する.

# /etc/hostsにhogehoge.com(localhost)を追加
$ echo "127.0.0.1 hogehoge.com" | sudo tee -a /etc/hosts

最後に今回作った証明書(cert.pem)は公的な認証局が署名したものではないので,
証明書をMacキーチェーンアクセスで開いて常に信頼するよう設定する.

キーチェーンアクセスで開く 信頼設定を変更

これでHTTPS化に必要な証明書の設定は完了.

nginxを挟んでHTTPS化する

次に公式の手順1に従ってnginxHTTPS化して, その後ろでPrometheusが動く構成(リバースプロキシ)をつくる.

今回も例に依ってDocker Composeで試すが, 非コンテナ環境の場合はコンテナ名で名前解決している部分を適切な名前(ホスト名)に置き換えて,
docker-compose.ymlで指定している場所に各種の設定ファイルを配置すれば動くはず.

  • Prometheus
    • リバースプロキシ用の設定を引数で設定
      • --web.external-url : 証明書のSANsに指定した名前+リクエストを受け付けるパス
      • --web.route-prefix : /を明示的に指定
  • nginx
    • PrometheusのリバースプロキシとHTTPSの設定をhttps.confに記述する
    • 秘密鍵, 証明書を指定の場所に配置する

コンテナを立ち上げてみる.

# cert.pemとprivate-key.pemは先ほど作ったオレオレ証明書と秘密鍵
$ tree .
.
├── cert.pem
├── docker-compose.yml
├── https.conf
└── private-key.pem

# コンテナ起動
$ docker-compose up -d --force-recreate --remove-orphans

# localhostの443ポートがnginxコンテナに割り当てられている
$ docker-compose ps
   Name                 Command               State              Ports
----------------------------------------------------------------------------------
nginx        /docker-entrypoint.sh ngin ...   Up      0.0.0.0:443->443/tcp, 80/tcp
prometheus   /bin/prometheus --config.f ...   Up      9090/tcp

# オレオレ証明書(cert.pem)を信頼する設定でPrometheus APIを叩いてみる
$ curl --cacert ./cert.pem https://hogehoge.com/prometheus/api/v1/label/job/values
{"status":"success","data":["prometheus"]}

コンテナが立ち上がり, hogehoge.comHTTPSで公開されていることが確認できた.

念の為Chromehttps://hogehoge.com/prometheus/を開いてみる.

HTTPSで開けた

オレオレ証明書が信頼されている

PrometheusHTTPSで公開されていて, Chromeがオレオレ証明書を信頼していることが確認できた.

Prometheus単独でHTTPS化する

今までPrometheusHTTPS化する際は先ほど試したようにリバースプロキシを使うのが推奨されていたのだが,

なんとversion 2.24からはPrometheus単独でのHTTPS化にも対応した2らしい(まだお試し機能らしいが)ので試してみる.

まずは新しいHTTPS関連の設定ファイルweb-config.yml3で証明書と秘密鍵の場所を指定する.
(この他にもクライアント認証やBasic認証も設定できるらしい.)

次にPrometheusの実行時引数--web.config.fileweb-config.ymlの場所を指定する.
また, hogehoge.comでアクセスを受けられるように--web.external-urlを設定する(nginxを使う場合と異なり/prometheusは不要).

コンテナを立ち上げてみる.

# cert.pemとprivate-key.pemは先ほど作ったオレオレ証明書と秘密鍵
$ tree .
.
├── cert.pem
├── docker-compose.yml
├── private-key.pem
└── web-config.yml

# コンテナ起動
$ docker-compose up -d --force-recreate --remove-orphans

# localhostの443ポートがPrometheusコンテナに割り当てられている
$ docker-compose ps
   Name                 Command               State               Ports
------------------------------------------------------------------------------------
prometheus   /bin/prometheus --config.f ...   Up      0.0.0.0:443->443/tcp, 9090/tcp

# オレオレ証明書(cert.pem)を信頼する設定でPrometheus APIを叩いてみる
$ curl --cacert ./cert.pem https://hogehoge.com/api/v1/label/job/values
{"status":"success","data":["prometheus"]}

次にChromehttps://hogehoge.com/を開くと, nginxを使ったときと同様にPrometheusHTTPSで公開されていることがわかる.

HTTPSで起動している

やったぜ.

ただしnginxを使う場合には無かった注意点として, 今回はPrometheus自身がHTTPSで起動しているため,
自身のメトリクス(/metrics)のスクレイプ設定がデフォルトのままだとプロトコルがHTTPのままなのでスクレイプに失敗する.

スクレイプに失敗している
デフォルト設定だとHTTPでスクレイプしているのが原因

今回はとりあえずPrometheusHTTPS化するのが目的だったので, ここでおわり.

おわり

PrometheusHTTPS化してみた.
nginxを使う方法はそれはそう…という感じだけど, Prometheus単体でHTTPS化できるのは知らなかった.

ただしPrometheus単独でのHTTPS対応はまだお試し機能っぽいのと,
Alertmanagerはまだ対応してない?みたいなので, 併せて対応する場合はnginxを使うように統一したほうが良さそう.

おまけ

顔をつよめに撫でられるのがすきなねこ