Skip to content

Commit

Permalink
Initial work on k8s admission controller
Browse files Browse the repository at this point in the history
Signed-off-by: Zach Hill <[email protected]>
  • Loading branch information
zhill committed Dec 6, 2018
0 parents commit 727435b
Show file tree
Hide file tree
Showing 15 changed files with 561 additions and 0 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
.idea

8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# Anchore Charts

This is the repository backing the Anchore Chart Repository

To use charts in this repository, add it in helm:
`helm repo add anchore_stable https://anchore-charts.s3-website-us-west-2.amazonaws.com/stable`

`helm install anchore_stable/<chart>`
21 changes: 21 additions & 0 deletions test/anchore-admission-controller/.helmignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Patterns to ignore when building packages.
# This supports shell glob matching, relative path matching, and
# negation (prefixed with !). Only one pattern per line.
.DS_Store
# Common VCS dirs
.git/
.gitignore
.bzr/
.bzrignore
.hg/
.hgignore
.svn/
# Common backup files
*.swp
*.bak
*.tmp
*~
# Various IDEs
.project
.idea/
*.tmproj
12 changes: 12 additions & 0 deletions test/anchore-admission-controller/Chart.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
name: anchore-admission-controller
description: A kubernetes admission controller for validating and mutating webhooks that operates against Anchore Engine to make access decisions and annotations
apiVersion: v1
appVersion: "1.0"
version: 0.1.0
maintainers:
- name: zhill
email: [email protected]
- name: btodhunter
email: [email protected]
icon: https://anchore.com/wp-content/uploads/2016/08/anchore.png

Empty file.
5 changes: 5 additions & 0 deletions test/anchore-admission-controller/requirements.yaml.old
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#dependencies:
#- name: anchore-engine
# version: 0.9.x
# repository: https://kubernetes-charts.storage.googleapis.com/
# condition: anchoreEngine.enabled
31 changes: 31 additions & 0 deletions test/anchore-admission-controller/templates/NOTES.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
Anchore engine policy validator is now installed.

Create a validating webhook resources to start enforcement:

KUBE_CA=$(kubectl config view --minify=true --flatten -o json | jq '.clusters[0].cluster."certificate-authority-data"' -r)
cat > validating-webook.yaml <<EOF
apiVersion: admissionregistration.k8s.io/v1beta1
kind: ValidatingWebhookConfiguration
metadata:
name: {{ template "anchore-admission-controller.fullname" . }}.admission.anchore.io
webhooks:
- name: {{ template "anchore-admission-controller.fullname" . }}.admission.anchore.io
clientConfig:
service:
namespace: default
name: kubernetes
path: /apis/admission.anchore.io/v1beta1/imagechecks
caBundle: $KUBE_CA
rules:
- operations:
- CREATE
apiGroups:
- ""
apiVersions:
- "*"
resources:
- pods
failurePolicy: Fail
EOF

kubectl apply -f validating-webook.yaml
16 changes: 16 additions & 0 deletions test/anchore-admission-controller/templates/_helpers.tpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{{/* vim: set filetype=mustache: */}}
{{/*
Expand the name of the chart.
*/}}
{{- define "anchore-admission-controller.name" -}}
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}}
{{- end -}}

