일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
- Navigation
- 이영직
- 구현
- FlatList
- 창의충전소
- 폴더구조
- 휴대폰 기기
- service 테스트
- 경우의 수
- 노마드코더
- 원복
- BFS
- 해외 대외활동
- Project Bee
- 완전탐색
- react
- 버튼 활성화
- 티스토리챌린지
- 오블완
- web view
- ReactNative
- bfs dfs
- 비트마스킹
- springboot
- 자료구조
- React Native
- React Natvive
- 상속 관계 매핑
- 백준 1992
- multipart upload
- Today
- Total
유미의 기록들
[최종 프로젝트] Signed URL 적용 본문
💡 배경
유료로 제공되는 강의 영상이 모든 사용자에게 무제한으로 노출되는 것을 방지하기 위해, 수강 유저에게만 제한적으로 접근권한을 주고자 한다. 기존의 구현 방식은 배포된 CloudFront 도메인과 S3경로만으로도 외부에서 접근 가능 했기 때문에 무단으로 강의 영상이 유출될 위험이 있었다. 따라서 제한된 시간동안만 유효하고 필요한 권한만 제공하는 SignedURL을 적용하려고 한다.
📝 Signed URL
어떠한 요청을 수행하는 데 필요한 제한된 권한과 시간을 제공하는 URL
Signed URL에는 쿼리스트링에 인증정보, 만료 날짜 및 시간 같은 추가 정보가 포함되서 콘텐츠에 대한 액세스를 세부적으로 제어할 수 있다
🚀 CloudFront에 SignedURL 적용하기
1. Signed URLs 인증 절차에 사용할 `공개키`와 `개인키` RSA key pair를 만든다.
2.`공개키`를 AWS CloudFront keygroups에 등록하고 해당 CloudFront에 접근제한을 설정하고 keygroups을 연결한다.
3. 애플리케이션에서 `개인키`를 사용하여 인증정보가 쿼리에 담겨있는 Signed URLs을 생성한다.
4. 해당 Signed URLs로 접근하면 url 쿼리에 등록된 개인키가 CloudFront에 등록된 공개키와 복호화를 성공하여 콘텐츠에 접근이 가능하다.
CloudFront에서 SignedURLs 를 사용하려면 2가지 방법이 있다
- 루트사용자가 aws에서 key pair 생성하는 방식
- 키 그룹을 생성하는 방법
AWS에서는 키 그룹을 생성하는 방법을 권장한다
1. RSA key pair 생성
RSA 알고리즘을 사용하면 `공개키`와 `개인키` 두 가지 키를 생성한다.
RSA 암호화 알고리즘
공개키 암호 시스템 중 하나이며, 암호화 뿐만 아니라 전자 서명이 가능한 최초의 알고리즘
공개키 암호화 방식
데이터를 안전하게 전달하기 위해 사용하는 기술이다. 쉽게 말하면, 데이터를 암호화해서 전달함으로써 중간에 누군가가 가로채도 데이터를 읽을 수 없고 특정한 사람만 데이터를 읽을 수 있도록 하는 방식이다
내가 친구에게 메시지를 보낸다고 가정했을때
- 친구에게 전달받은 공개키를 사용해서 메시지를 암호화한다
- 친구만 자신의 개인키로 메시지를 복호화할 수 있다
- 누군가가 중간에 메시지를 가로채도, 공개키만으로는 내용을 확인할 수 없음
전자 서명
원본 데이터가 자신의 것이라는 의미로 이 메시지를 내가 보냈고, 위조되지 않았음을 증명하기 위해 디지털 데이터에 서명을 하는 것이다
내가 친구에게 메시지를 보낸다고 가정했을때
- 나의 개인키를 사용하여 메시지에 서명을 생성한다 (개인키는 나만 들고 있으므로 나만 생성 가능)
- 서명이 포함된 메시지를 친구에게 보낸다
- 친구는 나의 공개키를 사용해서 서명을 검증한다
- 서명이 유효하면 나로부터 왔음을 확인하고, 중간에 변조되지 않았음을 보장할 수 있음
개인키 (Private Key)
- 비밀로 유지해야 하는 키
- 자신이 데이터를 암호화 해독하거나 자신의 데이터에 서명할 때 사용
- 예) 애플리케이션은 자신의 개인키를 사용해 URL에 서명하여 Signed URL을 생성한다.
공개키 (Public Key)
- 다른사람과 공유할 수 있는 키
- 다른 사람이 보낸 데이터를 암호화하거나 서명을 검증할 때 사용
예) CloudFront는 애플리케이션의 공개키를 등록해 요청의 서명을 검증한다
여기서는 암호화는 하지 않고, 서명 검증을 통해 SignedURL이 올바르게 생성되었고, 변조 되지 않았음을 확인하는 과정을 사용한다
이제는 서명 검증을 하기 위한 필요한 Key pair를 생성해보려고 한다.
OpenSSL을 사용하여 RSA 키 페어를 생성하고 private_key.pem이라는 파일에 저장한다
*OpenSSL : 암호화와 보안 프로토콜을 구현하는 오픈소스 라이브러리
openssl genrsa -out private_key.pem 2048
이렇게 만들어진 파일은 공개키와 개인키를 모두 포함한다. `private_key.pem`이라는 파일에서 `public_key.pem`이라는 파일로 공개키를 추출한다
openssl rsa -pubout -in private_key.pem -out public_key.pem
2. AWS CloudFront에 공개키 연결
CloudFront 공개키 등록
`CloudFront` > `Public Key` > `Create public key` 에서 공개키를 등록한다
Name을 지정하고, Key 입력하는 곳에 public_key.pem 파일을 넣으면 된다.
CloudFront에 Key groups 등록
`CloudFront` > `Key groups` > `Create Key group` 에서 키 그룹을 생성할 수 있다
위에서 만든 공개키를 선택하고 키 그룹을 생성한다
CloudFront id에 Key groups 연결
`CloudFront` > `Distributions` > `CloudFront id 선택` > `behavior` > `edit` 으로 이동 후 위에서 만든 키 그룹을 등록한다
이제 CloudFront에 접근 제한 설정을 했다. 저번에는 CloudFront에 접근했던 URL은 더 이상 접근을 할 수 없게 되고, Signed URLs을 통해서만 접근이 가능하다
3. Signed URLs 생성
이제 `Signed URLs` 를 코드상에서 생성해주면 된다. AWS 공식문서를 보면 언어별로 코드를 제공해주고 있다. 나는 SpringBoot를 사용하고 있으므로 Java 코드를 참고하였다.
영상을 조회할 때, SignedURL을 생성하는 코드
LectureVideoController - getLectureVideo 메소드
//signedURL 생성
String signedUrl = null;
try {
signedUrl = cloudFrontService.generateSignedUrl(lectureVideo.getFileName(), 60);
} catch (Exception e) {
throw new ApiException(ErrorStatus._INVALID_URL_FORMAT); //SignedURL 생성 실패
}
CloudFrontService
@Service
@RequiredArgsConstructor
public class CloudFrontService {
@Value("${cloud.aws.cloudfront.cloudFrontUrl}")
private String CLOUD_FRONT_URL;
@Value("${cloud.aws.cloudfront.keyPairId}")
private String KEY_PAIR_ID;
@Value("${cloud.aws.cloudfront.privateKeyPath}")
private String PRIVATE_KEY_PATH;
private final CloudFrontClient cloudFrontClient;
public String generateSignedUrl(String resourcePath, long expirationMinutes) throws Exception {
CloudFrontUtilities cloudFrontUtilities = CloudFrontUtilities.create();
Instant expirationDate = Instant.now().plus(expirationMinutes, ChronoUnit.MINUTES);
resourcePath = URLEncoder.encode(resourcePath, StandardCharsets.UTF_8);
CannedSignerRequest request = CannedSignerRequest.builder()
.resourceUrl(CLOUD_FRONT_URL+resourcePath)
.privateKey(new java.io.File(PRIVATE_KEY_PATH).toPath())
.keyPairId(KEY_PAIR_ID)
.expirationDate(expirationDate)
.build();
SignedUrl signedUrl = cloudFrontUtilities.getSignedUrlWithCannedPolicy(request);
return signedUrl.url();
}
}
'대외활동 기록 > 내일배움캠프' 카테고리의 다른 글
[최종 프로젝트] Service 테스트 코드 작성 (0) | 2024.11.15 |
---|---|
Multipart Upload 방식 vs Pre-signedURL 방식 (0) | 2024.11.14 |
[최종 프로젝트] CDN 적용하여 강의 컨텐츠 조회 성능 최적화 (1) | 2024.11.12 |
[최종 프로젝트] SpringBoot 프로젝트 EC2 배포 (2) | 2024.11.11 |
[최종 프로젝트] Reflection을 이용한 테스트 코드 (1) | 2024.11.10 |