Harborによるプライベートコンテナレジストリ構築ガイド:脆弱性の自動スキャンとイメージ署名の実践

Security tutorial - IT technology blog
Security tutorial - IT technology blog

パブリックレジストリの罠:手軽さに潜む深刻なリスク

アプリケーションをコンテナ化することは、貨物コンテナに荷物を詰め込む作業に似ています。各イメージにはソースコードだけでなく、依存ライブラリや最小限のOSそのものが丸ごと内包されています。

多くのチームが手軽さからDocker Hubなどのパブリックレジストリへ直接イメージをプッシュしがちですが、リスクはまさにここから始まります。リポジトリを誤ってPublic設定にしただけで、社内APIキーを含む.envファイルが全世界に晒されてしまう恐れがあります。さらに危険なのは、開発者が素性の知れないベースイメージを誤ってプルし、XMRigなどの暗号資産マイナーやC2サーバーへ接続するバックドアを仕込まれるケースです。

2022年頃、筆者のステージングサーバーでも、開発メンバーがネット上の出所不明なRedisイメージをプルしたことで暗号資産マイナーに感染した経験があります。CPU使用率は常に100%に張り付き、ファンが一晩中唸りを上げていました。このインシデント以来、「社内検証を通過していないイメージは本番環境で一切稼働させない」という鉄則を敷きました。そこで不可欠となるのが、自社で完全に管理できるPrivate Container Registry「Harbor」です。

Harborがシステムを強固に保護する仕組み

Harborは、Cloud Native Computing Foundation(CNCF)傘下のオープンソースプロジェクトです。単にイメージの保存や配信を行うデフォルトのDocker Registryにとどまらず、以下の3つの防御レイヤーを備えたセキュリティゲートウェイとして機能します。

  • Trivyによる自動脆弱性スキャン: HarborにはTrivyスキャナーが標準統合されています。docker pushが実行されると同時にイメージを自動展開し、CVEデータベースと照合します。Criticalレベルの脆弱性が検出された場合、Harborは即座にイメージをロックし、サーバーへのプルをブロックします。
  • Cosignによる電子署名と改ざん防止: ダウンロードされたイメージが配送途中で一切改ざんされていないことを保証します。SigstoreプロジェクトのCosignを採用することで、各コンテナに暗号論的な電子署名が付与されます。KubernetesクラスタやDockerホストは、社内パイプラインの正当な署名を持つイメージのみを実行許可します。
  • RBACとRobot Accountによる権限分離: プロジェクトごとに厳格なアクセス制御が行われます。バックエンドチームがフロントエンドのイメージを誤って操作することはありません。また、CI/CDパイプラインには管理者アカウントを使い回すのではなく、最小権限の専用トークンを払い出します。

Ubuntu上でセキュアなHarborを構築する手順

ステップ1:サーバーの事前準備

最低でも2 vCPU、4GB RAM、40GBストレージ(SSD推奨)が必要です。まずはDocker EngineおよびDocker Compose v2をインストールします。

# リポジトリの更新と依存パッケージのインストール
sudo apt update && sudo apt install -y curl wget ca-certificates gnupg

# 最新版Dockerのインストール
curl -fsSL https://get.docker.com -o get-docker.sh
sudo sh get-docker.sh
sudo systemctl enable --now docker

# バージョン確認
docker compose version

ステップ2:SSL/TLS証明書の作成

Harborはセキュリティ上、デフォルトで暗号化されていないHTTP通信を拒否します。Let’s Encryptや内部認証局(CA)の証明書がない場合は、テスト用に自己署名証明書(オレオレ証明書)を生成します。

sudo mkdir -p /data/cert
cd /data/cert

# 4096ビットのPrivate Keyを生成
sudo openssl genrsa -out registry.example.com.key 4096

# 有効期限365日のSSL証明書を生成
sudo openssl req -x509 -new -nodes -sha512 -days 365 \
  -subj "/C=VN/ST=Hanoi/L=Hanoi/O=DevOps/CN=registry.example.com" \
  -key registry.example.com.key \
  -out registry.example.com.crt

# Dockerデーモンがこの自己署名証明書を信頼するよう設定
sudo mkdir -p /etc/docker/certs.d/registry.example.com
sudo cp /data/cert/registry.example.com.crt /etc/docker/certs.d/registry.example.com/ca.crt
sudo systemctl restart docker

ステップ3:Harborの設定と起動

GitHub Releasesから公式のオフラインインストーラーをダウンロードします。

