Network Firewallの マネージドルールグループのルールをルールグループにコピーするLambda関数作成

2023.03.30

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

こんにちは、イムチェジョンです。

アジェンダ

  1. 背景説明
  2. マネージドルールグループのコピー
  3. コピーしたルールグループの自動アップデートする方法
  4. 結果確認

1. 背景説明

Network Firewallは、ネットワークトラフィックを詳細に制御するファイアウォールルールを定義できるサービスです。
Network Firewallには、AWSが管理するルールグループであるマネージドルールグループ(managed rule group)があります。
マネージドルールグループを使用すると、ユーザーが別にルールグループを作らなくてもAWSに管理してアップデートするルールでネットワークトラフィックを検査できます。

しかし、特定の状況ではマネージドルールグループが使用できない場合があります。
マネージドルールグループが使用できない例は下記のサイトをご参考ください。

どうしてもマネージドルールグループを使用したい場合は、マネージドルールグループを複製してルールグループとして使用することができます。
マネージドルールグループは2つに分かれていますが、ドメインおよびIPルールグループは複製できないため使用できません。 (脅威署名ルールグループのみ可能)

ただし、複製して使用すると、マネージドルールグループがアップデートした時に複製したルールグループまでアップデートしてくれない短所はありません。
この場合はLmabda関数を通じてアップデートすることができるので、ブログでその内容についてまとめます。

2. マネージドルールグループのコピー

まずはマネージドルールグループをコピーします。

VPC ページでネットワークファイアウォールのNetwork Firewall のルールグループに移動します。
Network Firewall のルールグループでルールグループがユーザ定義したルールグループであり、マネージドルールグループがAWSで管理しているルールグループです。

マネージドルールグループのタグをクリックして 「脅威署名ルールグループ」でコピーしたいマネージドルールグループをクリックします。

次に、画面の右上の ルールグループを複製 ボタンをクリックします。

すると、ルールグループの作成ページが出ます。
ここでルール変数やIP セット参照の詳細設定も追加できます。
今回はテストのため名前だけ設定して作成します。
名前はマネージドルールグループと区別するために ThreatSignaturesBotnetActionOrder-copyで設定しました。

このようにコピーされたルールグループを確認できます。

テストのために複数のマネージドルールグループをコピーしました。

3. コピーしたルールグループの自動アップデートする方法

今回はアップデートを実行してみます。
アップデートの方法は下記になります。

マネージドルールグループがアップデート -> SNSを使用してLambdaに通知 -> Lambda関数の実行 -> ルールグループをアップデート

Lambda関数作成

まず、Lambda関数を作成します。
関数名は任意で作成して、ランタイムはPython 3.9を選択します。

すると、画面のようにLambda関数が作成されます。
関数の ARNが必要なので、どこかにコピーをしておきます。

SNSを使用してLambdaに通知

次にはマネージドルールグループがアップデートされた時に通知をもらうためにSNSサブスクリプションを作成します。

注意)マネージドルールグループのアップデートの通知はバージニア北部(us-east-1)リージョンに移動する設定する必要があります。

VPCのNetwork Firewall のルールグループでマネージドルールグループ(脅威署名ルールグループ)の中で一つをクリックします。

マネージドルールグループの Amazon SNS トピックARNをコピーしておきます。
そして ARN をクリックしてサブスクリプションの作成ページに移動します。

上でコピーしておいた情報を入力します。
トピック ARN : 上でコピーした Amazon SNS トピックARN
プロトコル : AWS Lambda
エンドポイント : 上でコピーした Lambda関数の ARN

入力できたらサブスクリプションを作成します。
すると、画面のようにSNSサブスクリプションが作成されたのを確認できます。

Lambda関数でもトリガーとしてSNSが追加されたのを確認できます。

サブスクリプションの作成が完了されたら、既存のリージョンに戻ります。

Lambda関数の実行

まず、コードを作成する前に必要な権限などの設定を行います。

まず、 設定アクセス権限 タグで実行ロールの ロール名をクリックします。

すると、Lambda関数に割り当てたIAMロールのページが出ます。
ここで許可を追加を押してポリシーをアタッチをクリックします。

追加する役割が下記になります。

追加する権限はIAMポリシーで作成しておきました。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "network-firewall:UpdateRuleGroup",
                "network-firewall:DescribeRuleGroup"
            ],
            "Resource": [
                "arn:aws:network-firewall:ap-northeast-1:111111111111:stateful-rulegroup/*"
            ]
        }
    ]
}

次には設定一般設定タグで編集をクリックします。

タイムアウトを 8秒で設定して保存します。

今からLambda関数コードを修正します。

import json
import boto3

client = boto3.client('network-firewall')

def lambda_handler(event, context):
    
    ## 入ってくる SNS イベントを確認
    print(event)
    
    ## アップデートされたマネージドルールグループを確認
    ManegerdRuleArn = event["Records"][0]["Sns"]["MessageAttributes"]["managed_arn"]["Value"].split('/')
    ManegerdRuleName = ManegerdRuleArn[1]
    print(ManegerdRuleName)
    
    ManegerdRuleRes = client.describe_rule_group(
    RuleGroupArn='arn:aws:network-firewall:ap-northeast-1:aws-managed:stateful-rulegroup/' + ManegerdRuleName,
    Type='STATEFUL'
    )
    
    MyRuleName = ManegerdRuleName + '-copy'
    
    ## アップデートするルールグループの情報取得
    ## もし、対象のルールグループがない場合にはアップデートをしないまま Skip を表示
    try:
        MyRuleRes = client.describe_rule_group(
        RuleGroupName=MyRuleName,
        Type='STATEFUL'
        )
    except:
        print("Skip")
        return "Skip Updates"
    
    RuleGroupName = MyRuleRes['RuleGroupResponse']['RuleGroupName']
    RulesString = ManegerdRuleRes["RuleGroup"]["RulesSource"]["RulesString"]
    UpdateToken = MyRuleRes["UpdateToken"]
    RuleGroupArn = MyRuleRes["RuleGroupResponse"]["RuleGroupArn"]
    
    ## アップデート実行
    ## 成功すれば True / 失敗すれば False
    result = update(RuleGroupName, RulesString, UpdateToken, RuleGroupArn)   
    
    return result
    
    
def update(RuleGroupName, RulesString, UpdateToken, RuleGroupArn):
    
    try:
        response = client.update_rule_group(
        UpdateToken=UpdateToken,
        RuleGroupArn=RuleGroupArn,
        RuleGroupName=RuleGroupName,
        RuleGroup={
            'RulesSource': {
                'RulesString': '#test4\n' + RulesString
                }
            }
        )
        print("Success")
        return True
    except:
        return False

Deployをします。

4. 結果確認

最後に結果を確認してみます。
モニタリング タグで View CloudWatch logs ボタンをクリックします。

ログストリームが出ますが、その中で結果をクリックして確認してみます。

成功した場合

成功した場合にはSNSから来るイベントを出力してそこでアップデートされたマネージドルールグループの名前を取得します。
今回のマネージドルールグループはルールグループとしてコピーされているので、アップデートを実行します。
結果的に成功した Success をログで出力してLambda関数を終了します。

スキップした場合

スキップする場合、イベントを出力して対象のマネージドルールグループの名前を取得します。
今回のマネージドルールグループはルールグループとしてコピーされてないので、アップデートを実行する必要がありません。
なので、ログに Skipを出力してLambda関数を終了します。