{{/*
Create a default fully qualified app name.
We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
*/}}
{{- define "anchore-admission-controller.fullname" -}}
{{- $name := default .Chart.Name .Values.nameOverride -}}
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}}
{{- end -}}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
apiVersion: batch/v1
kind: Job
metadata:
name: "{{ .Release.Name }}-init-ca"
labels:
app: {{ template "anchore-admission-controller.fullname" . }}
component: admission-server
annotations:
"helm.sh/hook": pre-install
"helm.sh/hook-delete-policy": hook-succeeded
spec:
template:
metadata:
labels:
app: {{ template "anchore-admission-controller.fullname" . }}
component: admission-server
spec:
serviceAccountName: {{ template "anchore-admission-controller.fullname" . }}-init-ca
restartPolicy: OnFailure
volumes:
- name: init-ca-script
configMap:
name: {{.Release.Name}}-init-ca
containers:
- name: create-ca
image: "cfssl/cfssl:latest"
command:
- bash
- -xe
- /scripts/init-ca.sh
volumeMounts:
- name: init-ca-script
mountPath: /scripts
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: {{.Release.Name}}-init-ca
labels:
app: {{ template "anchore-admission-controller.fullname" . }}
annotations:
"helm.sh/hook": pre-install
"helm.sh/hook-weight": "-5"
data:
init-ca.sh: |-
#!/bin/bash -xe
# Adapted from https://github.com/openshift/kubernetes-namespace-reservation/blob/master/hack/install-kube.sh
apt-get update && apt-get install -y jq
curl -LO https://storage.googleapis.com/kubernetes-release/release/$(curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt)/bin/linux/amd64/kubectl
chmod +x ./kubectl
mv ./kubectl /usr/bin
# creates a client CA, args are sudo, dest-dir, ca-id, purpose
# purpose is dropped in after "key encipherment", you usually want
# '"client auth"'
# '"server auth"'
# '"client auth","server auth"'
function kube::util::create_signing_certkey {
local sudo=$1
local dest_dir=$2
local id=$3
local purpose=$4
# Create client ca
${sudo} /bin/bash -e <<EOF
rm -f "${dest_dir}/${id}-ca.crt" "${dest_dir}/${id}-ca.key"
openssl req -x509 -sha256 -new -nodes -days 365 -newkey rsa:2048 -keyout "${dest_dir}/${id}-ca.key" -out "${dest_dir}/${id}-ca.crt" -subj "/C=xx/ST=x/L=x/O=x/OU=x/CN=ca/emailAddress=x/"
echo '{"signing":{"default":{"expiry":"43800h","usages":["signing","key encipherment",${purpose}]}}}' > "${dest_dir}/${id}-ca-config.json"
EOF
}
# signs a serving certificate: args are sudo, dest-dir, ca, filename (roughly), subject, hosts...
function kube::util::create_serving_certkey {
local sudo=$1
local dest_dir=$2
local ca=$3
local id=$4
local cn=${5:-$4}
local hosts=""
local SEP=""
shift 5
while [ -n "${1:-}" ]; do
hosts+="${SEP}\"$1\""
SEP=","
shift 1
done
${sudo} /bin/bash -e <<EOF
cd ${dest_dir}
echo '{"CN":"${cn}","hosts":[${hosts}],"key":{"algo":"rsa","size":2048}}' | cfssl gencert -ca=${ca}.crt -ca-key=${ca}.key -config=${ca}-config.json - | cfssljson -bare serving-${id}
mv "serving-${id}-key.pem" "serving-${id}.key"
mv "serving-${id}.pem" "serving-${id}.crt"
rm -f "serving-${id}.csr"
EOF
}
which jq &>/dev/null || { echo "Please install jq (https://stedolan.github.io/jq/)."; exit 1; }
which cfssljson &>/dev/null || { echo "Please install cfssljson (https://github.com/cloudflare/cfssl))."; exit 1; }
# create necessary TLS certificates:
# - a local CA key and cert
# - a webhook server key and cert signed by the local CA
rm -rf ./_output/
CERT_DIR=_output/tmp/certs
mkdir -p "${CERT_DIR}"
kube::util::create_signing_certkey "" "${CERT_DIR}" serving '"server auth"'
# create webhook server key and cert
kube::util::create_serving_certkey "" "${CERT_DIR}" "serving-ca" {{ template "anchore-admission-controller.fullname" . }}.{{ .Release.Namespace }}.svc "{{ template "anchore-admission-controller.fullname" . }}.{{ .Release.Namespace }}.svc" "{{ template "anchore-admission-controller.fullname" . }}.{{ .Release.Namespace }}.svc"
cat > secret.yaml <<EOF
apiVersion: v1
kind: Secret
metadata:
name: {{ template "anchore-admission-controller.name" . }}
type: kubernetes.io/tls
data:
tls.crt: TLS_SERVING_CERT
tls.key: TLS_SERVING_KEY
EOF
sed "s/TLS_SERVING_CERT/$(base64 ${CERT_DIR}/serving-{{ template "anchore-admission-controller.fullname" . }}.{{ .Release.Namespace }}.svc.crt | tr -d '\n')/g" secret.yaml |
sed "s/TLS_SERVING_KEY/$(base64 ${CERT_DIR}/serving-{{ template "anchore-admission-controller.fullname" . }}.{{ .Release.Namespace }}.svc.key | tr -d '\n')/g" | kubectl -n {{ .Release.Namespace }} apply -f -
cat > api-service.yaml <<EOF
apiVersion: apiregistration.k8s.io/v1beta1
kind: APIService
metadata:
name: {{ .Values.apiService.version }}.{{ .Values.apiService.group }}
spec:
caBundle: SERVICE_SERVING_CERT_CA
group: {{ .Values.apiService.group }}
groupPriorityMinimum: 1000
versionPriority: 15
service:
name: {{ template "anchore-admission-controller.fullname" . }}
namespace: {{ .Release.Namespace }}
version: {{ .Values.apiService.version }}
EOF
sed "s/SERVICE_SERVING_CERT_CA/$(base64 ${CERT_DIR}/serving-ca.crt | tr -d '\n')/g" api-service.yaml | kubectl -n {{ .Release.Namespace }} apply -f -
68 changes: 68 additions & 0 deletions test/anchore-admission-controller/templates/init-ca/rbac.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
apiVersion: v1
kind: ServiceAccount
metadata:
namespace: {{ .Release.Namespace }}
annotations:
"helm.sh/hook": pre-install
"helm.sh/hook-weight": "-6"
name: {{ template "anchore-admission-controller.fullname" . }}-init-ca
---
kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
namespace: {{ .Release.Namespace }}
name: {{ template "anchore-admission-controller.fullname" . }}-init-ca
annotations:
"helm.sh/hook": pre-install
"helm.sh/hook-weight": "-6"
rules:
- apiGroups: [""] # "" indicates the core API group
resources: ["secrets", "deployments"]
verbs: ["get", "patch", "create"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
annotations:
"helm.sh/hook": pre-install
"helm.sh/hook-weight": "-6"
namespace: {{ .Release.Namespace }}
name: extension-{{ template "anchore-admission-controller.fullname" . }}-init-ca-admin
roleRef:
kind: Role
apiGroup: rbac.authorization.k8s.io
name: {{ template "anchore-admission-controller.fullname" . }}-init-ca
subjects:
- kind: ServiceAccount
name: {{ template "anchore-admission-controller.fullname" . }}-init-ca
---
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: {{ template "anchore-admission-controller.fullname" . }}-init-ca-cluster
annotations:
"helm.sh/hook": pre-install
"helm.sh/hook-weight": "-6"
rules:
- apiGroups: ["admissionregistration.k8s.io"]
resources: ["validatingwebhookconfigurations"]
verbs: ["get", "watch", "list", "create", "update", "patch"]
- apiGroups: ["apiregistration.k8s.io"]
resources: ["apiservices"]
verbs: ["get", "watch", "list", "create", "update", "patch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
annotations:
"helm.sh/hook": pre-install
"helm.sh/hook-weight": "-6"
name: extension-{{ template "anchore-admission-controller.fullname" . }}-init-ca-cluster
roleRef:
kind: ClusterRole
apiGroup: rbac.authorization.k8s.io
name: {{ template "anchore-admission-controller.fullname" . }}-init-ca-cluster
subjects:
- kind: ServiceAccount
namespace: {{ .Release.Namespace }}
name: {{ template "anchore-admission-controller.fullname" . }}-init-ca
82 changes: 82 additions & 0 deletions test/anchore-admission-controller/templates/rbac.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
apiVersion: v1
kind: List
metadata:
items:

# Service Account with which the controller operates
- apiVersion: v1
kind: ServiceAccount
metadata:
name: {{ template "anchore-admission-controller.fullname" . }}

# Allow delegate authentication and authorization to the service account
- apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: auth-delegator-{{ template "anchore-admission-controller.fullname" . }}-default
roleRef:
kind: ClusterRole
apiGroup: rbac.authorization.k8s.io
name: system:auth-delegator
subjects:
- kind: ServiceAccount
namespace: {{ .Release.Namespace }}
name: {{ template "anchore-admission-controller.fullname" . }}

- apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: auth-delegator-{{ template "anchore-admission-controller.fullname" . }}-admin
roleRef:
kind: ClusterRole
apiGroup: rbac.authorization.k8s.io
name: cluster-admin
subjects:
- kind: ServiceAccount
namespace: {{ .Release.Namespace }}
name: {{ template "anchore-admission-controller.fullname" . }}

# to let the admission server read the namespace reservations
- apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
annotations:
name: {{ template "anchore-admission-controller.fullname" . }}
rules:
- apiGroups:
- {{ .Values.apiService.group }}
resources:
- {{ template "anchore-admission-controller.fullname" . }}
verbs:
- get
- list
- watch
- create

# to let the admission server read the namespace reservations
- apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: {{ template "anchore-admission-controller.fullname" . }}-default
roleRef:
kind: ClusterRole
apiGroup: rbac.authorization.k8s.io
name: namespace-reservation-{{ template "anchore-admission-controller.fullname" . }}
subjects:
- kind: ServiceAccount
namespace: {{ .Release.Namespace }}
name: {{ template "anchore-admission-controller.fullname" . }}

# to read the config for terminating authentication
- apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
namespace: kube-system
name: extension-{{ template "anchore-admission-controller.fullname" . }}-authentication-reader-default
roleRef:
kind: Role
apiGroup: rbac.authorization.k8s.io
name: extension-api{{ template "anchore-admission-controller.fullname" . }}-authentication-reader
subjects:
- kind: ServiceAccount
name: {{ template "anchore-admission-controller.fullname" . }}
Loading

0 comments on commit 727435b

Please sign in to comment.