[AWS Systems Manager] AWS CLIでジャストインタイムノードアクセスをしてみた

[AWS Systems Manager] AWS CLIでジャストインタイムノードアクセスをしてみた

AWS CLIでもジャストインタイムノードアクセスは使用できるが、ポートフォワーディングはできなさそう
Clock Icon2025.05.08

ジャストインタイムノードアクセスは魅力的だけど、ポートフォワーディングできるか気になる

こんにちは、のんピ(@non____97)です。

皆さんはジャストインタイムノードアクセスでもSSM Session Managerのポートフォワーディングができるか気になったことはありますか? 私はあります。

SSMのポートフォワーディング機能を用いて、SSHやSFTP、RDP接続やDBへのアクセスすることがあります。

https://dev.classmethod.jp/articles/ssm-session-manage-port-forwarding/

https://dev.classmethod.jp/articles/aws-ssm-support-remote-host-port-forward/

ファイルの授受をする際には手元のSFTPツールやRDPクライアントを使いたいでしょうし、A5:SQL Mk-2やSSMSなどのSQLクライアントツールも手元のものを使いたいことが多いです。

つい先日ジャストインタイムノードアクセスなる機能がリリースされました。

https://dev.classmethod.jp/articles/aws-systems-manager-just-in-time-node-access/

ジャストインタイムノードアクセスを用いることで、プリンシパルにマネージドノードへの永続的な接続権限を付与することを回避し、自動承認や手動承認による一時的な権限付与を行うことが可能になります。

SSM Session Managerのポートフォワーディングを使う場合はAWS CLIを用いることになります。

先述の記事ではAWSマネジメントコンソールから接続する方法を紹介しましたが、AWS CLIでは試していませんでした。

実際に試してみましょう。

いきなりまとめ

  • AWS CLIでもジャストインタイムノードアクセスは使用できる
    • 取得する一時認証情報の有効期限は15分固定
    • SSM-JustInTimeAccessTokenRoleに付与されている権限で動作する
    • AWS CLIで操作する際はセッション名を固定にすることがお勧め
      • セッション名で誰が作成したアクセスリクエストか判別しており、アクセスリクエスト作成時のセッション名と違うセッション名では当該アクセスリクエストの一時認証情報を取得することができない
  • ただし、SSM Session Managerのポートフォワーディングとジャストインタイムノードアクセスは併用できない
    • ユーザーがコントロールできないセッションポリシーで、AWS-StartPortForwardingSessionを用いたssm:StartSessionが制限されている

やってみた

アクセスリクエストの作成

まずはアクセスリクエストの作成をします。

試しにAWSマネジメントコンソールで接続した時と同じようにstart-sessionで接続しようとすると、別APIを叩こうとするか確認します。

>  aws ssm start-session --target i-0d089c89e358c4c08

An error occurred (AccessDeniedException) when calling the StartSession operation: User: arn:aws:sts::<AWSアカウントID>:assumed-role/<申請者のIAMロール名>/botocore-session-1746585985 is not authorized to perform: ssm:StartSession on resource: arn:aws:ssm:us-east-1:<AWSアカウントID>:document/SSM-SessionManagerRunShell because no identity-based policy allows the ssm:StartSession action

はい、普通にエラーになりました。

それでは、start-access-requestでアクセスリクエストを作成します

> aws ssm start-access-request \
    --targets  Key=InstanceIds,Values=i-0d089c89e358c4c08 \
    --reason "どうしても今接続したいんです...!!!"
{
    "AccessRequestId": "oi-fba1914f1c6f"
}

アクセスリクエストの作成ができました。

なお、以下ドキュメントに記載のコマンド例は絶妙にオプション名や値の渡し方が実態と異なるので、AWS CLIのコマンドリファレンスを正とするのが良いでしょう。

https://docs.aws.amazon.com/systems-manager/latest/userguide/systems-manager-just-in-time-node-access-start-session.html

get-ops-itemと、list-ops-item-eventsでアクセスリクエストの情報とタイムラインを確認します。

