EB와 IAM 까지 만들었다면 이제 소스를 통해 실제로 접근이 가능한지 체크해야 한다.
SDK For Java v1
gradle 에서 아래를 추가한다.
// s3
implementation platform('com.amazonaws:aws-java-sdk-bom:1.11.1000')
implementation group: 'com.amazonaws', name: 'aws-java-sdk-sts', version: '1.11.895'
implementation group: 'com.amazonaws', name: 'aws-java-sdk-s3', version: '1.11.895'
S3 Client 에 접근하기 위해 Access Key와 Secret Key를 직접 소스에 입력한다.
STS 적용 전
AmazonS3 s3 = AmazonS3ClientBuilder.standard()
.withCredentials(new AWSStaticCredentialsProvider(new BasicAWSCredentials("AccessKey", "SecretKey")))
.build();
s3.putObject(new PutObjectRequest("버킷이름", "파일주소", 멀티파트 스트림)
.withCannedAcl(CannedAccessControlList.PublicRead));
위처럼 하는 경우 보안상 좋지 않으니 이제부터 임시 Access Key 와 임시 Secret Key 를 발급받아 사용할 것이다.
STS 적용 후
private AmazonS3 s3;
public AmazonS3 s3Client() throws UnsupportedEncodingException, NoSuchAlgorithmException, InvalidKeyException {
// System.getProperty("user.home")
// Window -> 사용자 계정 폴더
// Linux -> tomcat 기준 CATALINA_HOME 인 것 같음
// 설정 경로는 CATALINA_HOME으로 추정 ps -ef | grep catalina -> -Dcatalina.home=해당경로
// 경로를 바꾼다면 tomcat이 안되지 않을까 싶음
// System.getProperty를 "~/" 로 해보았으나 /usr/share/tomcat 을 추출함 -> /usr/share/tomcat/~/.aws/credentials (x)
File configFile = new File(System.getProperty("user.home"), ".aws/credentials");
AWSCredentialsProvider credentialsProvider = new ProfileCredentialsProvider(new ProfilesConfigFile(configFile), "default");
AWSSecurityTokenService stsClient = AWSSecurityTokenServiceClientBuilder.standard()
.withCredentials(credentialsProvider)
.build();
AssumeRoleRequest roleRequest = new AssumeRoleRequest()
.withRoleArn(resourceNumber)
.withRoleSessionName("세션이름 아무거나")
.withDurationSeconds(900); // 15분 부터 36시간 까지이며 기본은 1시간이다.
AssumeRoleResult assumeRoleResult = stsClient.assumeRole(roleRequest);
Credentials temporaryCredentials = assumeRoleResult.getCredentials();
log.debug("temp access key : {}", temporaryCredentials.getAccessKeyId());
log.debug("temp secret key : {}", temporaryCredentials.getSecretAccessKey());
AWSCredentials credentials = new BasicSessionCredentials(temporaryCredentials.getAccessKeyId(), temporaryCredentials.getSecretAccessKey(), temporaryCredentials.getSessionToken());
stsClient.shutdown();
if (s3 != null) s3.shutdown();
s3 = AmazonS3ClientBuilder.standard()
.withCredentials(new AWSStaticCredentialsProvider(credentials))
.build();
}
AWS 문서를 뒤져보면 ProfileCredentialsProvider
를 통해 서버내 위치한 ~/.aws/credentials
파일을 읽어서 기본 값인 default
를 읽어 Access Key와 Secret Key를 불러와 사용하는 것으로 나와있다.
하지만 문서대로 실행해보면 다음과 같은 에러를 볼 수 있다.Profile cannot be null
그래서 며칠간 이것저것 시도해본 결과 EB 정책으로 ec2-role
에 S3 정책을 부여했을 때 되는 것을 확인하여 ec2 프로필을 만들어서 해보았으나 여전히 sts:assumeRole Access Deny 403 에러를 만났었다.
그래서 바꾼 것이 File을 불러서 Profile을 읽고 (이거는 됨 왜 ? 왜 되는걸까) 사용하는 방식으로 변경하였다.
기본적으로 tomcat 기준으로 불러오다 보니 문서에서 말하는 ~/.aws/
경로가 아닌 /usr/share/tomcat/
경로에 위치해야 했다.
해당 경로에 아래 폴더 및 파일을 생성한다.
cd /usr/share/tomcat
mkdir .aws
cd .aws
vi config
[default]
region = ap-northeast-2
vi credentials
[default]
aws_access_key_id = 아까 복사해둔 Access Key
aws_secret_access_key = 아까 복사해둔 Secret Key
war 파일을 생성한 후 eb 에서 애플리케이션 배포를 통해 배포한 후 S3 접근 API로 확인하면 정상 접근 될 것이다.
SDK For Java v2
gradle 에 v1 버전을 주석처리하고 새로 추가한다.
v2 는 eb 환경이 아니고 기본 EC2에서 인스턴스를 만들었을 경우로 적용했다.
implementation platform('software.amazon.awssdk:bom:2.15.0')
implementation 'software.amazon.awssdk:kinesis' // 종속성 섹션에 사용할 SDK 모듈
implementation 'software.amazon.awssdk:sts'
implementation 'software.amazon.awssdk:s3'
private S3client s3;
public S3client s3Client() throws UnsupportedEncodingException, NoSuchAlgorithmException, InvalidKeyException {
ProfileCredentialsProvider profileCredentialsProvider = ProfileCredentialsProvider.create();
StsClient stsClient = StsClient.builder()
.credentialsProvider(profileCredentialsProvider)
.build();
AssumeRoleRequest assumeRoleRequest = AssumeRoleRequest.builder()
.roleArn(roleARN)
.roleSessionName("sessionName")
.durationSeconds(900)
.build();
StsAssumeRoleCredentialsProvider stsAssumeRoleCredentialsProvider = StsAssumeRoleCredentialsProvider.builder()
.refreshRequest(assumeRoleRequest)
.stsClient(stsClient)
.build();
AwsCredentials tempAwsCredentials = stsAssumeRoleCredentialsProvider.resolveCredentials();
AwsCredentialsProvider awsCredentialsProvider = () -> tempAwsCredentials;
stsClient.close();
if (s3 != null) s3Client.close();
s3 = S3Client.builder()
.credentialsProvider(awsCredentialsProvider)
.build();
}
ProfileCredentialsProvider credentialsProvider = ProfileCredentialsProvider.create();
S3 Policy 추가
퍼블릭 엑세스 차단은 모두 비활성화 한다.
eb를 통해 애플리케이션을 배포 하고 나면 S3 에 Bucket 이 새로 생성되며 해당 Bucket 을 클릭하고 상단 탭 중 권한 탭으로 들어가
버킷 정책을 편집하여 아래 내용을 추가한다.
{
"Version": "{ yyyy-mm-dd }",
"Statement": [
{
"Sid": "eb-ad78f54a-f239-4c90-adda-49e5f56cb51e",
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::{ 계정숫자 }:role/aws-elasticbeanstalk-ec2-role"
},
"Action": "s3:PutObject",
"Resource": "arn:aws:s3:::elasticbeanstalk-{ 리전값-계정숫자 }/resources/environments/logs/*"
},
{
"Sid": "eb-blahblah",
"Effect": "Deny",
"Principal": {
"AWS": "*"
},
"Action": "s3:DeleteBucket",
"Resource": "arn:aws:s3:::elasticbeanstalk-{ 리전값-계정숫자 }"
},
{
"Sid": "eb-blahblah",
"Effect": "Allow",
"Principal": {
"AWS": [
"arn:aws:iam::{ 계정숫자 }:role/aws-elasticbeanstalk-ec2-role",
"arn:aws:iam::{ 계정숫자 }:user/{ user1 역할명 }"
]
},
"Action": [
"s3:ListBucket",
"s3:ListBucketVersions",
"s3:GetObject",
"s3:GetObjectVersion"
],
"Resource": [
"arn:aws:s3:::elasticbeanstalk-{ 리전값-계정숫자 }",
"arn:aws:s3:::elasticbeanstalk-{ 리전값-계정숫자 }/resources/environments/*"
]
}
]
}
Difference ?
이것저것 시도해본 결과 EB를 통해 만들어진 EC2 는 aws cli 가 깔려있는 버전(?) 이라고 생각되고
그냥 EC2 상품에서 인스턴스를 만든 것과 다르다 라고 판단했다.
왜냐하면 ~/.aws/credentials
경로를 불러서 하는 방법이 잘 되기 때문이다.
'AWS' 카테고리의 다른 글
EFS Mount 하는 방법 (0) | 2023.05.18 |
---|---|
EC2 EBS Scale Up (0) | 2022.11.30 |
[STS 적용 - 4] NCS S3 STS 적용 (0) | 2021.11.11 |
[STS 적용 - 2] IAM 생성 (0) | 2021.11.11 |
[STS 적용 - 1] Elastic Beanstalk 생성 (0) | 2021.11.11 |