[アップデート] SSM Session Managerでのノード接続時の承認管理に役立つジャストインタイムノードアクセス機能が追加されました
SSM Session Managerで接続する際は手動で承認させたい
こんにちは、のんピ(@non____97)です。
皆さんはSSM Session Managerで接続する際は手動で承認させたいなと思ったことはありますか? 私はあります。
SSM Session ManagerでEC2インスタンスへ接続を細かに制御するのはそれなりに大変です。アクセス制御方法は以下記事が詳しいです。
かといって、緩いポリシーにして、OSに簡単にログインさせるのは避けたいところです。緩いポリシーによる過剰なアクセス許可は事故やトラブルにつながります。
細かいアクセス権限に時間を費やすのであれば、特権管理として承認ベースで管理したいです。
今回アップデートにより、ジャストインタイムノードアクセス(Just-in-time node access)機能が追加されました。
AWS Blogsにも投稿されていますね
これによって、特権管理の仕組みのように承認ベースでSSMのマネージドノードに接続させることが可能です。
以降ジャストインタイムノードアクセスについて紹介します。
いきなりまとめ
- ジャストインタイムノードアクセスとはノードへの長期的な接続権限を付与するのではなく、リクエストを受領して都度承認を行う
- 自動承認と手動承認が可能
- 自動承認はCedarで定義
- 手動承認は複数名、複数階層を定義可能
- 手動承認は再承認が不要な期間を1時間から14日(336時間)で設定可能
 
- Organizationsを導入している環境においては、Organizationsと連携させてIAM Identity Centerのユーザーの承認も可能
- ジャストインタイムノードアクセスは新しい統合エクスペリエンスとして動作
- アクセスリクエストのイベント(承認依頼/承認/承認キャンセル)のタイミングで、メールやSlack、Teamsに通知することが可能
- メール通知する場合、承認依頼者と承認者のIAMロールとメールアドレスをマッピングさせる
 
- 料金はノードあたりの時間料金が設定されいている
- 100ノード未満の場合は0.0137USD/h
 
- プリンパルがStartSessionの権限を持っている場合は、ジャストインタイムノードアクセスを用いた接続はできない- StartSessionの権限を持っておらず、対象のノードが手動承認の対象にマッチする場合は、セッション開始のタイミングでアクセスリクエストのポップアップが表示される
 
- ジャストインタイムノードアクセスで承認された状態で、Fleet ManagerからRDP接続をする場合、RDP接続のセッションの動画を記録し、S3バケットにPUTすることが可能
- KMSキーにTagKey=SystemsManagerJustInTimeNodeAccessManaged,TagValue=trueのタグを付与する必要がある
- 動画ファイルは接続を切断したタイミングで処理され、S3バケットにPUTされる
 
- KMSキーに
- 従来のSSM Session Managerの接続方法はスタンダードセッションと呼ぶ
- SSM Session Managerのセッションログ出力先やセッション時間などは今までの設定と共有
- ジャストインタイムノードアクセスはSSM Session Managerの一アクセス方法であり、SSM Session Manager自体を完全に取って置き換えるのものではない
 
