Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat/improvements #33

Merged
merged 4 commits into from
Apr 27, 2024
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
3 changes: 3 additions & 0 deletions .allstar/binary_artifacts.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
optConfig:
OptIn: true
action: issue
8 changes: 8 additions & 0 deletions .allstar/branch_protection.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
optConfig:
OptIn: true
action: issue
enforceDefault: true
requireApproval: false
blockForce: true
requireSignedCommits: true
enforceOnAdmins: true
3 changes: 3 additions & 0 deletions .allstar/dangerous_workflow.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
optConfig:
OptIn: true
action: issue
5 changes: 5 additions & 0 deletions .allstar/outside.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
optConfig:
OptIn: true
action: issue
pushAllowed: true
adminAllowed: false
17 changes: 17 additions & 0 deletions .allstar/scorecard.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
optConfig:
OptIn: true
action: issue
checks:
- Binary-Artifacts
- CI-Tests
- Dangerous-Workflow
- Dependency-Update-Tool
- License
- Packaging
- Pinned-Dependencies
- Signed-Releases
- SAST
- Security-Policy
- Token-Permissions
- Webhooks
threshold: 8
3 changes: 3 additions & 0 deletions .allstar/security.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
optConfig:
OptIn: true
action: issue
2 changes: 1 addition & 1 deletion .github/workflows/README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# PodSalsa Github Workflows
# PodSalsa GitHub Workflows

## Overview

Expand Down
20 changes: 12 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,19 +24,23 @@ The goal of this project is to provide a simple example of a Go application on G
- [x] OpenSSF best practices
- [x] Resolve "Code Scanning" alerts (as far as possible)
- [x] Document GitHub Actions Best Practices
- [ ] Implement the release workflow for sbom, docker images, code scanning, and signing
- [x] Implement the release workflow for sbom, docker images, code scanning, and signing
- [x] Create the go binaries for multiple platforms
- [x] Go lint and security scans
- [ ] Generates a Software Bill of Materials (SBOM)
- [ ] Create multi-arch docker images
- [ ] Signs the sbom, the binaries checksum and the container images with Cosign and GitHub OIDC
- [ ] Upload the sbom, binaires, checksums to GitHub Releases
- [ ] Pushes the container images to GitHub Container Registry and Harbor registry
- [ ] Document Security Policy (Verifying the release artifacts)
- [x] Generates a Software Bill of Materials (SBOM)
- [x] Create multi-arch docker images
- [x] Signs the sbom, the binaries checksum and the container images with Cosign and GitHub OIDC
- [x] Upload the sbom, binaires, checksums to GitHub Releases
- [x] Pushes the container images to GitHub Container Registry and Harbor registry
- [x] Document Security Policy (Verifying the release artifacts)
- [ ] Document Release Workflow

## Documentation

All the used workflows and security best practices are documented in the following files:

- [PodSalsa Github Workflows](./.github/workflows/README.md)
- [PodSalsa GitHub Workflows](./.github/workflows/README.md)
- [Verifying the release artifacts](./SECURITY.md#release-verification)
- [GitHub Actions Best Practices](./docs/best-practices.md)

More documentation will be added in the future.
54 changes: 54 additions & 0 deletions SECURITY-INSIGHTS.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
header:
schema-version: 1.0.0
expiration-date: '2025-04-25T10:00:00.000Z'
last-updated: '2024-04-26'
last-reviewed: '2024-04-26'
project-url: https://github.com/janfuhrer/podsalsa
changelog: https://github.com/janfuhrer/podsalsa/blob/main/CHANGELOG.md
license: https://github.com/janfuhrer/podsalsa/blob/main/LICENSE
project-lifecycle:
bug-fixes-only: false
core-team:
- name: Jan Fuhrer
contact: [email protected]
status: concept
contribution-policy:
accepts-pull-requests: true
accepts-automated-pull-requests: true
contributing-policy: https://github.com/janfuhrer/podsalsa/blob/main/CONTRIBUTING.md
code-of-conduct: https://github.com/janfuhrer/podsalsa/blob/main/CODE_OF_CONDUCT.md
distribution-points:
- https://github.com/janfuhrer/podsalsa/releases
- https://github.com/janfuhrer?tab=packages&repo_name=podsalsa
security-testing:
- tool-type: sca
tool-name: Dependabot
tool-version: latest
integration:
ad-hoc: false
ci: true
before-release: true
comment: |
Dependabot is enabled for this repo.
security-contacts:
- type: email
value: [email protected]
primary: true
vulnerability-reporting:
accepts-vulnerability-reports: true
bug-bounty-available: false
email-contact: [email protected]
security-policy: https://github.com/janfuhrer/podsalsa/blob/main/SECURITY.md
comment: |
Report security vulnerabilities via GitHub Security Advisory in this repository.
dependencies:
third-party-packages: true
dependencies-lists:
- https://github.com/janfuhrer/podsalsa/blob/main/go.mod
sbom:
- sbom-file: https://github.com/janfuhrer/podsalsa/releases
sbom-format: CycloneDX
sbom-url: https://github.com/janfuhrer/podsalsa/blob/main/SECURITY.md#sbom
- sbom-file: https://github.com/janfuhrer/podsalsa/pkgs/container/podsalsa
sbom-format: CycloneDX
sbom-url: https://github.com/janfuhrer/podsalsa/blob/main/SECURITY.md#sbom
126 changes: 124 additions & 2 deletions SECURITY.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,128 @@ To report a security issue, please use the GitHub Security Advisory ["Report a V

The contributor will send a response indicating the next steps in handling your report. After the initial reply to your report, the security team will keep you informed of the progress towards a fix and full announcement, and may ask for additional information or guidance.

## Release
## Release verification

TODO: Describe how to verify the release artifacts
The release workflow creates provenance for its builds using the [SLSA standard](https://slsa.dev), which conforms to the [Level 3 specification](https://slsa.dev/spec/v1.0/levels#build-l3). The provenance is stored in the `multiple.intoto.jsonl` file of each release and can be used to verify the integrity and authenticity of the release artifacts.

All signatures are created by [Cosign](https://github.com/sigstore/cosign) using the [keyless signing](https://docs.sigstore.dev/verifying/verify/#keyless-verification-using-openid-connect) method.

### Prerequisites

To verify the release artifacts, you will need the [slsa-verifier](https://github.com/slsa-framework/slsa-verifier), [cosign](https://github.com/sigstore/cosign) and [crane](https://github.com/google/go-containerregistry/blob/main/cmd/crane/README.md) binaries. See the [prerequisites verification](docs/prerequisites_verification.md) for installation instructions.

### Inspect Provenance

You can manually inspect the provenance of the release artifacts by decoding the `multiple.intoto.jsonl` file.

```bash
# get the latest release
export VERSION=$(curl -s "https://api.github.com/repos/janfuhrer/podsalsa/releases/latest" | jq -r '.tag_name')

# download the provenance file
curl -L -O https://github.com/janfuhrer/podsalsa/releases/download/$VERSION/multiple.intoto.jsonl

# decode the payload
cat multiple.intoto.jsonl | jq -r '.payload' | base64 -d | jq
```

### Verify Provenance of Release Artifacts

To verify the release artifacts (go binaries and sbom files), you can use the `slsa-verifier`. This verification works for all release artifcats (`*.tar.gz`, `*.zip`, `*.sbom`).

```bash
# example for the "podsalsa-darwin-amd64.tar.gz" artifact
export VERSION=$(curl -s "https://api.github.com/repos/janfuhrer/podsalsa/releases/latest" | jq -r '.tag_name')
export ARTIFACT=podsalsa-darwin-amd64.tar.gz

# download the artifact
curl -L -O https://github.com/janfuhrer/podsalsa/releases/download/$VERSION/$ARTIFACT

# download the provenance file
curl -L -O https://github.com/janfuhrer/podsalsa/releases/download/$VERSION/multiple.intoto.jsonl

# verify the artifact
slsa-verifier verify-artifact \
--provenance-path multiple.intoto.jsonl \
--source-uri github.com/janfuhrer/podsalsa \
--source-tag $VERSION \
$ARTIFACT

Verifying artifact podsalsa-darwin-amd64.tar.gz: PASSED
PASSED: Verified SLSA provenance
```

### Verify Provenance of Container Images

The `slsa-verifier` can also verify docker images. Verification can be done by tag or by digest. We recommend to always use the digest to prevent [TOCTOU attacks](https://github.com/slsa-framework/slsa-verifier?tab=readme-ov-file#toctou-attacks), as an image tag is not immutable.

```bash
export VERSION=$(curl -s "https://api.github.com/repos/janfuhrer/podsalsa/releases/latest" | jq -r '.tag_name')
IMAGE=ghcr.io/janfuhrer/podsalsa:$VERSION

# get the image digest and append it to the image name
# e.g. ghcr.io/janfuhrer/podsalsa:v0.2.0@sha256:...
IMAGE="${IMAGE}@"$(crane digest "${IMAGE}")

# verify the image
slsa-verifier verify-image "$IMAGE" \
--source-uri github.com/janfuhrer/podsalsa \
--source-versioned-tag $VERSION

PASSED: Verified SLSA provenance
```

As an alternative to the SLSA Verifier, you can use `cosign` to verify the docker images. Cosign also supports validating the attestation against `CUE` policies (see [Validate In-Toto Attestation](https://docs.sigstore.dev/verifying/attestation/#validate-in-toto-attestations) for more information), which is useful to ensure that some specific requirements are met. We provide a [policy.cue](./policy.cue) file to verify the correct workflow has triggered the release and that the image was generated from the correct source repository.

```bash
# download policy.cue
curl -L -O https://raw.githubusercontent.com/janfuhrer/podsalsa/main/policy.cue

# verify the image with cosign
cosign verify-attestation \
--type slsaprovenance \
--certificate-oidc-issuer https://token.actions.githubusercontent.com \
--certificate-identity-regexp '^https://github.com/slsa-framework/slsa-github-generator/.github/workflows/generator_container_slsa3.yml@refs/tags/v[0-9]+.[0-9]+.[0-9]+$' \
--policy policy.cue \
$IMAGE | jq
```

### Verify Signature of Checksum file

Since all release artifacts can be verified with the `slsa-verifier`, a checksum file is not necessary (the integrity is already verified by the SLSA Verifier). A use case might be to verify the integrity of downloaded files and only rely on Cosign instead of the SLSA Verifier.

The checksum file can be verified with `cosign` as follows:

```bash
export VERSION=$(curl -s "https://api.github.com/repos/janfuhrer/podsalsa/releases/latest" | jq -r '.tag_name')

# download the checksum, signature and certificate files
curl -L -O https://github.com/janfuhrer/podsalsa/releases/download/$VERSION/checksums.txt
curl -L -O https://github.com/janfuhrer/podsalsa/releases/download/$VERSION/checksums.txt.sig
curl -L -O https://github.com/janfuhrer/podsalsa/releases/download/$VERSION/checksums.txt.pem

# verify the checksum file
cosign verify-blob \
--certificate checksums.txt.pem \
--signature checksums.txt.sig \
--certificate-identity-regexp '^https://github.com/janfuhrer/podsalsa/.github/workflows/release.yml@refs/tags/v[0-9]+.[0-9]+.[0-9]+$' \
--certificate-oidc-issuer https://token.actions.githubusercontent.com \
checksums.txt
```

### SBOM

The Software Bill of Materials (SBOM) is generated for each release and can be used to verify the dependencies of the project.

The SBOM of the Go binaries is available in the `*.sbom` files of the release and can be verified with the `slsa-verifier` (see [Verify Provenance of Release Artifacts](#verify-provenance-of-release-artifacts)).

The SBOM of the container images can be downloaded with `cosign`. You have to specify the platform of the image to download the correct SBOM.

```bash
export VERSION=$(curl -s "https://api.github.com/repos/janfuhrer/podsalsa/releases/latest" | jq -r '.tag_name')
IMAGE=ghcr.io/janfuhrer/podsalsa:$VERSION

cosign download sbom ghcr.io/janfuhrer/podsalsa:$IMAGE --platform linux/arm64
```

The `cosign download sbom` command will be deprecated in the future. At the moment, I have not found another way to download the SBOM of the container images. There are open issues in the [cosign repository](https://github.com/sigstore/cosign/issues/2307) to provide a better way to download the SBOM.
14 changes: 13 additions & 1 deletion docs/best-practices.md
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ Private vulnerability reporting can be enabled in the repository settings. (see

### Prevent script injection

A GitHub Actions workflow can be triggered by specific events such as push, pull request, new release, and so on. Each workflow trigger provides a [Github context](https://docs.github.com/en/actions/learn-github-actions/contexts#github-context) which contains information about the event. This can be the branch name, username, user email, pull request title and body, etc. All this input should be treated as potentially untrusted data, and make sure it doesn't flow into shell or API calls where it can be interpreted as code.
A GitHub Actions workflow can be triggered by specific events such as push, pull request, new release, and so on. Each workflow trigger provides a [GitHub context](https://docs.github.com/en/actions/learn-github-actions/contexts#github-context) which contains information about the event. This can be the branch name, username, user email, pull request title and body, etc. All this input should be treated as potentially untrusted data, and make sure it doesn't flow into shell or API calls where it can be interpreted as code.

#### Example of a script injection attack with inline script

Expand Down Expand Up @@ -233,6 +233,18 @@ After activating the scorecard workflow, the results are uploaded to the reposit

The [Open Source Security Foundation (OpenSSF)](https://openssf.org/) provides a badge that indicates a project's security best practices score. The badge is generated based on the [OpenSSF Best Practices](https://www.bestpractices.dev/en/criteria/0) criteria. To get the badge, you need to register at the [OpenSSF Best Practices](https://www.bestpractices.dev/en) website and submit your repository. You will then need to answer a questionnaire about the project's security practices. The badge is generated based on the answers and is available once you have started answering the questionnaire. The badge can then be added to the repository's README file.

## OpenSSF Security Insights Specification

In order to report information about the security status of a project in a machine-processable way, OpenSSF has created the [Security Insights Specification](https://github.com/ossf/security-insights-spec/blob/main/specification.md). The specification defines a format for the `SECURITY-INSIGHTS.yml` file, which can be used to report project status (e.g. whether the project is actively maintained or not), contribution policies, security artifacts (e.g. threat model, self-assessment) and other security-related information.

ℹ️ The security insights file for this repository can be found in the file [SECURITY-INSIGHTS.yml](../SECURITY-INSIGHTS.yml).

## OpenSSF Allstar

[Allstar](https://github.com/ossf/allstar) is an OpenSSF project that continuously monitors GitHub organisations or repositories for security best practices. It can create issues in the repositories or fix them automatically. This can be useful to ensure that all repositories in an organisation are following the same security practices. It makes more sense to use Allstar at the organisation level rather than for personal repositories, since most of the checks are already covered by the OpenSSF Scorecard workflow and the OpenSSF Best Practices badge.

ℹ️ The Allstar configuration for this repository can be found in the [.allstar](../.allstar) directory.

## Dependency graph

By default, GitHub enables the dependency graph for public repositories. The dependency graph shows the *direct* and *transitive* dependencies of a repository, and is updated automatically. The graph is generated based on the package manifest files in the repository. It can be useful to see which packages are used in the repository, and which repositories depend on the repository. The dependency graph can be found in the `Insights` tab of the repository.
Expand Down
91 changes: 91 additions & 0 deletions docs/prerequisites_verification.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
# Prerequisites verification

## SLSA-Verifier

To verify the SLSA provenance, you need the [slsa-verifier](https://github.com/slsa-framework/slsa-verifier) binary. You can install it via Homebrew or download it from GitHub.

Download with Hombrew:

```bash
brew install slsa-verifier
```

Download binary from GitHub and verify checksum:

```bash
# get the latest release
export VERSION=$(curl -s "https://api.github.com/repos/slsa-framework/slsa-verifier/releases/latest" | jq -r '.tag_name')
export ARCH=darwin-arm64 # linux-amd64

# download binary and shasum file
curl -L -O https://github.com/slsa-framework/slsa-verifier/releases/download/$VERSION/slsa-verifier-$ARCH
curl -L -O https://raw.githubusercontent.com/slsa-framework/slsa-verifier/main/SHA256SUM.md

# simplify shasum file since it has all hashes for all versions in it
sed -n "/### \[${VERSION}\]/,/^### /p" SHA256SUM.md | grep -vE '^###|^$' > sha256sum_filtered

# shasum check on macOS
shasum -a 256 -c --ignore-missing --strict sha256sum_filtered

# shasum check on linux
sha256sum -c --strict --ignore-missing sha256sum_filtered

# make binary executable and move it to a location in your $PATH
chmod +x slsa-verifier-$ARCH
sudo mv slsa-verifier-$ARCH /usr/local/bin/slsa-verifier
```

## Cosign

As an alternative to the SLSA-Verifier, you can use the [Cosign](https://github.com/sigstore/cosign) CLI to verify the docker images and the checksum file.

Install Cosign via Homebrew or have a look at the [installation instructions](https://docs.sigstore.dev/system_config/installation/).

```bash
brew install cosign
```

## Crane

[Crane](https://github.com/google/go-containerregistry/blob/main/cmd/crane/README.md) is a tool for interacting with remote images and registries. We use it to get the image digest for the verification.

Download with Hombrew:

```bash
brew install crane
```

Download binary from GitHub and verify SLSA provenance:

```bash
# get the latest release
VERSION=$(curl -s "https://api.github.com/repos/google/go-containerregistry/releases/latest" | jq -r '.tag_name')
ARCH=Darwin_arm64 # Linux_amd64

# download binary package and provenance file
curl -sL "https://github.com/google/go-containerregistry/releases/download/$VERSION/go-containerregistry_$ARCH.tar.gz" > go-containerregistry.tar.gz
curl -sL https://github.com/google/go-containerregistry/releases/download/$VERSION/multiple.intoto.jsonl > provenance.intoto.jsonl

# verify SLSA provenance
slsa-verifier verify-artifact \
--provenance-path provenance.intoto.jsonl \
--source-uri github.com/google/go-containerregistry \
--source-tag $VERSION \
go-containerregistry.tar.gz

Verifying artifact go-containerregistry.tar.gz: PASSED
PASSED: Verified SLSA provenance

# unpack crane in the $PATH
tar -zxvf go-containerregistry.tar.gz crane
chmod +x crane
sudo mv crane /usr/local/bin/crane
```

## jq

[jq](https://github.com/jqlang/jq) is a lightweight and flexible command-line JSON processor. We use it to inspect the provenance files. You can install it via Homebrew or see the [installation instructions](https://jqlang.github.io/jq/download/).

```bash
brew install jq
```
Loading