Skip to main content

Snykインテグレーションを使ったAWSの脆弱性スキャン

AWS vulnerability scanning

2021年2月10日

0 分で読めます

AWSのKubernetes関連ツール群をお使いなら、Amazon Elastic Container Registry(ECR)とAmazon Elastic Kubernetes Service(EKS)のインテグレーションを通じて、Snykでワークフローに直接スキャンを組み込めます。さっそく始めましょう!

この記事では、Snykのテスト用アプリケーションを使ってアプリケーションをビルド、デプロイします。コードはこちらから入手できます。また、次の依存ツールをインストールしておく必要があります。

さっそく始めましょう

準備が整ったところで、始めましょう!

まず、Snykがリポジトリにアクセスできるよう、ECRを設定します。そのために、AWS Identity and Access Managementでポリシーとロールを割り当てます。これにより、Snykのバックエンドに適切な権限を付与し、ECRリポジトリ内のイメージの一覧表示や取得などを行えるようにします。

インテグレーションの設定手順はSnykのドキュメントにすべて記載されていますが、必要な設定情報はSnykのUIから直接確認できます。Settings/Integrations/ECR/Edit Settingsに移動し、まずUIに表示されるJSONを使ってポリシーを設定します。

{
"Version": "2012-10-17",
"Statement": [
 {
  "Sid": "SnykAllowPull",
  "Effect": "Allow",
  "Action": [
   "ecr:GetLifecyclePolicyPreview",
   "ecr:GetDownloadUrlForLayer",
   "ecr:BatchGetImage",
   "ecr:DescribeImages",
   "ecr:GetAuthorizationToken",
   "ecr:DescribeRepositories",
   "ecr:ListTagsForResource",
   "ecr:ListImages",
   "ecr:BatchCheckLayerAvailability",
   "ecr:GetRepositoryPolicy",
   "ecr:GetLifecyclePolicy"
  ],
  "Resource": "*"
 }
]
}

- oriこの設定により、JSONのActionセクションで定義された権限が、ECRアカウント内で指定したすべてのリポジトリとイメージに対してSnykに付与されます。これは、リポジトリとイメージの一覧表示、およびリポジトリからのイメージ取得に必要な最小限の権限です。手順に従って、このJSONをAWSのIAMポリシー設定に追加してください。

次に、ロールを追加し、手順に記載されているポリシーをそのロールに割り当てます。

ポリシーを実装するためのAWS IAMロールの作成手順。EC2の選択、ECR読み取り専用ポリシーの選択、SnykServiceRoleという名前の設定を含む

また、ロールを利用できるSnyk組織IDを指定して、ロールの適用範囲を設定する必要があります。新しく作成したロールの信頼関係を、ドキュメントに記載されたJSONで編集します。sts:ExternalIdの文字列にはSnyk組織IDを指定します。このJSONスニペットは、指定されたExternalIdがSnyk組織IDと一致する場合に、AWSプリンシパルがロールを引き受けられるようにするものです。

{
"Version": "2012-10-17",
"Statement": [
 {
  "Effect": "Allow",
  "Principal": {
   "AWS": "arn:aws:iam::198361731867:user/ecr-integration-user"
  },
  "Action": "sts:AssumeRole",
  "Condition": {
   "StringEquals": {
    "sts:ExternalId": "11111111-1111-1111-1111-111111111111"
   }
  }
 }
]
}

手順に記載されているように、このポリシーに複数のSnyk組織を追加する場合は、角括弧で囲んだJSON配列として追加します。

"sts:ExternalId": [
"11111111-1111-1111-1111-111111111111",
"22222222-2222-2222-2222-222222222222",
]

Snyk組織IDは、Settings > Generalに移動すると確認できます。

組織名、APIキー、組織IDの各フィールドが表示された、[一般]タブの設定ページ。

最後に、SnykのUIでこのロールを使ってECRに接続するよう設定します。Settings/Integrations/ECR/Edit Settingsに戻り、ECRを設定したリージョンと、先ほど作成したロールを入力します。

SnykをAmazon ECRアカウントに接続するためのアカウント認証情報フォーム。AWSリージョン、ロールARN、変更を保存の各項目が表示されています

これでECRインテグレーションの設定は完了です。次に、動作を確認しましょう。

まず、AWS CLIを使ってECRにリポジトリを作成します。

