Skip to content

Commit ae84f0f

Browse files
committed
feat: agent id is now stable and sent only once on start up
Best effort attempt to grab the Agent ID using the snyk-monitor's Deployment UID. This UID is stable and does not change on application upgrades unless the Deployment object is deleted from Kubernetes.
1 parent 229cb81 commit ae84f0f

File tree

9 files changed

+72
-38
lines changed

9 files changed

+72
-38
lines changed

snyk-monitor-deployment.yaml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,12 @@ spec:
4949
name: snyk-monitor
5050
key: namespace
5151
optional: true
52+
- name: SNYK_DEPLOYMENT_NAMESPACE
53+
valueFrom:
54+
fieldRef:
55+
fieldPath: metadata.namespace
56+
- name: SNYK_DEPLOYMENT_NAME
57+
value: snyk-monitor
5258
- name: SNYK_INTEGRATION_API
5359
valueFrom:
5460
configMapKeyRef:

snyk-monitor/templates/deployment.yaml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,12 @@ spec:
7272
key: integrationId
7373
- name: SNYK_WATCH_NAMESPACE
7474
value: {{ include "snyk-monitor.scope" . }}
75+
- name: SNYK_DEPLOYMENT_NAMESPACE
76+
valueFrom:
77+
fieldRef:
78+
fieldPath: metadata.namespace
79+
- name: SNYK_DEPLOYMENT_NAME
80+
value: {{ include "snyk-monitor.name" . }}
7581
- name: SNYK_INTEGRATION_API
7682
value: {{ .Values.integrationApi }}
7783
- name: SNYK_CLUSTER_NAME

src/common/config.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,9 @@ function loadExcludedNamespaces(): string[] | null {
1818
}
1919
}
2020

21+
// NOTE: The agent identifier is replaced with a stable identifier once snyk-monitor starts up
2122
config.AGENT_ID = uuidv4();
23+
2224
config.INTEGRATION_ID = config.INTEGRATION_ID.trim();
2325
config.CLUSTER_NAME = config.CLUSTER_NAME || 'Default cluster';
2426
config.IMAGE_STORAGE_ROOT = '/var/tmp';

src/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import { currentClusterName } from './supervisor/cluster';
99
import { beginWatchingWorkloads } from './supervisor/watchers';
1010
import { loadAndSendWorkloadEventsPolicy } from './common/policy';
1111
import { sendClusterMetadata } from './transmitter';
12+
import { setSnykMonitorAgentId } from './supervisor/agent';
1213

