Skip to content

Commit

Permalink
Merge branch 'main' into change_aws_secret_access
Browse files Browse the repository at this point in the history
  • Loading branch information
bretambrose authored Aug 23, 2023
2 parents 88dd2fe + 36b13af commit 0b1f6ce
Show file tree
Hide file tree
Showing 21 changed files with 414 additions and 105 deletions.
1 change: 1 addition & 0 deletions .builder/actions/build_samples.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ def run(self, env):
'samples/mqtt/basic_connect',
'samples/mqtt/custom_authorizer_connect',
'samples/mqtt/pkcs11_connect',
'samples/mqtt/pkcs12_connect',
'samples/mqtt/websocket_connect',
'samples/mqtt/windows_cert_connect',
'samples/mqtt/x509_credentials_provider_connect',
Expand Down
18 changes: 18 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -313,6 +313,7 @@ jobs:
runs-on: macos-latest
permissions:
id-token: write # This is required for requesting the JWT
security-events: write # This is required for pkcs12 sample to sign the key
steps:
- name: Build ${{ env.PACKAGE_NAME }} + consumers
run: |
Expand All @@ -330,6 +331,23 @@ jobs:
- name: run MQTT3 PubSub sample
run: |
python3 ${{ env.CI_UTILS_FOLDER }}/run_sample_ci.py --file ${{ env.CI_SAMPLES_CFG_FOLDER }}/ci_run_pubsub_cfg.json
- name: run PKCS12 sample
run: |
aws s3 cp s3://iot-sdk-ci-bucket-us-east1/pkcs12_identity.p12 ./pkcs12_identity.p12
pkcs12_identity_name=$(aws secretsmanager get-secret-value --region us-east-1 --secret-id "ci/macos/pkcs12_identity" --query "SecretString" | cut -f2 -d":" | cut -f2 -d\")
pkcs12_identity_password=$(aws secretsmanager get-secret-value --region us-east-1 --secret-id "ci/macos/pkcs12_identity_password" --query "SecretString" | cut -f2 -d":" | cut -f2 -d\")
cert=$(aws secretsmanager get-secret-value --region us-east-1 --secret-id "ci/PubSub/cert" --query "SecretString" | cut -f2 -d":" | cut -f2 -d\") && echo -e "$cert" > /tmp/certificate.pem
key=$(aws secretsmanager get-secret-value --region us-east-1 --secret-id "ci/PubSub/key" --query "SecretString" | cut -f2 -d":" | cut -f2 -d\") && echo -e "$key" > /tmp/privatekey.pem
iot_pkcs12_password=$(aws secretsmanager get-secret-value --region us-east-1 --secret-id "ci/PubSub/key_pkcs12_password" --query "SecretString" | cut -f2 -d":" | cut -f2 -d\")
openssl pkcs12 -export -in /tmp/certificate.pem -inkey /tmp/privatekey.pem -out ./iot_pkcs12_key.p12 -name PubSub_Thing_Alias -password pass:$iot_pkcs12_password
security create-keychain -p test_password build.keychain
security set-keychain-settings -lut 21600 build.keychain
security default-keychain -s build.keychain
security unlock-keychain -p test_password build.keychain
security import pkcs12_identity.p12 -A -k build.keychain -f pkcs12 -P $pkcs12_identity_password -T /usr/bin/codesign -T /usr/bin/security
security set-key-partition-list -S 'apple-tool:,apple:' -k test_password build.keychain
/usr/bin/codesign --force -s $pkcs12_identity_name ./aws-iot-device-sdk-cpp-v2/build/samples/mqtt/pkcs12_connect/pkcs12-connect -v
python3 ${{ env.CI_UTILS_FOLDER }}/run_sample_ci.py --file ${{ env.CI_SAMPLES_CFG_FOLDER }}/ci_run_pkcs12_connect_cfg.json
- name: configure AWS credentials (MQTT5)
uses: aws-actions/configure-aws-credentials@v1
with:
Expand Down
24 changes: 24 additions & 0 deletions .github/workflows/ci_run_pkcs12_connect_cfg.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
{
"language": "CPP",
"sample_file": "./aws-iot-device-sdk-cpp-v2/build/samples/mqtt/pkcs12_connect/pkcs12-connect",
"sample_region": "us-east-1",
"sample_main_class": "",
"arguments": [
{
"name": "--endpoint",
"secret": "ci/endpoint"
},
{
"name": "--pkcs12_file",
"data": "./iot_pkcs12_key.p12"
},
{
"name": "--pkcs12_password",
"secret": "ci/PubSub/key_pkcs12_password"
},
{
"name": "--verbosity",
"data": "Trace"
}
]
}
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -143,4 +143,4 @@ We need your help in making this SDK great. Please participate in the community

This library is licensed under the [Apache 2.0 License](./documents/LICENSE).

Latest released version: v1.26.0
Latest released version: v1.29.0
2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
1.26.0
1.29.0
2 changes: 1 addition & 1 deletion crt/aws-crt-cpp
108 changes: 57 additions & 51 deletions documents/Secure_Tunnel_Userguide.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,22 @@
# Secure Tunnel Guide
#Table of Contents
* [Introduction](#introduction)
* [Getting Started with Secure Tunnels](#getting-started-with-secure-tunnels)
+ [How to Create a Secure Tunnel Client](#how-to-create-a-secure-tunnel-client)
* [Callbacks](#callbacks)
+ [Setting Secure Tunnel Callbacks](#setting-secure-tunnel-callbacks)
+ [Available Callbacks](#available-callbacks)
* [Connecting and Disconnecting the Secure Tunnel Client](#connecting-and-disconnecting-the-secure-tunnel-client)
+ [Start (Connect)](#start)
+ [Stop (Disconnect)](#stop)
* [Multiplexing and Simultaneous TCP Connections](#multiplexing-and-simultaneous-tcp-connections)
+ [Opening a Secure Tunnel with Multiplexing](#opening-a-secure-tunnel-with-multiplexing)
+ [Service Ids Available on the Secure Tunnel](#service-ids-available-on-the-secure-tunnel)
+ [Using Service Ids](#using-service-ids)
+ [Using Connection Ids](#using-connection-ids)
* [Send Message](#send-message)
* [Secure Tunnel Best Practices/FAQ](#secure-tunnel-best-practices)

## Introduction
When devices are deployed behind restricted firewalls at remote sites, you need a way to gain access to those devices for troubleshooting, configuration updates, and other operational tasks. Use secure tunneling to establish bidirectional communication to remote devices over a secure connection that is managed by AWS IoT. Secure tunneling does not require updates to your existing inbound firewall rules, so you can keep the same security level provided by firewall rules at a remote site.

Expand Down Expand Up @@ -32,8 +50,40 @@ if (!secureTunnel->Start())
return -1;
}
```
## Callbacks
# Callbacks
## Setting Secure Tunnel Callbacks
The Secure Tunnel client uses callbacks to keep the user updated on its status and pass along relavant information. These can be set up using the Secure Tunnel builder's With functions.

```cpp
// Create Secure Tunnel Builder
SecureTunnelBuilder builder = SecureTunnelBuilder(...);

// Setting the onMessageReceived callback using the builder
builder.WithOnMessageReceived([&](SecureTunnel *secureTunnel, const MessageReceivedEventData &eventData) {
{
std::shared_ptr<Message> message = eventData.message;
if (message->getServiceId().has_value()){
fprintf(
stdout,
"Message received on service id:'" PRInSTR "'\n",
AWS_BYTE_CURSOR_PRI(message->getServiceId().value()));
}

if(message->getPayload().has_value()){
fprintf(
stdout,
"Message has payload:'" PRInSTR "'\n",
AWS_BYTE_CURSOR_PRI(message->getPayload().value()));
}
}
});

// Build Secure Tunnel Client
std::shared_ptr<SecureTunnel> secureTunnel = builder.Build();

// Messages received on a stream will now be printed to stdout.
```
## Available Callbacks
### OnConnectionSuccess
When the Secure Tunnel Client successfully connects with the Secure Tunnel service, this callback will return the available (if any) service ids.
Expand Down Expand Up @@ -67,53 +117,7 @@ When the Secure Tunnel service requests the Secure Tunnel client fully reset, th
### OnStopped
When the Secure Tunnel has reached a fully stopped state this callback is invoked.
## Setting Secure Tunnel Callbacks
The Secure Tunnel client uses callbacks to keep the user updated on its status and pass along relavant information. These can be set up using the Secure Tunnel builder's With functions.

```cpp
// Create Secure Tunnel Builder
SecureTunnelBuilder builder = SecureTunnelBuilder(...);

// Setting the onMessageReceived callback using the builder
builder.WithOnMessageReceived([&](SecureTunnel *secureTunnel, const MessageReceivedEventData &eventData) {
{
std::shared_ptr<Message> message = eventData.message;
if (message->getServiceId().has_value()){
fprintf(
stdout,
"Message received on service id:'" PRInSTR "'\n",
AWS_BYTE_CURSOR_PRI(message->getServiceId().value()));
}

if(message->getPayload().has_value()){
fprintf(
stdout,
"Message has payload:'" PRInSTR "'\n",
AWS_BYTE_CURSOR_PRI(message->getPayload().value()));
}
}
});

// Build Secure Tunnel Client
std::shared_ptr<SecureTunnel> secureTunnel = builder.Build();

if (secureTunnel == nullptr)
{
fprintf(stdout, "Secure Tunnel creation failed.\n");
return -1;
}

// Start the secure tunnel connection
if (!secureTunnel->Start())
{
fprintf("Failed to start Secure Tunnel\n");
return -1;
}

// Messages received on a stream will now be printed to stdout.
```
# How to Start and Stop
# Connecting and Disconnecting the Secure Tunnel Client
## Start
Invoking `Start()` on the Secure Tunnel Client will put it into an active state where it recurrently establishes a connection to the configured Secure Tunnel endpoint using the provided [Client Access Token](https://docs.aws.amazon.com/iot/latest/developerguide/secure-tunneling-concepts.html). If a [Client Token](https://docs.aws.amazon.com/iot/latest/developerguide/secure-tunneling-concepts.html) is provided, the Secure Tunnel Client will use it. If a Client Token is not provided, the Secure Tunnel Client will automatically generate one for use on a reconnection attempts. The Client Token for any initial connection to the Secure Tunnel service **MUST** be unique. Reusing a Client Token from a previous connection will result in a failed connection to the Secure Tunnel Service.
Expand Down Expand Up @@ -157,7 +161,7 @@ You can use multiple data streams per Secure Tunnel by using the [Multiplexing a

## Opening a Secure Tunnel with Multiplexing
To use Multiplexing, a Secure Tunnel must be created with one to three "services". A Secure Tunnel can be opened through the AWS IoT console [Secure Tunnel Hub](https://console.aws.amazon.com/iot/home#/tunnelhub) or by using the [OpenTunnel API](https://docs.aws.amazon.com/iot/latest/apireference/API_Operations_AWS_IoT_Secure_Tunneling.html). Both of these methods allow you to add services with whichever names suit your needs.
## Services Within the Secure Tunnel Client
## Service Ids Available on the Secure Tunnel
On a successfull connection to a Secure Tunnel, the Secure Tunnel Client will invoke the `OnConnectionSuccess` callback. This callback will return `ConnectionSuccessEventData` which contains any available Service Ids that can be used for multiplexing. Below is an example of how to set the callback using the Secure Tunnel Builder and check whether a Service Id is available.
```cpp
// Create Secure Tunnel Builder
Expand Down Expand Up @@ -202,9 +206,8 @@ builder.WithOnConnectionSuccess([&](SecureTunnel *secureTunnel, const Connection
Service Ids can be added to outbound Messages as shown below in the Send Message example. If the Service Id is both available on the current Secure Tunnel and there is an open stream with a Source device on that Service Id, the message will be sent. If the Service Id does not exist on the current Secure Tunnel or there is no currently active stream available on that Service Id, the Message will not be sent and a Warning will be logged. The `OnStreamStarted` callback is invoked when a stream is started and it returns a `StreamStartedEventData` which can be parsed to determine if a stream was started using a Service Id for Multiplexing. Incoming messages can also be parsed to determine if a Service Id has been set as shown above in the [Setting Secure Tunnel Callbacks](#setting-secure-tunnel-callbacks) code example.
## Using Connection Ids
Connection Ids can be added to outbound Messages as shown below in the Send Message example. If there is an active stream currently open using the combination of the Service Id and Connection Id, the message will be sent. If a Connection Id is not set on an outbound message, a Connecion Id of 1 is assumed and applied to the Message. When additional streams are activated, the `OnConnectionStarted` callback is invoked and returns a `ConnectionStartedEventData` which can be parsed to determine the Connection Id of the newly activated stream. A Connection Id will also be present in the `StreamStartedEventData` that is returned when the `OnStreamStarted` callback is invoked.
# Secure Tunnel Operations
## Send Message
# Send Message
The `SendMessage()` operation takes a description of the Message you wish to send and returns a success/failure in the synchronous logic that kicks off the `SendMessage()` operation. When the message is fully written to the socket, the `OnSendDataComplete` callback will be invoked.
```cpp
Expand Down Expand Up @@ -232,3 +235,6 @@ secureTunnel->SendMessage(message);
* If you do not provide a Client Token during creation of the Secure Tunnel, one will be automatically generated for you to use in reconnections. This token is not saved outside of the current Secure Tunnel Client. If the Client is destroyed, the original access tokens must be rotated to connect to the secure tunnel again. Information on rotating tokens can be found here: https://docs.aws.amazon.com/iot/latest/developerguide/iot-secure-tunneling-troubleshooting.html
* Client tokens MUST be unique. You cannot for example, pair a Client Token with an Access Token on one secure tunnel, and then use the same Client Token with a different Access Token on a separate secure tunnel. The Secure Tunnel Service will not allow a Client Token to be paired with more than one Access Token.
* A Secure Tunnel Client that has called `Start()` will continue to attempt to connect the Secure Tunnel Service until `Stop()` is called, even if the Secure Tunnel it is trying to connect with has been closed. You MUST call `Stop()` to cease future connection attempts.
* The [onStreamStarted](#onstreamstarted) and [onConnectionStarted](#onconnectionstarted) callbacks should be set to detect and store the service id and/or connection id of streams started by a source device for use with messages. The [Secure Tunnel sample](../samples/secure_tunneling/secure_tunnel/README.md) provides an basic example of how this can be done.
* Outgoing messages MUST be assigned a service id and/or a connection id if the established stream contains a service id or a connection id or the message will be rejected. e.g. If a stream is started using service id "ssh" and connection id (1), a message sent in response must also include the service id "ssh" and connection id (1) or it will not find an active stream to send it on. Refer to the [Send Message](#send-message) code block for instruction on adding a service id and/or connection id to your message.

4 changes: 3 additions & 1 deletion jobs/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
# This file is generated

cmake_minimum_required(VERSION 3.1)

project(IotJobs-cpp LANGUAGES CXX)
if (DEFINED SIMPLE_VERSION)
message("Jobs version is ${SIMPLE_VERSION}")
message("IotJobs version is ${SIMPLE_VERSION}")
set(PROJECT_VERSION ${SIMPLE_VERSION})
endif()

Expand Down
2 changes: 2 additions & 0 deletions jobs/cmake/iotjobs-cpp-config.cmake
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
# This file is generated

include(CMakeFindDependencyMacro)

find_dependency(aws-crt-cpp)
Expand Down
4 changes: 2 additions & 2 deletions jobs/include/aws/iotjobs/JobStatus.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,8 @@ namespace Aws

namespace JobStatusMarshaller
{
const char *AWS_IOTJOBS_API ToString(JobStatus val);
JobStatus AWS_IOTJOBS_API FromString(const Aws::Crt::String &val);
AWS_IOTJOBS_API const char *ToString(JobStatus val);
AWS_IOTJOBS_API JobStatus FromString(const Aws::Crt::String &val);
} // namespace JobStatusMarshaller
} // namespace Iotjobs
} // namespace Aws
4 changes: 2 additions & 2 deletions jobs/include/aws/iotjobs/RejectedErrorCode.h
Original file line number Diff line number Diff line change
Expand Up @@ -73,8 +73,8 @@ namespace Aws

namespace RejectedErrorCodeMarshaller
{
const char *AWS_IOTJOBS_API ToString(RejectedErrorCode val);
RejectedErrorCode AWS_IOTJOBS_API FromString(const Aws::Crt::String &val);
AWS_IOTJOBS_API const char *ToString(RejectedErrorCode val);
AWS_IOTJOBS_API RejectedErrorCode FromString(const Aws::Crt::String &val);
} // namespace RejectedErrorCodeMarshaller
} // namespace Iotjobs
} // namespace Aws
28 changes: 14 additions & 14 deletions jobs/source/JobStatus.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@

#include <assert.h>

static const size_t IN_PROGRESS_HASH = Aws::Crt::HashString("IN_PROGRESS");
static const size_t FAILED_HASH = Aws::Crt::HashString("FAILED");
static const size_t QUEUED_HASH = Aws::Crt::HashString("QUEUED");
static const size_t IN_PROGRESS_HASH = Aws::Crt::HashString("IN_PROGRESS");
static const size_t TIMED_OUT_HASH = Aws::Crt::HashString("TIMED_OUT");
static const size_t FAILED_HASH = Aws::Crt::HashString("FAILED");
static const size_t SUCCEEDED_HASH = Aws::Crt::HashString("SUCCEEDED");
static const size_t CANCELED_HASH = Aws::Crt::HashString("CANCELED");
static const size_t REJECTED_HASH = Aws::Crt::HashString("REJECTED");
Expand All @@ -30,14 +30,14 @@ namespace Aws
{
switch (status)
{
case JobStatus::IN_PROGRESS:
return "IN_PROGRESS";
case JobStatus::FAILED:
return "FAILED";
case JobStatus::QUEUED:
return "QUEUED";
case JobStatus::IN_PROGRESS:
return "IN_PROGRESS";
case JobStatus::TIMED_OUT:
return "TIMED_OUT";
case JobStatus::FAILED:
return "FAILED";
case JobStatus::SUCCEEDED:
return "SUCCEEDED";
case JobStatus::CANCELED:
Expand All @@ -56,24 +56,24 @@ namespace Aws
{
size_t hash = Crt::HashString(str.c_str());

if (hash == IN_PROGRESS_HASH)
if (hash == QUEUED_HASH)
{
return JobStatus::IN_PROGRESS;
return JobStatus::QUEUED;
}

if (hash == FAILED_HASH)
if (hash == IN_PROGRESS_HASH)
{
return JobStatus::FAILED;
return JobStatus::IN_PROGRESS;
}

if (hash == QUEUED_HASH)
if (hash == TIMED_OUT_HASH)
{
return JobStatus::QUEUED;
return JobStatus::TIMED_OUT;
}

if (hash == TIMED_OUT_HASH)
if (hash == FAILED_HASH)
{
return JobStatus::TIMED_OUT;
return JobStatus::FAILED;
}

if (hash == SUCCEEDED_HASH)
Expand Down
Loading

0 comments on commit 0b1f6ce

Please sign in to comment.