% aws ecr create-repository --repository-name goof
{
    "repository": {
        "repositoryArn": "arn:aws:ecr:us-west-2:478468688580:repository/goof",
        "registryId": "478468688580",
        "repositoryName": "goof",
        "repositoryUri": "478468688580.dkr.ecr.us-west-2.amazonaws.com/goof",
        "createdAt": "2021-02-03T13:40:59+00:00",
        "imageTagMutability": "MUTABLE",
        "imageScanningConfiguration": {
            "scanOnPush": false
        },
        "encryptionConfiguration": {
            "encryptionType": "AES256"
        }
    }
}

ECRにリポジトリができたので、そこにプッシュできるようDockerを設定しましょう。

% aws ecr get-login-password --region us-west-2 | docker login --username AWS --password-stdin 478468688580.dkr.ecr.us-west-2.amazonaws.com

このコマンドはログインパスワードを出力し、それをDocker CLIに渡してAWS ECRレジストリに対して認証します。ECRを有効にしたAWSリージョンを正しく指定してください。

次に、テスト用アプリケーションを確認します。これは多くの脆弱性を含むシンプルなNode.jsアプリケーションで、DockerでのビルドとKubernetesへのデプロイに必要な設定も含まれています。

% git clone https://github.com/mattj-io/goof.git goof
% cd goof

まず、Dockerを使ってアプリケーションをビルドします。

% docker build -t goof .

イメージのビルドが完了すると、ローカルのDockerリポジトリに表示されます。

% docker images
REPOSITORY                                TAG      IMAGE ID       CREATED      SIZE
goof                                      latest    7934ddc2fec9   2 days ago   1.04GB

上流のECRリポジトリにプッシュする前に、タグを付けます。リポジトリ名は、先ほどECRで設定したものに置き換えてください。

% docker tag goof:latest 478468688580.dkr.ecr.us-west-2.amazonaws.com/goof:latest
% docker images
REPOSITORY                                          TAG       IMAGE ID       CREATED      SIZE
478468688580.dkr.ecr.us-west-2.amazonaws.com/goof   latest    7934ddc2fec9   2 days ago   1.04GB
goof                                      latest    7934ddc2fec9   2 days ago   1.04GB   

これでECRにプッシュできます。

% docker push 478468688580.dkr.ecr.us-west-2.amazonaws.com/goof:latest 

プッシュが完了したら、ECRリポジトリでプッシュしたイメージを確認できます。

% aws ecr list-images --repository-name goof
{
    "imageIds": [
        {
            "imageDigest": "sha256:ca6c19e25b4d7917769ee535f0b073e04e8ddc32ead83493c03abc65e82e5e6c",
            "imageTag": "latest"
        },
        {
            "imageDigest": "sha256:cd100d7c505ced1f5c4f4eb6fbd7ac83a623f9bb483db1e828fb4cd3b3c01bd9"
        }
    ]
}

イメージがECRに格納されたら、Snykでスキャンするよう設定できます。SnykのUIでAdd Projectを選択し、ECRアイコンに移動します。

GitHub、Docker Hub、ECR、Kubernetes、CLI、その他のインテグレーションオプションを表示するSnykのプロジェクト設定メニュー

ECRの設定が正しければ、ECRで利用可能なすべてのリポジトリと、それぞれに含まれるイメージが表示されます。

aws-ecr、goof、latestの各リポジトリのチェックボックスとイメージ名フィールドが表示された、Snykのリポジトリ選択画面

先ほど作成したgoofリポジトリが表示され、その中にイメージタグが1つあります。イメージを選択し、Add selected repositoriesボタンをクリックします。SnykがECRからリポジトリをインポートし、スキャンとモニタリングを開始します。

インポートが完了すると、SnykのProjectsページに表示されます。

goofプロジェクトと最新のpackage.jsonファイルを表示したリポジトリダッシュボード。ステータスバッジと直近のテスト日時が表示されています

Snykはイメージ自体に加えて、イメージ内にデプロイされたNodeアプリケーションが使用するpackage.jsonも検出し、それぞれのプロジェクトを作成しています。

イメージ自体は古く脆弱なベースイメージを使用しています。Snykは多数の脆弱性を検出し、脆弱性の総数を減らせるベースイメージを推奨します。