cd /tmp
wget https://github.com/goharbor/harbor/releases/download/v2.10.0/harbor-offline-installer-v2.10.0.tgz
tar -xzvf harbor-offline-installer-v2.10.0.tgz
cd harbor
cp harbor.yml.tmpl harbor.yml

harbor.ymlを開き、重要なパラメータを編集します。

hostname: registry.example.com

http:
  port: 80
https:
  port: 443
  certificate: /data/cert/registry.example.com.crt
  private_key: /data/cert/registry.example.com.key

harbor_admin_password: StrongPassword2026!#
data_volume: /data/harbor

Trivyスキャナー統合フラグを付けてインストールスクリプトを実行します。

sudo ./install.sh --with-trivy

2〜3分後、docker psコマンドでステータスを確認します。Harborの主要な9つのコンテナ(registry、core、trivy-adapter、postgresql、redisなど)が正常に稼働していることが確認できます。

ステップ4:脆弱性イメージのブロックポリシーを設定

ブラウザでhttps://registry.example.comにアクセスし、adminアカウントでログインします。

  1. Projects > New Projectをクリックします。プロジェクト名をfintech-coreとし、アクセスレベルはPrivateのままにします。
  2. 作成したfintech-coreプロジェクトを開き、Configurationタブを選択します。
  3. Automatically scan images on push(プッシュ時の自動スキャン)を有効化します。
  4. Prevent vulnerable images from running(脆弱性イメージの実行抑止)を有効化し、ブロック閾値をHighまたはCriticalに設定します。

この設定が最終防壁となります。万が一開発者が既知の脆弱性を含むイメージを誤ってプッシュしても、本番サーバーからのdocker pullはHarborによって即座に拒否されます。

ステップ5:Cosignによるコンテナイメージの署名

脆弱性のブロックだけでは不十分です。デプロイ経路での改ざんを防ぐため、Cosignを使用してイメージに電子署名を付与します。

# Cosignバイナリのインストール
wget https://github.com/sigstore/cosign/releases/download/v2.2.3/cosign-linux-amd64 -O cosign
chmod +x cosign && sudo mv cosign /usr/local/bin/

# 署名用キーペアの生成(パスフレーズの入力を求められます)
cosign generate-key-pair
# このコマンドで秘密鍵(cosign.key)と公開鍵(cosign.pub)の2ファイルが生成されます

# Harborへログイン
docker login registry.example.com

# テスト用イメージのタグ付けとプッシュ
docker tag nginx:alpine registry.example.com/fintech-core/web:v1.0
docker push registry.example.com/fintech-core/web:v1.0

# プッシュしたイメージに署名
cosign sign --key cosign.key registry.example.com/fintech-core/web:v1.0

# 電子署名の検証
cosign verify --key cosign.pub registry.example.com/fintech-core/web:v1.0

verifyコマンドが正しいSHA-256ダイジェストを含むペイロードを返せば、イメージがビルド時の完全なオリジナル状態であることが証明されます。

ステップ6:Robot AccountによるCI/CDへの最小権限付与

CI/CDスクリプト内で個人アカウントや管理者パスワードを使用することは厳禁です。パイプラインログからトークンが漏洩した場合、レジストリ全体の制御権を奪われる危険があります。ベストプラクティスはRobot Accountの活用です。

  1. fintech-coreプロジェクト内のRobot Accountsタブへ移動し、Add Robot Accountをクリックします。
  2. 名前にgitlab-runnerと入力し、有効期限(例:90日)を設定します。
  3. アクセス権限として、このプロジェクトスコープ内のPushとPullのみにチェックを入れます。
  4. Saveをクリックし、表示されたSecret Tokenを直ちに保存します。トークンは一度しか表示されません。

Harbor 2.xでは、プロジェクト用Robot Accountのユーザー名にプロジェクト名のプレフィックスが付与されます。CI/CDランナーからは以下の構文でログインします。

docker login registry.example.com -u 'robot$fintech-core+gitlab-runner' -p 'YOUR_SECRET_TOKEN'

おわりに

Harborを導入する目的は、単なるDockerイメージの保管場所を作ることにとどまりません。サーバー上で実行されるコードを完全に掌握し、制御するための強固なセキュリティシールドを手に入れることにあります。

TrivyとCosignを組み合わせたHarbor環境の構築には2時間程度しかかかりませんが、サプライチェーン攻撃の膨大なリスクを未然に排除できます。早期に対策を講じるほど、将来背負う技術的負債を確実に削減できるはずです。

Share: