Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
113 changes: 113 additions & 0 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,50 @@ jobs:
name: unit_coverage
path: tests_coverage

ai_tests_server:
name: AI-authored tests
runs-on: ubuntu-22.04
steps:
- name: Checkout code
uses: actions/checkout@v6

- name: Set up Go
uses: actions/setup-go@v6
with:
go-version-file: server/go.mod

- name: Install Task
uses: go-task/setup-task@v2
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}

- name: Prepare environment
run: |
sudo apt-get update
sudo apt-get install -y gpg
task --yes server:deps:install:c

- name: Set up git config
run: task --yes ci:setup:git-config

- name: Install 3p-git-signatures
run: task --yes ci:install:3p-git-signatures

- name: Install ginkgo
run: task --yes deps:install:ginkgo

- name: Start buildkitd
run: |
docker run --detach --name trdl-buildkitd --privileged \
--publish 1234:1234 moby/buildkit:v0.31.2 --addr tcp://0.0.0.0:1234
timeout 120 bash -c 'until docker exec trdl-buildkitd \
buildctl --addr tcp://127.0.0.1:1234 debug workers >/dev/null 2>&1; do sleep 2; done'

- name: Test
env:
TRDL_SMOKE_BUILDKITD_ADDRESS: tcp://127.0.0.1:1234
run: task --yes server:test:ai

unit_client:
name: Client unit tests
runs-on: ubuntu-22.04
Expand Down Expand Up @@ -133,11 +177,78 @@ jobs:
name: e2e_coverage
path: tests_coverage

e2e_buildkit:
name: End-to-end tests (BuildKit client)
runs-on: ubuntu-22.04
timeout-minutes: 30
steps:
- name: Checkout code
uses: actions/checkout@v6

- name: Set up Go
uses: actions/setup-go@v6
with:
go-version-file: e2e/go.mod

- name: Install Task
uses: go-task/setup-task@v2
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}

- name: Set up prebuilt trdl test binary
run: |
task --yes client:build-with-coverage
echo TRDL_TEST_BINARY_PATH=$GITHUB_WORKSPACE/bin/coverage/trdl >> $GITHUB_ENV
echo TRDL_TEST_COVERAGE_DIR=$GITHUB_WORKSPACE/tests_coverage/e2e >> $GITHUB_ENV

- name: Set up git config
run: task --yes ci:setup:git-config

- name: Prepare environment
run: |
sudo apt-get update
sudo apt-get install -y gpg
task --yes server:deps:install:c

- name: Install 3p-git-signatures
run: task --yes ci:install:3p-git-signatures

- name: Install ginkgo
run: task --yes -p deps:install:ginkgo

- name: Setup vault
run: |
task --yes server:setup-vault-local
echo "$HOME/bin" >> $GITHUB_PATH

- name: Start buildkitd
run: |
docker run --detach --name trdl-buildkitd --privileged \
--publish 1234:1234 moby/buildkit:v0.31.2 --addr tcp://0.0.0.0:1234
timeout 120 bash -c 'until docker exec trdl-buildkitd \
buildctl --addr tcp://127.0.0.1:1234 debug workers >/dev/null 2>&1; do sleep 2; done'

- name: Test
env:
TRDL_TEST_BUILDKITD_ADDRESS: tcp://127.0.0.1:1234
run: task --yes e2e:test:e2e:flow-vault

- name: Collect buildkitd diagnostics
if: failure()
run: docker logs trdl-buildkitd || true

- name: Upload coverage artifact
uses: actions/upload-artifact@v7
with:
name: e2e_coverage_buildkit
path: tests_coverage

upload_coverage:
name: Upload coverage
needs:
- unit_server
- e2e_tests
- e2e_buildkit
runs-on: ubuntu-22.04
steps:
- name: Checkout code
Expand All @@ -158,8 +269,10 @@ jobs:
if: always()
needs:
- unit_server
- ai_tests_server
- unit_client
- e2e_tests
- e2e_buildkit
- upload_coverage
uses: werf/common-ci/.github/workflows/notification.yml@main
secrets:
Expand Down
1 change: 1 addition & 0 deletions docs/_includes/reference/vault_plugin/configure.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ Configure the plugin.

### Parameters