Goofの最新Dockerベースイメージへのアップグレード推奨事項を示すAWSの脆弱性スキャン結果。脆弱性の件数と深刻度が表示されています。

package.jsonには、アプリケーションに含まれるNodeパッケージが定義されています。package.jsonファイルで指定されている直接依存パッケージと、依存関係を通じて含まれる間接依存パッケージの両方が対象です。Snykはこれらすべてのパッケージの依存関係ツリーを作成し、脆弱性データベースを照会して、使用されている特定のバージョンに存在する脆弱性を検出します。このアプリケーションは脆弱なバージョンを使うよう設計されているため、多数の脆弱性が表示されます。

Goofysパッケージの脆弱性レポート。アーカイブ展開に伴う重大度の高い任意ファイル書き込みの問題と、修正方法の詳細を表示

個々の脆弱性に関する情報や、修正のためにアップグレードすべきパッケージについてのアドバイスも確認できます。SnykのUIで提供される情報をぜひ詳しくご覧ください。

EKSとのSnykインテグレーションを設定する

次に、Elastic Kubernetes ServiceとのSnykインテグレーションを設定します。Kubernetesインテグレーションは有料プランで提供されるため、設定にはSnykのいずれかのスタンダードプランの無料トライアルが必要です。

そのために、EKSを使ってKubernetesクラスターを作成しましょう。方法はいくつかありますが、最も簡単な方法の1つはeksctlツールを使うことです。

まずAWS CLIを使って、必要に応じてクラスターのノードにSSH接続するためのキーペアを作成します。

% aws ec2 create-key-pair --key-name demo --query "KeyMaterial" --output text > demo.pem

次にeksctlを使って、us-west-2リージョンにmattjarvis-skoというクラスターを作成します。Linuxノードのマネージドノードグループを使用し、キーペアを追加します。

% eksctl create cluster --name mattjarvis-sko --region us-west-2 --with-oidc --ssh-access --ssh-public-key SKO_demo --managed

このコマンドの完了には時間がかかりますが、完了するとEKSクラスターが利用可能になり、kubectlもクラスターと通信できるように設定されます。

% kubectl get nodes
NAME                                           STATUS   ROLES    AGE    VERSION
ip-192-168-24-115.us-west-2.compute.internal   Ready    <none>   2d5h   v1.18.9-eks-d1db3c
ip-192-168-84-146.us-west-2.compute.internal   Ready    <none>   2d5h   v1.18.9-eks-d1db3c

EKSクラスターが稼働したら、アプリケーションをデプロイするためのKubernetes設定を確認しましょう。goofアプリケーションのGitチェックアウトにはmanifestsディレクトリがあり、2つのKubernetes YAMLファイルが含まれています。

% ls manifests
goof-deployment.yaml goof-service.yaml

goof-deployment.yamlでは、goofアプリケーションと、依存関係として必要なmongodbポッドを定義しています。imageセクションは、先ほど設定したECRリポジトリを使うように変更してください。

% cat manifests/goof-deployment.yaml 
apiVersion: apps/v1
kind: Deployment
metadata:
  name: goof
spec:
  replicas: 1
  selector:
    matchLabels:
      app: goof
      tier: frontend
  template:
    metadata:
      labels:
        app: goof
        tier: frontend
    spec:
      containers:
        - name: goof
          image: 478468688580.dkr.ecr.us-west-2.amazonaws.com/goof
          resources:
            requests:
              cpu: 100m
              memory: 100Mi
          ports:
            - containerPort: 3001
            - containerPort: 9229
          env:
            - name: DOCKER
              value: "1"
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: goof-mongo
spec:
  replicas: 1
  selector:
    matchLabels:
      app: goof
      tier: backend
  template:
    metadata:
      labels:
        app: goof
        tier: backend
    spec:
      containers:
        - name: goof-mongo
          image: mongo
          ports:
            - containerPort: 27017

goof-service.yamlでは、mongodbサービスを定義し、ポート27017でmongodbポッドに接続できるようにします。これにより、goofアプリケーションがデータベースに接続します。また、実行中のアプリケーションへの外部接続を可能にする、外部向けのLoadBalancerサービスも定義しています。LoadBalancerの実装はクラスターをデプロイするプラットフォームによって異なります。AWSではElastic Load Balancerがプロビジョニングされ、外部ポート80からgoofポッドのポート3001(Node.jsアプリケーションが動作するポート)に接続します。

