Terraform Cloud その4 - ワークスペース間で共有する閉じられた空間で使用するModuleについて

## はじめに
### そもそもModuleとは
`Terraform`にはModuleという共通処理化する機能が備わっています。
そのModuleを使用する際、参照できるディレクトリに配置されている場合はsource変数で指定ディレクトリを渡して指定しますが、他のプロジェクトで同じModuleを使用したい場合に頭を悩ませることになります。
その様な場合にTerraformではWEBやSSHなどのプロトコルで実行環境から参照できる場所にModuleを置くことで、各実行環境にて共通のModuleを使用するができるようになります。
但し、公Moduleを公開する場合はアクセスの権限を気にする必要はないのですが、業務利用する場合などある一定のユーザのみ利用できるModuleにしなければならないという要件が含まれることは多々あることと思います。
今回の記事では`Terraform Cloud`利用観点でアクセスを絞ったModuleについての設定の仕方を紹介したいと思います。

### この記事で実現すること
* `Terraform Cloud Private Module`の設定
* VCSのPrivate Moduleを利用したModuleの利用

### この記事がターゲットとする読者層
#### 読者層
* Terraform Cloudに興味がある人
* Terraform CloudのModuleの共有の仕方に興味がある人

#### 必要スキル
* 多少のTerraform CloudとVCSの知識


## 前提の設定
### VCSはこのような感じです
まず、りVCS設定は終わっているものとします。こちらができていない方は過去の記事を参考にしてください。
![スクリーンショット 2020-10-11 15.45.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/372095/f6fa6921-f908-9593-b8bb-e807af85f40d.png)
この様な簡単なPrivate Repositoryを作っています。
main.tfも簡単な`Terraform Cloud`に`Workspace`を作成するだけのものです。

```
variable "organization_name" {
  type    = string
  default = "kuroseets"
}

variable "workspace_name" {
  type    = string
  default = ""
}

variable "operations" {
  type    = bool
  default = false
}

resource "tfe_workspace" "this" {
  name         = var.workspace_name
  organization = var.organization_name
  operations   = var.operations
}
```

## Terraform Cloud Private Modules
### 機能紹介
`Terraform Cloud`でもアカウント内で使い回すことのできる`Private Modules`という機能があり、`Terraform Cloud`の`Organization`にて関連づけられたメンバーのみ参照できる閉じられた環境で利用することを想定した機能です。
こちらはVCSのリポジトリ、ブランチを`Workspache`に紐付けてApplyするのと同様に、VSCのリポジトリをModule設定にて紐付けてpublishして利用できる様にします。

### Private Modulesのpublish(設定方法)
`owners`権限を持つメンバーでログインし、メニューバーから`Modules`をクリック。
![スクリーンショット 2020-10-11 15.41.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/372095/a8823de9-76bf-f1eb-5ba1-4b2ef817a4f8.png)
`Add module`をクリック。
![スクリーンショット 2020-10-11 15.41.32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/372095/490bac9a-fb9a-8470-3e87-f31367eb0d03.png)
VCSを選択。
![スクリーンショット 2020-10-11 15.41.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/372095/c1c2f22f-25f1-9b53-8533-873cce719f14.png)
Moduleとしてpublishするリポジトリを選択。
キャプチャにもある通り、Repository名は`terraform-<PROVIDER>-<NAME>`である必要があります。
![スクリーンショット 2020-10-11 15.41.53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/372095/f19cce0c-1109-3bf1-d216-03be2ba3fa3f.png)
今回は次の様になります。

```
PROVIDER = tfe
NAME     = test
```

次に、`Publish module`をクリック。
![スクリーンショット 2020-10-11 15.42.17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/372095/5c8296eb-57d4-3de8-0bf5-33bea074d6cb.png)
登録完了。
![スクリーンショット 2020-10-11 15.44.07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/372095/f9c3fbb8-33f1-97c9-d060-b26a563d6519.png)

