Skip to content

Commit e10c3d2

Browse files
author
Amir Moualem
authored
Merge pull request #246 from snyk/fix/multi-container-pods
Fix/multi container pods
2 parents b70712a + 79689b0 commit e10c3d2

File tree

7 files changed

+483
-19
lines changed

7 files changed

+483
-19
lines changed

src/kube-scanner/metadata-extractor.ts

+18-12
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { V1OwnerReference, V1Pod, V1Container, V1ContainerStatus } from '@kubernetes/client-node';
22
import { IWorkload, ILocalWorkloadLocator } from '../transmitter/types';
33
import { currentClusterName } from './cluster';
4-
import { KubeObjectMetadata } from './types';
4+
import { IKubeObjectMetadata } from './types';
55
import { getSupportedWorkload, getWorkloadReader } from './workload-reader';
66
import logger = require('../common/logger');
77

@@ -10,7 +10,7 @@ const loopingThreshold = 20;
1010
// Constructs the workload metadata based on a variety of k8s properties.
1111
// https://www.notion.so/snyk/Kubernetes-workload-fields-we-should-collect-c60c8f0395f241978282173f4c133a34
1212
export function buildImageMetadata(
13-
workloadMeta: KubeObjectMetadata,
13+
workloadMeta: IKubeObjectMetadata,
1414
containerStatuses: V1ContainerStatus[],
1515
): IWorkload[] {
1616
const { kind, objectMeta, specMeta, revision, podSpec } = workloadMeta;
@@ -26,7 +26,12 @@ export function buildImageMetadata(
2626
containerNameToStatus[containerStatus.name] = containerStatus;
2727
}
2828

29-
const images = containerStatuses.map(({ name: containerName }) => ({
29+
const images: IWorkload[] = [];
30+
for (const containerStatus of containerStatuses) {
31+
if (!(containerStatus.name in containerNameToSpec)) {
32+
continue
33+
}
34+
images.push({
3035
type: kind,
3136
name: name || 'unknown',
3237
namespace,
@@ -35,23 +40,24 @@ export function buildImageMetadata(
3540
uid,
3641
specLabels: specMeta.labels || {},
3742
specAnnotations: specMeta.annotations || {},
38-
containerName,
39-
imageName: containerNameToSpec[containerName].image,
40-
imageId: containerNameToStatus[containerName].imageID,
43+
containerName: containerStatus.name,
44+
imageName: containerNameToSpec[containerStatus.name].image,
45+
imageId: containerNameToStatus[containerStatus.name].imageID,
4146
cluster: currentClusterName,
4247
revision,
4348
podSpec,
44-
} as IWorkload),
45-
);
49+
} as IWorkload);
50+
}
51+
4652
return images;
4753
}
4854

4955
async function findParentWorkload(
5056
ownerRefs: V1OwnerReference[] | undefined,
5157
namespace: string,
52-
): Promise<KubeObjectMetadata | undefined> {
58+
): Promise<IKubeObjectMetadata | undefined> {
5359
let ownerReferences = ownerRefs;
54-
let parentMetadata: KubeObjectMetadata | undefined;
60+
let parentMetadata: IKubeObjectMetadata | undefined;
5561

5662
for (let i = 0; i < loopingThreshold; i++) {
5763
// We are interested only in a subset of all workloads.
@@ -76,7 +82,7 @@ async function findParentWorkload(
7682
return undefined;
7783
}
7884

79-
export function buildWorkloadMetadata(kubernetesMetadata: KubeObjectMetadata): ILocalWorkloadLocator {
85+
export function buildWorkloadMetadata(kubernetesMetadata: IKubeObjectMetadata): ILocalWorkloadLocator {
8086
if (!kubernetesMetadata.objectMeta ||
8187
kubernetesMetadata.objectMeta.namespace === undefined ||
8288
kubernetesMetadata.objectMeta.name === undefined) {
@@ -126,7 +132,7 @@ export async function buildMetadataForWorkload(pod: V1Pod): Promise<IWorkload[]
126132
);
127133
}
128134

129-
const podOwner: KubeObjectMetadata | undefined = await findParentWorkload(
135+
const podOwner: IKubeObjectMetadata | undefined = await findParentWorkload(
130136
pod.metadata.ownerReferences, pod.metadata.namespace);
131137

132138
return podOwner === undefined

src/kube-scanner/types.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ export interface IStaticAnalysisOptions {
3232
tmpDirPath: string;
3333
}
3434

35-
export interface KubeObjectMetadata {
35+
export interface IKubeObjectMetadata {
3636
kind: string;
3737
objectMeta: V1ObjectMeta;
3838
specMeta: V1ObjectMeta;

src/kube-scanner/watchers/handlers/workload.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
import { KubeObjectMetadata } from '../../types';
1+
import { IKubeObjectMetadata } from '../../types';
22
import { buildWorkloadMetadata } from '../../metadata-extractor';
33
import WorkloadWorker = require('../..');
44
import logger = require('../../../common/logger');
55

6-
export async function deleteWorkload(kubernetesMetadata: KubeObjectMetadata, workloadName: string): Promise<void> {
6+
export async function deleteWorkload(kubernetesMetadata: IKubeObjectMetadata, workloadName: string): Promise<void> {
77
try {
88
if (kubernetesMetadata.ownerRefs !== undefined && kubernetesMetadata.ownerRefs.length > 0) {
99
return;

src/kube-scanner/workload-reader.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
import { V1OwnerReference } from '@kubernetes/client-node';
22
import { k8sApi } from './cluster';
3-
import { KubeObjectMetadata, WorkloadKind } from './types';
3+
import { IKubeObjectMetadata, WorkloadKind } from './types';
44

55
type IWorkloadReaderFunc = (
66
workloadName: string,
77
namespace: string,
8-
) => Promise<KubeObjectMetadata | undefined>;
8+
) => Promise<IKubeObjectMetadata | undefined>;
99

1010
const deploymentReader: IWorkloadReaderFunc = async (workloadName, namespace) => {
1111
const deploymentResult = await k8sApi.appsClient.readNamespacedDeployment(
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
apiVersion: extensions/v1beta1
2+
kind: Deployment
3+
metadata:
4+
annotations:
5+
deployment.kubernetes.io/revision: "1"
6+
flux.weave.works/antecedent: security-tools:helmrelease/hello-world
7+
creationTimestamp: "2019-11-25T13:23:51Z"
8+
generation: 2
9+
labels:
10+
app: hello-world
11+
name: hello-world
12+
namespace: security-tools
13+
resourceVersion: "55787967"
14+
selfLink: /apis/extensions/v1beta1/namespaces/security-tools/deployments/hello-world
15+
uid: d2006330-0f86-11ea-ae05-4201c0a88014
16+
spec:
17+
progressDeadlineSeconds: 2147483647
18+
replicas: 1
19+
revisionHistoryLimit: 3
20+
selector:
21+
matchLabels:
22+
app: hello-world
23+
strategy:
24+
rollingUpdate:
25+
maxSurge: 1
26+
maxUnavailable: 1
27+
type: RollingUpdate
28+
template:
29+
metadata:
30+
annotations:
31+
json_logs: "true"
32+
prometheus.io/scrape: "false"
33+
creationTimestamp: null
34+
labels:
35+
app: hello-world
36+
spec:
37+
containers:
38+
- image: eu.gcr.io/cookie/hello-world:1.20191125.132107-4664980
39+
imagePullPolicy: IfNotPresent
40+
livenessProbe:
41+
failureThreshold: 3
42+
httpGet:
43+
path: /hello
44+
port: 8080
45+
scheme: HTTP
46+
initialDelaySeconds: 5
47+
periodSeconds: 5
48+
successThreshold: 1
49+
timeoutSeconds: 5
50+
name: hello-world
51+
ports:
52+
- containerPort: 8080
53+
name: http
54+
protocol: TCP
55+
readinessProbe:
56+
failureThreshold: 3
57+
httpGet:
58+
path: /hello
59+
port: 8080
60+
scheme: HTTP
61+
initialDelaySeconds: 5
62+
periodSeconds: 5
63+
successThreshold: 1
64+
timeoutSeconds: 5
65+
resources:
66+
limits:
67+
cpu: "2"
68+
memory: 512Mi
69+
requests:
70+
cpu: "1"
71+
memory: 128Mi
72+
terminationMessagePath: /dev/termination-log
73+
terminationMessagePolicy: File
74+
dnsPolicy: ClusterFirst
75+
restartPolicy: Always
76+
schedulerName: default-scheduler
77+
securityContext:
78+
fsGroup: 40500
79+
runAsUser: 40500
80+
serviceAccount: hello-world
81+
serviceAccountName: hello-world
82+
terminationGracePeriodSeconds: 30
83+
status:
84+
availableReplicas: 1
85+
conditions:
86+
- lastTransitionTime: "2019-11-25T13:23:51Z"
87+
lastUpdateTime: "2019-11-25T13:23:51Z"
88+
message: Deployment has minimum availability.
89+
reason: MinimumReplicasAvailable
90+
status: "True"
91+
type: Available
92+
observedGeneration: 2
93+
readyReplicas: 1
94+
replicas: 1
95+
updatedReplicas: 1

0 commit comments

Comments
 (0)