티스토리 뷰

개요

  • com.amazonaws 라이브러리 이용시 제대로 설정이 되어 있지 않으면 클라이언트 인스턴스 생성시 에러가 발생한다.
  • region과 credential 설정방식에 대해 이해하고 제대로 활용하기 위해서 정리함.

 

전제조건

  • 해당 클라이언트는 com.amazonaws이다.
    • AWS클라이언트는 com.amazonaws만 있는 것은 아니다.
      • 다른 클라이언트에서는 키값이 다른 경우가 있다.

 

provider에 대해

  • region과 credential 정보는 provider에 의해 얻는다.
  • region provider는 클라이언트 인스턴스 생성시 동작한다
  • credential provider는 클라이언트 동작시(예: S3의 put, get) 동작한다.
  • provider는 chain으로 이루어져있다.
    • chain이므로 첫번째 provider에서 정보를 가져올 수 있으면 그것을 이용하고, 없으면 다음 provider로 넘어간다.

 

provider chain(순서대로 동작)

기본 region provider chain

provider 설정 종류 관련 키
AwsEnvVarOverrideRegionProvider 시스템 환경 변수 AWS_REGION
AwsSystemPropertyRegionProvider 시스템 프로퍼티 aws.region
AwsProfileRegionProvider AWS프로파일 AWS_PROFILE
aws.profile
InstanceMetadataRegionProvider AWS인스턴스의 메타데이터  

 

기본 credential provider chain

provider 설정 종류 관련 키
EnvironmentVariableCredentialsProvider 시스템 환경 변수 AWS_ACCESS_KEY_ID
AWS_ACCESS_KEY
AWS_SECRET_KEY
AWS_SECRET_ACCESS_KEY
SystemPropertiesCredentialsProvider 시스템 프로퍼티 aws.accessKeyId
aws.secretKey
aws.sessionToken
WebIdentityTokenCredentialsProvider WebIdentityToken AWS_WEB_IDENTITY_TOKEN_FILE
AWS_ROLE_ARN
AWS_ROLE_SESSION_NAME
ProfileCredentialsProvider AWS프로파일 AWS_PROFILE
aws.profile
EC2ContainerCredentialsProviderWrapper AWS인스턴스의 메타데이터  

 

 

설정 종류에 대한 설명

  • 시스템 환경 변수
    • 관련키의 대문자 부분 
    • OS의 변수이다
  • 시스템 프로퍼티
    • 관련 키의 소문자 부분 
    • JVM의 변수이다
  • AWS프로파일
  • WebIdentityToken, AWS인스턴스의 메타데이터
    • AWS에서 기동될 때 이용 가능한 정보
    • 로컬에서는 사용되지 않기 때문에 자세히 확인하지는 않았다.

 

문제점

  • 같은 시스템에서 여러개의 region과 여러개의 credential을 이용하고 싶은 경우는 어떻게 할까?
    • 시스템 프로퍼티는 별개이므로 JVM기동시 시스템 프로퍼티를 나누어서 설정하면 해결
    • IDE에서 전체가 아닌 개별 테스트코드 동작시 시스템 프로퍼티를 설정하는 것은 귀찮은 일
      • 테스트코드에선 보통 active profile을 설정하니까 application.yaml의 값을 이용할 수 있다면 좋을텐데

 

해결방안

  • application.yaml을 이용하는 provider를 만들고 설정하자.(ApplicationPropertiesCredentialsProvider)

 

ApplicationPropertiesCredentialsProvider 작성 및 반영

ApplicationPropertiesCredentialsProvider작성

import com.amazonaws.auth.AWSCredentials;
import com.amazonaws.auth.AWSCredentialsProvider;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

/**
 * com.amazonaws用
 * application.yamlのpropertiesよりAWSCredentials取得する
 */
@Component
public class ApplicationPropertiesCredentialsProvider implements AWSCredentialsProvider {
    private final String accessKey;
    private final String secretKey;

    public ApplicationPropertiesCredentialsProvider(
            @Value("${cloud.aws.accessKey:#{null}}") String accessKey,
            @Value("${cloud.aws.secretKey:#{null}}") String secretKey) {
        this.accessKey = accessKey;
        this.secretKey = secretKey;
    }

    @Override
    public AWSCredentials getCredentials() {
        return new ApplicationPropertiesCredentials(accessKey, secretKey);
    }

    @Override
    public void refresh() {
    }
}

 

provider chain작성

import com.amazonaws.auth.AWSCredentialsProviderChain;
import com.amazonaws.auth.EC2ContainerCredentialsProviderWrapper;
import com.amazonaws.auth.EnvironmentVariableCredentialsProvider;
import com.amazonaws.auth.SystemPropertiesCredentialsProvider;
import com.amazonaws.auth.WebIdentityTokenCredentialsProvider;
import com.amazonaws.auth.profile.ProfileCredentialsProvider;
import org.springframework.stereotype.Component;

/**
 * com.amazonaws用
 * AWSCredentialsProviderChain
 */
@Component
public class CustomAwsCredentialProviderChain extends AWSCredentialsProviderChain {
    public CustomAwsCredentialProviderChain(
            ApplicationPropertiesCredentialsProvider applicationPropertiesCredentialsProvider) {
        super(applicationPropertiesCredentialsProvider,
                new EnvironmentVariableCredentialsProvider(),
                new SystemPropertiesCredentialsProvider(),
                WebIdentityTokenCredentialsProvider.create(),
                new ProfileCredentialsProvider(),
                new EC2ContainerCredentialsProviderWrapper());
    }
}
  • ApplicationPropertiesCredentialsProvider을 가장 앞에 구성

 

Bean설정에서 customAwsCredentialProviderChain을 이용하도록 구성

@Value("${cloud.aws.region:#{null}}")
Optional<String> cloudAwsRegion;

@Value("${cloud.aws.endpoint:#{null}}")
Optional<String> cloudAwsEndpoint;

@Bean
AmazonS3Client amazonS3Client(CustomAwsCredentialProviderChain customAwsCredentialProviderChain) {
    return this.buildAwsClient(AmazonS3ClientBuilder.standard(), customAwsCredentialProviderChain);
}

private <R> R buildAwsClient(AwsClientBuilder awsClientBuilder,
                             CustomAwsCredentialProviderChain credentialProvider) {
    this.setEndPointAndRegion(awsClientBuilder);
    awsClientBuilder.withCredentials(credentialProvider);
    return (R) awsClientBuilder.build();
}

private void setEndPointAndRegion(AwsClientBuilder awsClientBuilder) {
    if (this.cloudAwsRegion.isPresent()) {
        if (this.cloudAwsEndpoint.isEmpty()) {
            awsClientBuilder.withRegion(this.cloudAwsRegion.get());
        } else {
            awsClientBuilder.setEndpointConfiguration(
                    new AwsClientBuilder.EndpointConfiguration(
                            this.cloudAwsEndpoint.get(), this.cloudAwsRegion.get()));
        }
    }
}
  • region은 하나만 사용하므로 region provider는 설정하지 않음.

 

기대 효과

  • AWS에서 동작하는 경우는 ApplicationPropertiesCredentialsProvider을 이용하지 않음.
    • application.yaml에 cloud.aws.accessKey, cloud.aws.secretKey을 설정하지 않으면 반환할 결과가 없으므로 통과
  • 각 테스트 환경에서 각기 다른 credential을 이용
    • application-ut.yaml은 accessKeyUt를 설정하여 이용
    • application-it.yaml은 accessKeyIt 를 설정하여 이용

 

참고자료