본문 바로가기

STUDY/Spring

Spring Boot | S3파일 업로드 후 CloudFront SignedURL 생성하기

 

Spring Boot | S3 파일 업로드

1. gradle 설정 프로젝트 생성 후 AWS 의존성을 추가 dependencies { implementation 'org.springframework.boot:spring-boot-starter-thymeleaf' implementation 'org.springframework.boot:spring-boot-starter-..

gaemi606.tistory.com

 

S3와 CloudFront

Amazon Simple Storage Service(Amazon S3)? 인터넷 스토리지 서비스(저장소) = 데이터(사진, 동영상, 문서 등)를 저장해두는 곳 = 웹에서 파일에 접근 할 수 있음 저장 공간을 무제한으로 제공하고 고가용성

gaemi606.tistory.com


1. gradle에 의존성 추가

aws에서 제공하는 java sdk를 이용.

추가 후 refresh!

dependencies {
	implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
	implementation 'org.springframework.boot:spring-boot-starter-web'
	compileOnly 'org.projectlombok:lombok'
	annotationProcessor 'org.projectlombok:lombok'

	// AWS s3
	// https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-aws
	compile group: 'org.springframework.cloud', name: 'spring-cloud-starter-aws', version: '2.2.1.RELEASE'

	// AWS SDK
	// https://mvnrepository.com/artifact/com.amazonaws/aws-java-sdk
	compile group: 'com.amazonaws', name: 'aws-java-sdk', version: '1.11.534'

	developmentOnly("org.springframework.boot:spring-boot-devtools")

	testImplementation 'org.springframework.boot:spring-boot-starter-test'
}

 

 

SignedURL?
SignedURL은 만료 날짜 및 시간, 허용하는 IP 주소 등 추가 정보가 포함되는 URL로, 콘텐츠에 대한 액세스를 보다 세부적으로 제어할 수 있음. 이러한 정보를 이용해 프라이빗 콘텐츠 서비스를 제공할 수 있음. 

 

* CloudFrontUrlSigner 사용법 (공식문서)

 

2. SignedURL생성에 필요한 변수들 선언

 

* properties파일이나 yaml파일에 입력 후 @Value 애노테이션으로 불러와 사용하는 것을 추천

 // 사용할 protocol
 Protocol protocol = Protocol.https;
 
 // CloudFront의 domain
 String distributionDomain = "d1b2c3a4g5h6.cloudfront.net";
 
 // private key 파일을 File로 변환. path 정확히 입력할 것
 File privateKeyFile = new File("/path/to/cfcurlCloud/rsa-private-key.pem");
 
 // S3버킷의 키값 == 경로 및 파일명
 String s3ObjectKey = "a/b/images.jpeg";
 
 String keyPairId = "본인 키 페어 아이디";
 
 // 콘텐츠 접근 허용 시작 일시
 Date dateLessThan = DateUtils.parseISO8601Date("2012-11-14T22:20:00.000Z");
 
 // 콘텐츠 접근 중단 일시 (생략가능)
 Date dateGreaterThan = DateUtils.parseISO8601Date("2011-11-14T22:20:00.000Z");
 
 // 콘텐츠 접근을 허용할 ip주소 입력 (생략가능)
 String ipRange = "0.0.0.0/0";	// 모든 접근을 허용함

 

aws.yml

    @Value("${cloud.aws.cloudFront.distributionDomain}")
    private String distributionDomain;

    @Value("${cloud.aws.cloudFront.keyPairId}")
    private String keyPairId;

    @Value("${cloud.aws.path}")
    private String path;

3. 미리 지정된 정책 (getSignedURLWithCannedPolicy) 

기본 구조

위에서 선언한 변수들을 인자값으로 받아 key값을 확인한 후 SignedURL을 반환해줌

public static String getSignedURLWithCannedPolicy(SignerUtils.Protocol protocol,
                                                  String distributionDomain,
                                                  File privateKeyFile,
                                                  String s3ObjectKey,
                                                  String keyPairId,
                                                  Date dateLessThan)
                                           throws InvalidKeySpecException,
                                                  IOException

 

S3 버킷에 파일 업로드 후 fileName을 받아 인자값으로 넣어줌

 public String getSignedURLWithCannedPolicy( String fileName ) throws InvalidKeySpecException,
                                                                         IOException {
        String signedURL = "";

        try {
            SignerUtils.Protocol protocol = SignerUtils.Protocol.https;
            File privateKeyFile = ResourceUtils.getFile(path);
            String s3ObjectKey = fileName;
            Date dateLessThan = ServiceUtils.parseIso8601Date("2020-12-24T22:00:00.00Z");

            signedURL = CloudFrontUrlSigner.getSignedURLWithCannedPolicy(
                    protocol,
                    distributionDomain,
                    privateKeyFile,
                    s3ObjectKey,
                    keyPairId,
                    dateLessThan
            );
        } catch (Exception e) {
            e.printStackTrace();
        }
        return signedURL;
    }

 

4. 사용자 지정 정책 (getSignedURLWithCustomPolicy)

미리 준비된 정책을 사용할 때와 달리 정책 설명을 구성하는 부분이 필요함! 정책 설명은 JSON형식으로 작성해야 하는데, 이를 작성해주는 함수도 역시 존재함

 

  • resourcePath: 파일의 경로. 꼭 http://, https://, http*://로 시작해야 함.
  • epochDateLessThan: 콘텐츠 접근 만료 일시
  • limitToIpAddressCIDR: 접근을 허용할 클라이언트 IP 주소 (생략가능) 
  • epochDateGreaterThan: 콘텐츠 접근 허용 시작 일시 (생략가능)

limitToIpAddressCIDR값은 공인 아이피 주소를 넣어야 함! 아래 사이트에서 공인 아이피 주소 확인 가능.

null값을 넣는 것은 0.0.0.0/0과 같음 (모든 IP 주소 접근 허용)

checkip.amazonaws.com/

public static String buildCustomPolicyForSignedUrl(String resourcePath,
                                                   Date epochDateLessThan,
                                                   String limitToIpAddressCIDR,
                                                   Date epochDateGreaterThan)

 

getSignedURLWithCustomPolicy 기본구조

public static String getSignedURLWithCustomPolicy(String resourceUrlOrPath,
                                                  String keyPairId,
                                                  PrivateKey privateKey,
                                                  String policy)

 

PrivateKey는 SignerUtils의 loadPrivateKey를 통해 가져올 수 있다.

public String getSignedURLWithCustomPolicy (String fileName) throws InvalidKeySpecException,
                                                                        IOException {
        String signedURL = "";

        try {

            String resourcePath = "https://" + distributionDomain + "/" + fileName;
            Date dateLessThan = ServiceUtils.parseIso8601Date("2020-12-24T22:00:00.00Z");
            String ipRange = "0.0.0.0/0";

            String customPolicyForSignedUrl = CloudFrontUrlSigner.buildCustomPolicyForSignedUrl(
                    resourcePath, dateLessThan, ipRange, null
            );
            log.info("********** custom policy for signed url = " + customPolicyForSignedUrl);

            File privateKeyFile = ResourceUtils.getFile(path);
            PrivateKey privateKey = SignerUtils.loadPrivateKey(privateKeyFile);

            signedURL = CloudFrontUrlSigner.getSignedURLWithCustomPolicy(
                    resourcePath,
                    keyPairId,
                    privateKey,
                    customPolicyForSignedUrl
            );
            log.info("********** signedURLWithCustomPolicy = " + signedURL);

        } catch (Exception e) {
            e.printStackTrace();
        }

        return signedURL;
    }

 

 

5. 테스트

업로드 후 받아오는 URL을 S3가 아니라 CloudFront SignedURL로 변경하였음.


+) 참고

 

CloudFrontUrlSigner (AWS SDK for Java - 1.11.925)

static String getSignedURLWithCustomPolicy(SignerUtils.Protocol protocol, String distributionDomain, File privateKeyFile, String s3ObjectKey, String keyPairId, Date dateLessThan, Date dateGreaterThan, String ipRange) Returns a signed URL that provi

docs.aws.amazon.com

 

SignerUtils (AWS SDK for Java - 1.11.925)

 

docs.aws.amazon.com