Golden image anatomy
AWS IoT Greengrass core devices that are manufactured at scale are generally embedded Linux devices that have a Linux distribution that's constructed by using tools such as Yocto
Such devices often have their file system organized into multiple partitions. This guide uses golden image as a catch-all term. Your device might have several golden images, to flash the various partitions.
Your golden image might encompass the entirety of the device's file system or just part of it. This guide focuses on the parts of the file system you need to consider for AWS IoT Greengrass, without prescribing how to assemble your images more broadly.
Greengrass directory tree
To understand the golden image methods discussed in this guide, review the structure of the Greengrass directory tree shown in the following table.
Directory | Description |
|---|---|
| Launch parameters and symbolic links to the Greengrass nucleus version that is currently active. |
| Binaries, if any are installed (for example, the Greengrass CLI binary if that component is installed). This directory is often empty. |
| Scratchpad for Greengrass CLI interprocess communication (IPC). This directory is empty if you haven't installed the Greengrass CLI. |
| All Greengrass configuration, including component configuration. |
| Data for managing the state of deployments and rollbacks. |
| Log files for the nucleus and other components. |
| Artifacts and recipes for all components. |
| Storage for components of type |
| Scratchpad used by Greengrass to aggregate telemetry data ready for publishing. |
| Scratchpad for components. |
The logs, telemetry, and work directories contain only ephemeral data. They don't need be included in a golden image, so omit them if you want to minimize the size of the image.
The Greengrass CLI isn't usually installed on production devices, so the bin and cli_ipc_info directories are often empty and don't typically need to be included in a golden image.
The plugins directory includes data only if you manually installed a plugin (such as the fleet provisioning plugin or a custom provisioning plugin) when you installed Greengrass.
The data in the deployments directory is used only when a deployment is in progress and therefore isn't needed in a golden image.
Consequently the alts, config and packages directories are of the greatest interest. Sometimes these are the only Greengrass directories you need to include in a golden image, if you want to minimize the image size.
Contents of the packages directory
The packages directory has three subdirectories, as shown in the following table.
Sub-directory | Description |
|---|---|
| The zipped component artifacts that Greengrass downloads during deployments. |
| For artifacts that are |
| The component recipe files. |
artifacts
The following example tree listing of packages/artifacts shows how artifacts are stored.
user@machine:~$ sudo tree /greengrass/v2/packages/artifacts /greengrass/v2/packages/artifacts ├── aws.greengrass.DockerApplicationManager ├── aws.greengrass.LogManager │ └── 2.3.7 │ └── aws.greengrass.LogManager.jar ├── aws.greengrass.Nucleus │ └── 2.12.6 │ └── aws.greengrass.nucleus.zip ├── aws.greengrass.SecretManager │ └── 2.1.8 │ └── aws.greengrass.SecretManager.jar ├── aws.greengrass.SecureTunneling │ └── 1.0.19 │ └── GreengrassV2SecureTunnelingComponent-1.0-all.jar ├── aws.greengrass.labs.CertificateRotator │ └── 1.1.0 │ └── certificate-rotator.zip ├── aws.greengrass.labs.HomeAssistant │ └── 1.0.0 │ └── home-assistant.zip └── aws.greengrass.telemetry.NucleusEmitter └── 1.0.8 └── aws.greengrass.telemetry.NucleusEmitter.jar 15 directories, 7 files
artifacts-unarchived
The following example tree listing of packages/artifacts-unarchived shows artifacts that are extracted from .zip files.
user@machine:~$ sudo tree /greengrass/v2/packages/artifacts-unarchived /greengrass/v2/packages/artifacts-unarchived ├── aws.greengrass.Nucleus │ └── 2.12.6 │ └── aws.greengrass.nucleus │ ├── LICENSE │ ├── NOTICE │ ├── README.md │ ├── THIRD-PARTY-LICENSES │ ├── bin │ │ ├── greengrass.exe │ │ ├── greengrass.service │ │ ├── greengrass.service.procd.template │ │ ├── greengrass.service.template │ │ ├── greengrass.xml.template │ │ ├── loader │ │ └── loader.cmd │ ├── conf │ │ └── recipe.yaml │ └── lib │ └── Greengrass.jar ├── aws.greengrass.SecureTunneling │ └── 1.0.19 ├── aws.greengrass.labs.CertificateRotator │ └── 1.1.0 │ └── certificate-rotator │ ├── __pycache__ │ │ ├── config.cpython-310.pyc │ │ ├── config.cpython-311.pyc │ │ ├── effective_config.cpython-310.pyc │ │ ├── effective_config.cpython-311.pyc │ │ ├── main.cpython-311.pyc │ │ ├── pki.cpython-310.pyc │ │ ├── pki.cpython-311.pyc │ │ ├── pki_file.cpython-310.pyc │ │ ├── pki_file.cpython-311.pyc │ │ ├── pki_hsm.cpython-310.pyc │ │ ├── pki_hsm.cpython-311.pyc │ │ ├── pubsub.cpython-310.pyc │ │ ├── pubsub.cpython-311.pyc │ │ ├── state.cpython-310.pyc │ │ ├── state.cpython-311.pyc │ │ ├── state_committing_certificate.cpython-310.pyc │ │ ├── state_committing_certificate.cpython-311.pyc │ │ ├── state_creating_certificate.cpython-310.pyc │ │ ├── state_creating_certificate.cpython-311.pyc │ │ ├── state_getting_job.cpython-310.pyc │ │ ├── state_getting_job.cpython-311.pyc │ │ ├── state_idle.cpython-310.pyc │ │ ├── state_idle.cpython-311.pyc │ │ ├── state_machine.cpython-310.pyc │ │ ├── state_machine.cpython-311.pyc │ │ ├── state_updating_job.cpython-310.pyc │ │ ├── state_updating_job.cpython-311.pyc │ │ ├── topic_base.cpython-310.pyc │ │ └── topic_base.cpython-311.pyc │ ├── config.py │ ├── effective_config.py │ ├── main.py │ ├── pki.py │ ├── pki_file.py │ ├── pki_hsm.py │ ├── pubsub.py │ ├── requirements.txt │ ├── scripts │ │ └── run.cmd │ ├── state.py │ ├── state_committing_certificate.py │ ├── state_creating_certificate.py │ ├── state_getting_job.py │ ├── state_idle.py │ ├── state_machine.py │ ├── state_updating_job.py │ └── topic_base.py └── aws.greengrass.labs.HomeAssistant └── 1.0.0 └── home-assistant ├── config │ ├── automations.yaml │ ├── configuration.yaml │ ├── groups.yaml │ ├── scenes.yaml │ └── scripts.yaml ├── docker-compose.yml ├── install.py └── secret.py 17 directories, 67 files
Note that the alts directory links to the Nucleus .jar file in packages/artifacts-unarchived. For example:
user@machine:~$ sudo ls -l /greengrass/v2/alts/init total 8 lrwxrwxrwx 1 root root 97 Jun 27 08:12 distro -> /greengrass/v2/packages/artifacts-unarchived/aws.greengrass.Nucleus/2.12.6/aws.greengrass.nucleus -rw-r--r-- 1 root root 16 Jun 27 07:07 launch.params
Therefore, packages/artifacts-unarchived must be included in your golden image.
recipes
The following example tree listing of packages/recipes shows how recipes are stored. As the listing indicates, recipes are stored with digests to help Greengrass determine whether it already has the correct files when it receives a deployment. This highly specific format makes it difficult to compose a golden image. Consequently, taking a snapshot of a golden device is the recommended method for creating a golden image.
user@machine:~$ sudo tree /greengrass/v2/packages/recipes /greengrass/v2/packages/recipes ├── 0ya1warrMfzlq5PUTvOgfHOununru_xCLUFACECM_R0@2.3.7.metadata.json ├── 0ya1warrMfzlq5PUTvOgfHOununru_xCLUFACECM_R0@2.3.7.recipe.yaml ├── 89r1-ak7xPauDt4O7EG03sSXVUO8ysdHTk-YdF0NAAc@2.12.6.metadata.json ├── 89r1-ak7xPauDt4O7EG03sSXVUO8ysdHTk-YdF0NAAc@2.12.6.recipe.yaml ├── VAZ-Grqe5g43yO7UtasQOR5jcQGILgPeRZQhVikLd9o@1.0.0.metadata.json ├── VAZ-Grqe5g43yO7UtasQOR5jcQGILgPeRZQhVikLd9o@1.0.0.recipe.yaml ├── ViMYPYs99-AzSt1gL2L2YD5P7sIN-yEhy23wWJK_JN8@1.0.8.metadata.json ├── ViMYPYs99-AzSt1gL2L2YD5P7sIN-yEhy23wWJK_JN8@1.0.8.recipe.yaml ├── _1hT2A6X0ZYtB_CfI_ZUOEMDV96DfQVkSmZh2bbGYXg@1.0.19.metadata.json ├── _1hT2A6X0ZYtB_CfI_ZUOEMDV96DfQVkSmZh2bbGYXg@1.0.19.recipe.yaml ├── gQWwM7MSL2kOsBADU9bOQJ1QqO8ZI3hqpbKT5Bv4Ijk@1.1.0.metadata.json ├── gQWwM7MSL2kOsBADU9bOQJ1QqO8ZI3hqpbKT5Bv4Ijk@1.1.0.recipe.yaml ├── j_j5Seyy01FOcIh95nBFy4HYf8P1kT-jW_nmV18ldbk@2.1.8.metadata.json └── j_j5Seyy01FOcIh95nBFy4HYf8P1kT-jW_nmV18ldbk@2.1.8.recipe.yaml 0 directories, 14 files
System service
If Greengrass is installed as a system service, as it commonly is for embedded Linux devices, the golden image must also include the directories that contain the systemd startup scripts.
Docker images
If your device uses AWS IoT Greengrass components that feature Docker images as artifacts, these artifacts sit outside the Greengrass directory tree. Therefore, you need to include the golden device's Docker image registry in your golden image. This registry is typically stored in /var/lib/docker.
Alternatively, you can use Docker commands to make a copy of the Docker images that are stored on your golden device, and then load those Docker images onto each device on your manufacturing line. In general, this method is slower and becomes less scalable as the number of Docker images increases.
Secrets
If your devices use the secret manager component to synchronize secrets from AWS Secrets Manager, these secrets are stored in the config/config.tlog file in the Greengrass directory tree of your golden device. For example:
{"TS":1718878001465, "TP":["services","aws.greengrass.SecretManager","runtime","secretResponse"], "W":"changed", "V":"{\"secrets\":[ { \"arn\":\"arn:aws:secretsmanager:us-east-1:111122223333:secret:greengrass-home-assistant-KIzJfZ\", \"name\":\"greengrass-home-assistant\", \"versionId\":\"8e481177-9250-4458-9f1f-3690d28e4ae9\", \"encryptedSecretString\":\"AgV4j+We ... A7QjdE1w==\", \"versionStages\":[\"AWSCURRENT\"], \"createdDate\":1660648425915 } ] } "}
These secrets are also stored in the corresponding config/effectiveConfig.yaml file:
aws.greengrass.SecretManager: componentType: "PLUGIN" configuration: cloudSecrets: - arn: "arn:aws:secretsmanager:us-east-1:111122223333:secret:greengrass-home-assistant-KIzJfZ" dependencies: - "aws.greengrass.Nucleus:SOFT" lifecycle: {} runtime: secretResponse: "{\"secrets\":[{\"arn\":\"arn:aws:secretsmanager:us-east-1:111122223333:secret:greengrass-home-assistant-KIzJfZ\"\ ,\"name\":\"greengrass-home-assistant\",\"versionId\":\"8e481177-9250-4458-9f1f-3690d28e4ae9\"\ ,\"encryptedSecretString\":\"AgV4Rpc9 ... MYeVALYQ==\"\ ,\"versionStages\":[\"AWSCURRENT\"],\"createdDate\":1660648425915}]}" version: "2.1.8"
Even if you include the config directory in your golden image, it's important to remember that the Greengrass secret manager component encrypts the secret with the golden device's private key. Because each device has a unique private key, keys that were encrypted by your golden device can't be decrypted by your production devices.
For this reason, we recommend that you remove encrypted secrets from the golden image to prevent your production devices from incorrectly decrypting golden device secrets. Your application components should function adequately, or at least fail gracefully, when secrets aren't present on disk, before a device has its first communication with the cloud.
When secrets are a hard requirement
If your organization requires your production devices to be populated with secrets during manufacture, your production line needs a script or program that replicates the behavior of the secret manager component, to populate secrets on each production device. We don't recommend this approach because of its complexity and the possibility that your secrets might briefly be held in cleartext on your production programming station.