AWS SDK for Java で S3 署名付き URL 生成

備忘録。S3 の 署名付き URL を AWS SDK for Java で生成する。AWS の設定周りについては正しいかどうかは自信がない...。

<!-- https://mvnrepository.com/artifact/com.amazonaws/aws-java-sdk-s3 -->
<dependency>
    <groupId>com.amazonaws</groupId>
    <artifactId>aws-java-sdk-s3</artifactId>
    <version>1.11.1034</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.amazonaws/aws-java-sdk-sts -->
<dependency>
    <groupId>com.amazonaws</groupId>
    <artifactId>aws-java-sdk-sts</artifactId>
    <version>1.11.1034</version>
</dependency>

パターン1

IAM ユーザーの認証情報 (accessKey, secretKey) を利用して生成するパターン。

AmazonS3 amazonS3 = AmazonS3ClientBuilder.standard()
        .withCredentials(new ProfileCredentialsProvider())
        .build();

Date expiration = new Date();
expiration.setTime(Instant.now().toEpochMilli() + 1000 * 60 * 5); // 有効期限5分
GeneratePresignedUrlRequest request = new GeneratePresignedUrlRequest(bucketName, objectKey)
        .withMethod(HttpMethod.GET) // GET のみ許可する
        .withExpiration(expiration);

URL presignedUrl = amazonS3.generatePresignedUrl(request);

パターン2

AWS STS で一時的なセキュリティ認証情報を取得して生成するパターン。事前に AmazonS3ReadOnlyAccess をアタッチしたロールを作成する。また、「信頼関係の編集」で sts:RoleSessionName を追加する。

... (略)
"Condition": {
  "StringLike": {
    "sts:RoleSessionName": "${aws:username}"
  }
}
AWSSecurityTokenService stsClient = AWSSecurityTokenServiceClientBuilder.standard()
        .withCredentials(new ProfileCredentialsProvider())
        .build();

AssumeRoleRequest roleRequest = new AssumeRoleRequest()
        .withRoleArn(roleArn)
        .withRoleSessionName(roleSessionName);
AssumeRoleResult roleResult = stsClient.assumeRole(roleRequest);
Credentials sessionCredentials = roleResult.getCredentials();

BasicSessionCredentials awsCredentials = new BasicSessionCredentials(
        sessionCredentials.getAccessKeyId(),
        sessionCredentials.getSecretAccessKey(),
        sessionCredentials.getSessionToken());

AmazonS3 amazonS3 = AmazonS3ClientBuilder.standard()
        .withCredentials(new AWSStaticCredentialsProvider(awsCredentials))
        .build();

Date expiration = new Date();
expiration.setTime(Instant.now().toEpochMilli() + 1000 * 60 * 5); // 有効期限5分
GeneratePresignedUrlRequest request = new GeneratePresignedUrlRequest(bucketName, objectKey)
        .withMethod(HttpMethod.GET) // GET のみ許可する
        .withExpiration(expiration);

URL presignedUrl = amazonS3.generatePresignedUrl(request);

その他

パターン2では URL に X-Amz-Security-Token=... パラメータが付く。このパラメータで一時的なセキュリティ認証情報を渡す。

ちなみに、マネジメントコンソールの「開く」でも署名付き URL は生成できる。有効期限は5分。(X-Amz-Expires=300)