More Related Content Similar to Software Supply Chains for DevOps @ InfoQ Live 2021 (20) More from Aysylu Greenberg (18) Software Supply Chains for DevOps @ InfoQ Live 20212. Speaker introduction
● Sr Software Engineer @ Google
● Tech Lead of GCP Container Analysis
and Container Scanning team
● Maintainer of Grafeas and Kritis OSS
projects
● Track Host of the inaugural Software
Supply Chain track @ QCon SF 2019
● @aysylu22
Aysylu Greenberg
6. Modern Challenges in Software Supply Chains
https://security.googleblog.com/2021/06/introducing-slsa-end-to-end-framework.html
10. Software Supply Chains
Source code
Test
OSS &
proprietary libs
Build
Deploy to
Production
Deploy to
Staging
Incident
Monitor
workloads
Patch
Management
11. Software Supply Chains
Source code
Test
OSS &
proprietary libs
Build
Deploy to
Production
Deploy to
Staging
Monitor
workloads
CI pipeline
Incident
Patch
Management
12. Software Supply Chains
Source code
Test
OSS &
proprietary libs
Build
Deploy to
Production
Deploy to
Staging
Monitor
workloads
CD pipeline
Incident
Patch
Management
13. Software Supply Chains
Source code
Test
OSS &
proprietary libs
Build
Deploy to
Production
Deploy to
Staging
Monitor
workloads
Observability tools
Incident
Patch
Management
16. Source to Prod
CI/CD pipelines
Build &
Deploy
Build process
Automated test,
scan, analysis
Deploy
checks
Production
18. Incident: O11y to the Rescue
CI/CD pipelines
Automated test,
scan, analysis
Deploy
checks
Production
Build &
Deploy
Build process
19. Incident: from Prod to Source
CI/CD pipelines
Automated test,
scan, analysis
Deploy
checks
Production
Build &
Deploy
?
?
?
?
Build process
20. Incident: from Prod to Source
CI/CD pipelines
Automated test,
scan, analysis
Deploy
checks
Production
Build &
Deploy
?
?
?
?
?
Build process
21. Incident: from Prod to Source
Universal Artifact Metadata
Automated test,
scan, analysis
Deploy
checks
Production
Build &
Deploy
?
?
?
?
?
Build process
22. Incident: from Prod to Source
Universal Artifact Metadata
Automated test,
scan, analysis
Deploy
checks
Production
Build &
Deploy
?
?
?
?
?
Build process
24. Collect everything!
You never know when you’ll need that info and fine
granularity helps to avoid o11y gaps.
What level of
detail should we
collect?
25. Am I going to get
overwhelmed
with information?
26. The right signal to noise ratio is important.
Example: report all vulnerabilities on an image. False
positives?
Am I going to get
overwhelmed
with information?
28. The right signal to noise ratio is important.
Example: report all vulnerabilities on an image. False
positives?
Compliance (e.g. FedRAMP) requires detailed
information about software supply chain.
Am I going to get
overwhelmed
with information?
31. Horizontal query?
Across all artifacts with a specific property.
"Find all images that are built from a particular
Github commit that is known to have introduced a
security problem."
32. Vertical query?
Metadata across SDLC for a specific artifact.
"Find all source, build, test, vulnerabilities, and
deployments metadata for a container image."
35. Software Supply Chains Solutions
Universal Artifact Metadata
Automated test,
scan, analysis
Deploy
checks
Production
Build &
Deploy
Build process
36. Software Supply Chains Solutions
Automated test,
scan, analysis
Deploy
checks
Production
Build &
Deploy
Build process
Universal Artifact Metadata
39. Proprietary + Confidential
Proprietary + Confidential
Find all
workloads that
exceed build
horizon
occResp, _ := client.ListOccurrences(ctx,
&gpb.ListOccurrencesRequest{
Parent: fmt.Sprintf("projects/%s", *projectID),
Filter: `kind = "DEPLOYABLE"`,
})
for _, occ := range occResp.GetOccurrences() {
if occ.GetDeployment().GetUndeployTime() == nil {
// The workload is still running.
runningImgs[occ.GetResourceUri()] = true
}
}
for _, img := range runningImgs {
buildResp, _ := client.ListOccurrences(ctx,
&gpb.ListOccurrencesRequest{
Parent: fmt.Sprintf("projects/%s", *projectID),
Filter: fmt.Sprintf(`kind="BUILD_DETAILS" AND
resourceUrl=%q`, img),
})
// assume each build generates a unique container
image URI
build := buildResp.GetOccurrences()[0]
if time.Now().Sub(build.GetCreateTime().AsTime()) >
*buildHorizon {
log.Infof("Workload running image %s is
exceeding build horizon policy of %q.", img, *buildHorizon)
}
}
40. Proprietary + Confidential
Proprietary + Confidential
Find all
workloads that
exceed build
horizon
occResp, _ := client.ListOccurrences(ctx,
&gpb.ListOccurrencesRequest{
Parent: fmt.Sprintf("projects/%s", *projectID),
Filter: `kind = "DEPLOYABLE"`,
})
for _, occ := range occResp.GetOccurrences() {
if occ.GetDeployment().GetUndeployTime() == nil {
// The workload is still running.
runningImgs[occ.GetResourceUri()] = true
}
}
for _, img := range runningImgs {
buildResp, _ := client.ListOccurrences(ctx,
&gpb.ListOccurrencesRequest{
Parent: fmt.Sprintf("projects/%s", *projectID),
Filter: fmt.Sprintf(`kind="BUILD_DETAILS" AND
resourceUrl=%q`, img),
})
// assume each build generates a unique container
image URI
build := buildResp.GetOccurrences()[0]
if time.Now().Sub(build.GetCreateTime().AsTime()) >
*buildHorizon {
log.Infof("Workload running image %s is
exceeding build horizon policy of %q.", img, *buildHorizon)
}
}
41. Proprietary + Confidential
Proprietary + Confidential
Find all
workloads that
exceed build
horizon
occResp, _ := client.ListOccurrences(ctx,
&gpb.ListOccurrencesRequest{
Parent: fmt.Sprintf("projects/%s",
*projectID),
Filter: `kind = "DEPLOYABLE"`,
})
42. Proprietary + Confidential
Proprietary + Confidential
Find all
workloads that
exceed build
horizon
occResp, _ := client.ListOccurrences(ctx,
&gpb.ListOccurrencesRequest{
Parent: fmt.Sprintf("projects/%s", *projectID),
Filter: `kind = "DEPLOYABLE"`,
})
for _, occ := range occResp.GetOccurrences() {
if occ.GetDeployment().GetUndeployTime() == nil {
// The workload is still running.
runningImgs[occ.GetResourceUri()] = true
}
}
for _, img := range runningImgs {
buildResp, _ := client.ListOccurrences(ctx,
&gpb.ListOccurrencesRequest{
Parent: fmt.Sprintf("projects/%s", *projectID),
Filter: fmt.Sprintf(`kind="BUILD_DETAILS" AND
resourceUrl=%q`, img),
})
// assume each build generates a unique container
image URI
build := buildResp.GetOccurrences()[0]
if time.Now().Sub(build.GetCreateTime().AsTime()) >
*buildHorizon {
log.Infof("Workload running image %s is
exceeding build horizon policy of %q.", img, *buildHorizon)
}
}
43. Proprietary + Confidential
Proprietary + Confidential
Find all
workloads that
exceed build
horizon
occResp, _ := client.ListOccurrences(ctx,
&gpb.ListOccurrencesRequest{
Parent: fmt.Sprintf("projects/%s", *projectID),
Filter: `kind = "DEPLOYABLE"`,
})
for _, occ := range
occResp.GetOccurrences() {
if occ.GetDeployment().GetUndeployTime() == nil {
// The workload is still running.
runningImgs[occ.GetResourceUri()] = true
}
}
for _, img := range runningImgs {
buildResp, _ := client.ListOccurrences(ctx,
&gpb.ListOccurrencesRequest{
Parent: fmt.Sprintf("projects/%s", *projectID),
Filter: fmt.Sprintf(`kind="BUILD_DETAILS" AND
resourceUrl=%q`, img),
})
// assume each build generates a unique container
image URI
build := buildResp.GetOccurrences()[0]
if time.Now().Sub(build.GetCreateTime().AsTime()) >
*buildHorizon {
log.Infof("Workload running image %s is
exceeding build horizon policy of %q.", img, *buildHorizon)
44. Proprietary + Confidential
Proprietary + Confidential
Find all
workloads that
exceed build
horizon
occResp, _ := client.ListOccurrences(ctx,
&gpb.ListOccurrencesRequest{
Parent: fmt.Sprintf("projects/%s", *projectID),
Filter: `kind = "DEPLOYABLE"`,
})
for _, occ := range occResp.GetOccurrences() {
if occ.GetDeployment().GetUndeployTime() == nil {
// The workload is still running.
runningImgs[occ.GetResourceUri()] = true
}
}
for _, img := range runningImgs {
buildResp, _ := client.ListOccurrences(ctx,
&gpb.ListOccurrencesRequest{
Parent: fmt.Sprintf("projects/%s", *projectID),
Filter: fmt.Sprintf(`kind="BUILD_DETAILS" AND
resourceUrl=%q`, img),
})
// assume each build generates a unique container
image URI
build := buildResp.GetOccurrences()[0]
if time.Now().Sub(build.GetCreateTime().AsTime()) >
*buildHorizon {
log.Infof("Workload running image %s is
exceeding build horizon policy of %q.", img, *buildHorizon)
}
}
45. Proprietary + Confidential
Proprietary + Confidential
Find all
workloads that
exceed build
horizon
occResp, _ := client.ListOccurrences(ctx,
&gpb.ListOccurrencesRequest{
Parent: fmt.Sprintf("projects/%s", *projectID),
Filter: `kind = "DEPLOYABLE"`,
})
for _, occ := range occResp.GetOccurrences() {
if
occ.GetDeployment().GetUndeployTime() ==
nil {
// The workload is still running.
runningImgs[occ.GetResourceUri(
)] = true
}
}
for _, img := range runningImgs {
buildResp, _ := client.ListOccurrences(ctx,
&gpb.ListOccurrencesRequest{
Parent: fmt.Sprintf("projects/%s", *projectID),
Filter: fmt.Sprintf(`kind="BUILD_DETAILS" AND
resourceUrl=%q`, img),
})
// assume each build generates a unique container
image URI
build := buildResp.GetOccurrences()[0]
46. Proprietary + Confidential
Proprietary + Confidential
Find all
workloads that
exceed build
horizon
occResp, _ := client.ListOccurrences(ctx,
&gpb.ListOccurrencesRequest{
Parent: fmt.Sprintf("projects/%s", *projectID),
Filter: `kind = "DEPLOYABLE"`,
})
for _, occ := range occResp.GetOccurrences() {
if occ.GetDeployment().GetUndeployTime() == nil {
// The workload is still running.
runningImgs[occ.GetResourceUri()] = true
}
}
for _, img := range runningImgs {
buildResp, _ := client.ListOccurrences(ctx,
&gpb.ListOccurrencesRequest{
Parent: fmt.Sprintf("projects/%s", *projectID),
Filter: fmt.Sprintf(`kind="BUILD_DETAILS" AND
resourceUrl=%q`, img),
})
// assume each build generates a unique container
image URI
build := buildResp.GetOccurrences()[0]
if time.Now().Sub(build.GetCreateTime().AsTime()) >
*buildHorizon {
log.Infof("Workload running image %s is
exceeding build horizon policy of %q.", img, *buildHorizon)
}
}
47. Proprietary + Confidential
Proprietary + Confidential
Find all
workloads that
exceed build
horizon
occResp, _ := client.ListOccurrences(ctx,
&gpb.ListOccurrencesRequest{
Parent: fmt.Sprintf("projects/%s", *projectID),
Filter: `kind = "DEPLOYABLE"`,
})
for _, occ := range occResp.GetOccurrences() {
if occ.GetDeployment().GetUndeployTime() == nil {
// The workload is still running.
runningImgs[occ.GetResourceUri()] = true
}
}
for _, img := range runningImgs {
buildResp, _ := client.ListOccurrences(ctx,
&gpb.ListOccurrencesRequest{
Parent: fmt.Sprintf("projects/%s", *projectID),
Filter: fmt.Sprintf(`kind="BUILD_DETAILS" AND
resourceUrl=%q`, img),
})
// assume each build generates a unique container
image URI
build := buildResp.GetOccurrences()[0]
if time.Now().Sub(build.GetCreateTime().AsTime()) >
*buildHorizon {
log.Infof("Workload running image %s is
exceeding build horizon policy of %q.", img, *buildHorizon)
}
}
48. Proprietary + Confidential
Proprietary + Confidential
Find all
workloads that
exceed build
horizon
occResp, _ := client.ListOccurrences(ctx,
&gpb.ListOccurrencesRequest{
Parent: fmt.Sprintf("projects/%s", *projectID),
Filter: `kind = "DEPLOYABLE"`,
})
for _, occ := range occResp.GetOccurrences() {
if occ.GetDeployment().GetUndeployTime() == nil {
// The workload is still running.
runningImgs[occ.GetResourceUri()] = true
}
}
for _, img := range runningImgs {
buildResp, _ := client.ListOccurrences(ctx,
&gpb.ListOccurrencesRequest{
Parent: fmt.Sprintf("projects/%s", *projectID),
Filter: fmt.Sprintf(`kind="BUILD_DETAILS" AND
resourceUrl=%q`, img),
})
// assume each build generates a unique container
image URI
build := buildResp.GetOccurrences()[0]
if time.Now().Sub(build.GetCreateTime().AsTime()) >
*buildHorizon {
log.Infof("Workload running image %s is
exceeding build horizon policy of %q.", img, *buildHorizon)
}
}
49. Proprietary + Confidential
Proprietary + Confidential
Find all
workloads that
exceed build
horizon
occResp, _ := client.ListOccurrences(ctx,
&gpb.ListOccurrencesRequest{
Parent: fmt.Sprintf("projects/%s", *projectID),
Filter: `kind = "DEPLOYABLE"`,
})
for _, occ := range occResp.GetOccurrences() {
if occ.GetDeployment().GetUndeployTime() == nil {
// The workload is still running.
runningImgs[occ.GetResourceUri()] = true
}
}
for _, img := range runningImgs {
buildResp, _ :=
client.ListOccurrences(ctx,
&gpb.ListOccurrencesRequest{
Parent:
fmt.Sprintf("projects/%s", *projectID),
Filter:
fmt.Sprintf(`kind="BUILD_DETAILS" AND
resourceUrl=%q`, img),
})
50. Proprietary + Confidential
Proprietary + Confidential
Find all
workloads that
exceed build
horizon
occResp, _ := client.ListOccurrences(ctx,
&gpb.ListOccurrencesRequest{
Parent: fmt.Sprintf("projects/%s", *projectID),
Filter: `kind = "DEPLOYABLE"`,
})
for _, occ := range occResp.GetOccurrences() {
if occ.GetDeployment().GetUndeployTime() == nil {
// The workload is still running.
runningImgs[occ.GetResourceUri()] = true
}
}
for _, img := range runningImgs {
buildResp, _ := client.ListOccurrences(ctx,
&gpb.ListOccurrencesRequest{
Parent: fmt.Sprintf("projects/%s", *projectID),
Filter: fmt.Sprintf(`kind="BUILD_DETAILS" AND
resourceUrl=%q`, img),
})
// assume each build generates a unique container
image URI
build := buildResp.GetOccurrences()[0]
if time.Now().Sub(build.GetCreateTime().AsTime()) >
*buildHorizon {
log.Infof("Workload running image %s is
exceeding build horizon policy of %q.", img, *buildHorizon)
}
}
51. Proprietary + Confidential
Proprietary + Confidential
Find all
workloads that
exceed build
horizon
occResp, _ := client.ListOccurrences(ctx,
&gpb.ListOccurrencesRequest{
Parent: fmt.Sprintf("projects/%s", *projectID),
Filter: `kind = "DEPLOYABLE"`,
})
for _, occ := range occResp.GetOccurrences() {
if occ.GetDeployment().GetUndeployTime() == nil {
// The workload is still running.
runningImgs[occ.GetResourceUri()] = true
}
}
…
// assume each build generates a unique container image
URI
build := buildResp.GetOccurrences()[0]
if
time.Now().Sub(build.GetCreateTime().
AsTime()) > *buildHorizon {
log.Infof("Workload running
image %s is exceeding build horizon
policy of %q.", img, *buildHorizon)
}
}
52. Software Supply Chains Solutions
Automated test,
scan, analysis
Deploy
checks
Production
Build &
Deploy
��
Build process
Universal Artifact Metadata
56. Software Supply Chains Solutions
Automated test,
scan, analysis
Deploy
checks
Production
Build &
Deploy
��
Build process
Universal Artifact Metadata
57. spdx.dev
Open standard for communicating software bill of material
information, including components, licenses, copyrights, and
security references
Software Bill of
Materials
58. Software Supply Chains Solutions
Automated test,
scan, analysis
Deploy
checks
Production
Build &
Deploy
��
Build process
Universal Artifact Metadata
62. Proprietary + Confidential
Secure builds and supply chain
01
04
03
Some Open Problems (not a complete list)
05
Supply chain integrity
Data quality in vulnerability scanning
Security and integrity in OSS
02 Compliance