Gatekeeper is a customizable admission webhook for Kubernetes, which allows you to configure policy over what resources can be created in the cluster. In particular, we can use Gatekeeper to add policy to Shipwright Build
s. In this example, you can see how you can use a policy to control what source repositories Shipwright is allowed to build, so that you can have more control over what code executes inside your cluster.
Unless you are able to build images without root access in the build-process, there are risks to building arbitrary Open Container Initiative (OCI) images within your cluster. Because of these risks, an organization may want to limit builds to trusted sources, such as specific github organizations or an internally hosted git server. This is an example of how that can be configured using Gatekeeper.
If you do not have Gatekeeper installed already, see install instructions here. These examples were tested with version 3.4.
At the time of writing 3.5 has an open issue with parameters, but there is an open PR to fix it.
Build
resourcesEither Create or append to your gatekeeper-system config. This configmap specifies all resources that Gatekeeper will monitor.
apiVersion: config.gatekeeper.sh/v1alpha1
kind: Config
metadata:
name: config
namespace: "gatekeeper-system"
spec:
sync:
syncOnly:
- group: "shipwright.io"
version: "v1alpha1"
kind: "Build"
This constraint template will let us create our ShipwrightAllowlist
; in the parameters to the ShipwrightAllowlist
we will specify the allowed sources, and this constraint template will apply the logic.
This constraint template is based on this example in the Gatekeeper docs.
apiVersion: templates.gatekeeper.sh/v1beta1
kind: ConstraintTemplate
metadata:
name: shipwrightallowlist
spec:
crd:
spec:
names:
kind: ShipwrightAllowlist
targets:
- target: admission.k8s.gatekeeper.sh
rego: |
package shipwrightallowlist
violation[{"msg": msg}] {
input.review.object.kind == "Build"
repo_url := input.review.object.spec.source.url
# Remove the protocol from the url
repo = strings.replace_n({
"https://": "",
"http://": "",
"git://": "",
"ssh://": "",
}, repo_url)
# is the repo in the allowlist?
allowlist := [
good | source = input.parameters.allowedsources[_];
good = startswith(repo, source)
]
not any(allowlist)
msg := sprintf("The Build repo has not been pre-approved: %v. Allowed sources are: %v", [repo, input.parameters.allowedsources])
}
The ConstraintTemplate we created above creates a new Custom Resource Definition (CRD) called ShipwrightAllowlist
. With this CRD created, we can define a list of allowed sources to build from!
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: ShipwrightAllowlist
metadata:
name: shipwrightallowlist
spec:
match:
kinds:
- apiGroups: ["shipwright.io"]
kinds: ["Build"]
parameters:
# Remember to terminate the sources with a `/` at the end.
# Don't include the protocol. I.e.
# GOOD: "github.com/shipwright-io/"
# BAD: "https://github.com/shipwright-io"
allowedsources:
- "github.com/shipwright-io/"
This Build
below will be created, as is under the github.com/shipwright-io/
organization, so it is allowed by our policy.
# sample-go-build.yaml
apiVersion: shipwright.io/v1alpha1
kind: Build
metadata:
name: buildah-golang-build
spec:
source:
# We trust github.com/shipwright-io/
url: https://github.com/shipwright-io/sample-go
contextDir: docker-build
strategy:
name: buildah
kind: ClusterBuildStrategy
dockerfile: Dockerfile
output:
image: image-registry.openshift-image-registry.svc:5000/build-examples/taxi-app
Create it
$ kubectl apply -f sample-go-build.yaml
build.shipwright.io/buildah-golang-build created
However the build below will not be created, as it belongs to github.com/docker-library/
# hello-world-build.yaml
apiVersion: shipwright.io/v1alpha1
kind: Build
metadata:
name: kaniko-hello-world-build
annotations:
build.shipwright.io/build-run-deletion: "true"
spec:
source:
# Not an approved source!!!
url: https://github.com/docker-library/hello-world
contextDir: .
strategy:
name: kaniko
kind: ClusterBuildStrategy
dockerfile: Dockerfile.build
output:
image: image-registry.openshift-image-registry.svc:5000/build-examples/hello-world
Attempting to create this will yield an error.
$ kubectl apply -f hello-world-build.yaml
Error from server ([shipwrightallowlist] The Build repo has not been pre-approved: github.com/docker-library/hello-world. Allowed sources are: ["github.com/shipwright-io/"]): error when creating "hello-world-build.yaml": admission webhook "validation.gatekeeper.sh" denied the request: [shipwrightallowlist] The Build repo has not been pre-approved: github.com/docker-library/hello-world. Allowed sources are: ["github.com/shipwright-io/"]
With just a few yaml files, we can add layers of protection to the cluster. You can checkout Gatekeeper to learn more about the Kubernetes admission webhook, and also checkout Open Policy Agent which powers Gatekeeper and provides the policy language.