Skip to content

Commit

Permalink
test(GHW): Run Java Examples for PR CI (#749)
Browse files Browse the repository at this point in the history
  • Loading branch information
texastony committed Nov 15, 2024
1 parent 50933bb commit b5eecdb
Show file tree
Hide file tree
Showing 11 changed files with 293 additions and 100 deletions.
58 changes: 58 additions & 0 deletions .github/workflows/library_examples.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
# "Copyright Amazon.com Inc. or its affiliates. All Rights Reserved."
# "SPDX-License-Identifier: CC-BY-SA-4.0"
# This workflow runs any examples.
name: Library Examples
on:
workflow_call:
inputs:
dafny:
description: "The Dafny version to run"
required: true
type: string

jobs:
java:
runs-on: ubuntu-latest
permissions:
id-token: write
contents: read
defaults:
run:
shell: bash
steps:
- name: Support longpaths on Git checkout
run: |
git config --global core.longpaths true
- name: Configure AWS Credentials for Tests
uses: aws-actions/configure-aws-credentials@v4
with:
aws-region: us-west-2
role-to-assume: arn:aws:iam::370957321024:role/GitHub-CI-MPL-Dafny-Role-us-west-2
role-session-name: JavaExampleTests

- uses: actions/checkout@v4
- run: git submodule update --init libraries
- run: git submodule update --init smithy-dafny

- name: Setup Dafny
uses: dafny-lang/[email protected]
with:
dafny-version: ${{ inputs.dafny }}

- name: Setup Java 8
uses: actions/setup-java@v3
with:
distribution: "corretto"
java-version: 8

- name: Build AwsCryptographicMaterialProviders Java implementation
working-directory: ./AwsCryptographicMaterialProviders
run: |
# This works because `node` is installed by default on GHA runners
CORES=$(node -e 'console.log(os.cpus().length)')
make build_java CORES=$CORES
- name: Test AwsCryptographicMaterialProviders Java Examples
working-directory: ./AwsCryptographicMaterialProviders
run: |
make test_example_java
6 changes: 6 additions & 0 deletions .github/workflows/pull.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,11 @@ jobs:
uses: ./.github/workflows/library_java_tests.yml
with:
dafny: ${{needs.getVersion.outputs.version}}
pr-ci-examples:
needs: getVersion
uses: ./.github/workflows/library_examples.yml
with:
dafny: ${{needs.getVersion.outputs.version}}
pr-ci-net:
needs: getVersion
uses: ./.github/workflows/library_net_tests.yml
Expand All @@ -55,6 +60,7 @@ jobs:
- pr-ci-java
- pr-ci-net
- pr-interop-test
- pr-ci-examples
runs-on: ubuntu-latest
steps:
- name: Verify all required jobs passed
Expand Down
5 changes: 2 additions & 3 deletions AwsCryptographicMaterialProviders/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,5 @@ PYTHON_DEPENDENCY_MODULE_NAMES := \
--dependency-library-name=aws.cryptography.keyStore=aws_cryptographic_material_providers \
--dependency-library-name=aws.cryptography.keyStoreAdmin=aws_cryptographic_material_providers \

_polymorph_dependencies:
@echo "No polymorphing of dependency"

test_example_java:
$(GRADLEW) -p runtimes/java testExamples
3 changes: 3 additions & 0 deletions AwsCryptographicMaterialProviders/runtimes/java/README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
[//]: # "Copyright Amazon.com Inc. or its affiliates. All Rights Reserved."
[//]: # "SPDX-License-Identifier: CC-BY-SA-4.0"

# AWS Cryptographic Material Providers Library

The AWS Cryptographic Material Providers Library abstracts lower level cryptographic materials management of encryption and decryption materials.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
[//]: # "Copyright Amazon.com Inc. or its affiliates. All Rights Reserved."
[//]: # "SPDX-License-Identifier: CC-BY-SA-4.0"

## Examples (Java)

This project contains examples demonstrating how to use the
AWS Cryptographic Material Providers Library (MPL) in Java.

```
├── ..
└── Hierarchy: Examples for manging the Hierarchical Keyring's Key Store
```
Original file line number Diff line number Diff line change
Expand Up @@ -2,24 +2,19 @@
// SPDX-License-Identifier: Apache-2.0
package software.amazon.cryptography.example.hierarchy;

import java.util.Collections;
import java.util.Map;
import javax.annotation.Nullable;
import software.amazon.awssdk.services.dynamodb.DynamoDbClient;
import software.amazon.awssdk.services.kms.KmsClient;
import software.amazon.cryptography.keystore.model.AwsKms;
import software.amazon.cryptography.keystoreadmin.KeyStoreAdmin;
import software.amazon.cryptography.keystoreadmin.model.CreateKeyInput;
import software.amazon.cryptography.keystoreadmin.model.KMSIdentifier;
import software.amazon.cryptography.keystoreadmin.model.KeyManagementStrategy;

/*
The Hierarchical Keyring Example and Searchable Encryption Examples
rely on the existence of a DDB-backed key store with pre-existing
branch key material or beacon key material.
The Hierarchical Keyring Example relies on the existence of a
key store with pre-existing branch key material or beacon key material.
See the "Create KeyStore Table Example" for how to first set up
the DDB Table that will back this KeyStore.
This example demonstrates configuring a KeyStore and then
This example demonstrates configuring a Key Store Admin and then
using a helper method to create a branch key and beacon key
that share the same Id, then return that Id.
We will always create a new beacon key alongside a new branch key,
Expand All @@ -33,37 +28,56 @@ public static String CreateKey(
String keyStoreTableName,
String logicalKeyStoreName,
String kmsKeyArn,
@Nullable DynamoDbClient dynamoDbClient,
@Nullable KmsClient kmsClient
@Nullable DynamoDbClient dynamoDbClient
) {
if (kmsClient == null) {
kmsClient = KmsClient.create();
}
// 1. Configure your Key Store Admin resource.
KeyStoreAdmin admin = AdminProvider.admin(
keyStoreTableName,
logicalKeyStoreName,
dynamoDbClient
);

// 2. If you need to specify the Identifier for a Branch Key, you may.
// This is an optional argument.
// If an Identifier is not provided, a v4 UUID will be generated and used.
// This example provides a combination of a fixed string and a v4 UUID;
// this makes it easy for Crypto Tools to clean up these Example Branch Keys.
final String branchKeyId =
"mpl-java-example-" + java.util.UUID.randomUUID().toString();

// 3. Create a custom encryption context for the Branch Key.
// Most encrypted data should have an associated encryption context
// to protect integrity. This sample uses placeholder values.
// Note that the custom encryption context for a Branch Key is
// prefixed by the library with `aws-crypto-ec:`.
// For more information see:
// blogs.aws.amazon.com/security/post/Tx2LZ6WBJJANTNW/How-to-Protect-the-Integrity-of-Your-Encrypted-Data-by-Using-AWS-Key-Management
final Map<String, String> encryptionContext = Collections.singletonMap(
"ExampleContextKey",
"ExampleContextValue"
);

// 2. Create a new branch key and beacon key in our KeyStore.
// Both the branch key and the beacon key will share an Id.
// This creation is eventually consistent.

final String branchKeyId = admin
final String actualBranchKeyId = admin
.CreateKey(
CreateKeyInput
.builder()
// This is the KMS ARN that will be used to protect the Branch Key.
// It is a required argument.
.kmsArn(KMSIdentifier.builder().kmsKeyArn(kmsKeyArn).build())
.strategy(
KeyManagementStrategy
.builder()
.AwsKmsReEncrypt(AwsKms.builder().kmsClient(kmsClient).build())
.build()
)
// If you need to specify the Identifier for a Branch Key, you may.
// This is an optional argument.
.branchKeyIdentifier(branchKeyId)
// If a branch key Identifier is provided,
// custom encryption context MUST be provided as well.
.encryptionContext(encryptionContext)
.build()
)
.branchKeyIdentifier();

assert actualBranchKeyId.equals(branchKeyId);
return branchKeyId;
}

Expand All @@ -76,6 +90,6 @@ public static void main(final String[] args) {
final String keyStoreTableName = args[0];
final String logicalKeyStoreName = args[1];
final String kmsKeyArn = args[2];
CreateKey(keyStoreTableName, logicalKeyStoreName, kmsKeyArn, null, null);
CreateKey(keyStoreTableName, logicalKeyStoreName, kmsKeyArn, null);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,26 +21,19 @@ public class MutationExample {
public static String End2End(
String keyStoreTableName,
String logicalKeyStoreName,
String kmsKeyArnOriginal,
String kmsKeyArnTerminal,
String branchKeyId,
@Nullable DynamoDbClient dynamoDbClient,
@Nullable KmsClient kmsClient
) {
kmsClient = AdminProvider.kms(kmsClient);
KeyManagementStrategy strategy = AdminProvider.strategy(kmsClient);
KeyStoreAdmin admin = AdminProvider.admin(
keyStoreTableName,
logicalKeyStoreName,
dynamoDbClient
);
KeyManagementStrategy strategy = AdminProvider.strategy(kmsClient);

String branchKeyId = CreateKeyExample.CreateKey(
keyStoreTableName,
logicalKeyStoreName,
kmsKeyArnOriginal,
dynamoDbClient,
kmsClient
);
System.out.println("BranchKey ID to mutate: " + branchKeyId);
HashMap<String, String> terminalEC = new HashMap<>();
terminalEC.put("Robbie", "is a dog.");
Expand Down Expand Up @@ -101,18 +94,18 @@ public static String End2End(
public static void main(final String[] args) {
if (args.length <= 1) {
throw new IllegalArgumentException(
"To run this example, include the keyStoreTableName, logicalKeyStoreName, kmsKeyOriginal, and kmsKeyTerminal in args"
"To run this example, include the keyStoreTableName, logicalKeyStoreName, and kmsKeyTerminal in args"
);
}
final String keyStoreTableName = args[0];
final String logicalKeyStoreName = args[1];
final String kmsKeyArnOriginal = args[2];
final String kmsKeyArnTerminal = args[3];
final String kmsKeyArnTerminal = args[2];
final String branchKeyId = args[3];
End2End(
keyStoreTableName,
logicalKeyStoreName,
kmsKeyArnOriginal,
kmsKeyArnTerminal,
branchKeyId,
null,
null
);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
package software.amazon.cryptography.example.hierarchy;

import javax.annotation.Nullable;
import software.amazon.awssdk.services.dynamodb.DynamoDbClient;
import software.amazon.cryptography.keystoreadmin.KeyStoreAdmin;
import software.amazon.cryptography.keystoreadmin.model.KMSIdentifier;
import software.amazon.cryptography.keystoreadmin.model.VersionKeyInput;

/*
There can only be one active version for each branch key at a time.
The Hierarchical keyring typically uses each active branch key version
to satisfy multiple requests.
But you control the extent to which active branch keys are reused
and determine how often the active branch key is rotated.
Branch keys are not used to encrypt plaintext data keys.
They are used to derive the unique wrapping keys
that encrypt plaintext data keys.
The wrapping key derivation process produces a
unique 32 byte wrapping key with 28 bytes of randomness.
This means that a branch key can derive more than 79 octillion, or 296,
unique wrapping keys before cryptographic wear-out occurs.
Despite this very low exhaustion risk,
you might be required to rotate your active branch keys more often.
The active version of the branch key remains active until you rotate it.
Previous versions of the active branch key will not
be used to perform encrypt operations and
cannot be used to derive new wrapping keys.
But they can still be queried and provide wrapping keys
to decrypt the data keys that they encrypted while active.
Use the Key Store Admin's VersionKey operation to
rotate your active branch key.
When you rotate the active branch key,
a new branch key is created to replace the previous version.
The branch-key-id does not change when you rotate the active branch key.
You must specify the branch-key-id that identifies
the current active branch key when you call VersionKey.
*/
public class VersionKeyExample {

public static String VersionKey(
String keyStoreTableName,
String logicalKeyStoreName,
String kmsKeyArn,
String branchKeyId,
@Nullable DynamoDbClient dynamoDbClient
) {
// 1. Configure your Key Store Admin resource.
KeyStoreAdmin admin = AdminProvider.admin(
keyStoreTableName,
logicalKeyStoreName,
dynamoDbClient
);

// 2. Version the Branch Key
admin.VersionKey(
VersionKeyInput
.builder()
// This is the KMS ARN that will be used to protect the Branch Key.
// It is a required argument.
// This ARN MUST match the ARN that protects the Branch Key.
.kmsArn(KMSIdentifier.builder().kmsKeyArn(kmsKeyArn).build())
// This the Identifier for the Branch Key that is being rotated/versioned.
.branchKeyIdentifier(branchKeyId)
.build()
);

return branchKeyId;
}

public static void main(final String[] args) {
if (args.length <= 1) {
throw new IllegalArgumentException(
"To run this example, include the keyStoreTableName, logicalKeyStoreName, and kmsKeyArn in args"
);
}
final String keyStoreTableName = args[0];
final String logicalKeyStoreName = args[1];
final String kmsKeyArn = args[2];
final String branchKeyId = args[3];
VersionKey(
keyStoreTableName,
logicalKeyStoreName,
kmsKeyArn,
branchKeyId,
null
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
import software.amazon.awssdk.services.kms.KmsClient;
import software.amazon.cryptography.example.hierarchy.AdminProvider;

public class TestUtils {
public class Fixtures {

public static final String TEST_KEYSTORE_NAME = "KeyStoreDdbTable";
public static final String TEST_LOGICAL_KEYSTORE_NAME = "KeyStoreDdbTable";
Expand Down
Loading

0 comments on commit b5eecdb

Please sign in to comment.