Skip to content

Commit

Permalink
Merge pull request #246 from snyk/fix/multi-container-pods
Browse files Browse the repository at this point in the history
Fix/multi container pods
  • Loading branch information
Amir Moualem authored Dec 4, 2019
2 parents b70712a + 79689b0 commit e10c3d2
Show file tree
Hide file tree
Showing 7 changed files with 483 additions and 19 deletions.
30 changes: 18 additions & 12 deletions src/kube-scanner/metadata-extractor.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { V1OwnerReference, V1Pod, V1Container, V1ContainerStatus } from '@kubernetes/client-node';
import { IWorkload, ILocalWorkloadLocator } from '../transmitter/types';
import { currentClusterName } from './cluster';
import { KubeObjectMetadata } from './types';
import { IKubeObjectMetadata } from './types';
import { getSupportedWorkload, getWorkloadReader } from './workload-reader';
import logger = require('../common/logger');

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

const images = containerStatuses.map(({ name: containerName }) => ({
const images: IWorkload[] = [];
for (const containerStatus of containerStatuses) {
if (!(containerStatus.name in containerNameToSpec)) {
continue
}
images.push({
type: kind,
name: name || 'unknown',
namespace,
Expand All @@ -35,23 +40,24 @@ export function buildImageMetadata(
uid,
specLabels: specMeta.labels || {},
specAnnotations: specMeta.annotations || {},
containerName,
imageName: containerNameToSpec[containerName].image,
imageId: containerNameToStatus[containerName].imageID,
containerName: containerStatus.name,
imageName: containerNameToSpec[containerStatus.name].image,
imageId: containerNameToStatus[containerStatus.name].imageID,
cluster: currentClusterName,
revision,
podSpec,
} as IWorkload),
);
} as IWorkload);
}

return images;
}

async function findParentWorkload(
ownerRefs: V1OwnerReference[] | undefined,
namespace: string,
): Promise<KubeObjectMetadata | undefined> {
): Promise<IKubeObjectMetadata | undefined> {
let ownerReferences = ownerRefs;
let parentMetadata: KubeObjectMetadata | undefined;
let parentMetadata: IKubeObjectMetadata | undefined;

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

export function buildWorkloadMetadata(kubernetesMetadata: KubeObjectMetadata): ILocalWorkloadLocator {
export function buildWorkloadMetadata(kubernetesMetadata: IKubeObjectMetadata): ILocalWorkloadLocator {
if (!kubernetesMetadata.objectMeta ||
kubernetesMetadata.objectMeta.namespace === undefined ||
kubernetesMetadata.objectMeta.name === undefined) {
Expand Down Expand Up @@ -126,7 +132,7 @@ export async function buildMetadataForWorkload(pod: V1Pod): Promise<IWorkload[]
);
}

const podOwner: KubeObjectMetadata | undefined = await findParentWorkload(
const podOwner: IKubeObjectMetadata | undefined = await findParentWorkload(
pod.metadata.ownerReferences, pod.metadata.namespace);

return podOwner === undefined
Expand Down
2 changes: 1 addition & 1 deletion src/kube-scanner/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ export interface IStaticAnalysisOptions {
tmpDirPath: string;
}

export interface KubeObjectMetadata {
export interface IKubeObjectMetadata {
kind: string;
objectMeta: V1ObjectMeta;
specMeta: V1ObjectMeta;
Expand Down
4 changes: 2 additions & 2 deletions src/kube-scanner/watchers/handlers/workload.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { KubeObjectMetadata } from '../../types';
import { IKubeObjectMetadata } from '../../types';
import { buildWorkloadMetadata } from '../../metadata-extractor';
import WorkloadWorker = require('../..');
import logger = require('../../../common/logger');

export async function deleteWorkload(kubernetesMetadata: KubeObjectMetadata, workloadName: string): Promise<void> {
export async function deleteWorkload(kubernetesMetadata: IKubeObjectMetadata, workloadName: string): Promise<void> {
try {
if (kubernetesMetadata.ownerRefs !== undefined && kubernetesMetadata.ownerRefs.length > 0) {
return;
Expand Down
4 changes: 2 additions & 2 deletions src/kube-scanner/workload-reader.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { V1OwnerReference } from '@kubernetes/client-node';
import { k8sApi } from './cluster';
import { KubeObjectMetadata, WorkloadKind } from './types';
import { IKubeObjectMetadata, WorkloadKind } from './types';

type IWorkloadReaderFunc = (
workloadName: string,
namespace: string,
) => Promise<KubeObjectMetadata | undefined>;
) => Promise<IKubeObjectMetadata | undefined>;

const deploymentReader: IWorkloadReaderFunc = async (workloadName, namespace) => {
const deploymentResult = await k8sApi.appsClient.readNamespacedDeployment(
Expand Down
95 changes: 95 additions & 0 deletions test/fixtures/sidecar-containers/deployment.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
annotations:
deployment.kubernetes.io/revision: "1"
flux.weave.works/antecedent: security-tools:helmrelease/hello-world
creationTimestamp: "2019-11-25T13:23:51Z"
generation: 2
labels:
app: hello-world
name: hello-world
namespace: security-tools
resourceVersion: "55787967"
selfLink: /apis/extensions/v1beta1/namespaces/security-tools/deployments/hello-world
uid: d2006330-0f86-11ea-ae05-4201c0a88014
spec:
progressDeadlineSeconds: 2147483647
replicas: 1
revisionHistoryLimit: 3
selector:
matchLabels:
app: hello-world
strategy:
rollingUpdate:
maxSurge: 1
maxUnavailable: 1
type: RollingUpdate
template:
metadata:
annotations:
json_logs: "true"
prometheus.io/scrape: "false"
creationTimestamp: null
labels:
app: hello-world
spec:
containers:
- image: eu.gcr.io/cookie/hello-world:1.20191125.132107-4664980
imagePullPolicy: IfNotPresent
livenessProbe:
failureThreshold: 3
httpGet:
path: /hello
port: 8080
scheme: HTTP
initialDelaySeconds: 5
periodSeconds: 5
successThreshold: 1
timeoutSeconds: 5
name: hello-world
ports:
- containerPort: 8080
name: http
protocol: TCP
readinessProbe:
failureThreshold: 3
httpGet:
path: /hello
port: 8080
scheme: HTTP
initialDelaySeconds: 5
periodSeconds: 5
successThreshold: 1
timeoutSeconds: 5
resources:
limits:
cpu: "2"
memory: 512Mi
requests:
cpu: "1"
memory: 128Mi
terminationMessagePath: /dev/termination-log
terminationMessagePolicy: File
dnsPolicy: ClusterFirst
restartPolicy: Always
schedulerName: default-scheduler
securityContext:
fsGroup: 40500
runAsUser: 40500
serviceAccount: hello-world
serviceAccountName: hello-world
terminationGracePeriodSeconds: 30
status:
availableReplicas: 1
conditions:
- lastTransitionTime: "2019-11-25T13:23:51Z"
lastUpdateTime: "2019-11-25T13:23:51Z"
message: Deployment has minimum availability.
reason: MinimumReplicasAvailable
status: "True"
type: Available
observedGeneration: 2
readyReplicas: 1
replicas: 1
updatedReplicas: 1
Loading

0 comments on commit e10c3d2

Please sign in to comment.