SquidでHTTPS対応な透過的Proxyを構築する

http及びhttpsの通信を透過的に処理するProxyをAWS上に構築します。
https通信を透過的にproxyするには、一度通信の復号化が必要なため、Squidの「ssl-dump」機能を利用します。
本構成では、機能検証のため冗長性等は考慮していません。本番利用する場合には注意してください。

透過的プロキシの仕組みは以下の記事がすごく参考になりました。 milestone-of-se.nesuke.com

環境

  • Amazon Linux2
  • Squid : 3.5.20

手順

Squid導入

squidのインストールと自動起動設定をします。

yum install squid -y 
systemctl enable squid

ssl-dump用証明書作成

opensslで自己証明書を作成します。

openssl req -new -newkey rsa:2048 -sha256 -days 3650 -nodes -x509 -extensions v3_ca -keyout <秘密鍵の出力先>.pem -out <証明書の出力先>.cer 

パケットフォワーディングを有効

NATを有効化するためにパケットフォワーディングを有効化します。

echo 1 > /proc/sys/net/ipv4/ip_forward

Iptables 設定

Squidにきたhttp/httpsをSquidの待ち受けポートにポート変換します。(Squidの設定は後ほど)

  • 80 ⇒ 3128
  • 443 ⇒ 3129
iptables -t nat -A PREROUTING -i eth0 -p tcp -m tcp --dport 80 -j REDIRECT --to-ports 3128
iptables -t nat -A PREROUTING -i eth0 -p tcp -m tcp --dport 443 -j REDIRECT --to-ports 3129

iptablesの設定はOSの再起動でリセットされてしまうので、永続化します。

yum install iptables-services
iptables-save > /etc/sysconfig/iptables

Squidファイルの修正

HTTP/HTTPSの透過的Proxyモードを有効化します。
https_port のssl-dumpの設定(cer=xxx,key=xxx)で先ほど作成した自己証明書のPathを指定します。

</etc/squid/squid.conf>
#
# Recommended minimum configuration:
#

# Example rule allowing access from your local networks.
# Adapt to list your (internal) IP networks from where browsing
# should be allowed
acl localnet src 10.0.0.0/8     # RFC1918 possible internal network
acl localnet src 172.16.0.0/12  # RFC1918 possible internal network
acl localnet src 192.168.0.0/16 # RFC1918 possible internal network
acl localnet src fc00::/7       # RFC 4193 local private network range
acl localnet src fe80::/10      # RFC 4291 link-local (directly plugged) machines

acl SSL_ports port 443
acl Safe_ports port 80          # http
acl Safe_ports port 21          # ftp
acl Safe_ports port 443         # https
acl Safe_ports port 70          # gopher
acl Safe_ports port 210         # wais
acl Safe_ports port 1025-65535  # unregistered ports
acl Safe_ports port 280         # http-mgmt
acl Safe_ports port 488         # gss-http
acl Safe_ports port 591         # filemaker
acl Safe_ports port 777         # multiling http
acl CONNECT method CONNECT

#
# Recommended minimum Access Permission configuration:
#
# Deny requests to certain unsafe ports
http_access deny !Safe_ports

# Deny CONNECT to other than secure SSL ports
http_access deny CONNECT !SSL_ports

# Only allow cachemgr access from localhost
http_access allow localhost manager
http_access deny manager

# We strongly recommend the following be uncommented to protect innocent
# web applications running on the proxy server who think the only
# one who can access services on "localhost" is a local user
#http_access deny to_localhost

#
# INSERT YOUR OWN RULE(S) HERE TO ALLOW ACCESS FROM YOUR CLIENTS
#

# Example rule allowing access from your local networks.
# Adapt localnet in the ACL section to list your (internal) IP networks
# from where browsing should be allowed
http_access allow localnet
http_access allow localhost

# And finally deny all other access to this proxy
http_access deny all

# Squid normally listens to port 3128
http_port 3128 intercept ###HTTPアクセス用 Tranceparentモードの有効化
https_port 3129 intercept ssl-bump cert=xxx.cer key=xxx.pem   ###HTTPSアクセス用 Tranceparentモードの有効化&ssldumpの有効化


# Uncomment and adjust the following to add a disk cache directory.
#cache_dir ufs /var/spool/squid 100 16 256

# Leave coredumps in the first cache dir
coredump_dir /var/spool/squid

#
# Add any of your own refresh_pattern entries above these.
#
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

設定変更したらSquidを再起動します。

systemctl restart squid

Source/Destチェックの無効化(AWSコンソール上)

AWSコンソール上で、Squidを起動しているEC2の Source/Destチェックを無効化します。
f:id:ykoomaru:20191212231613p:plain

ルートテーブルの修正(AWSコンソール上)

デフォルトゲートウェイをSquidが起動しているEC2のENIに向けます。
この設定をすることで、インターネット向きの通信が全てProxyサーバーを経由するようになります。

