Skip to main content

Pulumiを使ってSnyk ContainerのKubernetesインテグレーションを自動化する

著者

Pas Apicella

feature snyk container purple

2022年2月9日

0 分で読めます

Infrastructure as Code(IaC)という言葉はよく耳にしますが、この文脈におけるコードは、プログラミング言語で書かれたコードとは少し異なります。IaCは通常、Terraform、CloudFormation、Kubernetes YAML、Azure Resource Managerテンプレートなどのツールを使ってインフラストラクチャを構成することを指し、インフラストラクチャをどのように作成するかを定義するものです。こうした構成では、最新のプログラミング言語がもたらす柔軟性や機能を活用できません。つまり、IaCもコードではありますが、通常はそういう種類のコードではありません。

このブログでは、JavaScript、Typescript、Python、Goなど複数の言語でコードを記述できるオープンソースツール、Pulumiを使って、Snyk ContainerのKubernetesインテグレーションの設定に必要なものをすべて作成する手順を紹介します。

Snyk Kubernetesインテグレーションの概要

SnykはKubernetesと連携し、稼働中のワークロードをインポートしてテストすることで、関連するイメージや構成に含まれる脆弱性を特定します。こうした脆弱性は、ワークロードのセキュリティを損なうおそれがあります。インポート後もSnykはワークロードを継続的に監視し、新しいイメージのデプロイやワークロード構成の変更に伴って発生するセキュリティ上の問題を検出します。

Pulumiとは?

Pulumiは、広く利用されているプログラミング言語を活用し、クラウドリソースのプロビジョニングと管理を簡素化するオープンソースのIaCツールです。

2017年の創業以来、PulumiはDevOpsチームのInfrastructure as Codeへの取り組み方を根本から変えてきました。ドメイン固有言語に頼る代わりに、実際のプログラミング言語を使ってクラウドネイティブなインフラストラクチャをプロビジョニング、廃止できます。