> aws ssm get-ops-item --ops-item-id oi-fba1914f1c6f
{
    "OpsItem": {
        "CreatedBy": "arn:aws:sts::<AWSアカウントID>:assumed-role/<申請者のIAMロール名>/botocore-session-1746585985",
        "OpsItemType": "/aws/accessrequest",
        "CreatedTime": "2025-05-07T11:50:06.144000+09:00",
        "Description": "OpsItem created for AccessRequest KLSOsG_FIAMEIbw=.",
        "LastModifiedBy": "arn:aws:sts::<AWSアカウントID>:assumed-role/AWSServiceRoleForSystemsManagerJustInTimeAccess/JustInTimeAccessService",
        "LastModifiedTime": "2025-05-07T11:50:09.226000+09:00",
        "Notifications": [],
        "RelatedOpsItems": [],
        "Status": "PendingApproval",
        "OpsItemId": "oi-fba1914f1c6f",
        "Version": "1746586209226",
        "Title": "Access Request - 2025-05-07 02:50 UTC",
        "Source": "aws.ssm",
        "OperationalData": {
            "/aws/accessrequest/approvaldetails": {
                "Value": "どうしても今接続したいんです...!!!",
                "Type": "SearchableString"
            },
            "/aws/accessrequest/context": {
                "Value": "{\"accessTokenRole\":\"SSM-JustInTimeAccessTokenRole\",\"targets\":{\"instanceId\":\"arn:aws:ec2:us-east-1:<AWSアカウントID>:instance/i-0d089c89e358c4c08\"}}",
                "Type": "SearchableString"
            },
            "/aws/accessrequest/accessduration": {
                "Value": "PT3600S",
                "Type": "SearchableString"
            },
            "/aws/accessrequest/approvalworkflow": {
                "Value": "{\"approvalSteps\":[{\"stepName\":\"ManualApproval\",\"timeoutSeconds\":\"604800\",\"inputs\":{\"minRequiredApprovals\":\"1\",\"notificationArn\":null,\"approvers\":[{\"arn\":\"arn:aws:iam::<AWSアカウントID>:role/<承認者のIAMロール名>\",\"id\":\"\",\"metadata\":{\"minRequiredApprovals\":0,\"approverType\":\"IamRole\"}}]},\"outputs\":{\"approverDecisions\":[{\"<承認者のIAMロール名>\":\"PendingApproval\"}],\"approvalStatus\":\"PendingApproval\"}}]}",
                "Type": "SearchableString"
            },
            "/aws/accessrequest": {
                "Value": "{\"requester\":{\"sourceOpsItemId\":\"oi-fba1914f1c6f\",\"isReplica\":\"false\",\"arn\":\"arn:aws:sts::<AWSアカウントID>:assumed-role/<申請者のIAMロール名>/botocore-session-1746585985\",\"sourceRegion\":\"\",\"id\":\"\",\"sourceAccountId\":\"\"},\"approvalPolicy\":\"policy1\",\"approvalPolicyVersion\":\"1\",\"automationExecutionId\"
:\"98ca2275-c4d8-42a5-b129-4f903662b15f\"}",
                "Type": "SearchableString"
            }
        },
        "OpsItemArn": "arn:aws:ssm:us-east-1:<AWSアカウントID>:opsitem/oi-fba1914f1c6f"
    }
}

> aws ssm list-ops-item-events \
    --filters Key=OpsItemId,Values=oi-fba1914f1c6f,Operator=Equal
{
    "Summaries": [
        {
            "OpsItemId": "oi-fba1914f1c6f",
            "EventId": "aa86f235-84b7-44c2-a3ed-e641029e3961",
            "Source": "aws.ssm",
            "DetailType": "AccessRequestDecision",
            "Detail": "{\"eventTime\":1746586207719,\"status\":\"AutoDeny\",\"reason\":\"\",\"message\":\"AccessRequest was Denied by Cedar Policy Evaluation\"}",
            "CreatedBy": {
                "Arn": "arn:aws:iam::<AWSアカウントID>:role/aws-service-role/justintimeaccess.ssm.amazonaws.com/AWSServiceRoleForSystemsManagerJustInTimeAccess"
            },
            "CreatedTime": "2025-05-07T11:50:17.798000+09:00"
        },
        {
            "OpsItemId": "oi-fba1914f1c6f",
            "EventId": "33ec37de-ba56-4e02-9541-a0aeca070a8b",
            "Source": "aws.ssm",
            "DetailType": "Creation",
            "Detail": "{\"eventTime\":1746586206315}",
            "CreatedBy": {
                "Arn": "arn:aws:sts::<AWSアカウントID>:assumed-role/<申請者のIAMロール名>/botocore-session-1746585985"
            },
            "CreatedTime": "2025-05-07T11:50:16.380000+09:00"
        }
    ]
}

