Azure Monitor Linux AgentをHTTPプロキシ経由で使う


はじめに

AzureでIaaSとPaaSを併用するとIaaSから野良PaaSへの外部流出の穴が開きます。
※最近ではプライベートリンクが出てきたので解消されているかもしれません。

そこでVMからインターネットへの接続はすべてプロキシ経由として
プロキシでURLフィルタリングすることでセキュリティを高めることが可能です。

しかし近年の通信はほぼほぼHTTPSになってきています。
HTTPS通信は暗号化されていますので、そのままではURLを取り出せずフィルタすることはできません。
※SSL通信では初めにCONNECTメソッドをHTTPで投げるためそのパケットからFQDNを取り出してフィルタすることは可能。

HTTPSのフィルタにはSSLインスペクションという技術を使います。
簡単に言うとMan in the Middle、なりすましです。

多くのファイアウォール製品の機能として提供されていますが、
OSSのSquidでもssl_bumpという機能で実現可能です。

Proxyサーバの構築

VMの構築

いつものAzureCLIで。

az vm create \
  --resource-group rg_sadakata --name sada.proxy.test --image RHEL \
  --admin-username sada --authentication-type password --admin-password XXXXXXXXXX

Squidの構築

・Squidのインストール

# yum install -y squid

・SSLインスペクションのための自己署名証明書の作成

# openssl req -new -newkey rsa:2048 -days 30 -nodes -x509 -keyout  /etc/squid/squidCA.pem -out /etc/squid/squidCA.pem
# chown squid:squid /etc/squid/squidCA.pem
# chmod 400 /etc/squid/squidCA.pem

・なりすまし用自己署名証明書を作成するフォルダの作成と初期化

# mkdir /var/lib/squid
# /usr/lib64/squid/ssl_crtd -c -s /var/lib/squid/ssl_db
# chown -R squid:squid /var/lib/squid/ssl_db

・Squidの設定ファイルを修正

# vi /etc/squid/squid.conf
http_port 3128 ssl-bump cert=/etc/squid/squidCA.pem
sslcrtd_program /usr/lib64/squid/ssl_crtd -s /var/lib/squid/ssl_db -M 4MB
sslcrtd_children 5
ssl_bump server-first all
sslproxy_cert_error allow all

・ファイアウォールでSquidへの通信を許可

# firewall-cmd --list-all
public (active)
・・・
  services: dhcpv6-client ssh
・・・ 

# firewall-cmd --permanent --add-service=squid
success

proxy # systemctl restart firewalld

proxy # firewall-cmd --list-all
public (active)
・・・
  services: dhcpv6-client squid ssh
・・・ 

・Squidのサービス登録と起動

# systemctl enable squid
# systemctl start squid
# systemctl status squid
・・・
Active: failed (Result: exit-code) since Tue 2020-06-30 07:07:50 UTC; 4min 32s ago
・・・
FATAL: The ssl_crtd helpers are crashing too rapidly, need help!
・・・

ん?

SELINUX無効化

ここでハマりました。
Squidのログを見てみると/var/lib/squid/ssl_dbを初期化せい、とのこと。

# tail /var/log/squid/cache.log
2020/06/30 02:55:47 kid1| helperOpenServers: Starting 5/5 'ssl_crtd' processes
(ssl_crtd): Uninitialized SSL certificate database directory: /var/lib/squid/ssl_db. To initialize, run "ssl_crtd -c -s /var/lib/squid/ssl_db".
(ssl_crtd): Uninitialized SSL certificate database directory: /var/lib/squid/ssl_db. To initialize, run "ssl_crtd -c -s /var/lib/squid/ssl_db".
(ssl_crtd): Uninitialized SSL certificate database directory: /var/lib/squid/ssl_db. To initialize, run "ssl_crtd -c -s /var/lib/squid/ssl_db".
(ssl_crtd): Uninitialized SSL certificate database directory: /var/lib/squid/ssl_db. To initialize, run "ssl_crtd -c -s /var/lib/squid/ssl_db".
(ssl_crtd): Uninitialized SSL certificate database directory: /var/lib/squid/ssl_db. To initialize, run "ssl_crtd -c -s /var/lib/squid/ssl_db".
・・・
2020/06/30 02:55:48 kid1| WARNING: ssl_crtd #Hlpr1 exited
2020/06/30 02:55:48 kid1| Too few ssl_crtd processes are running (need 1/5)
2020/06/30 02:55:48 kid1| Closing HTTP port [::]:3128
・・・
FATAL: The ssl_crtd helpers are crashing too rapidly, need help!