f:id:ykoomaru:20191212231815p:plain

通信テスト

デフォルトゲートウェイをProxyサーバーへ向けたサブネット上に、テスト用のEC2を起動し通信テストします。

http

特にプロキシを指定していませんが、問題なくHTMLを取得できています。

# curl http://www.google.com
<!doctype html><html itemscope="" itemtype="http://schema.org/WebPage" lang="ja"><head><meta content="&#19990;&#30028;&#20013;&#12398;&#12354;&#12425;&#12422;&#12427;&#2477
3;&#22577;&#12434;&#26908;&#32034;&#12377;&#12427;&#12383;&#12417;&#12398;&#12484;&#12540;&#12523;&#12434;&#25552;&#20379;&#12375;&#12390;&#12356;&#12414;&#12377;&#12290;&#12373;&#12414;&#12374;&#12414;&#12394;&#26908;&#32034;&#27231;&#33021;&#12434;&#27963;&#29992;&#12375;&#12390;&#12289;&#12362;&#25506;&#12375;&#12398;&#24773;&#22577;&#12434;&#35211;&#12388;&#12369;&#12390;&#12367;&#12384;&#12373;&#12356;&#12290;" name="description"><meta content="noodp" name="robots"><meta content="text/html; charset=UTF-8"http-equiv="Content-Type"><meta content="/images/branding/googleg/1x/googleg_standard_color_128dp.png" itemprop="image"><title>Google</title><script nonce="F1AzvU4PXx3yUsGHOKjBKw==">(function(){window.google=
<省略> 

https

証明書チェックあり

proxyで設定した自己証明書が原因でエラーとなります。(tlsを復号化しているので、中間攻撃と同じなため)

# curl https://www.google.com
curl: (60) SSL certificate problem: self signed certificate
More details here: https://curl.haxx.se/docs/sslcerts.html

curl failed to verify the legitimacy of the server and therefore could not
establish a secure connection to it. To learn more about this situation and
how to fix it, please visit the web page mentioned above.

証明書チェックなし

エラーを回避するためには、証明書チェックを外します。 curlの場合は、 -k オプションつけます。
証明書チェックを外した場合は、HTMLが取得できます。

# curl https://www.google.com -k
<!doctype html><html itemscope="" itemtype="http://schema.org/WebPage" lang="ja"><head><meta content="&#19990;&#30028;&#20013;&#12398;&#12354;&#12425;&#12422;&#12427;&#24773;&#22577;&#12434;&#26908;&#32034;&#12377;&#12427;&#12383;&#12417;&#12398;&#12484;&#12540;&#12523;&#12434;&#25552;&#20379;&#12375;&#12390;&#12356;&#12414;&#12377;&#12290;&#12373;&#12414;&#12374;&#12414;&#12394;&#26908;&#32034;&#27231;&#33021;&#12434;&#27963;&#29992;&#12375;&#12390;&#12289;&#12362;&#25506;&#12375;&#12398;&#24773;&#22577;&#12434;&#35211;&#12388;&#12369;&#12390;&#12367;&#12384;&#12373;&#12356;&#12290;" name="description"><meta content="noodp" name="robots"><meta content="text/html; charset=UTF-8"http-equiv="Content-Type"><meta content="/images/branding/googleg/1x/googleg_standard_color_128dp.png" itemprop="image"><title>Google</title><script nonce="tnfQ1aqNu90PTVnC7FS3wg==">(function(){window.google=

<省略>

AWS CLI (https)

証明書チェックあり

AWS CLI実行時も同様で、証明書のエラーがでます。

# aws ec2 describe-instances

SSL validation failed for https://ec2.ap-northeast-1.amazonaws.com/ [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed (_ssl.c:727)

証明書チェックなし

AWS CLI に --no-verify オプションを追加すると証明書エラーを回避できます。

#  aws ec2 describe-instances --no-verify
/usr/lib/python2.7/site-packages/urllib3/connectionpool.py:847: InsecureRequestWarning: Unverified HTTPS request is being made. Adding certificate verification is stronglyadvised. See: https://urllib3.readthedocs.io/en/latest/advanced-usage.html#ssl-warnings
  InsecureRequestWarning)
{
    "Reservations": [
        {
            "Instances": [

<省略>

最後に

AWS上では普段あまりやらない構成ですが、どなたかの参考になれば幸いです。 本番利用を見据えて冗長化やメンテナンス性を考慮するのであれば、TransitGateway + PaloAltoとかの構成のほうが良いのかなと思いました。 (本稿の構成だと、Squidの冗長化とかルートテーブルの修正とかつらそうなので...)

以下参考情報です。
GitHub - PaloAltoNetworks/TransitGatewayDeployment: Creates a Transit Gateway with two server VPCs and a security VPC

https://github.com/PaloAltoNetworks/TransitGatewayDeployment/raw/master/Documentation/images/TransitGateway.png