0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

microCMSのWebhookから中継サーバー経由でGitLabのジョブを実行させる(比較的安全な)方法

Last updated at Posted at 2023-06-08

この記事を書いた背景

microCMSの記事の更新情報をWebhook経由で送信しCI/CDツ⁠ー⁠ルでデプロイする場合に、ソースをGitHubで管理している場合は、GitHub Actionsなどを使うケースが多いと思います。
ただクライアントによってはGitを管理しているのがGitLabだった場合GibLabのCI/CDを使いたいケースがあり、そのために調べたことをメモしておこうと思い書きました。

GitLab CI/CDのパイプラインのトリガーの仕様

以下のように基本的にはGitLabのCI/CDの外部からのパイプラインのトリガーでは、POSTクエリにアクセスのためのTOKENなどを入れる形にする必要があります。

curl --request POST \
     --form token=<token> \
     --form ref=<ref_name> \
     "https://gitlab.example.com/api/v4/projects/<project_id>/trigger/pipeline"

公式Docs - Trigger a pipelineより

micrCMSのWebhookの仕様

各サービスに合わせた設定はあるのですが、2023年5月8日時点ではGitLab用の設定項目はありません。
そうしますとカスタム通知を使用する形となります。
カスタム通知の設定ではPOSTクエリを追加する項目は無く、追加できる項目はカスタムリクエストヘッダーとなります。
以下の公式にもあるようなGETクエリに入れる方法では問題なくジョブを実行できるのですが、GETクエリにトリガーのTOKENを入れるのはセキュリティ的な懸念があります。

curl --request POST \
    "https://gitlab.example.com/api/v4/projects/<project_id>/trigger/pipeline?token=<token>&ref=<ref_name>"

またカスタムリクエストヘッダーにTOKENを入れて更新情報の送信し、それをGitLab単体で上手く処理をするという方法で上手く動くやり方を見つけることができませんでした。

発想の転換 - 中継サーバーの使用

そこで発想を転換して中継サーバー経由で行うという形をしてみました。
以下のような順序で実現できると思いサンプルを作成しテストをしてみました。

  1. microCMSのWebhookのカスタム通知にTOKENなど必要なデータを格納し、一旦中継サーバーに送信させます。
  2. 中継サーバーにて受け取ったデータのカスタムリクエストヘッダーからTOKENref_namegitlab-ci.ymlの中で使用するであろうvariablesなどを抽出します。
  3. 抽出して各データをPOSTクエリにいれてGitLabに送信します。
  4. GitLabでは受け取ったデータをもとにgitlab-ci.ymlで指定したCI/CDのジョブを実行する

具体的な設定例

各サービスの具体的な設定例を記載していきます。

GitLabの設定

GitLabのクラウド版(SaaS)を使用する想定で設定します。

gitlab-ci.ymlの作成

左メニューのビルドのパイプラインエディタにてgitlab-ci.ymlを作り編集します。

stages:          # List of stages for jobs, and their order of execution
  - build
  - test
  - deploy
variables:
  RUN_BUILD_MODE: "test"
test-job:
  stage: test
  script:
    - echo "$RUN_BUILD_MODE"
  rules:
    - if: '$RUN_BUILD_MODE == "test"'
build-job:
  stage: build
  script:
    - echo "$RUN_BUILD_MODE"
  rules:
    - if: '$RUN_BUILD_MODE == "build"'

テスト用としてなので、ビルドが走ったらRUN_BUILD_MODE変数の内容によってジョブを振り分けてRUN_BUILD_MODEの内容をechoするだけの処理になります。

トリガーTOKENの追加

次にGitLab管理画面の設定の左メニューのCI/CDからパイプラインのトリガーで、トリガートークンの追加をしておきます。

micrCMSのWebhookの設定

API設定のWebhookの設定をしていきます。

基本的な設定箇所

Webhookの識別名(任意)中継サーバーのURLシークレットを入力していきます。
シークレットはWebhookリクエストがmicroCMSからのものであることを検証するためのヘッダ値となります。
micrCMSマニュアル | シークレット

