Skip to content

Commit fdaff86

Browse files
jeff-mccoyYrrepNoj
andauthored
Zarf Agent mutating webhook (zarf-dev#306)
- Introduce mutating webhook (zarf agent) - Mutate podSpec image paths - Mutate podSpec imagePullSecret - Mutate Flux GitRepository URL - Mutate Flux GitRepository secret - Add dev makefile targets for image rebuilds - Add manual github action for building a new zarf agent image - Update Big Bang example package 1.28 -> 1.33 - Migrate EFK -> PLG for Big Bang example - Fix OPA Gatekeeper failures on KIND clusters - Add Zarf Agent ADR Co-authored-by: Jon Perry <yrrepnoj@gmail.com>
1 parent e779f34 commit fdaff86

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

70 files changed

+1055
-1149
lines changed

.github/workflows/build-rust-injector.yml

-1
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@ jobs:
2626
- name: "Install cosign"
2727
uses: sigstore/cosign-installer@v2.1.0
2828

29-
3029
- name: "Install Rust And Build"
3130
uses: gmiam/rust-musl-action@v1.1.1
3231
with:

.github/workflows/build-zarf-agent.yml

+25-4
Original file line numberDiff line numberDiff line change
@@ -12,29 +12,50 @@ on:
1212
default: "master"
1313

1414
jobs:
15-
build-injector:
15+
build-agent:
1616
runs-on: ubuntu-latest
1717
steps:
18+
- name: "Install GoLang"
19+
uses: actions/setup-go@v2
20+
with:
21+
go-version: 1.18.x
22+
1823
- name: "Checkout Repo"
1924
uses: actions/checkout@v2
2025
with:
2126
ref: ${{ github.event.inputs.branchName }}
27+
28+
- name: "Setup caching"
29+
uses: actions/cache@v3
30+
with:
31+
path: |
32+
~/.cache/go-build
33+
~/go/pkg/mod
34+
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
35+
restore-keys: |
36+
${{ runner.os }}-go-
2237
2338
- name: "Install cosign"
2439
uses: sigstore/cosign-installer@v2.1.0
2540

26-
- name: Set up Docker Buildx
41+
- name: "Set up Docker Buildx"
2742
id: buildx
2843
uses: docker/setup-buildx-action@v2
2944

30-
- name: Login to Docker Hub
45+
- name: "Login to Docker Hub"
3146
uses: docker/login-action@v1
3247
with:
3348
username: ${{ secrets.DOCKERHUB_USERNAME }}
3449
password: ${{ secrets.DOCKERHUB_TOKEN }}
3550

51+
- name: "Build zarf binaries"
52+
run: make build-cli-linux
53+
54+
- name: "Rename binaries for packaging"
55+
run: mv build/zarf build/zarf-linux-amd64 && mv build/zarf-arm build/zarf-linux-arm64
56+
3657
- name: "Build and Publish the Image"
37-
run: buildx build --push --platform linux/arm64/v8,linux/amd64 --tag defenseunicorns/zarf-agent:${{ github.event.inputs.versionTag }} .
58+
run: docker buildx build --push --platform linux/arm64/v8,linux/amd64 --tag defenseunicorns/zarf-agent:${{ github.event.inputs.versionTag }} .
3859

3960
- name: "Sign the Image"
4061
run: cosign sign --key awskms:///${{ secrets.COSIGN_AWS_KMS_KEY }} -a release-engineer=https://github.com/${{ github.actor }} -a version=${{ github.event.inputs.versionTag }} defenseunicorns/zarf-agent:${{ github.event.inputs.versionTag }}

.github/workflows/release.yml

+15
Original file line numberDiff line numberDiff line change
@@ -13,18 +13,33 @@ jobs:
1313
uses: actions/setup-go@v2
1414
with:
1515
go-version: 1.18.x
16+
1617
- name: Checkout Repo
1718
uses: actions/checkout@v2
19+
20+
- name: "Setup caching"
21+
uses: actions/cache@v3
22+
with:
23+
path: |
24+
~/.cache/go-build
25+
~/go/pkg/mod
26+
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
27+
restore-keys: |
28+
${{ runner.os }}-go-
29+
1830
- name: Build Things For Release
1931
run: make build-cli init-package
32+
2033
- name: Set AWS Credentials
2134
uses: aws-actions/configure-aws-credentials@v1
2235
with:
2336
aws-access-key-id: ${{ secrets.AWS_GOV_ACCESS_KEY_ID }}
2437
aws-secret-access-key: ${{ secrets.AWS_GOV_SECRET_ACCESS_KEY }}
2538
aws-region: us-gov-west-1
39+
2640
- name: Push Release Artifacts to S3 Bucket
2741
run: aws s3 cp build s3://zarf-public/release/${{ github.ref_name }} --region us-gov-west-1 --recursive
42+
2843
- name: Create a Release For This Tag
2944
uses: softprops/action-gh-release@v1
3045
if: startsWith(github.ref, 'refs/tags/')

.github/workflows/test-k3d.yml

+14
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,26 @@ jobs:
1010
uses: actions/setup-go@v2
1111
with:
1212
go-version: 1.18.x
13+
1314
- name: "Checkout Repo"
1415
uses: actions/checkout@v2
16+
17+
- name: "Setup caching"
18+
uses: actions/cache@v3
19+
with:
20+
path: |
21+
~/.cache/go-build
22+
~/go/pkg/mod
23+
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
24+
restore-keys: |
25+
${{ runner.os }}-go-
26+
1527
- name: "Build CLI"
1628
run: make build-cli-linux
29+
1730
- name: "Make Packages"
1831
run: make init-package package-example-game package-example-data-injection package-example-gitops-data package-example-compose
32+
1933
- name: "Run Tests"
2034
# NOTE: This test run will create its own K3d cluster. A single cluster will be used throughout the test run.
2135
run: TESTDISTRO=k3d make test-e2e

.github/workflows/test-k3s.yml

+14
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,26 @@ jobs:
1010
uses: actions/setup-go@v2
1111
with:
1212
go-version: 1.18.x
13+
1314
- name: "Checkout Repo"
1415
uses: actions/checkout@v2
16+
17+
- name: "Setup caching"
18+
uses: actions/cache@v3
19+
with:
20+
path: |
21+
~/.cache/go-build
22+
~/go/pkg/mod
23+
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
24+
restore-keys: |
25+
${{ runner.os }}-go-
26+
1527
- name: "Build CLI"
1628
run: make build-cli-linux
29+
1730
- name: "Make Packages"
1831
run: make init-package package-example-game package-example-data-injection package-example-gitops-data package-example-compose
32+
1933
- name: "Run Tests"
2034
# NOTE: "PATH=$PATH" preserves the default user $PATH. This is needed to maintain the version of go installed
2135
# in a previous step. This test run will use Zarf to create a K3s cluster, and a brand new cluster will be

.github/workflows/test-kind.yml

+15
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,29 @@ jobs:
1010
uses: actions/setup-go@v2
1111
with:
1212
go-version: 1.18.x
13+
1314
- name: "Checkout Repo"
1415
uses: actions/checkout@v2
16+
1517
- name: "Create k8s Kind Cluster"
1618
uses: helm/kind-action@v1.2.0
19+
20+
- name: "Setup caching"
21+
uses: actions/cache@v3
22+
with:
23+
path: |
24+
~/.cache/go-build
25+
~/go/pkg/mod
26+
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
27+
restore-keys: |
28+
${{ runner.os }}-go-
29+
1730
- name: "Build CLI"
1831
run: make build-cli-linux
32+
1933
- name: "Make Packages"
2034
run: make init-package package-example-game package-example-data-injection package-example-gitops-data package-example-compose
35+
2136
- name: "Run Tests"
2237
# NOTE: We want to test providing a cluster to the test framework so this one creates its own KinD cluster
2338
# rather than having the test suite do it. The K3d tests do a self-provisioned cluster and the K3s tests

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ test/tf/public-ec2-instance/.terraform
2222
terraform.tfstate
2323
terraform.tfstate.backup
2424
.terraform.lock.hcl
25+
cosign.key
2526
.zarf*
2627
zarf-pki
2728
.scratch/

Dockerfile

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
FROM scratch
2+
ARG TARGETARCH
3+
4+
ADD "build/zarf-linux-$TARGETARCH" /zarf
5+
EXPOSE 8443
6+
7+
ENV USER=zarf
8+
9+
CMD ["/zarf", "agent", "-l=trace"]

Makefile

+25-5
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ ifneq ($(UNAME_S),Linux)
1616
endif
1717
endif
1818

19+
CLI_VERSION := $(if $(shell git describe --tags), $(shell git describe --tags), "UnknownVersion")
20+
BUILD_ARGS := -s -w -X 'github.com/defenseunicorns/zarf/src/config.CLIVersion=$(CLI_VERSION)'
1921
.DEFAULT_GOAL := help
2022

2123
.PHONY: help
@@ -38,17 +40,35 @@ vm-destroy: ## Destroy the VM
3840
clean: ## Clean the build dir
3941
rm -rf build
4042

41-
build-cli-linux: build-injector-registry ## Build the Linux CLI
42-
cd src && $(MAKE) build
43+
build-cli-linux-amd: build-injector-registry
44+
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags="$(BUILD_ARGS)" -o build/zarf src/main.go
4345

44-
build-cli-mac: build-injector-registry ## Build the Mac CLI
45-
cd src && $(MAKE) build-mac
46+
build-cli-linux-arm: build-injector-registry
47+
CGO_ENABLED=0 GOOS=linux GOARCH=arm64 go build -ldflags="$(BUILD_ARGS)" -o build/zarf-arm src/main.go
4648

47-
build-cli: build-injector-registry build-cli-linux build-cli-mac ## Build the CLI
49+
build-cli-mac-intel: build-injector-registry
50+
GOOS=darwin GOARCH=amd64 go build -ldflags="$(BUILD_ARGS)" -o build/zarf-mac-intel src/main.go
51+
52+
build-cli-mac-apple: build-injector-registry
53+
GOOS=darwin GOARCH=arm64 go build -ldflags="$(BUILD_ARGS)" -o build/zarf-mac-apple src/main.go
54+
55+
build-cli-linux: build-cli-linux-amd build-cli-linux-arm
56+
57+
build-cli: build-cli-linux-amd build-cli-linux-arm build-cli-mac-intel build-cli-mac-apple ## Build the CLI
4858

4959
build-injector-registry:
5060
cd src/injector/stage2 && $(MAKE) build-bootstrap-registry
5161

62+
# Inject and deploy a new dev version of zarf agent for testing (should have an existing zarf agent deployemt)
63+
# @todo: find a clean way to support Kind or k3d: k3d image import $(tag)
64+
dev-agent-image:
65+
$(eval tag := defenseunicorns/dev-zarf-agent:$(shell date +%s))
66+
$(eval arch := $(shell uname -m))
67+
CGO_ENABLED=0 GOOS=linux go build -o build/zarf-linux-$(arch) src/main.go
68+
DOCKER_BUILDKIT=1 docker build --tag $(tag) --build-arg TARGETARCH=$(arch) . && \
69+
kind load docker-image zarf-agent:$(tag) && \
70+
kubectl -n zarf set image deployment/agent-hook server=$(tag)
71+
5272
init-package: ## Create the zarf init package, macos "brew install coreutils" first
5373
$(ZARF_BIN) package create --confirm --architecture amd64
5474
$(ZARF_BIN) package create --confirm --architecture arm64

README.md

+1-2
Original file line numberDiff line numberDiff line change
@@ -287,7 +287,7 @@ Zarf is written entirely in [go](https://go.dev/), except for a single 400Kb bin
287287
- The OCI Registries used are both from [Docker](https://github.com/distribution/distribution)
288288
- Currently, the Registry and Git servers _are not HA_, see [#375](https://github.com/defenseunicorns/zarf/issues/376) and [#376](https://github.com/defenseunicorns/zarf/issues/376) for discussion on this
289289
- To avoid TLS issues, Zarf binds to `127.0.0.1:31999` on each node as a [NodePort](https://kubernetes.io/docs/concepts/services-networking/service/#type-nodeport) to allow all nodes to access the pod(s) in the cluster
290-
- Until [#306](https://github.com/defenseunicorns/zarf/pull/306) is merged, during helm install/upgrade a [Helm PostRender](https://helm.sh/docs/topics/advanced/#post-rendering) function is called to mutate images and [ImagePullSecrets](https://kubernetes.io/docs/concepts/containers/images/#specifying-imagepullsecrets-on-a-pod) so the deployed resources use the NodePort binding
290+
- A [mutating webhook](https://kubernetes.io/docs/reference/access-authn-authz/extensible-admission-controllers/) we call the Zarf Agent handles updating pod's [ImagePullSecrets](https://kubernetes.io/docs/concepts/containers/images/#specifying-imagepullsecrets-on-a-pod) so the deployed resources use the NodePort binding
291291
- Zarf uses a custom injector system to bootstrap a new cluster. See the PR [#329](https://github.com/defenseunicorns/zarf/pull/329) and [ADR](docs/adr/0003-image-injection-into-remote-clusters-without-native-support.md) for more details on how we came to this solution. The general steps are listed below:
292292
- Get a list of images in the cluster
293293
- Attempt to create an ephemeral pod using an image from the list
@@ -301,5 +301,4 @@ Zarf is written entirely in [go](https://go.dev/), except for a single 400Kb bin
301301
### Zarf Architecture
302302
![Architecture Diagram](./docs/architecture.drawio.svg)
303303

304-
305304
[Source DrawIO](docs/architecture.drawio.svg)

docs/adr/0005-mutating-webhook.md

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# 5. Mutating Webhook
2+
3+
Date: 2022-05-18
4+
5+
## Status
6+
7+
Accepted
8+
9+
## Context
10+
11+
Currently Zarf leverages [Helm Post Rendering](https://helm.sh/docs/topics/advanced/#post-rendering) to mutate image paths and secrets for K8s to use the internal [Zarf Registry](../../packages/zarf-registry/README.md). This works well for simple K8s deployments where Zarf is performing the actual manifest apply but fails when using a secondary gitops tools suchs as [Flux](https://github.com/fluxcd/flux2), [ArgoCD](https://argo-cd.readthedocs.io/en/stable/), etc. At that point, Zarf is unable to provide mutation and it is dependent on the package author to do the mutations themselves using rudimentary templating. Further, this issue also exists when for CRDs that references the [git server](../../packages/gitea/README.md). A `zarf prepare` command was added previously to make this less painful, but it still requires additional burden on package authors to do something we are able to prescribe in code.
12+
13+
## Decision
14+
15+
A [mutating webhook](https://kubernetes.io/docs/reference/access-authn-authz/extensible-admission-controllers/) is standard practice in K8s and there [are a lot of them](https://kubernetes.io/docs/reference/access-authn-authz/admission-controllers/#what-does-each-admission-controller-do). Using the normal Zarf componenet structure and deployment strategy we can leverage a mutating webhook to perform automatic imagePullSecret binding and image path updates as well as add additional as-needed mutations such as updating the [GitRepository](https://fluxcd.io/docs/components/source/gitrepositories/) CRD with the appropriate secret and custom URL for the git server if someone is using Flux.
16+
17+
## Consequences
18+
19+
While deploying the webhook will greatly reduce the package development burden, the nature of how helm manages resources still means we will have to be careful how we apply secrets that could collide with secrets deployed by helm with other tools. Additionally, to keep the webhook simple we are foregoing any side-effects in this iteration such as creating secrets on-demand in a namespace as it is created. Adding side effects carries with it the need to roll those back on failure, handle additional RBAC in the cluster and integrate with the K8s API in the webhook. Therefore, some care will have to be taken for now with how registry and git secrets are generated in a namespace. For example, in the case of [Big Bang](https://repo1.dso.mil/platform-one/big-bang/bigbang) these secrets can be created by those helm charts if we pass in the proper configuration.
20+
21+
Another benefit of this approach is another layer security for Zarf clusters. The Zarf Agent will act as an intermediary not allowing images not in the Zarf Registry or git repos not stored in the internal git server.

docs/architecture.drawio.svg

+1-1
Loading

docs/components.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ Zarf's work necessitates that some components are "always on" (a.k.a. required &
1818
| | Description |
1919
| ----------------------- | -------------------------------------------------------------------------------------------------------------------- |
2020
| container-seed-registry | Adds a container registry so Zarf can bootstrap itself into the cluster. |
21-
| container-registry | Adds a container registry service&mdash;[docker registry](https://docs.docker.com/registry/)&mdash;into the cluster. |
21+
| zarf-registry | Adds a container registry service&mdash;[docker registry](https://docs.docker.com/registry/)&mdash;into the cluster. |
2222

2323
&nbsp;
2424

examples/README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ To test create a virtual area to test all examples, you can run `make all` or `m
1212

1313
| Example | Description |
1414
|------------------------------------------------------------------|-------------|
15-
| [big-bang](./big-bang/README.md) | Demo BigBang v1.28.0 with all of its core services |
15+
| [big-bang](./big-bang/README.md) | Demo BigBang v1.33.0 with all of its core services |
1616
| [composable-packages](./composable-packages/README.md) | Demo building packages using components from other packages |
1717
| [data-injection](./data-injection/README.md) | Demo injecting data into a pod running on cluster |
1818
| [game](./game/README.md) | Demo deploying old-school DOS games |

examples/big-bang/kustomization/git-secret.yaml

-9
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,9 @@
11
bases:
2-
- git::https://repo1.dso.mil/platform-one/big-bang/bigbang.git/base?ref=tags/1.28.0
2+
- git::https://repo1.dso.mil/platform-one/big-bang/bigbang.git/base?ref=tags/1.33.0
33

44
configMapGenerator:
55
- name: common
66
namespace: bigbang
77
behavior: merge
88
files:
99
- values.yaml
10-
11-
resources:
12-
- git-secret.yaml
13-
14-
patchesStrategicMerge:
15-
- |-
16-
apiVersion: source.toolkit.fluxcd.io/v1beta1
17-
kind: GitRepository
18-
metadata:
19-
name: bigbang
20-
namespace: bigbang
21-
spec:
22-
url: http://zarf-gitea-http.zarf.svc.cluster.local:3000/zarf-git-user/mirror__repo1.dso.mil__platform-one__big-bang__bigbang.git
23-
secretRef:
24-
name: zarf-git-secret

0 commit comments

Comments
 (0)