パブリックレジストリの罠:手軽さに潜む深刻なリスク
アプリケーションをコンテナ化することは、貨物コンテナに荷物を詰め込む作業に似ています。各イメージにはソースコードだけでなく、依存ライブラリや最小限の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アカウントでログインします。
- Projects > New Projectをクリックします。プロジェクト名を
fintech-coreとし、アクセスレベルはPrivateのままにします。 - 作成した
fintech-coreプロジェクトを開き、Configurationタブを選択します。 - Automatically scan images on push(プッシュ時の自動スキャン)を有効化します。
- 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の活用です。
fintech-coreプロジェクト内のRobot Accountsタブへ移動し、Add Robot Accountをクリックします。- 名前に
gitlab-runnerと入力し、有効期限(例:90日)を設定します。 - アクセス権限として、このプロジェクトスコープ内のPushとPullのみにチェックを入れます。
- 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時間程度しかかかりませんが、サプライチェーン攻撃の膨大なリスクを未然に排除できます。早期に対策を講じるほど、将来背負う技術的負債を確実に削減できるはずです。
