JustLABv1/justscan
GitHub: JustLABv1/justscan
JustScan 是一个自托管的容器镜像漏洞扫描平台,整合 Trivy、Grype 和 Artifactory Xray,帮助团队在部署前自动化发现容器镜像中的安全漏洞。
Stars: 2 | Forks: 0
# JustScan

[](https://github.com/aquasecurity/trivy)
[](./LICENSE)
JustScan 是一个自托管的容器镜像漏洞扫描器,由 [Trivy](https://github.com/aquasecurity/trivy) 或 Artifactory Xray 提供支持。
## 目录
- [概述](#overview)
- [核心功能](#key-features)
- [架构](#architecture)
- [GitOps 仓库发现](#gitops-repository-discovery)
- [CLI](#cli)
- [快速开始](#quick-start)
- [配置参考](#configuration-reference)
- [OIDC 配置](#oidc-configuration)
- [前端配置](#frontend-configuration)
- [部署](#deployment)
- [Docker Compose](#docker-compose)
- [Helm](#helm)
- [GitLab CI:推送前扫描(上传归档)](#gitlab-ci-scan-before-push-uploaded-archive)
- [常见问题](#common-issues)
- [获取 NVD API Key](#getting-an-nvd-api-key)
- [开发](#development)
- [贡献](#contributing)
- [License](#license)
## 概述
JustScan 可帮助团队在部署前扫描容器镜像的漏洞。它支持通过 Trivy 进行本地扫描,以及通过 Artifactory Xray 进行远程扫描工作流,并提供 Web UI、API 访问和组织感知的工作流。
## 核心功能
- 针对容器镜像的自托管漏洞扫描
- 支持基于 Trivy 的本地扫描
- 支持 Artifactory Xray 集成
- 提供 Web UI,可查看扫描历史和结果
- 支持 OIDC SSO(Keycloak, Authentik, Okta, Azure AD, Google Workspace)
- 提供用于 CI/CD 自动化的 API endpoint
- 支持 Docker Compose 和 Helm 部署选项
## GitOps 仓库发现
可以在 Web UI 中连接 Git 仓库,以预览和调度镜像扫描。试运行(dry run)始终优先执行发现操作,且永远不会将扫描加入队列。
- **Auto**(默认模式)会检测未显式引用的 Kustomize 部署根目录,使用 Kustomize 内置的 Helm 支持对其进行渲染,并仅从生成的 Kubernetes 工作负载中提取镜像。如果不存在 Kustomization,它将改为扫描普通的 Kubernetes 工作负载清单。
- **Kustomize 入口**仅渲染由操作员提供的相对仓库路径。适用于拥有多个独立环境或无法进行推断的约定的仓库。
- **普通 Kubernetes 清单**跳过渲染步骤,直接从 YAML 清单中的 `containers`、`initContainers` 和 `ephemeralContainers` 中提取镜像。这支持不使用 Kustomize 的仓库。
当所选的 Kustomization 使用了 `helmCharts` 时,需要用到 Helm;提供的容器镜像中已包含它。在进行本地后端开发时,请安装 Helm,或者对不需要 Helm 渲染的仓库选择普通清单发现模式。
对于结合了多种部署机制的仓库,可以添加一个仓库专属的 `.justscan.yaml` 发现配置。它可以在一次试运行中组合 Kustomize 根目录、直接的 Helm chart 和选定的普通清单路径。部署后,请在您的 JustScan 主机上查看 `/docs/scan-and-analyze/gitops`;在部署前,请参阅[托管版 GitOps 文档](https://justscan.justlab.app/docs/scan-and-analyze/gitops)。
状态页面可以关注整个 Git 仓库,也可以关注一组精心挑选的已发现镜像名称。精选源始终使用仓库最近完成的发现结果,因此当所选镜像在 Git 中接收到新标签时,页面会随之更新。
## 架构
| Service | Tech | 默认端口 |
| -------- | -------------- | ------------ |
| Backend | Go (Gin) | `8080` |
| Frontend | Next.js | `3000` |
| Database | PostgreSQL 15+ | `5432` |
## CLI
`justscan` CLI 会将 registry 和归档扫描任务提交到正在运行的 JustScan 实例。Registry
pipeline 扫描会返回对 CI 友好的策略判定退出代码;本地 Docker/Podman/Apple Container 和归档输入将被流式传输到该实例进行远程分析。它不包含本地扫描器。发布归档文件会附加到每个 JustScan GitHub Release 中;你可以使用以下命令在本地构建它:
```
cd services/cli
go build ./cmd/justscan
```
配置一个非机密的 profile,并通过环境变量提供 pipeline 作用域内的组织 token:
```
justscan config set production \
--server https://justscan.example.com \
--org 00000000-0000-0000-0000-000000000000
export JUSTSCAN_TOKEN=""
justscan scan registry.example.com/my-app:1.2.3
```
对于交互式用户会话,请运行 `justscan login --profile production --email you@example.com`。
CLI 会提示输入密码,并将凭证存储在系统 keychain 中;仅在用于 CI/CD 或其他无人值守的自动化时才使用 `JUSTSCAN_TOKEN`。
部署后,请在同一个 JustScan 主机上打开 `/docs` 以查看 CLI 指南、CI/CD 提供商示例、GitOps 发现、操作员配置和故障排除。如果您尚未部署 JustScan,请浏览[托管版文档](https://justscan.justlab.app/docs)。
## 快速开始
### 前置条件
- Go 1.22+
- Node.js 20+ / pnpm
- PostgreSQL 15+
- 已安装 [Trivy](https://trivy.dev/latest/getting-started/installation/) 并将其添加到 `$PATH` 中以进行本地 Trivy 扫描
### 1. 数据库
创建数据库和用户:
```
CREATE DATABASE justscan;
CREATE USER justscan WITH PASSWORD 'yourpassword';
GRANT ALL PRIVILEGES ON DATABASE justscan TO justscan;
```
### 2. 后端配置
复制并编辑配置文件:
```
cp services/backend/config/config.yaml services/backend/config/config.local.yaml
```
根据您的实际数值修改 `config.yaml`(参见下方的[配置参考](#configuration-reference))。
### 3. 启动后端
```
cd services/backend
go run main.go
```
### 4. 启动前端
```
cd services/frontend
pnpm install
pnpm dev
```
打开 [http://localhost:3000](http://localhost:3000) 并注册第一个用户。
如果您打算使用 OIDC,请在首次登录前使用以下章节进行配置。当 `local_auth.enabled` 设置为 `false` 时,基于密码的 `/login` 和 `/register` endpoint 将被禁用,用户必须通过您的 OIDC 提供商登录。
## 配置参考
`services/backend/config/config.yaml`
### 必填字段
| Key | 描述 | 示例 |
| ------------------- | ------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------- |
| `jwt.secret` | **必填。** 用于签名和验证 JWT token 的密钥。必须是较长的随机字符串。如果为 `null` 或为空,身份验证将失败。 | `"a-very-long-random-secret-key-32chars"` |
| `database.server` | PostgreSQL 主机 | `localhost` |
| `database.port` | PostgreSQL 端口 | `5432` |
| `database.name` | 数据库名称 | `justscan` |
| `database.user` | 数据库用户 | `postgres` |
| `database.password` | 数据库密码 | `postgres` |
### 可选字段
| Key | 描述 | 默认值 |
| -------------------------------------- | ------------------------------------------------------------------------------------------------ | -------------------------------- |
| `port` | HTTP 监听端口 | `8080` |
| `log_level` | 日志详细程度:`debug`, `info`, `warn`, `error` | `info` |
| `allow_origins` | CORS 允许的源(列表) | `["http://localhost:3000"]` |
| `scanner.enable_trivy` | 启用本地 Trivy 扫描。对于仅使用 Artifactory Xray 的部署,请设置为 `false` | `true` |
| `scanner.trivy_path` | Trivy 二进制文件路径 | `trivy` |
| `scanner.enable_grype` | 为本地 Trivy 扫描启用 Grype 增强 | `false` |
| `scanner.grype_path` | Grype 二进制文件路径 | `grype` |
| `scanner.timeout` | 本地扫描器命令超时的旧版备用设置(以秒为单位) | `600` |
| `scanner.command_timeout_seconds` | Trivy、Grype 和 SBOM 执行的本地扫描器命令超时时间(以秒为单位) | `7200` |
| `scanner.progress_heartbeat_seconds` | 长时间运行的扫描在工作仍处于活动状态时刷新其活跃时间戳的频率 | `30` |
| `scanner.stale_timeout_seconds` | 仅在未记录到进度的情况下经过这么多秒后才使扫描失败 | `7200` |
| `scanner.concurrency` | 并发扫描数 | `2` |
| `scanner.db_max_age_hours` | JustScan 自动刷新每个 Trivy DB 之前的最大间隔时间 | `24` |
| `scanner.enable_osv_java_augmentation` | 查询免费的 OSV API 以获取额外的 Maven/Java 安全通告,并将其合并到扫描结果中 | `true` |
| `encryption.key` | 用于在静止状态下加密 registry 凭证的密钥。应为 32 个字符的字符串。 | `""` |
| `vuln_kb.nvd_api_key` | 用于丰富 CVE 数据的 NVD API key(可选,参见[获取 NVD API key](#getting-an-nvd-api-key)) | `""` |
| `vuln_kb.cache_days` | 缓存 NVD 数据的时长 | `7` |
| `oidc.enabled` | 启用 OIDC 单点登录 | `false` |
| `oidc.issuer_url` | 来自您提供商的 OIDC issuer URL | `""` |
| `oidc.client_id` | OIDC client ID | `""` |
| `oidc.client_secret` | OIDC client secret。在生产环境中建议使用环境变量。 | `""` |
| `oidc.redirect_uri` | 在您的 OIDC 提供商中注册的公共后端回调 URL | `""` |
| `oidc.scopes` | 请求的 OIDC scopes | `["openid", "email", "profile"]` |
| `oidc.admin_groups` | 应映射到 JustScan `admin` 角色的群组名称 | `[]` |
| `oidc.admin_roles` | 应映射到 JustScan `admin` 角色的角色名称 | `[]` |
| `oidc.groups_claim` | 包含群组成员身份的 claim 名称 | `"groups"` |
| `oidc.roles_claim` | 包含角色成员身份的 claim 名称 | `"roles"` |
| `local_auth.enabled` | 在启用 OIDC 的同时保持本地的用户名/密码身份验证处于启用状态 | `true` |
### Artifactory Xray registry 模式
Artifactory Xray registry 在 JustScan UI 中进行配置,并在 Artifactory 镜像拉取和 Xray API 请求中重用其 registry 凭证。现有的 Xray registry 在升级后默认为 **Limited** 模式。
- **Limited** 适用于普通消费者凭证。JustScan 通过 Artifactory 预热镜像,等待 Xray 公开产物结果,然后将其导入。它从不触发重新扫描,因此已完成的结果是有效的,但其新鲜度无法验证。请确保该仓库已在 Xray 中建立索引;远程产物也必须被允许进入 Artifactory 缓存。
- **Full** 适用于具有 Xray Read 以及 **Manage Xray Metadata** 权限的服务账号。预热镜像后,JustScan 会请求 `scanArtifact` 并等待 Xray 确认新的完整运行,然后再导入发现结果。被拒绝的请求将导致扫描失败并提示可操作的错误;JustScan 绝不会静默降级此模式。
Full 模式特意不使用 Artifactory 的旧版强制索引 endpoint。对于这两种模式,Xray 依然负责漏洞分析和策略评估。
### `config.yaml` 示例
```
log_level: info
port: 8080
database:
server: localhost
port: 5432
name: justscan
user: postgres
password: postgres
jwt:
secret: "replace-this-with-a-long-random-secret-minimum-32-characters"
allow_origins:
- "http://localhost:3000"
scanner:
trivy_path: trivy
timeout: 600
command_timeout_seconds: 7200
progress_heartbeat_seconds: 30
stale_timeout_seconds: 7200
concurrency: 2
db_max_age_hours: 24
enable_osv_java_augmentation: true
encryption:
key: "replace-with-32-char-encryption-key"
vuln_kb:
nvd_api_key: ""
cache_days: 7
oidc:
enabled: false
issuer_url: ""
client_id: ""
client_secret: ""
redirect_uri: ""
scopes: ["openid", "email", "profile"]
admin_groups: []
admin_roles: []
groups_claim: "groups"
roles_claim: "roles"
local_auth:
enabled: true
```
### 针对生产环境的安全默认设置
- 默认情况下,后端启动现在会强制要求使用强机密:
- `jwt.secret` 必须至少为 32 个字符
- `encryption.key` 必须至少为 32 个字符
- 仅对于本地开发,您可以通过以下方式绕过此限制:
```
security:
allow_insecure_defaults: true
```
或使用环境变量:
`BACKEND_SECURITY_ALLOW_INSECURE_DEFAULTS=true`
Pipeline 回调被限制为公共 HTTPS 目的地,且不跟随重定向。对于私有网络上的自托管回调接收器,请在后端配置中显式将确切的主机或 CIDR 加入允许列表:
```
security:
callback_allowed_hosts:
- ci.internal.example
callback_allowed_cidrs:
- 10.20.0.0/16
```
## OIDC 配置
JustScan 支持 OpenID Connect 提商,例如 Keycloak, Authentik, Okta, Azure AD 和 Google Workspace。
### 配置内容
在 `services/backend/config/config.yaml` 中或通过 `BACKEND_...` 环境变量设置这些值:
```
oidc:
enabled: true
issuer_url: "https://auth.example.com/application/o/justscan/"
client_id: "justscan"
client_secret: "replace-me"
redirect_uri: "https://scan.example.com/api/v1/auth/oidc/callback"
scopes: ["openid", "email", "profile"]
admin_groups:
- "justscan-admins"
admin_roles: []
groups_claim: "groups"
roles_claim: "roles"
local_auth:
enabled: true
```
### 必需的 URL
- `oidc.redirect_uri` 必须是公共的后端回调 URL,并且必须与在您的 OIDC 提供商中注册的重定向 URI 完全匹配。
- 前端 URL 必须列在 `allow_origins` 中。
- 将您的主要前端 URL 放在 `allow_origins` 的第一位。OIDC 登录成功后,JustScan 会将浏览器重定向到第一个 `allow_origins` 条目加上 `/auth/oidc/callback`。
- 通知消息在构建指向扫描详情页(例如 `/scans/`)的直接链接时,也会使用第一个 `allow_origins` 条目。
示例:
```
allow_origins:
- "https://scan.example.com"
oidc:
redirect_uri: "https://scan.example.com/api/v1/auth/oidc/callback"
```
### 角色映射
- 当 `oidc.admin_groups` 中的任何条目与配置的 `groups_claim` 匹配时,用户将被授予 JustScan `admin` 角色。
- 当 `oidc.admin_roles` 中的任何条目与配置的 `roles_claim` 匹配时,用户也将被授予 JustScan `admin` 角色。
- 每次进行 OIDC 登录时都会评估角色映射。从配置的群组或角色中移除用户,将在该用户下次登录时撤销其 JustScan 管理员权限。
### 用户配置行为
- 如果用户首次通过 OIDC 登录,且不存在与 OIDC `sub` claim 匹配的账号,JustScan 将检查是否存在具有相同电子邮件地址的现有本地账号。
- 如果电子邮件与现有的本地账号匹配,JustScan 会自动将该账号链接到 OIDC 身份。
- 如果不存在匹配的电子邮件,JustScan 将自动创建新的本地用户记录。
- 通过 OIDC 创建的用户不使用本地密码。
### 同时使用本地身份验证和 OIDC
- `local_auth.enabled: true`:本地登录和 OIDC 登录均可使用。
- `local_auth.enabled: false`:用户必须通过 OIDC 登录;密码登录和自行注册功能将被禁用。
### 提供商示例
- Keycloak:使用 realm issuer URL,例如 `https://keycloak.example.com/realms/justscan`
- Authentik:使用在 Authentik 应用程序/提供商设置中显示的提供商 issuer URL
- Azure AD / Entra ID:使用您租户和应用程序注册的 OpenID issuer
### 环境变量覆盖
所有配置值都可以使用 `BACKEND_` 前缀并通过将 `.` 替换为 `_` 的环境变量进行覆盖:
| Config key | 环境变量 |
| ---------------------------------- | ------------------------------------------ |
| `jwt.secret` | `BACKEND_JWT_SECRET` |
| `database.server` | `BACKEND_DATABASE_SERVER` |
| `database.port` | `BACKEND_DATABASE_PORT` |
| `database.name` | `BACKEND_DATABASE_NAME` |
| `database.user` | `BACKEND_DATABASE_USER` |
| `database.password` | `BACKEND_DATABASE_PASSWORD` |
| `encryption.key` | `BACKEND_ENCRYPTION_KEY` |
| `security.allow_insecure_defaults` | `BACKEND_SECURITY_ALLOW_INSECURE_DEFAULTS` |
| `security.callback_allowed_hosts` | `BACKEND_SECURITY_CALLBACK_ALLOWED_HOSTS` |
| `security.callback_allowed_cidrs` | `BACKEND_SECURITY_CALLBACK_ALLOWED_CIDRS` |
| `oidc.enabled` | `BACKEND_OIDC_ENABLED` |
| `oidc.issuer_url` | `BACKEND_OIDC_ISSUER_URL` |
| `oidc.client_id` | `BACKEND_OIDC_CLIENT_ID` |
| `oidc.client_secret` | `BACKEND_OIDC_CLIENT_SECRET` |
| `oidc.redirect_uri` | `BACKEND_OIDC_REDIRECT_URI` |
| `oidc.scopes` | `BACKEND_OIDC_SCOPES` |
| `oidc.admin_groups` | `BACKEND_OIDC_ADMIN_GROUPS` |
| `oidc.admin_roles` | `BACKEND_OIDC_ADMIN_ROLES` |
| `oidc.groups_claim` | `BACKEND_OIDC_GROUPS_CLAIM` |
| `oidc.roles_claim` | `BACKEND_OIDC_ROLES_CLAIM` |
| `local_auth.enabled` | `BACKEND_LOCAL_AUTH_ENABLED` |
## 前端配置
前端使用单一的环境变量:
| Variable | 描述 | 默认值 |
| --------------------- | ---------------- | ----------------------- |
| `NEXT_PUBLIC_API_URL` | 后端基础 URL | `http://localhost:8080` |
创建 `services/frontend/.env.local`:
```
NEXT_PUBLIC_API_URL=http://localhost:8080
```
## 部署
### Docker Compose
```
docker compose up -d
```
compose 文件会同时启动 PostgreSQL、后端和前端。
当使用默认启用 Trivy 的 Docker 镜像运行时,JustScan 会在容器启动时刷新 Trivy 的漏洞数据库和 Java 数据库,并且只要缓存的数据库超过了 `scanner.db_max_age_hours`,就会在扫描之前再次刷新。缓存存储在 `/app/data/trivy-cache` 下,因此当持久化 `/app/data` 时,它可以在容器重启后继续存在。
对于仅使用 Artifactory Xray 的部署,请通过设置 `JUSTSCAN_BACKEND_IMAGE_PREFIX=backend-minimal`,并在 `deploy/docker-compose/backend-config.yaml` 中设置 `scanner.enable_trivy: false` 及 `scanner.enable_grype: false` 来使用无扫描器的后端镜像。如果任何 registry 需要运行本地 Trivy 扫描,请保留默认的 `backend` 镜像。
JustScan 还可以使用免费的 OSV API 为 Maven 软件包补充 Java 发现结果。为了避免不必要的出站调用并维持在公共服务限制范围内,软件包/版本的查询结果会在本地数据库中进行缓存,并使用由 `vuln_kb.cache_days` 配置的相同缓存时间窗口进行刷新。
### Helm
Kubernetes chart 位于 `deploy/helm/justscan`,用于本地开发,并且每次 Git 标签发布时都会在 GHCR 上以 OCI Helm chart 的形式发布。
#### 前置条件
- Kubernetes 1.24+
- Helm 3.8+
- 如果仓库或包是私有的,则需要具有对 `ghcr.io/justlabv1/charts/justscan` 和 `ghcr.io/justlabv1/justscan` 的访问权限
如果对 GHCR 的访问是私有的,请先登录:
```
helm registry login ghcr.io -u YOUR_GITHUB_USER
```
#### 从已发布的 chart 安装
创建一个 values 文件,例如 `justscan-values.yaml`:
```
ingress:
enabled: true
className: nginx
hosts:
- host: scan.example.com
paths:
- path: /
pathType: Prefix
tls:
- secretName: justscan-tls
hosts:
- scan.example.com
backend:
image:
# Leave empty to use backend-.
# Use backend-minimal-1.2.3 for Artifactory Xray-only deployments.
tag: ""
secrets:
jwtSecret: "replace-with-a-long-random-secret"
encryptionKey: "replace-with-32-random-characters"
config:
allowOrigins:
- "https://scan.example.com"
oidc:
enabled: false
persistence:
enabled: true
size: 10Gi
postgresql:
enabled: true
auth:
password: "replace-with-a-db-password"
```
安装一个已发布的 chart 版本:
```
helm install justscan oci://ghcr.io/justlabv1/charts/justscan \
--version 1.2.3 \
--namespace justscan \
--create-namespace \
-f justscan-values.yaml
```
升级现有的 release:
```
helm upgrade justscan oci://ghcr.io/justlabv1/charts/justscan \
--version 1.2.3 \
--namespace justscan \
-f justscan-values.yaml
```
#### 发布仅包含 chart 的 release
如果您需要发布新的 Helm chart 版本,而无需构建或发布新的应用程序版本,请从 GitHub Actions 手动运行 `Release` workflow。
- 将 `chart_version` 设置为您想要发布的新的 Helm chart 版本。
- 将 `app_version` 设置为 chart 应继续使用其镜像标签的现有应用程序 release。
示例:发布 chart 版本 `1.2.4`,同时继续部署来自 `1.2.3` 的应用程序镜像标签。
该 workflow 将打包并推送 `oci://ghcr.io/justlabv1/charts/justscan:1.2.4`,其 `appVersion=1.2.3`,因此除非您显式覆盖镜像标签,否则 chart 仍将默认使用 `backend-1.2.3` 和 `frontend-1.2.3`。
#### 从本仓库内的 chart 安装
```
helm dependency build deploy/helm/justscan
helm install justscan deploy/helm/justscan \
--namespace justscan \
--create-namespace \
-f justscan-values.yaml
```
#### Helm chart 行为与必需的值
- 已发布的 chart 包会自动将 `backend.image.tag` 默认为 `backend-`,并将 `frontend.image.tag` 默认为 `frontend-`。仅在需要固定到其他镜像时才覆盖这些标签。
- 对于仅使用 Artifactory Xray 的部署,请将 `backend.image.tag` 设置为 `backend-minimal-`,并设置 `backend.config.scanner.enableTrivy=false` 以及 `backend.config.scanner.enableGrype=false`。
- 对于所有非简单的部署,`backend.secrets.jwtSecret` 是必需的。
- `backend.secrets.encryptionKey` 应该是一个随机的 32 个字符的字符串。它用于在静止状态下加密 registry 凭证。
- 当 `postgresql.enabled=true` 时,`postgresql.auth.password` 是必需的。
- 当 `postgresql.enabled=true` 时,后端会自动使用 `postgresql.auth.database`、`postgresql.auth.username` 和 Bitnami PostgreSQL 密码 secret。您只需要为外部数据库提供 `backend.config.database.*`。
- 当 `postgresql.enabled=false` 并且您连接到外部 PostgreSQL 实例时,`backend.secrets.dbPassword` 是必需的。
- 使用 `backend.secrets.existingSecretRefs..key` 来映射后端 secret 密钥。当大多数字段位于同一个 Kubernetes Secret 中时,请设置 `backend.secrets.existingSecret`;任何 `name` 为空的引用都将使用该 Secret。仅对于位于不同 Secret 中的字段才设置 `backend.secrets.existingSecretRefs..name`。
- `backend.config.allowOrigins` 必须包含用户在浏览器中打开的 URL。
- 如果 `backend.config.oidc.enabled=true`,则还必须设置 `backend.secrets.oidcClientSecret`、`backend.config.oidc.issuerUrl`、`backend.config.oidc.clientId`,以及 `backend.config.oidc.redirectUri` 或带有有效主机的 `ingress.enabled=true`。
- 如果您的 OIDC 提供商或其他出站 HTTPS 依赖项使用私有或自签名 CA,请设置 `backend.customCAs.configMapName` 和/或 `backend.customCAs.secretName` 以将 PEM CA 文件挂载到后端容器中。
- 对于生产环境,建议设置 `backend.persistence.enabled=true`,以便 Trivy 数据库和缓存数据在 pod 重启后依然存在。
使用不同的 Secret 存储外部数据库密码和加密密钥的示例:
```
postgresql:
enabled: false
backend:
config:
database:
server: postgres.example.com
name: justscan
user: justscan
secrets:
existingSecret: justscan-auth
existingSecretRefs:
jwtSecret:
key: jwt-secret
dbPassword:
name: justscan-db-credentials
key: password
encryptionKey:
name: justscan-crypto
key: encryption-key
```
#### 支持的 chart 配置
chart 暴露的重要值包括:
- 用于从 GHCR 拉取私有镜像或 chart 的 `imagePullSecrets`
- 用于 release 命名和 service account 控制的 `nameOverride`、`fullnameOverride` 和 `serviceAccount.name`
- `backend.config.scanner.enableTrivy`、`backend.config.scanner.trivyPath`、`backend.config.scanner.grypePath`、`backend.config.scanner.enableGrype`、`backend.config.scanner.timeout`、`backend.config.scanner.commandTimeoutSeconds`、`backend.config.scanner.progressHeartbeatSeconds`、`backend.config.scanner.staleTimeoutSeconds`、`backend.config.scanner.concurrency`、`backend.config.scanner.dbMaxAgeHours` 和 `backend.config.scanner.enableOsvJavaAugmentation`
- `backend.config.oidc.debug`、`backend.config.oidc.adminGroups`、`backend.config.oidc.adminRoles`、`backend.config.oidc.groupsClaim` 和 `backend.config.oidc.rolesClaim`
- 用于 OIDC 和其他出站 TLS 调用的自定义信任锚点的 `backend.customCAs.configMapName`、`backend.customCAs.secretName` 和 `backend.customCAs.bundlePath`
- `backend.persistence.existingClaim`、`backend.persistence.size` 和 `backend.persistence.storageClass`
- 如果前端必须调用与集群内 service 不同的后端 URL,则使用 `frontend.config.apiUrl`
#### 自定义 CA 示例
如果您的 OIDC 提供商使用自签名或私有 CA,请创建一个包含 PEM 证书的 ConfigMap 或 Secret,并从 chart 中引用它。
使用 ConfigMap 的示例:
```
kubectl create configmap justscan-oidc-ca \
--from-file=oidc-ca.crt=./oidc-ca.crt \
--namespace justscan
```
```
backend:
customCAs:
configMapName: justscan-oidc-ca
```
使用 Secret 的示例:
```
kubectl create secret generic justscan-oidc-ca \
--from-file=oidc-ca.crt=./oidc-ca.crt \
--namespace justscan
```
```
backend:
customCAs:
secretName: justscan-oidc-ca
```
后端的 entrypoint 会根据系统信任库以及挂载的文件构建一个组合的 CA bundle,并在 JustScan 启动之前通过 `SSL_CERT_FILE` 和 `GIT_SSL_CAINFO` 将其导出。更新引用的 ConfigMap 或 Secret 后,请重启后端 pod。
显示完整的 values schema:
```
helm show values oci://ghcr.io/justlabv1/charts/justscan --version 1.2.3
```
## GitLab CI:推送前扫描(上传归档)
您可以通过以下方式在 GitLab CI 中将镜像推送到任何 registry 之前对其进行扫描:
1. 在 CI 中构建镜像
2. 将其导出为归档文件(`docker save`)
3. 通过 `POST /api/v1/orgs//archive-scans` 将其上传到 JustScan
4. 轮询扫描状态直到完成
### 必需的 CI 变量
在您的 GitLab 项目/群组 CI/CD 变量中设置这些内容:
- `JUSTSCAN_API_URL`(示例:`https://scan.example.com`)
- `JUSTSCAN_API_TOKEN`(JustScan 个人或组织 token)
- `JUSTSCAN_ORG_ID`(接收扫描的组织 UUID)
### `.gitlab-ci.yml` 作业示例
### 注意事项
- 组织上传 endpoint 需要经过身份验证,并在接受归档正文之前对组织进行授权(`/api/v1/orgs//archive-scans`)。
- 默认情况下,上传归档扫描的归档大小限制为 `5 GB`。
- 扫描处理完成后,JustScan 会删除上传的归档文件。
- 对于 CI/CD 上传,请使用作用于目标组织的 pipeline token。
## 常见问题
### 所有受保护的 endpoint 都返回 401 Unauthorized
**原因:** `config.yaml` 中的 `jwt.secret` 为 `null` 或为空。
**修复:** 将 `jwt.secret` 设置为非空的随机字符串(建议至少 32 个字符),然后重启后端。之前颁发的所有 token 都将失效,用户需要重新登录。
### 无法连接到数据库
**检查:**
- PostgreSQL 是否正在配置的主机/端口上运行
- 数据库和用户是否存在且具有正确的权限
- `database.password` 是否正确
### 扫描卡在 `pending` 状态
**检查:**
- 是否已安装 `trivy` 并且可以通过配置的 `scanner.trivy_path` 路径进行访问
- 运行 `trivy --version` 进行验证
- 如果您使用的是 `backend-minimal` 镜像,请使用为 Artifactory Xray 配置的 registry,并保持禁用本地 Trivy 扫描
### Registry 凭证无法保存
**检查:**
- 是否在配置中设置了 `encryption.key`。凭证会使用此密钥进行静态加密。
- 如果密钥为空,加密将静默失败。
### 前端显示 CORS 错误
**检查:**
- 您的前端源是否列在了 `config.yaml` 的 `allow_origins` 中
- 示例:如果前端运行在端口 `3000`,请将 `"http://localhost:3000"` 添加到列表中
## 获取 NVD API Key
NVD(国家漏洞数据库)API key 用于通过来自 [nvd.nist.gov](https://nvd.nist.gov) 的额外元数据来丰富 CVE 条目。它是**可选的**。如果没有它,JustScan 和 Trivy 仍将扫描并报告漏洞,但 CVE 详细信息可能不够完整。
该 key 是免费的,由 NIST(美国国家标准与技术研究院)提供。
### 步骤
1. 前往 [https://nvd.nist.gov/developers/request-an-api-key](https://nvd.nist.gov/developers/request-an-api-key)
2. 输入您的电子邮件地址并提交表单
3. NIST 会在几分钟内通过电子邮件将 API key 发送给您
4. 在您的配置中进行设置:
```
vuln_kb:
nvd_api_key: "your-key-here"
cache_days: 7
```
或通过环境变量:
```
export BACKEND_VULN_KB_NVD_API_KEY="your-key-here"
```
### 速率限制
- 无 key:**5 个请求 / 30 秒**
- 有 key:**50 个请求 / 30 秒**
对于大多数自托管部署而言,未经过身份验证的限制已足够。如果您扫描大量镜像或频繁刷新 CVE 缓存,请使用 key 以避免触发速率限制。
## 开发
### 仓库结构
- `services/backend`:Go 后端
- `services/frontend`:Next.js 前端
- `deploy/docker-compose`:Docker Compose 设置
- `deploy/helm/justscan`:Helm chart
### 常用命令
```
# 后端
cd services/backend
go run main.go
go test ./...
# 前端
cd services/frontend
pnpm install
pnpm dev
pnpm lint
pnpm build
```
## 贡献
欢迎贡献。对于重大变更,请先提出 issue,以便在您开始之前就能对齐实现细节。
## License
该项目基于 MIT License 授权。详情请参阅 [LICENSE](./LICENSE)。
标签:DevSecOps, Web截图, 上游代理, 后端开发, 容器安全, 日志审计, 测试用例, 版权保护, 自托管