0
0

More than 1 year has passed since last update.

特定のCIDR範囲のVPCをチェックする

Posted at

はじめに

VPCが特定のCIDR範囲かどうかをチェックする方法を作ってみましたので記事にしました。

概要

以下の2つを作りました。

  • 作成済みのVPCのCIDR範囲をチェックするコマンド
    • 全リージョンを一度にチェック
  • "(作成済み・今後作成される)VPCのCIDR範囲をチェックするAWS Config"を作成するCFnテンプレート
    • リージョンごと
      • 複数のリージョンに設定するには、StackSetsなどを用いると良いと思います

きっかけ

以下のツイートポストを見かけたのがきっかけでした。

公式では以下になります。

そのため今回は"172.17.0.0/16"っぽい範囲をチェックする仕組みを作ってみました。

CIDRを評価する式は適当なので適宜変えてください。

参考

やったこと

事前準備

まずはNGなVPCを、以下のCFnテンプレートを用いて作成します。

createNgVpc.yaml
AWSTemplateFormatVersion: '2010-09-09'
Parameters:
  VpcCIDRBlock:
    Type: String
    Default: 172.17.0.0/16
  VpcName:
    Type: String
    Default: NgVpc
Resources:
  NgVPC:
    Type: AWS::EC2::VPC
    Properties:
      CidrBlock: !Ref VpcCIDRBlock
      Tags:
        - Key: Name
          Value: !Ref VpcName

チェックコマンド

チェックするコマンドとして、以下を作りました。CloudShellで実行できます。

regions=(`aws ec2 describe-regions --query Regions[*].RegionName --output text`)

for region in ${regions[@]}
do echo "[${region}]"
aws ec2 describe-vpcs --query 'Vpcs[].[{Name:Tags[?Key==`Name`].Value|[0],CIDR:CidrBlock}]' --output text --region ${region} | grep '^172.17.'
echo "---------------------"
done

以下のように出力されます。

クリックで表示
[ap-south-1]
---------------------
[eu-north-1]
---------------------
[eu-west-3]
---------------------
[eu-west-2]
---------------------
[eu-west-1]
---------------------
[ap-northeast-3]
172.17.0.0/16   NgVpc
---------------------
[ap-northeast-2]
---------------------
[ap-northeast-1]
---------------------
[ca-central-1]
---------------------
[sa-east-1]
---------------------
[ap-southeast-1]
---------------------
[ap-southeast-2]
---------------------
[eu-central-1]
---------------------
[us-east-1]
172.17.0.0/16   NgVpc
---------------------
[us-east-2]
---------------------
[us-west-1]
---------------------
[us-west-2]
---------------------

AWS Configを作るCFnテンプレート

まずは以前の記事を参考に、以下リソースを作ります。

  • S3
  • IAMロール
  • レコーダー
    • VPCのみレコード対象
  • 配信チャンネル
クリックで表示

S3のDeletionPolicyはわざと無効化しています。

createConfigRule.yaml
AWSTemplateFormatVersion: 2010-09-09

Resources:
  BucketForDeliveryChannel:
    Type: AWS::S3::Bucket
    # DeletionPolicy: Retain

  RoleForConfigRecorder:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
          - Effect: Allow
            Principal:
              Service:
                - config.amazonaws.com
            Action:
              - sts:AssumeRole
      ManagedPolicyArns:
        - arn:aws:iam::aws:policy/service-role/AWS_ConfigRole
      Policies:
        # 配信先への書き込み権限
        - PolicyName: ConfigPolicy
          PolicyDocument:
            Version: 2012-10-17
            Statement:
              - Effect: Allow
                Action:
                  - s3:PutObject*
                Resource:
                  - !Sub arn:aws:s3:::${BucketForDeliveryChannel}/*
                Condition:
                  StringLike:
                    s3:x-amz-acl: bucket-owner-full-control

  ConfigRecorder:
    Type: AWS::Config::ConfigurationRecorder
    Properties:
      RoleARN: !GetAtt RoleForConfigRecorder.Arn
      RecordingGroup:
        # https://docs.aws.amazon.com/ja_jp/config/latest/developerguide/resource-config-reference.html
        ResourceTypes:
          - AWS::EC2::VPC
    DependsOn: 
      - BucketForDeliveryChannel
      - RoleForConfigRecorder

  ConfigDeliveryChannel:
    Type: AWS::Config::DeliveryChannel
    Properties:
      S3BucketName: !Ref BucketForDeliveryChannel
    DependsOn: 
      - BucketForDeliveryChannel
      - RoleForConfigRecorder

次はルールを作成します。AWSマネージドルールには、今回に使えそうなルールがなかったので、Lambdaを作りそれを使います。

公式の例を参考に、LambdaにアタッチするIAMロールや、Lambdaのログ出力先のロググループ作成も加えています。

またNode.jsは、(Lambdaで使える最新の)18ではエラーになってしまったので、16を使っています。

クリックで表示
createConfigRule.yaml
AWSTemplateFormatVersion: 2010-09-09

Resources:
  LambdaExecutionRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: '2012-10-17'
        Statement:
          - Effect: Allow
            Principal:
              Service: lambda.amazonaws.com
            Action: sts:AssumeRole
      ManagedPolicyArns:
        - arn:aws:iam::aws:policy/service-role/AWSConfigRulesExecutionRole
      Policies:
        # CloudWatch
        - PolicyName: write-cloudwatchlogs
          PolicyDocument:
            Version: '2012-10-17'
            Statement:
              - Effect: Allow
                Action: 
                  - 'logs:CreateLogStream'
                  - 'logs:PutLogEvents'
                Resource: !Sub "arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/lambda/*"

  ConfigPermissionToCallLambda: 
    Type: AWS::Lambda::Permission
    Properties: 
      FunctionName: 
        Fn::GetAtt: 
          - VolumeAutoEnableIOComplianceCheck
          - Arn
      Action: "lambda:InvokeFunction"
      Principal: "config.amazonaws.com"
      SourceAccount: !Ref 'AWS::AccountId'
  VolumeAutoEnableIOComplianceCheck: 
    Type: AWS::Lambda::Function
    Properties: 
      Code: 
        ZipFile: 
          !Sub |
            var aws  = require('aws-sdk');
            var config = new aws.ConfigService();
            var ec2 = new aws.EC2();
            exports.handler = function(event, context) {
                compliance = evaluateCompliance(event, function(compliance, event) {
                      var configurationItem = JSON.parse(event.invokingEvent).configurationItem;
                      var putEvaluationsRequest = {
                          Evaluations: [{
                              ComplianceResourceType: configurationItem.resourceType,
                              ComplianceResourceId: configurationItem.resourceId,
                              ComplianceType: compliance,
                              OrderingTimestamp: configurationItem.configurationItemCaptureTime
                          }],
                          ResultToken: event.resultToken
                      };
                      config.putEvaluations(putEvaluationsRequest, function(err, data) {
                          if (err) context.fail(err);
                          else context.succeed(data);
                      });
                  });
              };
              function evaluateCompliance(event, doReturn) {
                  var configurationItem = JSON.parse(event.invokingEvent).configurationItem;
                  if (configurationItem.resourceType !== 'AWS::EC2::VPC')
                      doReturn('NOT_APPLICABLE', event);
                  else if ( (configurationItem.configuration.cidrBlock).indexOf("172.17.") === 0 )
                      doReturn('NON_COMPLIANT', event);
                  else
                      doReturn('COMPLIANT', event);
              }
      Handler: "index.handler"
      Runtime: nodejs16.x
      Timeout: 30
      Role: 
        Fn::GetAtt: 
          - LambdaExecutionRole
          - Arn
  ConfigRuleForVolumeAutoEnableIO: 
    Type: AWS::Config::ConfigRule
    Properties: 
      Source: 
        Owner: "CUSTOM_LAMBDA"
        SourceDetails: 
          - 
            EventSource: "aws.config"
            MessageType: "ConfigurationItemChangeNotification"
        SourceIdentifier: 
          Fn::GetAtt: 
            - VolumeAutoEnableIOComplianceCheck
            - Arn
    DependsOn: ConfigPermissionToCallLambda

  FunctionLogGroup:
    Type: AWS::Logs::LogGroup
    Properties:
      LogGroupName: !Sub "/aws/lambda/${VolumeAutoEnableIOComplianceCheck}"
      RetentionInDays: 3653

作成後、評価が終わると、非準拠の旨が表示されます。

image.png

片付け

CFnテンプレートで作成しているので、スタックの削除でリソースはなくなります。S3バケットは中にファイルがありますので、バケットを空にしてから削除する必要があります。

おわりに

AWS Configは以前少し触ってみたことがありましたが、今回はルールをLambdaで作成するところまでやってみました。以前は設計図と呼ばれるものがあったようですが、現在ではその方法はなくなっていたので結構手間取りました。
この記事がどなたかのお役に立てれば幸いです。

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