ジャストインタイムノードアクセスとは
概要
ジャストインタイムノードアクセスとはノードへの長期的な接続権限を付与するのではなく、リクエストを受領して都度承認を行う機能です。
「都度承認を行う」と聞くと手動承認のみをイメージしてしまいますが、自動承認も可能です。
自動承認を行う際のルールはCedarポリシーで定義します。
従来RBACやABACだと制御が難しかった複雑なルールも表現しやすそうです。
CedarポリシーはAmazon Verified Permissionsでも使われているので、Amazon Verified Permissionsに慣れている方は扱いやすいかもしれません。
実際の例は以下のとおりです。
// Users assuming IAM roles with a principal tag of "Elevated" can automatically access nodes tagged with the "Environment" key when the value equals "prod"
permit(principal, action == AWS::SSM::getTokenForInstanceAccess, resource)
when {
    // Verify IAM role principal tag
    context.iam.principalTags.getTag("AccessLevel") == "Elevated" &&
    
    // Verify the node has a tag with "Environment" tag key and a tag value of "prod"
    resource.hasTag("Environment") &&
    resource.getTag("Environment") == "prod"
};
Cedar公式ドキュメントも参考になるでしょう。
各ポリシーの評価順
自動承認と手動承認はそれぞれポリシーを定義します。
また、Organizationsレベルで承認をさせたくないリソースはアクセス拒否ポリシーとして定義することが可能です。
各ポリシーの評価順は以下のとおりです。
| ポリシーの種類 | 説明 | ポリシー数の制約 | 
|---|---|---|
| アクセス拒否ポリシー | 指定したノードへのアクセス要求の自動承認を明示的に防止するためのポリシー | Organizations内に一つのみ | 
| 自動承認ポリシー | ユーザーが自動的に接続できるノードを定義したポリシー | アカウントとリージョンごとに1つのみ | 
| 手動承認ポリシー | 指定したノードにアクセスするために提供する必要がある手動承認の数とレベルを定義したポリシー | 特になし | 
各ポリシーの詳細な説明や以下AWS公式ドキュメントおよび、その子ページが参考になります。
通知
承認を受け取った場合、承認をされた場合はメールもしくはチャットアプリへ通知することも可能です。
設定方法は以下公式ドキュメントが参考になります。
対応リージョン
ジャストインタイムノードアクセスはリージョナルな機能です。
現時点で使用できるリージョンは以下のとおりです。
- 東京
- ソウル
- ムンバイ
- シンガポール
- シドニー
- カナダ (中部)
- フランクフルト
- ストックホルム
- アイルランド
- ロンドン
- パリ
- サンパウロ
- バージニア北部
- オハイオ
- 北カリフォルニア
- オレゴン
大阪リージョンではまだサポートされていないので注意しましょう。
料金
ジャストインタイムノードアクセスを使用するにあたって、ノードあたりの時間料金が設定されています。
具体的には以下のとおりです。
| Tier | Price per node per month* | Price per node per hour | 
|---|---|---|
| Up to 100 nodes | $10.00 | $0.0137 | 
| 101 to 1,000 nodes | $7.50 | $0.0103 | 
| 1,001 to 10,000 nodes | $2.50 | $0.0034 | 
| 10,001+ nodes | $1.00 | $0.0014 | 
- Monthly prices are approximations-based calculations using 720 hours per month.
抜粋 : Centralized Operations Hub – AWS Systems Manager Pricing – Amazon Web Services
個人的には「時間料金」が何に対する時間なのか気になります。
ドキュメントを見ましたが、ジャストインタイムノードアクセスによって実際に接続している時間なのか、それともジャストインタイムノードアクセスを有効化している期間で稼働しているマネージドノードの台数の時間課金なのか確証は持てていません。
しかし、料金例には以下のような記載があり、後者 = ジャストインタイムノードアクセスを有効化している期間で稼働しているマネージドノードの台数の時間課金な気がしています。
Pricing Example #1
You have a Consolidated Billing family with two accounts, Account A and Account B. Account A has 500 nodes opted into just-in-time node access for the entire month and Account B has 1,000 nodes opted into just-in-time node access for the entire month.
Total usage aggregated at the Consolidated Billing family = 500 + 1,000 = 1,500 nodes.
Tier 1 cost = 100 nodes $10.00/node/month = $1,000.00
Tier 2 cost = (1,000 nodes – 100 nodes = 900 nodes) $7.50/node/month = $6,750.00
Tier 3 cost = (1,500 nodes – 1,000 nodes = 500 nodes) * $2.50/node/month = $1,250.00Total expected cost = $1,000.00 + $6,750.00 + $1,250.00 = $9,000.00
その場合、EC2インスタンスの台数が多い環境においては月10USD/台はちょっとインパクトが大きいかもしれないですね。
やってみる
ジャストインタイムノードアクセスの有効化
それでは実際にやってみましょう。
なお、Organizationsを導入している環境においては、Organizationsと連携させてIAM Identity Centerのユーザーの承認もできるようですが、今回はスタンドアロンアカウントです。
SSMのコンソールを見るとジャストインタイムノードアクセスが追加されていました。クリックしてみます。

新しい統合エクスペリエンスとして動作するようですね。新しい統合エクスペリエンスについては以下記事が詳しいです。
まだ有効にしていなかったので新しいエクスペリエンスを有効にするをクリックします。

3分ほどで有効化されました。

さらに追加できるウィジェットは特に内容です。

2分ほど待つと、マネージドノードの情報を確認できました。このタイミングでは特にジャストインタイムノードアクセス系の情報は載っていません。

無料で試すをクリックして、ジャストインタイムノードアクセスのセットアップをしましょう。
このタイミングでは特にパラメーターの指定はありませんね。ジャストインタイムノードアクセスを有効にするをクリックします。

