AWS IAMの安全な管理方法

by Hayato Hoshino | December 25, 2019
security | #aws #infrastructure

はじめに

こんにちは。IT 基盤部の星野です。 DeNA のエンターテインメント領域のサービスを中心に、多数のサービスのインフラを担当するチームをリードしています。最近では、全社的なクラウドセキュリティに関する調査・検討・導入も行っています。

本稿の内容とは関係ありませんが 2020年3月開催のTechCon2020で登壇 致します。既にregistrationも始まっておりますので、是非会場にお越しください。

さて、以前髙橋が DeNA の AWS アカウント管理とセキュリティ監査自動化 で、DeNAにおけるAWSセキュリティの取り組みについて触れ、人によるAWSマネジメントコンソールへのアクセスの安全な管理方法についてご紹介しました。今回は人によるAWSマネジメントコンソールへのアクセスについてではなく、システムによるAWSサービスへのアクセスの安全な管理方法について、DeNAで検討・考察した内容をご紹介したいと思います。

本稿では、システムからAWSサービスへ何らかの権限を伴うアクセスが発生するケースを考え、認証情報を持ち出せないか、又は持ち出されてもそれを継続して利用することができない管理方法について考察します。オンプレミスを含め、AWS以外に存在するシステムから利用する場合についても応用できる内容となっています。

目次

人によるAWSマネジメントコンソールへのアクセス

まず、人によるAWSマネジメントコンソールへのアクセス管理について簡単におさらい( DeNA の AWS アカウント管理とセキュリティ監査自動化 )すると以下のような内容でした。 ルートアカウントへのログインと作業用のログインを分け、以下のように紹介しました。

  • ルートアカウントへのログイン
    • ID・パスワード・MFA・IP制限によるログイン
      • パスワード・MFAは定められた方法で厳格に管理し、アカウント利用者には開示しない
      • 基本、日常的な作業目的ではログインしない
  • 日常的な作業アカウントへのログイン
    • IdP(Identity Provider)を用いたIDフェデレーションによるAWSマネジメントコンソールログイン
      • IdPはディレクトリサービスと連携する
      • マネジメントコンソールログイン用のIAM(AWS Identity and Access Management)ユーザは発行しない

このようにルートアカウントは普段使わず、IAMユーザも作成しないことが基本でした。 これにより、退職者や異動者によるコンソールアクセスは直ちに不可能になります。 では、システムによるAWSサービスへのアクセスはどのように管理すれば良いでしょうか。

システムによるAWSサービスへのアクセス

ケース別の管理方法

システムによるAWSサービスへのアクセスは、以下のようにすると安全に管理することができます。 大別すると、IAMユーザを作成するかしないかで管理方法が分かれ、それぞれ以下のような方法があります。

  • IAMユーザを作成しない場合
    • (1) IAMロールを作成してEC2インスタンスにロールをアタッチして使う(インスタンスプロファイルを使用する)
    • (2) IdP + STS(AWS Security Token Service)で IDフェデレーションを利用して一時的な権限を取得して使う
  • IAMユーザを作成した場合
    • (3) IP制限を入れ、定期的にIAMユーザのシークレットアクセスキーのローテートも行う
    • (4) 定期的にIAMユーザのシークレットアクセスキーのローテートを行う

まず、システムによるAWSサービスへのアクセスの場合でも、そもそもシークレットアクセスキー等の認証情報の管理が発生しない方が良く、できる限りIAMユーザを作成しない(1)の方法を取ることがベストプラクティスとなっています。ただし、EC2からの利用ではない場合や、OSへのログインユーザごとに厳格に権限を管理している場合は(1)の方法は取れません。

(2)では、フェデレーションしつつAPIコールをすることが可能で、個別のIAMユーザを管理する必要がなくなります。しかし、この方法の場合STSを発行する際に必ずIdPへのリクエストが必要になります。STS には有効期限が設定できるので毎回IdPにリクエストが飛ぶわけではありませんが、万が一IdPが落ちていたり応答不能な状態だった場合はSAML認証が失敗してしまいます。あまりサービスクリティカルではないところでは検討の余地がありますが、サービスの品質が本来直接サービス影響が無いはずのIdPに依存してしまうとまずい場合は、(2)の方法は取れません。

次に、やむを得ずIAMユーザを作成する(3)か(4)の方法を検討することになります。

(3)では、IP制限をいれることで退職者が即時利用不可になる状態を保つことができます。しかし、利用元のIPアドレスが固定できなかったり、許可するIPアドレスの管理が運用上現実的ではない場合もあると思います。また、IP制限だけでは異動者が利用できなくなる状態をつくることが難しい場合もあります。そのため、IAMユーザのシークレットアクセスキーのローテートは定期的に行う必要があります。

次の項で本稿のメイントピックでもあるIAMユーザのシークレットアクセスキーのローテート方法についてご紹介します。

IAMユーザのシークレットアクセスキーのローテートの方法

概要

IAMユーザのシークレットアクセスキーは同時に2つ発行することができます。これを利用して、以下の流れでシークレットアクセスキーをローテートすることができます。

  1. 新規にシークレットアクセスキーを発行する
  2. 新規に発行したシークレットーアクセスキーを利用するようにアプリケーションを更新する
  3. 古いシークレットアクセスキーが利用されなくなったことを確認してから、古いシークレットアクセスキーを削除する
    • 古いシークレットアクセスキーを削除する際には、安全のため古いシークレットアクセスキーが使用されていないことを確認するようにしてください。シークレットアクセスキーが使用されていないことを確認するには、シークレットアクセスキーの最終使用日時を見て判断することができます。シークレットアクセスキーの最終使用日時は認証情報レポートで確認することができます。

実際にローテートを行うには、手動で行う方法と自動で行う方法が考えられます。 定期的に手動で行うことも一つの手ですが、作業工数がかかったりミスや漏れが発生する可能性があるのでなるべく自動化したいと誰もが考えると思います。しかし自動化にあたり「IAMユーザのシークレットアクセスキーをローテートするために別のシークレットアクセスキーを使う」という状態では、またそのシークレットアクセスキーのローテートを考えなければならなく、堂々巡りになってしまいます。

そこで、以下のようにAWSの各種サービスを利用することで、追加のシークレットアクセスキーは発行せずにIAMユーザのシークレットアクセスキーを自動でローテートさせることができます。EC2インスタンスでも、AWSのインスタンスではなくてもどちらでも可能です。

1. 管理したいシークレットアクセスキーをAWS Secrets Managerに登録

まず、AWS Secrets Managerで、各シークレットアクセスキーを管理するシークレットを作成します。現在利用中のシークレットアクセスキーが格納されている状態にします。ここでは、例として iam-user-test001 というシークレットを作成しました。

2. サーバをAWS Systems Managerのマネージドインスタンスとして登録

シークレットアクセスキーを置いているサーバをAWS Systems Managerのマネージドインスタンスとして登録します。AWS Systems Manager、AWS Systems Managerエージェント(以下、SSMエージェント)を使い、以下の流れで登録します。

  1. 「AWS Systems Manager」 > 「インスタンスとノード」 > 「ハイブリッドアクティベーション」 から、「アクティベートを作成」
    • 「Activation Code」と「Activation ID」を得る
      • 「Activation Code」と「Activation ID」は利用可能回数・有効期限を指定することができるので、基本的に1度限りの使い捨てとする
    • AmazonEC2RunCommandRoleForManagedInstances という名前のIAMロールが自動で作成され、サーバにアタッチされる
      • 事前に作成しておいた任意のIAMロールを指定してアタッチすることも可能
      • 後からIAMロールを入れ替えることも可能
  2. サーバにSSMエージェント(amazon-ssm-agent)をインストールし、アクティベートを行う
  3. 「AWS Systems Manager」 > 「インスタンスとノード」 > 「マネージドインスタンス」 上で、サーバが認識されたことを確認
  4. 以下のようなカスタムポリシーを作成し、AWS Secrets Managerから情報を取得する権限を、IAMロール AmazonEC2RunCommandRoleForManagedInstances に付与する

カスタムポリシー例

{
    "Version": "2012-10-17",
    "Statement": {
        "Effect": "Allow",
        "Action": "secretsmanager:GetSecretValue",
        "Resource": "<シークレットのarn>"
    }
}

これで、サーバをAWS Systems Managerのマネージドインスタンスとして認識させ、必要な権限をIAMロール経由で付与することができました。

ただしAWS Systems Managerのマネージドインスタンス上で付与した権限は、EC2インスタンスにIAMロールをアタッチした時のように直接サーバからその権限を使えるのではなく、AWS Systems Manager側から操作する際に有効になります。したがって次に、シークレットアクセスキーをローテートするための AWS Systems Manager オートメーションドキュメント をYAML又はJSON形式で定義します。

3. AWS Systems Manager オートメーションドキュメントの作成

「AWS Systems Manager」 > 「ドキュメント」 > 「コマンドまたはセッションを作成」から、ドキュメントを作成します。以下の例は、サーバ上に配置した /home/hoshihaya/scripts/overwrite-secret-value.sh をAWS Systems Managerを使って実行するドキュメントをJSONで記述した例です。

ドキュメント例

{
  "schemaVersion": "2.2",
  "description": "Simple test document using the aws:runShellScript plugin.",
  "mainSteps": [
    {
      "action": "aws:runShellScript",
      "name": "OverwriteSecretValue",
      "inputs": {
        "timeoutSeconds": 60,
        "runCommand": [
          "/home/hoshihaya/scripts/overwrite-secret-value.sh"
        ]
      }
    }
  ]
}

