diff --git a/.gitignore b/.gitignore index c81a159f7c..7e5f36595b 100644 --- a/.gitignore +++ b/.gitignore @@ -45,3 +45,4 @@ __pycache__/ # QT Creator CMakeLists.txt.user +/docs/ota-client-guide/modules/ROOT/pages/_junk diff --git a/docs/Doxyfile.in b/docs/Doxyfile.in index 162d4224fe..e1f5190047 100644 --- a/docs/Doxyfile.in +++ b/docs/Doxyfile.in @@ -799,7 +799,6 @@ INPUT = @CMAKE_SOURCE_DIR@/docs \ @CMAKE_SOURCE_DIR@/tests \ @CMAKE_SOURCE_DIR@/src/aktualizr_info \ @CMAKE_SOURCE_DIR@/src/aktualizr_primary \ - @CMAKE_SOURCE_DIR@/src/uptane_generator \ @CMAKE_SOURCE_DIR@/src/aktualizr_secondary \ @CMAKE_SOURCE_DIR@/src/cert_provider \ @CMAKE_SOURCE_DIR@/src/hmi_stub \ @@ -821,6 +820,7 @@ INPUT = @CMAKE_SOURCE_DIR@/docs \ @CMAKE_SOURCE_DIR@/src/libaktualizr/utilities \ @CMAKE_SOURCE_DIR@/src/load_tests \ @CMAKE_SOURCE_DIR@/src/sota_tools \ + @CMAKE_SOURCE_DIR@/src/uptane-generator \ @CMAKE_SOURCE_DIR@/CONTRIBUTING.md \ @CMAKE_SOURCE_DIR@/CHANGELOG.md diff --git a/docs/INDEX.md b/docs/INDEX.md deleted file mode 100644 index 3be476fbb9..0000000000 --- a/docs/INDEX.md +++ /dev/null @@ -1,18 +0,0 @@ -Aktualizr is the HERE OTA Connect client. This client runs on any embedded device and can check for updates periodically or triggered by another system interaction. You can build this client from source or you can integrate it into your firmware with the Yocto toolset. - -When running on an embedded device, the aktualizr client uses a minimal amount of memory and CPU and doesn’t need to remain resident in the memory at all. The client can run on any Linux-based operating system, or any operating system that includes the GNU C Library. However, if you run aktualizr on a non-Linux system, you might have to customize it first. - -The client is responsible for the following tasks: - -* Communicating with the HERE OTA Connect server -* Authenticating using locally available device and user credentials -* Reporting current software and hardware configuration to the server -* Checking for any available updates for the device -* Downloaded any available updates -* Installing the updates on the system, or notifying other services of the availability of the downloaded file -* Receiving or generating installation reports (success or failure) for attempts to install received software -* Submitting installation reports to the server - -The aktualizr client application is a thin wrapper around the client library "libaktualizr". You could regard this library as a kind of toolbox. You can use the parts in this library to build a software update solution that conforms to the Uptane standard. - -For all controllers that run aktualizr or include libaktualizr, you’ll need to implement some form of key provisioning. The OTA Connect documentation explains in detail how to [select a provisioning method](https://docs.ota.here.com/client-config/client-provisioning-methods.html) that suits your use case. For more information on how you can use this library, also see the [reference docs](https://github.com/advancedtelematic/aktualizr/tree/master/docs). diff --git a/docs/README.adoc b/docs/README.adoc index 19a93b88c9..56d48909a0 100644 --- a/docs/README.adoc +++ b/docs/README.adoc @@ -1,34 +1,15 @@ -= Aktualizr reference docs += OTA Connect Developer Guide -This directory contains developer-focused documentation on various specialized aktualizr topics. +This directory contains the source of our **OTA Connect Developer Guide** which is published to our https://docs.ota.here.com[documentation portal]. -link:./client-provisioning-methods.adoc[client-provisioning-methods.adoc] - Describes how aktualizr handles provisioning with either shared credentials or device credentials. +You can also read the source files for this guide. To read this guide locally or in GitHub, start with the xref:ota-client-guide/modules/ROOT/nav.adoc[table of contents]. -link:./configuration.adoc[configuration.adoc] - A reference for aktualizr's TOML config files. - -link:./provisioning-methods-and-credentialszip.adoc[provisioning-methods-and-credentialszip.adoc] - An explanation of the format of credentials.zip, a bundle generated by HERE OTA Connect/OTA Community Edition containing necessary credentials and config for aktualizr and meta-updater. - -link:./deb-package-install.adoc[deb-package-install.adoc] - The https://github.com/advancedtelematic/aktualizr/releases[releases] page includes a .deb package for aktualizr. This isn't likely useful for most production use cases, but it can be handy for testing. This document guides you through how to use the .deb. - -link:./debugging-tips.adoc[debugging-tips.adoc] - Useful debugging info, mostly targeted at people contributing to the development of aktualizr. - -link:./fault-injection.adoc[fault-injection.adoc] - How to inject faults during aktualizr runs, to help test failure cases of the system. - -link:./provision-with-device-credentials.adoc[provision-with-device-credentials.adoc] - Provisioning with device credentials is a more secure way of provisioning devices. Unlike shared-credentials provisioning, each image is required to have some credentials side-loaded that are unique to the device which receives the image. This topic also explains of aktualizr's approach to using a hardware security module for provisioning with device credentials. - -link:./integrate-libaktualizr.adoc[integrate-libaktualizr.adoc] - How to use Aktualizr as a library ('libaktualizr') to implement custom software update clients. This can be used to integrate Aktualizr with a user interface or to deliver updates to a custom package manager. - -link:./linux-secondaries.adoc[linux-secondaries.adoc] - A quick how-to demonstrating aktualizr on a secondary ECU, using two QEMU devices. - -link:./rollback.adoc[rollback.adoc] - Developer documentation on how aktualizr, OSTree, and u-boot can be used to implement automatic rollback of a failed update. - -link:./schema-migrations.adoc[schema-migrations.adoc] - aktualizr uses a SQLite database for storing some config information and keys. This describes the steps needed for migrating the DB schema. Only useful for aktualizr developers. - -link:./security.adoc[security.adoc] - A brief description of properties a system running aktualizr must have to conform with the Uptane security model. - -link:./selectively-triggering-aktualizr.adoc[selectively-triggering-aktualizr.adoc] - Aktualizr normally runs as a service, polling for updates periodically. However, it can also be triggered externally--for example, in response to a shoulder-tap, or in response to user interaction on an HMI. This document describes how to do that. +[NOTE] +==== +Content includes, such as code snippets or reused text snippets will not render correctly in Github. +==== -== Developer documentation +== Reference documentation Additional documentation intended for developers that may need to use the libaktualizr API should refer to link:https://advancedtelematic.github.io/aktualizr/index.html[this doc]: [NOTE] @@ -76,4 +57,4 @@ make doxygen 1. In the second repo, make a directory for the tag or commit you wish to add, i.e. `mkdir 2018.63`. 1. Copy the contents of `/docs/html` into the directory you just created. (Something like `cp -a /docs/html/* /2018.63`.) 1. In the second repo, run `git add 2018.63`, `git commit -as`, and `git push`. -1. Wait a minute or two for github to refresh and render the files. +1. Wait a minute or two for github to refresh and render the files. \ No newline at end of file diff --git a/docs/client-provisioning-methods.adoc b/docs/client-provisioning-methods.adoc deleted file mode 100644 index a20c4ee4d0..0000000000 --- a/docs/client-provisioning-methods.adoc +++ /dev/null @@ -1,39 +0,0 @@ -// Copy of this topic: https://docs.ota.here.com/client-config/client-provisioning-methods.html adapted for aktualizr repo. Replaces duplicate "automatic-provisioning.adoc" - -In OTA Connect, the provisioning process ensures that the device has a certificate and a unique identifier. After a device has been provisioned, it can receive software updates. OTA Connect supports two types of provisioning: - -* *Provisioning with Shared Credentials* -+ -Devices use temporary provisioning credentials to request permanent credentials from the server. You download the temporary provisioning credentials from the OTA Connect web app and install them on a device. Once the device registers with the server for the first time, the server assigns permanent credentials to the device. The device then uses these permanent credentials for all future transactions. - - -* *Provisioning with Device Credentials* -+ -Devices already have permanent credentials installed. The server doesn't issue any credentials to devices. Instead, you use a root CA certificate to sign the credentials that you install on the device. You then install the same root CA certificate on the OTA Connect server. -Every time the device attempts to connect, the server verifies that the device credentials are signed by the same CA that you originally installed on the server. - -== Choosing a provisioning method - -The type of provisioning that you choose depends on your requirements. If you're just testing and want to get started quickly, provisioning with shared credentials is fine. It is easier to set up but is less secure. Because the server self-signs the credentials that it issues to devices, the devices have no way of verifying the integrity of the server. This level of security is not suitable for a production environment. The device should always be able to verify that is communicating with a genuine OTA Connect server. Once you move to production, you should look at some form of provisioning that uses device certificates. For more security, use a Hardware Security Module (HSM) to store the device certificates. - -=== Configure a Device to Provision with Shared Credentials - -To configure a device to provision with shared credentials, follow these steps: - -. Download a https://docs.ota.here.com/quickstarts/generating-provisioning-credentials.html[provisioning key]. -. Edit the following `.toml` configuration file: -+ -link:../config/sota-shared-cred.toml[config/sota-shared-cred.toml] -. Update the configuration file with the path to the zip file that you saved in the first step and start Aktualizr on the device. -+ -** When aktualizr starts, it uses the provisioning key to register with the device gateway HTTPS API. -** The server registers the new device and returns a PKCS#12 archive containing the real credentials for the device. This archive contains the root CA certificate and client certificate. -** The device unpacks the archive into the paths that are specified in the `[storage]` section of the config. -** The device uses this private key and certificate for all further communication with the server. - -=== Configure a Device to Provision with Device Credentials - -To configure a device to provision with device credentials, you need a root CA certificate obtained from a trusted certificate authority. - -* If you don't have a root CA certificate yet, you can https://docs.ota.here.com/prod/generate-and-install-a-root-certificate.html[generate and install a self-signed root CA certificate] or link:./provision-with-device-credentials.adoc#simulate-device-credential-provisioning-for-testing[simulate provisioning with device credentials]. -* When you're ready to move to production, follow the procedure to link:./provision-with-device-credentials.adoc#use-a-hardware-security-module-hsm-when-provisioning-with-device-credentials[use a Hardware Security Module to provision with device credentials] diff --git a/docs/client-provisioning-methods.adoc b/docs/client-provisioning-methods.adoc new file mode 120000 index 0000000000..fd7beb80bb --- /dev/null +++ b/docs/client-provisioning-methods.adoc @@ -0,0 +1 @@ +./ota-client-guide/modules/ROOT/pages/client-provisioning-methods.adoc \ No newline at end of file diff --git a/docs/configuration.adoc b/docs/configuration.adoc deleted file mode 100644 index 86c6568caa..0000000000 --- a/docs/configuration.adoc +++ /dev/null @@ -1,169 +0,0 @@ -= Configuration -:aktualizr-github-url: https://github.com/advancedtelematic/aktualizr/tree/master -ifdef::env-github[] -:aktualizr-github-url: .. -endif::[] - -Aktualizr is configured via `.toml` config files. One or more files or directories can be passed to the application via the `--config` flag (one per file or directory). If `--config` is not specified on the command line, aktualizr searches `/usr/lib/sota/conf.d` and `/etc/sota/conf.d/` for files with a `.toml` extension. Aktualizr searches for and processes these config files in systemd style, meaning that if multiple files are found with the same name, the last one found overrules and hides the others. Files are then processed in alphabetical order, so if a config option is specified in multiple files, the last entry found overrules the others. If an option is left unspecified in a file processed after another file in which it was specified, it is not overruled. - -Example config files used by unit tests, continuous integration tests, and https://github.com/advancedtelematic/meta-updater[meta-updater] recipes can be found in link:{aktualizr-github-url}/config/[], link:{aktualizr-github-url}/tests/config/[], and link:https://github.com/advancedtelematic/meta-updater/tree/rocko/recipes-sota/config/files[]. - -All fields are optional, and most have reasonable defaults that should be used unless you have a particular need to do otherwise. - -Some options can also be set on the command line. The command line input always takes precedence over the config files. See link:{aktualizr-github-url}/src/aktualizr_primary/main.cc[] (or run `aktualizr --help`) for the available command line options. - -== `logger` - -Configuration for the logger. - -[options="header"] -|========================================================================================== -| Name | Default | Description -| `loglevel` | `2` | Log level, 0-5 (trace, debug, info, warning, error, fatal). -|========================================================================================== - -== `p11` - -Options for using a PKCS#11 compliant device for storing cryptographic keys. - -NOTE: The key ID options require the corresponding options in the `tls` or `uptane` section to be set to `pkcs11`. - -[options="header"] -|========================================================================================== -| Name | Default | Description -| `module` | | Path to the shared object HSM driver. -| `pass` | | Password for accessing the HSM. -| `uptane_key_id` | | Key ID of the Uptane key in the HSM. -| `tls_cacert_id` | | Key ID of the TLS root CA certificate for authenticating the server. -| `tls_pkey_id` | | Key ID of the client's TLS private key. -| `tls_clientcert_id` | | Key ID of the client's TLS certificate. -|========================================================================================== - -== `tls` - -Configuration for client-server TLS connections. - -[options="header"] -|========================================================================================== -| Name | Default | Description -| `server` | | Server URL. -| `server_url_path` | | Path to a file that contains the server URL. -| `ca_source` | `"file"` | Where to read the TLS root CA certificate from. Options: `"file"`, `"pkcs11"`. -| `pkey_source` | `"file"` | Where to read the client's TLS private key from. Options: `"file"`, `"pkcs11"`. -| `cert_source` | `"file"` | Where to read the client's TLS certificate from. Options: `"file"`, `"pkcs11"`. -|========================================================================================== - -Note that `server_url_path` is only used if `server` is empty. If both are empty, the server URL will be read from `provision.provisioning_path` if it is set and contains a file named `autoprov.url`. - -== `provision` - -Options for how the device is provisioned with the backend. - -[options="header"] -|========================================================================================== -| Name | Default | Description -| `server` | | Server provisioning URL. If empty, set to `tls.server`. -| `p12_password` | | Password for PKCS#12 encryption. -| `expiry_days` | `"36000"` | Provided in the `ttl` field of the device provisioning request sent to the server. -| `provision_path` | | Path to an archive containing provisioning data. See link:{aktualizr-github-url}/docs/provisioning-methods-and-credentialszip.adoc[] for the specification of the contents of this file. -| `device_id` | | Device ID of the primary ECU. If left empty, a random name will be generated. -| `primary_ecu_serial` | | Serial number of the primary ECU. If left empty, a random serial will be generated. -| `primary_ecu_hardware_id` | | The hardware ID of the primary ECU (e.g., `"raspberry-pi"`). If left empty, the hostname of the device will be used. -| `ecu_registration_endpoint` | | Ecu provisioning URL. If empty, set to `uptane.director_server` with `/ecus` appended. -|========================================================================================== - -If you intend to provision with a server by using https://github.com/advancedtelematic/meta-updater[meta-updater], you will probably want to set `provision.provision_path = "/var/sota/sota_provisioning_credentials.zip"`. - -== `uptane` - -Options for Uptane. - -[options="header"] -[cols="1,1,20"] -|========================================================================================== -| Name | Default | Description -| `polling_sec` | `10` | Interval between polls (in seconds). -| `director_server` | | Director server URL. If empty, set to `tls.server` with `/director` appended. -| `repo_server` | | Image repository server URL. If empty, set to `tls.server` with `/repo` appended. -| `key_source` | `"file"` | Where to read the device's private key from. Options: `"file"`, `"pkcs11"`. -| `key_type` | `"RSA2048"` | Type of cryptographic keys to use. Options: `"ED25519"`, `"RSA2048"`, `"RSA3072"` or `"RSA4096"`. -| `secondary_config_file` | `""` | A path to a json file containing configuration of Secondary ECU(s) to be registered with the primary. - Examples here: link:{aktualizr-github-url}/config/secondary/virtualsec.json[Virtual Secondary config] and link:{aktualizr-github-url}/config/posix-secondary-config.json[Posix/IP Secondary config] -| `force_install_completion`| false | Forces installation completion. Causes a system reboot in case of an ostree package manager. Emulates a reboot in case of a fake package manager. -|========================================================================================== - -== `pacman` - -Options for package management and update installation. Note that this only coincidentally shares the name with the ArchLinux `pacman` tool. - -[options="header"] -|========================================================================================== -| Name | Default | Description -| `type` | `"ostree"` | Which package manager to use. Options: `"ostree"`, `"debian"`, `"none"`. -| `os` | | OSTree operating system group. Only used with `ostree`. -| `sysroot` | | Path to an OSTree sysroot. Only used with `ostree`. -| `ostree_server` | | OSTree server URL. Only used with `ostree`. If empty, set to `tls.server` with `/treehub` appended. -| `packages_file` | `"/usr/package.manifest"` | Path to a file for storing package manifest information. Only used with `ostree`. -| `fake_need_reboot` | false | Simulate a wait-for-reboot with the `"none"` package manager. Used for testing. -|========================================================================================== - -== `storage` - -Options for how Aktualizr stores data locally. - -[options="header"] -|========================================================================================== -| Name | Default | Description -| `type` | `"sqlite"` | What type of storage driver to use. Options: `"sqlite"`. The former `"filesystem"` option is now disabled, existing devices will be migrated (see note below) -| `path` | `"/var/sota"` | Directory for storage -| `sqldb_path` | `"sql.db"` | Relative path to the database file. -| `uptane_metadata_path` | `"metadata"` | Path to the uptane metadata store, for migration from `filesystem`. -| `uptane_private_key_path` | `"ecukey.der"` | Relative path to the Uptane specific private key, for migration from `filesystem`. -| `uptane_public_key_path` | `"ecukey.pub"` | Relative path to the Uptane specific public key, for migration from `filesystem`. -| `tls_cacert_path` | `"root.crt"` | Relative path to the TLS root CA certificate, for migration from `filesystem`. -| `tls_pkey_path` | `"pkey.pem"` | Relative path to the client's TLS private key, for migration from `filesystem`. -| `tls_clientcert_path` | `"client.pem"` | Relative path to the client's TLS certificate, for migration from `filesystem`. -|========================================================================================== - -The only supported storage option is now `sqlite`. - -Old systems configured with `filesystem` can be migrated by changing the `type` field to `sqlite` and keeping all the other fields as-is. -At the next Aktualizr run, the migration procedure will then run automatically and move existing data inside the database. - -== `import` - -Options for importing data from the filesystem into the storage. - -[options="header"] -|========================================================================================== -| Name | Default | Description -| `base_path` | `"/var/sota/import"` | Path to a common root directory to the subsequent files -| `uptane_private_key_path` | | Path to the device's private key. -| `uptane_public_key_path` | | Path to the device's public key. -| `tls_cacert_path` | | Path to the TLS root CA certificate. -| `tls_pkey_path` | | Path to the TLS private key. -| `tls_clientcert_path` | | Path to the TLS client certificate. -|========================================================================================== - -== `telemetry` - -Options for configuring how aktualizr communicates with the server. - -[options="header"] -|========================================================================================== -| Name | Default | Description -| `report_network` | `true` | Enable reporting of device networking information to the server. -|========================================================================================== - -== `bootloader` - -Options for configuring boot-specific behavior - -[options="header"] -|========================================================================================== -| Name | Default | Description -| `rollback_mode` | `"none"` | Controls rollback on supported platforms, see link:{aktualizr-github-url}/docs/rollback.adoc[]. Options: `"none"`, `"uboot_generic"`, `"uboot_masked"` -| `reboot_sentinel_dir` | `"/var/run/aktualizr-session"` | Base directory for reboot detection sentinel. Must reside in a temporary file system. -| `reboot_sentinel_name` | `"need_reboot"` | Name of the reboot detection sentinel. -| `reboot_command` | `"/sbin/reboot"` | Command to reboot the system after update completes. Applicable only if `uptane::force_install_completion` is set to `true`. -|========================================================================================== diff --git a/docs/configuration.adoc b/docs/configuration.adoc new file mode 120000 index 0000000000..62a1467c83 --- /dev/null +++ b/docs/configuration.adoc @@ -0,0 +1 @@ +./ota-client-guide/modules/ROOT/pages/aktualizr-config-options.adoc \ No newline at end of file diff --git a/docs/deb-package-install.adoc b/docs/deb-package-install.adoc deleted file mode 100644 index a76d18e78c..0000000000 --- a/docs/deb-package-install.adoc +++ /dev/null @@ -1,49 +0,0 @@ -== Installing aktualizr via debian package - -Aktualizr makes .deb packages available via the https://github.com/advancedtelematic/aktualizr/releases[GitHub releases page]. Download and install the .deb package, for example: - ----- -sudo apt install ./aktualizr.deb ----- - -=== Setting up aktualizr - -The debian package will install, enable, and start an `aktualizr` systemd service immediately after it's installed. However, there are some configuration steps that should be taken before the service starts. To use aktualizr with a server (i.e. https://github.com/advancedtelematic/ota-community-edition/[OTA Community Edition] or https://docs.ota.here.com[HERE OTA Connect]), you will need to download the provisioning credentials file provided by the server and place it at `/var/sota/sota_provisioning_credentials.zip`. - -You can pass any other command line arguments in this file, as well. - -For security reasons, we recommend creating the `/usr/lib/sota/sota.env` file even if you aren't going to use it. The file should be owned by root, with `600` permissions. - -=== Secondary ECUs - -The debian package ships with a default secondary ECU configured. This acts like a dummy device, dropping whatever file you send it into `/tmp/demo-virtual-secondary/firmware.bin`. - -=== Building the debian package - -After following the main build setup steps, just `make package` instead of `make` to create a debian package from your current branch, for example: - ----- -git clone --recursive https://github.com/advancedtelematic/aktualizr -cd aktualizr -mkdir build -cd build -cmake -DCMAKE_BUILD_TYPE=Debug -DBUILD_DEB=ON .. -make package ----- - -=== Making a Release on github - -Releases are built automatically by Travis from annotated tags of the form `major.minor`, where `major` and `minor` are numbers. We normally set `major` to the current year and `minor` to an incrementing number beginning at 1. - -To create a release, checkout the revision you want to bless, then: - ----- -git tag -as # e.g. git tag -a 2018.4 -git push github ----- - -Travis will build this tag and automatically create a release for it on github. This is normally a good time to update the link:../CHANGELOG.md[changelog] and the doxygen documentation. Ideally, the changelog should be updated with the new release number before creating the release so that the packaged source code includes the correct information about the release. The process for updating the doxygen is specified in the link:README.adoc#developer-documentation[docs README]. - -Once the release is ready on github, it should be edited to include a link to the changelog and doxygen documentation for that particular release. You can use a previous release as a model of how to format these links. - -Don't forget to test the resulting Debian packages manually! diff --git a/docs/deb-package-install.adoc b/docs/deb-package-install.adoc new file mode 120000 index 0000000000..d9907225b8 --- /dev/null +++ b/docs/deb-package-install.adoc @@ -0,0 +1 @@ +./ota-client-guide/modules/ROOT/pages/deb-package-install.adoc \ No newline at end of file diff --git a/docs/debugging-tips.adoc b/docs/debugging-tips.adoc deleted file mode 100644 index bd7261c410..0000000000 --- a/docs/debugging-tips.adoc +++ /dev/null @@ -1,183 +0,0 @@ -= Aktualizr Debugging Tips - -== Running Aktualizr in development - -The `sota-local.toml` configuration file sets the package manager to `PackageManagerFake`, which allows the installation process to be tested locally: - - # From the build directory - mkdir sota-prov - src/aktualizr_primary/aktualizr --config ../config/sota-local.toml - -For VS code, there is a `launch.json` provided in the `.vscode` directory. This assumes that the cmake build directory is `build`. - -== Creating a temporary OSTree environment - -Try the scripts available in the link:../tests/ostree-scripts[tests/ostree-scripts] directory. - -== Inspect stored info with aktualizr-info - -The aktualizr-info tool can be used to dump information stored in the libaktualizr database. By default, it displays basic information such as storage type, device ID, primary ECU serial and hardware ID and provisioning status. Additional information can be requested with link:../src/aktualizr_info/main.cc[various command line parameters]. - -== Valgrind and gdb - -If the target application or test is running under valgrind, then gdb can still be connected to the process without stopping it. First run `vgdb --port=2159` in a different shell on the same machine, then connect to it using `target remote localhost:2159` in gdb - -== Dumping SSL encrypted traffic - -First fetch and build sslkeylog from https://github.com/cajun-rat/sslkeylog - -Next copy aktualizr.service to /etc/systemd/system/aktualizr.service. -This will override the packages default config. - -Now modify `/etc/systemd/system/aktualizr.service` and add the following lines: - -``` -Environment=SSLKEYLOGFILE=/var/sota/premaster.txt -Environment=LD_PRELOAD=/usr/lib/libsslkeylog.so -``` - -Reload the config and restart - -``` -# systemctl daemon-reload -# systemctl restart aktualizr -``` - -The symmetric SSL keys will be logged in `/var/sota/premaster.txt` - -Now capture a packet dump with tcpdump - -``` -sudo tcpdump tcp port 443 -w upload.pcap -``` - -Fetch both of these down. In wireshark preferences set ssl.keylog_file to point to premaster.txt. If your https traffic not on port 443, then add the port to http.ssl.port. Now open upload.pcap. - -== Serve repo generated by uptane-generator - -aktualizr can be tested against a dummy repository containing fake images. - -First, generate a repository using link:../src/uptane_generator/main.cc[uptane-generator] tool: - -``` -uptane-generator generate -``` - -Then, serve the generated directory using a web server such as the link:../tests/fake_http_server/fake_test_server.py[fake test server]. - -For more information about using uptane-generator, see link:./uptane-generator.adoc[uptane-generator.adoc]. - -Here is an example configuration for nginx: - -``` -server { - listen 80; - listen [::]:80; - server_name localhost; - - location / { - try_files $request_uri $request_uri; - } - location /director/manifest { - try_files $request_uri $request_uri; - dav_methods PUT; - } - - root repo_dir/repo; -} -``` - -== Inject faults - -See link:./fault-injection.adoc[fault-injection.adoc] - -== Developing and debugging with an OpenEmbedded system - -By default OpenEmbedded builds fixed versions of software from a VCS using bitbake recipes. When developing Aktualizr itself it is useful to have a quicker edit-compile-run cycle and access to a debugger. The following steps will use OpenEmbedded to create a cross-compilation environment, then build inside that. - -1. Add the following to local.conf: -+ ----- -TOOLCHAIN_HOST_TASK_append = " nativesdk-cmake " ----- - -2. Build the SDK: -+ ----- -bitbake -c populate_sdk core-image-minimal ----- - -3. That will create a self-extracting installer that can be copied to your development machine. Install it by executing this script (or a similarly-named one, depending on your environment): -+ ----- -./tmp/deploy/sdk/poky-sota-glibc-x86_64-core-image-minimal-core2-64-toolchain-2.2.2.sh ----- - -4. Execute this script (or something similar, depending on where you installed it) to update the environment to point to the cross compilers: -+ ----- -. /opt/poky-sota/2.2.2/environment-setup-core2-64-poky-linux ----- -+ -You may want to verify that `which cmake` returns something like this: -+ ----- -/opt/poky-sota/2.2.2/sysroots/x86_64-pokysdk-linux/usr/bin/cmake ----- - -5. Create a cmake build directory for this cross-compile: -+ ----- -mkdir build-cross -cd build-cross -cmake .. -make aktualizr ----- - -The compiled 'aktualizr' executable can be copied to the remote system and run. - -Aktualizr can be debugged remotely by exposing a port from the VM to development machine (the --gdb option to the https://github.com/advancedtelematic/meta-updater/blob/master/scripts/run-qemu-ota[run-qemu-ota script] in https://github.com/advancedtelematic/meta-updater[meta-updater] does this), then: - -.On the target: ----- -gdbserver 0.0.0.0:2159 ./aktualizr --config /usr/lib/sota/sota.toml --loglevel 0 ----- - -.On the host: ----- -$ gdb aktualizr -(gdb) target remote localhost:2159 ----- - -In CLion the remote debugger is configured as follows: - -image:clion-debugger.png[CLion GDB configuration] - -It is also possible to run it inside valgrind: - -.On the target: ----- -valgrind --vgdb=yes --vgdb-error=0 ./aktualizr --config /usr/lib/sota/sota.toml -vgdb --port=2159 ----- - -Then connect the debugger as usual. - -== Bitbaking with debug symbols - -For every binary you want to debug (executables and shared libraries alike) you need to add these two lines in the recipe: - -``` -INHIBIT_PACKAGE_DEBUG_SPLIT = "1" -INHIBIT_PACKAGE_STRIP = "1" -``` - -You also need to make it build with debug symbols, which is recipe-dependent. For akualizr it means specifying - -``` --DCMAKE_BUILD_TYPE=Debug -``` - -instead of Release. However, this method does not install the sources on the device, so it helps to open the source file on your host machine. - - diff --git a/docs/debugging-tips.adoc b/docs/debugging-tips.adoc new file mode 120000 index 0000000000..ed50e9e132 --- /dev/null +++ b/docs/debugging-tips.adoc @@ -0,0 +1 @@ +./ota-client-guide/modules/ROOT/pages/debugging-tips.adoc \ No newline at end of file diff --git a/docs/ecu_events.adoc b/docs/ecu_events.adoc deleted file mode 100644 index 0f4fd67faa..0000000000 --- a/docs/ecu_events.adoc +++ /dev/null @@ -1,153 +0,0 @@ -= Client events reporting - -This is a technical document describing the format of the events reported to the back-end by aktualizr during an ongoing update installation. -It reflects the current state of aktualizr code. Future enhancements should be clearly marked as such (`TODO`), to avoid confusion. - -The corresponding C++ objects and their serialization method are defined in link:../src/libaktualizr/primary/reportqueue.h[reportqueue.h]. - -== Common fields - -* `deviceTime` is a timestamp of the event emission (not transmission which can be delayed) -* `eventType` contains two fields `id` and `version` which correspond the format of the custom fields -* `id` is a unique identifier generated on the client side -* `event` contains the custom fields as specified by the event type -* `event.correlationId` (when applicable) identifies the specific update requested by back-end -* `event.ecu` (when applicable) identifies the specific ECU in the vehicle which the event pertains to - -== Per-ECU events - -=== EcuDownloadStarted - -Emitted when the target download relating to a specific ecu has started. Note that since a target can apply to multiple ecus, more than one event can be sent for each target download. - -Contains a correlation id. - -Example: - -``` -{ - "deviceTime" : "2018-10-25T12:35:42Z", - "event" : - { - "correlationId" : "here-ota:campaigns:c017f968-5c7e-4bf6-9992-2134ff06432c", - "ecu" : "secondary_ecu_serial" - }, - "eventType" : - { - "id" : "EcuDownloadStarted", - "version" : 0 - }, - "id" : "313258b4-e4c6-4ce4-a4f3-011a3959d92b" -} -``` - -=== EcuDownloadCompleted - -Emitted when the target download relating to a specific ecu has ended (success or failure). Same caveat as `EcuDownloadStarted` applies. - -Success/failure indicated by the boolean `event.success`. -TODO: revisit that, maybe a status code instead + free form log string - -Contains a correlation id. - -Example: - -``` -{ - "deviceTime" : "2018-10-25T12:35:42Z", - "event" : - { - "correlationId" : "here-ota:campaigns:c017f968-5c7e-4bf6-9992-2134ff06432c", - "ecu" : "CA:FE:A6:D2:84:9D", - "success" : true - }, - "eventType" : - { - "id" : "EcuDownloadCompleted", - "version" : 0 - }, - "id" : "bfb0b452-ac41-4cf0-bec8-3b78469157ec" -} -``` - -=== EcuInstallationStarted - -Emitted when installation on a specific ecu has started. - -Contains a correlation id. - -Example: - -``` -{ - "deviceTime" : "2018-10-25T12:35:42Z", - "event" : - { - "correlationId" : "here-ota:campaigns:c017f968-5c7e-4bf6-9992-2134ff06432c", - "ecu" : "CA:FE:A6:D2:84:9D" - }, - "eventType" : - { - "id" : "EcuInstallationStarted", - "version" : 0 - }, - "id" : "9e3ad5f6-091d-4f63-96eb-20ba2e256631" -} -``` - -=== EcuInstallationCompleted - -Emitted when installation on a specific ecu has ended (success or failure). - -Success/failure indicated by the boolean `event.success`. -TODO: revisit that, maybe a status code instead + free form log string - -Some devices need a reboot after an installation to actually have an effect on the system. -TODO: use a status code `NEED_REBOOT`? - -Contains a correlation id. - -Example: - -``` -{ - "deviceTime" : "2018-10-25T12:35:42Z", - "event" : - { - "correlationId" : "here-ota:campaigns:c017f968-5c7e-4bf6-9992-2134ff06432c", - "ecu" : "CA:FE:A6:D2:84:9D", - "success" : true - }, - "eventType" : - { - "id" : "EcuInstallationCompleted", - "version" : 0 - }, - "id" : "74060fe8-c594-4f37-b676-4d3bedcb5ca5" -} -``` - -== Others - -=== campaign_accepted - -Emitted in response to a campaign confirmation request - -Example: - -``` -{ - "deviceTime" : "2018-10-25T12:56:52Z", - "event" : - { - "campaignId" : "123" - }, - "eventType" : - { - "id" : "campaign_accepted", - "version" : 0 - }, - "id" : "4fc0fb3d-21e3-4b3b-a902-b9c80913f086" - } -} -``` diff --git a/docs/ecu_events.adoc b/docs/ecu_events.adoc new file mode 120000 index 0000000000..2dbc02d89d --- /dev/null +++ b/docs/ecu_events.adoc @@ -0,0 +1 @@ +./ota-client-guide/modules/ROOT/pages/ecu_events.adoc \ No newline at end of file diff --git a/docs/fault-injection.adoc b/docs/fault-injection.adoc deleted file mode 100644 index 328a96c845..0000000000 --- a/docs/fault-injection.adoc +++ /dev/null @@ -1,67 +0,0 @@ -= Running aktualizr with fault injection - -To test the system in adverse conditions, it can be useful to make aktualizr fail in a controlled fashion. - -link:https://blitiri.com.ar/p/libfiu/[libfiu] provides a framework to do that, and aktualizr supports a number of controllable fail points. - -== Setup - -libfiu needs to be installed on the target machine. For local compilation on a Debian-derived system, the distribution package can be used: - - apt install fiu-utils libfiu-dev - -Fault injection must then be enabled at CMake configure time with the `-DFAULT_INJECTION=on` option (refer to general building instructions for more details). - -`fiu-run` and `fiu-ctrl` can now be used on the newly compiled aktualizr binary to inject faults (refer to corresponding man pages). - -For example, when using the fake package manager: - - fiu-run -c 'enable name=fake_package_install' aktualizr -c . once - -Our wrapper script in `./scripts/fiu` can be used in place, with the added feature of passing strings in failinfo parameters. - -Usage is as follow: - - ./scripts/fiu run -c 'enable name=fake_package_install,failinfo=reason' -- aktualizr -c . once - -== List of fail points - -Please try to keep this list up-to-date when inserting/removing fail points. - -- `fake_package_install`: make the fake package manager installation to fail, optionally with a failure code supplied via `failinfo` -- `secondary_install_xxx` (xxx is a virtual secondary ecu id): make a virtual secondary installation to fail, optionally with a failure code supplied via `failinfo` -- `fake_install_finalization_failure`: make the fake package manager installation finalization to fail - -== Use in unit tests - -It is encouraged to use fail points to help unit testing sad paths. Tests that require fault injection should only be run if the `FIU_ENABLE` macro is defined. - -== Example with a docker container - -The aktualizr application docker image is compiled with fault injection support. It can be used as a quick way to simulate intermitent installation failures. - -First build the image: - - ./docker/docker-build.sh - -It will tag an image `advancedtelematic/aktualizr-app:latest` which includes the common aktualizr tools, as well as the fiu tools (`fiu-run`, `fiu-ctrl`...) - -Then, prepare an environment for a simulated device, following the guide at link:https://docs.ota.here.com/quickstarts/install-a-client-locally-with-fake-secondaries.html[]. - -`aktualizr` will be run through docker instead of the local system, so all commands will start with: - - docker run -u $(id -u):$(id -g) -w $PWD -v $PWD:$PWD advancedtelematic/aktualizr-app - -It runs the docker image inside a container with the same permissions as the local user, with a volume mounted in the current local directory. - -Then, let's launch aktualizr with `fiu-run`: - - docker run --name aktualizr-fiu --rm -u $(id -u):$(id -g) -w $PWD -v $PWD:$PWD advancedtelematic/aktualizr-app fiu run -- aktualizr -c . - -You can try to install a package now, which will succeed. To make all subsequent installations fail with the reason "TEST_FAILURE", use: - - docker exec aktualizr-fiu fiu ctrl -c 'enable name=fake_package_install,failinfo=TEST_FAILURE' 1 - -To make installations succeed again: - - docker exec aktualizr-fiu fiu ctrl -c 'disable name=fake_package_install' 1 diff --git a/docs/fault-injection.adoc b/docs/fault-injection.adoc new file mode 120000 index 0000000000..802e0a0c42 --- /dev/null +++ b/docs/fault-injection.adoc @@ -0,0 +1 @@ +./ota-client-guide/modules/ROOT/pages/fault-injection.adoc \ No newline at end of file diff --git a/docs/integrate-libaktualizr.adoc b/docs/integrate-libaktualizr.adoc deleted file mode 100644 index 2461bac642..0000000000 --- a/docs/integrate-libaktualizr.adoc +++ /dev/null @@ -1,14 +0,0 @@ -= Integrate aktualizr into other software - -The aktualizr client is designed to be run as a standalone component on an embedded system and can manage the entire software update process. However, you might have requirements that got beyond what the standalone client can provide. - -For example, some in-vehicle interfaces are proprietary and under NDA, so their implementation must be kept separate from aktualizr. You might want to integrate the OTA update functionality yourself and minimize the involvement of external consultants. - -For this purpose, you can also use libaktualizr to make your own OTA update client. Typical scenarios for making your own client could be: - -* You want to integrate OTA Connect functionality with a third-party HMI -* You want to integrate OTA Connect with a third-party interface that installs software on secondary ECUs -* You want to constrain network traffic and software updates to specific vehicle states -* You want to provide motorists or service staff with progress indicators for specific software updates. - -To get started with libaktualizr see the link:../src/hmi_stub[reference client] and the https://advancedtelematic.github.io/aktualizr/class_aktualizr.html[reference documentation]. diff --git a/docs/integrate-libaktualizr.adoc b/docs/integrate-libaktualizr.adoc new file mode 120000 index 0000000000..504d0bda4d --- /dev/null +++ b/docs/integrate-libaktualizr.adoc @@ -0,0 +1 @@ +./ota-client-guide/modules/ROOT/pages/libaktualizr-why-use.adoc \ No newline at end of file diff --git a/docs/ota-client-guide/antora.yml b/docs/ota-client-guide/antora.yml new file mode 100644 index 0000000000..f29ed0fd42 --- /dev/null +++ b/docs/ota-client-guide/antora.yml @@ -0,0 +1,5 @@ +name: ota-client +title: OTA Connect Developer Guide +version: dev +nav: +- modules/ROOT/nav.adoc diff --git a/docs/ota-client-guide/modules/ROOT/_attributes.adoc b/docs/ota-client-guide/modules/ROOT/_attributes.adoc new file mode 100644 index 0000000000..dec438a296 --- /dev/null +++ b/docs/ota-client-guide/modules/ROOT/_attributes.adoc @@ -0,0 +1,4 @@ +:attachmentsdir: {moduledir}/assets/attachments +:examplesdir: {moduledir}/examples +:imagesdir: {moduledir}/assets/images +:partialsdir: {moduledir}/pages/_partials diff --git a/docs/ota-client-guide/modules/ROOT/assets/attachments/dual-bank-system-update-flow.svg b/docs/ota-client-guide/modules/ROOT/assets/attachments/dual-bank-system-update-flow.svg new file mode 100644 index 0000000000..8907db0455 --- /dev/null +++ b/docs/ota-client-guide/modules/ROOT/assets/attachments/dual-bank-system-update-flow.svg @@ -0,0 +1,4 @@ + + + + diff --git a/docs/ota-client-guide/modules/ROOT/assets/attachments/ostree-update-flow.svg b/docs/ota-client-guide/modules/ROOT/assets/attachments/ostree-update-flow.svg new file mode 100644 index 0000000000..36ea27d7ac --- /dev/null +++ b/docs/ota-client-guide/modules/ROOT/assets/attachments/ostree-update-flow.svg @@ -0,0 +1,4 @@ + + + + diff --git a/docs/clion-debugger.png b/docs/ota-client-guide/modules/ROOT/assets/images/clion-debugger.png similarity index 100% rename from docs/clion-debugger.png rename to docs/ota-client-guide/modules/ROOT/assets/images/clion-debugger.png diff --git a/docs/ota-client-guide/modules/ROOT/assets/images/dual-bank-system-update-flow.svg b/docs/ota-client-guide/modules/ROOT/assets/images/dual-bank-system-update-flow.svg new file mode 100644 index 0000000000..8907db0455 --- /dev/null +++ b/docs/ota-client-guide/modules/ROOT/assets/images/dual-bank-system-update-flow.svg @@ -0,0 +1,4 @@ + + + + diff --git a/docs/ota-client-guide/modules/ROOT/assets/images/ostree-update-flow.svg b/docs/ota-client-guide/modules/ROOT/assets/images/ostree-update-flow.svg new file mode 100644 index 0000000000..36ea27d7ac --- /dev/null +++ b/docs/ota-client-guide/modules/ROOT/assets/images/ostree-update-flow.svg @@ -0,0 +1,4 @@ + + + + diff --git a/docs/ota-client-guide/modules/ROOT/assets/images/prov-diff-devices.png b/docs/ota-client-guide/modules/ROOT/assets/images/prov-diff-devices.png new file mode 100644 index 0000000000..d3ef5b66c2 Binary files /dev/null and b/docs/ota-client-guide/modules/ROOT/assets/images/prov-diff-devices.png differ diff --git a/docs/ota-client-guide/modules/ROOT/assets/images/prov-diff-infra.png b/docs/ota-client-guide/modules/ROOT/assets/images/prov-diff-infra.png new file mode 100644 index 0000000000..492c921669 Binary files /dev/null and b/docs/ota-client-guide/modules/ROOT/assets/images/prov-diff-infra.png differ diff --git a/docs/ota-client-guide/modules/ROOT/assets/images/s1-prov.png b/docs/ota-client-guide/modules/ROOT/assets/images/s1-prov.png new file mode 100644 index 0000000000..3cc8dd30a1 Binary files /dev/null and b/docs/ota-client-guide/modules/ROOT/assets/images/s1-prov.png differ diff --git a/docs/ota-client-guide/modules/ROOT/assets/images/s5-install_device.png b/docs/ota-client-guide/modules/ROOT/assets/images/s5-install_device.png new file mode 100644 index 0000000000..730bcd5fc5 Binary files /dev/null and b/docs/ota-client-guide/modules/ROOT/assets/images/s5-install_device.png differ diff --git a/docs/ota-client-guide/modules/ROOT/assets/images/screenshot_provisioning_key_2.png b/docs/ota-client-guide/modules/ROOT/assets/images/screenshot_provisioning_key_2.png new file mode 100644 index 0000000000..ccfe96a229 Binary files /dev/null and b/docs/ota-client-guide/modules/ROOT/assets/images/screenshot_provisioning_key_2.png differ diff --git a/docs/ota-client-guide/modules/ROOT/assets/images/security-channels.png b/docs/ota-client-guide/modules/ROOT/assets/images/security-channels.png new file mode 100644 index 0000000000..7f873242de Binary files /dev/null and b/docs/ota-client-guide/modules/ROOT/assets/images/security-channels.png differ diff --git a/docs/ota-client-guide/modules/ROOT/examples/start.sh b/docs/ota-client-guide/modules/ROOT/examples/start.sh new file mode 100644 index 0000000000..36c2e22398 --- /dev/null +++ b/docs/ota-client-guide/modules/ROOT/examples/start.sh @@ -0,0 +1,366 @@ +#!/bin/bash + +[[ ${DEBUG} = true ]] && set -x +set -euo pipefail + +readonly KUBECTL=${KUBECTL:-kubectl} +readonly CWD=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd) +readonly DNS_NAME=${DNS_NAME:-ota.local} +export SERVER_NAME=${SERVER_NAME:-ota.ce} +readonly SERVER_DIR=${SERVER_DIR:-${CWD}/../generated/${SERVER_NAME}} +readonly DEVICES_DIR=${DEVICES_DIR:-${SERVER_DIR}/devices} + +readonly NAMESPACE=${NAMESPACE:-default} +readonly PROXY_PORT=${PROXY_PORT:-8200} +readonly DB_PASS=${DB_PASS:-root} +readonly VAULT_SHARES=${VAULT_SHARES:-5} +readonly VAULT_THRESHOLD=${VAULT_THRESHOLD:-3} + +readonly SKIP_CLIENT=${SKIP_CLIENT:-false} +readonly SKIP_WEAVE=${SKIP_WEAVE:-false} + + +check_dependencies() { + for cmd in ${DEPENDENCIES:-bash curl make http jq openssl kubectl kops}; do + [[ $(command -v "${cmd}") ]] || { echo "Please install '${cmd}'."; exit 1; } + done +} + +retry_command() { + local name=${1} + local command=${@:2} + local n=0 + local max=100 + while true; do + eval "${command}" &>/dev/null && return 0 + [[ $((n++)) -gt $max ]] && return 1 + echo >&2 "Waiting for ${name}" + sleep 5s + done +} + +first_pod() { + local app=${1} + ${KUBECTL} get pods --selector=app="${app}" --output jsonpath='{.items[0].metadata.name}' +} + +wait_for_pods() { + local app=${1} + retry_command "${app}" "[[ true = \$(${KUBECTL} get pods --selector=app=${app} --output json \ + | jq --exit-status '(.items | length > 0) and ([.items[].status.containerStatuses[].ready] | all)') ]]" + first_pod "${app}" +} + +print_hosts() { + retry_command "ingress" "${KUBECTL} get ingress -o json \ + | jq --exit-status '.items[0].status.loadBalancer.ingress'" + ${KUBECTL} get ingress --no-headers | awk -v ip=$(minikube ip) '{print ip " " $2}' +} + +kill_pid() { + local pid=${1} + kill -0 "${pid}" 2>/dev/null || return 0 + kill -9 "${pid}" +} + +skip_ingress() { + [ -f config/local.yaml ] && local_yaml="config/local.yaml" + + value=$(cat config/config.yaml \ + config/images.yaml \ + config/resources.yaml \ + config/secrets.yaml \ + $local_yaml | grep ^create_ingress | tail -n1) + echo $value | grep "false" +} + +make_template() { + local template=$1 + local output="${CWD}/../generated/${template}" + local extra="" + [ -f config/local.yaml ] && extra="--values config/local.yaml" + mkdir -p "$(dirname "${output}")" + kops toolbox template \ + --template "${template}" \ + --values config/config.yaml \ + --values config/images.yaml \ + --values config/resources.yaml \ + --values config/secrets.yaml \ + ${extra} \ + --output "${output}" +} + +apply_template() { + local template=$1 + make_template "${template}" + ${KUBECTL} apply --filename "${CWD}/../generated/${template}" +} + +generate_templates() { + skip_ingress || make_template templates/ingress + make_template templates/infra + make_template templates/services + for vault in ${VAULTS:-tuf-vault crypt-vault}; do + make_template "templates/vaults/${vault}.tmpl.yaml" + make_template "templates/jobs/${vault}-bootstrap.tmpl.yaml" + done +} + +new_client() { + export DEVICE_UUID=${DEVICE_UUID:-$(uuidgen | tr "[:upper:]" "[:lower:]")} + local device_id=${DEVICE_ID:-${DEVICE_UUID}} + local device_dir="${DEVICES_DIR}/${DEVICE_UUID}" + mkdir -p "${device_dir}" + + # This is a tag for including a chunk of code in the docs. Don't remove. tag::genclientkeys[] + openssl ecparam -genkey -name prime256v1 | openssl ec -out "${device_dir}/pkey.ec.pem" + openssl pkcs8 -topk8 -nocrypt -in "${device_dir}/pkey.ec.pem" -out "${device_dir}/pkey.pem" + openssl req -new -config "${CWD}/certs/client.cnf" -key "${device_dir}/pkey.pem" -out "${device_dir}/${device_id}.csr" + openssl x509 -req -days 365 -extfile "${CWD}/certs/client.ext" -in "${device_dir}/${device_id}.csr" \ + -CAkey "${DEVICES_DIR}/ca.key" -CA "${DEVICES_DIR}/ca.crt" -CAcreateserial -out "${device_dir}/client.pem" + cat "${device_dir}/client.pem" "${DEVICES_DIR}/ca.crt" > "${device_dir}/${device_id}.chain.pem" + ln -s "${SERVER_DIR}/server_ca.pem" "${device_dir}/ca.pem" || true + openssl x509 -in "${device_dir}/client.pem" -text -noout + # end::genclientkeys[] + + ${KUBECTL} proxy --port "${PROXY_PORT}" & + local pid=$! + trap "kill_pid ${pid}" EXIT + sleep 3s + + local api="http://localhost:${PROXY_PORT}/api/v1/namespaces/${NAMESPACE}/services" + http --ignore-stdin PUT "${api}/device-registry/proxy/api/v1/devices" credentials=@"${device_dir}/client.pem" \ + deviceUuid="${DEVICE_UUID}" deviceId="${device_id}" deviceName="${device_id}" deviceType=Other + kill_pid "${pid}" + + [[ ${SKIP_CLIENT} == true ]] && return 0 + + local gateway=${GATEWAY_ADDR:-$(${KUBECTL} get nodes --output jsonpath \ + --template='{.items[0].status.addresses[?(@.type=="InternalIP")].address}')} + local addr=${DEVICE_ADDR:-localhost} + local port=${DEVICE_PORT:-2222} + local options="-o StrictHostKeyChecking=no" + + ssh ${options} "root@${addr}" -p "${port}" "echo \"${gateway} ota.ce\" >> /etc/hosts" + scp -P "${port}" ${options} "${device_dir}/client.pem" "root@${addr}:/var/sota/client.pem" + scp -P "${port}" ${options} "${device_dir}/pkey.pem" "root@${addr}:/var/sota/pkey.pem" +} + +new_server() { + ${KUBECTL} get secret gateway-tls &>/dev/null && return 0 + mkdir -p "${SERVER_DIR}" "${DEVICES_DIR}" + + # This is a tag for including a chunk of code in the docs. Don't remove. tag::genserverkeys[] + openssl ecparam -genkey -name prime256v1 | openssl ec -out "${SERVER_DIR}/ca.key" + openssl req -new -x509 -days 3650 -config "${CWD}/certs/server_ca.cnf" -key "${SERVER_DIR}/ca.key" \ + -out "${SERVER_DIR}/server_ca.pem" + + openssl ecparam -genkey -name prime256v1 | openssl ec -out "${SERVER_DIR}/server.key" + openssl req -new -config "${CWD}/certs/server.cnf" -key "${SERVER_DIR}/server.key" -out "${SERVER_DIR}/server.csr" + openssl x509 -req -days 3650 -extfile "${CWD}/certs/server.ext" -in "${SERVER_DIR}/server.csr" -CAcreateserial \ + -CAkey "${SERVER_DIR}/ca.key" -CA "${SERVER_DIR}/server_ca.pem" -out "${SERVER_DIR}/server.crt" + cat "${SERVER_DIR}/server.crt" "${SERVER_DIR}/server_ca.pem" > "${SERVER_DIR}/server.chain.pem" + + openssl ecparam -genkey -name prime256v1 | openssl ec -out "${DEVICES_DIR}/ca.key" + openssl req -new -x509 -days 3650 -key "${DEVICES_DIR}/ca.key" -config "${CWD}/certs/device_ca.cnf" \ + -out "${DEVICES_DIR}/ca.crt" + # end::genserverkeys[] + + ${KUBECTL} create secret generic gateway-tls \ + --from-file "${SERVER_DIR}/server.key" \ + --from-file "${SERVER_DIR}/server.chain.pem" \ + --from-file "${SERVER_DIR}/devices/ca.crt" +} + +create_configs() { + ${KUBECTL} get configmap bootstrap-rules &>/dev/null || { + ${KUBECTL} create configmap bootstrap-rules --from-file config/vaults/bootstrap-rules.json + } + + declare -a policies=(tuf crypt) + for policy in "${policies[@]}"; do + ${KUBECTL} get configmap "${policy}-policy" &>/dev/null || { + ${KUBECTL} create configmap --from-file "config/vaults/${policy}-policy.hcl" "${policy}-policy" + } + ${KUBECTL} get secret "${policy}-tokens" &>/dev/null || { + ${KUBECTL} create secret generic "${policy}-tokens" + } + done +} + +create_databases() { + local pod + pod=$(wait_for_pods mysql) + ${KUBECTL} cp "${CWD}/sql" "${pod}:/tmp/" + ${KUBECTL} exec "${pod}" -- bash -c "mysql -p${DB_PASS} < /tmp/sql/install_plugins.sql || true" 2>/dev/null + ${KUBECTL} exec "${pod}" -- bash -c "mysql -p${DB_PASS} < /tmp/sql/create_databases.sql" +} + +init_vault() { + local vault=${1} + local api="http://localhost:${PROXY_PORT}/v1" + + if [[ $(http GET "${api}/sys/health" | jq '.initialized') = false ]]; then + local result + result=$(http --ignore-stdin --check-status PUT "${api}/sys/init" \ + secret_shares:="${VAULT_SHARES}" secret_threshold:="${VAULT_THRESHOLD}") + ${KUBECTL} create secret generic "${vault}-init" \ + --from-literal="root=$(echo "${result}" | jq --raw-output '.root_token')" \ + --from-literal="keys=$(echo "${result}" | jq --raw-output '.keys[]')" + fi +} + +unseal_vault() { + local vault=${1} + local pod=${2} + if ${KUBECTL} get secrets "${vault}-init" &>/dev/null; then + ${KUBECTL} get secrets "${vault}-init" -o json | + jq -r .data.keys | + base64 --decode | + awk 'BEGIN {print "export VAULT_ADDR=http://127.0.0.1:8200"} + {print "vault unseal "$0} + END {print "vault status"}' | + ${KUBECTL} exec -i "${pod}" sh + fi +} + +start_vaults() { + create_configs + + for vault in ${VAULTS:-tuf-vault crypt-vault}; do + apply_template "templates/vaults/${vault}.tmpl.yaml" + + local pod + pod=$(wait_for_pods "${vault}") + ${KUBECTL} port-forward "${pod}" "${PROXY_PORT}:${PROXY_PORT}" & + local pid=$! + trap "kill_pid ${pid}" EXIT + sleep 3s + + init_vault "${vault}" + unseal_vault "${vault}" "${pod}" + kill_pid "${pid}" + + apply_template "templates/jobs/${vault}-bootstrap.tmpl.yaml" + done +} + + +start_weave() { + [[ ${SKIP_WEAVE} == true ]] && return 0; + local version=$(${KUBECTL} version | base64 | tr -d '\n') + ${KUBECTL} apply -f "https://cloud.weave.works/k8s/net?k8s-version=${version}" +} + +start_ingress() { + skip_ingress && return 0; + apply_template templates/ingress +} + +start_infra() { + apply_template templates/infra + wait_for_pods kafka + create_databases +} + +start_services() { + apply_template templates/services + get_credentials +} + +get_credentials() { + ${KUBECTL} get secret "user-keys" &>/dev/null && return 0 + + ${KUBECTL} proxy --port "${PROXY_PORT}" & + local pid=$! + trap "kill_pid ${pid}" EXIT + sleep 3s + + local namespace="x-ats-namespace:default" + local api="http://localhost:${PROXY_PORT}/api/v1/namespaces/${NAMESPACE}/services" + local keyserver="${api}/tuf-keyserver/proxy" + local reposerver="${api}/tuf-reposerver/proxy" + local director="${api}/director/proxy" + local id + local keys + + retry_command "director" "[[ true = \$(http --print=b GET ${director}/health \ + | jq --exit-status '.status == \"OK\"') ]]" + retry_command "keyserver" "[[ true = \$(http --print=b GET ${keyserver}/health \ + | jq --exit-status '.status == \"OK\"') ]]" + retry_command "reposerver" "[[ true = \$(http --print=b GET ${reposerver}/health/dependencies \ + | jq --exit-status '.[].status == \"up\"') ]]" + + id=$(http --ignore-stdin --check-status --print=b POST "${reposerver}/api/v1/user_repo" "${namespace}" | jq --raw-output .) + http --ignore-stdin --check-status POST "${director}/api/v1/admin/repo" "${namespace}" + + retry_command "keys" "http --ignore-stdin --check-status GET ${keyserver}/api/v1/root/${id}" + keys=$(http --ignore-stdin --check-status GET "${keyserver}/api/v1/root/${id}/keys/targets/pairs") + echo ${keys} | jq '.[0] | {keytype, keyval: {public: .keyval.public}}' > "${SERVER_DIR}/targets.pub" + echo ${keys} | jq '.[0] | {keytype, keyval: {private: .keyval.private}}' > "${SERVER_DIR}/targets.sec" + + retry_command "root.json" "http --ignore-stdin --check-status -d GET \ + ${reposerver}/api/v1/user_repo/root.json \"${namespace}\"" && \ + http --ignore-stdin --check-status -d -o "${SERVER_DIR}/root.json" GET \ + ${reposerver}/api/v1/user_repo/root.json "${namespace}" + + echo "http://tuf-reposerver.${DNS_NAME}" > "${SERVER_DIR}/tufrepo.url" + echo "https://${SERVER_NAME}:30443" > "${SERVER_DIR}/autoprov.url" + cat > "${SERVER_DIR}/treehub.json" < []"; exit 1; } +command=$(echo "${1}" | sed 's/-/_/g') + +case "${command}" in + "start_all") + check_dependencies + start_weave + new_server + start_ingress + start_infra + start_vaults + start_services + ;; + "start_ingress") + start_ingress + ;; + "start_infra") + start_infra + ;; + "start_vaults") + start_vaults + ;; + "start_services") + start_services + ;; + "new_client") + new_client + ;; + "new_server") + new_server + ;; + "print_hosts") + print_hosts + ;; + "templates") + generate_templates + ;; + *) + echo "Unknown command: ${command}" + exit 1 + ;; +esac diff --git a/docs/ota-client-guide/modules/ROOT/nav.adoc b/docs/ota-client-guide/modules/ROOT/nav.adoc new file mode 100644 index 0000000000..3efad0a002 --- /dev/null +++ b/docs/ota-client-guide/modules/ROOT/nav.adoc @@ -0,0 +1,105 @@ +// MC: NOTE ABOUT TOC +// Adding "pageroot" attr so that TOC that will also work directly in GitHub. Because... +// In Antora the "pages" subdir is implcit added to the xref path at build time. +// if you add "/pages" Antora will intepret it as "pages/pages". +// The pages subdir is NOT implicit when viewing source files in Github. + +ifdef::env-github[:pageroot: pages/] +ifndef::env-github[:pageroot:] + +.Introduction to the Developer Tools +* xref:{pageroot}index.adoc[Introduction] +* xref:{pageroot}developer-tools.adoc[Developer Tools] +* xref:{pageroot}workflow-overview.adoc[Basic OTA update workflow] +* xref:{pageroot}evaluation-to-prod.adoc[Moving from Evaluation to Production] +// NEW topics + +.Key Concepts +// NEW/updated topics +* xref:{pageroot}software-management.adoc[Software Management] +** xref:{pageroot}supporting-technologies.adoc[Supporting technologies] +** xref:{pageroot}yocto.adoc[Yocto] +// --- +** xref:{pageroot}ostree-and-treehub.adoc[OSTree, and TreeHub] +// --- +* xref:{pageroot}security.adoc[Security] +** xref:{pageroot}pki.adoc[Key Management] +** xref:{pageroot}uptane.adoc[The Uptane security specification] +// future iteration: * xref:{pageroot}prod-intro[Testing and production environments] +* xref:{pageroot}client-provisioning-methods.adoc[Device provisioning] + +.Evaluate OTA Connect +* xref:{pageroot}intro-evaluate.adoc[Evaluating OTA Connect] +* xref:{pageroot}download-prov-key.adoc[Get a provisioning Key] +* xref:{pageroot}build-images.adoc[Use our sample recipes to build disk images] +** xref:{pageroot}build-raspberry.adoc[Build for a Raspberry Pi] +** xref:{pageroot}build-quemu.adoc[Build for QEMU] +** xref:{pageroot}build-agl.adoc[Build for Automotive Grade Linux] +* xref:{pageroot}simulate-device-basic.adoc[Simulate a device without building a disk image] +* xref:{pageroot}pushing-updates.adoc[Upload a sample software version] +* xref:{pageroot}update-single-device.adoc[Update a second device with the sample software] + +.Build your own OTA-enabled solution +* xref:{pageroot}intro-prep.adoc[Recommended Steps] +* xref:{pageroot}recommended-clientconfig.adoc[Recommended configurations] +* xref:{pageroot}account-setup.adoc[Set up multiple accounts] + +* xref:{pageroot}libaktualizr-why-use.adoc[Integrate libaktualizr into your solution] +** xref:{pageroot}libaktualizr-getstarted.adoc[Get Started with libaktualizr] +** xref:{pageroot}libaktualizr-update-secondary.adoc[Updating a Secondary ECU with libaktualizr] + +* xref:{pageroot}build-ota-enabled-images.adoc[Build and deploy OTA-enabled disk images] +** xref:{pageroot}supported-boards.adoc[Supported boards] +** xref:{pageroot}add-ota-functonality-existing-yocto-project.adoc[Add OTA functionality to a Yocto project] +** xref:{pageroot}libaktualizr-integrate.adoc[Add libaktualizr integration to a Yocto project] + +* xref:{pageroot}device-cred-prov-steps.adoc[Provision devices] +** xref:{pageroot}generate-selfsigned-root.adoc[Generate a self-signed root certificate] +** xref:{pageroot}provide-root-cert.adoc[Register your root certificate] +** xref:{pageroot}generate-devicecert.[Generate device certificates] +** xref:{pageroot}enable-device-cred-provisioning.adoc[Enable and install device certificates] + +* xref:{pageroot}secure-software-updates.adoc[Secure your software repository] +** xref:{pageroot}install-garage-sign-deploy.adoc[Install the Garage Deploy tool] +** xref:{pageroot}rotating-signing-keys.adoc[Manage keys for software metadata] +** xref:{pageroot}metadata-expiry.adoc[Manage metadata expiry dates] + +.Deploy your OTA-enabled solution +* xref:{pageroot}deploy-checklist.adoc[Deploying to Production] + + +.How to +* xref:{pageroot}cross-deploy-images.adoc[Transfer software to another repository] +* xref:{pageroot}simulate-device-cred-provtest.adoc[Simulate device credentials] +* xref:{pageroot}enable-shared-cred-provisioning.adoc[Configure devices to use shared-credential provisioning] +* xref:{pageroot}how-can-i-check-which-ostree-version-is-installed.adoc[Check which OSTree commit is deployed] +* xref:{pageroot}use-your-own-deviceid.adoc[Configure your own device IDs] +* xref:{pageroot}build-only-ostree.adoc[Build only the OSTree part] + +// Dev-authored topics +* xref:{pageroot}fault-injection.adoc[Simulate installation failures for testing] +* xref:{pageroot}posix-secondaries-bitbaking.adoc[Simulate a Primary and Secondary ECU] +** xref:{pageroot}posix-secondaries.adoc[Configuration and emulation on a local host] +* xref:{pageroot}fault-injection.adoc[Simulate installation failures for testing] +* xref:{pageroot}rollback.adoc[Set up rollback behavior] +* xref:{pageroot}deb-package-install.adoc[Install the client from a deb package] +* xref:{pageroot}aktualizr-repo.adoc[Simulate Uptane metadata transactions] +//---- + +.Reference +// MC: Do in second iteration: * xref:{pageroot}otaconnect-identifiers.adoc[Identifiers] +* xref:{pageroot}aktualizr-config-options.adoc[Configuration Options] +* xref:{pageroot}aktualizr-runningmodes-finegrained-commandline-control.adoc[Client Commands] +* xref:{pageroot}provisioning-methods-and-credentialszip.adoc[Contents of the credentials file] +* xref:{pageroot}useful-bitbake-commands.adoc[Bitbake commands] +* xref:{pageroot}ostree-usage.adoc[OSTree commands] + +.Troubleshooting +* xref:{pageroot}troubleshooting.adoc[Troubleshooting] + +.For Contributors +// Dev-authored topics +* xref:{pageroot}deb-package-install.adoc[Packaging an aktualizr Release on github] +* xref:{pageroot}schema-migrations.adoc[Add a schema migration] +* xref:{pageroot}debugging-tips.adoc[Debugging the Client] + diff --git a/docs/ota-client-guide/modules/ROOT/pages/_attributes.adoc b/docs/ota-client-guide/modules/ROOT/pages/_attributes.adoc new file mode 100644 index 0000000000..fb982443d7 --- /dev/null +++ b/docs/ota-client-guide/modules/ROOT/pages/_attributes.adoc @@ -0,0 +1,2 @@ +:moduledir: .. +include::{moduledir}/_attributes.adoc[] diff --git a/docs/ota-client-guide/modules/ROOT/pages/_partials/build-ota-enabled-images.adoc b/docs/ota-client-guide/modules/ROOT/pages/_partials/build-ota-enabled-images.adoc new file mode 100644 index 0000000000..e69de29bb2 diff --git a/docs/ota-client-guide/modules/ROOT/pages/_partials/how-prov-with-device-cred.adoc b/docs/ota-client-guide/modules/ROOT/pages/_partials/how-prov-with-device-cred.adoc new file mode 100644 index 0000000000..683638e220 --- /dev/null +++ b/docs/ota-client-guide/modules/ROOT/pages/_partials/how-prov-with-device-cred.adoc @@ -0,0 +1,5 @@ +When you provision with device credentials, you install permanent credentials each device *before* the device connects to the OTA Connect server. + +You would use the xref:pki.adoc[private key for your fleet] to sign the device certificates *and* your fleet root certificate. You then register your fleet root certificate on the OTA Connect server. + +Every time a device connects to the OTA Connect server, the server verifies that the device credentials are signed by a trusted source. It does this by comparing public key in the device certificate with the public key in your fleet root certificate. If they are both signed by the same private key, they should match and the device can be trusted. For a more detailed description of how device-credential provisioning works, see the xref:client-provisioning-methods.adoc[provisioning methods overview]. \ No newline at end of file diff --git a/docs/ota-client-guide/modules/ROOT/pages/_partials/recommended-steps-brief.adoc b/docs/ota-client-guide/modules/ROOT/pages/_partials/recommended-steps-brief.adoc new file mode 100644 index 0000000000..7702bae88f --- /dev/null +++ b/docs/ota-client-guide/modules/ROOT/pages/_partials/recommended-steps-brief.adoc @@ -0,0 +1,48 @@ +// tag::evaluate-steps[] +* *Use shared-credential provisioning for your devices* ++ +With shared-credential provisioning, you don't have to worry about installing certificates on your devices. + +* *Build disk images using our demo recipes* ++ +Use our demo build recipes to build an OTA-enabled disk images or simulate a device on your workstation. + +* *Use the standalone aktualizr client to test the OTA functionality* ++ +Aktualizr actually part of our demo build recipes and is included in the disk images that you'll build. + + + +//// +COMMENTING OUT UNTIL ORGANIZATIONS FEATURE STOPS BEING "ALPHA" +* *Set up different organizations* ++ +In OTA Connect, all devices, software, and user accounts belong to an *organization*. Users can see all devices and software for their organization. However, you don't want to mix up test software and production software. ++ +In a proper production workflow, you'll need separate organizations to manage the different stages: ++ +. A developer organization such as "acme-dev". +. A QA organization such as "acme-qa". +. A production organization such as "acme-prod". ++ +A user can belong to multiple organizations, and it's easy to switch between them. This provides you with a convenient way of separating your development, QA and production resources. +//// + +// DEVELOP + +* *Set up provisioning with device credentials* ++ +The term *device-credential provisioning* refers to the process of installing device certificates yourself rather than having the OTA Connect server install them automatically. + +* *Set up different user accounts* ++ +Avoid mixing up test software and production software by creating them all under the same user. + +* *Use offline keys to sign software metadata* ++ +Move the most important private keys from the server and take them offline. + +* *Integrate libaktualizr with the client software on your board* ++ +When you move to production, you'll want to integrate OTA functionality into your board's native software. + diff --git a/docs/ota-client-guide/modules/ROOT/pages/_partials/recommended-steps.adoc b/docs/ota-client-guide/modules/ROOT/pages/_partials/recommended-steps.adoc new file mode 100644 index 0000000000..dd1c95c80a --- /dev/null +++ b/docs/ota-client-guide/modules/ROOT/pages/_partials/recommended-steps.adoc @@ -0,0 +1,101 @@ +// tag::evaluate-steps[] +* *Use shared credential provisioning for your devices* ++ +With shared-credential provisioning, you don't have to worry about installing certificates on your devices. +The OTA Connect server automatically does this for you. All you need to do is provide a provisioning key that all your devices can share. + +* *Build disk images using our demo recipes* ++ +We support a couple of demo boards "out of the box". You don't need to worry about complex build configurations at this stage. Just follow our recipes to learn how to build an OTA-enabled disk image. ++ +If you don't want to wait several hours for a build to finish, you can also simulate an OTA-enabled device without building a disk image. +* *Use the standalone aktualizr client to test the OTA functionality* ++ +You don't need to do anything extra to use the standalone aktualizr client. It's actually part of our demo build configurations, so the aktualizr client is included in the disk image that you'll build. ++ +If you prefer to simulate an OTA-enabled device without building a disk image, you'll install the aktualizr client on your development computer. + +// end::evaluate-steps[] + +// tag::integrate-steps[] + +* *Set up different user logins* ++ +In OTA Connect, all devices and software belong to one *user* login. However, you don't want to mix up test software and production software by creating them all under the same user. ++ +In a proper production workflow, you'll need separate user logins to manage the different stages: ++ +. A developer user such as "dev@acme.com". +. A QA user such as ""qa@acme.com"". +. A production user such as "prod@acme.com"". ++ +These logins provide you with a convenient way of clearly separating your development, QA and production resources. + +//// +COMMENTING OUT UNTIL ORGANIZATIONS STOPS BEING "ALPHA" +* *Set up different organizations* ++ +In OTA Connect, all devices, software, and user accounts belong to an *organization*. Users can see all devices and software for their organization. However, you don't want to mix up test software and production software. ++ +In a proper production workflow, you'll need separate organizations to manage the different stages: ++ +. A developer organization such as "acme-dev". +. A QA organization such as "acme-qa". +. A production organization such as "acme-prod". ++ +A user can belong to multiple organizations, and it's easy to switch between them. This provides you with a convenient way of separating your development, QA and production resources. +//// + +* *Simulate device-credential provisioning for your devices* ++ +The term *device-credential provisioning* refers to the process of installing device certificates yourself rather than having the OTA Connect server install them automatically. ++ +Although it's convenient to have the OTA Connect server manage this process, the consequences of a security breach are much more severe. If an attacker compromises the OTA Connect server, they can provision their own devices and block your devices. ++ +To install your own device certificates, you need a fleet root certificate and private key to sign them. Installation can be tricky, so we've provided some instructions on how to generate your own self-sign certificate and simulate device-credential provisioning for testing. + +* *Use offline keys to sign software metadata* ++ +In the evaluation stage, the OTA Connect server also takes care of signing the metadata for your software updates. Devices verify the signatures on this metadata before they install any updates. ++ +However, if an attacker infiltrates the OTA Connect server, they'll be able to sign metadata for malicious software and have it installed on your devices. Such a breach could have potentially dire consequences. ++ +This is why you want to remove the most important private keys from the server and take them offline. For the integration phase, it's fine if you keep these keys on your development computer and sign the metadata locally before uploading the metadata to the OTA Connect server. Later, you'll want to keep these keys somewhere more secure. + +* *Try the libaktualizr demo app and build recipe* ++ +When you move to production, you'll want to integrate OTA functionality into your board's native software. This is more efficient than sending commands to our standalone aktualizr client. ++ +You can use our libaktualizr C++ library to integration all same functionality that standalone aktualizr provides. To prove you with some inspiration, we've created a demo app that integrates libaktualizr. We've also included a build recipe. You can use it to build a disk image that contains the demo app. + +// end::integrate-steps[] + +// tag::deploy-steps[] + +* *Set up full device-credential provisioning for your devices* ++ +At this point you should have your own fleet root certificate which you register with the OTA COnnect server under your production login. ++ +You should ideally have an automated process to sign your device certificates and install them on your disk images before they flashed to the target boards. ++ +You should also have an automated build process to build OTA-enabled images that also have device-credential provisioning enabled. + + +* *Create offline keys for production to sign software metadata* ++ +This step is not that different from the equivalent step during the integration phase: ++ +** During the integration phase, you generated a set of private keys with your *development* credentials. +** This time, you should generate another set with your *production* credentials. ++ +You should keep these keys on a secure storage medium such as a link:https://www.yubico.com/[YubiKey]. You would only plugin your YubiKey when you need to sign metadata on your local computer. + +* *Integrate libaktualizr with the client software on your board* ++ +Once you understand how to the libaktualizr demo application works, you'll want to build a fully-functional integration with your board's software. + +* *Build and cross-deploy your disk images to your production account* ++ +After you've finished integration and development, you'll need to move disk images from one account to another. For example, you might want to send a development build that you’re happy with to the QA team, or send that build to the deployment team once it’s passed QA. + +// end::deploy-steps[] \ No newline at end of file diff --git a/docs/ota-client-guide/modules/ROOT/pages/_partials/why-different-prov-methods.adoc b/docs/ota-client-guide/modules/ROOT/pages/_partials/why-different-prov-methods.adoc new file mode 100644 index 0000000000..2012b64491 --- /dev/null +++ b/docs/ota-client-guide/modules/ROOT/pages/_partials/why-different-prov-methods.adoc @@ -0,0 +1,14 @@ +If you followed the xref:getstarted::get-started.adoc[Get Started Guide], you used a provisioning key that was shared by all devices. In this scenario, the OTA Connect server generates the device credentials for you. This method is fine if you're just evaluating OTA Connect and want to get started quickly. If you want to do some serious testing and eventually move to production, you'll need a switch to a more secure provisioning method. + +In this case, you shouldn't use the OTA Connect server to generate your device credentials. If you generate *and* validate credentials with the same server, you're taking a big risk. Generation and validation should always be done by separate entities. +Otherwise, if an attacker were able to infiltrate the OTA Connect server, they would be able to provision their own devices + +Instead, you should use your own infrastructure to generate device credentials outside of OTA Connect. We call this method "provisioning with device credentials". + +== How to provision with device credentials + +When you provision with device credentials, you install permanent credentials each device *before* the device connects to the OTA Connect server. + +You would use the xref:pki.adoc[private key for your fleet] to sign the device certificates *and* your fleet root certificate. You then register your fleet root certificate on the OTA Connect server. + +Every time a device connects to the OTA Connect server, the server verifies that the device credentials are signed by a trusted source. It does this by comparing public key in the device certificate with the public key in your fleet root certificate. If they are both signed by the same private key, they should match and the device can be trusted \ No newline at end of file diff --git a/docs/ota-client-guide/modules/ROOT/pages/account-setup.adoc b/docs/ota-client-guide/modules/ROOT/pages/account-setup.adoc new file mode 100644 index 0000000000..f854559d2e --- /dev/null +++ b/docs/ota-client-guide/modules/ROOT/pages/account-setup.adoc @@ -0,0 +1,11 @@ += Set up multiple accounts + +In OTA Connect, all devices and software belong to one *user* login. However, you don't want to mix up test software and production software by creating them all under the same user. + +In a proper production workflow, you'll need separate user logins to manage the different stages: + +. A developer user such as "dev@acme.com". +. A QA user such as ""qa@acme.com"". +. A production user such as "prod@acme.com"". + +These logins provide you with a convenient way of clearly separating your development, QA and production resources. \ No newline at end of file diff --git a/docs/ota-client-guide/modules/ROOT/pages/add-ota-functonality-existing-yocto-project.adoc b/docs/ota-client-guide/modules/ROOT/pages/add-ota-functonality-existing-yocto-project.adoc new file mode 100644 index 0000000000..fa3b313216 --- /dev/null +++ b/docs/ota-client-guide/modules/ROOT/pages/add-ota-functonality-existing-yocto-project.adoc @@ -0,0 +1,68 @@ += Add OTA functionality to an existing Yocto project +:page-layout: page +:page-categories: [quickstarts] +:page-date: 2017-05-23 16:27:58 +:page-order: 6 +:icons: font + +If you already have a Yocto-based project that you want to update using {product-name}, you just need to do four things to get started: + +1. Clone the https://github.com/advancedtelematic/meta-updater[meta-updater] layer and add it to your https://www.yoctoproject.org/docs/2.1/ref-manual/ref-manual.html#structure-build-conf-bblayers.conf[bblayers.conf]. +2. Clone a BSP integration layer (`meta-updater-$\{PLATFORM}`, e.g. https://github.com/advancedtelematic/meta-updater-raspberrypi[meta-updater-raspberrypi]) and add it to your conf/bblayers.conf. If your board isn't supported yet, you could write a BSP integration for it yourself. See the <> section for the details. +3. Set up your https://www.yoctoproject.org/docs/2.1/ref-manual/ref-manual.html#var-DISTRO[distro]. If you are using "poky", the default distro in Yocto, you can change it in your conf/local.conf to "poky-sota". Alternatively, if you are using your own or a third-party distro configuration, you can add `INHERIT += " sota"` to it, thus combining the capabilities of your distro with meta-updater features. +4. {app-url}/#/profile/access-keys[Create a provisioning key, window="_blank"] and add it to your local.conf. + +You can then build your image as usual, with bitbake. After building the root file system, bitbake will then create an https://ostree.readthedocs.io/en/latest/manual/adapting-existing/[OSTree-enabled version] of it, commit it to your local OSTree repo, and push it to OTA Connect. Additionally, a live disk image will be created (normally named $\{IMAGE_NAME}.-sdimg-ota e.g. core-image-raspberrypi3.rpi-sdimg-ota). You can control this behavior through xref:add-ota-functonality-existing-yocto-project.adoc#_sota_related_variables_in_local_conf[OTA Connect-related variables in your local.conf]. + +== Supported boards + +// MC: Copied over from meta-updater on 29.07.2019 + +Currently supported platforms are: + +* https://github.com/advancedtelematic/meta-updater-raspberrypi[Raspberry Pi 2 and 3] +* https://github.com/advancedtelematic/meta-updater-minnowboard[Intel Minnowboard] +* https://github.com/advancedtelematic/meta-updater-qemux86-64[Native QEMU emulation] +* Renesas R-Car H3 and M3 +* https://github.com/advancedtelematic/meta-updater-ti/[TI BeagleBone Black] (rocko only, using TI SDK 05.03) +* https://github.com/advancedtelematic/meta-updater-ti/[TI AM65x industrial development kit] (rocko only, using TI SDK 05.03) + +Additionally, there is community support for https://github.com/ricardosalveti/meta-updater-riscv[RISC-V] boards, in particular the Freedom U540. + +We also historically supported the https://github.com/advancedtelematic/meta-updater-porter[Renesas Porter] board. + +=== Adding support for your board + +If your board isn't supported yet, you can add board integration code yourself. The main purpose of this code is to provide a bootloader that will be able to use https://ostree.readthedocs.io/en/latest/manual/atomic-upgrades/[OSTree's boot directory]. In the meta-updater integration layers we have written so far, the basic steps are: + +1. Make the board boot into http://www.denx.de/wiki/U-Boot[U-Boot] +2. Make U-boot import variables from /boot/loader/uEnv.txt and load the kernel with initramfs and kernel command-line arguments according to what is set in this file. + +You may take a look into https://github.com/advancedtelematic/meta-updater-minnowboard[Minnowboard] or https://github.com/advancedtelematic/meta-updater-raspberrypi[Raspberry Pi] integration layers for examples. + +Although we have focused on U-Boot and GRUB so far, other bootloaders can be configured to work with OSTree as well. + +Your images will also need network connectivity to be able to reach an actual OTA backend. Our 'poky-sota' distribution does not mandate or install a default network manager but our supported platforms use the `virtual/network-configuration` recipe, which can be used as a starting example. + +== SOTA-related variables in local.conf + +* `OSTREE_BRANCHNAME` - OSTree branch name. Defaults to `${SOTA_HARDWARE_ID}`. Particularly useful for grouping similar images. +* `OSTREE_REPO` - path to your OSTree repository. Defaults to `$\{DEPLOY_DIR_IMAGE}/ostree_repo` +* `OSTREE_OSNAME` - OS deployment name on your target device. For more information about deployments and osnames see the https://ostree.readthedocs.io/en/latest/manual/deployment/[OSTree documentation]. Defaults to "poky". +* `OSTREE_COMMIT_BODY` - Message attached to OSTree commit. Empty by default. +* `OSTREE_COMMIT_SUBJECT` - Commit subject used by OSTree. Defaults to `Commit-id: ${IMAGE_NAME}` +* `OSTREE_UPDATE_SUMMARY` - Set this to '1' to update summary of OSTree repository on each commit. '0' by default. +* `OSTREE_DEPLOY_DEVICETREE` - Set this to '1' to include devicetree(s) to boot +* `GARAGE_SIGN_AUTOVERSION` - Set this to '1' to automatically fetch the last version of the garage tools installed by the aktualizr-native. Otherwise use the fixed version specified in the recipe. +* `INITRAMFS_IMAGE` - initramfs/initrd image that is used as a proxy while booting into OSTree deployment. Do not change this setting unless you are sure that your initramfs can serve as such a proxy. +* `SOTA_PACKED_CREDENTIALS` - when set, your ostree commit will be pushed to a remote repo as a bitbake step. This should be the path to a zipped credentials file in https://github.com/advancedtelematic/aktualizr/blob/master/docs/credentials.adoc[the format accepted by garage-push]. +* `SOTA_DEPLOY_CREDENTIALS` - when set to '1' (default value), deploys credentials to the built image. Override it in `local.conf` to built a generic image that can be provisioned manually after the build. +* `SOTA_CLIENT_PROV` - which provisioning method to use. Valid options are `aktualizr-shared-prov`, `aktualizr-device-prov`, and `aktualizr-device-prov-hsm`. For more information on these provisioning methods, see the https://docs.ota.here.com/client-config/client-provisioning-methods.html[OTA Connect documentation]. The default is `aktualizr-shared-prov`. This can also be set to an empty string to avoid using a provisioning recipe. +* `SOTA_CLIENT_FEATURES` - extensions to aktualizr. The only valid options are `hsm` (to build with HSM support) and `secondary-network` (to set up a simulated 'in-vehicle' network with support for a primary node with a DHCP server and a secondary node with a DHCP client). +* `SOTA_SECONDARY_CONFIG` - a file containing JSON configuration for secondaries. It will be installed into `/etc/sota/ecus` on the device and automatically provided to aktualizr. See link:https://github.com/advancedtelematic/aktualizr/blob/master/docs/posix-secondaries-bitbaking.adoc[here] for more details. +* `SOTA_HARDWARE_ID` - a custom hardware ID that will be written to the aktualizr config. Defaults to MACHINE if not set. +* `SOTA_MAIN_DTB` - base device tree to use with the kernel. Used together with FIT images. You can change it, and the device tree will also be changed after the update. +* `SOTA_DT_OVERLAYS` - whitespace-separated list of used device tree overlays for FIT image. This list is OSTree-updateable as well. +* `SOTA_EXTRA_CONF_FRAGS` - extra https://lxr.missinglinkelectronics.com/uboot/doc/uImage.FIT/overlay-fdt-boot.txt[configuration fragments] for FIT image. +* `RESOURCE_xxx_pn-aktualizr` - controls maximum resource usage of the aktualizr service, when `aktualizr-resource-control` is installed on the image. See <> for details. +* `SOTA_POLLING_SEC` - sets polling interval for aktualizr to check for updates if aktualizr-polling-sec is included in the image. diff --git a/docs/ota-client-guide/modules/ROOT/pages/adoc-test.adoc b/docs/ota-client-guide/modules/ROOT/pages/adoc-test.adoc new file mode 100644 index 0000000000..05bb14427e --- /dev/null +++ b/docs/ota-client-guide/modules/ROOT/pages/adoc-test.adoc @@ -0,0 +1,23 @@ += Client provisioning methods +:page-layout: page +:page-categories: [client-config] +:page-date: 2018-07-05 13:31:58 +:page-order: 25 +:icons: font +:toc: macro + +In OTA Connect, the provisioning process ensures that the device has a certificate and a unique identifier. After a device has been provisioned, it can receive software updates. OTA Connect supports two types of provisioning: + +* *Provisioning with shared credentials* ++ +Devices use temporary provisioning credentials to request permanent credentials from the server. You download the temporary provisioning credentials from the OTA Connect web app and install them on a device. Once the device registers with the server for the first time, the server assigns permanent credentials to the device. The device then uses these permanent credentials for all future transactions. + + +* *Provisioning with device credentials* ++ +Devices already have permanent credentials installed. The server doesn't issue any credentials to devices. Instead, you use a root CA certificate to sign the credentials that you install on the device. You then install the same root CA certificate on the OTA Connect server. +Every time the device attempts to connect, the server verifies that the device credentials are signed by the same CA that you originally installed on the server. + +== Choosing a provisioning method + +The type of provisioning that you choose depends on your requirements. If you're just testing and want to get started quickly, provisioning with shared credentials is fine. It is easier to set up but is less secure. Because server self-signs the credentials that it issues to devices, the devices have no way of verifying the integrity of the server. This level of security is not suitable for a production environment. The device should always be able to verify that is communicating with a genuine OTA Connect server. Once you move to production, you should look at some form of provisioning that uses device certificates. For more security, use a Hardware Security Module (HSM) to store the device certificates. \ No newline at end of file diff --git a/docs/ota-client-guide/modules/ROOT/pages/aktualizr-config-options.adoc b/docs/ota-client-guide/modules/ROOT/pages/aktualizr-config-options.adoc new file mode 100644 index 0000000000..d7f39f1bb8 --- /dev/null +++ b/docs/ota-client-guide/modules/ROOT/pages/aktualizr-config-options.adoc @@ -0,0 +1,175 @@ += Client configuration options +:page-layout: page +:page-categories: [client-config] +:page-date: 2018-07-05 11:14:01 +:page-order: 20 +:icons: font +:aktualizr-github-url: https://github.com/advancedtelematic/aktualizr/tree/master +ifdef::env-github[] +:aktualizr-github-url: .. +endif::[] + +Here, we provide reference documentation on aktualizr's usage and configuration. However, if you need to go further than what's possible with the command-line interface, you can also use xref:libaktualizr-why-use.adoc[libaktualizr to make your own client]. In fact, aktualizr is a fairly thin wrapper around libaktualizr itself, and we provide also an https://github.com/advancedtelematic/aktualizr/tree/master/src/hmi_stub[even simpler reference client] along with https://advancedtelematic.github.io/aktualizr/class_aktualizr.html[doxygen docs] of the libaktualizr API. + +Aktualizr is configured via `.toml` config files. One or more files or directories can be passed to the application via the `--config` flag (one per file or directory). If `--config` is not specified on the command line, aktualizr searches `/usr/lib/sota/conf.d` and `/etc/sota/conf.d/` for files with a `.toml` extension. Aktualizr searches for and processes these config files in systemd style, meaning that if multiple files are found with the same name, the last one found overrules and hides the others. Files are then processed in alphabetical order, so if a config option is specified in multiple files, the last entry found overrules the others. If an option is left unspecified in a file processed after another file in which it was specified, it is not overruled. + +Example config files used by unit tests, continuous integration tests, and https://github.com/advancedtelematic/meta-updater[meta-updater] recipes can be found in link:{aktualizr-github-url}/config/[], link:{aktualizr-github-url}/tests/config/[], and link:https://github.com/advancedtelematic/meta-updater/tree/rocko/recipes-sota/config/files[]. + +All fields are optional, and most have reasonable defaults that should be used unless you have a particular need to do otherwise. + +Some options can also be set on the command line. The command line input always takes precedence over the config files. See link:{aktualizr-github-url}/src/aktualizr_primary/main.cc[] (or run `aktualizr --help`) for the available command line options. + +== `logger` + +Configuration for the logger. + + +[options="header"] +|========================================================================================== +| Name | Default | Description +| `loglevel` | `2` | Log level, 0-5 (trace, debug, info, warning, error, fatal). +|========================================================================================== + +== `p11` + +Options for using a PKCS#11 compliant device for storing cryptographic keys. + +NOTE: The key ID options require the corresponding options in the `tls` or `uptane` section to be set to `pkcs11`. + +[options="header"] +|========================================================================================== +| Name | Default | Description +| `module` | | Path to the shared object HSM driver. +| `pass` | | Password for accessing the HSM. +| `uptane_key_id` | | Key ID of the Uptane key in the HSM. +| `tls_cacert_id` | | Key ID of the TLS root CA certificate for authenticating the server. +| `tls_pkey_id` | | Key ID of the client's TLS private key. +| `tls_clientcert_id` | | Key ID of the client's TLS certificate. +|========================================================================================== + +== `tls` + +Configuration for client-server TLS connections. + +[options="header"] +|========================================================================================== +| Name | Default | Description +| `server` | | Server URL. +| `server_url_path` | | Path to a file that contains the server URL. +| `ca_source` | `"file"` | Where to read the TLS root CA certificate from. Options: `"file"`, `"pkcs11"`. +| `pkey_source` | `"file"` | Where to read the client's TLS private key from. Options: `"file"`, `"pkcs11"`. +| `cert_source` | `"file"` | Where to read the client's TLS certificate from. Options: `"file"`, `"pkcs11"`. +|========================================================================================== + +Note that `server_url_path` is only used if `server` is empty. If both are empty, the server URL will be read from `provision.provisioning_path` if it is set and contains a file named `autoprov.url`. + +== `provision` + +Options for how the device is provisioned with the backend. + +[options="header"] +|========================================================================================== +| Name | Default | Description +| `server` | | Server provisioning URL. If empty, set to `tls.server`. +| `p12_password` | | Password for PKCS#12 encryption. +| `expiry_days` | `"36000"` | Provided in the `ttl` field of the device provisioning request sent to the server. +| `provision_path` | | Path to an archive containing provisioning data. See link:{aktualizr-github-url}/docs/credentials.adoc[] for the specification of the contents of this file. +| `device_id` | | Device ID of the primary ECU. If left empty, a random name will be generated. +| `primary_ecu_serial` | | Serial number of the primary ECU. If left empty, a random serial will be generated. +| `primary_ecu_hardware_id` | | The hardware ID of the primary ECU (e.g., `"raspberry-pi"`). If left empty, the hostname of the device will be used. +| `ecu_registration_endpoint` | | Ecu provisioning URL. If empty, set to `uptane.director_server` with `/ecus` appended. +|========================================================================================== + +If you intend to provision with a server by using https://github.com/advancedtelematic/meta-updater[meta-updater], you will probably want to set `provision.provision_path = "/var/sota/sota_provisioning_credentials.zip"`. + +== `uptane` + +Options for Uptane. + +[options="header"] +|========================================================================================== +| Name | Default | Description +| `polling_sec` | `10` | Interval between polls (in seconds). +| `director_server` | | Director server URL. If empty, set to `tls.server` with `/director` appended. +| `repo_server` | | Image repository server URL. If empty, set to `tls.server` with `/repo` appended. +| `key_source` | `"file"` | Where to read the device's private key from. Options: `"file"`, `"pkcs11"`. +| `key_type` | `"RSA2048"` | Type of cryptographic keys to use. Options: `"ED25519"`, `"RSA2048"`, `"RSA3072"` or `"RSA4096"`. +| `secondary_configs_dir` | `""` | Directory containing individual secondary json configuration files. Example here: link:{aktualizr-github-url}/config/secondary/virtualsec.json[] +| `force_install_completion`| false | Forces installation completion. Causes a system reboot in case of an ostree package manager. Emulates a reboot in case of a fake package manager. +|========================================================================================== + +== `pacman` + +Options for package management and update installation. Note that this only coincidentally shares the name with the ArchLinux `pacman` tool. + +[options="header"] +|========================================================================================== +| Name | Default | Description +| `type` | `"ostree"` | Which package manager to use. Options: `"ostree"`, `"debian"`, `"none"`. +| `os` | | OSTree operating system group. Only used with `ostree`. +| `sysroot` | | Path to an OSTree sysroot. Only used with `ostree`. +| `ostree_server` | | OSTree server URL. Only used with `ostree`. If empty, set to `tls.server` with `/treehub` appended. +| `packages_file` | `"/usr/package.manifest"` | Path to a file for storing package manifest information. Only used with `ostree`. +| `fake_need_reboot` | false | Simulate a wait-for-reboot with the `"none"` package manager. Used for testing. +|========================================================================================== + +== `storage` + +Options for how Aktualizr stores data locally. + +[options="header"] +|========================================================================================== +| Name | Default | Description +| `type` | `"sqlite"` | What type of storage driver to use. Options: `"sqlite"`. The former `"filesystem"` option is now disabled, existing devices will be migrated (see note below) +| `path` | `"/var/sota"` | Directory for storage +| `sqldb_path` | `"sql.db"` | Relative path to the database file. +| `uptane_metadata_path` | `"metadata"` | Path to the uptane metadata store, for migration from `filesystem`. +| `uptane_private_key_path` | `"ecukey.der"` | Relative path to the Uptane specific private key, for migration from `filesystem`. +| `uptane_public_key_path` | `"ecukey.pub"` | Relative path to the Uptane specific public key, for migration from `filesystem`. +| `tls_cacert_path` | `"root.crt"` | Relative path to the TLS root CA certificate, for migration from `filesystem`. +| `tls_pkey_path` | `"pkey.pem"` | Relative path to the client's TLS private key, for migration from `filesystem`. +| `tls_clientcert_path` | `"client.pem"` | Relative path to the client's TLS certificate, for migration from `filesystem`. +|========================================================================================== + +The only supported storage option is now `sqlite`. + +Old systems configured with `filesystem` can be migrated by changing the `type` field to `sqlite` and keeping all the other fields as-is. +At the next Aktualizr run, the migration procedure will then run automatically and move existing data inside the database. + +== `import` + +Options for importing data from the filesystem into the storage. + +[options="header"] +|========================================================================================== +| Name | Default | Description +| `base_path` | `"/var/sota/import"` | Path to a common root directory to the subsequent files +| `uptane_private_key_path` | | Path to the device's private key. +| `uptane_public_key_path` | | Path to the device's public key. +| `tls_cacert_path` | | Path to the TLS root CA certificate. +| `tls_pkey_path` | | Path to the TLS private key. +| `tls_clientcert_path` | | Path to the TLS client certificate. +|========================================================================================== + +== `telemetry` + +Options for configuring how aktualizr communicates with the server. + +[options="header"] +|========================================================================================== +| Name | Default | Description +| `report_network` | `true` | Enable reporting of device networking information to the server. +|========================================================================================== + +== `bootloader` + +Options for configuring boot-specific behavior + +[options="header"] +|========================================================================================== +| Name | Default | Description +| `rollback_mode` | `"none"` | Controls rollback on supported platforms, see link:{aktualizr-github-url}/docs/rollback.adoc[]. Options: `"none"`, `"uboot_generic"`, `"uboot_masked"` +| `reboot_sentinel_dir` | `"/var/run/aktualizr-session"` | Base directory for reboot detection sentinel. Must reside in a temporary file system. +| `reboot_sentinel_name` | `"need_reboot"` | Name of the reboot detection sentinel. +|========================================================================================== + diff --git a/docs/ota-client-guide/modules/ROOT/pages/aktualizr-repo.adoc b/docs/ota-client-guide/modules/ROOT/pages/aktualizr-repo.adoc new file mode 100644 index 0000000000..cb93b46718 --- /dev/null +++ b/docs/ota-client-guide/modules/ROOT/pages/aktualizr-repo.adoc @@ -0,0 +1,117 @@ += Simulate Uptane metadata transactions + +The aktualizr-repo directory contains a basic tool that generates metadata according to the Uptane spec. It is comprised of three tools: + +. link:../src/aktualizr_repo/run/create_repo.sh[`create_repo.sh`] is a script to generate a new Uptane metadata repository, an OSTree repository, and all associated credentials and configuration. +. link:../src/aktualizr_repo/run/serve_repo.py[`serve_repo.py`] is a script for running a minimalistic Uptane server. +. link:../src/aktualizr_repo/main.cc[`aktualizr-repo`] is a low-level tool to generate and control an Uptane repository. It can be used to manipulate the repo created with `create_repo.sh`, or it can be used entirely independently. + +== create_repo.sh + +`create_repo.sh` generates the whole Uptane repo together with client and server certificates and OSTree repo that can be used both by meta-updater and by the device. `create_repo.sh` uses `aktualizr-repo`, so make sure it's in `PATH`. + +=== Usage + +`create_repo.sh ` + +Make sure that the repository path doesn't already exist and the machine where `serve_repo.py` will be running is accessible from the device specified by ``. + +=== Integration with bitbake + +`create_repo.sh` can work with bitbake running on the same machine. Copy `site.conf` from the generated directory to your `build/conf` or append it to your existing `site.conf`. `bitbake` will then commit the built rootfs to the generated OSTree repository and provision devices to automatically connect to `serve_repo.py`. + +== serve_repo.py + +`serve_repo.py` serves Uptane metadata and OSTree objects to the devices. + +=== Usage + +`serve_repo.py ` + +== aktualizr-repo + +`aktualizr-repo` can generate and control Uptane metadata. It is used by `create_repo.sh` and many aktualizr tests, but can also be used manually. See `aktualizr-repo --help` for basic usage details or the examples below for greater detail. + +=== Basic usage example + +1. Generate a new Uptane repository: ++ +``` +aktualizr-repo --path --command generate +``` + +2. Add a target to the images metadata: ++ +``` +aktualizr-repo --path --command image --filename --targetname --hwid +``` ++ +This step can be repeated as many times as necessary for each target. `--targetname` is optional. If it is not provided, it is assumed to be the same as the image name provided to `--filename`. + +3. Prepare director targets metadata for a given device: ++ +``` +aktualizr-repo --path --command addtarget --targetname --hwid --serial +``` ++ +This step can be repeated as many times as necessary for each target and ECU. + +4. Sign the director targets metadata and schedule the prepared update: ++ +``` +aktualizr-repo --path --command signtargets +``` + +=== Advanced usage examples + +==== Delegations + +`aktualizr-repo` supports first-order delegations. All delegations are therefore marked as terminating. To add a delegated role, use this: +``` +aktualizr-repo --path --command adddelegation --dname --dpattern +``` + +To add a target to a delegated role, add the `--dname` parameter to the `image` command. The targetname must match the pattern supplied in `--dpattern` to the `adddelegation` command. +``` +aktualizr-repo --path --command image --filename --targetname --hwid --dname +``` + +==== Generating metadata without a real file + +To add a target to the images metadata without providing an actual file, you can supply alternative parameters to the `image` command: +``` +aktualizr-repo --path --command image --targetname --targetsha256 --targetsha512 --targetlength --hwid +``` + +==== Advanced director metadata control + +To reset the director targets metadata or to prepare empty targets metadata, use the `emptytargets` command. If you then sign this metadata with `signtargets`, it will schedule an empty update. +``` +aktualizr-repo --path --command emptytargets +``` + +To populate the director targets metadata with the currently signed metadata (with the previous signature removed), use the `oldtargets` command. You can then add more targets with `addtarget` and re-sign with `signtargets`. +``` +aktualizr-repo --path --command oldtargets +``` + +==== Sign arbitrary metadata + +To sign arbitrary metadata with one of the Uptane keys, use the `sign` command: +``` +aktualizr-repo --path --command sign --repotype --keyname < +``` + +==== Add custom URLs + +To add a custom URL to an image in the Targets metadata of the Images repository: +``` +aktualizr-repo --path --command image --filename --targetname --hwid --url +``` + +To add a custom URL to an image in the Targets metadata of the Director: +``` +aktualizr-repo --path --command addtarget --targetname --hwid --serial --url +``` + +If a custom URL is set in both sets of metadata, libaktualizr will use the URL from the Director. \ No newline at end of file diff --git a/docs/ota-client-guide/modules/ROOT/pages/aktualizr-runningmodes-finegrained-commandline-control.adoc b/docs/ota-client-guide/modules/ROOT/pages/aktualizr-runningmodes-finegrained-commandline-control.adoc new file mode 100644 index 0000000000..524208a921 --- /dev/null +++ b/docs/ota-client-guide/modules/ROOT/pages/aktualizr-runningmodes-finegrained-commandline-control.adoc @@ -0,0 +1,88 @@ += Selectively trigger aktualizr +:page-layout: page +:page-categories: [client-config] +:page-date: 2018-08-22 11:01:14 +:page-order: 30 +:icons: font + +// NOTE: this page used to be done via include. I wanted to rearrange some things and add some content, and I wanted to see how it would look without having to get a PR to the aktualizr repo done, so I just pasted in the content. Original include commented out below. +// -Jon +// include::https://raw.githubusercontent.com/advancedtelematic/aktualizr/master/docs/selectively-triggering-aktualizr.adoc[lines=2..-1]] + +Aktualizr normally runs as a `systemd` service and regularly polls for updates. The default polling interval is set at 10s, and this should be increased by a few orders of magnitude in a production system. + +It is also possible to trigger the update cycle, or individual parts of the update cycle, manually or programmatically. This is done by using aktualizr's `--run-mode` option, or just supplying the operation name as a subcommand. + +For production use, however, we recommend xref:why-use-libaktualizr.adoc[using a wrapper around libaktualizr] instead. + +[NOTE] +==== +To selectively trigger aktualizr, you should disable the `systemd` service. If aktualizr runs continuously, it interferes with the manual triggering. + +To run the update cycle manually, first stop and disable the aktualizr background service: + + systemctl stop aktualizr && systemctl disable aktualizr + +Assuming aktualizr is being built using Yocto and meta-updater, the `systemd` service can also be disabled by default by adding the following to `local.conf`: + + SYSTEMD_AUTO_ENABLE_aktualizr = "disable" +==== + +== Triggering an entire update cycle + +An update cycle consists of: + +. Polling the server for updates and downloading (and verifying) update metadata. +. Downloading (and verifying) any update binaries available. +. Installing the update. +. Reporting the install results. + +To trigger the whole cycle, use the following command: + + aktualizr once + +== Triggering individual update stages + +It might not be desirable to always trigger a complete update cycle. For example, you may want to check for updates and download them, but get user permission before installing. Or, you may want to download an update when there is network connectivity then perform the installation later, without relying on the network. (Note that aktualizr is always _safe_ against network drops. The worst that can happen if the network becomes unavailable is that the update will fail and need to be retried later.) + +=== Triggering an update check + +Fetch the Uptane metadata: + + aktualizr check + +=== Downloading an available update + +Download an update: + + aktualizr download + +=== Installing downloaded update(s) + + aktualizr install + +=== Reporting installation results + +Installation reports are sent when aktualizr polls the server for updates, so the `check` run-mode should be used again after installing: + + aktualizr check + +=== Check for campaigns that target the device + +Campaigns provide a way to target software updates to specific groups of devices. You can set up campaigns in the OTA Connect web app. When a device comes online that matches the targeting criteria of a campaign, the OTA Connect server notifies the device that new software updates are available. + + aktualizr campaign_check + +If the device is targeted by one or more campaigns, aktualizr prints details of each applicable campaign including the campaign ID. You can then use the campaign ID for the `campaign_accept` command. + +=== Accept campaigns that target the device + +This run mode works together with the `campaign_check` mode. After you have received a list of applicable campaigns, you can accept the campaigns so that they are included in the software update process. + + aktualizr campaign_accept --campaign-id= + +For example: + + aktualizr campaign_accept --campaign-id=4df1a199-59d4-47f6-a261-d79b83020f65 + +Once aktualizr has accepted the campaign, the scheduled update becomes available to the device. The device can then install the update during a normal full update cycle or when the device runs in `check` mode. \ No newline at end of file diff --git a/docs/ota-client-guide/modules/ROOT/pages/build-agl.adoc b/docs/ota-client-guide/modules/ROOT/pages/build-agl.adoc new file mode 100644 index 0000000000..68abcbe559 --- /dev/null +++ b/docs/ota-client-guide/modules/ROOT/pages/build-agl.adoc @@ -0,0 +1 @@ +include::dev@getstarted:ROOT:page$automotive-grade-linux.adoc[] \ No newline at end of file diff --git a/docs/ota-client-guide/modules/ROOT/pages/build-images.adoc b/docs/ota-client-guide/modules/ROOT/pages/build-images.adoc new file mode 100644 index 0000000000..4a67a144a6 --- /dev/null +++ b/docs/ota-client-guide/modules/ROOT/pages/build-images.adoc @@ -0,0 +1,5 @@ += Build OTA-enabled Disk images + +As described in the xref:workflow-overview.adoc[workflow overview], you use the Yocto tools to build a disk image that you can flash to your devices. This disk image includes the OTA Connect client, which communicates with the OTA Connect server. You can learn more about the Yocto tools, in the xref:yocto.adoc[Yocto section]. + +If you don't have a physical microcontroller handy, you can xref:build-quemu.adoc[build an image for QEMU] and simulate a fully OTA-enabled device on your computer. \ No newline at end of file diff --git a/docs/ota-client-guide/modules/ROOT/pages/build-only-ostree.adoc b/docs/ota-client-guide/modules/ROOT/pages/build-only-ostree.adoc new file mode 100644 index 0000000000..387a3baaf5 --- /dev/null +++ b/docs/ota-client-guide/modules/ROOT/pages/build-only-ostree.adoc @@ -0,0 +1,12 @@ += I don't need to build the SD card images every time--how can I do a build that only does the OSTree part? +:page-layout: page +:page-categories: [faq] +:page-date: 2017-06-29 13:30:33 +:page-order: 99 +:icons: font + +You can select specific tasks to run with the `-c` option in bitbake. To build and push an image without generating the SD card images, you can do + + bitbake rpi-basic-image -c image_garagecheck + +NOTE: This will leave one artifact behind: a bzipped copy of the filesystem tree that gets committed to the OSTree repo. This can safely be deleted, however. diff --git a/docs/ota-client-guide/modules/ROOT/pages/build-ota-enabled-images.adoc b/docs/ota-client-guide/modules/ROOT/pages/build-ota-enabled-images.adoc new file mode 100644 index 0000000000..04e3b95f79 --- /dev/null +++ b/docs/ota-client-guide/modules/ROOT/pages/build-ota-enabled-images.adoc @@ -0,0 +1,3 @@ += Build OTA-enabled disk images + +Aside from our demo recipes, you can also create your own Yocto project from scratch. \ No newline at end of file diff --git a/docs/ota-client-guide/modules/ROOT/pages/build-quemu.adoc b/docs/ota-client-guide/modules/ROOT/pages/build-quemu.adoc new file mode 100644 index 0000000000..27810614ba --- /dev/null +++ b/docs/ota-client-guide/modules/ROOT/pages/build-quemu.adoc @@ -0,0 +1 @@ +include::dev@getstarted:ROOT:page$qemuvirtualbox.adoc[] \ No newline at end of file diff --git a/docs/ota-client-guide/modules/ROOT/pages/build-raspberry.adoc b/docs/ota-client-guide/modules/ROOT/pages/build-raspberry.adoc new file mode 100644 index 0000000000..9f84d95c7e --- /dev/null +++ b/docs/ota-client-guide/modules/ROOT/pages/build-raspberry.adoc @@ -0,0 +1,2 @@ +include::dev@getstarted:ROOT:page$raspberry-pi.adoc[] + diff --git a/docs/ota-client-guide/modules/ROOT/pages/client-provisioning-methods.adoc b/docs/ota-client-guide/modules/ROOT/pages/client-provisioning-methods.adoc new file mode 100644 index 0000000000..82cce1d575 --- /dev/null +++ b/docs/ota-client-guide/modules/ROOT/pages/client-provisioning-methods.adoc @@ -0,0 +1,72 @@ += Device Provisioning Methods +:page-layout: page +:page-categories: [client-config] +:page-date: 2018-07-05 13:31:58 +:page-order: 25 +:icons: font +:toc: macro + +Before devices can receive updates, each device needs to have a unique identity and a certificate. The provisioning process ensures that a signed certificate is associated with each device. This process is crucial for securing communication between devices and the OTA Connect server. +OTA Connect supports two provisioning methods. These methods determine the components that will play the role of the “issuer” and the “verifier” in your infrastructure. The “issuer” is the server that signs and issues your device certificates. The “verifier” is the server that verifies the authenticity of device certificates. +We refer these two methods as “provisioning with shared credentials” and “provisioning with device credentials”. + +* *Provisioning with shared credentials* ++ +This type of provisioning is great for testing because the OTA Connect server plays the role of both the “issuer” and “verifier” when creating device certificates. You can try out OTA Connect without involving the rest of your infrastructure. However, it’s not secure enough for a production scenario. ++ +* *Provisioning with device credentials* ++ +This is the provisioning method that you should use in production. In this scenario, the OTA Connect server doesn’t issue any credentials to devices; it simply inspects device certificates that come preinstalled. The OTA Connect server only plays the role of “verifier” and the “issuer” role is handled by your fleet certificate authority. + +.How the server roles change depending on which method you choose: +[caption="Figure 1: "] +image::prov-diff-infra.png[] + + +Note that in both cases, the server that plays “issuer” role, must have access to the private key and the root certificate for your fleet. The root certificate and private key are used to sign identity metadata and to verify the identity of connected devices. + +Let’s take a close look at how each method works. + +== Provisioning with shared credentials + +This method is called “provisioning with shared credentials” because you install a temporary provisioning key that is shared by all devices. +With this method, perform the following major steps: + +* You download a temporary provisioning key from the OTA Connect server and install it on a base software image. +* You then flash your base software image to your devices. +* Once each device boots up, it uses the shared provisioning key to request a permanent device certificate from the OTA Connect server. +* The OTA Connect server verifies the provisioning key, issues the device with an X.509 certificate which is then downloaded to the device. +* The device then uses this certificate for all future transactions. + +This method is fine for provisioning devices quickly but if a malicious actor steals your provisioning key, there’s no way to prevent unauthorized devices from provisioning. You’d have to blacklist the provisioning key for all devices and issue a new one. + +== Provisioning with device credentials + +If you’re using OTA Connect in production, you should provision with device credentials. +In this scenario, the OTA Connect server doesn’t issue any credentials to devices. You need to preinstall the device certificates yourself. +How you get the certificates on to your devices is your decision. Your chosen method can depend on many variables such as the storage method on the device, whether you have connectivity at your factory, and whether you choose an internal or 3rd party root of trust for your certificates. +For example, you might have a deployment process where your build system requests a certificate from your CA while a software image is being built. The device certificate is then installed on the image just before it is flashed to the target device. +Once a device boots up, it connects to the OTA Connect server and provides the pre-installed device certificate to verify the device identity. The OTA Connect server then verifies that the certificate came from your CA. +With method, it is extremely difficult for an unauthorized device to join your fleet. + + +The following diagram summarizes the differences in how devices are provisioned between the two methods. + +.How the server roles change depending on which method you choose: +[caption="Figure 2: "] +image::prov-diff-devices.png[] + +With “shared credential” provisioning, devices identified by the provisioning key and the device ID. The role of “issuer” is played by the OTA Connect server, which expects a provisioning key. +With “device credential” provisioning, you decide how devices are identified. You could generate and preinstall certificate signing request (CSR) files which provide your Certificate Authority (CA) with all the necessary identification details. + +== Setting up the OTA Connect Server for Provisioning + +If you want to use “shared credential” provisioning, we’ll generate a fleet root certificate and private key for you and store them on the OTA Connect server. We take the security of these keys and certificates extremely seriously: following industry best practices, they are kept in a Vault instance and only taken out when you request them. +If you want to use “device credential” provisioning, you’ll need to provide us with your own fleet root certificate so that the OTA Connect server can verify devices. +Of course, you can use both methods, but in that case, we recommend that you maintain separate user accounts: + +* one account for testing with “shared credential” provisioning +* one account for production with “device credential” provisioning + +Migrating devices from a test account to a production account is an extremely complex process and should be avoided. Instead, we recommend that you test with devices that will not go into production or devices that can be completely reset for production. +Once you are ready for production, you should use your production account, your own fleet root certificate, and production devices that have their device certificates preinstalled. diff --git a/docs/ota-client-guide/modules/ROOT/pages/cross-deploy-images.adoc b/docs/ota-client-guide/modules/ROOT/pages/cross-deploy-images.adoc new file mode 100644 index 0000000000..27485bf43c --- /dev/null +++ b/docs/ota-client-guide/modules/ROOT/pages/cross-deploy-images.adoc @@ -0,0 +1,51 @@ += Transfer disk images to a software repository in another account +:page-layout: page +:page-categories: [prod] +:page-date: 2018-03-15 13:52:05 +:page-order: 3 +:icons: font +:sectnums: +:garage-deploy-version: 2018.13 + +For our recommended production workflow, you will need to move disk images from one account to another from time to time. For example, you might want to send a development build that you're happy with to the QA team, or send that build to the deployment team once it's passed QA. You can do this with our `garage-deploy` tool. + +Before you start, make sure that you've installed the xref:install-garage-sign-deploy.adoc[`garage-deploy`] tool first. + +To transfer disk images to a different account, follow these steps: :: +. xref:getstarted::generating-provisioning-credentials.adoc[Download provisioning keys] for both accounts. ++ +We'll assume that you named them `source-credentials.zip` and `dest-credentials.zip`. ++ +. Select an image and commit ID to deploy, and the hardware ID(s) to deploy it to ++ +The image name is the one that appears in your {product-name} account--it will be the same as the `MACHINE` setting in Yocto by default, or the `OSTREE_BRANCHNAME` option if you set it. The commit ID is the hash of the OSTree commit, visible in the package details. The hardware IDs are for the destination account, and are equivalent to the `MACHINE` setting in your Yocto build. ++ +. Run `garage-deploy` ++ +You can see the available options with `--help`: ++ +---- +$ garage-deploy --help +garage-deploy command line options: + --help print usage + --version Current garage-deploy version + -v [ --verbose ] verbose logging (use twice for more + information) + -q [ --quiet ] Quiet mode + --commit arg OSTree commit to deploy + --name arg Name of image + -f [ --fetch-credentials ] arg path to source credentials + -p [ --push-credentials ] arg path to destination credentials + -h [ --hardwareids ] arg list of hardware ids + --cacert arg override path to CA root certificates, in the + same format as curl --cacert +---- ++ +For example, to deploy an image called `acme-modelB` with SHA `001ee11a28e3e08f3e93e31425f0721a7fb44946919284b629ca85a1cc3073cb` and make it installable on all Raspberry Pi devices on your target account, the command would be: ++ +---- +garage-deploy --commit 001ee11a28e3e08f3e93e31425f0721a7fb44946919284b629ca85a1cc3073cb \ + --name acme-modelB -f source-credentials.zip -p dest-credentials.zip -h raspberrypi3 +---- ++ +. Log into the destination account, and verify that your image has been deployed diff --git a/docs/ota-client-guide/modules/ROOT/pages/deb-package-install.adoc b/docs/ota-client-guide/modules/ROOT/pages/deb-package-install.adoc new file mode 100644 index 0000000000..ae20bf0bc7 --- /dev/null +++ b/docs/ota-client-guide/modules/ROOT/pages/deb-package-install.adoc @@ -0,0 +1,49 @@ +== Installing aktualizr via debian package + +Aktualizr makes .deb packages available via the https://github.com/advancedtelematic/aktualizr/releases[GitHub releases page]. Download and install the .deb package, for example: + +---- +sudo apt install ./aktualizr.deb +---- + +=== Setting up aktualizr + +The debian package will install, enable, and start an `aktualizr` systemd service immediately after it's installed. However, there are some configuration steps that should be taken before the service starts. To use aktualizr with a server (i.e. https://github.com/advancedtelematic/ota-community-edition/[OTA Community Edition] or https://docs.ota.here.com[HERE OTA Connect]), you will need to download the provisioning credentials file provided by the server and place it at `/var/sota/sota_provisioning_credentials.zip`. + +You can pass any other command-line arguments in this file, as well. + +For security reasons, we recommend creating the `/usr/lib/sota/sota.env` file even if you aren't going to use it. The file should be owned by root, with `600` permissions. + +=== Secondary ECUs + +The debian package ships with a default secondary ECU configured. This acts like a dummy device, dropping whatever file you send it into `/tmp/demo-virtual-secondary/firmware.bin`. + +=== Building the debian package + +After following the main build setup steps, just `make package` instead of `make` to create a debian package from your current branch, for example: + +---- +git clone --recursive https://github.com/advancedtelematic/aktualizr +cd aktualizr +mkdir build +cd build +cmake -DCMAKE_BUILD_TYPE=Debug -DBUILD_DEB=ON .. +make package +---- + +=== Making a Release on github + +Releases are built automatically by Travis from annotated tags of the form `major.minor`, where `major` and `minor` are numbers. We normally set `major` to the current year and `minor` to an incrementing number beginning at 1. + +To create a release, checkout the revision you want to bless, then: + +---- +git tag -as # e.g. git tag -a 2018.4 +git push github +---- + +Travis will build this tag and automatically create a release for it on github. This is normally a good time to update the link:../CHANGELOG.md[changelog] and the doxygen documentation. Ideally, the changelog should be updated with the new release number before creating the release so that the packaged source code includes the correct information about the release. The process for updating the doxygen is specified in the link:README.adoc#developer-documentation[docs README]. + +Once the release is ready on github, it should be edited to include a link to the changelog and doxygen documentation for that particular release. You can use a previous release as a model of how to format these links. + +Don't forget to test the resulting Debian packages manually! diff --git a/docs/ota-client-guide/modules/ROOT/pages/debugging-tips.adoc b/docs/ota-client-guide/modules/ROOT/pages/debugging-tips.adoc new file mode 100644 index 0000000000..d9d8d8f376 --- /dev/null +++ b/docs/ota-client-guide/modules/ROOT/pages/debugging-tips.adoc @@ -0,0 +1,183 @@ += Aktualizr Debugging Tips + +== Running Aktualizr in development + +The `sota-local.toml` configuration file sets the package manager to `PackageManagerFake`, which allows the installation process to be tested locally: + + # From the build directory + mkdir sota-prov + src/aktualizr_primary/aktualizr --config ../config/sota-local.toml + +For VS code, there is a `launch.json` provided in the `.vscode` directory. This assumes that the cmake build directory is `build`. + +== Creating a temporary OSTree environment + +Try the scripts available in the link:../tests/ostree-scripts[tests/ostree-scripts] directory. + +== Inspect stored info with aktualizr-info + +The aktualizr-info tool can be used to dump information stored in the libaktualizr database. By default, it displays basic information such as storage type, device ID, primary ECU serial and hardware ID and provisioning status. Additional information can be requested with link:../src/aktualizr_info/main.cc[various command line parameters]. + +== Valgrind and gdb + +If the target application or test is running under valgrind, then gdb can still be connected to the process without stopping it. First run `vgdb --port=2159` in a different shell on the same machine, then connect to it using `target remote localhost:2159` in gdb + +== Dumping SSL encrypted traffic + +First fetch and build sslkeylog from https://github.com/cajun-rat/sslkeylog + +Next copy aktualizr.service to /etc/systemd/system/aktualizr.service. +This will override the packages default config. + +Now modify `/etc/systemd/system/aktualizr.service` and add the following lines: + +``` +Environment=SSLKEYLOGFILE=/var/sota/premaster.txt +Environment=LD_PRELOAD=/usr/lib/libsslkeylog.so +``` + +Reload the config and restart + +``` +# systemctl daemon-reload +# systemctl restart aktualizr +``` + +The symmetric SSL keys will be logged in `/var/sota/premaster.txt` + +Now capture a packet dump with tcpdump + +``` +sudo tcpdump tcp port 443 -w upload.pcap +``` + +Fetch both of these down. In wireshark preferences set ssl.keylog_file to point to premaster.txt. If your https traffic not on port 443, then add the port to http.ssl.port. Now open upload.pcap. + +== Serve repo generated by aktualizr-repo + +aktualizr can be tested against a dummy repository containing fake images. + +First, generate a repository using link:../src/aktualizr_repo/main.cc[aktualizr-repo] tool: + +``` +aktualizr-repo generate +``` + +Then, serve the generated directory using a web server such as the link:../tests/fake_http_server/fake_test_server.py[fake test server]. + +For more information about using aktualizr-repo, see link:./aktualizr-repo.adoc[aktualizr-repo.adoc]. + +Here is an example configuration for nginx: + +``` +server { + listen 80; + listen [::]:80; + server_name localhost; + + location / { + try_files $request_uri $request_uri; + } + location /director/manifest { + try_files $request_uri $request_uri; + dav_methods PUT; + } + + root repo_dir/repo; +} +``` + +== Inject faults + +See link:./fault-injection.adoc[fault-injection.adoc] + +== Developing and debugging with an OpenEmbedded system + +By default OpenEmbedded builds fixed versions of software from a VCS using bitbake recipes. When developing Aktualizr itself it is useful to have a quicker edit-compile-run cycle and access to a debugger. The following steps will use OpenEmbedded to create a cross-compilation environment, then build inside that. + +1. Add the following to local.conf: ++ +---- +TOOLCHAIN_HOST_TASK_append = " nativesdk-cmake " +---- + +2. Build the SDK: ++ +---- +bitbake -c populate_sdk core-image-minimal +---- + +3. That will create a self-extracting installer that can be copied to your development machine. Install it by executing this script (or a similarly-named one, depending on your environment): ++ +---- +./tmp/deploy/sdk/poky-sota-glibc-x86_64-core-image-minimal-core2-64-toolchain-2.2.2.sh +---- + +4. Execute this script (or something similar, depending on where you installed it) to update the environment to point to the cross compilers: ++ +---- +. /opt/poky-sota/2.2.2/environment-setup-core2-64-poky-linux +---- ++ +You may want to verify that `which cmake` returns something like this: ++ +---- +/opt/poky-sota/2.2.2/sysroots/x86_64-pokysdk-linux/usr/bin/cmake +---- + +5. Create a cmake build directory for this cross-compile: ++ +---- +mkdir build-cross +cd build-cross +cmake .. +make aktualizr +---- + +The compiled 'aktualizr' executable can be copied to the remote system and run. + +Aktualizr can be debugged remotely by exposing a port from the VM to development machine (the --gdb option to the https://github.com/advancedtelematic/meta-updater/blob/master/scripts/run-qemu-ota[run-qemu-ota script] in https://github.com/advancedtelematic/meta-updater[meta-updater] does this), then: + +.On the target: +---- +gdbserver 0.0.0.0:2159 ./aktualizr --config /usr/lib/sota/sota.toml --loglevel 0 +---- + +.On the host: +---- +$ gdb aktualizr +(gdb) target remote localhost:2159 +---- + +In CLion the remote debugger is configured as follows: + +image::clion-debugger.png[CLion GDB configuration] + +It is also possible to run it inside valgrind: + +.On the target: +---- +valgrind --vgdb=yes --vgdb-error=0 ./aktualizr --config /usr/lib/sota/sota.toml +vgdb --port=2159 +---- + +Then connect the debugger as usual. + +== Bitbaking with debug symbols + +For every binary you want to debug (executables and shared libraries alike) you need to add these two lines in the recipe: + +``` +INHIBIT_PACKAGE_DEBUG_SPLIT = "1" +INHIBIT_PACKAGE_STRIP = "1" +``` + +You also need to make it build with debug symbols, which is recipe-dependent. For aktualizr it means specifying + +``` +-DCMAKE_BUILD_TYPE=Debug +``` + +instead of Release. However, this method does not install the sources on the device, so it helps to open the source file on your host machine. + + diff --git a/docs/ota-client-guide/modules/ROOT/pages/deploy-checklist.adoc b/docs/ota-client-guide/modules/ROOT/pages/deploy-checklist.adoc new file mode 100644 index 0000000000..14ee4346f3 --- /dev/null +++ b/docs/ota-client-guide/modules/ROOT/pages/deploy-checklist.adoc @@ -0,0 +1,41 @@ += Deployment Checklist + +OTA Connect is designed to integrate easily into development workflows: you build your image, push it, set auto-updates for some of your test-bench devices, and so on. But once you're ready to move from testing into production, you will likely want to do a few things differently. + +Here is a checklist for all the tasks you should consider when moving to production: + +[cols="2,5a,2a",options="header"] +|==================== +| Task | Summary | Documentation +|**Register the root certificate for your fleet ** | +* If you followed our recommendations, you should have accounts for development, testing and production. +** If you also followed our recommendation to use device-credential povisioning, you need to register your fleet root certificate with your production account + +* You might have already registered a self-signed root certificate with your test account. ++ +However, regardless of the type of certficate that you use, you'll need to register a new certificate with your *production* account. | +* xref:client-provisioning-methods.adoc[Device provisioning methods] +* xref:provide-root-cert.adoc[Register the Root Certificate for your Fleet] + +|**Generate and install final device certs** | +* Once you have your final fleet root certificate, you can use it to generate and sign device certificates. ++ +You can then automate the process of installing device certificates on your devices. + +* We can’t tell you exactly how to automate this process, but you can use the commands from our documentation as a guideline. +| xref:generate-devicecert.adoc[Generate a device certificate] + +|**Rotate production keys** | +* In line with our security concept, We recommend that you sign disk images with secure, offline keys. + +* Even if you've done this already for with a test account, you need to do it again with a `credentials.zip` from your production account. + +* You should keep these keys on a secure storage medium such as a link:https://www.yubico.com/[YubiKey]. You would only plugin your YubiKey when you need to sign metadata on your local computer.| xref:rotating-signing-keys.adoc[Manage keys for software metadata] + +|**Transfer disk images to your production repository** | +* When you're ready to deploy your software to production, you'll need to move all approved disk images from the software repository in your testing account to the one in your production account. | xref:cross-deploy-images.adoc[Transfer software to another repository] +|**Create production-ready client configuration** | +* You'll need to update the configuration for aktualizr or libaktualizr. ++ +Settings that are convenient for testing, such as small polling invervals, are not suitable for production and should be changed. | xref:recommended-clientconfig.adoc[Recommended client configurations] +|==================== \ No newline at end of file diff --git a/docs/ota-client-guide/modules/ROOT/pages/developer-tools.adoc b/docs/ota-client-guide/modules/ROOT/pages/developer-tools.adoc new file mode 100644 index 0000000000..718e9e96e3 --- /dev/null +++ b/docs/ota-client-guide/modules/ROOT/pages/developer-tools.adoc @@ -0,0 +1,64 @@ += Developer Tools + +Before we walk you through the basic workflow of an OTA update, it would be helpful to understand the tools that are involved at each stage. + +The following list contains an explanation of the tools that we'll reference in the following topics: + +.Developer tools +[width="100%",cols="1,3a", options="header"] +|==================== +| Name | Description +| *Aktualizr* | Aktualizr is the official OTA Connect client. You use it to interact with the OTA Connect server and install updates on your device. + +You can use it to easily evaluate OTA Connect functionality. By default, it's included in our demo build configurations. That means it's automatically installed on the demo disk images that you'll build. + +[NOTE] +==== +__Related Tool__: *libaktualizr* + +This is the C++ library that powers aktualizr. Aktualizr is actually a thin wrapper around this library. + +You can use it to add OTA update functionality to your own client applications. + +Later in this guide, we show you xref:libaktualizr-why-use.adoc[how to use libaktualizr]. +==== + +| *Yocto* | Yocto is an open source toolkit that you can use to build Linux-based disk images for almost any embedded device. It uses the concept of "recipes" to build disk images for different hardware architectures. + +You'll be using the common Yocto command `bitbake` to build disk images. You can start with our demo recipes then make your own recipes. + +[NOTE] +==== +__Related Tool__: *meta-updater* + +The "meta-updater" defines some of the important "ingredients" that go into our Yocto recipes. Yocto uses the concept of *layers* to bundle different types of "ingredients". In the case of OTA Connect, our "meta-updater" layer adds the aktualizr client and the OSTree tool to your Yocto builds. + +==== + +Later in this guide, we go into xref:yocto.adoc[more detail about how Yocto works]. + +| *OSTree* | OSTree is a tool for atomic full file system upgrades with rollback capability. OSTree has several advantages over traditional dual-bank systems, but the most important one is that it minimizes network bandwidth and data storage footprint by sharing files with the same contents across file system deployments. + +You probably wont have to use the OSTree CLI often, but it's handy for troubleshooting build issues. + +We also provide a more in-depth xref:yocto.adoc[explanation of OSTree] later in this guide. + +| *Garage Deploy* | +You use our `garage-deploy` tool to move disk images from one account to another—​for example, to send a development build to the QA team, or to send a release candidate to the deployment team. + +For more information on using `garage-deploy`, see the topic xref:cross-deploy-images.adoc[transfer software to a different repository]. + +[NOTE] +==== +__Related Tool__: *Garage Sign* + +This tool is actually bundled with the `garage-deploy` tool, but it serves a separate purpose. + +You use the `garage-sign` tool to create private keys for signing metadata about your software. This tool also downloads those keys to your local computer and disables the default private keys that are hosted on the OTA Connect server. + +For more information on using `garage-sign` to manage keys, see the topic "xref:rotating-signing-keys.adoc[Manage keys for software metadata]". + +==== + +| *OTA Connect Portal* | The OTA Connect portal isn't strictly a developer tool, but you'll need it to download a provisioning key to include in your disk images. It's a web application that you use to trigger updates and push software to your devices. You can access the portal under the following URL: https://connect.ota.here.com +|==================== \ No newline at end of file diff --git a/docs/ota-client-guide/modules/ROOT/pages/device-cred-prov-steps.adoc b/docs/ota-client-guide/modules/ROOT/pages/device-cred-prov-steps.adoc new file mode 100644 index 0000000000..d789093da4 --- /dev/null +++ b/docs/ota-client-guide/modules/ROOT/pages/device-cred-prov-steps.adoc @@ -0,0 +1,24 @@ += Set Up Device Provisioning + +In this section, you'll learn how provisioning in production is different from the provisioning method that you used to get started. You'll also understand the major steps involved in provisioning devices for production. + +== Why is there a different provisioning method for production? + +include::partial$why-different-prov-methods.adoc[] + +== How to provision with device credentials + +include::partial$how-prov-with-device-cred.adoc[] + +*To set up your environment for device credential provisioning, you need to perform the following major steps:* + + +* *xref:provide-root-cert.adoc[Provide us with the root certificate for your fleet]* ++ +We'll need to register this certificate for your account so that OTA Connect can validate your device certificates. +* *xref:install-device-certs.adoc[Install your device certificates on devices]* ++ +The installation process happens outside of OTA Connect but we can give you some pointers on how to set up this process. +* *xref:enable-device-cred-provisioning.adoc[Configure the OTA Connect client to use your device certificates for provisioning]* ++ +We show you how to do this with or without an HSM. \ No newline at end of file diff --git a/docs/ota-client-guide/modules/ROOT/pages/device-cred-prov-teststeps.adoc b/docs/ota-client-guide/modules/ROOT/pages/device-cred-prov-teststeps.adoc new file mode 100644 index 0000000000..d413166bd6 --- /dev/null +++ b/docs/ota-client-guide/modules/ROOT/pages/device-cred-prov-teststeps.adoc @@ -0,0 +1,23 @@ += Text Device-credential Provisioning + +Although shared-credential provisioning is useful for evaluating OTA Connect, we don't recommend that you use it in production. + +If you want to test provisioning properly, you should provision devices with their own certificates. In a production scenario, you'll need to automate the process of provisioning devices with their own certificates, but for testing you can provision devices manually. + +The following major steps show you how to provision test devices with device certificates: + +* xref:generate-selfsigned-root.adoc[Generate a test root certificate]. ++ +If you don't yet have your fleet's root certificate, we show you how to generate one yourself for testing. + +* xref:provide-testroot-cert.adoc[Provide us with your test root certificate] ++ +We'll need to register your test root certificate with a test account, so that the OTA Connect server can verify your test device certificates. + +* xref:generatetest-devicecert.adoc[Generate and sign a test device certificate] ++ +Once you've generated a test root certificate, you can use it to sign a test device certificate. + +* xref:enable-device-cred-provtest.adoc[Enable and install the device certificate] ++ +We show you how to enable device-credential provisioning and install a device certificate on a test device. Once you've provisioned test devices with certificates, they can authenticate with the OTA Connect server. \ No newline at end of file diff --git a/docs/ota-client-guide/modules/ROOT/pages/download-prov-key.adoc b/docs/ota-client-guide/modules/ROOT/pages/download-prov-key.adoc new file mode 100644 index 0000000000..6f2c93cec9 --- /dev/null +++ b/docs/ota-client-guide/modules/ROOT/pages/download-prov-key.adoc @@ -0,0 +1,3 @@ +include::dev@ota-web:ROOT:page$create-provisioning-key.adoc[] + +// MC: Images don't render from included files, added local copies of 's1-prov.png' and 'screenshot_provisioning_key_2.png' (from "ota-web") until I can find a better solution. \ No newline at end of file diff --git a/docs/ota-client-guide/modules/ROOT/pages/ecu_events.adoc b/docs/ota-client-guide/modules/ROOT/pages/ecu_events.adoc new file mode 100644 index 0000000000..0f4fd67faa --- /dev/null +++ b/docs/ota-client-guide/modules/ROOT/pages/ecu_events.adoc @@ -0,0 +1,153 @@ += Client events reporting + +This is a technical document describing the format of the events reported to the back-end by aktualizr during an ongoing update installation. +It reflects the current state of aktualizr code. Future enhancements should be clearly marked as such (`TODO`), to avoid confusion. + +The corresponding C++ objects and their serialization method are defined in link:../src/libaktualizr/primary/reportqueue.h[reportqueue.h]. + +== Common fields + +* `deviceTime` is a timestamp of the event emission (not transmission which can be delayed) +* `eventType` contains two fields `id` and `version` which correspond the format of the custom fields +* `id` is a unique identifier generated on the client side +* `event` contains the custom fields as specified by the event type +* `event.correlationId` (when applicable) identifies the specific update requested by back-end +* `event.ecu` (when applicable) identifies the specific ECU in the vehicle which the event pertains to + +== Per-ECU events + +=== EcuDownloadStarted + +Emitted when the target download relating to a specific ecu has started. Note that since a target can apply to multiple ecus, more than one event can be sent for each target download. + +Contains a correlation id. + +Example: + +``` +{ + "deviceTime" : "2018-10-25T12:35:42Z", + "event" : + { + "correlationId" : "here-ota:campaigns:c017f968-5c7e-4bf6-9992-2134ff06432c", + "ecu" : "secondary_ecu_serial" + }, + "eventType" : + { + "id" : "EcuDownloadStarted", + "version" : 0 + }, + "id" : "313258b4-e4c6-4ce4-a4f3-011a3959d92b" +} +``` + +=== EcuDownloadCompleted + +Emitted when the target download relating to a specific ecu has ended (success or failure). Same caveat as `EcuDownloadStarted` applies. + +Success/failure indicated by the boolean `event.success`. +TODO: revisit that, maybe a status code instead + free form log string + +Contains a correlation id. + +Example: + +``` +{ + "deviceTime" : "2018-10-25T12:35:42Z", + "event" : + { + "correlationId" : "here-ota:campaigns:c017f968-5c7e-4bf6-9992-2134ff06432c", + "ecu" : "CA:FE:A6:D2:84:9D", + "success" : true + }, + "eventType" : + { + "id" : "EcuDownloadCompleted", + "version" : 0 + }, + "id" : "bfb0b452-ac41-4cf0-bec8-3b78469157ec" +} +``` + +=== EcuInstallationStarted + +Emitted when installation on a specific ecu has started. + +Contains a correlation id. + +Example: + +``` +{ + "deviceTime" : "2018-10-25T12:35:42Z", + "event" : + { + "correlationId" : "here-ota:campaigns:c017f968-5c7e-4bf6-9992-2134ff06432c", + "ecu" : "CA:FE:A6:D2:84:9D" + }, + "eventType" : + { + "id" : "EcuInstallationStarted", + "version" : 0 + }, + "id" : "9e3ad5f6-091d-4f63-96eb-20ba2e256631" +} +``` + +=== EcuInstallationCompleted + +Emitted when installation on a specific ecu has ended (success or failure). + +Success/failure indicated by the boolean `event.success`. +TODO: revisit that, maybe a status code instead + free form log string + +Some devices need a reboot after an installation to actually have an effect on the system. +TODO: use a status code `NEED_REBOOT`? + +Contains a correlation id. + +Example: + +``` +{ + "deviceTime" : "2018-10-25T12:35:42Z", + "event" : + { + "correlationId" : "here-ota:campaigns:c017f968-5c7e-4bf6-9992-2134ff06432c", + "ecu" : "CA:FE:A6:D2:84:9D", + "success" : true + }, + "eventType" : + { + "id" : "EcuInstallationCompleted", + "version" : 0 + }, + "id" : "74060fe8-c594-4f37-b676-4d3bedcb5ca5" +} +``` + +== Others + +=== campaign_accepted + +Emitted in response to a campaign confirmation request + +Example: + +``` +{ + "deviceTime" : "2018-10-25T12:56:52Z", + "event" : + { + "campaignId" : "123" + }, + "eventType" : + { + "id" : "campaign_accepted", + "version" : 0 + }, + "id" : "4fc0fb3d-21e3-4b3b-a902-b9c80913f086" + } +} +``` diff --git a/docs/ota-client-guide/modules/ROOT/pages/enable-device-cred-provisioning.adoc b/docs/ota-client-guide/modules/ROOT/pages/enable-device-cred-provisioning.adoc new file mode 100644 index 0000000000..021eba730c --- /dev/null +++ b/docs/ota-client-guide/modules/ROOT/pages/enable-device-cred-provisioning.adoc @@ -0,0 +1,127 @@ += Enable device-credential provisioning and install device certificates + +//MC: This is a copy of the topic "enable-device-cred-provtest.adoc" but intended for the "deploy/production" use case. Need to use more includes to reduce redundancy. + +Once you're ready to provision devices in production, you need to build disk images that are configured to use device-credential provisioning. + +After you have flashed those images to devices, you boot the image and install the device certicate for each device. You can install the certificate to the device's fileystem or use an HSM. + +== Enable and install _without_ an HSM + +You don't need an HSM to provision with device credentials, but we recommend that you use one. If you want to do without an HSM for now, use this procedure. + +To enable device-credential provisioning and install device certificates _without_ an HSM, follow these steps: :: + +. Add the following lines to your `conf/local.conf`: ++ +---- +SOTA_CLIENT_PROV = "aktualizr-device-prov" +SOTA_DEPLOY_CREDENTIALS = "0" +SOTA_PACKED_CREDENTIALS = "/path/to/your/credentials.zip" +IMAGE_INSTALL_append = " dropbear " +---- ++ +[NOTE] +==== +The line `IMAGE_INSTALL_append = " dropbear "` ensures that an ssh server is installed on the image. You'll need to ssh into the device to copy the certificates to the device's filesystem. +==== +. Build a standard image using bitbake. +. Boot the image. +. Run the following commands to tell the device what server URL to connect to: ++ +[source,sh,subs="attributes"] +---- +unzip credentials.zip autoprov.url +scp -P 2222 autoprov.url root@localhost:/var/sota/import/gateway.url +---- ++ +[NOTE] +==== +You might remember that `credentials.zip` contains a provisioning key shared-credential provisioning. In this case we just need the `autoprov.url` file inside `credentials.zip`. This file contains the URL of your device gateway which is specific to your account. +==== +. Copy the device credentials and device gateway root CA certificate to the device. ++ +[source,sh,subs="attributes"] +---- +export device_dir=path/to/device/dir +scp -P 2222 -pr ${device_dir} root@localhost:/var/sota/import +---- ++ +[NOTE] +==== +Replace `path/to/device/dir` with the device directory that you noted when xref:generatetest-devicecert.adoc[generating the device certificate]. +==== ++ +. _(Optional)_ When the copy operation has completed, ssh into your device and check the aktualizr log output with the following `systemd` command: ++ +`journalctl -f -u aktualizr` ++ +Once the certificates have copied, the following chain of events should occur: ++ +.. The server authenticates the client device by verifying that the client's certificate was signed by the root CA private key that was uploaded in step 2. +.. The client device authenticates the server by verifying that the server's certificate was signed by the server's internal root CA private key. +.. The device is provisioned and appears online in the web UI. + + + +== Enable and install _with_ an HSM + +As described in the xref:index.adoc[introduction], it's a good idea to use a Hardware Security Model (HSM) to hold potentially sensitive device credentials. + +The following procedure describes how to use QEMU and link:https://www.opendnssec.org/softhsm/[SoftHSM] to simulate a device with an HSM. + +However, the procedure for your HSM will probably be different. We've provided these instructions as a basic guide to how this provisioning method works but you'll need to make further changes on your own. For example, you'll probably need to adapt your BSP so that aktualizr can access the keys from your HSM. + +To enable device-credential provisioning and install device certificates _with_ an HSM, follow these steps: :: + +. Add the following lines to your `conf/local.conf`: ++ +---- +SOTA_CLIENT_FEATURES = "hsm" +SOTA_CLIENT_PROV = "aktualizr-device-prov-hsm" +SOTA_DEPLOY_CREDENTIALS = "0" +IMAGE_INSTALL_append = " softhsm-testtoken dropbear " +---- ++ +[NOTE] +==== +The line `IMAGE_INSTALL_append = " softhsm-testtoken dropbear "` ensures that softhsm and an ssh server are installed on the image. You'll need to ssh into the device to copy the certificates to the hsm. +==== +. Build a standard image using bitbake. +. Boot the image. +. Run the following commands to tell the device what server URL to connect to: ++ +[source,sh,subs="attributes"] +---- +unzip credentials.zip autoprov.url +scp -P 2222 autoprov.url root@localhost:/var/sota/import/gateway.url +---- ++ +[NOTE] +==== +You might remember that `credentials.zip` contains a provisioning key shared-credential provisioning. In this case we just need the `autoprov.url` file inside `credentials.zip`. This file contains the URL of your device gateway which is specific to your account. +==== +. Copy the device credentials and device gateway root CA certificate to the device's HSM. ++ +[source,sh,subs="attributes"] +---- +export device_dir=path/to/device/dir +scp -P 2222 -pr ${device_dir} root@localhost:/var/sota/import +---- ++ +[NOTE] +==== +Replace `path/to/device/dir` with the device directory that you noted when xref:generatetest-devicecert.adoc[generating the device certificate]. + +For the QEMU simulated HSM, replace `path/to/device/dir` with the credentials directory of the relevant device. +==== ++ +. _(Optional)_ When the copy operation has completed, ssh into your device and check the aktualizr log output with the following `systemd` command: ++ +`journalctl -f -u aktualizr` ++ +Once the certificates have copied, the following chain of events should occur: ++ +.. The server authenticates the client device by verifying that the client's certificate was signed by the root CA private key that was uploaded in step 2. +.. The client device authenticates the server by verifying that the server's certificate was signed by the server's internal root CA private key. +.. The device is provisioned and appears online in the web UI. diff --git a/docs/ota-client-guide/modules/ROOT/pages/enable-device-cred-provtest.adoc b/docs/ota-client-guide/modules/ROOT/pages/enable-device-cred-provtest.adoc new file mode 100644 index 0000000000..5b179e2c19 --- /dev/null +++ b/docs/ota-client-guide/modules/ROOT/pages/enable-device-cred-provtest.adoc @@ -0,0 +1,126 @@ += Enable device-credential provisioning and install device certificates + +//MC: This is a copy of the topic "enable-device-cred-provisioning.adoc" but intended for the "test" use case. Need to use more includes to reduce redundancy. + +If you've followed our recommendation to use device-credential provisioning, you'll need to test how it works in your environment. You start by building disk images that are configured to use device-credential provisioning. + +After you have flashed those images to devices, you boot the image and install the device certicate for each device. You can install the certificate to the device's fileystem or use an HSM. + +== Enable and install _without_ an HSM + +You don't need an HSM to provision with device credentials, but we recommend that you use one. If you want to do without an HSM for now, use this procedure. + +To enable device-credential provisioning and install device certificates _without_ an HSM, follow these steps: :: + +. Add the following lines to your `conf/local.conf`: ++ +---- +SOTA_CLIENT_PROV = "aktualizr-device-prov" +SOTA_DEPLOY_CREDENTIALS = "0" +SOTA_PACKED_CREDENTIALS = "/path/to/your/credentials.zip" +IMAGE_INSTALL_append = " dropbear " +---- ++ +[NOTE] +==== +The line `IMAGE_INSTALL_append = " dropbear "` ensures that an ssh server is installed on the image. You'll need to ssh into the device to copy the certificates to the device's filesystem. +==== +. Build a standard image using bitbake. +. Boot the image. +. Run the following commands to tell the device what server URL to connect to: ++ +[source,sh,subs="attributes"] +---- +unzip credentials.zip autoprov.url +scp -P 2222 autoprov.url root@localhost:/var/sota/import/gateway.url +---- ++ +[NOTE] +==== +You might remember that `credentials.zip` contains a provisioning key shared-credential provisioning. In this case we just need the `autoprov.url` file inside `credentials.zip`. This file contains the URL of your device gateway which is specific to your account. +==== +. Copy the device credentials and device gateway root CA certificate to the device. ++ +[source,sh,subs="attributes"] +---- +export device_dir=path/to/device/dir +scp -P 2222 -pr ${device_dir} root@localhost:/var/sota/import +---- ++ +[NOTE] +==== +Replace `path/to/device/dir` with the device directory that you noted when xref:generatetest-devicecert.adoc[generating the device certificate]. +==== ++ +. _(Optional)_ When the copy operation has completed, ssh into your device and check the aktualizr log output with the following `systemd` command: ++ +`journalctl -f -u aktualizr` ++ +Once the certificates have copied, the following chain of events should occur: ++ +.. The server authenticates the client device by verifying that the client's certificate was signed by the root CA private key that was uploaded in step 2. +.. The client device authenticates the server by verifying that the server's certificate was signed by the server's internal root CA private key. +.. The device is provisioned and appears online in the web UI. + + +== Enable and install _with_ an HSM + +As described in the xref:index.adoc[introduction], it's a good idea to use a Hardware Security Model (HSM) to hold potentially sensitive device credentials. + +The following procedure describes how to use QEMU and link:https://www.opendnssec.org/softhsm/[SoftHSM] to simulate a device with an HSM. + +However, the procedure for your HSM will probably be different. We've provided these instructions as a basic guide to how this provisioning method works but you'll need to make further changes on your own. For example, you'll probably need to adapt your BSP so that aktualizr can access the keys from your HSM. + +To enable device-credential provisioning and install device certificates _with_ an HSM, follow these steps: :: + +. Add the following lines to your `conf/local.conf`: ++ +---- +SOTA_CLIENT_FEATURES = "hsm" +SOTA_CLIENT_PROV = "aktualizr-device-prov-hsm" +SOTA_DEPLOY_CREDENTIALS = "0" +IMAGE_INSTALL_append = " softhsm-testtoken dropbear " +---- ++ +[NOTE] +==== +The line `IMAGE_INSTALL_append = " softhsm-testtoken dropbear "` ensures that softhsm and an ssh server are installed on the image. You'll need to ssh into the device to copy the certificates to the hsm. +==== +. Build a standard image using bitbake. +. Boot the image. +. Run the following commands to tell the device what server URL to connect to: ++ +[source,sh,subs="attributes"] +---- +unzip credentials.zip autoprov.url +scp -P 2222 autoprov.url root@localhost:/var/sota/import/gateway.url +---- ++ +[NOTE] +==== +You might remember that `credentials.zip` contains a provisioning key shared-credential provisioning. In this case we just need the `autoprov.url` file inside `credentials.zip`. This file contains the URL of your device gateway which is specific to your account. +==== +. Copy the device credentials and device gateway root CA certificate to the device's HSM. ++ +[source,sh,subs="attributes"] +---- +export device_dir=path/to/device/dir +scp -P 2222 -pr ${device_dir} root@localhost:/var/sota/import +---- ++ +[NOTE] +==== +Replace `path/to/device/dir` with the device directory that you noted when xref:generatetest-devicecert.adoc[generating the device certificate]. + +For the QEMU simulated HSM, replace `path/to/device/dir` with the credentials directory of the relevant device. +==== ++ +. _(Optional)_ When the copy operation has completed, ssh into your device and check the aktualizr log output with the following `systemd` command: ++ +`journalctl -f -u aktualizr` ++ +Once the certificates have copied, the following chain of events should occur: ++ +.. The server authenticates the client device by verifying that the client's certificate was signed by the root CA private key that was uploaded in step 2. +.. The client device authenticates the server by verifying that the server's certificate was signed by the server's internal root CA private key. +.. The device is provisioned and appears online in the web UI. diff --git a/docs/ota-client-guide/modules/ROOT/pages/enable-shared-cred-provisioning.adoc b/docs/ota-client-guide/modules/ROOT/pages/enable-shared-cred-provisioning.adoc new file mode 100644 index 0000000000..738c0af2fc --- /dev/null +++ b/docs/ota-client-guide/modules/ROOT/pages/enable-shared-cred-provisioning.adoc @@ -0,0 +1,22 @@ += Enable shared-credential provisioning + +If you build a disk image with the default configuration, shared-credential provisioning is enabled by default. You can also enable it explicitly in your build configuration. + +To enable shared-credential provisioning, follow these steps: :: + +. If you haven't done so already, xref:download-prov-key.adoc[download a provisioning key] and note the path to the downloaded `credentials.zip` file. +. Add the following lines to your `conf/local.conf`: ++ +---- +SOTA_CLIENT_PROV = "aktualizr-shared-prov" +SOTA_PACKED_CREDENTIALS = "/path/to/your/credentials.zip" +---- ++ +[NOTE] +==== +If you're updating a configuration that was previously set to device-credential provisioning, make sure that you remove the line `SOTA_DEPLOY_CREDENTIALS = "0"`. +==== +. Build a standard image using bitbake. +. Boot the image. ++ +The device should now use the provisioning key to request permanent device credentials from the server. Check the dashboard in the OTA Connect Portal to make sure that the device shows up. \ No newline at end of file diff --git a/docs/ota-client-guide/modules/ROOT/pages/evaluation-to-prod.adoc b/docs/ota-client-guide/modules/ROOT/pages/evaluation-to-prod.adoc new file mode 100644 index 0000000000..857eb39852 --- /dev/null +++ b/docs/ota-client-guide/modules/ROOT/pages/evaluation-to-prod.adoc @@ -0,0 +1,40 @@ += Moving from evaluation to production + +The procedures to deploy OTA Connect in production are a little more complex than the basic xref:dev@getstarted::start-intro.adoc[Get Started] procedures. + +That's why it's better work in phases when setting up your OTA Connect in your organization. We recommend that you work in three main phases: + +. __Evaluate__ +. __Integrate__ +. __Deploy__ + +This guide contains chapters to guide you through each phase and the following sections give you an introduction the phased approach: + +== Evaluate + +During evaluation, you should focus on testing the basic update functionality to make sure that you understand how it works. At this stage you don't need to think about customization or production-level security. + +=== Recommendations + +Here are our recommendations for xref:intro-evaluate.adoc[evaluating OTA connect]: + +include::partial$recommended-steps.adoc[tags=evaluate-steps] + +== Integrate + +=== Recommendations + +Here are our recommendations for xref:intro-prep.adoc[integrating OTA Connect into your production environment]: + +include::partial$recommended-steps.adoc[tags=integrate-steps] + +== Deploy + +You've done your testing and now you're ready to xref:intro-prod.adoc[use OTA Connect in production]. You need to make sure that your device provisioning process is production-ready and that your software is available in your production account. + + +=== Recommendations + +Here are our recommendations for deploying OTA Connect to production: + +include::partial$recommended-steps.adoc[tags=deploy-steps] \ No newline at end of file diff --git a/docs/ota-client-guide/modules/ROOT/pages/fault-injection.adoc b/docs/ota-client-guide/modules/ROOT/pages/fault-injection.adoc new file mode 100644 index 0000000000..53c92629da --- /dev/null +++ b/docs/ota-client-guide/modules/ROOT/pages/fault-injection.adoc @@ -0,0 +1,67 @@ += Running aktualizr with fault injection + +To test the system in adverse conditions, it can be useful to make aktualizr fail in a controlled fashion. + +link:https://blitiri.com.ar/p/libfiu/[libfiu] provides a framework to do that, and aktualizr supports a number of controllable fail points. + +== Setup + +libfiu needs to be installed on the target machine. For local compilation on a Debian-derived system, the distribution package can be used: + + apt install fiu-utils libfiu-dev + +Fault injection must then be enabled at CMake configure time with the `-DFAULT_INJECTION=on` option (refer to general building instructions for more details). + +`fiu-run` and `fiu-ctrl` can now be used on the newly compiled aktualizr binary to inject faults (refer to corresponding man pages). + +For example, when using the fake package manager: + + fiu-run -c 'enable name=fake_package_install' aktualizr -c . once + +Our wrapper script in `./scripts/fiu` can be used in place, with the added feature of passing strings in failinfo parameters. + +Usage is as follow: + + ./scripts/fiu run -c 'enable name=fake_package_install,failinfo=reason' -- aktualizr -c . once + +== List of fail points + +Please try to keep this list up-to-date when inserting/removing fail points. + +- `fake_package_install`: make the fake package manager installation to fail, optionally with a failure code supplied via `failinfo` +- `secondary_install_xxx` (xxx is a virtual secondary ecu id): make a virtual secondary installation to fail, optionally with a failure code supplied via `failinfo` +- `fake_install_finalization_failure`: make the fake package manager installation finalization to fail + +== Use in unit tests + +It is encouraged to use fail points to help unit testing sad paths. Tests that require fault injection should only be run if the `FIU_ENABLE` macro is defined. + +== Example with a docker container + +The aktualizr application docker image is compiled with fault injection support. It can be used as a quick way to simulate intermittent installation failures. + +First build the image: + + ./docker/docker-build.sh + +It will tag an image `advancedtelematic/aktualizr-app:latest` which includes the common aktualizr tools, as well as the fiu tools (`fiu-run`, `fiu-ctrl`...) + +Then, prepare an environment for a simulated device, following the guide at link:https://docs.ota.here.com/quickstarts/install-a-client-locally-with-fake-secondaries.html[]. + +`aktualizr` will be run through docker instead of the local system, so all commands will start with: + + docker run -u $(id -u):$(id -g) -w $PWD -v $PWD:$PWD advancedtelematic/aktualizr-app + +It runs the docker image inside a container with the same permissions as the local user, with a volume mounted in the current local directory. + +Then, let's launch aktualizr with `fiu-run`: + + docker run --name aktualizr-fiu --rm -u $(id -u):$(id -g) -w $PWD -v $PWD:$PWD advancedtelematic/aktualizr-app fiu run -- aktualizr -c . + +You can try to install a package now, which will succeed. To make all subsequent installations fail with the reason "TEST_FAILURE", use: + + docker exec aktualizr-fiu fiu ctrl -c 'enable name=fake_package_install,failinfo=TEST_FAILURE' 1 + +To make installations succeed again: + + docker exec aktualizr-fiu fiu ctrl -c 'disable name=fake_package_install' 1 diff --git a/docs/ota-client-guide/modules/ROOT/pages/generate-devicecert.adoc b/docs/ota-client-guide/modules/ROOT/pages/generate-devicecert.adoc new file mode 100644 index 0000000000..fd949bdbbd --- /dev/null +++ b/docs/ota-client-guide/modules/ROOT/pages/generate-devicecert.adoc @@ -0,0 +1,66 @@ += Device Certificate Generation + +// MC: This is a slightly altered copy of "generatetest-devicecerta.doc" with wording that explains you should only use the examples as a reference, since we can't know the customers "real" certificate generation process. + +Once you have your final fleet root certificate, you can use it to generate and sign device certificates. You can then automate the process of installing device certificates on your devices. + +We can't tell you exactly how to automate this process, but heres a recap of the steps involved. + +*To generate a device certificate, follow these steps* + +. Generate a UUID for the device, and make a directory for it: ++ +[source,bash] +---- +export SERVER_NAME=myservername +export DEVICES_DIR = DEVICES_DIR="./${SERVER_NAME}/devices" CWD="${PWD}" +export DEVICE_UUID=$(uuidgen | tr "[:upper:]" "[:lower:]") +export device_id=${DEVICE_ID:-${DEVICE_UUID}} device_dir="${DEVICES_DIR}/${DEVICE_UUID}" +mkdir -p "${device_dir}" +---- ++ +[NOTE] +==== +You might want to update the line `export DEVICE_UUID=` and update it to reflect your own schema for generating device IDs. Currently this command generates a random ID. +==== +. Generate a device certificate and public key, and sign it with your fleet root certificate. ++ +As a reference, here is the command to generate and sign a device certificate with a self-signed root certificate. ++ +[source,bash] +---- +include::example$start.sh[tags="genclientkeys"] +---- + +. Find out the address of the device gateway for your OTA Connect Account ++ +You can get this address from the `credentials.zip` that you download from the OTA Connect Portal. ++ +You need this address to get the internal root CA certificate of the device gateway. This certificate is also necessary to provision devices. + +.. If you haven't done so already, xref:dev@ota-web::create-provisioning-key.adoc[download a provisioning key]. +.. Extract the contents of the `credentials.zip` file to a local folder. +.. In that folder, look for the file `autoprov` and open it with a text editor. ++ +You should see a URL that resembles the following example: ++ +`https://946f68b8-13d2-4647-b335-5a48777b5657.tcpgw.prod01.advancedtelematic.com:443` +.. Make a note of this URL. + +. Get the device gateway's root certificate with the following openssl command: ++ +---- +export device_gateway= +openssl s_client -connect ${device_gateway}:8000 -servername $device_gateway -showcerts | \ + sed -n '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' > ${device_dir}/root.crt +---- ++ +Replace, the placeholder `` with URL that you noted in the previous step. ++ +. Make a note where the actual `$(device_dir)` is on your computer. ++ +You can quickly get it with the command `echo $(device_dir)`. Your device directory should resemble the following example: ++ +`myservername/devices/4e7cdc4f-b7dc-4fb0-900f-a237ba3e804c/` +. Once have noted your device directory, you can xref:enable-device-cred-provisioning.adoc[install the device certificate on the device]. +// end::install-root-ca[] \ No newline at end of file diff --git a/docs/ota-client-guide/modules/ROOT/pages/generate-selfsigned-root.adoc b/docs/ota-client-guide/modules/ROOT/pages/generate-selfsigned-root.adoc new file mode 100644 index 0000000000..0760c8f777 --- /dev/null +++ b/docs/ota-client-guide/modules/ROOT/pages/generate-selfsigned-root.adoc @@ -0,0 +1,30 @@ += Generate a self-signed root certificate + +When you move to production, you'll need to register your fleet root certificate with OTA Connect server. This certificate needs to be signed by a trusted Certificate Authority (CA). + +If you don't yet have your own CA certificate for signing device certificates, you can generate a self-signed certificate for testing. + +// tag::install-root-ca[] + +To generate a self-signed root certificate, follow these steps: :: +. Create a directory structure for the keys, and get some sample configurations for the certificates from the OTA Community Edition project: ++ +[source,bash] +---- +export SERVER_NAME=myservername +export SERVER_DIR="./${SERVER_NAME}" DEVICES_DIR="./${SERVER_NAME}/devices" CWD="${PWD}" +mkdir -p "$DEVICES_DIR" certs +for file in client.cnf device_ca.cnf server.ext client.ext server.cnf server_ca.cnf; do + curl -o certs/$file https://raw.githubusercontent.com/advancedtelematic/ota-community-edition/master/scripts/certs/$file +done +---- ++ +Then, generate the key and cert using openssl on the command line: ++ +[source,bash] +---- +include::example$start.sh[tags="genserverkeys"] +---- ++ +This will create a `./${SERVER_DIR}/devices/` directory with the `ca.crt` certificate and a `ca.key` private key. Keep the private key safe and secure. +. Next, xref:provide-testroot-cert.adoc[register the test root certificate with your OTA Connect account]. \ No newline at end of file diff --git a/docs/ota-client-guide/modules/ROOT/pages/generatetest-devicecert.adoc b/docs/ota-client-guide/modules/ROOT/pages/generatetest-devicecert.adoc new file mode 100644 index 0000000000..79c8e70986 --- /dev/null +++ b/docs/ota-client-guide/modules/ROOT/pages/generatetest-devicecert.adoc @@ -0,0 +1,62 @@ += Generate a test device certificate + +// MC: This is a slightly altered copy of "generate-devicecert.doc" with wording that explains the process from the perspective of testing with a self-signed root cert. + +Once you have created a self-signed root certificate, you can use it to generate and sign device certificates. You then install these certificates on your test devices. + +*Generate a test device certificate, follow these steps* + +. Generate a UUID for the device, and make a directory for it: ++ +[source,bash] +---- +export SERVER_NAME=myservername +export DEVICES_DIR = DEVICES_DIR="./${SERVER_NAME}/devices" CWD="${PWD}" +export DEVICE_UUID=$(uuidgen | tr "[:upper:]" "[:lower:]") +export device_id=${DEVICE_ID:-${DEVICE_UUID}} device_dir="${DEVICES_DIR}/${DEVICE_UUID}" +mkdir -p "${device_dir}" +---- ++ +[NOTE] +==== +Replace `myservername` with the server name that you used to xref:generate-selfsigned-root.adoc[generate your root certificate] -- unless you actually used the placeholder suggestion `myservername` from that procedure. +==== +. Generate a device certificate and public key, and sign it with the root CA that you created previously. ++ +[source,bash] +---- +include::example$start.sh[tags="genclientkeys"] +---- + +. Find out the address of the device gateway for your OTA Connect Account ++ +You can get this address from the `credentials.zip` that you download from the OTA Connect Portal. ++ +You need this address to get the internal root CA certificate of the device gateway. This certificate is also necessary to provision devices. + +.. If you haven't done so already, xref:dev@ota-web::create-provisioning-key.adoc[download a provisioning key]. +.. Extract the contents of the `credentials.zip` file to a local folder. +.. In that folder, look for the file `autoprov` and open it with a text editor. ++ +You should see a URL that resembles the following example: ++ +`https://946f68b8-13d2-4647-b335-5a48777b5657.tcpgw.prod01.advancedtelematic.com:443` +.. Make a note of this URL. + +. Get the device gateway's root certificate with the following openssl command: ++ +---- +export device_gateway= +openssl s_client -connect ${device_gateway}:8000 -servername $device_gateway -showcerts | \ + sed -n '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' > ${device_dir}/root.crt +---- ++ +Replace, the placeholder `` with URL that you noted in the previous step. ++ +. Make a note where the actual `$(device_dir)` is on your computer. ++ +You can quickly get it with the command `echo $(device_dir)`. Your device directory should resemble the following example: ++ +`myservername/devices/4e7cdc4f-b7dc-4fb0-900f-a237ba3e804c/` +. Once have noted your device directory, you can xref:enable-device-cred-provtest.adoc[install the test device certificate on the device]. +// end::install-root-ca[] diff --git a/docs/ota-client-guide/modules/ROOT/pages/how-can-i-check-which-ostree-version-is-installed.adoc b/docs/ota-client-guide/modules/ROOT/pages/how-can-i-check-which-ostree-version-is-installed.adoc new file mode 100644 index 0000000000..44d55bb27a --- /dev/null +++ b/docs/ota-client-guide/modules/ROOT/pages/how-can-i-check-which-ostree-version-is-installed.adoc @@ -0,0 +1,19 @@ += How can I check which OSTree commit is deployed? +:page-layout: page +:page-categories: [faq] +:page-date: 2017-01-25 15:42:59 + +OSTree revisions are identified by a commit hash, just like in Git. You can check the revision running on a device with `ostree admin status`. + +The output should be something like this: + +---- +$ ostree admin status + +* agl fcac1276197670dc98bd082d3edd8e2dd8b349cd0ff7b4529ce103e45882514a.0 + origin refspec: fcac1276197670dc98bd082d3edd8e2dd8b349cd0ff7b4529ce103e45882514a + agl c399da4079f5de110bf8c2c379656ee0c08406daa479407074492ec226462639.0 + origin refspec: c399da4079f5de110bf8c2c379656ee0c08406daa479407074492ec226462639 +---- + +The commit with the star next to it is the currently deployed image. diff --git a/docs/ota-client-guide/modules/ROOT/pages/index.adoc b/docs/ota-client-guide/modules/ROOT/pages/index.adoc new file mode 100644 index 0000000000..c5c194e50f --- /dev/null +++ b/docs/ota-client-guide/modules/ROOT/pages/index.adoc @@ -0,0 +1,28 @@ += Introduction + +include::dev@getstarted::partial$product-intro.adoc[tags=standard-intro] + + +== Who is this guide for? + +This guide is for developers who want to set up OTA update functionality on devices. You can start with our standalone client and then integrate our client library into your own projects. + +Before you start these steps, make sure that you meet the following prerequisites: + +* *Access to a Linux-based operating system.* ++ +The more technical steps should work on Mac OS. If you're a Windows user, you can download a Linux-based software image and install it in on a virtual machine by using a free tool such as Oracle VM VirtualBox. + +* *Experience with the Linux-command line*. ++ +You might run into trouble if you don't understand what some of the commands in these steps are doing. + +* *Knowledge of C++*. ++ +This is necessary if you intend to do any integration work. You'll need be familiar with C++ to follow our examples. + +* *A login to the OTA Connect Portal* ++ +If you don't have one yet, you can find out how to get one in the link:{docs-url}/ota-web/dev/get-access.html[OTA Portal Connect guide]. + +If those prerequisites look OK to you, you can start by getting to know our xref:developer-tools.adoc[developer tools]. diff --git a/docs/ota-client-guide/modules/ROOT/pages/install-garage-sign-deploy.adoc b/docs/ota-client-guide/modules/ROOT/pages/install-garage-sign-deploy.adoc new file mode 100644 index 0000000000..10e46e721f --- /dev/null +++ b/docs/ota-client-guide/modules/ROOT/pages/install-garage-sign-deploy.adoc @@ -0,0 +1,86 @@ += Install the "garage deploy" tool +:page-layout: page +:page-categories: [prod] +:page-date: 2018-09-13 11:50:24 +:page-order: 2 +:icons: font +:garage-deploy-version: 2018.13 + +For our recommended production workflow, we recommend some extra security procedures. Before you can follow these procedures, you need to install our `garage-deploy` tool first. + +We currently provide released versions of `garage-deploy` for Ubuntu 18.04 (Bionic) and Ubuntu 16.04 (Xenial) which are available on https://github.com/advancedtelematic/aktualizr/releases/tag/{garage-deploy-version}. + +== Installation instructions + +=== Ubuntu 18.04 or 16.04 + +To install `garage-deploy` on an Ubuntu 18.04 machine, download the `garage-deploy` package and install it with the following command: + +[subs="attributes"] +---- +wget https://github.com/advancedtelematic/aktualizr/releases/download/{garage-deploy-version}/garage_deploy-ubuntu_18.04.deb +sudo apt install ./garage_deploy-ubuntu_18.04.deb +---- + +For Ubuntu 16.04: + +[subs="attributes"] +---- +wget https://github.com/advancedtelematic/aktualizr/releases/download/{garage-deploy-version}/garage_deploy-ubuntu_16.04.deb +sudo apt install ./garage_deploy-ubuntu_16.04.deb +---- + +=== Other debian-based distros or versions + +If you're using another version of Ubuntu, or another Debian-based distribution that we don't provide packages for, you can build a .deb yourself. Check out https://github.com/advancedtelematic/aktualizr/tree/{garage-deploy-version}[aktualizr], install the required dependencies link:https://github.com/advancedtelematic/aktualizr/tree/{garage-deploy-version}#dependencies[listed here] (exact package names may vary) and build the deb package yourself: + +[subs="attributes"] +---- +git clone --branch {garage-deploy-version} --recursive https://github.com/advancedtelematic/aktualizr +sudo apt install asn1c build-essential clang clang-check-3.8 clang-format-3.8 clang-tidy-3.8 cmake curl \ + doxygen graphviz lcov libarchive-dev libboost-dev libboost-filesystem-dev libboost-log-dev \ + libboost-program-options-dev libboost-serialization-dev libboost-iostreams-dev libcurl4-openssl-dev \ + libdpkg-dev libostree-dev libp11-2 libp11-dev libpthread-stubs0-dev libsodium-dev libsqlite3-dev \ + libssl-dev libsystemd-dev +cd aktualizr +mkdir build +cd build +cmake -DBUILD_SOTA_TOOLS=ON .. +make package +sudo apt install ./garage_deploy.deb +---- + +=== Binaries for other distros + +If you're using a non-debian-based distro, you will need to build and install the binary directly. + +First, install the required dependencies link:https://github.com/advancedtelematic/aktualizr/tree/{garage-deploy-version}#dependencies[listed here]. (These are the Ubuntu package names; the packages may be named differently in your distro's repositories.) Then, you can build as above, but with `garage-deploy` as the make target: + +[subs="attributes"] +---- +git clone --branch {garage-deploy-version} --recursive https://github.com/advancedtelematic/aktualizr +cd aktualizr +mkdir build +cd build +cmake -DBUILD_SOTA_TOOLS=ON .. +make garage-deploy +sudo apt install ./garage_deploy.deb +---- + +The executable will be available in `build/src/sota_tools/garage-deploy`. + +== Usage + +Once you've installed `garage-deploy` tool, you're ready to perform the following tasks: + +* Move device images from one account to another--for example, to send a development build to the QA team, or to send a release candidate to the deployment team. ++ +For more information, see "xref:crossdeploying-device-images-to-a-different-account.adoc[Cross-deploy device images to a different account]". + +* Create offline signing keys that you manage yourself and rotate out the installed online keys. ++ +For more information, see "xref:rotating-signing-keys.adoc[Manage keys for software metadata]". + + + + diff --git a/docs/ota-client-guide/modules/ROOT/pages/intro-evaluate.adoc b/docs/ota-client-guide/modules/ROOT/pages/intro-evaluate.adoc new file mode 100644 index 0000000000..e4da7b10fb --- /dev/null +++ b/docs/ota-client-guide/modules/ROOT/pages/intro-evaluate.adoc @@ -0,0 +1,5 @@ += Evaluate OTA Connect + +Here are our recommendations for xref:intro-evaluate.adoc[evaluating OTA connect]: + +include::partial$recommended-steps.adoc[tags=evaluate-steps] \ No newline at end of file diff --git a/docs/ota-client-guide/modules/ROOT/pages/intro-prep.adoc b/docs/ota-client-guide/modules/ROOT/pages/intro-prep.adoc new file mode 100644 index 0000000000..8ed83f6ada --- /dev/null +++ b/docs/ota-client-guide/modules/ROOT/pages/intro-prep.adoc @@ -0,0 +1,33 @@ += Build your own OTA-enabled solution + +Once you've evaluated the basic functions of OTA Connect, you're ready to build your own OTA-enabled solution. You probably have your client software that runs on your devices. In this phase, you'll start to integrate OTA update functionality into that client. + +You also need to make sure that your device provisioning process reflects what you want to use in production. You also want to set up the software repository for your development account. + +Here's our recommended steps for building your own OTA-enabled solution: + +* xref:account-setup.adoc[*Set up different user accounts*] ++ +Avoid mixing up test software and production software by uploading software under different user accounts. + +* xref:libaktualizr-why-use.adoc[*Integrate libaktualizr with the client software on your board*] ++ +When you move to production, you'll want to integrate OTA functionality into your board's native software. + +* xref:build-ota-enabled-images.adoc[*Build and deploy your integration*] ++ +Once have a working version of your integration, you'll want to build a disk image that contains it. You can then flash this image to other test devices. + +* xref:cross-deploy-images.adoc[*Transfer disk images to a QA repository*] ++ +After you've build your images, you'll want to hand them over to your QA team, who are ideally testing the software under a QA account with its own software repository. + +* xref:device-cred-prov-steps.adoc[*Set up provisioning with device credentials*] ++ +Install device certificates yourself rather than having the OTA Connect server install them automatically. This also allows you to set your own device IDs. + +* xref:secure-software-updates.adoc[*Secure your software repository*] ++ +To secure your software updates, all files are accompanied by metadata that is signed with several private keys. You need to move the most important private keys from the server and take them offline. + + \ No newline at end of file diff --git a/docs/ota-client-guide/modules/ROOT/pages/intro-prod.adoc b/docs/ota-client-guide/modules/ROOT/pages/intro-prod.adoc new file mode 100644 index 0000000000..7dbe023cc1 --- /dev/null +++ b/docs/ota-client-guide/modules/ROOT/pages/intro-prod.adoc @@ -0,0 +1,38 @@ + +== Moving to Production + +{product-name} is designed to integrate easily into development workflows: you build your image, push it, set auto-updates for some of your test-bench devices, and so on. But once you're ready to move from testing into production, you will likely want to do a few things differently. Here is a summary of our recommended workflow for moving from development to production. + +== Maintain separate accounts for development, testing and production + +There are (at least) two good reasons to separate your dev/testing accounts from production: + +* Isolation of production-ready deployments + +{product-name-short} does not support deleting devices or device images. We do this for auditability, but it does mean that your dev/testing account can end up getting a bit cluttered. You wouldn't want to accidentally select the wrong build on a production run. + +* Separation of responsibilities + +Chances are, your developer team isn't responsible for making the decision to push updates live. You can cross-deploy images that are ready for testing to a test account controlled by QA, then once again to an account for production once they've passed QA. + +''' + +To make this workflow possible, create an account for each environment you find useful (e.g. dev, QA, beta, production, etc.), and then read about xref:crossdeploying-device-images-to-a-different-account.adoc[using garage-deploy to cross-deploy images from one account to another]. + +== Manage your own chain(s) of trust + +When you create an account, and when you create provisioning credentials, we generate various keys for you. There's a xref:provisioning-methods-and-credentialszip.adoc[table here] listing everything that's in `credentials.zip`, but the main thing you need to know is that there are two root authorities that we initially generate: a root CA for authenticating your devices during provisioning, and a private key for signing the metadata of the images you build. We take the security of these keys/certificates extremely seriously: following industry best practices, they are kept in a link:https://www.vaultproject.io/[Vault] instance and only taken out when you request them. + +However, *we don't need to have the keys at all*. You can manage your own root CAs in both cases. Images you build get signed locally before being pushed, and {product-name-short} only needs to verify the signatures, and thus xref:enable-device-cred-provisioning.adoc#_use_a_hardware_security_module_hsm_when_provisioning_with_device_credentials[provision your devices with device credentials]. + +Once you've done that, we won't have any of your private key material at all. + +== Consider using a Hardware Security Module + +In the quickstart guides, we automatically provision your devices when they come online for the first time. To make this happen, the devices need to present a provisioning key. If the provisioning key is valid, then {product-name-short} bootstraps the provisioning process by negotiating unique, device-specific credentials in the form of X.509 certificates for mutual TLS authentication. It's these generated credentials that are used when the device connects to the server for updates. + +We refer to this method as provisioning with "shared" credentials. Although each device eventually receives device-specific credentials, the process begins with a shared credential: the provisioning key. + +{product-name} also supports provisioning with pre-loaded device credentials. In this case, the device is pre-loaded with the requisite bootstrap credentials, signed by a root CA of your choice. These can be stored in the HSM, obviating the need for a provisioning key on the device that could potentially be compromised, and also obviating the need for us to hold key material for provisioning. + +How the HSM for your individual board or device works is up to you, but you can xref:enable-device-cred-provisioning.adoc#_simulate_the_provisioning_process_with_device_credentials[simulate a hardware security module in QEMU] to get an idea of how the process works. We provide instructions for QEMU HSM provisioning only; if you need development support in adapting the instructions to your own board, link:mailto:otaconnect.support@here.com[contact us for a consultation]. diff --git a/docs/ota-client-guide/modules/ROOT/pages/libaktualizr-getstarted.adoc b/docs/ota-client-guide/modules/ROOT/pages/libaktualizr-getstarted.adoc new file mode 100644 index 0000000000..f238431d93 --- /dev/null +++ b/docs/ota-client-guide/modules/ROOT/pages/libaktualizr-getstarted.adoc @@ -0,0 +1,292 @@ += Get started +:page-layout: page +:page-categories: [using-libaktualizr] +:page-date: 2018-11-28 14:08:55 +:page-order: 2 +:icons: font + +== What is libaktualizr? + +Libaktualizr is a {cpp} library providing API access to the functionality that aktualizr provides. + +.Aktualizr vs. libaktualizr +**** +* **Aktualizr** is a {cpp} application that implements the client-side functionality for OTA Connect according to the Uptane security framework. It is designed to be run as a standalone component on an embedded system, and can manage the entire software update process. In implementation, it is actually a relatively thin wrapper around libaktualizr. +* **libaktualizr** provides a {cpp} API allowing developers to integrate OTA Connect updates with Uptane security into their own custom applications. +**** + +== How to build libaktualizr + +Before you can work with libaktualizr, you must build the main aktualizr project. + +Aktualizr is an open-source software project distributed under the Mozilla Public License 2.0 and is located on github: https://github.com/advancedtelematic/aktualizr + +You should build the project on a Linux system and your compiler must support the C++11 version of the standard. + +The project contains more dependencies than is practical to list here, so have a look at the https://github.com/advancedtelematic/aktualizr#dependencies[main readme] for the aktualizr project. + +The README contains an extended description on how to build aktualizr as well as the list of build and run-time dependencies. + +Once you have installed the dependencies, build the aktualizr project with the following commands: +[source,bash] +---- +git clone --recursive https://github.com/advancedtelematic/aktualizr.git +cd aktualizr +mkdir build +cd build +cmake -DCMAKE_BUILD_TYPE=Release .. +make +---- + +NOTE: The `--recursive` flag in the `git clone` command is needed to recursively clone all the *git submodules*. + +After the build is finished, you'll find the client library at the following location: `${PROJECT_ROOT}/build/src/libaktualizr/libaktualizr_static_lib.a`. + +== Integrating libaktualizr into your application + +To integrate libaktualizr in your application, you must first decide on one of the following build options: + +* Build libaktualizr "in tree" by adding it to an existing cmake project (recommended). +* Build libaktualizr "out-of-tree". + +=== Building libaktualizr in-tree +The easiest way to integrate with libaktualizr is to add it as a subdirectory to your cmake project. + +.To build libaktualizr in-tree, follow these steps: +. Clone the aktualizr into your project directory: ++ +[source,bash] +---- +$ git clone --recursive https://github.com/advancedtelematic/aktualizr.git +---- + +. Add it to your CMakeLists.txt: ++ +[source,cmake] +---- +add_subdirectory(aktualizr) +---- ++ +This command automatically adds the needed entries to `INCLUDE_DIRECTORIES` variable, create the `AKTUALIZR_EXTERNAL_LIBS` variable, which contains the list of external libraries required for linking with libaktualizr, and create the `aktualizr_static_lib` target. +. Do a test build of your application ++ +Whenever you build your application you must add these libraries as follows: ++ +[source,cmake] +target_link_libraries(your-app aktualizr_static_lib ${AKTUALIZR_EXTERNAL_LIBS}) ++ +You also might need to add the following line if you are using boost libraries: +[source,cmake] +add_definitions(-DBOOST_LOG_DYN_LINK) + +=== Building libaktualizr out-of-tree +If you don't want to make libaktualizr part of your cmake project, it's also possible to build libaktualizr out-of-tree. In this case you will need to specify the required libraries and includes for your application manually. Refer to your system's documentation on how to specify additional libraries and include directories for the target application. + +Here's an example of how to specify the required libraries for an out-of-tree build in cmake project: +[source,cmake] +---- +target_link_libraries(your-app ${AKTUALIZR_PROJECT_DIR}/build/src/libaktualizr/libaktualizr_static_lib.a) +target_link_libraries(your-app pthread) +target_link_libraries(your-app archive) +target_link_libraries(your-app boost_atomic) +target_link_libraries(your-app boost_chrono) +target_link_libraries(your-app boost_date_time) +target_link_libraries(your-app boost_filesystem) +target_link_libraries(your-app boost_log) +target_link_libraries(your-app boost_log_setup) +target_link_libraries(your-app boost_program_options) +target_link_libraries(your-app boost_regex) +target_link_libraries(your-app boost_system) +target_link_libraries(your-app boost_thread) +target_link_libraries(your-app crypto) +target_link_libraries(your-app curl) +target_link_libraries(your-app sodium) +target_link_libraries(your-app sqlite3) +target_link_libraries(your-app ssl) + +target_include_directories(your-app PRIVATE ${AKTUALIZR_PROJECT_DIR}/src/libaktualizr) +target_include_directories(your-app PRIVATE ${AKTUALIZR_PROJECT_DIR}/third_party/jsoncpp) + +add_definitions(-DBOOST_LOG_DYN_LINK) +---- + + +== How to use the libaktualizr API + +Libaktualizr provides a C++ API for fetching information about available updates and currently running OTA campaigns, downloading and installing the updates, and reporting the installation results. + +If you're yet not familiar with OTA Connect concepts such as "campaigns", have a look at the https://connect.ota.here.com/#/campaigns[OTA web app] first. You might need to register for a free developer account first. + +The main library header is https://github.com/advancedtelematic/aktualizr/blob/master/src/libaktualizr/primary/aktualizr.h[`primary/aktualizr.h`]. It also includes few other libaktualizr headers. + +To use the API, add the `src/libaktualizr` directory to your include path and add `# include "primary/aktualizr.h"` to your source file. + +When using the API, consider the following points: + +* Most of the API calls, unless specified otherwise, are asynchronous and return a `std::future` which contains the corresponding result type. +* Result types are defined in the https://github.com/advancedtelematic/aktualizr/blob/master/src/libaktualizr/primary/results.h[`primary/results.h`] header. +* Asynchronous commands are posted to the command queue and executed in sequential order in a separate thread. +* If the execution is paused, newly issued commands accumulate in the command queue and it's up to the caller to ensure that the queue doesn't get overloaded with unnecessary duplicate commands. + +For an example of how to use the libaktualizr API as a primary ECU, there are two applications in the aktualizr tree that you can use as references. Aktualizr itself is in `src/aktualizr_primary`, and there is a very simple demo of using libaktualizr to interact with an HMI (for example, to get user consent) in `src/hmi_stub`. + + +=== API Description + +==== General management, configuration and control flow + +* *Construct an aktualizr instance* ++ +[source,cpp] +---- +Aktualizr::Aktualizr(boost::filesystem::path config) +---- +An instance is constructed based on the provided config. A config should at least contain information about provisioning credentials (see +https://github.com/advancedtelematic/aktualizr/blob/master/docs/automatic-provisioning.adoc[`automatic-provisioning.adoc`], https://github.com/advancedtelematic/aktualizr/blob/master/docs/implicit-provisioning.adoc[`implicit-provisioning.adoc`] or https://github.com/advancedtelematic/aktualizr/blob/master/docs/hsm-provisioning.adoc[`hsm-provisioning.adoc`] depending on the used provisioning type), and about the local storage which will be used to store updates and metadata. +For description of all configuration options, please, refer to the https://github.com/advancedtelematic/aktualizr/blob/master/docs/configuration.adoc[`configuration.adoc`] document and to the https://github.com/advancedtelematic/aktualizr/tree/master/config[`config`] folder for configuration examples. + +* *Add a new secondary ECU* ++ +[source,cpp] +---- +void Aktualizr::AddSecondary(const std::shared_ptr &secondary) +---- +You must call this function before you call `Initialize`. To find out more about primary and secondary ECUs, see our https://docs.ota.here.com/concepts/ats-garage-security-with-uptane.html#primary-and-secondary-ecus[Uptane description]. + +* *Initialize aktualizr* ++ +[source,cpp] +---- +void Aktualizr::Initialize() +---- +Any secondary ECUs should be added before making this +call. This will provision with the server if required. This must be called before using any other aktualizr functions except `AddSecondary`. + +* *Set a callback to receive event notifications* ++ +[source,cpp] +---- +boost::signals2::connection Aktualizr::SetSignalHandler(std::function)> &handler) +---- +Returns a signal connection object, which can be disconnected if desired. The events are defined in the https://github.com/advancedtelematic/aktualizr/blob/master/src/libaktualizr/primary/events.h[`primary/events.h`] header. + +* *Pause a command* ++ +[source,cpp] +---- +void Aktualizr::Pause() +---- +Requests the currently running command to pause and freezes the command queue. All commands that were scheduled after the currently executed command will wait in the command queue until `Resume()` is issued. +Commands that are issued after `Resume()` will be put on a command queue, but not executed until `Resume()` is called. +The `Pause()` function returns immediately, while pausing the running command still may be in progress. The function has no effect if the execution was already paused. + +* *Resume a paused command* ++ +[source,cpp] +---- +void Aktualizr::Resume() +---- +Resumes the execution of a previously paused command and all subsequent commands in the command queue. +Returns immediately. The function has no effect if the execution was not paused. + +* *Abort execution* ++ +[source,cpp] +---- +void Aktualizr::Abort() +---- +Requests the currently running command to abort and flushes the command queue. +The `Abort()` function will block until the command queue is empty and all currently executing commands have stopped. You can also call Abort() on a previously paused class instance, this will clean the command queue, but aktualizr will remain in the paused state. To continue execution at some later point one needs to call Resume(). ++ +Abort() is also called by the Aktualizr class destructor. + +==== Campaign management commands + + +* *Check for campaigns* ++ +[source,cpp] +---- +std::future Aktualizr::CampaignCheck() +---- +The term "campaign" has a specific meaning in OTA Connect. A campaign allows users to approve updates and deploy them to devices. + +* *Accept a campaign* ++ +[source,cpp] +---- +std::future Aktualizr::CampaignAccept(const std::string &campaign_id) +---- +A campaign contains an update which must be accepted by the end user (or on behalf of the end user) before it can be installed on the device. This call accepts the campaign so that the update can be installed. + + + +==== Update management commands + +[cols="d,a"] + +| TASK | CALL + +* *Sends local device data to the server* ++ +[source,cpp] +---- +std::future Aktualizr::SendDeviceData() +---- +This data includes network status, installed packages and hardware information. + +* *Check for updates* ++ +[source,cpp] +---- +std::future Aktualizr::CheckUpdates() +---- +Fetches Uptane metadata and check for updates. This collects a client manifest, PUTs it to the director, updates the Uptane metadata (including root and targets), and then checks the metadata for updates to the target software. + +* *Download target files* ++ +[source,cpp] +---- +std::future Aktualizr::Download(const std::vector &updates) +---- +Downloads the target files that are specified in the input vector returned by `CheckUpdates`. + +* *Install software from target files* ++ +[source,cpp] +---- +std::future Aktualizr::Install(const std::vector &updates) +---- +Installs the software contained in the previously downloaded target files. + +* *Get a handle for downloaded target* ++ +[source,cpp] +---- +std::ifstream Aktualizr::GetStoredTarget(const Uptane::Target &target) +---- +Get target downloaded in Download call. Returned target is guaranteed to be verified and up-to-date according to the Uptane metadata downloaded in CheckUpdates call. + + + +==== Miscellaneous commands + + +* *Synchronously check for updates and install them* ++ +[source,cpp] +---- +void Aktualizr::UptaneCycle() +---- +Synchronously runs an "Uptane cycle" which checks for software updates, downloads any new target files, installs the update, and sends a manifest back to the server. + +* *Asynchronously run aktualizr* ++ +[source,cpp] +---- +std::future Aktualizr::RunForever() +---- +Automatic check and install updates indefinitely: runs UptaneCycle() in a loop at regular intervals until the destructor is called. + + + diff --git a/docs/ota-client-guide/modules/ROOT/pages/libaktualizr-integrate.adoc b/docs/ota-client-guide/modules/ROOT/pages/libaktualizr-integrate.adoc new file mode 100644 index 0000000000..153b600181 --- /dev/null +++ b/docs/ota-client-guide/modules/ROOT/pages/libaktualizr-integrate.adoc @@ -0,0 +1,8 @@ += Build disc images that contain your libaktualizr integration + +Assuming you followed our recommendation to use libaktualizr, you'll need to build disc images that contain your final integration. The build recipes that we provide in the evaluation stage are configured to use standalone aktualizr. + +To prepare for deployment, you'll need to use an updated recipe that includes your libaktualizr integration. + +* In our libaktualizr demo repository, we've included a https://github.com/advancedtelematic/libaktualizr-demo[demo recipe] called `meta-libaktualizr-demo` to point you in the right direction (documentation coming soon). +* For general information about customizing build recipes, also see the documentation in our https://github.com/advancedtelematic/meta-updater[`meta-updater` repository]. \ No newline at end of file diff --git a/docs/ota-client-guide/modules/ROOT/pages/libaktualizr-update-secondary.adoc b/docs/ota-client-guide/modules/ROOT/pages/libaktualizr-update-secondary.adoc new file mode 100644 index 0000000000..e3fd8e9d76 --- /dev/null +++ b/docs/ota-client-guide/modules/ROOT/pages/libaktualizr-update-secondary.adoc @@ -0,0 +1,109 @@ += Update a secondary ECU +:page-layout: page +:page-categories: [using-libaktualizr] +:page-date: 2018-11-28 14:06:25 +:page-order: 6 +:icons: font + +This page shows an example of how to use libaktualizr API to update +a secondary ECU. + +[source,cpp] +---- +boost::filesystem::path cfg_path("/var/sota/sota_local.toml"); +Aktualizr aktualizr(cfg_path); +---- +This will create a new aktualizr instance based on the provided config file. +Next, configure a secondary and add it to aktualizr: +[source,cpp] +---- +Uptane::SecondaryConfig sconfig; +sconfig.secondary_type = Uptane::SecondaryType::kVirtual; +sconfig.ecu_serial = "9b6abd606a761074df0092606465ddc9"; +sconfig.ecu_hardware_id = "TCU"; +sconfig.full_client_dir = "/var/sota/ecus/tcu"; +sconfig.ecu_private_key = "sec.private"; +sconfig.ecu_public_key = "sec.public"; +sconfig.target_name_path = "target_name"; +sconfig.metadata_path = "/var/sota/ecus/tcu/metadata"; +auto secondary = std::make_shared(sconfig); +aktualizr.AddSecondary(secondary); +---- + +Initialize call will provision the device on the backend: +[source,cpp] +---- +aktualizr.Initialize(); +---- + +Then provide the device information (like list of ECUs, +installed software versions, etc.) to the backend. +[source,cpp] +---- +aktualizr.SendDeviceData().get(); +---- + +Now it is possible to query the server about currently running campaigns for +the device: +[source,cpp] +---- +auto result = aktualizr.CampaignCheck().get(); +if (result.campaigns.empty()) { + std::cout << "System is up to date" <)> handler = event_handler; +aktualizr.SetSignalHandler(handler); +---- +The `event_handler()` function may look like this: +[source,cpp] +---- +void event_handler(const std::shared_ptr &event) +{ + if (event->variant == "DownloadProgressReport") { + const auto download_progress = + dynamic_cast(event.get()); + std::cout << "Download progress for file " + << download_progress->target.filename() << ": " + << download_progress->progress << "%\n"; + } +} +---- +After the targets were downloaded, it is possible to install them, +if the secondary type is supported: +[source,cpp] +---- +aktualizr.Install(update_result.updates).get(); +---- +Alternatively, you can get a file handle to the downloaded target and perform +the installation yourself. +[source,cpp] +---- +for (auto& target : update_result.updates) { + std::cout << "Installing file " << target.filename(); + auto handle = aktualizr.GetStoredTarget(target); + custom_install(handle); +} +---- diff --git a/docs/ota-client-guide/modules/ROOT/pages/libaktualizr-why-use.adoc b/docs/ota-client-guide/modules/ROOT/pages/libaktualizr-why-use.adoc new file mode 100644 index 0000000000..5efdcc9830 --- /dev/null +++ b/docs/ota-client-guide/modules/ROOT/pages/libaktualizr-why-use.adoc @@ -0,0 +1,25 @@ += Integrate libaktualizr into your solution + +//// +This topic is supposed to outline the main use cases the product aims to address. The body of the guide must show how to use the product to implement these use cases. + +For libaktualizr We already have this topic: https://docs.atsgarage.com/client-config/advanced-update-control-with-libaktualizr.html +The following text was taken from the linked topic and is a proposal for the introcdution to the integration guide. + +Feel free to adapt it or leave as-is. +//// + +The OTA Connect client (aktualizr) is designed to be run as a standalone component on an embedded system and can manage the entire software update process. However, most automotive production use cases will have requirements that go beyond what the standalone client can provide. For example, some in-vehicle interfaces are proprietary and under NDA, so their implementation must be kept separate from aktualizr. + += Why use libaktualizr? + +You can integrate the OTA update functionality yourself and minimize the involvement of external consultants. For this purpose, you can use libaktualizr to build your own OTA update solution. + +Typical scenarios for making your own client could be: + +* You want to integrate OTA Connect functionality with a third-party HMI +* You want to integrate OTA Connect with a third-party interface that installs software on secondary ECUs +* You want to constrain network traffic and software updates to specific vehicle states +* You want to provide motorists or service staff with progress indicators for specific software updates. + +To get started, have a look at our https://github.com/advancedtelematic/libaktualizr-demo[demo app] in GitHub (documentation coming soon) or read through our guide to xref:libaktualizr-getstarted.adoc[getting started with libaktualizr]. \ No newline at end of file diff --git a/docs/ota-client-guide/modules/ROOT/pages/metadata-expiry.adoc b/docs/ota-client-guide/modules/ROOT/pages/metadata-expiry.adoc new file mode 100644 index 0000000000..1736c70f5e --- /dev/null +++ b/docs/ota-client-guide/modules/ROOT/pages/metadata-expiry.adoc @@ -0,0 +1,32 @@ += Manage metadata expiry dates + +Once you take the keys for signing metadata offline, you need to be aware of when this metadata expires. You need to refresh the expiry date before it is reached, otherwise you won't be able to push updates. + +The default expiry dates are as follows: + +* For `targets.json`, the expiry date is **31 days** from when the metadata was last updated. +* For `root.json`, the expiry date is **365 days** from when the metadata was last updated. + +You can refresh the expiry date one of the following ways: + +* With `garage-sign`: ++ +If you previously followed the procedure to xref:rotating-signing-keys.adoc[take Uptane-related keys offline], you would have created a local image repository called `myimagerepo` and a key called `mytargets`. You use these same repository and key names to refresh the expiry dates. + +** Resign the current targets.json with your existing key: ++ +---- +garage-sign targets sign --repo myimagerepo --key-name mytargets +---- + +** Upload the newly signed targets.json to OTA Connect: ++ +---- +garage-sign targets push --repo myimagerepo +---- + +* With the `bitbake` command: ++ +Another option is to xref:build-ota-enabled-images.adoc[bitbake your main disk image] again. Specifically, the disk image that you flashed to your devices. ++ +Bitbaking again shouldn't take long as files are usually cached from the previous build. You don't have to do anything with the image, it's just that process of bitbaking also refreshes the expiry date for `targets.json.` \ No newline at end of file diff --git a/docs/ota-client-guide/modules/ROOT/pages/ostree-and-treehub.adoc b/docs/ota-client-guide/modules/ROOT/pages/ostree-and-treehub.adoc new file mode 100644 index 0000000000..015b8b9218 --- /dev/null +++ b/docs/ota-client-guide/modules/ROOT/pages/ostree-and-treehub.adoc @@ -0,0 +1,51 @@ +== OSTree + +link:http://ostree.readthedocs.io/en/latest/[OSTree] is an open-source tool that combines a "git-like" model for committing and downloading bootable filesystem trees, along with a layer for deploying them and managing the bootloader configuration. It is actively developed and support by Red Hat, and used in link:http://flatpak.org/[flatpak] and link:http://www.projectatomic.io/[Project Atomic]. + +For more on why OSTree is the best tool for the job of doing embedded device updates, you can also jump straight to xref:ostree-and-treehub.adoc#_comparing_full_filesystem_update_strategies[Comparing full-filesystem update strategies]. + +.Doing It Wrong™: Bad choices for embedded updates +**** +* Package managers ++ +Hey, every Linux distro does it this way--why don't I just use a dpkg/rpm/apk-based package manager for my embedded system? I can control it remotely, and as long as I maintain the same sequence of package installs from the same sources, I should have perfectly consistent filesystems, right? ++ +The problem with this approach is that updates aren't guaranteed to be atomic, so it's quite easy to get the system into a state that requires user intervention to fix, especially if it's rebooted during an update. That might be fine on the desktop or on a server where there's a reasonable expectation that a user could intervene, but it doesn't work for embedded devices. +* "Update Mode" and similar designs ++ +The idea here is that you boot into a mode that allows the root filesystem to be overwritten, either via a pre-downloaded image or via something streamed over the network. Fortunately, we rarely see this design in the wild anymore, with the occasional exception of industrial control systems where the update process is closely supervised. When we do see it, it's typically a legacy of days when microcontroller flashing would be done in person, with a new image streamed over a serial interface to overwrite the old system. This is a very poor choice for embedded, because of the risk that users may disconnect the device while the new image is being flashed, potentially bricking the device or requiring a more difficult intervention to fix. Lower-end home routers and DSL modems sometimes go this route; doing a quick Google search for "link:https://www.google.com/search?q=firmware+update+bricked+router[firmware update bricked router]" should show why this is a bad idea. +**** + +== TreeHub + +Since OSTree is "git-like", you can probably imagine that you can have remote repositories. TreeHub is exactly that. It's seamlessly integrated into the meta-updater layer and into the {product-name} site itself. Your builds get automatically pushed to TreeHub as soon as you make them, and you can use {product-name-short} to wirelessly update your devices--one at a time, or in targeted campaigns. You can even set certain devices to automatically pull updates from TreeHub as soon as they're pushed, and stop wasting time re-flashing the units on your test bench every time you build new code. + +== Comparing full-filesystem update strategies + +OSTree provides a number of very significant technological advantages over other full-filesystem updating schemes. For embedded systems that need a solution for safe, atomic, full-filesystem updates, the usual approach is to have some kind of *dual-bank* scheme. Here, we're going to take a look at the difference between OSTree and dual-bank systems, and the advantages OSTree can provide. + +=== Dual-bank + +In a dual-bank system, the read-only root filesystem is kept on a different partition from the writable user space, so that when an update is needed the whole partition can be overwritten. For atomicity and safety, this read-only partition is duplicated: there are two complete copies of the filesystem, kept on different partitions, and the active partition can be selected at boot time. + +When the system needs to be updated, the new filesystem image is written to the inactive partition, and the next time the system reboots, that partition becomes the active one. + +.Dual-bank update process (click to enlarge) +[caption="Figure 1: ",link={attachmentsdir}/dual-bank-system-update-flow.svg] +image::dual-bank-system-update-flow.svg[] + +The main advantage of this update model is its safety. Updates are always strictly atomic, and there is always a known good image that can be rolled back to. However, there are significant trade-offs in flexibility and materials costs that must be made: the size of the root partition must be chosen when the system is flashed for the very first time, and the duplication of the root partition doubles the space required. When choosing how big to make the root partition, a device manufacturer has to consider not just how big their filesystem image currently is, but also must estimate and plan for the size of all future updates. If the size chosen is too small, it may restrict the ability to add new features. Making it larger, of course, adds to the bill of goods for the product--and since it's duplicated, every extra megabyte of future capacity actually costs two megabytes to accommodate. + +=== OSTree + +OSTree checksums individual files and stores them as content-addressed objects, much like git. The read-only filesystem is built by "checking out" a particular revision, and hardlinking the content-addressed objects into the actual Linux directory structure. Multiple filesystem versions can be stored, and any content that is duplicated across versions is only stored once. A complete history of all versions is stored in TreeHub, but it is not required to store that complete revision history on the device. Only one partition is needed--writable user space can be on the same partition as the OSTree content store. + +When the system needs to be updated, {product-name} sends a small metadata file with a particular commit identifier. The client pulls that commit from TreeHub, only downloading the new files, and only downloading binary diffs of changed files. Once the pull is complete and verified, the system is instructed to boot into the new version the next time it starts up. + +.OSTree update process (click to enlarge) +[caption="Figure 2: ",link={attachmentsdir}/ostree-update-flow.svg] +image::ostree-update-flow.svg[] + +With OSTree, you no longer need to guess how much room you might need in the future to expand your system; the OSTree content store expands and contracts as needed. You also save a significant amount of space, since only diffs between versions need to be stored. OSTree also allows you to garbage-collect old images: if you upgrade 1.0 -> 1.1 -> 1.2, for example, by default the {product-name-short} client will garbage-collect all local objects unique to 1.0. If you decided later on that you in fact did want to go back to v1.0, you still could: if you pushed v1.0 from {product-name-short}, the client would download only the diff from TreeHub, repopulate the local object store, and then reboot into that version. Of course, it's also possible to configure OSTree to keep more than two revisions on the local disk; this can be particularly useful in QA workflows, allowing for rapid testing of a feature or an external integration against multiple different firmware versions. + +Best yet, you get all of these benefits *without having to give up the safety of a dual-bank setup*. Updates are still strictly atomic; if power is lost during the download of an update, the client will still boot into the old system when it starts up next, and will simply resume the download it had begun. You still always have a known good image on the system to roll back to; in fact, as stated above, you can keep an arbitrarily large number of revisions--an impossibility in a dual-bank system. diff --git a/docs/ota-client-guide/modules/ROOT/pages/ostree-usage.adoc b/docs/ota-client-guide/modules/ROOT/pages/ostree-usage.adoc new file mode 100644 index 0000000000..f65f4b014e --- /dev/null +++ b/docs/ota-client-guide/modules/ROOT/pages/ostree-usage.adoc @@ -0,0 +1,36 @@ += OSTree usage +:page-layout: page +:page-categories: [tips] +:page-date: 2017-06-06 15:23:36 +:page-order: 3 +:icons: font + +Sometimes, while troubleshooting, it might be helpful to see and manipulate your local OSTree repos. You can do that using the copy of ostree that bitbake builds. For the rest of these commands, we'll assume that you've exported the executable as `$OSTREE`, and the location of your local repo as `$REPO` (for example, like so): + + export OSTREE=$(pwd)/tmp/sysroots/x86_64-linux/usr/bin/ostree + export REPO=$(pwd)/tmp/deploy/images/raspberrypi3/ostree_repo/ + +=== Get a list of all branches in the repo + +You'll need a branch name for most other commands, so it's often useful to check your list of branches: + + $OSTREE refs --repo $REPO + +The branch name defaults to {MACHINE}-ota, so if you were building for raspberrypi3, your branch name would be raspberrypi3-ota by default. However, you can set the branch name for your build in local.conf using the *OSTREE_BRANCHNAME* configuration option, letting you keep your different builds, projects, or branches under different names. + +=== Show the log for a particular branch + + $OSTREE log --repo $REPO [branchname] + +=== List files in a particular commit + + $OSTREE ls --repo $REPO [commit] [path] + +The -R option is supported, for recursive file listing. + +=== See a diff between two commits or references + + $OSTREE diff --repo $REPO [ref1] [ref2] + +Refs can be branch names or commit hashes, much like in git. Note that this does not show the contents of the diff; it just shows files added, deleted, and modified. + diff --git a/docs/ota-client-guide/modules/ROOT/pages/pki.adoc b/docs/ota-client-guide/modules/ROOT/pages/pki.adoc new file mode 100644 index 0000000000..287b826cfb --- /dev/null +++ b/docs/ota-client-guide/modules/ROOT/pages/pki.adoc @@ -0,0 +1,30 @@ += Key Management + +Once you move to production, we recommend that you manage these keys offline in your own PKI rather than having all keys managed on the OTA Connect server. + +OTA Connect uses pairs of public and private keys to protect sensitive data. Normally, you use a PKI (Public Key Infrastructure) to manage these keys. + +== Risks of using OTA Connect as your PKI + +By default, OTA Connect server plays the role of a PKI so you don't have to think about key management. This is useful if you don't yet have your own PKI, but not so secure. + +If an attacker were able to take over your OTA Connect account, they would be able to provision their own devices and send malicious updates to your devices. If your device happens to be a vehicle, such a breach could have very dangerous consequences. + +This is why we recommend that you use your own PKI in production. + +== Key Types + +If you follow our security recommendations, you'll need to manage several different keys. + + +.Key Types +[width="100%",cols="2,2,4",options="header"] +|==================== +| Key Name | Purpose | Description +| Fleet Root | Device Identity | This key is used to sign your fleet root certificate. The root certificate certifies the identity of your fleet and is used to sign device certificates. The OTA Connect server can then validate device certificates to ensure that a connecting device is part of your fleet. + +If you obtain a root certificate from an external certificate authority such as DigiCert, you don't have to worry about managing this key. The certificate authority takes are of this for you. +| Uptane Root | Software Integrity | This key is used to sign the "root" metadata file for your software repository. This file contains information about all the roles that can sign software metadata. For more information on how to take these keys offline, see the topic "xref:rotating-signing-keys.adoc[Manage keys for software metadata]". +| Uptane Targets | Software Integrity | This key is used to sign the "targets" metadata file for software updates. This file contains information about all the valid software files in your software repository. For more information on how to take these keys offline, see the topic "xref:rotating-signing-keys.adoc[Manage keys for software metadata]". +|==================== + diff --git a/docs/ota-client-guide/modules/ROOT/pages/posix-secondaries-bitbaking.adoc b/docs/ota-client-guide/modules/ROOT/pages/posix-secondaries-bitbaking.adoc new file mode 100644 index 0000000000..a8576417cd --- /dev/null +++ b/docs/ota-client-guide/modules/ROOT/pages/posix-secondaries-bitbaking.adoc @@ -0,0 +1,199 @@ += Posix Secondaries: bitbaking and usage of Primary and Secondary images + +The goal of this doc is to guide a reader on bitbaking of two type of images `primary` and `secondary` that are targeted for QEMU or RPi +and running of which on the target makes it act as `Primary` and `Secondary` ECU of a single device. + +Please, refer to link:https://uptane.github.io/uptane-standard/uptane-standard.html[the Uptane standard] in order to grok the meaning of the `Primary` and `Secondary` terms in the given context from a theoretical standpoint. +Please, check out link:posix-secondaries.doc[this doc] to understand these terms from a practical standpoint and +to learn how `Primary` and `Secondary` can be emulated locally on an user's host. +It is highly advisable to follow the doc instructions and play with emulated `Primary` and `Secondary` prior to running steps described further in this doc. + +== Bitbaking + +It is assumed that a reader is familiar with Yocto and bitbaking in general as well as bitbaking of Aktualizr images in particular, +details of which are out of scope of this doc and can be found in the following guides: + +* link:https://github.com/advancedtelematic/meta-updater/blob/master/README.adoc[meta-updater README]. +* https://docs.ota.here.com/quickstarts/qemuvirtualbox.html[How to build 'core-image-minimal' image for QEMU] + +=== Primary +To bitbake an image for `Primary` run the following: +.... +bitbake primary-image +.... + + +.Primary configuration variables +[cols="1,1,10"] +|=== +|Name |Default |Description + +|`PRIMARY_IP` +|`"10.0.3.1"` +|An IP address to assign to one of the Primary's NIC for communication with Secondaries + +|`PRIMARY_PORT` +|`"9040"` +| A TCP port that Primary aktualizr listen on for connections from Secondaries + +|`PRIMARY_WAIT_TIMEOUT` +|`"120"` +|Time (seconds) to wait for connections from Secondaries. Only the secondaries that connected to Primary will be registered at the server and are part of the device Primary represents. + +|`PRIMARY_SECONDARIES` +|`"10.0.3.2:9050"` +| A space separated list of TCP/IP addresses of the Secondaries to be included into the list of ECUs served by the given Primary +|=== + +Please, note that PRIMARY_SECONDARIES can be a list of TCP/IP addresses in order to fulfill multiple secondaries use case. +For example, `PRIMARY_SECONDARIES = "10.0.3.2:9050 10.0.3.3:9050 10.0.3.4:9050"`. + + +=== Secondary +To bitbake an image for `Secondary` run the following +.... +bitbake secondary-image +.... + +.Secondary configuration variables +[cols="1,1,10"] +|=== +|Name |Default |Description + +|`SECONDARY_IP` +|`"10.0.3.2"` +|An IP address to assign to A Secondary NIC for communication with Primary + +|`SECONDARY_PORT` +|`"9050"` +|A TCP port that Secondary listen on for connections from Primary +|=== + +==== Multiple secondaries use case +In order to support multiple secondaries use case an user should + +* repeat the secondary bitbaking procedure corresponding number of times, each time +** specifying unique TCP/IP address by means of `SECONDARY_IP` and `SECONDARY_PORT` configuration variables +** copying and naming uniquely the resultant image file (e.g. `cp tmp/deploy/images/qemux86-64/secondary-image-qemux86-64.ota-ext4 secondary-images/secondary-image-qemux86-64.ota-ext4-001`) +* bitbake the primary image with `PRIMARY_SECONDARIES` listing the corresponding secondaries TCP/IP addresses +* run the primary by following the guide in <> +* run the secondaries by running the command specified in <> with a parameter pointing to corresponding secondary image. +For example, + +`../meta-updater/scripts/run-qemu-ota --no-gui --secondary-network secondary-images/secondary-image-qemux86-64.ota-ext4-001` + +`../meta-updater/scripts/run-qemu-ota --no-gui --secondary-network secondary-images/secondary-image-qemux86-64.ota-ext4-002` + +=== Specifics of bitbaking for Raspberry Pi + +It is assumed that a reader is a familiar with bitbaking for Raspberry Pi in general, see link:https://docs.ota.here.com/quickstarts/raspberry-pi.html[Build a Raspberry Pi image]. + +The aforementioned/above guide is relevant and applicable to building a Raspberry images of Primay and Secondary. +The following is specifics of building such images targeting RPi. + +* run `source meta-updater/scripts/envsetup.sh raspberrypi3` to get the build environment set up from a root of the yocto project (updater-repo) +* specify type of NIC to use for Primary for connection to Internet/backend. There are two options, ethernet NIC or Wifi. +By default ethernet NIC is used which implies that Raspberry Pi is connected to LAN with an access to Internet. To use WiFi NIC the following configuration variables should be defined in your local configuration (local.conf): + +.WiFi configuration variables +[cols="1,7,10"] +|=== +|Name |Default |Description + +|`RPI_WIFI_ENABLE` +|`"0"` +|A flag to enable/disable (default) WiFi on RPi board. + +|`RPI_WIFI_SSID` +|`N/A (mandatory if wifi is enabled)` +|SSID of a WiFi network to connect to. The SSID is case sensitive. + +|`RPI_WIFI_PWD` +|`N/A (mandatory if wifi is enabled)` +|Password to connect to the WiFi network router. +|=== + + +==== RPi networking details in a context of Posix secondaries support + +IP/Posix secondaries support implies that a single primary ECU connected to two IP networks: + +* an IP network with an access to Internet for communication with the OTA backend; +* an IP network that does not have access to Internet for communication with secondary ECU(s). The secondaries should be connected to this internal network. + +Taking into account that RPi has two NICs, ethernet and wifi the aforementioned requirements to networking can be fulfilled by applying the following approaches. + +===== Primary uses multihomed ethernet interface, Secondary uses ethernet interface + +Both primary and secondary ECUs has wifi turned off and are connected to the same LAN (via switch or router) that has an access to Internet. +Primary only network interface is configured in such way that it has two IP addresses assigned to it. + +The first one (10.0.3.1 by default) is statically defined (can be configured via `PRIMARY_IP` configuration variable) +and connects the primary to an internal IP network (10.0.3.0/8) that is aimed for communication with secondary ECU(s). +Secondary(ies) are connected to the same internal network (10.0.3.0/8) by assigning to their +ethernet interface corresponding IP addresses (10.0.3.x, 10.0.3.2 for the default only secondary, `SECONDARY_IP` configuration variable). + +The second IP address assigned to the primary ethernet NIC should be obtained from a DHCP server running on one of +the devices (usually a router) that is connected to the given LAN, has an access to Internet and provides each host connected to the given IP network with access to Internet +(via NATing IP packets, DHCP and NAT server can be hosted/running on different devices). + +The given networking option is enabled by default. + +===== Primary uses both wifi and ethernet interfaces, Secondary uses ethernet interface +Primary has wifi on, and its wifi NIC is connected to a LAN with an access to Internet. Also, Primary ethernet NIC +is assigned with an only IP address (10.0.3.1 by default) to connect to the internal network for communication +with secondary ECUs. +Secondary(ies) are connected to the same internal network (10.0.3.0/8) by assigning to their +ethernet interface corresponding IP addresses (10.0.3.x, 10.0.3.2 for the default only secondary, `SECONDARY_IP` configuration variable). + +===== Primary and Secondary uses wifi, only Primary uses ethernet NIC +In this case, both Primary and Secondary(ies) uses wifi NIC to connect to the internal network (wifi router should not have an Internet access). Secondary doesn't use ethernet NIC. +Primary connects to Internet via ethernet NIC that should be connected to LAN with an access to Internet. +`(The given approach is not supported by the meta-updater but can be applied by an advanced user)` + + +== Running + +It is assumed that a reader is familiar with details on running of bitbaked images targeted for QEMU, such information can be found in the following docs: + +* link:https://github.com/advancedtelematic/meta-updater/blob/master/README.adoc[meta-updater README]. +* https://docs.ota.here.com/quickstarts/qemuvirtualbox.html[How to build 'core-image-minimal' image for QEMU] + +=== Primary + +To launch QEMU VM acting as Primary run the following from your build directory +.... +../meta-updater/scripts/run-qemu-ota --no-gui --secondary-network primary-image +.... +`--secondary-network` option instructs QEMU to add NIC to the VM in order to communicate with Secondary VM(s) via it. + + +=== Secondary + +To launch QEMU VM acting as Secondary run the following from your build directory +.... +../meta-updater/scripts/run-qemu-ota --no-gui --secondary-network secondary-image +.... +`--secondary-network` option instructs QEMU to add NIC to the VM aimed for communication with Primary + +== Usage + +Once both Primary and Secondary VMs are running you should see that a new device has been registered at the server and you can start testing it. +The following are Tips & Tricks for using & troubleshooting of the Primary and Secondary VMs. + +* run `journalctl -f -u aktualizr` to see logs that are being output by aktualizr running on `Primary` VM; +* run `journalctl -f -u aktualizr-secondary` to see logs that are being output by aktualizr-secondary (posix/IP secondary) running on `Secondary` VM; +* By default, both aktualizr and aktualizr-secondary are running as systemd services. Use `systemctl stop|start|restart ` to control aktualizr and aktualizr-secondary daemons/services managed by systemd; +* To control aktualizr|aktualizr-secondary manually stop corresponding systemd service (see above) and run it from command line: +just type `aktualizr' | `aktualizr-secondary`; +* By default, both executables output logs of level 1 (INFO), specify log level 0 in their config to see debug logs. +In case of running from command line add corresponding parameter ` --loglevel 0`. +In case of running as a systemd service add corresponding configuration fragment into /etc/sota/conf.d/ folder, +e.g. `echo -e "[logger]\nloglevel = 0" > /etc/sota/conf.d/50-debug-logs.toml` and restart the service; +* In order to trigger a device re-provisioning, please, remove the DB file on Primary, i.e. `rm /var/sota/sql.db` +* If the DB file is removed on Secondary then the device should be re-provisioned (see above), +otherwise Primary/aktualizr will refuse to work with a 'new' secondary as it will have a "new" autogenerated ECU serial +that doesn't the one already been registered on Primary. +* OTA Connect does not support adding/removing secondary ECUs to a device that has been already registered. +Thus adding a new ECU to the list of secondaries on Primary won't take much effect, +the new ECU won't appear on the UI and it will be listed as not registered by aktualizr-info. \ No newline at end of file diff --git a/docs/ota-client-guide/modules/ROOT/pages/posix-secondaries.adoc b/docs/ota-client-guide/modules/ROOT/pages/posix-secondaries.adoc new file mode 100644 index 0000000000..15d24c701d --- /dev/null +++ b/docs/ota-client-guide/modules/ROOT/pages/posix-secondaries.adoc @@ -0,0 +1,108 @@ += Posix Secondaries aka IP Secondaries: configuration and emulation of Primary and Secondary on a local host + +The goal of this doc is to guide a reader on configuring and running two executables that can be built out of the given repository source code and act as Primary and Secondary correspondingly. + +The term `Secondary` is being used as it is defined by link:https://uptane.github.io/uptane-standard/uptane-standard.html[the Uptane standard]. +It refers to ECU, software/firmware/package updates of which are managed by another ECU that hosts and runs Uptane compliant software. The later ECU is called Primary and the sotfware it runs in our case is called aktualizr. + +A key component of this repository is libaktualizr which is a library implementing Uptane protocol and providing customers and community with capability to build application(s) one of the purposes of which is to update software/firmware/packages in compliance with the Uptane standard. In addition to libaktualizr, a user can find in this repo another two components: + +. *aktualizr*, aka aktualizr primary - a reference implementation of an application utilizing libaktualizr, its binary/executable is called aktualizr. Aktualizr can be used to emulate Primary ECU locally on a user's host; +. *aktualizr-secondary*, aka posix or IP secondary - a reference implementation intended for running on Secondary ECU and capable to communicate with Primary ECU aktualizr via TCP/IP protocol (implemenation relies on Posix API). Aktualizr-secondary can be used to emulate a Secondary ECU on a user's host. + + +== *Secondary* + +*Build* + +The Secondary executable is built by default, thus following build instructions outlined in link:../README.adoc[the repo's README] should do the trick. If the build procedure is completed successfully then aktualizr-secondary can be found in ``/src/aktualizr_secondary/aktualizr-secondary``. + +*Configure* + +A default configuration of aktualizr-secondary can be found in link:../config/posix-secondary.toml[/config/posix-secondary.toml]. + +Configuration parameters that are worth mentioning are located in [uptane] section: + +* `port` - TCP port to listen for a connection from Primary +* `primary_ip` - IP address of Primary ECU +* `primary_port` - TCP port that Primary's aktualizr listen on for a connection from Secondary + +More details on the configuration in general and specific parameters can be found here link:../docs/configuration.adoc[configuration details] + +*Run* + +``/src/aktualizr_secondary/aktualizr-secondary -c /config/posix-secondary.toml`` +Once it's started, you should see a message saying that aktualizr-secondary is listening on the port specified in the config. + + +== *Primary* + +*Build* + +The Primary executable is built by default, thus following build instructions outlined in link:../README.adoc[the repo's README] should do the trick. If the build procedure is completed successfully then aktualizr executable can be found in ``/src/aktualizr_primary/aktualizr``. + +*Configure* + +A default configuration of aktualizr acting as Primary can be found in link:../config/sota-local-with-secondaries.toml[/config/sota-local-with-secondaries.toml]. + +One configuration parameter that is worth mentioning is `[uptane]: secondary_config_file` which specifies a path +to secondary(ies) configuration file containing input parameters for aktualizr/Primary to communicate with any secondaries. +This is a link:../config/posix-secondary-config.json[default secondary configuration for Primary]. +In order to use the given default config file, either copy it into your current working directory or update +`[uptane]: secondary_config_file` value so it defines a full path to the secondary config file (e.g. ``/config/posix-secondary-config.json``). + +Configuration parameters of secondaries for Primary/aktualizr that are worth mentioning are: + +* `secondaries_wait_port` - TCP port aktualizr listen on for connections from Secondaries +* `secondaries_wait_timeout` - timeout (in sec) of waiting for connections from Secondaries. Primary/aktualizr waits for a connection from those secondaries that it failed to connect to at the startup time. +* `secondaries` - a list of Secondary TCP/IP addresses + +Put your credential.zip file into the current working directory or update `[provision] provision_path` in link:../config/sota-local-with-secondaries.toml[the config] so it specifies a full path to your credential file. + +*Run* + +``/src/aktualizr_primary/aktualizr -c /config/sota-local-with-secondaries.toml`` +Once aktualizr is running, check the output for *_Adding Secondary to Aktualizr_* and *_Provisioned successfully on Device Gateway_*. You should then see that a new device has been registered on the server and that it includes two ECUs: your local Primary and Secondary. You can now send updates to either ECU. + +== *Tips and Tricks* + +* Define an environment variable that points to the aktualizr source root directory on your host. For example: +.... +echo 'export AKT_PROJ_HOME=""' >> ~/.profile +.... +* Define an environment variable that points to the aktualizr build directory on your host. For example: +.... +echo 'export AKT_BUILD_DIR="$AKT_PROJ_HOME/build"' >> ~/.profile +.... +* Use ``$AKT_PROJ_HOME/config/sota-local-with-secondaries.toml`` as the config for your emulated Primary ECU +* Copy ``$AKT_PROJ_HOME/config/posix-secondary-config.json`` to the directory you run your Primary from, let's call it `PRIMARY_HOME_DIR` further. +* Copy your credential file ``credentials.zip`` to `PRIMARY_HOME_DIR` +* Use ``$AKT_PROJ_HOME/config/posix-secondary.toml`` as the config for your emulated Secondary ECU +* To run the primary launch the following from `PRIMARY_HOME_DIR` +.... +$AKT_PRIMARY -c $AKT_PROJ_HOME/config/sota-local-with-secondaries.toml +.... +* To run the secondary launch the following from `PRIMARY_HOME_DIR` (although it can be executed from any directory) +.... +$AKT_SECNDR -c $AKT_PROJ_HOME/config/posix-secondary.toml +.... +* Add --loglevel 0 to the aforementioned launch commands if you would like to see more logs +* To re-register your emulated multi-ECU device (or start playing it from scratch) remove ``storage`` directory from `PRIMARY_HOME_DIR` + +=== Multiple secondaries + +In order to emulate a device containing one primary ECU along with more than one secondary ECUs the following should be done. + +* Run the secondary executable `/src/aktualizr_secondary/aktualizr-secondary` desired number of times each from different directories. +Prior to running secondary executables, please, + + ** copy the configuration file /config/posix-secondary.toml to each directory the secondary will be launched from. + Let's call such directory as `SECONDARY_HOME_DIR`; + + ** update a value of `[network]:port` parameter of the config file in each `SECONDARY_HOME_DIR` directory in such way + that each secondary config specifies different port number (9050 by default) hence each secondary will listen on different port; + +* Update posix-secondary-config.json located in `PRIMARY_HOME_DIR` (see instructions in p. `Primary`) with details of each secondary + that was executed in previous step, specifically, add corresponding values to "secondaries" list field (e.g. `"secondaries": [{"addr": "127.0.0.1:9050"}, {"addr": "127.0.0.1:9051"}]`). + Once posix-secondary-config.json is updated run the primary, as result you should see that it is connected with multiple secondaries + in aktualizr logs as well as on UI. diff --git a/docs/ota-client-guide/modules/ROOT/pages/provide-root-cert.adoc b/docs/ota-client-guide/modules/ROOT/pages/provide-root-cert.adoc new file mode 100644 index 0000000000..d7c2c8a126 --- /dev/null +++ b/docs/ota-client-guide/modules/ROOT/pages/provide-root-cert.adoc @@ -0,0 +1,15 @@ += Register the Root Certificate for your Fleet + +//MC: This is a copy of the topic "provide-testroot-cert.adoc" but intended for the "prod" use case. Need to use more includes to reduce redundancy + +Once you are ready to move to production, you need to have your final fleet root certificate registered with your production account. Ideally, your fleet root certificate should come from an external certificate authority (CA) who can take care of safeguarding your private key. + +During testing, you might have followed our procedure to generate a self-signed root certificate and had it registered with your test account. We don't recommend using a self-signed certificate for production because it makes you more vulnerable to security breaches. Nevertheless, if you'd prefer to stick with a self-signed certificate, you'll need to generate another one and have it registered with your production account. + +* To register your fleet root certificate with HERE OTA Connect, send it to link:mailto:otaconnect.support@here.com[otaconnect.support@here.com]. + +If you followed our recommendations, you should have one OTA Connect account for testing and another for production. Make sure that you specify that this certificate is for your *production* account. + +* While you wait for confirmation from the OTA Connect support team, you can already set up your xref:generate-devicecert.adoc[device certificate generation]. + +* Once you've received confirmation that the fleet root certificate has been registered, you can xref:enable-device-cred-provisioning.adoc[enable device-credential provisioning and install the certificates] on your devices. \ No newline at end of file diff --git a/docs/ota-client-guide/modules/ROOT/pages/provide-testroot-cert.adoc b/docs/ota-client-guide/modules/ROOT/pages/provide-testroot-cert.adoc new file mode 100644 index 0000000000..b44e2940df --- /dev/null +++ b/docs/ota-client-guide/modules/ROOT/pages/provide-testroot-cert.adoc @@ -0,0 +1,13 @@ += Register your test root certificate + +//MC: This is a copy of the topic "provide-root-cert.adoc" but intended for the "test" use case. Need to use more includes to reduce redundancy + +Once you have a root certificate, you need to have it registered with your account so that the OTA Connect server can verify your device certificates. + +* To register your test root certificate with HERE OTA Connect, send it to link:mailto:otaconnect.support@here.com[otaconnect.support@here.com]. + +If you followed our recommendations, you should have one OTA Connect account for testing and another for production. Make sure that you specify that this certificate is for your *test* account. + +* While you wait for confirmation from the OTA Connect support team, you can already xref:generatetest-devicecert.adoc[generate a test device certificate]. + +* Once you've received confirmation that the root certificate has been registered, you can xref:enable-device-cred-provtest.adoc[enable device-credential provisioning and install the certificate] on a test device. \ No newline at end of file diff --git a/docs/ota-client-guide/modules/ROOT/pages/provisioning-methods-and-credentialszip.adoc b/docs/ota-client-guide/modules/ROOT/pages/provisioning-methods-and-credentialszip.adoc new file mode 100644 index 0000000000..53bec9a983 --- /dev/null +++ b/docs/ota-client-guide/modules/ROOT/pages/provisioning-methods-and-credentialszip.adoc @@ -0,0 +1,53 @@ += Provisioning methods and credentials.zip +:page-layout: page +:page-categories: [concepts] +:page-date: 2018-03-15 16:15:17 +:page-order: 99 +:icons: font + +If you're trying to work on integrating {product-name} into your device build, it may be helpful to have a little bit of reference information on how the different provisioning methods work together, and what exactly the magic sauce inside `credentials.zip` is. + +== `credentials.zip` file format + +First, a table: + +// formerly: include::https://raw.githubusercontent.com/advancedtelematic/aktualizr/master/docs/credentials.adoc[tag="credentials-table"]. Temporarily duping content untik Antora migration is done + +[options="header"] +|====================== +| Filename in zip | Purpose | Used by +| treehub.json | URL and OAuth2 authentication for treehub and Uptane repo | garage-sign, garage-push, garage-deploy +| client_auth.p12 | TLS client credentials for authentication with treehub | garage-push, garage-deploy +| autoprov_credentials.p12 | TLS client credentials that are required when provisioning devices with shared credentials | aktualizr, aktualizr-cert-provider +| autoprov.url | URL for provisioning server | aktualizr, aktualizr-cert-provider +| root.json | Initial Uptane root.json (for secure bootstrapping) | garage-sign +| targets.pub | Public key for offline Uptane image signing | garage-sign +| targets.sec | Private key for offline Uptane image signing | garage-sign +| tufrepo.url | URL to Uptane repository | garage-sign +|====================== + +As you can see, the relevant files for the device itself are `autoprov_credentials.p12` and `autoprov.url`. + +== Configuration options for provisioning with device credentials + +When provisioning with device credentials, OTA Connect needs to get various certificates and keys from somewhere. The following table summarizes what is needed, and where it comes from in the HSM. + +// formerly: include::https://raw.githubusercontent.com/advancedtelematic/aktualizr/master/docs/hsm-provisioning.adoc[tag="summary-table"]. Temporarily duping content untik Antora migration is done + +[options=header] +|=================== +| Configuration option | Where it will come from/what it does +| Server URL | Read from credentials archive +| Server Root CA cert | Read from credentials archive +| Fleet Root CA cert | Chain of trust for a device fleet; provided by the user. Must be uploaded by user to the server. +| Fleet Root CA private key | Key for signing device certs in the fleet; provided by user, but used only for signing. Not stored on device. +| TLS device cert | Pre-installed in the device HSM; must be signed by Fleet Root CA private key +| TLS device key | Pre-installed in the device HSM +| Device ID | Read from Common Name field of TLS device cert +| Uptane public/private key | Automatically generated by Aktualizr +| Uptane primary serial number | Automatically generated by Aktualizr +| Primary ECU Hardware ID | Automatically generated by Aktualizr +|=================== + + +NOTE: The "Fleet Root CA" is the one generated in step 1 of the xref:enable-device-cred-provisioning.adoc#_use_a_hardware_security_module_hsm_when_provisioning_with_device_credentials[use a Hardware Security Module to provision with device credentials]. instructions. \ No newline at end of file diff --git a/docs/ota-client-guide/modules/ROOT/pages/pushing-updates.adoc b/docs/ota-client-guide/modules/ROOT/pages/pushing-updates.adoc new file mode 100644 index 0000000000..62ee0d9f26 --- /dev/null +++ b/docs/ota-client-guide/modules/ROOT/pages/pushing-updates.adoc @@ -0,0 +1,108 @@ += Upload a sample software version +:page-partial: +:page-layout: page +:page-categories: [quickstarts] +:page-date: 2017-05-23 16:31:35 +:page-order: 6 +:icons: font + +Every time you bitbake a new image, it is automatically pushed to {product-name}. You can then send the updated image out to any of your devices. In this guide, you learn a few ways to push updated system images from your build machine or workstation to {product-name-short}. + +== Add a new package from an existing recipe + +The simplest update you can do is just adding an extra package to your image, choosing from packages that there are already recipes for. You can see a list of all the packages available with the `bitbake-layers show-recipes` command. + +=== Example task: Install vim + +// video::229856096[vimeo,854,480] + +Because you probably noticed it was missing the first time you went to edit a config file on your device, let's install vim. Add this line to your local.conf: + +---- +IMAGE_INSTALL_append = " vim " <1> <2> +---- +<1> Note the spaces before and after the package name. The `IMAGE_INSTALL_append` option naively appends a string to the list of packages to install, so we wrap it in spaces to make sure we don't alter the list in unexpected ways. + +<2> If you already added vim, try adding man or gdb. + +Now rebuild your image with `bitbake [image-name]`, where `[image-name]` is the same as the one you built in the quickstart guide, and push it to your device using {product-name-short}. Once you reboot, vim will be available. + +== Add a new layer someone else created + +Since Yocto layers are just recipes for how to build software from source, it's often quite easy to find a layer for the thing you're looking for. To add a layer to a Yocto build, you just need to download it, normally by cloning its git repo, and then add it to your `bblayers.conf`. This will make all of the recipes in the layer available to bitbake. + +To demonstrate this, we're going to try a two-step task. First, we're going to install https://6xq.net/pianobar/[pianobar], a command-line client for http://www.pandora.com/[Pandora]. Then, once we've got that working, we're going to add https://github.com/kylejohnson/Patiobar[Patiobar], a Node.js-based web front end for pianobar to turn your device into a web-controlled jukebox. + +=== Example task part 1: Install pianobar + +NOTE: Pandora doesn't work with IP addresses outside of the United States, so if your IP address is not US-American, it won't work by default. There is a `control-proxy` configuration option in pianobar though; see the manpage for details. + +We've created a simple layer called https://github.com/advancedtelematic/meta-jukebox[`meta-jukebox`] to use in this guide. It has one layer dependency: link:https://github.com/imyller/meta-nodejs[`meta-nodejs`]. First, clone those two layers into your project directory: + +---- +git clone https://github.com/advancedtelematic/meta-jukebox +git clone https://github.com/imyller/meta-nodejs +---- + +Then, add them to your `bblayers.conf`. Add these lines to `build/conf/bblayers.conf`: + +---- +BBLAYERS += "${METADIR}/meta-jukebox" +BBLAYERS += "${METADIR}/meta-nodejs" +---- + +Next, add the following two lines to your `local.conf`: + +---- +IMAGE_INSTALL_append = " pianobar " <1> +LICENSE_FLAGS_WHITELIST += " commercial " <2> +---- +<1> This tells bitbake to include the `pianobar` package in the built image. Note the spaces before and after the package name. The `IMAGE_INSTALL_append` option naively appends a string to the list of packages to install, so we wrap it in spaces to make sure we don't alter the list in unexpected ways. +<2> Pianobar has a dependency that doesn't have a fully open source license: it uses ffmpeg for mp3 decoding. By default, Yocto won't allow that. You need to explicitly permit it by whitelisting commercial licenses. + +Now rebuild your image with `bitbake [image-name]`, where `[image-name]` is the same as the one you built in the quickstart guide. Once you push the updated image to your device with {product-name-short} and reboot, you can type `pianobar` to start playing Pandora radio. + +=== Example task part 2: Install Patiobar (web front end) + +Okay, so you got pianobar running. But maybe you don't want to have to ssh into your device when you want to change channels or songs. Let's install https://github.com/kylejohnson/Patiobar[Patiobar] so we can control it using a web interface. + +Patiobar is also included in `meta-jukebox`. To build, just add `patiobar` to `IMAGE_INSTALL_append` in your local.conf. + +[WARNING] +==== +If you are building for 32-bit ARM (i.e. Raspberry Pi), you'll need some supporting packages. On Ubuntu/Debian: + +---- +sudo dpkg --add-architecture i386 +sudo apt-get update +sudo apt-get install g++-multilib libssl-dev:i386 libcrypto++-dev:i386 zlib1g-dev:i386 +---- + +For more details, see the https://github.com/imyller/meta-nodejs#cross-compiling-for-32-bit-target-on-64-bit-host[meta-nodejs README]. +==== + +The Patiobar recipe also includes a systemd service that will create a pianobar config based on options you set in your local.conf, and then starts both Patiobar and Pianobar in screen sessions. You can add these three lines if you wish: + +---- +PANDORA_USER=email@example.com <1> +PANDORA_PASSWORD=password <2> +PANDORA_PROXY=myproxy.example.com:3128 <3> +---- +<1> Your existing Pandora account name +<2> Pandora password +<3> An HTTP proxy server to use for Pandora API calls. You can leave it blank to use no proxy, or set it to 'auto' to automatically search for and select a US proxy on startup. + +Now, rebuild your image and push it to your device. + +After a reboot, Patiobar should launch automatically. Point your web browser to port 3000 on the device, and start listening! + +The screen sessions will be named `pianobar` and `patiobar` respectively; use `screen -r` to attach and see what's going on. You can restart the service with `systemctl restart patiobar`. + +== Make your own recipe or layer + +A complete guide to writing Yocto recipes is out of scope here, but http://www.yoctoproject.org/docs/current/dev-manual/dev-manual.html#new-recipe-writing-a-new-recipe[the Yocto Reference Manual] is a great resource. You can also take a look at the recipes in https://github.com/advancedtelematic/meta-jukebox[`meta-jukebox`] to use as examples: they're all fairly simple, and there are examples of four different types of recipe: + +* https://github.com/advancedtelematic/meta-jukebox/tree/master/recipes-multimedia/pianobar[Pianobar] itself is a fully manual recipe, though it's a pretty simple one; it has specific instructions for the compile and install steps, though they're essentially just `make` and `make install` with a couple of config options. +* https://github.com/advancedtelematic/meta-jukebox/tree/master/recipes-multimedia/libao[libao] and https://github.com/advancedtelematic/meta-jukebox/tree/master/recipes-multimedia/faad2[faad2] make use of https://en.wikipedia.org/wiki/GNU_Build_System[Autotools] to build. They include the line `inherit autotools` in the recipe, which automatically generates configure, compile, and install instructions based on Autotools. +* https://github.com/advancedtelematic/meta-jukebox/blob/master/recipes-support/python-beautifulsoup4/python-beautifulsoup4_4.6.0.bb[BeautifulSoup] is a Python project, with support for https://setuptools.readthedocs.io/en/latest/[setuptools]. Yocto supports setuptools out of the box, so python recipes are often just a few lines long: a source URI, license information, and `inherit setuptools`. +* https://github.com/advancedtelematic/meta-jukebox/tree/master/recipes-multimedia/patiobar[Patiobar] is a Node.js project, and includes a systemd service, so it inherits two recipe helpers: `npm-install` and `systemd`. (`npm-install` is provided by the https://github.com/imyller/meta-nodejs[`meta-nodejs`] layer.) It also has files that it installs directly from the recipe directory (i.e., not from the source repo), and uses a custom install script. diff --git a/docs/ota-client-guide/modules/ROOT/pages/recommended-clientconfig.adoc b/docs/ota-client-guide/modules/ROOT/pages/recommended-clientconfig.adoc new file mode 100644 index 0000000000..4fa933c5e6 --- /dev/null +++ b/docs/ota-client-guide/modules/ROOT/pages/recommended-clientconfig.adoc @@ -0,0 +1,36 @@ += Recommended client configurations + +Before you start developing or deploying to production, you should check that your configuration file has appropriate settings for your use case. + +For more details about the full client configuration settings, see the xref:aktualizr-config-options.adoc[client configuration reference]. + +== Recommended settings for development + +[cols="1,1,1a",options="header,footer"] +|==================== +|Name | Setting | Description +|`polling_sec` | `10` | +Interval between polls (in seconds). + +The default polling interval is 10 seconds which is designed to make it convenient for you to test and develop OTA update functions. +|`force_install_completion` | `true` | +Forces installation completion. Causes a system reboot in case of an ostree package manager. Emulates a reboot in case of a fake package manager. + +You'll want to set this to `true` when developing because it's more convenient. + +|==================== + +== Recommended settings for production + +[cols="1,1,1a",options="header,footer"] +|==================== +|Name | Setting | Description +|`polling_sec` | `86400` | When moving to production you'll want to have a much longer interval. +In fact, for production, we don't support intervals less the 1 hour (3,600 seconds). Longer internals help you to reduce the internet bandwidth and power consumption for your devices. + +We recommend an internal between 1 and 7 days (86,400 to 604,800 seconds). +|`force_install_completion` | `false` | +If you followed our recommendation to enable automatic rebooting for development, you should turn it off again for production. +|==================== + + diff --git a/docs/ota-client-guide/modules/ROOT/pages/rollback.adoc b/docs/ota-client-guide/modules/ROOT/pages/rollback.adoc new file mode 100644 index 0000000000..0bfcb5180f --- /dev/null +++ b/docs/ota-client-guide/modules/ROOT/pages/rollback.adoc @@ -0,0 +1,60 @@ += Rollbacks + +Since Aktualizr is a userspace application and relies on a lot of other software which can be +affected by an unsuccessful update, rollback functionality should be implemented in the bootloader. + +Some support from Aktualizr is nevertheless required. The most important thing is notifying bootloader +on successful boot (`Bootloader::setBootOK()`). Notifying on the update (`Bootloader::updateNotify`) +can also save the bootloader some write cycles to the environment storage. + +Currently only U-boot 'bootcount' rollback mechanism is supported. + +== U-boot + +More info about bootcount feature you can find in U-boot https://www.denx.de/wiki/DULG/UBootBootCountLimit[documentation]. + +When using 'bootcount' the system can be in one of three states: + + * No update: booting into main image + * Booting into rollback image + * Updated: update was installed, but it's not yet clear if it was successful + +'Updated' is a transition state, while 'No update' and 'Rollback' are steady states. +Transition to 'No update' is confirmed by Aktualizr, while going to 'Rollback' is forced by U-boot + +'bootcount' and 'upgrade_available' variables are recognized by U-boot. 'rollback' is Aktualizr-specific, +it prevents bootloader to try booting main image after falling back to rollback image. + +You can see the whole transition graph below. + + + + Aktualizr confirms successful update by + +-----------------------------------------------------+ +-----------------------+ + | setting upgrade_available=0; bootcount=0 | | | + | | | | U-boot increments + | | | | bootcount after every + V | V | unsuccessful boot ( i.e + +-----------------------+ +------------------------+ | (when upgrade_available = 1) + | No update | | Updated | | + | | Aktualizr announces update by | | | + | bootcount = 0 |----------------------------------> | bootcount <= bootlimit |----------+ + | upgrade_available = 0 | setting upgrade_available=1 | upgrade_available = 1 | + | rollback = 0 | | rollback = 0 | + | | | | + +-----------------------+ +------------------------+ + ^ | + Aktualizr announces update by | | + +-------------------------------------------------------+ | + | setting upgrade_available=1 | + | | + | | + +-----------------------+ | + | Rollback | | + | | After bootcount exceeded bootlimit U-boot | + | bootcount > bootlimit |<------------------------------------------------------+ + | upgrade_available = 0 | boots into rollback image and resets upgrade_avalable + | rollback = 1 | + | | + +-----------------------+ + diff --git a/docs/ota-client-guide/modules/ROOT/pages/rotating-signing-keys.adoc b/docs/ota-client-guide/modules/ROOT/pages/rotating-signing-keys.adoc new file mode 100644 index 0000000000..c53f258e3c --- /dev/null +++ b/docs/ota-client-guide/modules/ROOT/pages/rotating-signing-keys.adoc @@ -0,0 +1,93 @@ += Manage keys for software metadata + +OTA Connect has a security concept that includes signing metadata files with secure, offline keys. For more information about these files, see the xref:uptane.adoc#_uptane_metadata[Uptane metadata overview]. + +== How metadata is signed by default + +As part of the quickstart, the OTA Connect server automatically creates two initial keys as part of the account setup process. These keys are stored on the OTA Connect server and are used to automatically sign the two software metadata files. You don't have to think about this metadata at all. + +== How metadata should be signed in production + +Before using OTA Connect in production, however, you should create offline keys that you manage yourself, then rotate out the default keys that were automatically created for your account on the OTA Connect server. If you don't do this, you expose yourself to risks that we describe the in the xref:pki.adoc[key management] topic. + +Instead of being signed on the server, these metadata files will now be signed locally or on your build machine. The signing happens automatically whenever you push a new disk image to OTA Connect. However, you need to update your build cofiguration first. The following procedures show you how to do this. + +Before you start, make sure that you've installed the xref:install-garage-sign-deploy.adoc[`garage-deploy`] tool first. This tool includes the `garage-sign` utility, which you'll need for this procedure. + +== Rotate the keys for `root` and `targets` metadata + +=== Create a local image repository + +A image repository is just a directory structure containing signed metadata in JSON format. Create a new one called _myimagerepo_ with `garage-sign`: + +---- +garage-sign init --repo myimagerepo --credentials /path/to/credentials.zip +---- + +This command creates a `./tuf/myimagerepo/` directory tree in the current directory. +This directory should be secured on an encrypted filesystem. + +=== Generate new keys + +There are two metadata files in the repo and each file needs a new key to sign it. + +---- +garage-sign key generate --repo myimagerepo --name myroot --type rsa +garage-sign key generate --repo myimagerepo --name mytargets --type rsa +---- + +**** +IMPORTANT: It is critical to keep these keys offline on secure hardware. *Do not lose these keys.* +**** + +=== Rotate the online keys with your new offline keys + +This is a four-step process: + +. Pull the current `targets.json` from OTA Connect: ++ +---- +garage-sign targets pull --repo myimagerepo +---- +. Perform a complete root key rotation: ++ +---- +garage-sign move-offline --repo myimagerepo --old-root-alias origroot \ + --new-root myroot --new-targets mytargets +---- ++ +This command ++ +* removes the original `root` key from OTA Connect, +* generates a new `root.json` with the keys generated in the previous step (`myroot` and `mytargets`), +* signs the new `root.json` with both the old and new `root` keys, and +* uploads the newly signed `root.json` to OTA Connect ++ +. Sign the current `targets.json` with the new `targets` key: ++ +---- +garage-sign targets sign --repo myimagerepo --key-name mytargets +---- ++ +. Upload the newly signed `targets.json` to OTA Connect: ++ +---- +garage-sign targets push --repo myimagerepo +---- + +You have now successfully taken the keys for software metadata offline. + +NOTE: After rotating keys, you will no longer be able to upload packages through the OTA Connect web UI--only the usual way, through bitbake. + +== Push new images with bitbake + +Export the new offline `targets` into a new credentials file that you can use with `bitbake`: + +---- +garage-sign export-credentials --repo myimagerepo --target-key-name mytargets --to offline-credentials.zip +---- + +Update your `local.conf` to use the new `offline-credentials.zip` file and run `bitbake` as before. + +As part of the `bitbake` process, the image's metadata inside `targets.json` is signed with your offline TUF keys. The signed `targets.json` is then uploaded to your OTA Connect account. + diff --git a/docs/ota-client-guide/modules/ROOT/pages/schema-migrations.adoc b/docs/ota-client-guide/modules/ROOT/pages/schema-migrations.adoc new file mode 100644 index 0000000000..604f97ecf1 --- /dev/null +++ b/docs/ota-client-guide/modules/ROOT/pages/schema-migrations.adoc @@ -0,0 +1,19 @@ += How to add a schema migration +:aktualizr-github-url: https://github.com/advancedtelematic/aktualizr/tree/master +ifdef::env-github[] +:aktualizr-github-url: .. +endif::[] + +1. Modify link:{aktualizr-github-url}/config/sql/schema.sql[] as you see fit +2. Write a config/sql/migration/migrate.n+1.sql that will convert an existing data to format in schema.sql. Note that old migrations must not be modified. + +Make sure that the migrate.n+1.sql file updates the 'version' table: + + DELETE FROM version; + INSERT INTO version VALUES(...); + +3. Write a config/sql/rollback/rollback.n+1.sql that will revert the new data format to the previous one. It should contain the opposite steps of migrate.n+1.sql if possible. If the reverse operation is lossy, it should at the minimum bring the device to a state where it can be updated. + +The 'version' table has to be updated as well, to contain n. + +4. If the migration manipulates existing data in a non-trivial way (anything that's not simply a new table creation, deletion, renaming), it is strongly advised to write an explicit migration test with realistic data in link:{aktualizr-github-url}/src/libaktualizr/storage/sqlstorage_test.cc[], similar to `DbMigration18to19`. diff --git a/docs/ota-client-guide/modules/ROOT/pages/secure-software-updates-test.adoc b/docs/ota-client-guide/modules/ROOT/pages/secure-software-updates-test.adoc new file mode 100644 index 0000000000..0ac562a5af --- /dev/null +++ b/docs/ota-client-guide/modules/ROOT/pages/secure-software-updates-test.adoc @@ -0,0 +1,11 @@ += Test software update security + +//MC: This is a copy of the topic "secure-software-updates.adoc" but intended for the "test" use case. Need to use more includes to reduce redundancy. + +To secure your software updates, OTA Connect ensures that all software files have accompanying metadata that is signed according to the Uptane framework. + +When evaluating OTA Connect you don't have to worry about signing this metadata yourself. The OTA Connect server automatically signs the metadata after you upload software. + +However, for this process to work, the OTA Connect server must host the xref:pki.adoc[private keys] that are used to sign the metadata. This is a security risk -- if an attacker is able to infiltrate the OTA Connect server, they can use these private keys to sign metadata for malicious software and send it to your devices. + +To prevent an event like this from happening, you should take these private keys offline and sign the metadata in your development environment. Then you can push the signed metadata back to the server. To do this, you use the `garage-sign` command which is part of our xref:install-garage-sign-deploy.adoc[`garage-deploy`] tool. diff --git a/docs/ota-client-guide/modules/ROOT/pages/secure-software-updates.adoc b/docs/ota-client-guide/modules/ROOT/pages/secure-software-updates.adoc new file mode 100644 index 0000000000..b81b769f0c --- /dev/null +++ b/docs/ota-client-guide/modules/ROOT/pages/secure-software-updates.adoc @@ -0,0 +1,11 @@ += Secure your software updates + +//MC: This is a copy of the topic "secure-software-updates-test.adoc" but intended for the "prod" use case. Need to use more includes to reduce redundancy. + +To secure your software updates, OTA Connect ensures that all software files have accompanying metadata that is signed according to the Uptane framework. + +When evaluating OTA Connect you don't have to worry about signing this metadata yourself. The OTA Connect server automatically signs the metadata after you upload software. + +However, for this process to work, the OTA Connect server must host the xref:pki.adoc[private keys] that are used to sign the metadata. This is a security risk -- if an attacker is able to infiltrate the OTA Connect server, they can use these private keys to sign metadata for malicious software and send it to your devices. + +To prevent an event like this from happening, you should take these private keys offline and sign the metadata in your development environment. Then you can push the signed metadata back to the server. To do this, you use the `garage-sign` command which is part of our xref:install-garage-sign-deploy.adoc[`garage-deploy`] tool. \ No newline at end of file diff --git a/docs/ota-client-guide/modules/ROOT/pages/security.adoc b/docs/ota-client-guide/modules/ROOT/pages/security.adoc new file mode 100644 index 0000000000..b331f7e584 --- /dev/null +++ b/docs/ota-client-guide/modules/ROOT/pages/security.adoc @@ -0,0 +1,39 @@ += Security and Identity + +OTA Connect provides you with two levels of security which have different tradeoffs. You can work with the *default* security measures which are much less work to manage but expose you to certain risks. Or, you can follow our recommended *production-level* security measures which are more work to set up but provide more robust security. + +In both cases, communication between the devices and the OTA Connect is always secured via mutual TLS (X.509 certificates) for authorization, authentication, and encryption. + +The following sections describe the different security levels for device provisioning and software updates: + += Device provisioning + +When provisioning devices, you need to consider how to prevent unauthorized devices from provisioning. You also need to prevent your devices from being redirected to a malicious server. + +This is usually done with a PKI (Public Key Infrastructure). Devices are automatically issued with device certificates during production. The device certificates are validated by the server which compares them with the root certificate for the entire device fleet. + +* **Default security measure** ++ +By default, **the OTA Connect server acts as its own PKI** and manages device keys and certificates for you. ++ +All you have to do is download an initial provisioning key and bake it into the disk image that you'll flash to your devices. OTA Connect then takes care of issuing and validating device certificates. We call this type of provisioning xref:client-provisioning-methods.adoc[*shared-credential provisioning*] because you're using one provisioning key for your whole device fleet. ++ +{zwsp} +* **Production-level security measure** ++ +In short, you need to use your own PKI to allocate device certificates. You shouldn't leave this responsibility to the OTA Connect server. What makes things easy also makes things risky. If a malicious actor compromised your OTA Connect account, you would be in trouble because they could get your **private key** for signing device certificates. They could then provision whatever devices they wanted. + += Software updates + +Software updates are protected according to the xref:uptane.adoc[Uptane Framework] specifications. Uptane is one of the first comprehensive automotive OTA updating security frameworks available. This framework requires several metadata files to be signed by two separate keys. This metadata is also validated on the server. + +* **Default security measure** ++ +By default, the OTA Connect server acts as a PKI for these keys too. When you create an OTA Connect account, the keys are generated and stored on the server. When you upload software and create updates, the server uses these keys to automatically sign the metadata. You don't have to think about signing software metadata at all. ++ +{zwsp} +* **Production-level security measure** ++ +As with device provisioning, you should use your own PKI to sign metadata for your software files and updates. Take the two xref:pki.adoc[signing keys] offline and sign the metadata locally. ++ +Again, if a malicious actor compromised your OTA Connect account, they could get your **private keys** for signing software metadata. They could then upload infected software and push them out to your devices. This type of attack is infinitely more difficult if you keep your keys offline in a safe place. diff --git a/docs/ota-client-guide/modules/ROOT/pages/simulate-device-basic.adoc b/docs/ota-client-guide/modules/ROOT/pages/simulate-device-basic.adoc new file mode 100644 index 0000000000..bcdf5d575b --- /dev/null +++ b/docs/ota-client-guide/modules/ROOT/pages/simulate-device-basic.adoc @@ -0,0 +1 @@ +include::dev@getstarted:ROOT:page$simulate-device-workstation.adoc[] diff --git a/docs/ota-client-guide/modules/ROOT/pages/simulate-device-cred-provtest.adoc b/docs/ota-client-guide/modules/ROOT/pages/simulate-device-cred-provtest.adoc new file mode 100644 index 0000000000..a103adf8e8 --- /dev/null +++ b/docs/ota-client-guide/modules/ROOT/pages/simulate-device-cred-provtest.adoc @@ -0,0 +1,32 @@ += Simulate the provisioning process with device credentials + +To provision with device credentials in production, you need to have a root CA. If you want to test this provisioning method without generating a root CA, you can simulate it with the `aktualizr-cert-provider` command. + +To use the `aktualizr-cert-provider` command, you must still generate a xref:getstarted::generating-provisioning-credentials.adoc[provisioning key] that your devices can share. But with this method, you use the provisioning key to sign the device certificate. + +In production, you would use the root CA to sign the device certificate, but this method is useful for testing. + +To simulate provisioning with a device certificate, follow these steps: :: +1. Add the following lines to your local.conf: ++ +---- +SOTA_CLIENT_PROV = "aktualizr-ca-device-prov" +SOTA_DEPLOY_CREDENTIALS = "0" +---- + +1. Build a standard image using the bitbake command. +1. Boot the image. ++ +The device should not be able to provision with a provisioning key. To verify this, log in to the {product-name} server and make sure that the device does not appear in the list of devices. +1. Load the device credentials on to the device with `aktualizr-cert-provider` command: ++ +---- +aktualizr-cert-provider -c credentials.zip -t -d /var/sota/import -r -u +---- ++ +You can find the link:https://github.com/advancedtelematic/aktualizr/tree/master/src/cert_provider[`aktualizr-cert-provider` source] in the aktualizr repo. You can also find a compiled binary in the host work directory of bitbake. ++ +The path should resemble the following example: ++ +`tmp/work/x86_64-linux/aktualizr-native/1.0+gitAUTOINC+/build/src/cert_provider/aktualizr-cert-provider`. + diff --git a/docs/ota-client-guide/modules/ROOT/pages/software-management.adoc b/docs/ota-client-guide/modules/ROOT/pages/software-management.adoc new file mode 100644 index 0000000000..ae8e57a83e --- /dev/null +++ b/docs/ota-client-guide/modules/ROOT/pages/software-management.adoc @@ -0,0 +1,48 @@ += Software management + +When you develop software updates for OTA deployment, it's important to understand the different ways in which you can get software into OTA Connect. + +You can upload any file format you want to OTA Connect, but generally OTA Connect is designed to work with *disk images*. + +However, you might instead be accustomed to managing *software packages* with package managers. We don't recommend this method, but there's nothing to stop you delivering software packages with OTA Connect as well. + +Here's a summary of how each method works: + +== Uploading software within disk images + +A disk image is a snapshot of the entire filesystem on an ECU or other microcontroller that you can flash to another controller of the same type. + +In a typical development process, you might first simulate a microcontroller on you computer, set up the entire filesystem, create a disk image and flashe the image to a real microcontroller. + +For example, in our "Get Started" guide, we explain how to build a disk image for Raspberry Pi on a development computer then flash the image to an actual Raspberry Pi. + +*So how do you update individual pieces of software?* + +Well, suppose that you wanted to update the Bluetooth driver on your IVI from version 1 to 2. In this scenario, we'll assume that your IVI is already running a disk image that includes aktualizr -- the OTA Connect Client. + +* First, you would prepare an updated disk image of the filesystem that runs on your IVI. + +** This disk image is configured to include version 2 of your Bluetooth driver package as well as all the other software that hasn't changed. +** This "other" software includes aktualizr or another client that uses libaktualizr to regularly checks for updates. + +* You would use the OTA Connect build tools to build the final disk image. + +** The OTA Connect build process includes a step where the new disk image is automatically uploaded to the OTA Connect server. +** When you log into the OTA Connect Portal, you'll see the new disk image in your software repository. +** The disk image should ideally have some notes to explain that it contains the new version 2 Bluetooth driver. You can add more descriptive information in the OTA Connect Portal and select the disk image during the campaign creation process. + +In summary, software is added to disk images which get uploaded during the build process. + +== Uploading software packages + +If you've worked with Linux-based operating systems, you might expect software updates to come in the format of installable packages that have extensions like `.deb`, `.rpm` or in the case of Android, `.apk`. You can also upload these kinds of packages to OTA Connect. + +By default, the OTA Connect Client is designed to install disk images rather than packages. Your developers have to configure the OTA Connect Client to process and install packages instead. + +// ask dev how this works. + +Another problem with this approach is that it's quite easy to corrupt the filesystem if the installation process is interrupted in any way. For example if the microcontroller loses power or is rebooted, a human being must intervene to fix the filesystem. + +This kind of problem might be fine on the desktop or on a server where there's a reasonable expectation that a person could intervene, but there's no easy way to intervene for embedded devices. + +If you don't mind the risks and extra work, you can xref:dev@ota-web::upload-software-ui.adoc[upload software packages in the OTA Connect portal]. diff --git a/docs/ota-client-guide/modules/ROOT/pages/supported-boards.adoc b/docs/ota-client-guide/modules/ROOT/pages/supported-boards.adoc new file mode 100644 index 0000000000..82e32b6cac --- /dev/null +++ b/docs/ota-client-guide/modules/ROOT/pages/supported-boards.adoc @@ -0,0 +1,29 @@ +== Supported boards + +// MC: Copied over from meta-updater on 29.07.2019 + +Currently supported platforms are: + +* https://github.com/advancedtelematic/meta-updater-raspberrypi[Raspberry Pi 2 and 3] +* https://github.com/advancedtelematic/meta-updater-minnowboard[Intel Minnowboard] +* https://github.com/advancedtelematic/meta-updater-qemux86-64[Native QEMU emulation] +* Renesas R-Car H3 and M3 +* https://github.com/advancedtelematic/meta-updater-ti/[TI BeagleBone Black] (rocko only, using TI SDK 05.03) +* https://github.com/advancedtelematic/meta-updater-ti/[TI AM65x industrial development kit] (rocko only, using TI SDK 05.03) + +Additionally, there is community support for https://github.com/ricardosalveti/meta-updater-riscv[RISC-V] boards, in particular the Freedom U540. + +We also historically supported the https://github.com/advancedtelematic/meta-updater-porter[Renesas Porter] board. + +=== Adding support for your board + +If your board isn't supported yet, you can add board integration code yourself. The main purpose of this code is to provide a bootloader that will be able to use https://ostree.readthedocs.io/en/latest/manual/atomic-upgrades/[OSTree's boot directory]. In the meta-updater integration layers we have written so far, the basic steps are: + +1. Make the board boot into http://www.denx.de/wiki/U-Boot[U-Boot] +2. Make U-boot import variables from /boot/loader/uEnv.txt and load the kernel with initramfs and kernel command-line arguments according to what is set in this file. + +You may take a look into https://github.com/advancedtelematic/meta-updater-minnowboard[Minnowboard] or https://github.com/advancedtelematic/meta-updater-raspberrypi[Raspberry Pi] integration layers for examples. + +Although we have focused on U-Boot and GRUB so far, other bootloaders can be configured to work with OSTree as well. + +Your images will also need network connectivity to be able to reach an actual OTA backend. Our 'poky-sota' distribution does not mandate or install a default network manager but our supported platforms use the `virtual/network-configuration` recipe, which can be used as a starting example. \ No newline at end of file diff --git a/docs/ota-client-guide/modules/ROOT/pages/supporting-technologies.adoc b/docs/ota-client-guide/modules/ROOT/pages/supporting-technologies.adoc new file mode 100644 index 0000000000..6b7be2f92b --- /dev/null +++ b/docs/ota-client-guide/modules/ROOT/pages/supporting-technologies.adoc @@ -0,0 +1,5 @@ += Supporting Technologies + +If you've started working on an embedded software project, you've probably reached the point where you looked around for an update system, and found out that there isn't a lot of great tooling out there. Our experience has been that people tend to implement software updates on a case-by-case basis, leading to solutions that are specific to the target platform, proprietary, brittle, or insecure--or sometimes all of the above. {product-name} provides an open source solution that you can plug-and-play into your build process. + +In this section, we look at the parts of the system, and how they fit together. \ No newline at end of file diff --git a/docs/ota-client-guide/modules/ROOT/pages/troubleshooting.adoc b/docs/ota-client-guide/modules/ROOT/pages/troubleshooting.adoc new file mode 100644 index 0000000000..2227da0fcf --- /dev/null +++ b/docs/ota-client-guide/modules/ROOT/pages/troubleshooting.adoc @@ -0,0 +1,87 @@ += Troubleshooting +:page-layout: page +:page-categories: [tips] +:page-date: 2017-06-13 10:51:53 +:page-order: 99 +:icons: font + +== Build problems + +=== Bitbake fails with a strange Java error + +On Ubuntu 18.04 and some other distros, you may get an error with a Java stack trace that includes the following line: + +---- +java.security.InvalidAlgorithmParameterException: the trustAnchors parameter must be non-empty +---- + +This issue is due a change in the packaging for OpenJDK 9+ security certificates. It has a simple workaround, however. + +Run the following commands: + +---- +sudo rm /etc/ssl/certs/java/cacerts +sudo update-ca-certificates --fresh +---- + +Try the bitbake build again. +If the build still doesn't work, run the following commands: + +---- +sudo /usr/bin/printf '\xfe\xed\xfe\xed\x00\x00\x00\x02\x00\x00\x00\x00\xe2\x68\x6e\x45\xfb\x43\xdf\xa4\xd9\x92\xdd\x41\xce\xb6\xb2\x1c\x63\x30\xd7\x92' > /etc/ssl/certs/java/cacerts +sudo /var/lib/dpkg/info/ca-certificates-java.postinst configure +---- + +More detailed info about the cause of the bug, as well as links to the bug in various distros' issue trackers, can be found link:https://github.com/mikaelhg/broken-docker-jdk9-cacerts/blob/master/README.md[on github]. + +=== GnuTLS build fails with older kernels + +GnuTLS currently requires a kernel >= 3.17 to build. If you're using an older kernel, you'll see an error like this: + +---- +../../../gnutls-3.5.3/lib/nettle/rnd-linux.c: In function 'have_getrandom': +../../../gnutls-3.5.3/lib/nettle/rnd-linux.c:59:42: error: 'SYS_getrandom' undeclared (first use in this function) + # define getrandom(dst,s,flags) syscall(SYS_getrandom, (void*)dst, (size_t)s, (unsigned int)flags) +---- + +This is an upstream problem; until it's fixed in upstream poky, you can link:../files/gnutls-fix.patch[download this patch] to your `poky` directory and apply it to fix the issue. + +=== Build didn't work after switching architectures + +You might have tried something like this: + +---- +source meta-updater/scripts/envsetup.sh raspberrypi3 + +{ build an image ... } + +cd .. +source meta-updater/scripts/envsetup.sh qemux86-64 + +---- + +*This doesn't work.* The setup script sets up certain environment variables for bitbake, but it also generates your `local.conf` and `bblayers.conf` files. If it finds existing files, however, it leaves them alone, and only sets up the environment. If you want to switch architectures, you also need to change your config files. You can do that by deleting/renaming your old ones and re-generating the config files. Don't forget to add your credentials and other customizations to the re-generated files! + +Depending on your use case, however, it often makes more sense to just keep separate project directories for your separate architectures, and share the state cache and downloads directories between them. + +== Runtime problems + +=== File ownership incorrect after an update (static UID to name mapping) + +Yocto assigns numeric user IDs (UIDs) to Linux login names at system build time. This dynamic assignment does not always work correctly for an embedded system that is receiving software updates, because the numeric UID of a service can change between builds, but any files the service created on the file system will remain owned by the original UID. + +The solution is to manually set the contents of `/etc/passwd` and `/etc/group` for your system, so that the UIDs remain stable between builds. + +This is required if you have a service that does all of the following: + +* Creates files +* Runs as an account that is not one of the 'standard' accounts (`root`, `floppy`, `man`, `tape`, etc) +* The recipe for the service creates the user (using `useradd`) + +In this case, you should set `useradd`. The link:https://www.yoctoproject.org/docs/current/mega-manual/mega-manual.html#ref-classes-useradd[useradd] section of the Yocto Mega Manual describes this process in more detail. + + +.Don't see your problem here? +**** +We'd love to hear from you about how we can improve the docs and make {product-name} better. Contact link:mailto:otaconnect.support@here.com[otaconnect.support@here.com] and we'll do our best to help. +**** diff --git a/docs/ota-client-guide/modules/ROOT/pages/update-single-device.adoc b/docs/ota-client-guide/modules/ROOT/pages/update-single-device.adoc new file mode 100644 index 0000000000..52f87d416b --- /dev/null +++ b/docs/ota-client-guide/modules/ROOT/pages/update-single-device.adoc @@ -0,0 +1,14 @@ += Update a device with the sample software + +Once you've uploaded a few different software versions, you can try to push that software to a device that doesn't yet have the version installed. + +If you have more than one Raspberry Pi lying around, you could use the disk image that you created in the xref:build-raspberry.adoc[Raspberry Pi build instructions]. Flash that image to your second Raspberry Pi and boot it up. Otherwise, you could xref:build-quemu.adoc#_run_the_built_image_with_qemu[start another QEMU instance] based on the same disk image but with a different mac address. + +After your second device boots, it should automatically provision with OTA Connect. + +* Log in to the xref:https://connect.ota.here.com[OTA Connect Portal] and check that second devices shows up in the last of mostly recently provision devices. ++ +This list appears on the Dashboard that you see after you log in. If you see your second device, you're ready to send it an update. + +include::dev@ota-web::partial$devices.adoc[tags=single-device-install-steps] + diff --git a/docs/ota-client-guide/modules/ROOT/pages/update-your-client-configuration.adoc b/docs/ota-client-guide/modules/ROOT/pages/update-your-client-configuration.adoc new file mode 100644 index 0000000000..85fbea7f32 --- /dev/null +++ b/docs/ota-client-guide/modules/ROOT/pages/update-your-client-configuration.adoc @@ -0,0 +1,36 @@ += Recommended client configurations + +Before you start developing or deploying to production, you should check that your configuration file has appropriate settings for your use case. + +For more details about the full client configuration settings, see the xref:aktualizr-config-options.adoc[client configuration reference]. + +== Recommended settings for development + +[cols="1,1,1a",options="header,footer"] +|==================== +|Name | Default | Description +|`polling_sec` | `10` | +Interval between polls (in seconds). + +The default polling internal designed to make it convenient for you test and develop OTA update functions. +|`force_install_completion` | `true` | +Forces installation completion. Causes a system reboot in case of an ostree package manager. Emulates a reboot in case of a fake package manager. + +You'll want to set this to `true` when developing because it's more convenient. + +|==================== + +== Recommended settings for production + +[cols="1,1,1a",options="header,footer"] +|==================== +|Name | Default | Description +|`polling_sec` | `86400` | When moving to production you'll want to have a much longer interval. +In fact, for production, we don't support intervals less the 1 hour (3,600 seconds). Longer internals help you to reduce the internet bandwidth and power consumption for your devices. + +We recommend an internal between 1 and 7 days (86,400 to 604,800 seconds). +|`force_install_completion` | `false` | +If you followed our recommendation to enable automatic rebooting for development, you should turn it off again for production. +|==================== + + diff --git a/docs/ota-client-guide/modules/ROOT/pages/uptane-generator.adoc b/docs/ota-client-guide/modules/ROOT/pages/uptane-generator.adoc new file mode 100644 index 0000000000..01d1969435 --- /dev/null +++ b/docs/ota-client-guide/modules/ROOT/pages/uptane-generator.adoc @@ -0,0 +1,117 @@ += Aktualizr repo + +The uptane-generator directory contains a basic implementation of an Uptane server. It is comprised of three tools: + +. link:../src/uptane_generator/run/create_repo.sh[`create_repo.sh`] is a script to generate a new Uptane metadata repository, an OSTree repository, and all associated credentials and configuration. +. link:../src/uptane_generator/run/serve_repo.py[`serve_repo.py`] is a script for running a minimalistic Uptane server. +. link:../src/uptane_generator/main.cc[`uptane-generator`] is a low-level tool to generate and control an Uptane repository. It can be used to manipulate the repo created with `create_repo.sh`, or it can be used entirely independently. + +== create_repo.sh + +`create_repo.sh` generates the whole Uptane repo together with client and server certificates and OSTree repo that can be used both by meta-updater and by the device. `create_repo.sh` uses `uptane-generator`, so make sure it's in `PATH`. + +=== Usage + +`create_repo.sh ` + +Make sure that the repository path doesn't already exist and the machine where `serve_repo.py` will be running is accessible from the device specified by ``. + +=== Integration with bitbake + +`create_repo.sh` can work with bitbake running on the same machine. Copy `site.conf` from the generated directory to your `build/conf` or append it to your existing `site.conf`. `bitbake` will then commit the built rootfs to the generated OSTree repository and provision devices to automatically connect to `serve_repo.py`. + +== serve_repo.py + +`serve_repo.py` serves Uptane metadata and OSTree objects to the devices. + +=== Usage + +`serve_repo.py ` + +== uptane-generator + +`uptane-generator` can generate and control Uptane metadata. It is used by `create_repo.sh` and many aktualizr tests, but can also be used manually. See `uptane-generator --help` for basic usage details or the examples below for greater detail. + +=== Basic usage example + +1. Generate a new Uptane repository: ++ +``` +uptane-generator --path --command generate +``` + +2. Add a target to the images metadata: ++ +``` +uptane-generator --path --command image --filename --targetname --hwid +``` ++ +This step can be repeated as many times as necessary for each target. `--targetname` is optional. If it is not provided, it is assumed to be the same as the image name provided to `--filename`. + +3. Prepare director targets metadata for a given device: ++ +``` +uptane-generator --path --command addtarget --targetname --hwid --serial +``` ++ +This step can be repeated as many times as necessary for each target and ECU. + +4. Sign the director targets metadata and schedule the prepared update: ++ +``` +uptane-generator --path --command signtargets +``` + +=== Advanced usage examples + +==== Delegations + +`uptane-generator` supports first-order delegations. All delegations are therefore marked as terminating. To add a delegated role, use this: +``` +uptane-generator --path --command adddelegation --dname --dpattern +``` + +To add a target to a delegated role, add the `--dname` parameter to the `image` command. The targetname must match the pattern supplied in `--dpattern` to the `adddelegation` command. +``` +uptane-generator --path --command image --filename --targetname --hwid --dname +``` + +==== Generating metadata without a real file + +To add a target to the images metadata without providing an actual file, you can supply alternative parameters to the `image` command: +``` +uptane-generator --path --command image --targetname --targetsha256 --targetsha512 --targetlength --hwid +``` + +==== Advanced director metadata control + +To reset the director targets metadata or to prepare empty targets metadata, use the `emptytargets` command. If you then sign this metadata with `signtargets`, it will schedule an empty update. +``` +uptane-generator --path --command emptytargets +``` + +To populate the director targets metadata with the currently signed metadata (with the previous signature removed), use the `oldtargets` command. You can then add more targets with `addtarget` and re-sign with `signtargets`. +``` +uptane-generator --path --command oldtargets +``` + +==== Sign arbitrary metadata + +To sign arbitrary metadata with one of the Uptane keys, use the `sign` command: +``` +uptane-generator --path --command sign --repotype --keyname < +``` + +==== Add custom URLs + +To add a custom URL to an image in the Targets metadata of the Images repository: +``` +uptane-generator --path --command image --filename --targetname --hwid --url +``` + +To add a custom URL to an image in the Targets metadata of the Director: +``` +uptane-generator --path --command addtarget --targetname --hwid --serial --url +``` + +If a custom URL is set in both sets of metadata, libaktualizr will use the URL from the Director. diff --git a/docs/ota-client-guide/modules/ROOT/pages/uptane.adoc b/docs/ota-client-guide/modules/ROOT/pages/uptane.adoc new file mode 100644 index 0000000000..a8c76c2bc9 --- /dev/null +++ b/docs/ota-client-guide/modules/ROOT/pages/uptane.adoc @@ -0,0 +1,59 @@ += OTA Connect security: The Uptane framework +:page-layout: page +:page-categories: [concepts] +:page-date: 2018-01-10 13:55:45 +:page-order: 80 +:icons: font +:toc: macro + + +HERE OTA Connect aligns with the https://uptane.github.io[Uptane] security framework. Uptane was developed in response to the clear need for a comprehensive security model for automotive updates, and is the first security system that provides serious compromise resilience in that spacefootnote:["Uptane is the first compromise-resilient software update security system for the automotive industry.", https://uptane.github.io]. + +== Uptane structure + +The most important concept in Uptane is that there are two sets of metadata, from separate sources, that must agree with each other and have valid cryptographic signatures. + +// The {zwsp} in the following line is a zero-width space, and it's there as +// a workaround to make the footnote behave correctly. + +The first comes from the *image Repository*{zwsp}footnote:[This image repository is based on https://theupdateframework.com/[TUF (The Update Framework)].]. The image repository contains metadata for update packages that are _valid_ install targets, and its metadata is signed by a chain of trust with offline keys. + +The second comes from the *Director*, which controls what updates (selected from the valid install targets) should actually be installed on devices. The Director uses online keys, and is part of the OTA Connect service. + +== Uptane metadata + +The Uptane specification defines several different types of metadata, but the two main files that you need to manage are as follows: + +* `root.json`: ++ +This file contains information about all the roles that can sign software metadata. ++ +To see an example of this metadata, open the link:https://raw.githubusercontent.com/theupdateframework/tuf/develop/tests/repository_data/repository/metadata/root.json[sample `root.json` file] from the TUF (The Update Framework) website. + +* `targets.json`: ++ +The instance of `targets.json` in your image repository contains information about all the valid software files. ++ +As mentioned previously, there are two versions of each metadata file, one in your image repository and one in the Director service. ++ +The _other_ instance of `targets.json` is in the Director service. It only contains information about the software files that are included in a specific update. The entries in this file are cross-referenced with the corresponding entries in `targets.json` for your image repository. ++ +Basically this comparison is answering the question: ++ +"__Can I be sure that the files in this update really come from my offical software repository?__". ++ +To see an example of this metadata, open the link:https://raw.githubusercontent.com/theupdateframework/tuf/develop/tests/repository_data/repository/metadata/targets.json[sample `targets.json` file] from the TUF (The Update Framework) website. + +== Signing updates of system images + +OTA Connect manages the Director for you. When you create an update campaign, we update the Director behind the scenes, signing the metadata for each image-device tuple in the campaign. + +The keys for the metadata in your image repository should be managed on your side; we provide tooling to help you do just that. When you build a new device, bitbake automatically signs the image for you, using keys that you specify in the build's `local.conf`{zwsp}footnote:[These keys are packed inside the zip file specified by the `SOTA_PACKED_CREDENTIALS` line.]. Your initial key is created by HERE OTA Connect, delivered to you inside your `credentials.zip` file, and kept online for convenience and bootstrapping; for any production use you should xref:rotating-signing-keys.adoc[manage the keys for software metadata] yourself and store them securely offlinefootnote:[Proceed with caution! Once you take the key offline, HERE Technologies cannot recover it.]. + +== Primary and secondary ECUs + +In the Uptane framework, an ECU is categorized as either a primary or a secondary ECU. In most cases, a vehicle has one primary ECU and several secondary ECUs. The primary ECU is responsible for downloading and distributing software to the secondary ECUs. In many cases, the Telematics Control Unit (TCU) serves the role of primary ECU. A primary ECU also verifies and distributes the Uptane-compliant metadata associated with each piece of software. + +Secondary ECUs, such as the Transmission or Body control modules, receive the software and should also perform some form of metadata verification. If the ECU has sufficient processing capabilities, it should perform a full verification of the Uptane-compliant metadata, otherwise it should at least perform a partial verification. + +To get an overview of the ECUs detected in a device, open the OTA Connect web application and navigate to the device details for the device. This view shows the ECUs grouped according to whether they are primary and secondary ECUs. diff --git a/docs/ota-client-guide/modules/ROOT/pages/use-your-own-deviceid.adoc b/docs/ota-client-guide/modules/ROOT/pages/use-your-own-deviceid.adoc new file mode 100644 index 0000000000..3a6e50e481 --- /dev/null +++ b/docs/ota-client-guide/modules/ROOT/pages/use-your-own-deviceid.adoc @@ -0,0 +1,31 @@ += Configure your own device IDs + +In OTA Connect, a device has two types of identifier: an internal device UUID, and a standard device ID. + +// MC: use xref:otaconnect-identifiers.adoc[identifier]: when topic is finished +By default, OTA Connect generates a random device ID for you, but you can override this behavior. + +The standard way to specify device identity is in the device certificate -- specifically, in the Subject Distinguished Name (DN) field. + +This method requires that you use device-credential provisioning which tells OTA Connect to use your device certificates for authentication. This method is a little more complicated than the "shared-credential" provisioning method that you might have used in the "Get Started" guide. + +However you can try our test procedures to specify your own Device IDs. Earlier in this guide, we showed you how to xref:generate-devicecert.adoc[generate and sign a device certificate] using a self-signed root certificate. + +* You can define your own device ID in the device certificate, by changing step 1 of that procedure + +** Replace the existing sample command: ++ +`export device_id=${DEVICE_ID:-${DEVICE_UUID}}` ++ +Update the command with your device ID instead: ++ +`export device_id=` ++ +For example: +`export device_id=1HTHCATR81H391382` + +** You can then continue the test procedure to provision your device. + +* If you already have your own procedure for generating device certificates, then you're probably already using your own device IDs to bind each certificate to the device. + +In any case, OTA Connect uses the device ID that you've defined in your device certificates instead of automatically generating one. \ No newline at end of file diff --git a/docs/ota-client-guide/modules/ROOT/pages/useful-bitbake-commands.adoc b/docs/ota-client-guide/modules/ROOT/pages/useful-bitbake-commands.adoc new file mode 100644 index 0000000000..6c5f9c3dea --- /dev/null +++ b/docs/ota-client-guide/modules/ROOT/pages/useful-bitbake-commands.adoc @@ -0,0 +1,56 @@ += Useful Bitbake commands +:page-layout: page +:page-categories: [tips] +:page-date: 2017-06-06 15:23:05 +:page-order: 2 +:icons: font + +You're going to run into Yocto build problems eventually--that's a given. We provide here a guide to a few bitbake commands we find particularly useful. + +=== Clean the build environment + +Yocto does a lot of caching and tries to be as smart about it as possible. But if you're running into build problems for a particular package, a good first start is + + bitbake -c cleanall [package] + +This will remove everything in the work directory, everything in the state cache, and all previously downloaded source files. + +=== View the actual build environment bitbake will execute + + bitbake -e [package] > env.log + +This is the bazooka of bitbake troubleshooting. It will output the entire build environment that bitbake uses for that package or image. This output will be tens of thousands of lines long, but can be grepped for what you need. + +=== Launch the bitbake devshell for a package + + bitbake -c devshell [package] + +The devshell is the scalpel of bitbake troubleshooting. This command will open a new terminal in the package's build directory with bitbake's environment set up, after the source files have been fetched and all compile-time dependencies have been built, but before any configure/compile steps for the package have been taken. From here, you can troubleshoot specific problems with your build. + +=== Launch the dependency explorer for a package + + bitbake [package] -g -u depexp + +A GUI tool for exploring package dependencies. + +=== Show the layers currently in your build + + bitbake-layers show-layers + +Outputs a list of the layers currently in use, and their priorities. If a package exists in two or more layers, it will be build from the layer with higher priority. + +=== Show all available recipes + + bitbake-layers show-recipes + +=== List all packages that will be built in an image/package + + bitbake -g [package] && cat pn-depends.dot | grep -v -e '-native' | \ + grep -v digraph | grep -v -e '-image' | awk '{print $1}' | sort | uniq + +A concise text dump of all of the dependencies of a package. Includes both runtime and compile-time dependencies. + +=== Save verbose build log + + bitbake -v [package] 2>&1 | tee build.log + diff --git a/docs/ota-client-guide/modules/ROOT/pages/workflow-overview.adoc b/docs/ota-client-guide/modules/ROOT/pages/workflow-overview.adoc new file mode 100644 index 0000000000..fc421a19f7 --- /dev/null +++ b/docs/ota-client-guide/modules/ROOT/pages/workflow-overview.adoc @@ -0,0 +1,54 @@ += Basic Workflow +:page-layout: page +:page-categories: [concepts] +:page-date: 2017-01-16 18:12:09 +:page-order: 1 +:icons: font + +Although it's easy to get started with our quickstart guides and Yocto layers, there are quite a lot of moving pieces under the hood that make HERE OTA Connect work. Here, we're going to walk through what's actually happening when you: + +* Provision a new device +* Build a Yocto image that can do atomic full-filesystem updates with rollback +* Build a new version of the image and push the update to OTA Connect +* Send it to a client device for installation + +== Provisioning a new device + +OTA Connect uses mutual TLS authentication with X.509 certificates to secure communication with devices. This, of course, requires the devices to be provisioned with their unique certificates, and registered with the server. We make this process easy and automatic with *provisioning keys*. + +When you build a filesystem image, you include a provisioning key. When a device boots, it checks whether it has credentials already. If not, it attempts to auto-provision. It presents its provisioning key and a unique identifierfootnote:[This could be something like a VIN, serial number, or device MAC address. It needs to be something that is unique to a particular device, doesn't change, and is programmatically available. We use the MAC address by default.] to the OTA Connect provisioning servicefootnote:[Each user has a uniquely generated provisioning URL; it's included in the provisioning key bundle.]. If the provisioning key is valid and the identifier is unique, new credentials are issued to the device. It then appears in the user's OTA Connect account, with its unique identifier as the name. + +== Building the image + +The way OTA Connect does full-filesystem updates is unique, and offers xref:ostree-and-treehub.adoc#_comparing_full_filesystem_update_strategies[significant benefits over other systems]. OTA Connect makes use of link:http://ostree.readthedocs.io/en/latest/[libOSTree] to store the whole filesystem in a git-like repository (content-addressed object store); file objects in the repository are then hardlinked into their place in the filesystem at boot time by a specially configured boot loader. We've done integration work to use OSTree with link:http://www.denx.de/wiki/U-Boot/WebHome[u-boot] and link:https://www.gnu.org/software/grub/[GRUB], but in principle other boot loaders can also be integrated. + +When you do a Yocto build integrating our open-source link:https://github.com/advancedtelematic/meta-updater[meta-updater] layer, you get two different artifacts: + +* a *disk image* that includes the bootloader partition integrated with OSTree and the rootfs partition, and +* a local *OSTree repository* storing all of the filesystem revisions you've built. + +(There are actually some other intermediate images generated as well, but these two are the ones we care about.) + +The disk image is what you need to flash onto your device initially; the OSTree repository is what we use to update the images. + +== Pushing images to OTA Connect + +As mentioned above, OSTree repositories work quite a bit like git repositories; that includes the ability to have remote repositories. OTA Connect includes a server for OSTree repositories called TreeHub, and every time you build a new image, that image gets committed to your local OSTree repo, and then pushed to the TreeHub remote. + +This is all done with the meta-updater Yocto layer. Building the rootfs image and turning it into an OSTree commit is a publishing step, and there is a tool included in the layer called garage-push that authenticates with TreeHub and pushes the commit up to TreeHub. + +== Installing updates on devices + +In OTA Connect, we generally assume that updates will be OSTree images, but in fact OTA Connect can be used to send all kinds of other updates.footnote:[For more information on using OTA Connect for other types of update, please contact us at link:mailto:otaconnect.support@here.com[otaconnect.support@here.com].] But for now, let's look at the default OSTree update process. + +.OTA Connect device update flow +**** +. The client polls OTA Connect servers periodically to check if there are any new updates. +. If there are, the client requests to download the update, which consists of a metadata file pointing to a particular OSTree commit. (For other types of update, the download might be something else, like application binaries, installation packages containing binaries and install scripts, or data packs.) +. The update is cryptographically checked for validity following the https://uptane.github.io[Uptane specification]. +. The client checks if the reference is available locally; if it's not, the commit is downloaded from TreeHub, only actually downloading objects not already present in the repo. +. Each object's SHA is checked for correctness. +. Once all objects are downloaded and verified, a flag is set telling OSTree to boot into the new filesystem the next time it boots. +**** + + diff --git a/docs/ota-client-guide/modules/ROOT/pages/yocto.adoc b/docs/ota-client-guide/modules/ROOT/pages/yocto.adoc new file mode 100644 index 0000000000..fd3214914b --- /dev/null +++ b/docs/ota-client-guide/modules/ROOT/pages/yocto.adoc @@ -0,0 +1,8 @@ +== Yocto + +The link:https://www.yoctoproject.org/[Yocto Project] is an open source collaborative project that provides standardized high-quality infrastructure, tools, and methodology to help decrease the complexity and increase the portability of Linux implementations in the embedded industry. It enables its users to build custom operating systems using specific recipes for embedded devices. Most commercial embedded Linux distros already use and/or support Yocto, including link:http://www.windriver.com/announces/wind-river-linux-8/[Wind River] and link:http://www.enea.com/solutions/Enea-Linux/[Enea]. It's backed by major hardware vendors like Intel, AMD, Freescale, Mentor, Texas Instruments, and many others. If you need a highly performant customized Linux for your embedded device, whether it's IoT, automotive, or other kinds of mobility devices, the Yocto project is probably what you're using. + +HERE Technologies has created a https://github.com/advancedtelematic/meta-updater/[meta-updater layer] for Yocto, making it easy to get over-the-air update support into your devices. In many cases, it's as simple as adding meta-updater and a board support integration layer to your project and re-running bitbake. The main features of the meta-updater layer are OSTree and our OTA update client, aktualizr. OSTree handles the filesystem versioning, and aktualizr communicates with the server, downloads updates, and cryptographically verifies them following the xref:uptane.adoc[Uptane framework]. + + + diff --git a/docs/ota-client-guide/modules/nav.adoc b/docs/ota-client-guide/modules/nav.adoc new file mode 100644 index 0000000000..03a5eb0a9f --- /dev/null +++ b/docs/ota-client-guide/modules/nav.adoc @@ -0,0 +1,106 @@ +// MC: NOTE ABOUT TOC +// Adding "pageroot" attr so that TOC that will also work directly in GitHub. Because... +// In Antora the "pages" subdir is implcit added to the xref path at build time. +// if you add "/pages" Antora will intepret it as "pages/pages". +// The pages subdir is NOT implicit when viewing source files in Github. + +ifdef::env-github[:pageroot: pages/] +ifndef::env-github[:pageroot:] + +.Introduction to the Developer Tools +* xref:{pageroot}index.adoc[Introduction] +* xref:{pageroot}developer-tools.adoc[Developer Tools] +* xref:{pageroot}workflow-overview.adoc[Basic OTA update workflow] +* xref:{pageroot}evaluation-to-prod.adoc[Moving from Evaluation to Production] +// NEW topics + +.Key Concepts +// NEW/updated topics +* xref:{pageroot}software-management.adoc[Software Management] +** xref:{pageroot}supporting-technologies.adoc[Supporting technologies] +** xref:{pageroot}yocto.adoc[Yocto] +// --- +** xref:{pageroot}ostree-and-treehub.adoc[OSTree, and TreeHub] +// --- +* xref:{pageroot}security.adoc[Security] +** xref:{pageroot}pki.adoc[Key Management] +** xref:{pageroot}uptane.adoc[The Uptane security specification] +// future iteration: * xref:{pageroot}prod-intro[Testing and production environments] +* xref:{pageroot}client-provisioning-methods.adoc[Device provisioning] + +.Evaluate OTA Connect +* xref:{pageroot}intro-evaluate.adoc[Evaluating OTA Connect] +* xref:{pageroot}download-prov-key.adoc[Get a provisioning Key] +* xref:{pageroot}build-images.adoc[Use our sample recipes to build disk images] +** xref:{pageroot}build-raspberry.adoc[Build for a Raspberry Pi] +** xref:{pageroot}build-quemu.adoc[Build for QEMU] +** xref:{pageroot}build-agl.adoc[Build for Automotive Grade Linux] +* xref:{pageroot}simulate-device-basic.adoc[Simulate a device without building a disk image] +* xref:{pageroot}pushing-updates.adoc[Upload a sample software version] +* xref:{pageroot}update-single-device.adoc[Update a second device with the sample software] + +.Build your own OTA-enabled solution +* xref:{pageroot}intro-prep.adoc[Recommended Steps] +* xref:{pageroot}recommended-clientconfig.adoc[Recommended configurations] +* xref:{pageroot}account-setup.adoc[Set up multiple accounts] + +* xref:{pageroot}libaktualizr-why-use.adoc[Integrate libaktualizr into your solution] +** xref:{pageroot}libaktualizr-getstarted.adoc[Get Started with libaktualizr] +** xref:{pageroot}libaktualizr-update-secondary.adoc[Updating a Secondary ECU with libaktualizr] + +* xref:{pageroot}build-ota-enabled-images.adoc[Build and deploy OTA-enabled disk images] +** xref:{pageroot}supported-boards.adoc[Supported boards] +** xref:{pageroot}add-ota-functonality-existing-yocto-project.adoc[Add OTA functionality to a Yocto project] +** xref:{pageroot}libaktualizr-integrate.adoc[Add libaktualizr integration to a Yocto project] + +* xref:{pageroot}device-cred-prov-steps.adoc[Provision devices] +** xref:{pageroot}generate-selfsigned-root.adoc[Generate a self-signed root certificate] +** xref:{pageroot}provide-root-cert.adoc[Register your root certificate] +** xref:{pageroot}generate-devicecert.[Generate device certificates] +** xref:{pageroot}enable-device-cred-provisioning.adoc[Enable and install device certificates] + +* xref:{pageroot}secure-software-updates.adoc[Secure your software repository] +** xref:{pageroot}install-garage-sign-deploy.adoc[Install the Garage Deploy tool] +** xref:{pageroot}rotating-signing-keys.adoc[Manage keys for software metadata] +** xref:{pageroot}metadata-expiry.adoc[Manage metadata expiry dates] + +.Deploy your OTA-enabled solution +* xref:{pageroot}deploy-checklist.adoc[Deploying to Production] + + +.How to +* xref:{pageroot}cross-deploy-images.adoc[Transfer software to another repository] +* xref:{pageroot}simulate-device-cred-provtest.adoc[Simulate device credentials] +* xref:{pageroot}enable-shared-cred-provisioning.adoc[Configure devices to use shared-credential provisioning] +* xref:{pageroot}how-can-i-check-which-ostree-version-is-installed.adoc[Check which OSTree commit is deployed] +* xref:{pageroot}use-your-own-deviceid.adoc[Configure your own device IDs] +* xref:{pageroot}build-only-ostree.adoc[Build only the OSTree part] + +// Dev-authored topics +* xref:{pageroot}fault-injection.adoc[Simulate installation failures for testing] +* xref:{pageroot}posix-secondaries-bitbaking.adoc[Simulate a Primary and Secondary ECU] +** xref:{pageroot}posix-secondaries.adoc[Configuration and emulation on a local host] +* xref:{pageroot}fault-injection.adoc[Simulate installation failures for testing] +* xref:{pageroot}rollback.adoc[Set up rollback behavior] +* xref:{pageroot}deb-package-install.adoc[Install the client from a deb package] +* xref:{pageroot}uptane-generator.adoc[Simulate Uptane metadata transactions] +//---- + +.Reference +// MC: Do in second iteration: * xref:{pageroot}otaconnect-identifiers.adoc[Identifiers] +* xref:{pageroot}aktualizr-config-options.adoc[Configuration Options] +* xref:{pageroot}aktualizr-runningmodes-finegrained-commandline-control.adoc[Client Commands] +* xref:{pageroot}provisioning-methods-and-credentialszip.adoc[Contents of the credentials file] +* xref:{pageroot}useful-bitbake-commands.adoc[Bitbake commands] +* xref:{pageroot}ostree-usage.adoc[OSTree commands] + +.Troubleshooting +* xref:{pageroot}troubleshooting.adoc[Troubleshooting] + +.For Contributors +// Dev-authored topics +* xref:{pageroot}deb-package-install.adoc[Packaging an aktualizr Release on github] +* xref:{pageroot}schema-migrations.adoc[Add a schema migration] +* xref:{pageroot}debugging-tips.adoc[Debugging the Client] + + diff --git a/docs/posix-secondaries-bitbaking.adoc b/docs/posix-secondaries-bitbaking.adoc deleted file mode 100644 index 1745a9429e..0000000000 --- a/docs/posix-secondaries-bitbaking.adoc +++ /dev/null @@ -1,199 +0,0 @@ -= Posix Secondaries: bitbaking and usage of Primary and Secondary images - -The goal of this doc is to guide a reader on bitbaking of two type of images `primary` and `secondary` that are targeted for QEMU or RPi -and running of which on the target makes it act as `Primary` and `Secondary` ECU of a single device. - -Please, refer to link:https://uptane.github.io/uptane-standard/uptane-standard.html[the Uptane standard] in order to grok the meaning of the `Primary` and `Secondary` terms in the given context from a theoretical standpoint. -Please, check out link:posix-secondaries.doc[this doc] to understand these terms from a practical standpoint and -to learn how `Primary` and `Secondary` can be emulated locally on an user's host. -It is highly advisable to follow the doc instructions and play with emulated `Primary` and `Secondary` prior to running steps described further in this doc. - -== Bitbaking - -It is assumed that a reader is familiar with Yocto and bitbaking in general as well as bitbaking of Aktualizr images in particular, -details of which are out of scope of this doc and can be found in the following guides: - -* link:https://github.com/advancedtelematic/meta-updater/blob/master/README.adoc[meta-updater README]. -* https://docs.ota.here.com/quickstarts/qemuvirtualbox.html[How to build 'core-image-minimal' image for QEMU] - -=== Primary -To bitbake an image for `Primary` run the following: -.... -bitbake primary-image -.... - - -.Primary configuration variables -[cols="1,1,10"] -|=== -|Name |Default |Description - -|`PRIMARY_IP` -|`"10.0.3.1"` -|An IP address to assign to one of the Primary's NIC for communication with Secondaries - -|`PRIMARY_PORT` -|`"9040"` -| A TCP port that Primary aktualizr listen on for connections from Secondaries - -|`PRIMARY_WAIT_TIMEOUT` -|`"120"` -|Time (seconds) to wait for connections from Secondaries. Only the secondaries that connected to Primary will be registered at the server and are part of the device Primary represents. - -|`PRIMARY_SECONDARIES` -|`"10.0.3.2:9050"` -| A space separated list of TCP/IP addresses of the Secondaries to be included into the list of ECUs served by the given Primary -|=== - -Please, note that PRIMARY_SECONDARIES can be a list of TCP/IP addresses in order to fulfill multiple secondaries use case. -For example, `PRIMARY_SECONDARIES = "10.0.3.2:9050 10.0.3.3:9050 10.0.3.4:9050"`. - - -=== Secondary -To bitbake an image for `Secondary` run the following -.... -bitbake secondary-image -.... - -.Secondary configuration variables -[cols="1,1,10"] -|=== -|Name |Default |Description - -|`SECONDARY_IP` -|`"10.0.3.2"` -|An IP address to assign to A Secondary NIC for communication with Primary - -|`SECONDARY_PORT` -|`"9050"` -|A TCP port that Secondary listen on for connections from Primary -|=== - -==== Multiple secondaries use case -In order to support multiple secondaries use case an user should - -* repeat the secondary bitbaking procedure corresponding number of times, each time -** specifying unique TCP/IP address by means of `SECONDARY_IP` and `SECONDARY_PORT` configuration variables -** copying and naming uniquely the resultant image file (e.g. `cp tmp/deploy/images/qemux86-64/secondary-image-qemux86-64.ota-ext4 secondary-images/secondary-image-qemux86-64.ota-ext4-001`) -* bitbake the primary image with `PRIMARY_SECONDARIES` listing the corresponding secondaries TCP/IP addresses -* run the primary by following the guide in <> -* run the secondaries by running the command specified in <> with a parameter pointing to corresponding secondary image. -For example, - -`../meta-updater/scripts/run-qemu-ota --no-gui --secondary-network secondary-images/secondary-image-qemux86-64.ota-ext4-001` - -`../meta-updater/scripts/run-qemu-ota --no-gui --secondary-network secondary-images/secondary-image-qemux86-64.ota-ext4-002` - -=== Specifics of bitbaking for Raspberry Pi - -It is assumed that a reader is a familiar with bitbaking for Raspberry Pi in general, see link:https://docs.ota.here.com/quickstarts/raspberry-pi.html[Build a Raspberry Pi image]. - -The aforementioned/above guide is relevant and applicable to building a Raspberry images of Primay and Secondary. -The following is specifics of building such images targeting RPi. - -* run `source meta-updater/scripts/envsetup.sh raspberrypi3` to get the build environment set up from a root of the yocto project (updater-repo) -* specify type of NIC to use for Primary for connection to Internet/backend. There are two options, ethernet NIC or Wifi. -By default ethernet NIC is used which implies that Raspberry Pi is connected to LAN with an access to Internet. To use WiFi NIC the following configuration variables should be defined in your local configuration (local.conf): - -.WiFi configuration variables -[cols="1,7,10"] -|=== -|Name |Default |Description - -|`RPI_WIFI_ENABLE` -|`"0"` -|A flag to enable/disable (default) WiFi on RPi board. - -|`RPI_WIFI_SSID` -|`N/A (mandatory if wifi is enabled)` -|SSID of a WiFi network to connect to. The SSID is case sensitive. - -|`RPI_WIFI_PWD` -|`N/A (mandatory if wifi is enabled)` -|Password to connect to the WiFi network router. -|=== - - -==== RPi networking details in a context of Posix secondaries support - -IP/Posix secondaries support implies that a single primary ECU connected to two IP networks: - -* an IP network with an access to Internet for communication with the OTA backend; -* an IP network that does not have access to Internet for communication with secondary ECU(s). The secondaries should be connected to this internal network. - -Taking into account that RPi has two NICs, ethernet and wifi the aforementioned requirements to networking can be fulfilled by applying the following approaches. - -===== Primary uses multihomed ethernet interface, Secondary uses ethernet interface - -Both primary and secondary ECUs has wifi turned off and are connected to the same LAN (via switch or router) that has an access to Internet. -Primary only network interface is configured in such way that it has two IP addresses assigned to it. - -The first one (10.0.3.1 by default) is statically defined (can be configured via `PRIMARY_IP` configuration variable) -and connects the primary to an internal IP network (10.0.3.0/8) that is aimed for communication with secondary ECU(s). -Secondary(ies) are connected to the same internal network (10.0.3.0/8) by assigning to their -ethernet interface corresponding IP addresses (10.0.3.x, 10.0.3.2 for the default only secondary, `SECONDARY_IP` configuration variable). - -The second IP address assigned to the primary ethernet NIC should be obtained from a DHCP server running on one of -the devices (usually a router) that is connected to the given LAN, has an access to Internet and provides each host connected to the given IP network with access to Internet -(via NATing IP packets, DHCP and NAT server can be hosted/running on different devices). - -The given networking option is enabled by default. - -===== Primary uses both wifi and ethernet interfaces, Secondary uses ethernet interface -Primary has wifi on, and its wifi NIC is connected to a LAN with an access to Internet. Also, Primary ethernet NIC -is assigned with an only IP address (10.0.3.1 by default) to connect to the internal network for communication -with secondary ECUs. -Secondary(ies) are connected to the same internal network (10.0.3.0/8) by assigning to their -ethernet interface corresponding IP addresses (10.0.3.x, 10.0.3.2 for the default only secondary, `SECONDARY_IP` configuration variable). - -===== Primary and Secondary uses wifi, only Primary uses ethernet NIC -In this case, both Primary and Secondary(ies) uses wifi NIC to connect to the internal network (wifi router should not have an Internet access). Secondary doesn't use ethernet NIC. -Primary connects to Internet via ethernet NIC that should be connected to LAN with an access to Internet. -`(The given approach is not supported by the meta-updater but can be applied by an advanced user)` - - -== Running - -It is assumed that a reader is familiar with details on running of bitbaked images targeted for QEMU, such information can be found in the following docs: - -* link:https://github.com/advancedtelematic/meta-updater/blob/master/README.adoc[meta-updater README]. -* https://docs.ota.here.com/quickstarts/qemuvirtualbox.html[How to build 'core-image-minimal' image for QEMU] - -=== Primary - -To launch QEMU VM acting as Primary run the following from your build directory -.... -../meta-updater/scripts/run-qemu-ota --no-gui --secondary-network primary-image -.... -`--secondary-network` option instructs QEMU to add NIC to the VM in order to communicate with Secondary VM(s) via it. - - -=== Secondary - -To launch QEMU VM acting as Secondary run the following from your build directory -.... -../meta-updater/scripts/run-qemu-ota --no-gui --secondary-network secondary-image -.... -`--secondary-network` option instructs QEMU to add NIC to the VM aimed for communication with Primary - -== Usage - -Once both Primary and Secondary VMs are running you should see that a new device has been registered at the server and you can start testing it. -The following are Tips & Tricks for using & troubleshooting of the Primary and Secondary VMs. - -* run `journalctl -f -u aktualizr` to see logs that are being output by aktualizr running on `Primary` VM; -* run `journalctl -f -u aktualizr-secondary` to see logs that are being output by aktualizr-secondary (posix/IP secondary) running on `Secondary` VM; -* By default, both aktualizr and aktualizr-secondary are running as systemd services. Use `systemctl stop|start|restart ` to control aktualizr and aktualizr-secondary daemons/services managed by systemd; -* To control aktualizr|aktualizr-secondary manually stop corresponding systemd service (see above) and run it from command line: -just type `aktualizr' | `aktualizr-secondary`; -* By default, both executables output logs of level 1 (INFO), specify log level 0 in their config to see debug logs. -In case of running from command line add corresponding parameter ` --loglevel 0`. -In case of running as a systemd service add corresponding configuration fragment into /etc/sota/conf.d/ folder, -e.g. `echo -e "[logger]\nloglevel = 0" > /etc/sota/conf.d/50-debug-logs.toml` and restart the service; -* In order to trigger a device re-provisioning, please, remove the DB file on Primary, i.e. `rm /var/sota/sql.db` -* If the DB file is removed on Secondary then the device should be re-provisioned (see above), -otherwise Primary/aktualizr will refuse to work with a 'new' secondary as it will have a "new" autogenerated ECU serial -that doesn't the one already been registered on Primary. -* OTA Connect does not support adding/removing secondary ECUs to a device that has been already registered. -Thus adding a new ECU to the list of secondaries on Primary won't take much effect, -the new ECU won't appear on the UI and it will be listed as not registered by aktualizr-info. diff --git a/docs/posix-secondaries-bitbaking.adoc b/docs/posix-secondaries-bitbaking.adoc new file mode 120000 index 0000000000..26095edac1 --- /dev/null +++ b/docs/posix-secondaries-bitbaking.adoc @@ -0,0 +1 @@ +./ota-client-guide/modules/ROOT/pages/posix-secondaries-bitbaking.adoc \ No newline at end of file diff --git a/docs/posix-secondaries.adoc b/docs/posix-secondaries.adoc deleted file mode 100644 index 019f736449..0000000000 --- a/docs/posix-secondaries.adoc +++ /dev/null @@ -1,109 +0,0 @@ -= Posix Secondaries aka IP Secondaries: configuration and emulation of Primary and Secondary on a local host - -The goal of this doc is to guide a reader on configuring and running two executables that can be built out of the given repository source code and act as Primary and Secondary correspondingly. - -The term `Secondary` is being used as it is defined by link:https://uptane.github.io/uptane-standard/uptane-standard.html[the Uptane standard]. -It refers to ECU, software/firmware/package updates of which are managed by another ECU that hosts and runs Uptane compliant software. The later ECU is called Primary and the sotfware it runs in our case is called aktualizr. - -A key component of this repository is libaktualizr which is a library implementing Uptane protocol and providing customers and community with capability to build application(s) one of the purposes of which is to update software/firmware/packages in compliance with the Uptane standard. In addition to libaktualizr, a user can find in this repo another two components: - -. *aktualizr*, aka aktualizr primary - a reference implementation of an application utilizing libaktualizr, its binary/executable is called aktualizr. Aktualizr can be used to emulate Primary ECU locally on a user's host; -. *aktualizr-secondary*, aka posix or IP secondary - a reference implementation intended for running on Secondary ECU and capable to communicate with Primary ECU aktualizr via TCP/IP protocol (implemenation relies on Posix API). Aktualizr-secondary can be used to emulate a Secondary ECU on a user's host. - - -== *Secondary* - -*Build* - -The Secondary executable is built by default, thus following build instructions outlined in link:../README.adoc[the repo's README] should do the trick. If the build procedure is completed successfully then aktualizr-secondary can be found in ``/src/aktualizr_secondary/aktualizr-secondary``. - -*Configure* - -A default configuration of aktualizr-secondary can be found in link:../config/posix-secondary.toml[/config/posix-secondary.toml]. - -Configuration parameters that are worth mentioning are located in [uptane] section: - -* `port` - TCP port to listen for a connection from Primary -* `primary_ip` - IP address of Primary ECU -* `primary_port` - TCP port that Primary's aktualizr listen on for a connection from Secondary - -More details on the configuration in general and specific parameters can be found here link:../docs/configuration.adoc[configuration details] - -*Run* - -``/src/aktualizr_secondary/aktualizr-secondary -c /config/posix-secondary.toml`` -Once it's started, you should see a message saying that aktualizr-secondary is listening on the port specified in the config. - - -== *Primary* - -*Build* - -The Primary executable is built by default, thus following build instructions outlined in link:../README.adoc[the repo's README] should do the trick. If the build procedure is completed successfully then aktualizr executable can be found in ``/src/aktualizr_primary/aktualizr``. - -*Configure* - -A default configuration of aktualizr acting as Primary can be found in link:../config/sota-local-with-secondaries.toml[/config/sota-local-with-secondaries.toml]. - -One configuration parameter that is worth mentioning is `[uptane]: secondary_config_file` which specifies a path -to secondary(ies) configuration file containing input parameters for aktualizr/Primary to communicate with any secondaries. -This is a link:../config/posix-secondary-config.json[default secondary configuration for Primary]. -In order to use the given default config file, either copy it into your current working directory or update -`[uptane]: secondary_config_file` value so it defines a full path to the secondary config file (e.g. ``/config/posix-secondary-config.json``). - -Configuration parameters of secondaries for Primary/aktualizr that are worth mentioning are: - -* `secondaries_wait_port` - TCP port aktualizr listen on for connections from Secondaries -* `secondaries_wait_timeout` - timeout (in sec) of waiting for connections from Secondaries. Primary/aktualizr waits for a connection from those secondaries that it failed to connect to at the startup time. -* `secondaries` - a list of Secondary TCP/IP addresses - -Put your credential.zip file into the current working directory or update `[provision] provision_path` in link:../config/sota-local-with-secondaries.toml[the config] so it specifies a full path to your credential file. - -*Run* - -``/src/aktualizr_primary/aktualizr -c /config/sota-local-with-secondaries.toml`` -Once aktualizr is running, check the output for *_Adding Secondary to Aktualizr_* and *_Provisioned successfully on Device Gateway_*. You should then see that a new device has been registered on the server and that it includes two ECUs: your local Primary and Secondary. You can now send updates to either ECU. - -== *Tips and Tricks* - -* Define an environment variable that points to the aktualizr source root directory on your host. For example: -.... -echo 'export AKT_PROJ_HOME=""' >> ~/.profile -.... -* Define an environment variable that points to the aktualizr build directory on your host. For example: -.... -echo 'export AKT_BUILD_DIR="$AKT_PROJ_HOME/build"' >> ~/.profile -.... -* Use ``$AKT_PROJ_HOME/config/sota-local-with-secondaries.toml`` as the config for your emulated Primary ECU -* Copy ``$AKT_PROJ_HOME/config/posix-secondary-config.json`` to the directory you run your Primary from, let's call it `PRIMARY_HOME_DIR` further. -* Copy your credential file ``credentials.zip`` to `PRIMARY_HOME_DIR` -* Use ``$AKT_PROJ_HOME/config/posix-secondary.toml`` as the config for your emulated Secondary ECU -* To run the primary launch the following from `PRIMARY_HOME_DIR` -.... -$AKT_PRIMARY -c $AKT_PROJ_HOME/config/sota-local-with-secondaries.toml -.... -* To run the secondary launch the following from `PRIMARY_HOME_DIR` (although it can be executed from any directory) -.... -$AKT_SECNDR -c $AKT_PROJ_HOME/config/posix-secondary.toml -.... -* Add --loglevel 0 to the aforementioned launch commands if you would like to see more logs -* To re-register your emulated multi-ECU device (or start playing it from scratch) remove ``storage`` directory from `PRIMARY_HOME_DIR` - -=== Multiple secondaries - -In order to emulate a device containing one primary ECU along with more than one secondary ECUs the following should be done. - -* Run the secondary executable `/src/aktualizr_secondary/aktualizr-secondary` desired number of times each from different directories. -Prior to running secondary executables, please, - - ** copy the configuration file /config/posix-secondary.toml to each directory the secondary will be launched from. - Let's call such directory as `SECONDARY_HOME_DIR`; - - ** update a value of `[network]:port` parameter of the config file in each `SECONDARY_HOME_DIR` directory in such way - that each secondary config specifies different port number (9050 by default) hence each secondary will listen on different port; - -* Update posix-secondary-config.json located in `PRIMARY_HOME_DIR` (see instructions in p. `Primary`) with details of each secondary - that was executed in previous step, specifically, add corresponding values to "secondaries" list field (e.g. `"secondaries": [{"addr": "127.0.0.1:9050"}, {"addr": "127.0.0.1:9051"}]`). - Once posix-secondary-config.json is updated run the primary, as result you should see that it is connected with multiple secondaries - in aktualizr logs as well as on UI. - diff --git a/docs/posix-secondaries.adoc b/docs/posix-secondaries.adoc new file mode 120000 index 0000000000..b053868a38 --- /dev/null +++ b/docs/posix-secondaries.adoc @@ -0,0 +1 @@ +./ota-client-guide/modules/ROOT/pages/posix-secondaries.adoc \ No newline at end of file diff --git a/docs/provision-with-device-credentials.adoc b/docs/provision-with-device-credentials.adoc deleted file mode 100644 index 31c0fa91b7..0000000000 --- a/docs/provision-with-device-credentials.adoc +++ /dev/null @@ -1,76 +0,0 @@ -// Copy of this topic: https://docs.ota.here.com/prod/enable-implicit-provisioning.html adapted for aktualizr repo. Replaces duplicate "implicit-provisioning.adoc". - -= Provision with Device Credentials - -If you followed the "Getting Started" procedures, you used a https://docs.ota.here.com/quickstarts/generating-provisioning-credentials.html[provisioning key] that was shared by all devices that run the same software image. This key enables you to provision the permanent credentials for your test devices. This method is fine if you're just testing and want to get started quickly. When you move to production, a more secure option is to provision with credentials that are specific to each device. - -When you provision with device credentials, you install permanent credentials each device before the device connects to the server. Unlike shared-credential provisioning, the server doesn't issue any credentials to devices. Instead, you use a root CA certificate to sign the credentials that you install on the device. You then install the same root CA certificate on the OTA Connect server. - -Every time the device attempts to connect, the server verifies that the device credentials are signed by the same CA that you originally installed on the server. The device also verifies that is communicating with a genuine OTA Connect server. - -The following procedures describe different options for provisioning with device credentials. - -toc::[] - -== Simulate Device-credential Provisioning for Testing - -To provision with device credentials in production, you need to have a root CA. If you want to test this provisioning method without generating a root CA, you can simulate it with the `aktualizr-cert-provider` command. - -To use the `aktualizr-cert-provider` command, you must still generate a https://docs.ota.here.com/quickstarts/generating-provisioning-credentials.html[provisioning key] that your devcies can share. But with this method, you use the provisioning key to sign the device certificate. In production, you would use the root CA to sign the device certificate, but this method is useful for testing. - -To simulate provisioning with a device certificate, follow these steps: :: -1. Add the following lines to your local.conf: -+ ----- -SOTA_CLIENT_PROV = "aktualizr-device-prov" -SOTA_DEPLOY_CREDENTIALS = "0" ----- - -1. Build a standard image using the bitbake command. -1. Boot the image. -+ -The device should not be able to provision at this time. To verify this, log in to the OTA Connect server and make sure that the device does not appear in the list of devices. -1. Load the device credentials on to the device with `aktualizr-cert-provider` command: -+ ----- -aktualizr-cert-provider -c credentials.zip -t -d /var/sota/import -r -u ----- -+ -You can find the link:../src/cert_provider[`aktualizr-cert-provider` source] in this repo. You can also find a compiled binary in the host work directory of bitbake. The path is something like `tmp/work/x86_64-linux/aktualizr-native/1.0+gitAUTOINC+/build/src/cert_provider/aktualizr-cert-provider`. - -== Use a Hardware Security Module (HSM) When Provisioning with Device Credentials - -As described in our link:https://docs.ota.here.com/prod/prod-intro.html[guide for moving to production], it's a good idea to use a Hardware Security Model (HSM) to hold potentially sensitive device credentials. - -The following procedure describes how to use QEMU and link:https://www.opendnssec.org/softhsm/[SoftHSM] to simulate a device with an HSM. However, the procedure for your HSM will probably be different. We've provided these instructions as a basic guide to how this provisioning method works but you'll need to make further changes on your own. For example, you'll probably need to adapt your BSP so that aktualizr can access the keys from your HSM. - -To use an HSM when provisioning with device credentials, follow these steps: :: -. link:https://docs.ota.here.com/prod/generate-and-install-a-root-certificate.html[Generate and install a root certificate]. -. Add the following lines to your `conf/local.conf`: -+ ----- -SOTA_CLIENT_FEATURES = "hsm" -SOTA_CLIENT_PROV = "aktualizr-hsm-prov" -SOTA_DEPLOY_CREDENTIALS = "0" -IMAGE_INSTALL_append = " softhsm-testtoken " ----- -. Build a standard image using bitbake. Make sure that an ssh server is installed. Usually you can do this with `IMAGE_INSTALL_append = " dropbear "`. -. Boot the image. -. Run the following commands to tell the device what server URL to connect to: -+ ----- -unzip credentials.zip autoprov.url -scp -P 2222 autoprov.url root@localhost:/var/sota/import/gateway.url ----- -. Copy the device credentials and device gateway root CA certificate to the device's HSM. For the QEMU simulated HSM, enter the device directory whose credentials you want to copy, then enter the following command: -+ ----- -scp -P 2222 -pr ./ root@localhost:/var/sota/import ----- -.. The server authenticates the client device by verifying that the client's certificate was signed by the root CA private key that was uploaded in step 2. -.. The client device authenticates the server by verifying that the server's certificate was signed by the server's internal root CA private key. -.. The device is provisioned and appears online in the web UI. - -''' - -link:./provisioning-methods-and-credentialszip.adoc[More information] is available on provisioning with shared credentials, device credentials (with or without an HSM), and how the various files included in `credentials.zip` are related. diff --git a/docs/provision-with-device-credentials.adoc b/docs/provision-with-device-credentials.adoc new file mode 120000 index 0000000000..efce71f879 --- /dev/null +++ b/docs/provision-with-device-credentials.adoc @@ -0,0 +1 @@ +./ota-client-guide/modules/ROOT/pages/enable-device-cred-provisioning.adoc \ No newline at end of file diff --git a/docs/provisioning-methods-and-credentialszip.adoc b/docs/provisioning-methods-and-credentialszip.adoc deleted file mode 100644 index f4bf38aa4c..0000000000 --- a/docs/provisioning-methods-and-credentialszip.adoc +++ /dev/null @@ -1,78 +0,0 @@ -// Copy of this topic: https://docs.ota.here.com/concepts/provisioning-methods-and-credentialszip.html adapted for aktualizr repo. Replaces duplicate "credentials.adoc". - -= Provisioning methods and credentials.zip - -If you're trying to work on integrating OTA Connect into your device build, it may be helpful to have a little bit of reference information on how the different provisioning methods work together, and exactly what components are inside `credentials.zip`. - -== `credentials.zip` file format - -The following files are present in credentials.zip: - -// tag::credentials-table[] - -[options="header"] -|====================== -| Filename in zip | Purpose | Used by -| api_gateway.url | URL for gateway to Director | garage-sign -| treehub.json | URL and OAuth2 authentication for treehub and Uptane repo | garage-sign, garage-push, garage-deploy -| client_auth.p12 | TLS client credentials for authentication with treehub | garage-push, garage-deploy -| autoprov_credentials.p12 | TLS client credentials that are required when provisioning devices with shared credentials | aktualizr, aktualizr-cert-provider -| autoprov.url | URL for provisioning server | aktualizr, aktualizr-cert-provider -| root.json | Initial Uptane root.json (for secure bootstrapping) | garage-sign -| targets.pub | Public key for offline Uptane image signing | garage-sign -| targets.sec | Private key for offline Uptane image signing | garage-sign -| tufrepo.url | URL to Uptane repository | garage-sign -|====================== - -// end::credentials-table[] - -As you can see, the relevant files for the device itself are `autoprov_credentials.p12` and `autoprov.url`. - -== Configuration options for provisioning with shared credentials - -When provisioning with shared credentials, the process works as follows: - -1. The user downloads a package that contains an initial provisioning key. This is installed on all devices and is only used to bootstrap the provisioning process. -2. When Aktualizr first runs on a device, it uses this key/certificate to make a request to the device gateway https API. The server registers the new device and returns a PKCS#12 archive containing the real credentials for the device. -3. The device reads the root CA certificate and client certificate from this bundle. -3. The device uses this private key/certificate for all further communication with the server. - -The following items are relevant for this process: - -[options=header] -|=================== -| Configuration option | Where it will come from -| Server URL | Read from credentials archive -| TLS key/cert/root CA | Read from credentials archive -| Device ID | Automatically generated by Aktualizr -| Uptane public/private key | Automatically generated by Aktualizr -| Uptane primary serial number | Automatically generated by Aktualizr -| Primary ECU Hardware ID | Automatically generated by Aktualizr -|=================== - -An example `.toml` configuration file can be found at link:../config/sota-shared-cred.toml[]. This is what is used by the `aktualizr-shared-cred-prov` recipe in meta-updater. - -== Configuration options for provisioning with device credentials - -When provisioning with device credentials, OTA Connect needs to get various certificates and keys from somewhere. This table summarizes what is needed, and where it comes from in the HSM. - -// tag::summary-table[] - -[options=header] -|=================== -| Configuration option | Where it will come from/what it does -| Server URL | Read from credentials archive -| Server Root CA cert | Read from credentials archive -| Fleet Root CA cert | Chain of trust for a device fleet; provided by the user. Must be uploaded by user to the server. -| Fleet Root CA private key | Key for signing device certs in the fleet; provided by user, but used only for signing. Not stored on device. -| TLS device cert | Pre-installed in the device HSM; must be signed by Fleet Root CA private key -| TLS device key | Pre-installed in the device HSM -| Device ID | Read from Common Name field of TLS device cert -| Uptane public/private key | Automatically generated by Aktualizr -| Uptane primary serial number | Automatically generated by Aktualizr -| Primary ECU Hardware ID | Automatically generated by Aktualizr -|=================== - -// end::summary-table[] - -NOTE: The "Fleet Root CA" is the one generated in step 1 of the procedure: link:./provision-with-device-credentials.adoc#use-a-hardware-security-module-hsm-when-provisioning-with-device-credentials[use a Hardware Security Module to provision with device credentials]. diff --git a/docs/provisioning-methods-and-credentialszip.adoc b/docs/provisioning-methods-and-credentialszip.adoc new file mode 120000 index 0000000000..a75bb08afd --- /dev/null +++ b/docs/provisioning-methods-and-credentialszip.adoc @@ -0,0 +1 @@ +ota-client-guide/modules/ROOT/pages/provisioning-methods-and-credentialszip.adoc \ No newline at end of file diff --git a/docs/rollback.adoc b/docs/rollback.adoc deleted file mode 100644 index 0bfcb5180f..0000000000 --- a/docs/rollback.adoc +++ /dev/null @@ -1,60 +0,0 @@ -= Rollbacks - -Since Aktualizr is a userspace application and relies on a lot of other software which can be -affected by an unsuccessful update, rollback functionality should be implemented in the bootloader. - -Some support from Aktualizr is nevertheless required. The most important thing is notifying bootloader -on successful boot (`Bootloader::setBootOK()`). Notifying on the update (`Bootloader::updateNotify`) -can also save the bootloader some write cycles to the environment storage. - -Currently only U-boot 'bootcount' rollback mechanism is supported. - -== U-boot - -More info about bootcount feature you can find in U-boot https://www.denx.de/wiki/DULG/UBootBootCountLimit[documentation]. - -When using 'bootcount' the system can be in one of three states: - - * No update: booting into main image - * Booting into rollback image - * Updated: update was installed, but it's not yet clear if it was successful - -'Updated' is a transition state, while 'No update' and 'Rollback' are steady states. -Transition to 'No update' is confirmed by Aktualizr, while going to 'Rollback' is forced by U-boot - -'bootcount' and 'upgrade_available' variables are recognized by U-boot. 'rollback' is Aktualizr-specific, -it prevents bootloader to try booting main image after falling back to rollback image. - -You can see the whole transition graph below. - - - - Aktualizr confirms successful update by - +-----------------------------------------------------+ +-----------------------+ - | setting upgrade_available=0; bootcount=0 | | | - | | | | U-boot increments - | | | | bootcount after every - V | V | unsuccessful boot ( i.e - +-----------------------+ +------------------------+ | (when upgrade_available = 1) - | No update | | Updated | | - | | Aktualizr announces update by | | | - | bootcount = 0 |----------------------------------> | bootcount <= bootlimit |----------+ - | upgrade_available = 0 | setting upgrade_available=1 | upgrade_available = 1 | - | rollback = 0 | | rollback = 0 | - | | | | - +-----------------------+ +------------------------+ - ^ | - Aktualizr announces update by | | - +-------------------------------------------------------+ | - | setting upgrade_available=1 | - | | - | | - +-----------------------+ | - | Rollback | | - | | After bootcount exceeded bootlimit U-boot | - | bootcount > bootlimit |<------------------------------------------------------+ - | upgrade_available = 0 | boots into rollback image and resets upgrade_avalable - | rollback = 1 | - | | - +-----------------------+ - diff --git a/docs/rollback.adoc b/docs/rollback.adoc new file mode 120000 index 0000000000..c6e5dada12 --- /dev/null +++ b/docs/rollback.adoc @@ -0,0 +1 @@ +./ota-client-guide/modules/ROOT/pages/rollback.adoc \ No newline at end of file diff --git a/docs/schema-migrations.adoc b/docs/schema-migrations.adoc deleted file mode 100644 index 604f97ecf1..0000000000 --- a/docs/schema-migrations.adoc +++ /dev/null @@ -1,19 +0,0 @@ -= How to add a schema migration -:aktualizr-github-url: https://github.com/advancedtelematic/aktualizr/tree/master -ifdef::env-github[] -:aktualizr-github-url: .. -endif::[] - -1. Modify link:{aktualizr-github-url}/config/sql/schema.sql[] as you see fit -2. Write a config/sql/migration/migrate.n+1.sql that will convert an existing data to format in schema.sql. Note that old migrations must not be modified. - -Make sure that the migrate.n+1.sql file updates the 'version' table: - - DELETE FROM version; - INSERT INTO version VALUES(...); - -3. Write a config/sql/rollback/rollback.n+1.sql that will revert the new data format to the previous one. It should contain the opposite steps of migrate.n+1.sql if possible. If the reverse operation is lossy, it should at the minimum bring the device to a state where it can be updated. - -The 'version' table has to be updated as well, to contain n. - -4. If the migration manipulates existing data in a non-trivial way (anything that's not simply a new table creation, deletion, renaming), it is strongly advised to write an explicit migration test with realistic data in link:{aktualizr-github-url}/src/libaktualizr/storage/sqlstorage_test.cc[], similar to `DbMigration18to19`. diff --git a/docs/schema-migrations.adoc b/docs/schema-migrations.adoc new file mode 120000 index 0000000000..05b57e57ac --- /dev/null +++ b/docs/schema-migrations.adoc @@ -0,0 +1 @@ +./ota-client-guide/modules/ROOT/pages/schema-migrations.adoc \ No newline at end of file diff --git a/docs/security.adoc b/docs/security.adoc deleted file mode 100644 index f582fc1099..0000000000 --- a/docs/security.adoc +++ /dev/null @@ -1,23 +0,0 @@ -= Security - - -Aktualizr uses the UPTANE security framework, which assumes a powerful adversary which can: - -* Monitor and modify all network traffic -* Compromise the master update server (and all https keys) -* Compromise some of the other keys in the system - -There are several assumptions about the platform that need to be met by the platform Aktualizr is integrated in to produce a secure system. - - -== Assumption: DNS eventually resolves correctly - -An attacker who can poison the DNS cache of the local system can stop the system receiving updates until the DNS entry times out. - -Controlling DNS can only deny service: it does not allow the attacker to control the system in any way. - -The deployment should ensure that the DNS TTL is short enough, or deploy a secure system for name resolution such as DNSSEC. - -== Assumption: Time is trusted - -The local time of the system is used to check the validity of signatures. An attacker who can modify the local time of the system can cause signatures to either become invalid (denying service) or can allow an expired signature to be used. The default NTP implementation on many embedded systems is not secure against an attacker with control over the network, and so a secure source of time should be used. This might be a network time service (such as Google's https://roughtime.googlesource.com/roughtime[Roughtime]) or a local RTC. diff --git a/docs/security.adoc b/docs/security.adoc new file mode 120000 index 0000000000..acb44397f7 --- /dev/null +++ b/docs/security.adoc @@ -0,0 +1 @@ +./ota-client-guide/modules/ROOT/pages/security.adoc \ No newline at end of file diff --git a/docs/selectively-triggering-aktualizr.adoc b/docs/selectively-triggering-aktualizr.adoc deleted file mode 100644 index 33892d0141..0000000000 --- a/docs/selectively-triggering-aktualizr.adoc +++ /dev/null @@ -1,77 +0,0 @@ -= Selectively triggering aktualizr - -Aktualizr normally runs as a `systemd` service and regularly polls for updates. The default polling interval is set at 10s, and this should be increased by a few orders of magnitude in a production system. - -It is also possible to trigger the update cycle, or individual parts of the update cycle, manually or programmatically. This is done by using aktualizr's `--run-mode` option, or just supplying the operation name as a subcommand. - -[NOTE] -==== -To selectively trigger aktualizr, you should disable the `systemd` service. If aktualizr runs continuously, it interferes with the manual triggering. - -To run the update cycle manually, first stop and disable the aktualizr background service: - - systemctl stop aktualizr && systemctl disable aktualizr - -Assuming aktualizr is being built using Yocto and meta-updater, the `systemd` service can also be disabled by default by adding the following to `local.conf`: - - SYSTEMD_AUTO_ENABLE_aktualizr = "disable" -==== - -== Triggering an entire update cycle - -An update cycle consists of: - -. Polling the server for updates and downloading (and verifying) update metadata. -. Downloading (and verifying) any update binaries available. -. Installing the update. -. Reporting the install results. - -To trigger the whole cycle, use the following command: - - aktualizr once - -== Triggering individual update stages - -It might not be desirable to always trigger a complete update cycle. For example, you may want to check for updates and download them, but get user permission before installing. Or, you may want to download an update when there is network connectivity then perform the installation later, without relying on the network. (Note that aktualizr is always _safe_ against network drops. The worst that can happen if the network becomes unavailable is that the update will fail and need to be retried later.) - -=== Triggering an update check - -Fetch the Uptane metadata: - - aktualizr check - -=== Downloading an available update - -Download an update: - - aktualizr download - -=== Installing downloaded update(s) - - aktualizr install - -=== Reporting installation results - -Installation reports are sent when aktualizr polls the server for updates, so the `check` run-mode should be used again after installing: - - aktualizr check - -=== Check for campaigns that target the device - -Campaigns provide a way to target software updates to specific groups of devices. You can set up campaigns in the OTA Connect web app. When a device comes online that matches the targeting criteria of a campaign, the OTA Connect server notifies the device that new software updates are available. - - aktualizr campaign_check - -If the device is targeted by one or more campaigns, aktualizr prints details of each applicable campaign including the campaign ID. You can then use the campaign ID for the `campaign_accept` command. - -=== Accept campaigns that target the device - -This run mode works together with the `campaign_check` mode. After you have received a list of applicable campaigns, you can accept the campaigns so that they are included in the software update process. - - aktualizr campaign_accept --campaign-id= - -For example: - - aktualizr campaign_accept --campaign-id=4df1a199-59d4-47f6-a261-d79b83020f65 - -Once aktualizr has accepted the campaign, the scheduled update becomes available to the device. The device can then install the update during a normal full update cycle or when the device runs in `check` mode. diff --git a/docs/selectively-triggering-aktualizr.adoc b/docs/selectively-triggering-aktualizr.adoc new file mode 120000 index 0000000000..1acf603da1 --- /dev/null +++ b/docs/selectively-triggering-aktualizr.adoc @@ -0,0 +1 @@ +./ota-client-guide/modules/ROOT/pages/aktualizr-runningmodes-finegrained-commandline-control.adoc \ No newline at end of file