アクセスリクエスト時のコメントなどの各種情報を確認できました。

マネジメントコンソールからもアクセスリクエストが作成されていることを確認しました。

1.アクセスリクエストが作成されていることの確認-2.png

承認

承認をします。

承認もせっかくなので、AWS CLIで行います。

承認や拒否はsend-automation-signalで行います。

--automation-execution-idで指定するIDはget-ops-itemの出力結果のOpsItem.OperationalData./aws/accessrequest内のautomationExecutionIdです。

> aws ssm send-automation-signal \
    --automation-execution-id 98ca2275-c4d8-42a5-b129-4f903662b15f \
    --signal-type Approve \
    --payload '{"Comment":["OKです!!"]}'

> aws ssm get-ops-item --ops-item-id oi-fba1914f1c6f
{
    "OpsItem": {
        "CreatedBy": "arn:aws:sts::<AWSアカウントID>:assumed-role/<申請者のIAMロール名>/botocore-session-1746585985",
        "OpsItemType": "/aws/accessrequest",
        "CreatedTime": "2025-05-07T11:50:06.144000+09:00",
        "Description": "OpsItem created for AccessRequest KLSOsG_FIAMEIbw=.",
        "LastModifiedBy": "arn:aws:sts::<AWSアカウントID>:assumed-role/AWSServiceRoleForSystemsManagerJustInTimeAccess/JustInTimeAccessService",
        "LastModifiedTime": "2025-05-07T17:10:56.830000+09:00",
        "Notifications": [],
        "RelatedOpsItems": [],
        "Status": "Approved",
        "OpsItemId": "oi-fba1914f1c6f",
        "Version": "1746605456830",
        "Title": "Access Request - 2025-05-07 02:50 UTC",
        "Source": "aws.ssm",
        "OperationalData": {
            "/aws/accessrequest/approvaldetails": {
                "Value": "どうしても今接続したいんです...!!!",
                "Type": "SearchableString"
            },
            "/aws/accessrequest/context": {
                "Value": "{\"accessTokenRole\":\"SSM-JustInTimeAccessTokenRole\",\"targets\":{\"instanceId\":\"arn:aws:ec2:us-east-1:<AWSアカウントID>:instance/i-0d089c89e358c4c08\"}}",
                "Type": "SearchableString"
            },
            "/aws/accessrequest/accessduration": {
                "Value": "PT3600S",
                "Type": "SearchableString"
            },
            "/aws/accessrequest/approvalworkflow": {
                "Value": "{\"approvalSteps\":[{\"stepName\":\"ManualApproval\",\"timeoutSeconds\":\"604800\",\"inputs\":{\"minRequiredApprovals\":\"1\",\"notificationArn\":null,\"approvers\":[{\"arn\":\"arn:aws:iam::<AWSアカウントID>:role/<承認者のIAMロール名>\",\"id\":\"\",\"metadata\":{\"minRequiredApprovals\":0,\"approverType\":\"IamRole\"}}]},\"outputs\":{\"approverDecisions\":[{\"Decision\":\"Approve\",\"ApprovalDecisionTime\":\"2025-05-07T08:10:54.998302760Z\",\"Comment\":\"OKです!!\",\"EnhancedApprover\":\"<承認者のIAMロール名>\"}],\"approvalStatus\":\"Approved\"}}]}",
                "Type": "SearchableString"
            },
            "/aws/accessrequest/endtime": {
                "Value": "2025-05-07 09:10:56 UTC",
                "Type": "SearchableString"
            },
            "/aws/accessrequest": {
                "Value": "{\"requester\":{\"sourceOpsItemId\":\"oi-fba1914f1c6f\",\"isReplica\":\"false\",\"arn\":\"arn:aws:sts::<AWSアカウントID>:assumed-role/<申請者のIAMロール名>/
botocore-session-1746585985\",\"sourceRegion\":\"\",\"id\":\"\",\"sourceAccountId\":\"\"},\"approvalPolicy\":\"policy1\",\"approvalPolicyVersion\":\"1\",\"automationExecutionId\"
:\"98ca2275-c4d8-42a5-b129-4f903662b15f\"}",
                "Type": "SearchableString"
            },
            "/aws/accessrequest/starttime": {
                "Value": "2025-05-07 08:10:56 UTC",
                "Type": "SearchableString"
            }
        },
        "OpsItemArn": "arn:aws:ssm:us-east-1:<AWSアカウントID>:opsitem/oi-fba1914f1c6f"
    }
}

> aws ssm list-ops-item-events \
    --filters Key=OpsItemId,Values=oi-fba1914f1c6f,Operator=Equal
{
    "Summaries": [
        {
            "OpsItemId": "oi-fba1914f1c6f",
            "EventId": "482a0719-f48a-44b1-bc2e-ce3e0aebfdce",
            "Source": "aws.ssm",
            "DetailType": "StatusChange",
            "Detail": "{\"eventTime\":1746605456867,\"status\":\"Approved\"}",
            "CreatedBy": {
                "Arn": "arn:aws:iam::<AWSアカウントID>:role/aws-service-role/justintimeaccess.ssm.amazonaws.com/AWSServiceRoleForSystemsManagerJustInTimeAccess"
            },
            "CreatedTime": "2025-05-07T17:11:06.927000+09:00"
        },
        {
            "OpsItemId": "oi-fba1914f1c6f",
            "EventId": "fcd98fe0-9b72-4577-9148-6b8e2f673264",
            "Source": "aws.ssm",
            "DetailType": "ApproverDecision",
            "Detail": "{\"eventTime\":1746605455140,\"decision\":\"Approve\"}",
            "CreatedBy": {
                "Arn": "arn:aws:sts::<AWSアカウントID>:assumed-role/<承認者のIAMロール名>/<IAMユーザー名>"
            },
            "CreatedTime": "2025-05-07T17:11:05.200000+09:00"
        },
        {
            "OpsItemId": "oi-fba1914f1c6f",
            "EventId": "aa86f235-84b7-44c2-a3ed-e641029e3961",
            "Source": "aws.ssm",
            "DetailType": "AccessRequestDecision",
            "Detail": "{\"eventTime\":1746586207719,\"status\":\"AutoDeny\",\"reason\":\"\",\"message\":\"AccessRequest was Denied by Cedar Policy Evaluation\"}",
            "CreatedBy": {
                "Arn": "arn:aws:iam::<AWSアカウントID>:role/aws-service-role/justintimeaccess.ssm.amazonaws.com/AWSServiceRoleForSystemsManagerJustInTimeAccess"
            },
            "CreatedTime": "2025-05-07T11:50:17.798000+09:00"
        },
        {
            "OpsItemId": "oi-fba1914f1c6f",
            "EventId": "33ec37de-ba56-4e02-9541-a0aeca070a8b",
            "Source": "aws.ssm",
            "DetailType": "Creation",
            "Detail": "{\"eventTime\":1746586206315}",
            "CreatedBy": {
                "Arn": "arn:aws:sts::<AWSアカウントID>:assumed-role/<申請者のIAMロール名>/botocore-session-1746585985"
            },
            "CreatedTime": "2025-05-07T11:50:16.380000+09:00"
        }
    ]
}

承認されましたね。

ちなみに、承認者として指定されていないプリンシパルで承認しようとすると以下のようにエラーになります。

> aws ssm send-automation-signal \
    --automation-execution-id 98ca2275-c4d8-42a5-b129-4f903662b15f \
    --signal-type Approve \
    --payload '{"Comment":["OKです!!"]}'

An error occurred (InvalidAutomationSignalException) when calling the SendAutomationSignal operation: arn:aws:sts::<AWSアカウントID>:assumed-role/<IAMロール名>/botocore-session-1746604902 is not in the approver list of step ManualApproval. Valid approvers: [<承認者のIAMロール名>].

ジャストインタイムノードアクセスでSSMシェルアクセス

それではAWS CLIでアクセスします。

下準備としてget-access-tokenでジャストインタイムノードアクセスが承認されたことによって発行される一時認証情報を取得します。

>  aws ssm get-access-token \
    --access-request-id oi-fba1914f1c6f

An error occurred (AccessDeniedException) when calling the GetAccessToken operation: Invalid requesting identity.

エラーになります。

これは何回繰り返してもエラーになりました。

アクセスリクエストを作成したIAMロールにスイッチロールした状態でAWSマネジメントコンソールを確認すると、私からのリクエストの一覧に先ほどさ作成したアクセスリクエストが存在しません。

2.私からのリクエスト-2.png

