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

Admission Controller (Webhook) for Akri Configuration(s) #206

Merged
merged 83 commits into from
Feb 24, 2021
Merged
Show file tree
Hide file tree
Changes from 18 commits
Commits
Show all changes
83 commits
Select commit Hold shift + click to select a range
64b306d
Helm Chart updates
DazWilkin Jan 14, 2021
0c8ce09
Add 'webhooks' to the project
DazWilkin Jan 14, 2021
9e42e89
Commented Helm Chart `webhook-configuration`
DazWilkin Jan 14, 2021
080530d
Template `webhook-configuration`
DazWilkin Jan 14, 2021
3f43c1e
Webhook service
DazWilkin Jan 14, 2021
7c5e816
Dockerfile (draft)
DazWilkin Jan 14, 2021
b0e4af2
GitHub Action (draft)
DazWilkin Jan 14, 2021
562143d
Force build
DazWilkin Jan 14, 2021
492b555
Trying again
DazWilkin Jan 14, 2021
a288591
And again
DazWilkin Jan 14, 2021
a483149
Added GHCR secret to fork
DazWilkin Jan 14, 2021
3c33620
Grrr
DazWilkin Jan 14, 2021
21ffa76
Grrr
DazWilkin Jan 14, 2021
1117b5c
Issue w/ GitHub Action build
DazWilkin Jan 14, 2021
b6eca93
Undo
DazWilkin Jan 14, 2021
4174259
Consistency
DazWilkin Jan 14, 2021
50c4c28
Revised Rust Webhook to not require these
DazWilkin Jan 14, 2021
01d4ded
Preliminary README
DazWilkin Jan 14, 2021
6478473
Update `version.sh` and run `./version.sh -u -s`
DazWilkin Jan 15, 2021
f717254
Added `webhook-configuration`
DazWilkin Jan 15, 2021
530b436
Does this resolve Helm Linting concern?
DazWilkin Jan 15, 2021
801d3f0
r/AMD32V7/AMR32V7
DazWilkin Jan 15, 2021
2761bde
Are these required?
DazWilkin Jan 15, 2021
fe3d133
Follow pattern
DazWilkin Jan 15, 2021
5dd09a2
Follow Akri pattern
DazWilkin Jan 15, 2021
596c39b
r/webhook-configuration/webhookConfiguration
DazWilkin Jan 15, 2021
0d40538
correct path references
DazWilkin Jan 15, 2021
e11f5cd
Merge branch 'main' into webhook-configuration
DazWilkin Jan 15, 2021
106c27d
Cross-build Rust
DazWilkin Jan 15, 2021
1ccac5c
Exceptions no longer required
DazWilkin Jan 15, 2021
acc8cd8
Assume `./target/release/webhook-configuration`
DazWilkin Jan 15, 2021
2b37785
Expose x-plat targets to docker
DazWilkin Jan 15, 2021
16b6513
Omission
DazWilkin Jan 15, 2021
b0538f3
Improve handling of flags
DazWilkin Jan 15, 2021
60f2581
Tidy
DazWilkin Jan 15, 2021
cc4640b
Correct indendation
DazWilkin Jan 16, 2021
5e1c340
Version bump
DazWilkin Jan 16, 2021
ec75674
Update `CHANGELOG`
DazWilkin Jan 16, 2021
8340bfc
`cargo.lock` versions now bumped too
DazWilkin Jan 19, 2021
8ab5bbb
Temporarily (!) bumping build timeouts
DazWilkin Jan 19, 2021
93158ce
Corrected component reference
DazWilkin Jan 19, 2021
7ee4e38
Missed `build-arg=CROSS_BUILD_TARGET=...`
DazWilkin Jan 19, 2021
f98b976
Avoid Helm issue with un-`named` `Lists`
DazWilkin Jan 20, 2021
365dd09
Revert `CHANGELOG`
DazWilkin Jan 27, 2021
b32f50f
Added unit tests
DazWilkin Feb 3, 2021
9387a04
Filters Akri Configuration manifest so that it validates
DazWilkin Feb 4, 2021
cc52a7b
Added test for filtered `generation`
DazWilkin Feb 4, 2021
42d6dd8
Added test for extended (complete) Config
DazWilkin Feb 5, 2021
28f0f3d
To avoid GitHub Actions build failure
DazWilkin Feb 8, 2021
999e827
End-to-End Webhook tests
DazWilkin Feb 8, 2021
7fe7a67
Integration tests require `actix-rt`
DazWilkin Feb 8, 2021
345700d
Merge branch 'main' into webhook-configuration
DazWilkin Feb 8, 2021
1ac3dc5
Include `webhook-configuration` container image
DazWilkin Feb 8, 2021
9ac2365
Learns all the things!
DazWilkin Feb 8, 2021
d7e0bbc
Typo
DazWilkin Feb 9, 2021
bf8e62c
Added `webhook` to `test-case`s
DazWilkin Feb 9, 2021
019709a
Removed `get_agent_and_controller` reference
DazWilkin Feb 9, 2021
8dbe9c4
Simplified Actions `matrix`; Updated Webhook certs
DazWilkin Feb 9, 2021
3588d13
Override `webhookConfiguration.image.tag` to `pr-amd64`
DazWilkin Feb 9, 2021
5e82996
Add debugging
DazWilkin Feb 9, 2021
03adc3e
Typo
DazWilkin Feb 9, 2021
ff846af
sudo'ing `kubectl` commands
DazWilkin Feb 9, 2021
d5c9eab
Try subprocess; reduce test matrix
DazWilkin Feb 10, 2021
2a79b16
Add `shell=True`
DazWilkin Feb 10, 2021
6a811fb
More `describe`s
DazWilkin Feb 10, 2021
79b0a49
Correct `kubectl --selector` commands
DazWilkin Feb 10, 2021
effd520
Reflect r/ENTRYPOINT/CMD in Dockerfile
DazWilkin Feb 10, 2021
5dc2623
Try matrix
DazWilkin Feb 10, 2021
c27b5f7
Debugging Kubenernetes 1.16
DazWilkin Feb 10, 2021
56ee546
Additional MicroK8s 1.16+1.17 and debugging
DazWilkin Feb 10, 2021
206336f
Generate: `*-webhook-log` from GitHub Actions
DazWilkin Feb 11, 2021
2e5a53a
Add some debugging statements
DazWilkin Feb 11, 2021
b1e3e90
K8s 1.16 expects AdmissionReview to be v1beta1
DazWilkin Feb 11, 2021
56e9584
Checking K3s 1.16+1.17
DazWilkin Feb 11, 2021
a720388
Ordering may be significant
DazWilkin Feb 11, 2021
67e2ccc
Reverted
DazWilkin Feb 12, 2021
26de1fe
Don't delete CRDs; Remove redundant debugging
DazWilkin Feb 12, 2021
53bb1bc
Limit to distro-versions known to work for E2Es
DazWilkin Feb 12, 2021
5f4a640
Merge branch 'main' into webhook-configuration
DazWilkin Feb 22, 2021
600b93a
Bumped OpenAPI-generated sources due to Akri security audit issues
DazWilkin Feb 23, 2021
438061a
Documents `run-webook.py`
DazWilkin Feb 24, 2021
58c876f
Typo
DazWilkin Feb 24, 2021
6fc791e
`expect` only when providing useful message
DazWilkin Feb 24, 2021
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
36 changes: 36 additions & 0 deletions .github/workflows/build-webhook-configuration.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
name: Build Webhook Configuration

