初心者向け｜TerraformでAWS EC2環境を構築・SSH接続

## はじめに
この記事では Terraform を使って、**IaC (Infrastructure as Code)** でAWS 上に EC2 インスタンスを構築する方法を紹介します。
SSH 接続用のセキュリティグループとルールの作成と設定や、キーペアの発行と設定まで、初心者の方でも一つずつ手順を追えるように徹底的な説明していきます。

## 前提条件
このハンズオンを進める前に、以下の環境やツールが整っていることを確認してください：
- AWS アカウント（無料利用枠でもOK）
- AWS CLI
- 任意のコードエディタ（例：Visual Studio Code）

## セットアップ手順
このセクションでは、Terraformで AWS リソースを操作するための準備を進めていきます。
以下のステップを順番に実行してください。

### ① IAM ユーザーの作成
Terraform から AWS を操作するためには、アクセスキーを持った **IAM ユーザー** が必要です。

1. [AWS コンソール](https://aws.amazon.com/jp/console/)にログインし、IAM サービスを開きます
![IAMmenu.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2961920/1ebf9fb3-adf4-4d84-864b-060e10addeef.png)

2. 左メニューから **「ユーザー」** を選び、**「ユーザーの作成」** ボタンをクリック
![create-user.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2961920/9df1fb31-d957-42f5-af99-19d245ae69bb.png)

3. **ユーザー名**（例：terraformUser）を入力し、**「次へ」** ボタンをクリック
![2_username.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2961920/e22a53e6-fc8c-4d18-91bb-aa9cad8182ad.png)

4. ポリシーを設定します：**「AdministratorAccess」** （チュートリアルでは簡単にするため）をアタッチし、**「次へ」** ボタンをクリック
![3_administrator_access.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2961920/41a8fabe-b7d9-4aed-af0b-d7e040af50aa.png)

5. ユーザー情報の確認と作成
![4_userinfo_check.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2961920/9c4861b6-cc00-4ad2-a922-c63b9a119e61.png)

---

### ② アクセスキーの作成とダウンロード
次に、作成したユーザーの**アクセスキー**を作成してダウンロードします
1. 作成した **ユーザー名** をクリック
![4_select_user.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2961920/e30b444a-2cf5-4990-a230-2bcb2e3fb01c.png)

2. **「アクセスキーを作成」** をクリック
![5_access_key.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2961920/b5da36cd-9fad-49fe-9a0d-a133a1756ff8.png)

3. **「コマンドラインインターフェイス（CLI）」** を選択し、**チェックボックス** を入れて **「次へ」** ボタンをクリック
![6_access_key_settings.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2961920/fd94a3fa-9da6-4c82-a665-414330f1bbc6.png)

4. **説明タグ値**（例：terraformUserKey）を入力し、**「アクセスキーを作成」** ボタンをクリック
![7_key_tag.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2961920/3581f0a1-7668-41aa-b25e-c76cca534b9b.png)

5. アクセスキーの作成ができたら、**「.csv ファイルをダウンロード」** をクリックし、**「完了」** をクリック
![8_download_keys.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2961920/12e7cbae-e54c-49a7-bda9-72728dbf8558.png)
---
### ③ AWS CLI の設定
作成した IAM ユーザーを使用して、AWS CLI のプロファイル設定を行います。
まず、ターミナル（例：CMD）を開き、AWS CLI がインストールされているか確認します。

以下のコマンドを実行してください：
```
$ aws --version
```
正常にインストールされている場合は、下記のようなバージョン情報が出力されます：
```
$ aws --version
aws-cli/2.26.5 Python/3.13.2 Windows/11 exe/AMD64
```
もし aws コマンドが見つからない旨のエラーが表示された場合は、以下の公式リンクでインストールができます：
[AWS CLI インストールガイド](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html)

AWS CLI が正しくインストールされたら、以下のコマンドでプロファイルを設定します：
```
$ aws configure --profile terraformUser
```
実行すると、次のようなプロンプトが表示されますので、以下の情報を入力してください：
- **AWS Access Key ID**
  - IAM ユーザーのアクセスキー作成時にダウンロードした CSV ファイル（例：`terraformUser_accessKeys.csv`）を開いて確認できます
- **AWS Secret Access Key**
  - IAM ユーザーのアクセスキー作成時にダウンロードした CSV ファイル（例：`terraformUser_accessKeys.csv`）を開いて確認できます
- **Default region name**
  - 空のままで問題ありません（後ほど Terraform 側で指定します）
- **Default output format**
  - 空のままで問題ありません（json がデフォルト）

```
AWS Access Key ID [None]: XXXXXXXXXXXXXXXXX
AWS Secret Access Key [None]: XXXXXXXXXXXXXXXXXX
Default region name [None]:
Default output format [None]:
```
---
### ④ Terraformのインストール
>※ ターミナルは管理者として実行する必要がある場合があります。
- **Windowsの場合（Chocolatey使用）**
Terraformをインストールする最も簡単な方法は、Windows用パッケージマネージャー「Chocolatey」を使う方法です。 
```
$ choco install terraform
```
Chocolateyがインストールしていない場合は、以下の公式リンクでインストールができます：
[Chocolately インストールガイド](https://chocolatey.org/install)

- **Macの場合（Homebrew使用）**
```
$ brew install terraform
```

- **Linuxの場合 (APT使用)**
UbuntuなどのDebian系ディストリビューションの場合：
```
$ sudo apt-get update && sudo apt-get install -y terraform
```
---
### ⑤ Terraformのバージョン確認
以下のコマンドで、Terraformが正しくインストールされたかを確認できます：
```
$ terraform --version
Terraform v1.11.4
on windows_amd64
```
---
### ⑥ 新しいプロジェクトフォルダとTerraformファイル（.tf）の作成
Terraformプロジェクト用のフォルダを作成し、その中に設定ファイル（main.tf）を用意しましょう。

**💻 方法①：ターミナル（CMD）を使う場合（Windows）** 
1. フォルダを作成する
    ```
    $ mkdir C:\Users\<your_username>\terraform_practice
    ```
2. 作成したフォルダに移動する
    ```
    $ cd C:\Users\<your_username>\terraform_practice
    ```  
3. 空のTerraformファイルを作成する
    ```
    $ type nul > main.tf
    ```
4. コードエディタで作成したファイルを開く
    ```
    $ code main.tf
    ```
>※ `$ code main.tf` は **Visual Studio Code** を使用している場合のコマンドです。別のエディタを使っている方は、そちらで main.tf を開いてください。


**📁 方法②：エクスプローラー（GUI）を使う場合** 
ターミナルが苦手な方は、以下のように普段通りのWindows操作でもOKです。
1. `C:\Users\<あなたのユーザー名>` フォルダを開く
2. 右クリック → 「新規作成」→ 「フォルダー」で `terraform_practice` を作成
3. `terraform_practice` フォルダーを開き、右クリック → 「新規作成」→ 「テキスト ドキュメント」で `main.tf` を作成（拡張子 `.txt` を `.tf` に変更してください）
4. 好きなエディタ（VSCode、Notepad、Sublime Text など）で `main.tf` を開く

## Terraformのスクリプト
Terraform は HCL（HashiCorp Configuration Language） という独自の記法を使用し、クラウドリソース（EC2、 S3、 VPCなどのAWSサービス）をコードで定義して作成や管理することができます。

**本チュートリアルで使用するTerraformの構成要素（キーワード）**

   - `terraform (required_providers)`
   TerraformがAWSクラウドへ連携するためのプロバイダを指定する
   - `provider`
   指定したプロバイダを設定する
   - `resource`
   新しく作成したいAWSリソースを定義します。
   例: EC2インスタンス、S3バケット、セキュリティグループなど
   - `data`
   'resource'とは違い、AWSアカウントに既に存在するAWSリソースを参照します。
   - `output`
   Terraformの実行後に、取得したい情報を画面に表示させたい場合に使います。

**Terraformコードの基本構文（テンプレート）**
Terraformのブロックは、基本的に以下のような形式で書かれます：
```
<keyword> "<resource_type>" "<ローカル名>" {
    // 各種設定（属性）を書く場所 //
}
```
**それぞれの意味：**
   - **< keyword >**
   Terraformの命令タイプです。
   例：`resource`（新しいリソースを作成）や `data`（既存のリソースを参照）など。
   - **"< resource_type >"** 
   使いたいAWSリソースの種類。
   例：`"aws_instance"`（EC2）や `"aws_vpc"`（VPC）など。
   - **< ローカル名 >**
   Terraform内部で使う任意の名前です。他のリソースから参照する時にこの名前を使います。

---

Terraformの構成要素と基本構文が分かったところで、
さっそく最初のTerraformコードを書いてみましょう！

### ① プロバイダの指定(main.tf)
TerraformをAWSと連携させるために、まずはどのプロバイダを使うかを指定する必要があります。
作成した `main.tf` ファイルに、以下のコードを記述してください：
```
terraform {
    required_providers {
        aws = {
          source  = "hashicorp/aws"
          version = "5.95.0"
        }
    }
}
```
このブロックでは、Terraformが使用する 各プロバイダー（providers） を指定しています。
ここでは、HashiCorpが提供している公式の **AWSプロバイダー** を使っています。このプロバイダと最新バージョンを `https://registry.terraform.io/providers/hashicorp/aws/latest` で確認できます。

### ② プロバイダの設定
次に、先ほど指定した AWS プロバイダに対して、どのリージョン・どのアカウントを使うかを設定します。
以下のように、provider ブロックを追加しましょう：
```
terraform {
    required_providers {
        aws = {
          source  = "hashicorp/aws"
          version = "5.95.0"
        }
    }
}

------------- ↓ 追加 ↓ -------------

provider "aws" {
    region  = "ap-northeast-1"
    profile = "terraformUser"
}
```

この provider ブロックでは、Terraform が接続する AWS の情報を指定します：
・`region` :　使用する AWS リージョン（例：東京リージョン → "ap-northeast-1"）
・`profile` :　ローカルの AWS CLI で設定されたプロファイル名（`C:/Users/<your_username>/.aws/credentials` に定義されているもの）

>※ `"terraformUser"`のプロファイル名は、前のステップで `aws configure --profile terraformUser` を使って作成したユーザーを指定しています。

### ③ EC2のリソースの作成定義
次に、AWSに連携できるようにプロバイダの設定ができたら、AWSの**EC2インスタンス**を定義します：
```
terraform {
    required_providers {
        aws = {
          source  = "hashicorp/aws"
          version = "5.95.0"
        }
    }
}

provider "aws" {
    region  = "ap-northeast-1"
    profile = "terraformUser"
}

------------- ↓ 追加 ↓ -------------

resource "aws_instance" "my_ec2" {
    ami = "ami-05206bf8aecfc7ae6"
    instance_type = "t2.micro"

    tags = {
        Name = "terraformTestEc2"
    }
}
```
- `resource` はTerraformで**何らかのリソース**（例: EC2、 S3、 VPCなどのAWSサービス） を**作成する**ためのキーワードです。

- `"aws_instance"` は「AWSの**EC2インスタンス**」を示しています。

- `"my_ec2"` はこのリソースに対する**Terraform内部での名前**（ローカル名） です。他のリソースから参照するときにこの名前を使います。

- `ami` はEC2インスタンスの **「OS（オペレーティングシステム）」** を決めるものです。たとえば、Ubuntu や Amazon Linux、Windows Server などから選びます。
それと、AMI（Amazon Machine Image）は、OSだけでなく、**初期設定**や**ソフトウェア**を含むこともあります。

- `instance_type` は、EC2インスタンスに使うハードウェアの種類を決めるものです。メモリの量、CPU（プロセッサ）の性能、ネットワーク性能などがこの値によって変わります。

- `tags` では、このインスタンスにわかりやすい名前をつけることができます。AWSコンソール上でも識別しやすくなります。
　

**ami** と **instance_type** は、AWSコンソールでEC2サービスの中で使いたい値を確認できます。
![ami.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2961920/a4d89cf9-b4a2-4434-a089-b251a5ee1e7e.png)

![instance_type.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2961920/522c42d0-137c-4682-933d-52e321a93631.png)

- `ami-05206bf8aecfc7ae6` は **Amazon Linux**のオペレーティングシステムです。
- `t2.micro` は**無料枠**の対象で、初心者にとって扱いやすい**小型**のインスタンスです。

### ④ 既存VPCの指定
AWSアカウントには、最初から**デフォルトの VPC**（Virtual Private Cloud） という仮想ネットワークが用意されています。
新しいVPCを作成して指定しない場合は、EC2などのリソースはこの**デフォルト VPC内**に配置されます。
自分のパソコンからAWSクラウドにあるEC2に接続するため、このデフォルトVPCを参照し、「セキュリティグループ」と「インバウンドルール」を作成します。

まず、新しいセキュリティグループやルールを定義する前に、対象になる**デフォルトのVPCを指定**します：
```
terraform {
    required_providers {
        aws = {
          source  = "hashicorp/aws"
          version = "5.95.0"
        }
    }
}

provider "aws" {
    region  = "ap-northeast-1"
    profile = "terraformUser"
}

resource "aws_instance" "my_ec2" {
    ami = "ami-05206bf8aecfc7ae6"
    instance_type = "t2.micro"

    tags = {
        Name = "terraformTestEc2"
    }
}

------------- ↓ 追加 ↓ -------------

data "aws_vpc" "default_vpc" {
    default = true
}
```
- `data` ブロックは、すでにAWS上に存在するリソースを参照するためのものです。
新しく作成する `resource` ブロックとは違い、`data` は「読み取り専用」であり、Terraformで管理していないけれど必要な情報（例：既存のVPC）を取得するときに使います。

- `"aws_vpc"` は、AWSのVPC（Virtual Private Cloud)のリソースを指定します。
- `"default_vpc"` は、Terraform内部での名前（ローカル名）で、他の場所からこのVPCを参照するときに使います。
- `default = true` は、AWSアカウントに最初から存在している「デフォルトVPC」だけを対象にしています。

### ⑤ セキュリティグループの作成定義
次に、指定したVPCに新しいセキュリティグループを定義します：
```
terraform {
    required_providers {
        aws = {
          source  = "hashicorp/aws"
          version = "5.95.0"
        }
    }
}

provider "aws" {
    region  = "ap-northeast-1"
    profile = "terraformUser"
}

resource "aws_instance" "my_ec2" {
    ami = "ami-05206bf8aecfc7ae6"
    instance_type = "t2.micro"

    tags = {
        Name = "terraformTestEc2"
    }
}

data "aws_vpc" "default_vpc" {
    default = true
}

------------- ↓ 追加 ↓ -------------

resource "aws_security_group" "ssh_access" {
    name        = "ssh_access"
    description = "Access to EC2 using SSH"
    vpc_id      = data.aws_vpc.default_vpc.id
    tags = {
        Name = "ssh_access_security_group"
    }
}
```

- `resource` ブロックは、新しくAWS上に作るリソース を定義します。
- `"aws_security_group"` は、AWSのセキュリティグループ（Firewallのようなもの）を作るリソースです。

- `"ssh_access"` は、Terraform内部での名前（ローカル名）です。他の場所からこのセキュリティグループを参照するときに使います。

- `name` は、セキュリティグループの名前です。

- `description` は、セキュリティグループの説明です（管理画面などに表示されます）。

- `vpc_id` には、このセキュリティグループをどのVPCに作成するかを指定します。ここでは、上の `data` ブロックで取得した「デフォルトVPC」のIDを使っています。

- `tags` では、リソースに名前などのタグ情報をつけることができます。AWSコンソールではリソースを整理しやすくするためにタグ付けがよく使われます。

### ⑥ セキュリティグループにルールの追加
現時点では、名前と説明しか設定されていないセキュリティグループなので、作成したグループに**ルール**を追加しなければなりません。

セキュリティグループには、**受信（Ingress）** ルール と **送信（Egress）** ルール の2種類があります。
今回は、EC2 に接続できるようにするための **Ingress ルール** のみを設定します（外部からの接続を許可するイメージです）。
一方、Egress ルールは、EC2 から外部への通信を許可するための設定です。

>※ デフォルトではすべての Egress（送信）通信が許可されているため、今回は特に変更しません。

受信ルールを定義します：
```
terraform {
    required_providers {
        aws = {
          source  = "hashicorp/aws"
          version = "5.95.0"
        }
    }
}

provider "aws" {
    region  = "ap-northeast-1"
    profile = "terraformUser"
}

resource "aws_instance" "my_ec2" {
    ami = "ami-05206bf8aecfc7ae6"
    instance_type = "t2.micro"

    tags = {
        Name = "terraformTestEc2"
    }
}

data "aws_vpc" "default_vpc" {
    default = true
}

resource "aws_security_group" "ssh_access" {
    name        = "ssh_access"
    description = "Access to EC2 using SSH"
    vpc_id      = data.aws_vpc.default_vpc.id
    tags = {
        Name = "ssh_access_security_group"
    }
}

------------- ↓ 追加 ↓ -------------

resource "aws_vpc_security_group_ingress_rule" "ssh_access_rule" {
    security_group_id = aws_security_group.ssh_access.id

    cidr_ipv4   = "0.0.0.0/0"
    from_port   = 22
    ip_protocol = "tcp"
    to_port     = 22
}

```
- `resource` ブロックは、新しくAWS上に作成するリソースを定義します。

- `"aws_vpc_security_group_ingress_rule"` は、VPC セキュリティグループの「インバウンド通信の許可ルール」を定義するリソースです。

- `"ssh_access_rule"` は、このリソースのローカル名です。Terraform内部での識別に使います。

- `security_group_id` は、どのセキュリティグループにこのルールを追加するかを指定します。
ここでは、前に定義した `aws_security_group.ssh_access` の**ID**を指定しています。

- `cidr_ipv4 = "0.0.0.0/0"` は、すべてのIPv4アドレスからの接続を許可する設定です。
>⚠️ セキュリティの観点から、本番環境ではこの設定を制限することが推奨されます（例：自宅IPのみなど）。

- `from_port = 22` と `to_port = 22` は、ポート22番（SSH用）の接続を許可する設定です。

- `ip_protocol` = "tcp" は、TCPプロトコルを指定しています。SSHはTCPで動作します。

### ⑦ EC2インスタンスにセキュリティグループの追加
セキュリティグループとルールの定義を完了したら、最後に**EC2インスタンス**にセキュリティグループを追加します。
```
resource "aws_instance" "my_ec2" {
    ami = "ami-05206bf8aecfc7ae6"
    instance_type = "t2.micro"

    tags = {
        Name = "terraformTestEc2"
    }

------------- ↓ 追加 ↓ -------------

    vpc_security_group_ids = [aws_security_group.ssh_access.id]
}
```
- `vpc_security_group_ids` は、EC2インスタンスに適用する セキュリティグループのIDのリスト を指定します。
  - `[...]` で囲むことで、リスト（配列）形式で渡しています。今回は1つだけ指定していますが、複数のセキュリティグループを指定することも可能です。
- `aws_security_group.ssh_access.id` は、Terraformで前に定義した SSH用のセキュリティグループの**ID** を参照しています。

### ⑧ EC2のパブリックIPアドレスの出力
最後に、これから作成するEC2インスタンスに接続するため、AWSに割り当てられたパブリックIPアドレスを出力します

```
terraform {
    required_providers {
        aws = {
          source  = "hashicorp/aws"
          version = "5.95.0"
        }
    }
}

provider "aws" {
    region  = "ap-northeast-1"
    profile = "terraformUser"
}

resource "aws_instance" "my_ec2" {
    ami = "ami-05206bf8aecfc7ae6"
    instance_type = "t2.micro"

    tags = {
        Name = "terraformTestEc2"
    }
}

data "aws_vpc" "default_vpc" {
    default = true
}

resource "aws_security_group" "ssh_access" {
    name        = "ssh_access"
    description = "Access to EC2 using SSH"
    vpc_id      = data.aws_vpc.default_vpc.id
    tags = {
        Name = "ssh_access_security_group"
    }
}

------------- ↓ 追加 ↓ -------------

output "ec2_public_ip" {
    value       = aws_instance.my_ec2.public_ip
    description = "The public IP address of the EC2 instance"
}
```
- `output` ブロックは、Terraform 実行後に表示される「出力値」を定義します。
- `"ec2_public_ip"` は出力の名前です。この名前で `$ terraform output ec2_public_ip` のように呼び出すことができます。
- `value` には出力したい値を指定します。この例では、aws_instance.my_ec2.public_ip を指定しており、作成された EC2 インスタンスのパブリック IP アドレスを意味します。
- `description` は、この出力値の説明です。`terraform output -json` などで参照した際に説明として表示されます（任意ですが、ドキュメント的にとても有用です）。

## Terraformのコマンド
`main.tf` ファイルに以下の内容を記述できたら、Terraform コマンドを使ってインフラの構築を進めていきます。
 - プロバイダの指定
 - プロバイダの設定
 - EC2 インスタンスの作成定義
 - 既存 VPC の参照
 - セキュリティグループの作成定義
 - セキュリティグループにルールの追加
 - EC2 インスタンスにセキュリティグループの追加
 - EC2のパブリックIPの出力（output)

