LoginSignup
2
0

More than 1 year has passed since last update.

【AWS】Ownerタグに非準拠のリソースに作成者のユーザー名を自動で割り当てたい!

Last updated at Posted at 2023-03-01

AWS Configとは

AWS Config は、AWS リソースの設定を評価、監査、審査できるサービスです。Config では、AWS リソースの設定が継続的にモニタリングおよび記録され、望まれる設定に対する記録された設定の評価を自動的に実行できます。Config を使用すると、AWS リソース間の設定や関連性の変更を確認し、詳細なリソース設定履歴を調べ、社内ガイドラインで指定された設定に対する全体的なコンプライアンスを確認できます。これにより、コンプライアンス監査、セキュリティ分析、変更管理、運用上のトラブルシューティングを簡素化できます。

Configルールを使用することで、指定の設定に準拠しているかどうかを評価できます。

Configルールでタグ非準拠を修正する

Configルールに修復アクションを使用することもできますが、SSMドキュメントの書き方に慣れ親しんでいないので、Lambdaで日次で非準拠リソースを取得して修正する形にします!

Configルールの作成

まずはConfigルールを作成します。
今回はOwnerタグをつけていないVPCを評価するルールを作成します。

図3.png

AWSマネージドルールのrequired-tagsを選択します。

conf000001.JPG

適当な名前を付け、トリガーのリソースにVPCを設定します。
パラメータにはタグキーに「Owner」があるかどうかを評価したいので、tag1KeyにOwnerを設定します。
conf000002.JPG
conf000003.JPG
conf000005.JPG

Lambdaの作成

マネジメントコンソールからLambdaを開き、関数を作成します。

image.png

設定項目
関数名 なんでもいいです
ランタイム Python3.9
IAMロール 下記のポリシーが付与されたものをつけてあげてください

IAMロールに必要なポリシー

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "VisualEditor0",
            "Effect": "Allow",
            "Action": [
                "cloudtrail:LookupEvents",
                "config:GetComplianceDetailsByConfigRule",
                "config:GetResourceConfigHistory",
                "tag:TagResources"
            ],
            "Resource": "*"
        }
    ]
}

関数が作成出来たら下記のコードに置き換えて、保存します。
Configルール名は変更してください。
細かくは解説しませんが、非準拠リソースの一覧を取ってきて、そのリソースのイベントの中で最も古いイベントを行った人のユーザー名をOwnerタグの値に設定しています。
したがって、90日以上前に作成されたリソースに関してはタグ付けできません。
(証跡からAthena使ってクエリしたらできると思うので、やりたい方いたら!)
また、副次的にできてしまうリソース、例えば、TGWのアタッチメントを作成した際にできるENIやCloudFormationで作成されたリソースについては、ユーザーがサービス名になるので値もそのCFNを作成したユーザーを入れてくれはしないので、注意が必要です。

import boto3

def get_create_user(resource):
    client = boto3.client('cloudtrail')
    events = []
    response = client.lookup_events(
        LookupAttributes=[
            {
                'AttributeKey': 'ResourceName',
                'AttributeValue': resource
            },
        ]
    )
    events.extend(response['Events'])
    while 'NextToken' in response:
        response = client.lookup_events(
            LookupAttributes=[
                {
                    'AttributeKey': 'ResourceName',
                    'AttributeValue': resource
                },
            ],
            NextToken = response['NextToken']
        )
        events.extend(response['Events'])
    sorted_events = sorted(events, key = lambda x: x['EventTime'])
    oldest_event = sorted_events[0]
    return oldest_event['Username']
    
def set_owner_tag(resource, user):
    client = boto3.client('resourcegroupstaggingapi')
    tags = {
        'Owner' : user
    }
    print(tags)
    try:
        response = client.tag_resources(ResourceARNList = [resource], Tags = tags)
        print('Success {}'.format(resource))
        return True
    except Exception as e:
        raise e
        
def list_non_compliant_resources(rule_name):
    client = boto3.client('config')
    results = []
    response = client.get_compliance_details_by_config_rule(
        ConfigRuleName=rule_name,
        ComplianceTypes=[
            'NON_COMPLIANT'
        ]
    )
    results.extend(response['EvaluationResults'])
    while 'NextToken' in response:
        response = boto3.get_compliance_details_by_config_rule(
            ConfigRuleName=rule_name,
            ComplianceTypes=[
                'NON_COMPLIANT'
            ],
            NextToken = response['NextToken']
        )
        results.extend(response['EvaluationResults'])
    return results
    
def get_resource_arn(resource_id, resource_type):
    client = session.client('config')
    response = client.get_resource_config_history(
        resourceType=resource_type,
        resourceId=resource_id
    )
    return response['configurationItems'][0]['arn']
    
def lambda_handler(event, context):
    results = list_non_compliant_resources('Configルール名')
    for result in results:
        try:
            resource_type = result['EvaluationResultIdentifier']['EvaluationResultQualifier']['ResourceType']
            resource_id = result['EvaluationResultIdentifier']['EvaluationResultQualifier']['ResourceId']
            if not resource_id.startswith('arn'):
                arn = get_resource_arn(resource_id, resource_type)
            else:
                arn = resource_id
            owner = get_create_user(resource_id)
            set_owner_tag(arn, owner)
        except Exception as e:
            print(e)

ここまで出来たら、手動で実行してもよし、EventBridgeで定期的に実行してもよし!です!

まとめ

今回は、検証環境でありがちなOwnerタグのつけ忘れを防止するために、いろいろやってみました!
個人的にはかなり欲しいものだったので、もっとこういうやり方あるよ!って方いたら教えてください!!
少しでもこれで緩和されたらいいな…

読んでいただき、ありがとうございました!

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