これ何?
- Jenkinsのパラメータ付きビルドをAPI経由で実行しようとした時にCORSでハマった話です
- ググったのですが、まとまった記事がなかなか見つからなかったので記事にまとめてみました
- まぁ、CORSは常識ですよ!お前、勉強不足だよね!って言われてもしょうがない記事です
前提
curlでの実行は確認済み
以下、curlのコマンドです。
下記、コマンドにてJenkinsのパラメータビルドができることは確認済みでした。
http://hoge:8080/job/hoge_job
がJenkinsのパラメータ付きビルドのURL
です
$ curl -X POST \
-u JENKINS_USER:JENKINS_TOKEN \
http://hoge:8080/job/hoge_job/buildWithParameters?\
github_url=*
参考
JenkinsジョブをAPI経由でパラメータ付きビルドする
Node.jsのaxiosを採用
クライアントはNode.jsのaxiosを採用しました。
axiosはこちら
下記、postStartJobというメソッドを使って、jenkinsのjobを起動します。
// JenkinsのJobを開始する
postStartJob(data) {
return axios.post('http://hoge:8080/job/hoge_job/buildWithParameters', {}, {
params: {
github_url: data.GithubUrl,
},
auth: {
username: JENKINS_USER,
password: JENKINS_TOKEN,
},
});
}
現象😢
postStartJobメソッドを実行したところ下記エラーが発生しました。
うーん困った😓
Access to XMLHttpRequest at
'http://hoge:8080/job/technical_analysis_staging/buildWithParameters?
github_url=*' from origin 'http://fuga:8082' has been blocked by CORS policy:
Request header field authorization is not allowed
by Access-Control-Allow-Headers in preflight response.
原因
原因は2つあります。
原因1. Same-Origin Policy
Jenkinsのデフォルト設定だと、Same-Origin Policy(日本語では同一生成元ポリシー)が適用されて、違うドメインからのアクセスを許可していないから。
CORSまとめを参考にしました。@tomoyukilabsさん、ありがとうございます!
Same-Origin Policyとは、1995年Netscape社によってJavaScriptと同時にウェブブラウザに導入されたセキュリティ上の考え方で、コンテンツがブラウザに来る源泉(origin)に基づいて整理して、外部からのアクセスを防ぐというポリシーです。
WIKI より参照
つまり、今回、Jenkinsはhttp://hoge
でクライアントは http://fuga
で違うドメインであることから、Jeninsはアクセスを拒否したっていうわけです。
原因2. pre-flight
ライブラリのaxiosは異なるドメインに対してリクエストする時に、OPTIONSメソッドでpre-flightのリクエストを送信します。
axiosはデフォルトでapplication/json
フォーマットを使用しており、application/json
の場合、常にpre-flightされる仕様になっているとのことです。
https://github.com/axios/axios/issues/475#issuecomment-253968037 を参考
pre-flightとは、 CORS プロトコルが理解されているかどうかを確認する CORS リクエストとのことです。つまり、自分の理解だと、CORSがちゃんと設定できているドメインか事前にチェックするよ!
って確認する作業と理解しました。
https://developer.mozilla.org/ja/docs/Glossary/Preflight_request を参考
解決方法
Cors Filter PluginをJenkinsにインストールしてCORSの設定をする!
この解決方法で無事にJenkinsのパラメータビルドがAPI経由で実行できるようになりました
Cors Filter Pluginのインストール
プラグイン管理画面でcors
と検索してインストール
CORSの設定
システム設定より以下、設定する。
- Access-Control-Allow-Origins
- *
- Access-Control-Allow-Methods
- GET, OPTIONS, POST
- Access-Control-Allow-Headers
- authorization, content-type
Access-Control-Allow-Origins
- 許可するドメインを指定します。
*
の場合は全てのドメインからアクセス可能ということです。 - Jenkins側でアクセストークンが必要な設定になっているので特に問題ないかと思い、
*
を設定しました。本番環境では場合は、ちゃんと設定しようと思います。
Access-Control-Allow-Methods
- 異なるドメインから許可するメソッドを指定します。
- APIでメソッドは、GET, OPTIONS, POSTの3つなので、これらを許可します。 OPTIONSは、pre-flightで使うメソッドなので必須です。
Access-Control-Allow-Headers
- 異なるドメインから許可するヘッダーを指定します。
-
authorization
は、認証情報のヘッダーです。これがあることで、JENKINS_USER:JENKINS_TOKEN
の認証を通すことができます。
まとめ
- Same-Origin Policy があるので、同一ドメイン以外からAPIを実行する時にはCORSの設定が必要になる
- Node.jsのaxiosは、pre-flightを実行するので、OPTIONSメソッドを許可する必要がある
- Jenkinsの認証情報を送るには、
authorization
ヘッダーを許可する必要がある
あー、半日くらいハマったので疲れました
でも解決できてよかったです。まだまだ未熟だ。。。