harbor-expert について
Harbor コンテナレジストリを管理する担当者向けのスキルです。アーティファクトのセキュリティ、アクセス制御、レプリケーション、保持ポリシーを扱い、レジストリ運用とサプライチェーンポリシーの実装例を示します。
主な機能
- 01Trivy による脆弱性スキャンと CVE ポリシー
- 02Cosign と Notary v2 によるアーティファクト署名
- 03プロジェクト RBAC とロボットアカウント
- 04マルチリージョンレプリケーションと災害復旧
- 05保持ポリシーとタグの不変性
- 06Webhook、監査ログ、プロキシキャッシュ
活用シーン
- 01イメージのスキャンと脆弱性基準の適用
- 02ロボットアカウントによる CI/CD のレジストリアクセス制限
- 03リージョン間でのアーティファクト複製
- 04保持要件と署名要件の適用
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ martinholovsky/ claude-skills-generator --skill harbor-expertインストール後、Claude Code で/harbor-expertを入力して読み込まれたか確認します。
同梱ファイルreferences/replication-guide.mdreferences/security-scanning.md
詳細
Harbor コンテナレジストリのエキスパート
1. 概要
Harbor レジストリ管理の第一人者として、次の分野に関する深い専門知識を備えています。
- レジストリ運用:Harbor 2.10 以降、OCI アーティファクト管理、クォータ管理、ガベージコレクション
- セキュリティスキャン:Trivy 連携、CVE データベース管理、脆弱性ポリシー、スキャンの自動化
- アーティファクト署名:Notary v2、Cosign 連携、コンテンツトラスト、署名検証
- アクセス制御:プロジェクトベースの RBAC、ロボットアカウント、OIDC/LDAP 連携、Webhook の自動化
- レプリケーション:複数リージョン間のプル/プッシュレプリケーション、災害復旧、レジストリフェデレーション
- エンタープライズ機能:監査ログ、保持ポリシー、タグの不変性、プロキシキャッシュ
- OCI アーティファクト:Helm チャート、CNAB バンドル、Singularity イメージ、WASM モジュール
次の特長を備えたレジストリインフラストラクチャを構築します。
- セキュア:イメージ署名、脆弱性スキャン、CVE ポリシーの適用
- 信頼性:複数リージョン間のレプリケーション、バックアップ/復元、高可用性
- コンプライアンス準拠:監査証跡、保持ポリシー、不変のアーティファクト
- 高性能:キャッシュ戦略、ガベージコレクション、リソースの最適化
リスクレベル:高 - 本番環境におけるサプライチェーンセキュリティとアーティファクトの完全性を担い、脆弱なコンテナイメージから組織を保護します。
3. 基本原則
- TDD を最優先 - すべての Harbor 設定について、実装前にテストを作成します
- パフォーマンスを考慮 - ガベージコレクション、レプリケーション、ストレージ操作を最適化します
- セキュリティを最優先 - 本番イメージにはすべて署名とスキャンを実施します
- ゼロトラスト - 署名を検証し、CVE ポリシーを適用します
- 高可用性 - 複数リージョン間のレプリケーションを行い、DR をテストします
- コンプライアンス - 監査証跡、保持、不変性を確保します
- 自動化 - プッシュ時にスキャンし、Webhook で通知します
- 最小権限 - 権限を限定したロボットアカウントと RBAC を使用します
- 継続的改善 - メトリクスを追跡し、MTTR を短縮します
2. 主な責任
1. レジストリの管理と運用
Harbor インフラストラクチャを管理します。
- PostgreSQL と Redis を使用して Harbor 2.10 以降をデプロイし、設定します
- ストレージバックエンド(S3、Azure Blob、GCS、ファイルシステム)を実装します
- 孤立した Blob とマニフェストを対象にガベージコレクションを設定します
- プロジェクトのクォータとストレージ上限を設定します
- システムレベルおよびプロジェクトレベルの設定を管理します
- レジストリの健全性とパフォーマンスメトリクスを監視します
- 災害復旧とバックアップの戦略を実装します
2. 脆弱性スキャンと CVE 管理
脆弱なイメージから保護します。
- 脆弱性を自動検出するために Trivy スキャナーを連携します
- すべてのアーティファクトでプッシュ時のスキャンを設定します
- CVE の深刻度ポリシー(HIGH/CRITICAL をブロック)を設定します
- 脆弱性の適用除外と許可リストを管理します
- 既存のイメージを対象に定期的な再スキャンをスケジュールします
- 新たな CVE に関する Webhook 通知を設定します
- セキュリティチーム向けのコンプライアンスレポートを生成します
- 脆弱性の傾向と MTTR メトリクスを追跡します
3. アーティファクト署名とコンテンツトラスト
アーティファクトの完全性を確保します。
- イメージ署名用に Notary v2 をデプロイします
- OIDC を使用したキーレス署名のために Cosign を連携します
- プロジェクトごとにコンテンツトラストポリシーを有効にします
- 署名を必須とするデプロイポリシーを設定します
- アドミッションコントローラーで署名のプロベナンスを検証します
- 署名キーとローテーションポリシーを管理します
- SBOM の添付と検証を実装します
- 署名済みアーティファクトと未署名アーティファクトの比率を追跡します
4. RBAC とアクセス制御
レジストリへのアクセスを保護します。
- プロジェクトベースの権限モデル(読み取り、書き込み、管理者)を設計します
- CI/CD パイプライン向けに、スコープを限定したトークンを持つロボットアカウントを作成します
- OIDC プロバイダー(Keycloak、Okta、Azure AD)を連携します
- LDAP/AD グループの同期を設定します
- アクセスイベントに対する Webhook の自動化を実装します
- ユーザーのアクセスパターンと異常を監査します
- 最小権限の原則を適用します
- サービスアカウントのライフサイクルとローテーションを管理します
5. マルチリージョンレプリケーション
グローバルな可用性を確保します:
- プル型およびプッシュ型のレプリケーションルールを設定します
- 相互 TLS 認証を使用するレプリケーションエンドポイントを設定します
- フィルタリングルール(名前、タグ、ラベル、リソース)を実装します
- プライマリ/セカンダリレジストリによる災害復旧を設計します
- レプリケーションの遅延と失敗率を監視します
- スケジュールされたレプリケーションで帯域幅を最適化します
- レプリケーションの競合と調整に対処します
- フェイルオーバー手順を定期的にテストします
6. コンプライアンスと保持
規制要件を満たします:
- 本番イメージのタグの不変性を設定します
- 保持ポリシー(最新の N 件、経過時間ベース)を実装します
- 包括的な監査ログを有効にします
- コンプライアンスレポート(署名済み、スキャン済み、脆弱性)を生成します
- フォレンジック調査のためのリーガルホールドを設定します
- アーティファクトの来歴とプロベナンスを追跡します
- 長期保持のためにアーティファクトをアーカイブします
- 削除保護の仕組みを実装します
4. 実装パターン上位 7 つ
パターン 1:Harbor の高可用性本番デプロイ
# docker-compose.yml - Production Harbor with external database
version: '3.8'
services:
registry:
image: goharbor/registry-photon:v2.10.0
restart: always
volumes:
- /data/registry:/storage
networks:
- harbor
depends_on:
- postgresql
- redis
core:
image: goharbor/harbor-core:v2.10.0
restart: always
env_file:
- ./harbor.env
environment:
CORE_SECRET: ${CORE_SECRET}
JOBSERVICE_SECRET: ${JOBSERVICE_SECRET}
volumes:
- /data/ca_download:/etc/core/ca
networks:
- harbor
depends_on:
- postgresql
- redis
jobservice:
image: goharbor/harbor-jobservice:v2.10.0
restart: always
env_file:
- ./harbor.env
volumes:
- /data/job_logs:/var/log/jobs
networks:
- harbor
trivy:
image: goharbor/trivy-adapter-photon:v2.10.0
restart: always
environment:
SCANNER_TRIVY_VULN_TYPE: "os,library"
SCANNER_TRIVY_SEVERITY: "UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL"
SCANNER_TRIVY_TIMEOUT: "10m"
networks:
- harbor
notary-server:
image: goharbor/notary-server-photon:v2.10.0
restart: always
env_file:
- ./notary.env
networks:
- harbor
nginx:
image: goharbor/nginx-photon:v2.10.0
restart: always
ports:
- "443:8443"
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf:ro
- /data/cert:/etc/nginx/cert:ro
networks:
- harbor
networks:
harbor:
driver: bridge
# harbor.env - Core configuration
POSTGRESQL_HOST=postgres.example.com
POSTGRESQL_PORT=5432
POSTGRESQL_DATABASE=registry
POSTGRESQL_USERNAME=harbor
POSTGRESQL_PASSWORD=${DB_PASSWORD}
POSTGRESQL_SSLMODE=require
REDIS_HOST=redis.example.com:6379
REDIS_PASSWORD=${REDIS_PASSWORD}
REDIS_DB_INDEX=0
HARBOR_ADMIN_PASSWORD=${ADMIN_PASSWORD}
REGISTRY_STORAGE_PROVIDER_NAME=s3
REGISTRY_STORAGE_PROVIDER_CONFIG={"bucket":"harbor-artifacts","region":"us-east-1"}
パターン 2:CVE ポリシーを使用した Trivy スキャン
# Configure Trivy scanner via Harbor API
curl -X POST "https://harbor.example.com/api/v2.0/scanners" \
-u "admin:password" \
-H "Content-Type: application/json" \
-d '{
"name": "Trivy",
"url": "http://trivy:8080",
"description": "Primary vulnerability scanner",
"vendor": "Aqua Security",
"version": "0.48.0"
}'
# Set scanner as default
curl -X PATCH "https://harbor.example.com/api/v2.0/scanners/1" \
-u "admin:password" \
-H "Content-Type: application/json" \
-d '{"is_default": true}'
// Project-level CVE policy
{
"cve_allowlist": {
"items": [
{
"cve_id": "CVE-2023-12345"
}
],
"expires_at": 1735689600
},
"severity": "high",
"scan_on_push": true,
"prevent_vulnerable": true,
"auto_scan": true
}
署名とスキャン要件を組み合わせたデプロイポリシー:
{
"deployment_policy": {
"vulnerability_severity": "critical",
"signature_enabled": true
}
}
Trivy の統合、Webhook の自動化、CVE ポリシーのパターンについては、/home/user/ai-coding/new-skills/harbor-expert/references/security-scanning.md を参照してください。
パターン 3:CI/CD 用 Robot アカウント
# Create robot account with scoped permissions
curl -X POST "https://harbor.example.com/api/v2.0/projects/library/robots" \
-u "admin:password" \
-H "Content-Type: application/json" \
-d '{
"name": "github-actions",
"description": "CI/CD pipeline for GitHub Actions",
"duration": 90,
"level": "project",
"disable": false,
"permissions": [
{
"kind": "project",
"namespace": "library",
"access": [
{"resource": "repository", "action": "pull"},
{"resource": "repository", "action": "push"},
{"resource": "artifact", "action": "read"}
]
}
]
}'
レスポンスにはトークンが含まれます:
{
"id": 1,
"name": "robot$github-actions",
"secret": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...",
"expires_at": 1735689600,
"level": "project"
}
GitHub Actions での使用:
# .github/workflows/build.yml
- name: Login to Harbor
uses: docker/login-action@v3
with:
registry: harbor.example.com
username: robot$github-actions
password: ${{ secrets.HARBOR_ROBOT_TOKEN }}
- name: Build and push
uses: docker/build-push-action@v5
with:
push: true
tags: harbor.example.com/library/app:${{ github.sha }}
パターン 4:マルチリージョンレプリケーション
# Create replication endpoint
curl -X POST "https://harbor.example.com/api/v2.0/registries" \
-u "admin:password" \
-H "Content-Type: application/json" \
-d '{
"name": "harbor-eu",
"url": "https://harbor-eu.example.com",
"credential": {
"access_key": "robot$replication",
"access_secret": "token_here"
},
"type": "harbor",
"insecure": false
}'
# Create pull-based replication rule
curl -X POST "https://harbor.example.com/api/v2.0/replication/policies" \
-u "admin:password" \
-H "Content-Type: application/json" \
-d '{
"name": "replicate-production",
"description": "Pull production images from primary",
"src_registry": {
"id": 1
},
"dest_namespace": "production",
"trigger": {
"type": "scheduled",
"trigger_settings": {
"cron": "0 2 * * *"
}
},
"filters": [
{
"type": "name",
"value": "library/app-*"
},
{
"type": "tag",
"value": "v*"
},
{
"type": "label",
"value": "environment=production"
}
],
"deletion": false,
"override": true,
"enabled": true,
"speed": 0
}'
災害復旧戦略と高度なレプリケーションパターンについては、/home/user/ai-coding/new-skills/harbor-expert/references/replication-guide.md を参照してください。
パターン 5:Cosign によるイメージ署名
# Enable content trust in Harbor project settings
curl -X PUT "https://harbor.example.com/api/v2.0/projects/1/metadata/enable_content_trust" \
-u "admin:password" \
-H "Content-Type: application/json" \
-d '{"enable_content_trust": "true"}'
# Sign image with Cosign (keyless with OIDC)
export COSIGN_EXPERIMENTAL=1
cosign sign --oidc-issuer https://token.actions.githubusercontent.com \
harbor.example.com/library/app:v1.0.0
# Verify signature
cosign verify --certificate-identity-regexp "https://github.com/example/*" \
--certificate-oidc-issuer https://token.actions.githubusercontent.com \
harbor.example.com/library/app:v1.0.0
# Attach SBOM
cosign attach sbom --sbom sbom.spdx.json \
harbor.example.com/library/app:v1.0.0
署名を検証する Kyverno ポリシー:
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: verify-harbor-images
spec:
validationFailureAction: Enforce
background: false
rules:
- name: verify-signature
match:
any:
- resources:
kinds: [Pod]
verifyImages:
- imageReferences:
- "harbor.example.com/library/*"
attestors:
- count: 1
entries:
- keyless:
subject: "https://github.com/example/*"
issuer: "https://token.actions.githubusercontent.com"
rekor:
url: https://rekor.sigstore.dev
パターン 6:保持ポリシーとタグの不変性
# Configure retention policy
curl -X POST "https://harbor.example.com/api/v2.0/projects/library/retentions" \
-u "admin:password" \
-H "Content-Type: application/json" \
-d '{
"rules": [
{
"disabled": false,
"action": "retain",
"template": "latestPushedK",
"params": {
"latestPushedK": 10
},
"tag_selectors": [
{
"kind": "doublestar",
"decoration": "matches",
"pattern": "v*"
}
],
"scope_selectors": {
"repository": [
{
"kind": "doublestar",
"decoration": "repoMatches",
"pattern": "**"
}
]
}
},
{
"disabled": false,
"action": "retain",
"template": "nDaysSinceLastPush",
"params": {
"nDaysSinceLastPush": 90
},
"tag_selectors": [
{
"kind": "doublestar",
"decoration": "matches",
"pattern": "main-*"
}
]
}
],
"algorithm": "or",
"trigger": {
"kind": "Schedule",
"settings": {
"cron": "0 0 * * 0"
}
}
}'
# Enable tag immutability for production
curl -X POST "https://harbor.example.com/api/v2.0/projects/library/immutabletagrules" \
-u "admin:password" \
-H "Content-Type: application/json" \
-d '{
"tag_selectors": [
{
"kind": "doublestar",
"decoration": "matches",
"pattern": "v*.*.*"
}
],
"scope_selectors": {
"repository": [
{
"kind": "doublestar",
"decoration": "repoMatches",
"pattern": "production/**"
}
]
}
}'
パターン 7:Webhook の自動化とイベント処理
# Configure webhook for vulnerability scan results
curl -X POST "https://harbor.example.com/api/v2.0/projects/library/webhook/policies" \
-u "admin:password" \
-H "Content-Type: application/json" \
-d '{
"name": "notify-security-team",
"description": "Alert on critical vulnerabilities",
"enabled": true,
"event_types": [
"SCANNING_COMPLETED",
"SCANNING_FAILED"
],
"targets": [
{
"type": "http",
"address": "https://slack.com/api/webhooks/xxx",
"skip_cert_verify": false,
"payload_format": "CloudEvents"
}
]
}'
Webhook ペイロードの構造:
{
"specversion": "1.0",
"type": "harbor.scanning.completed",
"source": "harbor.example.com",
"id": "unique-id",
"time": "2024-01-15T10:30:00Z",
"data": {
"repository": "library/app",
"tag": "v1.0.0",
"scan_overview": {
"severity": "High",
"total_count": 5,
"fixable_count": 3,
"summary": {
"Critical": 0,
"High": 5,
"Medium": 12
}
}
}
}
6. 実装ワークフロー(TDD)
ステップ 1:最初に失敗するテストを書く
Harbor の設定を実装する前に、期待する動作を検証するテストを書きます:
# tests/test_harbor_config.py
import pytest
import requests
from unittest.mock import patch, MagicMock
class TestHarborProjectConfiguration:
"""Test Harbor project settings before implementation."""
def test_project_vulnerability_policy_blocks_critical(self):
"""Test that CVE policy blocks critical vulnerabilities."""
# Arrange
project_config = {
"prevent_vulnerable": True,
"severity": "critical",
"scan_on_push": True
}
# Act
result = validate_vulnerability_policy(project_config)
# Assert
assert result["blocks_critical"] == True
assert result["scan_enabled"] == True
def test_robot_account_follows_least_privilege(self):
"""Test robot account has minimal required permissions."""
# Arrange
robot_permissions = {
"namespace": "library",
"access": [
{"resource": "repository", "action": "pull"},
{"resource": "repository", "action": "push"}
]
}
# Act
result = validate_robot_permissions(robot_permissions)
# Assert
assert result["is_scoped"] == True
assert result["has_admin"] == False
assert len(result["permissions"]) <= 3
def test_replication_policy_has_filters(self):
"""Test replication policy includes proper filters."""
# Arrange
replication_config = {
"filters": [
{"type": "name", "value": "library/app-*"},
{"type": "tag", "value": "v*"}
],
"trigger": {"type": "scheduled"}
}
# Act
result = validate_replication_policy(replication_config)
# Assert
assert result["has_name_filter"] == True
assert result["has_tag_filter"] == True
assert result["is_scheduled"] == True
class TestHarborAPIIntegration:
"""Integration tests for Harbor API operations."""
@pytest.fixture
def harbor_client(self):
"""Create Harbor API client for testing."""
return HarborClient(
url="https://harbor.example.com",
username="admin",
password="test"
)
def test_create_project_with_security_policies(self, harbor_client):
"""Test project creation includes security policies."""
# Arrange
project_spec = {
"project_name": "test-project",
"public": False,
"metadata": {
"enable_content_trust": "true",
"prevent_vul": "true",
"severity": "high",
"auto_scan": "true"
}
}
# Act
result = harbor_client.create_project(project_spec)
# Assert
assert result.status_code == 201
project = harbor_client.get_project("test-project")
assert project["metadata"]["enable_content_trust"] == "true"
assert project["metadata"]["prevent_vul"] == "true"
def test_garbage_collection_schedule_configured(self, harbor_client):
"""Test GC schedule is properly configured."""
# Arrange
gc_schedule = {
"schedule": {
"type": "Weekly",
"cron": "0 2 * * 6"
},
"parameters": {
"delete_untagged": True,
"dry_run": False
}
}
# Act
result = harbor_client.set_gc_schedule(gc_schedule)
# Assert
assert result.status_code == 200
current_schedule = harbor_client.get_gc_schedule()
assert current_schedule["schedule"]["cron"] == "0 2 * * 6"
ステップ 2:テストに合格するための最小限の実装を行う
# harbor_client.py
import requests
from typing import Dict, Any
class HarborClient:
"""Harbor API client with security-first defaults."""
def __init__(self, url: str, username: str, password: str):
self.url = url.rstrip('/')
self.auth = (username, password)
self.session = requests.Session()
self.session.auth = self.auth
self.session.headers.update({"Content-Type": "application/json"})
def create_project(self, spec: Dict[str, Any]) -> requests.Response:
"""Create project with security policies."""
# Ensure security defaults
if "metadata" not in spec:
spec["metadata"] = {}
spec["metadata"].setdefault("enable_content_trust", "true")
spec["metadata"].setdefault("prevent_vul", "true")
spec["metadata"].setdefault("severity", "high")
spec["metadata"].setdefault("auto_scan", "true")
return self.session.post(
f"{self.url}/api/v2.0/projects",
json=spec
)
def set_gc_schedule(self, schedule: Dict[str, Any]) -> requests.Response:
"""Configure garbage collection schedule."""
return self.session.post(
f"{self.url}/api/v2.0/system/gc/schedule",
json=schedule
)
ステップ 3:必要に応じてリファクタリングする
テストに合格したら、エラー処理とパフォーマンスを改善するためにリファクタリングします:
# Refactored with retry logic and connection pooling
from requests.adapters import HTTPAdapter
from urllib3.util.retry import Retry
class HarborClient:
def __init__(self, url: str, username: str, password: str):
self.url = url.rstrip('/')
self.auth = (username, password)
self.session = self._create_session()
def _create_session(self) -> requests.Session:
"""Create session with retry and connection pooling."""
session = requests.Session()
session.auth = self.auth
session.headers.update({"Content-Type": "application/json"})
# Configure retries for resilience
retry_strategy = Retry(
total=3,
backoff_factor=1,
status_forcelist=[429, 500, 502, 503, 504]
)
adapter = HTTPAdapter(
max_retries=retry_strategy,
pool_connections=10,
pool_maxsize=10
)
session.mount("https://", adapter)
return session
ステップ 4:完全な検証を実行する
# Run all tests
pytest tests/test_harbor_config.py -v
# Run with coverage
pytest tests/test_harbor_config.py --cov=harbor_client --cov-report=term-missing
# Validate actual Harbor configuration
curl -s "https://harbor.example.com/api/v2.0/systeminfo" \
-u "admin:password" | jq '.harbor_version'
# Test scanner connectivity
curl -s "https://harbor.example.com/api/v2.0/scanners" \
-u "admin:password" | jq '.[].is_default'
# Verify replication endpoints
curl -s "https://harbor.example.com/api/v2.0/registries" \
-u "admin:password" | jq '.[].status'
7. パフォーマンスパターン
パターン 1:ガベージコレクションの最適化
悪い例 - GC の実行頻度が低く、ストレージが肥大化します:
# ❌ Monthly GC - storage fills up
{
"schedule": {
"type": "Custom",
"cron": "0 0 1 * *"
},
"parameters": {
"delete_untagged": false
}
}
良い例 - タグのないイメージを削除する GC を定期的に実行します:
# ✅ Weekly GC with untagged cleanup
curl -X POST "https://harbor.example.com/api/v2.0/system/gc/schedule" \
-u "admin:password" \
-H "Content-Type: application/json" \
-d '{
"schedule": {
"type": "Weekly",
"cron": "0 2 * * 6"
},
"parameters": {
"delete_untagged": true,
"dry_run": false,
"workers": 4
}
}'
# Monitor GC performance
curl -s "https://harbor.example.com/api/v2.0/system/gc" \
-u "admin:password" | jq '.[-1] | {status, deleted, duration: (.end_time - .start_time)}'
パターン 2:レプリケーションの最適化
悪い例 - フィルタリングなしの完全なレプリケーション:
# ❌ Replicate everything - wastes bandwidth
{
"name": "replicate-all",
"filters": [],
"trigger": {"type": "event_based"},
"speed": 0
}
良い例 - 帯域幅を制御し、フィルタリングしたスケジュールレプリケーション:
# ✅ Filtered replication with scheduling and rate limiting
curl -X POST "https://harbor.example.com/api/v2.0/replication/policies" \
-u "admin:password" \
-H "Content-Type: application/json" \
-d '{
"name": "replicate-production",
"filters": [
{"type": "name", "value": "production/**"},
{"type": "tag", "value": "v*"},
{"type": "label", "value": "approved=true"}
],
"trigger": {
"type": "scheduled",
"trigger_settings": {
"cron": "0 */4 * * *"
}
},
"speed": 10485760,
"override": true,
"enabled": true
}'
# Monitor replication performance
curl -s "https://harbor.example.com/api/v2.0/replication/executions?policy_id=1" \
-u "admin:password" | jq '[.[] | select(.status=="Succeed")] | length'
パターン 3:キャッシュとプロキシの設定
悪い例 - キャッシュせず、毎回直接プルします:
# ❌ Every pull hits upstream registry
docker pull docker.io/library/nginx:latest
# Slow and uses bandwidth
良い例 - Harbor をプロキシキャッシュとして使用します:
# ✅ Configure proxy cache endpoint
curl -X POST "https://harbor.example.com/api/v2.0/registries" \
-u "admin:password" \
-H "Content-Type: application/json" \
-d '{
"name": "dockerhub-cache",
"type": "docker-hub",
"url": "https://hub.docker.com",
"credential": {
"access_key": "username",
"access_secret": "token"
}
}'
# Create proxy cache project
curl -X POST "https://harbor.example.com/api/v2.0/projects" \
-u "admin:password" \
-H "Content-Type: application/json" \
-d '{
"project_name": "dockerhub-proxy",
"registry_id": 1,
"public": true
}'
# Pull through cache - subsequent pulls are instant
docker pull harbor.example.com/dockerhub-proxy/library/nginx:latest
パターン 4:ストレージバックエンドの最適化
悪い例 - ローカルファイルシステムストレージ:
# ❌ Filesystem storage - no HA, backup complexity
storage_service:
filesystem:
rootdirectory: /data/registry
良い例 - ライフサイクルポリシーを設定したオブジェクトストレージ:
# ✅ S3 storage with intelligent tiering
REGISTRY_STORAGE_PROVIDER_NAME=s3
REGISTRY_STORAGE_PROVIDER_CONFIG='{
"bucket": "harbor-artifacts",
"region": "us-east-1",
"rootdirectory": "/harbor",
"storageclass": "INTELLIGENT_TIERING",
"multipartcopythresholdsize": 33554432,
"multipartcopychunksize": 33554432,
"multipartcopymaxconcurrency": 100,
"encrypt": true,
"v4auth": true
}'
# Configure lifecycle policy for old artifacts
aws s3api put-bucket-lifecycle-configuration \
--bucket harbor-artifacts \
--lifecycle-configuration '{
"Rules": [{
"ID": "archive-old-artifacts",
"Status": "Enabled",
"Filter": {"Prefix": "harbor/"},
"Transitions": [{
"Days": 90,
"StorageClass": "GLACIER"
}],
"NoncurrentVersionTransitions": [{
"NoncurrentDays": 30,
"StorageClass": "GLACIER"
}]
}]
}'
パターン 5:データベース接続プーリング
悪い例 - デフォルトのデータベース接続:
# ❌ Default connections - bottleneck under load
POSTGRESQL_MAX_OPEN_CONNS=0
POSTGRESQL_MAX_IDLE_CONNS=2
良い例 - 最適化された接続プール:
# ✅ Tuned connection pool for production
POSTGRESQL_HOST=postgres.example.com
POSTGRESQL_PORT=5432
POSTGRESQL_MAX_OPEN_CONNS=100
POSTGRESQL_MAX_IDLE_CONNS=50
POSTGRESQL_CONN_MAX_LIFETIME=5m
POSTGRESQL_SSLMODE=require
# Redis connection optimization
REDIS_HOST=redis.example.com:6379
REDIS_PASSWORD=${REDIS_PASSWORD}
REDIS_DB_INDEX=0
REDIS_IDLE_TIMEOUT_SECONDS=30
# Monitor connection usage
psql -h postgres.example.com -U harbor -c \
"SELECT count(*) as active_connections FROM pg_stat_activity WHERE datname='registry';"
パターン 6:スキャンパフォーマンスのチューニング
悪い例 - 長いタイムアウトを設定した逐次スキャン:
# ❌ Slow scanning blocks pushes
SCANNER_TRIVY_TIMEOUT=30m
# No parallelization
良い例 - 最適化された設定による並列スキャン:
# ✅ Optimized Trivy scanner configuration
trivy:
environment:
SCANNER_TRIVY_TIMEOUT: "10m"
SCANNER_TRIVY_VULN_TYPE: "os,library"
SCANNER_TRIVY_SEVERITY: "UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL"
SCANNER_TRIVY_SKIP_UPDATE: "false"
SCANNER_TRIVY_GITHUB_TOKEN: "${GITHUB_TOKEN}"
SCANNER_TRIVY_CACHE_DIR: "/home/scanner/.cache/trivy"
SCANNER_STORE_REDIS_URL: "redis://redis:6379/5"
SCANNER_JOB_QUEUE_REDIS_URL: "redis://redis:6379/6"
volumes:
- trivy-cache:/home/scanner/.cache/trivy
deploy:
replicas: 3
resources:
limits:
memory: 4G
cpus: '2'
# Pre-download vulnerability database
docker exec trivy trivy image --download-db-only
5. セキュリティ標準
5.1 イメージ署名の要件
コンテンツ信頼ポリシー:
- すべての本番イメージは、デプロイ前に署名する必要があります
- 透明性を確保するため、Cosign によるキーレス署名(OIDC)を使用します
- 署名済みのすべてのイメージに SBOM を添付します
- アドミッションコントローラー(Kyverno)で署名を検証します
- 署名カバレッジの指標を追跡します(本番環境の目標:100%)
署名ワークフロー:
- CI/CD パイプラインでイメージをビルドします
- Trivy でスキャンします(CVE ポリシーを満たす必要があります)
- Syft または Trivy で SBOM を生成します
- Cosign でイメージに署名します(OIDC による一時キーを使用)
- SBOM をアーティファクトとして添付します
- Harbor レジストリにプッシュします
- Kubernetes へのデプロイ前に署名を検証します
5.2 脆弱性管理
CVE ポリシーの適用:
- CRITICAL:すべてのデプロイをブロックし、即時修正を必須とします
- HIGH:本番環境ではブロックし、開発環境では期限付きの免除がある場合に許可します
- MEDIUM:アラートのみとし、セキュリティダッシュボードで追跡します
- LOW/UNKNOWN:注意喚起のために記録します
スキャン設定:
- プッシュ時のスキャン:すべてのプロジェクトで有効
- 自動再スキャン:毎日 UTC の午前 2 時
- 脆弱性データベースの更新:6 時間ごと
- スキャンのタイムアウト:イメージごとに 10 分
- 保持期間:スキャン結果を 90 日間保持
免除プロセス:
- セキュリティチームが CVE の影響を確認します
- 有効期限を設定して許可リストにエントリーを追加します
- 緩和策または代替の制御策を文書化します
- コンプライアンスレポートで免除を追跡します
- 免除の有効期限の 7 日前にアラートを送信します
5.3 RBAC とアクセス制御
プロジェクトロール:
- プロジェクト管理者:すべての操作が可能で、メンバーの管理やポリシーの設定を行えます
- 開発者:イメージのプッシュ/プルとスキャン結果の表示ができますが、ポリシーは変更できません
- ゲスト:イメージのプルのみ可能で、メタデータへの読み取り専用アクセスができます
- 制限付きゲスト:特定のリポジトリのみプルできます
ロボットアカウントのベストプラクティス:
- すべての自動化にロボットアカウントを使用します(ユーザー認証情報は使用しません)
- 単一のプロジェクトに限定し、権限を最小限にします
- 有効期限を設定します(最長 90 日、60 日ごとにローテーション)
- 説明的な名前を使用します:
robot$service-environment-action - ロボットアカウントの使用状況を毎週監査します
- サービスの廃止時には直ちに取り消します
OIDC 統合:
# Harbor OIDC configuration
auth_mode: oidc_auth
oidc_name: Keycloak
oidc_endpoint: https://keycloak.example.com/auth/realms/harbor
oidc_client_id: harbor
oidc_client_secret: ${OIDC_SECRET}
oidc_scope: openid,profile,email,groups
oidc_verify_cert: true
oidc_auto_onboard: true
oidc_user_claim: preferred_username
oidc_group_claim: groups
5.4 サプライチェーンセキュリティ
アーティファクトの完全性:
- すべての本番プロジェクトでコンテンツ信頼を有効にします
- 信頼できる発行者からの署名のみを必須とします
- SBOM の存在と完全性を検証します
- ソースからデプロイまでのアーティファクトの来歴を追跡します
- アドミッションコントローラーに cosign の検証を実装します
ベースイメージのセキュリティ:
- 公式の最小ベースイメージ(distroless、alpine、chainguard)を使用します
- ベースイメージを使用前にスキャンします
- ベースイメージはタグではなくダイジェストで固定します
- ベースイメージの CVE 通知を監視します
- セキュリティパッチのリリースから 7 日以内にベースイメージを更新します
コンプライアンスの追跡:
- コンプライアンスレポートを毎週生成します
- 署名カバレッジ、スキャン合格率、CVE MTTR などの指標を追跡します
- アーティファクトへのアクセスパターンを監査します
- 署名されていない本番デプロイに対してアラートを送信します
- 関係者と毎月セキュリティレビューを実施します
8. よくある間違い
間違い 1:本番環境で未署名イメージを許可する
問題:
# ❌ No signature verification
apiVersion: v1
kind: Pod
spec:
containers:
- image: harbor.example.com/library/app:latest
解決策:
# ✅ Kyverno enforces signatures
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: require-signed-images
spec:
validationFailureAction: Enforce
rules:
- name: verify-signature
verifyImages:
- imageReferences: ["harbor.example.com/library/*"]
required: true
間違い 2:過度に許可的なロボットアカウント
問題:
# ❌ Project admin for CI/CD
{
"permissions": [{
"namespace": "library",
"access": [{"resource": "*", "action": "*"}]
}]
}
解決策:
# ✅ Minimal scoped permissions
{
"name": "ci-pipeline",
"duration": 90,
"permissions": [{
"namespace": "library",
"access": [
{"resource": "repository", "action": "pull"},
{"resource": "repository", "action": "push"},
{"resource": "artifact-label", "action": "create"}
]
}]
}
間違い 3:CVE ブロックポリシーがない
問題:
// ❌ Scan only, no enforcement
{
"scan_on_push": true,
"prevent_vulnerable": false
}
解決策:
// ✅ Block critical/high CVEs
{
"scan_on_push": true,
"prevent_vulnerable": true,
"severity": "high",
"auto_scan": true
}
間違い 4:レプリケーションの監視がない
問題:
# ❌ Set and forget replication
# No monitoring, failures go unnoticed
解決策:
# ✅ Monitor replication health
curl "https://harbor.example.com/api/v2.0/replication/executions?policy_id=1" \
-u "admin:password" | jq -r '.[] | select(.status=="Failed")'
# Alert on replication lag > 1 hour
LAST_SUCCESS=$(curl -s "..." | jq -r '.[-1].end_time')
LAG=$(( $(date +%s) - $(date -d "$LAST_SUCCESS" +%s) ))
if [ $LAG -gt 3600 ]; then
alert "Replication lag detected"
fi
間違い 5:ガベージコレクションを行わない
問題:
# ❌ Storage grows indefinitely
# Deleted artifacts never cleaned up
解決策:
# ✅ Scheduled garbage collection
# Harbor UI: Administration > Garbage Collection > Schedule
# Cron: 0 2 * * 6 (every Saturday 2 AM)
# Or via API
curl -X POST "https://harbor.example.com/api/v2.0/system/gc/schedule" \
-u "admin:password" \
-H "Content-Type: application/json" \
-d '{
"schedule": {
"type": "Weekly",
"cron": "0 2 * * 6"
},
"parameters": {
"delete_untagged": true,
"dry_run": false
}
}'
間違い 6:本番環境で :latest タグを使用する
問題:
# ❌ Non-deterministic deployments
image: harbor.example.com/library/app:latest
解決策:
# ✅ Immutable digest-based references
image: harbor.example.com/library/app@sha256:abc123...
# Or immutable semantic version
image: harbor.example.com/library/app:v1.2.3
# + tag immutability rule for v*.*.* pattern
9. テスト
Harbor 設定のユニットテスト
# tests/test_harbor_policies.py
import pytest
from harbor_client import HarborClient, validate_project_config
class TestProjectPolicies:
"""Unit tests for Harbor project configuration."""
def test_vulnerability_policy_requires_scanning(self):
"""Verify CVE policy requires scan_on_push."""
config = {
"prevent_vulnerable": True,
"severity": "high",
"scan_on_push": False # Invalid combination
}
result = validate_project_config(config)
assert result["valid"] == False
assert "scan_on_push required" in result["errors"]
def test_content_trust_requires_notary(self):
"""Verify content trust needs Notary configured."""
config = {
"enable_content_trust": True,
"notary_url": None
}
result = validate_project_config(config)
assert result["valid"] == False
def test_retention_policy_validation(self):
"""Verify retention rules are valid."""
policy = {
"rules": [{
"template": "latestPushedK",
"params": {"latestPushedK": -1} # Invalid
}]
}
result = validate_retention_policy(policy)
assert result["valid"] == False
class TestRobotAccounts:
"""Test robot account permission validation."""
def test_robot_account_expiration_required(self):
"""Robot accounts must have expiration."""
robot = {
"name": "ci-pipeline",
"duration": 0, # Never expires - bad
"permissions": [{"resource": "repository", "action": "push"}]
}
result = validate_robot_account(robot)
assert result["valid"] == False
assert "expiration required" in result["errors"]
def test_robot_account_max_duration(self):
"""Robot account max duration is 90 days."""
robot = {
"name": "ci-pipeline",
"duration": 365, # Too long
"permissions": [{"resource": "repository", "action": "push"}]
}
result = validate_robot_account(robot)
assert result["valid"] == False
assert "max duration 90 days" in result["errors"]
Harbor API を使った統合テスト
# tests/integration/test_harbor_api.py
import pytest
import os
from harbor_client import HarborClient
@pytest.fixture(scope="module")
def harbor():
"""Create Harbor client for integration tests."""
return HarborClient(
url=os.getenv("HARBOR_URL", "https://harbor.example.com"),
username=os.getenv("HARBOR_USER", "admin"),
password=os.getenv("HARBOR_PASSWORD")
)
class TestHarborAPIIntegration:
"""Integration tests against live Harbor instance."""
def test_health_check(self, harbor):
"""Verify Harbor API is accessible."""
result = harbor.health()
assert result.status_code == 200
assert result.json()["status"] == "healthy"
def test_scanner_configured(self, harbor):
"""Verify Trivy scanner is default."""
scanners = harbor.get_scanners()
default_scanner = next(
(s for s in scanners if s["is_default"]), None
)
assert default_scanner is not None
assert "trivy" in default_scanner["name"].lower()
def test_project_security_defaults(self, harbor):
"""Verify projects have security settings."""
# Create test project
project = harbor.create_project({
"project_name": "test-security-defaults",
"public": False
})
# Verify security defaults applied
metadata = harbor.get_project("test-security-defaults")["metadata"]
assert metadata.get("enable_content_trust") == "true"
assert metadata.get("prevent_vul") == "true"
assert metadata.get("auto_scan") == "true"
# Cleanup
harbor.delete_project("test-security-defaults")
def test_gc_schedule_exists(self, harbor):
"""Verify garbage collection is scheduled."""
schedule = harbor.get_gc_schedule()
assert schedule["schedule"]["type"] in ["Weekly", "Daily", "Custom"]
assert schedule["parameters"]["delete_untagged"] == True
class TestReplicationPolicies:
"""Test replication policy configurations."""
def test_replication_endpoint_tls(self, harbor):
"""Verify replication endpoints use TLS."""
endpoints = harbor.get_registries()
for endpoint in endpoints:
assert endpoint["url"].startswith("https://")
assert endpoint["insecure"] == False
def test_replication_has_filters(self, harbor):
"""Verify replication policies have filters."""
policies = harbor.get_replication_policies()
for policy in policies:
if policy["enabled"]:
assert len(policy.get("filters", [])) > 0, \
f"Policy {policy['name']} has no filters"
エンドツーエンドテスト
#!/bin/bash
# tests/e2e/test_harbor_workflow.sh
set -e
HARBOR_URL="${HARBOR_URL:-https://harbor.example.com}"
PROJECT="e2e-test-$(date +%s)"
echo "=== Harbor E2E Test Suite ==="
# Test 1: Create project with security defaults
echo "Test 1: Creating project with security defaults..."
curl -s -X POST "${HARBOR_URL}/api/v2.0/projects" \
-u "${HARBOR_USER}:${HARBOR_PASSWORD}" \
-H "Content-Type: application/json" \
-d "{\"project_name\": \"${PROJECT}\", \"public\": false}" \
-o /dev/null -w "%{http_code}" | grep -q "201"
echo "✓ Project created"
# Test 2: Verify security policies applied
echo "Test 2: Verifying security policies..."
METADATA=$(curl -s "${HARBOR_URL}/api/v2.0/projects/${PROJECT}" \
-u "${HARBOR_USER}:${HARBOR_PASSWORD}" | jq '.metadata')
echo "$METADATA" | jq -e '.auto_scan == "true"' > /dev/null
echo "✓ Auto scan enabled"
echo "$METADATA" | jq -e '.prevent_vul == "true"' > /dev/null
echo "✓ Vulnerability prevention enabled"
# Test 3: Push and scan image
echo "Test 3: Pushing and scanning image..."
docker pull alpine:latest
docker tag alpine:latest "${HARBOR_URL}/${PROJECT}/alpine:test"
docker push "${HARBOR_URL}/${PROJECT}/alpine:test"
# Wait for scan
sleep 30
SCAN_STATUS=$(curl -s "${HARBOR_URL}/api/v2.0/projects/${PROJECT}/repositories/alpine/artifacts/test" \
-u "${HARBOR_USER}:${HARBOR_PASSWORD}" | jq -r '.scan_overview.scan_status')
[ "$SCAN_STATUS" == "Success" ]
echo "✓ Image scanned successfully"
# Test 4: Create robot account
echo "Test 4: Creating robot account..."
ROBOT=$(curl -s -X POST "${HARBOR_URL}/api/v2.0/projects/${PROJECT}/robots" \
-u "${HARBOR_USER}:${HARBOR_PASSWORD}" \
-H "Content-Type: application/json" \
-d '{
"name": "e2e-test",
"duration": 1,
"permissions": [{"namespace": "'${PROJECT}'", "access": [{"resource": "repository", "action": "pull"}]}]
}')
echo "$ROBOT" | jq -e '.secret' > /dev/null
echo "✓ Robot account created"
# Cleanup
echo "Cleaning up..."
curl -s -X DELETE "${HARBOR_URL}/api/v2.0/projects/${PROJECT}" \
-u "${HARBOR_USER}:${HARBOR_PASSWORD}"
echo "✓ Cleanup complete"
echo "=== All E2E tests passed ==="
テストの実行
# Run unit tests
pytest tests/test_harbor_policies.py -v
# Run integration tests (requires HARBOR_URL, HARBOR_USER, HARBOR_PASSWORD)
pytest tests/integration/ -v --tb=short
# Run E2E tests
./tests/e2e/test_harbor_workflow.sh
# Run all tests with coverage
pytest tests/ --cov=harbor_client --cov-report=html
# Specific test markers
pytest -m "not integration" # Skip integration tests
pytest -m "security" # Run only security tests
13. 重要な注意事項
実装前チェックリスト
フェーズ 1:コードを書く前
- 既存の Harbor 設定とバージョンを確認します
- 影響を受けるプロジェクトとレプリケーションポリシーを特定します
- 現在のセキュリティポリシー(CVE のブロック、コンテンツトラスト)を確認します
- 既存のロボットアカウントとその権限を確認します
- 現在のガベージコレクションのスケジュールを記録します
- 新機能の失敗するテストを作成します
- 変更に関する Harbor API のドキュメントを確認します
フェーズ 2:実装中
- TDD ワークフロー(テスト、実装、リファクタリングの順)に従います
- すべての新しいプロジェクトにセキュリティのデフォルト設定を適用します
- ロボットアカウントには最小権限を使用します
- レプリケーションポリシーのフィルターを設定します
- すべてのアーティファクトでプッシュ時スキャンを有効にします
- 適切な保持ポリシーを設定します
- すべての API 呼び出しが期待どおりの結果を返すことをテストします
フェーズ 3:コミット前
- テストスイート全体(ユニットテスト、統合テスト、E2E テスト)を実行します
- すべてのセキュリティポリシーが適用されていることを確認します
- ガベージコレクションがスケジュールされていることを確認します
- レプリケーションのエンドポイントが正常であることを検証します
- スキャナーが稼働していることを確認します
- 監査ログに異常がないか確認します
- 必要に応じてドキュメントを更新します
本番前デプロイのチェックリスト
レジストリの設定:
- PostgreSQL と Redis を外部化します(組み込みのものは使用しません)
- ストレージバックエンドを設定します(ファイルシステムではなく、S3/GCS/Azure を使用します)
- TLS 証明書が有効で、自動更新されることを確認します
- バックアップ戦略を設定し、テストします
- リソース制限(CPU、メモリ、ストレージクォータ)を設定します
セキュリティの強化:
- Trivy スキャナーを統合し、デフォルトとして設定します
- すべてのプロジェクトでプッシュ時スキャンを有効にします
- CVE ブロックポリシー(HIGH/CRITICAL)を設定します
- 本番プロジェクトでコンテンツトラストを有効にします
- リリースタグでタグの不変性を有効にします
- ロボットアカウントに最小権限を適用します
- OIDC/LDAP 認証を設定します
- 監査ログを有効にします
レプリケーションと DR:
- マルチリージョンレプリケーションを設定します
- レプリケーションの監視とアラートを有効にします
- 災害復旧のランブックを文書化します
- 過去 90 日以内にフェイルオーバーをテストします
- RTO/RPO の要件を満たします
コンプライアンス:
- 保持ポリシーを設定します
- セキュリティイベントの Webhook 通知を設定します
- コンプライアンスレポートを毎週生成します
- 本番環境の署名カバレッジを 95%超にします
- 重大な CVE の MTTR を 7 日未満にします
運用準備:
- ガベージコレクションを毎週スケジュールします
- データベースのバキュームを毎月スケジュールします
- 監視ダッシュボードを設定します
- よくあるインシデントのランブックを用意します
- オンコールチームに Harbor の管理方法を習得させます
重要なセキュリティ管理策
絶対にしないでください:
- 署名されていないイメージを本番環境にデプロイする
- CRITICAL な CVE が検出され、スキャンに失敗したイメージを許可する
- CI/CD でユーザーの認証情報を使用する(ロボットアカウントを使用してください)
- 複数のサービスでロボットアカウントのトークンを共有する
- 本番プロジェクトでコンテンツトラストを無効にする
- DR イベントの前にレプリケーションテストを省略する
- プライベートレジストリへのパブリックアクセスを許可する
必ず実施してください:
- デプロイ前にすべてのイメージをスキャンする
- プロベナンス情報を付与して本番イメージに署名する
- ロボットアカウントのトークンを 90 日ごとにローテーションする
- レプリケーションの遅延と失敗を監視する
- バックアップ/復元手順を四半期ごとにテストする
- Trivy の脆弱性データベースを毎日更新する
- 不審なアクセスパターンを毎週監査する
- CVE の適用除外に有効期限を設定し、記録する
14. まとめ
包括的な脆弱性スキャン、アーティファクト署名、マルチリージョンレプリケーションを備えたセキュアなコンテナレジストリを管理する Harbor のエキスパートです。Trivy による CVE スキャン、Cosign によるイメージ署名、RBAC 制御、脆弱または未署名のイメージをブロックするデプロイポリシーを用いて、多層防御セキュリティを実装します。
PostgreSQL/Redis バックエンド、S3 ストレージ、災害復旧に向けたセカンダリーリージョンへのプルベースレプリケーションを備えた、高可用性レジストリインフラストラクチャを設計します。保持ポリシー、タグの不変性、監査ログ、セキュリティイベントの Webhook 通知によるコンプライアンス自動化を実装します。
署名済みアーティファクトを必須とし、CVE ポリシーを適用し、コンプライアンスレポートを生成して、Kubernetes のアドミッションコントローラーに署名検証を統合することで、ソフトウェアサプライチェーンを保護します。ガベージコレクション、クォータ管理、パフォーマンス監視によって、レジストリの運用を最適化します。
ミッション:サプライチェーン攻撃から組織を守りながら、開発者の生産性を高める、セキュアで信頼性の高いコンテナレジストリインフラストラクチャを提供します。
参考資料:
- セキュリティスキャン:
/home/user/ai-coding/new-skills/harbor-expert/references/security-scanning.md - レプリケーションガイド:
/home/user/ai-coding/new-skills/harbor-expert/references/replication-guide.md