Compare commits

..

60 Commits

Author SHA1 Message Date
Itxaka
b5b4d0d042 🤖 Add concurrency to CI (#33) 2023-06-15 11:20:19 +02:00
renovate[bot]
8420155746 Update docker/build-push-action action to v4 (#32)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-06-15 11:15:24 +02:00
renovate[bot]
a9359bf713 Update actions/checkout action to v3 (#31)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-06-15 11:15:01 +02:00
renovate[bot]
b31467e925 Update module github.com/mudler/yip to v1.2.0 (#28)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-06-15 11:14:48 +02:00
renovate[bot]
c5dc8db56b Update module github.com/jaypipes/ghw to v0.11.0 (#26)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-06-15 11:10:42 +02:00
renovate[bot]
a80703a556 Update module github.com/onsi/gomega to v1.27.8 (#24)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-06-15 11:10:22 +02:00
renovate[bot]
0b6f771d32 Update module github.com/kairos-io/kcrypt to v0.7.0 (#27)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-06-15 11:08:46 +02:00
renovate[bot]
72dd7d3e50 Update module github.com/onsi/ginkgo/v2 to v2.10.0 (#29)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-06-15 11:08:11 +02:00
Itxaka
0619047a20 Drop kairos and use sdk for collector (#20) 2023-06-15 09:35:01 +02:00
renovate[bot]
715664969a Add renovate.json (#6)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Itxaka <itxaka.garcia@spectrocloud.com>
2023-06-14 14:38:01 +02:00
Mauro Morales
bcda5b5b38 Update issue templates
relates to https://github.com/kairos-io/kairos/issues/1483
2023-06-13 12:17:08 +02:00
Itxaka
b2a0330dd8 Fix lint
Signed-off-by: Itxaka <itxaka.garcia@spectrocloud.com>
2023-05-10 00:31:15 +02:00
Itxaka
0b68d90081 Bump ghw and fix label (#17)
* Bump ghw and fix label

old label was the new FilesystemLabel. Now the label refers to the
partition label which is different

Signed-off-by: Itxaka <itxaka.garcia@spectrocloud.com>

* bump deps

Signed-off-by: Itxaka <itxaka.garcia@spectrocloud.com>

* Rework ginkgo

Signed-off-by: Itxaka <itxaka.garcia@spectrocloud.com>

* docker login

Signed-off-by: Itxaka <itxaka.garcia@spectrocloud.com>

* [Will drop]Allow building kcrypt from branches

Otherwise any changes that need both wont pass tests.

Signed-off-by: Itxaka <itxaka.garcia@spectrocloud.com>

* Dont build the iso 5 times

Signed-off-by: Itxaka <itxaka.garcia@spectrocloud.com>

* This confirms Im dumb and dont know how to program

Signed-off-by: Itxaka <itxaka.garcia@spectrocloud.com>

* debug logs

Signed-off-by: Itxaka <itxaka.garcia@spectrocloud.com>

* debug

Signed-off-by: Itxaka <itxaka.garcia@spectrocloud.com>

* 🤖 run in github CI

Signed-off-by: Itxaka <itxaka.garcia@spectrocloud.com>

* Debug

Signed-off-by: Itxaka <itxaka.garcia@spectrocloud.com>

* debug

Signed-off-by: Itxaka <itxaka.garcia@spectrocloud.com>

* Add /tmp/oem to scan dirs for config

Signed-off-by: Itxaka <itxaka.garcia@spectrocloud.com>

---------

Signed-off-by: Itxaka <itxaka.garcia@spectrocloud.com>
2023-05-10 00:24:58 +02:00
Itxaka
40267d4c24 Merge pull request #13 from kairos-io/bump-go-version-to-1.20.2
⬆️ Bump go to 1.20
2023-03-30 21:37:09 +02:00
Mauro Morales
e0ae7a12a4 Remove golint cuz it has some issues with cgo
Signed-off-by: Mauro Morales <mauro.morales@spectrocloud.com>
2023-03-30 09:21:09 +02:00
Mauro Morales
c2c50877da Remove patch number from defined go version
Signed-off-by: Mauro Morales <mauro.morales@spectrocloud.com>
2023-03-30 09:19:58 +02:00
Mauro Morales
7a2627fcc8 Add go version to workflow
Signed-off-by: Mauro Morales <mauro.morales@spectrocloud.com>
2023-03-29 15:47:00 +02:00
Mauro Morales
a0c4462f99 Update setup-go to v4
Signed-off-by: Mauro Morales <mauro.morales@spectrocloud.com>
2023-03-29 15:44:09 +02:00
Mauro Morales
145dd400b1 Add lint workflow
Signed-off-by: Mauro Morales <mauro.morales@spectrocloud.com>
2023-03-29 15:33:27 +02:00
Mauro Morales
95dbb0d0be Add yamllint
Signed-off-by: Mauro Morales <mauro.morales@spectrocloud.com>
2023-03-29 14:33:29 +02:00
Mauro Morales
0e56e52cbf Bump go to 1.20
Signed-off-by: Mauro Morales <mauro.morales@spectrocloud.com>
2023-03-29 14:28:45 +02:00
Dimitris Karakasilis
3a22134226 Run tests with sudo to be able to access /dev/kvm
Signed-off-by: Dimitris Karakasilis <dimitris@karakasilis.me>
2023-02-20 12:33:44 +02:00
Dimitris Karakasilis
7b561efed8 Try KVM on CI
Signed-off-by: Dimitris Karakasilis <dimitris@karakasilis.me>
2023-02-17 17:59:38 +02:00
Dimitris Karakasilis
6ff6262459 Configure earthly to use the docker mirror in CI
Signed-off-by: Dimitris Karakasilis <dimitris@karakasilis.me>
2023-02-17 17:11:26 +02:00
Dimitris Karakasilis
816013d33d Don't use the earthly script
in order to avoid nested docker and use the deployed docker mirror

Signed-off-by: Dimitris Karakasilis <dimitris@karakasilis.me>
2023-02-17 16:06:51 +02:00
Dimitris Karakasilis
8d0fb0148d export KUBECONFIG so that it's set when running commands in go tests
Error:

```
  [FAILED] Error from server (NotFound): namespaces "actions-runner-system" not found
```
coming from: /runner/_work/kcrypt-challenger/kcrypt-challenger/tests/encryption_test.go:157

is suspicious. That namespace shouldn't exist in the test k3d cluster,
no idea why it was looked up. I suspect the env for the following
command somehow pointed to the "outer" cluster:

```
cmd := exec.Command("kubectl", "get", "secrets", ...)
```

Signed-off-by: Dimitris Karakasilis <dimitris@karakasilis.me>
2023-02-17 15:53:02 +02:00
Dimitris Karakasilis
ffd5f18bcf Fix error interface conversion: interface {} is []uint8, not string
Signed-off-by: Dimitris Karakasilis <dimitris@karakasilis.me>
2023-02-17 15:20:18 +02:00
Dimitris Karakasilis
3b89def5b4 Make sure we run command in bash to avoid error in Ubuntu
```
set: Illegal option -o pipefail
```

Signed-off-by: Dimitris Karakasilis <dimitris@karakasilis.me>
2023-02-17 12:38:22 +02:00
Dimitris Karakasilis
887d67907b Avoid the host cluster CIDR to let DNS work in k3d
Signed-off-by: Dimitris Karakasilis <dimitris@karakasilis.me>
2023-02-17 11:52:14 +02:00
Dimitris Karakasilis
b0a7aa5fdf Revert "Try to fix the MTU problem in a hackish way (tmp)"
This reverts commit 40875bbae1.
2023-02-16 11:14:30 +02:00
Dimitris Karakasilis
40875bbae1 Try to fix the MTU problem in a hackish way (tmp)
Signed-off-by: Dimitris Karakasilis <dimitris@karakasilis.me>
2023-02-16 10:36:45 +02:00
Dimitris Karakasilis
7166b14c7e Revert "Bump earthly"
This reverts commit 9eb5d9b086.
2023-02-16 09:57:25 +02:00
Dimitris Karakasilis
9eb5d9b086 Bump earthly
hoping to get this fix:
https://github.com/earthly/earthly/issues/1934#issuecomment-1160819298

and see if it makes any difference

Signed-off-by: Dimitris Karakasilis <dimitris@karakasilis.me>
2023-02-16 09:53:30 +02:00
Dimitris Karakasilis
4da6a4f3b0 "Modernize" the +iso target
according to this example:
4e2dd37e70/Earthfile (L114)

Signed-off-by: Dimitris Karakasilis <dimitris@karakasilis.me>
2023-02-16 09:08:15 +02:00
Dimitris Karakasilis
74fc9c62b4 Switch to ubuntu because opensuse repos time out
Signed-off-by: Dimitris Karakasilis <dimitris@karakasilis.me>
2023-02-15 18:41:15 +02:00
Dimitris Karakasilis
f3f10b4919 Don't prompt
Signed-off-by: Dimitris Karakasilis <dimitris@karakasilis.me>
2023-02-15 18:10:01 +02:00
Dimitris Karakasilis
3d4829859b Run e2e tests on self-hosted runners
Signed-off-by: Dimitris Karakasilis <dimitris@karakasilis.me>
2023-02-15 17:52:14 +02:00
Dimitris Karakasilis
8a17ff714c Merge pull request #12 from kairos-io/346-tls-support
346 tls support
2023-02-15 12:28:20 +02:00
Dimitris Karakasilis
27114b8db8 Run e2e tests without earthly
getting closer to running them with KVM enabled. This will require self
hosted runners with KVM enabled but we will get there eventually.

Signed-off-by: Dimitris Karakasilis <dimitris@karakasilis.me>
2023-02-15 11:00:24 +02:00
Dimitris Karakasilis
1e3efb57cc Split scenarios in different GA jobs
to parallelise better and allow re-running just the failed tests

Signed-off-by: Dimitris Karakasilis <dimitris@karakasilis.me>
2023-02-15 09:58:16 +02:00
Dimitris Karakasilis
0c236b6145 Let OnFailure handle abnormal VM termination
now that peg gracefully terminates the VM when `Destroy` is called.

Signed-off-by: Dimitris Karakasilis <dimitris@karakasilis.me>
2023-02-14 16:15:11 +02:00
Dimitris Karakasilis
d390f77688 Bump peg (after merging PR#9)
Signed-off-by: Dimitris Karakasilis <dimitris@karakasilis.me>
2023-02-14 10:48:08 +02:00
Dimitris Karakasilis
266c4f20e9 Handle unexpected VM exit better and use a core image with working DNS
Also print serial output when something goes wrong

Signed-off-by: Dimitris Karakasilis <dimitris@karakasilis.me>
2023-02-14 10:09:46 +02:00
Dimitris Karakasilis
4c0b40d3a0 Add gettext-runtime in Earthly image
which provides the `envsubst` command needed in the e2e test script

Signed-off-by: Dimitris Karakasilis <dimitris@karakasilis.me>
2023-02-09 12:10:38 +02:00
Dimitris Karakasilis
08bb62f94e Remove TODO
Signed-off-by: Dimitris Karakasilis <dimitris@karakasilis.me>
2023-02-09 12:03:24 +02:00
Dimitris Karakasilis
0d3406fa7b Fallback to system CAs
No automated test for this case because it's complicated to get a
properly signed certificate in tests:

- the domain we use is sslip.io (not sure if letsencrypt would sign it)
- we need to use the letsencrypt production and that has quotas not
  suitable for CI

Signed-off-by: Dimitris Karakasilis <dimitris@karakasilis.me>
2023-02-09 11:48:59 +02:00
Dimitris Karakasilis
1cd4d9a7af Implement test that checks invalid cert case
Signed-off-by: Dimitris Karakasilis <dimitris@karakasilis.me>
2023-02-09 11:48:59 +02:00
Dimitris Karakasilis
d875e54171 Implement pinned certs
Signed-off-by: Dimitris Karakasilis <dimitris@karakasilis.me>
2023-02-09 11:48:59 +02:00
Dimitris Karakasilis
2967fb0a6c [WIP] Implement failing test for pinned cert
Signed-off-by: Dimitris Karakasilis <dimitris@karakasilis.me>
2023-02-09 11:48:59 +02:00
Dimitris Karakasilis
e9433d2ba7 Move challenger server inside the cluster and serve with TLS
Signed-off-by: Dimitris Karakasilis <dimitris@karakasilis.me>
2023-02-09 11:48:59 +02:00
Ettore Di Giacinto
7abdc7b092 📖 Update README 2023-02-07 12:29:13 +01:00
Dimitris Karakasilis
9448ecdd54 Ignore README changes in e2e workflow
Signed-off-by: Dimitris Karakasilis <dimitris@karakasilis.me>
2023-02-02 12:06:19 +02:00
Dimitris Karakasilis
d8cd48b411 Fix link in README to send users directly to "main" runs
Signed-off-by: Dimitris Karakasilis <dimitris@karakasilis.me>
2023-02-02 12:03:55 +02:00
Dimitris Karakasilis
43d629c974 Show "main" status in badge
Signed-off-by: Dimitris Karakasilis <dimitris@karakasilis.me>
2023-02-02 12:02:02 +02:00
Dimitris Karakasilis
b00d3af43b Rename "master" to "main" so that e2e tests run correctly
Signed-off-by: Dimitris Karakasilis <dimitris@karakasilis.me>
2023-02-02 11:58:12 +02:00
Dimitris Karakasilis
7d83e07b05 Fix typo in badge url
Signed-off-by: Dimitris Karakasilis <dimitris@karakasilis.me>
2023-02-02 11:56:38 +02:00
Dimitris Karakasilis
2fe3f3bc00 Add badges to the README
Signed-off-by: Dimitris Karakasilis <dimitris@karakasilis.me>
2023-02-02 11:54:45 +02:00
Dimitris Karakasilis
791d9dbb8b Merge pull request #11 from kairos-io/e2e-tests
E2e tests
2023-02-02 11:49:35 +02:00
Dimitris Karakasilis
7dc1e39ac7 Implement an e2e test suite for kcrypt encryption
Scenarios based on docs: https://kairos.io/docs/advanced/partition_encryption/

Signed-off-by: Dimitris Karakasilis <dimitris@karakasilis.me>
2023-02-02 11:48:44 +02:00
mudler
076a50b2e9 Drop unnecessary condition
Signed-off-by: mudler <mudler@c3os.io>
2023-01-24 17:53:38 +01:00
26 changed files with 1498 additions and 649 deletions

View 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
View 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

View File

@@ -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
View 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

View File

@@ -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
View 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

View File

@@ -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

View File

@@ -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/

View File

@@ -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

View File

@@ -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:
```

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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)
}

View File

@@ -82,4 +82,4 @@ spec:
- name: wss
port: 8082
protocol: TCP
targetPort: wss
targetPort: wss

View File

@@ -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() {

View File

@@ -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
View File

@@ -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
)

807
go.sum

File diff suppressed because it is too large Load Diff

6
renovate.json Normal file
View File

@@ -0,0 +1,6 @@
{
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
"extends": [
"config:base"
]
}

62
scripts/e2e-tests.sh Executable file
View 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/

View 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

View 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

View File

@@ -0,0 +1,8 @@
---
# Self-signed issuer
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: selfsigned
spec:
selfSigned: {}

View 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
View 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
View 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
}