Skip to content

Commit

Permalink
init: 0/1
Browse files Browse the repository at this point in the history
  • Loading branch information
yashvardhan-kukreja committed Apr 3, 2021
0 parents commit bf7a029
Show file tree
Hide file tree
Showing 16 changed files with 642 additions and 0 deletions.
1 change: 1 addition & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
bin/
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
bin/

31 changes: 31 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
FROM golang:1.16 AS builder

LABEL maintainer="yashvardhan-kukreja"

RUN mkdir -p /export/kube-bench

RUN mkdir -p /kube-bench-exporter
WORKDIR /kube-bench-exporter

ENV GO111MODULE=on

COPY go.mod .
COPY go.sum .

RUN go get -d ./...

COPY . .

RUN CGO_ENABLED=0 go build -o /bin/kube-bench-exporter -v .

# Packaging stage
FROM alpine

LABEL maintainer="yashvardhan-kukreja"

COPY --from=builder /bin/kube-bench-exporter /bin/kube-bench-exporter
COPY --from=builder /etc/passwd /etc/passwd

USER 10001

ENTRYPOINT ["/bin/kube-bench-exporter"]
21 changes: 21 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
MIT License

Copyright (c) 2021 Yashvardhan Kukreja

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
27 changes: 27 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
GOOS ?= $(shell go env GOOS)
GIT_VERSION := $(shell git describe --always --tags)
GIT_BRANCH := $(shell git branch | grep \* | cut -d ' ' -f2)
GIT_HASH := $(GIT_BRANCH)/$(shell git log -1 --pretty=format:"%H")

REGISTRY?=yashvardhankukreja
REPO=$(REGISTRY)/kyverno
IMAGE_TAG?=$(GIT_VERSION)

IMAGE_NAME := kube-bench-exporter

docker-build-dev: fmt tidy vet
@docker build -t $(REPO)/$(IMAGE_NAME):$(IMAGE_TAG) .

tidy:
go mod tidy

vet:
go vet ./...

# Run go fmt against code
fmt:
gofmt -s -w .

fmt-check:
gofmt -s -l .

137 changes: 137 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
# kube-bench-exporter

Helps you to export your cluster's [kube-bench](https://github.com/aquasecurity/kube-bench) reports to remote targets like multiple Amazon S3 buckets, Azure blob storage, etc. in one-go with ease.

> Disclaimer: As of now, it can only export the kube-bench reports to S3 buckets. Functionality around exporting to Azure Blob Store is Work-in-progress.
## But why do we need this?