さっき初期化したばかりなんだが。再度初期化し直してもダメ。

ググってみると、SELINUXが悪さをしているとのこと。
そういえば昔はOSインストールしたら速攻ファイアウォール(当時iptables)とSELINUX無効化してっけ。
いや、本来はちゃんとSELINUXの設定するべきですよ。
でもこの年になるまでSELINUXを理解せずに来てしまったので、
SELINUXの勉強はまたの機会にして今回の検証を進めます。

# getenforce
Enforcing
# vi /etc/selinux/config
SELINUX=enforcing # これを
SELINUX=disabled # こう直す

OSを再起動して反映させます。

# reboot

再度確認してみます。

# getenforce
Disabled

反映されてますね。
既にサービス登録してるのでOS再起動によりSquidも再起動されています。
Squidの状態を確認してみます。

# systemctl status squid
● squid.service - Squid caching proxy
   Loaded: loaded (/usr/lib/systemd/system/squid.service; enabled; vendor preset: disabled)
   Active: active (running) since Tue 2020-06-30 03:01:37 UTC; 1min 10s ago

# tail /var/log/squid/cache.log
・・・
2020/06/30 03:01:38 kid1| Accepting SSL bumped HTTP Socket connections at local=[::]:3128 remote=[::] FD 22 flags=9
・・・

ちゃんと起動してます、よかった。
3128ポートでssl_bumpも有効になっています。
一応netstatでも見ときます。

# netstat -antup|grep LISTEN|grep :3128
tcp6       0      0 :::3128                 :::*                    LISTEN      1164/(squid-1) 

Azure Monitorエージェントの構築

VMの構築

こちらもAzureCLIで。

# az vm create \
  --resource-group rg_sadakata --name sada.monitor.test --image RHEL \
  --admin-username sada --authentication-type password --admin-password XXXXXXXXXX

Azure Monitor Linux Agentの構築

・エージェントのインストール

# wget https://raw.githubusercontent.com/Microsoft/OMS-Agent-for-Linux/master/installer/scripts/onboard_agent.sh && sh onboard_agent.sh -w a9016fc8-37a9-4610-b7e9-272633794de5 -s 0baUDCuoKAZsAZQsmHjeVl2K+5jCR7xig1EEM5FvmRpJAeShQdQUpMytCKX04KStnPtVzcLX4pb4Fbbma0o8gQ== -d opinsights.azure.com
Shell bundle exiting with code 0

# /opt/microsoft/omsagent/bin/service_control restart a9016fc8-37a9-4610-b7e9-272633794de5

・エージェントログの確認
```

tail /var/opt/microsoft/omsagent/log/omsagent.log

・・・
2020-06-30 03:52:22 +0000 [info]: Sending OMS Heartbeat succeeded at 2020-06-30T03:52:22.776Z
2020-06-30 03:53:22 +0000 [info]: Sending OMS Heartbeat succeeded at 2020-06-30T03:53:22.777Z
```

・LogAnalyticsワークスペースにハートビートが届いていることの確認

Proxyに向ける

OSの設定

・まずはそのまま(Squidのアクセスログをtailしながら)

# curl "https://qiita.com/api/v2/users/sada808"
{"description":"SIer所属。\r\nMicrosoft MVP(Azure)を獲るべく頑張って記事書きます。","facebook_id":"","followees_count":0,"followers_count":2,"github_login_name":null,"id":"sada808","items_count":4,"linkedin_id":"","location":"","name":"","organization":"","permanent_id":24194,"profile_image_url":"https://qiita-image-store.s3.amazonaws.com/0/24194/profile-images/1473759232","team_only":false,"twitter_screen_name":"sada808","website_url":""}monitor # 

ちゃんとアクセスできます。Squidのアクセスログには出力されません。

・ではOSの環境設定を変更してProxyに向けます。

export HTTP_PROXY=http://10.0.0.5:3128/
export HTTPS_PROXY=https://10.0.0.5:3128/
export http_proxy=http://10.0.0.5:3128/
export https_proxy=https://10.0.0.5:3128/

・再度確認
※ちなみにSquidでFW設定してないと↓のエラーになります。

curl: (7) Failed connect to 10.0.0.4:3128; No route to host

では再度アクセスしてみます。

