Skip to main content

SnykでカスタムIaCルールを開発する

著者
Headshot of Teodora Sandu

Teodora Sandu

blog feature snyk iac magenta

2021年11月18日

0 分で読めます

クラウドネイティブ化が進む現在、インフラストラクチャ・アズ・コード(IaC)は、アプリケーションへの最初の入り口となることがよくあります。KubernetesやTerraformなどのテクノロジーがますます普及するなか、ほとんどのアプリ開発者は、キャリアのどこかで少なくとも一度はKubernetesまたはTerraformのリソースを更新することになるでしょう。

インフラストラクチャの更新や管理は、いくつかの構成ファイルを扱うだけで済む簡単な場合もあれば、複数のクラウドネイティブスタックを組み合わせた複雑なアーキテクチャを構築する難しい場合もあります。それでも変わらないのは、インフラストラクチャのセキュリティがアプリケーションのセキュリティに欠かせないということです。多くのクラウドプロバイダーやIaCスキャンツールには、標準またはコミュニティ提供の構成・セキュリティルールセットが備わっていますが、インフラストラクチャは多様で複雑なため、「すべてに通用する」アプローチでは対応しきれないことがよくあります。

この記事では、Snyk IaCのカスタムルールを使ってインフラストラクチャ環境を保護する方法を紹介します。Snyk IaCルールのSDK(snyk-iac-rules)を活用すれば、Snyk CLI向けのカスタムインフラストラクチャルールを作成、テストし、バンドルできるようになります。

Open Policy Agent(OPA)で柔軟性を最大限に高める

Snyk IaCは、オープンソースの汎用ポリシーエージェントであるOpen Policy Agent(OPA)と、そのポリシー定義言語Regoを使用してカスタムルールを定義します。フレームワークに依存しないエージェントであるOPAを使えば、インフラストラクチャ、アプリケーションの認可、Kubernetesのアドミッション制御など、クラウドネイティブスタック全体のポリシーを簡単に変更し、適用できます。

ルールはOPAのネイティブクエリ言語で記述されるため、Snyk以外でもエクスポートして再利用できます。つまり、ここでの取り組みは、OPAエコシステムのインテグレーション全体で活用できます。

この手順を進めるには、OPAに加えて、ルールのバンドルと配布に使用するWebAssembly(Wasm)とOCI artifactsの基本的な知識が必要です。

カスタムルールでセキュリティを強化する

カスタムルールを使えば、個々のユースケースに合わせて対応できます。セキュリティの専門家が脅威を想定して作成したルールセットと組み合わせることで、強力なツールになります。

カスタムルールの例として、セキュリティアーキテクトである私が、アプリケーション内のすべてのTerraform aws_iam_roleリソースに、owner、description、typeのタグを付けるという社内要件を定めているとします。

そのため、次のようなルールを実行したいと考えています。

  • 既存および今後作成されるすべてのIAMロールリソースに、owner、description、typeのタグが付いていることを確認する

  • タグの追加を忘れた場合に、アプリ開発者へ通知する。

また、この標準に従わないコード変更があった場合はCI/CDを失敗させ、本番環境に反映されないようにしたいと考えています。

それを実現する方法は何でしょうか。自分で作成、バンドル、公開したカスタムルールをSnyk CLIに設定し、選択した安全な場所に保存したうえで、CI/CD内で実行する方法です。

SnykでカスタムIaCルールを開発する

新しいSnyk IaCルールSDKを使えば、まさにそれができます。SDKをマシンにインストールし、カスタムルールのドキュメントを参考にすれば、新しいタグ付け標準をSnyk CLIですばやく適用できます。

例として、次のTerraformリソースに、owner、description、typeのタグを付けたいとします。

resource "aws_iam_role" "denied" {
  name = "denied"
  assume_role_policy = jsonencode({
      Version   = "2012-10-17"
      Statement = [
        {
          Action    = "sts:AssumeRole"
          Effect    = "Allow"
          Sid       = ""
          Principal = {
            Service = "ec2.amazonaws.com"
          }
        },
      ]
  })
  tags = {
    description = "a tag that describes something"
  }
}

