From c0fbcf7295dd3466950da7d5ca0caad8b2ae295a Mon Sep 17 00:00:00 2001 From: Subin Lee Date: Mon, 11 May 2026 15:07:50 +0900 Subject: [PATCH 1/3] feat(release): sign checksums.txt with cosign keyless Adds Sigstore-based keyless signing of checksums.txt via goreleaser's signs section. Each release will now publish checksums.txt.sig and checksums.txt.pem alongside the existing checksums file. The goreleaser job in release-please.yml gains id-token: write permission (for OIDC) and a sigstore/cosign-installer step. Mirrors the kubectl signed-artifact pattern: install scripts still verify SHA256 only (no change), and signature verification is documented as an optional advanced step in README.md. No user-facing behavior change for existing install/upgrade flows. Co-Authored-By: Claude Opus 4.7 (1M context) --- .github/workflows/release-please.yml | 6 +++++ .goreleaser.yaml | 18 ++++++++++++++ README.md | 36 ++++++++++++++++++++++++++++ 3 files changed, 60 insertions(+) diff --git a/.github/workflows/release-please.yml b/.github/workflows/release-please.yml index 140c0fc..c615ec5 100644 --- a/.github/workflows/release-please.yml +++ b/.github/workflows/release-please.yml @@ -150,6 +150,9 @@ jobs: needs: release-please if: ${{ needs.release-please.outputs.release_created == 'true' }} runs-on: ubuntu-latest + permissions: + contents: write + id-token: write steps: - name: Checkout uses: actions/checkout@v6 @@ -162,6 +165,9 @@ jobs: with: go-version: '1.26.1' + - name: Install cosign + uses: sigstore/cosign-installer@v3 + - name: Run GoReleaser uses: goreleaser/goreleaser-action@v7 with: diff --git a/.goreleaser.yaml b/.goreleaser.yaml index 3f509d2..71b3f3a 100644 --- a/.goreleaser.yaml +++ b/.goreleaser.yaml @@ -31,6 +31,24 @@ archives: checksum: name_template: checksums.txt +# Sign checksums.txt with cosign keyless (Sigstore + Fulcio + Rekor). +# Produces checksums.txt.sig and checksums.txt.pem alongside the checksums +# file in the GitHub release. Verification is documented in README.md +# under the "Advanced: signature verification" section. +signs: + - id: checksums-cosign + artifacts: checksum + cmd: cosign + signature: "${artifact}.sig" + certificate: "${artifact}.pem" + args: + - sign-blob + - "--yes" + - "--output-signature=${signature}" + - "--output-certificate=${certificate}" + - "${artifact}" + output: true + changelog: disable: true diff --git a/README.md b/README.md index 6c6a18e..a147e2a 100644 --- a/README.md +++ b/README.md @@ -79,6 +79,42 @@ solactl upgrade 또는 위의 설치 스크립트를 다시 실행해도 됩니다. +### 서명 검증 (고급) + +solactl 릴리스의 `checksums.txt` 는 [cosign keyless](https://docs.sigstore.dev/cosign/signing/overview/) 로 서명됩니다 (Sigstore Fulcio CA + Rekor transparency log). 추가 보안이 필요한 환경에서 선택적으로 검증할 수 있습니다. + +> 일반 설치는 SHA256 체크섬만 검증합니다 — kubectl 와 동일한 보안 모델입니다. 본 섹션의 서명 검증은 *선택* 입니다. + +릴리스 아티팩트: + +| 파일 | 용도 | +|------|------| +| `checksums.txt` | 각 바이너리 아카이브의 SHA256 | +| `checksums.txt.sig` | cosign keyless 서명 | +| `checksums.txt.pem` | 서명에 사용된 ephemeral 인증서 | + +검증 절차 (cosign 2.0+ 필요): + +```bash +TAG=$(curl -fsSL https://api.github.com/repos/solapi/solactl/releases/latest \ + | grep '"tag_name"' | sed -E 's/.*"tag_name": *"([^"]+)".*/\1/') +BASE="https://github.com/solapi/solactl/releases/download/${TAG}" + +curl -fsSLO "${BASE}/checksums.txt" +curl -fsSLO "${BASE}/checksums.txt.sig" +curl -fsSLO "${BASE}/checksums.txt.pem" + +cosign verify-blob checksums.txt \ + --signature checksums.txt.sig \ + --certificate checksums.txt.pem \ + --certificate-identity-regexp '^https://github\.com/solapi/solactl/\.github/workflows/release-please\.yml@refs/tags/v[0-9]+\.[0-9]+\.[0-9]+$' \ + --certificate-oidc-issuer 'https://token.actions.githubusercontent.com' +``` + +`Verified OK` 가 출력되면 `checksums.txt` 가 **이 저장소의 release 워크플로우가 발급한 서명** 임이 증명됩니다. 이후 `install.sh` / `install.ps1` 가 `checksums.txt` 로 바이너리의 SHA256 을 검증하므로 *서명된 체크섬 → 검증된 바이너리* 의 신뢰 체인이 완성됩니다. + +서명 데이터는 [Rekor transparency log](https://search.sigstore.dev/) 에서도 조회할 수 있습니다. + ## 사용법 ```bash From db8205317f0ffac2df88f5c2f6952518aa841623 Mon Sep 17 00:00:00 2001 From: Subin Lee Date: Mon, 11 May 2026 15:32:27 +0900 Subject: [PATCH 2/3] docs(verify): extract signature verification into VERIFYING.md Moves the cosign verification walkthrough out of README into a dedicated VERIFYING.md and replaces the README section with a short pointer. VERIFYING.md adds the parts that didn't fit in README: trust model, cosign install instructions per platform, certificate identity explanation, and troubleshooting for the common verify-blob failures. Co-Authored-By: Claude Opus 4.7 (1M context) --- README.md | 36 +----------- VERIFYING.md | 161 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 164 insertions(+), 33 deletions(-) create mode 100644 VERIFYING.md diff --git a/README.md b/README.md index a147e2a..7fff550 100644 --- a/README.md +++ b/README.md @@ -79,41 +79,11 @@ solactl upgrade 또는 위의 설치 스크립트를 다시 실행해도 됩니다. -### 서명 검증 (고급) +### 서명 검증 (고급, 선택) -solactl 릴리스의 `checksums.txt` 는 [cosign keyless](https://docs.sigstore.dev/cosign/signing/overview/) 로 서명됩니다 (Sigstore Fulcio CA + Rekor transparency log). 추가 보안이 필요한 환경에서 선택적으로 검증할 수 있습니다. +릴리스의 `checksums.txt` 는 [cosign keyless](https://docs.sigstore.dev/cosign/signing/overview/) 로 서명됩니다. 일반 설치 경로는 SHA256 체크섬만 검증하지만, 추가 보증이 필요하면 cosign 으로 서명을 검증할 수 있습니다 (kubectl 와 동일한 모델). -> 일반 설치는 SHA256 체크섬만 검증합니다 — kubectl 와 동일한 보안 모델입니다. 본 섹션의 서명 검증은 *선택* 입니다. - -릴리스 아티팩트: - -| 파일 | 용도 | -|------|------| -| `checksums.txt` | 각 바이너리 아카이브의 SHA256 | -| `checksums.txt.sig` | cosign keyless 서명 | -| `checksums.txt.pem` | 서명에 사용된 ephemeral 인증서 | - -검증 절차 (cosign 2.0+ 필요): - -```bash -TAG=$(curl -fsSL https://api.github.com/repos/solapi/solactl/releases/latest \ - | grep '"tag_name"' | sed -E 's/.*"tag_name": *"([^"]+)".*/\1/') -BASE="https://github.com/solapi/solactl/releases/download/${TAG}" - -curl -fsSLO "${BASE}/checksums.txt" -curl -fsSLO "${BASE}/checksums.txt.sig" -curl -fsSLO "${BASE}/checksums.txt.pem" - -cosign verify-blob checksums.txt \ - --signature checksums.txt.sig \ - --certificate checksums.txt.pem \ - --certificate-identity-regexp '^https://github\.com/solapi/solactl/\.github/workflows/release-please\.yml@refs/tags/v[0-9]+\.[0-9]+\.[0-9]+$' \ - --certificate-oidc-issuer 'https://token.actions.githubusercontent.com' -``` - -`Verified OK` 가 출력되면 `checksums.txt` 가 **이 저장소의 release 워크플로우가 발급한 서명** 임이 증명됩니다. 이후 `install.sh` / `install.ps1` 가 `checksums.txt` 로 바이너리의 SHA256 을 검증하므로 *서명된 체크섬 → 검증된 바이너리* 의 신뢰 체인이 완성됩니다. - -서명 데이터는 [Rekor transparency log](https://search.sigstore.dev/) 에서도 조회할 수 있습니다. +검증 절차와 신뢰 모델은 [VERIFYING.md](./VERIFYING.md) 를 참고하세요. ## 사용법 diff --git a/VERIFYING.md b/VERIFYING.md new file mode 100644 index 0000000..2a9463e --- /dev/null +++ b/VERIFYING.md @@ -0,0 +1,161 @@ +# 릴리스 서명 검증 + +`solactl` 의 모든 GitHub 릴리스는 [cosign keyless](https://docs.sigstore.dev/cosign/signing/overview/) 로 서명됩니다. 본 문서는 서명을 검증하는 절차와 그 의미를 설명합니다. + +## TL;DR + +```bash +TAG=$(curl -fsSL https://api.github.com/repos/solapi/solactl/releases/latest \ + | grep '"tag_name"' | sed -E 's/.*"tag_name": *"([^"]+)".*/\1/') +BASE="https://github.com/solapi/solactl/releases/download/${TAG}" + +curl -fsSLO "${BASE}/checksums.txt" +curl -fsSLO "${BASE}/checksums.txt.sig" +curl -fsSLO "${BASE}/checksums.txt.pem" + +cosign verify-blob checksums.txt \ + --signature checksums.txt.sig \ + --certificate checksums.txt.pem \ + --certificate-identity-regexp '^https://github\.com/solapi/solactl/\.github/workflows/release-please\.yml@refs/tags/v[0-9]+\.[0-9]+\.[0-9]+$' \ + --certificate-oidc-issuer 'https://token.actions.githubusercontent.com' +``` + +성공 시 `Verified OK` 가 출력됩니다. + +## 검증이 보장하는 것 + +서명 검증에 성공하면 다음이 증명됩니다. + +1. `checksums.txt` 는 **이 저장소** (`github.com/solapi/solactl`) 의 +2. **`.github/workflows/release-please.yml` 워크플로우** 가 +3. **태그된 릴리스 시점** (`refs/tags/v..`) 에 생성/서명한 파일이라는 점. + +이후 `install.sh` / `install.ps1` (또는 수동) 이 `checksums.txt` 로 각 바이너리 아카이브의 SHA256 을 검증하므로, + +> **서명된 체크섬 → 검증된 바이너리** + +의 신뢰 체인이 완성됩니다. + +## 일반 설치와의 관계 + +| 경로 | 검증 단계 | 추가 도구 | +|------|-----------|-----------| +| 일반 설치 (`install.sh` / `install.ps1`) | TLS + SHA256 (`checksums.txt`) | 불필요 | +| **고급 검증 (본 문서)** | TLS + SHA256 + cosign 서명 + Rekor 트랜스페어런시 로그 | `cosign` 2.0+ | + +`kubectl` 과 동일한 패턴입니다 — 일반 설치 경로는 SHA256 만 검증하고, 서명 검증은 추가 보증이 필요한 사용자가 선택적으로 수행합니다. + +## 신뢰 모델 + +cosign keyless 는 다음 구성 요소를 신뢰합니다. + +- **Sigstore Fulcio CA** — 짧은 수명의 X.509 인증서 발급 +- **GitHub Actions OIDC Provider** (`token.actions.githubusercontent.com`) — 워크플로우 실행 시점 신원 발급 +- **Sigstore Rekor** — 모든 서명을 외부에서 검증 가능한 트랜스페어런시 로그에 기록 + +키 페어를 직접 관리하지 않으므로 키 분실/회전 이슈가 없으며, Rekor 덕분에 *과거 어떤 서명이 발급되었는지* 가 외부에서 감사 가능합니다. + +## 필수 도구 + +[cosign](https://docs.sigstore.dev/cosign/installation/) 2.0 이상. + +```bash +# macOS +brew install cosign + +# Linux (예시 — 최신 버전은 cosign 릴리스 페이지 참조) +curl -fsSL -o /tmp/cosign \ + https://github.com/sigstore/cosign/releases/latest/download/cosign-linux-amd64 +chmod +x /tmp/cosign && sudo mv /tmp/cosign /usr/local/bin/cosign + +# Windows (PowerShell) +winget install sigstore.cosign +``` + +## 단계별 절차 + +### 1. 검증할 태그 선택 + +```bash +# 최신 릴리스 +TAG=$(curl -fsSL https://api.github.com/repos/solapi/solactl/releases/latest \ + | grep '"tag_name"' | sed -E 's/.*"tag_name": *"([^"]+)".*/\1/') + +# 또는 특정 태그 +TAG=v0.1.7 +``` + +### 2. 아티팩트 다운로드 + +```bash +BASE="https://github.com/solapi/solactl/releases/download/${TAG}" +curl -fsSLO "${BASE}/checksums.txt" +curl -fsSLO "${BASE}/checksums.txt.sig" +curl -fsSLO "${BASE}/checksums.txt.pem" +``` + +| 파일 | 용도 | +|------|------| +| `checksums.txt` | 각 바이너리 아카이브의 SHA256 목록 | +| `checksums.txt.sig` | cosign 서명 | +| `checksums.txt.pem` | 서명에 사용된 ephemeral 인증서 | + +### 3. cosign 으로 검증 + +```bash +cosign verify-blob checksums.txt \ + --signature checksums.txt.sig \ + --certificate checksums.txt.pem \ + --certificate-identity-regexp '^https://github\.com/solapi/solactl/\.github/workflows/release-please\.yml@refs/tags/v[0-9]+\.[0-9]+\.[0-9]+$' \ + --certificate-oidc-issuer 'https://token.actions.githubusercontent.com' +``` + +#### 인자 설명 + +- `--certificate-identity-regexp` — 서명자의 OIDC subject 가 매칭되어야 하는 정규식. **이 저장소의 `release-please.yml` 워크플로우가 정식 태그(`v..`) 위에서 실행되었을 때** 만 통과합니다. 위조된 fork 나 임의 브랜치에서 만든 서명은 거부됩니다. +- `--certificate-oidc-issuer` — OIDC 토큰 발급자. GitHub Actions 가 발급한 토큰만 허용. + +### 4. 바이너리 검증 (체인 완성) + +`checksums.txt` 가 진본임이 확인되었으므로, 그 안의 SHA256 으로 다운로드한 아카이브를 검증합니다. + +```bash +# Linux/macOS +sha256sum --check --ignore-missing checksums.txt + +# 또는 특정 파일만 +grep "solactl_0.1.7_linux_amd64.tar.gz$" checksums.txt | sha256sum --check +``` + +## 트러블슈팅 + +### `Error: no matching signatures` + +서명 또는 인증서 파일과 `checksums.txt` 가 동일 릴리스의 것이 아닐 가능성이 큽니다. 셋 다 동일 `${BASE}` 에서 다시 받으세요. + +### `Error: certificate identity not matched` + +`--certificate-identity-regexp` 가 인증서의 실제 subject 와 매치되지 않습니다. 다음을 확인하세요. + +```bash +openssl x509 -in checksums.txt.pem -noout -text \ + | grep -A1 "Subject Alternative Name" +``` + +`URI:https://github.com/solapi/solactl/.github/workflows/release-please.yml@refs/tags/vX.Y.Z` 형태여야 합니다. fork 또는 다른 워크플로우 경유로 서명된 경우 거부됩니다. + +### `Error: rekor log entry not found` + +네트워크가 [rekor.sigstore.dev](https://rekor.sigstore.dev) 에 접근할 수 없거나, 서명이 transparency log 에 기록되지 않았습니다. 회사 프록시 환경이면 해당 도메인을 허용 목록에 추가하세요. + +## Rekor 에서 직접 조회 + +서명은 Sigstore Rekor 트랜스페어런시 로그에 기록되며, 검증 도구 없이도 브라우저에서 조회할 수 있습니다. + +- https://search.sigstore.dev/ + +`checksums.txt` 의 SHA256 또는 인증서의 fingerprint 로 검색하면 해당 릴리스의 서명 이력을 확인할 수 있습니다. + +## 적용 이력 + +이 검증 절차는 본 저장소가 cosign keyless 서명을 도입한 **이후 릴리스부터** 적용됩니다. 도입 이전 릴리스에는 `checksums.txt.sig` / `checksums.txt.pem` 가 존재하지 않으며, 해당 릴리스는 SHA256 무결성 검증만으로 안전성을 평가해야 합니다. From e8406d2a14fb76d15d8c4a66f2ebb12b50429aab Mon Sep 17 00:00:00 2001 From: Subin Lee Date: Mon, 11 May 2026 15:41:58 +0900 Subject: [PATCH 3/3] docs(verify): drop kubectl reference from verification copy MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Removes "kubectl 와 동일한 모델/패턴" lines from README.md and VERIFYING.md per review feedback. Co-Authored-By: Claude Opus 4.7 (1M context) --- README.md | 2 +- VERIFYING.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 7fff550..eac858d 100644 --- a/README.md +++ b/README.md @@ -81,7 +81,7 @@ solactl upgrade ### 서명 검증 (고급, 선택) -릴리스의 `checksums.txt` 는 [cosign keyless](https://docs.sigstore.dev/cosign/signing/overview/) 로 서명됩니다. 일반 설치 경로는 SHA256 체크섬만 검증하지만, 추가 보증이 필요하면 cosign 으로 서명을 검증할 수 있습니다 (kubectl 와 동일한 모델). +릴리스의 `checksums.txt` 는 [cosign keyless](https://docs.sigstore.dev/cosign/signing/overview/) 로 서명됩니다. 일반 설치 경로는 SHA256 체크섬만 검증하지만, 추가 보증이 필요하면 cosign 으로 서명을 검증할 수 있습니다. 검증 절차와 신뢰 모델은 [VERIFYING.md](./VERIFYING.md) 를 참고하세요. diff --git a/VERIFYING.md b/VERIFYING.md index 2a9463e..2518543 100644 --- a/VERIFYING.md +++ b/VERIFYING.md @@ -43,7 +43,7 @@ cosign verify-blob checksums.txt \ | 일반 설치 (`install.sh` / `install.ps1`) | TLS + SHA256 (`checksums.txt`) | 불필요 | | **고급 검증 (본 문서)** | TLS + SHA256 + cosign 서명 + Rekor 트랜스페어런시 로그 | `cosign` 2.0+ | -`kubectl` 과 동일한 패턴입니다 — 일반 설치 경로는 SHA256 만 검증하고, 서명 검증은 추가 보증이 필요한 사용자가 선택적으로 수행합니다. +일반 설치 경로는 SHA256 만 검증하고, 서명 검증은 추가 보증이 필요한 사용자가 선택적으로 수행합니다. ## 신뢰 모델