on:
push:
# branches:
# - main
# paths:
# - webhooks/validating/configuration/**
# - version.txt

env:
AKRI_COMPONENT: webhook-configuration

jobs:
test:
runs-on: ubuntu-latest
steps:
- name: checkout
uses: actions/checkout@v2
- name: setup
uses: docker/setup-buildx-action@v1
- name: login
uses: docker/login-action@v1
with:
registry: ghcr.io
username: ${{ secrets.crUsername }}
password: ${{ secrets.crPassword }}
- name: build-push
uses: docker/build-push-action@v2
with:
push: true
build-args: |
COMPONENT=${{ matrix.component }}
context: .
file: ./build/containers/Dockerfile.webhook-configuration
tags: ghcr.io/${{ secrets.crUsername }}/${{ env.AKRI_COMPONENT }}:v1
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,4 @@
h2 = { git = "https://github.com/kate-goldenring/h2", branch = "master"}

[workspace]
members = ["shared", "controller", "agent", "samples/brokers/udev-video-broker"]
members = ["shared", "controller", "agent", "samples/brokers/udev-video-broker", "webhooks/validating/configuration"]
54 changes: 54 additions & 0 deletions build/containers/Dockerfile.webhook-configuration
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
ARG WEBHOOK="webhooks/validating/configuration"
bfjelds marked this conversation as resolved.
Show resolved Hide resolved