よくよく先ほど作成したアクセスリクエストの申請者を確認するとbotocore-session-1746585985となっていました。

現在のセッション名を確認すると、以下のようにbotocore-session-1746605475と異なるセッション名になっていました。

> aws sts get-caller-identity
{
    "UserId": "AROA6KUFAVPUU2TOWVHN4:botocore-session-1746605475",
    "Account": "<AWSアカウントID>",
    "Arn": "arn:aws:sts::<AWSアカウントID>:assumed-role/<申請者のIAMロール名>/botocore-session-1746605475"
}

セッション名で判定している可能性が高そうですね。

以下記事を参考にセッション名を固定にします。

https://dev.classmethod.jp/articles/aws-cli-assume-role-with-session-name/

具体的には以下のようにしました

[profile <申請者のIAMロール名>]
region = us-east-1
mfa_serial = arn:aws:iam::<AWSアカウントID>:mfa/<IAMユーザー名>
role_arn = arn:aws:iam::<AWSアカウントID>:role/<申請者のIAMロール名>
source_profile = default
role_session_name = botocore-session-1746585985

この状態で再度一時認証情報を取得します。

>  aws ssm get-access-token \
    --access-request-id oi-fba1914f1c6f
{
    "Credentials": {
        "AccessKeyId": "ASIA..(中略)..LQ",
        "SecretAccessKey": "/YcE..(中略)..+7",
        "SessionToken": "IQoJb..(中略)..DgS7orvS",
        "ExpirationTime": "2025-05-07T17:47:59+09:00"
    },
    "AccessRequestStatus": "Approved"
}

取得できました。

セッション名に紐づくということで、AWS CLIを使用する場合はセッション名をIAMユーザー名などの固定にした方が良さそうですね。

ちなみに一時認証情報の有効期限は15分でした。get-access-tokenのオプションなどを確認しましたが、変更することオプションはありませんでした。

一時認証情報を環境変数にセットして、SSMのシェルアクセスをします。

>  export AWS_ACCESS_KEY_ID=ASIA..(中略)..LQ
>  export AWS_SECRET_ACCESS_KEY=/YcE..(中略)..+7
>  export AWS_SESSION_TOKEN=IQoJb..(中略)..DgS7orvS

>  aws sts get-caller-identity
{
    "UserId": "AROA6KUFAVPU36W4M7ZFJ:oi-fba1914f1c6f-botocore-session-1746585985",
    "Account": "<AWSアカウントID>",
    "Arn": "arn:aws:sts::<AWSアカウントID>:assumed-role/SSM-JustInTimeAccessTokenRole/oi-fba1914f1c6f-botocore-session-1746585985"
}

>  aws ssm start-session \
    --target i-0d089c89e358c4c08

Starting session with SessionId: oi-fba1914f1c6f-botocore-session-1746585985-t54zohydktvxkbvdxoclep3qxe
/bin/bash
cd /home/$(whoami)
sh-5.2$ /bin/bash
[ec2-user@ip-172-31-9-4 bin]$ cd /home/$(whoami)
[ec2-user@ip-172-31-9-4 ~]$
[ec2-user@ip-172-31-9-4 ~]$ whoami
ec2-user
[ec2-user@ip-172-31-9-4 ~]$
[ec2-user@ip-172-31-9-4 ~]$ ls -l
total 904
-rw-r--r--. 1 root root 922103 Apr  8 04:55 amazon-linux-2023-smb-client-access-file-server.html

はい、接続できました。

取得した一時認証情報のセッションはSSM-JustInTimeAccessTokenRoleというIAMロールの権限で動いているようですね。

ジャストインタイムノードアクセスでポートフォワーディング

それでは、本題のジャストインタイムノードアクセスでポートフォワーディングデス。

>  aws ssm start-session --target i-0d089c89e358c4c08 \
           --document-name AWS-StartPortForwardingSession \
           --parameters '{"portNumber":["22"],"localPortNumber":["20022"]}'

An error occurred (AccessDeniedException) when calling the StartSession operation: User: arn:aws:sts::<AWSアカウントID>:assumed-role/SSM-JustInTimeAccessTokenRole/oi-fba1914f1c6f-botocore-session-1746585985 is not authorized to perform: ssm:StartSession on resource: arn:aws:ssm:us-east-1::document/AWS-StartPortForwardingSession because no identity-based policy allows the ssm:StartSession action

おや、接続できません。