カスタムルールのドキュメントにあるスタートガイドに従い、templateコマンドを実行して、ルールのひな形を生成します。

$ snyk-iac-rules template --rule CUSTOM-RULE-8

タグ付けの標準を中程度の重大度のルールにしたいため、ひな形を次のように変更し、タイトルとメッセージをカスタマイズします。

package rules

aws_iam_role_tags_missing(resource) {
    not resource.tags.owner
}

aws_iam_role_tags_missing(resource) {
    not resource.tags.description
}

aws_iam_role_tags_missing(resource) {
    not resource.tags.type
}

deny[msg] {
    resource := input.resource.aws_iam_role[name]
    aws_iam_role_tags_missing(resource)

    msg := {
        "publicId": "CUSTOM-RULE-8",
        "title": "IAM Role missing one of the required tags: owner, description or type",
        "severity": "medium",
        "msg": sprintf("input.resource.aws_iam_role[%s].tags", [name]),
        "issue": "",
        "impact": "",
        "remediation": "",
        "references": [],
    }
}

ルールをバンドルして公開する前に、ユニットテストを作成してルールの動作を検証します。また、サンプルのTerraformフィクスチャファイルを、生成された./rules/CUSTOM-RULE-8/fixtures/denied2.tfファイルに配置します。

package rules

import data.lib
import data.lib.testing

test_CUSTOM_RULE_8 {
        # array containing test cases where the rule is allowed
        allowed_test_cases := []

        # array containing cases where the rule is denied
        denied_test_cases := [{
            "want_msgs": ["input.resource.aws_iam_role[denied].tags"],
            "fixture": "denied2.tf",
        }]

        test_cases := array.concat(allowed_test_cases, denied_test_cases)
        testing.evaluate_test_cases("CUSTOM-RULE-8", "./rules/CUSTOM-RULE-8/fixtures", test_cases)
}

このルールをはじめ、その他のルールは公開GitHubリポジトリでご覧いただけます。

$ snyk-iac-rules test
PASS: 1/1

テストを実行して合格したことを確認したら、SDKでルールをバンドルします。さらに、--rulesフラグを使えば、Snyk CLIでローカルテストもできます。まず、今後のカスタムルールの実験をすべて行うtest-org組織で認証されていることを確認します。

$ snyk auth

次に、カスタムルールのバンドルをビルドして--rulesフラグに渡し、IaCの問題が検出されることを確認します。

$ snyk-iac-rules build .
Generated bundle: bundle.tar.gz

$ snyk iac test --rules=bundle.tar.gz ./fixtures/custom-rules/rules/CUSTOM-RULE-8/fixtures/denied2.tf

Testing ./fixtures/custom-rules/rules/CUSTOM-RULE-8/fixtures/denied2.tf...

Infrastructure as code issues:
  ✗ IAM Role missing one of the required tags: owner, description or type [Medium Severity] [CUSTOM-RULE-8]
    introduced by input > resource > aws_iam_role[denied] > tags

Organization:      test-org
Type:              Terraform
Target file:       ./fixtures/custom-rules/rules/CUSTOM-RULE-8/fixtures/denied2.tf
Project name:      fixtures
Open source:       no
Project path:      ./fixtures/custom-rules/rules/CUSTOM-RULE-8/fixtures/denied2.tf

Tested ./fixtures/custom-rules/rules/CUSTOM-RULE-8/fixtures/denied2.tf for known issues, found 1 issues

Snyk CLIがルールを解釈できることを確認したら、ルールをOCIレジストリ(今回はDockerHub)にプッシュし、カスタムルールの最初のバージョンとしてタグ付けします。こうしておけば、将来、互換性を損なう変更を加えた場合に、新しいタグを使ってルールを段階的に展開できます。

$ snyk-iac-rules push --r docker.io/snykgoof/oci-example:v1 bundle.tar.gz

最後に、公開Group IaC Settings APIを使ってSnykグループのIaC設定を構成し、部門内のすべてのチームに新しいカスタムルールの使用を徹底します。

