はじめに
VPCが特定のCIDR範囲かどうかをチェックする方法を作ってみましたので記事にしました。
概要
以下の2つを作りました。
- 作成済みのVPCのCIDR範囲をチェックするコマンド
- 全リージョンを一度にチェック
- "(作成済み・今後作成される)VPCのCIDR範囲をチェックするAWS Config"を作成するCFnテンプレート
- リージョンごと
- 複数のリージョンに設定するには、StackSetsなどを用いると良いと思います
- リージョンごと
きっかけ
以下のツイートポストを見かけたのがきっかけでした。
公式では以下になります。
そのため今回は"172.17.0.0/16"っぽい範囲をチェックする仕組みを作ってみました。
CIDRを評価する式は適当なので適宜変えてください。
参考
やったこと
事前準備
まずはNGなVPCを、以下のCFnテンプレートを用いて作成します。
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はわざと無効化しています。
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を使っています。
クリックで表示
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
作成後、評価が終わると、非準拠の旨が表示されます。
片付け
CFnテンプレートで作成しているので、スタックの削除でリソースはなくなります。S3バケットは中にファイルがありますので、バケットを空にしてから削除する必要があります。
おわりに
AWS Configは以前少し触ってみたことがありましたが、今回はルールをLambdaで作成するところまでやってみました。以前は設計図と呼ばれるものがあったようですが、現在ではその方法はなくなっていたので結構手間取りました。
この記事がどなたかのお役に立てれば幸いです。