* `buildkitd_address` (string, optional) — An address of a running buildkitd (unix://, tcp://, docker-container:// or kube-pod:// scheme) to build release artifacts with the BuildKit client; the docker CLI is used if not set. Build secrets are sent to that daemon, and tcp:// is neither encrypted nor authenticated, so securing the channel and isolating the daemon is the administrator's responsibility.
* `git_repo_url` (string, required) — URL of the Git repository.
* `git_trdl_channels_branch` (string, optional) — A special Git branch to store the trdl channels configuration file.
* `git_trdl_channels_path` (string, optional) — A path in the Git repository to the trdl channels configuration file (trdl_channels.yaml is used by default).
Expand Down
25 changes: 24 additions & 1 deletion docs/pages_en/QUICKSTART.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,9 +52,32 @@ Notes on the `kubernetes` driver:

* the target namespace must exist, and the Vault process needs permissions to manage Deployments and Pods in it: the builder runs as a BuildKit Deployment and is removed after the build;
* the cluster is targeted via the standard kubeconfig or in-cluster ServiceAccount resolution;
* rootless BuildKit (`rootless=true`) requires the PodSecurity level `baseline`; it does not run under `restricted`;
* rootless BuildKit (`rootless=true`) does not fit the `baseline` PodSecurity level either: buildx gives the builder pod `seccompProfile: Unconfined` and the `unconfined` AppArmor annotation, and both are already forbidden at `baseline`. The builder namespace has to be labelled `privileged` (or be exempt from PodSecurity admission);
* see the [buildx kubernetes driver documentation](https://docs.docker.com/build/builders/drivers/kubernetes/) for the available driver options.

#### Building against an external buildkitd

Both buildx drivers above shell out to the `docker` CLI, so they require the binary to be present next to the plugin. When the plugin runs in an environment without the `docker` binary (for example, embedded into another process shipped in a distroless image), the build can be pointed at an already running `buildkitd` instead: the plugin then talks to it directly with the BuildKit client, and no builder is provisioned or removed per build.

The buildkitd address is set per project in the plugin configuration:

```shell
vault write trdl-test-project/configure ... buildkitd_address=tcp://buildkitd.trdl-build.svc:1234
```

or, as a fallback for all projects, with the `TRDL_BUILDKITD_ADDRESS` environment variable of the Vault process. The per-project setting takes precedence. The supported address schemes are:

* `unix://` and `tcp://` — direct gRPC connection to buildkitd, no external binaries required;
* `docker-container://` and `kube-pod://` — connection through `docker exec`/`kubectl exec`, requiring the corresponding CLI.

When `buildkitd_address` is not set, builds go through `docker buildx` exactly as described above. Deploying `buildkitd` itself is out of trdl's scope: on Kubernetes it is typically a Deployment or StatefulSet in a dedicated namespace whose PodSecurity labels are managed by the cluster owner, since BuildKit requires a relaxed seccomp/AppArmor profile even in rootless mode.

Securing the connection and isolating the daemon is the administrator's responsibility. The plugin sends the entire build context and every build secret over this connection — the project build secrets and, when mac signing is configured, the signing certificate, its password and the notary key. What that requires:

* **`tcp://` is plaintext and unauthenticated.** The plugin neither encrypts the traffic nor verifies the identity of the daemon it connects to, so anyone able to intercept the connection or take over the endpoint's address receives those secrets. Use `tcp://` only over a channel made confidential and authenticated by other means — a network segment no other workload can reach, a service mesh with mTLS, or an equivalent tunnel. When that cannot be guaranteed, run buildkitd alongside the plugin and use `unix://` to a socket shared between them.
* **The address is a trust boundary.** Whoever can write the project configuration, or set `TRDL_BUILDKITD_ADDRESS` for the Vault process, decides which daemon receives the release secrets. Write access to `<project>/configure` has to be restricted to the same people who are trusted with the release keys.
* **The daemon is shared and unrestricted.** buildkitd executes the project's build instructions, and no builder is created or removed per build, so concurrent releases and every project pointed at the same address share one instance, its cache and its privileges. Dedicate an instance per trust domain, and treat access to it as access to the release artifacts it produces.

### Setting up the project

#### Git repository
Expand Down
25 changes: 24 additions & 1 deletion docs/pages_ru/QUICKSTART.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,32 @@ TRDL_BUILDX_DRIVER_OPTS_KUBE='namespace=trdl-build;rootless=true'

* целевой namespace должен существовать, а процессу Vault нужны права на управление Deployment и Pod в нём: сборщик работает как BuildKit Deployment и удаляется после сборки;
* кластер определяется стандартным способом — через kubeconfig или in-cluster ServiceAccount;
* rootless BuildKit (`rootless=true`) требует уровень PodSecurity `baseline`; под `restricted` он не работает;
* rootless BuildKit (`rootless=true`) не укладывается и в уровень PodSecurity `baseline`: buildx задаёт поду сборщика `seccompProfile: Unconfined` и AppArmor-аннотацию `unconfined`, а оба этих значения запрещены уже на `baseline`. Namespace сборщика должен быть помечен как `privileged` (либо исключён из PodSecurity-admission);
* доступные опции драйвера — в [документации buildx kubernetes driver](https://docs.docker.com/build/builders/drivers/kubernetes/).

#### Сборка через внешний buildkitd

Оба buildx-драйвера выше запускают CLI `docker`, поэтому требуют наличия бинарника рядом с плагином. Если плагин работает в окружении без бинарника `docker` (например, встроен в другой процесс, поставляемый в distroless-образе), сборку можно направить на уже запущенный `buildkitd`: плагин обращается к нему напрямую через клиент BuildKit, и сборщик не создаётся и не удаляется на каждую сборку.

Адрес buildkitd задаётся для каждого проекта в конфигурации плагина:

```shell
vault write trdl-test-project/configure ... buildkitd_address=tcp://buildkitd.trdl-build.svc:1234
```

или, как запасной вариант для всех проектов, переменной окружения `TRDL_BUILDKITD_ADDRESS` процесса Vault. Значение из конфигурации проекта имеет приоритет. Поддерживаемые схемы адреса:

* `unix://` и `tcp://` — прямое gRPC-соединение с buildkitd, внешние бинарники не нужны;
* `docker-container://` и `kube-pod://` — соединение через `docker exec`/`kubectl exec`, требуется соответствующий CLI.

Если `buildkitd_address` не задан, сборка идёт через `docker buildx`, как описано выше. Развёртывание самого `buildkitd` находится вне зоны ответственности trdl: в Kubernetes это обычно Deployment или StatefulSet в отдельном namespace, метки PodSecurity которого задаёт владелец кластера, поскольку BuildKit требует ослабленный профиль seccomp/AppArmor даже в rootless-режиме.

Защита канала и изоляция демона — ответственность администратора. Через это соединение плагин передаёт весь контекст сборки и все секреты сборки: секреты проекта, а если настроена подпись для macOS — сертификат подписи, его пароль и notary-ключ. Что из этого следует:

* **`tcp://` — соединение без шифрования и без аутентификации.** Плагин не шифрует трафик и не проверяет идентичность демона, к которому подключается, поэтому любой, кто способен перехватить соединение или занять адрес endpoint'а, получает эти секреты. Используйте `tcp://` только поверх канала, конфиденциальность и аутентичность которого обеспечены иными средствами: сетевой сегмент, недоступный другим нагрузкам, service mesh с mTLS или равноценный туннель. Если это не гарантировано, запускайте buildkitd рядом с плагином и используйте `unix://` с общим сокетом.
* **Адрес — граница доверия.** Тот, кто может записать конфигурацию проекта или задать `TRDL_BUILDKITD_ADDRESS` для процесса Vault, выбирает, какой демон получит секреты релиза. Право записи в `<проект>/configure` должно быть только у тех, кому доверены ключи релиза.
* **Демон общий и ничем не ограничен.** buildkitd выполняет инструкции сборки проекта, при этом сборщик не создаётся и не удаляется на каждую сборку — параллельные релизы и все проекты, направленные на один адрес, используют один экземпляр, его кэш и его привилегии. Выделяйте отдельный экземпляр на каждый домен доверия и считайте доступ к нему доступом к выпускаемым артефактам.

### Подготовка проекта

#### Git-репозиторий
Expand Down
2 changes: 1 addition & 1 deletion e2e/Taskfile.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ tasks:
outputDir: '{{.outputDir | default "../tests_coverage/e2e" }}'

test:e2e:flow-vault:
desc: "Run the Vault plugin e2e test. Honours TRDL_BUILDX_DRIVER, so it doubles as the buildx driver check."
desc: "Run the Vault plugin e2e test. Honours TRDL_BUILDX_DRIVER and TRDL_TEST_BUILDKITD_ADDRESS, so it doubles as the buildx driver and BuildKit client check."
cmd: ginkgo --vv --keep-going --cover --covermode=atomic --coverpkg=github.com/werf/trdl/client/...,github.com/werf/trdl/server/... --output-dir={{.outputDir}} ./tests/flow_vault
vars:
outputDir: '{{.outputDir | default "../tests_coverage/e2e" }}'
Expand Down
Loading
Loading