0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

EC2にSSM接続できる環境のテンプレートを作る

Posted at

初めに

以前👇の記事で、Terraformの環境を整備しました。

今回の記事ではこの環境を使って検証用のLinuxサーバを構築するテンプレートを作ってみようと思います。

目次

  1. 基本設定
  2. VPC、サブネットの作成
  3. IAMロールの作成
  4. VPCエンドポイントの作成
  5. EC2の作成
  6. 構築

リソース構築

基本設定

tfファイルはモジュールごとに分割して管理する方法もありますが、今回は大した量のコードではないので1つのtfファイルに全記述をします。

それでは早速リソースを記述する前の基本設定を書いていきます。

main.tf
terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 6.0"
    }
  }
  required_version = ">= 1.13.0"
}

provider "aws" {
    region = "ap-northeast-1"
    default_tags {
        tags = {
          terraform = "true"
          }
    }
}

terraform セクション

  • required_providersでは利用するプロバイダーの設定を記載します。
    今回はAWSのみなので、awsセクションのみの記載で、source = "hashicorp/aws"でTerraform公式のAWSプロバイダを利用するようにし、version = "~> 6.0"の記載でバージョンを6.XX系に固定します。

provider "aws" セクション

  • 上記で設定した、プロバイダーに関する設定を記載します。今回はregion = "ap-northeast-1"と記載し作成するリソースを東京リージョンと明示的に指定します。
  • Terraformで管理するリソースすべてにタグを付与したいので、default_tagsセクションでリソースに付与するタグを設定します。

VPC、サブネットの作成

続いてはVPCとサブネットを記載します。

main.tf
# --------------------------
# VPC & Private Subnet
# --------------------------
resource "aws_vpc" "main" {
  cidr_block           = "10.0.0.0/16"
  enable_dns_support   = true
  enable_dns_hostnames = true

  tags = { Name = "miyazaki-ssm-vpc" }
}

resource "aws_subnet" "private" {
  vpc_id                  = aws_vpc.main.id
  cidr_block              = "10.0.1.0/24"
  map_public_ip_on_launch = false
  availability_zone       = "ap-northeast-1a"

  tags = { Name = "miyazaki-private-subnet" }
}

resource "aws_security_group" "ec2_sg" {
  name        = "ssm-ec2-sg"
  description = "Allow SSM communication"
  vpc_id      = aws_vpc.main.id

  egress {
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }

  tags = { Name = "miyazaki-ssm-ec2-sg" }
}

resource "aws_security_group" "vpcep_sg" {
  name        = "miyazaki-ssm-vpcep-sg"
  description = "Allow SSM communication"
  vpc_id      = aws_vpc.main.id

  ingress {
    from_port   = 443
    to_port     = 443
    protocol    = "TCP"
    cidr_blocks = ["0.0.0.0/0"]
  }

  tags = { Name = "miyazaki-ssm-vpcep-sg" }
}

resource "aws_vpc" "main" セクション

  • aws_vpcという機能を使ってVPCを作成します。作成するリソースにはローカルで使えるmainという名前を与えます。 ※以降もresourceの文法は同じになるので説明は省略します。
  • cidr_block = "10.0.0.0/16"名前の通りCIDR範囲を指定します。
  • enable_dns_support = true VPC内のDNS解決を有効にします。
  • enable_dns_hostnames = true VPC内のDNSホスト名を有効にします。
  • tags 付与したいタグを記載します。  ※以降はtagsの説明は省略します。

resource "aws_subnet" "private" セクション

  • vpc_id = aws_vpc.main.id どのVPCにサブネットを作成するか指定します。aws_vpc.main.idで👆で作成したVPCのVPCIDを指定します。
  • map_public_ip_on_launch = false パブリックIPv4の自動割り当ての設定です。EC2へはSSMで接続するので、今回はfalseを指定します。
  • availability_zone = "ap-northeast-1a" サブネットを"ap-northeast-1a"に作成する記載です。

resource "aws_security_group" セクション

  • EC2用にアウトバウンドのみ許可したSCG、VPCエンドポイント用の443のインバウンドを許可したルールを持つSCGを作ります。
  • egressでアウトバウンドルール、ingressでインバウンドルールを設定します。

IAMロールの作成

続いてはEC2にアタッチするIAMロールを作成していきます。

main.tf
# --------------------------
# IAM Role for EC2 SSM
# --------------------------
resource "aws_iam_role" "ec2_ssm_role" {
  name = "miyazaki-ec2-ssm-role"

  assume_role_policy = jsonencode({
    Version = "2012-10-17",
    Statement = [{
      Effect = "Allow",
      Principal = { Service = "ec2.amazonaws.com" },
      Action = "sts:AssumeRole"
    }]
  })
}

resource "aws_iam_role_policy_attachment" "ssm_core" {
  role       = aws_iam_role.ec2_ssm_role.name
  policy_arn = "arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore"
}

resource "aws_iam_instance_profile" "ec2_ssm_profile" {
  name = "miyazaki-ec2-ssm-profile"
  role = aws_iam_role.ec2_ssm_role.name
}

resource "aws_iam_role" "ec2_ssm_role" セクション

  • EC2に付与する用のIAMロールを作成します。
  • assume_role_policy = jsonencode で信頼されたエンティティを指定しています。今回はEC2がこのロールを引き受けられるように設定しています。