まずは Terraform を初期化し、設定内容を適用していきましょう。
以下の順番で Terraform の基本コマンドを実行していきます。

### **初期化 (terraform init)**
Terraform を初めて実行する際は、まず初期化を行います。下記のコマンドで必要な**プロバイダプラグイン**(`"hashicorp/aws"`)などがダウンロードされます。
```
$ terraform init
```
>`terraform init` 実行時に `terraform {required_providers {}}`　ブロックのコードで **hashicorp/aws バージョン 5.95.0** が自動的にダウンロードされ、Terraform の作業環境がセットアップされます。

![スクリーンショット 2025-04-30 103744.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2961920/13b7006f-8791-4948-99de-d08019a25e4d.png)

### **計画の確認 (terraform plan)**
 実際にリソースを作成・変更・削除する前に、Terraform がどのような操作を行うかを確認できます。
```
$ terraform plan
```
このコマンドを実行すると、作成・変更・削除されるリソースの一覧が表示されます。
```
Terraform will perform the following actions:

# aws_instance.my_ec2 will be created
+ resource "aws_instance" "my_ec2" {
    + ami = "ami-05206bf8aecfc7ae6"
        ...
    }
      
# aws_security_group.ssh_access will be created
+ resource "aws_security_group" "ssh_access" {
    + arn = (known after apply)
        ...
    }

 # aws_vpc_security_group_ingress_rule.ssh_access_rule will be created
  + resource "aws_vpc_security_group_ingress_rule" "ssh_access_rule" {
    + arn = (known after apply)
        ...
    }

Plan: 3 to add, 0 to change, 0 to destroy.

Changes to Outputs:
  + ec2_public_ip = (known after apply)
```

