Skip to main content

クラウドリソースのカバレッジを高め、インフラストラクチャのドリフトを低減する

著者
Headshot of Stephane Jourdan

Stephane Jourdan

feature iac drift purple

2022年3月23日

0 分で読めます

廃止のお知らせ:管理対象リソースのドリフト検出

snyk iac describe --only-managed and snyk iac describe --driftを含む、管理対象リソースのドリフト検出は廃止されました。管理対象リソースのドリフト検出の提供終了日は2023年9月30日です。

開発者にとって、クラウド環境で実際に稼働しているものを最大限に可視化することは、安全性を保つうえで欠かせません。Infrastructure as Code(IaC)を使えば、クラウドインフラストラクチャを自動化し、クラウドへのデプロイを管理下に置いて、簡単に監査できます。しかし、インフラストラクチャのIaCカバレッジを100%にして維持するには、多くの課題があります。

クラウド環境で実際にデプロイされ稼働しているもののセキュリティが、私たちのセキュリティの上限です。多くの場合、私たちや他のチーム、認証済みサービスによる手作業が定期的に行われています。こうした変更はIaCや監査から見えず、設定ミスやセキュリティ上の懸念につながります。そこで重要になるのがドリフト管理です。まだIaCの管理下にないリソースや、何らかの理由で変更されたリソースをレポートで把握したいのです。

この記事では、Snyk IaCを活用して、IaC(Infrastructure as Code)の管理対象外のクラウドリソース(未管理リソース)や、想定された状態からドリフトしたリソース(管理対象リソース)を開発者が見つける方法をご紹介します。

環境をセットアップする

Snyk IaCでは、検出したリソースをTerraformリソースとして一覧表示できるため、検出対象となったクラウドサービスの部分を簡単に把握できます。たとえば、Amazon API Gateway v2のサービス1つは、少なくとも12個のTerraformリソースで構成されています。Snykが提供する検出情報をもとに、変更を元に戻すか、新しいリソースをインポートするか、あるいは新たな変更を削除するかをすばやく判断できます。

一緒に試すには、以下のTerraformファイルを使って、手順で使用する2つのAWSリソースを作成できます。ランダムなサフィックスが付いた「user1」という名前のIAMユーザー、アクセスキー、読み取り専用アクセス用のアタッチ済みポリシーが作成されます。

この記事の執筆時点では、Terraform v1.1.7とAWSプロバイダー v3.74.2を使用しました

以下のHCL設定を再利用します:

main.tf

resource "random_string" "prefix" {
  length  = 6
  upper   = false
  special = false
}

resource "aws_iam_user" "user1" {
  name = "user1-${random_string.prefix.result}"

  tags = {
    Name = "user1-${random_string.prefix.result}"
    manual = "true"
  }
}

resource "aws_iam_access_key" "user1" {
  user = aws_iam_user.user1.name
}

resource "aws_iam_user_policy_attachment" "user1" {
  user       = aws_iam_user.user1.name
  policy_arn = "arn:aws:iam::aws:policy/ReadOnlyAccess"
}

このTerraform設定を適用します:

$ terraform init
[...]
$ terraform apply
[...]

ディレクトリのルートにterraform.tfstateがあることを確認します:

$ ls -al terraform.tfstate
-rw-r--r--  1 sjourdan  staff  5049 Mar 16 18:31 terraform.tfstate

また、IAMユーザーがAWS上に正常に作成されていることを確認します。

何もない状態から始める

まず、Terraformの管理下にないクラウドリソースをすべて一覧表示します:

$ snyk iac describe --only-unmanaged

Terraformの管理下にないリソースが大量に表示されるでしょう。これは有益な情報ですが、今回の目的にはあまり役立ちません。Snyk IaCには、検出されたリソースをすべて.snykポリシーファイルに追加して、一括で無視する機能が組み込まれています。

既存の未管理リソースをすべて無視して、先ほど作成した2つのリソースだけがある管理された環境で、より正確に作業できるようにしましょう:

$ snyk iac describe --only-unmanaged --json  | snyk iac update-exclude-policy

もう一度スキャンし、検出されたドリフトが現在無視されていることを確認します(あとでインポートをスケジュールする時間は十分にあります)。

$ snyk iac describe --only-unmanaged

Scanned states (1)
Found 3 resource(s)
 - 100% coverage