1314
process.on('uncaughtException', (err) => {
1415
if (state.shutdownInProgress) {
@@ -63,6 +64,7 @@ cleanUpTempStorage();
6364

6465
// Allow running in an async context
6566
setImmediate(async function setUpAndMonitor(): Promise<void> {
67+
await setSnykMonitorAgentId();
6668
await sendClusterMetadata();
6769
await loadAndSendWorkloadEventsPolicy();
6870
await monitor();

src/supervisor/agent.ts

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import { config } from '../common/config';
2+
import { logger } from '../common/logger';
3+
import { k8sApi } from './cluster';
4+
import { retryKubernetesApiRequest } from './kuberenetes-api-wrappers';
5+
6+
export async function setSnykMonitorAgentId(): Promise<void> {
7+
const name = config.DEPLOYMENT_NAME;
8+
const namespace = config.DEPLOYMENT_NAMESPACE;
9+
10+
const agentId = await getSnykMonitorDeploymentUid(name, namespace);
11+
if (agentId === undefined) {
12+
return;
13+
}
14+
15+
config.AGENT_ID = agentId;
16+
}
17+
18+
async function getSnykMonitorDeploymentUid(
19+
name: string,
20+
namespace: string,
21+
): Promise<string | undefined> {
22+
try {
23+
const attemptedApiCall = await retryKubernetesApiRequest(() =>
24+
k8sApi.appsClient.readNamespacedDeployment(name, namespace),
25+
);
26+
return attemptedApiCall.body.metadata?.uid;
27+
} catch (error) {
28+
logger.error(
29+
{ error, namespace, name },
30+
'could not read the snyk-monitor deployment unique id',
31+
);
32+
return undefined;
33+
}
34+
}

src/transmitter/payload.ts

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ import {
99
IWorkloadMetadataPayload,
1010
IWorkloadMetadata,
1111
IWorkloadLocator,
12-
IKubernetesMonitorMetadata,
1312
ScanResultsPayload,
1413
IDependencyGraphPayload,
1514
IWorkloadEventsPolicyPayload,
@@ -38,17 +37,10 @@ export function constructDepGraph(
3837
name,
3938
};
4039

41-
const monitorMetadata: IKubernetesMonitorMetadata = {
42-
agentId: config.AGENT_ID,
43-
namespace: config.WATCH_NAMESPACE,
44-
version: config.MONITOR_VERSION,
45-
};
46-
4740
return {
4841
imageLocator,
4942
agentId: config.AGENT_ID,
5043
dependencyGraph: JSON.stringify(scannedImage.pluginResult),
51-
metadata: monitorMetadata,
5244
};
5345
});
5446

@@ -78,17 +70,10 @@ export function constructScanResults(
7870
name,
7971
};
8072

81-
const monitorMetadata: IKubernetesMonitorMetadata = {
82-
agentId: config.AGENT_ID,
83-
namespace: config.WATCH_NAMESPACE,
84-
version: config.MONITOR_VERSION,
85-
};
86-
8773
return {
8874
imageLocator,
8975
agentId: config.AGENT_ID,
9076
scanResults: scannedImage.scanResults,
91-
metadata: monitorMetadata,
9277
};
9378
});
9479
}

src/transmitter/types.ts

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -31,25 +31,16 @@ export interface IImageLocator extends IWorkloadLocator {
3131
imageWithDigest?: string;
3232
}
3333

34-
export interface IKubernetesMonitorMetadata {
35-
agentId: string;
36-
version: string;
37-
namespace?: string;
38-
}
39-
4034
export interface IDependencyGraphPayload {
4135
imageLocator: IImageLocator;
4236
agentId: string;
4337
dependencyGraph?: string;
44-
metadata: IKubernetesMonitorMetadata;
4538
}
4639

4740
export interface ScanResultsPayload {
4841
imageLocator: IImageLocator;
4942
agentId: string;
5043
scanResults: ScanResult[];
51-
/** @deprecated TODO: This should be sent in a separate API. */
52-
metadata: IKubernetesMonitorMetadata;
5344
}
5445

5546
export interface IWorkloadMetadataPayload {

test/system/kind.spec.ts

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import * as nock from 'nock';
33
import { copyFile, readFile, mkdir, exists } from 'fs';
44
import { promisify } from 'util';
55
import { resolve as resolvePath } from 'path';
6+
import { v4 as uuid } from 'uuid';
67

78
import * as kubectl from '../helpers/kubectl';
89
import * as kind from '../setup/platforms/kind';
@@ -25,6 +26,7 @@ const existsAsync = promisify(exists);
2526
* Error: Client network socket disconnected before secure TLS connection was established
2627
*/
2728
import { state as kubernetesMonitorState } from '../../src/state';
29+
import * as kubernetesApiWrappers from '../../src/supervisor/kuberenetes-api-wrappers';
2830

2931
async function tearDown() {
3032
console.log('Begin removing the snyk-monitor...');
@@ -38,6 +40,8 @@ async function tearDown() {
3840

3941
beforeAll(tearDown);
4042
afterAll(async () => {
43+
jest.restoreAllMocks();
44+
4145
kubernetesMonitorState.shutdownInProgress = true;
4246
await tearDown();
4347
// TODO cleanup the images we saved to /var/tmp?
@@ -48,6 +52,17 @@ test('Kubernetes-Monitor with KinD', async (jestDoneCallback) => {
4852
.spyOn(fsExtra, 'emptyDirSync')
4953
.mockReturnValue({});
5054

55+
const agentId = uuid();
56+
const retryKubernetesApiRequestMock = jest
57+
.spyOn(kubernetesApiWrappers, 'retryKubernetesApiRequest')
58+
.mockResolvedValueOnce({
59+
body: {
60+
metadata: {
61+
uid: agentId,
62+
},
63+
},
64+
});
65+
5166
try {
5267
await exec('which skopeo');
5368
console.log('Skopeo already installed :tada:');
@@ -102,7 +117,7 @@ test('Kubernetes-Monitor with KinD', async (jestDoneCallback) => {
102117
expect(
103118
requestBody,
104119
).toEqual<transmitterTypes.IWorkloadEventsPolicyPayload>({
105-
agentId: expect.any(String),
120+
agentId,
106121
cluster: expect.any(String),
107122
userLocator: expect.any(String),
108123
policy: regoPolicyContents,
@@ -123,7 +138,7 @@ test('Kubernetes-Monitor with KinD', async (jestDoneCallback) => {
123138
expect(requestBody).toEqual<
124139
Partial<transmitterTypes.IClusterMetadataPayload>
125140
>({
126-
agentId: expect.any(String),
141+
agentId,
127142
cluster: expect.any(String),
128143
userLocator: expect.any(String),
129144
// also should have version here but due to test limitation it is undefined
@@ -199,7 +214,7 @@ test('Kubernetes-Monitor with KinD', async (jestDoneCallback) => {
199214
]),
200215
}),
201216
}),
202-
agentId: expect.any(String),
217+
agentId,
203218
});
204219
} catch (error) {
205220
jestDoneCallback(error);
@@ -230,8 +245,7 @@ test('Kubernetes-Monitor with KinD', async (jestDoneCallback) => {
230245
.reply(500, (uri, requestBody: transmitterTypes.ScanResultsPayload) => {
231246
try {
232247
expect(requestBody).toEqual<transmitterTypes.ScanResultsPayload>({
233-
metadata: expect.any(Object),
234-
agentId: expect.any(String),
248+
agentId,
235249
imageLocator: expect.objectContaining({
236250
imageId: expect.any(String),
237251
}),
@@ -277,7 +291,7 @@ test('Kubernetes-Monitor with KinD', async (jestDoneCallback) => {
277291
try {
278292
expect(requestBody).toEqual<transmitterTypes.IDependencyGraphPayload>(
279293
{
280-
agentId: expect.any(String),
294+
agentId,
281295
dependencyGraph: expect.stringContaining('docker-image|java'),
282296
imageLocator: {
283297
userLocator: expect.any(String),
@@ -288,11 +302,10 @@ test('Kubernetes-Monitor with KinD', async (jestDoneCallback) => {
288302
type: expect.any(String),
289303
imageWithDigest: expect.any(String),
290304
},
291-
metadata: expect.objectContaining({
292-
agentId: expect.any(String),
293-
}),
294305
},
295306
);
307+
308+
expect(retryKubernetesApiRequestMock).toHaveBeenCalled();
296309
jestDoneCallback();
297310
} catch (error) {
298311
jestDoneCallback(error);

test/unit/transmitter-payload.spec.ts

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -125,11 +125,6 @@ describe('transmitter payload tests', () => {
125125
type: 'type',
126126
}),
127127
);
128-
expect(firstPayload.metadata).toEqual({
129-
agentId: config.AGENT_ID,
130-
namespace: 'b7',
131-
version: '1.2.3',
132-
});
133128

134129
config.WATCH_NAMESPACE = backups.namespace;
135130
config.MONITOR_VERSION = backups.version;

0 commit comments

Comments
 (0)