作成したドキュメントは、メンテナンスウィンドウを利用することで定期的に自動実行することができます。

  • 「AWS Systems Manager 」>「メンテナンスウィンドウ」から「メンテナンスウィンドウを作成」
  • 「AWS Systems Manager 」>「メンテナンスウィンドウ」>「メンテナンスウィンドウID(自分で作成したもの)」から「RunCommandタスクの登録」

4. scriptをサーバに設置

AWS Systems Manager オートメーションドキュメントから実行するscriptをサーバ上に配置します。 ドキュメントのrunCommandで指定したpathにscriptを作成し、実行権限をつけておきます。ここの例では /home/hoshihaya/scripts/overwrite-secret-value.sh になります。

script例

#!/bin/bash
aws secretsmanager get-secret-value --secret-id iam-user-test001 --region ap-northeast-1 | \
  jq -r .SecretString | \
  jq -r '"aws_access_key_id=" + .aws_access_key_id, "aws_secret_access_key=" + .aws_secret_access_key' \
  > /path/to/credentials

上記scriptをAWS Systems Manager オートメーションドキュメントから実行すると、credentialsファイルの中身は以下のようになります。

実行後のcredentialsファイルの中身

$ cat /path/to/credentials
aws_access_key_id=XXXXXXXX12345
aws_secret_access_key=YYYYYYYY12345

5. ローテート実施

ここまでできると、以下の流れで実際にサーバ上のシークレットアクセスキーを自動でローテートさせることができます。 (AWS Lambda については本稿では割愛します)

  • AWS Lambdaで以下の処理を実行
    • IAM create-access-key APIを呼び出してシークレットアクセスキーを更新
    • 更新された認証情報をAWS Secrets Managerに保存
  • AWS Systems Managerオートメーションドキュメントで以下の処理を実行
    • サーバでAWS Secrets Managerからシークレットアクセスキー情報を取得
    • 既存のシークレットアクセスキーを書き換え
    • 【任意】稼働中のdaemonプロセス等で環境変数や設定ファイルを再読み込みさせる
  • AWS Lambdaで以下の処理を実行
    • 古いシークレットアクセスキーが使われていないことを確認し、削除または無効にする

SSMエージェントの安全性について

これまで述べた内容は、SSMエージェントをサーバにインストールしてサーバのアクティベートを行うことで実現できていますが、アクティベートした後の認証情報はSSMエージェントが持っているはずです。SSMエージェント自体は安全なのでしょうか。もし、SSMエージェントが持っているはずの認証情報を持ち出された場合どうなるのでしょうか。

このあたりの詳しい情報は公式サイトには記載されていないため、ここからはAWS公式の情報を参照したのではなくサーバ上で調査した結果からの推測になりますのでご了承ください。

amazon-ssm-agent は初回のアクティベート時に/var/lib/amazon/ssm/Vault/Store/ 以下にハードウェア情報から生成されたfingerprintを保持し、その情報を使ってwss://ssmmessages.ap-northeast-1.amazonaws.com/v1/control-channel/${インスタンスID}?role=subscribe&stream=input のような宛先とwebsocketでコネクションを確立ようとしますが、ここに不整合があるとコネクションが確立せずhibernateモード(休止モード)に入るようでした。hibernate モードに入る様子は/var/log/amazon/ssm/amazon-ssm-agent.log から確認できます。

また、コネクション確立後に amazon-ssm-agent daemonプロセスにアタッチしてシステムコールを暫く見ていると、定期的に /root/.aws/credentials を更新していることがわかりました。実際に /root/.aws/credentials の中身も書き換わっていました。このファイルは自分で置いたものではないので amazon-ssm-agent が生成し使っているものと思われますが、この認証情報だけを持ち出してもAWSを操作することはできませんでした。また、前述の通り定期的にローテートもされているようでした。

私が確認できた範囲では、SSMエージェントが持っている認証情報を持ち出しても簡単には使えないことがわかりました。

どうしてもどの条件にも当てはまらない場合

それでもどうしても上記のすべての条件に当てはまらず、ローテートもできないIAMユーザが存在してしまうことがあると思います。 その場合は、

  • 退職時や異動時に即時失効させるフローを整える
  • 定期的に監査を行い、退職者や異動者が使っていたIAMユーザが存在していないことや長期間使用されていないIAMユーザが存在しないことをチェックする
  • GuardDutyやCloudTrail等を使って不穏な動きが無いかを追う

等を行い、IAMユーザの削除漏れや異常を検知できる仕組みを整備することが大切です。

さいごに

本稿では、主にIAMユーザの取り扱いに関する考え方や方法をご紹介致しました。 皆様の良きIAM管理の一助となれば幸いです。