Kubernetes 상에서 Elasticsearch를 운영 중에 있는데, Self-Signed CA를 적용하였더니 Spring Application에서 연결을 하지 못하는 문제가 발생하였습니다.
Spring Boot 3.1에서 추가된 SSL Bundle 기능을 이용하여 인증서를 처리해보겠습니다.
먼저 Kubernetes상에서 cert-manager와 ECK를 통해 Elasticsearch를 구성하였다고 가정합니다.
관련 설정
사용한 Certificate
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: {{ .Values.elasticsearch.name }}-cert
namespace: {{ .Values.namespace }}
spec:
secretName: {{ .Values.elasticsearch.name }}-cert
isCA: false
subject:
organizations:
- "eFFx"
privateKey:
algorithm: RSA
size: 2048
encoding: PKCS1
issuerRef:
kind: Issuer
name: <사용할 Issuer>
commonName: {{ .Values.elasticsearch.name }}-es-http
dnsNames:
- {{ .Values.elasticsearch.name }}-es-http
- {{ .Values.elasticsearch.name }}-es-http.{{ .Values.namespace }}
- {{ .Values.elasticsearch.name }}-es-http.{{ .Values.namespace }}.svc
- {{ .Values.elasticsearch.name }}-es-http.{{ .Values.namespace }}.svc.cluster.local
- {{ .Values.elasticsearch.name }}-es-internal-http
- {{ .Values.elasticsearch.name }}-es-internal-http.{{ .Values.namespace }}
- {{ .Values.elasticsearch.name }}-es-internal-http.{{ .Values.namespace }}.svc
- {{ .Values.elasticsearch.name }}-es-internal-http.{{ .Values.namespace }}.svc.cluster.local
- {{ .Values.elasticsearch.name }}-es-transport
- {{ .Values.elasticsearch.name }}-es-transport.{{ .Values.namespace }}
- {{ .Values.elasticsearch.name }}-es-transport.{{ .Values.namespace }}.svc
- {{ .Values.elasticsearch.name }}-es-transport.{{ .Values.namespace }}.svc.cluster.local
keystores:
jks:
create: true
password: <JKS 비밀번호>
그 다음 Spring application.yaml에서 sslBundle을 이용하여, 인증서를 주입합니다.
spring:
elasticsearch:
uris: ${ELASTICSEARCH_URI}
host: ${ELASTICSEARCH_HOST}
port: ${ELASTICSEARCH_PORT}
username: ${ELASTICSEARCH_USERNAME}
password: ${ELASTICSEARCH_PASSWORD}
ssl:
bundle:
jks:
es:
reload-on-update: true
keystore:
location: ${CERT_PATH}/keystore.jks
password: ${CERT_PASSWORD}
type: JKS
truststore:
location: ${CERT_PATH}/truststore.jks
password: ${CERT_PASSWORD}
type: JKS
이렇게 하면 Spring 에서 SslBundles 라고 하는 Bean을 통해 주입받을 수 있습니다.
생소한 기능이다 보니 공식 블로그 글을 첨부합니다.
https://spring.io/blog/2023/06/07/securing-spring-boot-applications-with-ssl
Securing Spring Boot Applications With SSL
Secure Sockets Layer (SSL) and Transport Layer Security (TLS) are key components of securing communications between systems in a layered or service-oriented architecture. Spring Boot applications in such an architecture often accept incoming network connec
spring.io
이후 ElasticsearchConfig를 작성합니다.
import org.springframework.beans.factory.annotation.Value
import org.springframework.boot.ssl.SslBundles
import org.springframework.context.annotation.ComponentScan
import org.springframework.context.annotation.Configuration
import org.springframework.data.elasticsearch.client.ClientConfiguration
import org.springframework.data.elasticsearch.client.elc.ElasticsearchConfiguration
import java.time.Duration
@Configuration
class ElasticsearchConfig(
private val sslBundles: SslBundles
) : ElasticsearchConfiguration() {
@Value("\${spring.elasticsearch.host}")
private lateinit var host: String
@Value("\${spring.elasticsearch.port}")
private lateinit var port: String
@Value("\${spring.elasticsearch.username}")
private lateinit var username: String
@Value("\${spring.elasticsearch.password}")
private lateinit var password: String
override fun clientConfiguration(): ClientConfiguration =
ClientConfiguration.builder()
.connectedTo("$host:$port")
.usingSsl(sslBundles.getBundle("es").createSslContext())
.withBasicAuth(username, password)
.build()
}
SslBundles를 주입받어서 sslContext로 변경하여 주입하면 됩니다.
만약 RestTemplate 같은 경우에는 바로 sslBundle을 사용할 수 있습니다.
마지막으로 Kubernetes 에서 Deployment를 작성합니다.
apiVersion: apps/v1
kind: Deployment
metadata:
name: effx-backend
labels:
app: effx-backend
spec:
replicas: 1
selector:
matchLabels:
app: effx-backend
template:
metadata:
name: effx-backend
labels:
app: effx-backend
spec:
containers:
- name: effx-backend
image: <image>
ports:
- containerPort: 8080
protocol: TCP
env:
...
- name: CERT_PATH
value: /etc/effx/cert # 경로는 아무곳이나 겹치지 않으면 됩니다.
- name: CERT_PASSWORD
value: <위에서 작성한 JKS 비밀번호 (가능하면 valueFrom을 사용합시다.)>
volumeMounts:
- name: elasticsearch-cert
mountPath: /etc/effx/cert
volumes:
- name: elasticsearch-cert
secret:
secretName: elasticsearch-cert
restartPolicy: Always
이렇게 하면 컨테이너에 인증서가 마운트되어 Spring에서 사용할 수 있습니다.
참고 문서: https://piotrminkowski.com/2024/02/19/spring-boot-ssl-hot-reload-on-kubernetes/
'Spring | Java | Kotlin' 카테고리의 다른 글
[Debezium] Kafka Connect Custom SMT로 JSONB 처리하기 (1) | 2025.04.21 |
---|---|
[Debezium] PostgreSQL to ElasticSearch CDC (0) | 2025.04.21 |