yuj1osm's tech blog

クラウドやセキュリティなど

Amazon CloudWatch Logsで機密データを保護できるようになりました

AWS re:Invent 2022が始まり、アップデートが増えてきました。
Amazon CloudWatch Logsで機密データを保護できるようになったようなので、検証してみました。

aws.amazon.com

アップデート概要

Amazon CloudWatch LogsはAWSが提供しているログ監視サービスです。
システムやアプリケーション、 AWSサービスからのログを一元化して監視することができ、検索や検知に活用できます。
今回はそのCloudWatch Logsに対して、データ保護ポリシーを適用することで、ログ中の機密データを検知して自動的にマスクできるようになりました。
HIPPA、GDPRPCI-DSSといった規制にも役立つ機能です。

以下がユーザガイドになります。

docs.aws.amazon.com

保護できるデータの種類は以下にまとまっており、本記事の執筆時点では日本語対応はしていないようです。

docs.aws.amazon.com

検証

機密データを検知させてみる

ロググループを作成します。

「アクション」から「Create data protection policy」を押下します。

プルダウンで保護対象を選択します。 「EmailAddress」と「Name」を選択してみました。

適当なログストリームを作成して、サンプルのメールアドレスを流してみます。

アスタリスクでマスクされていることを確認できました。

次に氏名を流してみましたが、日本語氏名はマスクされないようです。

※アンマスクしたもの(アンマスク方法は後述)

機密データとして検知すると、警告表示が出ます。

「Data protection」というタブが追加されており、検知数を確認できます。

アンマスクしてみる

「Display」から「Temporarily unmask protection data」を押下するとアンマスクできます。

ただし「logs:Unmask」権限が必要なので、権限が無いと以下のようにエラーになります。
「ReadOnlyAccess」でもアンマスクはできませんでした。

IAMユーザに以下「logs:Unmask」権限を付与しましょう。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": "logs:Unmask",
            "Resource": "*"
        }
    ]
}

「logs:Unmask」権限を付与したIAMユーザで「Temporarily unmask protection data」を押下すると、以下のようにアンマスクされたログが確認できます。

検知ログの転送

検知ログはCloudWatch Logs、Kinesis Data Firehose、S3に送信することができます。
今回は、新たに作成したCloudWatch Logsのロググループに転送設定をしてみました。

以下のように新たにログを生成します。
検知は2件です。

※アンマスクしたものが以下です。

カウントが2件増え、合計4件になりました。

転送先のロググループのログストリームを確認してみると、検知した2件がどのカテゴリで検知したかを確認できます。
※黒塗りはAWSアカウントIDです。

機密データが紛れ込んだときに、気付けるようなアラートの実装も簡単にできそうです。

まとめ

セキュリティ監視の現場では、機密データはマスクして欲しいという要望は多いので、非常に良い機能だと思います。
日本語が未対応のため、今後のアップデートでさらに使いやすくなるのではないかと思います。

Session Managerのログ保存

前回、「Session Managerを使用したEC2接続」をご紹介しましたが、この機能を使ってコマンドログを取ることができます。
前回の記事の設定を流用します。

Session ManagerでコマンドログをS3に保存する

バケットを作成

ログ保存用のバケットを作成します。

暗号化は「Amazon S3 マネージドキー (SSE-S3)」を選択し、その他の設定はデフォルトのままにします。

IAMロールを設定

S3にログを保存するためのインラインポリシーをロールに追加します。

S3保存と暗号化に必要な権限を付与します。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "s3:PutObject"
            ],
            "Resource": "arn:aws:s3:::sessionmanager-log-bucket/*"
        },
        {
            "Effect": "Allow",
            "Action": [
                "s3:GetEncryptionConfiguration"
            ],
            "Resource": "*"
        }
    ]
}

ポリシー作成は公式ドキュメントが参考になります。

docs.aws.amazon.com

S3エンドポイントを作成

インターネットを経由しない閉じた環境でS3に接続するため、S3エンドポイントをGateway型で作成します。

インスタンスが配置されているVPCと、サブネットで指定しているルートテーブルを選択します。

Session Managerのログ設定を有効化

System Managerの画面からSession Managerのログ設定を有効化します。

S3へのログ転送と暗号化を有効化し、転送先のバケットを指定します。

Session Managerで接続

EC2の画面から、Session Managerで接続します。

適当なコマンドを入力し、終了します。

Session Managerの画面で、セッション履歴が確認できます。

バケットにログファイルが格納されています。

まとめ

Session Managerでコマンドログを取る方法を紹介しました。
今回はEC2と同一アカウントのS3に保存しましたが、ログを保存するアカウントを別途用意するとより安心です。
さらに、権限を正しく設定することで、ログの改ざんを防ぐことも重要になります。

Session Managerを使用したEC2接続

Session Managerを使用したEC2接続の方法を紹介します。

