"지금은 잘 돌아가니까 문제 없다"라는 접근은 문제가 발생하기 전까지 문제를 방치하는 마음가짐이기 때문에 이전에 이 게시글에서 언급한대로 EC2 내부 문제를 겪고 CloudWatch를 통해 모니터링을 하고 있지만 Memory check뿐만 아니라 전반적인 모니터링을 springboot 환경에서 할 수 있는 방법은 없을까 찾아보다가 SpringBoot Actuator를 적용해봐야겠다고 생각(PR 링크)했다.
Spring Actuator란?
Spring Actuator는 아래와 같이 build.gradle에 dependencies로 추가만 해주면 즉각 사용할 수 있기 때문에 SpringBoot 프레임워크를 바탕으로 백엔드 API를 구현할 경우 서버 모니터링 관리를 용이하게 할 수 있게 해준다.
// Actuator
implementation 'org.springframework.boot:spring-boot-starter-actuator'
Actuator 보안 이슈 및 안전하게 사용하는 방법
default 경로인 /actuator로 접속하게 되면 내부 모니터링 정보를 확인할 수 있는 href 경로가 제시되기 때문에 보안 이슈를 고려하지 않고 무분별하게 다 허용하여 사용할 경우 API Key, credential 정보, 서비스 IP 주소와 같은 정보들이 유출될 수 있고 데이터베이스보안 전공 수업 때 서비스(애플리케이션)의 보안에 대해서도 함께 배웠던 내용을 상기해보면 가용성을 침해할 수 있기 때문에 항상 trade-off를 고려해서 구축해야 한다.
지금 Actuator를 구성할 때 git secret 민감 정보를 .env를 통해 관리하고 있는 경우 Spring Actuator의 env endpoint를 enable && expose까지 허용하면서 EC2 인바운드 규칙에서 모든 IP 주소에 대해서 접근을 허용하기까지 했을 때 서비스에서 사용 중인 환경 변수를 누구나 볼 수 있게 되는 치명적인 상황이 닥칠 수 있다. 환경변수 관련 actuator 공식 문서 링크
또한 Actuator는 heapdump라는 엔드포인트를 제공하고 있다. 서비스 운영 중 민감 정보가 메모리에 남아있는 경우 현재 서비스가 점유 중인 heap 메모리를 dump하여 이를 보여주기 때문에 datasource DB 정보까지 확인 가능하다. heapdump 관련 actuator 공식 문서 링크
Actuator의 shutdown 엔드포인트의 경우 default가 disable이지만 활성화시켰을 때 문제가 발생할 수 있다. 이 엔드포인트에 접속하게 되면 바로 application을 shutdown 시켜버릴 수 있기 때문에 가용성 문제가 생긴다. shutdown 관련 actuator 공식 문서 링크
그렇다면 어떻게 보안 측면도 고려해서 모니터링 시스템을 구축해볼 수 있을까?
아래는 내가 보안 이슈를 고려하여 작성한 application-actuator.yml 파일이다. 이 코드를 작성하면서 안전하게 actuator를 사용하는 방법을 적용하고자 했다.
spring:
config:
activate:
on-profile: "actuator"
management:
endpoints:
web:
exposure:
include: health
base-path: /whoa-actuator
jmx:
exposure:
exclude: "*"
enabled-by-default: false
endpoint:
health:
enabled: true
show-details: always
1. Actuator에서 제공하는 endpoint를 disable 상태로 두고 필요한 사항만 include한다.
shutdown을 제외한 대다수의 endpoint는 enable이 되어있기 때문에 이 설정을 유지할 경우 잠재적인 위험 요인이 될 수 있으므로 management.endpoint.enabled-by-default 속성을 false로 하여 모든 엔드포인트에 대해 disable 상태로 만든다. 그리고 운영 중 필요한 엔드포인트만 management.endpoint.엔드포인트이름.enabled 속성을 true로 만든다. 위 코드처럼 나는 heath check를 하기 위해 다른 엔드포인트를 비활성화로 세팅/명시를 하였고 health만 별도로 활성화시켰다.
2. endpoint 노출이 필요할 경우 필요한 것만 include한다.
위 코드에서처럼 health를 enabled true로 하였다고 하더라도 바로 사용할 수 없는 것이 actuator endpoint의 특징이기 때문에 이 엔드포인트를 expose 노출시켜서 필요한 것만 노출하여 이용할 수 있도록 만들어준다. HTTP WEB의 경우 health endpoint만이 유일하게 기본적으로 expose되어있기 때문에 다른 엔드포인트를 이용하고 싶은 경우 management.endpoints.web.exposure.include 속성에 병렬적으로 작성해야 한다. JMX의 경우 모든 endpoint가 expose되어있다는 특징이 있어서 JMX 형태로 actuator를 사용하지 않을 것이기 때문에 management.endpoints.jmx.exposure.exclude 속성에 "*"로 두어 모든 엔드포인트를 JMX로 사용 불가하게 만들었다.
3. actuator default 경로를 사용하지 않고 경로를 변경하여 운영한다.
해커들이 웹 사이트를 attack할 때 actuator 페이지가 존재하는지 확인하는 경우가 있으므로 보편적인 default 경로로 놔두는 것은 위험하다. 따라서 management.endpoints.web.base-path 속성을 별도로 적어서 서비스 고유의 actuator 경로를 지정해주었다.
3-1. 이 밖에도 actuator는 management.server.port 속성을 통해 다른 포트에서 실행되도록 할 수도 있다.
3-2. 뿐만 아니라 actuator에 접근할 때는 Security 인증을 받은 사용자만 접근 가능하도록 한다.
SecurityFilterChain에서 "/actuator 경로/**에 대해서는 hasRole 등을 통해 특정 권한만 가진 사용자만 접근하도록 하는 것이 안정적이다. 하지만 이 프로젝트는 Security 없이, 로그인 없이도 모든 사용자가 이용 가능하도록 만들고자 고안된 서비스이기 때문에 이 방식은 적용해볼 수 없었다.
이렇게 안전하게 보안까지 고려하여 Actuator를 작성하는 방법을 터득하게 되었다~
거의 대다수가 같은 시기에 있는... 고등학교 친구들을 보면 배울 점이 많고 생각도 많아지는데 지금보다 열심히 해야겠돠
'SpringBoot > 구현 고민들' 카테고리의 다른 글
[Spring] Widget 구현 방안 (4) | 2024.09.29 |
---|---|
[Spring] ElasticSearch 검색 필터링 API 고도화 고민 : 쿼리 라이브러리 비교 (6) | 2024.09.22 |
[Spring] GET 요청 쿼리 스트링이 많을 경우 @RequestBody vs @ModelAttribute (0) | 2024.08.23 |
[Spring] Facade Pattern 적용 계기 및 이유 (0) | 2024.08.07 |
[Spring] AWS S3 Base64 인코딩된 이미지 처리 과정 고민 및 구현 과정 (0) | 2024.07.12 |