注意書きが表示されました。

了承しますをクリックして次に進めます。
セットアップが完了した後、注意書きに書かれていたIAMロールやCloudFormation StackSetsを確認します。
SSM-JustInTimeAccessTokenRoleにアタッチされているIAMポリシーはAWSSystemsManagerJustInTimeAccessTokenPolicyのみでした。
また、信頼ポリシーでは以下のようにジャストインタイムノードアクセスのサービスプリンシパルからの許可をしていました。
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "Service": "justintimeaccess.ssm.amazonaws.com"
            },
            "Action": [
                "sts:AssumeRole",
                "sts:TagSession"
            ]
        }
    ]
}
StackSetsではAWS-QuickSetup-SSM-LA-wkey5とAWS-QuickSetup-JITNA-LA-f5fqvが作成されていました。


また、スタック一覧は以下のとおりです。

各StackSet Instanceを作成する前にデプロイ用のIAMロールを作っていそうですね。
手動承認ポリシーを作成します。アクセス時間(= 再承認が不要な時間)1時間で今回は承認者一人で1階層のみ設定します。

「マネージャー2人のうち1人と、部長1人の承認が必要」といったことも実現できそうです。
なお、特定のノードのみを選択した場合、タグで絞り込むようです。

手動承認ポリシーの作成が完了しました。

SSMのコンソールの左ペインの設定からジャストインタイムノードアクセスの情報を確認します。

ここから通知やセッション設定ができそうですね。
なお、確認したところセッション設定で設定できるパラメーターはSSM Session Managerの設定と連動していました。
SSM Session Managerの設定で変更したものはジャストインタイムノードアクセスのセッション設定に反映され、ジャストインタイムノードアクセスのセッション設定で変更したものはSSM Session Managerの設定に反映されました。
「あっちもこっちも変更しなければならない」ということは避けられますね。
ジャストインタイムノードアクセスを用いたSSM Session Managerによる接続
ジャストインタイムノードアクセスを用いたSSM Session Managerによる接続を実際に行います。
SSMのコンソールからターミナルセッションを開始するをクリックします。

すると、特にアクセスリクエストをするポップアップは表示され、すんなり接続できました。

ドキュメントをよくよくみているとStartSessionの権限を持っている場合は、ジャストインタイムノードアクセスの管理からは外れるようです。
ジャストインタイムノードアクセスを設定しても、セッションマネージャー用に設定した既存のIAMポリシーや設定には影響しません。StartSessionユーザーがノードに接続する際にジャストインタイムノードアクセスのみが使用されるようにするには、IAMポリシーなどからセッションマネージャーアクションへの権限を削除する必要があります。ジャストインタイムノードアクセスを設定したら、セッションマネージャーへの権限を削除する前に、一部のユーザーとノードで承認ポリシーをテストし、ポリシーが期待どおりに機能していることを確認することをお勧めします。
StartSessionを持っておらず、ReadOnlyAccessのみがアタッチされたIAMロールにスイッチロールして、再度接続しようとしてみます。

アクセスリクエストのポップアップが表示されましたね。アクセスリクエストを作成をクリックします。
すると、StartAccessRequestの権限不足により弾かれてしまいました。

以下AWS公式ドキュメントにジャストインタイムノードアクセスユーザー向けのIAMポリシーがあったため、こちらをIAMロールにアタッチして再度トライします。
すると、今度は正常にアクセスリクエストを作成することができました。

どのロールからの承認が必要なのかはアクセスリクエストの承認タブから確認できます。

また、タイムラインのタブからはいつリクエストが行われたのかを確認できます。

AdministratorAccessは付与されているが、承認者として指定されていないIAMロールにスイッチして、アクセスリクエストを確認します。


承認者として指定されていないがために、AdministratorAccessが付与されていたとしても承認はできないようになっています。
続いて、承認者として指定したIAMロールにスイッチして、アクセスリクエストを確認します。

承認できそうですね。
詳細を表示をクリックすると、アクセスリクエストの詳細を確認できました。

ただし、アクセスリクエストをした時のメッセージはマネジメントコンソール上では確認できませんでした。
承認をしましょう。承認メッセージを入力してApproveをクリックします。

すると、承認ステータスが承認済みとなり、タイムラインにも誰によって承認されたのかのイベントが記録されていました。

アクセスリクエストの承認タブからも誰が承認したのかの確認はできます。

