2
0

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 1 year has passed since last update.

レートリミットをAWS CDK でやってみた(WAF使用)

Last updated at Posted at 2023-01-31
1 / 10

レートリミットとは

レートリミットとは、リソースの過剰使用やサービス拒否攻撃を防ぐために使用されます。
サーバーへのリクエストの頻度を制御し、特定の時間内にクライアントやIPアドレスからのリクエスト数を制限するために使用されます。

今回はIPアドレスベースでの制限になります。


背景

最近ではポケモン徹底攻略さんのサイトが大量リクエストで落とされるなど、DDos攻撃対策も必要ですね。


基本的に、サーバーサイドを使用するときは、Nestjsを使用していて、Nestjsでの実装方法もあります。
ですがサーバーサイドで実装すると、

  • オリジンにリクエストは届くので、サーバーサイドがスケールしてマシーンリソースを食ってしまう(リソース割きたくない)
  • 実装するには、Redisなどを用意して、IPアドレスを保存する仕組みが必要

以上を考えると、サーバーサイドにリクエストが届くよりも前段のほうでレートリミットかけたほうがいいので
今回はALBにアタッチします。場合によっては、cloudfrontにもアタッチできると思います。


参考

クラスメソッドさんで紹介されている、AWS WAF を使用した方法を、AWS CDKのコードに落としてみました。


環境

"typescript": "~4.9.4"
"aws-cdk": "2.60.0",

コード

carbon (1).png

rate-limit-construct.ts
rate-limit-construct.ts
import { ApplicationLoadBalancer } from 'aws-cdk-lib/aws-elasticloadbalancingv2';
import { CfnWebACL, CfnWebACLAssociation } from 'aws-cdk-lib/aws-wafv2';
import { Construct } from 'constructs';

export interface RateLimitConstructProps {
  limit?: number;
  immunityTime?: number;
  searchString?: string;
}

export class RateLimitConstruct extends Construct {
  public acl: CfnWebACL;

  constructor(scope: Construct, id: string, props?: RateLimitConstructProps) {
    super(scope, id);

    const aggregateKeyType = 'IP';
    const nonPriority = 0;
    const minLimit = 100; // See https://docs.aws.amazon.com/ja_jp/waf/latest/developerguide/limits.html
    const minImmunityTime = 300; // See https://docs.aws.amazon.com/ja_jp/waf/latest/APIReference/API_ImmunityTimeProperty.html

    const limit = props?.limit ?? minLimit;
    const immunityTime = props?.immunityTime ?? minImmunityTime;
    const searchString = props?.searchString ?? '/';
    const RuleAction = { Allow: { allow: {} }, Block: { block: {} } };
    const visibilityConfig = {
      metricName: `target:${searchString}`,
      sampledRequestsEnabled: true,
      cloudWatchMetricsEnabled: true,
    };

    this.acl = new CfnWebACL(this, CfnWebACL.name, {
      name: 'PcmStgRateLimit',
      defaultAction: RuleAction.Allow,
      scope: 'REGIONAL',
      visibilityConfig,
      challengeConfig: { immunityTimeProperty: { immunityTime } },
      description: `Limit ${aggregateKeyType} Base.Up to ${limit} Requests Per ${immunityTime} seconds`,
      rules: [
        {
          name: `${aggregateKeyType}BaseLimit${limit}Per${immunityTime}SecondsRule`,
          priority: nonPriority,
          action: RuleAction.Block,
          visibilityConfig,
          statement: {
            rateBasedStatement: {
              limit,
              aggregateKeyType,
              scopeDownStatement: {
                byteMatchStatement: {
                  fieldToMatch: { uriPath: {} },
                  positionalConstraint: 'STARTS_WITH',
                  searchString,
                  textTransformations: [
                    {
                      type: 'NONE',
                      priority: nonPriority,
                    },
                  ],
                },
              },
            },
          },
        },
      ],
    });
  }

  attachToALB(alb: ApplicationLoadBalancer, waf: CfnWebACL) {
    new CfnWebACLAssociation(this, `AttachToALB`, {
      resourceArn: alb.loadBalancerArn,
      webAclArn: waf.attrArn,
    });
  }
}

上記constructを使った例

carbon (2).png

sample-stack.ts
sample-stack.ts
import { RateLimitConstruct } from './rate-limit-construct';
import { ApplicationLoadBalancer } from 'aws-cdk-lib/aws-elasticloadbalancingv2';

const loadBalancer = new ApplicationLoadBalancer(this, ApplicationLoadBalancer.name, options);

const rateLimit = new RateLimitConstruct(this, RateLimitConstruct.name);

rateLimit.attachToALB(loadBalancer, rateLimit.acl);

  • ApplicationLoadBalancerを初期化するoptionsは適宜引数に渡してください。

参考

2
0
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
2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?