본문 바로가기

SW 아키텍처 이야기

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

Maven Central Repository에 라이브러리를 배포하는 마지막 이야기는 CI(Continous Integration)에 적용하는 것이다.

참고로 기존 글들은 다음과 같은 주제로 다루었다.

우선, CI 적용 시에 고려사항과 이에 대한 해결 방법은 다음과 같다.

  • 실제 배포가 아닌 경우에도 불필요한 Maven plugin들이 실행됨 (속도 문제) : Maven Profile을 통해 필요한 경우만 추가된 Maven Plugin을 적용
  • GPG 보안 키(Secret Key) 대한 패스워드(passphrase) Sonatype 인증 정보 노출 문제 : CI 환경에서 제공하는 변수 암호화 적용

그리고 CI 환경으로는 오픈소스에 무료로 사용 가능한 Travis CI(https://travis-ci.org)를 사용하지만, 대부분의 CI 환경에서는 비슷한 방식을 제공한다.   

Maven Profile 적용

새롭게 추가된 4개의 Maven plugin(source, javadoc, gpg, nexus-staging)은 일반적인 빌드 상황에서는 필요하지 않고, 실제로 deploy될 때문 실행되면 된다. 따라서 이를 별도의 Maven Profile로 분리하는 것이다. 좋다.

<!-- Profiles -->
<profiles>
	<profile>
		<id>release</id>
		<build>
			<finalName>${project.artifactId}-${project.version}</finalName>
			<plugins>
				<!--
				 * maven-source-plugin
				 * maven-javadoc-plugin
				 * maven-gpg-plugin
				 * nexus-staging-maven-plugin
				-->
			</plugins>
		</build>
	</profile>
</profiles>

이후 deploy가 필요한 경우만 다음과 같이 "release" 프로파일을 지정해 maven을 실행하면 된다.

mvn clean deploy -P release

GPG 처리를 위한 Secure Key 등록

PGP/GPG 전자서명을 위해서는 반드시 보안 키와 보안 키 사용을 위한 비밀번호(passphrase)가 필요하다. 문제는 CI 환경에 이들을 노출할 수 없다는 것이다. 이를 해결하려면 보안 키 자체를 다른 방식으로 암호화하고 이를 형상서버에 등록해 주고, 실제 사용할 때에 2개의 비밀번호를 암호화된 환경 변수로 제공하여 처리한다. 여기서 2개의 비빌번호란 보안 키 파일을 암호화할 때에 사용한 비밀번호(password, 대칭키 암복호화 사용)와 보안 키 자체 사용을 위한 등록한 비밀번호(passphrase)이다.

보안 키 파일 암호화 (w/ AES-256) 

gpg에 생성된 키는 내부적으로 관리되기 때문에 별도의 gpg 명령을 통해 추출해야 하며, 이를 openssl 프로그램을 통해 대칭키 암복호화 방식으로 암호화한 파일로 변환해야 한다.

$ gpg -export-secret-keys ABCDEF0123456789 > secretkey.gpg 

$ openssl enc -e -in secretkey.gpg -out secretkey.gpg.enc -aes256 -pass "pass:password!!!“

$ rm secretkey.gpg 

 첫번째 명령은 기존에 설치한 gpg를 통해 생성된 보안 키(secret key)를 id 지정을 통해 secretkey.gpg 파일로 추출하는 것이다. 그리고 두번째는 추출된 보안 키 파일을 지정한 대칭키 암복호화 알고리지즘(AES-256)과 비밀번호 지정을 통해 암호화를 한다. 마지막 명령을 추출된 보안 키를 삭제하는 것이로 실제로 형상서버에 등록하는 파일은 AES-256으로 암호화된 secretkey.gpg.enc만 필요하기 때문이다.

참고로 Travis의 OpenSSL 적용 버전이 현재 1.0.2g로 암호화할 때에 사용 1.0.X 버전을 사용해야 한다. 상위 버전을 사용하면 Travis에서 복호화 시에 오류가 발생하기 때문이다. ^^;

보안 키 파일 복호화 처리

아울러 CI 상에서 암호화된 보안 키를 복호화하는 처리를 다음과 같은 shell script를 통해 처리를 제공해야 한다. (파일명 예시 : setup_deploy.sh)

#!/bin/sh
openssl enc -d -in secretkey.gpg.enc -out secretkey.gpg -aes256 -pass "pass:$SECRET_KEY_DEC_KEY"

 그리고 필요한 시점에 이 스크립트를 실행하는 travis 설정(.travis.yml)을 추가해야 한다.

before_install:
  - chmod +x mvnw
  - chmod +x setup_deploy.sh
  - ./setup_deploy.sh
  - gpg --import secretkey.gpg

여기서 before_install 단계(step)는 기본 인프라 관련 패키지 설치 등에 사용(추가 language 설치 등)되는 부분으로 조금 뒤에 조건 처리 부분에서 설명한다.

아울러, gpg 사용을 위해 복호화된 키 파일을 임포트(import)처리까지 해줘야 한다.

비밀번호(password) 등 문자열 암호화 처리

Gpg 보안 키 파일을 복호화하는 setup_deploy.sh에는 복호화를 위한 비밀번호(password)를 지정해야 하는데, 직접 지정하지 않고 OS의 환경 변수로 지정하였다. 그리고 이런 중요한 문자열은 CI에서 제공하는 환경 변수 암호화 기능을 사용해야 한다.

Travis CI도 문자열에 대한 암호화를 사용할 수 있는데, Travis CLI를 설치하고 간단하게 하나의 명령을 통해 처리할 수 있다. 다만, 특정 repository(Travis에 연결된 GitHub의 owner/repository)에서만 사용할 수 있음에 유의하자.

$ gem install travis

$ travis encrypt NAME="value" –r owner/project
Secure: "… encrypted data …"

-r 옵션을 통해 사용 repository 정보와 함께 환경 변수명(NAME)과 값을 지정하면 화면 상에 암호화된 값이 출력된다. 이 값은 잘 기록해 놓아야 한다. (사실 다시 실행해도 동일한 결과가 나오긴 한다.)

또는 별도 travis CLI 설치 없이도 http://rkh.github.io/travis-encrypt/public에 접속하면 JavaScript 방식으로 동일하게 암호화 값을 얻을 수 있다.

참고로 암호화해야 할 대상(4개)은 다음과 같다.

  • OSSRH 계정 정보(user / password)
  • GPG 보안키(secure key) 비밀번호(passphrase)
  • GPG 보안키 복호화 (AES-256 password)

암호화한 정보는 다시 travis 설정(.travis.yml)에 다음고 같이 추가하면 된다.

env:
  global:
    - secure: Br+XXO5HPQV...
    - secure: YfFz4PHNwj4...
    - secure: q+u6dZclpt7...
    - secure: Lgh6Fc2zMp+...

각각은 다음과 같은 환경변수 이름과 값에 대한 암호화된 값이다.

  • MAVEN_REPO_USERNAME : Maven settings.xml에 사용
  • MAVEN_REPO_PASSWORD : Maven settings.xml에 사용
  • MAVEN_GPG_PASSPHRASE : Maven settings.xml에 사용
  • SECRET_KEY_DEC_KEY : setup_deploy.sh에 사용

참고로 settings.xml에 지정된 환경변수는 다음과 같다.

<servers>
    <server>
        <id>ossrh</id>
        <username>${env.MAVEN_REPO_USERNAME}</username>
        <password>${env.MAVEN_REPO_PASSWORD}</password>
    </server>
</servers>

<profiles>
    <profile>
        <id>release</id>
        <activation>
            <activeByDefault>true</activeByDefault>
        </activation>
        <properties>
            <gpg.executable>gpg</gpg.executable>
            <gpg.passphrase>${env.MAVEN_GPG_PASSPHRASE}</gpg.passphrase>
        </properties>
    </profile>
</profiles>

setup_deploy.sh도 이미 본 것과 같이 "$SECRET_KEY_DEC_KEY"로 지정되었다.

openssl enc -d -in secretkey.gpg.enc -out secretkey.gpg -aes256 -pass "pass:$SECRET_KEY_DEC_KEY"

조건별 릴리즈 처리

이제 마지막으로 Travis 상에서 조건에 따른 deploy 처리를 추가해 보자. 예를 들면 development branch에 대한 변경은 별도 deploy를 하지 않고, master branch가 변경되었을 때만 deploy를 처리하는 것이다.

이를 위해서 우선 Travis가 제공하는 빌드의 라이프사이크과 각 단계(task)를 이해할 필요가 있다. Travis가 CI Job을 처리할 때에는 다음과 같은 단계(task)를 순차적으로 진행하고 각 단계별 처리를 Travis 설정 파일(.travis.yml)에서 지정할 수 있다. (위에서 setup_deploy.sh를 before_install 단계에서 실행한 것 같이) 

  • 0. VM 생성 / Repository clone
  • 1. (optional) “apt addons” (참고 : OS Ubuntu 16.04.6 LTS, Docker 18.06)
  • 2. (optional) “cache components”
  • 3. “before_install
  • 4. “install” : install any dependencies required (eg: mvn install)
  • 5. “before_script
  • 6. “script” : run the build script (eg: mvn test)
  • 7. (optional) “before_cache
  • 8. “after_success” or “after_failure
  • 9.  (optional) “before_deploy
  • 10. (optional) “deploy”
  • 11. (optional) “after_deploy
  • 12. “after_script

그리고 "deploy" 단계에서는 특정 조건을 다음과 같이 지정할 수 있다.

deploy:
  provider: script
  script: "./mvnw clean deploy -DskipTests=true -P release --settings settings.xml"
  skip_cleanup: true
  on:
      branch: master

"on" 부분에서 "master" 브랜치만을 대상으로 mvnw 명령(mvn wrapper)에 "-P release" Maven Profile과 "--settings settings.xml" 지정을 통해 OSSRH로의 배포를 처리하는 것이다.

결과 예시

실제 처리된 결과는 Travis CI에서 다음과 같이 확인할 수 있다.

 참조 : : https://travis-ci.org/RedCA-Family/code-analyst

아울러, 지금까지 설명한 내용들을 별도의 프로젝트로 구성해 놓았다. 추후 실제 적용 시에 이 프로젝트를 활용하면 좋을 것 같다.

https://github.com/switchover/code-analysis

 

switchover/code-analysis

Code Analysis. Contribute to switchover/code-analysis development by creating an account on GitHub.

github.com

이상으로 오픈소스 라이브러리를 OSSRH를 통해 Maven Central Repository에 배포하는 안내를 마친다.

Written with by Vincent Han