FROM rustlang/rust:nightly-slim as builder

ARG WEBHOOK

RUN apt-get update && \
apt-get install -y --no-install-recommends \
libssl-dev \
pkg-config

WORKDIR /akri

# For: akri_shared::akri::configuration::KubeAkriConfig;
COPY ./shared ./shared

RUN USER=root cargo new --bin ./${WEBHOOK}

# Saves repeatedly building the dependencies
# Because the project doesn't use main, add it here, purely as a throwaway
COPY ${WEBHOOK}/Cargo.toml ./${WEBHOOK}/Cargo.toml
RUN echo "fn main() {}" > ./${WEBHOOK}/src/main.rs
RUN cargo build --release --manifest-path=./${WEBHOOK}/Cargo.toml
RUN rm ./${WEBHOOK}/src/*.rs
RUN rm ./${WEBHOOK}/target/release/deps/webhook_configuration*

COPY ${WEBHOOK}/src/main.rs ./${WEBHOOK}/src
RUN cargo build --release --manifest-path=./${WEBHOOK}/Cargo.toml


FROM debian:buster-slim as runtime

ARG WEBHOOK

LABEL org.label-schema.docker.dockerfile="./Dockerfile" \
org.label-schema.url="https://github.com/deislabs/akri/" \
org.label-schema.vcs-ref=$VCS_REF \
org.label-schema.vcs-url="https://github.com/deislabs/akri.git" \
org.label-schema.vcs-type="Git"

WORKDIR /bin

# Copy from builder and rename to 'server'
COPY --from=builder /akri/${WEBHOOK}/target/release/webhook-configuration /server

RUN apt update \
&& apt install -y \
ca-certificates \
libssl-dev \
pkg-config \
&& rm -rf /var/lib/apt/lists/*

ENTRYPOINT ["/server"]
CMD ["--tls-crt-file=/path/to/crt","--tls-key-file=/path/to/key","--port=8443"]
kate-goldenring marked this conversation as resolved.
Show resolved Hide resolved
137 changes: 137 additions & 0 deletions deployment/helm/templates/webhook-configuration.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
{{- if .Values.rbac.enabled }}
bfjelds marked this conversation as resolved.
Show resolved Hide resolved
apiVersion: v1
kind: List
items:
- apiVersion: v1
kind: ServiceAccount
metadata:
name: {{ .Values.webhook-configuration.name }}
namespace: {{ .Release.Namespace }}
- apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: {{ .Values.webhook-configuration.name }}
namespace: {{ .Release.Namespace }}
rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["get"]
- apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: {{ .Values.webhook-configuration.name }}
namespace: {{ .Release.Namespace }}
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: {{ .Values.webhook-configuration.name }}
subjects:
- kind: ServiceAccount
name: {{ .Values.webhook-configuration.name }}
namespace: {{ .Release.Namespace }}
- apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ .Values.webhook-configuration.name }}
spec:
replicas: 1
selector:
matchLabels:
app: {{ .Values.webhook-configuration.name }}
template:
metadata:
labels:
app: {{ .Values.webhook-configuration.name }}
spec:
{{- if .Values.rbac.enabled }}
serviceAccountName: {{ .Values.webhook-configuration.name }}
{{- end }}
containers:
- name: webhook
{{- if .Values.useDevelopmentContainers }}
{{- if .Values.useLatestContainers }}
image: {{ printf "%s:latest-dev" .Values.webhook-configuration.image.repository | quote }}
{{- else }}
image: {{ printf "%s:%s" .Values.webhook-configuration.image.repository (default (printf "v%s-dev" .Chart.AppVersion) .Values.webhook-configuration.image.tag) | quote }}
{{- end }}
{{- else }}
{{- if .Values.useLatestContainers }}
image: {{ printf "%s:latest" .Values.webhook-configuration.image.repository | quote }}
{{- else }}
image: {{ printf "%s:%s" .Values.webhook-configuration.image.repository (default (printf "v%s" .Chart.AppVersion) .Values.webhook-configuration.image.tag) | quote }}
{{- end }}
{{- end }}
imagePullPolicy: {{ .Values.webhook-configuration.image.pullPolicy }}
args:
- --tls-crt-file=/secrets/tls.crt
- --tls-key-file=/secrets/tls.key
- --port=8443
volumeMounts:
- name: secrets
mountPath: /secrets
readOnly: true
volumes:
- name: secrets
secret:
secretName: {{ .Values.webhook-configuration.name }}
{{- with .Values.imagePullSecrets }}
imagePullSecrets:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- if .Values.webhook-configuration.allowOnControlPlane }}
tolerations:
{{- /* Allow this pod to run on the master. */}}
- key: node-role.kubernetes.io/master
effect: NoSchedule
{{- end }}
{{- if or .Values.webhook-configuration.linuxOnly .Values.webhook-configuration.onlyOnControlPlane .Values.webhook-configuration.nodeSelectors }}
nodeSelector:
{{- if .Values.webhook-configuration.nodeSelectors }}
{{- toYaml .Values.webhook-configuration.nodeSelectors | nindent 8 }}
{{- end }}
{{- if .Values.webhook-configuration.linuxOnly }}
"kubernetes.io/os": linux
{{- end }}
{{- if .Values.webhook-configuration.onlyOnControlPlane }}
node-role.kubernetes.io/master: ""
{{- end }}
{{- end }}
- apiVersion: v1
kind: Service
metadata:
name: {{ .Values.webhook-configuration.name }}
spec:
selector:
app: {{ .Values.webhook-configuration.name }}
ports:
- name: http
port: 443
targetPort: 8443
- apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingWebhookConfiguration
metadata:
name: {{ .Values.webhook-configuration.name }}
webhooks:
- name: {{ .Values.webhook-configuration.name }}.{{ .Release.Namespace }}.svc
clientConfig:
service:
name: {{ .Values.webhook-configuration.name }}
namespace: {{ .Release.Namespace }}
port: 443
path: "/validate"
caBundle: {{ required "please rerun helm install" .Values.webhook-configuration.caBundle }}
rules:
- operations:
- "CREATE"
- "UPDATE"
apiGroups:
- {{ .Values.crds.group }}
apiVersions:
- {{ .Values.crds.version }}
resources:
- "configurations"
scope: "*"
admissionReviewVersions:
- v1
sideEffects: None
{{- end }}
28 changes: 27 additions & 1 deletion deployment/helm/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -298,4 +298,30 @@ udev:
# targetPort is the service targetPort of the instance service
targetPort: 8083
# protocol is the service protocol of the instance service
protocol: TCP
protocol: TCP

# Admission Controllers (Webhooks)
webhook-configuration:
# enabled defines whether to apply the Akri Admission Controller (Webhook) for Akri Configurations
enabled: false
# name of the webhook
name: akri-webhook-configuration
# base64-encoded CA certificate (PEM) used by Kubernetes to validate the Webhook's certificate
caBundle: null
image:
# repository is the Akri Webhook for Configurations image reference
repository: ghcr.io/deislabs/akri/webhook-configuration
tag:
# pullPolicy is the Akri Controller pull policy
pullPolicy: Always
# onlyOnControlPlane dictates whether the Akri Controller will only run on nodes with
# the label with (key, value) of ("node-role.kubernetes.io/master", "")
onlyOnControlPlane: false
# allowOnControlPlane dictates whether a toleration will be added to allow to Akri Controller
# to run on the control plane node
allowOnControlPlane: true
# linuxOnly dictates whether the Akri Controller will only run on a linux node
linuxOnly: true
# nodeSelectors is the array of nodeSelectors used to target nodes for the Akri Controller to run on
# This can be set from the helm command line using `--set controller.nodeSelectors.label="value"`
nodeSelectors: {}
17 changes: 17 additions & 0 deletions webhooks/validating/configuration/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
[package]
name = "webhook-configuration"
version = "0.1.0"
authors = ["DazWilkin <[email protected]>"]
edition = "2018"

