

本文属于机器翻译版本。若本译文内容与英语原文存在差异，则一律以英文原文为准。

# 配置远程设备和使用物联网代理
<a name="configure-remote-device"></a>

IoT 代理用于接收包含客户端访问令牌的 MQTT 消息，并在远程设备上启动本地代理。如果希望安全隧道使用 MQTT 传送客户端访问令牌，则必须在远程设备上安装并运行物联网代理。IoT 代理必须订阅以下保留的物联网 MQTT 主题：

**注意**  
如果要通过订阅保留 MQTT 主题之外的方法将目标客户端访问令牌传送到远程设备，您可能需要目标客户端访问令牌（CAT）侦听器和本地代理。CAT 侦听器必须使用您选择的客户端访问令牌传送机制，并且能够在目标模式下启动本地代理。

## IoT 代理代码段
<a name="agent-snippet"></a>

IoT 代理必须订阅以下保留物联网 MQTT 主题，这样才能接收 MQTT 消息并启动本地代理：

`$aws/things/thing-name/tunnels/notify`

`thing-name`与远程设备关联 AWS IoT 的事物的名称在哪里。

以下是 MQTT 消息有效载荷示例：

```
{
    "clientAccessToken": "destination-client-access-token",
    "clientMode": "destination",
    "region": "aws-region",
    "services": ["destination-service"]
}
```

当您收到 MQTT 消息后，IoT 代理必须在远程设备上使用适当参数启动本地代理。

以下 Java 代码演示了如何使用[AWS IoT 设备 SDK](https://github.com/aws/aws-iot-device-sdk-java) 和 [ProcessBuilder](https://docs.oracle.com/javase/8/docs/api/java/lang/ProcessBuilder.html)Java 库来构建用于安全隧道的简单物联网代理。

```
// Find the IoT device endpoint for your AWS 账户
final String endpoint = iotClient.describeEndpoint(new DescribeEndpointRequest().withEndpointType("iot:Data-ATS")).getEndpointAddress();

// Instantiate the IoT Agent with your AWS credentials
final String thingName = "RemoteDeviceA";
final String tunnelNotificationTopic = String.format("$aws/things/%s/tunnels/notify", thingName);
final AWSIotMqttClient mqttClient = new AWSIotMqttClient(endpoint, thingName,
                 "your_aws_access_key", "your_aws_secret_key");

try {
    mqttClient.connect();
    final TunnelNotificationListener listener = new TunnelNotificationListener(tunnelNotificationTopic);
    mqttClient.subscribe(listener, true);
}
finally {
    mqttClient.disconnect();
}

private static class TunnelNotificationListener extends AWSIotTopic {
    public TunnelNotificationListener(String topic) {
        super(topic);
    }

    @Override
    public void onMessage(AWSIotMessage message) {
        try {
            // Deserialize the MQTT message
            final JSONObject json = new JSONObject(message.getStringPayload());
 
            final String accessToken = json.getString("clientAccessToken");
            final String region = json.getString("region");
            
            final String clientMode = json.getString("clientMode");
            if (!clientMode.equals("destination")) {
                throw new RuntimeException("Client mode " + clientMode + " in the MQTT message is not expected");
            }

            final JSONArray servicesArray = json.getJSONArray("services");
            if (servicesArray.length() > 1) {
                throw new RuntimeException("Services in the MQTT message has more than 1 service");
            }
            final String service = servicesArray.get(0).toString();
            if (!service.equals("SSH")) {
                throw new RuntimeException("Service " + service + " is not supported");
            }

            // Start the destination local proxy in a separate process to connect to the SSH Daemon listening port 22
            final ProcessBuilder pb = new ProcessBuilder("localproxy",
                        "-t", accessToken,
                        "-r", region,
                        "-d", "localhost:22");
            pb.start();
        }
        catch (Exception e) {
            log.error("Failed to start the local proxy", e);
        }
    }
}
```