Azure DevOps PipelineとDockerの統合
前提条件
Linux OS システム
Azure DevOpsのビルドシステム
Linux エージェントにインストールされた JDK
DigiCert® Software Trust Manager Accessの設定(下記参照)
Dockerのインストール
DigiCert® Software Trust Manager PKCS11ライブラリ (クライアントツール)
Dockerのバージョンは、20.10.7です。
注記
クライアントツールは、DigiCert Oneポータルの DigiCert® Software Trust Manager -> リソース -> クライアントツールでダウンロードすることができます。
Software Trust Managerのセットアップ
クライアントツールを使用し、DigiCert® Software Trust Managerに接続して操作を行うには、DigiCert OneでのSTMへのアクセス権がなければなりません。これがない場合は、DigiCert Oneの管理者に連絡してログインを要求してください。
実行権限
SMで操作を実行するためにクライアントツールを使用できるように、ユーザーに正しい権限を選択しなければなりません。また、コンプライアンス上必要なため、管理者はユーザーの多要素認証を有効にすることも重要です。
アカウントマネージャで、そのユーザーに対して、少なくともユーザーの表示と組織の表示を有効にします。DigiCert® Software Trust Managerでは、すべての権限を有効にします。
クライアント認証用証明書のセットアップ
クライアントツールと PKCS11ライブラリが操作を行うには、DigiCert® Software Trust Managerとの接続と認証が必要です。接続と認証には、クライアント認証証明書が役立ちます。DigiCert Oneプラットフォームで、アカウントマネージャ-> アクセス -> クライアント認証で、ユーザー用の証明書を生成できます。
To generate a certificate for the user:
Sign in to DigiCert ONE.
Navigate to the Profile icon > Admin Profile > Authentication certificates > Create authentication certificate.
重要
証明書を生成した後に表示される情報には再アクセスできないため、後で使用できるように、画面で指定されているすべての情報を記録しておかなければなりません。
APIトークンのセットアップ
API token setup
クライアントツールやPKCS11ライブラリの操作を行うために、STMでログインを許可するAPIトークンが必要です。これは、DigiCert Oneでアカウントマネージャ -> アクセス -> APIトークンに移動し、次にAPIトークンの作成を選択して行うことができます。
To generate an API token:
Sign in to DigiCert ONE.
Navigate to the Profile icon > Admin Profile > API tokens > Create API token.
重要
APIトークンは作成後一度しかアクセスできないため、後で使用できるように詳細を保存しておかなければなりません。
Dockerのコンテントトラストのセットアップ
Dockerコンテントトラストは、Linuxシステム上でしかDigiCert STMを動作させません。また、生成されたリポジトリとターゲットキーは、セットアップされたマシンに残ります(PKCS11で管理することはできません)。
重要
Docker Content Trustがセットアップされたマシンとユーザーで、Azure DevOpsエージェントが実行されるように設定を行ってください。リポジトリとターゲットキーはセットアップされたマシンに残り、移植することはできません。
PKCS11ライブラリのセットアップ
Linux OS用の共有ライブラリをダウンロードし、STM プロバイダを PKCS11に登録します。これは、DigiCert Oneプラットフォームの DigiCert® Software Trust Manager -> リソース -> クライアントツールで見つけることができます。ライブラリファイルの名前を変更し、Dockerがピックアップできるように特定の場所にコピーします。
Sign in to DigiCert ONE.
Navigate to DigiCert® Software Trust Manager > Resources > Client tool repository.
Downloading the shared library for the Linux OS.
Rename the library file and copy to a specific location so that Docker can pick it up.
Linuxユーザーの場合:smpkcs11.so を libykcs11.so に名前を付け替え、/usr/local/lib にコピーしてください。
Docker ルートキーのセットアップ
Dockerのルートキーを生成する必要があります。ルートキーには、"CN=root"が含まれる証明書が必要です。以下の例では、java に付属している keytooLを使って、STM 上で生成しています。
まず、これらのパラメータを含む PKCS11設定ファイルを作成する必要があります。
name=signingmanager library="<Path to PKCS11 shared library file(smpkcs11.so)>" slotListIndex=0
以下に示す例では、この設定はPkcs11properties.cfg というファイルに作成されます。
次に、keytool コマンドを発行して、ルートキーを生成することができます。
keytool -keystore NONE -storetype PKCS11 -storepass NONE -providerClass sun.security.pkcs11.SunPKCS11 -providerArg <Path to pkcs11properties.cfg> -genkeypair -keyalg EC -keysize 256 -dname “CN=root” -alias docker_root_key
重要
Dockerの鍵はRSA鍵ではなく、ECDSA 256鍵である場合にのみ動作します。
Docker委任キーのセットアップ
Docker delegation key setup
画像に署名するために使用する、Docker用の委任キーと証明書を生成します。これは、STMのDigiCert OneポータルまたはSTM CLIを使用して行うことができます。
smctl keypair generate ecdsa <Delegation Key Alias> --cert-alias=<Delegation Cert Alias> --cert-profile-id=<Certificate Profile ID> --generate-cert=true --key-type=PRODUCTION
注記
STM CLI (smctl) ツールは、パイプラインの SM 環境変数 (後述) を設定するまでは動作しません。委任キーが dockerで動作するためには、ECDSA 256ビットキーでなければなりません。
鍵ペア名と証明書名は一意の入力でなければなりません(ポータル上に既に存在することはできません)。
証明書プロファイルIDは DigiCert Oneポータルの DigiCert® Software Trust Manager > 証明書 > 証明書管理 > 証明書プロファイルで取得できます。証明書の生成に使用するプロファイルを選択します(プロファイルカテゴリは生成された鍵タイプに基づき、テスト/プロダクションでなければなりません)。
委任キーをDocker signerとして追加する
Dockerリポジトリを初期化し、リポジトリの鍵を内部で生成し、以前に生成した委任キーをリポジトリ用の委任として追加しなければなりません。これを行うには、Dockerの委任キー用に生成された証明書をDigiCert Oneポータルからダウンロードし、Docker上の委任として追加できるようにします。
Secure Signing Manager > 証明書管理 > 証明書と進み、前のステップで使用したエイリアスを持つ証明書を選択します。詳細ページから証明書をダウンロードし、その情報をコマンドを使用します。
docker trust signer add --key <Docker Delegation Key.crt from previous step> "<Name of the delegation>" <Registry URL>/<Repository Name>
例:
docker trust signer add --key digicert_delegation.crt "Digicert" digicert/hello-digicert
その後、委任を使って検査することができます。
docker trust inspect –pretty <Registry URL>/<Repository Name>
コンテントトラストが有効な状態で画像のプッシュが行われると、dockerは委任キーを使ってタグに署名し、トラストデータをリモートの公証サーバにプッシュします。コンテントトラストが有効な状態で画像のプル/ランが行われると、画像が検証されます。
Azure DevOps パイプラインとの統合
パイプライン用のエージェントのセットアップ
Docker Signingパイプラインのエージェントとして使用できるのは、Linuxノードのみです。これは、Dockerコンテントトラストがセットアップされたのと同じLinuxマシンに接続するセルフホストエージェントを使用しなければなりません。Azure DevOpsで、ノードがLinuxマシンと dockerココンテントトラストがセットアップされたユーザーに接続するように セットアップされていることを確認してください。この例では、default という名前のエージェントプールがセットアップされ、その上に1つのLinuxノードが Dockerコンテンツのトラストがセットアップされた同じマシンとユーザーに接続しています。
pool: name: 'default' demands: agent.os -equals Linux
パイプライン用の環境変数の設定
Environment variables setup for pipeline
クライアントツールがDigiCert® Software Trust Managerと接続してサービスを提供するためには、これらの環境変数が必要です。これらは、以下の例のようにパイプラインの一部である環境変数として統合することもできますし、OS環境レベルで設定することもできます。
変数:
- name: SM_CLIENT_CERT_PASSWORD value: ********* - name: SM_CLIENT_CERT_FILE value: <Path to Client Auth Cert File> - name: SM_HOST value: https://clientauth.one.digicert.com - name: SM_API_KEY value: <API Token> - name: PKCS11_CONFIG value: <Path to pkcs11properties.cfg> #Remove the following variable if you want to enable trust for specific actions - name: DOCKER_CONTENT_TRUST value: 1
これらの環境変数の値については、以下に説明します。SM_CLIENT_CERT_PASSWORD は、クライアント認証の設定により取得されたパスワードです。SM_CLIENT_CERT_FILEは、クライアント認証の設定からダウンロードされた証明書です。SM_HOSTは、クライアント認証のある、DigiCert Oneポータルへのパスです。
注記
DigiCert ONE 製品のセルフホスト型インスタンスに接続しない限り、ほとんどの場合、このパスはそのまま残ります。SM_API_KEYは、APIトークン設定中に生成されるAPIトークンです。DOCKER_CONTENT_TRUST は、パイプライン内の操作に対して、画像署名と検証を強制する環境変数です。ここで定義されている場合、Docker 操作に対して特に無効化しない限り、パイプラインのすべての操作に適用されます。この環境変数は、特定の操作に対してのみ設定することもできます。
コンテントトラスト頼なしでのDockerビルド
Docker build without content trust
他のベース画像の上にビルドされた画像の場合、ベース画像に関連するトラストデータがないことがあります。パイプライン全体に対して DOCKER_CONTENT_TRUST 環境変数が設定されている場合、ベース画像の1つにトラストデータがないために、ビルドステップが失敗してしまいます。このように、特定のビルド操作に対して無効化することができます。
- script: docker build -t <Registry URL>/<Repository name>:<Tag> --disable-content-trust=true <Path to Directory containing Dockerfile> displayName: 'Docker build'
Docker プッシュ署名入りタグ
Docker push signed tags
DOCKER_CONTENT_TRUSTが環境変数としてパイプライン全体に設定されている場合に、Azure DevOpsのパイプラインステップで署名付きタグをプッシュする例:
- script: docker push <Registry URL>/<Repository name>:<Tag> displayName: 'Docker Sign and Push'
パイプライン全体に環境変数 DOCKER_CONTENT_TRUST を設定しているため、PKCS11ライブラリを使い STM からの委譲キーで自動的に署名が行われます。
Azure DevOpsのパイプラインステップで、特定の操作のみ DOCKER_CONTENT_TRUSTを有効にして署名付きタグをプッシュする例:
- script: DOCKER_CONTENT_TRUST=1 docker push <Registry URL>/<Repository name>:<Tag> displayName: 'Docker Sign and Push’
注記
タグがプッシュ操作で指定されていない場合、画像は署名されず、トラストメタデータは公証サーバにプッシュされません。
署名付き画像のプルと検証
環境変数としてパイプライン全体でDOCKER_CONTENT_TRUSTを有効にすると、任意の署名付き画像のDocker pull/runが自動的にその画像を検証するようになります。この操作は、Docker Content Trustがセットアップされているマシンに限定されるものではありません。どのマシンでも行うことができます。
- script: docker pull <Registry URL>/<Repository name>:<Tag> displayName: 'Docker Pull & Verify'
DOCKER_CONTENT_TRUSTがパイプライン全体に対して環境変数として有効になっていない場合、図のように特定の操作に対してのみ有効化することができます。
- script: DOCKER_CONTENT_TRUST=1 docker pull <Registry URL>/<Repository name>:<Tag> displayName: 'Docker Pull & Verify'
サンプルパイプライン
trigger: - main pool: name: 'default' demands: agent.os -equals Linux variables: - name: SM_CLIENT_CERT_PASSWORD value: gxmiK9Oe72Pn - name: SM_CLIENT_CERT_FILE value: "/home/siddharth/smtools/local_pkcs12.p12" - name: SM_HOST value: https://clientauth.one.digicert.com - name: SM_API_KEY value: 01ff018928e385329550b6e7a7_9b38fc5fbb4ef99ceeb7d61e6984107efa4283583cb7a64f5e292582cd3ed848 - name: PKCS11_CONFIG value: "/home/siddharth/smtools/pkcs11properties.cfg" - name: DOCKER_CONTENT_TRUST value: 1 steps: - task: Gradle@2 displayName: 'Gradle Build' inputs: workingDirectory: '' gradleWrapperFile: 'gradlew' gradleOptions: '-Xmx3072m' javaHomeOption: 'path' jdkDirectory: '/usr/lib/jvm/java-11-openjdk-amd64' jdkArchitectureOption: 'x64' publishJUnitResults: true testResultsFiles: '**/TEST-*.xml' tasks: 'build' - script: docker build -t siddharthsrinivas/hello-world:$(Build.BuildId) --disable-content-trust=true $(System.DefaultWorkingDirectory)/ displayName: 'Docker build' - script: | docker tag siddharthsrinivas/hello-world:$(Build.BuildId) siddharthsrinivas/hello-world:latest docker push siddharthsrinivas/hello-world:$(Build.BuildId) docker push siddharthsrinivas/hello-world:latest displayName: 'Docker Sign and Push' - script: | docker image rm siddharthsrinivas/hello-world:$(Build.BuildId) docker image rm siddharthsrinivas/hello-world:latest docker pull siddharthsrinivas/hello-world:$(Build.BuildId) docker pull siddharthsrinivas/hello-world displayName: 'Docker Verify'