EC2インスタンス作成時にホスト名変更＆AD参加する（UserData編）
Tags: aws, windows, ec2, activedirectory
Published: 2021-04-19 13:18:48

検証環境でWindows Serverをたくさんたてるのだが、
①（AWS Managed ADではない）ADに参加
②ホスト名を、自分がつけたNameタグの値に揃える
これはだいたい必ずやる。②に関しては、自動的につけられるランダムなホスト名だと分かりづらいので早々に自分がつけたい名前にしておきたいという意図。

<br>
これを一々手動でやるのはとても面倒なので（再起動も発生するし）、もちろん自動化したい。自動化する方法は色々あるが、今回は一番原始的（？）UserDataスクリプトを利用する方法を使ってみる。

ちなみにUserDataスクリプトはインスタンス作成時の一回しか実行されないので、少々柔軟性にかけるし、何かしらの問題でスクリプト実行が失敗したら手動で直さないといけない。とはいえアドホックでやるには簡単な方法だし楽な場合もある。

AWS Managed ADを使う場合は、インスタンス作成時に簡単に指定できちゃうのだが、EC2上に構築したADや、オンプレのAD等の場合はこういう方法を使う必要がある。

<br>
ドメイン参加にはその権限を持ったドメインアカウントが必要なのだが、その認証情報をスクリプトにハードコードしたくはないのでSecrets Managerを使うとしよう。

「その他シークレット」のタイプで作成。
参加するドメインは`onprem.example.com`という設定だ。
![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/epbervqypq4rcsvq10n7.png)

こんな感じでドメインアカウントのユーザー名とパスワードを設定しておく（もちろん、コンピュータをドメイン参加させる権限のあるアカウントを使ってね）。 
![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/h551iospq3not6ty3sif.png)

`onprem.example.com/DomainJoin`という名前でシークレットを作成した。 
![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ne6ktw8q2wb4fwb0nhov.png)

<br>
ここから先は、EC2インスタンスプロファイル（IAMロール）にこの2つの権限が必要になってくる。
①さきほど作成したシークレット`onprem.example.com/DomainJoin`を読み取る権限
②EC2のタグを読み取る権限（Nameタグの値を読み取って、ホスト名に使う必要があるので）

こんな感じのポリシーを最低限追加しておく必要あり。
```
"Statement": [
        {
            "Sid": "ReadTag",
            "Effect": "Allow",
            "Action": "ec2:DescribeTags",
            "Resource": "*"
        },
        {
            "Sid": "SecretsMgrRead",
            "Effect": "Allow",
            "Action": [
                "secretsmanager:GetSecretValue"
            ],
            "Resource": "arn:aws:secretsmanager:<リージョン>:<AWSアカウント番号>:secret:onprem.example.com/DomainJoin-tewFSS"
        }
    ]
```

`secretsmanager:GetSecretValue`アクションの権限で指定する`Resource`の値は、さきほど作成したシークレットのARNを代入する。Secrets Managerで簡単に確認できる。
![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2n2g6nzp67d3fwmrjzwb.png)
 
<br>
これで準備が揃ったので、こういうスクリプトをUserDataに貼り付けて、Windows ServerのEC2インスタンスをたてる。
※AWS Tools for PowerShellを使うので、Amazonが提供する標準Windows ServerのAMIを使っていることを想定。自前のAMIを使うのであれば、AWS Tools for PowerShellをイメージにあらかじめ入れておく必要あり。

```
<powershell>
# ドメイン名とシークレット名を定義
$domainName = "onprem.example.com"
$secretName = "onprem.example.com/DomainJoin"

# シークレットの値をとってくる
$secretManager = Get-SECSecretValue -SecretId $secretName

# シークレットの値をオブジェクトに入れる
$secret = $secretManager.SecretString | ConvertFrom-Json

# ドメイン参加用認証情報を作成
$username = $domainName + "\" + $secret.Account
$password = $secret.Password | ConvertTo-SecureString -AsPlainText -Force
$credential = New-Object System.Management.Automation.PSCredential($username,$password)

# EC2インスタンスメタデータからインスタンスIDを取得し、続けてNameタグを取得
$instanceID = Get-EC2InstanceMetadata -Category InstanceId
$nameTag = Get-EC2Tag -Filter @{Name="resource-id";Value="$instanceID"},@{Name="key";Value="Name"}
$newName = $nameTag.Value

# ドメイン参加を実施
Add-Computer -DomainName "$domainName" -NewName "$newName" -Credential $credential -Passthru -Force -Restart
</powershell>
```

<br>
これで、EC2インスタンス作成と同時にドメイン参加・ホスト名変更までできた。ローカルアドミンのパスワードを一度も復号化する必要なくドメインアカウントでログインできるので便利。

<br>
ちなみに、ドメイン参加のためにはドメインコントローラーを名前解決できる必要があるので、
①Route 53 Resolverのアウトバウンドエンドポイントを作成し、ルールでADドメインの名前は、ADのDNSサーバーにルーティングさせる
②DHCPオプションセットを設定しておく
③UserDataスクリプトに、DNS設定をADに向けるように設定する操作を追加する
のどれかをする必要はある（他にも方法あるかも）。
私の場合は、①を設定しているので他の設定は特に不要。

<br>
次回にはSystems Manager Automationを使う方法かChefを使う方法を試そうかなと思う。

<br>
※イラストはこちらからご提供いただきました：
<a href="https://www.freepik.com/vectors/computer">Computer vector created by macrovector - www.freepik.com</a>