Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
0
Help us understand the problem. What is going on with this article?
@hmatsu47

AMI をアカウント跨ぎで(他リージョンへ)スケジュールコピーする Lambda 関数

More than 1 year has passed since last update.

以前、AMIを他リージョンへスケジュールコピーするLambda関数という記事を書きましたが、それをアカウントを跨いで実行するためのものです。

ポイント

  • コピー対象の AMI 全てにコピー先のアカウントに対するアクセス権を付与する
  • コピー元アカウントの KMS キーを利用できるようにコピー先で作成する Lambda 関数のロールに必要なポリシーを付与する
  • コピー先アカウントからはコピー元のタグは不可視なので、別項目(「説明」:description)をキーにしてコピー対象を絞り込む

なお、今回は、

  • AMI のアクセス権付与はコピー元アカウントで
  • AMI コピーはコピー先アカウントで

それぞれ実行するための Lambda 関数を作成します。

※前回同様、コピー元の AMI は KMS カスタマー管理キーで暗号化されているものとします(デフォルトキー=AWS マネージドキーは不可)。

作業内容

1. コピー元アカウントで KMS キーにキーユーザーを登録

AMI 暗号化のために使っている KMS カスタマー管理キーに対して、

  • 4. の Lambda 関数で利用するロール(キーユーザーとして)
    • 前回記事「1. ロール作成」と同じ要領で作成。面倒なら 4. の Lambda 関数作成時に合わせて作成して KMS カスタマー管理キーに追加する。↓の 2. も同様。
  • コピー先アカウント(アカウント ID)

を追加します。

2. コピー先アカウントで KMS カスタマー管理キーを作成してキーユーザーを登録

カスタマー管理キーを作成し、キーユーザーとして 5. の Lambda 関数で利用するロールを追加します。

3. コピー先アカウントでポリシーを登録

コピー元アカウントの KMS カスタマー管理キーを使えるように、コピー先アカウントに以下のポリシーを登録します。

ポリシー登録
{ 
    "Version": "2012-10-17", 
    "Statement": [ 
        { 
            "Sid": "AllowUseOfCMK", 
            "Effect": "Allow", 
            "Action": [ 
                "kms:Encrypt", 
                "kms:Decrypt", 
                "kms:ReEncrypt*", 
                "kms:GenerateDataKey*", 
                "kms:DescribeKey" 
            ], 
            "Resource": "arn:aws:kms:ap-northeast-1:【コピー元アカウントID】:key/XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX" 
        }, 
        { 
            "Sid": "AllowUseofCMKToCreateEncryptedResources", 
            "Effect": "Allow", 
            "Action": "kms:CreateGrant", 
            "Resource": "arn:aws:kms:ap-northeast-1:【コピー元アカウントID】:key/XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX", 
            "Condition": { 
                "Bool": { 
                    "kms:GrantIsForAWSResource": true 
                } 
            } 
        } 
    ] 
}

※「key/」の後ろにはコピー元 AMI の暗号化に使う KMS カスタマー管理キーの ID を入力します。

登録したら、2. の KMS カスタマー管理キーのキーユーザーとして登録した Lambda 関数のロールにこのポリシーを追加で付与します。

4. コピー元アカウントで AMI アクセス権付与のための Lambda 関数を作成

Python 3.7 で以下のコードを登録します。

AMIアクセス権付与
import boto3 
import os 

def lambda_handler(event, context): 
    region = os.environ["REGION"] 
    tagKey = os.environ["TAG_KEY"] 
    owner  = os.environ["OWNER"] 
    share  = os.environ["SHARE"] 

    # 変更対象のイメージを抽出 
    client = boto3.client('ec2', region) 
    images = client.describe_images( 
        Filters=[{'Name':'tag-key','Values':[tagKey]}], 
        Owners=[owner] 
    ) 

    # 変更対象イメージがあれば変更実行 
    for image in images['Images']: 
        modifyKey = image['ImageId'] 
        print("Modifying Image Attribute '{}'.".format(modifyKey)) 
        client.modify_image_attribute( 
            ImageId=modifyKey, 
            LaunchPermission={'Add':[{'UserId':share}]} 
        ) 
        for snapshot in image['BlockDeviceMappings']: 
            client.modify_snapshot_attribute( 
                CreateVolumePermission={'Add':[{'UserId':share}]}, 
                SnapshotId=snapshot['Ebs']['SnapshotId'] 
            ) 

