-
Notifications
You must be signed in to change notification settings - Fork 1
/
index.js
98 lines (86 loc) · 2.82 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
const express = require('express')
const app = express()
const port = 8080
const child_process = require('child_process')
app.use(express.json())
app.get('/', (req, res) => res.send('Listening for POSTs'))
app.post('/', async (req, res) => {
const errors = []
await req.body.request.object.spec.containers.forEach(container => {
const image = container.image
const subject = req.body.request.object.metadata?.annotations[`subject.cosign.sigstore.dev/${container.name}`]
const issuer = req.body.request.object.metadata?.annotations[`issuer.cosign.sigstore.dev/${container.name}`]
if (!subject && !issuer) {
console.debug(`skipping checking ${image} has neither subject or issuer specified`)
return
}
const response = child_process.spawnSync("cosign", ["verify", "--k8s-keychain", "--output", "json", image])
if (response.status !== 0)
return errors.push(response.stderr)
var cosign
try {
cosign = JSON.parse(response.stdout.toString())
}
catch (_) {
return errors.push(`Unable to parse response from cosign for ${image}`)
}
let signs = cosign
.filter(sig => sig.critical.type === "cosign container image signature")
if (subject)
signs = signs.filter(sig => sig.optional.Subject === subject)
if (issuer)
signs = signs.filter(sig => sig.optional.Issuer === issuer)
if (signs.length === 0) {
if (subject && issuer)
return errors.push(`${image} is not signed with the subject ${subject} AND issuer ${issuer}`)
else if (subject)
return errors.push(`${image} is not signed with the subject ${subject}`)
else if (issuer)
return errors.push(`${image} is not signed with the issuer ${issuer}`)
}
})
if (errors.length === 0) {
console.debug(`allowing ${req.body.request.object.metadata.namespace}/${req.body.request.object.metadata.name}`)
return res.json(allowedTemplate(req.body.request.uid))
} else {
console.warn(errors.join(", "))
return res.json(notAllowedTemplate(req.body.request.uid, errors.join(", ")))
}
})
const allowedTemplate = uid => {
return {
"apiVersion": "admission.k8s.io/v1",
"kind": "AdmissionReview",
"response": {
"uid": uid,
"allowed": true
}
}
}
const notAllowedTemplate = (uid, reason) => {
return {
"apiVersion": "admission.k8s.io/v1",
"kind": "AdmissionReview",
"response": {
"uid": uid,
"allowed": false,
"status": {
"code": 403,
"message": reason
}
}
}
}
app.listen(port, () =>
console.log(`Listening at :${port}`)
)
if (process.env["CRT"] && process.env["KEY"]) {
const https = require('https')
const options = {
key: process.env["KEY"],
cert: process.env["CRT"]
}
https.createServer(options, app).listen(8443, () =>
console.log(`Listening at :8443`)
)
}