Terraform Cloudのremote state sharingを試してみる

## remote state sharing
分割されたtfstateを参照する場合、[terraform_remote_state](https://registry.terraform.io/providers/hashicorp/terraform/latest/docs/data-sources/remote_state)を利用する。これを利用することで別のtfstateのoutputで定義した情報を参照することができる。
tfstateへのアクセスを制限する場合は実行ユーザのアクセス権限を設定することで制御するが、Terraform Cloudではそれに加えてtfstate側(Terraform Cloud Workspace側)のアクセス制御の機能として [remote state sharing](https://www.hashicorp.com/blog/announcing-controlled-remote-state-access-for-terraform-cloud-and-enterprise)がある。

Workspace Settings → General Settingsから変更でき、`Share with all workspaces in this organization` を選択すると別のworkspaceからtfstateを参照可能になる。`Share with specific workspaces`を選択して対象のworkspaceを指定すると、指定したworkspaceからはtfstateの参照が可能となり、指定していないworkspaceからはtfstateの参照が不可能となる。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14181/fff7414c-f094-e8c9-f0f1-22b07160d7ee.png)

## 動作検証
実際にremote state sharingを試してみる

### 検証環境
network-workspaceとapp-workspaceという2つのworkspaceを準備する。
network-workspaceではネットワーク関連のリソースを定義し、app-workspaceではアプリ固有のリソースを定義することを想定する。また、app-workspaceはnetwork-workspaceのoutputを参照する。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14181/d33800c1-5424-3e28-cf7e-acd504f48d2e.png)


network-workspaceのremote state sharingで、app-workspaceからのアクセスを許可すればapp-workspaceのリソース構築は成功するし、app-workspaceからのアクセスを許可しなければapp-workspaceのリソース構築は失敗することが期待できる。

### ローカルplan実行
network-workspaceのremote state sharingで、アクセスを許可した状態で app-workspaceでplanを実行する。
このとき、無事terraform_remote_stateを用いてnetwork-workspaceのoutputを参照できている。
(事前にapply済のためここのplanでは差分なしになっている)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14181/cac40cd7-7452-9b29-0fe9-9e2be87e3922.png)


```
$ terraform  plan
data.terraform_remote_state.network: Reading...
data.terraform_remote_state.network: Read complete after 2s
data.aws_subnet.sample: Reading...
data.aws_subnet.sample: Read complete after 0s [id=subnet-xxxx]

No changes. Your infrastructure matches the configuration.

Terraform has compared your real infrastructure against your configuration and found no differences, so no changes are needed.
```

続いて、network-workspaceのremote state sharingで、アクセスを許可せずに app-workspaceでplanを実行する。
するとなぜか今度もplanに成功してしまう。本当は `data.terraform_remote_state.network` の参照でエラーになって欲しかった。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14181/26171281-5b85-0dd5-68a3-588bea5699b6.png)


```
$ terraform  plan
data.terraform_remote_state.network: Reading...
data.terraform_remote_state.network: Read complete after 2s
data.aws_subnet.sample: Reading...
data.aws_subnet.sample: Read complete after 0s [id=subnet-xxxx]

No changes. Your infrastructure matches the configuration.

Terraform has compared your real infrastructure against your configuration and found no differences, so no changes are needed.
```

### なぜ実行できるのか
app-workspaceの[Execution Mode](https://developer.hashicorp.com/terraform/cloud-docs/workspaces/settings#execution-mode)をLocalにしてplanを実行したから。
Terraform Cloudには、Terraform Cloud上でterraform planを実行する Remote Execution Modeと、ローカルでterraform planを実行する Local Execution Modeがある。Remote Execution Modeの場合はローカルでterraform planを実行しても、Terraform Cloud上で実行したplan結果が表示されるだけになる。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14181/53a68e08-626d-863e-0957-d9d4e09250f1.png)

Local Execution Modeの場合、Terraform Cloudは単なるtfstate置き場になる。このときローカルでterraform planを実行しても直接network workspaceのリソースを参照するので、remote state sharingも機能しなくなると推測する。

### リモートplan実行
app-workspaceのExecution ModeをRemoteに変更してplanを実行する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14181/fdb39367-0e1d-ebea-fdcd-22fdb7953959.png)

```
$ terraform  plan
...
Terraform v1.3.6
on linux_amd64
Initializing plugins and modules...
data.terraform_remote_state.network: Reading...
╷
│ Error: Error retrieving state: forbidden
│ 
│ This Terraform run is not authorized to read the state of the workspace 'sample-network-workspace'.
│ Most commonly, this is required when using the terraform_remote_state data source.
│ To allow this access, 'sample-network-workspace' must configure this workspace ('sample-app-workspace')
│ as an authorized remote state consumer. For more information, see:
│ https://www.terraform.io/docs/cloud/workspaces/state.html#accessing-state-from-other-workspaces.
│ 
│ 
│ 
╵
Operation failed: failed running terraform plan (exit 1)
```

となり、無事 remote state sharingによるアクセス制御に成功した。

また、network-workspaceの remote state sharingでapp-workspaceにアクセスを許可して再度planを実行してみる。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14181/a856e117-09f7-22d4-06f7-5b73445ea8d6.png)

すると、今度はplanの実行に成功する。もちろん、全workspaceにアクセスを許可しても結果は同じ。

```
$ terraform  plan
...
Terraform v1.3.6
on linux_amd64
Initializing plugins and modules...
data.terraform_remote_state.network: Reading...
data.terraform_remote_state.network: Read complete after 0s
data.aws_subnet.sample: Reading...
data.aws_subnet.sample: Read complete after 1s [id=subnet-xxxx]

No changes. Your infrastructure matches the configuration.

Terraform has compared your real infrastructure against your configuration
and found no differences, so no changes are needed.
```

### tfe_outputsを利用する
Terraform Cloudを利用する場合、outputの参照に terraform_remote_stateを使わずにtfe_outputsを使う方法がある。
[こちらのドキュメント](https://developer.hashicorp.com/terraform/language/state/remote-state-data)では、terraform_remote_stateのoutputsを使わずにtfe_outputsを利用することを推奨している。

tfe_outputsを利用する場合も同じ。
network-workspaceの remote state sharingでapp-workspaceにアクセスを許可してplanを実行すると成功し、アクセスを許可しないとplanに失敗する。
ただし、失敗時のエラーがforbiddenではなくUnsupported attributeになる。

```
$ terraform  plan
...
Terraform v1.3.6
on linux_amd64
Initializing plugins and modules...
data.tfe_outputs.network: Reading...
data.tfe_outputs.network: Read complete after 0s [id=xxxx]
╷
│ Error: Unsupported attribute
│ 
│   on network.tf line 3, in data "aws_subnet" "sample":
│    3:   id = data.tfe_outputs.network.values.subnet_id
│ 
│ This object does not have an attribute named "subnet_id".
╵
Operation failed: failed running terraform plan (exit 1)
```

アクセスエラー時に401ではなく404を返すのはセキュリティ的には正しい挙動か。


## まとめ
* Terraform Cloudにおけるwrokspace間のリソース参照の制御にremote state sharing機能がある
* remote state sharingはTerraform Cloud上でterraform planを実行するRemote Execution Modeのときのみ有効
* ローカルでterraform planを実行するLocal Execution Modeのときはremote state sharingではアクセス制御できない
* terraform_remote_stateでもtfe_outputsでもアスセス制御は可能だがエラー時のレスポンスが異なる