Revisiting driftctl

driftctl[^1] について。

![f566aeccf21307-a.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/569971/16fc6854-fc22-97e3-081a-6a4b216ee888.png)

https://docs.driftctl.com/0.40.0

個人的には Infrastructure as Code (IaC) を取り入れるのは比較的簡単だと思う。

Terraform に複雑な文法は存在しないし、Terraform の本や記事は大量にある。

一方、IaC を維持することは相応に難しいと思う。なぜか。

console が存在するため、console で変更し、状態の乖離が生まれるから。

改めて driftctl[^1] について導入を検討する。

## tl;dr
- 現在は Google Cloud でも使える。当初は AWS のみだった。
- 意図しない IAM の付与などを監査できる。CI (Continuous Integration) の step として組み込めそう。
- `.driftignore`[^4] の管理が重要。

## About driftctl
Snyk の OSS。

> driftctl is CLI tool that measures infrastructure as code coverage, and tracks infrastructure drift.
> 
> driftctl は、コード・カバレッジとしてインフラストラクチャを測定し、インフラストラクチャのドリフトを追跡する CLI ツールである。

## Getting stated
### IAM
driftctl を実行する（させる）ためには、以下の role が必要。
- `roles/viewer` 閲覧者
- `roles/serviceusage.serviceUsageAdmin` Service Usage 管理者
or
- `roles/serviceusage.serviceUsageAdmin` Service Usage 管理者
- `roles/cloudasset.viewer` クラウド アセット閲覧者

### Installation[^2]
- Cloud Shell に install する。
```bash
curl -L https://github.com/snyk/driftctl/releases/latest/download/driftctl_linux_amd64 -o driftctl
chmod +x driftctl
sudo mv driftctl /usr/local/bin/
```

### Usage[^3]
- scan 対象の project を指定することが重要。`CLOUDSDK_CORE_PROJECT`

```bash: command
CLOUDSDK_CORE_PROJECT=hoge\
  driftctl scan --to gcp+tf --from tfstate+gs://hoge-tfstate/env/dev/default.tfstate
```

