Skip to content

Latest commit

 

History

History
578 lines (458 loc) · 17.2 KB

File metadata and controls

578 lines (458 loc) · 17.2 KB

OSSF Scorecard Improvements Plan

Current Score: 6.6/10 → 7.5+/10 (in progress) Target Score: 9.5+/10 Last Updated: 2025-10-24

🎉 Recent Improvements (October 24, 2025)

✅ Completed: Comprehensive Security Tooling Stack

PR: #19 - Self-hosted runners + OSSF security stack Commits: c0d536b, e481937

Security Scanning Enhancements

Added Tools:

  1. Semgrep - Multi-language SAST with 2000+ security rules
  2. Gitleaks 8.28.0 - Fast secret scanner
  3. TruffleHog 3.90.3 - Comprehensive secret scanner with verification
  4. Nancy - OSS Index dependency scanner
  5. go-licenses - License compliance analysis
  6. Syft 1.34.2 - SBOM generation (CycloneDX + SPDX)
  7. Grype 0.101.1 - Binary vulnerability scanner
  8. Cosign 3.0.2 - Container signing (Sigstore)

Migration to Native Binaries:

  • All security tools now use native binaries (no Docker actions)
  • Eliminates container overhead and permission issues
  • Consistent tool versions across workflows

Expected Impact:

  • ✅ SAST check: Enhanced (semgrep + gosec + CodeQL)
  • ✅ Vulnerabilities check: Comprehensive (govulncheck + OSV + Nancy + Grype)
  • ✅ Supply Chain: SBOM generation for all artifacts
  • ✅ Security Policy: Enhanced with detailed tool documentation

CI/CD Improvements

Lint Workflow:

  • Migrated all linters to native tools (golangci-lint, markdownlint, yamllint, hadolint)
  • Removed Docker action dependencies
  • Faster execution with local binaries

CI Workflow:

  • Added staticcheck, errcheck, ineffassign
  • Post-build SBOM generation
  • Post-build binary scanning with Grype
  • Enhanced code quality checks

Security Workflow:

  • 4 new security jobs: semgrep, nancy, gitleaks, trufflehog
  • License compliance checking
  • SBOM with license information
  • All tools produce SARIF for GitHub Security

Release Workflow:

  • SBOM generation for all release artifacts
  • Container image signing with Cosign v3 (keyless OIDC)
  • SLSA provenance (existing)

Packaging Infrastructure

Package Types:

  • RPM: EL8/9/10 with mock builds
  • DEB: Debian 12/13, Ubuntu 24.04
  • FreeBSD: amd64/arm64

Security Features:

  • SELinux support for RHEL/Oracle Linux
  • Proper systemd hardening
  • Unprivileged service user
  • Secure file permissions

Paths Fixed:

  • Binary: /usr/sbin/ocserv-agent (was incorrectly in /etc/)
  • Config: /etc/ocserv-agent/ (read-only for service)
  • Logs: /var/log/ocserv-agent/ (writable)

Documentation

New Documentation:

  • docs/SECURITY_TOOLS.md - Comprehensive security tools guide
  • docs/PACKAGING.md - Package building and installation guide

Updated Documentation:

  • This file (OSSF_SCORECARD_IMPROVEMENTS.md)

Standards Compliance

Standard Before After Status
OSSF Scorecard 4.9/10 6.6/10 🟡 In Progress
SLSA Build L3 Partial ✅ Full ✅ Complete
OSPS Baseline L3 Partial ✅ Full ✅ Complete
EU CRA No SBOM ✅ SBOM ✅ Complete
NIST SSDF Partial ✅ Full ✅ Complete

📊 Current Status

Passing Checks (Score 10/10)

  • Binary-Artifacts: No binaries in repo
  • Dangerous-Workflow: No dangerous GitHub Action patterns
  • Dependency-Update-Tool: Dependabot configured
  • License: Valid FSF/OSI license (MIT)
  • SAST: CodeQL static analysis enabled
  • Vulnerabilities: No known unfixed vulnerabilities

Failing Checks (Score 0/10)

  • 🔴 Code-Review (0/10): All 30 changesets lack review
  • 🔴 Contributors (0/10): Single-organization project
  • 🔴 Fuzzing (0/10): No fuzzing framework
  • 🔴 Pinned-Dependencies (0/10): 49+ unpinned dependencies
  • 🔴 Security-Policy (0/10): Missing SECURITY.mdFIXED
  • 🔴 Token-Permissions (0/10): Excessive workflow permissions

Problematic Checks

  • ⚠️ Branch-Protection (-1): Integration error
  • ⚠️ Signed-Releases (5/10): Only 1 of 2 artifacts signed
  • ⚠️ Maintained (0/10): Repository too young (<90 days)

🎯 Improvement Plan

Phase 1: Quick Wins (Score: 4.9 → 6.5)