% cat manifests/goof-service.yaml   
apiVersion: v1
kind: Service
metadata:
  name: goof
spec:
  type: LoadBalancer
  ports:
  - protocol: TCP
    port: 80
    targetPort: 3001
    name: "http"
  - protocol: TCP
    port: 9229
    targetPort: 9229
    name: "debug"
  selector:
    app: goof
    tier: frontend
---
apiVersion: v1
kind: Service
metadata:
  name: goof-mongo
spec:
  ports:
  - protocol: TCP
    port: 27017
    targetPort: 27017
    name: "mongo"
  selector:
    app: goof
    tier: backend

それでは、アプリケーションをクラスターにデプロイしましょう。

FIXME TO HERE

% kubectl create -f manifests/goof-deployment.yaml
% kubectl create -f manifests/goof-service.yaml

% kubectl get pods
NAME                         READY   STATUS    RESTARTS   AGE
goof-5589f855f8-hzvjw        1/1     Running   0          2d13h
goof-mongo-775d5b7d8-w4658   1/1     Running   0          2d13h

% kubectl get services
NAME         TYPE           CLUSTER-IP      EXTERNAL-IP                                                               PORT(S)                       AGE
goof         LoadBalancer   10.100.94.189   adae6cf9abdb84b63919cc27c2ecafcb-1847540121.us-west-2.elb.amazonaws.com   80:32621/TCP,9229:31301/TCP   2d13h
goof-mongo   ClusterIP      10.100.97.98    <none>                                                                    27017/TCP                     2d13h
kubernetes   ClusterIP      10.100.0.1      <none>          

EXTERNAL-IPフィールドのURLは、LoadBalancerサービスの一部としてプロビジョニングされたELBから提供されます。このURLを使って、実行中のアプリケーションを表示できます。ブラウザーでアクセスすると、goofアプリケーションが動作していることを確認できます。

「Goof TODO」という見出しと、空のテキスト入力欄が表示されたシンプルなTODOアプリのインターフェース。

これでアプリケーションはEKSクラスターにデプロイされ、実行されています。最後に、SnykとEKSクラスターを連携させ、本番環境で稼働するワークロードをスキャンできるようにします。SnykのKubernetesインテグレーションは、Kubernetesの単一ポッドで動作するオペレーターで構成されます。Kubernetes APIに問い合わせて、クラスター内のコンテナイメージをスキャンし、Snykのバックエンドと通信します。

CloudFormationでEKSクラスターをデプロイする場合は、SnykインテグレーションをデプロイするためのAWSクイックスタートを利用できます。今回はデモでeksctlを使うため、手動でインストールする手順を見ていきましょう。

最初に、Snyk Kubernetes MonitorをデプロイするHelmチャートを含むHelmリポジトリを追加します。

helm repo add snyk-charts https://snyk.github.io/kubernetes-monitor/

次に、Snyk Monitor用の独立した名前空間を作成します。Kubernetesでは、アプリケーションごとに名前空間を分けるのが一般的なベストプラクティスです。権限をより細かく制御できるためです。

kubectl create namespace snyk-monitor

次に、SnykのintegrationIDを含むシークレットをKubernetesに作成します。これは、Snyk Monitorのプロセスが上流のSnyk APIと通信し、クラスター内で稼働するポッドの情報をSnykに送るために使われます。イメージの取得時にログインが必要なプライベートレジストリを使う場合は、認証情報もdockercfg.jsonセクションに渡す必要があります。詳しくはSnyk Monitorのドキュメントをご覧ください。

kubectl create secret generic snyk-monitor -n snyk-monitor --from-literal=dockercfg.json={} --from-literal=integrationId=11111111-1111-1111-1111-111111111111

シークレットを作成したら、Helmを使ってsnyk-monitor名前空間にSnyk Monitorをインストールします。

helm upgrade --install snyk-monitor snyk-charts/snyk-monitor --namespace snyk-monitor --set clusterName="Production"

Helmチャートの処理が完了すると、クラスターのsnyk-monitor名前空間でsnyk-monitorポッドが実行されていることを確認できます。

% kubectl get pods -n snyk-monitor
NAME                            READY   STATUS    RESTARTS   AGE
snyk-monitor-589cff67c7-kcj8j   1/1     Running   0          2d22h

