背景:Docker Hubがボトルネックになった時
開発チームの規模が拡大し、マイクロサービスが5つから30以上に増えた頃、パブリックなDocker Hubへのイメージプッシュにおいて多くの課題が顕在化し始めました。まず、有料アカウントのコストが急増したことです。さらに、Docker Hubでは匿名または無料アカウントに対して「6時間あたり200プル」のレートリミットが課されています。この制限により、リリースのピーク時にCI/CDパイプラインが途中で停止するトラブルに見舞われました。そして何より、社内のセキュリティポリシーにより、企業のソースコードを含むコンテナイメージをサードパーティのクラウド上に配置することが厳しく禁止されていたのです。
当時のビルドインフラは、従来の古いCentOS 7サーバーからCentOS Stream 9への移行期にありました。チームが必要としていたのは、オフィスの社内LAN内に直接設置できるオンプレミスのプライベートレジストリでした。これには、ロールベースアクセス制御(RBAC)、ストレージ容量のクォータ管理、そして本番のKubernetesクラスタへデプロイする前の自動脆弱性スキャン機能が求められていました。
Nexus OSSとHarborを比較検討した結果、チームはCNCFのGraduatedステータスを持つオープンソースプロジェクト「Harbor」を選定しました。Harborは以下の3つの課題を見事に解決してくれました。
- 転送速度と制御性: すべてのデータが社内サーバーに保管されます。1Gbpsのローカルネットワーク経由なら、800MBのイメージもわずか数秒でプル可能で、インターネット回線の帯域を一切消費しません。
- プロアクティブなセキュリティ: Trivyエンジンがイメージの各レイヤーを自動スキャンします。CriticalレベルのCVEが検出された場合、プル操作を即座にブロックするセキュリティポリシーを設定できます。
- 一元的な管理機能: LDAP/Active Directoryによるアカウント同期、明確なプロジェクト単位の権限管理、Cosignによるコンテナイメージの電子署名に対応しています。
CentOS Stream 9での前提パッケージのインストール
HarborはDocker Composeによって制御されるコンテナ群として動作します。そのため、最初のステップとしてCentOS Stream 9上にクリーンなDocker EngineとComposeプラグインの環境をセットアップします。
1. Docker CEおよびDocker Compose Pluginのインストール
まず、リポジトリ管理ツールをインストールし、Docker公式のリポジトリを追加した上で、必要なパッケージをインストールします。
# リポジトリ管理ツールのインストール
sudo dnf install -y dnf-plugins-core
# RHEL/CentOS向けDocker CE公式リポジトリの追加
sudo dnf config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
# Docker Engine、CLI、containerd、Docker Composeプラグインのインストール
sudo dnf install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin
# Dockerサービスを起動し自動起動を有効化
sudo systemctl enable --now docker
# Dockerの動作バージョン確認
sudo docker version
2. ファイアウォール(Firewalld)の設定
HarborはデフォルトでHTTP(80)とHTTPS(443)の2つのポートを使用します。ファイアウォールでこれら2つのポートを恒久的に開放します。
sudo firewall-cmd --permanent --add-service=http
sudo firewall-cmd --permanent --add-service=https
sudo firewall-cmd --reload
3. 自己署名SSL/TLS証明書(Self-signed Certificate)の作成
Dockerデーモンはデフォルトで、暗号化されていないHTTP経由でのレジストリとの通信を拒否します。セキュリティリスクのあるinsecure-registries設定を使用するのではなく、最初からHTTPSを有効にしておくことが推奨されます。ここでは、社内ドメインregistry.internal.lan向けにSAN(Subject Alternative Name)対応の自己署名証明書を作成する手順を示します。
# 証明書格納用ディレクトリの作成
sudo mkdir -p /data/cert && cd /data/cert
# 内部CA用の秘密鍵を生成
sudo openssl genrsa -out ca.key 4096
# 有効期限10年のCA証明書を作成
sudo openssl req -x509 -new -nodes -sha512 -days 3650 \
-subj "/C=VN/ST=Hanoi/L=Hanoi/O=ITFromZero/CN=registry.internal.lan" \
-key ca.key -out ca.crt
# Harborサーバー用の秘密鍵を生成
sudo openssl genrsa -out server.key 4096
# 証明書署名要求(CSR)を作成
sudo openssl req -sha512 -new \
-subj "/C=VN/ST=Hanoi/L=Hanoi/O=ITFromZero/CN=registry.internal.lan" \
-key server.key -out server.csr
# ブラウザやDockerでの検証エラーを防ぐSAN設定ファイルの作成
cat <<EOF | sudo tee v3.ext
authorityKeyIdentifier=keyid,issuer
basicConstraints=CA:FALSE
keyUsage = digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment
extendedKeyUsage = serverAuth
subjectAltName = @alt_names
[alt_names]
DNS.1=registry.internal.lan
DNS.2=registry
EOF
# 作成したCAでHarborサーバー証明書に署名
sudo openssl x509 -req -sha512 -days 365 \
-extfile v3.ext \
-CA ca.crt -CAkey ca.key -CAcreateserial \
-in server.csr -out server.crt
Harborのインストールと設定
1. Harbor Offline Installerのダウンロード
オフラインパッケージは約800MBで、必要なすべてのコンテナイメージが含まれています。これにより、オンライン版インストーラーに比べて迅速かつ安定したインストールが可能です。
cd /opt
sudo wget https://github.com/goharbor/harbor/releases/download/v2.10.0/harbor-offline-installer-v2.10.0.tgz
sudo tar -zxvf harbor-offline-installer-v2.10.0.tgz
cd harbor
2. 設定ファイル harbor.yml の編集
テンプレートファイルからコピーを作成し、テキストエディタで設定ファイルを開きます。
sudo cp harbor.yml.tmpl harbor.yml
sudo vi harbor.yml
ドメイン、証明書のパス、および管理者パスワードを以下のように設定します。
# Harborサーバーのドメイン名またはFQDN
hostname: registry.internal.lan
# HTTPポート(HTTPSへのリダイレクト用)
http:
port: 80
# HTTPS設定と作成した証明書・秘密鍵のパス
https:
port: 443
certificate: /data/cert/server.crt
private_key: /data/cert/server.key
# デフォルト管理者(admin)アカウントのパスワード
harbor_admin_password: StrongPassword123!
# イメージ、データベース、Redisキャッシュのデータ保存先
data_volume: /data/harbor
3. Trivyスキャナーを有効にしてインストールスクリプトを実行
インストールスクリプトの実行時には、必ず --with-trivy フラグを付与してください。このオプションにより、脆弱性解析用コンテナが自動的に取得・構築されます。
sudo ./install.sh --with-trivy
イメージの展開と9つのサブサービスの初期化には約2〜3分かかります。ターミナルに ----Harbor has been installed and started successfully.---- と表示されれば、システムの準備は完了です。
実際の運用とセキュリティ検証
1. Dockerクライアント側での証明書信頼設定
CA証明書を信頼設定に登録しない場合、ログインコマンドの実行時にDockerクライアントが x509: certificate signed by unknown authority というエラーを出力します。各ワーカーノードや開発端末のDocker信頼ディレクトリに ca.crt をコピーしてください。
# ドメイン名に対応するcerts.dディレクトリの作成
sudo mkdir -p /etc/docker/certs.d/registry.internal.lan/
# HarborサーバーからルートCAファイルをコピー
sudo cp /data/cert/ca.crt /etc/docker/certs.d/registry.internal.lan/ca.crt
# Dockerデーモンの設定を再読み込み(再起動)
sudo systemctl restart docker
社内DNSサーバーがまだ構築されていない場合は、hostsファイルに一時的にHarborサーバーのIPをマッピングします。
echo "192.168.1.50 registry.internal.lan" | sudo tee -a /etc/hosts
2. ログインとテストイメージのプッシュ
ターミナルから管理者アカウントを使用してレジストリにログインします。
docker login registry.internal.lan
# Username: admin
# Password: StrongPassword123!
続いて、alpine:3.18 イメージをローカルにプルし、タグを付与してデフォルトプロジェクトである library にプッシュしてみましょう。
# Docker Hubから軽量イメージをプル
docker pull alpine:3.18
# Harborプライベートレジストリ向けのタグを付与
docker tag alpine:3.18 registry.internal.lan/library/alpine:3.18
# LAN経由で社内レジストリにイメージをプッシュ
docker push registry.internal.lan/library/alpine:3.18
3. CVEスキャンと自動ブロック機能の有効化
ブラウザを開き、https://registry.internal.lan にアクセスして admin アカウントでログインします。
- Projects にアクセスし、library を選択して Repositories タブに切り替えます。
- リポジトリ
alpineをクリックすると、先ほどプッシュした3.18タグが表示されます。 - このタグにチェックを入れ、Scan ボタンをクリックします。約15〜30秒後、Vulnerabilities 列に検出された脆弱性が「Low」「Medium」「High」「Critical」の4段階で詳細に一覧表示されます。
脆弱性を含むイメージが本番環境へデプロイされるリスクを根本から防ぐため、Project Settings タブに移動して以下の2つのポリシーを有効化します。
- Prevent vulnerable images from running: 遮断の閾値を High または Critical に設定します。この閾値を超えるイメージに対する
docker pull要求は、Harborによって直ちに拒否され、412 Precondition Failedエラーが返されます。 - Automatically scan images on push: レジストリへのイメージプッシュが完了した時点で、自動的にスキャンを実行する仕組みを有効化します。
4. Harborサービスの稼働状況監視
運用中は、以下のコマンドでHarborの全コンテナ群の稼働状態(ヘルスチェック)を確認できます。
cd /opt/harbor
sudo docker compose ps
harbor-core、registry、nginx、harbor-db、trivy-adapter などのすべてのコンテナが Up (healthy) 状態になっている必要があります。セキュリティスキャンのデバッグが必要な場合は、以下のコマンドでリアルタイムログを確認できます。
sudo docker compose logs -f trivy-adapter
この構成を導入することで、データセキュリティが完全に保護された閉域ネットワーク内のコンテナイメージ中継基盤が実現し、外部インターネットへの帯域逼迫問題も完全に解消されます。

