Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add documentation and examples #7

Merged
merged 8 commits into from
Nov 15, 2019
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# STAGE 1
FROM golang:1.13.4 as builder

WORKDIR /go/github.com/jetstack/preflight

# Run a dependency resolve with just the go mod files present for
# better caching
COPY ./go.mod .
COPY ./go.sum .

RUN go mod download

## Bring in everything else and build an amd64 image
COPY . .
RUN GOOS=linux GOARCH=amd64 go install .

# STAGE 2
# Use a distroless nonroot base image for just our executable
FROM gcr.io/distroless/base:nonroot
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of using multi stage builds, which don't play well with go's module caching, consider using 'go_container.sh' from 'kind' which makes use of a docker volume to cache go dependencies, giving you host-like performance 😀 this works okay, but is just a bit slow for iterative development: https://github.com/kubernetes-sigs/kind/blob/master/hack/go_container.sh

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will do in a separate PR: #8

COPY --from=builder /go/bin/preflight /bin/preflight
ADD ./preflight-packages /preflight-packages
ADD ./examples/pods.preflight.yaml /etc/preflight/preflight.yaml
ENTRYPOINT ["preflight"]
CMD ["check", "--config-file", "/etc/preflight/preflight.yaml"]
9 changes: 9 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ COMMIT:=$(shell git rev-list -1 HEAD)
DATE:=$(shell date -uR)
GOVERSION:=$(shell go version | awk '{print $$3 " " $$4}')

IMAGE_NAME?=preflight:latest
OVERLAY?=sample

define LDFLAGS
-X "github.com/jetstack/preflight/cmd.PreflightVersion=$(VERSION)" \
-X "github.com/jetstack/preflight/cmd.Platform=$(GOOS)/$(GOARCH)" \
Expand Down Expand Up @@ -33,3 +36,9 @@ lint: vet

clean:
cd $(ROOT_DIR) && rm -rf ./builds

build-docker-image:
docker build -t $(IMAGE_NAME) .

push-docker-image:
docker push $(IMAGE_NAME)
88 changes: 86 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,86 @@
# preflight
Automatically perform Kubernetes cluster configuration checks using Open Policy Agent (OPA)
# Jetstack Preflight

