OpenSearch Nori Plugin 설치 중 타임아웃·409·403 연속 발생

리소스 하나를 추가했을 뿐인데 세 개의 에러가 연달아 터졌다. AWS OpenSearch에 analysis-nori 플러그인을 설치하면서 Terraform 타임아웃, 409 Conflict, 403 Forbidden을 순서대로 만났다. 세 에러는 각각 원인이 달랐고, 하나를 해결하면 다음 문제가 나타나는 식이었다. Blue/Green 배포가 플러그인 연결을 인프라 교체로 만들고, Terraform의 선언적 재apply가 Access Policy를 덮어씌웠다.

환경: AWS OpenSearch Service, Terraform, EKS


리소스 하나가 세 개의 에러를 만든 경위

검색 기능 강화를 위해 AWS OpenSearch Service에 한국어 형태소 분석기인 analysis-nori 플러그인을 설치해야 했다. Terraform으로 aws_opensearch_package_association 리소스 하나만 추가하면 끝날 것으로 예상했다.

전체 흐름은 이랬다.

sequenceDiagram
    participant TF as Terraform
    participant AWS as OpenSearch (AWS)
    participant App as Application

    TF->>AWS: apply (Nori Association)
    AWS-->>AWS: Blue/Green 배포 시작
    Note over AWS: 수십 분 소요
    TF--xTF: 10분 타임아웃 → tainted

    TF->>AWS: destroy / re-apply 시도
    AWS--xTF: 409 Conflict (배포 진행 중)

    AWS-->>AWS: Blue/Green 완료 + Access Policy 덮어쓰기
    App->>AWS: curl /health (unsigned)
    AWS--xApp: 403 Forbidden (anonymous)

타임아웃: 플러그인 연결이 도메인 전체를 재배포한다

terraform apply를 실행했지만 10분이 지나자 Error: timeout으로 실패했다. 리소스 하나를 연결하는 작업이 왜 10분이 넘게 걸리는지 의아했다.

원인은 패키지 연결(Association)이 도메인의 Blue/Green 배포를 트리거한다는 점에 있었다. Blue/Green 배포란 새 노드를 띄우고 데이터를 옮긴 뒤 트래픽을 전환하는 방식인데, 데이터 양과 노드 규모에 따라 수십 분 이상 걸릴 수 있다. 플러그인을 “연결”하는 게 아니라 사실상 도메인 전체를 재배포하는 것이었다.

여기서 중요한 분기가 생겼다. Terraform은 타임아웃으로 실패 판정을 내리고 리소스를 tainted(다음 apply 시 삭제 후 재생성 대상)로 표시했지만, AWS 백그라운드에서는 Blue/Green 배포가 여전히 진행 중이었다. Terraform과 AWS의 상태가 어긋나기 시작했고, 이것이 다음 문제의 씨앗이 됐다.

해결은 타임아웃 설정 하나로 간단하다.

resource "aws_opensearch_package_association" "nori" {
  domain_name = var.domain_name
  package_id  = var.nori_package_id
 
  timeouts {
    create = "60m"
  }
}

Blue/Green 배포 지연은 AWS의 구조적 특성이다. Terraform이 충분히 기다리도록 timeouts.create를 명시적으로 설정해야 한다.


409: Terraform 실패가 AWS 작업 실패가 아니었다

tainted 리소스를 정리하려고 terraform destroy와 재 apply를 시도했다. 이번엔 409 Conflict 에러가 발생했다.

AWS OpenSearch는 한 번에 하나의 설정 변경(Config Change)만 허용한다. 첫 번째 시도로 촉발된 Blue/Green 배포가 아직 끝나지 않았기 때문에, 추가적인 수정이나 삭제 요청이 전부 거부된 것이다.

이 상황에서 할 수 있는 건 기다리는 것뿐이었다. AWS 콘솔에서 도메인 상태가 Active로 돌아오는 것을 확인한 뒤, terraform untaintterraform apply -refresh-only로 Terraform 상태를 실제 AWS 상태와 동기화했다.

Terraform apply가 실패했다고 AWS 작업이 실패한 것이 아니다. 관리형 서비스에서 State 불일치가 생기면 refresh-only로 먼저 동기화해야 한다.


