Squidにホワイトリストを設定してUbuntuのインスタンスからパッケージダウンロードする

こんにちは、岩城です。私の備忘録シリーズです。先日、プライベートサブネット上のインスタンスからインターネットへ接続してパッケージをダウンロードする際、許可されたURLに限定して接続する方法を調べる機会がありました。備忘録としてまとめておきます。
2019.03.12

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

はじめに

こんにちは、岩城です。私の備忘録シリーズです。 先日、プライベートサブネット上のインスタンスからインターネットへ接続してパッケージをダウンロードする際、許可されたURLに限定して接続する方法を調べる機会がありました。備忘録としてまとめておきます。

経緯

プライベートサブネット上のインスタンスからパッケージダウンロードを可能とする構成としては、NAT Gatewayの利用が挙げられます。NAT Gatewayはマネージドサービスなのでインスタンスの管理が不要となり、利用するシーンは多いと思います。しかし、今回の機会ではホワイトリストによる接続許可が要件であり、NAT Gatewayにはそのような機能がなく断念しました。そこで、プロキシとなるインスタンスを構築して、ホワイトリスト接続を許可する構成にしようと考えました。

Amazon Linuxだったら楽だった

今回の機会で利用するOSはUbuntuであり、プロキシを立てるほかありませんでしたが、以下エントリのとおりAmazon Linuxだったら楽だったかも知れません。

【小ネタ】えっ、Private SubnetからNATサーバを経由せずにyum updateができるって!?

Amazon LinuxはyumパッケージのリポジトリがS3にあるため、エンドポイントを利用してプライベートサブネットから接続する構成を取ることができます。この場合、接続がS3に制限されるため、場合によってはホワイトリストの要件が不要になるかも知れません。

やってみた

構成

次の構成を考えてみます。

  • Direct Connectを利用した閉域網
  • パブリックサブネットとプライベートサブネットに分ける
  • パブリックサブネットにプロキシを立てる
  • プロキシのパッケージはSquidを採用する
  • UbuntuのデフォルトのリポジトリリストをSquidにホワイトリストとして設定する

プロキシをインストール&設定する

プロキシインスタンスでの作業です。まずは、squidをインストールします。

$ sudo yum update
$ sudo yum install -y squid
$ squid -v
Squid Cache: Version 3.5.20
Service Name: squid
configure options:
(省略)

ホワイトリストの設定などを含めsquid.confを変更します。

$ sudo vi /etc/squid/squid.conf
#
# Recommended minimum configuration:
#
# ローカルネットワークからのアクセスを許可
acl localnet src 10.0.0.0/8	# RFC1918 possible internal network

# ポート80、443以外のHTTP通信を拒否する
acl Safe_ports port 80		# http
acl Safe_ports port 443		# https
http_access deny !Safe_ports

# SSLの場合、ポート443以外のHTTP通信を拒否する
acl SSL_ports port 443		# https      
acl CONNECT method CONNECT
http_access deny CONNECT !SSL_ports

# ローカルホストからのcachemgrのアクセスのみを許可する
http_access allow manager localhost
http_access deny manager

# ローカルホストからのアクセスを許可する
http_access allow localhost

# ローカルネットワーク以外からのアクセスを拒否する
http_access deny !localnet

# ホワイトリストに定義したドメインからのアクセスを許可する
acl whitelist dstdomain "/etc/squid/whitelist"
http_access allow whitelist

# これまで定義した以外のアクセスはすべて拒否する
http_access deny all

# Squidのリッスンポート(デフォルトは3128)
http_port 8080

# コアダンプ出力ディレクトリ
coredump_dir /var/spool/squid

# キャッシュ保存期間の設定(デフォルト)
refresh_pattern ^ftp:		1440	20%	10080
refresh_pattern ^gopher:	1440	0%	1440
refresh_pattern -i (/cgi-bin/|\?) 0	0%	0
refresh_pattern .		0	20%	4320

# 外部にプロキシのホスト名を非表示にする
visible_hostname unknown

