1. Docs
  2. Pulumi IaC
  3. Using Pulumi
  4. Policy as code
  5. Snyk Container Scanning

Snyk Container Scanning

    Overview

    Snyk container scanning is a Pulumi policy as code template that allows you to uses the Snyk CLI to scan docker.Image resources for vulnerabilities.

    For more information on Pulumi’s Policy as Code solution, see Get started with Pulumi policy as code.

    Using Snyk Container Scanning

    In this guide, we’ll show you how to create a Policy Pack that enables Snyk container scanning.

    Prerequisites

    Running the policy pack

    This guide assumes the following directory structure:

    .
    ├── infra # Your Pulumi IaC program lives here.
    └── policy # Your policy pack will live here. Directory is assumed to be initially empty.
    

    Your Pulumi IaC program should have at least one docker.Image resource, similar to the following:

    import * as pulumi from "@pulumi/pulumi";
    import * as docker from "@pulumi/docker";
    
    const exampleImage = new docker.Image("exampleImage", {
        imageName: "docker.io/your-user-name/your-image-name",
        buildOnPreview: true,
        build: {
            dockerfile: "./app/Dockerfile",
            context: "./app",
        },
        skipPush: true,
    });
    
    import pulumi
    import pulumi_docker as docker
    
    example_image = docker.Image("exampleImage",
        image_name="docker.io/your-user-name/your-image-name",
        build_on_preview=True,
        build=docker.DockerBuildArgs(
            dockerfile="./app/Dockerfile",
            context="./app",
        ),
        skip_push=True)
    
    package main
    
    import (
     "github.com/pulumi/pulumi-docker/sdk/v4/go/docker"
     "github.com/pulumi/pulumi/sdk/v3/go/pulumi"
    )
    
    func main() {
        pulumi.Run(func(ctx *pulumi.Context) error {
            _, err := docker.NewImage(ctx, "exampleImage", &docker.ImageArgs{
                ImageName:      pulumi.String("docker.io/your-user-name/your-image-name"),
                BuildOnPreview: pulumi.Bool(true),
                Build: &docker.DockerBuildArgs{
                    Dockerfile: pulumi.String("./app/Dockerfile"),
                    Context:    pulumi.String("./app"),
                },
                SkipPush:       pulumi.Bool(true),
            })
    
            if err != nil {
                return err
            }
    
            return nil
        })
    }
    
    using System.Collections.Generic;
    using System.Linq;
    using Pulumi;
    using Docker = Pulumi.Docker;
    
    return await Deployment.RunAsync(() =>
    {
        var exampleImage = new Docker.Image("exampleImage", new()
        {
            ImageName = "docker.io/your-user-name/your-image-name",
            BuildOnPreview = true,
            Build = new Docker.Inputs.DockerBuildArgs
            {
                Dockerfile = "./app/Dockerfile",
                Context = "./app",
            },
            SkipPush = true,
        });
    
    });
    
    package generated_program;
    
    import com.pulumi.Context;
    import com.pulumi.Pulumi;
    import com.pulumi.core.Output;
    import com.pulumi.docker.Image;
    import com.pulumi.docker.ImageArgs;
    import com.pulumi.docker.inputs.DockerBuildArgs;
    import java.util.List;
    import java.util.ArrayList;
    import java.util.Map;
    import java.io.File;
    import java.nio.file.Files;
    import java.nio.file.Paths;
    
    public class App {
        public static void main(String[] args) {
            Pulumi.run(App::stack);
        }
    
        public static void stack(Context ctx) {
            var exampleImage = new Image("exampleImage", ImageArgs.builder()
                .imageName("docker.io/your-user-name/your-image-name")
                .buildOnPreview(true)
                .build(DockerBuildArgs.builder()
                    .dockerfile("./app/Dockerfile")
                    .context("./app")
                    .build())
                .skipPush(true)
                .build());
    
        }
    }
    
    resources:
      exampleImage:
        type: docker:Image
        properties:
          imageName: "docker.io/your-user-name/your-image-name"
          buildOnPreview: true # This must be set for the policy to work on `pulumi preview`
          build:
            dockerfile: "./app/Dockerfile"
            context: "./app"
          skipPush: true
    

    Start by initializing a new policy in the policy/ directory:

    cd policy
    pulumi policy new snyk-typescript
    

    You can then run the policy against your Pulumi program:

    cd ../infra
    pulumi preview --policy-pack ../infra
    
    Note that the Snyk container policy is a stack policy. This means that in order to have containers correctly scanned during a pulumi preview, your docker.Image resources must have the buildOnPreview set to true. If you run the policy pack during a pulumi update, the policy will execute after your containers have been built, and after they have been pushed if you have not explicitly specified the skipPush input to be true.

    Configuration options

    Configuration parameters

    The Snyk policy template supports the following configurable options:

    • dockerfileScanning (boolean): If set to true, Snyk will also scan your image’s Dockerfile for additional remediation suggestions. If this value is set, pulumiProgramAbsPath must also be set. Default value is false.
    • excludeBaseImageVulns (boolean): If set to true, Snyk will exclude vulnerabilities in the base image for your Dockerfile as defined in the FROM directive, and limit its results to layers added on top of the base image. Default value is false.
    • failOn (enum): If set to upgradable, the image will be in violation only for vulnerabilities that have a known upgrade path. If set to all, the image will be in violation for all vulnerabilities. Default value is all.
    • pulumiProgramAbsPath (string): The absolute path on disk to the Pulumi program to which this policy is being applied.Required (and only useful) if dockerfileScanning is set to true. Default value is an empty string.
    • severityThreshold (enum): The minimum level of vulnerabilities to be reported, and if any are found, to find the image in violation of the policy. Valid values are "low", "medium", "high", "critical". Default value is critical.

    Setting configuration values

    To set the configuration, you can do one of the following:

    1. Hard-code the values in index.ts within the templated policy. (These values will serve as defaults and may still be overridden on a per-run basis by either of the methods that follow.)

    2. Create a JSON file with the configuration values, e.g.:

      {
          "snyk-container-scan": {
              "enforcementLevel": "disabled",
              "dockerfileScanning": true,
              "pulumiProgramAbsPath": "/path/to/pulumi/iac/program"
          }
      }
      

      And then pass that value to the Pulumi CLI when running the policy, e.g.:

      pulumi preview --policy-pack /path/to/policy --policy-pack-config /path/to/policy-config.json
      

      (Relative paths in the above command will also work.)

    3. If using Pulumi Cloud’s server-side enforcement, policy pack configuration can be set centrally managed in the Pulumi Cloud UI. For details, see Configuring policy packs.

    Next Steps

    Once you’ve tested the Policy Pack, an organization administrator can publish the Policy Pack to Pulumi Cloud to be enforced across your organization. To learn more,see Enforcing a Policy Pack Across an Organization.

      PulumiUP 2024. Watch On Demand.