Skip to content

Commit 91b97b8

Browse files
authored
Merge pull request #148 from snyk/fix/use-pvc-storage
feat: static scanning
2 parents 9a3d64c + 759dbcf commit 91b97b8

24 files changed

+312
-51
lines changed

.dockerignore

+1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ node_modules
77

88
config.local.json
99
node_modules/
10+
dist/
1011
coverage/
1112
.nyc_output/
1213
.idea/

Dockerfile

+19-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,20 @@
1+
#---------------------------------------------------------------------
2+
# STAGE 1: Build skopeo inside a temporary container
3+
#---------------------------------------------------------------------
4+
FROM golang:1.13.1-alpine3.10 AS skopeo-build
5+
6+
RUN apk --no-cache add git make gcc musl-dev ostree-dev go-md2man
7+
RUN git clone --depth 1 -b 'v0.1.39' https://github.com/containers/skopeo $GOPATH/src/github.com/containers/skopeo
8+
RUN cd $GOPATH/src/github.com/containers/skopeo \
9+
&& make binary-local-static DISABLE_CGO=1 \
10+
&& make install
11+
12+
#---------------------------------------------------------------------
13+
# STAGE 2: Build the kubernetes-monitor
14+
#---------------------------------------------------------------------
115
FROM node:dubnium-alpine
216

3-
MAINTAINER Snyk Ltd
17+
LABEL maintainer="Snyk Ltd"
418

519
ENV NODE_ENV production
620

@@ -13,6 +27,10 @@ RUN apk --no-cache add --virtual curl-dep curl \
1327
&& rm docker-${DOCKERVERSION}.tgz \
1428
&& apk del curl-dep
1529

30+
COPY --from=skopeo-build /usr/bin/skopeo /usr/bin/skopeo
31+
COPY --from=skopeo-build /etc/containers/registries.d/default.yaml /etc/containers/registries.d/default.yaml
32+
COPY --from=skopeo-build /etc/containers/policy.json /etc/containers/policy.json
33+
1634
WORKDIR /root
1735

1836
# Add manifest files and install before adding anything else to take advantage of layer caching

package-lock.json

+65-9
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

+2-2
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
"pretest": "./scripts/build-image.sh",
77
"test": "npm run lint && npm run build && npm run test:unit && npm run test:integration",
88
"test:unit": "./tap test/unit -R spec",
9-
"test:integration": "./tap test/integration -Rdot --timeout=600",
9+
"test:integration": "./tap test/integration -Rdot --timeout=600 && STATIC_ANALYSIS=true ./tap test/integration -Rdot --timeout=1200",
1010
"test:coverage": "npm run test:unit -- --coverage",
1111
"test:watch": "tsc-watch --onSuccess 'npm run test:unit'",
1212
"start": "bin/start",
@@ -41,7 +41,7 @@
4141
"needle": "^2.4.0",
4242
"response-time": "^2.3.2",
4343
"snyk-config": "^2.2.0",
44-
"snyk-docker-plugin": "^1.25.0",
44+
"snyk-docker-plugin": "^1.32.1",
4545
"source-map-support": "^0.5.9",
4646
"tslib": "^1.9.3",
4747
"ws": "^7.0.0",

snyk-monitor-cluster-permissions.yaml

+1
Original file line numberDiff line numberDiff line change
@@ -83,4 +83,5 @@ data:
8383
namespace: ""
8484
integrationApi: ""
8585
clusterName: ""
86+
staticAnalysis: "false"
8687
---

snyk-monitor-deployment.yaml

+11
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ spec:
2626
- name: docker-config
2727
readOnly: true
2828
mountPath: "/root/.docker"
29+
- name: temporary-storage
30+
mountPath: "/snyk-monitor"
2931
env:
3032
- name: SNYK_INTEGRATION_ID
3133
valueFrom:
@@ -50,6 +52,12 @@ spec:
5052
name: snyk-monitor
5153
key: clusterName
5254
optional: true
55+
- name: SNYK_STATIC_ANALYSIS
56+
valueFrom:
57+
configMapKeyRef:
58+
name: snyk-monitor
59+
key: staticAnalysis
60+
optional: true
5361
resources:
5462
requests:
5563
cpu: '250m'
@@ -69,4 +77,7 @@ spec:
6977
items:
7078
- key: dockercfg.json
7179
path: config.json
80+
- name: temporary-storage
81+
emptyDir:
82+
sizeLimit: 20Gi
7283
serviceAccountName: snyk-monitor

snyk-monitor-namespaced-permissions.yaml

+1
Original file line numberDiff line numberDiff line change
@@ -75,4 +75,5 @@ data:
7575
namespace: snyk-monitor
7676
integrationApi: ""
7777
clusterName: ""
78+
staticAnalysis: "false"
7879
---

snyk-monitor/templates/deployment.yaml

+15
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,17 @@ spec:
2727
terminationMessagePath: /dev/termination-log
2828
terminationMessagePolicy: File
2929
volumeMounts:
30+
{{- if ne .Values.featureFlags.staticAnalysis true }}
3031
- name: docker-socket-mount
3132
mountPath: /var/run/docker.sock
33+
{{- end }}
3234
- name: docker-config
3335
readOnly: true
3436
mountPath: "/root/.docker"
37+
{{- if eq .Values.featureFlags.staticAnalysis true }}
38+
- name: temporary-storage
39+
mountPath: "/snyk-monitor"
40+
{{- end }}
3541
env:
3642
- name: SNYK_INTEGRATION_ID
3743
valueFrom:
@@ -44,6 +50,8 @@ spec:
4450
value: {{ .Values.integrationApi }}
4551
- name: SNYK_CLUSTER_NAME
4652
value: {{ .Values.clusterName }}
53+
- name: SNYK_STATIC_ANALYSIS
54+
value: {{ quote .Values.featureFlags.staticAnalysis }}
4755
resources:
4856
requests:
4957
cpu: '250m'
@@ -52,12 +60,19 @@ spec:
5260
cpu: '1'
5361
memory: '2Gi'
5462
volumes:
63+
{{- if ne .Values.featureFlags.staticAnalysis true }}
5564
- name: docker-socket-mount
5665
hostPath:
5766
path: {{ .Values.dockerSocketHostPath }}
67+
{{- end }}
5868
- name: docker-config
5969
secret:
6070
secretName: {{ .Values.monitorSecrets }}
6171
items:
6272
- key: dockercfg.json
6373
path: config.json
74+
{{- if eq .Values.featureFlags.staticAnalysis true }}
75+
- name: temporary-storage
76+
emptyDir:
77+
sizeLimit: 20Gi
78+
{{- end }}

snyk-monitor/values.yaml

+3
Original file line numberDiff line numberDiff line change
@@ -27,3 +27,6 @@ clusterName: ""
2727

2828
# The path of the docker socket on the node. For PKS: /var/vcap/data/sys/run/docker/docker.sock
2929
dockerSocketHostPath: "/var/run/docker.sock"
30+
31+
featureFlags:
32+
staticAnalysis: false

src/app.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,10 @@ import { beginWatchingWorkloads } from './kube-scanner/watchers/namespaces';
55

66
function safeMonitoring() {
77
try {
8-
logger.info({cluster: currentClusterName}, 'Starting to monitor');
8+
logger.info({cluster: currentClusterName}, 'starting to monitor');
99
beginWatchingWorkloads();
1010
} catch (error) {
11-
logger.error({error}, 'An error occurred while monitoring the cluster');
11+
logger.error({error}, 'an error occurred while monitoring the cluster');
1212
}
1313
}
1414

src/cli/process.ts

+15-3
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,22 @@
1-
import { ChildProcessPromise, spawn, SpawnPromiseResult } from 'child-process-promise';
1+
import { spawn, SpawnPromiseResult } from 'child-process-promise';
2+
import logger = require('../common/logger');
23

34
export function exec(bin: string, ...args: string[]):
4-
ChildProcessPromise<SpawnPromiseResult> {
5+
Promise<SpawnPromiseResult> {
56
if (process.env.DEBUG === 'true') {
67
args.push('--debug');
78
}
89

9-
return spawn(bin, args, { env: process.env, capture: [ 'stdout', 'stderr' ] });
10+
// Ensure we're not passing the whole environment to the shelled out process...
11+
// For example, that process doesn't need to know secrets like our integrationId!
12+
const env = {
13+
PATH: process.env.PATH,
14+
};
15+
16+
return spawn(bin, args, { env, capture: [ 'stdout', 'stderr' ] })
17+
.catch((error) => {
18+
const message = (error && error.stderr) || 'Unknown reason';
19+
logger.warn({message, bin, args}, 'could not spawn the process');
20+
throw error;
21+
});
1022
}

src/common/config.ts

+2
Original file line numberDiff line numberDiff line change
@@ -7,5 +7,7 @@ const config = require('snyk-config')(__dirname + '/../..', {
77
config.AGENT_ID = uuidv4();
88
config.INTEGRATION_ID = config.INTEGRATION_ID.trim();
99
config.CLUSTER_NAME = config.CLUSTER_NAME || 'Default cluster';
10+
config.IMAGE_STORAGE_ROOT = '/snyk-monitor';
11+
config.STATIC_ANALYSIS = config.STATIC_ANALYSIS || false;
1012

1113
export = config;

src/common/features.ts

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import * as config from './config';
2+
3+
export function isStaticAnalysisEnabled(): boolean {
4+
return config.STATIC_ANALYSIS === true;
5+
}

src/images/index.ts

+27-3
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,41 @@
11
import logger = require('../common/logger');
2-
import { pull } from './docker';
2+
import { pull as dockerPull } from './docker';
3+
import { pull as skopeoCopy, getDestinationForImage } from './skopeo';
4+
import { unlink } from 'fs';
5+
import { isStaticAnalysisEnabled } from '../common/features';
6+
7+
export { getDestinationForImage };
38

49
export async function pullImages(images: string[]): Promise<string[]> {
510
const pulledImages: string[] = [];
611

712
for (const image of images) {
813
try {
9-
await pull(image);
14+
if (isStaticAnalysisEnabled()) {
15+
await skopeoCopy(image);
16+
} else {
17+
await dockerPull(image);
18+
}
1019
pulledImages.push(image);
1120
} catch (error) {
12-
logger.error({error, image}, 'Failed to pull image');
21+
logger.error({error, image}, 'failed to pull image');
1322
}
1423
}
1524

1625
return pulledImages;
1726
}
27+
28+
export async function removePulledImages(images: string[]) {
29+
if (!isStaticAnalysisEnabled()) {
30+
return;
31+
}
32+
33+
for (const image of images) {
34+
try {
35+
const destination = getDestinationForImage(image);
36+
await new Promise((resolve) => unlink(destination, resolve));
37+
} catch (error) {
38+
logger.warn({error, image}, 'failed to delete pulled image');
39+
}
40+
}
41+
}

0 commit comments

Comments
 (0)