본문 바로가기

SW 아키텍처 이야기

오픈소스 라이브러리 Maven Central Repository에 배포하기 (#2)

지난 글에서는 Maven Repository와 Central Repsitory에 대해 간단히 알아봤다.

2020/11/08 - [SW 아키텍처 이야기] - 오픈소스 라이브러리 Maven Central Repository에 배포하기 (#1)

이제 본격적으로 OSS Repository Hosting을 활용해 라이브러리를 Central Repository에 배포해 보자.

OSS Repository Hosting은 오픈소스 프로젝트의 바이너리에 대한 무료 호스팅 서비스를 제공하는데, Sonatype의 Nexus Repository Manager로 운영이 된다. 사이트 주소는 https://oss.sonatype.org이며 Maven repository에 대한 표준과 함께 다음과 같은 서비스를 제공한다.

  • 개발 버전(snapshots) 배포
  • 최종 릴리즈 버전 스테이징
  • 릴리즈 승인 및 Maven Central Repository 동기화

우선, 전체적인 절차를 먼저 짚어보자.

Sonatype에 먼저 가입을 하고 나서 내가 사용할 groupId에 대한 승인을 받아야 한다. Maven의 groupId는 일반적으로 도메인의 역순을 사용하는데 Java에서 패키지를 생각하면 된다. (eg: 도메인이 mycompany.com이라면 보통 com.mycompany로 시작)

그리고 OSSRH나 Maven Central Repository에 artifact를 올리려면 몇 가지 제약사항을 만족해야 한다. Javadoc(*-javadoc.jar)나 소스(*-sources.jar)도 같이 배포를 해야하고 배포되는 파일들에 대하 PGP로 전자서명을 해야 한다. 전자서명은 혹시나 모를 변조에 대비하기 위한 것이다.

1. Sonatype 가입

OSSRH를 사용하려면 sonatype에 가입해야 하는데, sonatype에서 운영하는 JIRA에 가입하면 된다. 가입에 필요한 정보와 절차는 간단하다. 

https://issues.sonatype.org/secure/Signup!default.jspa

이메일, 사용자 이름, 사용자계정(username), 그리고 패스워드만 입력하면 끝이다. 

2. 프로젝트 정보 생성

다음으로 JIRA ticket을 통해 오픈소스 프로젝트에 대한 정보 생성을 요청한다. 여기서 중요한 부분은 배포에 사용할 groupId를 승인 받는 것이다.

JIRA ticket은 다음과 같이 상단 "Create" 버튼을 클릭한 후에 필요한 정보를 입력한다.

  • 입력해야 할 정보는 다음과 같다.
  • Issue Type : "New Project"를 선택한다.
  • Summary : 오픈소스 프로젝트 또는 라이브러리 이름을 입력한다.
  • Description & Attachment : 상세 설명과 관련 파일을 등록할 수 있다.
  • Group Id : 사용하고자 하는 GroupId를 입력한다.
  • Project URL : 오픈소스 프로젝트에 대한 소개 사이트 주소를 입력한다. 별도 소개 사이트가 없고 GitHub를 사용한다면 그냥 GitHub 주소를 입력하면 된다. 
  • SCM URL : 형상서버 주소를 입력한다. 당연히 GitHub면 GitHub 주소를 입력한다.
  • Username(s) : 방금 전에 생성한 JIRA 계정를 입력한다. 여러 명을 지정할 수도 있다.

3. GroupId 소유에 대한 자격 증명

JIRA issue가 생성되었다면 조금 후에 다음과 같은 comment가 등록이 된다.

다음과 같은 방법으로 등록한 Group Id, 즉 도메인에 대한 소유를 확인해 달라는 것이다.

  • DNS 상에 생성된 issue URL을 지정한 TXT record 등록
  • 홈페이지가 없다면, 형상 서버로 Redirect 되도록 설정
  • 도메인 주소 사용 이메일로 메일 전송 (수신 : central@sonatype.com)

혹 GitHub를 사용한 경우라면 groupId를 io.github.[username]” 또는  com.github.[username]”로 사용할 수 있다고 되어 있는데, 이 경우에도 “TICKET ID”에 해당되는 Public Repo를 생성해야 한다. 예를 들어 https://github.com/switchover/OSSRH-51812 와 같이 repository만 생성해 놓으면 된다.

그런 후에 해당 Issue에 추가로 조치가 되었다고 comment를 남기면 된다. 그런 후 승인이 되었다는 comment를 받으면 이제 등록이 가능하다.

4. Javadoc 및 sources jar 생성

Maven Central Repository에 라이브러리 jar를 배포하기 위해서는 javadoc jar와 sources jar도 같이 올려야 한다. 이를 위해서는 Maven pom.xml에 몇 가지 plugin을 추가해야 한다.

4.1 Javadoc jar 생성

Jar로 패키지되면서 Javadoc도 같이 생성시키기 위해서 다음과 같이 Maven Javadoc plugin을 추가로 설정해 주면 된다.

<plugin>
	<artifactId>maven-javadoc-plugin</artifactId>
	<version>3.0.1</version>
	<configuration>
		<additionalJOption>-Xdoclint:none</additionalJOption>
	</configuration>
	<executions>
		<execution>
			<id>attach-javadocs</id>
			<goals>
				<goal>jar</goal>
			</goals>
		</execution>
	</executions>
</plugin>

goal을 "jar"로 지정하면 package 단계(phase)에서 javadoc 관련 파일들을 생성하고 jar 파일로 압축한다. 추가로 지정된 설정인 "-Xdoclint:none"은 Doc Lint 점검을 해제하기 위한 설정인데, 만약 Doc Lint상에 잘못된 부분이 확인되면 전체 빌드가 중지되기 때문에 되도록 설정해 주는 것이 좋다.

4.2 Sources jar 생성

다음으로 Sources도 jar 압축 파일로 생성해야 하며 이를 위해 Maven Source plugin을 추가해 줘야 한다.

<plugin>
	<artifactId>maven-source-plugin</artifactId>
	<version>3.0.1</version>
	<executions>
		<execution>
			<id>attach-sources</id>
			<goals>
				<goal>jar-no-fork</goal>
			</goals>
		</execution>
	</executions>
</plugin>

이 plugin도 package 단계에서 실행되는데, 여기서는 일반적인 "jar" 대신 "jar-no-fork" goal을 지정했다. "jar"로 지정해도 크게 문제가 되진 않지만, fork로 기존 빌드 라이프사이클에서 분리되어 별도로 실행되면서 "generate-sources" 단계(phase)를 포함해서 몇 개의 단계가 두 번 실행된다. 

5. PGP/GPG 전자서명

다음 단계로는 생성된 파일들(*.jar, *-javadoc.jar, *-sources.jar 등)에 대해서 전자서명으로 위변조 방지를 제공해야 한다. 요구되는 전자서명 방식은 PGP(Pretty Good Privacy)인데, 공개키 기반이며  이를 표준화한 것이 OpenPGP(RFC4880)이다. 그리고 GPG는 GnuPG(GPG, GNU Privacy Guard)는 GNU에서 구현한 OpenPGP로 가장 많이 쓰는 PGP 프로그램이라고 생각하면 된다.

정리하면, PGP 전자서명을 위해서는 GPG(또는 Windows에서 사용 가능한 Gpg4Win)을 사용하면 된다. 그리고 공개키 기반이기 때문에 전자서명 검증을 위해 Public Key를 공개해야 한다.

참고로 공개키 기반 암호화 및 전자서명은 별도로 정리할 예정이다.

이에 대한 구체적인 과정을 확인해 보자. 

5.1 GPG 설치 및 확인

GPG는 공식 사이트(gnupg.org/download/index.html) 또는 OS의 package manager(eg: yum, apt, brew 등)를 통해 쉽게 설치 가능하다. Windows는 공식 사이트에서 Gpg4win을 다운로드하여 설치하면 된다.

설치 이후 다음과 같이 버전을 확인할 수 있다.

5.2 키(Key pair) 생성

이제 키를 생성해 보자. 공개키 기반이기 때문에 public key와 secret key가 같이 생성된다.

이름과 이메일 주소를 입력한 후에 Okay를 입력하면 다음과 같이 비밀번호(passphrase)를 입력하는 화면이 나타나다.

그리고 비밀번호를 입력하면 다음과 같은 정보가 나타났다.

5.3 생성 키 확인

이제 생성된 키를 확인해 보자. 참고로 생성된 키들은 GPG 내부적으로만 생성된 것이며 별도 파일로 생성되진 않는다.

공개키는 "--list-keys" 옵션으로, 비밀키는 "--list-secret-keys" 옵션으로 확인 가능하며 실제 전자서명을 위해 해당 키를 사용하기 위해서는 ID를 사용한다. (위에서 ABCD...789가 ID이다)

5.4 전자서명 확인(테스트)

이제 전자서명이 잘 되는지 테스트를 해보자.

전자서명하고자 하는 파일명에 대하여 "gpg -ab [파일]"과 같이 실행하면 비밀키에 대한 비밀번호(passphrase)를 입력하는 화면이 나타나고 정상적인 비밀번호라고 하면 "파일.asc" 파일이 생성된다. 그리고 다시 "gpg --verify [파일.asc]" 명령을 실행하면 누가 전자서명을 했는지 이메일 정보와 함께 정상적으로 전자서명이 되었는지 확인이 가능하다.

여기서 -ab 옵션은 각각 다음과 같은 의미이다.

  • -a : ASCII 기반(armored) 파일 생성
  • -b : 별도 전자서명 파일(detached signature) 생성

5.5 공개 키 등록 및 검색

내가 서명한 전자서명에 대하여 다른 사람이 검증을 하기 위해서는 공개 키(public key)가 필요하다. PGP의 공개키 공유 방식은 peer-to-peer 방식이다. 이를 web of trust라고 한다. 다만, 모든 개인이 다른 사람의 공개 키를 갖고 있는 것은 불가능에 가깝기 때문에 PGP Key Server가 존재하며 다음과 같은 명령을 통해 손쉽게 PGP Key Server에 등록이 가능하다.

그런 후에 PGP Key Server의 웹사이트를 통해 검색이 가능하게 된다. 검색은 이메일, 이름, ID로 가능하다.

5.6 Maven 적용(GPG Plugin)

이제 드디어 Maven에 PGP 전자서명을 처리할 수 있다. 이를 위해 다음과 같이 Maven GPG Plugin을 설정한다.

<plugin>
	<groupId>org.apache.maven.plugins</groupId>
	<artifactId>maven-gpg-plugin</artifactId>
	<version>1.6</version>
	<executions>
		<execution>
			<id>sign-artifacts</id>
			<phase>verify</phase>
			<goals>
				<goal>sign</goal>
			</goals>
		</execution>
	</executions>
</plugin>

"verify" 단계(phase)에서 "sign" goal을 통해 전자서명 파일(*.asc)들을 생성하는 설정인데, gpg 실행 명령과 비밀키에 대한 설정이 필요하다. 일반적으로 이런 정보들은 공개되는 형상서버가 아닌 maven의 settings.xml 파일에 다음과 같이 보관되어야 한다. 아울러 비밀번호(passphrase)는 환경 변수를 통해 지정한다.

<profiles>
    <profile>
        <properties>
            <gpg.executable>gpg</gpg.executable>
            <gpg.passphrase>${env.MAVEN_GPG_PASSPHRASE}</gpg.passphrase>
        </properties>
    </profile>
</profiles>

 ☑︎ "verfy" 단계는 package 단계 이후 생성된 패키지에 대한 품질을 점검하는 단계로 install 단계 전에 실행된다.

이제 배포를 위한 distribution 설정과 deploy 처리 등이 남았는데, 다음 글을 통해 더 이어가보자.

Written with by Vincent Han