Nexus RepositoryをHTTPS化し、Gradleで利用する際の手順

# 当記事の概要
Nexus Repository（Sonatype Nexus Repository）は、Sonatype社が提供するアーティファクトリポジトリです。作成したライブラリを開発者間で共有するために使用したり、ビルド時に必要となるライブラリをインターネットから都度取得するのではなく、ローカルのネットワーク上のサーバから取得するためのキャッシュとして使用することができます。

直近でNexus RepositoryをHTTPS化し、Gradleでのbuild、publishで使用することがありましたので、その環境の準備の手順を紹介します。

なお、サーバ証明書は自己署名証明書を使用します。

# 前提環境
- OS : Rocky Linux 9.4
- Nexus Repository 3.69.0-02
- Gradle 8.5

# 手順

## Nexus Repositoryの設定
まず、Nexus Repositoryをインストールします。インストールそのものは当記事の本題ではないため、[Nexus Repository Manager Install](https://qiita.com/k-yasuhiro/items/4127b6c21d52268175aa)を参照いただければと思います。

この記事に沿ってNexus Repositoryをインストールすると、以下の2つのディレクトリができます。

- インストールディレクトリ ： /opt/nexus （/opt/nexus-<バージョン番号> ディレクトリのシンボリックリンク）
- データディレクトリ ： /opt/sonatype-work/nexus3 


次に、Nexus Repositoryが稼働している場合、一旦停止させます。

```bash
systemctl stop nexus
```

JDKに付属のkeytoolを使用し、自己署名証明書を作成します（Nexus Repositoryの導入時にJDKが前提となるため、keytoolも存在するはず）。

まずキーペアを作成し、キーストアファイルを`<インストールディレクトリ>/etc/ssl` に出力します。

```bash
# キーペアの作成
keytool -genkeypair -keystore /opt/nexus/etc/ssl/keystore.jks -alias nexus -keyalg RSA -sigalg SHA256withRSA -validity 365
```

すると、以下のような質問が出てきます。これは分かりづらい質問ですが、Common Nameを入力します。具体的にはサーバのホスト名、IPアドレスを入力します。この項目とパスワード以外は何も入力せずにEnterキーでよいのですが、**Common Nameだけは必ずサーバのホスト名、または、IPアドレスを入力してください**（設定しないと`gradle publish`で証明書を信頼できずエラーになります）。

```bash
What is your first and last name?
  [Unknown]:
```

また、「keystore password（キーストアのパスワード）」、「key password（キーパスワード）」の入力が求められるので、任意のパスワードを入力してください（「key password（キーパスワード）」は、何も入力せずにEnterを押すと、「keystore password（キーストアのパスワード）」と同じものが設定されます）。


次にCSRを作成します。出力先は先ほどと同じ`<インストールディレクトリ>/etc/ssl`です。

```bash
keytool -certreq -alias nexus -keystore /opt/nexus/etc/ssl/keystore.jks -file /opt/nexus/etc/ssl/nexus.csr
```

最後に証明書を作成します。出力先は同様に`<インストールディレクトリ>/etc/ssl`です。

```bash
keytool -gencert -rfc -alias nexus -keystore /opt/nexus/etc/ssl/keystore.jks -infile /opt/nexus/etc/ssl/nexus.csr -outfile /opt/nexus/etc/ssl/nexus.pem
```

次にNexus Repositoryの設定ファイルを修正します。Nexus Repositoryの設定ファイルは、`<インストールディレクトリ>/etc/nexus-default.properties` と `<データディレクトリ>/etc/nexus.properties` があります。`nexus-default.properties`は修正不可のため、`<データディレクトリ>/etc/nexus.properties`の方を修正します。

```bash
# <データディレクトリ>/etc/nexus.propertiesを編集
vi /opt/sonatype-work/nexus3/etc/nexus.properties
```

修正内容は、以下の2行を追加します。

```properties
# SSLのポートとして8443を使用
application-port-ssl=8443

# JettyのHTTPS用の設定ファイル「${jetty.etc}/jetty-https.xml」を参照するように末尾に追加
nexus-args=${jetty.etc}/jetty.xml,${jetty.etc}/jetty-http.xml,${jetty.etc}/jetty-requestlog.xml,${jetty.etc}/jetty-https.xml
```

`${jetty.etc}/jetty-https.xml` も修正します。

```bash
vi /opt/nexus/etc/jetty/jetty-https.xml
```

以下の通り、`KeyStorePassword`、`KeyManagerPassword`、`TrustStorePassword`の3つを修正します。「keystore password(キーストアのパスワード)」、「key password(キーパスワード)」は、キーペアを生成したときに入力したパスワードです。

```xml
  <New id="sslContextFactory" class="org.eclipse.jetty.util.ssl.SslContextFactory$Server">
    <Set name="KeyStorePath"><Property name="ssl.etc"/>/keystore.jks</Set>
    <Set name="KeyStorePassword">[keystore password(キーストアのパスワード)]</Set>
    <Set name="KeyManagerPassword">[key password(キーパスワード)]</Set>
    <Set name="TrustStorePath"><Property name="ssl.etc"/>/keystore.jks</Set>
    <Set name="TrustStorePassword">[keystore password(キーストアのパスワード)]</Set>
    <Set name="EndpointIdentificationAlgorithm"></Set>
    <Set name="NeedClientAuth"><Property name="jetty.ssl.needClientAuth" default="false"/></Set>
    <Set name="WantClientAuth"><Property name="jetty.ssl.wantClientAuth" default="false"/></Set>
    <Set name="IncludeProtocols">
      <Array type="java.lang.String">
        <Item>TLSv1.2</Item>
      </Array>
    </Set>
  </New>
```

ここまで設定したら、Nexus Repositoryを起動します。

```bash
systemctl start nexus
```

以下のURLにアクセスし、HTTPSでアクセスできることを確認します。

```text
https://<ホスト名>:8443/
```


## Gradle側の設定
Gradleで、自己署名証明書を使用したNexus Repositoryにpublishするためには、自己署名証明書をあらかじめJavaキーストアにインポートしておく必要があります。

以下のコマンドを実行し、Nexus Repositoryから証明書を取得し、ファイルに保存します。

```bash
echo -n | openssl s_client -connect <ホスト名>:8443 | sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' > ~/tmp/nexus.crt
```

次に、Javaキーストアに証明書をインポートします。

```bash
keytool -import -trustcacerts -keystore <Gradleで使用するJDKのパス>/lib/security/cacerts -storepass <任意のパスワード> -noprompt -alias nexus -file ~/tmp/nexus.crt
```

次に、Gradleの設定ファイル（`gradle.properties`）で、Javaキーストアのパス、および、上記コマンドの`storepass`で指定したパスワードを設定します。

```properties
systemProp.javax.net.ssl.trustStore=<Gradleで使用するJDKのパス>/lib/security/cacerts
systemProp.javax.net.ssl.trustStorePassword=<keytoolコマンドで設定したstorepass>
```

なお、`gradle.properties`は、Gradleプロジェクトのルートなどに配置することができますが、パスワードも含まれるためGitで管理すべきではありません。そのため、`<各自のホームディレクトリ>/.gradle/gradle.properties` に配置・管理するとよいです。

Gradleのビルドファイル（`build.gradle`）では以下の通り設定します（Nexus Repositoryに関連する箇所のみ抜粋）。パスワードは直接記述するのではなく、環境変数などを参照するようにしてください。


```gradle
// maven-publish プラグインを指定する
plugins {
    // 他のプラグインは省略
    id 'maven-publish'
}

publishing {
    publications {
        myLibrary(MavenPublication) {
            artifactId = "xxxx"
            from components.java
        }
    }
    repositories {
        maven {
            url "https://<Nexus Repositoryのホスト名>:8443/repository/<リポジトリ>/"
            credentials {
                username "<ユーザ名>"
                password "<パスワード>"
            }
        }
    }
}
```

以上で設定が完了しましたので、Gradleでのpublishを実行できるようになっているはずです。

```bash
gradle publish
```



# 参考
- [NexusをHTTPS化する](https://www.tssol.net/blog/2019/10/15/nexus-enable-https/)
- [自己証明書を使用しNexusに443ポートで接続](https://qiita.com/k-yasuhiro/items/c501a12b8bad14d10588)
- [Nexus 3でSSLを有効化](https://help.talend.com/ja-JP/installation-guide-windows/8.0/enable-ssl-for-nexus-3)