mirror of
https://github.com/kairos-io/kcrypt-challenger.git
synced 2025-09-04 16:21:05 +00:00
Compare commits
60 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
b5b4d0d042 | ||
|
8420155746 | ||
|
a9359bf713 | ||
|
b31467e925 | ||
|
c5dc8db56b | ||
|
a80703a556 | ||
|
0b6f771d32 | ||
|
72dd7d3e50 | ||
|
0619047a20 | ||
|
715664969a | ||
|
bcda5b5b38 | ||
|
b2a0330dd8 | ||
|
0b68d90081 | ||
|
40267d4c24 | ||
|
e0ae7a12a4 | ||
|
c2c50877da | ||
|
7a2627fcc8 | ||
|
a0c4462f99 | ||
|
145dd400b1 | ||
|
95dbb0d0be | ||
|
0e56e52cbf | ||
|
3a22134226 | ||
|
7b561efed8 | ||
|
6ff6262459 | ||
|
816013d33d | ||
|
8d0fb0148d | ||
|
ffd5f18bcf | ||
|
3b89def5b4 | ||
|
887d67907b | ||
|
b0a7aa5fdf | ||
|
40875bbae1 | ||
|
7166b14c7e | ||
|
9eb5d9b086 | ||
|
4da6a4f3b0 | ||
|
74fc9c62b4 | ||
|
f3f10b4919 | ||
|
3d4829859b | ||
|
8a17ff714c | ||
|
27114b8db8 | ||
|
1e3efb57cc | ||
|
0c236b6145 | ||
|
d390f77688 | ||
|
266c4f20e9 | ||
|
4c0b40d3a0 | ||
|
08bb62f94e | ||
|
0d3406fa7b | ||
|
1cd4d9a7af | ||
|
d875e54171 | ||
|
2967fb0a6c | ||
|
e9433d2ba7 | ||
|
7abdc7b092 | ||
|
9448ecdd54 | ||
|
d8cd48b411 | ||
|
43d629c974 | ||
|
b00d3af43b | ||
|
7d83e07b05 | ||
|
2fe3f3bc00 | ||
|
791d9dbb8b | ||
|
7dc1e39ac7 | ||
|
076a50b2e9 |
12
.github/ISSUE_TEMPLATE/file-issues-on-main-kairos-repo.md
vendored
Normal file
12
.github/ISSUE_TEMPLATE/file-issues-on-main-kairos-repo.md
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
---
|
||||
name: File issues on main Kairos repo
|
||||
about: Tell users to file their issues on the main Kairos repo
|
||||
title: ''
|
||||
labels: ''
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
:warning: All Kairos issues are tracked in our main repo, please file your issue there, thanks! :warning:
|
||||
|
||||
https://github.com/kairos-io/kairos/issues
|
114
.github/workflows/e2e-tests.yml
vendored
Normal file
114
.github/workflows/e2e-tests.yml
vendored
Normal file
@@ -0,0 +1,114 @@
|
||||
name: End to end tests
|
||||
on:
|
||||
push:
|
||||
paths-ignore:
|
||||
- 'README.md'
|
||||
branches:
|
||||
- main
|
||||
pull_request:
|
||||
paths-ignore:
|
||||
- 'README.md'
|
||||
|
||||
concurrency:
|
||||
group: ci-e2e-${{ github.head_ref || github.ref }}-${{ github.repository }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
build-iso:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v4
|
||||
with:
|
||||
go-version: ^1.20
|
||||
- name: Login to DockerHub
|
||||
uses: docker/login-action@v1
|
||||
with:
|
||||
username: ${{ secrets.DOCKER_LOGIN }}
|
||||
password: ${{ secrets.DOCKER_PASS }}
|
||||
- name: Install earthly
|
||||
uses: Luet-lab/luet-install-action@v1
|
||||
with:
|
||||
repository: quay.io/kairos/packages
|
||||
packages: utils/earthly
|
||||
- name: build iso
|
||||
run: |
|
||||
# Configure earthly to use the docker mirror in CI
|
||||
# https://docs.earthly.dev/ci-integration/pull-through-cache#configuring-earthly-to-use-the-cache
|
||||
mkdir -p ~/.earthly/
|
||||
cat << EOF > ~/.earthly/config.yml
|
||||
global:
|
||||
buildkit_additional_config: |
|
||||
[registry."docker.io"]
|
||||
mirrors = ["registry.docker-mirror.svc.cluster.local:5000"]
|
||||
[registry."registry.docker-mirror.svc.cluster.local:5000"]
|
||||
insecure = true
|
||||
EOF
|
||||
|
||||
earthly -P +iso
|
||||
- uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: challenger.iso.zip
|
||||
path: |
|
||||
build/*.iso
|
||||
e2e-tests:
|
||||
needs:
|
||||
- build-iso
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- label: "local-encryption"
|
||||
- label: "remote-auto"
|
||||
- label: "remote-static"
|
||||
- label: "remote-https-pinned"
|
||||
- label: "remote-https-bad-cert"
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v4
|
||||
with:
|
||||
go-version: ^1.20
|
||||
- name: Login to DockerHub
|
||||
uses: docker/login-action@v1
|
||||
with:
|
||||
username: ${{ secrets.DOCKER_LOGIN }}
|
||||
password: ${{ secrets.DOCKER_PASS }}
|
||||
- name: Install deps
|
||||
run: |
|
||||
curl -L https://github.com/mudler/luet/releases/download/0.33.0/luet-0.33.0-linux-amd64 -o luet
|
||||
chmod +x luet
|
||||
sudo mv luet /usr/bin/luet
|
||||
sudo mkdir -p /etc/luet/repos.conf.d/
|
||||
sudo luet repo add -y kairos --url quay.io/kairos/packages --type docker
|
||||
LUET_NOLOCK=true sudo -E luet install -y container/kubectl utils/k3d utils/earthly
|
||||
- name: Download artifacts
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: challenger.iso.zip
|
||||
- name: Run tests
|
||||
env:
|
||||
LABEL: ${{ matrix.label }}
|
||||
run: |
|
||||
sudo apt update && \
|
||||
sudo apt install -y git qemu-system-x86 qemu-utils swtpm jq make glibc-tools \
|
||||
openssl curl gettext ca-certificates curl gnupg lsb-release
|
||||
|
||||
export ISO=$PWD/$(ls *.iso)
|
||||
|
||||
# We run with sudo to be able to access /dev/kvm
|
||||
./scripts/e2e-tests.sh
|
||||
- uses: actions/upload-artifact@v3
|
||||
if: failure()
|
||||
with:
|
||||
name: ${{ matrix.label }}-test.logs.zip
|
||||
path: tests/**/logs/*
|
||||
if-no-files-found: warn
|
11
.github/workflows/image.yml
vendored
11
.github/workflows/image.yml
vendored
@@ -8,12 +8,17 @@ on:
|
||||
tags:
|
||||
- '*'
|
||||
|
||||
|
||||
concurrency:
|
||||
group: ci-image-${{ github.head_ref || github.ref }}-${{ github.repository }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
docker:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Prepare
|
||||
id: prep
|
||||
@@ -53,11 +58,11 @@ jobs:
|
||||
password: ${{ secrets.QUAY_PASSWORD }}
|
||||
|
||||
- name: Build
|
||||
uses: docker/build-push-action@v2
|
||||
uses: docker/build-push-action@v4
|
||||
with:
|
||||
builder: ${{ steps.buildx.outputs.name }}
|
||||
context: .
|
||||
file: ./Dockerfile
|
||||
platforms: linux/amd64,linux/arm64
|
||||
push: true
|
||||
tags: ${{ steps.prep.outputs.tags }}
|
||||
tags: ${{ steps.prep.outputs.tags }}
|
||||
|
36
.github/workflows/lint.yml
vendored
Normal file
36
.github/workflows/lint.yml
vendored
Normal file
@@ -0,0 +1,36 @@
|
||||
name: Lint
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
pull_request:
|
||||
paths:
|
||||
- '**'
|
||||
|
||||
|
||||
concurrency:
|
||||
group: ci-lint-${{ github.head_ref || github.ref }}-${{ github.repository }}
|
||||
cancel-in-progress: true
|
||||
|
||||
env:
|
||||
FORCE_COLOR: 1
|
||||
jobs:
|
||||
lint:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v4
|
||||
with:
|
||||
go-version: ^1.20
|
||||
- name: Install earthly
|
||||
uses: Luet-lab/luet-install-action@v1
|
||||
with:
|
||||
repository: quay.io/kairos/packages
|
||||
packages: utils/earthly
|
||||
- name: Run Lint checks
|
||||
run: |
|
||||
earthly +lint
|
14
.github/workflows/unit-tests.yml
vendored
14
.github/workflows/unit-tests.yml
vendored
@@ -1,9 +1,15 @@
|
||||
---
|
||||
name: Unit tests
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
pull_request:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
pull_request:
|
||||
|
||||
|
||||
concurrency:
|
||||
group: ci-unit-${{ github.head_ref || github.ref }}-${{ github.repository }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
unit-tests:
|
||||
|
21
.yamllint
Normal file
21
.yamllint
Normal file
@@ -0,0 +1,21 @@
|
||||
extends: default
|
||||
|
||||
rules:
|
||||
# 80 chars should be enough, but don't fail if a line is longer
|
||||
line-length:
|
||||
max: 150
|
||||
level: warning
|
||||
|
||||
# accept both key:
|
||||
# - item
|
||||
#
|
||||
# and key:
|
||||
# - item
|
||||
indentation:
|
||||
indent-sequences: whatever
|
||||
|
||||
truthy:
|
||||
check-keys: false
|
||||
|
||||
document-start:
|
||||
present: false
|
@@ -1,5 +1,5 @@
|
||||
# Build the manager binary
|
||||
FROM golang:1.18 as builder
|
||||
FROM golang:1.20 as builder
|
||||
|
||||
WORKDIR /workspace
|
||||
# Copy the Go Modules manifests
|
||||
|
90
Earthfile
90
Earthfile
@@ -1,14 +1,16 @@
|
||||
VERSION 0.6
|
||||
ARG BASE_IMAGE=quay.io/kairos/core-opensuse:latest
|
||||
ARG BASE_IMAGE=quay.io/kairos/core-ubuntu:latest
|
||||
ARG OSBUILDER_IMAGE=quay.io/kairos/osbuilder-tools
|
||||
ARG GO_VERSION=1.18
|
||||
# renovate: datasource=docker depName=golang
|
||||
ARG GO_VERSION=1.20
|
||||
ARG LUET_VERSION=0.33.0
|
||||
|
||||
build-challenger:
|
||||
FROM golang:alpine
|
||||
COPY . /work
|
||||
WORKDIR /work
|
||||
RUN CGO_ENABLED=0 go build -o kcrypt-discovery-challenger ./cmd/discovery
|
||||
SAVE ARTIFACT /work/kcrypt-discovery-challenger AS LOCAL kcrypt-discovery-challenger
|
||||
SAVE ARTIFACT /work/kcrypt-discovery-challenger kcrypt-discovery-challenger AS LOCAL kcrypt-discovery-challenger
|
||||
|
||||
image:
|
||||
FROM $BASE_IMAGE
|
||||
@@ -16,17 +18,24 @@ image:
|
||||
COPY +build-challenger/kcrypt-discovery-challenger /system/discovery/kcrypt-discovery-challenger
|
||||
SAVE IMAGE $IMAGE
|
||||
|
||||
image-rootfs:
|
||||
FROM +image
|
||||
SAVE ARTIFACT --keep-own /. rootfs
|
||||
|
||||
grub-files:
|
||||
FROM alpine
|
||||
RUN apk add wget
|
||||
RUN wget https://raw.githubusercontent.com/c3os-io/c3os/master/overlay/files-iso/boot/grub2/grub.cfg -O grub.cfg
|
||||
SAVE ARTIFACT --keep-own grub.cfg grub.cfg
|
||||
|
||||
iso:
|
||||
ARG OSBUILDER_IMAGE
|
||||
ARG ISO_NAME=challenger
|
||||
FROM $OSBUILDER_IMAGE
|
||||
RUN zypper in -y jq docker
|
||||
WORKDIR /build
|
||||
WITH DOCKER --allow-privileged --load $IMAGE=(+image --IMAGE=test)
|
||||
RUN /entrypoint.sh --name $ISO_NAME --debug build-iso --date=false --local test --output /build/
|
||||
END
|
||||
# See: https://github.com/rancher/elemental-cli/issues/228
|
||||
RUN sha256sum $ISO_NAME.iso > $ISO_NAME.iso.sha256
|
||||
COPY --keep-own +grub-files/grub.cfg /build/files-iso/boot/grub2/grub.cfg
|
||||
COPY --keep-own +image-rootfs/rootfs /build/rootfs
|
||||
RUN /entrypoint.sh --name $ISO_NAME --debug build-iso --squash-no-compression --date=false --local --overlay-iso /build/files-iso --output /build/ dir:/build/rootfs
|
||||
SAVE ARTIFACT /build/$ISO_NAME.iso kairos.iso AS LOCAL build/$ISO_NAME.iso
|
||||
SAVE ARTIFACT /build/$ISO_NAME.iso.sha256 kairos.iso.sha256 AS LOCAL build/$ISO_NAME.iso.sha256
|
||||
|
||||
@@ -41,12 +50,61 @@ test:
|
||||
COPY go.mod go.sum ./
|
||||
RUN go mod download && go mod verify
|
||||
|
||||
RUN go get github.com/onsi/gomega/...
|
||||
RUN go get github.com/onsi/ginkgo/v2/ginkgo/internal@v2.1.4
|
||||
RUN go get github.com/onsi/ginkgo/v2/ginkgo/generators@v2.1.4
|
||||
RUN go get github.com/onsi/ginkgo/v2/ginkgo/labels@v2.1.4
|
||||
RUN go install -mod=mod github.com/onsi/ginkgo/v2/ginkgo
|
||||
|
||||
COPY . /work
|
||||
RUN PATH=$PATH:$GOPATH/bin ginkgo run --covermode=atomic --coverprofile=coverage.out -p -r pkg/challenger cmd/discovery/client
|
||||
RUN go run github.com/onsi/ginkgo/v2/ginkgo run --covermode=atomic --coverprofile=coverage.out -p -r pkg/challenger cmd/discovery/client
|
||||
SAVE ARTIFACT coverage.out AS LOCAL coverage.out
|
||||
|
||||
# Generic targets
|
||||
# usage e.g. ./earthly.sh +datasource-iso --CLOUD_CONFIG=tests/assets/qrcode.yaml
|
||||
datasource-iso:
|
||||
ARG OSBUILDER_IMAGE
|
||||
ARG CLOUD_CONFIG
|
||||
FROM $OSBUILDER_IMAGE
|
||||
RUN zypper in -y mkisofs
|
||||
WORKDIR /build
|
||||
RUN touch meta-data
|
||||
|
||||
COPY ${CLOUD_CONFIG} user-data
|
||||
RUN cat user-data
|
||||
RUN mkisofs -output ci.iso -volid cidata -joliet -rock user-data meta-data
|
||||
SAVE ARTIFACT /build/ci.iso iso.iso AS LOCAL build/datasource.iso
|
||||
|
||||
luet:
|
||||
FROM quay.io/luet/base:$LUET_VERSION
|
||||
SAVE ARTIFACT /usr/bin/luet /luet
|
||||
|
||||
e2e-tests-image:
|
||||
FROM opensuse/tumbleweed
|
||||
RUN zypper in -y go git qemu-x86 qemu-arm qemu-tools swtpm docker jq docker-compose make glibc libopenssl-devel curl gettext-runtime
|
||||
ENV GOPATH="/go"
|
||||
|
||||
COPY . /test
|
||||
WORKDIR /test
|
||||
|
||||
IF [ -e /test/build/kairos.iso ]
|
||||
ENV ISO=/test/build/kairos.iso
|
||||
ELSE
|
||||
COPY +iso/kairos.iso kairos.iso
|
||||
ENV ISO=/test/kairos.iso
|
||||
END
|
||||
|
||||
COPY +luet/luet /usr/bin/luet
|
||||
RUN mkdir -p /etc/luet/repos.conf.d/
|
||||
RUN luet repo add -y kairos --url quay.io/kairos/packages --type docker
|
||||
RUN LUET_NOLOCK=true luet install -y container/kubectl utils/k3d
|
||||
|
||||
e2e-tests:
|
||||
FROM +e2e-tests-image
|
||||
ARG LABEL
|
||||
|
||||
WITH DOCKER --allow-privileged
|
||||
RUN ./scripts/e2e-tests.sh
|
||||
END
|
||||
|
||||
lint:
|
||||
BUILD +yamllint
|
||||
|
||||
yamllint:
|
||||
FROM cytopia/yamllint
|
||||
COPY . .
|
||||
RUN yamllint .github/workflows/
|
||||
|
4
Makefile
4
Makefile
@@ -103,7 +103,7 @@ vet: ## Run go vet against code.
|
||||
|
||||
.PHONY: test
|
||||
test: manifests generate fmt vet envtest ## Run tests.
|
||||
KUBEBUILDER_ASSETS="$(shell $(ENVTEST) use $(ENVTEST_K8S_VERSION) -p path)" go test ./... -coverprofile cover.out
|
||||
KUBEBUILDER_ASSETS="$(shell $(ENVTEST) use $(ENVTEST_K8S_VERSION) -p path)" go test ./pkg/... -coverprofile cover.out
|
||||
|
||||
##@ Build
|
||||
|
||||
@@ -257,4 +257,4 @@ undeploy-dev: ## Undeploy controller from the K8s cluster specified in ~/.kube/c
|
||||
kubesplit: manifests kustomize
|
||||
rm -rf helm-chart
|
||||
mkdir helm-chart
|
||||
$(KUSTOMIZE) build config/default | kubesplit -helm helm-chart
|
||||
$(KUSTOMIZE) build config/default | kubesplit -helm helm-chart
|
||||
|
64
README.md
64
README.md
@@ -1,10 +1,72 @@
|
||||
# kcrypt-challenger
|
||||
<h1 align="center">
|
||||
<br>
|
||||
<img width="184" alt="kairos-white-column 5bc2fe34" src="https://user-images.githubusercontent.com/2420543/193010398-72d4ba6e-7efe-4c2e-b7ba-d3a826a55b7d.png"><br>
|
||||
Kcrypt challenger
|
||||
<br>
|
||||
</h1>
|
||||
|
||||
<h3 align="center">Kcrypt TPM challenger</h3>
|
||||
<p align="center">
|
||||
<a href="https://opensource.org/licenses/">
|
||||
<img src="https://img.shields.io/badge/licence-APL2-brightgreen"
|
||||
alt="license">
|
||||
</a>
|
||||
<a href="https://github.com/kairos-io/kcrypt-challenger/issues"><img src="https://img.shields.io/github/issues/kairos-io/kcrypt-challenger"></a>
|
||||
<a href="https://kairos.io/docs/" target=_blank> <img src="https://img.shields.io/badge/Documentation-blue"
|
||||
alt="docs"></a>
|
||||
<img src="https://img.shields.io/badge/made%20with-Go-blue">
|
||||
<img src="https://goreportcard.com/badge/github.com/kairos-io/kcrypt-challenger" alt="go report card" />
|
||||
<a href="https://github.com/kairos-io/kcrypt-challenger/actions/workflows/e2e-tests.yml?query=branch%3Amain"> <img src="https://github.com/kairos-io/kcrypt-challenger/actions/workflows/e2e-tests.yml/badge.svg?branch=main"></a>
|
||||
</p>
|
||||
|
||||
|
||||
With Kairos you can build immutable, bootable Kubernetes and OS images for your edge devices as easily as writing a Dockerfile. Optional P2P mesh with distributed ledger automates node bootstrapping and coordination. Updating nodes is as easy as CI/CD: push a new image to your container registry and let secure, risk-free A/B atomic upgrades do the rest.
|
||||
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<th align="center">
|
||||
<img width="640" height="1px">
|
||||
<p>
|
||||
<small>
|
||||
Documentation
|
||||
</small>
|
||||
</p>
|
||||
</th>
|
||||
<th align="center">
|
||||
<img width="640" height="1">
|
||||
<p>
|
||||
<small>
|
||||
Contribute
|
||||
</small>
|
||||
</p>
|
||||
</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
|
||||
📚 [Getting started with Kairos](https://kairos.io/docs/getting-started) <br> :bulb: [Examples](https://kairos.io/docs/examples) <br> :movie_camera: [Video](https://kairos.io/docs/media/) <br> :open_hands:[Engage with the Community](https://kairos.io/community/)
|
||||
|
||||
</td>
|
||||
<td>
|
||||
|
||||
🙌[ CONTRIBUTING.md ]( https://github.com/kairos-io/kairos/blob/master/CONTRIBUTING.md ) <br> :raising_hand: [ GOVERNANCE ]( https://github.com/kairos-io/kairos/blob/master/GOVERNANCE.md ) <br>:construction_worker:[Code of conduct](https://github.com/kairos-io/kairos/blob/master/CODE_OF_CONDUCT.md)
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
| :exclamation: | This is experimental! |
|
||||
|-|:-|
|
||||
|
||||
This is the Kairos kcrypt-challenger Kubernetes Native Extension.
|
||||
|
||||
## Usage
|
||||
|
||||
See the documentation in our website: https://kairos.io/docs/advanced/partition_encryption/.
|
||||
|
||||
## Installation
|
||||
|
||||
To install, use helm:
|
||||
|
||||
```
|
||||
|
@@ -17,6 +17,7 @@ import (
|
||||
)
|
||||
|
||||
var errPartNotFound error = fmt.Errorf("pass for partition not found")
|
||||
var errBadCertificate error = fmt.Errorf("unknown certificate")
|
||||
|
||||
func NewClient() (*Client, error) {
|
||||
conf, err := unmarshalConfig()
|
||||
@@ -68,7 +69,9 @@ func (c *Client) generatePass(postEndpoint string, p *block.Partition) error {
|
||||
bpass := base64.RawURLEncoding.EncodeToString(pass)
|
||||
|
||||
opts := []tpm.Option{
|
||||
tpm.WithAdditionalHeader("label", p.Label),
|
||||
tpm.WithCAs([]byte(c.Config.Kcrypt.Challenger.Certificate)),
|
||||
tpm.AppendCustomCAToSystemCA,
|
||||
tpm.WithAdditionalHeader("label", p.FilesystemLabel),
|
||||
tpm.WithAdditionalHeader("name", p.Name),
|
||||
tpm.WithAdditionalHeader("uuid", p.UUID),
|
||||
}
|
||||
@@ -91,7 +94,7 @@ func (c *Client) waitPass(p *block.Partition, attempts int) (pass string, err er
|
||||
|
||||
for tries := 0; tries < attempts; tries++ {
|
||||
var generated bool
|
||||
pass, generated, err = getPass(challengeEndpoint, p)
|
||||
pass, generated, err = getPass(challengeEndpoint, c.Config.Kcrypt.Challenger.Certificate, p)
|
||||
if err == errPartNotFound {
|
||||
// IF server doesn't have a pass for us, then we generate one and we set it
|
||||
err = c.generatePass(postEndpoint, p)
|
||||
@@ -102,14 +105,20 @@ func (c *Client) waitPass(p *block.Partition, attempts int) (pass string, err er
|
||||
tries = 0
|
||||
continue
|
||||
}
|
||||
|
||||
if generated { // passphrase is encrypted
|
||||
return c.decryptPassphrase(pass)
|
||||
}
|
||||
|
||||
if err == nil || err == errPartNotFound { // passphrase not encrypted or not available
|
||||
if err == errBadCertificate { // No need to retry, won't succeed.
|
||||
return
|
||||
}
|
||||
|
||||
if err == nil { // passphrase available, no errors
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Printf("Failed with error: %s . Will retry.\n", err.Error())
|
||||
time.Sleep(1 * time.Second) // network errors? retry
|
||||
}
|
||||
|
||||
|
@@ -1,8 +1,9 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"github.com/kairos-io/kairos/pkg/config"
|
||||
"github.com/kairos-io/kairos-sdk/collector"
|
||||
kconfig "github.com/kairos-io/kcrypt/pkg/config"
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
type Client struct {
|
||||
@@ -16,8 +17,9 @@ type Config struct {
|
||||
// Non-volatile index memory: where we store the encrypted passphrase (offline mode)
|
||||
NVIndex string `yaml:"nv_index,omitempty"`
|
||||
// Certificate index: this is where the rsa pair that decrypts the passphrase lives
|
||||
CIndex string `yaml:"c_index,omitempty"`
|
||||
TPMDevice string `yaml:"tpm_device,omitempty"`
|
||||
CIndex string `yaml:"c_index,omitempty"`
|
||||
TPMDevice string `yaml:"tpm_device,omitempty"`
|
||||
Certificate string `yaml:"certificate,omitempty"`
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -25,12 +27,21 @@ type Config struct {
|
||||
func unmarshalConfig() (Config, error) {
|
||||
var result Config
|
||||
|
||||
c, err := config.Scan(config.Directories(kconfig.ConfigScanDirs...), config.NoLogs)
|
||||
o := &collector.Options{NoLogs: true, MergeBootCMDLine: false}
|
||||
if err := o.Apply(collector.Directories(append(kconfig.ConfigScanDirs, "/tmp/oem")...)); err != nil {
|
||||
return result, err
|
||||
}
|
||||
|
||||
c, err := collector.Scan(o, func(d []byte) ([]byte, error) {
|
||||
return d, nil
|
||||
})
|
||||
if err != nil {
|
||||
return result, err
|
||||
}
|
||||
|
||||
if err = c.Unmarshal(&result); err != nil {
|
||||
a, _ := c.String()
|
||||
err = yaml.Unmarshal([]byte(a), &result)
|
||||
if err != nil {
|
||||
return result, err
|
||||
}
|
||||
|
||||
|
@@ -16,9 +16,11 @@ import (
|
||||
|
||||
const DefaultNVIndex = "0x1500000"
|
||||
|
||||
func getPass(server string, partition *block.Partition) (string, bool, error) {
|
||||
func getPass(server, certificate string, partition *block.Partition) (string, bool, error) {
|
||||
msg, err := tpm.Get(server,
|
||||
tpm.WithAdditionalHeader("label", partition.Label),
|
||||
tpm.WithCAs([]byte(certificate)),
|
||||
tpm.AppendCustomCAToSystemCA,
|
||||
tpm.WithAdditionalHeader("label", partition.FilesystemLabel),
|
||||
tpm.WithAdditionalHeader("name", partition.Name),
|
||||
tpm.WithAdditionalHeader("uuid", partition.UUID))
|
||||
if err != nil {
|
||||
@@ -36,6 +38,9 @@ func getPass(server string, partition *block.Partition) (string, bool, error) {
|
||||
if strings.Contains(result.Error, "No secret found for") {
|
||||
return "", false, errPartNotFound
|
||||
}
|
||||
if strings.Contains(result.Error, "x509: certificate signed by unknown authority") {
|
||||
return "", false, errBadCertificate
|
||||
}
|
||||
return "", false, fmt.Errorf(result.Error)
|
||||
}
|
||||
|
||||
|
@@ -82,4 +82,4 @@ spec:
|
||||
- name: wss
|
||||
port: 8082
|
||||
protocol: TCP
|
||||
targetPort: wss
|
||||
targetPort: wss
|
||||
|
@@ -20,14 +20,13 @@ import (
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
. "github.com/onsi/gomega"
|
||||
|
||||
"k8s.io/client-go/kubernetes/scheme"
|
||||
"k8s.io/client-go/rest"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
"sigs.k8s.io/controller-runtime/pkg/envtest"
|
||||
"sigs.k8s.io/controller-runtime/pkg/envtest/printer"
|
||||
logf "sigs.k8s.io/controller-runtime/pkg/log"
|
||||
"sigs.k8s.io/controller-runtime/pkg/log/zap"
|
||||
|
||||
@@ -44,10 +43,7 @@ var testEnv *envtest.Environment
|
||||
|
||||
func TestAPIs(t *testing.T) {
|
||||
RegisterFailHandler(Fail)
|
||||
|
||||
RunSpecsWithDefaultAndCustomReporters(t,
|
||||
"Controller Suite",
|
||||
[]Reporter{printer.NewlineReporter{}})
|
||||
RunSpecs(t, "Control")
|
||||
}
|
||||
|
||||
var _ = BeforeSuite(func() {
|
||||
|
@@ -1,3 +1,3 @@
|
||||
#!/bin/bash
|
||||
|
||||
docker run --privileged -v /var/run/docker.sock:/var/run/docker.sock --rm -t -v $(pwd):/workspace -v earthly-tmp:/tmp/earthly:rw earthly/earthly:v0.6.21 --allow-privileged $@
|
||||
docker run --privileged -v /var/run/docker.sock:/var/run/docker.sock --rm -t -v $(pwd):/workspace -v earthly-tmp:/tmp/earthly:rw earthly/earthly:v0.7.8 --allow-privileged $@
|
172
go.mod
172
go.mod
@@ -1,134 +1,162 @@
|
||||
module github.com/kairos-io/kairos-challenger
|
||||
|
||||
go 1.18
|
||||
go 1.20
|
||||
|
||||
require (
|
||||
github.com/google/uuid v1.3.0
|
||||
github.com/gorilla/websocket v1.5.0
|
||||
github.com/jaypipes/ghw v0.9.0
|
||||
github.com/kairos-io/kairos v1.24.3-56.0.20230118103822-e3dbd41dddd1
|
||||
github.com/kairos-io/kcrypt v0.4.5-0.20230118125949-27183fbce7ea
|
||||
github.com/jaypipes/ghw v0.11.0
|
||||
github.com/kairos-io/kairos-sdk v0.0.8
|
||||
github.com/kairos-io/kcrypt v0.7.0
|
||||
github.com/kairos-io/tpm-helpers v0.0.0-20230119140150-3fa97128ef6b
|
||||
github.com/mudler/go-pluggable v0.0.0-20220716112424-189d463e3ff3
|
||||
github.com/mudler/yip v0.11.4
|
||||
github.com/onsi/ginkgo v1.16.5
|
||||
github.com/onsi/ginkgo/v2 v2.7.0
|
||||
github.com/onsi/gomega v1.25.0
|
||||
github.com/mudler/go-pluggable v0.0.0-20230126220627-7710299a0ae5
|
||||
github.com/mudler/go-processmanager v0.0.0-20220724164624-c45b5c61312d
|
||||
github.com/mudler/yip v1.2.0
|
||||
github.com/onsi/ginkgo/v2 v2.10.0
|
||||
github.com/onsi/gomega v1.27.8
|
||||
github.com/pkg/errors v0.9.1
|
||||
k8s.io/api v0.24.2
|
||||
k8s.io/apimachinery v0.24.2
|
||||
k8s.io/client-go v0.24.2
|
||||
sigs.k8s.io/controller-runtime v0.12.2
|
||||
github.com/spectrocloud/peg v0.0.0-20230407121159-2e15270c4a46
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
k8s.io/api v0.27.2
|
||||
k8s.io/apimachinery v0.27.2
|
||||
k8s.io/client-go v0.27.2
|
||||
sigs.k8s.io/controller-runtime v0.15.0
|
||||
)
|
||||
|
||||
require (
|
||||
atomicgo.dev/cursor v0.1.1 // indirect
|
||||
atomicgo.dev/keyboard v0.2.9 // indirect
|
||||
cloud.google.com/go v0.93.3 // indirect
|
||||
github.com/Azure/go-autorest v14.2.0+incompatible // indirect
|
||||
github.com/Azure/go-autorest/autorest v0.11.18 // indirect
|
||||
github.com/Azure/go-autorest/autorest/adal v0.9.13 // indirect
|
||||
github.com/Azure/go-autorest/autorest/date v0.3.0 // indirect
|
||||
github.com/Azure/go-autorest/logger v0.2.1 // indirect
|
||||
github.com/Azure/go-autorest/tracing v0.6.0 // indirect
|
||||
atomicgo.dev/schedule v0.0.2 // indirect
|
||||
github.com/Masterminds/goutils v1.1.1 // indirect
|
||||
github.com/Masterminds/semver/v3 v3.1.1 // indirect
|
||||
github.com/Masterminds/sprig/v3 v3.2.2 // indirect
|
||||
github.com/PuerkitoBio/purell v1.1.1 // indirect
|
||||
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 // indirect
|
||||
github.com/Masterminds/semver/v3 v3.2.1 // indirect
|
||||
github.com/Masterminds/sprig/v3 v3.2.3 // indirect
|
||||
github.com/Microsoft/go-winio v0.6.1 // indirect
|
||||
github.com/Microsoft/hcsshim v0.10.0-rc.8 // indirect
|
||||
github.com/StackExchange/wmi v1.2.1 // indirect
|
||||
github.com/avast/retry-go v3.0.0+incompatible // indirect
|
||||
github.com/aybabtme/rgbterm v0.0.0-20170906152045-cc83f3b3ce59 // indirect
|
||||
github.com/beorn7/perks v1.0.1 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.1.2 // indirect
|
||||
github.com/bramvdbogaerde/go-scp v1.2.1 // indirect
|
||||
github.com/cavaliergopher/grab/v3 v3.0.1 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.2.0 // indirect
|
||||
github.com/chuckpreslar/emission v0.0.0-20170206194824-a7ddd980baf9 // indirect
|
||||
github.com/codingsince1985/checksum v1.2.6 // indirect
|
||||
github.com/containerd/cgroups v1.1.0 // indirect
|
||||
github.com/containerd/console v1.0.3 // indirect
|
||||
github.com/containerd/containerd v1.7.1 // indirect
|
||||
github.com/containerd/continuity v0.3.0 // indirect
|
||||
github.com/containerd/stargz-snapshotter/estargz v0.14.3 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/denisbrodbeck/machineid v1.0.1 // indirect
|
||||
github.com/emicklei/go-restful v2.9.5+incompatible // indirect
|
||||
github.com/evanphx/json-patch v4.12.0+incompatible // indirect
|
||||
github.com/docker/cli v23.0.5+incompatible // indirect
|
||||
github.com/docker/distribution v2.8.1+incompatible // indirect
|
||||
github.com/docker/docker v23.0.5+incompatible // indirect
|
||||
github.com/docker/docker-credential-helpers v0.7.0 // indirect
|
||||
github.com/docker/go-connections v0.4.0 // indirect
|
||||
github.com/docker/go-units v0.5.0 // indirect
|
||||
github.com/emicklei/go-restful/v3 v3.10.1 // indirect
|
||||
github.com/evanphx/json-patch/v5 v5.6.0 // indirect
|
||||
github.com/folbricht/tpmk v0.1.2-0.20230104073416-f20b20c289d7 // indirect
|
||||
github.com/form3tech-oss/jwt-go v3.2.5+incompatible // indirect
|
||||
github.com/fsnotify/fsnotify v1.5.4 // indirect
|
||||
github.com/fsnotify/fsnotify v1.6.0 // indirect
|
||||
github.com/ghodss/yaml v1.0.0 // indirect
|
||||
github.com/go-logr/logr v1.2.3 // indirect
|
||||
github.com/go-logr/zapr v1.2.0 // indirect
|
||||
github.com/go-logr/logr v1.2.4 // indirect
|
||||
github.com/go-logr/zapr v1.2.4 // indirect
|
||||
github.com/go-ole/go-ole v1.2.6 // indirect
|
||||
github.com/go-openapi/jsonpointer v0.19.5 // indirect
|
||||
github.com/go-openapi/jsonreference v0.19.5 // indirect
|
||||
github.com/go-openapi/swag v0.19.14 // indirect
|
||||
github.com/go-openapi/jsonpointer v0.19.6 // indirect
|
||||
github.com/go-openapi/jsonreference v0.20.1 // indirect
|
||||
github.com/go-openapi/swag v0.22.3 // indirect
|
||||
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect
|
||||
github.com/gofrs/uuid v4.4.0+incompatible // indirect
|
||||
github.com/gogo/protobuf v1.3.2 // indirect
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
|
||||
github.com/golang/protobuf v1.5.2 // indirect
|
||||
github.com/golang/protobuf v1.5.3 // indirect
|
||||
github.com/google/certificate-transparency-go v1.1.4 // indirect
|
||||
github.com/google/gnostic v0.5.7-v3refs // indirect
|
||||
github.com/google/go-attestation v0.4.4-0.20220404204839-8820d49b18d9 // indirect
|
||||
github.com/google/go-cmp v0.5.9 // indirect
|
||||
github.com/google/go-containerregistry v0.15.2 // indirect
|
||||
github.com/google/go-tpm v0.3.3 // indirect
|
||||
github.com/google/go-tpm-tools v0.3.10 // indirect
|
||||
github.com/google/go-tspi v0.3.0 // indirect
|
||||
github.com/google/gofuzz v1.1.0 // indirect
|
||||
github.com/google/gofuzz v1.2.0 // indirect
|
||||
github.com/google/pprof v0.0.0-20230228050547-1710fef4ab10 // indirect
|
||||
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect
|
||||
github.com/google/uuid v1.3.0 // indirect
|
||||
github.com/gookit/color v1.5.2 // indirect
|
||||
github.com/gookit/color v1.5.3 // indirect
|
||||
github.com/hashicorp/errwrap v1.1.0 // indirect
|
||||
github.com/hashicorp/go-multierror v1.1.1 // indirect
|
||||
github.com/huandu/xstrings v1.3.2 // indirect
|
||||
github.com/imdario/mergo v0.3.13 // indirect
|
||||
github.com/itchyny/gojq v0.12.11 // indirect
|
||||
github.com/huandu/xstrings v1.3.3 // indirect
|
||||
github.com/imdario/mergo v0.3.15 // indirect
|
||||
github.com/ipfs/go-log v1.0.5 // indirect
|
||||
github.com/ipfs/go-log/v2 v2.5.1 // indirect
|
||||
github.com/itchyny/gojq v0.12.12 // indirect
|
||||
github.com/itchyny/timefmt-go v0.1.5 // indirect
|
||||
github.com/joho/godotenv v1.4.0 // indirect
|
||||
github.com/joho/godotenv v1.5.1 // indirect
|
||||
github.com/josharian/intern v1.0.0 // indirect
|
||||
github.com/json-iterator/go v1.1.12 // indirect
|
||||
github.com/lithammer/fuzzysearch v1.1.5 // indirect
|
||||
github.com/mailru/easyjson v0.7.6 // indirect
|
||||
github.com/kairos-io/kairos v1.24.3-56.0.20230329142538-b6ae4b58c07d // indirect
|
||||
github.com/klauspost/compress v1.16.5 // indirect
|
||||
github.com/lithammer/fuzzysearch v1.1.7 // indirect
|
||||
github.com/mailru/easyjson v0.7.7 // indirect
|
||||
github.com/mattn/go-isatty v0.0.17 // indirect
|
||||
github.com/mattn/go-runewidth v0.0.14 // indirect
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 // indirect
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
|
||||
github.com/mitchellh/copystructure v1.2.0 // indirect
|
||||
github.com/mitchellh/go-homedir v1.1.0 // indirect
|
||||
github.com/mitchellh/reflectwalk v1.0.2 // indirect
|
||||
github.com/moby/sys/sequential v0.5.0 // indirect
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
|
||||
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 // indirect
|
||||
github.com/nxadm/tail v1.4.8 // indirect
|
||||
github.com/prometheus/client_golang v1.13.0 // indirect
|
||||
github.com/prometheus/client_model v0.2.0 // indirect
|
||||
github.com/prometheus/common v0.37.0 // indirect
|
||||
github.com/prometheus/procfs v0.8.0 // indirect
|
||||
github.com/pterm/pterm v0.12.53 // indirect
|
||||
github.com/opencontainers/go-digest v1.0.0 // indirect
|
||||
github.com/opencontainers/image-spec v1.1.0-rc3 // indirect
|
||||
github.com/opentracing/opentracing-go v1.2.0 // indirect
|
||||
github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5 // indirect
|
||||
github.com/prometheus/client_golang v1.15.1 // indirect
|
||||
github.com/prometheus/client_model v0.4.0 // indirect
|
||||
github.com/prometheus/common v0.42.0 // indirect
|
||||
github.com/prometheus/procfs v0.9.0 // indirect
|
||||
github.com/pterm/pterm v0.12.61 // indirect
|
||||
github.com/qeesung/image2ascii v1.0.1 // indirect
|
||||
github.com/rivo/uniseg v0.4.3 // indirect
|
||||
github.com/rivo/uniseg v0.4.4 // indirect
|
||||
github.com/sergi/go-diff v1.3.1 // indirect
|
||||
github.com/shopspring/decimal v1.3.1 // indirect
|
||||
github.com/sirupsen/logrus v1.9.0 // indirect
|
||||
github.com/spf13/cast v1.5.0 // indirect
|
||||
github.com/spf13/pflag v1.0.5 // indirect
|
||||
github.com/twpayne/go-vfs v1.7.2 // indirect
|
||||
github.com/vbatts/tar-split v0.11.3 // indirect
|
||||
github.com/wayneashleyberry/terminal-dimensions v1.1.0 // indirect
|
||||
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect
|
||||
go.opencensus.io v0.24.0 // indirect
|
||||
go.uber.org/atomic v1.10.0 // indirect
|
||||
go.uber.org/multierr v1.8.0 // indirect
|
||||
go.uber.org/zap v1.23.0 // indirect
|
||||
golang.org/x/crypto v0.5.0 // indirect
|
||||
golang.org/x/net v0.5.0 // indirect
|
||||
golang.org/x/oauth2 v0.4.0 // indirect
|
||||
golang.org/x/sys v0.4.0 // indirect
|
||||
golang.org/x/term v0.4.0 // indirect
|
||||
golang.org/x/text v0.6.0 // indirect
|
||||
golang.org/x/time v0.0.0-20220411224347-583f2d630306 // indirect
|
||||
gomodules.xyz/jsonpatch/v2 v2.2.0 // indirect
|
||||
go.uber.org/multierr v1.9.0 // indirect
|
||||
go.uber.org/zap v1.24.0 // indirect
|
||||
golang.org/x/crypto v0.7.0 // indirect
|
||||
golang.org/x/mod v0.10.0 // indirect
|
||||
golang.org/x/net v0.10.0 // indirect
|
||||
golang.org/x/oauth2 v0.7.0 // indirect
|
||||
golang.org/x/sync v0.2.0 // indirect
|
||||
golang.org/x/sys v0.8.0 // indirect
|
||||
golang.org/x/term v0.8.0 // indirect
|
||||
golang.org/x/text v0.9.0 // indirect
|
||||
golang.org/x/time v0.3.0 // indirect
|
||||
golang.org/x/tools v0.9.3 // indirect
|
||||
gomodules.xyz/jsonpatch/v2 v2.3.0 // indirect
|
||||
google.golang.org/appengine v1.6.7 // indirect
|
||||
google.golang.org/protobuf v1.28.1 // indirect
|
||||
google.golang.org/genproto v0.0.0-20230323212658-478b75c54725 // indirect
|
||||
google.golang.org/grpc v1.54.0 // indirect
|
||||
google.golang.org/protobuf v1.30.0 // indirect
|
||||
gopkg.in/inf.v0 v0.9.1 // indirect
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect
|
||||
gopkg.in/yaml.v1 v1.0.0-20140924161607-9f9df34309c0 // indirect
|
||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
howett.net/plist v1.0.0 // indirect
|
||||
k8s.io/apiextensions-apiserver v0.24.2 // indirect
|
||||
k8s.io/component-base v0.24.2 // indirect
|
||||
k8s.io/klog/v2 v2.80.1 // indirect
|
||||
k8s.io/kube-openapi v0.0.0-20220328201542-3ee0da9b0b42 // indirect
|
||||
k8s.io/utils v0.0.0-20220210201930-3a6ce19ff2f9 // indirect
|
||||
sigs.k8s.io/json v0.0.0-20211208200746-9f7c6b3444d2 // indirect
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.2.1 // indirect
|
||||
k8s.io/apiextensions-apiserver v0.27.2 // indirect
|
||||
k8s.io/component-base v0.27.2 // indirect
|
||||
k8s.io/klog/v2 v2.90.1 // indirect
|
||||
k8s.io/kube-openapi v0.0.0-20230501164219-8b0f38b5fd1f // indirect
|
||||
k8s.io/utils v0.0.0-20230220204549-a5ecb0141aa5 // indirect
|
||||
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.2.3 // indirect
|
||||
sigs.k8s.io/yaml v1.3.0 // indirect
|
||||
)
|
||||
|
6
renovate.json
Normal file
6
renovate.json
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
|
||||
"extends": [
|
||||
"config:base"
|
||||
]
|
||||
}
|
62
scripts/e2e-tests.sh
Executable file
62
scripts/e2e-tests.sh
Executable file
@@ -0,0 +1,62 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
# This scripts prepares a cluster where we install the kcrypt CRDs.
|
||||
# This is where sealed volumes are created.
|
||||
|
||||
GINKGO_NODES="${GINKGO_NODES:-1}"
|
||||
K3S_IMAGE="rancher/k3s:v1.26.1-k3s1"
|
||||
|
||||
SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
|
||||
CLUSTER_NAME=$(echo $RANDOM | md5sum | head -c 10; echo;)
|
||||
export KUBECONFIG=$(mktemp)
|
||||
|
||||
# https://unix.stackexchange.com/a/423052
|
||||
getFreePort() {
|
||||
echo $(comm -23 <(seq "30000" "30200" | sort) <(ss -Htan | awk '{print $4}' | cut -d':' -f2 | sort -u) | shuf | head -n "1")
|
||||
}
|
||||
|
||||
cleanup() {
|
||||
echo "Cleaning up $CLUSTER_NAME"
|
||||
k3d cluster delete "$CLUSTER_NAME" || true
|
||||
rm -rf "$KUBECONFIG"
|
||||
}
|
||||
trap cleanup EXIT
|
||||
|
||||
# Create a cluster and bind ports 80 and 443 on the host
|
||||
# This will allow us to access challenger server on 10.0.2.2 which is the IP
|
||||
# on which qemu "sees" the host.
|
||||
# We change the CIDR because k3s creates iptables rules that block DNS traffic to this CIDR
|
||||
# (something like that). If you run k3d inside a k3s cluster (inside a Pod), DNS won't work
|
||||
# inside the k3d server container unless you use a different CIDR.
|
||||
# Here we are avoiding CIDR "10.43.x.x"
|
||||
k3d cluster create "$CLUSTER_NAME" --k3s-arg "--cluster-cidr=10.49.0.1/16@server:0" --k3s-arg "--service-cidr=10.48.0.1/16@server:0" -p '80:80@server:0' -p '443:443@server:0' --image "$K3S_IMAGE"
|
||||
k3d kubeconfig get "$CLUSTER_NAME" > "$KUBECONFIG"
|
||||
|
||||
# Build the docker image
|
||||
IMG=controller:latest make docker-build
|
||||
|
||||
# Import the image to the cluster
|
||||
k3d image import -c "$CLUSTER_NAME" controller:latest
|
||||
|
||||
# Install cert manager
|
||||
kubectl apply -f https://github.com/jetstack/cert-manager/releases/latest/download/cert-manager.yaml
|
||||
kubectl wait --for=condition=Available deployment --timeout=2m -n cert-manager --all
|
||||
|
||||
# Replace the CLUSTER_IP in the kustomize resource
|
||||
# Only needed for debugging so that we can access the server from the host
|
||||
# (the 10.0.2.2 IP address is only useful from within qemu)
|
||||
export CLUSTER_IP=$(docker inspect "k3d-${CLUSTER_NAME}-server-0" | jq -r '.[0].NetworkSettings.Networks[].IPAddress')
|
||||
envsubst \
|
||||
< "$SCRIPT_DIR/../tests/assets/challenger-server-ingress.template.yaml" \
|
||||
> "$SCRIPT_DIR/../tests/assets/challenger-server-ingress.yaml"
|
||||
|
||||
# Install the challenger server kustomization
|
||||
kubectl apply -k "$SCRIPT_DIR/../tests/assets/"
|
||||
|
||||
# 10.0.2.2 is where the vm sees the host
|
||||
# https://stackoverflow.com/a/6752280
|
||||
export KMS_ADDRESS="10.0.2.2.challenger.sslip.io"
|
||||
|
||||
go run github.com/onsi/ginkgo/v2/ginkgo -v --nodes $GINKGO_NODES --label-filter $LABEL --fail-fast -r ./tests/
|
37
tests/assets/challenger-patch.yaml
Normal file
37
tests/assets/challenger-patch.yaml
Normal file
@@ -0,0 +1,37 @@
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: controller-manager
|
||||
namespace: system
|
||||
spec:
|
||||
template:
|
||||
spec:
|
||||
containers:
|
||||
- name: manager
|
||||
# Don't try to pull the image we built locally
|
||||
imagePullPolicy: IfNotPresent
|
||||
args:
|
||||
- "--health-probe-bind-address"
|
||||
- ":8081"
|
||||
- "--metrics-bind-address"
|
||||
- "127.0.0.1:8080"
|
||||
- "--namespace"
|
||||
- "default"
|
||||
- "--leader-elect"
|
||||
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: kcrypt-escrow-server
|
||||
namespace: system
|
||||
spec:
|
||||
type: ClusterIP
|
||||
selector:
|
||||
control-plane: controller-manager
|
||||
ports:
|
||||
- name: wss
|
||||
port: 8082
|
||||
protocol: TCP
|
||||
targetPort: 8082
|
35
tests/assets/challenger-server-ingress.template.yaml
Normal file
35
tests/assets/challenger-server-ingress.template.yaml
Normal file
@@ -0,0 +1,35 @@
|
||||
---
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: challenger-server
|
||||
annotations:
|
||||
cert-manager.io/cluster-issuer: "selfsigned"
|
||||
kubernetes.io/ingress.class: "traefik"
|
||||
spec:
|
||||
tls:
|
||||
- hosts:
|
||||
- 10.0.2.2.challenger.sslip.io
|
||||
- ${CLUSTER_IP}.challenger.sslip.io
|
||||
secretName: kms-tls
|
||||
rules:
|
||||
- host: 10.0.2.2.challenger.sslip.io
|
||||
http:
|
||||
paths:
|
||||
- pathType: Prefix
|
||||
path: "/"
|
||||
backend:
|
||||
service:
|
||||
name: kcrypt-controller-kcrypt-escrow-server
|
||||
port:
|
||||
number: 8082
|
||||
- host: ${CLUSTER_IP}.challenger.sslip.io
|
||||
http:
|
||||
paths:
|
||||
- pathType: Prefix
|
||||
path: "/"
|
||||
backend:
|
||||
service:
|
||||
name: kcrypt-controller-kcrypt-escrow-server
|
||||
port:
|
||||
number: 8082
|
8
tests/assets/cluster-issuer.yaml
Normal file
8
tests/assets/cluster-issuer.yaml
Normal file
@@ -0,0 +1,8 @@
|
||||
---
|
||||
# Self-signed issuer
|
||||
apiVersion: cert-manager.io/v1
|
||||
kind: ClusterIssuer
|
||||
metadata:
|
||||
name: selfsigned
|
||||
spec:
|
||||
selfSigned: {}
|
13
tests/assets/kustomization.yaml
Normal file
13
tests/assets/kustomization.yaml
Normal file
@@ -0,0 +1,13 @@
|
||||
# Adds namespace to all resources.
|
||||
namespace: default
|
||||
|
||||
bases:
|
||||
- ../../config/default
|
||||
|
||||
resources:
|
||||
- challenger-server-ingress.yaml
|
||||
- cluster-issuer.yaml
|
||||
|
||||
patchesStrategicMerge:
|
||||
# Fix labels and selectors to make challenger server accessible
|
||||
- challenger-patch.yaml
|
391
tests/encryption_test.go
Normal file
391
tests/encryption_test.go
Normal file
@@ -0,0 +1,391 @@
|
||||
package e2e_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path"
|
||||
"strconv"
|
||||
"strings"
|
||||
"syscall"
|
||||
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
. "github.com/onsi/gomega"
|
||||
. "github.com/spectrocloud/peg/matcher"
|
||||
"gopkg.in/yaml.v3"
|
||||
|
||||
client "github.com/kairos-io/kairos-challenger/cmd/discovery/client"
|
||||
)
|
||||
|
||||
var installationOutput string
|
||||
var vm VM
|
||||
|
||||
var _ = Describe("kcrypt encryption", func() {
|
||||
var config string
|
||||
|
||||
BeforeEach(func() {
|
||||
RegisterFailHandler(printInstallationOutput)
|
||||
_, vm = startVM()
|
||||
fmt.Printf("\nvm.StateDir = %+v\n", vm.StateDir)
|
||||
|
||||
vm.EventuallyConnects(1200)
|
||||
})
|
||||
|
||||
JustBeforeEach(func() {
|
||||
configFile, err := os.CreateTemp("", "")
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
defer os.Remove(configFile.Name())
|
||||
|
||||
err = os.WriteFile(configFile.Name(), []byte(config), 0744)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
err = vm.Scp(configFile.Name(), "config.yaml", "0744")
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
installationOutput, err = vm.Sudo("/bin/bash -c 'set -o pipefail && kairos-agent manual-install --device auto config.yaml 2>&1 | tee manual-install.txt'")
|
||||
Expect(err).ToNot(HaveOccurred(), installationOutput)
|
||||
})
|
||||
|
||||
AfterEach(func() {
|
||||
vm.GatherLog("/run/immucore/immucore.log")
|
||||
err := vm.Destroy(func(vm VM) {
|
||||
// Stop TPM emulator
|
||||
tpmPID, err := os.ReadFile(path.Join(vm.StateDir, "tpm", "pid"))
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
if len(tpmPID) != 0 {
|
||||
pid, err := strconv.Atoi(string(tpmPID))
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
syscall.Kill(pid, syscall.SIGKILL)
|
||||
}
|
||||
})
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
})
|
||||
|
||||
// https://kairos.io/docs/advanced/partition_encryption/#offline-mode
|
||||
When("doing local encryption", Label("local-encryption"), func() {
|
||||
BeforeEach(func() {
|
||||
config = `#cloud-config
|
||||
|
||||
install:
|
||||
encrypted_partitions:
|
||||
- COS_PERSISTENT
|
||||
reboot: false # we will reboot manually
|
||||
|
||||
hostname: metal-{{ trunc 4 .MachineID }}
|
||||
users:
|
||||
- name: kairos
|
||||
passwd: kairos
|
||||
`
|
||||
})
|
||||
|
||||
It("boots and has an encrypted partition", func() {
|
||||
vm.Reboot()
|
||||
vm.EventuallyConnects(1200)
|
||||
out, err := vm.Sudo("blkid")
|
||||
Expect(err).ToNot(HaveOccurred(), out)
|
||||
Expect(out).To(MatchRegexp("TYPE=\"crypto_LUKS\" PARTLABEL=\"persistent\""), out)
|
||||
})
|
||||
})
|
||||
|
||||
//https://kairos.io/docs/advanced/partition_encryption/#online-mode
|
||||
When("using a remote key management server (automated passphrase generation)", Label("remote-auto"), func() {
|
||||
var tpmHash string
|
||||
var err error
|
||||
|
||||
BeforeEach(func() {
|
||||
tpmHash, err = vm.Sudo("/system/discovery/kcrypt-discovery-challenger")
|
||||
Expect(err).ToNot(HaveOccurred(), tpmHash)
|
||||
|
||||
kubectlApplyYaml(fmt.Sprintf(`---
|
||||
apiVersion: keyserver.kairos.io/v1alpha1
|
||||
kind: SealedVolume
|
||||
metadata:
|
||||
name: "%[1]s"
|
||||
namespace: default
|
||||
spec:
|
||||
TPMHash: "%[1]s"
|
||||
partitions:
|
||||
- label: COS_PERSISTENT
|
||||
quarantined: false
|
||||
`, strings.TrimSpace(tpmHash)))
|
||||
|
||||
config = fmt.Sprintf(`#cloud-config
|
||||
|
||||
hostname: metal-{{ trunc 4 .MachineID }}
|
||||
users:
|
||||
- name: kairos
|
||||
passwd: kairos
|
||||
|
||||
install:
|
||||
encrypted_partitions:
|
||||
- COS_PERSISTENT
|
||||
grub_options:
|
||||
extra_cmdline: "rd.neednet=1"
|
||||
reboot: false # we will reboot manually
|
||||
|
||||
kcrypt:
|
||||
challenger:
|
||||
challenger_server: "http://%s"
|
||||
nv_index: ""
|
||||
c_index: ""
|
||||
tpm_device: ""
|
||||
`, os.Getenv("KMS_ADDRESS"))
|
||||
})
|
||||
|
||||
AfterEach(func() {
|
||||
cmd := exec.Command("kubectl", "delete", "sealedvolume", tpmHash)
|
||||
out, err := cmd.CombinedOutput()
|
||||
Expect(err).ToNot(HaveOccurred(), out)
|
||||
})
|
||||
|
||||
It("creates a passphrase and a key/pair to decrypt it", func() {
|
||||
// Expect a LUKS partition
|
||||
vm.Reboot(750)
|
||||
vm.EventuallyConnects(1200)
|
||||
out, err := vm.Sudo("blkid")
|
||||
Expect(err).ToNot(HaveOccurred(), out)
|
||||
Expect(out).To(MatchRegexp("TYPE=\"crypto_LUKS\" PARTLABEL=\"persistent\""), out)
|
||||
|
||||
// Expect a secret to be created
|
||||
cmd := exec.Command("kubectl", "get", "secrets",
|
||||
fmt.Sprintf("%s-cos-persistent", tpmHash),
|
||||
"-o=go-template='{{.data.generated_by|base64decode}}'",
|
||||
)
|
||||
|
||||
secretOut, err := cmd.CombinedOutput()
|
||||
Expect(err).ToNot(HaveOccurred(), string(secretOut))
|
||||
Expect(string(secretOut)).To(MatchRegexp("tpm"))
|
||||
})
|
||||
})
|
||||
|
||||
// https://kairos.io/docs/advanced/partition_encryption/#scenario-static-keys
|
||||
When("using a remote key management server (static keys)", Label("remote-static"), func() {
|
||||
var tpmHash string
|
||||
var err error
|
||||
|
||||
BeforeEach(func() {
|
||||
tpmHash, err = vm.Sudo("/system/discovery/kcrypt-discovery-challenger")
|
||||
Expect(err).ToNot(HaveOccurred(), tpmHash)
|
||||
|
||||
kubectlApplyYaml(fmt.Sprintf(`---
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: %[1]s
|
||||
namespace: default
|
||||
type: Opaque
|
||||
stringData:
|
||||
pass: "awesome-plaintext-passphrase"
|
||||
`, tpmHash))
|
||||
|
||||
kubectlApplyYaml(fmt.Sprintf(`---
|
||||
apiVersion: keyserver.kairos.io/v1alpha1
|
||||
kind: SealedVolume
|
||||
metadata:
|
||||
name: %[1]s
|
||||
namespace: default
|
||||
spec:
|
||||
TPMHash: "%[1]s"
|
||||
partitions:
|
||||
- label: COS_PERSISTENT
|
||||
secret:
|
||||
name: %[1]s
|
||||
path: pass
|
||||
quarantined: false
|
||||
`, tpmHash))
|
||||
|
||||
config = fmt.Sprintf(`#cloud-config
|
||||
|
||||
hostname: metal-{{ trunc 4 .MachineID }}
|
||||
users:
|
||||
- name: kairos
|
||||
passwd: kairos
|
||||
|
||||
install:
|
||||
encrypted_partitions:
|
||||
- COS_PERSISTENT
|
||||
grub_options:
|
||||
extra_cmdline: "rd.neednet=1"
|
||||
reboot: false # we will reboot manually
|
||||
|
||||
kcrypt:
|
||||
challenger:
|
||||
challenger_server: "http://%s"
|
||||
nv_index: ""
|
||||
c_index: ""
|
||||
tpm_device: ""
|
||||
|
||||
`, os.Getenv("KMS_ADDRESS"))
|
||||
})
|
||||
|
||||
AfterEach(func() {
|
||||
cmd := exec.Command("kubectl", "delete", "sealedvolume", tpmHash)
|
||||
out, err := cmd.CombinedOutput()
|
||||
Expect(err).ToNot(HaveOccurred(), out)
|
||||
|
||||
cmd = exec.Command("kubectl", "delete", "secret", tpmHash)
|
||||
out, err = cmd.CombinedOutput()
|
||||
Expect(err).ToNot(HaveOccurred(), out)
|
||||
})
|
||||
|
||||
It("creates uses the existing passphrase to decrypt it", func() {
|
||||
// Expect a LUKS partition
|
||||
vm.Reboot()
|
||||
vm.EventuallyConnects(1200)
|
||||
out, err := vm.Sudo("blkid")
|
||||
Expect(err).ToNot(HaveOccurred(), out)
|
||||
Expect(out).To(MatchRegexp("TYPE=\"crypto_LUKS\" PARTLABEL=\"persistent\""), out)
|
||||
Expect(out).To(MatchRegexp("/dev/mapper.*LABEL=\"COS_PERSISTENT\""), out)
|
||||
})
|
||||
})
|
||||
|
||||
When("the key management server is listening on https", func() {
|
||||
var tpmHash string
|
||||
var err error
|
||||
|
||||
BeforeEach(func() {
|
||||
tpmHash, err = vm.Sudo("/system/discovery/kcrypt-discovery-challenger")
|
||||
Expect(err).ToNot(HaveOccurred(), tpmHash)
|
||||
|
||||
kubectlApplyYaml(fmt.Sprintf(`---
|
||||
apiVersion: keyserver.kairos.io/v1alpha1
|
||||
kind: SealedVolume
|
||||
metadata:
|
||||
name: "%[1]s"
|
||||
namespace: default
|
||||
spec:
|
||||
TPMHash: "%[1]s"
|
||||
partitions:
|
||||
- label: COS_PERSISTENT
|
||||
quarantined: false
|
||||
`, strings.TrimSpace(tpmHash)))
|
||||
})
|
||||
|
||||
When("the certificate is pinned on the configuration", Label("remote-https-pinned"), func() {
|
||||
BeforeEach(func() {
|
||||
cert := getChallengerServerCert()
|
||||
kcryptConfig := createConfigWithCert(fmt.Sprintf("https://%s", os.Getenv("KMS_ADDRESS")), cert)
|
||||
kcryptConfigBytes, err := yaml.Marshal(kcryptConfig)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
config = fmt.Sprintf(`#cloud-config
|
||||
|
||||
hostname: metal-{{ trunc 4 .MachineID }}
|
||||
users:
|
||||
- name: kairos
|
||||
passwd: kairos
|
||||
|
||||
install:
|
||||
encrypted_partitions:
|
||||
- COS_PERSISTENT
|
||||
grub_options:
|
||||
extra_cmdline: "rd.neednet=1"
|
||||
reboot: false # we will reboot manually
|
||||
|
||||
%s
|
||||
|
||||
`, string(kcryptConfigBytes))
|
||||
})
|
||||
|
||||
It("successfully talks to the server", func() {
|
||||
vm.Reboot()
|
||||
vm.EventuallyConnects(1200)
|
||||
out, err := vm.Sudo("blkid")
|
||||
Expect(err).ToNot(HaveOccurred(), out)
|
||||
Expect(out).To(MatchRegexp("TYPE=\"crypto_LUKS\" PARTLABEL=\"persistent\""), out)
|
||||
Expect(out).To(MatchRegexp("/dev/mapper.*LABEL=\"COS_PERSISTENT\""), out)
|
||||
})
|
||||
})
|
||||
|
||||
When("the no certificate is set in the configuration", Label("remote-https-bad-cert"), func() {
|
||||
BeforeEach(func() {
|
||||
config = fmt.Sprintf(`#cloud-config
|
||||
|
||||
hostname: metal-{{ trunc 4 .MachineID }}
|
||||
users:
|
||||
- name: kairos
|
||||
passwd: kairos
|
||||
|
||||
install:
|
||||
encrypted_partitions:
|
||||
- COS_PERSISTENT
|
||||
grub_options:
|
||||
extra_cmdline: "rd.neednet=1"
|
||||
reboot: false # we will reboot manually
|
||||
|
||||
kcrypt:
|
||||
challenger:
|
||||
challenger_server: "https://%s"
|
||||
nv_index: ""
|
||||
c_index: ""
|
||||
tpm_device: ""
|
||||
`, os.Getenv("KMS_ADDRESS"))
|
||||
})
|
||||
|
||||
It("fails to talk to the server", func() {
|
||||
out, err := vm.Sudo("cat manual-install.txt")
|
||||
Expect(err).ToNot(HaveOccurred(), out)
|
||||
Expect(out).To(MatchRegexp("could not encrypt partition.*x509: certificate signed by unknown authority"))
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
func printInstallationOutput(message string, callerSkip ...int) {
|
||||
fmt.Printf("This is the installation output in case it's useful:\n%s\n", installationOutput)
|
||||
|
||||
// Ensures the correct line numbers are reported
|
||||
Fail(message, callerSkip[0]+1)
|
||||
}
|
||||
|
||||
func kubectlApplyYaml(yamlData string) {
|
||||
yamlFile, err := os.CreateTemp("", "")
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
defer os.Remove(yamlFile.Name())
|
||||
|
||||
err = os.WriteFile(yamlFile.Name(), []byte(yamlData), 0744)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
cmd := exec.Command("kubectl", "apply", "-f", yamlFile.Name())
|
||||
out, err := cmd.CombinedOutput()
|
||||
Expect(err).ToNot(HaveOccurred(), out)
|
||||
}
|
||||
|
||||
func getChallengerServerCert() string {
|
||||
cmd := exec.Command(
|
||||
"kubectl", "get", "secret", "-n", "default", "kms-tls",
|
||||
"-o", `go-template={{ index .data "ca.crt" | base64decode }}`)
|
||||
out, err := cmd.CombinedOutput()
|
||||
Expect(err).ToNot(HaveOccurred(), string(out))
|
||||
|
||||
return string(out)
|
||||
}
|
||||
|
||||
func createConfigWithCert(server, cert string) client.Config {
|
||||
return client.Config{
|
||||
Kcrypt: struct {
|
||||
Challenger struct {
|
||||
Server string "yaml:\"challenger_server,omitempty\""
|
||||
NVIndex string "yaml:\"nv_index,omitempty\""
|
||||
CIndex string "yaml:\"c_index,omitempty\""
|
||||
TPMDevice string "yaml:\"tpm_device,omitempty\""
|
||||
Certificate string "yaml:\"certificate,omitempty\""
|
||||
}
|
||||
}{
|
||||
Challenger: struct {
|
||||
Server string "yaml:\"challenger_server,omitempty\""
|
||||
NVIndex string "yaml:\"nv_index,omitempty\""
|
||||
CIndex string "yaml:\"c_index,omitempty\""
|
||||
TPMDevice string "yaml:\"tpm_device,omitempty\""
|
||||
Certificate string "yaml:\"certificate,omitempty\""
|
||||
}{
|
||||
Server: server,
|
||||
NVIndex: "",
|
||||
CIndex: "",
|
||||
TPMDevice: "",
|
||||
Certificate: cert,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
191
tests/suite_test.go
Normal file
191
tests/suite_test.go
Normal file
@@ -0,0 +1,191 @@
|
||||
package e2e_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path"
|
||||
"strconv"
|
||||
"testing"
|
||||
|
||||
"github.com/google/uuid"
|
||||
process "github.com/mudler/go-processmanager"
|
||||
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
. "github.com/onsi/gomega"
|
||||
. "github.com/spectrocloud/peg/matcher"
|
||||
machine "github.com/spectrocloud/peg/pkg/machine"
|
||||
"github.com/spectrocloud/peg/pkg/machine/types"
|
||||
)
|
||||
|
||||
func TestE2e(t *testing.T) {
|
||||
RegisterFailHandler(Fail)
|
||||
RunSpecs(t, "kcrypt-challenger e2e test Suite")
|
||||
}
|
||||
|
||||
func user() string {
|
||||
user := os.Getenv("SSH_USER")
|
||||
if user == "" {
|
||||
user = "kairos"
|
||||
}
|
||||
return user
|
||||
}
|
||||
|
||||
func pass() string {
|
||||
pass := os.Getenv("SSH_PASS")
|
||||
if pass == "" {
|
||||
pass = "kairos"
|
||||
}
|
||||
|
||||
return pass
|
||||
}
|
||||
|
||||
func startVM() (context.Context, VM) {
|
||||
if os.Getenv("ISO") == "" {
|
||||
fmt.Println("ISO missing")
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
vmName := uuid.New().String()
|
||||
|
||||
stateDir, err := os.MkdirTemp("", "")
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
emulateTPM(stateDir)
|
||||
|
||||
sshPort, err := getFreePort()
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
memory := os.Getenv("MEMORY")
|
||||
if memory == "" {
|
||||
memory = "2096"
|
||||
}
|
||||
cpus := os.Getenv("CPUS")
|
||||
if cpus == "" {
|
||||
cpus = "2"
|
||||
}
|
||||
|
||||
opts := []types.MachineOption{
|
||||
types.QEMUEngine,
|
||||
types.WithISO(os.Getenv("ISO")),
|
||||
types.WithMemory(memory),
|
||||
types.WithCPU(cpus),
|
||||
types.WithSSHPort(strconv.Itoa(sshPort)),
|
||||
types.WithID(vmName),
|
||||
types.WithSSHUser(user()),
|
||||
types.WithSSHPass(pass()),
|
||||
types.OnFailure(func(p *process.Process) {
|
||||
defer GinkgoRecover()
|
||||
|
||||
var stdout, stderr, serial, status string
|
||||
|
||||
if stdoutBytes, err := os.ReadFile(p.StdoutPath()); err != nil {
|
||||
stdout = fmt.Sprintf("Error reading stdout file: %s\n", err)
|
||||
} else {
|
||||
stdout = string(stdoutBytes)
|
||||
}
|
||||
|
||||
if stderrBytes, err := os.ReadFile(p.StderrPath()); err != nil {
|
||||
stderr = fmt.Sprintf("Error reading stderr file: %s\n", err)
|
||||
} else {
|
||||
stderr = string(stderrBytes)
|
||||
}
|
||||
|
||||
if status, err = p.ExitCode(); err != nil {
|
||||
status = fmt.Sprintf("Error reading exit code file: %s\n", err)
|
||||
}
|
||||
|
||||
if serialBytes, err := os.ReadFile(path.Join(p.StateDir(), "serial.log")); err != nil {
|
||||
serial = fmt.Sprintf("Error reading serial log file: %s\n", err)
|
||||
} else {
|
||||
serial = string(serialBytes)
|
||||
}
|
||||
|
||||
Fail(fmt.Sprintf("\nVM Aborted.\nstdout: %s\nstderr: %s\nserial: %s\nExit status: %s\n",
|
||||
stdout, stderr, serial, status))
|
||||
}),
|
||||
types.WithStateDir(stateDir),
|
||||
// Serial output to file: https://superuser.com/a/1412150
|
||||
func(m *types.MachineConfig) error {
|
||||
m.Args = append(m.Args,
|
||||
"-chardev", fmt.Sprintf("socket,id=chrtpm,path=%s/swtpm-sock", path.Join(stateDir, "tpm")),
|
||||
"-tpmdev", "emulator,id=tpm0,chardev=chrtpm", "-device", "tpm-tis,tpmdev=tpm0",
|
||||
"-chardev", fmt.Sprintf("stdio,mux=on,id=char0,logfile=%s,signal=off", path.Join(stateDir, "serial.log")),
|
||||
"-serial", "chardev:char0",
|
||||
"-mon", "chardev=char0",
|
||||
)
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
// Set this to true to debug.
|
||||
// You can connect to it with "spicy" or other tool.
|
||||
var spicePort int
|
||||
if os.Getenv("MACHINE_SPICY") != "" {
|
||||
spicePort, err = getFreePort()
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
fmt.Printf("Spice port = %d\n", spicePort)
|
||||
opts = append(opts, types.WithDisplay(fmt.Sprintf("-spice port=%d,addr=127.0.0.1,disable-ticketing", spicePort)))
|
||||
}
|
||||
|
||||
if os.Getenv("KVM") != "" {
|
||||
opts = append(opts, func(m *types.MachineConfig) error {
|
||||
m.Args = append(m.Args,
|
||||
"-enable-kvm",
|
||||
)
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
m, err := machine.New(opts...)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
vm := NewVM(m, stateDir)
|
||||
|
||||
ctx, err := vm.Start(context.Background())
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
if os.Getenv("MACHINE_SPICY") != "" {
|
||||
cmd := exec.Command("spicy",
|
||||
"-h", "127.0.0.1",
|
||||
"-p", strconv.Itoa(spicePort))
|
||||
err = cmd.Start()
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
}
|
||||
|
||||
return ctx, vm
|
||||
}
|
||||
|
||||
// return the PID of the swtpm (to be killed later) and the state directory
|
||||
func emulateTPM(stateDir string) {
|
||||
t := path.Join(stateDir, "tpm")
|
||||
err := os.MkdirAll(t, os.ModePerm)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
cmd := exec.Command("swtpm",
|
||||
"socket",
|
||||
"--tpmstate", fmt.Sprintf("dir=%s", t),
|
||||
"--ctrl", fmt.Sprintf("type=unixio,path=%s/swtpm-sock", t),
|
||||
"--tpm2", "--log", "level=20")
|
||||
err = cmd.Start()
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
err = os.WriteFile(path.Join(t, "pid"), []byte(strconv.Itoa(cmd.Process.Pid)), 0744)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
}
|
||||
|
||||
// https://gist.github.com/sevkin/96bdae9274465b2d09191384f86ef39d
|
||||
// GetFreePort asks the kernel for a free open port that is ready to use.
|
||||
func getFreePort() (port int, err error) {
|
||||
var a *net.TCPAddr
|
||||
if a, err = net.ResolveTCPAddr("tcp", "localhost:0"); err == nil {
|
||||
var l *net.TCPListener
|
||||
if l, err = net.ListenTCP("tcp", a); err == nil {
|
||||
defer l.Close()
|
||||
return l.Addr().(*net.TCPAddr).Port, nil
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
Reference in New Issue
Block a user