エラーメッセージからポートフォワーディングをする際に使用するSSMドキュメントであるAWS-StartPortForwardingSessionへの権限が付与されていないようです。

IAMロールSSM-JustInTimeAccessTokenRoleにアタッチされているAWSSystemsManagerJustInTimeAccessTokenPolicyを確認します。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "SsmStartSession",
            "Effect": "Allow",
            "Action": [
                "ssm:StartSession"
            ],
            "Resource": [
                "arn:aws:ec2:*:*:instance/*",
                "arn:aws:ssm:*:*:managed-instance/*",
                "arn:aws:ssm:*:*:document/SSM-SessionManagerRunShell"
            ]
        },
        {
            "Sid": "TerminateAndResumeSession",
            "Effect": "Allow",
            "Action": [
                "ssm:TerminateSession",
                "ssm:ResumeSession"
            ],
            "Resource": "arn:aws:ssm:*:*:session/*"
        },
        {
            "Sid": "GuiConnect",
            "Effect": "Allow",
            "Action": [
                "ssm-guiconnect:CancelConnection",
                "ssm-guiconnect:GetConnection",
                "ssm-guiconnect:StartConnection"
            ],
            "Resource": "*"
        },
        {
            "Sid": "SessionManagerKmsPermission",
            "Effect": "Allow",
            "Action": [
                "kms:GenerateDataKey"
            ],
            "Resource": "arn:aws:kms:*:*:key/*",
            "Condition": {
                "StringEquals": {
                    "aws:ResourceTag/SystemsManagerJustInTimeNodeAccessManaged": "true"
                }
            }
        },
        {
            "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"
                }
            }
        },
        {
            "Sid": "RdpStartSession",
            "Effect": "Allow",
            "Action": [
                "ssm:StartSession"
            ],
            "Resource": [
                "arn:aws:ec2:*:*:instance/*",
                "arn:aws:ssm:*:*:managed-instance/*",
                "arn:aws:ssm:*:*:document/AWS-StartPortForwardingSession"
            ],
            "Condition": {
                "StringEquals": {
                    "aws:CalledViaFirst": "ssm-guiconnect.amazonaws.com"
                }
            }
        },
        {
            "Sid": "SsmRdpSsoSetup",
            "Effect": "Allow",
            "Action": [
                "sso:ListDirectoryAssociations*",
                "identitystore:DescribeUser",
                "ssm:GetCommandInvocation"
            ],
            "Resource": "*",
            "Condition": {
                "StringEquals": {
                    "aws:CalledViaFirst": "ssm-guiconnect.amazonaws.com"
                }
            }
        },
        {
            "Sid": "SsmRdpSsoSetupSendCommand",
            "Effect": "Allow",
            "Action": [
                "ssm:SendCommand"
            ],
            "Resource": [
                "arn:aws:ec2:*:*:instance/*",
                "arn:aws:ssm:*:*:managed-instance/*",
                "arn:aws:ssm:*:*:document/AWSSSO-CreateSSOUser"
            ],
            "Condition": {
                "StringEquals": {
                    "aws:CalledViaFirst": "ssm-guiconnect.amazonaws.com"
                }
            }
        }
    ]
}

AWS-StartPortForwardingSessionへの権限はありますが、リクエストを実行した最初のサービスがssm-guiconnect.amazonaws.comである必要があるようです。

IAMロールSSM-JustInTimeAccessTokenRoleに以下新規ポリシーをインラインで追加します。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "SsmStartSession",
            "Effect": "Allow",
            "Action": [
                "ssm:StartSession"
            ],
            "Resource": [
                "arn:aws:ec2:*:*:instance/*",
                "arn:aws:ssm:*:*:managed-instance/*",
                "arn:aws:ssm:*:*:document/AWS-StartPortForwardingSession"
            ]
        }
    ]
}

この状態で再度一時認証情報を取得し、再度接続します。

> aws ssm start-session --target i-0d089c89e358c4c08 \
    --document-name AWS-StartPortForwardingSession \
    --parameters '{"portNumber":["22"],"localPortNumber":["20022"]}'

An error occurred (AccessDeniedException) when calling the StartSession operation: User: arn:aws:sts::984900217833:assumed-role/SSM-JustInTimeAccessTokenRole/oi-46d4f663fc5e-<AWS CLIセッション名>> is not authorized to perform: ssm:StartSession on resource: arn:aws:ssm:us-east-1::document/AWS-StartPortForwardingSession because no session policy allows the ssm:StartSession action

