SSMのセッションマネージャをTerraformで設定する

# TerraformでAWSセッションマネージャを管理する
Terraformでセッションマネージャの設定も管理したかったのですが方法がわからないでいたところ教えていただいたので共有と備忘録がてら記載します。


## AWS SSMのセッションマネージャが発表
1ヶ月ほど前ですかね、EC2にSSHなしでコンソールアクセスできるサービスが発表されましたね。
[最新 – AWS Systems Manager セッションマネージャーで EC2 インスタンスへのシェルアクセスを実現](https://aws.amazon.com/jp/blogs/news/new-session-manager/)

## Terraformで管理したい
セッションマネージャでアクセスしたコンソールのヒストリの保存先として、CloudWatch LogsやS3(暗号化の有無など)を設定できますがTerrafomのドキュメント等読んでいてもそれっぽいのがみつからなかったので以下を教えていただきました。

Terraform の AWS用モジュール [session-manager-settings](https://registry.terraform.io/modules/gazoakley/session-manager-settings/aws/1.0.1) 

モジュールのコードを読んでみると `aws_ssm_document` を利用するようでした。


## セッションマネージャの設定はSSMのセッションドキュメント
私は `aws_ssm_session_hogehufa` みたいのが新しく追加されてたりしないかなみたいな気持ちで居たのですが、セッションマネージャはSSMのドキュメントの1つ(ドキュメントタイプがsession)のようです。([AWS Systems Manager Documents の Types of SSM Documents](https://docs.aws.amazon.com/systems-manager/latest/userguide/sysman-ssm-docs.html)を読むとまだsessionは存在してない…、セッションマネージャ以外で利用することはないからかな？)

また、先程のモジュールに記載があるようにSSMのドキュメント名は `SSM-SessionManagerRunShell` と書いてあり、 CLIのドキュメント([start-session - AWS CLI 1.16.38 Command Reference](https://docs.aws.amazon.com/cli/latest/reference/ssm/start-session.html#options))のオプションにも同様のドキュメント名が存在しているのでデフォルト名かな？と思って探してみましたがありませんでした。

```sh
❯ aws ssm get-document --name SSM-SessionManagerRunShell

An error occurred (InvalidDocument) when calling the GetDocument operation: Document with name SSM-SessionManagerRunShell does not exist.
```

この環境では一度もセッションマネージャを触っていなかったので、試しにWebコンソールから設定画面を開いてみました。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/31262/e12947f5-3c2b-1324-be82-c0137a24fb35.png)

そして、もう一度同様のコマンドを実行してみると存在していました。

```sh
❯ aws ssm get-document --name SSM-SessionManagerRunShell
{
    "Name": "SSM-SessionManagerRunShell",
    "DocumentVersion": "1",
    "Content": "{\"schemaVersion\":\"1.0\",\"description\":\"Document to hold regional settings for Session Manager\",\"sessionType\":\"Standard_Stream\",\"inputs\":{\"s3BucketName\":\"\",\"s3KeyPrefix\":\"\",\"s3EncryptionEnabled\":true,\"cloudWatchLogGroupName\":\"\",\"cloudWatchEncryptionEnabled\":true}}",
    "DocumentType": "Session",
    "DocumentFormat": "JSON"
}
```

なので、一度でもセッションマネージャを利用していればこのデフォルトのSSMドキュメントが生成されるようです。


## Terraformで設定する
さて長々とセッションマネージャのこと見てきましたが、早速先程のモジュールを利用してTerraromを書いていきましょう。


### providerは1.36以上を利用
セッションマネージャを `aws_ssm_document` で利用するにはバージョン1.36以上のproviderを利用する必要があります。
数ヶ月前から利用しているTerraformの環境ですと、providerが古いままの可能性があるので、versionを指定し、`terraform init`するなどしてproviderを更新してください。

```provider.tf
variable "aws_profile" {}

provider "aws" {
  version    = "~> 1.36"
  region     = "ap-northeast-1"
  profile    = "${var.aws_profile}"
}
```

### moduleを利用しssmを設定する
お試しで、暗号化したS3を利用し、暗号化して保存する設定にしてみました。

```ssm.tf
resource "aws_s3_bucket" "session_manager_log_bucket" {
  bucket = "momiage-man-session-manager-log"

  server_side_encryption_configuration {
    rule {
      apply_server_side_encryption_by_default {
        sse_algorithm     = "AES256"
      }
    }
  }
}

module "session-manager-settings" {
  source  = "gazoakley/session-manager-settings/aws"

  s3_bucket_name            = "${aws_s3_bucket.session_manager_log_bucket.id}"
  s3_encryption_enabled     = true
}
```

applyすると怒られました…

```sh
Error: Error applying plan:

1 error(s) occurred:

* module.session-manager-settings.aws_ssm_document.session_manager_prefs: 1 error(s) occurred:

* aws_ssm_document.session_manager_prefs: Error creating SSM document: DocumentAlreadyExists: Document with same name SSM-SessionManagerRunShell already exists
	status code: 400, request id: 83076668-c2f4-435e-914d-621e51e4a827

Terraform does not automatically rollback in the face of errors.
Instead, your Terraform state file has been partially updated with
any resources that successfully completed. Please address the error
above and apply again to incrementally change your infrastructure.
```

さっきコンソールからアクセスして、`SSM-SessionManagerRunShell` を作成したからだ…
消しましょう…

webコンソールから削除するところみつけれなかったのでコマンドで。

```sh
❯ aws ssm delete-document --name SSM-SessionManagerRunShell
❯ aws ssm get-document --name SSM-SessionManagerRunShell

An error occurred (InvalidDocument) when calling the GetDocument operation: Document with name SSM-SessionManagerRunShell does not exist.
```

削除コマンドにメッセージなかったので、getして消えたことを確認します。
Applyを実行すると今度は正常に作成できました。

このモジュールは一度もアクセスしたことがない人用みたいですね…
`aws_ssm_document` モジュールにもimportは実装されていないようなので、一度でもアクセスした人はcliでドキュメントの削除が必要そうです。

### moduleではなく自分でterraformのコードを記述する
先程のモジュールを使って実現したことをコードで書いても以下だけなので、わざわざ使わなくても良いかもしれません。

```ssm.tf
resource "aws_ssm_document" "session-manager-settings" {
  name            = "SSM-SessionManagerRunShell"
  document_type   = "Session"
  document_format = "JSON"

  content = <<DOC
{
    "schemaVersion": "1.0",
    "description": "Document to hold regional settings for Session Manager",
    "sessionType": "Standard_Stream",
    "inputs": {
        "s3BucketName": "${aws_s3_bucket.session_manager_log_bucket.id}",
        "s3EncryptionEnabled": true
    }
}
DOC
}
```

#### ドキュメント記述の注意点
`aws_ssm_document` の content内の `s3EncryptionEnabled` に渡す情報を、string(`"true"`)にしてしまうとフラグ扱いを受けずに、暗号化が有効になりませんでした。
`"` で囲っていても何もエラーにもならないので注意してください。

# おわりに
セッションマネージャのおかげでEC2に外向きのSSHの穴を閉じて運用ができたり。
誰がいつサーバ内にアクセスしたか(ユーザ管理をちゃんとしていないと意味ないですが…)、アクセスした際の操作した内容の保存といったが簡単にできるようになって大変ありがたいです。

最初はWebコンソールだけしかないかなと思ったりはしていたんですが、普通にAWS CLIから(追加モジュールのインストールは必要ですが…)SSHしているような感覚でEC2にアクセスができるので使い勝手も良さそうです。

まだ小さく利用開始したところなので、今後の運用等でメリット・デメリットを見つけていこうと思います。