### **適用 (terraform apply)**
問題がなければ、実際にリソースを作成します。
```
$ terraform apply
```
![スクリーンショット 2025-04-30 142157.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2961920/a52d2809-cb33-4f4d-a065-f33ecb104cf4.png)

`terraform plan` コマンドのときと同じように変更内容が表示されます。確認メッセージが表示されたら、内容を確認して問題なければ、**「yes」** と入力して適用を完了させましょう。
![スクリーンショット 2025-04-30 142249.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2961920/8d8fa90a-662c-4d36-8330-6364d2b5b71e.png)

上記のように **「Apply complete!」** というメッセージが表示されれば、AWS への構築が正常に完了しました。

AWS コンソールで確認すると、下記のように新しく作成した**EC2インスタンス**と**セキュリティグループ**があるはずです。
![ec2_instance.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2961920/a8d7e878-abb6-4855-bd4f-8f574caf3d84.png)
![security_group.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2961920/b84aee3d-723c-454b-98ae-6c75ac16a75d.png)

---

## EC2との接続、Terraformのスクリプト更新
EC2インスタンスが立ち上がったら、ターミナルからSSHで接続してみましょう！

まず、EC2のパブリックIPに確認するため、下記のようなコマンドがあります
```
$ terraform output ec2_public_ip
```
上記のコマンドで出力されたIPアドレスを使って、SSHで接続を試みます：
```
$ ssh ec2-user@<パブリックIP>
```
>💡 **補足** ：`ec2-user` は、Amazon Linux や多くの公式AMI(EC2設定)で使用されるデフォルトのログインユーザー名です。
OSによって異なる場合があります（例：Ubuntuなら ubuntu、Debianなら admin など）。
今回は Amazon Linux AMI を使っているため、ec2-user が正しいユーザー名です。

