-
Notifications
You must be signed in to change notification settings - Fork 878
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add Snyk policy example #1624
Draft
jkodroff
wants to merge
1
commit into
master
Choose a base branch
from
snyk-policy
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Draft
Add Snyk policy example #1624
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
# snyn-container-scan-policy | ||
|
||
Scan Pulumi-managed Docker containers with Snyk and Pulumi Policy as Code: | ||
|
||
- The code in the `infra` directory creates two `docker.Image` resources: | ||
1. An image sourced from the `alpine` image, which does not have critical vulnerabilities. | ||
1. An image sourced from the `debian` image, which has critical vulnerabilities. | ||
- The code in the `policy` directory contains a Pulumi Policy Pack which calls the Snyk CLI. If the Snyk CLI fails (e.g. because it detects vulnerabilities), the resource will be considered in violation and the `pulumi preview` (or `pulumi up`) operation will fail. | ||
|
||
To run the demo: | ||
|
||
```bash | ||
cd infra | ||
pulumi preview --policy-pack ../policy | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We should probably mention here:
|
||
``` | ||
|
||
## Configuration Options | ||
|
||
The `snyk-container-scan` policy has the following configurable options. These can be set by altering values in `policy-config.json` and calling Pulumi CLI with the `--policy-config` option, e.g.: | ||
|
||
```bash | ||
cd infra | ||
pulumi preview --policy-pack ../policy --policy-pack-config policy-config.json | ||
Comment on lines
+22
to
+23
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. When I run this, I get the following error. Expected?
|
||
``` | ||
|
||
- `dockerfileScanning` (boolean): If set to `true`, Snyk will scan the Dockerfile of each image in the stack to scan for vulnerabilities in the upstream image. If set to `true`, `pulumiProgramAbsPath` must also be set to the absolute path on disk of the Pulumi program that contains the images so that the Snyk CLI can locate the Dockerfile. | ||
- `excludeBaseImageVulns` (boolean): If true, do not show vulnerabilities introduced only by the base image. Defaults to `false`. | ||
- `failOn`: Valid values: `all`, `upgradable`. Defaults to `all`. | ||
- `pulumiProgramAbsPath` (string, optional): The absolute path on disk to the Pulumi (IaC) program. Used by Snyk to scan Dockerfiles for vulnerabilities. Only used (and required) if `dockerfileScanning` is set to `true`. | ||
- `severityThreshold`: The minimum severity of found issues to report. If any issues are found at or above the minimum severity, the stack will contain violations. Valid values: `low`, `medium`, `high`, `critical`. Defaults to `critical`. | ||
|
||
For additional information on Snyk CLI options, see: <https://docs.snyk.io/snyk-cli/commands/container-test> | ||
|
||
## Enabling Dockerfile Scanning | ||
|
||
Snyk can scan Dockerfiles for vulnerabilities. Because there's no direct relationship between the location on disk of a Pulumi program and any policy packs that might be running, we need to configure the Snyk policy to know where the Pulumi program is running. | ||
|
||
The following script will add the needed absolute path configuration: | ||
|
||
```bash | ||
cd infra | ||
./add-dockerfile-scanning.sh | ||
``` | ||
|
||
Because Dockerfile scanning requires the absolute path to the Pulumi program to be supplied via policy configuration, server-side policy enforcement requires that the Pulumi program be run from a known location on disk (i.e. whatever the path on disk is that the policy is configured with in the Pulumi Cloud console) if Dockerfile scanning is desired. If <https://github.com/pulumi/pulumi-policy/issues/333> is implemented, this restriction can be lifted and the configuration value can be removed. | ||
|
||
## Troubleshooting | ||
|
||
### Failed to connect to Docker Daemon | ||
|
||
If Pulumi gives the following error: | ||
|
||
```text | ||
Docker native provider returned an unexpected error from Configure: failed to connect to any docker daemon | ||
``` | ||
|
||
Start Docker Desktop on your machine. | ||
|
||
### Snyk Unable to find Docker Socket | ||
|
||
If the Snyk CLI gives you an error similar to the following: | ||
|
||
```text | ||
connect ENOENT /var/run/docker.sock | ||
``` | ||
|
||
You may need to set the `DOCKER_HOST` environment variable. At the time of writing, the Snyk CLI appears to assume that the Docker socket is running in the older (privileged) location. The newer version of Docker use a socket placed in the current user's home directory, e.g.: | ||
|
||
```bash | ||
export DOCKER_HOST=unix:///Users/jkodroff/.docker/run/docker.sock | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
/bin/ | ||
/node_modules/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
FROM alpine:3.19.1 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
FROM debian:12.5 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
name: snyk-container-scan-policy-ts | ||
runtime: nodejs | ||
description: A minimal TypeScript Pulumi program | ||
config: | ||
pulumi:tags: | ||
value: | ||
pulumi:template: typescript |
2 changes: 2 additions & 0 deletions
2
snyk-container-scan-policy-ts/infra/add-dockerfile-scanning.sh
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
#!/bin/bash | ||
echo "$(jq --arg pwd "$(pwd)" '.["snyk-container-scan"] += {"pulumiProgramAbsPath": $pwd}' policy-config.json)" > policy-config.json |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
import * as docker from "@pulumi/docker"; | ||
|
||
// This image does not have critical issues: | ||
new docker.Image("alpine", { | ||
imageName: "docker.io/joshkodroff/snyk-policy-alpine", | ||
buildOnPreview: true, | ||
build: { | ||
dockerfile: "AlpineDockerfile", | ||
platform: "linux/amd64", | ||
}, | ||
skipPush: true, | ||
}); | ||
|
||
// This image has critical issues: | ||
new docker.Image("debian", { | ||
imageName: "docker.io/joshkodroff/snyk-policy-debian", | ||
buildOnPreview: true, | ||
build: { | ||
dockerfile: "DebianDockerfile", | ||
platform: "linux/amd64", | ||
}, | ||
skipPush: true, | ||
}); | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
{ | ||
"name": "snyk-container-scan-policy-ts", | ||
"main": "index.ts", | ||
"devDependencies": { | ||
"@types/node": "^18" | ||
}, | ||
"dependencies": { | ||
"@pulumi/docker": "^4.5.1", | ||
"@pulumi/pulumi": "^3.0.0" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
{ | ||
"snyk-container-scan": { | ||
"enforcementLevel": "mandatory", | ||
"dockerfileScanning": false | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
{ | ||
"compilerOptions": { | ||
"strict": true, | ||
"outDir": "bin", | ||
"target": "es2016", | ||
"module": "commonjs", | ||
"moduleResolution": "node", | ||
"sourceMap": true, | ||
"experimentalDecorators": true, | ||
"pretty": true, | ||
"noFallthroughCasesInSwitch": true, | ||
"noImplicitReturns": true, | ||
"forceConsistentCasingInFileNames": true | ||
}, | ||
"files": [ | ||
"index.ts" | ||
] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
/bin/ | ||
/node_modules/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
runtime: nodejs | ||
description: A minimal Policy Pack for AWS using TypeScript. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,98 @@ | ||
import { PolicyPack, PolicyResource, ReportViolation, StackValidationArgs } from "@pulumi/policy"; | ||
const awaitSpawn = require("await-spawn"); | ||
const fs = require("fs"); | ||
|
||
interface SnykPolicyConfig { | ||
dockerfileScanning: boolean, | ||
excludeBaseImageVulns: boolean, | ||
failOn: string, | ||
pulumiProgramAbsPath: string, | ||
severityThreshold: string, | ||
} | ||
|
||
const validateStack = async (args: StackValidationArgs, reportViolation: ReportViolation) => { | ||
const config = args.getConfig<SnykPolicyConfig>(); | ||
|
||
if (config.dockerfileScanning && !config.pulumiProgramAbsPath) { | ||
throw new Error("If `dockerfileScanning` is configured to be `true`, `pulumiProgramAbsPath` must be set to the absolute path of the Pulumi program this policy is evaluating."); | ||
} | ||
|
||
const dockerImages = args.resources.filter(x => x.type === "docker:index/image:Image"); | ||
for (const image of dockerImages) { | ||
await validateStackImage(config, image, reportViolation); | ||
} | ||
}; | ||
|
||
const validateStackImage = async (config: SnykPolicyConfig, image: PolicyResource, reportViolation: ReportViolation) => { | ||
const commandArgs = [ | ||
"container", | ||
"test", | ||
image.props["imageName"], | ||
]; | ||
|
||
if (config.dockerfileScanning) { | ||
const dockerfileAbsPath = `${config.pulumiProgramAbsPath}/${image.props.dockerfile}`; | ||
|
||
if (!fs.existsSync(dockerfileAbsPath)) { | ||
const msg = `dockerfileScanning is set to 'true', but the Dockerfile at path '${dockerfileAbsPath}' could not be found. Either reconfigure the policy to turn off Dockerfile scanning, or set the value of docker.Image.snyk.dockerfileAbsPath resource to the absolute path of the Dockerfile in a resource transform.`; | ||
reportViolation(msg); | ||
return; | ||
} | ||
|
||
commandArgs.push(`--file=${dockerfileAbsPath}`); | ||
} | ||
|
||
if (config.excludeBaseImageVulns) { | ||
commandArgs.push("--exclude-base-image-vulns"); | ||
} | ||
|
||
commandArgs.push(`--severity-threshold=${config.severityThreshold}`); | ||
|
||
try { | ||
await awaitSpawn("snyk", commandArgs); | ||
} catch (e) { | ||
let errorMessage = `Snyk validation failed.`; | ||
|
||
if (e.stdout && e.stdout.toString()) { | ||
errorMessage += `\n${e.stdout.toString()}`; | ||
} | ||
|
||
if (e.stderr && e.stderr.toString()) { | ||
errorMessage += `\n${e.stderr.toString()}`; | ||
} | ||
|
||
reportViolation(errorMessage); | ||
} | ||
}; | ||
|
||
new PolicyPack("snyk-container-scanning", { | ||
policies: [{ | ||
name: "snyk-container-scan", | ||
configSchema: { | ||
properties: { | ||
"dockerfileScanning": { | ||
default: true, | ||
type: "boolean", | ||
}, | ||
"excludeBaseImageVulns": { | ||
default: false, | ||
type: "boolean" | ||
}, | ||
"failOn": { | ||
default: "all", | ||
enum: ["all", "upgradable"] | ||
}, | ||
"pulumiProgramAbsPath": { | ||
type: "string" | ||
}, | ||
"severityThreshold": { | ||
default: "critical", | ||
enum: ["low", "medium", "high", "critical"] | ||
}, | ||
}, | ||
}, | ||
enforcementLevel: "mandatory", | ||
description: "Scans Docker Images with Snyk", | ||
validateStack: validateStack, | ||
}], | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
{ | ||
"name": "synk-container-scan", | ||
"version": "0.0.1", | ||
"main": "index.ts", | ||
"devDependencies": { | ||
"@types/node": "^18" | ||
}, | ||
"dependencies": { | ||
"@pulumi/docker": "^4.5.1", | ||
"@pulumi/policy": "^1.10.0", | ||
"@pulumi/pulumi": "^3.0.0", | ||
"await-spawn": "^4.0.2" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
{ | ||
"compilerOptions": { | ||
"outDir": "bin", | ||
"target": "es6", | ||
"module": "commonjs", | ||
"moduleResolution": "node", | ||
"declaration": true, | ||
"sourceMap": false, | ||
"stripInternal": true, | ||
"experimentalDecorators": true, | ||
"pretty": true, | ||
"noFallthroughCasesInSwitch": true, | ||
"noImplicitAny": true, | ||
"noImplicitReturns": true, | ||
"forceConsistentCasingInFileNames": true, | ||
"strictNullChecks": true, | ||
}, | ||
"files": [ | ||
"index.ts" | ||
] | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Suggest adding just a slight but of intro here that makes it clear this is an example that shows how to do this, rather than a tool for doing this, if that makes sense.