Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

X509 in ci #327

Merged
merged 18 commits into from
Feb 2, 2023
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
2097465
Run X509 sample in CI
TwistedTwigleg Oct 19, 2022
cabce4e
Fix CI yml file
TwistedTwigleg Oct 19, 2022
29ab00f
Correctly pass the CA file in CI
TwistedTwigleg Oct 19, 2022
35ad698
Properly remove CA file, fix readme not linking correctly to X509 mat…
TwistedTwigleg Oct 19, 2022
1c04cd8
Merge branch 'main' of https://github.com/aws/aws-iot-device-sdk-java…
TwistedTwigleg Nov 9, 2022
cfd3e7f
Initial step to simplify run_sample_ci and make it based on JSON conf…
TwistedTwigleg Nov 10, 2022
105afbe
Fix error in pure data fields in run_sample_ci
TwistedTwigleg Nov 10, 2022
d59705a
Fix Windows cert connect sample using wrong path
TwistedTwigleg Nov 10, 2022
8ae2a5e
Fix websockets not running correctly in CI
TwistedTwigleg Nov 10, 2022
22b503c
Fix PKCS11 and Windows Cert sample running
TwistedTwigleg Nov 10, 2022
acfaeb6
Further PKCS11 and Windows Cert Connect fixes
TwistedTwigleg Nov 10, 2022
a3e8a56
Hopefully last minor change to fix WindowsCertConnect
TwistedTwigleg Nov 10, 2022
b068606
Merge branch 'main' into X509InCI
TwistedTwigleg Nov 10, 2022
d3060d2
Sync run_sample_ci for Javascript fixes
TwistedTwigleg Nov 10, 2022
e0f1a23
Merge branch 'X509InCI' of https://github.com/aws/aws-iot-device-sdk-…
TwistedTwigleg Nov 10, 2022
1aaa700
Merge branch 'main' of https://github.com/aws/aws-iot-device-sdk-java…
TwistedTwigleg Feb 2, 2023
cd28d75
Add the new samples to the improved workflow
TwistedTwigleg Feb 2, 2023
1386fcd
Trivial change to bump CI
TwistedTwigleg Feb 2, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ env:
CI_JOBS_ROLE: ${{ secrets.AWS_CI_JOBS_ROLE }}
CI_FLEET_PROVISIONING_ROLE: ${{ secrets.AWS_CI_FLEET_PROVISIONING_ROLE }}
CI_DEVICE_ADVISOR: ${{ secrets.AWS_CI_DEVICE_ADVISOR_ROLE }}
CI_X509_ROLE: ${{ secrets.AWS_CI_X509_ROLE }}