以上でpublishが完了しました。

### 呼び出し方
source変数は`<TERRAFORM CLOUD URL>/<ORGANIZATION>/<NAME>/<PROVIDER>`となります。
複数バージョンが存在する場合はversion変数を指定します。

```
module "create_workspace" {
  source         = "app.terraform.io/kuroseets/test/tfe"
  version        = "0.0.2"
  workspace_name = "test-ws"
}
```

## VSCのPrivate Repositoryを使用したModules
### 機能紹介
もう一つはTerraform Cloudにてpublishせずに、そのままVCSのPrivate Repositoryを参照する方法です。
Public Repositoryでしたらアクセス権限を考慮せず利用することが可能ですが、Private Repositoryを利用することで利用できるユーザを絞っています。
Private Repositoryを利用する場合の準備では、`Terraform Cloud`にて`SSH Keys`で秘密鍵を設定します。対になる公開鍵がVCSにて取り込まれていたらRepositoryにアクセスできるようになります。

### 設定方法
#### SSH鍵作成
どこかターミナル環境でSSH鍵を発行します。

```
ssh-keygen -t rsa -m PEM
```

#### Terraform CloudのOrganization設定
Terrafomr Cloudにて秘密鍵を登録します。
メニューバーのSettingsをクリックし、SSH Keysをクリック。
![スクリーンショット 2020-10-11 16.17.18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/372095/22e786d9-4856-6d84-d149-b852d5c73d4d.png)

Nameと秘密鍵を入力して`Add private SSH key`をクリック。
![スクリーンショット 2020-10-11 16.17.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/372095/66b0e0b1-fc9b-6626-9882-c14ef36804c2.png)

`Organization`に秘密鍵の登録完了。
![スクリーンショット 2020-10-11 16.22.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/372095/0e97ec79-c27a-f0ea-0ed2-21d6ac5837e0.png)

#### Terraform CloudのWorkspace設定
引き続き、`Workspace`の鍵を指定します。
`Workspaces`をクリックした後設定するWorkspace名をクリック。
![スクリーンショット 2020-10-11 16.23.50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/372095/f97f30ce-7f0f-0195-f875-790bb23cc889.png)

`Workspace`のメニューより`Settings`をクリックし、表示されたサブメニューの`SSH Key`をクリックする。
![スクリーンショット 2020-10-11 16.24.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/372095/8586f7ea-4245-75ea-74fc-a77e9c7bcad5.png)

`SSH key`ドロップダウンより先ほど登録したSSH鍵を指定し、`Update SSH key`をクリック。
![スクリーンショット 2020-10-11 16.28.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/372095/e2a16a7f-c097-51d2-acc3-5f35178f7893.png)

このダイアログが出ていたら登録完了。
![スクリーンショット 2020-10-11 16.30.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/372095/a02a6982-52ec-4e90-b6c2-adbb59fc2ed8.png)

#### VCSに公開鍵を設定(今回はGitHUB)
鍵を登録するユーザのメニューを開き、`Settings`画面を開きます。
![スクリーンショット 2020-10-11 16.33.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/372095/69afa2ca-a06b-8b72-bda2-3ca2ce394b9b.png)

`SSH and GPG keys`をクリック。
![スクリーンショット 2020-10-11 16.34.01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/372095/738b63da-6cd5-5159-d505-d73fc2b2242c.png)

SSH keys画面で`New SSH key`をクリック。
![スクリーンショット 2020-10-11 16.34.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/372095/6d6d5af3-611c-7400-228c-b3798f3be541.png)

TitleとKeyを入力し`Add SSH key`をクリック。
![スクリーンショット 2020-10-11 16.34.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/372095/ff481513-cc0c-3f61-a177-ed6d3f1768e7.png)

パスワード入力を求められた場合はパスワードを入力。
![スクリーンショット 2020-10-11 16.35.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/372095/c5df917a-9737-e3cb-249a-098f32095739.png)

