ELB == SSLアクセラレータ ==> Jenkins で動く環境を構築する

AWSでSSL使う場合はACMが便利だったのでいろんなところで使っていますが、
あまり考えないでJenkins環境にも適用したらちょっとハマったところがあったのでメモ。

## 環境

.NETのビルドが必要だったのでWindows Serverで。
Jenkinsはそろそろ2系のパイプラインに置き換えたいけど諸事情でゴニョゴニョ
IISを挟んでいるのは途中の通信をいじりたいため、Linuxだったら多分nginxとかでいいと思う。

| | |
| ---- | ---- |
| OS | Windows Server 2012 R2 |
| Web | IIS |
| Jenkins | 1.651 |


## 通信経路のイメージ

`ELB - https/443` ==> `IIS - http/80` ==> `Jenkins - http/80以外`

通信に手を入れるのでELBとJenkinsの間にWEB(IIS)を挟んでいる。


## ハマるところまでの手順メモ

- Jenkinsのインストール
    - Windowsサービスとしてインストールする
    - サービス設定
        1. Jenkinsの設定 > システムの設定 > Jenkinsの位置 > Jenkins URL
            - Jenkinsの処理結果URL諸々に使用されるので、ELBで公開しているhttpsのURLを指定
            - `https://some-domain/` など
        2. Jenkinsの設定 > グローバルセキュリティの設定
            - セキュリティを有効化 にチェック、認証方法は任意(ユーザーデータベースは確実に使える)
            - 認証がなければダッシュボード辺りまでは行けるかもしれないけど、他の機能で引っかかるのであまり変わらない
- IISインストール
    - Application Request Routingをインストール
        - Jenkinsへの転送設定とヘッダ書換に使用
    - ポート80番でWebサイトを構築
        - うちはvhostでいろいろ使ってたから独自に作ったけど、他に用途がなければ Default Web Site 使ってもOK
    - IISマネージャから転送設定
        1. サイト > ↑で作成したサイト > IIS > URL 書き換え
        2. 規則の追加 > 受信規則 > 空の規則
            - 名前: to-jenkins-routing(一意であればよい)
            - 要求されたURL: パターンに一致する。
            - 使用: 正規表現
            - パターン: `.*`
            - アクションの種類: 書き換え
            - アクションのプロパティ: `http://localhost:1080/{R:0}` (1080でJenkins立てている場合)


```xml:web.config
<configuration>
  <system.webServer>
    <rewrite>
      <rules>
        <rule name="to-jenkins-routing" stopProcessing="true">
          <match url=".*" negate="false" />
          <conditions logicalGrouping="MatchAll" trackAllCaptures="false" />
          <action type="Rewrite" url="http://localhost:1080/{R:0}" />
        </rule>
      </rules>
    </rewrite>
  </system.webServer>
</configuration>
```

## 何にハマったか(事象)

これでhttpsでログイン画面は表示できた。
ログインすると Chrome さんから `ERR_CONNECTION_REFUSED` とか怒られた。


## 何が起こっているか(原因?)

多分 [stackoverflow](https://stackoverflow.com/questions/23703523/jenkins-does-not-redirect-to-https) のこんな感じ。

> Except when Jenkins tries to redirect (e.g after login, after clicking `Build`, etc). Whenever Jenkins tries to redirect to any page, it sends me to `http://` page (not `httpS://`)

ログイン時にリダイレクトが発生していて、それが `http://` に向いているからアクセスできない。
うちが引っかかったのはログインだったけど、リダイレクトが使われる遷移は全滅する模様。


## で、どうしたか(対策)

斜め読みなので全部は把握してないけど一旦この内容

> Tomcat rewrite the `http://` URLs to `https://` URLs by using `urlrewritefilter` as suggested in `this answer`(リンク)

記事の場合はWEBホストがTomcatだったけど、要はURLを書き換えてね、ということで。


### IIS でやってみる

- ↑と同じURL書き換えのページまで飛ぶ
    1. 規則の追加 > 受信規則 > 空の規則
        - 名前: to-https(一意であればよい)
        - 必須条件: `{RESPONSE_LOCATION}` が `^http://` のパターンに一致
            - なくても動くがあったほうが必要な場合のみ詳細チェックするから軽そう
        - 一致するスコープ: サーバー変数
        - 変数名: RESPONSE_LOCATION
        - 変数値: パターンに一致する
        - 使用: 正規表現
        - パターン: `^http://[^/]+(/.*)?$`
        - アクションの種類
        - 書き換え
        - アクションのプロパティ - 値: `https://[mydomain]{R:1}`
        - 既存のサーバー変数を置き換える: ✔

```xml:web.config
<configuration>
  <system.webServer>
    <rewrite>
      <rules>
        <rule name="to-jenkins-routing" stopProcessing="true">
          <match url=".*" negate="false" />
          <conditions logicalGrouping="MatchAll" trackAllCaptures="false" />
          <action type="Rewrite" url="http://localhost:1080/{R:0}" />
        </rule>
      </rules>
      <!-- ここから下が追加 -->
      <outboundRules>
        <rule name="to-https" preCondition="precond-location-http">
          <match serverVariable="RESPONSE_LOCATION" pattern="^http://[^/]+(/.*)?$" />
          <action type="Rewrite" value="https://some-domain{R:1}" />
        </rule>
        <preConditions>
          <preCondition name="precond-location-http">
            <add input="{RESPONSE_LOCATION}" pattern="^http://" />
          </preCondition>
        </preConditions>
      </outboundRules>
    </rewrite>
  </system.webServer>
</configuration>
```

で、めでたくログイン後も各ページ遷移できるようになりました(๑•̀ㅂ•́)و✧

----

## メモ

- RESTのJenkinsAPIを使う分にはLocationヘッダとか気にする必要ないのでこの辺考慮はあまり不要。
- 最初ELBで80も疎通通っていたので https でログイン => http にリダイレクト => ログイン失敗 => httpsのログイン画面にリダイレクト、でブラウザ上からは何が起こってるかよくわからなかった(´・ω・｀)