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.
Subdirectory |
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.