티스토리 뷰

CodePipeline과 Slack Bot으로 스마트하게 배포하는 구조를 정리한다. 핵심은 배포 직전에 Slack에서 사람이 승인하도록 만드는 것이다.

만들고 싶었던 흐름

  • GitHub push 하면 Docker 자동 빌드 및 테스트
  • 빌드가 완료되면 배포 직전에 confirm을 Slack Bot으로 받기
  • Slack에서 최종 컨펌을 하면 배포 시작
  • 배포가 완료 및 실패가 되면 Slack으로 알림 받기

트리거는 GitHub Actions vs CodePipeline

빌드 트리거는 GitHub Actions와 CodePipeline으로 하는 방법 2가지가 있다.

트리거 종류로는 비용이 바뀌지 않으니 CodePipeline에서 처리하는 것이 관리적 측면에서 좋다고 판단했다. AWS 리소스 접근 권한을 IAM 역할로 처리할 수 있고, 파이프라인 전체가 한 콘솔에서 보이기 때문이다.

전체 순서

  • CodePipeline에서 트리거를 push할 때 작동되도록 설정
  • buildspec.yml에서 빌드 및 테스트
  • confirm 단계에서 SNS로 알림 전송
  • SNS 트리거를 발동으로 Lambda에 슬랙봇 confirm 보냄
  • confirm 내용을 API Gateway로 보냄
  • API Gateway가 처리하여 다시 확인용 Lambda로 보내어 처리
  • 결과를 CodePipeline에 전달하여 처리, Slack Bot으로 처리 결과 전송
  • 배포 결과 SNS로 슬랙봇에 전달

왜 이렇게 여러 단계를 거치나

처음 보면 Lambda가 두 개나 나와서 복잡해 보인다. 이유가 있다.

CodePipeline의 수동 승인(Manual Approval) 단계는 SNS로 알림을 보낼 수 있지만, 승인 응답은 AWS 콘솔에서만 받는다. Slack 버튼으로 승인하려면 그 응답을 CodePipeline API로 전달할 무언가가 필요하다.

  • Lambda 1 (발송용) — SNS 메시지를 받아 Slack에 버튼이 달린 메시지를 보낸다. 이때 approvalToken과 파이프라인 정보를 버튼 payload에 심는다
  • API Gateway — Slack이 버튼 클릭 이벤트를 보낼 공개 엔드포인트 역할
  • Lambda 2 (처리용) — 클릭 이벤트를 받아 PutApprovalResult API를 호출한다
// Lambda 2 핵심 부분
await codepipeline.putApprovalResult({
  pipelineName,
  stageName,
  actionName,
  token: approvalToken,
  result: {
    status: approved ? 'Approved' : 'Rejected',
    summary: `${userName} 님이 ${approved ? '승인' : '거절'}`,
  },
}).promise();

구현할 때 걸리는 지점들

1. approvalToken은 유효 시간이 있다

승인 토큰은 기본 7일 후 만료된다. 그 전에 응답하지 않으면 파이프라인이 실패 처리된다. Slack 메시지에 만료 시각을 같이 표시해두면 좋다.

2. Slack 응답은 3초 안에 해야 한다

Slack은 인터랙션 요청에 3초 안에 응답하지 않으면 타임아웃 에러를 표시한다. CodePipeline API 호출이 그보다 오래 걸릴 수 있으므로, 먼저 200을 반환하고 실제 처리는 비동기로 하는 구조가 필요하다.

3. 요청 서명 검증은 필수다

API Gateway 엔드포인트는 인터넷에 열려 있다. 검증 없이 두면 누구나 배포를 승인할 수 있다. Slack이 보내는 X-Slack-Signature 헤더를 반드시 검증해야 한다.

const crypto = require('crypto');

const base = `v0:${timestamp}:${rawBody}`;
const mySig = 'v0=' + crypto
  .createHmac('sha256', SLACK_SIGNING_SECRET)
  .update(base)
  .digest('hex');

// timestamp가 5분 이상 지났으면 리플레이 공격으로 간주하고 거부

4. 누가 승인했는지 남긴다

Slack 페이로드의 user.name을 승인 요약에 넣어두면 나중에 감사 추적이 된다. 배포 사고가 났을 때 "누가 승인했나"를 확인할 수 있어야 한다.

5. 승인자 권한 제한

Slack 채널에 있는 아무나 승인 버튼을 누를 수 있으면 곤란하다. 허용된 사용자 ID 목록을 Lambda에서 확인하는 로직을 넣는 게 안전하다.

더 간단한 대안도 있다

직접 만들기 전에 검토해볼 만한 것들이다.

  • AWS Chatbot — SNS와 Slack을 연결해주는 관리형 서비스. Lambda 없이 알림을 받을 수 있다. 다만 승인 버튼 같은 인터랙션은 제약이 있다
  • GitHub Actions Environments — 환경별로 required reviewers를 지정하면 GitHub UI에서 승인을 받는다. Slack 연동은 GitHub 앱으로 알림만 받는 형태
  • Slack 워크플로 빌더 — 코드 없이 간단한 승인 흐름을 만들 수 있다

승인 UI를 Slack 안에 완전히 넣고 싶은 게 아니라면, 알림만 Slack으로 보내고 승인은 콘솔에서 하는 구조가 훨씬 간단하다. 파이프라인 하나에 Lambda 두 개와 API Gateway를 유지보수하는 비용도 무시할 수 없다.

정리

  • CodePipeline 수동 승인은 알림은 SNS, 응답은 콘솔이 기본이다
  • Slack에서 승인하려면 Lambda 2개 + API Gateway가 필요하다
  • 트리거는 CodePipeline 쪽이 관리 측면에서 유리하다
  • Slack 인터랙션은 3초 안에 응답해야 한다
  • 요청 서명 검증은 필수. 안 하면 누구나 배포를 승인할 수 있다
  • 간단하게 가려면 AWS Chatbot이나 GitHub Environments도 검토
댓글


최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday