Maven 사용 시 Repository Credential(계정 정보) 안전하게 사용하기

jaclyn·2021년 4월 3일
0

개요

Maven 의 경우 과거에 많이 쓰였던(혹은 지금도) Java기반 프로젝트의 빌드 관리 도구로 많이 채택되었던 도구이다.
js의 npm, yarn 처럼 java, kotlin 등 프로젝트에서 사용되는 라이브러리 dependency를 관리할 수도 있고 그 외 빌드 프로세스도 구성이 가능하다.

일반적으로 회사에서 Maven을 사용할 때 사내에서 개발한 java 기반 라이브러리를 공통적으로 쓰거나 폐쇄망에서 빌드 및 배포가 이뤄져야 하는 경우가 많다.
그렇다보니, 사내에서 공통으로 사용할 수 있는 사설 Repository의 필요성이 대두된다.

보통 Nexus Repository를 사내에 구축해 사용하게 되는데 Nexus를 프록시 형태로 구성하여 Maven Central Repository에 등록된 라이브러리 등을 가져오고 회사에서 개발한 내부 라이브러리 자산 등은 Nexus에 직접 등록하여 외부/사내 라이브러리를 모두 Nexus Repository에서 가져올 수 있는 형태로 구성한다.

Nexus Repository 구성 방식
출처 : https://www.egovframe.go.kr/wiki/doku.php?id=egovframework:dev2:dep:nexus

What is Problem?

여기까진 모두 깔끔해보이지만, Nexus Repository에 접근하기 위한 계정을 생성하고 그 계정을 어떻게 사용하는지가 중요하다.

일반적으로 가장 간단하게 Maven을 통해 Nexus Repository에 접근해 빌드를 수행하는 maven 구성은 아래처럼 Pom.xml에 빌드 시 접근할 repository를 지정해주고,
settings.xml에는 해당 Repository의 Login 정보를 지정해준다.

pom.xml 예시

<project>
  ...
  <repositories>
    <repository>
      <id>my-company-nexus</id>
      <url>http://nexus.my.company.com/repo</url>
    </repository>
  </repositories>
  ...
</project>
${user.home}/.m2/settings.xml 예시

<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0 https://maven.apache.org/xsd/settings-1.0.0.xsd">
  ...
  <servers>
    <server>
      <id>my-company-nexus</id>
      <username>nexus_admin</username> // Nexus repo id
      <password>repository1234</password> // Nexus repo pw
    </server>
  </servers>
  ...
</settings>

여기서 문제가 발생한다.
개발자 모두가 이 소스코드를 공유하고 각자의 pc나 github에 위 소스가 그대로 올라간다면 Nexus repository의 계정정보의 유출 위험은 높아진다.

그럼 어떻게 하드코딩을 하지 않고 사용할 수 있을까?

How to use more safety?

1. Vault를 이용한 방법 (vault-maven-plugin)

만약 회사에 Vault가 구성되어 있다면 Vault에 Secret을 저장하고 Maven에서 불러올 수 있다.
vault-maven-plugin이 존재하는데 아래와 같이 사용하면 된다.

1) pom.xml에 plugin 정의 및 vault 내부의 Nexus Credential pull 해오기

(주의 : 여기서 Vault의 Token값은 서버의 환경변수나 로컬의 환경변수에 넣어놓고 사용하는 것이 좋습니다.)

아래 과정이 실행되면 ${project.username} 과 ${project.password} 값에 Vault에 저장되어있는 Nexus Credential이 할당된다.

pom.xml

<build>
    <plugins>
        <plugin>
            <groupId>com.deciphernow</groupId>
            <artifactId>vault-maven-plugin</artifactId>
            <version>1.0.0-SNAPSHOT</version>
            <executions>
                <execution>
                    <id>pull</id>
                    <phase>initialize</phase>
                    <goals>
                        <goal>pull</goal>
                    </goals>
                    <configuration>
                        <servers>
                            <server>
                                <url>https://vault.example.com</url>
                                <token>bf6ba314-47f1-4b9d-ab87-2b8e53fc640f</token> 
				// vault token값을 환경변수에 넣어놓고 ${env.VAULT_TOKEN} 이런식으로 받아오는 것이 더 안전합니다.
                                <paths>
                                    <path>
                                        <name>secret/user</name>
					// Vault에 Secret이 저장되어 있는 Path를 적어줍니다.
                                        <mappings>
                                            <mapping>
                                                <key>vault.password</key>
                                                <property>project.password</property> 
						//여기에 password가 저장됩니다.
                                            </mapping>
                                            <mapping>
                                                <key>vault.username</key>
                                                <property>project.username</property>
						//여기에 id가 저장됩니다
                                            </mapping>
                                        </mappings>
                                    </path>
                                </paths>
                            </server>
                        </servers>
                    </configuration>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

참고 : https://github.com/DecipherNow/vault-maven-plugin

2) settings.xml 작성

${user.home}/.m2/settings-security.xml

<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0 https://maven.apache.org/xsd/settings-1.0.0.xsd">
  ...
  <servers>
    <server>
      <id>my-company-nexus</id>
      <username>${project.username}</username> // Nexus repo id
      <password>${project.password}</password> // Nexus repo pw
    </server>
  </servers>
  ...
</settings>

2. 형상관리 도구에 settings.xml이 업로드되지 않도록 하기

