インフラのコード化: AWS上にTerraformでActive DirectoryとDNSサーバー（Windows）を自動セットアップしてみた

## はじめに

AWSを活用すれば、クラウド上で手軽にWindowsサーバーを構築し、リモート操作環境を素早く整えることができます。

:::note info
**今回は、[前回の内容](https://qiita.com/free-honda/items/bb905ccc557844a41afa)に引き続き、Terraformを使ってWindowsサーバーを構築し、Active DirectoryとDNSサーバーを自動セットアップする方法を試してみます。**
:::

この記事は、個人レベルの検証をもとに作成しています。**そのため、内容が実運用環境に適さない場合がありますので、ご了承ください。**

***この内容が、どなたかの技術的な参考になれば幸いです。***

## 書こうと思ったきっかけ
普段はLinuxサーバーを使うことが多いのですが、日常的にWindowsサーバーも利用しています。

インフラ領域において、Active Directoryは非常に重要なサービスの1つだと思います。***私自身、Active Directoryのサーバー管理を担当していた経験があり、日々触れてきました。***

:::note warn
**以前、自宅検証レベルでAWS上にWindowsサーバーを構築し、マルチ構成でActive Directoryをセットアップしたことがあります。**
:::

***今回は、Terraformを使って、よりスマートに開発を進めてみようと思います！***

## そもそも、Active Directoryとは？（DNSは割愛）
Active Directory（アクティブディレクトリ）は、Windows Serverに標準搭載されているディレクトリサービス機能です。

:::note info
**ネットワーク上のユーザー、デバイス、アプリケーションなどの情報を一元管理するために使用されます。**
:::

今回は、AWS上で以下の構成を用いてActive Directory（AD）とDNSを構築します。***ADとDNSは通常、1台のWindows Serverで兼用して運用されることが一般的で、私の環境でもこれを1台のサーバーで設定します。***

![スクリーンショット 2024-09-08 15.56.34.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3662571/7e380044-2d34-52a6-c076-c9d3056df9c5.png)
引用画像：https://blogs.manageengine.jp/role_of_dns/

Active Directoryは非常に便利なサービスですが、最初は私もかなり苦戦しました。実際に触れて試行錯誤しながら覚えてきた経験があります。

今では、半日くらいActive Directoryについて語れるほど勉強してきましたが、ここでは割愛します（笑）。***興味のある方は、以下の記事を参考にしてみてください。***

https://dev.classmethod.jp/articles/jsys_usermanagement/

## 補足: `user_data` に PowerShell スクリプトを追加

少し補足となりますが、前回のシンプルなシングル構成の検証用Terraformコードをベースに、`user_data` に PowerShell スクリプトを追加する方法を採用しています。

:::note warn
- **Active Directoryの役割をインストールし、フォレストを作成。**
- **ドメイン名は `example.local` に設定。**
- **セーフモード管理者パスワードとして `AdminPassword123` を設定（実運用では適切なパスワードに変更してください）。**
:::

また、セキュリティグループの設定後にインスタンスが作成されるよう、`depends_on` を使用しています。

さらに今回は、Active Directoryに加えてDNS機能も自動で設定される構成になっています。***また、設定を調整することで、外向けのDNSサーバーとしても運用できる構成となっています。***

### もっと補足：`user_data`の設定場所はここ

普段、マネジメントコンソール上でEC2を構築したことがある方は、なんとなくイメージがつくかもしれませんが、一応補足としてご説明します。

:::note
***EC2を起動する際の「高度な設定」オプションの最下部に、`user_data`を設定する項目があります。***
:::

今回は、Terraformを使ってこの部分にPowerShellスクリプトを追加しています。

![Screenshot 2025-01-09 at 22.12.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3662571/5d2a4f6a-49d2-6c22-788e-394c99da23c7.png)

`user_data`については、直近の記事でも詳しくまとめていますので、興味がある方はぜひ参考にしてください。

https://qiita.com/free-honda/items/7a7bce3aedcff9a98393

## 今回使うコードについて

今回使用するコードは、シンプルなシングル構成で、検証目的に特化して作成しています。

:::note alert
**注意点として、`key_name` の部分は環境に合わせて修正が必要です。コードを使用する際には、適宜修正を行ってください。**
:::

また、`associate_public_ip_address = true` の設定により、パブリックIPアドレスが自動的に割り当てられる仕様になっています。

```main.tf
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   = 3389
    to_port     = 3389
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"] # RDPアクセスを許可
  }

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

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

# EC2インスタンス作成 (Windows Server)
resource "aws_instance" "windows_ec2" {
  ami                         = "ami-045921da241a7a9c6" # 指定されたWindows ServerのAMI ID
  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                    = "honda" # 修正: キーペアを指定

  user_data = <<-EOF
    <powershell>
    # Active Directory機能のインストール
    Install-WindowsFeature AD-Domain-Services

    # フォレストの作成
    Install-ADDSForest `
        -DomainName "example.local" `
        -SafeModeAdministratorPassword (ConvertTo-SecureString "AdminPassword123" -AsPlainText -Force) `
        -InstallDns `
        -Force
    </powershell>
  EOF

  depends_on = [aws_security_group.public_sg]

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

## 実際にやってみた

ここでは、CloudShellでのTerraformのセットアップが完了していることを前提に進めます。

**まだセットアップが完了していない方は、過去の記事を参考にしてセットアップを実施してください。**

https://qiita.com/free-honda/items/19b4e7db8b8f24d41277

まず、以下のコマンドを入力して、**main.tf**というファイルを作成します。

```bash
vi main.tf
```

``vi``では、ファイル編集後にESCキーを押し、``:wq``で保存して終了します。

```main.tf
# 上記の完成した全体のコードをコピーして貼り付けてください。
```

次に、以下のコマンドで Terraform を初期化します。

```bash
terraform init
```

実際に、以下のように「``Terraform has been successfully initialized!``」と表示され、成功が確認できました。

```bash
Partner and community providers are signed by their developers.

・・・（省略）

Terraform has been successfully initialized!
You may now begin working with Terraform. Try running "terraform plan" to see

・・・（省略）

rerun this command to reinitialize your working directory. If you forget, other
commands will detect it and remind you to do so if necessary.
```

次に、以下のコマンドを入力して、確認メッセージが表示されたら「``yes``」と入力します。

```bash
terraform apply
```

その後、以下のように「``Apply complete! Resources: xx added, 0 changed, 0 destroyed.``」と表示され、成功したことが確認できました。

![Screenshot 2025-01-09 at 19.21.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3662571/54ecc79f-9242-8810-3cd8-4f5e30f37f9c.png)


Terraformで構築したWindowsサーバーをAWSマネジメントコンソールで確認します。***以下のスクリーンショットのように、サーバーが1台構築されていることが確認できました。***

![Screenshot 2025-01-09 at 22.37.56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3662571/440c220b-0841-b7df-6323-ae54b04bb4a9.png)

### 初期パスワードとRDP接続について
初期パスワードの確認方法については、以下の記事で詳しくご紹介していますので、参考にしてください。

https://qiita.com/free-honda/items/98086628f844afe73079

また、RDP（リモートデスクトップ）の接続方法についても、直近の記事でまとめています。興味がある方はぜひご覧ください。

https://qiita.com/free-honda/items/bb905ccc557844a41afa

## Active Directoryが設定されているか確認してみた
今回は最も簡単な確認方法として、自分自身のWindowsサーバーがドメインに参加しているかを確認しました。

システムのプロパティ画面を確認したところ、ドメイン名が「`example.local`」になっていることが確認でき、***Active Directoryが正常に構成されていることを確認しました。***

![Screenshot 2025-01-09 at 22.24.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3662571/ae9ec69a-24c4-bb00-88b7-5b1bdd8f1006.png)

次に、サーバーマネージャーの画面を確認したところ、想定通り「AD DS（Active Directory Domain Services）」と「DNS」の機能が追加されていることが確認できました。

![Screenshot 2025-01-09 at 22.26.44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3662571/3381958b-0ffd-a056-5dbe-26b42869fea6.png)

:::note alert
**ただし、一部の細かいオプションや役割・機能が追加されていないように見受けられました。この点については、次回の改善項目として検討したいと思います。**
:::

## まとめ
今回は少し難しい内容だったかもしれませんが、`user_data`を活用してスムーズに構築を進めることができました。***そのため、大きくつまずくことなく作業を完了できたと思います。***

:::note warn
**とはいえ、今回の構築は最低限の設定に留まっています。「インフラをどこまでコード化するのか」という点については、改めて難しい課題だと感じました。**
:::

***この技術検証は実施している人が少ないかもしれませんが、この内容がどなたかの技術的な参考やサポートになれば幸いです。***

## おまけ: DNSも正常に設定されていました
今回のコードを使って、DNSも正常にインストールされていることを確認できました。

![Screenshot 2025-01-09 at 22.31.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3662571/929b56b7-7163-0366-1346-d5a30c2b06ba.png)

今後は、このDNSサーバーに前方参照ゾーンなど必要な設定を追加し、インターネットに公開する外向けのDNSサーバーとして運用していきたいと思います。

## 参考記事

https://dev.classmethod.jp/articles/ec2-active-directory-aws-infra/