Created
November 19, 2025 16:24
-
-
Save yannhowe/dc976c3531b5c1304482159ef20a3ef0 to your computer and use it in GitHub Desktop.
CrowdStrike 容器镜像和软件包扫描器 (中文版)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/bin/bash | |
| # CrowdStrike 容器镜像和软件包扫描器 (JSON 输出) | |
| # | |
| # 此脚本从 CrowdStrike Falcon Cloud Security APIs 获取容器镜像详情和软件包 (SBOM) | |
| # 并以结构化 JSON 格式输出。 | |
| # | |
| # 作者: CrowdStrike | |
| # 版本: 1.0 | |
| # 许可证: MIT | |
| set -e | |
| # 配置 | |
| FALCON_CLOUD=${FALCON_CLOUD:-"us-1"} | |
| BASE_URL="https://api.crowdstrike.com" | |
| # 显示详细帮助的函数 | |
| show_help() { | |
| cat << 'EOF' | |
| ================================================================================ | |
| CrowdStrike 容器镜像和软件包扫描器 (JSON 输出) | |
| ================================================================================ | |
| 描述: | |
| 从 CrowdStrike Falcon Cloud Security APIs 获取容器镜像详情和软件包 (SBOM) | |
| 并以结构化 JSON 格式输出。 | |
| 前提条件: | |
| 1. 具有 'falcon-container-image:read' 权限的 CrowdStrike API 凭据 | |
| 2. jq 命令行 JSON 处理器 | |
| 3. curl 用于 API 请求 | |
| 设置: | |
| export FALCON_CLIENT_ID="your-client-id" | |
| export FALCON_CLIENT_SECRET="your-client-secret" | |
| export FALCON_CLOUD="us-1" # 可选: us-1, us-2, eu-1, us-gov-1 | |
| 用法: | |
| ./get-image-packages-json-zh.sh [选项] | |
| 选项: | |
| --repository REPO 按仓库名称过滤 | |
| --registry REG 按注册表过滤 | |
| --tag TAG 按标签过滤 | |
| --digest DIGEST 按镜像摘要过滤 | |
| --limit NUM 限制镜像数量 (默认: 3, 最大: 100) | |
| --package-limit NUM 限制每个镜像的软件包数量 (默认: 1000) | |
| --format FORMAT 输出格式 (默认: combined) | |
| -h, --help 显示此帮助 | |
| 输出格式: | |
| combined - 镜像及其软件包 (默认) | |
| images-only - 仅镜像元数据 | |
| packages-only - 仅第一个找到的镜像的软件包 | |
| 示例: | |
| # 获取 2 个镜像及其软件包 (组合格式) | |
| ./get-image-packages-json-zh.sh --limit 2 | |
| # 获取 nginx 镜像及其软件包 | |
| ./get-image-packages-json-zh.sh --repository nginx --limit 1 | |
| # 仅获取 Docker Hub 的镜像元数据 | |
| ./get-image-packages-json-zh.sh --registry docker.io --format images-only | |
| # 获取特定镜像的软件包 | |
| ./get-image-packages-json-zh.sh --digest sha256:abc123... --format packages-only | |
| # 按多个条件过滤 | |
| ./get-image-packages-json-zh.sh --registry docker.io --tag latest --limit 5 | |
| 输出结构 (组合格式): | |
| { | |
| "images": [ | |
| { | |
| "registry": "docker.io", | |
| "repository": "nginx", | |
| "tag": "latest", | |
| "digest": "sha256:...", | |
| "base_os": "Debian GNU", | |
| "config": {"architecture": "amd64"}, | |
| "packages": [ | |
| { | |
| "package_name_version": "nginx-1.21.6-1", | |
| "type": "apt", | |
| "license": "BSD-2-Clause", | |
| "vulnerability_count": 0, | |
| "vulnerabilities": [] | |
| } | |
| ] | |
| } | |
| ], | |
| "total_images": 1, | |
| "generated_at": "2025-11-19T15:54:48Z" | |
| } | |
| 过滤: | |
| 可用的过滤字段: | |
| - registry: 容器注册表 (docker.io, gcr.io 等) | |
| - repository: 仓库名称 (nginx, alpine 等) | |
| - tag: 镜像标签 (latest, stable, v1.0 等) | |
| - digest: SHA256 摘要 | |
| - 多个过滤器使用 AND 逻辑组合 | |
| 使用的 API 端点: | |
| - POST /oauth2/token (身份验证) | |
| - GET /container-security/combined/images/detail/v1 (镜像详情) | |
| - GET /container-security/combined/packages/v1 (软件包清单) | |
| 故障排除: | |
| 1. "获取访问令牌失败": | |
| - 验证 FALCON_CLIENT_ID 和 FALCON_CLIENT_SECRET | |
| - 检查 API 客户端是否具有 'falcon-container-image:read' 权限 | |
| 2. "jq: 命令未找到": | |
| - 安装 jq: apt-get install jq (Ubuntu) 或 brew install jq (macOS) | |
| 3. 空结果: | |
| - 检查过滤器是否过于严格 | |
| - 验证您的环境中是否存在容器镜像 | |
| 4. 速率限制: | |
| - 减少 --limit 和 --package-limit 值 | |
| - 如果多次运行,在请求之间添加延迟 | |
| 支持: | |
| CrowdStrike 开发者门户: https://falcon.crowdstrike.com/documentation | |
| 容器安全 APIs: https://falcon.crowdstrike.com/documentation/page/container-security-apis | |
| ================================================================================ | |
| EOF | |
| } | |
| # 显示用法摘要的函数 | |
| show_usage() { | |
| cat << 'EOF' | |
| CrowdStrike 容器镜像和软件包扫描器 (JSON 输出) | |
| 用法: ./get-image-packages-json-zh.sh [选项] | |
| 常用示例: | |
| ./get-image-packages-json-zh.sh --limit 2 | |
| ./get-image-packages-json-zh.sh --repository nginx --limit 1 | |
| ./get-image-packages-json-zh.sh --registry docker.io --format images-only | |
| 需要设置: | |
| export FALCON_CLIENT_ID="your-client-id" | |
| export FALCON_CLIENT_SECRET="your-client-secret" | |
| 使用 --help 查看详细文档。 | |
| EOF | |
| } | |
| # 检查是否未提供参数 | |
| if [[ $# -eq 0 ]]; then | |
| show_usage | |
| exit 0 | |
| fi | |
| # 检查必需的环境变量 | |
| if [[ -z "$FALCON_CLIENT_ID" || -z "$FALCON_CLIENT_SECRET" ]]; then | |
| echo "❌ 错误: 缺少 CrowdStrike API 凭据" >&2 | |
| echo "" >&2 | |
| echo "必需的环境变量:" >&2 | |
| echo " export FALCON_CLIENT_ID=\"your-client-id\"" >&2 | |
| echo " export FALCON_CLIENT_SECRET=\"your-client-secret\"" >&2 | |
| echo "" >&2 | |
| echo "可选:" >&2 | |
| echo " export FALCON_CLOUD=\"us-1\" # us-1, us-2, eu-1, us-gov-1" >&2 | |
| echo "" >&2 | |
| echo "从此处获取 API 凭据: https://falcon.crowdstrike.com/api-clients-and-keys" >&2 | |
| echo "必需权限: falcon-container-image:read" >&2 | |
| echo "" >&2 | |
| echo "使用 --help 查看完整文档。" >&2 | |
| exit 1 | |
| fi | |
| # 检查 jq 依赖 | |
| if ! command -v jq &> /dev/null; then | |
| echo "❌ 错误: 需要 jq 但未安装" >&2 | |
| echo "" >&2 | |
| echo "安装 jq:" >&2 | |
| echo " Ubuntu/Debian: sudo apt-get install jq" >&2 | |
| echo " macOS: brew install jq" >&2 | |
| echo " RHEL/CentOS: sudo yum install jq" >&2 | |
| exit 1 | |
| fi | |
| # 获取 OAuth2 令牌的函数 | |
| get_token() { | |
| local response | |
| response=$(curl -s -X POST "$BASE_URL/oauth2/token" \ | |
| -H "Content-Type: application/x-www-form-urlencoded" \ | |
| -d "client_id=$FALCON_CLIENT_ID&client_secret=$FALCON_CLIENT_SECRET") | |
| local token | |
| token=$(echo "$response" | jq -r '.access_token') | |
| if [[ "$token" == "null" ]]; then | |
| echo "获取访问令牌失败:" >&2 | |
| echo "$response" | jq '.' >&2 | |
| exit 1 | |
| fi | |
| echo "$token" | |
| } | |
| # 获取镜像详情的函数 | |
| get_image_details() { | |
| local filter="$1" | |
| local limit="${2:-3}" | |
| local params="limit=$limit&with_config=true" | |
| if [[ -n "$filter" ]]; then | |
| params="$params&filter=$filter" | |
| fi | |
| curl -s -X GET "$BASE_URL/container-security/combined/images/detail/v1?$params" \ | |
| -H "Authorization: Bearer $ACCESS_TOKEN" \ | |
| -H "Content-Type: application/json" | |
| } | |
| # 获取特定镜像软件包的函数 | |
| get_image_packages() { | |
| local image_digest="$1" | |
| local limit="${2:-1000}" | |
| local filter="image_digest:'$image_digest'" | |
| local params="limit=$limit&filter=$filter" | |
| curl -s -X GET "$BASE_URL/container-security/combined/packages/v1?$params" \ | |
| -H "Authorization: Bearer $ACCESS_TOKEN" \ | |
| -H "Content-Type: application/json" | |
| } | |
| # 解析命令行参数 | |
| REPOSITORY="" | |
| REGISTRY="" | |
| TAG="" | |
| IMAGE_DIGEST="" | |
| LIMIT=3 | |
| PACKAGE_LIMIT=1000 | |
| OUTPUT_FORMAT="combined" # combined, images-only, packages-only | |
| while [[ $# -gt 0 ]]; do | |
| case $1 in | |
| --repository) | |
| REPOSITORY="$2" | |
| shift 2 | |
| ;; | |
| --registry) | |
| REGISTRY="$2" | |
| shift 2 | |
| ;; | |
| --tag) | |
| TAG="$2" | |
| shift 2 | |
| ;; | |
| --digest) | |
| IMAGE_DIGEST="$2" | |
| shift 2 | |
| ;; | |
| --limit) | |
| LIMIT="$2" | |
| shift 2 | |
| ;; | |
| --package-limit) | |
| PACKAGE_LIMIT="$2" | |
| shift 2 | |
| ;; | |
| --format) | |
| OUTPUT_FORMAT="$2" | |
| shift 2 | |
| ;; | |
| -h|--help) | |
| show_help | |
| exit 0 | |
| ;; | |
| *) | |
| echo "未知选项: $1" >&2 | |
| exit 1 | |
| ;; | |
| esac | |
| done | |
| # 获取访问令牌 (将输出抑制到 stderr) | |
| ACCESS_TOKEN=$(get_token) | |
| # 为镜像构建过滤字符串 | |
| FILTERS=() | |
| if [[ -n "$REPOSITORY" ]]; then | |
| FILTERS+=("repository:'$REPOSITORY'") | |
| fi | |
| if [[ -n "$REGISTRY" ]]; then | |
| FILTERS+=("registry:'$REGISTRY'") | |
| fi | |
| if [[ -n "$TAG" ]]; then | |
| FILTERS+=("tag:'$TAG'") | |
| fi | |
| if [[ -n "$IMAGE_DIGEST" ]]; then | |
| FILTERS+=("image_digest:'$IMAGE_DIGEST'") | |
| fi | |
| FILTER_STRING="" | |
| if [[ ${#FILTERS[@]} -gt 0 ]]; then | |
| FILTER_STRING=$(IFS='+'; echo "${FILTERS[*]}") | |
| fi | |
| # 获取镜像详情 | |
| IMAGE_RESPONSE=$(get_image_details "$FILTER_STRING" "$LIMIT") | |
| # 检查错误 | |
| if echo "$IMAGE_RESPONSE" | jq -e '.errors | length > 0' > /dev/null 2>&1; then | |
| echo "$IMAGE_RESPONSE" | jq '{error: "API 错误", details: .errors}' | |
| exit 1 | |
| fi | |
| # 处理不同的输出格式 | |
| case $OUTPUT_FORMAT in | |
| "images-only") | |
| echo "$IMAGE_RESPONSE" | |
| exit 0 | |
| ;; | |
| "packages-only") | |
| # 获取第一个镜像摘要并仅返回软件包 | |
| FIRST_DIGEST=$(echo "$IMAGE_RESPONSE" | jq -r '.resources[0].digest // empty') | |
| if [[ -n "$FIRST_DIGEST" ]]; then | |
| get_image_packages "$FIRST_DIGEST" "$PACKAGE_LIMIT" | |
| else | |
| echo '{"error": "未找到镜像或摘要不可用", "resources": []}' | |
| fi | |
| exit 0 | |
| ;; | |
| "combined") | |
| # 默认: 将镜像与其软件包组合 | |
| ;; | |
| *) | |
| echo '{"error": "无效格式。使用: combined, images-only, 或 packages-only"}' >&2 | |
| exit 1 | |
| ;; | |
| esac | |
| # 处理镜像并与软件包组合 | |
| COMBINED_RESULT='{"images": []}' | |
| # 处理每个镜像 | |
| IMAGES=$(echo "$IMAGE_RESPONSE" | jq -r '.resources[] | @base64') | |
| if [[ -z "$IMAGES" ]]; then | |
| echo '{"images": [], "message": "未找到符合条件的镜像"}' | |
| exit 0 | |
| fi | |
| for image_data in $IMAGES; do | |
| # 解码镜像数据 | |
| IMAGE_JSON=$(echo "$image_data" | base64 --decode) | |
| # 获取摘要 | |
| DIGEST=$(echo "$IMAGE_JSON" | jq -r '.digest // ""') | |
| if [[ -n "$DIGEST" && "$DIGEST" != "null" ]]; then | |
| # 获取此镜像的软件包 | |
| PACKAGE_RESPONSE=$(get_image_packages "$DIGEST" "$PACKAGE_LIMIT") | |
| # 检查软件包错误 | |
| if echo "$PACKAGE_RESPONSE" | jq -e '.errors | length > 0' > /dev/null 2>&1; then | |
| PACKAGES='{"error": "获取软件包失败", "details": []}' | |
| else | |
| PACKAGES=$(echo "$PACKAGE_RESPONSE" | jq '.resources') | |
| fi | |
| else | |
| PACKAGES='[]' | |
| fi | |
| # 将镜像与软件包组合 | |
| COMBINED_IMAGE=$(echo "$IMAGE_JSON" | jq --argjson packages "$PACKAGES" '. + {packages: $packages}') | |
| # 添加到结果 | |
| COMBINED_RESULT=$(echo "$COMBINED_RESULT" | jq --argjson image "$COMBINED_IMAGE" '.images += [$image]') | |
| done | |
| # 添加元数据 | |
| TOTAL_IMAGES=$(echo "$IMAGE_RESPONSE" | jq '.resources | length') | |
| COMBINED_RESULT=$(echo "$COMBINED_RESULT" | jq --argjson total "$TOTAL_IMAGES" '. + {total_images: $total, generated_at: now | strftime("%Y-%m-%dT%H:%M:%SZ")}') | |
| # 输出最终 JSON | |
| echo "$COMBINED_RESULT" | jq '.' |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment