> For the complete documentation index, see [llms.txt](https://docs.cybus.io/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.cybus.io/2-4-2/guides/system-connectivity/cloud-iot-platforms/aws-iot-core-integration.md).

# AWS IoT Core Integration

This guide describes how to integrate AWS IoT Core with Connectware. You configure a service commissioning file that publishes shop floor data to the AWS IoT Core message broker over MQTT with X.509 mutual TLS and receives cloud-to-device messages in return. A complete example file is available at the end of this guide.

## Objectives

* Establishing a mutual TLS (mTLS) authenticated MQTT connection between Connectware and AWS IoT Core.
* Creating an AWS IoT policy that authorizes the connection to connect, publish, subscribe, and receive.
* Publishing shop floor data from an ISA-95 topic hierarchy to AWS IoT Core topics.
* Receiving cloud-to-device commands from AWS IoT Core in Connectware.

## Prerequisites

To follow this guide, you will need the following:

* A running instance of Cybus Connectware.
* An AWS account with access to the AWS IoT Core console or the AWS Command Line Interface (CLI).
* An AWS IoT thing with an activated X.509 device certificate and its private key. If you do not have one yet, follow [Getting started with AWS IoT Core](https://docs.aws.amazon.com/iot/latest/developerguide/iot-gs.html).
* Access to the [Admin UI](/2-4-2/access/admin-ui.md) with sufficient [user permissions](/2-4-2/access/user-management.md).
* Basic knowledge of MQTT and the Connectware [services](/2-4-2/data-flows/services.md) concept (for example, [service commissioning files](/2-4-2/data-flows/service-commissioning-files.md), [connections](/2-4-2/data-flows/service-commissioning-files/resources/cybus-connection.md), [endpoints](/2-4-2/data-flows/service-commissioning-files/resources/cybus-endpoint.md), and [mappings](/2-4-2/data-flows/service-commissioning-files/resources/cybus-mapping.md)).

## Connectware and AWS IoT Core Integration

AWS IoT Core provides a managed MQTT message broker. Connectware connects to it like any other device: over TLS on port 8883, authenticated with an X.509 client certificate. The [MQTT connector](/2-4-2/connectors/enterprise-connectors/mqtt.md) handles the connection, and `Cybus::Mapping` and `Cybus::Endpoint` resources route data between the Connectware topic hierarchy and AWS IoT Core topics.

The broker is reachable at the device data endpoint of your AWS account, which has the form `<account-specific-prefix>-ats.iot.<region>.amazonaws.com`. You find it on the **Settings** page of the AWS IoT Core console, or with the AWS CLI:

{% code lineNumbers="true" %}

```bash
aws iot describe-endpoint --endpoint-type iot:Data-ATS
```

{% endcode %}

The AWS IoT Core broker differs from a generic MQTT broker in a few ways that matter for this integration (see [AWS IoT Core MQTT documentation](https://docs.aws.amazon.com/iot/latest/developerguide/mqtt.html)):

* AWS IoT Core supports MQTT Quality of Service (QoS) levels 0 and 1, but not QoS 2. Do not configure `qos: 2` on endpoints or mappings that target AWS IoT Core.
* Every action requires authorization by an AWS IoT policy. Without the matching policy statement, a connect attempt is rejected, a publish is silently dropped, or a subscription is refused.
* Topic names that begin with `$` are [reserved for AWS IoT Core](https://docs.aws.amazon.com/iot/latest/developerguide/topics.html) (for example, `$aws/things/...`). A topic can contain at most seven forward slashes, and the client ID can be at most 128 bytes.
* Retained messages are supported, but publishing them requires the additional `iot:RetainPublish` policy action.
* If a second client connects with the same client ID, AWS IoT Core disconnects the first client.

The MQTT topics on the Connectware side follow an ISA-95-style equipment hierarchy (`<enterprise>/<site>/<area>/<line>/<cell>`). The mapping subscribes with wildcards across all levels, so any machine in the hierarchy is picked up without changing the integration. On the AWS side, this guide uses the `dt/` prefix for device-to-cloud telemetry and the `cmd/` prefix for cloud-to-device commands, following the AWS whitepaper [Designing MQTT Topics for AWS IoT Core](https://docs.aws.amazon.com/whitepapers/latest/designing-mqtt-topics-aws-iot-core/designing-mqtt-topics-aws-iot-core.html).

{% hint style="info" %}
To connect through an AWS IoT Greengrass Core at the edge instead of connecting directly to the cloud, see [AWS IoT Greengrass Integration](/2-4-2/guides/system-connectivity/cloud-iot-platforms/aws-iot-greengrass-integration.md).
{% endhint %}

### AWS IoT Policy

AWS IoT Core authorizes every MQTT action against the AWS IoT policy that is attached to the device certificate. The policy must allow Connectware to connect with its client ID, publish to the telemetry topics, and subscribe to and receive from the command topic.

The following policy matches the topics used in this guide. Replace the region and the account ID with your own values.

{% code title="connectware-policy.json" lineNumbers="true" %}

```json
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": "iot:Connect",
      "Resource": "arn:aws:iot:eu-central-1:123456789012:client/connectware-shopfloor"
    },
    {
      "Effect": "Allow",
      "Action": "iot:Publish",
      "Resource": "arn:aws:iot:eu-central-1:123456789012:topic/dt/*"
    },
    {
      "Effect": "Allow",
      "Action": "iot:Subscribe",
      "Resource": "arn:aws:iot:eu-central-1:123456789012:topicfilter/cmd/connectware-shopfloor/commands"
    },
    {
      "Effect": "Allow",
      "Action": "iot:Receive",
      "Resource": "arn:aws:iot:eu-central-1:123456789012:topic/cmd/connectware-shopfloor/commands"
    }
  ]
}
```

{% endcode %}

`iot:Publish` and `iot:Receive` use `topic/` resources, while `iot:Subscribe` uses `topicfilter/` resources. AWS IoT policies use `*` as the wildcard character, not the MQTT wildcards `+` and `#`. For more policy variants, see the [AWS IoT publish/subscribe policy examples](https://docs.aws.amazon.com/iot/latest/developerguide/pub-sub-policy.html).

### AWS IoT Core Connection Parameters

The connection requires the device data endpoint, a client ID, and the certificate material. We add the endpoint, the client ID, and the topic root as parameters to the service commissioning file, so you can set them when you install the service.

Do not worry about copying the service commissioning file snippets together into one, the complete example file is available at the end of this guide.

* `awsIotEndpoint`: The device data endpoint of your AWS account, as returned by `describe-endpoint`.
* `clientId`: The MQTT client ID. It must match the client resource in the `iot:Connect` policy statement and must be unique within your AWS account, because AWS IoT Core disconnects an existing connection that uses the same client ID.
* `topicRoot`: The root of the MQTT topic hierarchy on the Connectware side. Defaults to `enterprise`.

{% code lineNumbers="true" %}

```yaml
parameters:
  awsIotEndpoint:
    description: Device data endpoint (iot:Data-ATS) of your AWS account
    type: string
    default: a1b2c3d4e5f6g7-ats.iot.eu-central-1.amazonaws.com

  clientId:
    description: MQTT client ID, must match the client ARN in the AWS IoT policy
    type: string
    default: connectware-shopfloor

  topicRoot:
    description: Root of the MQTT topic hierarchy
    type: string
    default: enterprise
```

{% endcode %}

The MQTT connector expects the certificate material as string values containing the content of the PEM files, not as file paths (see [MQTT Connection Properties](/2-4-2/connectors/enterprise-connectors/mqtt/mqttconnection.md)). We add the three PEM blocks to the `definitions` section of the service commissioning file:

* `caCert`: The Amazon root CA certificate (`AmazonRootCA1.pem`) that Connectware uses to validate the broker certificate. Download it from the Amazon Trust Services repository listed under [AWS IoT server authentication](https://docs.aws.amazon.com/iot/latest/developerguide/server-authentication.html).
* `clientCert`: The device certificate that AWS IoT Core issued when you registered the thing.
* `clientPrivateKey`: The private key that belongs to the device certificate.

{% code lineNumbers="true" %}

```yaml
definitions:
  # The Amazon root CA certificate as PEM file content (AmazonRootCA1.pem)
  caCert: |
    -----BEGIN CERTIFICATE-----
    -----END CERTIFICATE-----
  # The device certificate as PEM file content
  clientCert: |
    -----BEGIN CERTIFICATE-----
    -----END CERTIFICATE-----
  # The device private key as PEM file content
  clientPrivateKey: |
    -----BEGIN RSA PRIVATE KEY-----
    -----END RSA PRIVATE KEY-----
```

{% endcode %}

{% hint style="warning" %}
The private key authenticates your Connectware instance against your AWS account. Treat the service commissioning file as a secret and restrict who can read it.
{% endhint %}

### AWS IoT Core Connection

To connect to AWS IoT Core, we set up a `Cybus::Connection` resource that uses the MQTT connector with `scheme: mqtts` on port 8883 and `mutualAuthentication: true`, so Connectware presents the device certificate during the TLS handshake and validates the broker certificate against the Amazon root CA.

{% code lineNumbers="true" %}

```yaml
resources:
  awsIotConnection:
    type: Cybus::Connection
    properties:
      protocol: Mqtt
      connection:
        host: !ref awsIotEndpoint
        port: 8883
        scheme: mqtts
        clientId: !ref clientId
        keepalive: 60
        mutualAuthentication: true
        caCert: !ref caCert
        clientCert: !ref clientCert
        clientPrivateKey: !ref clientPrivateKey
```

{% endcode %}

AWS IoT Core supports keep-alive intervals between 30 and 1200 seconds. The MQTT connector defaults to `0`, which disables client-side keep-alive pings. AWS IoT Core then applies its server default of 1200 seconds and disconnects the client after prolonged inactivity. A value of 60 seconds keeps the connection alive even when no data flows.

### Publishing Shop Floor Data to AWS IoT Core

A `Cybus::Mapping` resource forwards telemetry from the ISA-95 topic hierarchy to AWS IoT Core. The named wildcards `+site`, `+area`, `+line`, and `+cell` capture the levels of the source topic, and the publish side reuses them as `$site`, `$area`, `$line`, and `$cell` to mirror the hierarchy under the `dt/` prefix.

{% code lineNumbers="true" %}

```yaml
telemetryMapping:
  type: Cybus::Mapping
  properties:
    mappings:
      - subscribe:
          topic: !sub '${topicRoot}/+site/+area/+line/+cell/telemetry'
          qos: 1
        publish:
          connection: !ref awsIotConnection
          topic: dt/$site/$area/$line/$cell/telemetry
          qos: 1
```

{% endcode %}

A message published to `enterprise/hamburg/assembly/line-1/press-01/telemetry` now arrives on the AWS IoT Core topic `dt/hamburg/assembly/line-1/press-01/telemetry`. The payload is forwarded unchanged. To reshape it before it reaches the cloud, for example to add a timestamp or flatten a structure, add rules to the mapping (see [Rule Engine](/2-4-2/data-flows/rule-engine.md)).

QoS 1 on both sides gives at-least-once delivery from the internal broker to AWS IoT Core. Keep the AWS payload limit of 128 KB per publish in mind when you aggregate messages.

### Receiving Commands from AWS IoT Core

For the opposite direction, a `Cybus::Endpoint` resource subscribes to the cloud-to-device command topic, and a mapping republishes every command to the Connectware topic hierarchy, where any other Connectware service can pick it up, for example to write a setpoint to a PLC.

{% code lineNumbers="true" %}

```yaml
commandEndpoint:
  type: Cybus::Endpoint
  properties:
    protocol: Mqtt
    connection: !ref awsIotConnection
    subscribe:
      topic: !sub 'cmd/${clientId}/commands'
      qos: 1

commandMapping:
  type: Cybus::Mapping
  properties:
    mappings:
      - subscribe:
          endpoint: !ref commandEndpoint
        publish:
          topic: !sub '${topicRoot}/cloud/aws-iot/commands'
```

{% endcode %}

Any application in your AWS account that is authorized to publish to `cmd/connectware-shopfloor/commands`, for example an AWS IoT rule or a Lambda function, can now send messages to the shop floor. Connectware republishes them to `enterprise/cloud/aws-iot/commands`.

## Verifying the Integration

1. Install the service and set the parameters with the values from your AWS account.
2. Check that the connection is in the **Connected** state on the service details page in the Admin UI. If the certificate material is wrong or the policy lacks the `iot:Connect` statement, the connection does not reach the connected state.
3. In the AWS IoT Core console, open the **MQTT test client** and subscribe to `dt/#`.
4. Publish a test message to `enterprise/hamburg/assembly/line-1/press-01/telemetry`, for example with an MQTT client or the Admin UI. The message appears in the MQTT test client on `dt/hamburg/assembly/line-1/press-01/telemetry`.
5. In the MQTT test client, publish a message to `cmd/connectware-shopfloor/commands`. Use the [Data Explorer](/2-4-2/monitoring/data-explorer.md) to check that the message arrives on `enterprise/cloud/aws-iot/commands`.

If messages do not arrive in one direction, check the AWS IoT policy first. AWS IoT Core drops unauthorized publishes without disconnecting the client, so a missing `iot:Publish` or `iot:Receive` statement shows up as silently missing messages rather than as a connection error.

## Service Commissioning File Example

{% file src="/files/4C0Kcc5KAF8dm78YIAjV" %}

{% code title="aws-iot-core-example.yml" lineNumbers="true" expandable="true" %}

```yaml
---
# ----------------------------------------------------------------------------
# Service Commissioning File
# ----------------------------------------------------------------------------
# Copyright: Cybus GmbH
# Contact: support@cybus.io
# ----------------------------------------------------------------------------
# AWS IoT Core Integration (Example)
# ----------------------------------------------------------------------------

description: >
  Service commissioning file for the bidirectional integration between
  Connectware and AWS IoT Core (Example)

metadata:
  name: AWS IoT Core Integration
  provider: cybus
  homepage: https://www.cybus.io
  version: 1.0.0

parameters:
  awsIotEndpoint:
    description: Device data endpoint (iot:Data-ATS) of your AWS account
    type: string
    default: a1b2c3d4e5f6g7-ats.iot.eu-central-1.amazonaws.com

  clientId:
    description: MQTT client ID, must match the client ARN in the AWS IoT policy
    type: string
    default: connectware-shopfloor

  topicRoot:
    description: Root of the MQTT topic hierarchy
    type: string
    default: enterprise

definitions:
  # The Amazon root CA certificate as PEM file content (AmazonRootCA1.pem)
  caCert: |
    -----BEGIN CERTIFICATE-----
    -----END CERTIFICATE-----
  # The device certificate as PEM file content
  clientCert: |
    -----BEGIN CERTIFICATE-----
    -----END CERTIFICATE-----
  # The device private key as PEM file content
  clientPrivateKey: |
    -----BEGIN RSA PRIVATE KEY-----
    -----END RSA PRIVATE KEY-----

resources:
  # Mutual TLS connection to the AWS IoT Core message broker
  awsIotConnection:
    type: Cybus::Connection
    properties:
      protocol: Mqtt
      connection:
        host: !ref awsIotEndpoint
        port: 8883
        scheme: mqtts
        clientId: !ref clientId
        keepalive: 60
        mutualAuthentication: true
        caCert: !ref caCert
        clientCert: !ref clientCert
        clientPrivateKey: !ref clientPrivateKey

  # Publishes shop floor data from the ISA-95 topic hierarchy to AWS IoT Core
  telemetryMapping:
    type: Cybus::Mapping
    properties:
      mappings:
        - subscribe:
            topic: !sub '${topicRoot}/+site/+area/+line/+cell/telemetry'
            qos: 1
          publish:
            connection: !ref awsIotConnection
            topic: dt/$site/$area/$line/$cell/telemetry
            qos: 1

  # Receives cloud-to-device commands from AWS IoT Core
  commandEndpoint:
    type: Cybus::Endpoint
    properties:
      protocol: Mqtt
      connection: !ref awsIotConnection
      subscribe:
        topic: !sub 'cmd/${clientId}/commands'
        qos: 1

  commandMapping:
    type: Cybus::Mapping
    properties:
      mappings:
        - subscribe:
            endpoint: !ref commandEndpoint
          publish:
            topic: !sub '${topicRoot}/cloud/aws-iot/commands'
```

{% endcode %}


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.cybus.io/2-4-2/guides/system-connectivity/cloud-iot-platforms/aws-iot-core-integration.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
