Evident.ioを使ってセキュリティオートメーションしてみた

Evident.ioのAuto Remediation機能を使って、EC2インスタンスにインターネットからのSSH通信が無制限(0.0.0.0/0)に開放されているセキュリティグループがアタッチされている場合、自動修復するセキュリティオートメーションを実現してみました。
2018.11.05

こんにちは、佐伯です。

Evident.ioにはAuto Remediationという機能があり、Evident.ioのAmazon SNSインテグレーションを使用して、セキュリティオートメーションを行うことができます。今回は公式ドキュメントに沿って、セキュリティオートメーションを設定してみました。

やってみた

今回試したセキュリティオートメーションは、「セキュリティグループが好ましくないEC2インスタンスを自動修復する」というものです。該当するセキュリティグループとして「インターネットからのSSH(22/TCP)が無制限(0.0.0.0/0)に開放されている」ものを対象にし、EC2インスタンスにアタッチされていた場合に自動修復を行います。

手順としては以下のドキュメントに沿った形になっています。

Auto Remediationの仕組み

Evident.ioのAuto Remediationは以下のような仕組みで動作します。

引用元: evident-automation/autoremediate/aws at master · PaloAltoNetworks/evident-automation

  • Evident.ioがAWS APIをコールして、AWS環境をモニタリング
  • シグネチャに違反するような設定が存在した場合、アラートをAmazon SNSに送信
  • Amazon SNSがAWS Lambdaを起動
  • AWS Lambdaで問題となる設定を修正

制限事項

Evident.ioではOrganization, Sub Organization, Teams, Usersという形で実際の組織構造に合わせた形でユーザー管理を行うことができます。外部アカウント(AWSアカウントやAzureアカウント)はひとつのチームに紐付ける形になります。

ひとつのチームに複数のAWSアカウントが紐づけられている場合、Amazon SNSインテグレーションの設定で複数の外部アカウント設定することができます。しかし、Evident.ioのアラートをAmazon SNSを介して修正を実行するAWS Lambdaと連携させます。そのため複数アカウントのアラートをひとつのAmazon SNSに送信しても、自アカウント以外では問題の修正はできません。また、ひとつのアラートに対してひとつのAWS Lambdaが実行されるように設定する必要があります。

複数アカウント対応については、AWS Lambdaの処理内でアカウントの判別を行いAssumeRoleをすれば実現できそうですが、複雑さが増しメンテナンスにコストがかかってしまうので、各アカウントに対応するAmazon SNSインテグレーションを作成したほうが良さそうです。複数アラートの対応についても同様で様々なパターンに対応するAWS Lambdaを作成するよりはアラートごとにAWS Lambdaを作ったほうがシンプルかと思います。

Amazon SNSインテグレーションの作成

Evident.ioでSNSインテグレーションの設定を行います。ドキュメントは以下となります。

Evident.ioの[Control Panel]->[Integrations]->[Amazon SNS]をクリックします。AWSで必要な設定の手順が記載されているので、手順に沿って設定を行います。

SNSトピックの作成

SNSインテグレーションを設定するためにAWSで、SNSトピックを作成します。サブスクリプションにはAmazon SNSインテグレーションの動作確認とAWS Lambdaを作成する際のデバッグ用に自身のメールアドレスを登録し、作成したSNSトピックからのメール送信を承認しておきましょう。

作成したSNSトピックのARNをEvident.io側に入力します。

IAMポリシーの作成

SNSPublishを許可するIAMポリシーを作成します。SNSトピックのARNを入力すると、コピペ用のポリシードキュメントに自動的にARNが入る形になっています。

IAMロールの作成

Evident.ioのAWSアカウントを信頼するIAMロールを作成します。信頼するAWSアカウントIDや外部IDについては、Evident.ioの画面に表示されているので、それをコピペしてIAMロールを作成し、作成したIAMロールのARNをEvident.io側に入力します。

外部アカウントとアラートタイプの選択

制限事項でも述べたようにひとつの外部アカウントのみを対象とします。アラートタイプは対象とするシグネチャによりけりだったりするのですが、今回はFailを選択します。

アラートの更新通知

