セキュリティ対策：Terraformで構築したWebサーバーに特定のIPアドレスからのみSSH接続する方法

## はじめに

特定のIPアドレスからのみSSH接続を許可する設定は、セキュリティを大幅に強化する有効な方法です。

しかし、私の環境ではIPアドレスが動的に変化する（DHCP技術の影響で頻繁に変更される）ため、これまでIPアドレス制御を行っていませんでした。

今回の内容は、自分用の備忘録としてまとめたものです。***その点をご理解いただければ幸いです。***

## 書こうと思ったきっかけ

普段、AWS上でEC2などを利用してウェブサーバーを構築する際、SSH接続の設定を`0.0.0.0/0`で全てのアクセスを許可していました。

:::note alert
**しかし、これはセキュリティ上非常に危険な設定であることを改めて認識し、今回IPアドレスを絞ったアクセス制御を検証してみようと思いました。**
:::

これまで全てを許可していた理由として、自宅のグローバルIPアドレスが1週間に1回程度変更されるため、固定IPが使えない状況がありました。

***この点については、別の方法で回避できないか、今後模索していきたいと考えています。***

## IPアドレスを絞るメリット

- **1. セキュリティの強化**
  - **不正アクセスのリスク軽減**  
    指定したIPアドレス以外からの接続を拒否することで、不正アクセスやブルートフォース攻撃を受ける可能性を大幅に減らせます。
  - **攻撃対象の縮小**  
    攻撃者が接続を試みても、許可されていないIPアドレスからのアクセスは即座にブロックされるため、無駄な試行を防げます。

- **2. アクセス管理の明確化**
  - **管理者の限定**  
    接続可能なIPアドレスを指定することで、SSHアクセスを信頼できる管理者やシステムに限定できます。
  - **ログの簡素化**  
    許可されたIPアドレス以外の接続がないため、監視ログが簡潔になり、異常なアクセスを見つけやすくなります。

- **3. コンプライアンス対応**
  - **セキュリティ基準の遵守**  
    一部の規制や業界標準（例：ISO 27001、SOC 2など）では、リモートアクセスの制限を推奨している場合があり、この方法はそれに適合します。

- **4. 攻撃の検知と対策が容易**
  - **不正な試行を排除**  
    指定外のIPアドレスからのアクセス試行がブロックされるため、攻撃の兆候がすぐに分かります。
  - **ファイアウォールとの統合が容易**  
    IP制限を組み合わせることで、より強固な防御を構築できます。

## Terraformで環境を構築してみた

今回は、最近ハマっているTerraformを使って簡単に環境を自動構築してみます。

***セキュリティグループのSSH接続に関しては、自宅のグローバルIPアドレスを確認し、適宜修正してください。***

