やったことのまとめ
Prometheus
にクライアント認証をかけてみた.
Prometheus
単独でクライアント認証を行う方法と,
クライアント認証をかけたnginx
でリバースプロキシする方法をそれぞれ試した.
Prometheus
, nginx
はすべてDocker Desktop for Mac
で動かした.
つかうもの
- macOS Big Sur 11.2.3
- Docker Desktop for Mac
- Version 3.3.1
- Docker Engine Version 20.10.5
- Docker Compose Version 1.29.0
- Prometheus (Docker)
- nginx (Docker)
- OpenSSL
- 1.1.1d
やったこと
各種秘密鍵と証明書の作成
まずはクライアント認証に必要なサーバーとクライアントの秘密鍵+証明書をOpenSSL
で作成する.
# nginxコンテナを起動してOpenSSLを使う
$ docker container run --rm -it -v="$PWD:/workdir" -w="/workdir" --entrypoint=/bin/bash nginx:1.21.0
# サーバー用のオレオレ証明書を作成
# ホスト名はprometheus.hogehoge.comとしてSANsの設定もしておく(Chromeで開くため)
$ openssl genpkey -algorithm RSA -out server-private-key.pem
$ openssl req -x509 -key server-private-key.pem -out server-cert.pem -addext 'subjectAltName = DNS:prometheus.hogehoge.com'
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) []:prometheus.hogehoge.com
Email Address []:
# クライアント認証局の証明書を作成(オレオレ認証局)
$ openssl genpkey -algorithm RSA -out client-ca-private-key.pem
$ openssl req -x509 -key client-ca-private-key.pem -out client-ca-cert.pem -days 365
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) []:client-ca
Email Address []:
# 署名のための準備
$ mkdir -p demoCA/newcerts && touch demoCA/index.txt
$ echo 01 > ./demoCA/serial
# クライアント証明書を作成(クライアント認証局で署名する)
# PKCS#12形式のものも作成しておく
$ openssl genpkey -algorithm RSA -out client-private-key.pem
$ openssl req -new -key client-private-key.pem -out client-csr.pem
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) []:client
Email Address []:
A challenge password []:
An optional company name []:
$ openssl ca -in client-csr.pem -out client-cert.pem -keyfile client-ca-private-key.pem -cert client-ca-cert.pem -days 365
Sign the certificate? [y/n]:y
1 out of 1 certificate requests certified, commit? [y/n]y
$ openssl pkcs12 -export -clcerts -in client-cert.pem -inkey client-private-key.pem -out client-cert.p12
Enter Export Password: fugafuga
Verifying - Enter Export Password: fugafuga
# コンテナから出ると鍵と証明書が作成されている
$ exit
$ ls -1
client-ca-cert.pem
client-ca-private-key.pem
client-cert.p12
client-cert.pem
client-csr.pem
client-private-key.pem
demoCA
server-cert.pem
server-private-key.pem
今回は鍵と証明書をたくさん使っていて後で混乱しそうなのでここに内容をまとめておく.
- サーバー認証局の証明書(
server-cert.pem
)- サーバー証明書に署名した認証局の証明書
- 今回はオレオレ証明書なのでサーバー証明書と同一だが, ちゃんとした認証局(CA)によってサーバー証明書を発行した場合は認証局の証明書を使う.
- サーバー認証局の秘密鍵(
server-private-key.pem
)- サーバー証明書に署名した認証局の秘密鍵
- 今回はオレオレ証明書なのでサーバー秘密鍵と同一
- このあとは使わない
- サーバー証明書(
server-cert.pem
)- サーバー(Prometheus)の身元を証明する証明書. 今回はオレオレ証明書を使う.
- ホスト名はprometheus.hogehoge.comとした(オレオレ証明書なので任意の名前)
- サーバー秘密鍵(
server-private-key.pem
)- サーバー(Prometheus)に持たせる秘密鍵
- クライアント認証局の証明書(
client-ca-cert.pem
)- クライアント証明書に署名した認証局の証明書
- クライアント認証局の秘密鍵(
client-ca-private-key.pem
)- クライアント証明書に署名した認証局の秘密鍵
- このあとは使わない
- クライアント証明書(
client-cert.pem
,client-cert.p12
)- クライアントの身元を証明する証明書
- クライアント(Prometheus, Grafana, User)ごとに分けてもいいけど, 面倒なので全部同じものを使う
- クライアント秘密鍵(
client-private-key.pem
)- クライアントに持たせる秘密鍵
- クライアントのCSR(
client-csr.pem
)- クライアント証明書を発行するときに使ったCSR
- このあとは使わない
ついでにブラウザでも動作確認できるように, Macでサーバー証明書を信頼する設定とクライアント証明書を持たせる設定を行う.
Finderからclient-cert.p12
とserver-cert.pem
をそれぞれダブルクリックして,
証明書をキーチェーンアクセス
で信頼するように設定する.
最後に, 今回はサーバー証明書で実在しないドメイン(prometheus.hogehoge.com)を指定しているので,
Macの/etc/hosts
に名前解決の設定を記述しておく.
# /etc/hostsにprometheus.hogehoge.com(localhostに飛ばす)を追加
$ echo "127.0.0.1 prometheus.hogehoge.com" | sudo tee -a /etc/hosts
以上で証明書とか秘密鍵の準備は完了.
Prometheus単独でクライアント認証をかける
Prometheus自体にクライアント認証の仕組みがあるので1,
サーバー証明書とサーバー秘密鍵(HTTPS化してサーバーの身元を証明するのに使用),
クライアント認証局の証明書(クライアントの身元を確認するのに使用)を持たせる.
クライアント認証の設定はweb-config.yml
に記述する.
Prometheus自身のメトリクスを取得する際にもクライアント認証を突破する必要があるので,
クライアント証明書とクライアント秘密鍵(クライアントの身元を証明するのに使用),
サーバー認証局の証明書(HTTPSサーバーの身元を確認するのに使用)も持たせることにする.
(Prometheus自身のメトリクスを取得しない場合は不要)
クライアント認証を突破するための設定はprometheus.yml
のscrape_configs
2に記述する.
あとは指定のパスにそれぞれの秘密鍵, 証明書ファイルを配置する.
今回はDocker
で起動するのでパスを指定してマウントしてあげれば良い.
以上で準備ができたので, いよいよDocker
で起動する.
# ディレクトリの状態(使わないものは消している)
$ ls -1
client-ca-cert.pem
client-cert.pem
client-private-key.pem
docker-compose.yml
prometheus.yml
server-cert.pem
server-private-key.pem
web-config.yml
# コンテナを起動する
$ docker compose up -d --force-recreate --remove-orphans
動作確認のため,
Chromeで https://prometheus.hogehoge.com を開く.
Macにクライアント証明書をもたせたため, 問題なく閲覧できた.
今度はクライアント証明書を使わずに https://prometheus.hogehoge.com を開いてみる.
要求されたクライアント証明書を提示しなかったため, 閲覧ができない.
以上でPrometheus
にクライアント認証がかかっていることを確認できた.
# コンテナを終了しておく
$ docker compose down
Prometheus+nginxでクライアント認証をかける
Prometheus
の前段にnginx
(リバースプロキシ)を用意して, そこでクライアント認証をかけることもできる.
nginx
にサーバー証明書とサーバー秘密鍵(HTTPSサーバーの身元を証明するのに使用),
クライアント認証局の証明書(クライアントの身元を確認するのに使用)を持たせる.
今回はHTTPS化と認証まわりの設定をhttps.conf
に記述する.
今回はクライアント認証を行うポート(443)と別に認証をかけないポート(44433)も用意してみる.
この場合Prometheus
自体にはクライアント認証をかけないのでweb-config.yml
は不要,
さらに自身のメトリクスを取得する場合でもクライアント証明書とクライアント秘密鍵は不要となる.
(したがってprometheus.yml
も自分で作らずデフォルトのものを使用する)
あとは各種ファイルをnginx
のコンテナにマウントして起動する.
(先程とは異なり, Prometheus
にファイルを持たせないなど設定が変わっていることに注意)
# ディレクトリの状態(使わないものを消している)
$ ls -1
client-ca-cert.pem
docker-compose.yml
https.conf
server-cert.pem
server-private-key.pem
# コンテナを起動する
$ docker compose up -d --force-recreate --remove-orphans
Chromeでhttps://prometheus.hogehoge.comを開く.
クライアント証明書を提示しなかったので認証に失敗した.
(クライアント証明書を要求された際に"OK"を選択すると認証に成功する)
この状態で次はhttps://prometheus.hogehoge.com:44433を開く.
44433ポートにはクライアント認証をかけていないため, そのまま開くことができた.
こんな感じの出し分けをPrometheus
単独でやるのは難しいが,nginx
を使うと比較的カンタンに実現できるし, Prometheus
自身のメトリクスを取得するためにクライアント証明書などを持たせる必要もなくなる.
クライアント認証以外の認証方式も設定しやすいので,
個人的にはこちらのほうがすき.
# コンテナを終了しておく
$ docker compose down
おわり
Prometheus
にクライアント認証をかけてみた.
セキュリティ要件でPrometheus
へのアクセスに認証が必要な場合は,
基本は前段のnginx
で認証設定をかけてクライアント側(Grafana
とか)に認証情報を持たせてアクセスするのが良いと思う.