monitor # curl "https://qiita.com/api/v2/users/sada808"
curl: (60) Peer's certificate issuer has been marked as not trusted by the user.
More details here: http://curl.haxx.se/docs/sslcerts.html

curl performs SSL certificate verification by default, using a "bundle" of Certificate Authority (CA) public keys (CA certs). 
If the default bundle file isn't adequate, you can specify an alternate file using the --cacert option.
If this HTTPS server uses a certificate signed by a CA represented in the bundle, the certificate verification probably failed due to a problem with the certificate (it might be expired, or the name might not match the domain name in the URL).
If you'd like to turn off curl's verification of the certificate, use the -k (or --insecure) option.

オレオレ証明書使ってるので証明書エラーになります。今回は検証なので-kオプションで無視します。

monitor # curl "https://qiita.com/api/v2/users/sada808" -k
{"description":"SIer所属。\r\nMicrosoft MVP(Azure)を獲るべく頑張って記事書きます。","facebook_id":"","followees_count":0,"followers_count":2,"github_login_name":null,"id":"sada808","items_count":4,"linkedin_id":"","location":"","name":"","organization":"","permanent_id":24194,"profile_image_url":"https://qiita-image-store.s3.amazonaws.com/0/24194/profile-images/1473759232","team_only":false,"twitter_screen_name":"sada808","website_url":""}monitor # 

無事アクセスできました。
ではSquidのアクセスログには出力されているか。

1593491969.108     12 10.0.0.5 TAG_NONE/200 0 CONNECT qiita.com:443 - HIER_DIRECT/52.68.176.31 -
1593491969.399    222 10.0.0.5 TCP_MISS/200 1274 GET https://qiita.com/api/v2/users/sada808 - HIER_DIRECT/52.68.176.31 application/json

ちゃんと出力されています。
ちなみに1行目が冒頭に記載したCONNECTメソッドです。
FQDNはわかるものの、それ以降のURLはわかりません。
2行目ではちゃんとSSLを復号化されてURLまで見えています。

SquidのSSLインターセプトの挙動が確認できたので
本題のAzure monitor Agentをプロキシに向けます。

エージェントの設定

・OSの環境変数でよしなにやってくれるかと思ったらやってくれませんでした。
ググってみたらomsagentとしての設定があるとのこと。

# proxyconf="https://10.0.0.4:3128"
# echo $proxyconf >>/etc/opt/microsoft/omsagent/proxy.conf
# chown omsagent:omiusers /etc/opt/microsoft/omsagent/proxy.conf

# /opt/microsoft/omsagent/bin/service_control restart a9016fc8-37a9-4610-b7e9-272633794de5

挙動を確認

Squidのアクセスログを確認

1593492291.113    121 10.0.0.5 TAG_NONE/200 0 CONNECT a9016fc8-37a9-4610-b7e9-272633794de5.ods.opinsights.azure.com:443 - HIER_DIRECT/40.79.194.105 -

ちゃんとProxy向いてくれてます。

エージェントログの確認

2020-06-30 04:45:30 +0000 [info]: Sending OMS Heartbeat succeeded at 2020-06-30T04:45:30.009Z
・・・
2020-06-30 04:45:31 +0000 [info]: Encountered retryable exception. Will retry sending data later.
2020-06-30 04:45:31 +0000 [warn]: temporarily failed to flush the buffer. next_retry=2020-06-30 04:46:01 +0000 error_class="RuntimeError" error="Net::HTTP.Post raises exception: OpenSSL::SSL::SSLError, 'SSL_connect returned=1 errno=0 state=error: certificate verify failed (self signed certificate in certificate chain)'" plugin_id="object:3fee00cd188c"

やはり証明書チェックでエラーになってますね。

さいごに

色々ハマったので今回はここまで。

以下をもう少し粘ってみようと思います。

・よく自己署名証明書を使うときにWindowsブラウザ用に証明書配ったりするので、そのノリでLinuxのルート証明機関としてインストールできないか。

・OMS AgentはFluentdのPluginでRubyで書かれている。Net::HTTPのPostメソッドでエラーになってるので、この辺りをcurlみたいにコンフィグとかで無視するようにできないか。

しかしアクセスログ見るとわかるように、Azure MonitorエージェントはFQDNに対してリクエストを投げてます。
つまりわざわざSSLをインターセプトしなくてもFQDNによるフィルタが可能になるはずです。

最悪FQDNフィルタに逃げよう・・・。