🙆

Session Managerの詰まりポイント

2023/07/29に公開

はじめに

今回はプライベートサブネットのEC2にSession Managerを使って接続する方法を解説します。
私は初めてSession Managerを使った時はどこに何を作ればよいか分からず非常に苦労した思い出があります。
そこで、Session Managerを作成する際に、どこに何を作れば良いかの?という部分に焦点を当ててみたいと思います。

今回はterraformを使って作成していますが、どこに何を作成すれば良いか?ということが理解できれば
マネジメントコンソールからでも問題なく作成できると思います。
全体のコードはgithubに置いてます。
https://github.com/Sou-y-g/CT-Subject/tree/main/week8

Session Manager

まずは簡単にSession Managerの特徴です。
Session Managerはポートに依存せず、SSHを使わずにブラウザベースでEC2へ接続ができるという機能です。
さらにセッション中のログをCloudWatch LogsやS3へ保存することも可能です。

最近はEC2 Instance Connect Endpointというサービスを使って簡単にプライベートサブネットのEC2に接続できるようになりました。
しかし、どうしてもSSHを使えない場合や、接続セッションのログを監査したいという場合は、CloudWatch LogsやS3にログを出力できるSession Managerを使う必要があります。

必要なリソース

それでは、必要なリソースを見ていきましょう。
先に全体像はこのようになります。

では、一つずつ分解していきましょう。

SSM Agent

まずはEC2にSystems ManagerのSSM Agentがインストールされている必要があります。
AmazonLinux 2やAmazonLinux 2023, Ubuntu Serverのように最初からSSM AgentがインストールされたAMIもあります。
https://docs.aws.amazon.com/ja_jp/systems-manager/latest/userguide/ami-preinstalled-agent.html

このSSM Agentを使ってSystems Managerに対してポーリングをすることで
私たちが命令したコマンドをSystems Manager経由でSSM Agentが受け取ります。

SSM AgentはEC2以外にも、物理サーバーや、仮想サーバーにもインストールすることが可能です。

VPCエンドポイント

Session Managerで接続する場合は3つのインターフェイス型のVPCエンドポイントが必要です。

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

コードにするとこのようになります。

VPCエンドポイント
vpc.tf
#VPC_Endpoint x3(type:Interface)
resource "aws_vpc_endpoint" "ssm" {
  vpc_id             = aws_vpc.vpc.id
  service_name       = "com.amazonaws.${var.region}.ssm"
  vpc_endpoint_type  = "Interface"
  security_group_ids = [aws_security_group.endpoint-sg.id]
  subnet_ids         = [aws_subnet.private.id]
  private_dns_enabled = true

  tags = {
    Name = "${var.tag}-vpc-endpoint"
  }
}

resource "aws_vpc_endpoint" "ec2messages" {
  vpc_id             = aws_vpc.vpc.id
  service_name       = "com.amazonaws.${var.region}.ec2messages"
  vpc_endpoint_type  = "Interface"
  security_group_ids = [aws_security_group.endpoint-sg.id]
  subnet_ids         = [aws_subnet.private.id]
  private_dns_enabled = true

  tags = {
    Name = "${var.tag}-vpc-endpoint"
  }
}

resource "aws_vpc_endpoint" "ssmmessages" {
  vpc_id             = aws_vpc.vpc.id
  service_name       = "com.amazonaws.${var.region}.ssmmessages"
  vpc_endpoint_type  = "Interface"
  security_group_ids = [aws_security_group.endpoint-sg.id]
  subnet_ids         = [aws_subnet.private.id]
  private_dns_enabled = true

  tags = {
    Name = "${var.tag}-vpc-endpoint"
  }
}

セキュリティグループ

Session Managerに最低限必要なセキュリティグループは2つです。
「VPCエンドポイントのセキュリティグループ」と「EC2のセキュリティグループ」です。

まずはVPCエンドポイントのセキュリティグループです。
VPCエンドポイントのセキュリティグループはHTTPSのインバウンドのみが必要です。

VPCエンドポイントのセキュリティグループ
module/network/main.tf
# Endpoint sg
resource "aws_security_group" "endpoint-sg" {
  name   = "for endpoint"
  vpc_id = aws_vpc.vpc.id

  ingress {
    from_port   = 443
    to_port     = 443
    protocol    = "tcp"
  }

  tags = {
    Name = "${var.tag}-endpoint-sg"
  }
}

VPCエンドポイントもEC2も同じVPC内なので、CIDR範囲はVPC内としています。

これはEC2からの通信を受け入れるためのセキュリティグループです。

次にEC2のセキュリティグループです。
これはHTTPSのアウトバウンドのみが必要です。

EC2のセキュリティグループ
module/ec2/main.tf
# EC2 SecurityGroup for connect to SMM
resource "aws_security_group" "sg_ec2" {
  name   = "for connect to ssm"
  vpc_id = var.vpc_id

  egress {
    from_port   = 443
    to_port     = 443
    protocol    = "tcp"
    cidr_blocks = [var.vpc_cidr]
  }

  tags = {
    Name = "${var.tag}-sg"
  }
}

最初の説明にあったように、EC2はSSM Agentを使ってSSMに対してポーリングを行います。
そのため、EC2はインバウンドではなく、アウトバウンドを設定します。

IAMロール

Session Managerを使うためには、EC2に「AmazonSSMManagedInstanceCore」というポリシーが必要です。

IAMロール
module/ec2/main.tf
# IAM Role & 信頼ポリシー
resource "aws_iam_role" "role" {
  name = "ssm-role"
  assume_role_policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        Action = "sts:AssumeRole"
        Effect = "Allow"
        Principal = {
          Service = "ec2.amazonaws.com"
        }
      }
    ]
  })
}

# Session Manager用のPolicy
resource "aws_iam_role_policy_attachment" "policy" {
  policy_arn = "arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore"
  role       = aws_iam_role.role.name
}

# Profile
resource "aws_iam_instance_profile" "profile" {
  name = "ssm-profile"
  role = aws_iam_role.role.name
}

接続

これで各リソースが作成できたので、EC2のマネジメントコンソールから接続してみたいと思います。
EC2の一覧から接続するEC2を選択して「接続」を押します。

次に、「セッションマネージャー」のタブを選択して「接続」を押します。

これで接続ができました!

注意点

コスト

インターフェイス型のエンドポイントは時間単位で料金がかかります。
SessionManagerの場合は最低3つのエンドポイントが必要なため、3つ分の料金がかかります。

EC2 Instance Connect Endpointは無料なので、それと比べると高く感じてしまいますね。

EC2のマネコンから接続できない!

設定は間違いないはずなのにEC2のマネコンから接続ができない!という事が以前に何度かありました。
私の経験では、各リソースを作成してすぐの場合は、EC2のマネコン上では以下のような画面が表示されました。

大体の場合はしばらく時間を置くと接続できるようになりました。
どうしてもダメな時は、EC2を再起動すると繋がったということもありました。

繋がらない時は一度試してみて下さい。

まとめ

今回は意外とハマりやすい?Session Managerについてまとめてみました。
SSM Agentがポーリングを行っているというのは知らなかったので、よい勉強になりました。

参考資料
https://dev.classmethod.jp/articles/terraform-session-manager-linux-ec2-vpcendpoint/

GitHubで編集を提案

Discussion