403: 재apply가 Access Policy를 덮어썼다

Nori 플러그인 설치가 완료(Active)된 직후, 애플리케이션의 헬스 체크가 실패하며 403 Forbidden이 발생했다. 파드 내부에서 직접 확인했다.

curl https://vpc-....es.amazonaws.com/
# 403 Forbidden
# "User: anonymous is not authorized ..."

첫 반응은 “Nori 설치가 도메인 접근에 영향을 줬나”였지만, 응답 메시지가 anonymous is not authorized였다. Nori 플러그인은 검색 기능을 추가하는 것이지 접근 정책을 바꾸는 것이 아니다.

실제 원인은 Terraform의 선언적 특성에 있었다. tainted 리소스를 정리하려고 재 apply를 반복하는 과정에서 Access Policy가 코드의 기본값(root 계정만 허용)으로 덮어쓰여진 것이었다. 애플리케이션은 SigV4 서명 없이 요청을 보내고 있었고, 엄격해진 Access Policy에 의해 anonymous로 분류되어 차단됐다.

단기 복구는 Access PolicyPrincipal*(모든 AWS 계정)로 여는 것이었다. 보안은 Security Group(EKS Node, Bastion만 허용)과 FGAC(Basic Auth)로 유지된다. Principal을 여는 게 불안할 수 있지만, 네트워크 계층(SG)과 인증 계층(FGAC)이 독립적으로 동작하므로 한쪽을 열더라도 다른 계층이 통제한다.

장기적으로는 애플리케이션에 AWS SDK(SigV4) 서명 로직을 추가해 IAM 기반 접근 제어로 전환하기로 했다.


이 장애가 남긴 것

관리형 서비스의 설정 변경은 인프라 교체를 수반할 수 있다. 플러그인 하나를 연결하는 것도 Blue/Green 배포를 트리거한다. aws_opensearch_package_association처럼 사소해 보이는 리소스라도 Terraform timeouts를 넉넉히 잡아야 한다. 409가 나오면 작업을 멈추고 AWS 콘솔에서 도메인 상태를 먼저 확인해야 한다.

Terraform apply 실패가 AWS 작업 실패가 아니다. Terraform은 타임아웃으로 실패 처리했지만 AWS는 계속 작업 중이었다. 이 불일치를 모르고 destroy를 재시도하면 409에 부딪히고, refresh-only 없이 재apply를 반복하면 의도하지 않은 설정이 덮어쓰여진다. refresh-only를 State 불일치 첫 대응으로 습관화해야 한다.

보안은 계층이다. Principal을 넓히는 것이 보안 약화로 보일 수 있지만, 네트워크(SG)와 인증(IAM/FGAC)이 독립적으로 동작하는 구조라면 한 계층을 열더라도 다른 계층이 통제를 유지한다. 각 계층이 무엇을 보호하는지 명확히 알 때만 이 판단이 안전하다.


앞으로의 방향

현재 애플리케이션은 SigV4 서명 없이 OpenSearch에 접근하고 있다. Principal: * + SG + FGAC 구조는 동작하지만, 애플리케이션 레벨에서 AWS SDK 서명이 없으면 IAM 기반 접근 제어로 전환할 수 없다. SigV4 서명 로직 추가가 완료되면 Principal을 IAM Role로 좁혀 최소 권한 원칙을 적용하는 것이 다음 과제다.

또한 Blue/Green 배포가 진행 중인 동안 서비스 가용성에 영향이 없는지 검증한 적이 없다. 다음 도메인 변경 시에는 배포 진행 중 latency와 에러율을 CloudWatch로 모니터링하는 것을 기본 절차로 포함할 예정이다.


참고 자료


정보 공백 요약

#필요한 정보이유위치
1타임아웃 → 409 → 403 발생 타임라인 (AWS 콘솔 도메인 상태 변화 기록)세 문제의 연쇄 흐름 시각적 근거오프닝 섹션
2Access Policy 변경 전후 OpenSearch 접속 성공/실패 로그”403 해소 후 정상화” 정량적 근거해결 방법 섹션