A 512 MB gateway can fail before its application starts. Add a JVM, Docker, a few optimistic log files, and a remote-update agent, then wait for the first brownout or certificate rotation. Edge devices are not inherently weak; treating an industrial IoT gateway like a small server is the mistake.
AWS IoT Greengrass Core v2.18, released July 8, 2026, supports a more disciplined design. Its C-based nucleus lite runtime targets Linux devices with 512 MB RAM or less, uses less than 5 MB of RAM and less than 5 MB of disk or flash, has no JVM dependency, and allocates a fixed memory amount after startup. Those are operating characteristics, not marketing footnotes. They change which failures are plausible at 03:00 on a factory floor.
The useful question is not “Can Greengrass run here?” Ask which runtime, trust boundary, update mechanism, and local workload this device can sustain without making remote recovery depend on luck. This guide uses AWS IoT Greengrass Core v2.18, nucleus lite, and fleet provisioning to answer it for industrial gateways.
AWS IoT Greengrass Core v2.18: choose the runtime by failure budget
Greengrass V2 has three working units: core devices, components, and deployments. A core device runs the Greengrass runtime and maps to an AWS IoT Thing with its own certificate. Components package deployable software and configuration. Deployments select component versions and configuration overrides, then apply them to a device or group. The model is simple. Its operational consequences aren’t.
Full Greengrass nucleus remains the right runtime for substantial gateways. Use it when the node needs Docker containers, AWS Lambda functions, scripted or interpreted-language components, Windows, Linux without systemd, or Greengrass capabilities that nucleus lite doesn’t support, including AWS IoT SiteWise gateways. An x86_64 industrial PC collecting OPC-UA, Modbus TCP, camera telemetry, and containerized analytics often fits this category. It has enough memory for container overhead and enough storage for artifacts, logs, and rollback state.
Nucleus lite is deliberately narrower. AWS introduced it in Greengrass Version 2.14.0 in December 2024 for constrained Linux devices, and it is written in C with only the C standard library as a dependency. It fits ARM sensor concentrators, compact robotics controllers, smart energy meters, and purpose-built local-control appliances. Its disk layout separates the nucleus lite binary, configuration, logs, and Greengrass component areas. Put those areas on partitions or mount points with distinct ownership and quotas where hardware permits. A runaway component shouldn’t consume the space needed for runtime configuration or logs.
[OPINION] “One runtime everywhere” is the wrong default. A mixed fleet is less aesthetically tidy, but it fits industrial hardware as it actually exists.
A practical plant design has two tiers. Heavy gateways run full nucleus directly on the host or inside Docker, translate industrial protocols, execute containerized analytics, and maintain a local store-and-forward buffer. Small field hubs run nucleus lite natively under systemd and own a narrow responsibility: acquire a signal, perform deterministic local logic, publish an approved telemetry schema, and receive authenticated, authorized Greengrass deployments. Both tiers remain first-class Greengrass core devices, authenticate through AWS IoT Core, and can be managed in the same Greengrass service and fleet model. What they don’t share is a feature set. Nucleus lite doesn’t implement everything full nucleus does, so components, recipes, lifecycle assumptions, and deployment targets have to be kept separate or explicitly tested for lite compatibility — a Docker, Lambda, Python, or SiteWise deployment written for a full-nucleus gateway can’t simply be retargeted at a lite device.
Build the industrial IoT gateway as explicit trust zones
Picture the gateway as four layers, moving out from the machine. First is the OT-facing adapter: OPC-UA, Modbus, CAN, serial, GMSL camera input, or a vendor SDK. Next comes a local normalization process that validates units, timestamps, sequence numbers, and schema versions. The Greengrass component layer runs control, inference, forwarding, and health functions. Outside that sits the AWS IoT Core connection, protected by device identity, TLS, and narrowly scoped authorization. Crossing a layer should also cross a policy boundary.
Don’t let a cloud-connected process talk directly to every local bus just because it can. Split the protocol adapter from the MQTT publisher. The adapter can run with access to /dev/ttyUSB0 or a dedicated VLAN; the publisher receives a Unix socket or loopback message containing normalized readings. A compromise in a telemetry component then becomes a bounded incident, not an invitation to issue arbitrary PLC commands.
Components should expose small, safe configuration surfaces
Greengrass components are versioned bundles with recipes, artifacts, dependencies, and lifecycle commands. Deployment configuration merges with component configuration, so treat configuration as an API. Expose pollIntervalMs, endpoint identifiers, retention limits, and allow-listed topic roots. Do not expose shell fragments, arbitrary artifact URLs, or a generic command field. Remote configuration is production control; an unrestricted string field is remote code execution wearing a name tag.
{
"RecipeFormatVersion": "2020-01-25",
"ComponentName": "com.example.LineTelemetry",
"ComponentVersion": "1.4.0",
"ComponentConfiguration": {
"DefaultConfiguration": {
"pollIntervalMs": 1000,
"topicRoot": "factory/THING_NAME/telemetry",
"maxSpoolMiB": 64
}
},
"Manifests": [{
"Platform": { "os": "linux", "architecture": "armv7l" },
"Artifacts": [{
"Uri": "s3://example-artifacts/line-telemetry/1.4.0/line-telemetry",
"Permission": { "Execute": "OWNER" }
}],
"Lifecycle": {
"Run": "\"{artifacts:path}/line-telemetry\" --poll-interval-ms \"{configuration:/pollIntervalMs}\" --topic-root \"{configuration:/topicRoot}\" --max-spool-mib \"{configuration:/maxSpoolMiB}\""
}
}]
}
The artifact is downloaded into the component artifact directory before the run command executes. Replace THING_NAME in the deployment override with that device’s exact Thing name, so the resulting root is factory/<ThingName>/telemetry, and have the application reject an unresolved placeholder. The application must parse these quoted arguments as its own typed configuration; it should not treat them as a configuration-file path or execute configuration as shell input.
For full nucleus, a Python OPC-UA collector can be reasonable when operations teams need rapid protocol adaptation. For nucleus lite, prefer a C binary with bounded allocation and a compact artifact. The application has to match the runtime’s intent. A sub-5 MB runtime footprint won’t rescue an unbounded Python process or an inference model that reserves 700 MB.
AI-capable hardware belongs at the heavy end of this split. Advantech’s July 7, 2026 collaboration with StereoLabs highlights GMSL stereo vision platforms based on NVIDIA Jetson Thor, Jetson AGX Orin, and Jetson Orin NX. These devices can host perception pipelines and Greengrass full nucleus for managed deployment and telemetry aggregation. Keep camera frames local unless a defined business and security requirement permits export. Publish inference events, model version, confidence bands, and device health by default—not raw imagery.
Fleet provisioning for AWS IoT Greengrass Core v2.18
Manual certificate installation doesn’t scale beyond a lab bench, and shared production credentials are indefensible. AWS IoT fleet provisioning gives a factory-reset device a controlled path to its own AWS IoT Thing, certificate, policy, and Greengrass identity. The bootstrap identity is a provisioning claim certificate embedded during manufacturing, and it is not the device’s permanent identity. Be precise about what’s actually secret here: an X.509 certificate is public identity material, so the thing that must be protected is the claim private key shipped alongside it. The pair together is a high-value, tightly constrained enrollment credential — and that distinction is what tells you where to spend effort in manufacturing handling and in incident response, since a leaked claim private key is what lets an attacker enroll, not the certificate on its own.
The provisioning path has six moving parts: a token exchange IAM role, an AWS IoT role alias, an IoT policy for operational devices, a constrained claim-certificate policy, a fleet provisioning template, and the claim certificate plus private key. During first boot, the device connects with the claim certificate over TLS, requests provisioning, receives a unique certificate and Thing registration, attaches that certificate to its Thing, stores its new identity, then reconnects using that identity. Verify the certificate-to-Thing attachment before treating the device as operational. Claim credentials should have permission to provision only; they should not publish plant telemetry or read operational topics.
aws iam create-role --role-name GreengrassV2TokenExchangeRole --assume-role-policy-document file://device-role-trust-policy.json
aws iot create-policy --policy-name GreengrassV2IoTThingPolicy --policy-document file://greengrass-v2-iot-policy.json

