はじめに
実リソースとコードの差異を検出することをドリフト検出と言うそうです。
今回は、Terraformで作成したAWSリソースとtfstateファイルの差異を検出します。
Snykで試したかったことがこれです!
まとめ
ドリフト検出を試して、おおむね満足のいく結果になりました。SGのインバウンドルール追加は検出されませんでしたが。理由は調査中です。
使いこなすには、ポリシーで何を検出しないか決めたり、コードの定義もデフォルトに任せず明記したほうがいいかも。
あと、結果をJSON形式で出力すれば、tfstateファイルに管理外のリソースをインポートしやすくなるかもしれないですね。
目次
環境
試すこと
TerraformでEC2インスタンスを構築した後、手動でEIPとSGのインバウンドルールを追加し、ドリフト検出します。
実行コマンドは以下です。
$ snyk iac describe IaC describe Usage Note: This feature is available in Snyk CLI version v1.876.0 or greater. snyk iac describe [<OPTIONS>] Description The snyk iac describe command detects infrastructure drift and unmanaged resources. It compares resources in your Terraform state file against actual resources in your cloud provider and outputs a report. - Resources in your Terraform state files are managed resources. - Changes to managed resources not reflected in the Terraform state file are drifts. - Resources that exist but are not in your Terraform state file are unmanaged resources. For detailed information and examples, see IaC describe command examples https://docs.snyk.io/prod ucts/snyk-infrastructure-as-code/detect-drift-and-manually-created-resources/iac-describe-command- examples For a list of related commands see the snyk iac help; iac --help Exit codes Possible exit codes and their meaning: 0: success, no drift found 1: drifts or unmanaged resources found 2: failure Required options Note: To use the describe command, you must use one of these options: --only-unmanaged Report resources not found in any Terraform states. --only-managed or --drift Scan managed resources found in Terraform states for changes. --all Scan both managed and unmanaged resources.
リソース作成前にドリフト検出する
tfstateファイルは存在しないので、これといった結果はありません。
「IaC Coverage: 0%」が重要そうですね。
$ snyk iac describe --drift Scanned states (1) Scan duration: 16s Provider version used to scan: 4.28.0. Use --tf-provider-version to use another version. Snyk Scanning Infrastructure As Code Discrepancies... Info: Resources under IaC, but different to terraform states. Resolve: Reapply IaC resources or update into terraform. Test Summary IaC Coverage: 0% Info: To reach full coverage, remove resources or move it to Terraform. Tip: Run --help to find out about commands and flags. Scanned with aws provider version 4.28.0. Use --tf-provider-version to update.
TerraformでEC2インスタンスを構築する
ドリフト検出するために、以下のtfファイルでEC2インスタンスを構築します。
provider "aws" { region = "ap-northeast-1" } resource "aws_instance" "mito-ec2" { ami = "ami-0f36dcfcc94112ea1" instance_type = "t2.micro" key_name = "キー名" associate_public_ip_address = "true" vpc_security_group_ids = [ aws_security_group.mito_sg.id ] tags = { Name = "mito-ec2" } } resource "aws_security_group" "mito_sg" { name = "mito_sg" # インバウンド dynamic "ingress" { for_each = [22, 80] content { from_port = ingress.value to_port = ingress.value protocol = "tcp" cidr_blocks = ["0.0.0.0/0"] } } # アウトバウンド egress { from_port = 0 to_port = 0 protocol = "-1" cidr_blocks = ["0.0.0.0/0"] } }
EC2インスタンスを変更する前に、ドリフト検出する
Changed Resourcesが2となっているけど、まぁ今回は気にしない。
Ignore resourcesで、検出したくないリソースが指定できそうです。
$ snyk iac describe --drift Scanned states (1) Scan duration: 14s Provider version used to scan: 4.28.0. Use --tf-provider-version to use another version. Snyk Scanning Infrastructure As Code Discrepancies... Info: Resources under IaC, but different to terraform states. Resolve: Reapply IaC resources or update into terraform. Changed resources: 2 State: Generated [ Changed Resources: 1 ] Resource Type: aws_ebs_volume ID: vol-056e51aa5a6148297 + timeouts: null => {} State: tfstate://terraform.tfstate [ Changed Resources: 1 ] Resource Type: aws_instance ID: i-0683a97d236667e6f ~ arn: arn:aws:ec2:ap-northeast-1:xxxx:instance/i-0683a97d236667e6f => arn:aws:ec2:ap-northeast-1::instance/i-0683a97d236667e6f - user_data_replace_on_change: false Test Summary Managed Resources: 3 Changed Resources: 2 IaC Coverage: 100% Info: To reach full coverage, remove resources or move it to Terraform. Tip: Run --help to find out about commands and flags. Scanned with aws provider version 4.28.0. Use --tf-provider-version to update.
EIPを付与した後に、ドリフト検出する
手動でEC2インスタンスに付与し、ドリフト検出してみました。
結果、「public_dns」と「public_ip」が検出されました。想定通りです。
$ snyk iac describe --drift Scanned states (1) Scan duration: 7s Provider version used to scan: 4.28.0. Use --tf-provider-version to use another version. Snyk Scanning Infrastructure As Code Discrepancies... Info: Resources under IaC, but different to terraform states. Resolve: Reapply IaC resources or update into terraform. Changed resources: 2 State: Generated [ Changed Resources: 1 ] Resource Type: aws_ebs_volume ID: vol-056e51aa5a6148297 + timeouts: null => {} State: tfstate://terraform.tfstate [ Changed Resources: 1 ] Resource Type: aws_instance ID: i-0683a97d236667e6f ~ arn: arn:aws:ec2:ap-northeast-1:xxxx:instance/i-0683a97d236667e6f => arn:aws:ec2:ap-northeast-1::instance/i-0683a97d236667e6f ~ public_dns: ec2-54-65-55-184.ap-northeast-1.compute.amazonaws.com => ec2-52-69-152-84.ap-northeast-1.compute.amazonaws.com ~ public_ip: 54.65.55.184 => 52.69.152.84 - user_data_replace_on_change: false Test Summary Managed Resources: 3 Changed Resources: 2 IaC Coverage: 100% Info: To reach full coverage, remove resources or move it to Terraform. Tip: Run --help to find out about commands and flags. Scanned with aws provider version 4.28.0. Use --tf-provider-version to update.
SGのインバウンドルールを追加した後に、ドリフト検出する
インバウンドルールに443を追加しましたが、これは検出されませんでした。
$ snyk iac describe --drift Scanned states (1) Scan duration: 7s Provider version used to scan: 4.28.0. Use --tf-provider-version to use another version. Snyk Scanning Infrastructure As Code Discrepancies... Info: Resources under IaC, but different to terraform states. Resolve: Reapply IaC resources or update into terraform. Changed resources: 2 State: Generated [ Changed Resources: 1 ] Resource Type: aws_ebs_volume ID: vol-056e51aa5a6148297 + timeouts: null => {} State: tfstate://terraform.tfstate [ Changed Resources: 1 ] Resource Type: aws_instance ID: i-0683a97d236667e6f ~ arn: arn:aws:ec2:ap-northeast-1:xxxx:instance/i-0683a97d236667e6f => arn:aws:ec2:ap-northeast-1::instance/i-0683a97d236667e6f ~ public_dns: ec2-54-65-55-184.ap-northeast-1.compute.amazonaws.com => ec2-52-69-152-84.ap-northeast-1.compute.amazonaws.com ~ public_ip: 54.65.55.184 => 52.69.152.84 - user_data_replace_on_change: false Test Summary Managed Resources: 3 Changed Resources: 2 IaC Coverage: 100% Info: To reach full coverage, remove resources or move it to Terraform. Tip: Run --help to find out about commands and flags. Scanned with aws provider version 4.28.0. Use --tf-provider-version to update.
EC2インスタンスを削除して、ドリフト検出する
EC2インスタンスを削除し、SGは残したままでドリフト検出しました。
結果、Missing Resourceとaws_instanceは、Missing Resourcesとして検出されました。
残ったManaged ResourcesはSGのようです。
$ snyk iac describe --drift Scanned states (1) Scan duration: 8s Provider version used to scan: 4.28.0. Use --tf-provider-version to use another version. Snyk Scanning Infrastructure As Code Discrepancies... Info: Resources under IaC, but different to terraform states. Resolve: Reapply IaC resources or update into terraform. Missing resources: 2 State: Generated [ Missing Resources: 1 ] Resource Type: aws_ebs_volume ID: vol-056e51aa5a6148297 State: tfstate://terraform.tfstate [ Missing Resources: 1 ] Resource Type: aws_instance ID: i-0683a97d236667e6f Test Summary Managed Resources: 1 Missing Resources: 2 IaC Coverage: 33% Info: To reach full coverage, remove resources or move it to Terraform. Tip: Run --help to find out about commands and flags. Scanned with aws provider version 4.28.0. Use --tf-provider-version to update.
JSON形式で、ドリフト検出の結果を出力する
JSON形式で出力した場合、出管理下にあるリソース、管理下にないリソースが分かりやすいですね。
$ snyk iac describe --json --drift Scanned states (1) Scan duration: 7s Provider version used to scan: 4.28.0. Use --tf-provider-version to use another version. { "options": { "deep": true, "only_managed": true, "only_unmanaged": false }, "summary": { "total_resources": 3, "total_changed": 2, "total_unmanaged": 0, "total_missing": 0, "total_managed": 3, "total_iac_source_count": 1 }, "managed": [ { "id": "vol-02205209f17fcac8b", "type": "aws_ebs_volume" }, { "id": "i-01b5dbaa8fadcd935", "type": "aws_instance", "human_readable_attributes": { "Name": "mito-ec2" }, "source": { "source": "tfstate://terraform.tfstate", "namespace": "", "internal_name": "mito-ec2" } }, { "id": "sg-0354feb133037f2f0", "type": "aws_security_group", "source": { "source": "tfstate://terraform.tfstate", "namespace": "", "internal_name": "mito_sg" } } ], "unmanaged": null, "missing": null, "differences": [ { "res": { "id": "vol-02205209f17fcac8b", "type": "aws_ebs_volume" }, "changelog": [ { "type": "create", "path": [ "timeouts" ], "from": null, "to": {}, "computed": false } ] }, { "res": { "id": "i-01b5dbaa8fadcd935", "type": "aws_instance", "human_readable_attributes": { "Name": "mito-ec2" }, "source": { "source": "tfstate://terraform.tfstate", "namespace": "", "internal_name": "mito-ec2" } }, "changelog": [ { "type": "update", "path": [ "arn" ], "from": "arn:aws:ec2:ap-northeast-1:xxxx:instance/i-01b5dbaa8fadcd935", "to": "arn:aws:ec2:ap-northeast-1::instance/i-01b5dbaa8fadcd935", "computed": true }, { "type": "update", "path": [ "public_dns" ], "from": "ec2-35-77-229-240.ap-northeast-1.compute.amazonaws.com", "to": "ec2-54-65-228-246.ap-northeast-1.compute.amazonaws.com", "computed": true }, { "type": "update", "path": [ "public_ip" ], "from": "35.77.229.240", "to": "54.65.228.246", "computed": true }, { "type": "delete", "path": [ "user_data_replace_on_change" ], "from": false, "to": null, "computed": false } ] } ], "coverage": 100, "alerts": { "": [ { "message": "You have unmanaged security group rules that could be false positives, find out more at https://docs.driftctl.com/limitations" }, { "message": "You have diffs on computed fields, check the documentation for potential false positive drifts: https://docs.driftctl.com/limitations" } ] }, "provider_name": "aws", "provider_version": "4.28.0", "scan_duration": 7, "date": "2022-08-29T08:11:36.782188621Z" }
オプション「--all」による検出
全リソースが11sで検出されました。早いですね。
$ snyk iac describe --all Scanned states (1) Scan duration: 11s Provider version used to scan: 4.28.0. Use --tf-provider-version to use another version. Snyk Scanning Infrastructure As Code Discrepancies... Info: Resources under IaC, but different to terraform states. Resolve: Reapply IaC resources or update into terraform. Changed resources: 2 State: Generated [ Changed Resources: 1 ] Resource Type: aws_ebs_volume ID: vol-02205209f17fcac8b + timeouts: null => {} State: tfstate://terraform.tfstate [ Changed Resources: 1 ] Resource Type: aws_instance ID: i-01b5dbaa8fadcd935 ~ arn: arn:aws:ec2:ap-northeast-1:xxxx:instance/i-01b5dbaa8fadcd935 => arn:aws:ec2:ap-northeast-1::instance/i-01b5dbaa8fadcd935 ~ public_dns: ec2-35-77-229-240.ap-northeast-1.compute.amazonaws.com => ec2-54-65-228-246.ap-northeast-1.compute.amazonaws.com ~ public_ip: 35.77.229.240 => 54.65.228.246 - user_data_replace_on_change: false Unmanaged resources: 71 Service: Unidentified [ Unmanaged Resources: 8 ] Resource Type: aws_cloudformation_stack ID: xxxx Resource Type: aws_iam_group ID: xxxx Resource Type: aws_iam_group_policy ID: xxxx Resource Type: aws_network_acl_rule ID: xxxx Resource Type: aws_s3_bucket_public_access_block ID: xxxx Service: aws_ec2 [ Unmanaged Resources: 13 ] Resource Type: aws_ebs_snapshot ID: xxxx Resource Type: aws_ebs_volume ID: xxxx Resource Type: aws_eip ID: xxxx Resource Type: aws_eip_association ID: xxxx Resource Type: aws_instance ID: xxxx Resource Type: aws_key_pair ID: xxxx Service: aws_iam [ Unmanaged Resources: 26 ] Resource Type: aws_iam_access_key ID: xxxx Resource Type: aws_iam_policy ID: xxxx Resource Type: aws_iam_policy_attachment ID: xxxx Resource Type: aws_iam_role ID: AWSCloud9SSMAccessRole Resource Type: aws_iam_role_policy ID: xxxx Resource Type: aws_iam_user ID: xxxx Service: aws_route53 [ Unmanaged Resources: 1 ] Resource Type: aws_route53_zone ID: xxxxx Service: aws_s3 [ Unmanaged Resources: 1 ] Resource Type: aws_s3_bucket ID: cf-templates-xxxx-ap-northeast-1 Service: aws_vpc [ Unmanaged Resources: 22 ] Resource Type: aws_security_group ID: sg-xxxxx Resource Type: aws_security_group_rule ID: sgrule-xxxx Test Summary Managed Resources: 3 Changed Resources: 2 Unmanaged Resources: 71 IaC Coverage: 4% Info: To reach full coverage, remove resources or move it to Terraform. Tip: Run --help to find out about commands and flags. Scanned with aws p