git을 예시로 설명하자면, settings.xml이 아예 올라가지 않도록 .gitignore에 settings.xml을 적기해주어 실수로라도 형상관리 서버에 업로드되지 않도록 해야한다.

.gitignore
# denied list
./settings.xml

3. maven을 통해 password를 암호화 하기

Maven에서는 빌드 설정값에 들어가는 민감한 값들을 안전하게 사용할 수 있도록
AES 기반의 Encrpyt 기능도 제공하고 있다.

간단하게 아래와 같이 사용할 수 있다.

1) maven master password 생성(암/복호화 키값으로 사용되는 Master key)

아래 명령어 실행 후 Master Password 생성에 사용할 평문 키 값 입력

$ mvn --encrypt-master-password
Master Pasword: // 입력
{jSMOWnoPFgsHVpMvz5VrIt5kRbzGpI8u+9EF1iFQyJQ=}

2) 생성된 Master Password를 Vault, 환경변수 등에 저장하여 settings-security.xml에 등록

2-1)권고하지 않는 방식 : **그냥 평문으로 저장하는 경우

${user.home}/.m2/settings-security.xml

<settingsSecurity>
  <master>{jSMOWnoPFgsHVpMvz5VrIt5kRbzGpI8u+9EF1iFQyJQ=}</master>
</settingsSecurity>

2-2) 가장 권고하는 방식 : Vault에 마스터키 저장 후에 Master key 불러오기

위 vault에서 Master key를 가져오는 형태로 pom.xml 작성
아래 예시에서는 Master key를 ${project.masterkey}에 저장

pom.xml

<build>
    <plugins>
        <plugin>
            <groupId>com.deciphernow</groupId>
            <artifactId>vault-maven-plugin</artifactId>
            <version>1.0.0-SNAPSHOT</version>
            <executions>
                <execution>
                    <id>pull</id>
                    <phase>initialize</phase>
                    <goals>
                        <goal>pull</goal>
                    </goals>
                    <configuration>
                        <servers>
                            <server>
                                <url>https://vault.example.com</url>
                                <token>bf6ba314-47f1-4b9d-ab87-2b8e53fc640f</token> 
				// vault token값을 환경변수에 넣어놓고 ${env.VAULT_TOKEN} 이런식으로 받아오는 것이 더 안전합니다.
                                <paths>
                                    <path>
                                        <name>secret/masterkey</name>
					// Vault에 Secret이 저장되어 있는 Path를 적어줍니다.
                                        <mappings>
                                            <mapping>
                                                <key>vault.masterkey</key>
                                                <property>project.masterkey</property> 
						//여기에 Master Key
                                            </mapping>
                                        </mappings>
                                    </path>
                                </paths>
                            </server>
                        </servers>
                    </configuration>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

그 후 settings-security.xml에서 사용

${user.home}/.m2/settings-security.xml

<settingsSecurity>
  <master>${project.masterkey}</master>
</settingsSecurity>

2-3) Vault 사용하지 못할 경우 : 환경변수로 사용

환경변수에 masterkey 등록
명령어 : export MVN_MASTER_KEY={jSMOWnoPFgsHVpMvz5VrIt5kRbzGpI8u+9EF1iFQyJQ=}

그 후 settings-security.xml에서 사용

${user.home}/.m2/settings-security.xml

<settingsSecurity>
  <master>${env.MVN_MASTER_KEY}</master>
</settingsSecurity>

3) Nexus Credential password 암호화 및 사용

Maven을 이용해 password 암호화

$ mvn --encrpyt-password
Password:
{COQLCE6DU6GtcS5P=}

[1] Vault에 이 값을 저장해 settings.xml에서 불러와 사용하거나
[2] 환경변수에 넣고 불러오거나
[3] 평문 형태로 사용

1 > 2 > 3 순서로 안전함

In Conclusion

필자의 블로그 글을 보면 Vault와 같은 Secret manager를 구성해놓고 여러군데에서 활용할 수 있는 곳이 많은 것을 알 수 있다.

Vault나 AWS secrets manager 와 같은 Tool을 적극적으로 구축하고 사용하자, 정말 좋다.
맹신할 수는 없지만 흩어져서 관리되는 Secret들을 중앙집권화해서 관리를 잘 한다면 보안적으로 더 낫다고 보여진다.

Maven 얘기로 돌아가서, 필자가 설명한 여러가지 방식을 combine해서 사용한다면(vault + 환경변수 + 암호화) Nexus Credential 유출의 위험성을 크게 줄일 수 있다고 생각한다.

물론 Nexus Credential이 정말 별거 아닐 수 있다. '빌드된 소스 털려봤자 뭐하겠냐' 라고 생각할 수도 있지만 어찌됐든 Reverse Engineering 고-오-수들은 많기에 시간만 있다면 분석이 다 가능하다.
회사의 소중한 자산이 Nexus에 많이 등록되어 있다면 번거롭더라도 위처럼 구성해주는 것이 좋다.

Nexus Credential이 아니더라도 Maven 구성을 하면서 민감한 정보들은 다 위 방식을 응용하면 안전하게 사용할 수 있다.
다음은 Gradle Security에 대해 작성해볼 생각이다.(요즘 바빠서 언제 할지는 모르겠지만)

profile
DevSecOps

0개의 댓글