1.1 Security Policy ✅ COMPLETED

  • Create SECURITY.md
  • Vulnerability disclosure policy
  • Contact information
  • Response timeline

Impact: +1.0 points (Security-Policy: 0 → 10)

1.2 Code Review Process (HIGH PRIORITY)

Problem: All commits pushed directly to main without review

Solutions:

  1. Enable Branch Protection Rules:

    # Via GitHub UI: Settings → Branches → Branch protection rules
    # Or via gh CLI:
    gh api repos/dantte-lp/ocserv-agent/branches/main/protection \
      --method PUT \
      --field required_pull_request_reviews[required_approving_review_count]=1 \
      --field required_pull_request_reviews[dismiss_stale_reviews]=true \
      --field enforce_admins=true \
      --field required_linear_history=true
  2. Workflow Changes:

    • All changes via Pull Requests
    • Require 1 approval before merge
    • Enable "Require review from Code Owners"
    • Dismiss stale reviews when new commits pushed
  3. Exception Handling:

    • Emergency hotfixes: Create PR, get fast-track review
    • Documentation updates: Still require PR (can be self-approved with justification)

Impact: +1.0 points (Code-Review: 0 → 10)

Implementation Steps:

# 1. Setup branch protection
gh repo edit dantte-lp/ocserv-agent --enable-issues=true --enable-projects=false
gh api -X PUT /repos/dantte-lp/ocserv-agent/branches/main/protection \
  -f required_pull_request_reviews[required_approving_review_count]=1 \
  -f required_status_checks[strict]=true \
  -f required_status_checks[contexts][]=CI \
  -f required_status_checks[contexts][]=Security \
  -f required_status_checks[contexts][]=Lint \
  -f enforce_admins=true

# 2. Create CODEOWNERS file
echo "* @dantte-lp" > .github/CODEOWNERS

1.3 Token Permissions Restriction (MEDIUM PRIORITY)

Problem: Workflows have excessive permissions

Current Issues:

  • release.yml: contents: write, packages: write, id-token: write
  • Some workflows don't specify permissions at all (default: all)

Solutions:

  1. CI Workflow (.github/workflows/ci.yml):
permissions:
  contents: read
  actions: read  # For artifact downloads
  1. Lint Workflow (.github/workflows/lint.yml):
permissions:
  contents: read
  pull-requests: read  # Already correct
  1. Security Workflow (.github/workflows/security.yml):
# Top-level (default for all jobs)
permissions:
  contents: read

jobs:
  gosec:
    permissions:
      contents: read
      security-events: write  # For SARIF upload

  codeql:
    permissions:
      contents: read
      security-events: write

  trivy:
    permissions:
      contents: read
      security-events: write

  scorecard:
    permissions:
      contents: read
      security-events: write
      id-token: write  # Required for OIDC
      actions: read    # Required for scorecard
  1. Release Workflow (.github/workflows/release.yml):
permissions: {}  # No default permissions

jobs:
  build-artifacts:
    permissions:
      contents: read

  build:  # SLSA provenance
    permissions:
      id-token: write
      contents: write  # For uploading assets
      actions: read

  release:
    permissions:
      contents: write  # For creating release

  container:
    permissions:
      contents: read
      packages: write  # For GHCR push

Impact: +1.0 points (Token-Permissions: 0 → 10)


Phase 2: Dependency Pinning (Score: 6.5 → 7.5)

2.1 Pin GitHub Actions to SHA Hashes (HIGH EFFORT)

Problem: All GitHub Actions use version tags (@v4, @v5) instead of SHA hashes

Why Pin?

  • Security: Prevents supply chain attacks via compromised action versions
  • Reproducibility: Ensures builds are deterministic
  • OSSF Requirement: Necessary for Scorecard score

Actions to Pin (22 unique actions):

