Azure DevOps Services |Azure DevOps Server |Azure DevOps Server 2022 |Azure DevOps Server 2020
Azure Pipelines テンプレート を使用すると、YAML パイプラインで再利用可能なコンテンツ、ロジック、およびパラメーターを定義できます。 この記事では、次の方法でテンプレートを使用してパイプラインのセキュリティを強化する方法について説明します。
- 悪意のあるコード侵入を防ぐためにパイプラインの外部構造を定義する。
- 資格情報のスキャンなどのタスクを実行する手順を自動的に含めます。
- Azure Pipelines の基本的なセキュリティ フレームワークを形成し、すべてのパイプライン構造とコンポーネントに適用される 、保護されたリソースに対するチェックの適用に役立ちます。
この記事は、Azure Pipelines のセキュリティ対策を実装するのに役立つシリーズの一部です。 詳細については、「 Azure Pipelines のセキュリティ保護」を参照してください。
[前提条件]
| カテゴリ | 必要条件 |
|---|---|
| Azure DevOps | - Azure DevOps をセキュリティで保護し、Azure Pipelines を セキュリティで保護する方法に関するページの推奨事項を実装します。 - YAML と Azure Pipelines に関する基本的な知識。 詳細については、「最初のパイプラインの作成」を参照してください。 |
| アクセス許可 | - パイプラインのアクセス許可を変更するには: プロジェクト管理者グループのメンバー。 - 組織のアクセス許可を変更するには: プロジェクト コレクション管理者グループのメンバー。 |
テンプレートを含める、拡張する
Azure Pipelines には、および extends テンプレートが用意されています。
includesテンプレートには、C++ の#includeと同様に、テンプレートを参照する外部ファイルにテンプレートのコードが直接含まれています。 次のパイプラインの例では、 セクションにstepsテンプレートを挿入します。steps: - template: templates/include-npm-steps.ymlextendsテンプレートは、パイプラインの外側の構造を定義し、対象を絞ったカスタマイズのための特定のポイントを提供します。 C++ のコンテキストでは、extendsテンプレートは継承に似ています。
extends テンプレートを使用する場合は、includesを使用して、テンプレートと最終的なパイプラインの両方で一般的な構成を行うこともできます。 詳細については、「 再利用可能で安全なプロセスのためにパイプラインで YAML テンプレートを使用する」を参照してください。
テンプレートを拡張する
最も安全なパイプラインの場合は、まず extends テンプレートを使用します。 これらのテンプレートは、パイプラインの外部構造を定義し、悪意のあるコード侵入を防ぐのに役立ちます。
次の例は、 template.ymlという名前のテンプレート ファイルを示しています。
parameters:
- name: usersteps
type: stepList
default: []
steps:
- ${{ each step in parameters.usersteps }}:
- ${{ step }}
次のパイプラインの例では、 template.yml テンプレートを拡張します。
# azure-pipelines.yml
resources:
repositories:
- repository: templates
type: git
name: MyProject/MyTemplates
ref: refs/tags/v1
extends:
template: template.yml@templates
parameters:
usersteps:
- script: echo This is my first step
- script: echo This is my second step
ヒント
extendsテンプレートを設定するときは、特定の Git ブランチまたはタグに固定して、破壊的変更が既存のパイプラインに影響しないようにすることを検討してください。 前の例では、この機能を使用しています。
パイプラインのセキュリティ機能
YAML パイプライン構文には、いくつかの組み込み保護が含まれています。
Extends テンプレートは、パイプラインのセキュリティを強化するために使用を強制できます。 次のいずれかの制限を実装できます。
ステップ ターゲット
指定した手順を、ホストではなくコンテナーで実行するように制限できます。 コンテナー内のステップはエージェント ホストにアクセスできないため、エージェントの構成を変更したり、後で実行するために悪意のあるコードを残したりすることはできません。
たとえば、許可されていないソースからパッケージを取得したり、コードやシークレットを外部の場所にアップロードしたりできないように、コンテナーでユーザー ステップを実行してネットワークにアクセスできないようにすることができます。
次のパイプライン例では、ホスト ネットワークを変更する可能性があるステップをエージェント ホスト上で実行し、その後、ネットワーク アクセスを制限するコンテナー内のステップを実行します。
resources:
containers:
- container: builder
image: mysecurebuildcontainer:latest
steps:
- script: echo This step runs on the agent host
- script: echo This step runs inside the builder container
target: builder
タイプ セーフ パラメーター
パイプラインを実行する前に、テンプレートとそのパラメーターは定数に変換されます。 テンプレート パラメーター 入力パラメーターのタイプ セーフを強化できます。
次のテンプレート例では、パラメーターは、文字列を許可するのではなく、特定の選択肢を列挙することで、使用可能なパイプライン プールオプションを制限します。
# template.yml
parameters:
- name: userpool
type: string
default: Azure Pipelines
values:
- Azure Pipelines
- private-pool-1
- private-pool-2
pool: ${{ parameters.userpool }}
steps:
- script: echo Hello world
テンプレートを拡張するには、パイプラインで使用可能なプールの選択肢のいずれかを指定する必要があります。
# azure-pipelines.yml
extends:
template: template.yml
parameters:
userpool: private-pool-1
エージェント ログ コマンドの制限
ユーザー ステップは、標準出力に出力される特別な形式の文字列である ログ コマンドを使用してサービスを要求します。 ログ 記録コマンドがユーザー ステップに提供するサービスを制限できます。
restricted モードでは、アーティファクトのアップロードやテスト結果の添付などのほとんどのエージェント サービスは、コマンドのログ記録には使用できません。
次の例では、 target プロパティは、成果物の発行タスクが失敗するように、発行成果物を制限するようにエージェントに指示します。
- task: PublishBuildArtifacts@1
inputs:
artifactName: myartifacts
target:
commands: restricted
ログ 記録コマンドの変数
setvariable コマンドはrestricted モードで引き続き許容されるため、REST API を介して取得された未解決の問題など、ユーザーが指定したデータを出力するタスクは、インジェクション攻撃に対して脆弱になる可能性があります。 悪意のあるユーザー コンテンツは、後続のタスクに環境変数としてエクスポートする変数を設定し、エージェント ホストを侵害する可能性があります。
このリスクを軽減するには、 setvariable ログ コマンドを使用して、設定可能な変数を明示的に宣言します。
settableVariablesで空のリストを指定した場合、すべての変数設定は許可されません。
次の例では、 settableVariables を expectedVar に制限し、変数の先頭に ok を付けます。 タスクは、 BadVarと呼ばれる別の変数を設定しようとして失敗します。
- task: PowerShell@2
target:
commands: restricted
settableVariables:
- expectedVar
- ok*
inputs:
targetType: 'inline'
script: |
Write-Host "##vso[task.setvariable variable=BadVar]myValue"
条件付きステージまたはジョブの実行
ステージとジョブは、特定の条件下でのみ実行するように制限できます。 次の例では、制限付きコードが main ブランチに対してのみビルドされるようにします。
jobs:
- job: buildNormal
steps:
- script: echo Building the normal, unsensitive part
- ${{ if eq(variables['Build.SourceBranchName'], 'refs/heads/main') }}:
- job: buildMainOnly
steps:
- script: echo Building the restricted part that only builds for main branch
構文の変更
Azure Pipelines テンプレートには、YAML 構文を反復処理して変更する柔軟性があります。 イテレーションを使用すると、特定の YAML セキュリティ機能を適用できます。
テンプレートでは、承認されたタスクのみを実行できるように、ユーザー ステップを書き換えることもできます。 たとえば、テンプレートはインライン スクリプトの実行を防ぐことができます。
次のテンプレート例では、スクリプト ステップの種類 bash、 powershell、 pwsh、および script が実行されないようにします。 スクリプトの完全なロックダウンのために、 BatchScript と ShellScriptをブロックすることもできます。
# template.yml
parameters:
- name: usersteps
type: stepList
default: []
steps:
- ${{ each step in parameters.usersteps }}:
- ${{ if not(or(startsWith(step.task, 'Bash'),startsWith(step.task, 'CmdLine'),startsWith(step.task, 'PowerShell'))) }}:
- ${{ step }}
# The following lines replace tasks like Bash@3, CmdLine@2, PowerShell@2
- ${{ else }}:
- ${{ each pair in step }}:
${{ if eq(pair.key, 'inputs') }}:
inputs:
${{ each attribute in pair.value }}:
${{ if eq(attribute.key, 'script') }}:
script: echo "Script removed by template"
${{ else }}:
${{ attribute.key }}: ${{ attribute.value }}
${{ elseif ne(pair.key, 'displayName') }}:
${{ pair.key }}: ${{ pair.value }}
displayName: 'Disabled by template: ${{ step.displayName }}'
上記のテンプレートを拡張する次のパイプラインの例では、スクリプトステップは削除され、実行されません。
# azure-pipelines.yml
extends:
template: template.yml
parameters:
usersteps:
- task: MyTask@1
- script: echo This step is stripped out and not run
- bash: echo This step is stripped out and not run
- powershell: echo "This step is stripped out and not run"
- pwsh: echo "This step is stripped out and not run"
- script: echo This step is stripped out and not run
- task: CmdLine@2
displayName: Test - stripped out
inputs:
script: echo This step is stripped out and not run
- task: MyOtherTask@2
テンプレートの手順
テンプレートは、資格情報のスキャンや静的コード チェックなどを行うために、パイプラインにステップを自動的に含めることができます。 次のテンプレートは、すべてのジョブのユーザー ステップの前後にステップを挿入します。
parameters:
jobs: []
jobs:
- ${{ each job in parameters.jobs }}:
- ${{ each pair in job }}:
${{ if ne(pair.key, 'steps') }}:
${{ pair.key }}: ${{ pair.value }}
steps:
- task: CredScan@1
- ${{ job.steps }}
- task: PublishMyTelemetry@1
condition: always()
テンプレートの強制
セキュリティ メカニズムとしてのテンプレートの有効性は、適用に依存します。 テンプレートの使用を強制するための重要な制御ポイントは、 保護されたリソースです。
エージェント プールやリポジトリなどの保護されたリソースに対して、承認とチェックを構成できます。 例については、「リポジトリ リソース チェックの追加」を参照してください。
必要なテンプレート
特定のテンプレートの使用を強制するには、リソースのサービス接続に 必要なテンプレート チェックを構成します。 このチェックは、パイプラインがテンプレートから拡張されている場合にのみ適用されます。
パイプライン ジョブを表示すると、チェックの状態を監視できます。 パイプラインが必要なテンプレートから拡張されていない場合、チェックは失敗します。
必要なテンプレートを使用すると、チェックに合格します。
たとえば、次の params.yml テンプレートは、それを拡張するすべてのパイプラインで参照する必要があります。
# params.yml
parameters:
- name: yesNo
type: boolean
default: false
- name: image
displayName: Pool Image
type: string
default: ubuntu-latest
values:
- windows-latest
- ubuntu-latest
- macOS-latest
steps:
- script: echo ${{ parameters.yesNo }}
- script: echo ${{ parameters.image }}
次のパイプライン例では、 params.yml テンプレートを拡張し、承認を求めます。 パイプラインエラーを示すには、params.ymlへの extends 参照をコメント アウト します。
# azure-pipeline.yml
resources:
containers:
- container: my-container
endpoint: my-service-connection
image: mycontainerimages
extends:
template: params.yml
parameters:
yesNo: true
image: 'windows-latest'