Skip to content

Commit e410e34

Browse files
authored
Use consistent encoding for GBEK across languages (#36431)
* Use consistent encoding for GBEK across languages * syntax * build * fmt
1 parent 303c4a2 commit e410e34

6 files changed

Lines changed: 32 additions & 13 deletions

File tree

sdks/java/core/src/main/java/org/apache/beam/sdk/options/PipelineOptions.java

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -420,7 +420,7 @@ public Long create(PipelineOptions options) {
420420
* <p>Beam will infer the secret type and value based on the secret itself. This guarantees that
421421
* any data at rest during the performing a GBK, so this can be used to guarantee that data is not
422422
* unencrypted. Runners with this behavior include the Dataflow, Flink, and Spark runners. The
423-
* option should be structured like:
423+
* secret should be a url safe base64 encoded 32 byte value. The option should be structured like:
424424
*
425425
* <pre><code>
426426
* --gbek=type:<secret_type>;<secret_param>:<value>
@@ -432,14 +432,19 @@ public Long create(PipelineOptions options) {
432432
* --gbek=type:GcpSecret;version_name:my_secret/versions/latest"
433433
* </code></pre>
434434
*
435-
* All variables should use snake case to allow consistency across languages.
435+
* All variables should use snake case to allow consistency across languages. For an example of
436+
* generating a properly formatted secret, see
437+
* https://github.com/apache/beam/blob/c8df4da229da49d533491857e1bb4ab5dbf4fd37/sdks/java/core/src/test/java/org/apache/beam/sdk/transforms/GroupByKeyIT.java#L82
436438
*/
437439
@Description(
438440
"When set, will replace all GroupByKey transforms in the pipeline the option. Beam will"
439441
+ " infer the secret type and value based on the secret itself. This guarantees that"
440442
+ " any data at rest during the performing a GBK, so this can be used to guarantee"
441443
+ " that data is not unencrypted. Runners with this behavior include the Dataflow,"
442-
+ " Flink, and Spark runners. The option should be structured like:"
444+
+ " Flink, and Spark runners. The secret should be a url safe base64 encoded 32 byte"
445+
+ " value. For an example of generating a properly formatted secret, see"
446+
+ " https://github.com/apache/beam/blob/c8df4da229da49d533491857e1bb4ab5dbf4fd37/sdks/java/core/src/test/java/org/apache/beam/sdk/transforms/GroupByKeyIT.java#L82"
447+
+ " When passing in the gbek option, it should be structured like:"
443448
+ " --gbek=type:<secret_type>;<secret_param>:<value>, for example "
444449
+ " --gbek=type:GcpSecret;version_name:my_secret/versions/latest. All variables "
445450
+ " should use snake case to allow consistency across languages.")

sdks/java/core/src/main/java/org/apache/beam/sdk/transforms/GroupByEncryptedKey.java

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,8 @@
3939
* the output. This is useful when the keys contain sensitive data that should not be stored at rest
4040
* by the runner.
4141
*
42-
* <p>The transform requires a {@link Secret} which returns a 32 byte secret which can be used to
43-
* generate a {@link SecretKeySpec} object using the HmacSHA256 algorithm.
42+
* <p>The transform requires a {@link Secret} which returns a base64 encoded 32 byte secret which
43+
* can be used to generate a {@link SecretKeySpec} object using the HmacSHA256 algorithm.
4444
*
4545
* <p>Note the following caveats: 1) Runners can implement arbitrary materialization steps, so this
4646
* does not guarantee that the whole pipeline will not have unencrypted data at rest by itself. 2)
@@ -153,7 +153,7 @@ private static class EncryptMessage<K, V> extends DoFn<KV<K, V>, KV<byte[], KV<b
153153
@Setup
154154
public void setup() {
155155
try {
156-
byte[] secretBytes = this.hmacKey.getSecretBytes();
156+
byte[] secretBytes = java.util.Base64.getUrlDecoder().decode(this.hmacKey.getSecretBytes());
157157
this.mac = Mac.getInstance("HmacSHA256");
158158
this.mac.init(new SecretKeySpec(secretBytes, "HmacSHA256"));
159159
this.cipher = Cipher.getInstance("AES/GCM/NoPadding");
@@ -229,7 +229,9 @@ private static class DecryptMessage<K, V>
229229
public void setup() {
230230
try {
231231
this.cipher = Cipher.getInstance("AES/GCM/NoPadding");
232-
this.secretKeySpec = new SecretKeySpec(this.hmacKey.getSecretBytes(), "AES");
232+
this.secretKeySpec =
233+
new SecretKeySpec(
234+
java.util.Base64.getUrlDecoder().decode(this.hmacKey.getSecretBytes()), "AES");
233235
} catch (Exception ex) {
234236
throw new RuntimeException(
235237
"Failed to initialize cryptography libraries needed for GroupByEncryptedKey", ex);

sdks/java/core/src/test/java/org/apache/beam/sdk/transforms/GroupByEncryptedKeyTest.java

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ public class GroupByEncryptedKeyTest implements Serializable {
5858

5959
private static class FakeSecret implements Secret {
6060
private final byte[] secret =
61-
"aKwI2PmqYFt2p5tNKCyBS5qYmHhHsGZc".getBytes(Charset.defaultCharset());
61+
"YUt3STJQbXFZRnQycDV0TktDeUJTNXFZV0hoSHNHWmM".getBytes(Charset.defaultCharset());
6262

6363
@Override
6464
public byte[] getSecretBytes() {
@@ -123,7 +123,10 @@ public static void setup() throws IOException {
123123
byte[] secretBytes = new byte[32];
124124
new SecureRandom().nextBytes(secretBytes);
125125
client.addSecretVersion(
126-
secretName, SecretPayload.newBuilder().setData(ByteString.copyFrom(secretBytes)).build());
126+
secretName,
127+
SecretPayload.newBuilder()
128+
.setData(ByteString.copyFrom(java.util.Base64.getUrlEncoder().encode(secretBytes)))
129+
.build());
127130
}
128131
gcpSecret = new GcpSecret(secretName.toString() + "/versions/latest");
129132
}

sdks/java/core/src/test/java/org/apache/beam/sdk/transforms/GroupByKeyIT.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,10 @@ public static void setup() throws IOException {
8282
byte[] secretBytes = new byte[32];
8383
new SecureRandom().nextBytes(secretBytes);
8484
client.addSecretVersion(
85-
secretName, SecretPayload.newBuilder().setData(ByteString.copyFrom(secretBytes)).build());
85+
secretName,
86+
SecretPayload.newBuilder()
87+
.setData(ByteString.copyFrom(java.util.Base64.getUrlEncoder().encode(secretBytes)))
88+
.build());
8689
}
8790
gcpSecretVersionName = secretName.toString() + "/versions/latest";
8891
}

sdks/java/core/src/test/java/org/apache/beam/sdk/transforms/GroupByKeyTest.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,9 @@ public static void setup() throws IOException {
153153
new SecureRandom().nextBytes(secretBytes);
154154
client.addSecretVersion(
155155
secretName,
156-
SecretPayload.newBuilder().setData(ByteString.copyFrom(secretBytes)).build());
156+
SecretPayload.newBuilder()
157+
.setData(ByteString.copyFrom(java.util.Base64.getUrlEncoder().encode(secretBytes)))
158+
.build());
157159
}
158160
gcpSecretVersionName = secretName.toString() + "/versions/latest";
159161
}

sdks/python/apache_beam/options/pipeline_options.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1726,8 +1726,12 @@ def _add_argparse_args(cls, parser):
17261726
'secret itself. This guarantees that any data at rest during the '
17271727
'GBK will be encrypted. Many runners only store data at rest when '
17281728
'performing a GBK, so this can be used to guarantee that data is '
1729-
'not unencrypted. Runners with this behavior include the '
1730-
'Dataflow, Flink, and Spark runners. The option should be '
1729+
'not unencrypted. The secret should be a url safe base64 encoded '
1730+
'32 byte value. To generate a secret in this format, you can use '
1731+
'Secret.generate_secret_bytes(). For an example of this, see '
1732+
'https://github.com/apache/beam/blob/c8df4da229da49d533491857e1bb4ab5dbf4fd37/sdks/python/apache_beam/transforms/util_test.py#L356. ' # pylint: disable=line-too-long
1733+
'Runners with this behavior include the Dataflow, '
1734+
'Flink, and Spark runners. The option should be '
17311735
'structured like: '
17321736
'--gbek=type:<secret_type>;<secret_param>:<value>, for example '
17331737
'--gbek=type:GcpSecret;version_name:my_secret/versions/latest'))

0 commit comments

Comments
 (0)