Preflight is a tool to automatically perform Kubernetes cluster configuration checks using [Open Policy Agent (OPA)](https://www.openpolicyagent.org/).

<!-- markdown-toc start - Don't edit this section. Run M-x markdown-toc-refresh-toc -->
**Table of Contents**

- [Jetstack Preflight](#jetstack-preflight)
- [Background](#background)
- [Preflight Packages](#preflight-packages)
- [Install Preflight](#install-preflight)
- [Use Preflight locally](#use-preflight-locally)
- [Get periodic reports by running Preflight as a CronJob](#get-periodic-reports-by-running-preflight-as-a-cronjob)

<!-- markdown-toc end -->


## Background

Preflight was originally designed to automate Jetstack's
production readiness assessments.
These are consulting sessions in which a Jetstack engineer inspects a customer's
cluster to suggest improvements and identify configuration issues.
The product of this assessment is a report
which describes any problems and offers remediation advice.

While these assessments have provided a lot of value to many customers,
with a complex system like Kubernetes its hard to thoroughly check everything.
Automating the checks allows them to be more comprehensive and much faster.

The automation also allows the checks to be run repeatedly,
meaning they can be deployed in-cluster to provide continuous configuration checking.

This enables new interesting use cases as policy compliance audits.

Jetstack plans to offer Preflight as a subscription service for customers,
and to assist Customer Reliability Engineers (CREs) in keeping clusters running smoothly.

## Preflight Packages

Policies for cluster configuration are encoded into "Preflight Packages".

You can find some examples in [./preflight-packages](./preflight-packages) and you can also [write your own Preflight Packages](./docs/how_to_write_packages.md).

Preflight Packages are a very thin wrapper around OPA's policies. A package is made of [Rego](https://www.openpolicyagent.org/docs/latest/#rego) files (OPA's high-level declarative language) and a *Policy Manifest*.

The *Policy Manifest* is a YAML file intended to add metadata to the rules, so the tool can display useful information when a rule doesn't pass.

Since the logic in these packages is just Rego, you can add tests to your policies and use OPA's command line to run them (see [OPA Policy Testing tutorial](https://www.openpolicyagent.org/docs/latest/policy-testing/)).

Additionally, Preflight has a built-in linter for packages:

```
preflight package lint <path to package>
```

## Install Preflight

You can compile Preflight by running `make build`. It will create the binary in `builds/preflight`.


## Use Preflight locally

Create your `preflight.yaml` configuration file (you can take inspiration from the ones in `./examples`).

Run Preflight (by default it looks for `./preflight.yaml`)

```
preflight check
```

You can try `./examples/pods.preflight.yaml` without having to change a line, if you have your kubeconfig* (~/.kube/config) pointing to a working cluster.

```
preflight check --config-file=./examples/pods.preflight.yaml
```

You will see a CLI formatted report if everything goes well. Also, you will get a JSON report in `./output`.

If you want to visualice the report in your browser, you can access [preflight.jetstack.io](https://preflight.jetstack.io/) and load the JSON report. **This is a static website. Your report is not being uploaded to any server. Everything happens in your browser.**

You can give it a try without even running the tool, since we provide some report examples ([gke.json](./examples/reports/gke.json), [pods.json](./examples/reports/pods.json)) ready to be loaded in [preflight.jetstack.io](https://preflight.jetstack.io/).

## Get periodic reports by running Preflight as a CronJob

See [Run Preflight In-Cluster](./docs/preflight-in-cluster.md).
4 changes: 4 additions & 0 deletions deployment/kubernetes/base/00-namespace.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
apiVersion: v1
kind: Namespace
metadata:
name: preflight
77 changes: 77 additions & 0 deletions deployment/kubernetes/base/01-rbac.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
apiVersion: policy/v1beta1
kind: PodSecurityPolicy
metadata:
name: jetstack-preflight
annotations:
seccomp.security.alpha.kubernetes.io/allowedProfileNames: 'docker/default,runtime/default'
apparmor.security.beta.kubernetes.io/allowedProfileNames: 'runtime/default'
seccomp.security.alpha.kubernetes.io/defaultProfileName: 'runtime/default'
apparmor.security.beta.kubernetes.io/defaultProfileName: 'runtime/default'
spec:
privileged: false
# Required to prevent escalations to root.
allowPrivilegeEscalation: false
# This is redundant with non-root + disallow privilege escalation,
# but we can provide it for defense in depth.
requiredDropCapabilities:
- ALL
# Allow core volume types.
volumes:
- 'configMap'
- 'secret'
hostNetwork: false
hostIPC: false
hostPID: false
runAsUser:
# Require the container to run without root privileges.
rule: 'MustRunAsNonRoot'
seLinux:
# This policy assumes the nodes are using AppArmor rather than SELinux.
rule: 'RunAsAny'
supplementalGroups:
rule: 'MustRunAs'
ranges:
# Forbid adding the root group.
- min: 1
max: 65535
fsGroup:
rule: 'MustRunAs'
ranges:
# Forbid adding the root group.
- min: 1
max: 65535
readOnlyRootFilesystem: true
---
apiVersion: v1
kind: ServiceAccount
metadata:
namespace: preflight
name: preflight
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: list-pods-global
rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["list"]
- apiGroups: ['policy']
resources: ['podsecuritypolicies']
verbs: ['use']
resourceNames:
- jetstack-preflight
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: preflight-list-pods-global
namespace: preflight
subjects:
- kind: ServiceAccount
name: preflight
namespace: preflight
roleRef:
kind: ClusterRole
name: list-pods-global
apiGroup: rbac.authorization.k8s.io
47 changes: 47 additions & 0 deletions deployment/kubernetes/base/02-cronjob.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
apiVersion: batch/v1beta1
kind: CronJob
metadata:
name: preflight
namespace: preflight
labels:
app.kubernetes.io/name: preflight
app.kubernetes.io/version: master
app.kubernetes.io/part-of: jetstack-subscription
spec:
schedule: "0 */1 * * *"
concurrencyPolicy: Forbid
jobTemplate:
metadata:
labels:
app.kubernetes.io/name: preflight
app.kubernetes.io/version: master
spec:
template:
spec:
serviceAccountName: preflight
restartPolicy: Never
containers:
- name: preflight
image: jetstack/preflight:latest
imagePullPolicy: Always
resources:
requests:
cpu: 100m
memory: 50Mi
limits:
cpu: 100m
memory: 50Mi
volumeMounts:
- name: config
mountPath: /etc/preflight
readOnly: true
- name: gcs-credentials
mountPath: /var/run/secrets/preflight
readOnly: true
volumes:
- name: config
configMap:
name: preflight-config
- name: gcs-credentials
secret:
secretName: gcs-credentials
4 changes: 4 additions & 0 deletions deployment/kubernetes/base/kustomization.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
resources:
- 00-namespace.yaml
- 01-rbac.yaml
- 02-cronjob.yaml
1 change: 1 addition & 0 deletions deployment/kubernetes/overlays/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
credentials.json
14 changes: 14 additions & 0 deletions deployment/kubernetes/overlays/sample/custom-image.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# Change the CronJob to use a custom image
apiVersion: batch/v1beta1
kind: CronJob
metadata:
name: preflight
spec:
jobTemplate:
spec:
template:
spec:
containers:
- name: preflight
# You can change this to use an image of your choice.
image: eu.gcr.io/jetstack-preflight/preflight-cli:latest
14 changes: 14 additions & 0 deletions deployment/kubernetes/overlays/sample/kustomization.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
bases:
- ../../base/
configMapGenerator:
- name: preflight-config
namespace: preflight
files:
- preflight.yaml
secretGenerator:
- name: gcs-credentials
namespace: preflight
files:
- credentials.json
patchesStrategicMerge:
- custom-image.yaml
22 changes: 22 additions & 0 deletions deployment/kubernetes/overlays/sample/preflight.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
cluster-name: mycluster

data-gatherers:
k8s/pods:
kubeconfig: {}

package-sources:
- type: local
dir: /preflight-packages/

enabled-packages:
- "jetstack.io/pods"

outputs:
- type: gcs
format: json
bucket-name: preflight-results
credentials-path: /var/run/secrets/preflight/credentials.json
- type: gcs
format: html
bucket-name: preflight-results
credentials-path: /var/run/secrets/preflight/credentials.json
28 changes: 28 additions & 0 deletions docs/datagatherers/gke.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# GKE data gatherer

It pulls information about one cluster from the GKE API.

## Configuration

[Here](../../examples/gke.preflight.yaml) you have a sample configuration file setting up the GKE data gatherer.

You have to set these parameters in the configuration:

- **project:** the ID of your Google Cloud Platform project.
- **zone:** the compute zone where your cluster is running.
- **cluster:** the name of your GKE cluster.
- **credentials** *optional* **:** path to a file containing valid credentials for your cluster. Useful if you want to configure a separate service account. If not specified, it will attept to use Workload Identity. If you run Preflight locally on your machine, you can just run `gcloud auth application-default login`

## Data

The output of the GKE data gatherer follows this format:

```json
{
"Cluster": {...}
}
```

The `Cluster` property is a JSON representation of [google.golang.org/api/container/v1#Cluster](https://godoc.org/google.golang.org/api/container/v1#Cluster).

> Tip: Use the 'intermediate' output format to get the raw output from the data gatherer. You can use that try your rego rules.
17 changes: 17 additions & 0 deletions docs/datagatherers/k8s_pods.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# k8s/pods data gatherer

It pulls information about the Pods running in a cluster.

## Configuration

[Here](../../examples/pods.preflight.yaml) you have a sample configuration file setting up the k8s/pods data gatherer.

You just have to set the `kubeconfig` parameter in the configuration. It should point to your kubeconfig* file.

Preflight will use the context that is active in that *kubeconfig*.

## Data

The output of the k8s/pods data gatherer is a JSON representation of a [PodList](https://godoc.org/k8s.io/api/core/v1#PodList).

> Tip: Use the 'intermediate' output format to get the raw output from the data gatherer. You can use that try your rego rules.
3 changes: 3 additions & 0 deletions docs/how_to_write_packages.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# How to write Preflight Packages

> TODO
Loading