:::details scan
```bash: log
gcp_iam_verifier@cloudshell:~ (hoge)$ CLOUDSDK_CORE_PROJECT=hoge\
  driftctl scan --to gcp+tf --from tfstate+gs://hoge-tfstate/env/dev/default.tfstate
Scanned states (1)      
Found resources not covered by IaC:
  google_compute_address:
    - projects/hoge/regions/asia-northeast2/addresses/nat-auto-ip-21669046-5-1704943320202150
        Address: xx.xx.xx.xx, Name: nat-auto-ip-21669046-5-1704943320202150
  google_compute_disk:
    - projects/hoge/zones/asia-northeast2-a/disks/gke-cluster-hoge-service-pool-0d194ef2-d6sk
        Name: gke-cluster-hoge-service-pool-0d194ef2-d6sk
  google_compute_firewall:
    - projects/hoge/global/firewalls/default-allow-icmp
    - projects/hoge/global/firewalls/default-allow-internal
    - projects/hoge/global/firewalls/default-allow-rdp
    - projects/hoge/global/firewalls/default-allow-ssh
    - projects/hoge/global/firewalls/gke-cluster-hoge-fdda8f5b-all
    - projects/hoge/global/firewalls/gke-cluster-hoge-fdda8f5b-exkubelet
    - projects/hoge/global/firewalls/gke-cluster-hoge-fdda8f5b-inkubelet
    - projects/hoge/global/firewalls/gke-cluster-hoge-fdda8f5b-master
    - projects/hoge/global/firewalls/gke-cluster-hoge-fdda8f5b-vms
    - projects/hoge/global/firewalls/k8s-7e03882898f0acc7-node-http-hc
    - projects/hoge/global/firewalls/k8s-fw-a551924e3cf67427db25e0a105f0fb7a
  google_compute_forwarding_rule:
    - projects/hoge/regions/asia-northeast2/forwardingRules/a551924e3cf67427db25e0a105f0fb7a
  google_compute_global_address:
    - projects/hoge/global/addresses/hoge-ip-range
        Address: 10.88.80.0, Name: hoge-ip-range
  google_compute_instance:
    - projects/hoge/zones/asia-northeast2-a/instances/gke-cluster-hoge-service-pool-0d194ef2-d6sk
  google_compute_instance_group:
    - projects/hoge/zones/asia-northeast2-a/instanceGroups/gke-cluster-hoge-process-pool-7ccd9538-grp
        Name: gke-cluster-hoge-process-pool-7ccd9538-grp
    - projects/hoge/zones/asia-northeast2-a/instanceGroups/gke-cluster-hoge-service-pool-0d194ef2-grp
        Name: gke-cluster-hoge-service-pool-0d194ef2-grp
    - projects/hoge/zones/asia-northeast2-a/instanceGroups/gke-cluster-hoge-service-pool-61ee2fe7-grp
        Name: gke-cluster-hoge-service-pool-61ee2fe7-grp
  google_compute_instance_group_manager:
    - projects/hoge/zones/asia-northeast2-a/instanceGroupManagers/gke-cluster-hoge-process-pool-7ccd9538-grp
        Name: gke-cluster-hoge-process-pool-7ccd9538-grp
    - projects/hoge/zones/asia-northeast2-a/instanceGroupManagers/gke-cluster-hoge-service-pool-0d194ef2-grp
        Name: gke-cluster-hoge-service-pool-0d194ef2-grp
    - projects/hoge/zones/asia-northeast2-a/instanceGroupManagers/gke-cluster-hoge-service-pool-61ee2fe7-grp
        Name: gke-cluster-hoge-service-pool-61ee2fe7-grp
  google_compute_network:
    - projects/hoge/global/networks/default
  google_compute_subnetwork:
    - projects/hoge/regions/africa-south1/subnetworks/default
        Name: default
    - projects/hoge/regions/asia-east1/subnetworks/default
        Name: default
    - projects/hoge/regions/asia-east2/subnetworks/default
        Name: default
    - projects/hoge/regions/asia-northeast1/subnetworks/default
        Name: default
    - projects/hoge/regions/asia-northeast2/subnetworks/default
        Name: default
    - projects/hoge/regions/asia-northeast3/subnetworks/default
        Name: default
    - projects/hoge/regions/asia-south1/subnetworks/default
        Name: default
    - projects/hoge/regions/asia-south2/subnetworks/default
        Name: default
    - projects/hoge/regions/asia-southeast1/subnetworks/default
        Name: default
    - projects/hoge/regions/asia-southeast2/subnetworks/default
        Name: default
    - projects/hoge/regions/australia-southeast1/subnetworks/default
        Name: default
    - projects/hoge/regions/australia-southeast2/subnetworks/default
        Name: default
    - projects/hoge/regions/europe-central2/subnetworks/default
        Name: default
    - projects/hoge/regions/europe-north1/subnetworks/default
        Name: default
    - projects/hoge/regions/europe-southwest1/subnetworks/default
        Name: default
    - projects/hoge/regions/europe-west1/subnetworks/default
        Name: default
    - projects/hoge/regions/europe-west10/subnetworks/default
        Name: default
    - projects/hoge/regions/europe-west12/subnetworks/default
        Name: default
    - projects/hoge/regions/europe-west2/subnetworks/default
        Name: default
    - projects/hoge/regions/europe-west3/subnetworks/default
        Name: default
    - projects/hoge/regions/europe-west4/subnetworks/default
        Name: default
    - projects/hoge/regions/europe-west6/subnetworks/default
        Name: default
    - projects/hoge/regions/europe-west8/subnetworks/default
        Name: default
    - projects/hoge/regions/europe-west9/subnetworks/default
        Name: default
    - projects/hoge/regions/me-central1/subnetworks/default
        Name: default
    - projects/hoge/regions/me-central2/subnetworks/default
        Name: default
    - projects/hoge/regions/me-west1/subnetworks/default
        Name: default
    - projects/hoge/regions/northamerica-northeast1/subnetworks/default
        Name: default
    - projects/hoge/regions/northamerica-northeast2/subnetworks/default
        Name: default
    - projects/hoge/regions/southamerica-east1/subnetworks/default
        Name: default
    - projects/hoge/regions/southamerica-west1/subnetworks/default
        Name: default
    - projects/hoge/regions/us-central1/subnetworks/default
        Name: default
    - projects/hoge/regions/us-east1/subnetworks/default
        Name: default
    - projects/hoge/regions/us-east4/subnetworks/default
        Name: default
    - projects/hoge/regions/us-east5/subnetworks/default
        Name: default
    - projects/hoge/regions/us-east7/subnetworks/default
        Name: default
    - projects/hoge/regions/us-south1/subnetworks/default
        Name: default
    - projects/hoge/regions/us-west1/subnetworks/default
        Name: default
    - projects/hoge/regions/us-west2/subnetworks/default
        Name: default
    - projects/hoge/regions/us-west3/subnetworks/default
        Name: default
    - projects/hoge/regions/us-west4/subnetworks/default
        Name: default
    - projects/hoge/regions/us-west8/subnetworks/default
        Name: default
  google_project_iam_member:
    - hoge/roles/artifactregistry.reader/serviceAccount:terraform@hoge.iam.gserviceaccount.com
    - hoge/roles/cloudasset.viewer/group:gcp-hoge-developers@example.jp
    - hoge/roles/cloudscheduler.admin/serviceAccount:terraform@hoge.iam.gserviceaccount.com
    - hoge/roles/cloudsql.admin/serviceAccount:terraform@hoge.iam.gserviceaccount.com
    - hoge/roles/cloudsql.client/serviceAccount:terraform@hoge.iam.gserviceaccount.com
    - hoge/roles/compute.admin/serviceAccount:terraform@hoge.iam.gserviceaccount.com
    - hoge/roles/container.admin/serviceAccount:terraform@hoge.iam.gserviceaccount.com
    - hoge/roles/container.clusterAdmin/serviceAccount:terraform@hoge.iam.gserviceaccount.com
    - hoge/roles/iam.serviceAccountAdmin/serviceAccount:terraform@hoge.iam.gserviceaccount.com
    - hoge/roles/iam.serviceAccountCreator/serviceAccount:terraform@hoge.iam.gserviceaccount.com
    - hoge/roles/iam.serviceAccountDeleter/serviceAccount:terraform@hoge.iam.gserviceaccount.com
    - hoge/roles/iam.serviceAccountUser/serviceAccount:terraform@hoge.iam.gserviceaccount.com
    - hoge/roles/owner/user:danny@example.jp
    - hoge/roles/pubsub.admin/serviceAccount:terraform@hoge.iam.gserviceaccount.com
    - hoge/roles/resourcemanager.projectIamAdmin/serviceAccount:terraform@hoge.iam.gserviceaccount.com
    - hoge/roles/run.admin/serviceAccount:terraform@hoge.iam.gserviceaccount.com
    - hoge/roles/secretmanager.admin/serviceAccount:terraform@hoge.iam.gserviceaccount.com
    - hoge/roles/serviceusage.serviceUsageAdmin/group:gcp-hoge-developers@example.jp
    - hoge/roles/serviceusage.serviceUsageAdmin/serviceAccount:terraform@hoge.iam.gserviceaccount.com
    - hoge/roles/storage.admin/serviceAccount:terraform@hoge.iam.gserviceaccount.com
    - hoge/roles/viewer/group:gcp-hoge-developers@example.jp
    - hoge/roles/vpcaccess.admin/serviceAccount:terraform@hoge.iam.gserviceaccount.com
  google_sql_database_instance:
    - hoge
  google_storage_bucket:
    - hoge-tfstate
Found 106 resource(s)
 - 16% coverage
 - 17 resource(s) managed by Terraform
 - 89 resource(s) not managed by Terraform
 - 0 resource(s) found in a Terraform state but missing on the cloud provider
Scan duration: 4s
Provider version used to scan: . Use --tf-provider-version to use another version.
gcp_iam_verifier@cloudshell:~ (hoge)$ 
```
:::

## Practice
- 許容するものを `.driftignore`[^4] に定義する。
- `.driftignore` に存在しない service account/mail account の role が追加された場合 coverage が 100 を切る。それをチェックする。

```bash
# driftctl scan --driftignore /path/to/driftignore
CLOUDSDK_CORE_PROJECT=hoge\
  driftctl scan --to gcp+tf --from tfstate+gs://hoge-tfstate/env/dev/default.tfstate  --driftignore /home/gcp_iam_verifier/.driftignore
```

```bash:log
gcp_iam_verifier@cloudshell:~ (hoge)$ cat .driftignore
*
!google_project_iam_member
*serviceAccount:terraform@hoge.iam.gserviceaccount.com
*yamamoto_daisuke@example.jp
*gcp-hoge-developers@example.jp
gcp_iam_verifier@cloudshell:~ (hoge)$ CLOUDSDK_CORE_PROJECT=hoge  driftctl scan --to gcp+tf --from tfstate+gs://hoge-tfstate/env/dev/default.tfstate  --driftignore /home/gcp_iam_verifier/.driftignore
Scanned states (1)      
Found 14 resource(s)   
 - 100% coverage
Congrats! Your infrastructure is fully in sync.
Scan duration: 2s
Provider version used to scan: . Use --tf-provider-version to use another version.
gcp_iam_verifier@cloudshell:~ (hoge)$ 
```

[^1]: https://docs.driftctl.com/0.40.0
[^2]: https://docs.driftctl.com/0.40.0/installation
[^3]: https://docs.driftctl.com/0.40.0/providers/google/authentication
[^4]: https://docs.driftctl.com/next/usage/filtering/driftignore/