15 KiB
Security Scanning
Complete guide to security scanning workflows in the StellaOps CI/CD pipeline.
Security Scanning Overview
StellaOps implements a defense-in-depth security scanning strategy:
┌─────────────────────────────────────────────────────────────────┐
│ SECURITY SCANNING LAYERS │
├─────────────────────────────────────────────────────────────────┤
│ │
│ Layer 1: PRE-COMMIT │
│ └── Secrets scanning (pre-commit hook) │
│ │
│ Layer 2: PULL REQUEST │
│ ├── SAST (Static Application Security Testing) │
│ ├── Secrets scanning │
│ ├── Dependency vulnerability audit │
│ └── License compliance check │
│ │
│ Layer 3: MAIN BRANCH │
│ ├── All Layer 2 scans │
│ ├── Container image scanning │
│ └── Extended SAST analysis │
│ │
│ Layer 4: SCHEDULED │
│ ├── Weekly deep SAST scan (Monday) │
│ ├── Weekly dependency audit (Sunday) │
│ ├── Daily container scanning │
│ └── Nightly regression security tests │
│ │
│ Layer 5: RELEASE │
│ ├── Final vulnerability gate │
│ ├── SBOM generation and signing │
│ ├── Provenance attestation │
│ └── Container signing │
│ │
└─────────────────────────────────────────────────────────────────┘
Scanning Workflows
1. SAST Scanning (sast-scan.yml)
Purpose: Detect security vulnerabilities in source code through static analysis.
Triggers:
- Pull requests (source code changes)
- Push to main/develop
- Weekly Monday 3:30 AM UTC
- Manual dispatch
Scanned Languages:
- C# / .NET
- JavaScript / TypeScript
- Python
- YAML
- Dockerfile
Checks Performed:
| Check | Tool | Scope |
|---|---|---|
| Code vulnerabilities | Semgrep/CodeQL (placeholder) | All source |
| .NET security analyzers | Built-in Roslyn | C# code |
| Dependency vulnerabilities | dotnet list --vulnerable |
NuGet packages |
| Dockerfile best practices | Hadolint | Dockerfiles |
Configuration:
# sast-scan.yml inputs
workflow_dispatch:
inputs:
scan_level:
type: choice
options:
- quick # Fast scan, critical issues only
- standard # Default, balanced coverage
- comprehensive # Full scan, all rules
fail_on_findings:
type: boolean
default: true # Block on findings
.NET Security Analyzer Rules:
The workflow enforces these security-critical CA rules as errors:
| Category | Rules | Description |
|---|---|---|
| SQL Injection | CA2100 | Review SQL queries for vulnerabilities |
| Cryptography | CA5350-5403 | Weak crypto, insecure algorithms |
| Deserialization | CA2300-2362 | Unsafe deserialization |
| XML Security | CA3001-3012 | XXE, XPath injection |
| Web Security | CA3061, CA5358-5398 | XSS, CSRF, CORS |
2. Secrets Scanning (secrets-scan.yml)
Purpose: Detect hardcoded credentials, API keys, and secrets in code.
Triggers:
- Pull requests
- Push to main/develop
- Manual dispatch
Detection Patterns:
| Secret Type | Example Pattern |
|---|---|
| API Keys | sk_live_[a-zA-Z0-9]+ |
| AWS Keys | AKIA[0-9A-Z]{16} |
| Private Keys | -----BEGIN RSA PRIVATE KEY----- |
| Connection Strings | Password=.*;User ID=.* |
| JWT Tokens | eyJ[A-Za-z0-9-_]+\.[A-Za-z0-9-_]+ |
| GitHub Tokens | gh[ps]_[A-Za-z0-9]{36} |
Tool Options (Placeholder):
# Choose one by uncommenting in sast-scan.yml:
# Option 1: TruffleHog (recommended for open source)
# - name: TruffleHog Scan
# uses: trufflesecurity/trufflehog@main
# with:
# extra_args: --only-verified
# Option 2: Gitleaks
# - name: Gitleaks Scan
# uses: gitleaks/gitleaks-action@v2
# env:
# GITLEAKS_LICENSE: ${{ secrets.GITLEAKS_LICENSE }}
# Option 3: Semgrep
# - name: Semgrep Secrets
# uses: returntocorp/semgrep-action@v1
# with:
# config: p/secrets
Allowlist Configuration:
Create .gitleaksignore or .secretsignore for false positives:
# Ignore test fixtures
src/__Tests/**/*
docs/examples/**/*
# Ignore specific files
path/to/test-credentials.json
# Ignore by rule ID
[allowlist]
regexes = ["test_api_key_[a-z]+"]
3. Container Scanning (container-scan.yml)
Purpose: Scan container images for OS and application vulnerabilities.
Triggers:
- Dockerfile changes
- Daily schedule (4 AM UTC)
- Manual dispatch
Scan Targets:
| Image | Built From | Scanned Components |
|---|---|---|
stellaops/authority |
src/Authority/Dockerfile |
OS packages, .NET runtime |
stellaops/scanner |
src/Scanner/Dockerfile |
OS packages, .NET runtime, analyzers |
stellaops/concelier |
src/Concelier/Dockerfile |
OS packages, .NET runtime |
| (9 total images) | ... | ... |
Vulnerability Severity Levels:
| Severity | Action | Example |
|---|---|---|
| CRITICAL | Block release | Remote code execution |
| HIGH | Block release (configurable) | Privilege escalation |
| MEDIUM | Warning | Information disclosure |
| LOW | Log only | Minor issues |
| UNKNOWN | Log only | Unclassified |
Tool Options (Placeholder):
# Choose one by uncommenting in container-scan.yml:
# Option 1: Trivy (recommended)
# - name: Trivy Scan
# uses: aquasecurity/trivy-action@master
# with:
# image-ref: ${{ steps.build.outputs.image }}
# format: sarif
# output: trivy-results.sarif
# severity: CRITICAL,HIGH
# Option 2: Grype
# - name: Grype Scan
# uses: anchore/scan-action@v3
# with:
# image: ${{ steps.build.outputs.image }}
# fail-build: true
# severity-cutoff: high
# Option 3: Snyk Container
# - name: Snyk Container
# uses: snyk/actions/docker@master
# env:
# SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
4. Dependency Security Scanning (dependency-security-scan.yml)
Purpose: Audit NuGet and npm packages for known vulnerabilities.
Triggers:
- Weekly Sunday 2 AM UTC
- Pull requests (dependency file changes)
- Manual dispatch
Scanned Files:
| Ecosystem | Files |
|---|---|
| NuGet | src/Directory.Packages.props, **/*.csproj |
| npm | **/package.json, **/package-lock.json |
Vulnerability Sources:
- GitHub Advisory Database
- NVD (National Vulnerability Database)
- OSV (Open Source Vulnerabilities)
- Vendor security advisories
Scan Process:
┌─────────────────────────────────────────────────────────────────┐
│ DEPENDENCY SECURITY SCAN │
├─────────────────────────────────────────────────────────────────┤
│ │
│ ┌──────────────┐ │
│ │ scan-nuget │ dotnet list package --vulnerable │
│ └──────┬───────┘ │
│ │ │
│ ▼ │
│ ┌──────────────┐ │
│ │ scan-npm │ npm audit --json │
│ └──────┬───────┘ │
│ │ │
│ ▼ │
│ ┌──────────────┐ │
│ │ summary │ Aggregate results, generate report │
│ └──────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────┘
Example Output:
## Dependency Vulnerability Audit
### NuGet Packages
| Package | Installed | Vulnerable | Severity | Advisory |
|---------|-----------|------------|----------|----------|
| Newtonsoft.Json | 12.0.1 | < 13.0.1 | HIGH | GHSA-xxxx |
### npm Packages
| Package | Installed | Vulnerable | Severity | Advisory |
|---------|-----------|------------|----------|----------|
| lodash | 4.17.15 | < 4.17.21 | CRITICAL | npm:lodash:1 |
5. License Compliance (dependency-license-gate.yml)
Purpose: Ensure all dependencies use approved licenses.
Approved Licenses:
| License | SPDX ID | Status |
|---|---|---|
| MIT | MIT | Approved |
| Apache 2.0 | Apache-2.0 | Approved |
| BSD 2-Clause | BSD-2-Clause | Approved |
| BSD 3-Clause | BSD-3-Clause | Approved |
| ISC | ISC | Approved |
| MPL 2.0 | MPL-2.0 | Review Required |
| LGPL 2.1+ | LGPL-2.1-or-later | Review Required |
| GPL 2.0+ | GPL-2.0-or-later | Blocked (copyleft) |
| AGPL 3.0 | AGPL-3.0 | Blocked (copyleft) |
Blocked on Violation:
- GPL-licensed runtime dependencies
- Unknown/proprietary licenses without explicit approval
Scan Results & Reporting
GitHub Step Summary
All security scans generate GitHub Step Summary reports:
## SAST Scan Summary
| Check | Status |
|-------|--------|
| SAST Analysis | ✅ Pass |
| .NET Security | ⚠️ 3 warnings |
| Dependency Check | ✅ Pass |
| Dockerfile Lint | ✅ Pass |
### .NET Security Warnings
- CA5350: Weak cryptographic algorithm (src/Crypto/Legacy.cs:42)
- CA2100: SQL injection risk (src/Data/Query.cs:78)
SARIF Integration
Scan results are uploaded in SARIF format for IDE integration:
- name: Upload SARIF
uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: scan-results.sarif
Artifact Retention
| Artifact | Retention |
|---|---|
| SARIF files | 30 days |
| Vulnerability reports | 90 days |
| License audit logs | 1 year |
Security Gates
PR Merge Requirements
| Gate | Threshold | Block Merge? |
|---|---|---|
| SAST Critical | 0 | Yes |
| SAST High | 0 | Configurable |
| Secrets Found | 0 | Yes |
| Vulnerable Dependencies (Critical) | 0 | Yes |
| Vulnerable Dependencies (High) | 5 | Warning |
| License Violations | 0 | Yes |
Release Requirements
| Gate | Threshold | Block Release? |
|---|---|---|
| Container Scan (Critical) | 0 | Yes |
| Container Scan (High) | 0 | Yes |
| SBOM Generation | Success | Yes |
| Signature Verification | Valid | Yes |
Remediation Workflows
Dependency Vulnerability Fix
-
Renovate Auto-Fix:
# renovate.json { "vulnerabilityAlerts": { "enabled": true, "labels": ["security"], "automerge": false } } -
Manual Override:
# Update specific package dotnet add package Newtonsoft.Json --version 13.0.3 # Audit and fix npm npm audit fix
False Positive Suppression
.NET Analyzer Suppression:
// Suppress specific instance
#pragma warning disable CA2100 // Review SQL queries for vulnerability
var query = $"SELECT * FROM {tableName}";
#pragma warning restore CA2100
// Or in .editorconfig
[*.cs]
dotnet_diagnostic.CA2100.severity = none # NOT RECOMMENDED
Semgrep/SAST Suppression:
// nosemgrep: sql-injection
var query = $"SELECT * FROM {tableName}";
Container Scan Ignore:
# .trivyignore
CVE-2021-44228 # Log4j - not applicable (no Java)
CVE-2022-12345 # Accepted risk with mitigation
Configuration Files
Location
| File | Purpose | Location |
|---|---|---|
.gitleaksignore |
Secrets scan allowlist | Repository root |
.trivyignore |
Container scan ignore list | Repository root |
.semgrepignore |
SAST ignore patterns | Repository root |
renovate.json |
Dependency update config | Repository root |
.editorconfig |
Analyzer severity | Repository root |
Example .trivyignore
# Ignore by CVE ID
CVE-2021-44228
# Ignore by package
pkg:npm/lodash@4.17.15
# Ignore with expiration
CVE-2022-12345 exp:2025-06-01
Scheduled Scan Summary
| Day | Time (UTC) | Workflow | Focus |
|---|---|---|---|
| Daily | 2:00 AM | nightly-regression.yml |
Security tests |
| Daily | 4:00 AM | container-scan.yml |
Image vulnerabilities |
| Sunday | 2:00 AM | dependency-security-scan.yml |
Package audit |
| Monday | 3:30 AM | sast-scan.yml |
Deep code analysis |
Monitoring & Alerts
Notification Channels
Configure notifications for security findings:
# In workflow
- name: Notify on Critical
if: steps.scan.outputs.critical_count > 0
run: |
curl -X POST "${{ secrets.SLACK_WEBHOOK }}" \
-d '{"text":"🚨 Critical security finding in '${{ github.repository }}'"}'
Dashboard Integration
Security scan results can be exported to:
- Grafana dashboards (via OTLP metrics)
- Security Information and Event Management (SIEM)
- Vulnerability management platforms