[Kube-bench](https://github.com/aquasecurity/kube-bench) runs CIS Benchmark Tests over your kubernetes cluster and exports the results to stdout but it doesn't have a native support to exporting those same results to a remote storage like an Amazon S3 bucket.

Hence, with this kube-bench-exporter you can do that and that too to multiple S3 buckets (or Azure Blob storage) concurrently in one-go.

## How does kube-bench-exporter work?
kube-bench-exporter works on the idea of sidecar pattern (kinda) where the sidecar container is the kube-bench-exporter container which is delegated to export your [kube-bench](https://github.com/aquasecurity/kube-bench) reports.

The main kube-bench container remains untouched and up-to-date with [kube-bench upstream](https://github.com/aquasecurity/kube-bench) and it simply runs the way it usually runs and exports the reports to a local .txt file via piping through stdout, and exits.

The only difference here is that, behind the scenes, the exported report will be mounted on a shared volume and this report will be read by our kube-bench-exporter sidecar container which it will upload to all the user-specified targets like S3 buckets.

And that too, it performs all the uploads to all the targets concurrently in one-go in a manner of Asynchronous fan-out instead of uploading to each target one-by-one. This is done to ensures two things:
- Avoiding convoy effect: If a certain upload is taking time to get processed, other uploads don't end up waiting for it to complete. (The go-scheduler context switches from the upload which is stuck to other upload tasks so as to ensure minimal amount of waiting time).
- Avoiding Single-point-of-failure: If a certain upload fails due to an error, then still other uploads asynchronously happen without being affected.

<p align="center" style="margin:20px 20px 20px 20px;"><img src="./assets/kube-bench-exporter-architecture.jpg" alt="architecture" /></p>


## How to use it?
Say, you want to export your kube-bench reports to 2 of your S3 buckets.
- First of all, create a secret containing credentials to an IAM user having enough access to upload files to those 2 S3 buckets.
```yaml
apiVersion: v1
kind: Secret
metadata:
name: aws-creds ### DO NOT TOUCH THIS
namespace: kube-system ### DO NOT TOUCH THIS
stringData:
AWS_ACCESS_KEY: <access key of your IAM user>
AWS_SECRET_ACCESS_KEY: <secret access key of your IAM user>
```
- Now, create a configmap containing the details of the S3 buckets in which you want your kube-bench reports to exported. kube-bench-exporter will export (fan-out) to all the below targets concurrently.
Say, there are two targets:
- A bucket named "bucket1" in the region "us-east-1" and you want the reports to be uploaded under the folder "sample-folder/kube-bench-reports".
- A bucket named "bucket2" in the region "ap-southeast-1" and you want the reports to be uploaded at root directory in that bucket.
```yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: target-config ### DO NOT TOUCH THIS
namespace: kube-system ### DO NOT TOUCH THIS
data:
target-config.yaml: | ### DO NOT TOUCH THIS
##### EDIT FROM HERE ON
[
{
"type": "s3",
"config": {
"bucket": "bucket1",
"region": "us-east-1",
"prefix": "sample-folder/kube-bench-reports"
}
},
{
"type": "s3",
"config": {
"bucket": "bucket2",
"region": "ap-southeast-1"
}
}
]
```
- Finally, use the following manifest for all the hardwork of running, generating and exporting your kube-bench reports periodically. You don't have to mess around with the below manifest. DO NOT TOUCH ANYTHING IN THE BELOW MANIFEST. Just update the field which are commented in the manifest with "UPDATE:"
```yaml
apiVersion: batch/v1
kind: Job
metadata:
name: kube-bench-exporter
namespace: kube-system
spec:
template:
spec:
hostPID: true
initContainers:
- name: kube-bench
image: aquasec/kube-bench:latest
command: ["/bin/sh"]
args: ["-c", "kube-bench -v 3 --logtostderr --benchmark eks-1.0 > /export/kube-bench/report.txt"] ## UPDATE: Tweak this according to the kind of k8s cluster you have. For reference: checkout https://github.com/aquasecurity/kube-bench#running-in-a-kubernetes-cluster
volumeMounts:
- name: var-lib-kubelet
mountPath: /var/lib/kubelet
readOnly: true
- name: etc-systemd
mountPath: /etc/systemd
readOnly: true
- name: etc-kubernetes
mountPath: /etc/kubernetes
readOnly: true
- name: published-report
mountPath: /export/kube-bench/
containers:
- name: kube-bench-exporter-sidecar
image: yashvardhankukreja/kube-bench-exporter:v0.0.1
imagePullPolicy: Never
envFrom:
- secretRef:
name: aws-creds
volumeMounts:
- name: published-report
mountPath: /export/kube-bench/
readOnly: true
- name: target-config
mountPath: /etc/config/
restartPolicy: Never
volumes:
- name: var-lib-kubelet
hostPath:
path: "/var/lib/kubelet"
- name: etc-systemd
hostPath:
path: "/etc/systemd"
- name: etc-kubernetes
hostPath:
path: "/etc/kubernetes"
- name: target-config
configMap:
name: target-config
- name: published-report
emptyDir: {}
```
**PS: Checkout [examples](./examples)**
## Output you will get
Say, the above Job ran on 16/09/2021, then the report will be uploaded to the user-provided targets with the name: `16-09-2021-kube-bench-report.txt`

Specifically, in the above example, the report will be at the following places:
- For "bucket1" (region: us-east-1) - `sample-folder/kube-bench-reports/16-09-2021-kube-bench-report.txt`
- For "bucket2" (region: ap-southeast-1) - `16-09-2021-kube-bench-report.txt` (in the root itself)


Binary file added assets/kube-bench-exporter-architecture.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
92 changes: 92 additions & 0 deletions examples/cronjob.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
apiVersion: v1
kind: Secret
metadata:
name: aws-creds ### DO NOT TOUCH THIS
namespace: kube-system ### DO NOT TOUCH THIS
stringData:
AWS_ACCESS_KEY: AKxxxxxxxxxxxxxxxxxxS
AWS_SECRET_ACCESS_KEY: uxxxxxxxxxxxxxxxxxxxxxxkn
---
apiVersion: v1
kind: ConfigMap
metadata:
name: target-config
namespace: kube-system
data:
target-config.json: |
[
{
"type": "s3",
"config": {
"bucket": "bucket1234",
"region": "us-east-1",
"prefix": "sample-folder/sub-folder"
}
},
{
"type": "s3",
"config": {
"bucket": "bucket5678",
"region": "us-east-1"
}
}
]
---
apiVersion: batch/v1beta1
kind: CronJob
metadata:
name: kube-bench-exporter
namespace: kube-system
spec:
schedule: "0 0 1 * *" ## run every month
jobTemplate:
spec:
template:
spec:
hostPID: true
initContainers:
- name: kube-bench
image: aquasec/kube-bench:latest
command: ["/bin/sh"]
args: ["-c", "kube-bench -v 3 --logtostderr --benchmark eks-1.0 > /export/kube-bench/report.txt"]
volumeMounts:
- name: var-lib-kubelet
mountPath: /var/lib/kubelet
readOnly: true
- name: etc-systemd
mountPath: /etc/systemd
readOnly: true
- name: etc-kubernetes
mountPath: /etc/kubernetes
readOnly: true
- name: published-report
mountPath: /export/kube-bench/
containers:
- name: kube-bench-exporter-sidecar
image: yashvardhankukreja/kube-bench-exporter:v0.0.1
envFrom:
- secretRef:
name: aws-creds
volumeMounts:
- name: published-report
mountPath: /export/kube-bench/
readOnly: true
- name: target-config
mountPath: /etc/config/
restartPolicy: Never
volumes:
- name: var-lib-kubelet
hostPath:
path: "/var/lib/kubelet"
- name: etc-systemd
hostPath:
path: "/etc/systemd"
- name: etc-kubernetes
hostPath:
path: "/etc/kubernetes"
- name: target-config
configMap:
name: target-config
- name: published-report
emptyDir: {}
---
Loading

0 comments on commit bf7a029

Please sign in to comment.