Congrats! Your infrastructure is fully in sync.

これで、クリーンな状態から始める準備ができました。

IAMでドリフトを起こしてみましょう!

実際の状況を再現するために、次の3種類のドリフトを作成します:

  1. 既存のIAMユーザーを変更する(元に戻す対象)

  2. 新しいIAMポリシーを手動でアタッチする(削除する対象)

  3. 新しいIAMユーザーを作成する(改善する対象)

そのために、AWS IAMコンソールに移動します。

タグを追加して既存のIAMユーザーを変更する

  1. IAMユーザーのページで「user1」をクリックします

  2. Tagsタブをクリックします

  3. Edit Tagsボタンをクリックします

  4. 新しいキー(「environment」)と値(「production」)を追加します

  5. Saveをクリックします

既存のIAMユーザーに強力なポリシーをアタッチする

  1. IAMユーザーのページで「user1」をクリックします

  2. Permissionsタブをクリックします

  3. Add permissionsボタンをクリックします

  4. Attach existing policies directlyをクリックします

  5. Administrator Accessを選択します

  6. Next: Reviewをクリックします

  7. Add permissionsをクリックして確定します

別のIAMユーザーを手動で作成する

  1. IAMユーザーのページでAdd Usersボタンをクリックします

  2. User name:フィールドに「user2」と入力します

  3. Access keyを選択します

  4. Next: Permissionsボタンをクリックします

  5. アクセス許可やタグは設定しません

  6. Create userをクリックします(表示された認証情報は不要なので、破棄してかまいません)。

これで、Snyk IaCのドリフト検出を使って、こうした手動変更に対処する準備ができました。

管理対象・未管理のインフラストラクチャのドリフト

ここからは、Snyk IaCがこれらの変更をどのように検出するかを確認しましょう。まずはTerraformでまったく管理されていないリソースから始めます。

$ snyk iac describe --only-unmanaged

Scanned states (1)
Found resources not covered by IaC:
  aws_iam_access_key:
    - AKIASBXWQ3AYQETE6OFR
        User: user2
  aws_iam_policy_attachment:
    - user1-84i30k-arn:aws:iam::aws:policy/AdministratorAccess
  aws_iam_user:
    - user2
Found 6 resource(s)
 - 50% coverage
 - 3 resource(s) managed by Terraform
 - 3 resource(s) not managed by Terraform
 - 0 resource(s) found in a Terraform state but missing on the cloud provider

このスキャンでは、Terraformリソースの用語を使って次のように報告されました:

  • 手動で作成したIAMユーザー「user2」と、そのIAMアクセスキー

  • Terraform管理下のIAMユーザー「user1」に手動でアタッチしたIAMポリシー。

次に、さまざまなTerraformステートで見つかった、Terraform管理下のリソースの変更だけを確認します:

$ snyk iac describe –only-managed
Scanned states (1)
Found changed resources:
  From tfstate://terraform.tfstate
    - user1-84i30k (aws_iam_user.user1):
        + tags.environment: <nil> => "production"
Found 5 resource(s)
 - 100% coverage
 - 5 resource(s) managed by Terraform
     - 1/5 resource(s) out of sync with Terraform state
 - 0 resource(s) found in a Terraform state but missing on the cloud provider

このスキャンでは大きく異なる結果が報告され、所要時間も大幅に長くなりました(「未管理」スキャンモードの9秒に対して36秒)。

この出力から、HCL内で「user1」というリソース名で定義された「user1-84i30k」というIAMユーザーに、「environment」という名前のタグがあり、値が「production」に設定されていることがわかります。

対応計画

Snykのドリフト検出ツールにより、期待と実際の状態との予期しない差異が4つ見つかりました。この記事では、チームが次のように判断したとします:

  • IAMユーザー「user2」は本番環境で使用されているため、Terraformにインポートする。

  • セキュリティ上の理由から、IAMユーザー「user2」のアクセスキーをローテーションする。

  • 「user1」がAdministratorであってはならない。

  • 「user1」の新しいタグは要件上必要なので、Terraformにインポートする。

対象

リソースタイプ

名前

ドリフトタイプ

アクション

IAMユーザー

aws_iam_user

user2

未管理

インポート

IAMアクセスキー

aws_iam_access_key

AKIASBXWQ3AYQETE6OFR