ログを表示して、snyk-monitorからSnykにデータが送信されていることも確認できます。

% kubectl logs snyk-monitor-589cff67c7-kcj8j
----snipped for brevity-----
{"name":"kubernetes-monitor","hostname":"snyk-monitor-589cff67c7-kcj8j","pid":6,"level":30,"workloadLocator":{"userLocator":"eb30b15b-a0a5-47a4-ab75-7e50b853d6a9","cluster":"Production","namespace":"default","type":"Deployment","name":"goof"},"attempt":1,"msg":"workload metadata sent upstream successfully","time":"2021-02-04T10:43:42.789Z","v":0}
{"name":"kubernetes-monitor","hostname":"snyk-monitor-589cff67c7-kcj8j","pid":6,"level":30,"workloadLocator":{"userLocator":"eb30b15b-a0a5-47a4-ab75-7e50b853d6a9","cluster":"Production","namespace":"default","type":"Deployment","name":"goof-mongo"},"attempt":1,"msg":"workload metadata sent upstream successfully","time":"2021-02-04T10:43:42.821Z","v":0}

MonitorからSnykにデータが送信されるまで、ワークロードがSnykのUIに表示されるまで少し時間がかかることがあります。1分ほど経つと、Add Project/Kubernetesに移動して、クラスター内で稼働しているワークロードを確認できます。

GitHub、Docker Hub、ECR、Kubernetes、CLI、公開GitHubリポジトリ、その他のオプションを表示するプロジェクト作成メニュー

稼働中のワークロードが表示されます。追加するには、チェックボックスを選択してSnykにインポート、テストさせるだけです。

Production環境、defaultおよびsynke-monitor名前空間、デプロイオプションを表示した、Kubernetesワークロードの選択画面。

プロジェクトをインポートしたら、Projectsページに移動して、インポートしたプロジェクトの詳細を確認できます。まず注目したいのは、Snykがワークロードの実行時設定を検出し、その設定にセキュリティ上の問題がないかチェックしていることです。ここでは、root権限で実行されていることやCPU制限が設定されていないことなど、複数のセキュリティテストに失敗しています。

default/deployment.apps/goof の Kubernetes デプロイメントセキュリティレポート。脆弱性、依存関係、メタデータ、安全な設定のチェック項目を表示。

ワークロード自体を確認すると、Snykがベースイメージとそのイメージに含まれるすべての脆弱性を検出し、脆弱性への露出が少ない代替ベースイメージを推奨していることが分かります。

コンテナイメージの脆弱性スキャン結果とアップグレードの推奨事項を表示したAWS ECRイメージの詳細ページ

まとめ

このデモでは、ソフトウェア開発ライフサイクル全体にセキュリティテストを組み込み始める方法を紹介しました。これは、クラウドネイティブ環境でワークロードとインフラストラクチャのセキュリティを維持するための重要な戦略です。

Snykはさまざまな統合開発環境、ソースコード管理ツール、CI/CDシステムとも連携できるため、デプロイパイプライン全体をカバーできます。

AmazonのコンテナおよびKubernetesサービスをお使いの場合、ECRとEKSの両方にSnykを簡単に連携できます。CloudFormationテンプレートを使ってすべてをデプロイするためのAWSクイックスタートも用意されています。Snykの無料アカウントに登録して、ぜひお試しください!

Capture the Flagを始めよう

オンデマンドのバーチャル入門ワークショップを見て、Capture the Flagの課題の解き方を学びましょう。

続きを読む

blog feature snyk container custom base recommendations
Blog

Evo Agentic AppSecのご紹介:AI開発のスピードに対応するセキュリティ

AI駆動型開発のスピードに、従来のセキュリティワークフローは追いついていません。SnykのAgentic AppSecは、セキュリティエージェントが脆弱性を継続的に検出、修正、検証し、人が基準を定められるようにします。

feature insights context
Blog

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

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

Blog

AIコーディングエージェントが不適切なアクセス制御を繰り返し実装する理由

AIコーディングエージェントは、コンパイルが通りレビューも通過する一方で、あるテナントのデータを別のテナントに公開してしまう認可ロジックを生成することがあります。不適切なアクセス制御が検出しにくい理由と、その防止策をご紹介します。