0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

ひろ亭Advent Calendar 2021

Day 10

AWS CLIで Web サイトを構築、管理、運用する(10日目)

Last updated at Posted at 2021-12-09

ついに10日目!!!!!
正直ここまで続けられるとは思いませんでした。。

というわけで、予告通り、セキュリティ周りいってみましょ。

今後、静的サイトに加えて動的コンテンツを入れていく予定なので 今回は Web Application Firewall (WAF) を導入します。

AWS では、 AWS WAF というサービスが用意されています。なぜか、Cloudfront のコンソールでは Amazon WAF という表記だったりしますが・・・

さて、やっていきましょ!

10日目の要約

WAFをつかうよ!

AWS CLI の準備

このあたりをみて、好きなバージョンとお使いのOSにあった環境設定をしてくださいね。
なんなら、 AWS CloudShell で実行するのも楽でよいと思います。
この記事シリーズは、AWS CloudShell で実行し、実行例を載せています。

バージョン1
https://docs.aws.amazon.com/ja_jp/cli/latest/userguide/install-cliv1.html

バージョン2
https://docs.aws.amazon.com/ja_jp/cli/latest/userguide/install-cliv2.html

概要

AWS WAF の設定を行い、 WebACL をCloudFront と関連づけてセキュリティ向上させるよ!

さあ、やってみよう!

AWS WAF の WebACL に関連づけるマネージドルールを json ファイルにまとめよう

AWS WAF のルールは AWS が用意している マネージドルールというものがあります。さらにその中には無償で使える基本パック的なルールが存在します。
今回は、そのルールを3つピックアップして json ファイルで用意しておきます。
対象のルールは以下の通りです。

名前 ルールの管理名 説明
Anonymous IP list AWS-AWSManagedRulesAnonymousIpList このグループには、viewer IDの難読化を許可するサービスからのリクエストをブロックできるルールが含まれています。これには、VPN、プロキシ、Torノード、およびホスティングプロバイダーから発信されたリクエストが含まれる場合があります。これは、アプリケーションからIDを隠そうとしている可能性のあるビューアを除外する場合に役立ちます。
Core rule set AWS-AWSManagedRulesCommonRuleSet Webアプリケーションに一般的に適用できるルールが含まれています。これにより、OWASPの出版物に記載されている脆弱性を含む、さまざまな脆弱性の悪用に対する保護が提供されます。
Known bad inputs AWS-AWSManagedRulesKnownBadInputsRuleSet 無効であることがわかっており、脆弱性の悪用または発見に関連するリクエストパターンをブロックできるルールが含まれています。これにより、悪意のある攻撃者が脆弱なアプリケーションを発見するリスクを減らすことができます。
Linux operating system AWS-AWSManagedRulesLinuxRuleSet LFI攻撃など、Linuxに固有の脆弱性の悪用に関連するリクエストパターンをブロックするルールが含まれています。これにより、ファイルの内容を公開したり、攻撃者がアクセスしてはならないコードを実行したりする攻撃を防ぐことができます。

以下のように、json ファイルを作ります。

waf_rules.json
[
            {
                "Name": "AWS-AWSManagedRulesCommonRuleSet",
                "Priority": 0,
                "Statement": {
                    "ManagedRuleGroupStatement": {
                        "VendorName": "AWS",
                        "Name": "AWSManagedRulesCommonRuleSet"
                    }
                },
                "OverrideAction": {
                    "None": {}
                },
                "VisibilityConfig": {
                    "SampledRequestsEnabled": true,
                    "CloudWatchMetricsEnabled": true,
                    "MetricName": "AWS-AWSManagedRulesCommonRuleSet"
                }
            },
            {
                "Name": "AWS-AWSManagedRulesLinuxRuleSet",
                "Priority": 1,
                "Statement": {
                    "ManagedRuleGroupStatement": {
                        "VendorName": "AWS",
                        "Name": "AWSManagedRulesLinuxRuleSet"
                    }
                },
                "OverrideAction": {
                    "None": {}
                },
                "VisibilityConfig": {
                    "SampledRequestsEnabled": true,
                    "CloudWatchMetricsEnabled": true,
                    "MetricName": "AWS-AWSManagedRulesLinuxRuleSet"
                }
            },
            {
                "Name": "AWS-AWSManagedRulesKnownBadInputsRuleSet",
                "Priority": 1,
                "Statement": {
                    "ManagedRuleGroupStatement": {
                        "VendorName": "AWS",
                        "Name": "AWSManagedRulesKnownBadInputsRuleSet"
                    }
                },
                "OverrideAction": {
                    "None": {}
                },
                "VisibilityConfig": {
                    "SampledRequestsEnabled": true,
                    "CloudWatchMetricsEnabled": true,
                    "MetricName": "AWS-AWSManagedRulesKnownBadInputsRuleSet”
                }
            },
            {
                "Name": "AWS-AWSManagedRulesAnonymousIpList",
                "Priority": 1,
                "Statement": {
                    "ManagedRuleGroupStatement": {
                        "VendorName": "AWS",
                        "Name": "AWSManagedRulesAnonymousIpList"
                    }
                },
                "OverrideAction": {
                    "None": {}
                },
                "VisibilityConfig": {
                    "SampledRequestsEnabled": true,
                    "CloudWatchMetricsEnabled": true,
                    "MetricName": "AWS-AWSManagedRulesAnonymousIpList”
                }
            }
        ]

