Bouncy Castle 프로바이더
Bouncy Castle 프로바이더 (Bouncy Castle Providers)
Pulsar의 보안·암호화 기능은 BouncyCastle JAR에 의존해요. 이번에는 Bouncy Castle이 무엇이고, Pulsar에서 FIPS 버전과 non-FIPS 버전을 어떻게 구성하는지 함께 살펴볼게요.
출처: 문서
본문
BouncyCastle 소개 (BouncyCastle Introduce)
Bouncy Castle은 기본 Java 암호화 확장(JCE)을 보완하는 Java 라이브러리로, Sun이 기본 제공하는 JCE보다 더 많은 암호 스위트와 알고리즘을 제공해요.
여기에 더해 Bouncy Castle은 PEM, ASN.1 같은 난해한 형식을 읽는 유틸리티가 많아서, 직접 다시 작성하고 싶지 않은 사람에게 아주 유용해요.
Pulsar에서 보안과 암호화는 BouncyCastle JAR에 의존성이 있어요. Bouncy Castle FIPS 설치·구성에 대한 자세한 내용은 BC FIPS Documentation을 참고하세요. 특히 User Guides와 Security Policy PDF를 확인해요.
Bouncy Castle은 FIPS와 non-FIPS 버전을 모두 제공해요. 하지만 JVM에서는 두 버전을 동시에 포함할 수 없고, 다른 버전을 포함하기 전에 현재 버전을 제외해야 해요.
Pulsar에서 종단 간 암호화의 보안·암호화 메서드도 Bouncy Castle 라이브러리에 의존해요. 이 문서는 Pulsar를 사용하면서 BouncyCastle FIPS(BC-FIPS)와 non-FIPS(BC-non-FIPS) 버전 간 구성에 대해 다뤄요.
Pulsar에서 BouncyCastle 모듈 패키징 방식 (How BouncyCastle modules packaged in Pulsar)
Pulsar의 bouncy-castle 모듈에서는 bouncy-castle-bc(non-FIPS 버전용)와 bouncy-castle-bcfips(FIPS 버전용)라는 두 하위 모듈을 제공해, BC jar를 함께 패키징해 Bouncy Castle의 포함·제외를 더 쉽게 해요.
이 목표를 위해 여러 bouncy-castle jar를 함께 bouncy-castle-bc 또는 bouncy-castle-bcfips jar로 패키징해야 해요. 각 원본 bouncy-castle jar는 보안과 관련되므로 BouncyCastle이 각 jar의 서명(signed)을 제공해요. 하지만 재패키징할 때 Maven shade가 BouncyCastle jar 파일을 폭발시켜 서명을 META-INF에 넣는데, 이런 서명은 새 uber-jar에는 유효하지 않아요(서명은 원본 BC jar용이기 때문). 보통 java.lang.SecurityException: Invalid signature file digest for Manifest main attributes 같은 오류를 만나게 돼요.
mvn pom 파일에서 이런 서명을 제외해 위 오류를 피할 수 있어요.
<exclude>META-INF/*.SF</exclude>
<exclude>META-INF/*.DSA</exclude>
<exclude>META-INF/*.RSA</exclude>
하지만 이는 새로운 난해한 오류로 이어질 수도 있어요. 예: java.security.NoSuchAlgorithmException: PBEWithSHA256And256BitAES-CBC-BC SecretKeyFactory not available. 알고리즘을 찾을 위치를 명시적으로 지정하면, 예: SecretKeyFactory.getInstance("PBEWithSHA256And256BitAES-CBC-BC","BC") 실제 오류를 얻을 수 있어요: java.security.NoSuchProviderException: JCE cannot authenticate the provider BC
그래서 우리는 jar-in-jar 방식을 사용하는 executable packer plugin을 사용해 단일 executable jar에서 BouncyCastle 서명을 보존해요.
BC-non-FIPS 의존성 포함 (Include dependencies of BC-non-FIPS)
bouncy-castle/bc/pom.xml로 정의되는 Pulsar 모듈 bouncy-castle-bc는 Pulsar에 필요한 non-FIPS jar를 포함하며, jar-in-jar로 패키징돼요(<classifier>pkg</classifier> 제공 필요).
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcpkix-jdk15on</artifactId>
<version>${bouncycastle.version}</version>
</dependency>
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-ext-jdk15on</artifactId>
<version>${bouncycastle.version}</version>
</dependency>
이 bouncy-castle-bc 모듈을 사용하면 BouncyCastle non-FIPS jar를 쉽게 포함·제외할 수 있어요.
BC-non-FIPS 모듈(bouncy-castle-bc)을 포함하는 모듈 (Modules that include BC-non-FIPS module)
Pulsar 클라이언트는 bouncy-castle 모듈이 필요하므로 pulsar-client-original이 bouncy-castle-bc 모듈을 포함하고, jar-in-jar 패키지를 참조하도록 <classifier>pkg</classifier>를 설정해요. 다음 예제처럼 포함돼요.
<dependency>
<groupId>org.apache.pulsar</groupId>
<artifactId>bouncy-castle-bc</artifactId>
<version>${pulsar.version}</version>
<classifier>pkg</classifier>
</dependency>
기본적으로 bouncy-castle-bc는 pulsar-client-original에 이미 포함돼 있고, pulsar-client-original은 pulsar-client-admin, pulsar-broker 같은 많은 다른 모듈에 포함돼 있어요. 하지만 위의 shaded jar와 서명 문제 때문에 Pulsar의 bouncy-castle 모듈을 pulsar-client-all의 다른 shaded 모듈(예: pulsar-client-shaded, pulsar-client-admin-shaded, pulsar-broker-shaded)에 직접 패키징하면 안 돼요. 그래서 shaded 모듈에서는 bouncy-castle 모듈을 제외해요.
<filters>
<filter>
<artifact>org.apache.pulsar:pulsar-client-original</artifact>
<includes>
<include>**</include>
</includes>
<excludes>
<exclude>org/bouncycastle/**</exclude>
</excludes>
</filter>
</filters>
즉, bouncy-castle 관련 jar는 이 fat jar들에 shaded되지 않아요.
BC-FIPS 모듈 (bouncy-castle-bcfips) (Module BC-FIPS)
bouncy-castle/bcfips/pom.xml로 정의되는 Pulsar 모듈 bouncy-castle-bcfips는 Pulsar에 필요한 FIPS jar를 포함해요. bouncy-castle-bc와 유사하게 bouncy-castle-bcfips도 쉽게 포함/제외할 수 있도록 jar-in-jar 패키지로 패키징돼요.
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bc-fips</artifactId>
<version>${bouncycastle.bc-fips.version}</version>
</dependency>
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcpkix-fips</artifactId>
<version>${bouncycastle.bcpkix-fips.version}</version>
</dependency>
BC-non-FIPS 제외하고 BC-FIPS 포함 (Exclude BC-non-FIPS and include BC-FIPS)
BC-non-FIPS에서 BC-FIPS 버전으로 전환하고 싶다면, pulsar-broker 모듈의 예시는 다음과 같아요.
<dependency>
<groupId>org.apache.pulsar</groupId>
<artifactId>pulsar-broker</artifactId>
<version>${pulsar.version}</version>
<exclusions>
<exclusion>
<groupId>org.apache.pulsar</groupId>
<artifactId>bouncy-castle-bc</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.apache.pulsar</groupId>
<artifactId>bouncy-castle-bcfips</artifactId>
<version>${pulsar.version}</version>
<classifier>pkg</classifier>
</dependency>
더 많은 예시는 bcfips-include-test 모듈을 참고할 수 있어요.
더 알아보기 (Learn more)
- 종단 간 암호화에서 BouncyCastle 사용은 Encryption 문서를 참고해요.
- 전송 계층 암호화는 TLS transport 문서를 봐요.
- Bouncy Castle FIPS 구성은 BC FIPS Documentation을 참고해요.