登録した公開鍵が確認できたら登録完了。
![スクリーンショット 2020-10-11 16.35.27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/372095/1cca8c7a-3e01-d499-01bf-5525c1c7f0e4.png)

### 呼び出し方
source変数には`git cloneする際の文字列`を指定します。

```
module "create_workspace" {
  source         = "git@github.com:kuroseets/terraform-tfe-test.git"
  workspace_name = "test-ws"
}
```

バージョンを指定する場合は、version変数を使用せず、下記の様にrefを指定します。

```
source         = "git@github.com:kuroseets/terraform-tfe-test.git?ref=v0.0.2"
```

## 双方を比較しての私感
`Private Modules`とVCSのPrivate RepositoryでSSH鍵を利用するModulesを比較して一番懸念される観点はセキュリティになると思います。
`Terraform Cloud`で実装する場合、これはSaasにて一定のメンバーからしかアクセスできないことが担保されていると考えて間違いないと思います。
一方VCSを使用する場合ですが、この場合はアクセス権限管理がVCSのものになりますので冗長のように見え、一見セキュリティに難があると感じるかもしれませんが、`Private Modules`を利用する状況で`Workspace`にVSCを利用していないことは想像し辛いところがあります。
要はTerraformのModule以外のコードもVCSにて管理され、一定の権限でアクセスできる様になっているのと同様、Moduleも一定の権限でしかアクセスできないと考えると、セキュリティレベルは同等のものが担保されている状態であると言えます。
あとは使い勝手に関してのメリット・デメリットで判断すれば良いのかなと思います。
### 個人的なメリデメ
||メリット|デメリット|
|:--|:--|:--|
|Terraform Cloud Private Modules|Applyする環境と一体感がある|Publishに`owners`権限が必要<br />Repositoryのtag付必須<br />Repositoryに一定の命名規則|
|Private RepositoryをModuleとして参照|Terraform Cloudから切り離せる|SSH鍵を管理する必要がある<br />source変数の書き方が残念|
並べてみましたけど、どっちでも良いですね。
`Terraform Cloud Free`の様なある程度の規模の範囲で`Organization`を区切って使う場合はあまり気にすることは無いと思いますので、使いたい様に使えば良いと思います。
逆に、`Terraform Cloud Team & Governance`以上の`Organization`が大きくなる場合に、複数のプロジェクトや権限が異なるメンバーなどいろいろ条件が違う人たち一箇所で使用する場合、全体に適用される`Private Modules`が足枷で動きが鈍くなるのではという気がしますの。
その場合は横断で使うものは`Private Modules`、各プロジェクトの範囲で利用するものはプロジェクトの範囲で閲覧権限のあVCS Private Repositoryで実装するのが良いのではと感じます。

## 今回記事を書いた理由
以上となります。
今回この記事を書いた理由は、Terraform-jpのSlack内で`Terraform Cloud`の話題になった際に意外に`Private Modules`を使っている人が少ないと感じたことからでした。
もし、「こうやってるよー」という意見があれば教えていただきたいところです。

今回もありがとうございました。

## 参考ページ
https://www.terraform.io/docs/modules/sources.html

## 関連記事
[Terraform Cloud その1 - まずは使ってみた(ローカル実行からリモート実行に変更)](https://qiita.com/kuroseets/items/be8980a7c9764f28ed11)
[Terraform Cloud その2 - Gihubと連携してみた(VCSとWorking Directoryの設定)](https://qiita.com/kuroseets/items/9104c926b14cd52ffc03)
[Terraform Cloud その3 - Terraform CloudをTerraformで管理する](https://qiita.com/kuroseets/items/bdd160edef10f715c426)
[Terraform Cloud その4 - ワークスペース間で共有する閉じられた空間で使用するModuleについて](https://qiita.com/kuroseets/items/be51dabf7f2ecfb24055)