今回はインターネットからのSSHが許可されているセキュリティグループを検知し、修正することが目的ですので、アラートの更新については通知しません。

シグネチャの選択

シグネチャはAmazon High Risk Signaturesの中からGlobal Admin Port Access - SSH (TCP Port 22) Detectedのみを選択します。このシグネチャのアラートを検知し、自動修正を行います。

なお、シグネチャの説明はこんな感じです。

監査ログの送信

こちらもセキュリティオートメーションには不要なオプションですので無効のままとします。以上の項目を入力し、SaveでAmazon SNSインテグレーションを作成します。何かエラーがあって作成に失敗した場合は外部IDが更新されていると思うので、IAMロールに設定した外部IDにEvident.io側を修正するか、IAMロール側の信頼関係を新たに生成された外部IDに設定し直してください。

Amazon SNSインテグレーションのテストと有効化

Amazon SNSインテグレーション作成後、Test and Activateで通知テストと有効化を行います。また、このタイミングで指定したシグネチャのアラートが通知されるか、AWS側の設定を変更してテストを行うことをおすすめします。

AWSの設定に問題なければAmazon SNSから以下のようなメールが届くかと思います。

アラート通知のテスト

ビルトインで用意されているシグネチャはルールの詳細が確認できないこともあり、どういった設定がアラートの対象となるのか実際にAWSの設定をシグネチャのアラート対象となるように変更して、アラートが通知されることを確認しておきましょう。

今回対象としたシグネチャGlobal Admin Port Access - SSH (TCP Port 22) Detectedであれば、シグネチャをコピーしてカスタムシグネチャとして利用できます。コピーしてカスタムシグネチャとして登録するとシグネチャのコードまで確認できるので、実際にコードを確認する方法もあります。

確認した結果、Global Admin Port Access - SSH (TCP Port 22) Detectedのシグネチャは、インターネットからのSSHが許可されているセキュリティグループがパブリックサブネット(インターネットゲートウェイがルートテーブルに存在)に配置されたEC2インスタンスにアタッチされてされている場合にFailになるということがわかりました。(たぶん)

AWS Lambdaの作成

さて、ここからAWS Lambdaを作っていきます。基本的には以下のGitHubリポジトリのソースを使わせていただきます。

イベントメッセージの確認

シグネチャGlobal Admin Port Access - SSH (TCP Port 22) Detectedでは以下のようなJSONメッセージが送信されました。各relationshipsにはEvident.ioの情報が入っており、作成するAWS Lambdaではこの情報は必要ないので削除させていただきました。

今回作成するAWS LambdaはGitHubリポジトリのソースそのままで動きましたが、うまく動作しない場合などイベントメッセージを見てデバッグする流れになります。事前にイベントメッセージを確認しておくことをおすすめします。