Action Current Target SHA (example)
actions/checkout@v4 v4 b4ffde65f46336ab88eb53be808477a3936bae11 (v4.1.1)
actions/setup-go@v5 v5 0a12ed9d6a96ab950c8f026ed9f722fe0da7ef32 (v5.0.2)
actions/upload-artifact@v4 v4 50769540e7f4bd5e21e526ee35c689e35e0d6874 (v4.4.3)
actions/download-artifact@v4 v4 fa0a91b85d4f404e444e00e005971372dc801d16 (v4.1.8)
codecov/codecov-action@v4 v4 015f24e6818733317a2da2edd6290ab26238649a (v4.6.0)
golangci/golangci-lint-action@v4 v4 971e284b6050e8a5849b72094c50ab08da042db8 (v4.0.1)
github/codeql-action/init@v3 v3 4f3212b61783c3c68e8309a0f18a699764811cda (v3.27.1)
github/codeql-action/autobuild@v3 v3 4f3212b61783c3c68e8309a0f18a699764811cda
github/codeql-action/analyze@v3 v3 4f3212b61783c3c68e8309a0f18a699764811cda
github/codeql-action/upload-sarif@v3 v3 4f3212b61783c3c68e8309a0f18a699764811cda
securego/gosec@master master ⚠️ Use tagged version!
aquasecurity/trivy-action@master master ⚠️ Use tagged version!
ossf/scorecard-action@v2.3.1 v2.3.1 62b2cac7ed8198b15735ed49ab1e5cf35480ba46 (v2.3.1)
softprops/action-gh-release@v1 v1 c062e08bd532815e2082a85e87e3ef29c3e6d191 (v2.0.8)
docker/setup-qemu-action@v3 v3 49b3bc8e6bdd4a60e6116a5414239cba5943d3cf (v3.2.0)
docker/setup-buildx-action@v3 v3 c47758b77c9736f4b2ef4073d4d51994fabfe349 (v3.7.1)
docker/login-action@v3 v3 9780b0c442fbb1117ed29e0efdff1e18412f7567 (v3.3.0)
docker/metadata-action@v5 v5 60a0d343a0d8a18aedee9d34e62251f752153bdb (v5.6.1)
docker/build-push-action@v5 v5 4f58ea79222b3b9dc2c8bbdd6debcef730109a75 (v5.4.0)
slsa-framework/slsa-github-generator@v2.0.0 v2.0.0 Keep version tag (trusted)
avto-dev/markdown-lint@v1 v1 04d43ee9191307b50935a753da3b775ab695eceb (v1.2.0)
ibiqlik/action-yamllint@v3 v3 2576378a8e339169678f9939646ee3ee325e845c (v3.1.1)
hadolint/hadolint-action@v3.1.0 v3.1.0 54c9adbab1582c2ef04b2016b760714a4bfde3cf (v3.1.0)

Automated Pinning Script:

#!/bin/bash
# pin-actions.sh - Pin GitHub Actions to SHA hashes

declare -A SHAS=(
  ["actions/checkout@v4"]="b4ffde65f46336ab88eb53be808477a3936bae11"
  ["actions/setup-go@v5"]="0a12ed9d6a96ab950c8f026ed9f722fe0da7ef32"
  # ... add all mappings
)

