From 053ac39f1d130305cab4c152c20074c55431db7d Mon Sep 17 00:00:00 2001 From: Maksim Khimchenko Date: Fri, 26 Jun 2026 13:35:01 +0300 Subject: [PATCH 1/2] Add VEX attestation infrastructure for module builds. Enable cosign OpenVEX signing via base/vex image, giterminism secrets for registry and Vault, and CI build credentials. Signed-off-by: Maksim Khimchenko --- .github/workflows/build_dev.yml | 4 +- .github/workflows/build_prod.yml | 20 +++-- .github/workflows/deploy_dev.yml | 2 +- .werf/base-images.yaml | 7 ++ .werf/defines/vex.tmpl | 143 +++++++++++++++++++++++++++++++ werf-giterminism.yaml | 14 +++ 6 files changed, 183 insertions(+), 7 deletions(-) create mode 100644 .werf/defines/vex.tmpl diff --git a/.github/workflows/build_dev.yml b/.github/workflows/build_dev.yml index 6e88c9e..789123e 100644 --- a/.github/workflows/build_dev.yml +++ b/.github/workflows/build_dev.yml @@ -130,11 +130,13 @@ jobs: registry: ${{ vars.DEV_REGISTRY }} registry_login: ${{ vars.DEV_MODULES_REGISTRY_LOGIN }} registry_password: ${{ secrets.DEV_MODULES_REGISTRY_PASSWORD }} - - uses: deckhouse/modules-actions/build@v4 + - uses: deckhouse/modules-actions/build@v15 with: module_source: "${{ vars.DEV_MODULE_SOURCE }}" module_name: ${{ vars.MODULE_NAME }} module_tag: ${{ env.MODULES_MODULE_TAG }} + registry_user: ${{ vars.DEV_MODULES_REGISTRY_LOGIN }} + registry_password: ${{ secrets.DEV_MODULES_REGISTRY_PASSWORD }} source_repo: ${{ secrets.SOURCE_REPO }} source_repo_ssh_key: ${{ secrets.SOURCE_REPO_SSH_KEY }} svace_enabled: ${{ contains(github.event.pull_request.labels.*.name, 'analyze/svace') || inputs.svace_enabled == true }} diff --git a/.github/workflows/build_prod.yml b/.github/workflows/build_prod.yml index 1c6ccbe..142d263 100644 --- a/.github/workflows/build_prod.yml +++ b/.github/workflows/build_prod.yml @@ -52,12 +52,14 @@ jobs: registry: ${{ vars.DEV_REGISTRY }} registry_login: ${{ vars.DEV_MODULES_REGISTRY_LOGIN }} registry_password: ${{ secrets.DEV_MODULES_REGISTRY_PASSWORD }} - - uses: deckhouse/modules-actions/build@v4 + - uses: deckhouse/modules-actions/build@v15 with: module_source: "${{ vars.PROD_REGISTRY }}/${{ vars.PROD_MODULE_SOURCE_NAME }}/ce/modules" module_name: ${{ vars.MODULE_NAME }} module_tag: ${{ github.ref_name }} secondary_repo: "${{ vars.DEV_MODULE_SOURCE }}/${{ vars.MODULE_NAME }}" + registry_user: ${{ vars.DEV_MODULES_REGISTRY_LOGIN }} + registry_password: ${{ secrets.DEV_MODULES_REGISTRY_PASSWORD }} source_repo: ${{ secrets.SOURCE_REPO }} source_repo_ssh_key: ${{ secrets.SOURCE_REPO_SSH_KEY }} @@ -95,12 +97,14 @@ jobs: registry: ${{ vars.DEV_REGISTRY }} registry_login: ${{ vars.DEV_MODULES_REGISTRY_LOGIN }} registry_password: ${{ secrets.DEV_MODULES_REGISTRY_PASSWORD }} - - uses: deckhouse/modules-actions/build@v4 + - uses: deckhouse/modules-actions/build@v15 with: module_source: "${{ vars.PROD_REGISTRY }}/${{ vars.PROD_MODULE_SOURCE_NAME }}/ee/modules" module_name: ${{ vars.MODULE_NAME }} module_tag: ${{ github.ref_name }} secondary_repo: "${{ vars.DEV_MODULE_SOURCE }}/${{ vars.MODULE_NAME }}" + registry_user: ${{ vars.DEV_MODULES_REGISTRY_LOGIN }} + registry_password: ${{ secrets.DEV_MODULES_REGISTRY_PASSWORD }} source_repo: ${{ secrets.SOURCE_REPO }} source_repo_ssh_key: ${{ secrets.SOURCE_REPO_SSH_KEY }} @@ -138,12 +142,14 @@ jobs: registry: ${{ vars.DEV_REGISTRY }} registry_login: ${{ vars.DEV_MODULES_REGISTRY_LOGIN }} registry_password: ${{ secrets.DEV_MODULES_REGISTRY_PASSWORD }} - - uses: deckhouse/modules-actions/build@v4 + - uses: deckhouse/modules-actions/build@v15 with: module_source: "${{ vars.PROD_REGISTRY }}/${{ vars.PROD_MODULE_SOURCE_NAME }}/fe/modules" module_name: ${{ vars.MODULE_NAME }} module_tag: ${{ github.ref_name }} secondary_repo: "${{ vars.DEV_MODULE_SOURCE }}/${{ vars.MODULE_NAME }}" + registry_user: ${{ vars.DEV_MODULES_REGISTRY_LOGIN }} + registry_password: ${{ secrets.DEV_MODULES_REGISTRY_PASSWORD }} source_repo: ${{ secrets.SOURCE_REPO }} source_repo_ssh_key: ${{ secrets.SOURCE_REPO_SSH_KEY }} @@ -181,12 +187,14 @@ jobs: registry: ${{ vars.DEV_REGISTRY }} registry_login: ${{ vars.DEV_MODULES_REGISTRY_LOGIN }} registry_password: ${{ secrets.DEV_MODULES_REGISTRY_PASSWORD }} - - uses: deckhouse/modules-actions/build@v4 + - uses: deckhouse/modules-actions/build@v15 with: module_source: "${{ vars.PROD_REGISTRY }}/${{ vars.PROD_MODULE_SOURCE_NAME }}/se/modules" module_name: ${{ vars.MODULE_NAME }} module_tag: ${{ github.ref_name }} secondary_repo: "${{ vars.DEV_MODULE_SOURCE }}/${{ vars.MODULE_NAME }}" + registry_user: ${{ vars.DEV_MODULES_REGISTRY_LOGIN }} + registry_password: ${{ secrets.DEV_MODULES_REGISTRY_PASSWORD }} source_repo: ${{ secrets.SOURCE_REPO }} source_repo_ssh_key: ${{ secrets.SOURCE_REPO_SSH_KEY }} @@ -224,11 +232,13 @@ jobs: registry: ${{ vars.DEV_REGISTRY }} registry_login: ${{ vars.DEV_MODULES_REGISTRY_LOGIN }} registry_password: ${{ secrets.DEV_MODULES_REGISTRY_PASSWORD }} - - uses: deckhouse/modules-actions/build@v4 + - uses: deckhouse/modules-actions/build@v15 with: module_source: "${{ vars.PROD_REGISTRY }}/${{ vars.PROD_MODULE_SOURCE_NAME }}/se-plus/modules" module_name: ${{ vars.MODULE_NAME }} module_tag: ${{ github.ref_name }} secondary_repo: "${{ vars.DEV_MODULE_SOURCE }}/${{ vars.MODULE_NAME }}" + registry_user: ${{ vars.DEV_MODULES_REGISTRY_LOGIN }} + registry_password: ${{ secrets.DEV_MODULES_REGISTRY_PASSWORD }} source_repo: ${{ secrets.SOURCE_REPO }} source_repo_ssh_key: ${{ secrets.SOURCE_REPO_SSH_KEY }} diff --git a/.github/workflows/deploy_dev.yml b/.github/workflows/deploy_dev.yml index 83081a6..2fae061 100644 --- a/.github/workflows/deploy_dev.yml +++ b/.github/workflows/deploy_dev.yml @@ -62,7 +62,7 @@ jobs: registry_login: ${{ vars.DEV_MODULES_REGISTRY_LOGIN }} registry_password: ${{ secrets.DEV_MODULES_REGISTRY_PASSWORD }} - if: ${{ github.event.inputs.enableBuild == 'true' }} - uses: deckhouse/modules-actions/build@v4 + uses: deckhouse/modules-actions/build@v15 with: module_source: "${{ vars.DEV_MODULE_SOURCE }}" module_name: ${{ vars.MODULE_NAME }} diff --git a/.werf/base-images.yaml b/.werf/base-images.yaml index 0b37d7e..2a5a799 100644 --- a/.werf/base-images.yaml +++ b/.werf/base-images.yaml @@ -9,3 +9,10 @@ {{- $_ := unset $baseImages "REGISTRY_PATH" }} {{- $_ := set . "Images" $baseImages }} +--- +image: base/vex +from: {{ index $.Images "builder/distroless" }} +final: false +shell: + install: + - pm install coreutils ca-certificates cosign=2.6.3 jq curl bash diff --git a/.werf/defines/vex.tmpl b/.werf/defines/vex.tmpl new file mode 100644 index 0000000..f1571f9 --- /dev/null +++ b/.werf/defines/vex.tmpl @@ -0,0 +1,143 @@ +# put image with vex mitigations to registry. +# Mitigations can be found in the known_vulnerabilities.vex file in the image directory +# input parameters: +# list of $ and image name. +# list ($ "common/kubernetes") +{{- define "vex mitigation" }} + {{- $context := index . 0 }} + {{- $imageName := index . 1 }} + {{- $knownVulnPath := "" }} + {{- $isVault := false }} + {{- if eq $imageName "dev" }} + {{- $knownVulnPath = "/deckhouse-controller/known_vulnerabilities.vex" }} + {{- else if eq $imageName "dev/install" }} + {{- $knownVulnPath = "/dhctl/known_vulnerabilities.vex" }} + {{- else if eq $imageName "bundle" }} + {{- $knownVulnPath = "/known_vulnerabilities.vex" }} + {{- else if hasKey $context "ModulePriority" }} + {{- $knownVulnPath = (printf "/%smodules/%s-%s/images/%s/known_vulnerabilities.vex" $context.ModulePath $context.ModulePriority $context.ModuleName $context.ImageName) }} + {{- else }} + {{- $knownVulnPath = (printf "/images/%s/known_vulnerabilities.vex" $context.ImageName) }} + {{- end }} + {{- $vexFile := false }} + {{- if eq (len ($context.Files.Glob $knownVulnPath)) 1 }} + {{- $vexFile = true }} + {{- end }} + {{- $werfSignKey := env "WERF_SIGN_KEY" "" }} + {{- $vaultKey := env "VAULT_KEY" "" }} + {{- $actionsIdToken := env "ACTIONS_ID_TOKEN_REQUEST_TOKEN" "" }} + {{- if or (ne $werfSignKey "") (ne $vaultKey "") (ne $actionsIdToken "") }} + {{- $isVault = true }} + {{- end }} + {{- if $vexFile }} +--- +image: {{ $imageName }}-vex-artifact +fromImage: base/vex +final: true +secrets: +- id: REGISTRY_USER + env: REGISTRY_USER +- id: REGISTRY_PASSWORD + env: REGISTRY_PASSWORD +{{- if eq $isVault true }} +{{- if ne $werfSignKey "" }} +- id: VAULT_ADDR + env: VAULT_ADDR +- id: VAULT_KEY + env: WERF_SIGN_KEY +- id: VAULT_ROLE + env: WERF_VAULT_AUTH_ROLE +- id: VAULT_JWT + env: WERF_VAULT_AUTH_JWT +- id: TRANSIT_SECRET_ENGINE_PATH + env: TRANSIT_SECRET_ENGINE_PATH +{{- else }} +- id: VAULT_ADDR + env: VAULT_ADDR +- id: VAULT_KEY + env: VAULT_KEY +- id: VAULT_ROLE + env: VAULT_ROLE +- id: TRANSIT_SECRET_ENGINE_PATH + env: TRANSIT_SECRET_ENGINE_PATH +{{- if eq $actionsIdToken "" }} +- id: VAULT_JWT + env: VAULT_ID_TOKEN +{{- end }} +{{- end }} +{{- if ne $actionsIdToken "" }} +- id: ACTIONS_ID_TOKEN_REQUEST_TOKEN + env: ACTIONS_ID_TOKEN_REQUEST_TOKEN +- id: ACTIONS_ID_TOKEN_REQUEST_URL + env: ACTIONS_ID_TOKEN_REQUEST_URL +{{- end }} +{{- end }} +git: +- add: {{ $knownVulnPath }} + to: /known_vulnerabilities.vex + stageDependencies: + install: + - "**/*" +dependencies: +- image: {{ $imageName }} + before: install + imports: + - type: ImageDigest + targetEnv: IMAGE_DIGEST + - type: ImageRepo + targetEnv: IMAGE_REPO +shell: + install: + - export REGISTRY_USER="$(cat /run/secrets/REGISTRY_USER)" + - export REGISTRY_PASSWORD="$(cat /run/secrets/REGISTRY_PASSWORD)" +{{- if $isVault }} + - export VAULT_ADDR="$(cat /run/secrets/VAULT_ADDR)" + - export VAULT_ROLE="$(cat /run/secrets/VAULT_ROLE)" + - export TRANSIT_SECRET_ENGINE_PATH="$(cat /run/secrets/TRANSIT_SECRET_ENGINE_PATH)" + - VAULT_KEY=$(cat /run/secrets/VAULT_KEY) + - export VAULT_KEY="hashivault://${VAULT_KEY#hashivault://}" +{{- if ne $actionsIdToken "" }} + - export ACTIONS_ID_TOKEN_REQUEST_TOKEN="$(cat /run/secrets/ACTIONS_ID_TOKEN_REQUEST_TOKEN)" + - export ACTIONS_ID_TOKEN_REQUEST_URL="$(cat /run/secrets/ACTIONS_ID_TOKEN_REQUEST_URL)" + - export VAULT_AUTH_PATH="github" + - > + export VAULT_JWT=$(jq -r .value <<< $(curl -fsH "Authorization: bearer ${ACTIONS_ID_TOKEN_REQUEST_TOKEN}" "${ACTIONS_ID_TOKEN_REQUEST_URL}&audience=github-access-aud" )) + - > + if [ -n "${VAULT_JWT}" ]; then + echo "Received Actions token"; + else + echo "Actions token empty"; + fi +{{- else }} + - export VAULT_AUTH_PATH="fox" + - export VAULT_JWT="$(cat /run/secrets/VAULT_JWT)" +{{- end }} + - > + export VAULT_TOKEN="$(curl -fX POST "${VAULT_ADDR}/v1/auth/${VAULT_AUTH_PATH}/login" -d '{"role":"'${VAULT_ROLE}'","jwt":"'${VAULT_JWT}'"}' | jq -r '.auth.client_token')" + - > + if [ -n "${VAULT_TOKEN}" ]; then + echo "Received Vault token"; + else + echo "Vault token empty"; + fi + - echo "Using predicate known_vulnerabilities.vex" +{{- else }} + - | + echo -e "\033[33mWARNING!!! Cosign will sign attestation with self-generated key pair!\033[0m" + export COSIGN_PASSWORD="" + cosign generate-key-pair + export VAULT_KEY="cosign.key" +{{- end }} + - | + cosign attest \ + --replace \ + --registry-username="${REGISTRY_USER}" \ + --registry-password="${REGISTRY_PASSWORD}" \ + --predicate /known_vulnerabilities.vex \ + --type openvex \ + --key ${VAULT_KEY} \ + --tlog-upload=false \ + -y -d \ + "${IMAGE_REPO}@${IMAGE_DIGEST}" + {{- end }} +{{- end }} diff --git a/werf-giterminism.yaml b/werf-giterminism.yaml index 8243e41..0621b10 100644 --- a/werf-giterminism.yaml +++ b/werf-giterminism.yaml @@ -12,6 +12,9 @@ config: - SVACE_ENABLED - SVACE_ANALYZE_HOST - SVACE_ANALYZE_SSH_USER + - ACTIONS_ID_TOKEN_REQUEST_TOKEN + - VAULT_KEY + - WERF_SIGN_KEY allowUncommittedFiles: - "base_images.yml" secrets: @@ -19,6 +22,17 @@ config: - GOPROXY - SOURCE_REPO - DISTRO_PACKAGES_PROXY + allowEnvVariables: + - REGISTRY_USER + - REGISTRY_PASSWORD + - VAULT_ADDR + - WERF_SIGN_KEY + - WERF_VAULT_AUTH_ROLE + - WERF_VAULT_AUTH_JWT + - TRANSIT_SECRET_ENGINE_PATH + - ACTIONS_ID_TOKEN_REQUEST_TOKEN + - ACTIONS_ID_TOKEN_REQUEST_URL + stapel: mount: allowBuildDir: true From 330048f6ea1cb11a3292261fe2f38386f502cdf4 Mon Sep 17 00:00:00 2001 From: Maksim Khimchenko Date: Fri, 26 Jun 2026 15:40:13 +0300 Subject: [PATCH 2/2] Fix VEX build: correct vex include and/or REGISTRY credentials in CI. Signed-off-by: Maksim Khimchenko --- .github/workflows/build_prod.yml | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/.github/workflows/build_prod.yml b/.github/workflows/build_prod.yml index 142d263..6538028 100644 --- a/.github/workflows/build_prod.yml +++ b/.github/workflows/build_prod.yml @@ -51,15 +51,15 @@ jobs: with: registry: ${{ vars.DEV_REGISTRY }} registry_login: ${{ vars.DEV_MODULES_REGISTRY_LOGIN }} - registry_password: ${{ secrets.DEV_MODULES_REGISTRY_PASSWORD }} + registry_password: ${{ secrets.PROD_MODULES_REGISTRY_PASSWORD }} - uses: deckhouse/modules-actions/build@v15 with: module_source: "${{ vars.PROD_REGISTRY }}/${{ vars.PROD_MODULE_SOURCE_NAME }}/ce/modules" module_name: ${{ vars.MODULE_NAME }} module_tag: ${{ github.ref_name }} secondary_repo: "${{ vars.DEV_MODULE_SOURCE }}/${{ vars.MODULE_NAME }}" - registry_user: ${{ vars.DEV_MODULES_REGISTRY_LOGIN }} - registry_password: ${{ secrets.DEV_MODULES_REGISTRY_PASSWORD }} + registry_user: ${{ vars.PROD_MODULES_REGISTRY_LOGIN }} + registry_password: ${{ secrets.PROD_MODULES_REGISTRY_PASSWORD }} source_repo: ${{ secrets.SOURCE_REPO }} source_repo_ssh_key: ${{ secrets.SOURCE_REPO_SSH_KEY }} @@ -96,15 +96,15 @@ jobs: with: registry: ${{ vars.DEV_REGISTRY }} registry_login: ${{ vars.DEV_MODULES_REGISTRY_LOGIN }} - registry_password: ${{ secrets.DEV_MODULES_REGISTRY_PASSWORD }} + registry_password: ${{ secrets.PROD_MODULES_REGISTRY_PASSWORD }} - uses: deckhouse/modules-actions/build@v15 with: module_source: "${{ vars.PROD_REGISTRY }}/${{ vars.PROD_MODULE_SOURCE_NAME }}/ee/modules" module_name: ${{ vars.MODULE_NAME }} module_tag: ${{ github.ref_name }} secondary_repo: "${{ vars.DEV_MODULE_SOURCE }}/${{ vars.MODULE_NAME }}" - registry_user: ${{ vars.DEV_MODULES_REGISTRY_LOGIN }} - registry_password: ${{ secrets.DEV_MODULES_REGISTRY_PASSWORD }} + registry_user: ${{ vars.PROD_MODULES_REGISTRY_LOGIN }} + registry_password: ${{ secrets.PROD_MODULES_REGISTRY_PASSWORD }} source_repo: ${{ secrets.SOURCE_REPO }} source_repo_ssh_key: ${{ secrets.SOURCE_REPO_SSH_KEY }} @@ -141,15 +141,15 @@ jobs: with: registry: ${{ vars.DEV_REGISTRY }} registry_login: ${{ vars.DEV_MODULES_REGISTRY_LOGIN }} - registry_password: ${{ secrets.DEV_MODULES_REGISTRY_PASSWORD }} + registry_password: ${{ secrets.PROD_MODULES_REGISTRY_PASSWORD }} - uses: deckhouse/modules-actions/build@v15 with: module_source: "${{ vars.PROD_REGISTRY }}/${{ vars.PROD_MODULE_SOURCE_NAME }}/fe/modules" module_name: ${{ vars.MODULE_NAME }} module_tag: ${{ github.ref_name }} secondary_repo: "${{ vars.DEV_MODULE_SOURCE }}/${{ vars.MODULE_NAME }}" - registry_user: ${{ vars.DEV_MODULES_REGISTRY_LOGIN }} - registry_password: ${{ secrets.DEV_MODULES_REGISTRY_PASSWORD }} + registry_user: ${{ vars.PROD_MODULES_REGISTRY_LOGIN }} + registry_password: ${{ secrets.PROD_MODULES_REGISTRY_PASSWORD }} source_repo: ${{ secrets.SOURCE_REPO }} source_repo_ssh_key: ${{ secrets.SOURCE_REPO_SSH_KEY }} @@ -186,15 +186,15 @@ jobs: with: registry: ${{ vars.DEV_REGISTRY }} registry_login: ${{ vars.DEV_MODULES_REGISTRY_LOGIN }} - registry_password: ${{ secrets.DEV_MODULES_REGISTRY_PASSWORD }} + registry_password: ${{ secrets.PROD_MODULES_REGISTRY_PASSWORD }} - uses: deckhouse/modules-actions/build@v15 with: module_source: "${{ vars.PROD_REGISTRY }}/${{ vars.PROD_MODULE_SOURCE_NAME }}/se/modules" module_name: ${{ vars.MODULE_NAME }} module_tag: ${{ github.ref_name }} secondary_repo: "${{ vars.DEV_MODULE_SOURCE }}/${{ vars.MODULE_NAME }}" - registry_user: ${{ vars.DEV_MODULES_REGISTRY_LOGIN }} - registry_password: ${{ secrets.DEV_MODULES_REGISTRY_PASSWORD }} + registry_user: ${{ vars.PROD_MODULES_REGISTRY_LOGIN }} + registry_password: ${{ secrets.PROD_MODULES_REGISTRY_PASSWORD }} source_repo: ${{ secrets.SOURCE_REPO }} source_repo_ssh_key: ${{ secrets.SOURCE_REPO_SSH_KEY }} @@ -231,14 +231,14 @@ jobs: with: registry: ${{ vars.DEV_REGISTRY }} registry_login: ${{ vars.DEV_MODULES_REGISTRY_LOGIN }} - registry_password: ${{ secrets.DEV_MODULES_REGISTRY_PASSWORD }} + registry_password: ${{ secrets.PROD_MODULES_REGISTRY_PASSWORD }} - uses: deckhouse/modules-actions/build@v15 with: module_source: "${{ vars.PROD_REGISTRY }}/${{ vars.PROD_MODULE_SOURCE_NAME }}/se-plus/modules" module_name: ${{ vars.MODULE_NAME }} module_tag: ${{ github.ref_name }} secondary_repo: "${{ vars.DEV_MODULE_SOURCE }}/${{ vars.MODULE_NAME }}" - registry_user: ${{ vars.DEV_MODULES_REGISTRY_LOGIN }} - registry_password: ${{ secrets.DEV_MODULES_REGISTRY_PASSWORD }} + registry_user: ${{ vars.PROD_MODULES_REGISTRY_LOGIN }} + registry_password: ${{ secrets.PROD_MODULES_REGISTRY_PASSWORD }} source_repo: ${{ secrets.SOURCE_REPO }} source_repo_ssh_key: ${{ secrets.SOURCE_REPO_SSH_KEY }}