このコマンドを実行すると、次のようなエラーが表示されるはずです：
```
Permission denied (publickey,gssapi-keyex,gssapi-with-mic).
```
これは、EC2インスタンスにSSHで接続するには **「キーペア（公開鍵・秘密鍵）」** による認証が必要だからです。

今回、SSHのインバウンドルールを追加したことで、自分のパソコンからEC2の「玄関先」までたどり着ける状態になっています。ですが、まだ鍵（＝認証情報）がないため、ドアを開けることができず、「Permission denied（許可されていません）」というエラーになります。

>※ 補足：もしSSHのインバウンドルールを設定していなければ、EC2にたどり着くことすらできず、「Permission denied」ではなく 「接続タイムアウト」 というエラーになります（通信自体がブロックされているため）。

### SSH接続のための「キーペア」の作成とTerraformへの統合
EC2に接続できるように **キーペア** を作成し、それをTerraformからEC2に登録する方法を説明します。

**１． ローカルでSSHキーペアを作成**
以下のコマンドを使って、SSHキーペアを生成します
```
$ ssh-keygen -t rsa -b 4096 -f C:\Users\<your_username>\.ssh\terraform_key
```
実行すると、`Enter passphrase (empty for no passphrase):`では、**空のまま**で問題ありません。

新しいキーペアを作成すると、`C:\Users\<your_username>\.ssh\`の中に、`terraform_key`(秘密鍵)と`terraform_key.pub`(公開鍵)が生成されています。
<br>
**２． 作成したキーペアをTerraformへの統合**
キーペアの作成ができたら、Terraformのスクリプトにその **キーペア** を追加しましょう。
下記のコードを`main.tf`に追加します
```
resource "aws_key_pair" "ec2_key" {
  key_name = "ec2_key_pair"
  public_key = file("C:/Users/<your_username>/.ssh/terraform_key.pub")
}
```
- `file("file-path")`では、ローカル環境にあるファイルを読み込むコマンドです。
>⚠️ 注意：ファイルパスを確認し、`<your_username>` の部分は、ご自身のPCのユーザー名に置き換えてください。

次に、AWSの`key_pair`リソースを定義したら、EC2インスタンスにもそのキーペアを追加します
```
resource "aws_instance" "my_ec2" { 
    ami = "ami-05206bf8aecfc7ae6"
    instance_type = "t2.micro"
    tags = {
        Name = "terraformTestEc2"
    }

    vpc_security_group_ids = [aws_security_group.ssh_access.id]
    
------------- ↓ 追加 ↓ -------------

    key_name = "ec2_key_pair"
}
```
<br>

**３．TerraformのコマンドでEC2インスタンスを更新**
下記のコマンドを実行します
> ※ `$ terraform apply` は、`$ terraform plan` と同様にリソースの**作成・変更・削除内容** を事前に表示してくれるため、ここでは plan を省略して直接 apply を実行しています。 
```
$ terraform apply
```

実行すると、EC2インスタンスが一度 **「破棄（destroy）」** されてから、新しく **「作成（create）」** されることが表示されます。
![スクリーンショット 2025-05-01 102355.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2961920/c073e9d1-1d28-4112-b9cc-a9b9c674d470.png)

これは、今回 `aws_instance` リソースの設定に `key_name` を追加したためです。
Terraformはこの変更を検出し、「既存のインスタンスには適用できない（＝変更できない）」と判断します。
>一部の属性は **不変（immutable）** であり、変更にはリソースの再作成が必要です。

`key_name` はその代表的な例で、**インスタンスの作成時にしか指定できない属性**です。すでに存在しているインスタンスには後から追加・変更できないため、Terraformは以下のような手順を自動で行います：
1. 既存のEC2インスタンスを削除（destroy）
2. 新しい設定を元に、同じ構成で再作成（create）

> `terraform plan` や `terraform apply` の出力にも反映されており、次のような記号で示されます：`-/+` → 「リソースを削除して再作成する」という意味

このように、インスタンスが再作成されるのは想定された挙動であり、特に今回のように `key_name` のような変更できない属性を追加した場合には避けられません。
コードの変更内容に納得している場合は、`terraform apply` の実行時に **「yes」** と入力して、変更を適用しましょう。

適用が完了すると、以下のようなメッセージが表示されます：
```
Apply complete! Resources: 2 added, 0 changed, 1 destroyed.
```
>Terraformの `output` に定義している `ec2_public_ip` にも、**新しいパブリックIPアドレス**が表示されるはずです（インスタンスが再作成されたため、IPも変わる場合があります）。

**新しいキーペアを使ってEC2に再接続してみよう**

ここまでで、キーペアの設定とEC2の再作成が完了しました。
それでは、今度は先ほど作成したSSHキーペアを使って、EC2インスタンスへの接続を試みましょう！
EC2の**パブリックIP**は以下のコマンドで再確認できます：
```
$ terraform output ec2_public_ip
```
その後、先ほど作成した秘密鍵を指定して、SSHでEC2のパブリックIPに接続します：
```
$ ssh -i C:\Users\<your_username>\.ssh\terraform_key ec2-user@<パブリックIP>
```
- `-i` は、身分証明のために**秘密鍵ファイル (identity file)** を指定します。

実行すると、以下のようなターミナル出力が表示され、正常にEC2インスタンスに接続できたことが確認できます：

```
   ,     #_
   ~\_  ####_        Amazon Linux 2023
  ~~  \_#####\
  ~~     \###|
  ~~       \#/ ___   https://aws.amazon.com/linux/amazon-linux-2023
   ~~       V~' '->
    ~~~         /
      ~~._.   _/
         _/ _/
       _/m/'