curl --location --request PATCH 'https://api.snyk.io/v3/groups/<group_id>/settings/iac/?version=2021-11-03~beta' \
--header 'Content-Type: application/vnd.api+json' \
--header 'Authorization: token <API key from Snyk>' \
--data-raw '{
   "data": {
         "type": "iac_settings",
         "attributes": {
           "custom_rules": {
             "oci_registry_url": "https://registry-1.docker.io/snykgoof/oci-example",
             "oci_registry_tag": "v1",
             "is_enabled": true
           }
       }
   }
}'

これらすべての手順は、公開GitHubリポジトリでご覧いただけるGitHub Actionsワークフローを使って自動化しました。これで、グループ配下の組織で認証されたアプリ開発者やCI/CDパイプラインには、すべてこのカスタムルールが適用されます。Snyk CLIとSnyk IaC Rules SDKをGitHubと連携する方法については、ドキュメントをご覧ください。

会社の異なる部門に別々のカスタムルールを適用したい場合は、組織レベルでカスタムルールの設定を上書きすることで、その組織にだけ別のルールセットを適用できます。たとえば、引き続き--rulesフラグを使ってSnyk CLIでカスタムルールをテストできるよう、test-org組織ではカスタムルールの設定を無効にしています。これにより、カスタムルールをローカルで指定できます。

構成ファイルの検出が有効で、カスタムルールが無効になっているSnyk Infrastructure as Codeの設定

将来的に、Platformチームにより厳格なカスタムルールセットが必要になった場合は、別のOCI artifactに保存した別のカスタムルールバンドルを使うよう、その組織を設定できます。

Snyk IaCのカスタムルールを活用する

ここまで、セキュリティアーキテクトとしてSnyk IaCルールSDKを使い、部門向けに新たなセキュリティ標準を設定する方法を見てきました。次に、アプリ開発者が開発中にこの機能をどのように活用できるかを見てみましょう。

新しいIAMロールを設定するため、アプリケーションのTerraformインフラストラクチャにaws_iam_roleリソースを追加するとします。

resource "aws_iam_role" "new_role" {
  name               = "new_role"
  assume_role_policy = jsonencode({
    Version   = "2021-11-18"
    Statement = [
      {
        Action    = "sts:AssumeRole"
        Effect    = "Allow"
        Sid       = ""
        Principal = {
          Service = "ec2.amazonaws.com"
        }
      },
    ]
  })
}

ローカルでテストし、IAMロールが正しく設定されていることを確認しました。しかし、部門ではすべてのリソースに非常に厳格なタグ付けが求められていることを忘れていました。PRを作成しようとすると、プッシュ先のリポジトリではSnyk IaC GitHub Actionが実行されるように設定されており、チェックに失敗していることがわかります。

レビューが必要な状態のGitHubプルリクエスト。IaCのカスタムセキュリティチェック1件が失敗、5件が成功し、マージがブロックされている。

結果を確認すると、追加したファイルが原因でPRチェックに失敗していることがわかります。具体的には、リソースにowner、description、typeのタグが付いていません。

カスタムルールCUSTOM-RULE-8で必須のIAMロールタグの欠落を検出し、Snyk Infrastructure as Codeのスキャンが失敗したことを示すGitHub Actionsのログ

コードに戻って不足しているタグを追加します。変更をプッシュしてPRチェックを再実行すれば、新しいリソースを安心して本番環境に反映できます。

Snyk IaCでアプリケーションを保護する

Snyk Infrastructure as Code(Snyk IaC)は、開発者にセキュリティインテリジェンスと、Terraform、CloudFormation、Kubernetesの設定、ARMテンプレート向けのインライン修正を提供します。修正はコードに直接マージできるため、安全性を保ちながら開発を加速できます。

Snyk IaCは開発者が作業する環境に対応し、Terraform CloudやCI/CDツールに加え、ソースコード管理ツール(GitHub、GitLab、Bitbucket)やIDEなどの開発ツールと連携します。

Snyk IaCは、プラットフォーム上で今すぐ無料で利用を開始するか、最新のSnyk CLIをダウンロードしてご利用いただけます。

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

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