カスタムリクエストヘッダーの設定

  1. GitLabのパイプラインのトリガー用トークンのためにKeyをX-GITLAB-TOKENとしてトークンを格納
  2. X-GITLAB-REF-NAMEにjobを実行するブランチ名を格納
  3. X-BUILD-MODEにはgitlab-ci.ymlでjobを実行するstageを振り分けるためにvariablesで設定した変数へ渡す値を格納させる

ここへの値は、buildtestreviewなどとしてgitlab-ci.ymlで処理を振り分けるための変数に入れるための値となります。

中継サーバーの設定

適当なサーバーを用意します。
例としてのサンプルはPHPで記載しておきますが、その他の言語でも良いと思います。

環境変数の追加

micrCMSのシークレット(キー)やGitLabのプロジェクトIDなどあまり外に漏らしたくないものはハードコーディングしないようにします。
環境変数にこれらを追加して使用します。httpd.confphp.ini.htaccessなどに追加して設定します。

例:

setEnv MICROCMS_SECRET_KEY <micrCMSで設定したシークレット>
setEnv GITLAB_PROJECT_ID <GitLabのプロジェクトID>

PHPプログラム

次にPHPの記述をしていきます。

<?php
$data = file_get_contents('php://input');

/*
 * microCMSの環境変数に格納させたシークレットをgetenvで取得
*/ 
$secret = getenv('MICROCMS_SECRET_KEY');

/* 
* 検証するための処理
*/
//署名を生成
$expectedSignature = hash_hmac('sha256', $data, $secret);

// リクエストヘッダーから署名を取得
$signature = $_SERVER['HTTP_X_MICROCMS_SIGNATURE'];

// 署名の検証
if (!hash_equals($signature, $expectedSignature)) {
    //署名の検証がエラーならthrow new Exceptionで処理をストップさせる
    throw new Exception('Invalid signature.');
}

/*
 * microCMSのシグネチャチェックが通った場合処理を実行
 */
//各変数に仮の値を入れておく
$token = 'TOKEN';
$refName = 'REF_NAME';
$buildMode = 'test';
/*
 * GitLabのプロジェクトIDも環境変数に入れて管理
 * 汎用性を高めるならばmicrCMS側のカスタムヘッダに入れる方法が良い
 */
$projectId = getenv('GITLAB_PROJECT_ID');

// headerからTOKENやRefNameを取得し変数に入れておく
$headers = getallheaders();
foreach($headers as $header => $value) {
    switch($header) {
        case "X-GITLAB-TOKEN":
            $token = $value;
            break;
        case "X-GITLAB-REF-NAME":
            $refName = $value;
            break;
        case "X-BUILD-MODE":
            $buildMode = $value;
            break;
        default:
            // 他のヘッダーに対する処理があれば追加する
            break;
    }
}
// microCMSから必要な情報がこない場合はエラー処理
if($token === 'TOKEN' || $refName === 'REF_NAME') {
    throw new Exception('Value Not Set');
}

/*
* curlの準備
*/
$curl = curl_init();

$data = array(
    'token' => $token,
    'ref' => $refName,
    'variables[RUN_BUILD_MODE]' => $buildMode,
);

curl_setopt_array($curl, array(
    CURLOPT_URL => "https://gitlab.com/api/v4/projects/$projectId/trigger/pipeline",
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_POST => true,
    CURLOPT_POSTFIELDS => http_build_query($data),
));

$response = curl_exec($curl);
curl_close($curl);
?>

動作のチェック

記事の作成

microCMSで適当な記事を作成して公開ボタンをクリックします。

ジョブの確認

GibLab側のビルドのパイプライン上でジョブの実行状況が確認できます。

今後の対応

とりあえず中継サーバーを挟むことでCI/CDのジョブを実行することができました。
ただ、microCMSさんは開発の速度がとても速い会社なので、もしかして近くにGitLab用の設定ができるようになるかもしれません。
そうなるとこの方法は無用になるかと思われます。

0
0
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?