未管理

ローテーション

アタッチ済みIAMポリシー

aws_iam_policy_attachment

arn:aws:iam::aws:policy/AdministratorAccess

未管理

削除

IAMユーザーのタグ

aws_iam_user

tags.environment

管理対象

インポート

デプロイパイプラインは修復手段ではない

Terraformのデプロイパイプラインはすでに整備されています。次にterraform applyが実行されたら、正常な状態に戻ると期待するかもしれません。

この場合、Terraformはどう動作するでしょうか?デプロイジョブは次のようになります:

$ terraform apply
Terraform will perform the following actions:

  # aws_iam_user.user1 will be updated in-place
  ~ resource "aws_iam_user" "user1" {
        id            = "user1-84i30k"
        name          = "user1-84i30k"
      ~ tags          = {
          - "environment" = "production" -> null
            # (1 unchanged element hidden)
        }
[...]

Plan: 0 to add, 1 to change, 0 to destroy.

Terraformは、手動で作成またはアタッチされたリソースを検出することを本来想定していません。変更されたリソースを単純に元の状態に戻します(この状況では望ましい動作ではありません)。

対象

リソースタイプ

名前

ドリフトタイプ

アクション

IAMユーザー

aws_iam_user

user2

未管理

なし

IAMアクセスキー

aws_iam_access_key

AKIASBXWQ3AYQETE6OFR

未管理

なし

アタッチ済みIAMポリシー

aws_iam_policy_attachment

arn:aws:iam::aws:policy/AdministratorAccess

未管理

なし

IAMユーザーのタグ

aws_iam_user

tags.environment

管理対象

元に戻す

どの場合も、期待する情報は得られません:

  • 手動で作成したIAMユーザーとアクセスキーは報告されない(役に立たない)

  • 管理対象ユーザーに手動でアタッチしたAdministratorポリシーは報告されない(役に立たない)

  • 管理対象ユーザーに手動で追加した重要なタグは元に戻される(有害)

この種の検出と作業には、別のタイプのツールが必要です。

カバレッジを改善する

未管理リソースのカバレッジは、現時点で50%です:

$ snyk iac describe --only-unmanaged

Scanned states (1)
Found resources not covered by IaC:
  aws_iam_access_key:
    - AKIASBXWQ3AYQETE6OFR
        User: user2
  aws_iam_policy_attachment:
    - user1-84i30k-arn:aws:iam::aws:policy/AdministratorAccess
  aws_iam_user:
    - user2
Found 6 resource(s)
 - 50% coverage
 - 3 resource(s) managed by Terraform
 - 3 resource(s) not managed by Terraform
 - 0 resource(s) found in a Terraform state but missing on the cloud provider

チームの計画に沿って改善していきましょう。

「user1」のIAMポリシーを削除する

まず、最も緊急で簡単な対応として、管理対象のIAMユーザー「user1」から「Administrator」ポリシーを削除します:

  • IAM > Users > 「user1」に移動します

  • Permissionsをクリックし、「AdministratorAccess」を削除します

$ snyk iac describe --only-unmanaged
Scanned states (1)
Found resources not covered by IaC:
  aws_iam_access_key:
    - AKIASBXWQ3AYQETE6OFR
        User: user2
  aws_iam_user:
    - user2
Found 5 resource(s)
 - 60% coverage
 - 3 resource(s) managed by Terraform
 - 2 resource(s) not managed by Terraform

これでAWSリソースのカバレッジは50%から60%に上がりました。

対象

リソースタイプ

名前

ドリフトタイプ

アクション

ステータス

IAMユーザー

aws_iam_user

user2

未管理

インポート

IAMアクセスキー

aws_iam_access_key

AKIASBXWQ3AYQETE6OFR

未管理

ローテーション

アタッチ済みIAMポリシー

aws_iam_policy_attachment

arn:aws:iam::aws:policy/AdministratorAccess

未管理

削除

*

IAMユーザーのタグ

aws_iam_user

tags.environment

管理対象

追加

続けましょう。

Terraformのデプロイパイプラインのブロックを解除する

現在、aws_iam_user.user1のタグに対する手動変更によってパイプラインがブロックされています。デプロイが行われると、タグはHCLの内容に戻されます。解決策は何でしょうか?Snyk IaCのドリフト出力を使ってTerraform設定を調整します。

次の情報が得られています:

Found changed resources:
  From tfstate://terraform.tfstate
    - user1-84i30k (aws_iam_user.user1):
        + tags.environment: <nil> => "production"

この出力から、次のことがわかります:

  • 名前が「user1」のaws_iam_userリソースを探しています

  • このリソースはterraform.tfstate内にあります(数十、数百ものステートがある場合に非常に便利です)

  • 新しいタグキーenvironmentの値は「production」です。

IAMユーザーのリソースにenvironment = "production"を追加して更新すると、次のようになります:

resource "aws_iam_user" "user1" {
 name = "user1-${random_string.prefix.result}"

 tags = {
   Name = "user1-${random_string.prefix.result}"
   environment = "production"
 }
}

これで、安全にTerraformのデプロイパイプラインのブロックを解除できます:

$ terraform apply
No changes. Your infrastructure matches the configuration.
Apply complete! Resources: 0 added, 0 changed, 0 destroyed.

これで、現時点で「管理対象」のドリフトを修正できました:

$ snyk iac describe --only-managed
Scanned states (1)
Found 3 resource(s)
 - 100% coverage
Congrats! Your infrastructure is fully in sync.

対象

リソースタイプ

名前

ドリフトタイプ

アクション

ステータス

IAMユーザー

aws_iam_user

user2

未管理

インポート

IAMアクセスキー

aws_iam_access_key

AKIASBXWQ3AYQETE6OFR

未管理

ローテーション

アタッチ済みIAMポリシー

aws_iam_policy_attachment

arn:aws:iam::aws:policy/AdministratorAccess

未管理

削除

*

IAMユーザーのタグ

aws_iam_user

tags.environment

管理対象

追加

*

IAMユーザーuser2をインポートしてキーをローテーションする

次に「user2」に対処します。以下を行います:

  • Terraformにインポートする

  • キーをローテーションする

まずIAMユーザーをTerraformにインポートします。簡単な方法を1つご紹介します。

まず、Snyk IaCから情報を収集します:

リソースタイプ

名前

aws_iam_user

user2

aws_iam_user resourceはどのようにインポートするのでしょうか?Terraform公式ドキュメントによると、IAMユーザーは名前を使ってインポートできます。例: $ terraform import aws_iam_user.lb loadbalancer。

必須の引数はnameだけです。そこで、この基本構造をHCLファイルに追加しましょう:

resource "aws_iam_user" "user2" {
 name = "user2" # required
}

次に、このユーザーをTerraformにインポートします:

$ terraform import aws_iam_user.user2 user2
aws_iam_user.user2: Importing from ID "user2"...
aws_iam_user.user2: Import prepared!
  Prepared aws_iam_user for import
aws_iam_user.user2: Refreshing state... [id=user2]

Import successful!

カバレッジはどのように変化したでしょうか?確認してみましょう:

$ snyk iac describe --only-unmanaged
Scanned states (1)
Found resources not covered by IaC:
  aws_iam_access_key:
    - AKIASBXWQ3AYQETE6OFR
        User: user2
Found 5 resource(s)
 - 80% coverage
 - 4 resource(s) managed by Terraform
 - 1 resource(s) not managed by Terraform

カバレッジは60%から80%に上がり、残るリソースは1つだけです。

対象

リソースタイプ

名前

ドリフトタイプ

アクション

ステータス

IAMユーザー

aws_iam_user

user2

未管理

インポート

*

IAMアクセスキー

aws_iam_access_key

AKIASBXWQ3AYQETE6OFR

未管理

ローテーション

アタッチ済みIAMポリシー

aws_iam_policy_attachment

arn:aws:iam::aws:policy/AdministratorAccess

未管理

削除

*

IAMユーザーのタグ

aws_iam_user

tags.environment

管理対象

追加

*

キーをローテーションする

次にこの作業に取りかかりましょう。キーをローテーションし、Terraformに追加します。新しいキーを作成するために、まずHCLに追加します(たとえば、関係するチームに渡せます)。最後にAWSから古いキーを削除します。

aws_iam_access_keyのTerraformドキュメントはとてもわかりやすいので、user2の名前を引数に取るリソースを1つ作成するだけです:

resource "aws_iam_access_key" "user2" {
 user = aws_iam_user.user2.name
}

先ほどデプロイパイプラインのブロックを解除したので、Terraformを使って安全に適用し、新しいキーを作成できます:

$ terraform apply 
[...]
Terraform will perform the following actions:

  # aws_iam_access_key.user2 will be created
  + resource "aws_iam_access_key" "user2" {
      + create_date          = (known after apply)
      + encrypted_secret     = (known after apply)
      + id                   = (known after apply)
      + key_fingerprint      = (known after apply)
      + secret               = (sensitive value)
      + ses_smtp_password_v4 = (sensitive value)
      + status               = "Active"
      + user                 = "user2"
    }

Plan: 1 to add, 0 to change, 0 to destroy.

aws_iam_access_key.user2: Creating...
aws_iam_access_key.user2: Creation complete after 1s [id=AKIASBXWQ3AY4KPUNIHZ]

Apply complete! Resources: 1 added, 0 changed, 0 destroyed.

削除する古いキーがまだ残っています。Snyk IaCの出力から、キー名がAKIASBXWQ3AYQETE6OFRであることがわかっています。

このキーを削除する最も簡単な方法は次のとおりです:

  • IAM > Users > user2 > Security Credentialsに移動します

  • Snyk IaCが報告したAKIASBXWQ3AYQETE6OFRという名前のキーを、無効化してから削除します。

現在のカバレッジを確認しましょう。

$ snyk iac describe --only-unmanaged
Scanned states (1)
Found 5 resource(s)
 - 100% coverage
Congrats! Your infrastructure is fully in sync.

おめでとうございます!Snyk IaCのドリフト検出のおかげで、すべてが管理下に戻りました。

対象

リソースタイプ

名前

ドリフトタイプ

アクション

ステータス

IAMユーザー

aws_iam_user

user2

未管理

インポート

*

IAMアクセスキー

aws_iam_access_key

AKIASBXWQ3AYQETE6OFR

未管理

ローテーション

*

アタッチ済みIAMポリシー

aws_iam_policy_attachment

arn:aws:iam::aws:policy/AdministratorAccess

未管理

削除

*

IAMユーザーのタグ

aws_iam_user

tags.environment

管理対象

追加

*

まとめ

この記事では、Snyk IaCのドリフト検出によって手動で作成されたAWSリソースを見つけ、Terraformの用語と適切な情報を使ってレポートすることで、開発者がTerraformのHCLコードにリソースをインポートできることを紹介しました。また、変更を自動的に元に戻すことが必ずしも望ましいとは限らず、デプロイパイプラインとあわせて軽量なドリフト検出・アラートシステムが必要であることも確認しました。

すべてのインフラストラクチャはコードで管理されるべきだと、私たちは確信しています。そうすることで、エンジニアは問題に対するセキュリティのフィードバックと可視性を、できるだけ早く得られます。

そのためSnyk IaCは、AWSアカウントで実際に稼働しているすべてのリソースをTerraformコードにすばやく再統合し、IaCのカバレッジを全体的に高め、セキュリティ上の問題を減らすのに役立ちます。Snyk IaCは、クラウドセキュリティチームとエンジニアリングチームの間のフィードバックループを閉じ、エンジニアが理解しやすい言葉で実行可能な修正方法をエンジニアに直接伝えることで、より迅速な修正を実現します。

ソースコードの段階からインフラを保護

Snykはワークフロー内のIaCセキュリティとコンプライアンスを自動化し、構成ドリフトや不足しているリソースを検出します。

続きを読む

feature insights context
Blog

自律型攻撃はすでに始まっている。防御もそのスピードに追いつかなければならない。

自律型攻撃者によって、防御に使える時間は短くなっています。継続的な検出、修復、検証、予防で、セキュリティチームが攻撃に歩調を合わせる方法をご紹介します。

Blog

Evo ADSのエージェント動作ガバナンスが一般提供開始:MCPの利用を管理

Evo ADSのエージェント動作ガバナンスが、MCPガバナンスから一般提供を開始しました。主要なAIコーディングエージェント全体で、MCPサーバーの利用を検出、承認、監視、記録、ブロックできます。

illustration hero ai
Blog

Agentic AppSecとは?

Agentic AppSecが、根拠に基づき、範囲を限定され、独立して検証されるAIエージェントを活用して、アプリケーションセキュリティの一連のプロセスを実行する方法をご紹介します。