Skip to content

Commit 513ecd5

Browse files
authored
Secure Tunnel WebSocket Protocol V3 Support (#557)
* Secure Tunnel WebSocket Protocol V3 Support * Updated Secure Tunnel Sample and documentation * Updated Secure Tunnel Notification Sample and documentation * Secure Tunnel integration Test
1 parent 76e54d8 commit 513ecd5

File tree

14 files changed

+1427
-449
lines changed

14 files changed

+1427
-449
lines changed

codebuild/integration-tests.sh

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
set -e
2+
3+
env
4+
5+
pushd $CODEBUILD_SRC_DIR/secure_tunneling/tests
6+
7+
mkdir _build
8+
cd _build
9+
cmake -DCMAKE_PREFIX_PATH=/tmp/install ..
10+
make -j
11+
12+
tunnel_info=$(aws iotsecuretunneling open-tunnel --destination-config services=ssh,ssh2,ssh3 --timeout-config maxLifetimeTimeoutMinutes=10) && echo -e "$tunnel_info" > /tmp/tunnel_info.pem
13+
14+
export SECTUN_SOURCE_TOKEN=$(sed '4!d' /tmp/tunnel_info.pem | cut -d'"' -f4)
15+
export SECTUN_DESTINATION_TOKEN=$(sed '5!d' /tmp/tunnel_info.pem | cut -d'"' -f4)
16+
export SECTUN_ENDPOINT="data.tunneling.iot.us-east-1.amazonaws.com"
17+
18+
echo "Running Secure Tunnel Test"
19+
./secure_tunnel_test

codebuild/linux-integration-tests.yml

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
version: 0.2
2+
env:
3+
shell: bash
4+
#this buildspec assumes the ubuntu 14 image
5+
phases:
6+
install:
7+
commands:
8+
- wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | apt-key add -
9+
- add-apt-repository ppa:ubuntu-toolchain-r/test
10+
- apt-add-repository "deb http://apt.llvm.org/bionic/ llvm-toolchain-bionic-8 main"
11+
- apt-get update -y
12+
- apt-get install cmake -y -f
13+
14+
build:
15+
commands:
16+
- echo Build started on `date`
17+
# Building of dependencies happens in setup-linux
18+
- $CODEBUILD_SRC_DIR/codebuild/samples/setup-linux.sh
19+
20+
# Run the integration tests
21+
- $CODEBUILD_SRC_DIR/codebuild/integration-tests.sh
22+
post_build:
23+
commands:
24+
- echo Build completed on `date`
25+

crt/aws-crt-cpp

Submodule aws-crt-cpp updated 1 file

documents/Secure_Tunnel_Userguide.md

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ When a WebSocket upgrade request fails to connect, this callback will return an
4343
### OnConnectionShutdown
4444
When the WebSocket connection shuts down, this callback will be invoked.
4545

46-
### OnSendDataComplete
46+
### OnSendMessageComplete
4747
When a message has been completely written to the socket, this callback will be invoked.
4848

4949
### OnMessageReceived
@@ -55,6 +55,12 @@ When a stream is started by a Source connected to the Destination, the Destinati
5555
### OnStreamStopped
5656
When an open stream is closed, this callback will be invoked and return the stopped stream's information.
5757

58+
### OnConnectionStarted
59+
When a connection start message is received and a new active connection is established, the Destination will invoke this callback and return the connection information.
60+
61+
### OnConnectionReset
62+
When a connection has ended either in error or closed intentionally by the secure tunnel peer, the client will invoke this callback and return the connection information.
63+
5864
### OnSessionReset
5965
When the Secure Tunnel service requests the Secure Tunnel client fully reset, this callback is invoked.
6066

@@ -135,21 +141,24 @@ if (!secureTunnel->Start())
135141
return -1;
136142
}
137143
```
144+
### Reconnecting
145+
A Secure Tunnel Client that has been started will attempt to reconnect upon a failed connection attempt or disconnection until `Stop()` is called. If the secure tunnel closes or the access tokens change, the Secure Tunnel Client will become disconnected and continue to attempt a reconnection until `Stop()` is called. The Secure Tunnel Client implements a Full Jitter Backoff Algorithm along with an exponential back off timer. More information on both can be found here: https://aws.amazon.com/blogs/architecture/exponential-backoff-and-jitter/
138146

139147
## Stop
140-
Invoking `Stop()` on the Secure Tunnel Client breaks the current connection (if any) and moves the client into an idle state.
148+
Invoking `Stop()` on the Secure Tunnel Client breaks the current connection (if any) and moves the client into an idle state. A Secure Tunnel Client that has been stopped will no longer attempt to reconnect and is ready to be cleaned up.
141149
```cpp
142150
if(!secureTunnel->Stop()){
143151
fprintf(stdout, "Failed to stop the Secure Tunnel connection session. Exiting..\n");
144152
}
145153
```
146-
# Multiplexing
147-
You can use multiple data streams per Secure Tunnel by using the [Multiplexing](https://docs.aws.amazon.com/iot/latest/developerguide/multiplexing.html) feature.
154+
# Multiplexing and Simultaneous TCP Connections
155+
You can use multiple data streams per Secure Tunnel by using the [Multiplexing and Simultaneous TCP Connections](https://docs.aws.amazon.com/iot/latest/developerguide/multiplexing.html) features.
156+
148157

149158
## Opening a Secure Tunnel with Multiplexing
150159
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.
151160
## Services Within the Secure Tunnel Client
152-
On a successfull connection to a Secure Tunnel, the Secure Tunnel Client will invoke the `OnConnectionSuccess` callback. This callback will return `ConnectionSuccessEventData` that will contain 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.
161+
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.
153162
```cpp
154163
// Create Secure Tunnel Builder
155164
SecureTunnelBuilder builder = SecureTunnelBuilder(...);
@@ -191,6 +200,8 @@ builder.WithOnConnectionSuccess([&](SecureTunnel *secureTunnel, const Connection
191200
```
192201
## Using Service Ids
193202
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.
203+
## Using Connection Ids
204+
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.
194205
# Secure Tunnel Operations
195206
196207
## Send Message
@@ -201,11 +212,16 @@ Crt::String serviceId_string = "ssh";
201212
Crt::String message_string = "any payload";
202213
203214
ByteCursor serviceId = ByteCursorFromString(serviceId_string);
215+
uint32_t connectionId = 1
204216
ByteCursor payload = ByteCursorFromString(message_string);
205217
206218
// Create Message
207219
std::shared_ptr<Message> message = std::make_shared<Message>();
220+
// Add a Service Id
208221
message->withServiceId(serviceId);
222+
// Add a Connection Id
223+
message->withConnectionId(connectionId);
224+
// Add a payload
209225
message->withPayload(payload);
210226
211227
// Send Message
Lines changed: 13 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -1,72 +1,33 @@
1-
## Secure Tunnel
1+
# Secure Tunnel
22

33
[**Return to main sample list**](../../README.md)
44

5-
This sample uses AWS IoT [Secure Tunneling](https://docs.aws.amazon.com/iot/latest/developerguide/secure-tunneling.html) Service to connect a destination and a source with each other through the AWS Secure Tunnel endpoint using access tokens using the [V2WebSocketProtocol](https://github.com/aws-samples/aws-iot-securetunneling-localproxy/blob/main/V2WebSocketProtocolGuide.md). For more information, see the [Secure Tunnel Userguide](../../../documents/Secure_Tunnel_Userguide.md)
6-
7-
Your IoT Core Thing's [Policy](https://docs.aws.amazon.com/iot/latest/developerguide/iot-policies.html) must provide privileges for this sample to connect, subscribe, publish, and receive. Below is a sample policy that can be used on your IoT Core Thing that will allow this sample to run as intended.
8-
9-
<details>
10-
<summary>(see sample policy)</summary>
11-
<pre>
12-
{
13-
"Version": "2012-10-17",
14-
"Statement": [
15-
{
16-
"Effect": "Allow",
17-
"Action": [
18-
"iot:Publish",
19-
"iot:Receive"
20-
],
21-
"Resource": [
22-
"arn:aws:iot:<b>region</b>:<b>account</b>:topic/$aws/things/<thing_name>/tunnels/notify"
23-
]
24-
},
25-
{
26-
"Effect": "Allow",
27-
"Action": [
28-
"iot:Subscribe"
29-
],
30-
"Resource": [
31-
"arn:aws:iot:<b>region</b>:<b>account</b>:topicfilter/$aws/things/<thing_name>/tunnels/notify"
32-
]
33-
},
34-
{
35-
"Effect": "Allow",
36-
"Action": [
37-
"iot:Connect"
38-
],
39-
"Resource": [
40-
"arn:aws:iot:<b>region</b>:<b>account</b>:client/test-*"
41-
]
42-
}
43-
]
44-
}
45-
</pre>
46-
47-
Replace with the following with the data from your AWS account:
48-
* `<region>`: The AWS IoT Core region where you created your AWS IoT Core thing you wish to use with this sample. For example `us-east-1`.
49-
* `<account>`: Your AWS IoT Core account ID. This is the set of numbers in the top right next to your AWS account name when using the AWS IoT Core website.
50-
* `<thingname>`: The name of your AWS IoT Core thing you want the device connection to be associated with
51-
52-
Note that in a real application, you may want to avoid the use of wildcards in your ClientID or use them selectively. Please follow best practices when working with AWS on production applications using the SDK. Also, for the purposes of this sample, please 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.
5+
This sample uses AWS IoT [Secure Tunneling](https://docs.aws.amazon.com/iot/latest/developerguide/secure-tunneling.html) Service to connect a destination or a source Secure Tunnel Client to an AWS Secure Tunnel endpoint using access tokens using the [V3WebSocketProtocol](https://github.com/aws-samples/aws-iot-securetunneling-localproxy/blob/main/V3WebSocketProtocolGuide.md). For more information, see the [Secure Tunnel Userguide](../../../documents/Secure_Tunnel_Userguide.md)
536

547
## How to run
558

569
Create a new secure tunnel in the AWS IoT console (https://console.aws.amazon.com/iot/) (AWS IoT/Manage/Tunnels/Create tunnel) and retrieve the destination and source access tokens. (https://docs.aws.amazon.com/iot/latest/developerguide/secure-tunneling-tutorial-open-tunnel.html). Once you have these tokens, you are ready to open a secure tunnel.
5710

11+
### Destination Mode
12+
5813
To run the sample with a destination access token in destination mode (default), you can use the following command:
5914

6015
``` sh
61-
./secure_tunnel --region <region> --access_token_file <path to destination access token>
16+
./secure_tunnel --signing_region <signing_region> --access_token_file <path to destination access token>
6217
```
6318

64-
However, for this sample to work, it will also need another instance of the sample running in source mode. You can run another instance of the sample in source mode using the same command, but adding the `--localProxyModeSource` flag:
19+
The sample will create a Secure Tunnel connection and remain connected in `DESTINATION MODE` and will echo any messages it receives through the Secure Tunnel back to the Source Device.
20+
21+
### Source Mode
22+
23+
While the focus of the Secure Tunnel Client for the IoT Device SDK is to connect with Secure Tunnels in `DESTINATION MODE` we also support connecting in `SOURCE MODE`. The token file should be the Source Token in this instance and you must add the `--localProxyModeSource` flag:
6524

6625
``` sh
67-
./secure_tunnel --region <region> --access_token_file <path to source access token> --localProxyModeSource
26+
./secure_tunnel --signing_region <signing_region> --access_token_file <path to source access token> --localProxyModeSource
6827
```
6928

7029
Then two samples will then connect to each other through the AWS Secure Tunnel endpoint and establish a stream through which data can be transmitted in either direction.
30+
The sample will create a Secure Tunnel connection in `SOURCE MODE` and will open a stream using an available `Service Id`. It will then send n messages on the opened stream. It will then create a new simultaneous TCP connection on the stream and send an additional n messages on the new TCP connection. It will then exit.
7131

32+
### Proxy
7233
Note that a proxy server may be used via the `--proxy_host` and `--proxy_port` argument. If the proxy server requires a user name and password to connect, you can use `--proxy_user_name` and `--proxy_password` to in the sample to pass the required data to the sample.

0 commit comments

Comments
 (0)