resource "aws_iam_role_policy_attachment" "ssm_core" セクション

  • ロールにポリシーをアタッチする記載です。
  • role = aws_iam_role.ec2_ssm_role.name で対象のロールを指定しています。
  • policy_arn = "arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore" でアタッチするポリシーを指定しています。今回はAmazonSSMManagedInstanceCore を付与しています。

resource "aws_iam_instance_profile" "ec2_ssm_profile" セクション

  • インスタンスプロファイルを作成する記載です。
  • name = "miyazaki-ec2-ssm-profile" で作成するインスタンスプロファイル名を、role = aws_iam_role.ec2_ssm_role.name でプロファイルに紐づけるIAMロールを指定しています。

VPCエンドポイントの作成

main.tf
# --------------------------
# VPC Endpoints for SSM
# --------------------------

resource "aws_vpc_endpoint" "ssm" {
  vpc_id              = aws_vpc.main.id
  service_name        = "com.amazonaws.ap-northeast-1.ssm"
  vpc_endpoint_type   = "Interface"
  subnet_ids          = [aws_subnet.private.id]
  security_group_ids  = [aws_security_group.vpcep_sg.id]
  private_dns_enabled = true

  tags = { Name = "miyazaki-ssm-endpoint" }
}

resource "aws_vpc_endpoint" "ec2messages" {
  vpc_id              = aws_vpc.main.id
  service_name        = "com.amazonaws.ap-northeast-1.ec2messages"
  vpc_endpoint_type   = "Interface"
  subnet_ids          = [aws_subnet.private.id]
  security_group_ids  = [aws_security_group.vpcep_sg.id]
  private_dns_enabled = true

  tags = { Name = "miyazaki-ec2messages-endpoint" }
}

resource "aws_vpc_endpoint" "ssmmessages" {
  vpc_id              = aws_vpc.main.id
  service_name        = "com.amazonaws.ap-northeast-1.ssmmessages"
  vpc_endpoint_type   = "Interface"
  subnet_ids          = [aws_subnet.private.id]
  security_group_ids  = [aws_security_group.vpcep_sg.id]
  private_dns_enabled = true

  tags = { Name = "miyazaki-ssmmessages-endpoint" }
}

resource "aws_vpc_endpoint" "ssm" セクション

  • service_name = "com.amazonaws.ap-northeast-1.ssm" で作成するVPCエンドポイントのサービス名を指定します。
  • vpc_endpoint_type = "Interface" は作成するエンドポイントのタイプを指定します。今回はすべて"Interface" 型で作成します。
  • security_group_ids = [aws_security_group.vpcep_sg.id] エンドポイントに付与するセキュリティグループを指定します。付与するものはVPC作成の際に合わせて作成した、エンドポイント用のセキュリティグループです。
  • private_dns_enabled = true VPC内でDNSをこのエンドポイントで解決させる必要があるのですべてtrue で作成します。

※※※他2つのリソースもサービス名が異なるだけなので説明は割愛します。

EC2の作成

main.tf
# --------------------------
# EC2 Instance
# --------------------------
data "aws_ami" "amazon_linux" {
  most_recent = true
  owners      = ["amazon"]

  filter {
    name   = "name"
    values = ["amzn2-ami-hvm-*-x86_64-gp2"]
  }
}

resource "aws_instance" "ssm_ec2" {
  ami                         = data.aws_ami.amazon_linux.id
  instance_type               = "t3.micro"
  subnet_id                   = aws_subnet.private.id
  vpc_security_group_ids       = [aws_security_group.ec2_sg.id]
  iam_instance_profile         = aws_iam_instance_profile.ec2_ssm_profile.name
  associate_public_ip_address  = false

  tags = {
    Name = "miyazaki-ssm-private-ec2"
  }
}

data "aws_ami" "amazon_linux" セクション

  • dateではリソースの構築に用いる情報を定義します。
  • 今回は起動するEC2のAMIを常に最新のものを使いたかったのdateセクションを用意しています。
  • most_recent = trueの記述で、常に最新のバージョンのAMIを取得するようにします。
  • owners = ["amazon"]で対象をAWS公式のAMIを対象にします。
  • 今回はSSMエージェントがあらかじめインストールされているものを使いたいため、filterでAmazonLinuxに絞ります。

resource "aws_instance" "ssm_ec2" セクション

  • ami = data.aws_ami.amazon_linux.idで👆で取得したAMIを指定します。
  • instance_type = "t3.micro"インスタンスタイプは無料利用枠のものを指定します。
  • vpc_security_group_ids = [aws_security_group.ec2_sg.id]はVPCの作成時に作ったEC2用のセキュリティグループを指定します。
  • iam_instance_profile = aws_iam_instance_profile.ec2_ssm_profile.nameこちらもEC2用に作成したIAMロールを指定します。
  • associate_public_ip_address = false SSM接続をするのにパブリックIPは必要ないので、falseをしてします。

構築

コードがそろったので、あとは実行するだけです。

terraform ini #初期化
terraform plan #構築リソースの確認
terraform apply #リソースの構築

applyが完了すれば、コンソールからSSM接続ができるようになっているはずです。
エラーが出た際や、コードの値を変えたい場合はteraformの公式ドキュメントを参照してみてください。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?