Pulumiがサポートするプログラミング言語:

  • Python

  • JavaScript

  • Go

  • TypeScript

  • .NET言語(C#、F#、VB)

PulumiでSnyk Kubernetesインテグレーションをインストールする方法

いよいよ実践です。Pulumiをセットアップして自動化を開始するまで、順を追って説明します。以下の手順で進めます。

  1. SnykアプリでKubernetesインテグレーションIDを設定する

  2. サンプルリポジトリをクローンする

  3. Google Cloudで認証する

  4. 新しいPulumiスタックを作成する

  5. 必要なPulumi構成変数を設定する

  6. pulumi upで一式をデプロイする

  7. Kubernetes構成を取得する

  8. セットアップ全体を破棄する

前提条件

  1. Kubernetesインテグレーションを利用するには、SnykのBusinessまたはEnterpriseアカウントが必要です。アカウントをお持ちでない場合は、Businessを14日間無料でお試しください。

  2. 今回はGoogle Cloudにデプロイするため、アカウントが必要です。アカウントをお持ちでない場合は、こちらから無料で登録してください。いずれの場合も、こちらの手順に従ってPulumiをGoogle Cloudアカウントに接続してください。

  3. この例では、gcloud CLIがパスに設定されていることを前提としています。これはGoogle Cloud SDKの一部としてインストールされます。

  4. Python 3、Pulumiアカウント、Pulumi CLIが必要です。

  5. Pulumiでは、環境のデフォルトとしてPython 3が設定されている必要があります。Python 2とPython 3を両方インストールしている場合、エイリアスの作成が必要になることがあります。次のコマンドを実行し、最新の3.xバージョンを使用していることを確認してください。

❯ python --version
Python 3.9.9

ステップ1:SnykアプリでKubernetesインテグレーションIDを設定する

Snykにログインし、Kubernetesインテグレーションを自動設定する組織を選択します。空の組織でも、プロジェクトがある既存の組織でも構いません。この例では、選択した組織でKubernetesインテグレーションがまだ設定されていないことを確認してください。

次に、インテグレーション > Kubernetes > 接続をクリックします。SnykのBusinessまたはEnterpriseアカウントをお持ちでない場合、この手順は実行できません。

後で必要になるため、インテグレーションIDを控えておきます。

Kubernetesインテグレーションが未接続と表示されたSnykのプロジェクト設定画面。[接続]ボタンが強調表示されています。

これで準備完了です。Pulumi Infrastructure as Codeを使って、Snyk Kubernetesインテグレーションのデモをセットアップできます。Pulumiでは次の処理を行います。

ステップ2:サンプルリポジトリをクローンする

以下の手順に沿って、次のデモ用GitHubリポジトリをクローンします。

$ git clone https://github.com/papicella/snyk-kubernetes-integration
Cloning into 'snyk-kubernetes-integration'...
remote: Enumerating objects: 18, done.
remote: Counting objects: 100% (18/18), done.
remote: Compressing objects: 100% (14/14), done.
remote: Total 18 (delta 8), reused 14 (delta 4), pack-reused 0
Receiving objects: 100% (18/18), 8.76 KiB | 4.38 MiB/s, done.
Resolving deltas: 100% (8/8), done.

リポジトリをクローンしたら、そのディレクトリにcdで移動し、次のコマンドを実行します…

ステップ3:Google Cloudで認証する

このデモをデプロイするには、ローカル認証を使ってGoogle Cloudで認証します。PulumiとGoogle Cloudの連携には他の方法もありますが、このデモではこれが最も簡単です。

$ gcloud auth login

ステップ4:新しいPulumiスタックを作成する

この例の独立したデプロイ先となる新しいスタックを作成します。例としてdevを使用します。

$ pulumi stack init dev

ステップ5:必要なPulumi構成変数を設定する

多くの場合、同じプロジェクト内のスタックごとに異なる値が必要になります。たとえば、Google Cloud Computeインスタンスのサイズを変えたり、開発用スタックと本番用スタックでKubernetesクラスターのサーバー数を変えたりできます。

スタックのキーと値のペアはプロジェクトのスタック設定ファイルに保存されます。このファイルは自動的にPulumi.<stack-name>.yamlという名前になります。通常、このファイルを意識する必要はありませんが、プロジェクトのソースコードとともにチェックインしてバージョン管理することもできます。

以下のように、次の構成変数をスタックに追加します。

$ pulumi config set gcp:project [your-gcp-project-here] # Eg: snyk-cx-se-demo
$ pulumi config set gcp:zone us-central1-c # any valid GCP zone here
$ pulumi config set password --secret [your-cluster-password-here] # password for the cluster
$ pulumi config set master_version 1.21.6-gke.1500 # any valid K8s master version on GKE

デフォルトでは、クラスターにはn1-standard-1タイプのノードが3つ作成されます。この設定は変更できます。たとえば、n1-standard-2タイプのノードを5つにする場合は、次のコマンドを実行します。

$ pulumi config set node_count 5
$ pulumi config set node_machine_type n1-standard-2

最後に、Snyk Kubernetesインテグレーションをクラスターに自動設定するために必要な設定を行います。KubernetesインテグレーションIDとSnyk組織IDが必要です。この例では、両者は同じです。

$ pulumi config set snyk_K8s_integration_id K8S_INTEGRATION_ID #same as ORG_ID at the moment
$ pulumi config set snyk_org_id ORG_ID # your Snyk ORG ID under settings

このように、スタックは便利な形で構成できます。プロビジョニング後に変更することも可能です。

完了すると、次の内容を含むPulumi.dev.yamlファイルが作成されます。

config:
gcp-K8s-integration-demo:master_version: 1.21.5-gke.1302
gcp-K8s-integration-demo:node_count: "3"
gcp-K8s-integration-demo:node_machine_type: n1-standard-2
gcp-K8s-integration-demo:password:
    secure: AAABsomesecret+EnF1p4w==
gcp-K8s-integration-demo:snyk_K8s_integration_id: yyyy1234
gcp-K8s-integration-demo:snyk_org_id: yyyy1234
gcp:project: snyk-cx-se-demo
gcp:zone: us-central1-c

ステップ6:pulumi upで一式をデプロイする

pulumi upコマンドで一式をデプロイすると、GKEクラスターやSnykコントローラーのHelmチャートなど、Snyk Kubernetesインテグレーションに必要なGoogle Cloudリソースがすべてプロビジョニングされます。続いて、Spring Bootアプリケーションを実行するKubernetesデプロイメントが作成されます。

$ pulumi up

プレビューが表示され、確認を求められた後、Snyk Kubernetesインテグレーションのデモに必要なリソースのプロビジョニングが始まります。

$ pulumi up
Previewing update (dev)

View Live: https://app.pulumi.com/papicella/gcp-K8s-integration-demo/dev/previews/1db6492c-ae23-4e87-abf0-41e09fb62177

    Type                                                              Name                          Plan
+   pulumi:pulumi:Stack                                               gcp-K8s-integration-demo-dev  create
+   ├─ kubernetes:helm.sh/v3:Chart                                    snyk-monitor                  create
+   │  ├─ kubernetes:core/v1:ServiceAccount                           snyk-monitor/snyk-monitor     create
+   │  ├─ kubernetes:networking.k8s.io/v1:NetworkPolicy               snyk-monitor/snyk-monitor     create
+   │  ├─ kubernetes:rbac.authorization.k8s.io/v1:ClusterRole         snyk-monitor                  create
+   │  ├─ kubernetes:rbac.authorization.k8s.io/v1:ClusterRoleBinding  snyk-monitor                  create
+   │  └─ kubernetes:apps/v1:Deployment                               snyk-monitor/snyk-monitor     create
+   ├─ gcp:container:Cluster                                          pulumi-gke-cluster            create
+   ├─ pulumi:providers:kubernetes                                    gke_k8s                       create
+   ├─ kubernetes:core/v1:Namespace                                   snyk-monitor                  create
+   ├─ kubernetes:core/v1:Namespace                                   apples                        create
+   ├─ kubernetes:core/v1:ConfigMap                                   snyk-monitor-custom-policies  create
+   ├─ kubernetes:core/v1:Service                                     springboot-employee-api       create
+   ├─ kubernetes:core/v1:Secret                                      snyk-monitor                  create
+   └─ kubernetes:apps/v1:Deployment                                  springboot-employee-api       create

Resources:
    + 15 to create

約5分後、クラスターの準備が整い、Snykコントローラーがインストールされ、サンプルワークロードのデプロイメントがSnyk組織に自動インポートされます。

Do you want to perform this update? yes
Updating (dev)

View Live: https://app.pulumi.com/papicella/gcp-K8s-integration-demo/dev/updates/1

    Type                                                              Name                          Status
+   pulumi:pulumi:Stack                                               gcp-K8s-integration-demo-dev  created
+   ├─ kubernetes:helm.sh/v3:Chart                                    snyk-monitor                  created
+   │  ├─ kubernetes:core/v1:ServiceAccount                           snyk-monitor/snyk-monitor     created
+   │  ├─ kubernetes:networking.k8s.io/v1:NetworkPolicy               snyk-monitor/snyk-monitor     created
+   │  ├─ kubernetes:rbac.authorization.k8s.io/v1:ClusterRole         snyk-monitor                  created
+   │  ├─ kubernetes:rbac.authorization.k8s.io/v1:ClusterRoleBinding  snyk-monitor                  created
+   │  └─ kubernetes:apps/v1:Deployment                               snyk-monitor/snyk-monitor     created
+   ├─ gcp:container:Cluster                                          pulumi-gke-cluster            created
+   ├─ pulumi:providers:kubernetes                                    gke_k8s                       created
+   ├─ kubernetes:core/v1:Namespace                                   snyk-monitor                  created
+   ├─ kubernetes:core/v1:Namespace                                   apples                        created
+   ├─ kubernetes:core/v1:Service                                     springboot-employee-api       created
+   ├─ kubernetes:core/v1:ConfigMap                                   snyk-monitor-custom-policies  created
+   ├─ kubernetes:core/v1:Secret                                      snyk-monitor                  created
+   └─ kubernetes:apps/v1:Deployment                                  springboot-employee-api       created

Outputs:
    kubeconfig: "[secret]"

Resources:
    + 15 created

Duration: 6m28s

以下のスクリーンショットで、すべてが想定どおりに作成されたことを確認できます。

Google Cloudに作成されたGKEクラスター:

pulumi-gke-cluster-008049bクラスターの詳細を表示するGoogle Kubernetes Engineコンソール。

自動設定されたSnyk Kubernetesインテグレーション:

Kubernetesインテグレーションが接続済みで、Kubernetesワークロードの追加オプションとインテグレーションの詳細が表示されたSnykの設定ページ。

apples名前空間から自動インポートされたサンプルワークロード:

セキュリティ問題の深刻度別の件数が表示された Kubernetes プロジェクトと、別のプロジェクトを追加するオプションが表示された Snyk Projects ダッシュボード
Kubernetesのデプロイに52件の脆弱性とセキュアな設定チェックの失敗があることを示すSnykのダッシュボード

構成を詳しく見る

Pythonファイル__main__.pyを詳しく見て、Snyk Kubernetesインテグレーションがどのようにインストール、設定されたのかを確認しましょう。

Snykコントローラーが使用するRegoポリシーファイルは現在、apples名前空間のワークロードのみをインポートし、CronJobまたはServiceタイプのものは除外するようにハードコードされています。この設定は__main__.pyで変更できます。また、Pythonコードに直接記述する代わりに、外部ファイルとして使用することもできます。

snyk_monitor_custom_policies_str = """package snyk
orgs := ["%s"]
default workload_events = false
workload_events {
input.metadata.namespace == "apples"
    input.kind != "CronJob"
    input.kind != "Service"
}""" % (SNYK_ORG_ID)

以下は、Helmチャートを使ってSnykコントローラーをインストールするPythonコードです。Helmチャートを取得するリポジトリを指定し、Snyk組織IDと先ほどのカスタムポリシーファイルを指定している点に注目してください。これらはすべて、GKEクラスターにSnykコントローラーをインストールし、Snykと連携するために必要です。

# Deploy the snyk controller using it's helm chart
snyk_monitor_chart = Chart(
    "snyk-monitor",
    ChartOpts(
        chart="snyk-monitor",
        version="1.79.0",
        namespace="snyk-monitor",
        fetch_opts=FetchOpts(
            repo="https://snyk.github.io/kubernetes-monitor",
        ),
        values={
          "clusterName": "K8s-integration-demo-cluster",
          "policyOrgs": "{%s}" % (SNYK_ORG_ID),
          "workloadPoliciesMap": "snyk-monitor-custom-policies"
        }
    ),
    opts=ResourceOptions(provider=k8s_provider)
)

Pythonコードでは、apples名前空間にSpring Bootのサンプルアプリケーションもデプロイしています。このアプリケーションは、SnykコントローラーによってSnykアプリに自動インポートされました。デプロイに使用したPythonコードは次のとおりです。

# deploy spring boot employee app

"""springboot employee api container, replicated 1 time."""
app_name = "springboot-employee-api"
app_labels = { "app": app_name }

springboot_employee_api = k8s.apps.v1.Deployment(
            app_name,
            metadata={
              "namespace": "apples",
            },
            spec=k8s.apps.v1.DeploymentSpecArgs(
                replicas=1,
                selector=k8s.meta.v1.LabelSelectorArgs(match_labels=app_labels),
                template=k8s.core.v1.PodTemplateSpecArgs(
                    metadata=k8s.meta.v1.ObjectMetaArgs(labels=app_labels),
                    spec=k8s.core.v1.PodSpecArgs(
                        containers=[
                            k8s.core.v1.ContainerArgs(
                                name=app_name,
                                image="pasapples/springbootemployee:cnb",
                                ports=[k8s.core.v1.ContainerPortArgs(
                                  container_port=8080
                                )]
                            )
                        ]
                    ),
                ),
            ),
            opts=ResourceOptions(provider=k8s_provider)
)

ステップ7:Kubernetes構成を取得する

ここで取得した構成は、~/.kube/configファイルに使用するか、ローカルに保存してKUBECONFIG環境変数に設定できます。もちろん、普段使っているGoogle Cloudのコマンドもすべて使用できます。

たとえば、次のようにします。

$ pulumi stack output kubeconfig --show-secrets > kubeconfig.yaml
$ KUBECONFIG=./kubeconfig.yaml kubectl get po -n apples
NAME                                                READY   STATUS    RESTARTS   AGE
springboot-employee-api-fyrj9hr2-66d8456f5f-hqqhx   1/1     Running   0          17m

いくつかのkubectlコマンドを使って、snyk-monitor名前空間にインストールされたSnykコントローラーと、Pulumiで管理されるようになったConfigMapおよびSecretを表示しています。

$ kubectl get all -n snyk-monitor
NAME                              READY   STATUS    RESTARTS   AGE
pod/snyk-monitor-db67744d-szl79   1/1     Running   0          8m52s

NAME                           READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/snyk-monitor   1/1     1            1           8m53s

NAME                                    DESIRED   CURRENT   READY   AGE
replicaset.apps/snyk-monitor-db67744d   1         1         1       8m53s

$ kubectl get secret -n snyk-monitor -l app.kubernetes.io/managed-by=pulumi
NAME           TYPE     DATA   AGE
snyk-monitor   Opaque   2      42m

$ kubectl get configmap -n snyk-monitor -l app.kubernetes.io/managed-by=pulumi
NAME                           DATA   AGE
snyk-monitor-custom-policies   1      42m

ステップ8:セットアップ全体を破棄する

作業が完了したら、すべてのリソースとスタックを破棄できます。

$ pulumi destroy
$ pulumi stack rm

まとめると、Pulumiを使ってSnyk Kubernetesインテグレーションをインストール、設定する方法を学びました。このインテグレーションを使うと、稼働中のワークロードをインポートしてテストし、関連するイメージや構成に含まれる脆弱性を特定できます。こうした脆弱性は、ワークロードのセキュリティを損なうおそれがあります。

その他のリソース

Pulumiを使い、PythonからSnyk Kubernetesインテグレーションを簡単に設定する方法を学びました。コンテナセキュリティへの取り組みを始める際に役立つリンクをご紹介します。

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

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