Skip to content

Commit a97e302

Browse files
HADOOP-19013. Adding x-amz-server-side-encryption-aws-kms-key-id in the get file attributes for S3A. (apache#6646)
Contributed by: Mukund Thakur
1 parent 129d91f commit a97e302

File tree

5 files changed

+81
-0
lines changed

5 files changed

+81
-0
lines changed

hadoop-tools/hadoop-aws/src/main/java/org/apache/hadoop/fs/s3a/impl/AWSHeaders.java

+3
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,9 @@ public interface AWSHeaders {
5555
/** Header for optional server-side encryption algorithm. */
5656
String SERVER_SIDE_ENCRYPTION = "x-amz-server-side-encryption";
5757

58+
/** Header for optional server-side encryption algorithm. */
59+
String SERVER_SIDE_ENCRYPTION_AWS_KMS_KEY_ID = "x-amz-server-side-encryption-aws-kms-key-id";
60+
5861
/** Range header for the get object request. */
5962
String RANGE = "Range";
6063

hadoop-tools/hadoop-aws/src/main/java/org/apache/hadoop/fs/s3a/impl/HeaderProcessing.java

+6
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@
4747
import static org.apache.hadoop.fs.s3a.Statistic.INVOCATION_XATTR_GET_NAMED;
4848
import static org.apache.hadoop.fs.s3a.Statistic.INVOCATION_XATTR_GET_NAMED_MAP;
4949
import static org.apache.hadoop.fs.s3a.commit.CommitConstants.X_HEADER_MAGIC_MARKER;
50+
import static org.apache.hadoop.fs.s3a.impl.AWSHeaders.SERVER_SIDE_ENCRYPTION_AWS_KMS_KEY_ID;
5051
import static org.apache.hadoop.fs.statistics.impl.IOStatisticsBinding.trackDuration;
5152

5253
/**
@@ -185,6 +186,9 @@ public class HeaderProcessing extends AbstractStoreOperation {
185186
public static final String XA_SERVER_SIDE_ENCRYPTION =
186187
XA_HEADER_PREFIX + AWSHeaders.SERVER_SIDE_ENCRYPTION;
187188

189+
public static final String XA_ENCRYPTION_KEY_ID =
190+
XA_HEADER_PREFIX + SERVER_SIDE_ENCRYPTION_AWS_KMS_KEY_ID;
191+
188192
/**
189193
* Storage Class XAttr: {@value}.
190194
*/
@@ -363,6 +367,8 @@ private Map<String, byte[]> retrieveHeaders(
363367
md.versionId());
364368
maybeSetHeader(headers, XA_SERVER_SIDE_ENCRYPTION,
365369
md.serverSideEncryptionAsString());
370+
maybeSetHeader(headers, XA_ENCRYPTION_KEY_ID,
371+
md.ssekmsKeyId());
366372
maybeSetHeader(headers, XA_STORAGE_CLASS,
367373
md.storageClassAsString());
368374

hadoop-tools/hadoop-aws/src/test/java/org/apache/hadoop/fs/s3a/EncryptionTestUtils.java

+33
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,11 @@
1919
package org.apache.hadoop.fs.s3a;
2020

2121
import java.io.IOException;
22+
import java.util.Map;
23+
import java.util.Optional;
2224

25+
import org.apache.hadoop.fs.s3a.impl.HeaderProcessing;
26+
import org.assertj.core.api.Assertions;
2327
import software.amazon.awssdk.services.s3.model.HeadObjectResponse;
2428

2529
import org.apache.commons.codec.digest.DigestUtils;
@@ -28,6 +32,8 @@
2832
import org.apache.hadoop.fs.Path;
2933

3034
import static org.apache.hadoop.fs.s3a.Constants.S3_ENCRYPTION_KEY;
35+
import static org.apache.hadoop.fs.s3a.impl.HeaderProcessing.XA_ENCRYPTION_KEY_ID;
36+
import static org.apache.hadoop.fs.s3a.impl.HeaderProcessing.XA_SERVER_SIDE_ENCRYPTION;
3137
import static org.assertj.core.api.Assertions.assertThat;
3238

3339
public final class EncryptionTestUtils {
@@ -111,4 +117,31 @@ public static void assertEncrypted(S3AFileSystem fs,
111117
}
112118
}
113119

120+
/**
121+
* Assert that a path is encrypted with right encryption settings.
122+
* @param fs filesystem.
123+
* @param path path
124+
* @param algorithm encryption algorithm.
125+
* @param kmsKey full kms key if present.
126+
* @throws IOException any IOE.
127+
*/
128+
public static void validateEncryptionFileAttributes(S3AFileSystem fs,
129+
Path path,
130+
String algorithm,
131+
Optional<String> kmsKey) throws IOException {
132+
Map<String, byte[]> xAttrs = fs.getXAttrs(path);
133+
Assertions.assertThat(xAttrs.get(XA_SERVER_SIDE_ENCRYPTION))
134+
.describedAs("Server side encryption must not be null")
135+
.isNotNull();
136+
Assertions.assertThat(HeaderProcessing.decodeBytes(xAttrs.get(XA_SERVER_SIDE_ENCRYPTION)))
137+
.describedAs("Server side encryption algorithm must match")
138+
.isEqualTo(algorithm);
139+
Assertions.assertThat(xAttrs)
140+
.describedAs("Encryption key id should be present")
141+
.containsKey(XA_ENCRYPTION_KEY_ID);
142+
kmsKey.ifPresent(s -> Assertions
143+
.assertThat(HeaderProcessing.decodeBytes(xAttrs.get(XA_ENCRYPTION_KEY_ID)))
144+
.describedAs("Encryption key id should match with the kms key")
145+
.isEqualTo(s));
146+
}
114147
}

hadoop-tools/hadoop-aws/src/test/java/org/apache/hadoop/fs/s3a/ITestS3AEncryptionSSEKMSDefaultKey.java

+21
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,18 @@
1919
package org.apache.hadoop.fs.s3a;
2020

2121
import java.io.IOException;
22+
import java.util.Optional;
2223

24+
import org.junit.Test;
2325
import software.amazon.awssdk.services.s3.model.HeadObjectResponse;
2426

2527
import org.apache.hadoop.conf.Configuration;
2628
import org.apache.hadoop.fs.Path;
29+
import org.apache.hadoop.fs.contract.ContractTestUtils;
2730

31+
import static org.apache.hadoop.fs.contract.ContractTestUtils.dataset;
32+
import static org.apache.hadoop.fs.contract.ContractTestUtils.writeDataset;
33+
import static org.apache.hadoop.fs.s3a.EncryptionTestUtils.validateEncryptionFileAttributes;
2834
import static org.hamcrest.CoreMatchers.containsString;
2935

3036
/**
@@ -56,4 +62,19 @@ protected void assertEncrypted(Path path) throws IOException {
5662
md.serverSideEncryptionAsString());
5763
assertThat(md.ssekmsKeyId(), containsString("arn:aws:kms:"));
5864
}
65+
66+
@Test
67+
public void testEncryptionFileAttributes() throws Exception {
68+
describe("Test for correct encryption file attributes for SSE-KMS with server default key.");
69+
Path path = path(createFilename(1024));
70+
byte[] data = dataset(1024, 'a', 'z');
71+
S3AFileSystem fs = getFileSystem();
72+
writeDataset(fs, path, data, data.length, 1024 * 1024, true);
73+
ContractTestUtils.verifyFileContents(fs, path, data);
74+
// we don't know the KMS key in case of server default option.
75+
validateEncryptionFileAttributes(fs,
76+
path,
77+
EncryptionTestUtils.AWS_KMS_SSE_ALGORITHM,
78+
Optional.empty());
79+
}
5980
}

hadoop-tools/hadoop-aws/src/test/java/org/apache/hadoop/fs/s3a/ITestS3AEncryptionWithDefaultS3Settings.java

+18
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
package org.apache.hadoop.fs.s3a;
2020

2121
import java.io.IOException;
22+
import java.util.Optional;
2223

2324
import org.junit.Ignore;
2425
import org.junit.Test;
@@ -36,6 +37,7 @@
3637
import static org.apache.hadoop.fs.s3a.Constants.S3_ENCRYPTION_ALGORITHM;
3738
import static org.apache.hadoop.fs.s3a.Constants.SERVER_SIDE_ENCRYPTION_ALGORITHM;
3839
import static org.apache.hadoop.fs.s3a.EncryptionTestUtils.AWS_KMS_SSE_ALGORITHM;
40+
import static org.apache.hadoop.fs.s3a.EncryptionTestUtils.validateEncryptionFileAttributes;
3941
import static org.apache.hadoop.fs.s3a.S3AEncryptionMethods.SSE_KMS;
4042
import static org.apache.hadoop.fs.s3a.S3ATestUtils.getTestBucketName;
4143
import static org.apache.hadoop.fs.s3a.S3ATestUtils.removeBaseAndBucketOverrides;
@@ -97,6 +99,22 @@ protected void assertEncrypted(Path path) throws IOException {
9799
EncryptionTestUtils.assertEncrypted(fs, path, SSE_KMS, kmsKey);
98100
}
99101

102+
@Test
103+
public void testEncryptionFileAttributes() throws Exception {
104+
describe("Test for correct encryption file attributes for SSE-KMS with user default setting.");
105+
Path path = path(createFilename(1024));
106+
byte[] data = dataset(1024, 'a', 'z');
107+
S3AFileSystem fs = getFileSystem();
108+
writeDataset(fs, path, data, data.length, 1024 * 1024, true);
109+
ContractTestUtils.verifyFileContents(fs, path, data);
110+
Configuration c = fs.getConf();
111+
String kmsKey = getS3EncryptionKey(getTestBucketName(c), c);
112+
validateEncryptionFileAttributes(fs, path, AWS_KMS_SSE_ALGORITHM, Optional.of(kmsKey));
113+
}
114+
115+
116+
117+
100118
@Override
101119
@Ignore
102120
@Test

0 commit comments

Comments
 (0)