[dependencies]
actix = "0.10.0"
actix-web = { version = "3.3.2", features = ["openssl"] }
akri-shared = { path = "../../../shared" }
clap = "3.0.0-beta.2"
k8s-openapi = { version = "0.10.0", features = ["v1_18"] }
openapi = { git = "https://github.com/DazWilkin/openapi-admission-v1" }
openssl = "0.10"
rustls = "0.18.0"
serde = { version = "1.0.118", features = ["derive"] }
serde_json = "1.0.61"
70 changes: 70 additions & 0 deletions webhooks/validating/configuration/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
# Akri Admission Controller (Webhook) for validating Akri Configurations

This Admission Controller (Webhook) validates Akri Configuration files.

The HTTP service that implements the Webhook must be configured to use TLS. The Webhook expects its TLS certificate and private key to be stored within a Kubernetes [Secret](https://kubernetes.io/docs/concepts/configuration/secret/#tls-secrets).

It is recommended to use [`cert-manager`](https://cert-manager.io) in Kubernetes. `cert-manager` makes it easy to generate TLS certificates and private keys and, because it's a Kubernetes-native app, `cert-manager` stores these in Kubernetes Secrets. You may use a self-signed (!) CA with `cert-manager` and certificates signed by this CA will work with the Webhook.

If you wish to install the Webhook, before installing the Helm Chart for Akri, you will need to have PEM-encoded versions of CA certificate, Webhook certificate and private key. The Webhook handler expects a Secret, with the same name (!), containing its certificate and private key, to exist in the Namespace where it will be deployed.

If you're using `cert-manager` and have an `Issuer` called `ca`, you may generate a Secret for a Webhook called `${WEBHOOK}` in Namespace `${NAMESPACE}` with the following commands:

```bash
WEBHOOK="akri-webhook-configuration" # Default name if not provided
NAMESPACE="default"

echo "
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: ${WEBHOOK}
namespace: ${NAMESPACE}
spec:
secretName: ${WEBHOOK}
duration: 8760h
renewBefore: 720h
isCA: false
privateKey:
algorithm: RSA
encoding: PKCS1
size: 2048
usages:
- server auth
dnsNames:
- ${WEBHOOK}.${NAMESPACE}.svc
- ${WEBHOOK}.${NAMESPACE}.svc.cluster.local
issuerRef:
name: ca
kind: Issuer
group: cert-manager.io
" | kubectl apply --filename=-
```

> **NOTE** You must provide the above with a `${NAMESPACE}` even if the value is `default` so that it may construct qualified DNS for the Webhook Service.


When Kubernetes is configured to use the Webhook, it requires the base64-encoded PEM certificate of the CA. The CA certificate may be obtained from the Webhook's certificate using:

```bash
CABUNDLE=$(\
kubectl get secret/${WEBHOOK} \
--namespace=${NAMESPACE} \
--output=jsonpath="{.data.ca\.crt}") && echo ${CABUNDLE}
```

Now you may proceed to install the Helm Chart for Akri, enabling the Webhook and providing the `CABUNDLE`:

```bash
WEBHOOK=...
NAMESPACE=...
CABUNDLE=...

helm install webhook akri-helm-charts/akri-dev \
--namespace=${DEFAULT} \
--set=webhook.enabled=true \
--set=webhook.name=${WEBHOOK} \
--set=webhook.caBundle=${CABUNDLE} \
--set=webhook.image.repository=ghcr.io/deislabs/akri/webhook-configuration \
--set=webhook.image.tag=v1
```
Loading