EC2にSSHする際の鍵の管理って大変ですよねー
22ポートの穴あけもしなければいけないので管理が面倒。。。
そんなお悩みはAWS Systems ManagerのSession Managerを使用すれば解決できます
概要や動作するイメージからTerraformでの設定方法を紹介していきます
Session Managerとは
鍵不要、22ポートの穴あけ不要でEC2へアクセスできるAWS Systems Managerの機能の1つ。
アクセスするにはAWSコンソールやAWS CLIを使用します
操作ログはCloudWatch LogsやS3で保管することができます。
アクセスしたIAMユーザの履歴をCloudTrailに残すこともできます。
プライベートサブネットのEC2にもアクセスできるので踏み台サーバがいりません。
また、IAMロールでIAMユーザのアクセス制御を行えます
Session Managerに関する公式ドキュメントは↓になります
イメージ
実装に入る前に
Session ManagerはどのようにしてEC2へアクセスするか気になりませんか?
BlackBeltの60Pに答えがありました。
- AWS コンソールやCLIでSession Managerへアクセス
- SSM Agent経由でEC2にアクセス
⇒SSM AgentがSession Managerを見に行くため、EC2側にIAMロールが必要
操作ログもEC2にS3やCloudWatch Logsへのアクセス権限(IAMロール)がないとダメです
ゴール
- パブリックサブネットにあるEC2にSession Managerを使用してアクセスする
- 操作ログがS3に出力されたことを確認する
実装方針
↑を参考に今回は以下のステップで実装していきます
- EC2インスタンスにSSM Agentをインストールする
- 操作ログ用のS3バケットを作成する
- Session ManagerおよびS3にアクセスするIAMポリシーを作成する
- IAMロールを作成する
- インスタンスプロファイルを作成し、EC2にアタッチする
- 操作ログをS3に保存するようにSession Managerの設定をする
やらないこと
クライアント(IAMユーザ)ー EC2間で送信されるセッションデータの暗号化はしません。
Terraform
EC2インスタンスにSSM Agentをインストールする
EC2にSSM AgentがインストールされていないとSession Managerが使えません。
ただ、特定のAMIを使用していればすでにインストールされており、作業はありません。
私が使用しているAmazon Linux 2023はその対象でありすでにインストールされています
SSM Agentをインストール済みのAMIは↓をご覧ください
インストール済みのAMIではなかった方は↓を参考にしてみてください
操作ログ用のS3バケットを作成する
操作ログを保存しておくS3バケットを作成します。
パブリックアクセスもブロックしておきます
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
######################## # S3 ######################## # ログ用S3バケット resource "aws_s3_bucket" "log_bucket" { # バケット名は世界で一意のため、各々変えてください bucket = "example-log-bucket" } # ブロックパブリックアクセス resource "aws_s3_bucket_public_access_block" "log_bucket" { bucket = aws_s3_bucket.log_bucket.id block_public_acls = true block_public_policy = true ignore_public_acls = true restrict_public_buckets = true } |
Session ManagerおよびS3にアクセスするIAMポリシーを作成する
公式ドキュメントによると、
Session Managerを使うにはAmazonSSMManagedInstanceCoreというIAMポリシーが必要。
操作ログをS3に保存するために必要な権限はこちらを参考に、
- s3:PutObject
- s3:GetEncryptionConfiguration
なので、IAMポリシーを作成する流れとしては
- AmazonSSMManagedInstanceCoreを参照する
- 1.にS3系の権限を追加する
- 2.をもとに新しいIAMポリシーを作成する
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
# AmazonSSMManagedInstanceCoreを参照 data "aws_iam_policy" "ssm_core" { name = "AmazonSSMManagedInstanceCore" } # 操作ログを保存するためにS3への操作権限を追加 data "aws_iam_policy_document" "ec2_ssm_policy_doc" { source_policy_documents = [data.aws_iam_policy.ssm_core.policy] statement { effect = "Allow" actions = [ "s3:PutObject", ] resources = [ "${aws_s3_bucket.log_bucket.arn}", "${aws_s3_bucket.log_bucket.arn}/*" ] } statement { effect = "Allow" actions = [ "s3:GetEncryptionConfiguration" ] resources = [ "*" ] } } # SSMを使用するためのIAMポリシーの作成 resource "aws_iam_policy" "ec2_ssm_policy" { name = "ec2_ssm_policy" policy = data.aws_iam_policy_document.ec2_ssm_policy_doc.json } |
IAMロールを作成する
ここでやっていることは
- aws_iam_roleでIAMロールを作成。
- EC2がIAMポリシーを使えるように信頼ポリシーを定義し、IAMロールに紐づけ。
- IAMポリシーをIAMロールへ紐づけ。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
# IAMロール resource "aws_iam_role" "ec2_role" { name = "ec2_role" assume_role_policy = data.aws_iam_policy_document.assume_role.json } # 信頼ポリシー data "aws_iam_policy_document" "assume_role" { statement { actions = ["sts:AssumeRole"] principals { type = "Service" identifiers = ["ec2.amazonaws.com"] } } } # IAMポリシーをIAMロールに紐づける resource "aws_iam_role_policy_attachment" "ssm_core" { role = aws_iam_role.ec2_role.name policy_arn = aws_iam_policy.ec2_ssm_policy.arn } |
インスタンスプロファイルを作成し、EC2にアタッチする
先ほど作成したIAMロールをもとにインスタンスプロファイルを作成します
1 2 3 4 5 |
# インスタンスプロファイル resource "aws_iam_instance_profile" "main" { name = "instance_profile" role = aws_iam_role.ec2_role.name } |
これをEC2にアタッチします。すでにあるaws_instanceブロックに1行追加します
1 2 3 4 5 6 |
resource "aws_instance" "main" { ---略------------------------- iam_instance_profile = aws_iam_instance_profile.main.name } |
操作ログをS3に保存するようにSession Managerの設定をする
Session Managerの設定はSSMのドキュメントを使用します。
具体的には、↓のリポジトリを参考にコードを書きました
プロパティ | 説明 |
name | ドキュメント名。 |
document_type | ドキュメントのタイプ。 Session Managerで使用するため、「Session」を指定。 |
document_format | ドキュメントのフォーマット。JSONかYAMLか選べる |
content | ドキュメントの中身。 フォーマットをJSONにしたので、jsonencodeでJsonへ変換。 |
schemaVersion | スキーマのバージョン。 2023/11時点で1.0のみサポートされている。 |
description | 説明。わかりやすいように入れておけばOK |
sessionType | セッションのタイプ。 参考にしたコードから「Standard_Stream」のまま。 |
inputs | セッションに対する設定。 |
s3BucketName | ログを保存するS3バケット名。 |
s3KeyPrefix | S3のどの階層に保存するか。 |
s3EncryptionEnabled | 操作ログを暗号化するか。 trueにした場合、S3は暗号化されている必要がある。 ただ、デフォルトでS3は暗号化されているため設定は必要ない。 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
# ドキュメント resource "aws_ssm_document" "session_manager_prefs" { name = "Test-SSM-SessionManagerRunShell" document_type = "Session" document_format = "JSON" content = jsonencode({ schemaVersion = "1.0" description = "Document to hold regional settings for Session Manager" sessionType = "Standard_Stream" inputs = { # ログを保存するS3のバケット名に書き換えてください s3BucketName = "example-log-bucket" s3KeyPrefix = "session_manager/" s3EncryptionEnabled = true } }) } |
完成したコード
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 |
######################## # S3 ######################## # ログ用S3バケット resource "aws_s3_bucket" "log_bucket" { # バケット名は世界で一意のため、各々変えてください bucket = "example-log-bucket" } # ブロックパブリックアクセス resource "aws_s3_bucket_public_access_block" "log_bucket" { bucket = aws_s3_bucket.log_bucket.id block_public_acls = true block_public_policy = true ignore_public_acls = true restrict_public_buckets = true } ######################## # IAM ######################## # AmazonSSMManagedInstanceCoreを参照 data "aws_iam_policy" "ssm_core" { name = "AmazonSSMManagedInstanceCore" } # 操作ログを保存するためにS3への操作権限を追加 data "aws_iam_policy_document" "ec2_ssm_policy_doc" { source_policy_documents = [data.aws_iam_policy.ssm_core.policy] statement { effect = "Allow" actions = [ "s3:PutObject", ] resources = [ "${aws_s3_bucket.log_bucket.arn}", "${aws_s3_bucket.log_bucket.arn}/*" ] } statement { effect = "Allow" actions = [ "s3:GetEncryptionConfiguration" ] resources = [ "*" ] } } # SSMを使用するためのIAMポリシーの作成 resource "aws_iam_policy" "ec2_ssm_policy" { name = "ec2_ssm_policy" policy = data.aws_iam_policy_document.ec2_ssm_policy_doc.json } # IAMロール resource "aws_iam_role" "ec2_role" { name = "ec2_role" assume_role_policy = data.aws_iam_policy_document.assume_role.json } # 信頼ポリシー data "aws_iam_policy_document" "assume_role" { statement { actions = ["sts:AssumeRole"] principals { type = "Service" identifiers = ["ec2.amazonaws.com"] } } } # IAMポリシーをIAMロールに紐づける resource "aws_iam_role_policy_attachment" "ssm_core" { role = aws_iam_role.ec2_role.name policy_arn = aws_iam_policy.ec2_ssm_policy.arn } # インスタンスプロファイル resource "aws_iam_instance_profile" "main" { name = "instance_profile" role = aws_iam_role.ec2_role.name } ######################## # EC2 ######################## resource "aws_instance" "main" { ---略------------------------- iam_instance_profile = aws_iam_instance_profile.main.name } ######################## # SSM ######################## # ドキュメント resource "aws_ssm_document" "session_manager_prefs" { name = "Test-SSM-SessionManagerRunShell" document_type = "Session" document_format = "JSON" content = jsonencode({ schemaVersion = "1.0" description = "Document to hold regional settings for Session Manager" sessionType = "Standard_Stream" inputs = { # ログを保存するS3のバケット名に書き換えてください s3BucketName = "example-log-bucket" s3KeyPrefix = "session_manager/" s3EncryptionEnabled = true } }) } |
動作確認
コードが完成したら、terraform applyして動作確認をしていきます
Session Managerを使ってEC2にSSH接続する
AWSコンソールを使用してSSH接続を試してみます。
CLIでアクセスする方法は下記を参考にしてみてください
Systems Manager > Session Manager にいき、「セッションの開始」をクリック
接続したいインスタンスを選択して、「Next」をクリック
Terraformで作成したSSM ドキュメントを選択し、「Next」をクリック
「Start session」をクリックして、EC2にアクセス
アクセスできました!
右上の「終了」をクリックすると、ダイアログが表示されます。
もう一度「終了」をクリックすると、セッションを閉じることができます
操作ログの確認
操作ログの保存先のS3バケットを見てみると、session_managerというフォルダがあります
※フォルダ名はSSM ドキュメントのs3KeyPrefixで設定した文字列
この中にlogファイルが保存されています!
SSM ドキュメントも確認してみる
一応、SSM ドキュメントも確認しておきます
Systems Manager > ドキュメント > 自己所有 で確認できます
最後に….ハマりポイント
S3にログが保存されず、かなりハマりました。
原因はIAMロールに適切な権限を設定していなかったから。
エラーメッセージが出るわけではないので原因の特定に時間がかかりました。
S3に操作ログが保存されないよーという方は
インスタンスプロファイルのIAMロールを確認してみてください
参考
https://pages.awscloud.com/rs/112-TZM-766/images/20200212_AWSBlackBelt_SystemsManager_0214.pdf
コメント