2차 프로젝트에서 MSA기반으로 마이그레이션 하면서 JWT 인증 기능을 어떻게 설계할지 골이 조금 아팠는데 말입니다.
하는 김에 API GW랑 람다를 써서 서버리스 기반의 효율이 좋은 서비스를 구축해보자는 생각이 들었답니다.
이 둘을 굳이 사용하겠다고 선정한 이유는 뭐냐면 우선 사용한 만큼 금액이 나오고, 프리티어기간이 남아있어서
적용 했을 때 비용적으로 상당히 효율적인 접근이라고 생각했다지요.
- Lambda + APIGW 프리이터 제공량 : 매 달 100만건의 요청 및 호출
- 테스트 외에 요청하는 경우 굉장히 드물었고, JWT를 위해 ECS 서비스를 하나 더 생성하는거는 좀 비효율적이라고 생각했었음
또, 1차 프로젝트 결과물을 가지고 취약점 분석을 진행했을 때, ALB 무단 접근 같은 상황이 발생할 수 있다는 것을 인지했어여.
그래서 ALB로 직접 도달이 아니라 그 앞단에서 IP를 확인 가능하게 설계하자고 의견을 제시했고, 그게 API GW가 되는게 좋겠다고 생각했습니다.
또 API GW랑 람다에서 CORS 설정이 되더라구요?
아직 CI/CD 파이프라인이 구축되어있지 않은 상태에서 스프링 파일에서 CORS Config 처리하려면 여간 귀찮은 게 아니란 말이에요.
근데 이제, 여기서 처리하면 배포를 새로 하지 않아도 되는 편리함.
이 얼마나 좋은가.
하여 선정하게 되었습니다.
그래서. 여튼. 어쨌든 간에.
APIGW 적용 해보겠음.
1. APIGW 생성
- 필자는 HTTP API 로 진행했슴다.
- 스킵하겠음. 생각보다 EZ하기에.
2. 경로 설정 == Routes
- 서버 엔드포인트에 맞는 경로 지정
- HTTP 요청에 맞춰서(GET,POST...) 진행
- 귀찮으면 모든 요청을 허용하는 ANY 추천
- OPTIONS : CORS 처리할 때 사용 → 모든 경로에 설정 필요
- {proxy+} : proxy에 어떤 값이 오던 해당 경로로 매핑한다
- 필자의 팀의 경우 엔드포인트가 user/login | user/signup 이런 식으로 되어있단말이죵
- 그래서 user/{proxy} == proxy에 어떤 엔드포인트가 오던 해당 경로로 매핑한다는 의미랍니당
⇒ 여러분들 API 명세서에 맞게 작성해주시면 댄다지요.
3. Authorization → JWT 인증
3_1. JWT 복호화 : 사용자 정보 추출 Lambda 함수 생성
import jwt from 'jsonwebtoken';
const SECRET_KEY = Buffer.from(
'jwt 시크릿키',
'base64'
);
export const handler = async (event, context) => {
const rawToken = event.headers?.authorization || event.headers?.Authorization;
const authorizationToken = rawToken?.split(' ')[1];
if (!authorizationToken) {
return { isAuthorized: false };
}
try {
const token = jwt.verify(authorizationToken, SECRET_KEY, { algorithms: ['HS256'] });
const userId = token.userId;
console.log('JWT 검증 성공:', userId);
return {
isAuthorized: true,
context: {
userId: userId.toString(), // context 값은 문자열이어야 합니다
}
};
} catch (err) {
console.error('JWT 검증 실패:', err);
return { isAuthorized: false };
}
};
흐름
1. 로그인 시 session storage에 JWT 토큰 저장
2. 프론트에서 백으로 요청 시 authorization 헤더의 토큰 값 추출
const rawToken = event.headers?.authorization || event.headers?.Authorization;
const authorizationToken = rawToken?.split(' ')[1];
3. 토큰 복호화
const token = jwt.verify(authorizationToken, SECRET_KEY, { algorithms: ['HS256'] });
const userId = token.userId;
console.log('JWT 검증 성공:', userId); -> Cloudwatch 로그 기록
- algorithms: ['HS256'] : JWT 토큰 생성할때 지정한 알고리즘에 맞게 설정 필요
4. 반환
return {
isAuthorized: true,
context: {
userId: userId.toString(), // context 값은 문자열이어야 합니다
}
};
- isAuthorized: true : lambda v2인가에서부터는 얘가 필수로 들어가야 동작이 됩니다.(알고 싶지 않았어...)
- APIGW 로 전달해야 하는 값을 context에 넣어서 전달
5. 좌측에 Deploy 눌러야해욥
3_2. 권한 부여자 관리
- Lambda로 권한 부여자 생성해주시면 됩니답
3_3. 인증 연결
JWT 인증이 필요한 엔드포인트에 함수 연결
== 필자의 팀은 account 관련 작업 진행 할 때마다 사용자 인증을 받아서, 계좌 관련 엔드포인트 두 곳에 인증 절차를 박아버렸답니당
3_4.Integrations - 목적지 설정
1. 통합 생성
== 최종 목적지 생성
== 서버가 돌아가고 있는 곳
ex1) ALB - ECS cluster - Service(user service) → ALB arn이 최종 목적지
ex2) 그냥 EC2 위에서 돌아가고 있으면 EC2 private ip가 최종 목적지
2. 통합 연결
필자의 경우
- Account관련 엔드포인트는 모두 Account 서비스가 돌아가고 있는 ECS 와 연결되어있는 ALB로 냅다 보내버렸습니다.
- User(login/logout/siginup..)와 관련된 엔드포인트는 모두 User 서비스가 돌아가고있는 ECS 와 연관되어있는 ALB로 냅다 보내버렸습니다
+a) 매개변수 매핑
편의성을 위한 작업인데용
하셔두 대고 안하셔도 대구
저는 백엔드 다시 배포하는게 너무 싫어서 했슴당
- 앞에서 Lambda 함수에서 context에 userID 넣은거 기억나시나요
- 값 : API GW가 지금 가지고 있는 값
- 수정할 매개변수 : 백엔드에서 헤더 조회시 볼 수 있는 값
⇒ 람다에서 JWT 복호화 이후 context에 넣은 userId값을 auth-userId로 HTTP헤더에 넣어서 백으로 요청한다
⇒ 백에서는 header값을 받아와 auth-userId라는 변수로 접근 가능하도록
4. CORS 처리
4_1. CORS fonfig 관련 lambda함수 생성
export const handler = async (event) => {
return {
statusCode: 200,
headers: {
"Access-Control-Allow-Origin": "*", // 또는 정확한 도메인
"Access-Control-Allow-Methods": "GET, POST, PUT, DELETE, OPTIONS",
"Access-Control-Allow-Headers": "Content-Type, Authorization"
},
body: JSON.stringify({ message: "Preflight OK" }),
};
};
- 원래 * 여기에 localhost:8080이나 도메인 이름 넣어야 보안 측면으로 올바른 설정 방법임다!
4_2. 통합 생성
- 아까 생성한 CORS 관련 람다 함수를 사용해서 통합을 하나 생성해줍니다
4_3. 통합연결
- 모든 OPTION에 해당 통합을 연결해주세요
- → 이게 APIGW 에서 매핑 직전에 OPtion을 먼저 들렀다가 나가는 형식인 것 같더라구여
5. 흐름 확인
- 파라미터에 요청이 들어온 헤더(requestHeader)로부터 auth-userId (매개변수 매핑한 값) 을 가져와서 식별할때 사용하는 흐름 입니당
끗!
'☁️ 뭉게뭉게 클라우드' 카테고리의 다른 글
[Cloud | DeepDive] 최종 프로젝트 회고 | 클라우드 네이티브 엔지니어링 2회차 (3) | 2025.07.04 |
---|---|
[AWS | Cloud] ECS Fargate기반 실행 | ECR (0) | 2025.07.03 |
[Cloud | DeepDive] 2차 프로젝트 회고 | 클라우드 네이티브 엔지니어링 2회차 (0) | 2025.06.28 |
[Cloud | DeepDive] ZAP 을 사용한 취약점 분석 및 설명 (0) | 2025.06.28 |
[Cloud | DeepDive] 1차 프로젝트 취약점 분석 | ZAP (0) | 2025.06.28 |