この記事はSpeee Advent Calendar 2019 1日目の記事です。
あらすじ
長い間AWSアカウントを運用していると、様々な理由で不要なリソースというものが生まれます。
- 長く運用されているアカウントで昔のリソースがIaCされていなくて使われなくなったリソースが残り続けていたり
- dev兼用だったりして不意に誰かの検証リソースが残っていたり
- などなど理由は様々です
使ってないリソースは消すに限ります。
本記事では、使ってないSecurityGroupをAWS Configを使って洗い出す方法をご紹介します。
AWS Config
AWS Configには様々な機能がありますが、機能の一つにAWSリソース間の依存関係をSQLライクなクエリで抽出する機能があります。
https://docs.aws.amazon.com/ja_jp/config/latest/developerguide/querying-AWS-resources.html
使ったことがない方向けに雰囲気を共有するためにAWS Configのサンプルクエリを一つ紹介します。
下記は使っていないEBSボリュームを抽出するクエリです。
SELECT
resourceId,
resourceType,
configuration.volumeType,
configuration.size,
resourceCreationTime,
tags,
configuration.encrypted,
configuration.availabilityZone,
configuration.state.value
WHERE
resourceType = 'AWS::EC2::Volume'
AND configuration.state.value <> 'in-use'
AWS ConfigのクエリはAWS Config用のデータのみを参照するのでFROM句は使いません。
基本的にSELECTとWHEREで欲しい情報の列と行を絞る感じになります。
JOINはサポートしていないけどGROUP BYはあります。HAVING BYはないです。
実際に使っていないSecurityGroupを抽出する方法
では実際に使っていないSecurityGroupを抽出していきます。
紹介するクエリはコンソールかCLIかSDKかなんらか方法で実行して下さい。
得られた結果を加工したりするので得意な言語のSDKがおすすめです。
Step1:他のAWSリソースから参照されているSecurityGroupを出す
まずは以下のクエリを実行します。
SELECT
relationships.resourceId
WHERE
resourceType != 'AWS::EC2::VPC' AND
relationships.resourceType = 'AWS::EC2::SecurityGroup'
GROUP BY
relationships.resourceId
このクエリを実行するとセキュリティグループを参照しているリソース(例えばELB)が参照しているリソース(例えばELBが参照しているVPC,SecurityGroup,Subnet)のID一覧を得ることができます。
ややこしいですね。
クエリを少し解説すると、WHERE句のrelationships.resourceType = 'AWS::EC2::SecurityGroup'
はSecurityGroupを参照しているAWSリソースを抽出しています。relationshipsというカラムにそのリソースが参照している依存関係の情報があります。
VPCを除いているのは、全てのSecurityGroupはVPCに紐付けられるのでVPCにしか参照されていない(つまり他から使われていない)SecurityGroupもクエリに含められてしまうからです。
GROUP BYは参照先のリソースIDで集約しています。
このクエリを実行するとSecurityGroup以外にもVPCやSubnetのIDも含まれてしまうので、得られた結果のうちを sg-
から始まるidだけをスクリプトか何かで抽出します。
本当はHavingが使えればそこで絞れて良いのですが...
最終的にここで抽出されたSecurityGroupのIdは、何かのawsリソースから参照されているSecurityGroupの一覧になります。
Step2:他のAWSリソースから参照されていないSecurityGroupを出す
全SecurityGroup - 他のAWSリソースから参照されているSecurityGroup = 他のAWSリソースから参照されていないSecurityGroup
です。
以下のクエリを実行します。
SELECT
resourceId,
resourceName
WHERE
resourceType = 'AWS::EC2::SecurityGroup' AND
resourceId NOT IN (
'sg-xxxxxx',
'sg-yyyyyy',
'sg-zzzzzz',
...
)
IN句に入れるIDはstep1で抽出したIDになります。サブクエリとか使えると良いんですがね..
これで晴れて他のAWSリソースから参照されていないSecurityGroupの一覧が出せました。
Step3:SecurityGroupのルールで参照されているSecurityGroupを除く
もう一つ考慮するケースがあって他のSecurityGroupのsrcやdestに指定されているSecurityGroupは消すことができません。
なのでSecurityGroupのルールとして使われているSecurityGroupを除きます。
Step2:で得られたSecurityGroupIdに対して何らスクリプトでループを回して各SecurityGroupIdに対して以下のクエリを実行します。
(この辺もうちょいいい感じでクエリ書けるかもしれません)
SELECT
*
WHERE
resourceType = 'AWS::EC2::SecurityGroup' AND (
configuration.ipPermissions.userIdGroupPairs.groupId = 'sg-xxxxxx'
OR
configuration.ipPermissionsEgress.userIdGroupPairs.groupId = 'sg-xxxxxx'
)
SELECTの結果が0ならどのSecurityGroupにも参照されていません。消せる候補です。
終わりに
以上のステップで使っていないSecurityGroupを洗い出すことができました。あとは一覧をチェックして消すのみです。一応消す前は人の目を挟んだ方がいいと思います。
不要なゴミは消して快適なAWS運用を実現しましょう!!