[ec2-user@ip-XXX-XX-XX-XXX ~]$ 
```
> `$ exit` コマンドで、SSHの接続を切ることができます

**まとめ**

これで、AWSクラウド上にEC2インスタンスを構築し、SSHアクセス用のインバウンドルールを持つセキュリティグループを定義・実装し、ローカルPCからアクセスできるようにするためのキーペアを設定しました。すべてTerraformを使って実現しました。

もし、このEC2インスタンスを引き続き使用する予定がない場合、ここからは**作成したリソース（EC2、セキュリティグループ、ルール、キーペア）を削除**する方法を説明します。これにより、無駄なリソースが残らず、AWSの利用料金が発生し続けることを防げます。

## AWS上のリソース削除とローカル環境のファイル・設定のクリーンアップ
**１．Terraformで作成したリソースの削除**
Terraformで作成したAWSのリソースを削除するには、`$ terraform destroy` コマンドを使います。このコマンドは、`$ terraform apply` で作成したすべてのリソースを削除し、作業を元の状態に戻します。

以下のコマンドで、EC2インスタンス、セキュリティグループ、ルール、そしてキーペア　(全ての作成したリソース）を削除します：
```
$ terraform destroy
```
実行すると、削除対象のリソース一覧が表示されます。確認メッセージが出たら、**「yes」** と入力して削除を実行しましょう。

![スクリーンショット 2025-05-01 112417.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2961920/779087bc-b8ad-425f-8dcc-7c9658e0889a.png)
これで、Terraformで作成した全てのリソースが削除されます。

**２．AWS IAMの'terraformUser'ユーザーの削除**
次に、IAMユーザーの`terraformUser`をAWS Management Consoleから削除する手順を説明します。

1. [AWS Management Console](https://aws.amazon.com/jp/console/)にサインイン
2. **「IAM」** を検索して、IAMダッシュボードを開いて、 **「ユーザー」** をクリック
3. `terraformUser` の**チェックボックス**を入れ、**「削除」**をクリック
![delete_user.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2961920/9cbc5aa4-57c7-4ac0-8f5f-31c912504f31.png)
4.  **「confirm」** を入力し、 **「ユーザーを削除」** をクリック
    ![confirm_del.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2961920/76cf9adc-dedf-43ad-b070-8aff2f48dcb5.png)

これで、IAMユーザーの`terraformUser`が完全に削除されます。この操作により、そのユーザーのアクセスキーやポリシー、グループなども一緒に削除されます。

**３．AWS CLIの'terraformUser'ユーザーとアクセスキーの削除**
ローカルマシンで設定した **terraformUser** のアクセスキーを削除します。

- AWS CLIの**設定ファイル**からアクセスキーを削除
コードエディタで `C:\Users\<your_username>\.aws\credentials` を開き、`[terraformUser]`、`aws_access_key_id`、`aws_secret_access_key`の3行を削除します
    ```
    [terraformUser]
    aws_access_key_id = EXAMPLEKEY
    aws_secret_access_key = EXAMPLESECRETKEY
    ```    
- アクセスキー情報ファイルの削除
ローカルにダウンロードしている **アクセスキーのCSVファイル**（通常は`C:\Users\<your_username>\Downloads\terraformUser_accessKeys.csv`）も削除します。アクセスキーのファイルをダウンロードした場所に移動し、削除してください。

**４．EC2への接続に使ったキーペアを削除**
ローカルマシンに保存したSSHキーペアを削除します。
ローカルマシンで、秘密鍵（`terraform_key`） およびその公開鍵（`terraform_key.pub`）ファイルを削除します。

Windowsの場合、以下の場所に保存されているファイルを削除します：
`C:\Users\<your_username>\.ssh\terraform_key`
`C:\Users\<your_username>\.ssh\terraform_key.pub`

これで、EC2にアクセスするために使用したキーペアが削除されました。

**５．Terraform作業フォルダの削除**
最後に、ローカルでTerraformの操作に使っていた作業ディレクトリ（`terraform_practice/` のフォルダ）とそのフォルダの中に入っているファイル（`main.tf`）などを削除して、ローカル環境を前の状態に戻るようにクリーンアップしましょう。
- Windows PowerShell の場合:
    ```
    $ Remove-Item -Recurse -Force "C:\Users\<your_username>\terraform_practice"
    ```
- コマンドプロンプト（cmd） の場合
    ```
    $ rmdir /s /q "C:\Users\<your_username>\terraform_practice"
    ```

## まとめ
これで、Terraformを使って構築したAWS環境（EC2インスタンス、セキュリティグループ、キーペアなど）を安全に削除し、IAMユーザーやローカル環境のファイルまできれいに片付けることができました。

一連の流れを通して、以下の内容を体験しました：
- Terraformによるインフラ定義と構築
（EC2インスタンス、セキュリティグループ、SSH接続ルールの設定と作成）
- キーペアの作成
- Terraformで構築したインフラにリソース変更・追加
- SSHでローカルパソコンから構築したEC2に接続
- リソースの削除と環境クリーンアップ