Session Managerとは

AWS Systems Managerという、AWSリソースの構成や変更を管理するサービスがあり、Session Managerはその1機能です。
Session Managerを利用することで、従来のSSHを使わずに、AWSマネジメントコンソールからEC2へ接続することができます。

docs.aws.amazon.com

何が嬉しいか

HTTPSで接続できるため、SSHキーの鍵管理や通信許可が不要

HTTPSは空いているけど、社内ルールでSSHが制限されている場合があります。
また、SSHキーの管理にも気を使わなければならないため、運用負担が大きいです。 Session ManagerはHTTPSで接続できるため、手軽に導入することができます。

踏み台サーバが不要

パブリックサブネットやプライベートサブネットに配置しているEC2へもアクセスできるため、踏み台サーバが不要になります。

パブリックIPが不要

EC2へパブリックIPを付与しなくても接続することができます。

前提条件

EC2にSSM Agentの導入が必要

Amazon Linux 2などデフォルトで導入されているケースがありますが、導入されていない場合は手動でインストールする必要があります。

EC2にSystem Managerへの適切な権限が必要

AWS管理ポリシー「AmazonSSMManagedInstanceCore」を含む権限が、インスタンスにアタッチされている必要があります。

インターネットを経由しない場合は、適切なVPCエンドポイントが必要

インターネットを経由しない完全に閉じた環境でSession Managerを使用する場合は、以下のVPCエンドポイントを用意し、それらにアタッチするセキュリティグループでインバウンド443ポートを許可する必要があります。

  • com.amazonaws.region.ssm
  • com.amazonaws.region.ec2messages
  • com.amazonaws.region.ssmmessages

Session Managerで接続してみる

IAMロールを作成

EC2がSystem Managerを使用するために、EC2にアタッチするIAMロールを作成します。
信頼されたエンティティタイプは「AWSのサービス」、ユースケースは「EC2」を選択します。

ポリシーは、AWS管理ポリシー「AmazonSSMManagedInstanceCore」を選択します。

ロール名を付けて、ロールを作成します。

EC2を作成

今回は、デフォルトでSSM Agentがインストールされている、Amazon Linux 2をプライベートサブネットに配置した構成にします。
任意の名前を付けて、Amazon Linux 2を選択します。

キーペアはなしを選択します。

プライベートサブネットを選択します。
セキュリティグループは、デフォルトでインバウンドSSHが設定されていますが、不要なので削除します。

インスタンスプロファイルは先ほど作成したロールを選択します。

インスタンスが起動できたので、一度接続を確認してみます。

VPCエンドポイントを設定していないので、この時点では接続できません。

セキュリティグループを作成

後に作成するVPCエンドポイント用のセキュリティグループを作成します。
インバウンドルールで、VPC CIDERからのHTTPSを許可します。

エンドポイントを作成

以下3つのエンドポイントを作成します。

  • com.amazonaws.region.ssm
  • com.amazonaws.region.ec2messages
  • com.amazonaws.region.ssmmessages

サービスから検索し、選択します。

EC2を配置しているVPCとサブネットを選択します。
セキュリティグループは先ほど作成したものを選択します。
ポリシーはデフォルトのフルカスタムのままにします。

同じ要領で他のエンドポイントを作成します。

Session Managerで接続

先ほどと同様に、EC2の画面からSession Managerで接続してみます。
今度は「接続」ボタンがアクティブになっているので、「接続」ボタンを押下します。

プライベートサブネットに配置したインスタンスに、Session Managerを使用して接続することができました。

まとめ

Session Managerを使用したEC2接続の方法を紹介しました。
設定項目が多いですが、順に追っていけばできるはずです。
うまくいかない場合は、ロールやセキュリティグループを見直してみてください。
セキュリティを考慮しながら、簡単にプライベートサブネットのインスタンスへ接続することができるため、ぜひ活用してみてください。

マルチアカウント構成とIAM設計

AWSアカウントを複数運用している組織は多いと思います。
今回はクロスアカウントアクセスを利用した、Jumpアカウント方式を紹介します。

各アカウントにIAMユーザを作成する問題点

AWSアカウントは用途ごとに分けた方が管理がしやすいです。
マルチアカウントの考え方については、以下が分かりやすいです。

https://d0.awsstatic.com/events/jp/2017/summit/slide/D4T2-2.pdf

例えば以下のように、開発/ステージング/本番と3つのアカウントがあったとします。
それぞれのアカウントにIAMユーザを作成すると、アカウントごとにログインが必要になります。
また、IAMユーザが増えていくことでユーザやポリシーの管理が煩雑になり、セキュリティ上のリスクも高まります。

クロスアカウントアクセスによるJumpアカウント方式

Jumpアカウントを用意し、IAMユーザをこのアカウントに集約することで、権限を整理しやすくなります。
利用者は、まずJumpアカウントにログインし、各アカウントへスイッチロールすることでログインすることができます。
各アカウントでどのような操作を許可するかは、スイッチ先のロールに対して必要な権限を付与すればよいです。

IAMの設計例

権限設計の切り口は様々ですが、チームリーダーはある程度の権限を持たせたいけどチームメンバーは権限を絞りたい、というのも一つの方法です。

以下のような設計にすると運用しやすくなると思います。

前提

  • 前述の開発/ステージング/本番の3面環境
  • admin01/admin02:Jumpアカウントの管理者
  • leader01:チームリーダー
  • member01:チームメンバー

設計ポイント解説

  • Jumpアカウントで、管理者グループ「JumpAdminGroup」、リーダーグループ「LeaderGroup」、メンバーグループ「MemberGroup」を作成し、IAMユーザを所属させる。
  • Jumpアカウントで、管理者ロール「Jump_AdminRole」を作成し、管理者グループ「JumpAdminGroup」からのみスイッチロールを許可する。
    ※管理者同士のクロスチェックや緊急時に対応できるようにするため、管理者権限を持つユーザは複数人いるとよいでしょう。
  • 管理者ロール「Jump_AdminRole」は、JumpアカウントのIAMユーザやグループの管理に使用する。
  • 開発環境/ステージング環境/本番環境で、リーダーロール「<env>_LeaderRole」、メンバーロール「<env>_MenberRole」、読み取り専用ロール「<env>_ReadOnlyRole」を作成する。
  • 読み取り専用ロール「<env>_ReadOnlyRole」は、リーダーとメンバーの両方がスイッチでき、設定確認のみの場合はこのロールを使うルールにする。
    ※設定確認するだけのために高い権限を与えていると、操作ミスで設定を変更してしまう可能性があるため、読み取り専用ロールは作成しておくとよいです。例えば、Linuxでずっとrootのまま作業しませんよね?
  • リーダーロール「<env>_LeaderRole」は、リーダーグループ「LeaderGroup」からのみスイッチロールを許可し、サポート問い合わせや課金情報閲覧などある程度の権限を与えておく。
  • メンバーロール「<env>_MemberRole」は、メンバーグループ「MemberGroup」からのみスイッチロールを許可し、開発運用に必要な権限のみ与えておく。

人員変更があれば、JumpアカウントでIAMユーザを作成/削除し、グループへの追加/削除をするだけです。
さらに、これらのグループやロールをCloudFormationで構成すると、自動化や管理がしやすくなります。

まとめ

マルチアカウントのIAM設計のうちJumpアカウント戦略について紹介しました。
マルチアカウントとIAMの設計はなかなか難しく、社内体制や事業拡大とともに変わっていくものです。
ユーザからの要望や組織の変化に合わせて、適宜見直していく運用が大事だと思います。

Amazon S3アクセスポイントを使用したアクセス制御

Amazon S3アクセスポイントを使用したアクセス制御について紹介します。

Amazon S3アクセスポイントとは

バケットに対して、アクセスポイントという単位でアクセス権限を設定することができます。

docs.aws.amazon.com

何が嬉しいのか

従来のバケットポリシーは、バケットに対して1つ設定するものだったので、アクセス要件が変わると既存のバケットポリシーを変更する必要がありました。
要件が追加されるたびにバケットポリシーが長く複雑になり、管理が大変になってしまいます。
さらに、既存のポリシーを変更するため、設定を誤ると影響範囲も広くなってしまいます。

アクセスポイントはバケットに対して複数作成することができ、アクセスポイントごとにポリシーを設定することができます。
そのため、アクセス要件ごとにポリシーを分けることができ、管理しやすくなり、影響範囲を最小限に抑えられます。

S3アクセスポイントを設定してみる

事前準備1:IAMユーザ作成

バケットにアクセスするためのIAMユーザを作成します。
アクセス権限は「AdministratorAccess」を付与します。
※テスト用なので実運用では最小権限にする。

事前準備2:バケット作成

バケットを作成して、ファイルを格納します。

アクセスポイント設定

バケットの設定画面から、「アクセスポイント」→「アクセスポイントの作成」を押下します。

アクセスポイント名を付け、ネットワークオリジンはインターネットを選択する。