# access.logのフォーマット(ローカル時間 送信元IP リクエストステータス レスポンスサイズ リクエストメソッド リクエストURL ユーザ名 階層コード コンテンツタイプ)
logformat squid %tl %>a %Ss/%03>Hs %<st %rm %ru %[un %Sh/%<a %mt

squidを再起動してsquid.confを反映します。

$ sudo systemctl restart squid

squidの起動を確認します。

$ ps -ef |grep squid
root      3403     1  0 04:39 ?        00:00:00 /usr/sbin/squid -f /etc/squid/squid.conf
squid     3405  3403  1 04:39 ?        00:00:00 (squid-1) -f /etc/squid/squid.conf
squid     3406  3405  0 04:39 ?        00:00:00 (logfile-daemon) /var/log/squid/access.log
ec2-user  3414  3276  0 04:40 pts/0    00:00:00 grep --color=auto squid

$ nc -l -p 8080
Ncat: bind to :::8080: Address already in use. QUITTING.

aptで利用するプロキシを設定する

aptを実行したいUbuntuインスタンスでの作業です。/etc/apt/apt.confを作成し、プロキシを指定します。

$ sudo vi /etc/apt/apt.conf
Acquire::http::Proxy "http://プロキシのIP:8080";
Acquire::https::Proxy "http://プロキシのIP:8080";

試しにapt updateしてみます。

$ sudo apt update

この時点ではまだconnection timed out が出力してupdateできません。

ホワイトリストを設定する

Ubuntuインスタンスのデフォルトのリポジトリリストを確認する

Ubuntuインスタンスでの作業です。/etc/apt/sources.listを確認して、リポジトリのURLを確認します。

$ cat /etc/apt/sources.list |grep -v ^#
deb http://ap-northeast-1.ec2.archive.ubuntu.com/ubuntu/ bionic main restricted
deb-src http://ap-northeast-1.ec2.archive.ubuntu.com/ubuntu/ bionic main restricted

deb http://ap-northeast-1.ec2.archive.ubuntu.com/ubuntu/ bionic-updates main restricted
deb-src http://ap-northeast-1.ec2.archive.ubuntu.com/ubuntu/ bionic-updates main restricted

deb http://ap-northeast-1.ec2.archive.ubuntu.com/ubuntu/ bionic universe
deb-src http://ap-northeast-1.ec2.archive.ubuntu.com/ubuntu/ bionic universe
deb http://ap-northeast-1.ec2.archive.ubuntu.com/ubuntu/ bionic-updates universe
deb-src http://ap-northeast-1.ec2.archive.ubuntu.com/ubuntu/ bionic-updates universe

deb http://ap-northeast-1.ec2.archive.ubuntu.com/ubuntu/ bionic multiverse
deb-src http://ap-northeast-1.ec2.archive.ubuntu.com/ubuntu/ bionic multiverse
deb http://ap-northeast-1.ec2.archive.ubuntu.com/ubuntu/ bionic-updates multiverse
deb-src http://ap-northeast-1.ec2.archive.ubuntu.com/ubuntu/ bionic-updates multiverse

deb http://ap-northeast-1.ec2.archive.ubuntu.com/ubuntu/ bionic-backports main restricted universe multiverse
deb-src http://ap-northeast-1.ec2.archive.ubuntu.com/ubuntu/ bionic-backports main restricted universe multiverse

deb http://security.ubuntu.com/ubuntu bionic-security main restricted
deb-src http://security.ubuntu.com/ubuntu bionic-security main restricted
deb http://security.ubuntu.com/ubuntu bionic-security universe
deb-src http://security.ubuntu.com/ubuntu bionic-security universe
deb http://security.ubuntu.com/ubuntu bionic-security multiverse
deb-src http://security.ubuntu.com/ubuntu bionic-security multiverse

複数行出力されますが、次の2つのURLを指定していることが分かります。

  • http://ap-northeast-1.ec2.archive.ubuntu.com
  • http://security.ubuntu.com

これらをホワイトリストに登録します。

ホワイトリストにリポジトリを登録する

プロキシインスタンスでの作業です。/etc/squid/whitelistを作成し、先程の2つのURLのドメインを記載します。

$ sudo vi /etc/squid/whitelist
ap-northeast-1.ec2.archive.ubuntu.com
security.ubuntu.com

次に、squidを再起動および起動確認をします。

$ sudo systemctl restart squid

$ ps -ef |grep squid
root      3403     1  0 04:39 ?        00:00:00 /usr/sbin/squid -f /etc/squid/squid.conf
squid     3405  3403  1 04:39 ?        00:00:00 (squid-1) -f /etc/squid/squid.conf
squid     3406  3405  0 04:39 ?        00:00:00 (logfile-daemon) /var/log/squid/access.log
ec2-user  3414  3276  0 04:40 pts/0    00:00:00 grep --color=auto squid

$ nc -l -p 8080
Ncat: bind to :::8080: Address already in use. QUITTING.

動作確認

いよいよ動作確認です。Ubuntuインスタンス上でsudo apt updateを実行します。

$ sudo apt update
(省略)

出力が長いので省略しますが、今度は成功します。

pip3でパッケージインストールする際に利用するURLをホワイトリストに追加する

ここではpip3を利用してbash_kernelのインストールを想定し、プロキシを利用する方法とホワイトリストへの追加方法を紹介します。

プロキシを設定する

まずは、pip3を実行するUbuntuインスタンスで.bashrcの末尾にhttps_proxyhttp_proxyの環境変数を設定します。

$ vi ~/.bashrc
(省略)
export https_proxy="http://プロキシのIP:8080"
export http_proxy="http://プロキシのIP:8080"

ホワイトリストを追加する

ホワイトリストを設定していない状態でpip3 install bash_kernelを実行します。 ProxyErrorが出力されインストールすることができないことを確認できます。

$ pip3 install bash_kernel
(省略)
pip._vendor.requests.exceptions.ProxyError: HTTPSConnectionPool(host='pypi.python.org', port=443): Max retries exceeded with url: /simple/bash-kernel/ (Caused by ProxyError('Cannot connect to proxy.', OSError('Tunnel connection failed: 403 Forbidden',)))

つぎに、プロキシインスタンスでSquidのアクセスログを確認して、ホワイトリストに追加するURLを特定します。

$ sudo tail -f /var/log/squid/access.log
18/Mar/2019:02:47:16 +0000 10.10.21.106 TCP_DENIED/403 3767 CONNECT pypi.python.org:443 - HIER_NONE/- text/html
18/Mar/2019:02:47:16 +0000 10.10.21.106 TCP_DENIED/403 3767 CONNECT pypi.python.org:443 - HIER_NONE/- text/html
18/Mar/2019:02:47:16 +0000 10.10.21.106 TCP_DENIED/403 3767 CONNECT pypi.python.org:443 - HIER_NONE/- text/html
18/Mar/2019:02:47:17 +0000 10.10.21.106 TCP_DENIED/403 3767 CONNECT pypi.python.org:443 - HIER_NONE/- text/html
18/Mar/2019:02:47:19 +0000 10.10.21.106 TCP_DENIED/403 3767 CONNECT pypi.python.org:443 - HIER_NONE/- text/html
18/Mar/2019:02:47:23 +0000 10.10.21.106 TCP_DENIED/403 3767 CONNECT pypi.python.org:443 - HIER_NONE/- text/html

リクエストURLをホワイトリストに追加した後、ホワイトリストを読み込むために、Squidを再起動します。 上記ログではpypi.python.orgだけ出力していますが、ホワイトリストに追加した後で再度pip3 install bash_kernelを実行するとpypi.orgfiles.pythonhosted.orgが必要であることが分かります。

$ sudo vi /etc/squid/whitelist
ap-northeast-1.ec2.archive.ubuntu.com
security.ubuntu.com
bootstrap.pypa.io
pypi.python.org
pypi.org
files.pythonhosted.org
$ sudo systemctl restart squid

以上で準備が整いました。再度、Ubuntuインスタンスでpip3 install bash_kernelを実行します。

$ pip3 install bash_kernel
Collecting bash_kernel
  Using cached https://files.pythonhosted.org/packages/93/7a/50edf4a05663429b4ca6e789a10fd3d1b581ec869a036b9d7d9ba1ffc34a/bash_kernel-0.7.1-py2.py3-none-any.whl
Collecting pexpect>=4.0 (from bash_kernel)
  Using cached https://files.pythonhosted.org/packages/89/e6/b5a1de8b0cc4e07ca1b305a4fcc3f9806025c1b651ea302646341222f88b/pexpect-4.6.0-py2.py3-none-any.whl
Collecting ptyprocess>=0.5 (from pexpect>=4.0->bash_kernel)
  Using cached https://files.pythonhosted.org/packages/d1/29/605c2cc68a9992d18dada28206eeada56ea4bd07a239669da41674648b6f/ptyprocess-0.6.0-py2.py3-none-any.whl
Installing collected packages: ptyprocess, pexpect, bash-kernel
Successfully installed bash-kernel-0.7.1 pexpect-4.6.0 ptyprocess-0.6.0

無事bash_kernelをインストールすることができました。

ハマったこと

http_access allow whitelisthttp_access deny allよりも下に記述したため、プロキシを通じた接続ができませんでした。 全ての通信を拒否するルールの下にホワイトリストによる通信の許可ルールを意味がありません。 当然と言われればそれまでなのですが、squid.confに記載されている順序で設定が優先されることに気づくまでに時間が掛かってしまいました。

おわりに

本エントリがどなたかのお役に立てれば幸いです。