Provisioning creates a controlled trust path from a shared claim to a unique device identity.
The token-exchange role trust policy permits AWS IoT Core to assume the role through certificates. Its permissions policy should grant only the AWS service actions required by deployed components. If a telemetry component writes to Amazon Kinesis, scope its role permissions to the intended stream ARN and required write actions. Don’t grant broad service access because a future component might need it. Make that future component request a new role policy deliberately.
Use Thing-bound authorization, not fleet-wide wildcards
A provisioning template creates the Thing, attaches the operational IoT policy, and creates a certificate using AWS::IoT::Certificate::Id. A shared IoT policy is easier to operate, while a per-device policy supports stricter authorization and cleaner exception handling. For homogeneous low-risk telemetry hubs, a shared policy constrained with Thing policy variables can be acceptable. For gateways that can influence control paths, use per-device policies and bind MQTT client IDs and topic prefixes to the Thing name. The deployment override for the component above must use the same factory/<ThingName>/telemetry convention.
One thing to be clear about before you copy the policy below: it’s a narrowing of AWS’s documented minimum Greengrass V2 core device policy, not a replacement for it. Start from the current documented baseline, then scope it to the Thing the way this does. A core device isn’t only publishing your telemetry — it also talks on AWS-reserved topic paths for deployments, jobs, and health reporting, and a policy that grants your factory/ tree and nothing else produces a device that connects, looks fine, and silently never processes a deployment.
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": ["iot:Connect"],
"Resource": "arn:aws:iot:REGION:ACCOUNT:client/${iot:Connection.Thing.ThingName}",
"Condition": {
"Bool": { "iot:Connection.Thing.IsAttached": "true" }
}
},
{
"Effect": "Allow",
"Action": ["iot:Publish", "iot:Receive"],
"Resource": "arn:aws:iot:REGION:ACCOUNT:topic/factory/${iot:Connection.Thing.ThingName}/*",
"Condition": {
"Bool": { "iot:Connection.Thing.IsAttached": "true" }
}
},
{
"Effect": "Allow",
"Action": ["iot:Subscribe"],
"Resource": "arn:aws:iot:REGION:ACCOUNT:topicfilter/factory/${iot:Connection.Thing.ThingName}/*",
"Condition": {
"Bool": { "iot:Connection.Thing.IsAttached": "true" }
}
},
{
"Effect": "Allow",
"Action": ["iot:Publish", "iot:Receive"],
"Resource": "arn:aws:iot:REGION:ACCOUNT:topic/$aws/things/${iot:Connection.Thing.ThingName}/greengrassv2/*",
"Condition": {
"Bool": { "iot:Connection.Thing.IsAttached": "true" }
}
},
{
"Effect": "Allow",
"Action": ["iot:Subscribe"],
"Resource": "arn:aws:iot:REGION:ACCOUNT:topicfilter/$aws/things/${iot:Connection.Thing.ThingName}/greengrassv2/*",
"Condition": {
"Bool": { "iot:Connection.Thing.IsAttached": "true" }
}
},
{
"Effect": "Allow",
"Action": ["iot:Publish", "iot:Receive"],
"Resource": "arn:aws:iot:REGION:ACCOUNT:topic/$aws/things/${iot:Connection.Thing.ThingName}/jobs/*",
"Condition": {
"Bool": { "iot:Connection.Thing.IsAttached": "true" }
}
},
{
"Effect": "Allow",
"Action": ["iot:Subscribe"],
"Resource": "arn:aws:iot:REGION:ACCOUNT:topicfilter/$aws/things/${iot:Connection.Thing.ThingName}/jobs/*",
"Condition": {
"Bool": { "iot:Connection.Thing.IsAttached": "true" }
}
},
{
"Effect": "Allow",
"Action": ["iot:Publish"],
"Resource": "arn:aws:iot:REGION:ACCOUNT:topic/$aws/things/${iot:Connection.Thing.ThingName}/greengrassv2/health/json",
"Condition": {
"Bool": { "iot:Connection.Thing.IsAttached": "true" }
}
},
{
"Effect": "Allow",
"Action": [
"greengrass:GetComponentVersionArtifact",
"greengrass:ResolveComponentCandidates",
"greengrass:GetDeploymentConfiguration",
"greengrass:ListThingGroupsForCoreDevice"
],
"Resource": "*"
},
{
"Effect": "Allow",
"Action": ["iot:AssumeRoleWithCertificate"],
"Resource": "arn:aws:iot:REGION:ACCOUNT:rolealias/GreengrassV2TokenExchangeRoleAlias",
"Condition": {
"Bool": { "iot:Connection.Thing.IsAttached": "true" }
}
}
]
}
Replace REGION and ACCOUNT during policy generation; never ship placeholders and hope provisioning fixes them. Be careful about what a provisioning template actually does for you: parameters like serial number, hardware revision, and manufacturing batch supply values, they don’t check them. If you want a device that shouldn’t be enrolled to never get an identity, that check belongs in a pre-provisioning hook — a function the service calls before the template creates the Thing and certificate — or in another controlled backend process. A claim certificate copied from one production run must not become a universal enrollment pass.
Hardening Greengrass core devices beyond TLS
TLS is necessary, not the whole design. Synchronize device clocks with a trustworthy time source before certificate validation turns into a boot-loop problem. Select modern cipher suites and disable legacy CBC-based ciphers. Full nucleus deployments using Java should explicitly align Java cryptography and TLS parameters with the organization’s approved baseline. For nucleus lite, validate TLS behavior against that same baseline in the actual firmware build, not just on a developer workstation.
Run every component as an unprivileged user unless it truly needs a privileged device interface. Use a narrowly privileged adapter process for serial devices or GPIO and keep the rest unprivileged. Apply read-only mounts where possible without covering Greengrass-managed component artifact directories, and cap log directories with filesystem quotas. A gateway with perfect MQTT authorization can still fail under 100% disk usage.
AWS recommends using the Greengrass secret manager component or the default credential provider chain instead of hardcoded credentials. Follow that rule literally. Retrieve a vendor API token at runtime, cache it only as long as necessary, and restrict access to the component that needs it. Never put credentials, personal data, or sensitive production identifiers in MQTT topic paths, device names, Thing type attributes, component configuration, or logs. Logs tend to outlive the incident that created them.
[OPINION] I’d rather debug a denied action from a narrow policy than investigate a gateway that had broad permissions “for convenience.”
Build structured logs with an allow-list of fields: timestamp, component version, correlation ID, severity, error class, and bounded numeric metrics. Mask identifiers before emission. For a machine-vision component, log a frame hash or event ID rather than a frame or a person-derived label. Rotate logs locally and export only the subset needed for observability. This matters on small flash devices, where verbose logs create both a privacy problem and a wear problem.
Operate without routine SSH. Greengrass deployments handle component updates; AWS Systems Manager can support controlled commands, automation documents, diagnostics, and patch workflows. The multi-account pattern described in AWS guidance for managing multiple IoT gateways remains useful with V2: isolate factories or projects in separate accounts, then use a central management account for governed operations. Cross-account access should be explicit, logged, and short-lived. Direct shell access is an exception path, not fleet management.
Containers, Kubernetes, and the limit of abstraction
Run full nucleus in Docker when the gateway already has a mature container lifecycle and sufficient headroom. AWS documents patterns using Amazon ECS Anywhere, Amazon ECR, and Greengrass components, including deployments where ECS Anywhere places the Greengrass container at the edge and Greengrass deploys its own components such as AWS IoT SiteWise Edge data-processing modules. This can make base-image updates and environment consistency cleaner. It also adds cgroups, image storage, network namespaces, and another update chain.
For a rugged 512 MB board, Docker is usually the wrong bet. Nucleus lite running directly under systemd has fewer layers, fixed runtime allocation, and less storage pressure. Measure the complete steady-state budget: kernel page cache, application RSS, TLS buffers, offline queue, logs, artifacts, and any model memory. “The agent uses less than 5 MB” is not a capacity plan.
KubeEdge, K3s, and MicroK8s make sense on powerful edge nodes when Kubernetes is already the operating model. KubeEdge extends Kubernetes deployment, networking, and cloud-edge data synchronization to edge devices. A sensible hybrid puts KubeEdge on heavy nodes, potentially hosting Greengrass in a container, while nucleus lite serves devices too small for a Kubernetes stack. Don’t force a tiny actuator hub into Kubernetes just to satisfy architectural symmetry. Symmetry does not cool a CPU or recover a corrupted flash partition.
The deployment test that matters
Before production, test a deployment under power loss, absent DNS, expired certificates, full logs, a rejected component artifact, and a blocked upstream route. Test rollback after a component schema change. Test a clock that is wrong by days. Then verify that the device still preserves its local safety behavior while cloud connectivity is unavailable. Industrial IoT gateways are judged in those uncomfortable intervals, not by a green deployment status in a console.

A layered edge architecture keeps constrained endpoints manageable as industrial fleets expand.
AWS IoT Greengrass Core v2.18 gives teams a credible split: full nucleus for substantial gateways and nucleus lite for constrained, deterministic endpoints. Fleet provisioning gives each device an identity; least-privilege components and policies keep that identity from becoming excessive authority. For every gateway review, ask one concrete question: if this device loses power, time, storage, and cloud access in the same hour, what exactly is still allowed to happen?