環境変数等は以下のように入力します。
attr-change.png

なお、AMI の抽出対応を 5. と同様に「説明」(description)にしたい場合は 5. を参考にコードを書き替えてください。

テストしてみてうまく動作したら、必要に応じて CloudWatch イベントの cron 式で定時実行をセットします。

5. コピー先アカウントで AMI コピーを行う Lambda 関数を作成

Python 3.7 で以下のコードを登録します。

AMIコピー
import boto3 
import os 

def lambda_handler(event, context): 
    sourceRegion = os.environ["SOURCE_REGION"] 
    destRegion = os.environ["DEST_REGION"] 
    sourceDescription = os.environ["SOURCE_DESCRIPTION"] 
    destTagKey = os.environ["DEST_TAG_KEY"] 
    owner = os.environ["OWNER"] 
    encryptKey = os.environ["ENCRYPT_KEY"] 

    # コピー対象のイメージを抽出 
    sourceClient = boto3.client('ec2', sourceRegion) 
    sourceImages = sourceClient.describe_images( 
        Filters=[{'Name':'description','Values':[sourceDescription]}], 
        Owners=[owner] 
    ) 

    # 削除対象のイメージを抽出 
    destClient = boto3.client('ec2', destRegion) 
    deleteImages = destClient.describe_images( 
        Filters=[{'Name':'tag-key','Values':[destTagKey]}], 
        Owners=[owner] 
    ) 

    # コピー対象イメージがあればコピー実行 
    for sourceImage in sourceImages['Images']: 
        copyKey = sourceImage['ImageId'] 
        print("Copying Image '{}' to {}.".format(copyKey, destRegion)) 
        new_ami = destClient.copy_image( 
            DryRun=False, 
            SourceRegion=sourceRegion, 
            SourceImageId=copyKey, 
            Name=sourceImage['Name'], 
            Description='', 
            Encrypted=True, 
            KmsKeyId=encryptKey 
            ) 
        destClient.create_tags(Resources=[new_ami['ImageId']], Tags=[{'Key':destTagKey,'Value':''}]) 

    # 削除対象イメージがあれば削除実行 
    for deleteImage in deleteImages['Images']: 
        deleteKey = deleteImage['ImageId'] 
        print("Deleting Image '{}' from {}.".format(deleteKey, destRegion)) 
        try: 
            destClient.deregister_image(ImageId=deleteKey) 
            for snapshot in deleteImage['BlockDeviceMappings']: 
                destClient.delete_snapshot(SnapshotId=snapshot['Ebs']['SnapshotId'], DryRun=False) 
        except destClient.exceptions.NoSuchEntityException: 
            print("Image '{}' not found.".format(deleteKey)) 

環境変数等は以下のように入力します。
attr-copy.png

※コピー対象の AMI の絞り込みには以下の項目を使います。
attr-ami.png

テストしてみてうまく動作したら、必要に応じて CloudWatch イベントの cron 式で定時実行をセットします(4. の 10 ~ 15 分程度後の時間を指定)。

その他

以前、一度にコピーできる AMI の数は 25 個だった気がするのですが、最近実行してみたところ 50 個まで同時にコピーできるようになっていました。

0
Help us understand the problem. What is going on with this article?
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
hmatsu47
名古屋で士業向けWebサービスのインフラ構築管理、たまにアプリケーション開発をやっています。 業務利用しているもの、個人研究など、気長にのんびり投稿していきます。ニッチ狙いが多めです。 IPA RISS(001158)・NW・DB/日商・大商2級コレクター?(簿記・ビジネス法務・ビジネス会計)。
infra-workshop
インフラ技術を勉強したい人たちのためのオンライン勉強会です

Comments

No comments
Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account Login
0
Help us understand the problem. What is going on with this article?