jobs:
linux-compat:
Expand Down Expand Up @@ -301,3 +302,11 @@ jobs:
Sample_UUID=$(python3 -c "import uuid; print (uuid.uuid4())")
python3 ./utils/run_sample_ci.py --language Java --sample_file 'samples/Identity' --sample_region ${{ env.AWS_DEFAULT_REGION }} --sample_secret_endpoint 'ci/endpoint' --sample_secret_certificate 'ci/FleetProvisioning/cert' --sample_secret_private_key 'ci/FleetProvisioning/key' --sample_arguments "--template_name CI_FleetProvisioning_Template --template_parameters '{SerialNumber:${Sample_UUID}}'" --sample_main_class 'identity.FleetProvisioningSample'
python3 utils/delete_iot_thing_ci.py --thing_name "Fleet_Thing_${Sample_UUID}" --region "us-east-1"
- name: configure AWS credentials (X509)
uses: aws-actions/configure-aws-credentials@v1
with:
role-to-assume: ${{ env.CI_X509_ROLE }}
aws-region: ${{ env.AWS_DEFAULT_REGION }}
- name: run X509 sample
run: |
python3 ./utils/run_sample_ci.py --language Java --sample_file 'samples/X509CredentialsProviderConnect' --sample_region ${{ env.AWS_DEFAULT_REGION }} --sample_secret_endpoint 'ci/endpoint' --sample_secret_certificate_x509 'ci/PubSub/cert' --sample_secret_private_key_x509 'ci/PubSub/key' --sample_secret_ca_x509 'ci/PubSub/ca' --sample_secret_endpoint_x509 'ci/X509/endpoint_credentials' --sample_secret_alias_x509 'ci/X509/alias' --sample_arguments '--signing_region us-east-1 --x509_thing_name CI_PubSub_Thing' --sample_main_class 'x509credentialsproviderconnect.X509CredentialsProviderConnect'
49 changes: 49 additions & 0 deletions samples/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
* [Pkcs11 Connect](#pkcs11-connect)
* [Raw Connect](#raw-connect)
* [WindowsCert Connect](#windowscert-connect)
* [X509 Connect](#x509-credentials-provider-connect)
* [CustomAuthorizer Connect](#custom-authorizer-connect)
* [CustomKeyOperationPubSub](#custom-key-operations-pubsub)
* [Shadow](#shadow)
Expand Down Expand Up @@ -369,6 +370,54 @@ Your Thing's [Policy](https://docs.aws.amazon.com/iot/latest/developerguide/iot-
</pre>
</details>

## x509 Credentials Provider Connect

This sample is similar to the [Basic Pub-Sub](#basic-pub-sub), but the connection uses a X.509 certificate
to source the AWS credentials when connecting.

See the [Authorizing direct calls to AWS services using AWS IoT Core credential provider](https://docs.aws.amazon.com/iot/latest/developerguide/authorizing-direct-aws.html) page for instructions on how to setup the IAM roles, the trust policy for the IAM roles, how to setup the IoT Core Role alias, and how to get the credential provider endpoint for your AWS account.

source: `samples/X509CredentialsProviderConnect`

To run the x509 Credentials Provider Connect sample use the following command:

``` sh
mvn compile exec:java -pl samples/X509CredentialsProviderConnect "-Dexec.mainClass=x509credentialsproviderconnect.X509CredentialsProviderConnect" -Dexec.args=' --endpoint <endpoint> --ca_file <path to root CA> --signing_region <signing region> --x509_ca_file <path to x509 CA> --x509_cert <path to x509 cert> --x509_endpoint <x509 credentials endpoint> --x509_key <path to x509 key> --x509_role_alias <alias> -x509_thing_name <thing name>'
```

To run the sample using the latest SDK release:

``` sh
mvn -P latest-release compile exec:java -pl samples/X509CredentialsProviderConnect "-Dexec.mainClass=x509credentialsproviderconnect.X509CredentialsProviderConnect" -Dexec.args=' --endpoint <endpoint> --ca_file <path to root CA> --signing_region <signing region> --x509_ca_file <path to x509 CA> --x509_cert <path to x509 cert> --x509_endpoint <x509 credentials endpoint> --x509_key <path to x509 key> --x509_role_alias <alias> -x509_thing_name <thing name>'
```

Your Thing's [Policy](https://docs.aws.amazon.com/iot/latest/developerguide/iot-policies.html) must provide privileges for this sample to connect. Make sure your policy allows a client ID of `test-*` to connect or use `--client_id <client ID here>` to send the client ID your policy supports.

<details>
<summary>(see sample policy)</summary>
<pre>
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"iot:Connect"
],
"Resource": [
"arn:aws:iot:<b>region</b>:<b>account</b>:client/test-*"
]
},
{
"Effect":"Allow",
"Action":"iot:AssumeRoleWithCertificate",
"Resource":"arn:aws:iot:<b>region</b>:<b>account</b>:rolealias/<b>role-alias</b>"
}
]
}
</pre>
</details>

## Custom Authorizer Connect

This sample makes an MQTT connection and connects through a [Custom Authorizer](https://docs.aws.amazon.com/iot/latest/developerguide/custom-authentication.html). On startup, the device connects to the server and then disconnects. This sample is for reference on connecting using a custom authorizer.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ public void addCommonX509Commands()
{
registerCommand(
m_cmd_x509_role, "<str>", "Role alias to use with the x509 credentials provider (required for x509)");
registerCommand(m_cmd_x509_endpoint, "<str>", "Endpoint to fetch x509 credentials from (required for x509)");
registerCommand(m_cmd_x509_endpoint, "<str>", "The credentials endpoint to fetch x509 credentials from (required for x509)");
registerCommand(
m_cmd_x509_thing_name, "<str>", "Thing name to fetch x509 credentials on behalf of (required for x509)");
registerCommand(
Expand Down Expand Up @@ -167,7 +167,7 @@ public MqttClientConnection buildCustomKeyOperationConnection(
buildConnectionSetupCAFileDefaults(builder);
buildConnectionSetupConnectionDefaults(builder, callbacks);
buildConnectionSetupProxyDefaults(builder);

MqttClientConnection conn = builder.build();
builder.close();
return conn;
Expand Down Expand Up @@ -250,6 +250,7 @@ public MqttClientConnection buildWebsocketX509MQTTConnection(MqttClientConnectio

MqttClientConnection conn = builder.build();
builder.close();
provider.close();
return conn;

} catch (CrtRuntimeException ex) {
Expand Down
81 changes: 78 additions & 3 deletions utils/run_sample_ci.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
current_folder += "/"
tmp_certificate_file_path = str(current_folder) + "tmp_certificate.pem"
tmp_private_key_path = str(current_folder) + "tmp_privatekey.pem.key"
tmp_ca_file_path = str(current_folder) + "tmp_ca.pem"
tmp_pfx_file_path = str(current_folder) + "tmp_pfx_certificate.pfx"
tmp_pfx_certificate_path = ""
tmp_pfx_certificate_store_location = "CurrentUser\\My"
Expand All @@ -26,6 +27,7 @@
def get_secrets_and_launch(parsed_commands):
global tmp_certificate_file_path
global tmp_private_key_path
global tmp_ca_file_path
global tmp_pfx_file_path
global tmp_pfx_certificate_path
exit_code = 0
Expand All @@ -34,6 +36,11 @@ def get_secrets_and_launch(parsed_commands):
sample_private_key = ""
sample_custom_authorizer_name = ""
sample_custom_authorizer_password = ""
sample_certificate_x509 = ""
sample_private_key_x509 = ""
sample_ca_x509 = ""
sample_endpoint_x509 = ""
sample_role_alias_x509 = ""
TwistedTwigleg marked this conversation as resolved.
Show resolved Hide resolved

print("Attempting to get credentials from secrets using Boto3...")
secrets_client = boto3.client(
Expand All @@ -56,13 +63,42 @@ def get_secrets_and_launch(parsed_commands):
# lgtm [py/clear-text-storage-sensitive-data]
file.write(secret_data["SecretString"])
sample_private_key = tmp_private_key_path

if (parsed_commands.sample_secret_custom_authorizer_name != ""):
sample_custom_authorizer_name = secrets_client.get_secret_value(
SecretId=parsed_commands.sample_secret_custom_authorizer_name)["SecretString"]
if (parsed_commands.sample_secret_custom_authorizer_password != ""):
sample_custom_authorizer_password = secrets_client.get_secret_value(
SecretId=parsed_commands.sample_secret_custom_authorizer_password)["SecretString"]

if (parsed_commands.sample_secret_certificate_x509 != ""):
secret_data = secrets_client.get_secret_value(
SecretId=parsed_commands.sample_secret_certificate_x509)
with open(tmp_certificate_file_path, "w") as file:
# lgtm [py/clear-text-storage-sensitive-data]
file.write(secret_data["SecretString"])
sample_certificate_x509 = tmp_certificate_file_path
if (parsed_commands.sample_secret_private_key_x509 != ""):
secret_data = secrets_client.get_secret_value(
SecretId=parsed_commands.sample_secret_private_key_x509)
with open(tmp_private_key_path, "w") as file:
# lgtm [py/clear-text-storage-sensitive-data]
file.write(secret_data["SecretString"])
sample_private_key_x509 = tmp_private_key_path
if (parsed_commands.sample_secret_ca_x509 != ""):
secret_data = secrets_client.get_secret_value(
SecretId=parsed_commands.sample_secret_ca_x509)
with open(tmp_ca_file_path, "w") as file:
# lgtm [py/clear-text-storage-sensitive-data]
file.write(secret_data["SecretString"])
sample_ca_x509 = tmp_ca_file_path
if (parsed_commands.sample_secret_endpoint_x509 != ""):
sample_endpoint_x509 = secrets_client.get_secret_value(
SecretId=parsed_commands.sample_secret_endpoint_x509)["SecretString"]
if (parsed_commands.sample_secret_alias_x509 != ""):
sample_role_alias_x509 = secrets_client.get_secret_value(
SecretId=parsed_commands.sample_secret_alias_x509)["SecretString"]

except Exception:
sys.exit("ERROR: Could not get secrets to launch sample!")

Expand All @@ -78,8 +114,17 @@ def get_secrets_and_launch(parsed_commands):
exit_code = extra_step_return
if (extra_step_return == 0):
print("Launching sample...")
exit_code = launch_sample(parsed_commands, sample_endpoint, sample_certificate,
sample_private_key, sample_custom_authorizer_name, sample_custom_authorizer_password)
exit_code = launch_sample(parsed_commands=parsed_commands,
sample_endpoint=sample_endpoint,
sample_certificate=sample_certificate,
sample_private_key=sample_private_key,
sample_custom_authorizer_name=sample_custom_authorizer_name,
sample_custom_authorizer_password=sample_custom_authorizer_password,
sample_certificate_x509=sample_certificate_x509,
sample_private_key_x509=sample_private_key_x509,
sample_ca_x509=sample_ca_x509,
sample_endpoint_x509=sample_endpoint_x509,
sample_role_alias_x509=sample_role_alias_x509)

if (exit_code == 0):
print("SUCCESS: Finished running sample! Exiting with success")
Expand All @@ -95,6 +140,8 @@ def get_secrets_and_launch(parsed_commands):
os.remove(tmp_private_key_path)
if (os.path.isfile(tmp_pfx_file_path)):
os.remove(tmp_pfx_file_path)
if (os.path.isfile(tmp_ca_file_path)):
os.remove(tmp_ca_file_path)

return exit_code

Expand Down Expand Up @@ -200,7 +247,10 @@ def make_windows_pfx_file():
return 1


def launch_sample(parsed_commands, sample_endpoint, sample_certificate, sample_private_key, sample_custom_authorizer_name, sample_custom_authorizer_password):
def launch_sample(parsed_commands, sample_endpoint, sample_certificate, sample_private_key,
sample_custom_authorizer_name, sample_custom_authorizer_password,
sample_certificate_x509, sample_private_key_x509, sample_ca_x509,
sample_endpoint_x509, sample_role_alias_x509):
global tmp_certificate_file_path
global tmp_private_key_path
global tmp_pfx_file_path
Expand All @@ -223,6 +273,21 @@ def launch_sample(parsed_commands, sample_endpoint, sample_certificate, sample_p
if (sample_custom_authorizer_password != ""):
launch_arguments.append("--custom_auth_password")
launch_arguments.append(sample_custom_authorizer_password)
if (sample_certificate_x509 != ""):
launch_arguments.append("--x509_cert")
launch_arguments.append(sample_certificate_x509)
if (sample_private_key_x509 != ""):
launch_arguments.append("--x509_key")
launch_arguments.append(sample_private_key_x509)
if (sample_ca_x509 != ""):
launch_arguments.append("--x509_ca_file")
launch_arguments.append(sample_ca_x509)
if (sample_endpoint_x509 != ""):
launch_arguments.append("--x509_endpoint")
launch_arguments.append(sample_endpoint_x509)
if (sample_role_alias_x509 != ""):
launch_arguments.append("--x509_role_alias")
launch_arguments.append(sample_role_alias_x509)
if (parsed_commands.sample_arguments != ""):
sample_arguments_split = parsed_commands.sample_arguments.split(" ")
for arg in sample_arguments_split:
Expand Down Expand Up @@ -329,6 +394,16 @@ def main():
argument_parser.add_argument("--sample_run_certutil", metavar="<Set to 'True' to run Certutil (Windows ONLY)>", required=False,
default="", help="Runs CertUtil on the private key and certificate passed and makes a certificate.pfx file, "
"which is used automatically in the --cert argument. Used for Windows Certificate Connect sample")
argument_parser.add_argument("--sample_secret_certificate_x509", metavar="<Name of certificate secret to use in X509>", required=False,
default="", help="The name of the secret containing the certificate PEM file to use in X509")
argument_parser.add_argument("--sample_secret_private_key_x509", metavar="<Name of private key secret to use in X509>", required=False,
default="", help="The name of the secret containing the private key PEM file to use in X509")
argument_parser.add_argument("--sample_secret_ca_x509", metavar="<Name of CA key secret to use in X509>", required=False,
default="", help="The name of the secret containing the CA PEM file to use in X509")
argument_parser.add_argument("--sample_secret_endpoint_x509", metavar="<Name of credentials provider endpoint secret>",
required=False, default="", help="The name of the secret containing the credentials provider endpoint (X509)")
argument_parser.add_argument("--sample_secret_alias_x509", metavar="<Name of the IoT role alias secret>",
required=False, default="", help="The name of the secret containing the IoT Core role alias (X509)")
argument_parser.add_argument("--sample_arguments", metavar="<Arguments here in single string!>",
required=False, default="",
help="Arguments to pass to sample. In Java, these arguments will be in a double quote (\") string")
Expand Down