for workflow in .github/workflows/*.yml; do
  for action in "${!SHAS[@]}"; do
    sha="${SHAS[$action]}"
    # Replace with SHA and add comment
    sed -i "s|uses: ${action}|uses: ${action%%@*}@${sha} # ${action}|g" "$workflow"
  done
done

Manual Process:

  1. For each action, find the latest release tag
  2. Get commit SHA for that tag: gh api repos/{owner}/{repo}/git/ref/tags/{tag}
  3. Replace @v4 with @<sha> # v4
  4. Add comment to indicate original version

Impact: +1.0 points (Pinned-Dependencies: 0 → 10)

2.2 Pin Docker Base Images

Current Issues:

  • Dockerfile uses golang:1.25-alpine without digest

Solution:

# Before:
FROM golang:1.25-alpine AS builder

# After:
FROM golang:1.25-alpine@sha256:abcdef123... AS builder

Get Digest:

docker pull golang:1.25-alpine
docker inspect --format='{{index .RepoDigests 0}}' golang:1.25-alpine

Also check:

  • deploy/compose/docker-compose.yml
  • deploy/compose/docker-compose.dev.yml
  • deploy/compose/docker-compose.test.yml

Phase 3: Signing & Provenance (Score: 7.5 → 8.0)

3.1 Signed Releases (MEDIUM PRIORITY)

Problem: Only 1 of 2 artifacts signed

Current Status:

  • SLSA provenance generated ✅
  • Some artifacts not signed ⚠️

Solutions:

  1. GPG Sign All Release Artifacts:
# .github/workflows/release.yml
- name: Sign artifacts
  run: |
    echo "${{ secrets.GPG_PRIVATE_KEY }}" | gpg --import
    for file in dist/*.tar.gz; do
      gpg --detach-sign --armor "$file"
    done
  1. Cosign for Container Images:
- name: Sign container image
  run: |
    cosign sign --key env://COSIGN_KEY ghcr.io/${{ github.repository }}:${{ steps.meta.outputs.version }}
  env:
    COSIGN_KEY: ${{ secrets.COSIGN_PRIVATE_KEY }}
    COSIGN_PASSWORD: ${{ secrets.COSIGN_PASSWORD }}

Impact: +0.5 points (Signed-Releases: 5 → 10)

3.2 GPG Commit Signing

Problem: Commits not GPG signed (shows as "Unverified" on GitHub)

Solutions:

  1. Generate GPG Key:
gpg --full-generate-key
# Select: (1) RSA and RSA
# Key size: 4096
# Expiration: 2 years
# Name: dantte-lp
# Email: <your-github-email>
  1. Configure Git:
gpg --list-secret-keys --keyid-format=long
# Copy key ID (after sec rsa4096/)
git config --global user.signingkey <KEY_ID>
git config --global commit.gpgsign true
git config --global tag.gpgsign true
  1. Add to GitHub:
gpg --armor --export <KEY_ID>
# Copy output and add to GitHub Settings → SSH and GPG keys
  1. Sign Previous Commits (if needed):
# Rebase and sign last N commits
git rebase --exec 'git commit --amend --no-edit --gpg-sign' -i HEAD~N

Impact: Improves trust, required for Code-Review score


Phase 4: Advanced Improvements (Score: 8.0 → 9.0+)

4.1 Fuzzing Integration

Options:

  1. OSS-Fuzz (Recommended):

    • Submit project to Google OSS-Fuzz
    • Continuous fuzzing infrastructure
    • Automatic bug reports
  2. Go-fuzz:

// internal/config/config_fuzz_test.go
//go:build gofuzz
package config

func FuzzLoadConfig(f *testing.F) {
    f.Add([]byte("valid config"))
    f.Fuzz(func(t *testing.T, data []byte) {
        // Fuzz config parser
    })
}
  1. GitHub Actions Fuzzing:
# .github/workflows/fuzz.yml
- name: Run fuzz tests
  run: go test -fuzz=. -fuzztime=30s ./...

Impact: +1.0 points (Fuzzing: 0 → 10)

4.2 Multi-Contributor Project

Problem: Single organization contributor

Solutions:

  • Encourage external contributions
  • Good first issues for newcomers
  • Clear contributing guidelines (✅ already have)
  • Community engagement

Impact: +1.0 points (Contributors: 0 → 10) - Takes time

4.3 CII Best Practices Badge

Steps:

  1. Complete self-certification: https://bestpractices.coreinfrastructure.org/
  2. Answer ~60 questions about project practices
  3. Achieve "passing" level (later: silver, gold)

Requirements:

  • Public version control ✅
  • Unique version numbers ✅
  • Release notes ✅
  • License ✅
  • Documentation ✅
  • Test suite ✅
  • ...and more

Impact: +1.0 points (CII-Best-Practices: 0 → 10)


📅 Implementation Timeline

Week 1: Quick Wins

  • Day 1: Create SECURITY.md ✅
  • Day 2-3: Setup branch protection rules
  • Day 4-5: Restrict token permissions in workflows
  • Day 6-7: Setup GPG commit signing

Expected Score: 6.5/10

Week 2: Dependency Pinning

  • Day 1-3: Pin all GitHub Actions to SHA hashes
  • Day 4-5: Pin Docker base images with digests
  • Day 6-7: Test and validate all workflows

Expected Score: 7.5/10

Week 3: Signing & Provenance

  • Day 1-3: Implement GPG signing for all artifacts
  • Day 4-5: Add Cosign for container images
  • Day 6-7: Verify and document signing process

Expected Score: 8.0/10

Month 2+: Advanced Improvements

  • Fuzzing integration
  • Community building for multi-contributor
  • CII Best Practices certification
  • SLSA Level 3 compliance

Expected Score: 9.0+/10


🔧 Tools & Resources

Automated Checking

# Check current score
curl https://api.scorecard.dev/projects/github.com/dantte-lp/ocserv-agent

# Run scorecard locally
docker run -e GITHUB_AUTH_TOKEN=<token> gcr.io/openssf/scorecard:stable \
  --repo=github.com/dantte-lp/ocserv-agent --show-details

Helpful Links


✅ Progress Tracking

Check Current Target Status
Binary-Artifacts 10 10 ✅ Done
Branch-Protection -1 10 🔄 Pending
CI-Tests N/A N/A ✅ Done
CII-Best-Practices 0 8 ⏳ Future
Code-Review 0 10 🔴 High Priority
Contributors 0 5 ⏳ Future
Dangerous-Workflow 10 10 ✅ Done
Dependency-Update-Tool 10 10 ✅ Done
Fuzzing 0 8 🟡 Medium Priority
License 10 10 ✅ Done
Maintained 0 10 ⏳ Time-based
Packaging -1 8 ⏳ Future
Pinned-Dependencies 0 10 🔴 High Priority
SAST 10 10 ✅ Done
Security-Policy 10 10 ✅ Done
Signed-Releases 5 10 🟡 Medium Priority
Token-Permissions 0 10 🔴 High Priority
Vulnerabilities 10 10 ✅ Done

Current Score: 4.9/10 Projected Score (Phase 1): 6.5/10 (+1.6) Projected Score (Phase 2): 7.5/10 (+1.0) Projected Score (Phase 3): 8.0/10 (+0.5) Projected Score (Phase 4): 9.0+/10 (+1.0+)


Last Updated: 2025-10-23 Next Review: After Phase 1 completion