承認時のメッセージであるThis request has been approved.も記録されています。
こちらのアクセスリクエストは1年間残るようです。
To help you meet compliance requirements, Systems Manager retains all access requests for 1 year. Systems Manager also emits EventBridge events for just-in-time node access for failed access requests and status updates to access requests for manual approvals.
Just-in-time node access using Systems Manager - AWS Systems Manager
誰がいつ承認したのかを調査する際に、都度CloudTrailで検索する手間を省けて良いですね。
実際にセッションを開始してみます。

無事接続できました。
なお、セッションIDは<アクセスリクエストID>-<IAMユーザー名>-<ランダムな文字列>となっており、ジャストインタイムノードアクセスを用いてアクセスしているか簡単に判別d系ますね。
接続をすると、アクセスリクエストのセッションの詳細タブで各セッションの情報を確認できました。

なお、今回はSSMコンソールから接続しましたが、EC2のコンソールから接続する際もジャストインタイムノードアクセスでアクセスすることが可能です。

ノードのインサイトを確認をのぞいてみると、ジャストインタイムノードアクセス、過去 30 日というウィジェットが追加されていました。

従来のSSM Session Managerの接続方法はスタンダードセッションと呼ぶようですね。
ここからジャストインタイムノードアクセスはSSM Session Managerの一アクセス方法であり、SSM Session Manager自体を完全に取って置き換えるのものではないことが分かります。
通知の設定
続いて、通知設定を行った場合どのような通知がされるのか確認します。
今回はSlackとメールの2つを設定します。
まずは、Amazon Q Developer in chat applications(旧称: AWS Chatbot)を用いた設定です。
事前にワークスペースの連携は行なっていたので、チャネルの設定からです。
承認ステータスが変わった場合と、アクセスリクエストが来た時の通知を行うようにします。

IAMロールにアタッチするべきIAMポリシーの情報はドキュメントにはなかったので、以下ドキュメントのアクセスリクエスト承認者向けのIAMポリシーを設定しました。
チャネル設定が完了すると以下のようになります。

続いて、メール通知です。
通知は全イベントを通知するようにしました。また、メール通知先の設定は使用しているIAMロールとEメールアドレスをマッピングすることで行います。

RDPセッションの記録
続いて、RDPセッションの記録を行います。
この設定をすると、RDPセッション時の操作が録画されそうな雰囲気があります。
記録データは指定したS3バケットにPUTされるようです。
詳細な内容は以下ドキュメントに記載されています。
既に存在していたS3バケットとKMSキーを指定します。

ジャストインタイムノードアクセスによるRDP接続
ジャストインタイムノードアクセスによるRDP接続を行います。
Fleet ManagerからRDP接続をします。

認証情報を入力して接続します。

アクセスリクエストをするポップアップが表示されました。アクセスリクエストを作成をクリックします。

正常にアクセスリクエストが作成されました。

承認者として指定したIAMロールとマッピングしたメールアドレスで何か受信しているかどうか確認したところ、AWS Systems Manager Just-In-Time access request status updateというタイトルのメールを受信しました。

また、Slackを確認するとRequester Access Request Status Updateというメッセージが投稿されていました。

良い感じですね。
リンクを辿って承認をします。

承認された際のメールとSlackメッセージは以下のとおりです。


承認されたことが分かりますね。ただ、やはりアクセスリクエスト時および承認時に入力したメッセージはどこにも表示されないので、このメッセージでやり取りするのは現実的ではないですね。
承認されたということで、RDP接続します。

再度認証情報を確認すると、StartSessionの権限がないがためにエラーになっていました。

ジャストインタイムノードアクセスをするためにはStartSessionを付与しないことが条件なので、このエラーは解せません。
CloudTrailを眺めると、StartSessionがAccessDeniedとなった後にジャストインタイムノードアクセスの処理が行われているようです。

最終的にCreateGrantでAccessDeniedになっていることから、ここが怪しいですね。
実際のイベントを確認しましょう。
{
    "eventVersion": "1.11",
    "userIdentity": {
        "type": "AssumedRole",
        "principalId": "AROA6KUFAVPU36W4M7ZFJ:oi-531e4a9aa0ee-<iamユーザー名>",
        "arn": "arn:aws:sts::<AWSアカウントID>:assumed-role/SSM-JustInTimeAccessTokenRole/oi-531e4a9aa0ee-<iamユーザー名>",
        "accountId": "<AWSアカウントID>",
        "accessKeyId": "ASIA6KUFAVPU2KDFI7LY",
        "sessionContext": {
            "sessionIssuer": {
                "type": "Role",
                "principalId": "AROA6KUFAVPU36W4M7ZFJ",
                "arn": "arn:aws:iam::<AWSアカウントID>:role/SSM-JustInTimeAccessTokenRole",
                "accountId": "<AWSアカウントID>",
                "userName": "SSM-JustInTimeAccessTokenRole"
            },
            "attributes": {
                "creationDate": "2025-04-30T06:29:51Z",
                "mfaAuthenticated": "false"
            }
        },
        "invokedBy": "ssm-guiconnect.amazonaws.com"
    },
    "eventTime": "2025-04-30T06:29:59Z",
    "eventSource": "kms.amazonaws.com",
    "eventName": "CreateGrant",
    "awsRegion": "us-east-1",
    "sourceIPAddress": "ssm-guiconnect.amazonaws.com",
    "userAgent": "ssm-guiconnect.amazonaws.com",
    "errorCode": "AccessDenied",
    "errorMessage": "User: arn:aws:sts::<AWSアカウントID>:assumed-role/SSM-JustInTimeAccessTokenRole/oi-531e4a9aa0ee-<iamユーザー名> is not authorized to perform: kms:CreateGrant on resource: arn:aws:kms:us-east-1:<AWSアカウントID>:key/41aed227-ab0d-41ee-a758-0e1aafd35b8c because no session policy allows the kms:CreateGrant action",
    "requestParameters": null,
    "responseElements": null,
    "requestID": "ecab4a60-5c7d-456b-82ab-6e8bb0bf943b",
    "eventID": "f57ae65c-4c25-443c-af53-dbaf751668eb",
    "readOnly": false,
    "eventType": "AwsApiCall",
    "managementEvent": true,
    "recipientAccountId": "<AWSアカウントID>",
    "eventCategory": "Management"
}
SSM-JustInTimeAccessTokenRoleでCreateGrantの権限が不足していそうです。
SSM-JustInTimeAccessTokenRoleにアタッチされているIAMポリシーのAWSSystemsManagerJustInTimeAccessTokenPolicyを確認すると、以下ステートメントがありました。
    {
      "Sid" : "RdpKmsPermission",
      "Effect" : "Allow",
      "Action" : [
        "kms:CreateGrant"
      ],
      "Resource" : "arn:aws:kms:*:*:key/*",
      "Condition" : {
        "StringEquals" : {
          "aws:ResourceTag/SystemsManagerJustInTimeNodeAccessManaged" : "true"
        },
        "StringLike" : {
          "kms:ViaService" : "ssm-guiconnect.*.amazonaws.com"
        },
        "Bool" : {
          "aws:ViaAWSService" : "true"
        }
      }
    },
CreateGrantを叩くにはKMSキーに対してSystemsManagerJustInTimeNodeAccessManagedというタグを設定するのが必須のようです。
以下コマンドでKMSキーにこちらのタグを設定してあげます。
> aws kms tag-resource \
    --key-id 41aed227-ab0d-41ee-a758-0e1aafd35b8c \
    --tags TagKey=SystemsManagerJustInTimeNodeAccessManaged,TagValue=true
この状態で再度トライすると、接続できました。

アクティブな接続タブを確認すると、レコーディングステータスがレコーディングとなっていますね。

指定したS3バケットを覗いてみると、mp4のオブジェクトがいくつか出力されていました。

やはり、記録ファイルというのは動画でした。これは嬉しいですね。
記録された動画は若干カクつきますが、解像度は高めで文字が潰れて見えないということはありませんでした。
参考までにGIFアニメにすると以下のような感じです。

また、動画はセッションを切断したタイミングで処理されるようです。

切断前にOS再起動をしたり、停止をするとアップロードされない可能性があります。
きめ細かいアクセス制御と特権管理がしやすくなった
SSM Session Managerでノードへの接続時の承認管理に役立つジャストインタイムノードアクセス機能が追加されたアップデートを紹介しました。
きめ細かいアクセス制御と特権管理がしやすくなりましたね。EC2インスタンスが中心なワークロードで運用が大きく変わりそうなアップデートです。
AWS公式ドキュメントではSSM Session Managerの従来の接続方法から切り替える方法も紹介されていました。
運用に刺さる場合はスタンダードセッションから乗り換えを検討しましょう。
この記事が誰かの助けになれば幸いです。
以上、クラウド事業本部 コンサルティング部の のんピ(@non____97)でした!










