【AWSの呼吸 参ノ型】AWS Client VPNでIPアドレスを制限する方法
今回はAWS ClientVPNで、IPアドレスの制限を行う方法を書きたいと思います。
ClientVPNを使いたいけど、自社等のセキュリティポリシー的にアクセス元を制限しないと使えないという方はぜひ活用してみてください。
目次
やりたいこと
AWS ClientVPNに接続する際に接続元のIPアドレスが許可されたものでなければ、接続を拒否する。
IP制限を行う方法
- 2020年11月にサポートが開始されたクライアント接続ハンドラを使って実現します
- IP制限の処理をLambdaで実装し、クライアント接続ハンドラに割り当てます
- するとClientVPNエンドポイントに接続があった際にClientVPN側でLambdaを呼び出してチェックしてくれます
Lambda設定
まずはクライアント接続ハンドラに割り当てるためのLambda関数を作成します。
Lambda関数の作成
今回はこんな感じで作りました。
その他も利用中の環境に合わせてよしなに設定してください。
- ランタイム:Python 3.8
- トリガー:なし (ClientVPN側で割り当てれば指定する必要なし)
- VPC:なし
- IAMロール:自動生成されるもの
- 環境変数:許可したいIPアドレスのホワイトリスト
実装例
ポイントは"event['public-ip']"にClientVPNの接続元のIPアドレスが格納されてくるので、その値とホワイトリストを照合するところです。
照合した結果、許可されていれば"allow": にTrueを指定して、ClientVPN側に返却することで、ClientVPN側でその接続を許可してくれます。
また、今回の実装例では今後CIDRでホワイトリストを指定したくなるようなケースも見越して、ipaddressモジュールで実装してみました。 その方が単純な文字列での照合よりはIPアドレスの扱いに柔軟性が出てよいのかな思います。
import ipaddress import os def lambda_handler(event, context): # IPアドレスの判定フラグを初期化 # 許可:True / 拒否:False flag = False # 許可するIPアドレスのリストを環境変数から取得 allow_ip_list = [x.strip() for x in str(os.environ['ENV_IP_LIST']).split(',')] # 接続元のIPアドレスをClientVPNから取得 src_ip = ipaddress.ip_address(event['public-ip']) # 接続元IPが許可されているものかリストと照合 for ip in allow_ip_list: ip_nw = ipaddress.ip_network(ip) if src_ip in ip_nw: flag = True break else: flag = False # ClientVPNに結果を返却 return { "allow": bool(flag), "error-msg-on-failed-posture-compliance": "IP address is not allowed to access.", "posture-compliance-statuses": [], "schema-version": "v1" }
上記ではロギングとエラーハンドリングは割愛してます。
例えば、拒否したIPアドレスを後で把握できるようにログ出力しておくなどの実装はしておいた方がよいかもしれません。
クライアント接続ハンドラの設定
先ほど作成したLambdaをClientVPN側に設定します。
AWSマネージメントコンソールにて、[クライアント VPN エンドポイント] > [クライアント VPN エンドポイントの変更]を開きます。
([クライアント VPN エンドポイントの変更]は利用するクライアントVPNエンドポイント選択して、アクションから開けます。)
参考にしたページ
- [アップデート] 接続元 IP 制限もできるように! AWS Client VPN で クライアント接続ハンドラ機能がサポートされました | Developers.IO
- AWS SAMのLambda (Python)で環境変数で設定した値を配列で受け取る - Qiita
- ipaddress --- IPv4/IPv6 操作ライブラリ — Python 3.9.1 ドキュメント
- 特定のIPだけ許可したい時の判定方法 - thirose’s blog
- Connection authorization - AWS Client VPN
以上。