はい、今度もエラーになりました。

エラーメッセージは最初と同じかと思いましたが、because no session policy allows the ssm:StartSession actionとセッションポリシーで許可されていないようです。

参考までに、この時のCloudTrailのイベントは以下のとおりです。

{
    "eventVersion": "1.11",
    "userIdentity": {
        "type": "AssumedRole",
        "principalId": "AROA6KUFAVPU36W4M7ZFJ:oi-fba1914f1c6f-botocore-session-1746585985",
        "arn": "arn:aws:sts::<AWSアカウントID>:assumed-role/SSM-JustInTimeAccessTokenRole/oi-fba1914f1c6f-botocore-session-1746585985",
        "accountId": "<AWSアカウントID>",
        "accessKeyId": "ASIA6KUFAVPU7NH4CXUN",
        "sessionContext": {
            "sessionIssuer": {
                "type": "Role",
                "principalId": "AROA6KUFAVPU36W4M7ZFJ",
                "arn": "arn:aws:iam::<AWSアカウントID>:role/SSM-JustInTimeAccessTokenRole",
                "accountId": "<AWSアカウントID>",
                "userName": "SSM-JustInTimeAccessTokenRole"
            },
            "attributes": {
                "creationDate": "2025-05-07T08:53:47Z",
                "mfaAuthenticated": "false"
            }
        }
    },
    "eventTime": "2025-05-07T08:57:22Z",
    "eventSource": "ssm.amazonaws.com",
    "eventName": "StartSession",
    "awsRegion": "us-east-1",
    "sourceIPAddress": "<IPアドレス>",
    "userAgent": "aws-cli/2.27.5 md/awscrt#0.26.1 ua/2.1 os/macos#24.4.0 md/arch#arm64 lang/python#3.13.3 md/pyimpl#CPython cfg/retry-mode#standard md/installer#source md/prompt#off md/command#ssm.start-session",
    "errorCode": "AccessDenied",
    "errorMessage": "User: arn:aws:sts::<AWSアカウントID>:assumed-role/SSM-JustInTimeAccessTokenRole/oi-fba1914f1c6f-botocore-session-1746585985 is not authorized to perform: ssm:StartSession on resource: arn:aws:ssm:us-east-1::document/AWS-StartPortForwardingSession because no session policy allows the ssm:StartSession action",
    "requestParameters": null,
    "responseElements": null,
    "requestID": "5454dde7-bcdf-441d-a264-12393bc48a35",
    "eventID": "c16d1eda-13e8-442c-9f29-5806faec724d",
    "readOnly": false,
    "eventType": "AwsApiCall",
    "managementEvent": true,
    "recipientAccountId": "<AWSアカウントID>",
    "eventCategory": "Management",
    "tlsDetails": {
        "tlsVersion": "TLSv1.2",
        "cipherSuite": "ECDHE-RSA-AES128-GCM-SHA256",
        "clientProvidedHostHeader": "ssm.us-east-1.amazonaws.com"
    }
}

CloudTrailにてGetAccessToken近辺でセッションポリシーを設定していそうなイベントを確認しましたが、特にありませんでした。

また、get-access-tokenのオプションを確認しましたが、セッションポリシーを制御するものはありませんでした。

ということで、私が調べた限りでは現状、ジャストインタイムノードアクセスではポートフォワーディングはできないようです。

AWS CLIでもジャストインタイムノードアクセスは使用できるが、ポートフォワーディングはできなさそう

AWS CLIでジャストインタイムノードアクセスをしてみました。

一方、冒頭に記載したポートフォワーディングはできなさそうです。

そのため、EC2インスタンスへSSM Session Managerで接続したい全IAMユーザー、全IAMロールからStartSessionの権限を削除し、ジャストインタイムノードアクセスに完全に寄せてしまう運用は現状難しそうです。

私が見てきた環境ではポートフォワーディングの需要はそれなりにあるので、現時点での採用難易度は高いように感じています。

セッションポリシーのコントロールをユーザー側でできるようになると嬉しいですね。

この記事が誰かの助けになれば幸いです。

以上、クラウド事業本部 コンサルティング部の のんピ(@non____97)でした!

Share this article

facebook logohatena logotwitter logo

© Classmethod, Inc. All rights reserved.