.yml파일 내부에 access key, secret key 같은 민감한 정보를 원격 리포지토리에 업로드할 시 그대로 노출되기 때문에 이를 보호할 필요성을 느껴 이를 해결할 수 있는 과정을 소개하고자 합니다.
기존 프로젝트에 중요 key 정보를 숨길 수 있는 기능을 구현하기 위한 방법을 찾던 중, spring cloud aws 내부에 이를 지원하는 기능이 있어 기존 AWS SDK for JAVA에서 의존성을 교체합니다.
이어서 로컬 환경과 클라우드 환경에서 각각 key 정보를 숨기는 방법에 대해 알아봅니다.
본문 1 - 로컬 환경에서 key 숨기기
spring cloud AWS란
dependency 설정
이후 구현 과정
설정할 필요없다
key setting
gitignore 추가
테스트
본문 2 - 배포 환경에서 key 숨기기
EC2 역할 추가
application.yml 수정
테스트
오류

AWS에서 제공해주는 Java SDK용 라이브러리는 어플리케이션과 통합을 위해 개발자가 직접 설정해야 하는 코드가 많습니다.
이를 위해 Spring Cloud AWS가 등장하였고
각 AWS 서비스의 다양한 종속성을 Spring에 통합하여 최대한 설정 코드를 작성하지 않도록 합니다.
현재는 S3 위주로 구현하기 때문에
spring cloud AWS의 다른 기능들은 추후에 다루겠습니다.
기존 AWS에서 제공했던 SDK용 종속성에서
이를 포함하는 spring cloud aws로 변경합니다.
implementation 'com.amazonaws:aws-java-sdk-s3:1.12.420'
implementation 'com.amazonaws:aws-java-sdk-core:1.12.420'
에서
implementation 'org.springframework.cloud:spring-cloud-starter-aws:2.2.6.RELEASE'
로 변경.
또한 Spring Cloud는 기본적으로 jaxb를 사용하고 있습니다.
Java 9 이상부터 수동으로 다음 모듈을 추가해야 합니다.
implementation 'javax.xml.bind:jaxb-api:2.3.1'
spring cloud for aws에 aws-java-sdk 라이브러리가 내장되어 있기 때문에 이후의 구현 과정은 전에 구현했었던 프로젝트와 똑같습니다.
링크 - SpringBoot와 AWS S3 연동, 이미지 전송하기
이전처럼 AmazonS3Client를 직접 만들기 위해 Configuration 클래스를 만들 필요가 없습니다.
parameter 0 of constructor in com.example.image_change_service.service.awss3storageservice required a single bean, but 2 were found:
- awss3client: defined by method 'awss3client' in class path resource [com/example/image_change_service/configure/amazons3clientbeanconfig.class]
- amazons3: defined in unknown location
이와같이 bean이 2개 만들어졌다고 오류가 발생하는데,
Spring Cloud AWS에서 자동으로 yml 설정파일을 이용하여 자동으로 Bean을 만들어줍니다.
AmazonS3ClientAmazonS3ResourceLoaderkey 정보를 외부에 노출시키지 않기 위해 다음과 같이 aws.yml 파일을 따로 만듭니다.
cloud:
aws:
credentials:
access-key: ~~~
secret-key: ~~~
이후 spring에서도 application.yml 뿐만 아니라 aws.yml까지 인식할 수 있도록 코드를 수정합니다.
public static final String APPLICATION_LOCATIONS = "spring.config.location="
+ "classpath:application.yml,"
+ "classpath:aws.yml";
static {
System.setProperty("com.amazonaws.sdk.disableEc2Metadata", "true");
}
public static void main(String[] args) {
new SpringApplicationBuilder(ImageChangeServiceApplication.class)
.properties(APPLICATION_LOCATIONS)
.run(args);
}
.gitignore에 aws.yml을 추가하여 원격저장소에 해당 파일이 올라가지 않도록 설정합니다.
이제 로컬환경에서 테스트를 진행해보면 잘 작동하는 것을 확인할 수 있습니다.
하지만, 배포 환경에서는 aws.yml 파일을 직접 만들어야 하는 번거로움이 있습니다.
이를 해결해주는 방법을 소개합니다.
EC2에 AmazonS3FullAccess 정책이 담긴 역할을 추가합니다.
이제, 어플리케이션에서 S3에 접근하기 위해서는 Access key와 Secret key를 통해 AWS로부터 인증을 받아 해당 역할(ex. cd-ec2-role)을 위임받아야 S3에 접근할 수 있게 됩니다.


이제 EC2는 별다른 조치 없이
할당된 IAM Role에 따라 access-key와 secret-key를 할당받습니다.

cloud:
aws:
credentials:
instanceProfile: true
해당 옵션은 AWS의 instanceProfile을 사용한다는 설정입니다.
이를 통해 이전에 만들었던 aws.yml 대신에 EC2 내부에 있는 instanceProfile를 이용해여 key값을 찾아냅니다.
2023-04-26 15:38:17.893 ERROR 25899 --- [http-nio-8080-exec-2] c.e.i.service.AwsS3StorageService : Unable to load AWS credentials from any provider in the chain: [com.amazonaws.auth.EC2ContainerCredentialsProviderWrapper@7b99868f: AWS_EC2_METADATA_DISABLED is set to true, not loading credentials from EC2 Instance Metadata service, com.amazonaws.auth.profile.ProfileCredentialsProvider@7f1826dc: profile file cannot be null]
try {
amazonS3Client.putObject(bucketName, fileName, file.getInputStream(), objectMetadata);
} catch (AmazonClientException | IOException exception) {
logger.error(exception.getLocalizedMessage());
}
bucket에 파일을 넣는 과정에서 위와 같은 ERROR가 발생하였습니다.
com.amazonaws.sdk.disableEc2Metadata = true 설정을 지워서 해결했습니다.
[Spring] - Spring Cloud AWS 의존성 추가시 "Failed to connect to service endpoint" 에러 발생원인 및 해결방법
해당 포스팅은 ERROR가 난 메서드를 추적하여 원인을 밝혀낸 과정을 설정하고 있는데, 여기서 com.amazonaws.sdk.disableEc2Metadata 설정을 true로 하면 "EC2 Instance Metadata Service is disabled" 예외메세지가 출력되는데 해당 메세지가 ERROR로 출력되는 것입니다.
EC2 인스턴스 메타데이터 조회 API 호출로직을 실행하지 않았다는 의미인데, 해당 메세지는 ERROR라고 보기엔 어렵기 때문에 과감하게 지워주었습니다.