アクセスポイントポリシーは、オブジェクトに対する「s3:GetObject」を許可します。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::<accountID>:user/testuser01"
            },
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:ap-northeast-1:<accountID>:accesspoint/ap-testuser01/object/*"
        }
    ]
}

アクセスポイントが作成されました。

アクセスポイント経由でアクセスしてみる

CloudShellから想定通りアクセスできました。

$ aws s3api get-object --bucket arn:aws:s3:ap-northeast-1:<accountID>:accesspoint/ap-testuser01 --key test.txt output.txt
{
    "AcceptRanges": "bytes",
    "LastModified": "2022-10-15T07:47:12+00:00",
    "ContentLength": 3,
    "ETag": "\"900150983cd24fb0d6963f7d28e17f72\"",
    "ContentType": "text/plain",
    "Metadata": {}
}

しかし、このままではアクセスポイントを経由しない場合もアクセスできてしまいます。

$ aws s3api get-object --bucket accesspoints-test-bucket --key test.txt output.txt 
{
    "AcceptRanges": "bytes",
    "LastModified": "2022-10-15T07:47:12+00:00",
    "ContentLength": 3,
    "ETag": "\"900150983cd24fb0d6963f7d28e17f72\"",
    "ContentType": "text/plain",
    "Metadata": {}
}

そこで、アクセスポイントを経由しないアクセスを拒否します。

バケットポリシーに以下を設定します。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Deny",
            "Principal": "*",
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::accesspoints-test-bucket/*",
            "Condition": {
                "StringNotEquals": {
                    "s3:DataAccessPointArn": "arn:aws:s3:ap-northeast-1:<accountID>:accesspoint/ap-testuser01"
                }
            }
        }
    ]
}

アクセスポイントを経由した場合のみアクセスできました。

$ aws s3api get-object --bucket arn:aws:s3:ap-northeast-1:<accountID>:accesspoint/ap-testuser01 --key test.txt output.txt
{
    "AcceptRanges": "bytes",
    "LastModified": "2022-10-15T07:47:12+00:00",
    "ContentLength": 3,
    "ETag": "\"900150983cd24fb0d6963f7d28e17f72\"",
    "ContentType": "text/plain",
    "Metadata": {}
}
$ aws s3api get-object --bucket accesspoints-test-bucket --key test.txt output.txt 

An error occurred (AccessDenied) when calling the GetObject operation: Access Denied

まとめ

バケットポリシーでのアクセス制御はポリシーが複雑になりがちでした。
アクセスポイントを利用することで、要件ごとにポリシーを分けることができるため、管理がしやすくなりました。

Amazon S3のアクセス制御

Amazon S3のアクセス制御について紹介します。

Amazon S3とは

S3はAWSが提供するオブジェクトストレージであり、様々なアクセス制御方法が用意されています。

docs.aws.amazon.com

アクセス制御方法

IAMポリシー

IAMユーザやグループに対して、どのバケットやフォルダに対してどのような操作が可能か定義する。

バケットポリシー

バケットに対して、どのAWSアカウントやIAMがどのような操作が可能か定義する。

ACL

バケットやオブジェクトに対して、どのAWSアカウントがどのような操作が可能か定義する。
現在AWSでは非推奨。

S3ブロックパブリックアクセス

バケットやオブジェクトへのパブリックアクセスをブロックする。
デフォルトで有効。

IAMポリシーとバケットポリシーを試す

事前準備1:IAMユーザ作成

バケットにアクセスするためのIAMユーザを作成します。
アクセス権限は未設定です。

事前準備2:バケット作成

バケットを作成して、ファイルを格納します。

ブロックパブリックアクセスはオンで、バケットポリシーは未設定です。

IAMユーザでバケットへアクセス

IAMポリシーもバケットポリシーも未設定なので、バケットへアクセスすることができません。

そこで、IAMポリシー「AmazonS3FullAccess」を付与してみます。

バケットとその配下のオブジェクトにアクセスすることができました。

バケットポリシーに以下を追加しても、オブジェクトにアクセスすることができます。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::<accountID>:user/testuser01"
            },
            "Action": "s3:*",
            "Resource": [
                "arn:aws:s3:::access-controle-test-bucket",
                "arn:aws:s3:::access-controle-test-bucket/*"
            ]
        }
    ]
}

IAMポリシーとバケットポリシーの注意点

前述のようなバケットポリシーで特定ユーザを明示的に許可しても、他のユーザからもアクセスできてしまいます。
そのため、明示的にDenyポリシーも併せて利用するべきです。

IAMポリシーには読み取り専用として使われる、「ReadOnlyAccess」ポリシーというものがあります。

便利なポリシーですが、バケットからオブジェクトをダウンロードすることができてしまいます。
例えば、機密情報をバケットに格納しても、「ReadOnlyAccess」ポリシーがあればデータを持ち出されるリスクがあります。
そのため、以下のようなDenyポリシーも併せて利用するべきです。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Deny",
            "Action": "s3:Get*",
            "Resource": "*"
        }
    ]
}

Denyポリシーでダウンロードが失敗した例です。

まとめ

今回は、IAMポリシーとバケットポリシーを紹介しました。
データ保管には便利なサービスですが、設定を誤ったために情報漏洩してしまうという事例が起きています。
設定が意図したとおりに動くか、しっかりとテストしておくことが重要です。
今一度、S3のセキュリティを見直してみるとよいかもしれません。