```main.tf
# AWSプロバイダーの設定
provider "aws" {
  region = "ap-northeast-1" # Tokyo region
}

# VPC作成
resource "aws_vpc" "main_vpc" {
  cidr_block           = "10.0.0.0/16"
  enable_dns_support   = true
  enable_dns_hostnames = true

  tags = {
    Name = "terraform-main-vpc"
  }
}

# サブネット作成 (パブリックサブネット)
resource "aws_subnet" "public_subnet" {
  vpc_id                  = aws_vpc.main_vpc.id
  cidr_block              = "10.0.1.0/24"
  map_public_ip_on_launch = true

  tags = {
    Name = "terraform-public-subnet"
  }
}

# インターネットゲートウェイ作成
resource "aws_internet_gateway" "main_igw" {
  vpc_id = aws_vpc.main_vpc.id

  tags = {
    Name = "terraform-main-igw"
  }
}

# ルートテーブル作成
resource "aws_route_table" "public_route_table" {
  vpc_id = aws_vpc.main_vpc.id

  route {
    cidr_block = "0.0.0.0/0"
    gateway_id = aws_internet_gateway.main_igw.id
  }

  tags = {
    Name = "terraform-public-route-table"
  }
}

# サブネットとルートテーブルの関連付け
resource "aws_route_table_association" "public_association" {
  subnet_id      = aws_subnet.public_subnet.id
  route_table_id = aws_route_table.public_route_table.id
}

# セキュリティグループ作成
resource "aws_security_group" "public_sg" {
  vpc_id = aws_vpc.main_vpc.id

  ingress {
    from_port   = 80
    to_port     = 80
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"] # HTTPアクセスを許可
  }

  ingress {
    from_port   = 22
    to_port     = 22
    protocol    = "tcp"
    cidr_blocks = ["xx.xx.xx.xx/32"] # 指定IPアドレスからのSSHアクセスを許可
  }

  egress {
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["0.0.0.0/0"] # すべてのアウトバウンドを許可
  }

  tags = {
    Name = "terraform-public-sg"
  }
}

# EC2インスタンス作成
resource "aws_instance" "apache_ec2" {
  ami                         = "ami-0b6fe957a0eb4c1b9" # Amazon Linux 2 AMI (Tokyo region)
  instance_type               = "t2.micro"
  subnet_id                   = aws_subnet.public_subnet.id
  security_groups             = [aws_security_group.public_sg.id]
  associate_public_ip_address = true # パブリックIPv4アドレスを有効化
  key_name                    = "xxx" # SSH接続に使用するキーペア名を指定

  user_data = <<-EOF
    #!/bin/bash
    yum update -y
    yum install -y httpd
    systemctl start httpd
    systemctl enable httpd
    echo "<html><body><h1>Welcome to Apache Server powered by Terraform!</h1></body></html>" > /var/www/html/index.html
  EOF

  depends_on = [aws_security_group.public_sg]

  tags = {
    Name = "terraform-apache-ec2"
  }
}
```

## 実際にSSH接続してみた
まず、以下のコマンドを実行して、SSHキーの権限が適切に設定されていることを確認します。

```bash
chmod 400 "xxx.pem"
```

次に、以下のようなSSHコマンドを使ってサーバーにログインします。

```bash
ssh -i "xxx.pem" ec2-user@ec2-xx-xx-xx-xx.ap-northeast-1.compute.amazonaws.com
```

このように、自宅のグローバルIPアドレスを使用して問題なくサーバーにSSH接続できることを確認しました。

```bash
$ ssh -i "xxx.pem" ec2-user@ec2-xx-xx-xx-xx.ap-northeast-1.compute.amazonaws.com
Warning: Permanently added 'ec2-xx-xx-xx-xx.ap-northeast-1.compute.amazonaws.com' (ED25519) to the list of known hosts.
   ,     #_
   ~\_  ####_        Amazon Linux 2
  ~~  \_#####\
  ~~     \###|       AL2 End of Life is 2025-06-30.
  ~~       \#/ ___
   ~~       V~' '->
    ~~~         /    A newer version of Amazon Linux is available!
      ~~._.   _/
         _/ _/       Amazon Linux 2023, GA and supported until 2028-03-15.
       _/m/'           https://aws.amazon.com/linux/amazon-linux-2023/

-bash: warning: setlocale: LC_CTYPE: cannot change locale (UTF-8): No such file or directory
[ec2-user@ip-10-0-1-211 ~]$ 
```

## まとめ
ここまでお読みいただき、ありがとうございました。***今回は簡単な内容でしたが、SSH接続のような基本的な操作においても、細かいセキュリティ要件を守ることが重要です。***

:::note
**これからもサーバー管理者として、こうしたポイントを大切にしていきたいと思います。**
:::

この記事が少しでも皆さんのお役に立てば幸いです！

## おまけ
今回は、自宅のグローバルIPアドレス以外からの接続を試したところ、正常に接続できないことを確認しました。

***この結果から、設定が正しく機能していることが確認でき、検証は成功です！***