ファイルが作成できたら、以下のように wafv2 create-webacl コマンドを実行して WebACL を作成します。

aws wafv2 create-web-acl --name waf --scope=CLOUDFRONT \
--region us-east-1 --default-action "Allow={}"  \
--visibility-config SampledRequestsEnabled=true,CloudWatchMetricsEnabled=true,MetricName=waf  \
--rules file://waf_rules.json

正常に実行できたら、以下のようなレスポンスが返ります。

{
    "Summary": {
        "Name": "waf",
        "Id": "********-***-****-****-************",
        "Description": "",
        "LockToken": "********-***-****-****-************",
        "ARN": "arn:aws:wafv2:us-east-1:************:global/webacl/waf/********-***-****-****-************"
    }
}

これで、ルールが紐づいている WebACL が作成できました。
上記の ARN の値を用いて、 CloudFront の設定をここ数日と同様に変更します。

CloudFront の設定変更を準備する

やはり、基本的には、6日目で実施したものと似た内容です。

cloudfront get-distribution-config コマンドで現状の設定を取得する
ETag の値を確認する
取得した json ファイルに対して、設定変更を加える
cloudfront update-distribution コマンドを実行して更新する
この記事では、3と4についてのみ記載します。1と2の実施内容については、6日目の記事をご確認ください。

取得した json ファイルに対して設定変更を加える

WebACL を設定する箇所については、以下のようになっていると思います。

"WebACLId": "",

この WebACLId に対して、作成した WebACL の ARN を指定します。

"WebACLId": "arn:aws:wafv2:us-east-1:************:global/webacl/waf/********-***-****-****-************"

cloudfront update-distribution コマンドを実行して更新する

準備ができたら、6日目と同様に cloudfront update-distribution コマンドを実行して、設定変更を行います。

aws cloudfront update-distribution --id <CloudFront Distribution ID> ¥
--cli-input-json file://distribution_webacl.json ¥
--if-match 確認したETag の値

コマンド実行に成功すると、Distribution の内容が記された json が返されます。
やはり長いので割愛します。

動作確認

いつもどおり CloudShell から curl コマンドを実行します。

curl https://<ドメイン名>/

するとどうでしょう。HTTP403が返ってきます!

<!DOCTYPE html>
<html lang="ja">
<meta charset="UTF-8">
<head>
  <title>えらーです m9('ω')</title>
</head>
<body>
  <h1>残念〜!</h1>
  <h2>アクセスできませーん!</h2>
</body>
</html>

おそらくですが、CloudShell の機能が「Anonymous IP list」ルールに抵触しているのかとおもいます(個人の感想です)

これだと今後の動作確認に支障が出かねないので、curl 実行時は ローカル環境(Macbook Pro(macOS 12.0.1))から実施します。

では、改めて・・・

curl https://<ドメイン名>/

ローカル側では問題なく 正常に index.html の内容が返ってきました。

<html lang="ja">
<head>
  <title>Advent calendar 2021</title>
</head>
<body>
  <h1>Hello world!!</h1>
  <h2>Advent calendar 2021 DAY 3</h2>
</body>
</html>

ちなみに Core rule set には UserAgent の設定がされていない(NoUserAgent_HEADER)というルールが存在します。なので、以下のように UserAgent が設定されていない状態で curl をローカル側で実行すると弾かれるようになります。

curl https://ドメイン名/ -A ""
<!DOCTYPE html>
<html lang="ja">
<meta charset="UTF-8">
<head>
  <title>えらーです m9('ω')</title>
</head>
<body>
  <h1>残念〜!</h1>
  <h2>アクセスできませーん!</h2>
</body>
</html>

まとめ

CloudShell が Anonymous IP list ルールでブロックされるっぽい(?)ことに驚きですが、AWS WAF が動作しているという証左にもなりますね💦💦

ということで、 AWS WAF を導入し、セキュリティ向上につなげられたのではないかと思います。

  • 今回使ったコマンド
  • wafv2 create-web-acl
  • (cloudfront get-distribution-config)
  • cloudfront update-distribution
0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?