Skip to content

Commit 5859546

Browse files
authored
Merge pull request #219 from kubero-dev/feature/add-more-security-context-values-for-apps
Feature / Add more security features to run containers
2 parents 07bc0bc + f1f6f58 commit 5859546

File tree

7 files changed

+293
-94
lines changed

7 files changed

+293
-94
lines changed

client/src/components/apps/new.vue

Lines changed: 153 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -351,43 +351,98 @@
351351
inset
352352
></v-switch>
353353
</v-col>
354-
<!--
355354
<v-col
356355
cols="12"
357356
md="6"
358357
>
359358
<v-switch
360-
v-model="security.allowPrivilegeEscalation"
361-
:label="`Allow privilege escalation: ${security.allowPrivilegeEscalation}`"
359+
v-model="buildpack.run.securityContext.readOnlyRootFilesystem"
360+
label="Read only root filesystem"
362361
color="primary"
363362
inset
364363
></v-switch>
365364
</v-col>
366-
-->
365+
</v-row>
366+
367+
<v-row>
367368
<v-col
368369
cols="12"
369370
md="6"
370371
>
371372
<v-switch
372-
v-model="security.readOnlyRootFilesystem"
373-
label="Read only root filesystem"
373+
v-model="buildpack.run.securityContext.allowPrivilegeEscalation"
374+
label="Allow privilege escalation"
374375
color="primary"
375376
inset
376377
></v-switch>
377378
</v-col>
378-
<!--
379379
<v-col
380380
cols="12"
381381
md="6"
382382
>
383383
<v-switch
384-
v-model="security.runAsNonRoot"
385-
:label="`Run as non root: ${security.runAsNonRoot}`"
384+
v-model="buildpack.run.securityContext.runAsNonRoot"
385+
label="Run as non root"
386386
color="primary"
387387
inset
388388
></v-switch>
389389
</v-col>
390-
-->
390+
</v-row>
391+
392+
<v-row>
393+
<v-col
394+
cols="12"
395+
md="6"
396+
>
397+
<v-text-field
398+
v-model="buildpack.run.securityContext.runAsUser"
399+
:rules="uidRules"
400+
label="Run as user"
401+
></v-text-field>
402+
</v-col>
403+
<v-col
404+
cols="12"
405+
md="6"
406+
>
407+
<v-text-field
408+
v-model="buildpack.run.securityContext.runAsGroup"
409+
:rules="uidRules"
410+
label="Run as group"
411+
></v-text-field>
412+
</v-col>
413+
</v-row>
414+
415+
<v-row>
416+
<v-col
417+
cols="12"
418+
md="6"
419+
>
420+
<v-select
421+
v-model="buildpack.run.securityContext.capabilities.add"
422+
:items="capabilities"
423+
:menu-props="{ maxHeight: '400' }"
424+
label="Capabilities add"
425+
multiple
426+
hint="Select one or more"
427+
persistent-hint
428+
chips
429+
></v-select>
430+
</v-col>
431+
<v-col
432+
cols="12"
433+
md="6"
434+
>
435+
<v-select
436+
v-model="buildpack.run.securityContext.capabilities.drop"
437+
:items="capabilities"
438+
:menu-props="{ maxHeight: '400' }"
439+
label="Capabilities drop"
440+
multiple
441+
hint="Select one or more"
442+
persistent-hint
443+
chips
444+
></v-select>
445+
</v-col>
391446
</v-row>
392447

