見出し画像

akippaインフラ改善物語 Vol.1

前回から始めた、akippaのインフラ(AWS)を改善していく物語の1回目です。

前回がVol.1で今回をVol.2とすべきだったのですが、前回のタイトルにつけ忘れてしまっていたので今回をVol.1として綴っていきます。
大抵のプログラミング言語でも、配列のインデックスは0からなので問題ないでしょう。(Lua?知らない子だねぇ)

前回からのアップデート

シリーズ化は「akippaのエンジニアリングを知ってもらう」という最大の目的があるのですが、他にも「シリーズ化を宣言する事で、進捗させないわけにはいかなくなる」という、自分への適度なプレッシャーも目的としています。

というわけで、現在は最初に掲げた「AWSアカウントの分割」を進めている真っ最中です。

AWSアカウントの分割

現状構成を再掲しますが、1つのAWSアカウント内でVPCによるisolationが実現されている状態です。これを、AWSも強く推奨しているアカウント単位のisolationへスイッチさせる事がファーストステップです。

現状構成

具体的には、本番環境のみ現行AWSアカウントに残し、開発環境を別のAWSアカウントへ移行させる作戦です。

「開発環境」とひと括りにしたものの、ここには複数の環境(開発環境・検証環境…etc)が内在するため、できればそれぞれの環境ごとでAWSアカウントを分けたいところです。

しかしながら、そこまで分割するにはデプロイフローの見直しなど影響範囲が大きくなってしまうため、まずは「本番とそれ以外」という単位で分割することにしました。

また、アカウントを分割するとトレードオフになるのが「アカウント管理の手間」です。

ここはついでにAWS Organizationsをしれっと導入したいところなのですが、運用コストとの天秤で今回は断念し、「ジャンプアカウント + スイッチロール」作戦を採用しました。

目指す構成

移行対象のリソース

akippaのシステムアークテクチャはオーソドックスなWebアプリケーション構成をとっているので、移行対象リソースはほぼ以下に集約されます。

  • EC2(+ALB)

  • RDS(Aurora)

  • S3

  • Route53

リソースだけ眺めると単純な移行に見えますが、実際に取り組み始めると、AWSそのものの知見不足や、把握し切れていなかった構成意図や背景などがあり、当然ハマります。ハマりました。

ハマったポイント

それぞれでハマったポイントと、どうやって解決したのか?というtipsです。どこかの誰かの参考になれば幸いです。

暗号化されたEBSスナップショットの共有

EC2を移行したい場合は、対象インスタンスからAMIでEBSのスナップショットを作成し、スナップショットを移行先アカウントへ共有すればOKです。

しかしながら、akippaのEBSは本番環境以外も原則KMS(Key Management Service)キーで暗号化されています。

セキュリティという観点ではとても良いことですが、この状態で移行先アカウントが共有されたスナップショットからインスタンスを作成しようとすると、キーを利用した復号に失敗するためインスタンスが作成できません。

KMSキーも移行先アカウントと共有してしまえば解決なのですが、本番用途で利用しているキーですので、一時的とはいえキーポリシーを変更する事は避けたいです。

手間はかかりますが、以下のようなアプローチで対応することとしました。

  1. 現行アカウントで新しいCMK(Customer Managed Key)を作成する

    1. 移行用途のみで利用するため、移行完了後に削除する前提です

  2. 作成したキーが移行先アカウントでも利用可能なポリシーを定義する

  3. 既存のキーで暗号化されているスナップショットをコピーする

    1. コピー時の暗号化設定で、1.のKMSキーを指定します

  4. コピーされたスナップショットを移行先アカウントと共有します

アカウント間でKMSキーを共有するポリシーは、以下のようになります。

{
    "Sid": "Allow use of the key with target account",
    "Effect": "Allow",
    "Principal": {
        "AWS": "arn:aws:iam::xxxxxxxxxxxx:role/some-role"
    },
    "Action": [
        "kms:DescribeKey",
        "kms:CreateGrant",
        "kms:ReEncryptFrom"
    ],
    "Resource": "*"
}

S3バケットのクロスアカウントコピー

現在のAWS運用は「コンソールから可能な操作はコンソールで」としているため、バケット間のオブジェクトコピーもAWSコンソールから行うこととしました。具体的な手順は、以下を参考にさせていただきました。

上記手順でコピーそのものは出来たのですが、コピー後のオブジェクト所有者変更が期待どおりに変更できないケースに遭遇しました。

  1. うまく行ったケース

    1. コピー完了後、ACLを無効にしてオブジェクト所有者をバケット所有者に強制

    2. 再度ACLを有効にして、オブジェクト所有者をオブジェクトライターに指定

    3. バケット内のオブジェクトは新しいアカウントが所有者になっている

  2. うまく行かなかったケース

    1. うまく行ったケースの2.を実行すると、オブジェクト所有者がコピー元アカウントに戻ってしまう

バケットのACLを無効にしてしまえば良いのですが、まずは出来る限り移行前と同じ状態・設定を担保したいところです。

2023年4月からS3バケットのデフォルトセキュリティ設定が変更される、という情報をキャッチしていたので、その影響も考えましたが、バケットを作ったのが3月だっため関連は無さそうです。

1.と2.に1ヶ月ほどのブランクがあったため、手順の違いや設定差分を自分の作業記録から確認しましたが、どうにも差分が見当たりません。無限に時間を溶かしそうな予感がしてきたので、潔くCLIでコピーする作戦に切り替えました。

コピー元のIAMロールに追加したポリシーです。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "s3:ListBucket",
                "s3:GetObject"
            ],
            "Resource": [
                "arn:aws:s3:::SRC_BUCKET_NAME",
                "arn:aws:s3:::SRC_BUCKET_NAME/*"
            ]
        },
        {
            "Effect": "Allow",
            "Action": [
                "s3:ListBucket",
                "s3:PutObject",
                "s3:PutObjectAcl"
            ],
            "Resource": [
                "arn:aws:s3:::DST_BUCKET_NAME",
                "arn:aws:s3:::DST_BUCKET_NAME/*"
            ]
        }
    ]
}

コピー先S3バケットに追加したポリシーです。

{
    "Effect": "Allow",
    "Principal": {
        "AWS": "arn:aws:iam::xxxxxxxxxxxx:role/some-role"
    },
    "Action": [
        "s3:PutObject",
        "s3:PutObjectAcl"
    ],
    "Resource": [
        "arn:aws:s3:::TARGET_BUCKET/*",
        "arn:aws:s3:::TARGET_BUCKET"
    ],
    "Condition": {
        "StringEquals": {
            "s3:x-amz-acl": "bucket-owner-full-control"
        }
    }
},
{
    "Effect": "Allow",
    "Principal": {
        "AWS": "arn:aws:iam::xxxxxxxxxxxx:role/some-role"
    },
    "Action": "s3:ListBucket",
    "Resource": [
        "arn:aws:s3:::TARGET_BUCKET/*",
        "arn:aws:s3:::TARGET_BUCKET"
    ]
}

コピー先バケットはACL無効の状態で問題ないため、CloudShellからsyncします。

aws s3 sync s3://SRC_BUCKET/dir s3://DST_BUCKET/dir --acl bucket-owner-full-control

今までの試行錯誤は何だったんだ?というくらいスムーズにコピーが完了しました。ACLを有効にしても、オブジェクト所有者はコピー先アカウントのままです。CLI万歳。

他にもハマったポイントはあるのですが、それは次回に持ち越したいと思います。次回までには「アカウント分割が完了したぞ!」とお伝えできるよう、引き続き地道な改善を積み重ねていきます。


この記事が気に入ったらサポートをしてみませんか?