Skip to content

Commit 489e99b

Browse files
HADOOP-19197. S3A: KMS Encryption Context support: follow-up
Followup the main HADOOP-19197 patch to address serialization and compilation issues * Recreate serialization ID * Restore two arg constructor * Define DEFAULT_S3_ENCRYPTION_CONTEXT to specify what the default value is (just "", but being explicit) * Restore ability to unmarshal old version encryption secrets. * Tests This allows for YARN services to load DTs supplied by older releases. If they marshall the secrets again the fact they were the older version is lost, they get upgraded. This may complicate any worker node launch where the DT list is modified before passing to the launched process
1 parent 8c65e08 commit 489e99b

10 files changed

Lines changed: 258 additions & 44 deletions

File tree

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

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -786,6 +786,13 @@ private Constants() {
786786
public static final String S3_ENCRYPTION_CONTEXT =
787787
"fs.s3a.encryption.context";
788788

789+
/**
790+
* Default S3-SSE encryption context.
791+
* value:{@value}
792+
*/
793+
public static final String DEFAULT_S3_ENCRYPTION_CONTEXT =
794+
"";
795+
789796
/**
790797
* Client side encryption (CSE-CUSTOM) with custom cryptographic material manager class name.
791798
* Custom keyring class name for CSE-KMS.

hadoop-tools/hadoop-aws/src/main/java/org/apache/hadoop/fs/s3a/auth/delegation/EncryptionSecrets.java

Lines changed: 70 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -25,12 +25,18 @@
2525
import java.io.Serializable;
2626
import java.util.Objects;
2727

28+
import com.google.common.annotations.VisibleForTesting;
29+
import org.slf4j.Logger;
30+
import org.slf4j.LoggerFactory;
31+
2832
import org.apache.commons.lang3.StringUtils;
2933
import org.apache.hadoop.fs.s3a.S3AEncryptionMethods;
3034
import org.apache.hadoop.io.LongWritable;
3135
import org.apache.hadoop.io.Text;
3236
import org.apache.hadoop.io.Writable;
3337

38+
import static org.apache.hadoop.fs.s3a.Constants.DEFAULT_S3_ENCRYPTION_CONTEXT;
39+
3440
/**
3541
* Encryption options in a form which can serialized or marshalled as a hadoop
3642
* Writeable.
@@ -52,9 +58,24 @@
5258
*/
5359
public class EncryptionSecrets implements Writable, Serializable {
5460

61+
private static final Logger LOG =
62+
LoggerFactory.getLogger(EncryptionSecrets.class);
63+
5564
public static final int MAX_SECRET_LENGTH = 2048;
5665

57-
private static final long serialVersionUID = 1208329045511296375L;
66+
/**
67+
* Change this after any change to the payload: {@value}.
68+
*/
69+
private static final long serialVersionUID = 8834417969966697162L;
70+
71+
@VisibleForTesting
72+
public static final long SERIAL_VERSION_UID_CURRENT = serialVersionUID;
73+
74+
/**
75+
* Serial version ID prior to {@link #encryptionContext} field being added: {@value}.
76+
*/
77+
@VisibleForTesting
78+
public static final long SERIAL_VERSION_UID_1 = 1208329045511296375L;
5879

5980
/**
6081
* Encryption algorithm to use: must match one in
@@ -70,7 +91,7 @@ public class EncryptionSecrets implements Writable, Serializable {
7091
/**
7192
* Encryption context: base64-encoded UTF-8 string.
7293
*/
73-
private String encryptionContext = "";
94+
private String encryptionContext = DEFAULT_S3_ENCRYPTION_CONTEXT;
7495

7596
/**
7697
* This field isn't serialized/marshalled; it is rebuilt from the
@@ -86,7 +107,24 @@ public EncryptionSecrets() {
86107
}
87108

88109
/**
89-
* Create a pair of secrets.
110+
* Create a tuple of secrets. The encryption context is set to "".
111+
* This constructor is used in external implementations of S3A delegation
112+
* tokens, sp MUST be retained even if there is no use in our own
113+
* production code.
114+
* @param encryptionAlgorithm algorithm enumeration.
115+
* @param encryptionKey key/key reference.
116+
* @throws IOException failure to initialize.
117+
* @deprecated use {@link #EncryptionSecrets(S3AEncryptionMethods, String, String)}
118+
* which takes an encryption context.
119+
*/
120+
public EncryptionSecrets(final S3AEncryptionMethods encryptionAlgorithm,
121+
final String encryptionKey) throws IOException {
122+
this(encryptionAlgorithm.getMethod(), encryptionKey,
123+
DEFAULT_S3_ENCRYPTION_CONTEXT);
124+
}
125+
126+
/**
127+
* Create a 3/tuple of secrets.
90128
* @param encryptionAlgorithm algorithm enumeration.
91129
* @param encryptionKey key/key reference.
92130
* @param encryptionContext base64-encoded string with the encryption context key-value pairs.
@@ -99,7 +137,7 @@ public EncryptionSecrets(final S3AEncryptionMethods encryptionAlgorithm,
99137
}
100138

101139
/**
102-
* Create a pair of secrets.
140+
* Create a 3/tuple of secrets.
103141
* @param encryptionAlgorithm algorithm name
104142
* @param encryptionKey key/key reference.
105143
* @param encryptionContext base64-encoded string with the encryption context key-value pairs.
@@ -137,13 +175,26 @@ public void write(final DataOutput out) throws IOException {
137175
public void readFields(final DataInput in) throws IOException {
138176
final LongWritable version = new LongWritable();
139177
version.readFields(in);
140-
if (version.get() != serialVersionUID) {
178+
boolean readContext;
179+
180+
final long versionId = version.get();
181+
if (versionId == SERIAL_VERSION_UID_1) {
182+
LOG.info("Unmarshalling Encryption Secrets from older client; "
183+
+ "setting encryption context to \"\"");
184+
readContext = false;
185+
} else if (versionId == serialVersionUID) {
186+
readContext = true;
187+
} else {
141188
throw new DelegationTokenIOException(
142-
"Incompatible EncryptionSecrets version");
189+
"Incompatible EncryptionSecrets version: " + versionId);
143190
}
144191
encryptionAlgorithm = Text.readString(in, MAX_SECRET_LENGTH);
145192
encryptionKey = Text.readString(in, MAX_SECRET_LENGTH);
146-
encryptionContext = Text.readString(in);
193+
if (readContext) {
194+
encryptionContext = Text.readString(in);
195+
} else {
196+
encryptionContext = DEFAULT_S3_ENCRYPTION_CONTEXT;
197+
}
147198
init();
148199
}
149200

@@ -168,14 +219,26 @@ private void init() throws IOException {
168219
encryptionAlgorithm);
169220
}
170221

222+
/**
223+
* Get the encryption algorithm
224+
* @return the encryption algorithm
225+
*/
171226
public String getEncryptionAlgorithm() {
172227
return encryptionAlgorithm;
173228
}
174229

230+
/**
231+
* Get the encryption key
232+
* @return the encryption key
233+
*/
175234
public String getEncryptionKey() {
176235
return encryptionKey;
177236
}
178237

238+
/**
239+
* Get the encryption context
240+
* @return the encryption context
241+
*/
179242
public String getEncryptionContext() {
180243
return encryptionContext;
181244
}

hadoop-tools/hadoop-aws/src/main/java/org/apache/hadoop/fs/s3a/commit/files/PendingSet.java

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@
2020

2121
import javax.annotation.Nullable;
2222
import java.io.IOException;
23-
import java.io.ObjectInputStream;
2423
import java.util.ArrayList;
2524
import java.util.HashMap;
2625
import java.util.HashSet;
@@ -152,20 +151,6 @@ public void add(SinglePendingCommit commit) {
152151
}
153152
}
154153

155-
/**
156-
* Deserialize via java Serialization API: deserialize the instance
157-
* and then call {@link #validate()} to verify that the deserialized
158-
* data is valid.
159-
* @param inStream input stream
160-
* @throws IOException IO problem or validation failure
161-
* @throws ClassNotFoundException reflection problems
162-
*/
163-
private void readObject(ObjectInputStream inStream) throws IOException,
164-
ClassNotFoundException {
165-
inStream.defaultReadObject();
166-
validate();
167-
}
168-
169154
/**
170155
* Validate the data: those fields which must be non empty, must be set.
171156
* @throws ValidationFailure if the data is invalid

hadoop-tools/hadoop-aws/src/main/java/org/apache/hadoop/fs/s3a/commit/files/SinglePendingCommit.java

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@
2020

2121
import javax.annotation.Nullable;
2222
import java.io.IOException;
23-
import java.io.ObjectInputStream;
2423
import java.io.Serializable;
2524
import java.net.URI;
2625
import java.net.URISyntaxException;
@@ -186,21 +185,6 @@ public static SinglePendingCommit load(FileSystem fs,
186185
return instance;
187186
}
188187

189-
/**
190-
* Deserialize via java Serialization API: deserialize the instance
191-
* and then call {@link #validate()} to verify that the deserialized
192-
* data is valid.
193-
* @param inStream input stream
194-
* @throws IOException IO problem
195-
* @throws ClassNotFoundException reflection problems
196-
* @throws ValidationFailure validation failure
197-
*/
198-
private void readObject(ObjectInputStream inStream) throws IOException,
199-
ClassNotFoundException {
200-
inStream.defaultReadObject();
201-
validate();
202-
}
203-
204188
/**
205189
* Set the various timestamp fields to the supplied value.
206190
* @param millis time in milliseconds

hadoop-tools/hadoop-aws/src/main/java/org/apache/hadoop/fs/s3a/commit/files/UploadEtag.java

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
import software.amazon.awssdk.services.s3.model.CompletedPart;
2626

2727
/**
28-
* Stores ETag and checksum values from {@link CompletedPart} responses from S3.
28+
* Stores ETag and checksum values from {@link CompletedPart} responses from S3.
2929
* These values need to be stored to be later passed to the
3030
* {@link software.amazon.awssdk.services.s3.model.CompleteMultipartUploadRequest
3131
* CompleteMultipartUploadRequest}
@@ -37,8 +37,17 @@ public class UploadEtag implements Serializable {
3737
*/
3838
private static final long serialVersionUID = 1L;
3939

40+
/**
41+
* CompletedPart's ETag value.
42+
*/
4043
private String etag;
44+
/**
45+
* Algorithm used to calculate the checksum.
46+
*/
4147
private String checksumAlgorithm;
48+
/**
49+
* CompletedPart's checksum value.
50+
*/
4251
private String checksum;
4352

4453
public UploadEtag() {

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
import org.apache.hadoop.conf.Configuration;
3232
import org.apache.hadoop.fs.s3a.S3AUtils;
3333

34+
import static org.apache.hadoop.fs.s3a.Constants.DEFAULT_S3_ENCRYPTION_CONTEXT;
3435
import static org.apache.hadoop.fs.s3a.Constants.S3_ENCRYPTION_CONTEXT;
3536

3637
/**
@@ -61,7 +62,7 @@ public static String getS3EncryptionContext(String bucket, Configuration conf)
6162
}
6263
if (encryptionContext == null) {
6364
// no encryption context, return ""
64-
return "";
65+
return DEFAULT_S3_ENCRYPTION_CONTEXT;
6566
}
6667
return encryptionContext;
6768
}

0 commit comments

Comments
 (0)