393448
</v-expansion-panel-content>
@@ -815,6 +870,17 @@ export default {
815870
buildpack: {
816871
run: {
817872
command: '',
873+
securityContext: {
874+
readOnlyRootFilesystem: true,
875+
allowPrivilegeEscalation: false,
876+
runAsNonRoot: false,
877+
runAsUser: 0,
878+
runAsGroup: 0,
879+
capabilities: {
880+
add: [],
881+
drop: [],
882+
},
883+
},
818884
},
819885
build: {
820886
command: '',
@@ -824,7 +890,15 @@ export default {
824890
run: {
825891
command: '',
826892
securityContext: {
827-
readOnlyRootFilesystem: true
893+
readOnlyRootFilesystem: true,
894+
allowPrivilegeEscalation: false,
895+
runAsNonRoot: false,
896+
runAsUser: 0,
897+
runAsGroup: 0,
898+
capabilities: {
899+
add: [],
900+
drop: [],
901+
},
828902
},
829903
},
830904
build: {
@@ -937,18 +1011,58 @@ export default {
9371011
allowPrivilegeEscalation: false,
9381012
runAsNonRoot: false,
9391013
readOnlyRootFilesystem: true,
940-
/*
9411014
runAsUser: 0,
9421015
runAsGroup: 0,
9431016
capabilities: {
9441017
add: [],
9451018
drop: [],
9461019
},
1020+
/*
9471021
seLinuxOptions: {
9481022
level: 's0:c0,c1',
9491023
},
9501024
*/
9511025
},
1026+
capabilities: [
1027+
'AUDIT_CONTROL',
1028+
'AUDIT_READ',
1029+
'AUDIT_WRITE',
1030+
'BLOCK_SUSPEND',
1031+
'CHOWN',
1032+
'DAC_OVERRIDE',
1033+
'DAC_READ_SEARCH',
1034+
'FOWNER',
1035+
'FSETID',
1036+
'IPC_LOCK',
1037+
'IPC_OWNER',
1038+
'KILL',
1039+
'LEASE',
1040+
'LINUX_IMMUTABLE',
1041+
'MAC_ADMIN',
1042+
'MAC_OVERRIDE',
1043+
'MKNOD',
1044+
'NET_ADMIN',
1045+
'NET_BIND_SERVICE',
1046+
'NET_BROADCAST',
1047+
'NET_RAW',
1048+
'SETFCAP',
1049+
'SETGID',
1050+
'SETPCAP',
1051+
'SETUID',
1052+
'SYS_ADMIN',
1053+
'SYS_BOOT',
1054+
'SYS_CHROOT',
1055+
'SYS_MODULE',
1056+
'SYS_NICE',
1057+
'SYS_PACCT',
1058+
'SYS_PTRACE',
1059+
'SYS_RAWIO',
1060+
'SYS_RESOURCE',
1061+
'SYS_TIME',
1062+
'SYS_TTY_CONFIG',
1063+
'SYSLOG',
1064+
'WAKE_ALARM',
1065+
],
9521066
nameRules: [
9531067
v => !!v || 'Name is required',
9541068
v => v.length <= 60 || 'Name must be less than 60 characters',
@@ -969,6 +1083,10 @@ export default {
9691083
v => !!v || 'Schedule is required',
9701084
v => /(((\d+,)+\d+|(\d+(\/|-)\d+)|\d+|\*) ?){5,7}/.test(v) || 'Not a valid crontab format',
9711085
],
1086+
uidRules: [
1087+
//v => !!v || 'UID is required',
1088+
v => /^\d+$/.test(v) || 'Not a number',
1089+
],
9721090
/*
9731091
buildpackRules: [
9741092
v => !!v || 'Buildpack is required',
@@ -1146,7 +1264,7 @@ export default {
11461264
loadApp() {
11471265
if (this.app !== 'new') {
11481266
axios.get(`/api/pipelines/${this.pipeline}/${this.phase}/${this.app}`).then(response => {
1149-
this.resourceVersion = response.data.metadata.resourceVersion;
1267+
this.resourceVersion = response.data.resourceVersion;
11501268
11511269
if (response.data.spec.ingress.tls.length > 0) {
11521270
this.ssl = true;
@@ -1165,7 +1283,7 @@ export default {
11651283
this.panel.push(4)
11661284
}
11671285
1168-
this.security.readOnlyRootFilesystem = response.data.spec.image.run.securityContext?.readOnlyRootFilesystem != false; // reversed since it is a boolean
1286+
this.security = response.data.spec.image.run.securityContext || {};
11691287
11701288
this.deploymentstrategy = response.data.spec.deploymentstrategy;
11711289
this.buildstrategy = response.data.spec.buildstrategy || 'plain';
@@ -1273,12 +1391,18 @@ export default {
12731391
}
12741392
*/
12751393
1276-
1394+
/*
12771395
postdata.image.run.securityContext = {
12781396
readOnlyRootFilesystem: this.security.readOnlyRootFilesystem,
1279-
//runAsNonRoot: true,
1397+
runAsNonRoot: this.security.runAsNonRoot,
1398+
runAsUser: parseInt(this.security.runAsUser),
1399+
runAsGroup: parseInt(this.security.runAsGroup),
1400+
capabilities: {
1401+
add: this.security.capabilities.add,
1402+
drop: this.security.capabilities.drop,
1403+
},
12801404
}
1281-
1405+
*/
12821406
axios.put(`/api/pipelines/${this.pipeline}/${this.phase}/${this.app}`, postdata
12831407
// eslint-disable-next-line no-unused-vars
12841408
).then(response => {
@@ -1363,12 +1487,18 @@ export default {
13631487
if (postdata.image.run == undefined) {
13641488
postdata.image.run = {};
13651489
}
1366-
1490+
/*
13671491
postdata.image.run.securityContext = {
13681492
readOnlyRootFilesystem: this.security.readOnlyRootFilesystem,
1369-
//runAsNonRoot: true,
1493+
runAsNonRoot: this.security.runAsNonRoot,
1494+
runAsUser: parseInt(this.security.runAsUser),
1495+
runAsGroup: parseInt(this.security.runAsGroup),
1496+
capabilities: {
1497+
add: this.security.capabilities.add,
1498+
drop: this.security.capabilities.drop,
1499+
},
13701500
}
1371-
1501+
*/
13721502
axios.post(`/api/apps`, postdata)
13731503
// eslint-disable-next-line no-unused-vars
13741504
.then(response => {
@@ -1459,4 +1589,7 @@ export default {
14591589
.v-expansion-panel-header {
14601590
background: cardBackground;
14611591
}
1592+
.theme--light.v-chip:not(.v-chip--active) {
1593+
background: #BBB;
1594+
}
14621595
</style>

config.yaml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,12 @@ buildpacks:
2424
fetch:
2525
repository: ghcr.io/kubero-dev/buildpacks/fetch
2626
tag: main
27+
securityContext:
28+
runAsUser: 1000
29+
runAsGroup: 1000
30+
capabilities:
31+
add:
32+
- SYS_PTRACE
2733
build:
2834
repository: node
2935
tag: latest

src/kubero.ts

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import debug from 'debug';
22
import { Server } from "socket.io";
33
import { IApp, IPipeline, IPipelineList, IKubectlAppList, IDeployKeyPair, IKubectlPipelineList, IKubectlApp, IPodSize, IKuberoConfig} from './types';
44
import { App } from './modules/application';
5+
import { Buildpack } from './modules/config';
56
import { GithubApi } from './git/github';
67
import { BitbucketApi } from './git/bitbucket';
78
import { GiteaApi } from './git/gitea';
@@ -195,6 +196,10 @@ export class Kubero {
195196
});
196197

197198
if (pipeline && pipeline.metadata && pipeline.metadata.resourceVersion) {
199+
pipeline.spec.buildpack.fetch.securityContext = Buildpack.SetSecurityContext(pipeline.spec.buildpack.fetch.securityContext);
200+
pipeline.spec.buildpack.build.securityContext = Buildpack.SetSecurityContext(pipeline.spec.buildpack.build.securityContext);
201+
pipeline.spec.buildpack.run.securityContext = Buildpack.SetSecurityContext(pipeline.spec.buildpack.run.securityContext);
202+
198203
pipeline.spec.resourceVersion = pipeline.metadata.resourceVersion;
199204

200205
delete pipeline.spec.git.keys.priv
@@ -873,7 +878,13 @@ export class Kubero {
873878
}
874879

875880
public getBuildpacks() {
876-
return this.config.buildpacks;
881+
let buildpackList: Buildpack[] = [];
882+
for (const buildpack of this.config.buildpacks) {
883+
const b = new Buildpack(buildpack);
884+
buildpackList.push(b);
885+
}
886+
887+
return buildpackList;
877888
}
878889

879890
public getEvents(namespace: string) {

src/modules/application.ts

Lines changed: 11 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1-
import { IApp, IKubectlMetadata, IKubectlApp, IGithubRepository, ICronjob, IPodSize, IExtraVolume} from '../types';
1+
import { IApp, IKubectlMetadata, IKubectlApp, IGithubRepository, ICronjob, IPodSize, IExtraVolume, ISecurityContext} from '../types';
22
import { IAddon } from './addons';
3+
import { Buildpack } from './config';
34

45
export class KubectlApp implements IKubectlApp{
56
apiVersion: string;
@@ -73,39 +74,18 @@ export class App implements IApp{
7374
fetch: {
7475
repository: string,
7576
tag: string,
76-
securityContext?: {
77-
readOnlyRootFilesystem?: boolean;
78-
allowPrivilegeEscalation?: boolean;
79-
capabilities?: {
80-
drop?: string[];
81-
add?: string[];
82-
}
83-
}
77+
securityContext?: ISecurityContext
8478
}
8579
build: {
8680
repository: string,
8781
tag: string,
88-
securityContext?: {
89-
readOnlyRootFilesystem?: boolean;
90-
allowPrivilegeEscalation?: boolean;
91-
capabilities?: {
92-
drop?: string[];
93-
add?: string[];
94-
}
95-
}
82+
securityContext?: ISecurityContext
9683
}
9784
run: {
9885
repository: string,
9986
tag: string,
10087
readOnly?: boolean,
101-
securityContext?: {
102-
readOnlyRootFilesystem?: boolean;
103-
allowPrivilegeEscalation?: boolean;
104-
capabilities?: {
105-
drop?: string[];
106-
add?: string[];
107-
}
108-
}
88+
securityContext: ISecurityContext
10989
}
11090
};
11191

@@ -193,6 +173,12 @@ export class App implements IApp{
193173
run: app.image.run,
194174
}
195175

176+
// function to set security context, required for backwards compatibility
177+
// Added in v1.11.0
178+
this.image.fetch.securityContext = Buildpack.SetSecurityContext(this.image.fetch.securityContext)
179+
this.image.build.securityContext = Buildpack.SetSecurityContext(this.image.build.securityContext)
180+
this.image.run.securityContext = Buildpack.SetSecurityContext(this.image.run.securityContext)
181+
196182
this.vulnerabilityscan = app.vulnerabilityscan
197183

198184
this.imagePullSecrets = []

0 commit comments

Comments
 (0)