【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アドレスホワイトリスト
    • カンマ区切りのIPアドレスのリストを環境変数の値として登録します(実装例では"ENV_IP_LIST")
    • 例: xxx.xxx.xxx.xxx,yyy.yyy.yyyy.yyyy,zzz.zzz.zzz.zzz・・・

実装例

ポイントは"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エンドポイント選択して、アクションから開けます。)

f:id:wingfair:20210116120006p:plain
クライアント接続ハンドラ設定画面

参考にしたページ

以上。