{
    "data": {
        "id": "1306879672",
        "type": "alerts",
        "attributes": {
            "created_at": "2018-11-05T03:57:05.000Z",
            "status": "fail",
            "risk_level": "high",
            "resource": "sg-xxxxxxxxxxxxxxxxx",
            "ended_reason": null,
            "replaced_by_id": null,
            "replaced_by_status": null,
            "updated_at": "2018-11-05T03:57:05.000Z",
            "started_at": "2018-11-05T03:57:05.000Z",
            "ended_at": null
        },
        "relationships": {}
    },
    "included": [
        {
            "id": "18511",
            "type": "external_accounts",
            "attributes": {
                "created_at": "2018-07-01T03:42:31.000Z",
                "name": "xxxxxxxxxxxx",
                "updated_at": "2018-11-04T08:32:57.000Z",
                "provider": "amazon",
                "arn": "arn:aws:iam::012345678910:role/Evident-Service-Role",
                "account": "012345678910",
                "external_id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
                "cloudtrail_name": "Evident-User-Attribution"
            },
            "relationships": {}
        },
        {
            "id": "1",
            "type": "regions",
            "attributes": {
                "code": "ap_northeast_1",
                "name": null,
                "created_at": "2014-06-05T23:42:37.000Z",
                "updated_at": "2014-06-05T23:42:37.000Z",
                "provider": "amazon"
            }
        },
        {
            "id": "34",
            "type": "signatures",
            "attributes": {
                "copyable": true,
                "created_at": "2014-06-05T23:43:30.000Z",
                "description": "Global permission to access the well known services TCP port 22 (SSH) should not be allowed in a security group.\n\n",
                "identifier": "AWS:EC2-002",
                "name": "Global Admin Port Access - SSH (TCP Port 22) Detected",
                "resolution": "Reduce the permitted IP Addresses or ranges allowed to communicate to destination hosts on TCP port 22.\n\nWe recommend utilizing the static office or home IP addresses of your employees as the permitted hosts, or deploying a bastion host with 2-factor authentication if this is infeasible. This bastion host becomes the only permitted IP to communicate with any other nodes inside your account.\n\nIf you must permit global access to TCP port 22 (SSH), then you may suppress this alert.  \n  \nFor more information on Ports, see [AWS: Ports.]( http://docs.aws.amazon.com/workspaces/latest/adminguide/client_ports.html)\n\n",
                "risk_level": "high",
                "supports_user_attribution": true,
                "updated_at": "2017-12-06T19:20:27.000Z"
            },
            "relationships": {}
        },
        {
            "id": "1305262756",
            "type": "metadata",
            "attributes": {
                "data": {
                    "details": {
                        "attachedEC2Instances": [
                            "i-xxxxxxxxxxxxxxxxx"
                        ],
                        "message": "Security Group security-automation-test has TCP port 22 exposed globally and an attached Instance has a public IP.",
                        "securityGroup": {
                            "description": "security-automation-test",
                            "groupId": "sg-xxxxxxxxxxxxxxxxx",
                            "groupName": "security-automation-test",
                            "ipPermissions": [
                                {
                                    "fromPort": 22,
                                    "ipProtocol": "tcp",
                                    "ipRanges": [
                                        "0.0.0.0/0"
                                    ],
                                    "ipv4Ranges": [
                                        {
                                            "cidrIp": "0.0.0.0/0",
                                            "description": null
                                        }
                                    ],
                                    "ipv6Ranges": [],
                                    "prefixListIds": [],
                                    "toPort": 22,
                                    "userIdGroupPairs": []
                                }
                            ],
                            "ipPermissionsEgress": [
                                {
                                    "fromPort": null,
                                    "ipProtocol": "-1",
                                    "ipRanges": [
                                        "0.0.0.0/0"
                                    ],
                                    "ipv4Ranges": [
                                        {
                                            "cidrIp": "0.0.0.0/0",
                                            "description": null
                                        }
                                    ],
                                    "ipv6Ranges": [],
                                    "prefixListIds": [],
                                    "toPort": null,
                                    "userIdGroupPairs": []
                                }
                            ],
                            "ownerId": "012345678910",
                            "tags": [],
                            "vpcId": "vpc-xxxxxxxx"
                        },
                        "tags": []
                    }
                }
            }
        }
    ]
}

AWS Lambda関数の作成

AWS Lambdaにセキュリティグループの設定を変更させるため、IAMロールを作成します。今回はAmazonEC2FullAccessポリシーとAWSLambdaBasicExecutionRoleポリシーをアタッチしたロールを作成しました。

コードはAWS_EC2_security_group_global_inbound_remediate.pyを使用します。

先程作成したIAMロールをアタッチし、AWS_EC2_security_group_global_inbound_remediate.pyをコピペしてLambda関数を作成します。

Lambda関数作成後にSNSトピックにAWS Lambdaへのサブスクリプションを作成します。

テスト

実際にパブリックサブネットに配置したEC2にインターネット(0.0.0.0/0)からのSSHが許可されているセキュリティグループをアタッチし、実際に動作するか確認してみましょう。セキュリティグループアタッチ後、しばらくするとCloudWatch Logsにログ出力があり...

セキュリティグループから該当するルールが削除されていました!

まとめ

今回はドキュメントに沿った形でセキュリティオートメーションを実現してみました。Evident.ioがAWSアカウントのモニタリングをしてくれて、アラートがあった場合AWS Lambdaへの連携までを行ってくれるので、比較的簡単にセキュリティオートメーションに取り組めるのではないでしょうか!

参考リンク