{"_id":"gcp-iot-provision","_rev":"40-cd5e59821e11ae28f8f56df9773b6c3c","name":"gcp-iot-provision","dist-tags":{"use-api-key-70d014cd051671eac1c011b18a253b19833cfcec":"0.1.0-use-api-key-70d014cd051671eac1c011b18a253b19833cfcec","use-api-key-34f0049bb856d6d788486d4b02becdba46778294":"0.1.0-use-api-key-34f0049bb856d6d788486d4b02becdba46778294","dependabot-npm-and-yarn-minimist-1-2-6-6fcb6912765eed66678f8ffdba8110051bb65533":"0.2.0-dependabot-npm-and-yarn-minimist-1-2-6-6fcb6912765eed66678f8ffdba8110051bb65533","dependabot-npm-and-yarn-moment-2-29-3-7c3bbbe07a24ed25ea7bd0a512b3c8beefc0b42b":"0.2.0-dependabot-npm-and-yarn-moment-2-29-3-7c3bbbe07a24ed25ea7bd0a512b3c8beefc0b42b","dependabot-npm-and-yarn-node-forge-1-3-1-34801fadbe6449712929c65e58bef087ddfdee49":"0.2.0-dependabot-npm-and-yarn-node-forge-1-3-1-34801fadbe6449712929c65e58bef087ddfdee49","dependabot-automation-bd10fbdcd31aed687926e3c7a678772e985af583":"0.2.0-dependabot-automation-bd10fbdcd31aed687926e3c7a678772e985af583","fix-dependabot-location-19e04aee08846ffec9536de7216601c0ffa9f4ee":"0.2.1-fix-dependabot-location-19e04aee08846ffec9536de7216601c0ffa9f4ee","dependabot-npm-and-yarn-minimist-1-2-6-3f850e85b59a5f8fe4b98e32af8d035b9f50feb3":"0.2.2-dependabot-npm-and-yarn-minimist-1-2-6-3f850e85b59a5f8fe4b98e32af8d035b9f50feb3","dependabot-npm-and-yarn-moment-2-29-3-312b699e0064649a3f286f6e9d7cb837dff38aec":"0.2.3-dependabot-npm-and-yarn-moment-2-29-3-312b699e0064649a3f286f6e9d7cb837dff38aec","dependabot-npm-and-yarn-node-forge-1-3-1-fd3e783334351dec8d893cca0a52c4f4dfe7ac8d":"0.2.4-dependabot-npm-and-yarn-node-forge-1-3-1-fd3e783334351dec8d893cca0a52c4f4dfe7ac8d","dependabot-npm-and-yarn-google-cloud-functions-framework-3-1-1-dfef560917c4cb151a248258f92139ac736490d8":"0.2.4-dependabot-npm-and-yarn-google-cloud-functions-framework-3-1-1-dfef560917c4cb151a248258f92139ac736490d8","dependabot-npm-and-yarn-google-cloud-functions-framework-3-1-1-58e990e8530b0be79dfa036fad30318197590f7e":"0.2.5-dependabot-npm-and-yarn-google-cloud-functions-framework-3-1-1-58e990e8530b0be79dfa036fad30318197590f7e","dependabot-npm-and-yarn-google-cloud-functions-framework-3-1-2-bc00a4e5900a2ca4dfd837ecb084b4e76c2b466b":"0.2.5-dependabot-npm-and-yarn-google-cloud-functions-framework-3-1-2-bc00a4e5900a2ca4dfd837ecb084b4e76c2b466b","dependabot-npm-and-yarn-balena-sdk-16-22-0-14f427b32bf2be89722d613ff25928d178d92c0f":"0.2.5-dependabot-npm-and-yarn-balena-sdk-16-22-0-14f427b32bf2be89722d613ff25928d178d92c0f","doc-device-env-vars-fd750c9be0194b58d91e32531fb6768cfbbc623a":"0.2.5-doc-device-env-vars-fd750c9be0194b58d91e32531fb6768cfbbc623a","dependabot-npm-and-yarn-balena-sdk-16-22-0-0a2d6fd35c83a2cb526ba1dd48ba26640cb79e4b":"0.2.6-dependabot-npm-and-yarn-balena-sdk-16-22-0-0a2d6fd35c83a2cb526ba1dd48ba26640cb79e4b","uniform-readme-sections-5716c780868f8f33d9ba0275b116a9434b40526d":"0.2.6-uniform-readme-sections-5716c780868f8f33d9ba0275b116a9434b40526d","dependabot-npm-and-yarn-balena-sdk-16-22-0-bad5e68351a454284dd7f5fc02bbb30702cb852c":"0.2.7-dependabot-npm-and-yarn-balena-sdk-16-22-0-bad5e68351a454284dd7f5fc02bbb30702cb852c","dependabot-npm-and-yarn-balena-sdk-16-24-0-cee7aefb76ac8e6f577cb7f15a1c276bb190f803":"0.2.7-dependabot-npm-and-yarn-balena-sdk-16-24-0-cee7aefb76ac8e6f577cb7f15a1c276bb190f803","add-repo-yml-0f09d42662b1a0426f0a64d4c53ea9fe36c12e43":"0.2.7-add-repo-yml-0f09d42662b1a0426f0a64d4c53ea9fe36c12e43","latest":"0.2.7","dependabot-npm-and-yarn-moment-2-29-4-3c89a9bfdd6cd07673085dda5660f43122540b27":"0.2.8-dependabot-npm-and-yarn-moment-2-29-4-3c89a9bfdd6cd07673085dda5660f43122540b27","dependabot-npm-and-yarn-balena-sdk-16-24-0-e479ec99c7493b1767876aace931060e2ba779d1":"0.2.8-dependabot-npm-and-yarn-balena-sdk-16-24-0-e479ec99c7493b1767876aace931060e2ba779d1","dependabot-npm-and-yarn-balena-sdk-16-24-1-7c665096990208ee780836fc66c3f427b58842b3":"0.2.8-dependabot-npm-and-yarn-balena-sdk-16-24-1-7c665096990208ee780836fc66c3f427b58842b3","dependabot-npm-and-yarn-balena-sdk-16-25-1-7b00e089f16c793d9a6f0c297bf551174dc5d257":"0.2.8-dependabot-npm-and-yarn-balena-sdk-16-25-1-7b00e089f16c793d9a6f0c297bf551174dc5d257","dependabot-npm-and-yarn-balena-sdk-16-26-1-74dae0779fde7dd493a3edb773c03dac8363a525":"0.2.8-dependabot-npm-and-yarn-balena-sdk-16-26-1-74dae0779fde7dd493a3edb773c03dac8363a525","dependabot-npm-and-yarn-balena-sdk-16-26-2-ed8fde2922e091a06e196673eb570786e6750e66":"0.2.8-dependabot-npm-and-yarn-balena-sdk-16-26-2-ed8fde2922e091a06e196673eb570786e6750e66","dependabot-npm-and-yarn-balena-sdk-16-26-5-7bbc0e6ee003cee970259a7e257cc03566a8114d":"0.2.8-dependabot-npm-and-yarn-balena-sdk-16-26-5-7bbc0e6ee003cee970259a7e257cc03566a8114d","dependabot-npm-and-yarn-balena-sdk-16-27-0-cb71ef781b6efb37aaefa3eb61a4c20341d06eb6":"0.2.8-dependabot-npm-and-yarn-balena-sdk-16-27-0-cb71ef781b6efb37aaefa3eb61a4c20341d06eb6","dependabot-npm-and-yarn-balena-sdk-16-28-1-019ea09d1b26e78a3bdac40d7eb6aa83bfd0e5c3":"0.2.8-dependabot-npm-and-yarn-balena-sdk-16-28-1-019ea09d1b26e78a3bdac40d7eb6aa83bfd0e5c3","dependabot-npm-and-yarn-balena-sdk-16-28-2-d6a3b568c784f156bada381c3aa1fe5dfcb5e24e":"0.2.8-dependabot-npm-and-yarn-balena-sdk-16-28-2-d6a3b568c784f156bada381c3aa1fe5dfcb5e24e","dependabot-npm-and-yarn-balena-sdk-16-28-4-b597d1b00d9af56382041066e2a3057ec7d40d39":"0.2.8-dependabot-npm-and-yarn-balena-sdk-16-28-4-b597d1b00d9af56382041066e2a3057ec7d40d39"},"versions":{"0.1.0-use-api-key-70d014cd051671eac1c011b18a253b19833cfcec":{"name":"gcp-iot-provision","version":"0.1.0-use-api-key-70d014cd051671eac1c011b18a253b19833cfcec","keywords":["balena","balenaCloud","google","iotcore","iot","gcp"],"author":{"name":"Ken Bannister","email":"ken@balena.io"},"license":"Apache-2.0","_id":"gcp-iot-provision@0.1.0-use-api-key-70d014cd051671eac1c011b18a253b19833cfcec","maintainers":[{"name":"balena.io","email":"accounts+npm@balena.io"}],"homepage":"https://github.com/balena-io-examples/gcp-iot-provision","bugs":{"url":"https://github.com/balena-io-examples/gcp-iot-provision/issues"},"dist":{"shasum":"b7f1f26b7e6b12a477c3913c86759de49fa28f37","tarball":"https://registry.npmjs.org/gcp-iot-provision/-/gcp-iot-provision-0.1.0-use-api-key-70d014cd051671eac1c011b18a253b19833cfcec.tgz","fileCount":7,"integrity":"sha512-p/Tt5O1Dqs49dB01276Y6OHPJpGAdsheiYRWhDwd1a+NJxE/otMXMVLDCMrMDlKZwhtg6dL4Gjwdyym4tm9obg==","signatures":[{"sig":"MEUCIEHGIqqAiFJ8OOL85rtdmUPrk0DfZBJ+TveHDxFHD7oCAiEA14vl6XoP1Jdlu3u8MBgZ36omt3eb1M1/ZDQ9v0FaRFo=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":135516,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJigwKAACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmomSw//UMoXR5xbilXIGQ+7ygRPC4uJT7/X3xVbEHaaf0yasaTvNxmZ\r\nLNrfngk/2Hp+TeltXM9pBAlmep2i2GIq2g8lNlqyJGbWAs4D/lfTvbbSOQUC\r\ndpb/F3HU0d2x/tao8T8T4SjCBmklxBIiU+JCiISaB13qVRIjDbeLuGFKOeSG\r\np76eAGMXt0gLhmHOsqut+hgsKpepesDoQCSdCQrBfj5rNnkE1iqpUWKh1v3l\r\nFRKhfxfayVkECMYbIbM706i3Pr1dLor2erzg6Ph5PbbP40LgHmro2+2hS5k6\r\nUlK+t0512OapDialZtrlxPC33TF/SQbRVM81yxTtsJoG5wwAqacmSRu1DBfK\r\nq97I5WzdZUrj7mKqVAWO7wyM7PR4Vxa059jrf/b7eyLNYZboiOHe2m0irxB5\r\nqcIxZ3Oapxb6FdaTIAMGL0BpI6cKwMDm9sWrK40AOzkgH8cVhxSYeK4u6xc1\r\nhzGXvm40hYr5N0zu/zKwsdnmLw9MQlevRASljeQibKpIiMRWPgINKacQD9C4\r\nO3HJHPVSjjdYHsUxLwJeE5eJZMtqmqQqaRjYGu/FldXeC8OxPPDgY7pL+PVE\r\nj8LmkNqhZQpBsUVJgCG7WszJd3l7EVuLWkCanggLpuzj2lGKATwF06OOTI/7\r\n8+MyFP2aJ0IeWLieWiuVMS7n5lNnudA0yCA=\r\n=EjPC\r\n-----END PGP SIGNATURE-----\r\n"},"main":"index.js","type":"module","gitHead":"70d014cd051671eac1c011b18a253b19833cfcec","private":false,"scripts":{"start":"node index.js"},"_npmUser":{"name":"balena.io","email":"accounts+npm@balena.io"},"repository":{"url":"git+https://github.com/balena-io-examples/gcp-iot-provision.git","type":"git"},"versionist":{"publishedAt":"2022-05-17T02:01:37.400Z"},"_npmVersion":"6.14.17","description":"Google Cloud function to provision a balena device to IoT Core","directories":{},"_nodeVersion":"14.17.1","dependencies":{"balena-sdk":"^16.11.2","@google-cloud/iot":"^2.5.0","@google-cloud/functions-framework":"^2.1.0"},"_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/gcp-iot-provision_0.1.0-use-api-key-70d014cd051671eac1c011b18a253b19833cfcec_1652753024327_0.12207146678714298","host":"s3://npm-registry-packages"},"deprecated":"Deprecated: no longer maintained. The GitHub repository has been archived and no further releases will be published."},"0.1.0-use-api-key-34f0049bb856d6d788486d4b02becdba46778294":{"name":"gcp-iot-provision","version":"0.1.0-use-api-key-34f0049bb856d6d788486d4b02becdba46778294","keywords":["balena","balenaCloud","google","iotcore","iot","gcp"],"author":{"name":"Ken Bannister","email":"ken@balena.io"},"license":"Apache-2.0","_id":"gcp-iot-provision@0.1.0-use-api-key-34f0049bb856d6d788486d4b02becdba46778294","maintainers":[{"name":"balena.io","email":"accounts+npm@balena.io"}],"homepage":"https://github.com/balena-io-examples/gcp-iot-provision","bugs":{"url":"https://github.com/balena-io-examples/gcp-iot-provision/issues"},"dist":{"shasum":"ac4f02e90e50ed638a1ac0e8645b39c3bce01d63","tarball":"https://registry.npmjs.org/gcp-iot-provision/-/gcp-iot-provision-0.1.0-use-api-key-34f0049bb856d6d788486d4b02becdba46778294.tgz","fileCount":7,"integrity":"sha512-QMQh0idsOCRFhY7ibfq/UUYGdXYf8c9WuRba24rjmaSlm7x7W8jNok6spbi5f5plx2GUU1OS1BxA6pYjt9Mz3g==","signatures":[{"sig":"MEQCIAKKhWTLT4jX5t1ua6Hhm+XJv4xQwazYNNzq1bH8xsx6AiArPWK1kGC/MxazZOU5Pr1t8waoH2/MhhN8pBFHQYSNFQ==","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":135609,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJigwQ6ACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmpeAQ//fbwu/VRCxU/TP1myROFRzVd6BydgzHPAR4NO+7FktGjBr/yW\r\nkDYEdpa94h5Vmf+ir5hz+bgHqofX/S4KqCzNm7QLMP8ZbPdQzPeTqa6xesxy\r\nYDbPkSzXDwVp2Qjz41Vh1avg0XA7V781fWgPkHRbSWaOgx+RW0sNSvJsXJMt\r\nBJjxHmrEhZjG57zU/ZjXCfE5abL7i5dINqgBwU900Ty1kSwmlDqBJKDaxrQ7\r\nMl37GQVnNv5x6EdtIjPEnBeM013Yz4/TD6MheUMYatpNTNxWpmmCKPqtc4EL\r\nnVbC9yJUMm8dDuM3S4hA/dw3SH+ItREToeolNf6vc9wIs2caH1cffg3HiDnG\r\nC5DJB5Vl3kuI2QtgjX3JVAfmzJOCuMcOr1q6riqbfnQftnlPjwqfng/ZbbVq\r\n8eXWugGLBGdCGdqQ5rh1vhtpMt/xt+2rw91lI2UTd5watrf8w2hGyjFrP8WT\r\n3ajbR+tU4XbN0Mqk1gjXoS1TRSj9xFMtDFdAZCd/OBNaKUWz/BXibj7zX9HQ\r\nhTGZVR0Phwi53duo3uRllDx9Pp//lfszVIGhKyzesH8cpeCpqT2osjY15vuL\r\nEuGmJopwNurxKNZU5YAPMn9D7rRGNEQeONOKKa/WtNrFxvURc5rB5FhO2pHi\r\nF6lbHlZqg2ZEj4piLh4EMAS93p0QHHOBUW8=\r\n=NKp1\r\n-----END PGP SIGNATURE-----\r\n"},"main":"index.js","type":"module","readme":"# Google Cloud Function for IoT Device Provisioning\n\nThis Cloud Function allows you to provision and synchronize a balena device with Google Cloud IoT Core in a secure and automated way via an HTTP endpoint. The Cloud Function may be called by a balena device, as seen in the [cloud-relay](https://github.com/balena-io-examples/cloud-relay) example.\n\n| Method | Action |\n|-------------|--------|\n| POST | Provisions a balena device with IoT Core. First the function verifies the device UUID with balenaCloud. Then it creates a public/private key pair and adds the device to the registry. Finally the function pushes the private key to a balena device environment variable. |\n| DELETE | Removes a balena device from the IoT Core registry and removes the balena device environment variable for the private key. Essentially reverses the actions from provisioning with HTTP POST. |\n\n## Setup and Testing\n### Google Cloud setup\nThe Cloud Function interacts with Google Cloud IoT Core via client code operating with service account credentials. You must setup a Google Cloud project with an IoT Core registry. The service account must have the *Cloud IoT Provisioner* role to manage device records in the IoT Core registry. See the IoT Core [documentation](https://cloud.google.com/iot/docs/how-tos) for more background.\n\n### Development setup\nClone this repo\n```\n$ git clone https://github.com/balena-io-examples/gcp-iot-provision\n```\n\nThe sections below show how to test the Cloud Function on a local test server and deploy to Cloud Functions. In either case you must provide the environment variables in the table below as instructed for the test/deployment.\n\n| Key         |    Value    |\n|-------------|-------------|\n| BALENA_API_KEY | for use of balena API; found in balenaCloud dashboard at: `account -> Preferences -> Access tokens` |\n| GCP_PROJECT_ID | Google Cloud project ID, like `my-project-000000`|\n| GCP_REGION | Google Cloud region for registry, like `us-central1` |\n| GCP_REGISTRY_ID | Google Cloud registry ID you provided to create the registry |\n| GCP_SERVICE_ACCOUNT |base64 encoding of the JSON formatted GCP service account credentials provided by Google when you created the service account. Example below, assuming the credentials JSON is contained in a file.<br><br>`cat <credentials.txt> \\| base64 -w 0` |\n\n### HTTP API\nThe HTTP endpoint expects a request containing a JSON body with the attributes below. Use POST to add a device to the cloud registry, DELETE to remove.\n\n| Attribute | Value |\n|-----------|-------|\n| uuid | UUID of device  |\n| balena_service | (optional) Name of service container on balena device that uses provisioned key and certificate, for example `cloud-relay`. If defined, creates service level variables; otherwise creates device level variables. Service level variables are more secure. |\n\n\n### Test locally\nThe Google Functions Framework is a convenient tool for local testing. \nFirst, start a local HTTP server ([docs reference](https://cloud.google.com/functions/docs/running/function-frameworks)) using a script like below.\n\n```\nexport BALENA_API_KEY=<...>\n... <other environment variables from table above>\nexport GCP_SERVICE_ACCOUNT=<...>\n\nnpx @google-cloud/functions-framework --target=provision\n```\n\nNext, use `curl` to send an HTTP request to the local server to provision a device. See the *HTTP API* section above for body contents.\n\n```\ncurl -X POST http://localhost:8080 -H \"Content-Type:application/json\" \\\n   -d '{ \"uuid\": \"<device-uuid>\", \"balena_service\": \"<service-name>\" }'\n```\n\nAfter a successful POST, you should see the device appear in your IoT Core registry and `GCP_CLIENT_PATH`, `GCP_DATA_TOPIC_ROOT`, `GCP_PRIVATE_KEY`, and `GCP_PROJECT_ID` variables appear in balenaCloud for the device. After a successful DELETE, those variables disappear.\n\n## Deploy\nTo deploy to Cloud Functions, use the command below. See the [command documentation](https://cloud.google.com/sdk/gcloud/reference/functions/deploy) for the format of `yaml-file`, which contains the variables from the table in the *Development setup* section above.\n\n```\ngcloud functions deploy provision --runtime=nodejs14 --trigger-http \\\n   --env-vars-file=<yaml-file> --allow-unauthenticated \\\n   --service-account=<name>@<xxxx>.iam.gserviceaccount.com\n```\n\nThe result is a Cloud Function like below. Notice the `TRIGGER` tab, which provides the URL for the function.\n\n![Alt text](docs/cloud-function.png)\n\n### Test the Cloud Function\nTo test the function, use a command like below, where the URL is from the `TRIGGER` tab in the console. See the *HTTP API* section above for body contents.\n\n```\ncurl -X POST https://<region>-<projectID>.cloudfunctions.net/provision \\\n   -H \"Content-Type:application/json\" \\\n   -d '{ \"uuid\": \"<device-uuid>\", \"balena_service\": \"<service-name>\" }'\n```\n\nAfter a successful POST, you should see the device appear in your IoT Core registry and `GCP_CLIENT_PATH`, `GCP_DATA_TOPIC_ROOT`, `GCP_PRIVATE_KEY`, and `GCP_PROJECT_ID` variables appear in balenaCloud for the device. After a successful DELETE, those variables disappear.\n","gitHead":"34f0049bb856d6d788486d4b02becdba46778294","private":false,"scripts":{"test":"echo \"No tests yet\" && exit 0","start":"node index.js"},"_npmUser":{"name":"balena.io","email":"accounts+npm@balena.io"},"repository":{"url":"git+https://github.com/balena-io-examples/gcp-iot-provision.git","type":"git"},"versionist":{"publishedAt":"2022-05-17T02:08:59.471Z"},"_npmVersion":"6.14.17","description":"Google Cloud function to provision a balena device to IoT Core","directories":{},"_nodeVersion":"14.17.1","dependencies":{"balena-sdk":"^16.11.2","@google-cloud/iot":"^2.5.0","@google-cloud/functions-framework":"^2.1.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","_npmOperationalInternal":{"tmp":"tmp/gcp-iot-provision_0.1.0-use-api-key-34f0049bb856d6d788486d4b02becdba46778294_1652753466774_0.6216512563052814","host":"s3://npm-registry-packages"},"deprecated":"Deprecated: no longer maintained. The GitHub repository has been archived and no further releases will be published."},"0.2.0-dependabot-npm-and-yarn-minimist-1-2-6-6fcb6912765eed66678f8ffdba8110051bb65533":{"name":"gcp-iot-provision","version":"0.2.0-dependabot-npm-and-yarn-minimist-1-2-6-6fcb6912765eed66678f8ffdba8110051bb65533","keywords":["balena","balenaCloud","google","iotcore","iot","gcp"],"author":{"name":"Ken Bannister","email":"ken@balena.io"},"license":"Apache-2.0","_id":"gcp-iot-provision@0.2.0-dependabot-npm-and-yarn-minimist-1-2-6-6fcb6912765eed66678f8ffdba8110051bb65533","maintainers":[{"name":"balena.io","email":"accounts+npm@balena.io"}],"homepage":"https://github.com/balena-io-examples/gcp-iot-provision","bugs":{"url":"https://github.com/balena-io-examples/gcp-iot-provision/issues"},"dist":{"shasum":"beea44c84cb83248dfa67dc3f89aaaef0919169d","tarball":"https://registry.npmjs.org/gcp-iot-provision/-/gcp-iot-provision-0.2.0-dependabot-npm-and-yarn-minimist-1-2-6-6fcb6912765eed66678f8ffdba8110051bb65533.tgz","fileCount":7,"integrity":"sha512-Lx777NLk/qfteb3/c+POr1UW0auio9oyoaJQC0jUfpEkftMDMChec6DnXCpaBJ7q+I6gLk6vIuAYXRlGSc0gJw==","signatures":[{"sig":"MEUCIQCIJDVf9hDIxrFDVI6dfrTP9KK0XMagjyOwZOwBdhH5EwIgOhsZvnHR8qGjc8JJdQD9mczzpZWw7dEv3C8EbUhSz1k=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":135780,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJig6fWACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2Vmqb7Q/+JtiKXjpq29wNriBckGPHRefDMb74aYR8Wq01qvCDLKt/EYdu\r\nPyQPK29X06yl3XXZAevJ/DltLn3wJ6TnuvjG9NL2lOjxu6NLHNhOOz/rWKiX\r\nGjMeDM8ApX548IHy3dufWI9dcjJdAVI14hk2uhxuhalPEaP6bRF7kl+u8pxV\r\nWiwXHgqzHiBKyKiMio0/K9sF4GqaT/O34JZMDpvvcHdCtClBaCLCEt4DXjc7\r\nrXv+fG6ECsjk8dVaGYo7/krShw3NGMlUE2A8ZXTnCpC1amTG4O0UXku15aEM\r\nQ3fS2yyARYMJggXBfIQoYt9F1ZzUmoo3sd/07iCRmEFLp5v07mdkHNY4NFcx\r\nQ6pJKkKFO3LGBieAvTVVl3uHsF9m3aQOEOtdDMIA7etsHrLCKj3yPB9F9kZB\r\nQuXrSIL299FGLB9p5IzNJtGOaY3p8/TseOWfCrxXkcnB40+Vdv2nRFoYMYmz\r\nxs/3mPK5DUgHyVORkQmLnhYD4UmY/5vsOvOrrRkpLi+sR0QDPtLa1GKJJIpZ\r\nUx5OI+kBj+U58fJDvddmCuepYUIHhn8HDJFcR0rxljzOzTTWglQvvgvTF1jl\r\n8ERrdMI4UqrsIvIaFjFCXYQth1K/4jyqjts2YsiTX/79pLZj0tgAquMXksPp\r\nbd0DSi1WlnnehqX3CFuku6VTpRbSDz+65XQ=\r\n=uuEn\r\n-----END PGP SIGNATURE-----\r\n"},"main":"index.js","type":"module","readme":"# Google Cloud Function for IoT Device Provisioning\n\nThis Cloud Function allows you to provision and synchronize a balena device with Google Cloud IoT Core in a secure and automated way via an HTTP endpoint. The Cloud Function may be called by a balena device, as seen in the [cloud-relay](https://github.com/balena-io-examples/cloud-relay) example.\n\n| Method | Action |\n|-------------|--------|\n| POST | Provisions a balena device with IoT Core. First the function verifies the device UUID with balenaCloud. Then it creates a public/private key pair and adds the device to the registry. Finally the function pushes the private key to a balena device environment variable. |\n| DELETE | Removes a balena device from the IoT Core registry and removes the balena device environment variable for the private key. Essentially reverses the actions from provisioning with HTTP POST. |\n\n## Setup and Testing\n### Google Cloud setup\nThe Cloud Function interacts with Google Cloud IoT Core via client code operating with service account credentials. You must setup a Google Cloud project with an IoT Core registry. The service account must have the *Cloud IoT Provisioner* role to manage device records in the IoT Core registry. See the IoT Core [documentation](https://cloud.google.com/iot/docs/how-tos) for more background.\n\n### Development setup\nClone this repo\n```\n$ git clone https://github.com/balena-io-examples/gcp-iot-provision\n```\n\nThe sections below show how to test the Cloud Function on a local test server and deploy to Cloud Functions. In either case you must provide the environment variables in the table below as instructed for the test/deployment.\n\n| Key         |    Value    |\n|-------------|-------------|\n| BALENA_API_KEY | for use of balena API; found in balenaCloud dashboard at: `account -> Preferences -> Access tokens` |\n| GCP_PROJECT_ID | Google Cloud project ID, like `my-project-000000`|\n| GCP_REGION | Google Cloud region for registry, like `us-central1` |\n| GCP_REGISTRY_ID | Google Cloud registry ID you provided to create the registry |\n| GCP_SERVICE_ACCOUNT |base64 encoding of the JSON formatted GCP service account credentials provided by Google when you created the service account. Example below, assuming the credentials JSON is contained in a file.<br><br>`cat <credentials.txt> \\| base64 -w 0` |\n\n### HTTP API\nThe HTTP endpoint expects a request containing a JSON body with the attributes below. Use POST to add a device to the cloud registry, DELETE to remove.\n\n| Attribute | Value |\n|-----------|-------|\n| uuid | UUID of device  |\n| balena_service | (optional) Name of service container on balena device that uses provisioned key and certificate, for example `cloud-relay`. If defined, creates service level variables; otherwise creates device level variables. Service level variables are more secure. |\n\n\n### Test locally\nThe Google Functions Framework is a convenient tool for local testing. \nFirst, start a local HTTP server ([docs reference](https://cloud.google.com/functions/docs/running/function-frameworks)) using a script like below.\n\n```\nexport BALENA_API_KEY=<...>\n... <other environment variables from table above>\nexport GCP_SERVICE_ACCOUNT=<...>\n\nnpx @google-cloud/functions-framework --target=provision\n```\n\nNext, use `curl` to send an HTTP request to the local server to provision a device. See the *HTTP API* section above for body contents.\n\n```\ncurl -X POST http://localhost:8080 -H \"Content-Type:application/json\" \\\n   -d '{ \"uuid\": \"<device-uuid>\", \"balena_service\": \"<service-name>\" }'\n```\n\nAfter a successful POST, you should see the device appear in your IoT Core registry and `GCP_CLIENT_PATH`, `GCP_DATA_TOPIC_ROOT`, `GCP_PRIVATE_KEY`, and `GCP_PROJECT_ID` variables appear in balenaCloud for the device. After a successful DELETE, those variables disappear.\n\n## Deploy\nTo deploy to Cloud Functions, use the command below. See the [command documentation](https://cloud.google.com/sdk/gcloud/reference/functions/deploy) for the format of `yaml-file`, which contains the variables from the table in the *Development setup* section above.\n\n```\ngcloud functions deploy provision --runtime=nodejs14 --trigger-http \\\n   --env-vars-file=<yaml-file> --allow-unauthenticated \\\n   --service-account=<name>@<xxxx>.iam.gserviceaccount.com\n```\n\nThe result is a Cloud Function like below. Notice the `TRIGGER` tab, which provides the URL for the function.\n\n![Alt text](docs/cloud-function.png)\n\n### Test the Cloud Function\nTo test the function, use a command like below, where the URL is from the `TRIGGER` tab in the console. See the *HTTP API* section above for body contents.\n\n```\ncurl -X POST https://<region>-<projectID>.cloudfunctions.net/provision \\\n   -H \"Content-Type:application/json\" \\\n   -d '{ \"uuid\": \"<device-uuid>\", \"balena_service\": \"<service-name>\" }'\n```\n\nAfter a successful POST, you should see the device appear in your IoT Core registry and `GCP_CLIENT_PATH`, `GCP_DATA_TOPIC_ROOT`, `GCP_PRIVATE_KEY`, and `GCP_PROJECT_ID` variables appear in balenaCloud for the device. After a successful DELETE, those variables disappear.\n","gitHead":"6fcb6912765eed66678f8ffdba8110051bb65533","private":false,"scripts":{"test":"echo \"No tests yet\" && exit 0","start":"node index.js"},"_npmUser":{"name":"balena.io","email":"accounts+npm@balena.io"},"repository":{"url":"git+https://github.com/balena-io-examples/gcp-iot-provision.git","type":"git"},"versionist":{"publishedAt":"2022-05-17T13:47:11.840Z"},"_npmVersion":"6.14.17","description":"Google Cloud function to provision a balena device to IoT Core","directories":{},"_nodeVersion":"14.17.1","dependencies":{"balena-sdk":"^16.11.2","@google-cloud/iot":"^2.5.0","@google-cloud/functions-framework":"^2.1.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","_npmOperationalInternal":{"tmp":"tmp/gcp-iot-provision_0.2.0-dependabot-npm-and-yarn-minimist-1-2-6-6fcb6912765eed66678f8ffdba8110051bb65533_1652795350567_0.7905165614978771","host":"s3://npm-registry-packages"},"deprecated":"Deprecated: no longer maintained. The GitHub repository has been archived and no further releases will be published."},"0.2.0-dependabot-npm-and-yarn-moment-2-29-3-7c3bbbe07a24ed25ea7bd0a512b3c8beefc0b42b":{"name":"gcp-iot-provision","version":"0.2.0-dependabot-npm-and-yarn-moment-2-29-3-7c3bbbe07a24ed25ea7bd0a512b3c8beefc0b42b","keywords":["balena","balenaCloud","google","iotcore","iot","gcp"],"author":{"name":"Ken Bannister","email":"ken@balena.io"},"license":"Apache-2.0","_id":"gcp-iot-provision@0.2.0-dependabot-npm-and-yarn-moment-2-29-3-7c3bbbe07a24ed25ea7bd0a512b3c8beefc0b42b","maintainers":[{"name":"balena.io","email":"accounts+npm@balena.io"}],"homepage":"https://github.com/balena-io-examples/gcp-iot-provision","bugs":{"url":"https://github.com/balena-io-examples/gcp-iot-provision/issues"},"dist":{"shasum":"c436e656347ecc78ad77cff18e924fdf828488ed","tarball":"https://registry.npmjs.org/gcp-iot-provision/-/gcp-iot-provision-0.2.0-dependabot-npm-and-yarn-moment-2-29-3-7c3bbbe07a24ed25ea7bd0a512b3c8beefc0b42b.tgz","fileCount":7,"integrity":"sha512-pTCmRZtp2638/mqZ82teDwvXFRDl4YzdYkUjmdZwqQ183riVtiLIaqu6H2vm4tm+3PbtW9z1dw1MaN2fDnM1Qw==","signatures":[{"sig":"MEUCIHa6zHTsDuWK5tWvL5h6Dh6UVB2hiHCHOKun/97QpPY6AiEA1Zr6/jkSxDo0GH9xr10OB41glGDV06GHgAjQmH/ZHns=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":135779,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJig7kjACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmoDTw/8DoZrOZcGYm+VjrY3Ex4MNPKa7iVdifBY1H70sA3ThBvgo4VO\r\nj+lenOSPoo+NTbn+hOQsz8UV6Aoq8SJ501CVtAQyifb5P3KOAhu9hVUvGJ8+\r\n+4mI/R2ukey3vhEFTxHQRvRWyQzjhuQACXZ0qjJ47QE188NXMvy6ZLx7/RZ2\r\nPHsk+vUBLuofgXGU14CnH4XZTYkULBz/W1yXV/4nh3y4Z172bvO/BJz02R3A\r\nqDpw5JuqycDVEpLX6qRQlKXqHJaYUAqgJNwbcyNfr0qkmvmRNlwwMul5yAxE\r\nLENkAazqoWtnB09zk8wE/Dg+WEjp1v15Dv7Nja7Nb5CyY04xDiijwqOjJak/\r\nVPNemeMQyi9hV5pDqes1NsrxqBLPmEzERBcPuAJnnZNunAzXsX1dUtJ89AL6\r\nYZYy12MmgRCkr+FvvKCNQd2eAGr1E+ZHUMgxVMIVdHfl6KSoJ4/fVXCAe7K+\r\nbJF1+SC4jHHndR2edWIY+SAHjtCUNK43QMkD+N+MPQ207dcWN2nYGw4L2vpw\r\nuDzwVMiAGUjV//l5r/B4W361IUCvxEPWzt4mUFAUYKqjbot+/2Ye4+Uo5nhM\r\n8flL5bfcDHjhXzDjTY5uPyO34Ohe9DluN3VbmSbE35gb4vXi+Ip2kIuBxsMs\r\nRuls4Piuzxe0bPjqXTrgfJpTCRce8ew0EAU=\r\n=WeA5\r\n-----END PGP SIGNATURE-----\r\n"},"main":"index.js","type":"module","readme":"# Google Cloud Function for IoT Device Provisioning\n\nThis Cloud Function allows you to provision and synchronize a balena device with Google Cloud IoT Core in a secure and automated way via an HTTP endpoint. The Cloud Function may be called by a balena device, as seen in the [cloud-relay](https://github.com/balena-io-examples/cloud-relay) example.\n\n| Method | Action |\n|-------------|--------|\n| POST | Provisions a balena device with IoT Core. First the function verifies the device UUID with balenaCloud. Then it creates a public/private key pair and adds the device to the registry. Finally the function pushes the private key to a balena device environment variable. |\n| DELETE | Removes a balena device from the IoT Core registry and removes the balena device environment variable for the private key. Essentially reverses the actions from provisioning with HTTP POST. |\n\n## Setup and Testing\n### Google Cloud setup\nThe Cloud Function interacts with Google Cloud IoT Core via client code operating with service account credentials. You must setup a Google Cloud project with an IoT Core registry. The service account must have the *Cloud IoT Provisioner* role to manage device records in the IoT Core registry. See the IoT Core [documentation](https://cloud.google.com/iot/docs/how-tos) for more background.\n\n### Development setup\nClone this repo\n```\n$ git clone https://github.com/balena-io-examples/gcp-iot-provision\n```\n\nThe sections below show how to test the Cloud Function on a local test server and deploy to Cloud Functions. In either case you must provide the environment variables in the table below as instructed for the test/deployment.\n\n| Key         |    Value    |\n|-------------|-------------|\n| BALENA_API_KEY | for use of balena API; found in balenaCloud dashboard at: `account -> Preferences -> Access tokens` |\n| GCP_PROJECT_ID | Google Cloud project ID, like `my-project-000000`|\n| GCP_REGION | Google Cloud region for registry, like `us-central1` |\n| GCP_REGISTRY_ID | Google Cloud registry ID you provided to create the registry |\n| GCP_SERVICE_ACCOUNT |base64 encoding of the JSON formatted GCP service account credentials provided by Google when you created the service account. Example below, assuming the credentials JSON is contained in a file.<br><br>`cat <credentials.txt> \\| base64 -w 0` |\n\n### HTTP API\nThe HTTP endpoint expects a request containing a JSON body with the attributes below. Use POST to add a device to the cloud registry, DELETE to remove.\n\n| Attribute | Value |\n|-----------|-------|\n| uuid | UUID of device  |\n| balena_service | (optional) Name of service container on balena device that uses provisioned key and certificate, for example `cloud-relay`. If defined, creates service level variables; otherwise creates device level variables. Service level variables are more secure. |\n\n\n### Test locally\nThe Google Functions Framework is a convenient tool for local testing. \nFirst, start a local HTTP server ([docs reference](https://cloud.google.com/functions/docs/running/function-frameworks)) using a script like below.\n\n```\nexport BALENA_API_KEY=<...>\n... <other environment variables from table above>\nexport GCP_SERVICE_ACCOUNT=<...>\n\nnpx @google-cloud/functions-framework --target=provision\n```\n\nNext, use `curl` to send an HTTP request to the local server to provision a device. See the *HTTP API* section above for body contents.\n\n```\ncurl -X POST http://localhost:8080 -H \"Content-Type:application/json\" \\\n   -d '{ \"uuid\": \"<device-uuid>\", \"balena_service\": \"<service-name>\" }'\n```\n\nAfter a successful POST, you should see the device appear in your IoT Core registry and `GCP_CLIENT_PATH`, `GCP_DATA_TOPIC_ROOT`, `GCP_PRIVATE_KEY`, and `GCP_PROJECT_ID` variables appear in balenaCloud for the device. After a successful DELETE, those variables disappear.\n\n## Deploy\nTo deploy to Cloud Functions, use the command below. See the [command documentation](https://cloud.google.com/sdk/gcloud/reference/functions/deploy) for the format of `yaml-file`, which contains the variables from the table in the *Development setup* section above.\n\n```\ngcloud functions deploy provision --runtime=nodejs14 --trigger-http \\\n   --env-vars-file=<yaml-file> --allow-unauthenticated \\\n   --service-account=<name>@<xxxx>.iam.gserviceaccount.com\n```\n\nThe result is a Cloud Function like below. Notice the `TRIGGER` tab, which provides the URL for the function.\n\n![Alt text](docs/cloud-function.png)\n\n### Test the Cloud Function\nTo test the function, use a command like below, where the URL is from the `TRIGGER` tab in the console. See the *HTTP API* section above for body contents.\n\n```\ncurl -X POST https://<region>-<projectID>.cloudfunctions.net/provision \\\n   -H \"Content-Type:application/json\" \\\n   -d '{ \"uuid\": \"<device-uuid>\", \"balena_service\": \"<service-name>\" }'\n```\n\nAfter a successful POST, you should see the device appear in your IoT Core registry and `GCP_CLIENT_PATH`, `GCP_DATA_TOPIC_ROOT`, `GCP_PRIVATE_KEY`, and `GCP_PROJECT_ID` variables appear in balenaCloud for the device. After a successful DELETE, those variables disappear.\n","gitHead":"7c3bbbe07a24ed25ea7bd0a512b3c8beefc0b42b","private":false,"scripts":{"test":"echo \"No tests yet\" && exit 0","start":"node index.js"},"_npmUser":{"name":"balena.io","email":"accounts+npm@balena.io"},"repository":{"url":"git+https://github.com/balena-io-examples/gcp-iot-provision.git","type":"git"},"versionist":{"publishedAt":"2022-05-17T15:00:07.485Z"},"_npmVersion":"6.14.17","description":"Google Cloud function to provision a balena device to IoT Core","directories":{},"_nodeVersion":"14.17.1","dependencies":{"balena-sdk":"^16.11.2","@google-cloud/iot":"^2.5.0","@google-cloud/functions-framework":"^2.1.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","_npmOperationalInternal":{"tmp":"tmp/gcp-iot-provision_0.2.0-dependabot-npm-and-yarn-moment-2-29-3-7c3bbbe07a24ed25ea7bd0a512b3c8beefc0b42b_1652799779552_0.7211013872781362","host":"s3://npm-registry-packages"},"deprecated":"Deprecated: no longer maintained. The GitHub repository has been archived and no further releases will be published."},"0.2.0-dependabot-npm-and-yarn-node-forge-1-3-1-34801fadbe6449712929c65e58bef087ddfdee49":{"name":"gcp-iot-provision","version":"0.2.0-dependabot-npm-and-yarn-node-forge-1-3-1-34801fadbe6449712929c65e58bef087ddfdee49","keywords":["balena","balenaCloud","google","iotcore","iot","gcp"],"author":{"name":"Ken Bannister","email":"ken@balena.io"},"license":"Apache-2.0","_id":"gcp-iot-provision@0.2.0-dependabot-npm-and-yarn-node-forge-1-3-1-34801fadbe6449712929c65e58bef087ddfdee49","maintainers":[{"name":"balena.io","email":"accounts+npm@balena.io"}],"homepage":"https://github.com/balena-io-examples/gcp-iot-provision","bugs":{"url":"https://github.com/balena-io-examples/gcp-iot-provision/issues"},"dist":{"shasum":"9c105f6c41cf9742bbf3042ac0d38c0767326a88","tarball":"https://registry.npmjs.org/gcp-iot-provision/-/gcp-iot-provision-0.2.0-dependabot-npm-and-yarn-node-forge-1-3-1-34801fadbe6449712929c65e58bef087ddfdee49.tgz","fileCount":7,"integrity":"sha512-0q+tSosPepwI4W4l7u4PI7e5nPbGM623vfM/JairDZyH/bu794+TDfVSJTJpJD/vSFHQ3Uhbv92+kebx9Sotrw==","signatures":[{"sig":"MEUCID78h5MlCmfZ5B3rd7J1QkMjxap69AlLi4hgY9aFGsVxAiEAyE0+42KBfY192Du8EqRYyfmB3yeJg3Nk53sjOlZYVGE=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":135782,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJig7k8ACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmrqUQ/+P57N1UX6yX0Gf9r/6WNo7XQ9QZkhIms0FwbGiY8cuIxM2XTs\r\n7MCgY6atXYeeukr05APN4yVSxESQXCaf8boHE7czY5XqAmTGFMK5Fki3E5S7\r\nVXdlM9HjuCXIGnmFQRLwGqOUzvZJrhyD/6Li40osZ32wGZZBCVUWf8kqaXxP\r\n6AZHsEPhMORA/ZmQ7FtWgcoj9mF1KTc+WArkySzyHweRYt5y8XbJ+xM/QQ31\r\nMTCLVccIanNYy9Oz2nm1LktJOm0Gt+z3V/Va+kXAkURMNRqLxAeynw0lWJ7k\r\nyCsWRTg0CtKOl65EqTR29lpO666/qI1FIwnwzx4Onau3tYi0IXru58r3SvXK\r\nlArP2iGRz2CIxOafyV8ehwn8mCI02ZD7RpOMvqO+kpHbI4ciqB9/Jo0iUf9F\r\nW4q0pk747RXZxK7Kp/v2w3KJigSBCh4RiqKI1EJvjEs6hGYc8GtQFHpqsSo6\r\nyrMoNY8P4lXfUgA0KpiGTaYR2jry6DgZpWJRl0nnPUEu5DabvbvOGlI3w5XL\r\nwN/LP70bm23WMqMQPn4GPlXGGdgl7arTc6bDAl2kL0Gnzmfval7qSLVVV4+y\r\nihUO76+aGyvfk8gSbtiR2+OsQ6TodHiFep+djIg/OAUofGrbgE0vzJw6/fe9\r\n0BiZzV8Y6xUfmBwtzGQsG43hDOY/zxSHysY=\r\n=xnsh\r\n-----END PGP SIGNATURE-----\r\n"},"main":"index.js","type":"module","readme":"# Google Cloud Function for IoT Device Provisioning\n\nThis Cloud Function allows you to provision and synchronize a balena device with Google Cloud IoT Core in a secure and automated way via an HTTP endpoint. The Cloud Function may be called by a balena device, as seen in the [cloud-relay](https://github.com/balena-io-examples/cloud-relay) example.\n\n| Method | Action |\n|-------------|--------|\n| POST | Provisions a balena device with IoT Core. First the function verifies the device UUID with balenaCloud. Then it creates a public/private key pair and adds the device to the registry. Finally the function pushes the private key to a balena device environment variable. |\n| DELETE | Removes a balena device from the IoT Core registry and removes the balena device environment variable for the private key. Essentially reverses the actions from provisioning with HTTP POST. |\n\n## Setup and Testing\n### Google Cloud setup\nThe Cloud Function interacts with Google Cloud IoT Core via client code operating with service account credentials. You must setup a Google Cloud project with an IoT Core registry. The service account must have the *Cloud IoT Provisioner* role to manage device records in the IoT Core registry. See the IoT Core [documentation](https://cloud.google.com/iot/docs/how-tos) for more background.\n\n### Development setup\nClone this repo\n```\n$ git clone https://github.com/balena-io-examples/gcp-iot-provision\n```\n\nThe sections below show how to test the Cloud Function on a local test server and deploy to Cloud Functions. In either case you must provide the environment variables in the table below as instructed for the test/deployment.\n\n| Key         |    Value    |\n|-------------|-------------|\n| BALENA_API_KEY | for use of balena API; found in balenaCloud dashboard at: `account -> Preferences -> Access tokens` |\n| GCP_PROJECT_ID | Google Cloud project ID, like `my-project-000000`|\n| GCP_REGION | Google Cloud region for registry, like `us-central1` |\n| GCP_REGISTRY_ID | Google Cloud registry ID you provided to create the registry |\n| GCP_SERVICE_ACCOUNT |base64 encoding of the JSON formatted GCP service account credentials provided by Google when you created the service account. Example below, assuming the credentials JSON is contained in a file.<br><br>`cat <credentials.txt> \\| base64 -w 0` |\n\n### HTTP API\nThe HTTP endpoint expects a request containing a JSON body with the attributes below. Use POST to add a device to the cloud registry, DELETE to remove.\n\n| Attribute | Value |\n|-----------|-------|\n| uuid | UUID of device  |\n| balena_service | (optional) Name of service container on balena device that uses provisioned key and certificate, for example `cloud-relay`. If defined, creates service level variables; otherwise creates device level variables. Service level variables are more secure. |\n\n\n### Test locally\nThe Google Functions Framework is a convenient tool for local testing. \nFirst, start a local HTTP server ([docs reference](https://cloud.google.com/functions/docs/running/function-frameworks)) using a script like below.\n\n```\nexport BALENA_API_KEY=<...>\n... <other environment variables from table above>\nexport GCP_SERVICE_ACCOUNT=<...>\n\nnpx @google-cloud/functions-framework --target=provision\n```\n\nNext, use `curl` to send an HTTP request to the local server to provision a device. See the *HTTP API* section above for body contents.\n\n```\ncurl -X POST http://localhost:8080 -H \"Content-Type:application/json\" \\\n   -d '{ \"uuid\": \"<device-uuid>\", \"balena_service\": \"<service-name>\" }'\n```\n\nAfter a successful POST, you should see the device appear in your IoT Core registry and `GCP_CLIENT_PATH`, `GCP_DATA_TOPIC_ROOT`, `GCP_PRIVATE_KEY`, and `GCP_PROJECT_ID` variables appear in balenaCloud for the device. After a successful DELETE, those variables disappear.\n\n## Deploy\nTo deploy to Cloud Functions, use the command below. See the [command documentation](https://cloud.google.com/sdk/gcloud/reference/functions/deploy) for the format of `yaml-file`, which contains the variables from the table in the *Development setup* section above.\n\n```\ngcloud functions deploy provision --runtime=nodejs14 --trigger-http \\\n   --env-vars-file=<yaml-file> --allow-unauthenticated \\\n   --service-account=<name>@<xxxx>.iam.gserviceaccount.com\n```\n\nThe result is a Cloud Function like below. Notice the `TRIGGER` tab, which provides the URL for the function.\n\n![Alt text](docs/cloud-function.png)\n\n### Test the Cloud Function\nTo test the function, use a command like below, where the URL is from the `TRIGGER` tab in the console. See the *HTTP API* section above for body contents.\n\n```\ncurl -X POST https://<region>-<projectID>.cloudfunctions.net/provision \\\n   -H \"Content-Type:application/json\" \\\n   -d '{ \"uuid\": \"<device-uuid>\", \"balena_service\": \"<service-name>\" }'\n```\n\nAfter a successful POST, you should see the device appear in your IoT Core registry and `GCP_CLIENT_PATH`, `GCP_DATA_TOPIC_ROOT`, `GCP_PRIVATE_KEY`, and `GCP_PROJECT_ID` variables appear in balenaCloud for the device. After a successful DELETE, those variables disappear.\n","gitHead":"34801fadbe6449712929c65e58bef087ddfdee49","private":false,"scripts":{"test":"echo \"No tests yet\" && exit 0","start":"node index.js"},"_npmUser":{"name":"balena.io","email":"accounts+npm@balena.io"},"repository":{"url":"git+https://github.com/balena-io-examples/gcp-iot-provision.git","type":"git"},"versionist":{"publishedAt":"2022-05-17T15:00:39.424Z"},"_npmVersion":"6.14.17","description":"Google Cloud function to provision a balena device to IoT Core","directories":{},"_nodeVersion":"14.17.1","dependencies":{"balena-sdk":"^16.11.2","@google-cloud/iot":"^2.5.0","@google-cloud/functions-framework":"^2.1.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","_npmOperationalInternal":{"tmp":"tmp/gcp-iot-provision_0.2.0-dependabot-npm-and-yarn-node-forge-1-3-1-34801fadbe6449712929c65e58bef087ddfdee49_1652799804429_0.8332334072362733","host":"s3://npm-registry-packages"},"deprecated":"Deprecated: no longer maintained. The GitHub repository has been archived and no further releases will be published."},"0.2.0-dependabot-automation-bd10fbdcd31aed687926e3c7a678772e985af583":{"name":"gcp-iot-provision","version":"0.2.0-dependabot-automation-bd10fbdcd31aed687926e3c7a678772e985af583","keywords":["balena","balenaCloud","google","iotcore","iot","gcp"],"author":{"name":"Ken Bannister","email":"ken@balena.io"},"license":"Apache-2.0","_id":"gcp-iot-provision@0.2.0-dependabot-automation-bd10fbdcd31aed687926e3c7a678772e985af583","maintainers":[{"name":"balena.io","email":"accounts+npm@balena.io"}],"homepage":"https://github.com/balena-io-examples/gcp-iot-provision","bugs":{"url":"https://github.com/balena-io-examples/gcp-iot-provision/issues"},"dist":{"shasum":"61d843176123dd85f433317f067dbf39fdd2399f","tarball":"https://registry.npmjs.org/gcp-iot-provision/-/gcp-iot-provision-0.2.0-dependabot-automation-bd10fbdcd31aed687926e3c7a678772e985af583.tgz","fileCount":8,"integrity":"sha512-HUX0XJIVjq0t0+X5o6aSRizNXhI+Ck2Xlrjtij211URjnARFrPsTU9SKQD+0n28JWGbTaQt3dsOiXTsZcmo+QQ==","signatures":[{"sig":"MEUCIQCKvPR9UPHJXAGm7KAwBG/r3p0CDtCUrl6lNm71gFQM6wIgSYI3IohoEaQsADieZF1GTGZhT7abLEweKf3WTfHCHC4=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":136019,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJig7ntACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmqT+hAAogN5p29FeltAxzONp6HqSShYymb8V4WCZtddS7vMz4r7FUHy\r\nL1TfhT0ZDBLp1dI+ictbNnNy5b6SPcXxB+k3ffoSn+8a6c25ODLtDzPntsUK\r\nQ9fBGF3HRWNNEqm800I6CAINn6BIPYLcF5umPiRYp3Jh1WiAxY+fjr/aVGSI\r\ncrwU3wG3C+AcdWb0ZgODM2y2p4bfHUtXvzTIwO+FPe0Qoy2HJmEKNgEA4C2s\r\nksVl/+Nj8c6TG7FtWyf+6DT6W3ss5N/Wtmr4fsVAXzlebGNN9ngTMmxnff/d\r\nHq2g3eEvtUVt2jK9B5tR8N9FZbwjQPEr5H3N4nHEo3LZ72BQ3vTyChHHA9vn\r\nEtuOG1W5xBBZA612Ssul2rso8ut3ZlhsZn7KpNVdi2gP+qASaBJjGWTHr6pt\r\nlDCMrPzP9A3e6qiZAmaLlRQJOu/2tMyGrcKAtdbADRjl22sKOBkilXFU+FoV\r\n4q2h9dNXx5gNNK8SUg9G6T+VNSp6bWwsNM9K76RwyQTdI2q9pYMrQqqSElTd\r\nHIV34m1LgfCqEWHSNEblQXbJ0s6kQRaUCRVMapITpEvVQtf9aF4QCj1TGugI\r\n7/nRybzYmWmHDiaFMypSeqPcKKiNlJLsyxTLam2k3fM14Vvx/PwHfdpYgJGo\r\niY3GuhLlWJhtnIAcb9u+RR7YF6sygr6pR60=\r\n=koh0\r\n-----END PGP SIGNATURE-----\r\n"},"main":"index.js","type":"module","readme":"# Google Cloud Function for IoT Device Provisioning\n\nThis Cloud Function allows you to provision and synchronize a balena device with Google Cloud IoT Core in a secure and automated way via an HTTP endpoint. The Cloud Function may be called by a balena device, as seen in the [cloud-relay](https://github.com/balena-io-examples/cloud-relay) example.\n\n| Method | Action |\n|-------------|--------|\n| POST | Provisions a balena device with IoT Core. First the function verifies the device UUID with balenaCloud. Then it creates a public/private key pair and adds the device to the registry. Finally the function pushes the private key to a balena device environment variable. |\n| DELETE | Removes a balena device from the IoT Core registry and removes the balena device environment variable for the private key. Essentially reverses the actions from provisioning with HTTP POST. |\n\n## Setup and Testing\n### Google Cloud setup\nThe Cloud Function interacts with Google Cloud IoT Core via client code operating with service account credentials. You must setup a Google Cloud project with an IoT Core registry. The service account must have the *Cloud IoT Provisioner* role to manage device records in the IoT Core registry. See the IoT Core [documentation](https://cloud.google.com/iot/docs/how-tos) for more background.\n\n### Development setup\nClone this repo\n```\n$ git clone https://github.com/balena-io-examples/gcp-iot-provision\n```\n\nThe sections below show how to test the Cloud Function on a local test server and deploy to Cloud Functions. In either case you must provide the environment variables in the table below as instructed for the test/deployment.\n\n| Key         |    Value    |\n|-------------|-------------|\n| BALENA_API_KEY | for use of balena API; found in balenaCloud dashboard at: `account -> Preferences -> Access tokens` |\n| GCP_PROJECT_ID | Google Cloud project ID, like `my-project-000000`|\n| GCP_REGION | Google Cloud region for registry, like `us-central1` |\n| GCP_REGISTRY_ID | Google Cloud registry ID you provided to create the registry |\n| GCP_SERVICE_ACCOUNT |base64 encoding of the JSON formatted GCP service account credentials provided by Google when you created the service account. Example below, assuming the credentials JSON is contained in a file.<br><br>`cat <credentials.txt> \\| base64 -w 0` |\n\n### HTTP API\nThe HTTP endpoint expects a request containing a JSON body with the attributes below. Use POST to add a device to the cloud registry, DELETE to remove.\n\n| Attribute | Value |\n|-----------|-------|\n| uuid | UUID of device  |\n| balena_service | (optional) Name of service container on balena device that uses provisioned key and certificate, for example `cloud-relay`. If defined, creates service level variables; otherwise creates device level variables. Service level variables are more secure. |\n\n\n### Test locally\nThe Google Functions Framework is a convenient tool for local testing. \nFirst, start a local HTTP server ([docs reference](https://cloud.google.com/functions/docs/running/function-frameworks)) using a script like below.\n\n```\nexport BALENA_API_KEY=<...>\n... <other environment variables from table above>\nexport GCP_SERVICE_ACCOUNT=<...>\n\nnpx @google-cloud/functions-framework --target=provision\n```\n\nNext, use `curl` to send an HTTP request to the local server to provision a device. See the *HTTP API* section above for body contents.\n\n```\ncurl -X POST http://localhost:8080 -H \"Content-Type:application/json\" \\\n   -d '{ \"uuid\": \"<device-uuid>\", \"balena_service\": \"<service-name>\" }'\n```\n\nAfter a successful POST, you should see the device appear in your IoT Core registry and `GCP_CLIENT_PATH`, `GCP_DATA_TOPIC_ROOT`, `GCP_PRIVATE_KEY`, and `GCP_PROJECT_ID` variables appear in balenaCloud for the device. After a successful DELETE, those variables disappear.\n\n## Deploy\nTo deploy to Cloud Functions, use the command below. See the [command documentation](https://cloud.google.com/sdk/gcloud/reference/functions/deploy) for the format of `yaml-file`, which contains the variables from the table in the *Development setup* section above.\n\n```\ngcloud functions deploy provision --runtime=nodejs14 --trigger-http \\\n   --env-vars-file=<yaml-file> --allow-unauthenticated \\\n   --service-account=<name>@<xxxx>.iam.gserviceaccount.com\n```\n\nThe result is a Cloud Function like below. Notice the `TRIGGER` tab, which provides the URL for the function.\n\n![Alt text](docs/cloud-function.png)\n\n### Test the Cloud Function\nTo test the function, use a command like below, where the URL is from the `TRIGGER` tab in the console. See the *HTTP API* section above for body contents.\n\n```\ncurl -X POST https://<region>-<projectID>.cloudfunctions.net/provision \\\n   -H \"Content-Type:application/json\" \\\n   -d '{ \"uuid\": \"<device-uuid>\", \"balena_service\": \"<service-name>\" }'\n```\n\nAfter a successful POST, you should see the device appear in your IoT Core registry and `GCP_CLIENT_PATH`, `GCP_DATA_TOPIC_ROOT`, `GCP_PRIVATE_KEY`, and `GCP_PROJECT_ID` variables appear in balenaCloud for the device. After a successful DELETE, those variables disappear.\n","gitHead":"bd10fbdcd31aed687926e3c7a678772e985af583","private":false,"scripts":{"test":"echo \"No tests yet\" && exit 0","start":"node index.js"},"_npmUser":{"name":"balena.io","email":"accounts+npm@balena.io"},"repository":{"url":"git+https://github.com/balena-io-examples/gcp-iot-provision.git","type":"git"},"versionist":{"publishedAt":"2022-05-17T15:04:09.471Z"},"_npmVersion":"6.14.17","description":"Google Cloud function to provision a balena device to IoT Core","directories":{},"_nodeVersion":"14.17.1","dependencies":{"balena-sdk":"^16.11.2","@google-cloud/iot":"^2.5.0","@google-cloud/functions-framework":"^2.1.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","_npmOperationalInternal":{"tmp":"tmp/gcp-iot-provision_0.2.0-dependabot-automation-bd10fbdcd31aed687926e3c7a678772e985af583_1652799981025_0.9797703913069917","host":"s3://npm-registry-packages"},"deprecated":"Deprecated: no longer maintained. The GitHub repository has been archived and no further releases will be published."},"0.2.0":{"name":"gcp-iot-provision","version":"0.2.0","keywords":["balena","balenaCloud","google","iotcore","iot","gcp"],"author":{"name":"Ken Bannister","email":"ken@balena.io"},"license":"Apache-2.0","_id":"gcp-iot-provision@0.2.0","maintainers":[{"name":"balena.io","email":"accounts+npm@balena.io"}],"homepage":"https://github.com/balena-io-examples/gcp-iot-provision","bugs":{"url":"https://github.com/balena-io-examples/gcp-iot-provision/issues"},"dist":{"shasum":"e5b955ddf242c61eee17afe5d679f7417e9df488","tarball":"https://registry.npmjs.org/gcp-iot-provision/-/gcp-iot-provision-0.2.0.tgz","fileCount":8,"integrity":"sha512-qTPt+1wIU1Jj1zmjDkGo0d+rozZMo/8of2ofXAXu4NGX2C8hjzTz8eAcrgmH1uVg6kZFeXf2HLpZTka1oaIIRw==","signatures":[{"sig":"MEUCIQCYb0/qf3aKll+L47f5Z56psHfVust/pJeJmO0EyEdVLwIgCcAvGkePZIE7hOuFOAglcn0sHxtamNXM2Sp+Jq23qS0=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":135956,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJig73fACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2Vmr+hA/8CZwV5OP9Ge6YUToHW/AuchziDb/m3GbMiSymlX52ca0c8da4\r\n5ykpij0ISpaWJ3OKF/C98bEaTO5XsfEHYYhiCi+Z7RNi5UADpNXANcBw3DNF\r\nxJG9k6qeYusnzbkC1IW+LpSKGfsfmoohhRaq5VdgPO6cTgasi2TibOh6ImFl\r\n4/3FBPprBmlLOXT7aKQWXY6RbeYYNNWqBw+FTdavzHrn3Tr+zfcV+cjoStRJ\r\nXzTeQ1kzfQjVpfv6M8zaBgPg4Mc3DBPd84QdGJ24kA17Htf0irlY9UKWnBuy\r\nYYsTxYMF2gvA0yDhrXnwi38m42ULT5jaZr9I7y4+OwHsRYWMNmdnPph5heBp\r\nA/ZNwstWmJzxueHPaZdrKexMUDycBg4ENSc0tvHdbCpNaxoQpTuD+xsCLt8Q\r\n6sd1n7pxq/j2b1pGAIWW0Kb00zoBZrWhiUq5OODoyb/yOLSIWZud77Fg89oz\r\nBLX1moN3Ycis9A9rEH1BWcHnRLfAZv0h6jefr/P5EbnfT+xQ9TCCadz8C7kS\r\nB33WsHPDOnrrpkfwf4WJMEJCP/OA/ixKUn+klLzBEE6HXsc0X7moOzJnP5kZ\r\nthGkKK7AUKWNdigY5mKQdAXBy5SidXZMusHHtDgCfet2zh/LpJ387kK79DAd\r\nfcIXVJcXxDuAvPajvz0lGO1g/MhnwXbTSkE=\r\n=eoza\r\n-----END PGP SIGNATURE-----\r\n"},"main":"index.js","type":"module","gitHead":"9e261b18f898e47af39b5d03f480c15a268497ae","private":false,"scripts":{"test":"echo \"No tests yet\" && exit 0","start":"node index.js"},"_npmUser":{"name":"balena.io","email":"accounts+npm@balena.io"},"repository":{"url":"git+https://github.com/balena-io-examples/gcp-iot-provision.git","type":"git"},"versionist":{"publishedAt":"2022-05-17T15:21:21.420Z"},"_npmVersion":"6.14.17","description":"Google Cloud function to provision a balena device to IoT Core","directories":{},"_nodeVersion":"14.17.1","dependencies":{"balena-sdk":"^16.11.2","@google-cloud/iot":"^2.5.0","@google-cloud/functions-framework":"^2.1.0"},"_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/gcp-iot-provision_0.2.0_1652800991381_0.8156724903298462","host":"s3://npm-registry-packages"},"deprecated":"Deprecated: no longer maintained. The GitHub repository has been archived and no further releases will be published."},"0.2.1-fix-dependabot-location-19e04aee08846ffec9536de7216601c0ffa9f4ee":{"name":"gcp-iot-provision","version":"0.2.1-fix-dependabot-location-19e04aee08846ffec9536de7216601c0ffa9f4ee","keywords":["balena","balenaCloud","google","iotcore","iot","gcp"],"author":{"name":"Ken Bannister","email":"ken@balena.io"},"license":"Apache-2.0","_id":"gcp-iot-provision@0.2.1-fix-dependabot-location-19e04aee08846ffec9536de7216601c0ffa9f4ee","maintainers":[{"name":"balena.io","email":"accounts+npm@balena.io"}],"homepage":"https://github.com/balena-io-examples/gcp-iot-provision","bugs":{"url":"https://github.com/balena-io-examples/gcp-iot-provision/issues"},"dist":{"shasum":"f28396ff5099a7fb49e5c9c495c726b49ce1db4f","tarball":"https://registry.npmjs.org/gcp-iot-provision/-/gcp-iot-provision-0.2.1-fix-dependabot-location-19e04aee08846ffec9536de7216601c0ffa9f4ee.tgz","fileCount":8,"integrity":"sha512-AvOZRG3wDKmfshP6Ji/oNh7o/whW/TardlOxRWrncHY3HDlaBfq1RY+moTu1uBc/sMs4eDTSkbyAsUtM+tQ5uQ==","signatures":[{"sig":"MEUCIQCrIrf5VIkxpucfx+Su9kGYUUzgXopYt6KOorceTBWaQwIgT543MEx8v8pKvjCBON0Xm0voOviRFX1vZRwNGiNr9IM=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":136110,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJig88VACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmpA4g/9ENCrn3WQqVum48em2sbnrTwIxANGqpQKwAJcz7fAi1w1janx\r\nIDz23pz9+5ntOhTATsq9AqhlpMo+c0OmmPhC2JpQVzVGxDmNX4YgkR1CU6oO\r\nMIgovk/DPwrpwXc+OjatWZ128mT23id98WlysqUfGvI6nIfbg53d4RLh8ctw\r\nzFhKOJwx2Rp4u3VaRX6+4Zwts9J3z7VDlUpnARkjieJ8QxjxjdLDmTVKo8v6\r\n22viQZ8nYNGOZ5L7RGYh7Kt8n51/oEOHr9qAQ2PRpLkXYECUI+aG1ewiqzRm\r\nXzOxC1rDaNGHX5/cneuEuXnVLLyl45c0E6Au6a7kzAnMJHilULyoXonVWDF2\r\na0pFi3Cvz5akUHB1KGl3Yhmba4Yn7G+/ueFS68pzhqgFGR0DBYIBc+5GO9r0\r\nX3+VgXtbPHFmdqELfCB7zRpD920g6po6JYZJNJnv6B9Cne90wjsSueLG4WDx\r\ncQWlDT0MVrxEaK+FdaVSHsMn8Gk6WsRHPHQh5b6S0JdsPtHxOhOEizvwoTDh\r\ny5xH31sU/ugryqXViGT4BIIuPqOqQFCDbh6uYb7fo+a15wRa/jMnxZNnYv0W\r\nskYg5uxrVE6y8jXGb7QQwMYnd8k/FMZrLn/bV/UiPZsh6gdiQgVH4940fL3z\r\n1DH8kfP8C9//Eh/WeSwJG6Am2Eja3o3TcgM=\r\n=bt0j\r\n-----END PGP SIGNATURE-----\r\n"},"main":"index.js","type":"module","readme":"# Google Cloud Function for IoT Device Provisioning\n\nThis Cloud Function allows you to provision and synchronize a balena device with Google Cloud IoT Core in a secure and automated way via an HTTP endpoint. The Cloud Function may be called by a balena device, as seen in the [cloud-relay](https://github.com/balena-io-examples/cloud-relay) example.\n\n| Method | Action |\n|-------------|--------|\n| POST | Provisions a balena device with IoT Core. First the function verifies the device UUID with balenaCloud. Then it creates a public/private key pair and adds the device to the registry. Finally the function pushes the private key to a balena device environment variable. |\n| DELETE | Removes a balena device from the IoT Core registry and removes the balena device environment variable for the private key. Essentially reverses the actions from provisioning with HTTP POST. |\n\n## Setup and Testing\n### Google Cloud setup\nThe Cloud Function interacts with Google Cloud IoT Core via client code operating with service account credentials. You must setup a Google Cloud project with an IoT Core registry. The service account must have the *Cloud IoT Provisioner* role to manage device records in the IoT Core registry. See the IoT Core [documentation](https://cloud.google.com/iot/docs/how-tos) for more background.\n\n### Development setup\nClone this repo\n```\n$ git clone https://github.com/balena-io-examples/gcp-iot-provision\n```\n\nThe sections below show how to test the Cloud Function on a local test server and deploy to Cloud Functions. In either case you must provide the environment variables in the table below as instructed for the test/deployment.\n\n| Key         |    Value    |\n|-------------|-------------|\n| BALENA_API_KEY | for use of balena API; found in balenaCloud dashboard at: `account -> Preferences -> Access tokens` |\n| GCP_PROJECT_ID | Google Cloud project ID, like `my-project-000000`|\n| GCP_REGION | Google Cloud region for registry, like `us-central1` |\n| GCP_REGISTRY_ID | Google Cloud registry ID you provided to create the registry |\n| GCP_SERVICE_ACCOUNT |base64 encoding of the JSON formatted GCP service account credentials provided by Google when you created the service account. Example below, assuming the credentials JSON is contained in a file.<br><br>`cat <credentials.txt> \\| base64 -w 0` |\n\n### HTTP API\nThe HTTP endpoint expects a request containing a JSON body with the attributes below. Use POST to add a device to the cloud registry, DELETE to remove.\n\n| Attribute | Value |\n|-----------|-------|\n| uuid | UUID of device  |\n| balena_service | (optional) Name of service container on balena device that uses provisioned key and certificate, for example `cloud-relay`. If defined, creates service level variables; otherwise creates device level variables. Service level variables are more secure. |\n\n\n### Test locally\nThe Google Functions Framework is a convenient tool for local testing. \nFirst, start a local HTTP server ([docs reference](https://cloud.google.com/functions/docs/running/function-frameworks)) using a script like below.\n\n```\nexport BALENA_API_KEY=<...>\n... <other environment variables from table above>\nexport GCP_SERVICE_ACCOUNT=<...>\n\nnpx @google-cloud/functions-framework --target=provision\n```\n\nNext, use `curl` to send an HTTP request to the local server to provision a device. See the *HTTP API* section above for body contents.\n\n```\ncurl -X POST http://localhost:8080 -H \"Content-Type:application/json\" \\\n   -d '{ \"uuid\": \"<device-uuid>\", \"balena_service\": \"<service-name>\" }'\n```\n\nAfter a successful POST, you should see the device appear in your IoT Core registry and `GCP_CLIENT_PATH`, `GCP_DATA_TOPIC_ROOT`, `GCP_PRIVATE_KEY`, and `GCP_PROJECT_ID` variables appear in balenaCloud for the device. After a successful DELETE, those variables disappear.\n\n## Deploy\nTo deploy to Cloud Functions, use the command below. See the [command documentation](https://cloud.google.com/sdk/gcloud/reference/functions/deploy) for the format of `yaml-file`, which contains the variables from the table in the *Development setup* section above.\n\n```\ngcloud functions deploy provision --runtime=nodejs14 --trigger-http \\\n   --env-vars-file=<yaml-file> --allow-unauthenticated \\\n   --service-account=<name>@<xxxx>.iam.gserviceaccount.com\n```\n\nThe result is a Cloud Function like below. Notice the `TRIGGER` tab, which provides the URL for the function.\n\n![Alt text](docs/cloud-function.png)\n\n### Test the Cloud Function\nTo test the function, use a command like below, where the URL is from the `TRIGGER` tab in the console. See the *HTTP API* section above for body contents.\n\n```\ncurl -X POST https://<region>-<projectID>.cloudfunctions.net/provision \\\n   -H \"Content-Type:application/json\" \\\n   -d '{ \"uuid\": \"<device-uuid>\", \"balena_service\": \"<service-name>\" }'\n```\n\nAfter a successful POST, you should see the device appear in your IoT Core registry and `GCP_CLIENT_PATH`, `GCP_DATA_TOPIC_ROOT`, `GCP_PRIVATE_KEY`, and `GCP_PROJECT_ID` variables appear in balenaCloud for the device. After a successful DELETE, those variables disappear.\n","gitHead":"19e04aee08846ffec9536de7216601c0ffa9f4ee","private":false,"scripts":{"test":"echo \"No tests yet\" && exit 0","start":"node index.js"},"_npmUser":{"name":"balena.io","email":"accounts+npm@balena.io"},"repository":{"url":"git+https://github.com/balena-io-examples/gcp-iot-provision.git","type":"git"},"versionist":{"publishedAt":"2022-05-17T16:34:05.249Z"},"_npmVersion":"6.14.17","description":"Google Cloud function to provision a balena device to IoT Core","directories":{},"_nodeVersion":"14.17.1","dependencies":{"balena-sdk":"^16.11.2","@google-cloud/iot":"^2.5.0","@google-cloud/functions-framework":"^2.1.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","_npmOperationalInternal":{"tmp":"tmp/gcp-iot-provision_0.2.1-fix-dependabot-location-19e04aee08846ffec9536de7216601c0ffa9f4ee_1652805397747_0.4525883482729991","host":"s3://npm-registry-packages"},"deprecated":"Deprecated: no longer maintained. The GitHub repository has been archived and no further releases will be published."},"0.2.1":{"name":"gcp-iot-provision","version":"0.2.1","keywords":["balena","balenaCloud","google","iotcore","iot","gcp"],"author":{"name":"Ken Bannister","email":"ken@balena.io"},"license":"Apache-2.0","_id":"gcp-iot-provision@0.2.1","maintainers":[{"name":"balena.io","email":"accounts+npm@balena.io"}],"homepage":"https://github.com/balena-io-examples/gcp-iot-provision","bugs":{"url":"https://github.com/balena-io-examples/gcp-iot-provision/issues"},"dist":{"shasum":"79394328b30cf4427c3aca3d94ee0030facc5d17","tarball":"https://registry.npmjs.org/gcp-iot-provision/-/gcp-iot-provision-0.2.1.tgz","fileCount":8,"integrity":"sha512-U8Gnjwp0Oi9GjhT8STeEYA/aSLY4qw8hrR3W/Rlk11fS0rdezW0yDbPQVq5ozpZEBGMTxxi+KWd0uQ+yplMtNA==","signatures":[{"sig":"MEUCIQCEiunCJt+KNv5+FAK13pS7v/WR0/NyhGgfD+ipIVLHrwIgG8aHT4wlGkBQl6WURVldnZO49N3TGO3TlblH6ud3qH8=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":136045,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJig9B2ACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2Vmq0hw//cCMZYL1vPQ2fhmcT+oYvoRlq7+hq8d1Yv7jBJTobgG/M7IrM\r\nQydCB6oeT2LCseL84SSVa1lrK+D0TCvR4LjUaMh4rdNGoJQhJhMbd4ZE1+Wm\r\nJ3u7FK9FZBAsHMFa0fwuuVSH2jaufxl/sFsWdYSXi8ti4oXsnhjwjbnJm8om\r\noG8ETBXcwvphNOm/eo01GOXVbY17ipeHgD40Tl0gt5VMu/z4Vv33Fe+b+sik\r\n54rxFyr+oen1cuF7yhIv8Yk0TjpZCQgP3EVzpLwNT94O3LO31J5GZTCDmY1D\r\n+mKPUD9Uks9DMqnX4+4FXgxZfQNZJzZ5Z7KrQuTNGem6isi2gF2rNKjcoD0/\r\nNKdmIfBP+O/cCw5Yq6npT9BDHYGktVG6Kqzxgn9r4XKXvEhLnMG8I5ml2mIh\r\nMBdSy/uNfjxiKYEFAqQhXQG8YEsX/zvvMsfmbdEZXuPCMYI8DWVenY2UrGaO\r\nvgBA4tsdtUeY5thseeB2Ymibrr1bYBmbb6sGFnKgD4i6Fzcr2fX1NEkOFd2K\r\nRUdKvgGUDrmsh2VdT83FNzCbkgoV6gCYlb4FRQ9f1xisePaF7Yv0kPvV81UQ\r\nvzsbARtVBBvPZSs4PjOm8v0a8yI+9YLzpwuXYf3vlaO7ARYaaXMwcyZk3tQs\r\nC1cpDEGqptzLwpazyNy/MGDP/bMlQQNjGqM=\r\n=Onxv\r\n-----END PGP SIGNATURE-----\r\n"},"main":"index.js","type":"module","gitHead":"be831d4bc1fbd4100756898e524d3fe559463584","private":false,"scripts":{"test":"echo \"No tests yet\" && exit 0","start":"node index.js"},"_npmUser":{"name":"balena.io","email":"accounts+npm@balena.io"},"repository":{"url":"git+https://github.com/balena-io-examples/gcp-iot-provision.git","type":"git"},"versionist":{"publishedAt":"2022-05-17T16:40:17.274Z"},"_npmVersion":"6.14.17","description":"Google Cloud function to provision a balena device to IoT Core","directories":{},"_nodeVersion":"14.17.1","dependencies":{"balena-sdk":"^16.11.2","@google-cloud/iot":"^2.5.0","@google-cloud/functions-framework":"^2.1.0"},"_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/gcp-iot-provision_0.2.1_1652805750742_0.8872481590092498","host":"s3://npm-registry-packages"},"deprecated":"Deprecated: no longer maintained. The GitHub repository has been archived and no further releases will be published."},"0.2.2-dependabot-npm-and-yarn-minimist-1-2-6-3f850e85b59a5f8fe4b98e32af8d035b9f50feb3":{"name":"gcp-iot-provision","version":"0.2.2-dependabot-npm-and-yarn-minimist-1-2-6-3f850e85b59a5f8fe4b98e32af8d035b9f50feb3","keywords":["balena","balenaCloud","google","iotcore","iot","gcp"],"author":{"name":"Ken Bannister","email":"ken@balena.io"},"license":"Apache-2.0","_id":"gcp-iot-provision@0.2.2-dependabot-npm-and-yarn-minimist-1-2-6-3f850e85b59a5f8fe4b98e32af8d035b9f50feb3","maintainers":[{"name":"balena.io","email":"accounts+npm@balena.io"}],"homepage":"https://github.com/balena-io-examples/gcp-iot-provision","bugs":{"url":"https://github.com/balena-io-examples/gcp-iot-provision/issues"},"dist":{"shasum":"6fa13c7137feb450399f01a975c77554dc73fbf7","tarball":"https://registry.npmjs.org/gcp-iot-provision/-/gcp-iot-provision-0.2.2-dependabot-npm-and-yarn-minimist-1-2-6-3f850e85b59a5f8fe4b98e32af8d035b9f50feb3.tgz","fileCount":8,"integrity":"sha512-VoYEgYCYg73w4I/+15DPJQLD0W/HLT2+jPzOqlps6B5CzSgHm/GI+X80r/giMyljdkWh2SbMNBJI+UausMqRBA==","signatures":[{"sig":"MEQCIHIAd+950uJBxmFYBf+xd8luQhckdKrn0f1pU0E1jscrAiAuWFhMt+umiSHnpPfhkHs8DhQiHtxK2Cj9PBASXIgVqw==","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":136213,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJihAUhACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmoY0A/7BRDuRZFeekyeD7bU5GwPFrLOhS6wpySOZajaQlDvwtfguxNi\r\ng5n60rI8DeOYc/Jgn6rJV+vuVOO+aGSbV+g9OsS+vQNs59XhuAUxUGwidgt3\r\nWtYUvl8FxR6JR3q5VgDXL+FitCXy0rTZNxebcETdYgW7Ubvy44gAI2wb1Zjm\r\nL1lwmuQmBLj5iiGHoNnbIGStVx300GioBnpuZUeP7Ks/O60Qi99f/7HjMVsM\r\n/e21FshFzOq4/YCvnuJyDOJFqyRhBs1LQUd+455fyON4yG1ColOuHq4PpCCT\r\ntpyct/HbKJotNuHLhbHvoPR5/QgU5tNQa2PhMAAGxUaUYsrMPC2NBc5pOuPc\r\n0mbhphZ2/Jim8dFEiZ/141BTlCrKGjLsz9oEHmiZxYcyaIMr/gcxFRdeVIjK\r\nCuMokfxjvQk2LGm5yLbjrZvJixSogjugZt8R7yX+xuPzIRk5poxmRuQGw9Qr\r\n/7FlKiEueCjWpGkigbawQbKo+lRAmcDLAPk8qVSvkW2vcDKufkb3He3dun7x\r\nVrLnEu2TGGv6P8r/LHAKTh9pLv0kmC3vb2kv+E3wYQRfNMDS4vJBgE9NgJaT\r\nEhev2jqDSE4cSl9l2wCc4MjrUUK4COqt2nDhiaAFYmqgsHNKcG3BMWfZIQgB\r\nDWbatPFY77RqvBi0lk34F2kj9DdW3g1fPXc=\r\n=s3P3\r\n-----END PGP SIGNATURE-----\r\n"},"main":"index.js","type":"module","readme":"# Google Cloud Function for IoT Device Provisioning\n\nThis Cloud Function allows you to provision and synchronize a balena device with Google Cloud IoT Core in a secure and automated way via an HTTP endpoint. The Cloud Function may be called by a balena device, as seen in the [cloud-relay](https://github.com/balena-io-examples/cloud-relay) example.\n\n| Method | Action |\n|-------------|--------|\n| POST | Provisions a balena device with IoT Core. First the function verifies the device UUID with balenaCloud. Then it creates a public/private key pair and adds the device to the registry. Finally the function pushes the private key to a balena device environment variable. |\n| DELETE | Removes a balena device from the IoT Core registry and removes the balena device environment variable for the private key. Essentially reverses the actions from provisioning with HTTP POST. |\n\n## Setup and Testing\n### Google Cloud setup\nThe Cloud Function interacts with Google Cloud IoT Core via client code operating with service account credentials. You must setup a Google Cloud project with an IoT Core registry. The service account must have the *Cloud IoT Provisioner* role to manage device records in the IoT Core registry. See the IoT Core [documentation](https://cloud.google.com/iot/docs/how-tos) for more background.\n\n### Development setup\nClone this repo\n```\n$ git clone https://github.com/balena-io-examples/gcp-iot-provision\n```\n\nThe sections below show how to test the Cloud Function on a local test server and deploy to Cloud Functions. In either case you must provide the environment variables in the table below as instructed for the test/deployment.\n\n| Key         |    Value    |\n|-------------|-------------|\n| BALENA_API_KEY | for use of balena API; found in balenaCloud dashboard at: `account -> Preferences -> Access tokens` |\n| GCP_PROJECT_ID | Google Cloud project ID, like `my-project-000000`|\n| GCP_REGION | Google Cloud region for registry, like `us-central1` |\n| GCP_REGISTRY_ID | Google Cloud registry ID you provided to create the registry |\n| GCP_SERVICE_ACCOUNT |base64 encoding of the JSON formatted GCP service account credentials provided by Google when you created the service account. Example below, assuming the credentials JSON is contained in a file.<br><br>`cat <credentials.txt> \\| base64 -w 0` |\n\n### HTTP API\nThe HTTP endpoint expects a request containing a JSON body with the attributes below. Use POST to add a device to the cloud registry, DELETE to remove.\n\n| Attribute | Value |\n|-----------|-------|\n| uuid | UUID of device  |\n| balena_service | (optional) Name of service container on balena device that uses provisioned key and certificate, for example `cloud-relay`. If defined, creates service level variables; otherwise creates device level variables. Service level variables are more secure. |\n\n\n### Test locally\nThe Google Functions Framework is a convenient tool for local testing. \nFirst, start a local HTTP server ([docs reference](https://cloud.google.com/functions/docs/running/function-frameworks)) using a script like below.\n\n```\nexport BALENA_API_KEY=<...>\n... <other environment variables from table above>\nexport GCP_SERVICE_ACCOUNT=<...>\n\nnpx @google-cloud/functions-framework --target=provision\n```\n\nNext, use `curl` to send an HTTP request to the local server to provision a device. See the *HTTP API* section above for body contents.\n\n```\ncurl -X POST http://localhost:8080 -H \"Content-Type:application/json\" \\\n   -d '{ \"uuid\": \"<device-uuid>\", \"balena_service\": \"<service-name>\" }'\n```\n\nAfter a successful POST, you should see the device appear in your IoT Core registry and `GCP_CLIENT_PATH`, `GCP_DATA_TOPIC_ROOT`, `GCP_PRIVATE_KEY`, and `GCP_PROJECT_ID` variables appear in balenaCloud for the device. After a successful DELETE, those variables disappear.\n\n## Deploy\nTo deploy to Cloud Functions, use the command below. See the [command documentation](https://cloud.google.com/sdk/gcloud/reference/functions/deploy) for the format of `yaml-file`, which contains the variables from the table in the *Development setup* section above.\n\n```\ngcloud functions deploy provision --runtime=nodejs14 --trigger-http \\\n   --env-vars-file=<yaml-file> --allow-unauthenticated \\\n   --service-account=<name>@<xxxx>.iam.gserviceaccount.com\n```\n\nThe result is a Cloud Function like below. Notice the `TRIGGER` tab, which provides the URL for the function.\n\n![Alt text](docs/cloud-function.png)\n\n### Test the Cloud Function\nTo test the function, use a command like below, where the URL is from the `TRIGGER` tab in the console. See the *HTTP API* section above for body contents.\n\n```\ncurl -X POST https://<region>-<projectID>.cloudfunctions.net/provision \\\n   -H \"Content-Type:application/json\" \\\n   -d '{ \"uuid\": \"<device-uuid>\", \"balena_service\": \"<service-name>\" }'\n```\n\nAfter a successful POST, you should see the device appear in your IoT Core registry and `GCP_CLIENT_PATH`, `GCP_DATA_TOPIC_ROOT`, `GCP_PRIVATE_KEY`, and `GCP_PROJECT_ID` variables appear in balenaCloud for the device. After a successful DELETE, those variables disappear.\n","gitHead":"3f850e85b59a5f8fe4b98e32af8d035b9f50feb3","private":false,"scripts":{"test":"echo \"No tests yet\" && exit 0","start":"node index.js"},"_npmUser":{"name":"balena.io","email":"accounts+npm@balena.io"},"repository":{"url":"git+https://github.com/balena-io-examples/gcp-iot-provision.git","type":"git"},"versionist":{"publishedAt":"2022-05-17T20:25:30.436Z"},"_npmVersion":"6.14.17","description":"Google Cloud function to provision a balena device to IoT Core","directories":{},"_nodeVersion":"14.17.1","dependencies":{"balena-sdk":"^16.11.2","@google-cloud/iot":"^2.5.0","@google-cloud/functions-framework":"^2.1.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","_npmOperationalInternal":{"tmp":"tmp/gcp-iot-provision_0.2.2-dependabot-npm-and-yarn-minimist-1-2-6-3f850e85b59a5f8fe4b98e32af8d035b9f50feb3_1652819232955_0.6093284564030175","host":"s3://npm-registry-packages"},"deprecated":"Deprecated: no longer maintained. The GitHub repository has been archived and no further releases will be published."},"0.2.2":{"name":"gcp-iot-provision","version":"0.2.2","keywords":["balena","balenaCloud","google","iotcore","iot","gcp"],"author":{"name":"Ken Bannister","email":"ken@balena.io"},"license":"Apache-2.0","_id":"gcp-iot-provision@0.2.2","maintainers":[{"name":"balena.io","email":"accounts+npm@balena.io"}],"homepage":"https://github.com/balena-io-examples/gcp-iot-provision","bugs":{"url":"https://github.com/balena-io-examples/gcp-iot-provision/issues"},"dist":{"shasum":"2baae4c0b3cdbb36129542b22fda8fe2a4b9ab01","tarball":"https://registry.npmjs.org/gcp-iot-provision/-/gcp-iot-provision-0.2.2.tgz","fileCount":8,"integrity":"sha512-cD7s3uO91ifhfrkaJQD/lsdDu3PhfRo9API6DR35/Mo/dEMdoZhEkVV3j2Kwi2g6PrN+JaGh1v5QkML0Rw2N8g==","signatures":[{"sig":"MEUCICwqCt2RTGKdEKjhDv6nsHfKK67XsgzGPgh0Y8cYBjHUAiEA9NFJgZvED/tmtsay7ZPBX3GLzq2p9NOxbsiIvheOgdE=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":136133,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJihAdtACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2Vmo9yBAAjvF+4iowWY2bZCbBnnTZdVRjLTXjCCtJOJvPATSap3DGdFjw\r\nBPkfc3XYOdJEij3SrOiP8akwjpIIDMZRI9mPz6cr5UHG81FCo9u7oEhGklRG\r\n9j6lCiQnC7K9JYV2Yb27Yx84pI9gDb+4A/Dzrux+GrWj1crqc1cBht8xf6hx\r\n03+YfBNUmcj8p4Atljpfj/ZXgT1UduVtxTpPU9wgOQW9HytHqXiiU/ednG2n\r\nGyM4QZKSsADuHj3uDCR0T2MGGjKmWukaCtrKmy6azi19DOpQHSKdzUo7NXch\r\nfgi7rpkKhcUfbfOTe3+9oyKbBtgcldd11/l6Z/b9Ij+W8Qe1lfC2mhcvtbwS\r\nZluseDeU1SNbyUi62lH3VDI0DSF2zcuOagVsiPepsci98faUxzwXNGSa+Ne4\r\nhhVwHqL+4eOSVGuF44qwhX5rm7dPh5J9LlE+iV5mLy+ptT+9zQDUJbqey8bt\r\nsWIKQ2DypC6r2jlC3BqcOZO6PAC6jjH5+KRxPeAN5McY0fTfddO5kUlE55gd\r\nmx05KLqkmwpqA/aqQwiUmonYynbWeeA8oJtQYs8MYWToF169JsPt2cKJ/EfK\r\nkNcfFSOJaoMko9j8sFAXoDnqyyvJpN3tJEYGpRKUYFHpTCFkDcbiU63AEdte\r\nZvk1MerSAIeYBPTZpyqJW4/PhOcCW+kFO8Y=\r\n=f6Iq\r\n-----END PGP SIGNATURE-----\r\n"},"main":"index.js","type":"module","gitHead":"5c3c66192b5600becb91a24519f3e0cdde650c46","private":false,"scripts":{"test":"echo \"No tests yet\" && exit 0","start":"node index.js"},"_npmUser":{"name":"balena.io","email":"accounts+npm@balena.io"},"repository":{"url":"git+https://github.com/balena-io-examples/gcp-iot-provision.git","type":"git"},"versionist":{"publishedAt":"2022-05-17T20:34:56.916Z"},"_npmVersion":"6.14.17","description":"Google Cloud function to provision a balena device to IoT Core","directories":{},"_nodeVersion":"14.17.1","dependencies":{"balena-sdk":"^16.11.2","@google-cloud/iot":"^2.5.0","@google-cloud/functions-framework":"^2.1.0"},"_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/gcp-iot-provision_0.2.2_1652819821456_0.5614277385170585","host":"s3://npm-registry-packages"},"deprecated":"Deprecated: no longer maintained. The GitHub repository has been archived and no further releases will be published."},"0.2.3-dependabot-npm-and-yarn-moment-2-29-3-312b699e0064649a3f286f6e9d7cb837dff38aec":{"name":"gcp-iot-provision","version":"0.2.3-dependabot-npm-and-yarn-moment-2-29-3-312b699e0064649a3f286f6e9d7cb837dff38aec","keywords":["balena","balenaCloud","google","iotcore","iot","gcp"],"author":{"name":"Ken Bannister","email":"ken@balena.io"},"license":"Apache-2.0","_id":"gcp-iot-provision@0.2.3-dependabot-npm-and-yarn-moment-2-29-3-312b699e0064649a3f286f6e9d7cb837dff38aec","maintainers":[{"name":"balena.io","email":"accounts+npm@balena.io"}],"homepage":"https://github.com/balena-io-examples/gcp-iot-provision","bugs":{"url":"https://github.com/balena-io-examples/gcp-iot-provision/issues"},"dist":{"shasum":"fcf8d212cc571d05b415966e67c8887ed41cb924","tarball":"https://registry.npmjs.org/gcp-iot-provision/-/gcp-iot-provision-0.2.3-dependabot-npm-and-yarn-moment-2-29-3-312b699e0064649a3f286f6e9d7cb837dff38aec.tgz","fileCount":8,"integrity":"sha512-y/BxFoNOEsCSFB0CfkG8Ht7c9pJjYHuYwrJY8goQunqAFliWd/JMdBAedEF+FqPby519fxE0mkwnNtJdnGiL3Q==","signatures":[{"sig":"MEUCIEQ9sjiF35TCbvAWDVwplMhIheUh8coNRqLw2fL6TFK/AiEAn2rYXBCe6qQ9h/509Nn9OzGabByF5pYP2hasiUbw5qM=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":136300,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJihAyIACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2Vmp2kQ/7BBMlzXeyfWYcQapdjfGtcxSTev6JtEoEK3D3lOk0+XnGI6ZP\r\n8GyAdFe1t7CuWzZpvIJuzW5f+5oEWLHJfEXjYReVXdBIU9+GZj9vhNau/8ZD\r\nOXsyKOml5S+e8OQ+IuDV+jTCHfh5vnNGlnhbconcObag8/x/q08eEbDWOt08\r\n9Jbf1ZyQfPF4/1R2vYEYKNVq3rsGquAS9OC+76+5BJms1V0CQmm0/i0N2Vht\r\n//oSbV5u8my++T6K9cqVsmfXylblhCuLme+FhBXtPl1oy6iJfMFiLXDqXI/I\r\nW7COF9xfc+zuNT02cs8v+51I3g6aMZPCIBEkk3rdWe3R1lBXkOuVDyCF4LSz\r\n4TgEaBR3dpm8jEZh/JR/4nu/u8osVWc2aU5KZdD29f8eu7SWYT+atL4zbAVK\r\nySm1NgBftmU1jYCV07vRtgxHawrD1WUrWg5pzzwXALm8WkC2Aa4RZvPH4pb9\r\n3jXy9MRfn+OqOrRQbXCDwswXrqtfOK/G7tzif5zpF83mNi8DDoUrQUn5laqY\r\nyP0MweKiT18ikkpjD9fCIzgG/I0jpLZZk1WxgNAKICMg8lFFdnMudt6ZTefj\r\nEBx/g+tev46wjXx1Y7xKjHfG2BqdbhUvYchgcD31TY7pfpCvx4Np7UCWBkQv\r\nxP+wqhwglD+ysf9tzkTVeJy7+cfe2jknaok=\r\n=9J52\r\n-----END PGP SIGNATURE-----\r\n"},"main":"index.js","type":"module","readme":"# Google Cloud Function for IoT Device Provisioning\n\nThis Cloud Function allows you to provision and synchronize a balena device with Google Cloud IoT Core in a secure and automated way via an HTTP endpoint. The Cloud Function may be called by a balena device, as seen in the [cloud-relay](https://github.com/balena-io-examples/cloud-relay) example.\n\n| Method | Action |\n|-------------|--------|\n| POST | Provisions a balena device with IoT Core. First the function verifies the device UUID with balenaCloud. Then it creates a public/private key pair and adds the device to the registry. Finally the function pushes the private key to a balena device environment variable. |\n| DELETE | Removes a balena device from the IoT Core registry and removes the balena device environment variable for the private key. Essentially reverses the actions from provisioning with HTTP POST. |\n\n## Setup and Testing\n### Google Cloud setup\nThe Cloud Function interacts with Google Cloud IoT Core via client code operating with service account credentials. You must setup a Google Cloud project with an IoT Core registry. The service account must have the *Cloud IoT Provisioner* role to manage device records in the IoT Core registry. See the IoT Core [documentation](https://cloud.google.com/iot/docs/how-tos) for more background.\n\n### Development setup\nClone this repo\n```\n$ git clone https://github.com/balena-io-examples/gcp-iot-provision\n```\n\nThe sections below show how to test the Cloud Function on a local test server and deploy to Cloud Functions. In either case you must provide the environment variables in the table below as instructed for the test/deployment.\n\n| Key         |    Value    |\n|-------------|-------------|\n| BALENA_API_KEY | for use of balena API; found in balenaCloud dashboard at: `account -> Preferences -> Access tokens` |\n| GCP_PROJECT_ID | Google Cloud project ID, like `my-project-000000`|\n| GCP_REGION | Google Cloud region for registry, like `us-central1` |\n| GCP_REGISTRY_ID | Google Cloud registry ID you provided to create the registry |\n| GCP_SERVICE_ACCOUNT |base64 encoding of the JSON formatted GCP service account credentials provided by Google when you created the service account. Example below, assuming the credentials JSON is contained in a file.<br><br>`cat <credentials.txt> \\| base64 -w 0` |\n\n### HTTP API\nThe HTTP endpoint expects a request containing a JSON body with the attributes below. Use POST to add a device to the cloud registry, DELETE to remove.\n\n| Attribute | Value |\n|-----------|-------|\n| uuid | UUID of device  |\n| balena_service | (optional) Name of service container on balena device that uses provisioned key and certificate, for example `cloud-relay`. If defined, creates service level variables; otherwise creates device level variables. Service level variables are more secure. |\n\n\n### Test locally\nThe Google Functions Framework is a convenient tool for local testing. \nFirst, start a local HTTP server ([docs reference](https://cloud.google.com/functions/docs/running/function-frameworks)) using a script like below.\n\n```\nexport BALENA_API_KEY=<...>\n... <other environment variables from table above>\nexport GCP_SERVICE_ACCOUNT=<...>\n\nnpx @google-cloud/functions-framework --target=provision\n```\n\nNext, use `curl` to send an HTTP request to the local server to provision a device. See the *HTTP API* section above for body contents.\n\n```\ncurl -X POST http://localhost:8080 -H \"Content-Type:application/json\" \\\n   -d '{ \"uuid\": \"<device-uuid>\", \"balena_service\": \"<service-name>\" }'\n```\n\nAfter a successful POST, you should see the device appear in your IoT Core registry and `GCP_CLIENT_PATH`, `GCP_DATA_TOPIC_ROOT`, `GCP_PRIVATE_KEY`, and `GCP_PROJECT_ID` variables appear in balenaCloud for the device. After a successful DELETE, those variables disappear.\n\n## Deploy\nTo deploy to Cloud Functions, use the command below. See the [command documentation](https://cloud.google.com/sdk/gcloud/reference/functions/deploy) for the format of `yaml-file`, which contains the variables from the table in the *Development setup* section above.\n\n```\ngcloud functions deploy provision --runtime=nodejs14 --trigger-http \\\n   --env-vars-file=<yaml-file> --allow-unauthenticated \\\n   --service-account=<name>@<xxxx>.iam.gserviceaccount.com\n```\n\nThe result is a Cloud Function like below. Notice the `TRIGGER` tab, which provides the URL for the function.\n\n![Alt text](docs/cloud-function.png)\n\n### Test the Cloud Function\nTo test the function, use a command like below, where the URL is from the `TRIGGER` tab in the console. See the *HTTP API* section above for body contents.\n\n```\ncurl -X POST https://<region>-<projectID>.cloudfunctions.net/provision \\\n   -H \"Content-Type:application/json\" \\\n   -d '{ \"uuid\": \"<device-uuid>\", \"balena_service\": \"<service-name>\" }'\n```\n\nAfter a successful POST, you should see the device appear in your IoT Core registry and `GCP_CLIENT_PATH`, `GCP_DATA_TOPIC_ROOT`, `GCP_PRIVATE_KEY`, and `GCP_PROJECT_ID` variables appear in balenaCloud for the device. After a successful DELETE, those variables disappear.\n","gitHead":"312b699e0064649a3f286f6e9d7cb837dff38aec","private":false,"scripts":{"test":"echo \"No tests yet\" && exit 0","start":"node index.js"},"_npmUser":{"name":"balena.io","email":"accounts+npm@balena.io"},"repository":{"url":"git+https://github.com/balena-io-examples/gcp-iot-provision.git","type":"git"},"versionist":{"publishedAt":"2022-05-17T20:56:34.065Z"},"_npmVersion":"6.14.17","description":"Google Cloud function to provision a balena device to IoT Core","directories":{},"_nodeVersion":"14.17.1","dependencies":{"balena-sdk":"^16.11.2","@google-cloud/iot":"^2.5.0","@google-cloud/functions-framework":"^2.1.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","_npmOperationalInternal":{"tmp":"tmp/gcp-iot-provision_0.2.3-dependabot-npm-and-yarn-moment-2-29-3-312b699e0064649a3f286f6e9d7cb837dff38aec_1652821128343_0.8453535759434603","host":"s3://npm-registry-packages"},"deprecated":"Deprecated: no longer maintained. The GitHub repository has been archived and no further releases will be published."},"0.2.3":{"name":"gcp-iot-provision","version":"0.2.3","keywords":["balena","balenaCloud","google","iotcore","iot","gcp"],"author":{"name":"Ken Bannister","email":"ken@balena.io"},"license":"Apache-2.0","_id":"gcp-iot-provision@0.2.3","maintainers":[{"name":"balena.io","email":"accounts+npm@balena.io"}],"homepage":"https://github.com/balena-io-examples/gcp-iot-provision","bugs":{"url":"https://github.com/balena-io-examples/gcp-iot-provision/issues"},"dist":{"shasum":"f91ab2447cb4e4c030ecc8144f4f5661e2e35df1","tarball":"https://registry.npmjs.org/gcp-iot-provision/-/gcp-iot-provision-0.2.3.tgz","fileCount":8,"integrity":"sha512-fvGr3FpssqdjUGQ53CbjqF3iNeACNbJiDac9zncBGURo2gFVKjU8fpM/Sonj4OxV6+ZpoYUAfCYQ8+V23edWeQ==","signatures":[{"sig":"MEUCIQDculEd4FdhCu2D/0KnO9tf2jn3CljeP1hPtHOVKlY02gIgNCI95CLo5xTtzoLwLjVcQ73XKmLZD3VUI4nyEutpzx8=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":136221,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJihA9WACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmqZmhAAof2lo0xDZ/rX0eQnHJPuV+5fu9jvO+awF3AY6LtEl3mFnFkF\r\npH/oY6/Zy60urZEZvxpZSAzE5brfz3WP5mTKBFDm4vVa+olxGYp4cdwz2aAL\r\ntsvxciMPIy3NDqiDlVlNEEBMEj2dc16F/rpR+CZqfmbqB2pI/YKbj5OaqVcC\r\niapRozJlbqGwZrYzcMZoFkbm7qXONmQa/oRMR1KrJz5P6neVtxaIr3tmfMdl\r\nK4MIgS5m8dy9NXuEutyFeL8I5hAFNxQ5ZYVw/qZgHNdDuglHX1Ka+nLaxFxi\r\nGZK8QtE4rYWK8Bf6GcRtbFsFbsWueL0EtIuzSB0H+VGv3tEUFWiYQyhMAHrv\r\nkGpXVKFzuHvG+MQ0Au2U/22+pl3XqKQJbhF4/p1pDJvHxKaA87gwbFHKJ9af\r\nIlzxY6m+N/e86ALfjZ8wSxELDC3FOg+jE6Covki/Pe1kGybcUiBaiKgxj1jA\r\n2/IWjV8tbSYS+a4NCXx524qYAYPQnVnRkKEw1vXhh+p2Xm+f9XW9cl9N5AwQ\r\nPa/uSVJuVY3Imv8g0UeP9HU7BZsaLpgT99kKJS3lCYv2njJZ6uqzSA4QLplV\r\n35ligJR1imzfbJ4Uxjihil6ONbPxu30nRKEINlRJnkwORqCLx+kcRLQH8dq2\r\nSitkXNyRJAfIeFVOlhhpaO/hxglTLa6TURA=\r\n=I81f\r\n-----END PGP SIGNATURE-----\r\n"},"main":"index.js","type":"module","gitHead":"7f4f5958ba2ff43470807a9b89cc1e695aba65d1","private":false,"scripts":{"test":"echo \"No tests yet\" && exit 0","start":"node index.js"},"_npmUser":{"name":"balena.io","email":"accounts+npm@balena.io"},"repository":{"url":"git+https://github.com/balena-io-examples/gcp-iot-provision.git","type":"git"},"versionist":{"publishedAt":"2022-05-17T21:08:56.975Z"},"_npmVersion":"6.14.17","description":"Google Cloud function to provision a balena device to IoT Core","directories":{},"_nodeVersion":"14.17.1","dependencies":{"balena-sdk":"^16.11.2","@google-cloud/iot":"^2.5.0","@google-cloud/functions-framework":"^2.1.0"},"_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/gcp-iot-provision_0.2.3_1652821846211_0.7226875203747773","host":"s3://npm-registry-packages"},"deprecated":"Deprecated: no longer maintained. The GitHub repository has been archived and no further releases will be published."},"0.2.4-dependabot-npm-and-yarn-node-forge-1-3-1-fd3e783334351dec8d893cca0a52c4f4dfe7ac8d":{"name":"gcp-iot-provision","version":"0.2.4-dependabot-npm-and-yarn-node-forge-1-3-1-fd3e783334351dec8d893cca0a52c4f4dfe7ac8d","keywords":["balena","balenaCloud","google","iotcore","iot","gcp"],"author":{"name":"Ken Bannister","email":"ken@balena.io"},"license":"Apache-2.0","_id":"gcp-iot-provision@0.2.4-dependabot-npm-and-yarn-node-forge-1-3-1-fd3e783334351dec8d893cca0a52c4f4dfe7ac8d","maintainers":[{"name":"balena.io","email":"accounts+npm@balena.io"}],"homepage":"https://github.com/balena-io-examples/gcp-iot-provision","bugs":{"url":"https://github.com/balena-io-examples/gcp-iot-provision/issues"},"dist":{"shasum":"0bfaf0b3116a8cd2a74cbf6fdd5e83e56dad7afd","tarball":"https://registry.npmjs.org/gcp-iot-provision/-/gcp-iot-provision-0.2.4-dependabot-npm-and-yarn-node-forge-1-3-1-fd3e783334351dec8d893cca0a52c4f4dfe7ac8d.tgz","fileCount":8,"integrity":"sha512-TzYS/SJ+cy5jLbfK50TAThpNnOa132UeL4F+/ZWfc9hnSG8O8WVq24lvs1Da4G40QsQq78+47RqWNfHBDhLQQA==","signatures":[{"sig":"MEUCIQDFU0MOLHoaZthN55xe1NQaNjF16Qc7wka8C8FSlYv/+gIgFMt8QUxZQsAeGRH4xnwKNSP59pX2/0k6riqVSQYH/9I=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":136393,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJihBHbACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmqZqhAApJgCdH7cbzdOeSLXBX7HHJ1LM+VQRpQ0x28aStwqYS7gtacS\r\n2LpohcXEGXpWN/hKzFqv7bNf3StlCvGXhBVmwS3ErNY/QGZQ5y8CHSvMywDa\r\nlXgVFGhWWD/ZINL6M54CCpKeJJsEnO3GE+x3nZk51/re4ZSPCFSa7IIlctjH\r\nVqFx/dha7SRCV6fVF1716M6RKduBgZVI8RosQL56yk2k02coF0Cx1ScFyVYx\r\ngtbZilWzql+6eIYs2Mh195wiXqQu9PoxfHDJUNMRMpW6ZU1H6t18KGWjPHqG\r\no0L67pNUohlOO9Ihmi8yx1j/ngZpBLFGHeacAtamGde5iR4TSX/yiWXvc+hC\r\nw2Iden8MFf0NsnSkCEtADev1A76GQeFjQ5vtDa3LEJii5K3iM6we64CVrSwb\r\n2/vAvqFSrnoBRdF4tms3C3UmnFuamnmhCPsAwa5dpI0yz4PjIY+nDT8u0mey\r\nF+7Blwmx3LIMK+jiNlDxMSvShL2EXlEkFBYTVLhi8rMLolnxxiui2fXNu/gO\r\n8zgRioLzVb/TIERyJHb2kJt86OZzR5XjsHhH8Oau3avVp7FVGBllhilWchXO\r\nfS879XDu8xT6dYrU/8/tY9VFxSxEYcs3y/Gdct1BBNi+q777SdQwyxbfYsSP\r\nK93yBjzmWA+B8nk9SlQbyhrX9etvkVgnWu0=\r\n=WeH6\r\n-----END PGP SIGNATURE-----\r\n"},"main":"index.js","type":"module","readme":"# Google Cloud Function for IoT Device Provisioning\n\nThis Cloud Function allows you to provision and synchronize a balena device with Google Cloud IoT Core in a secure and automated way via an HTTP endpoint. The Cloud Function may be called by a balena device, as seen in the [cloud-relay](https://github.com/balena-io-examples/cloud-relay) example.\n\n| Method | Action |\n|-------------|--------|\n| POST | Provisions a balena device with IoT Core. First the function verifies the device UUID with balenaCloud. Then it creates a public/private key pair and adds the device to the registry. Finally the function pushes the private key to a balena device environment variable. |\n| DELETE | Removes a balena device from the IoT Core registry and removes the balena device environment variable for the private key. Essentially reverses the actions from provisioning with HTTP POST. |\n\n## Setup and Testing\n### Google Cloud setup\nThe Cloud Function interacts with Google Cloud IoT Core via client code operating with service account credentials. You must setup a Google Cloud project with an IoT Core registry. The service account must have the *Cloud IoT Provisioner* role to manage device records in the IoT Core registry. See the IoT Core [documentation](https://cloud.google.com/iot/docs/how-tos) for more background.\n\n### Development setup\nClone this repo\n```\n$ git clone https://github.com/balena-io-examples/gcp-iot-provision\n```\n\nThe sections below show how to test the Cloud Function on a local test server and deploy to Cloud Functions. In either case you must provide the environment variables in the table below as instructed for the test/deployment.\n\n| Key         |    Value    |\n|-------------|-------------|\n| BALENA_API_KEY | for use of balena API; found in balenaCloud dashboard at: `account -> Preferences -> Access tokens` |\n| GCP_PROJECT_ID | Google Cloud project ID, like `my-project-000000`|\n| GCP_REGION | Google Cloud region for registry, like `us-central1` |\n| GCP_REGISTRY_ID | Google Cloud registry ID you provided to create the registry |\n| GCP_SERVICE_ACCOUNT |base64 encoding of the JSON formatted GCP service account credentials provided by Google when you created the service account. Example below, assuming the credentials JSON is contained in a file.<br><br>`cat <credentials.txt> \\| base64 -w 0` |\n\n### HTTP API\nThe HTTP endpoint expects a request containing a JSON body with the attributes below. Use POST to add a device to the cloud registry, DELETE to remove.\n\n| Attribute | Value |\n|-----------|-------|\n| uuid | UUID of device  |\n| balena_service | (optional) Name of service container on balena device that uses provisioned key and certificate, for example `cloud-relay`. If defined, creates service level variables; otherwise creates device level variables. Service level variables are more secure. |\n\n\n### Test locally\nThe Google Functions Framework is a convenient tool for local testing. \nFirst, start a local HTTP server ([docs reference](https://cloud.google.com/functions/docs/running/function-frameworks)) using a script like below.\n\n```\nexport BALENA_API_KEY=<...>\n... <other environment variables from table above>\nexport GCP_SERVICE_ACCOUNT=<...>\n\nnpx @google-cloud/functions-framework --target=provision\n```\n\nNext, use `curl` to send an HTTP request to the local server to provision a device. See the *HTTP API* section above for body contents.\n\n```\ncurl -X POST http://localhost:8080 -H \"Content-Type:application/json\" \\\n   -d '{ \"uuid\": \"<device-uuid>\", \"balena_service\": \"<service-name>\" }'\n```\n\nAfter a successful POST, you should see the device appear in your IoT Core registry and `GCP_CLIENT_PATH`, `GCP_DATA_TOPIC_ROOT`, `GCP_PRIVATE_KEY`, and `GCP_PROJECT_ID` variables appear in balenaCloud for the device. After a successful DELETE, those variables disappear.\n\n## Deploy\nTo deploy to Cloud Functions, use the command below. See the [command documentation](https://cloud.google.com/sdk/gcloud/reference/functions/deploy) for the format of `yaml-file`, which contains the variables from the table in the *Development setup* section above.\n\n```\ngcloud functions deploy provision --runtime=nodejs14 --trigger-http \\\n   --env-vars-file=<yaml-file> --allow-unauthenticated \\\n   --service-account=<name>@<xxxx>.iam.gserviceaccount.com\n```\n\nThe result is a Cloud Function like below. Notice the `TRIGGER` tab, which provides the URL for the function.\n\n![Alt text](docs/cloud-function.png)\n\n### Test the Cloud Function\nTo test the function, use a command like below, where the URL is from the `TRIGGER` tab in the console. See the *HTTP API* section above for body contents.\n\n```\ncurl -X POST https://<region>-<projectID>.cloudfunctions.net/provision \\\n   -H \"Content-Type:application/json\" \\\n   -d '{ \"uuid\": \"<device-uuid>\", \"balena_service\": \"<service-name>\" }'\n```\n\nAfter a successful POST, you should see the device appear in your IoT Core registry and `GCP_CLIENT_PATH`, `GCP_DATA_TOPIC_ROOT`, `GCP_PRIVATE_KEY`, and `GCP_PROJECT_ID` variables appear in balenaCloud for the device. After a successful DELETE, those variables disappear.\n","gitHead":"fd3e783334351dec8d893cca0a52c4f4dfe7ac8d","private":false,"scripts":{"test":"echo \"No tests yet\" && exit 0","start":"node index.js"},"_npmUser":{"name":"balena.io","email":"accounts+npm@balena.io"},"repository":{"url":"git+https://github.com/balena-io-examples/gcp-iot-provision.git","type":"git"},"versionist":{"publishedAt":"2022-05-17T21:19:22.201Z"},"_npmVersion":"6.14.17","description":"Google Cloud function to provision a balena device to IoT Core","directories":{},"_nodeVersion":"14.17.1","dependencies":{"balena-sdk":"^16.11.2","@google-cloud/iot":"^2.5.0","@google-cloud/functions-framework":"^2.1.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","_npmOperationalInternal":{"tmp":"tmp/gcp-iot-provision_0.2.4-dependabot-npm-and-yarn-node-forge-1-3-1-fd3e783334351dec8d893cca0a52c4f4dfe7ac8d_1652822491001_0.7146374328655967","host":"s3://npm-registry-packages"},"deprecated":"Deprecated: no longer maintained. The GitHub repository has been archived and no further releases will be published."},"0.2.4":{"name":"gcp-iot-provision","version":"0.2.4","keywords":["balena","balenaCloud","google","iotcore","iot","gcp"],"author":{"name":"Ken Bannister","email":"ken@balena.io"},"license":"Apache-2.0","_id":"gcp-iot-provision@0.2.4","maintainers":[{"name":"balena.io","email":"accounts+npm@balena.io"}],"homepage":"https://github.com/balena-io-examples/gcp-iot-provision","bugs":{"url":"https://github.com/balena-io-examples/gcp-iot-provision/issues"},"dist":{"shasum":"ef6aa418f6619b2bd4b15ef19361a2079a3a85f2","tarball":"https://registry.npmjs.org/gcp-iot-provision/-/gcp-iot-provision-0.2.4.tgz","fileCount":8,"integrity":"sha512-MR9+SjMQFJ7KALsOtdCU+gvSTKR3hIzAuzICmiSuVffc2uKKMsP5TjUngEVMvS+0OVGop62Q4KoPGgi0gC8Cyw==","signatures":[{"sig":"MEUCIQDj1bMNxXedDfkgDeJcERGel7mdIHT6CJBu+7XyPPuN9AIgH+PU8/yqxc8RHRczWbL0kGvNQ0Y40nVL86TGictOpbM=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":136311,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJihBZwACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmrAiQ/9EMfs60SBKvBm/sVsOKScz6aqKKncNhie41Nmwm9dqDvsZ3lN\r\nk36qCAHfpDyp4g9NmUJ7d08HSGDaWubxdgg9Fr2sNKgnI3HtngKGbBdzNEMy\r\nG2EKXRBGTdTVYY9C62Ek7SaAYWvUoDn6pSjFQDH9I7/xdgdr8Wv73+N/fnFM\r\nsgOBBcD4bx/0NEHiWaJLJBYUbCqJgSbcA1nP0ptnkRC+8j1UULW/9hJqcK8o\r\nSEG8V9emQQQ57C+S2mKxWfO4Hd+596y6XbM9mMkR+VjMi/JDO0zphspDz3er\r\n8Az6CSgPwZcZnAsYJDuAU1TNtyKgVF37SXNw35gLC7AeGDn/fiUSgcRBJl2q\r\nhKNgO1+JlTPxSTXBlbgUhu0k5JjosrNvCJgPpvmEEdGaanhjZjAHDZ4W+Vv/\r\no8tzFdg0gvKcaESpBjQT0XOUCB2Wp1hLUjHe1G00gXzC1P1tvmk+oM9SDYZi\r\ngl8G8M9oNNneGZ7CevwChD+0VHOE3drY0WlFilGQdPpaYPOBNbHnO/BAmYiv\r\ncRSny+G9xpzCCR67msba/VSY8g5Xv9Zb5WoxN9mx1Mxi26NYjYpitPHNPIqM\r\nympJUauqsknS6sT2Fe0CFY/1OoJgAYE9rbgjCpOvC32quDrBX4fYBfsjKF7a\r\nVUfU6YEvv690XJxOK61Cp4vC/eeq2htq7HM=\r\n=bffr\r\n-----END PGP SIGNATURE-----\r\n"},"main":"index.js","type":"module","gitHead":"dbf23c1fd76271ccd0a061cb008a114c7475168b","private":false,"scripts":{"test":"echo \"No tests yet\" && exit 0","start":"node index.js"},"_npmUser":{"name":"balena.io","email":"accounts+npm@balena.io"},"repository":{"url":"git+https://github.com/balena-io-examples/gcp-iot-provision.git","type":"git"},"versionist":{"publishedAt":"2022-05-17T21:39:26.887Z"},"_npmVersion":"6.14.17","description":"Google Cloud function to provision a balena device to IoT Core","directories":{},"_nodeVersion":"14.17.1","dependencies":{"balena-sdk":"^16.11.2","@google-cloud/iot":"^2.5.0","@google-cloud/functions-framework":"^2.1.0"},"_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/gcp-iot-provision_0.2.4_1652823664012_0.006955925940595131","host":"s3://npm-registry-packages"},"deprecated":"Deprecated: no longer maintained. The GitHub repository has been archived and no further releases will be published."},"0.2.4-dependabot-npm-and-yarn-google-cloud-functions-framework-3-1-1-dfef560917c4cb151a248258f92139ac736490d8":{"name":"gcp-iot-provision","version":"0.2.4-dependabot-npm-and-yarn-google-cloud-functions-framework-3-1-1-dfef560917c4cb151a248258f92139ac736490d8","keywords":["balena","balenaCloud","google","iotcore","iot","gcp"],"author":{"name":"Ken Bannister","email":"ken@balena.io"},"license":"Apache-2.0","_id":"gcp-iot-provision@0.2.4-dependabot-npm-and-yarn-google-cloud-functions-framework-3-1-1-dfef560917c4cb151a248258f92139ac736490d8","maintainers":[{"name":"balena.io","email":"accounts+npm@balena.io"}],"homepage":"https://github.com/balena-io-examples/gcp-iot-provision","bugs":{"url":"https://github.com/balena-io-examples/gcp-iot-provision/issues"},"dist":{"shasum":"3e293bb96ec8ef1345a39a7801fed017a91b261f","tarball":"https://registry.npmjs.org/gcp-iot-provision/-/gcp-iot-provision-0.2.4-dependabot-npm-and-yarn-google-cloud-functions-framework-3-1-1-dfef560917c4cb151a248258f92139ac736490d8.tgz","fileCount":8,"integrity":"sha512-GO2xCiIb95y5ripJwME5Ql13kBWQOI2hAXHmGcLVB90IlhGgXz5vtIbltRiJdPtjprg05dB3kUCkBZP1PC+W0w==","signatures":[{"sig":"MEQCIDBE8NN3wfWpyq6C6F9jjfPXUmlSIQcnR/79kxLhfdEIAiAYmxE6YUshXTC07L/jczW3KlaH0MCZSZH4Ln5knCQcrw==","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":136438,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJihBnPACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmqPzQ//Y9xmo/hMnbQDUppk/LIPNwgWWPQNhH4oW/hhcOBLi7HHiLWp\r\nviAN5vXpEWH46f7ECgCq+QRCHAH+G0xj5OsbtZljZgFTY6jeWNH9u0aRt8uN\r\nV/97H8L1QvSQn4nliVEtSUJGjR0tKJotaWFR4HrtQkOWiMo47p9U/oco46ek\r\nqBUXlZFvgFgMmEK86IfZj7pW5Vk1E+EdDS+8q7vKmrxHqG8jQ/w4l/dUaeBw\r\nIG6oNP8nnbz5ZWRISFmFCiO7lU8r/6/1DWmcdj7deqHv8jaloIoI1L00NFI5\r\nfqWl22sUCo5CIQ3ZfCnCYhXIEculkBLIE5uufVNIP8jHn4EToXd21jcg6R+T\r\nDAyHssEPZ4/cnLTNYTCONwItO68uxWSkZOoHdX7Jg2JAK0XuTklDH4iOtiW1\r\nc4g916CtkWGRXgUcWlpbyG5qA5HgwmhYK9D3y93uXUzPBzoXbAM6+EYphT7i\r\nGDcNMjyl4aP2WkbNwIgchvlJyzkXZ8/ARgXFgKGJq+L103CzOhWi55zWioUi\r\nyNRozz+TfX6dbmE4pBDJKQlrCLVF+5navmnXagEPCiyUVMg14Yc7wm1/9un6\r\n9Vb4PrFA4H/RANkxieq1mB6kzLXt9l2Bv6zE2XwqTFM3FsdpAOMl1RYIq8PP\r\ns0Kmbym5TbDqEHXhh2Itmz71WPVB0FWaY/Q=\r\n=CnZZ\r\n-----END PGP SIGNATURE-----\r\n"},"main":"index.js","type":"module","readme":"# Google Cloud Function for IoT Device Provisioning\n\nThis Cloud Function allows you to provision and synchronize a balena device with Google Cloud IoT Core in a secure and automated way via an HTTP endpoint. The Cloud Function may be called by a balena device, as seen in the [cloud-relay](https://github.com/balena-io-examples/cloud-relay) example.\n\n| Method | Action |\n|-------------|--------|\n| POST | Provisions a balena device with IoT Core. First the function verifies the device UUID with balenaCloud. Then it creates a public/private key pair and adds the device to the registry. Finally the function pushes the private key to a balena device environment variable. |\n| DELETE | Removes a balena device from the IoT Core registry and removes the balena device environment variable for the private key. Essentially reverses the actions from provisioning with HTTP POST. |\n\n## Setup and Testing\n### Google Cloud setup\nThe Cloud Function interacts with Google Cloud IoT Core via client code operating with service account credentials. You must setup a Google Cloud project with an IoT Core registry. The service account must have the *Cloud IoT Provisioner* role to manage device records in the IoT Core registry. See the IoT Core [documentation](https://cloud.google.com/iot/docs/how-tos) for more background.\n\n### Development setup\nClone this repo\n```\n$ git clone https://github.com/balena-io-examples/gcp-iot-provision\n```\n\nThe sections below show how to test the Cloud Function on a local test server and deploy to Cloud Functions. In either case you must provide the environment variables in the table below as instructed for the test/deployment.\n\n| Key         |    Value    |\n|-------------|-------------|\n| BALENA_API_KEY | for use of balena API; found in balenaCloud dashboard at: `account -> Preferences -> Access tokens` |\n| GCP_PROJECT_ID | Google Cloud project ID, like `my-project-000000`|\n| GCP_REGION | Google Cloud region for registry, like `us-central1` |\n| GCP_REGISTRY_ID | Google Cloud registry ID you provided to create the registry |\n| GCP_SERVICE_ACCOUNT |base64 encoding of the JSON formatted GCP service account credentials provided by Google when you created the service account. Example below, assuming the credentials JSON is contained in a file.<br><br>`cat <credentials.txt> \\| base64 -w 0` |\n\n### HTTP API\nThe HTTP endpoint expects a request containing a JSON body with the attributes below. Use POST to add a device to the cloud registry, DELETE to remove.\n\n| Attribute | Value |\n|-----------|-------|\n| uuid | UUID of device  |\n| balena_service | (optional) Name of service container on balena device that uses provisioned key and certificate, for example `cloud-relay`. If defined, creates service level variables; otherwise creates device level variables. Service level variables are more secure. |\n\n\n### Test locally\nThe Google Functions Framework is a convenient tool for local testing. \nFirst, start a local HTTP server ([docs reference](https://cloud.google.com/functions/docs/running/function-frameworks)) using a script like below.\n\n```\nexport BALENA_API_KEY=<...>\n... <other environment variables from table above>\nexport GCP_SERVICE_ACCOUNT=<...>\n\nnpx @google-cloud/functions-framework --target=provision\n```\n\nNext, use `curl` to send an HTTP request to the local server to provision a device. See the *HTTP API* section above for body contents.\n\n```\ncurl -X POST http://localhost:8080 -H \"Content-Type:application/json\" \\\n   -d '{ \"uuid\": \"<device-uuid>\", \"balena_service\": \"<service-name>\" }'\n```\n\nAfter a successful POST, you should see the device appear in your IoT Core registry and `GCP_CLIENT_PATH`, `GCP_DATA_TOPIC_ROOT`, `GCP_PRIVATE_KEY`, and `GCP_PROJECT_ID` variables appear in balenaCloud for the device. After a successful DELETE, those variables disappear.\n\n## Deploy\nTo deploy to Cloud Functions, use the command below. See the [command documentation](https://cloud.google.com/sdk/gcloud/reference/functions/deploy) for the format of `yaml-file`, which contains the variables from the table in the *Development setup* section above.\n\n```\ngcloud functions deploy provision --runtime=nodejs14 --trigger-http \\\n   --env-vars-file=<yaml-file> --allow-unauthenticated \\\n   --service-account=<name>@<xxxx>.iam.gserviceaccount.com\n```\n\nThe result is a Cloud Function like below. Notice the `TRIGGER` tab, which provides the URL for the function.\n\n![Alt text](docs/cloud-function.png)\n\n### Test the Cloud Function\nTo test the function, use a command like below, where the URL is from the `TRIGGER` tab in the console. See the *HTTP API* section above for body contents.\n\n```\ncurl -X POST https://<region>-<projectID>.cloudfunctions.net/provision \\\n   -H \"Content-Type:application/json\" \\\n   -d '{ \"uuid\": \"<device-uuid>\", \"balena_service\": \"<service-name>\" }'\n```\n\nAfter a successful POST, you should see the device appear in your IoT Core registry and `GCP_CLIENT_PATH`, `GCP_DATA_TOPIC_ROOT`, `GCP_PRIVATE_KEY`, and `GCP_PROJECT_ID` variables appear in balenaCloud for the device. After a successful DELETE, those variables disappear.\n","gitHead":"dfef560917c4cb151a248258f92139ac736490d8","private":false,"scripts":{"test":"echo \"No tests yet\" && exit 0","start":"node index.js"},"_npmUser":{"name":"balena.io","email":"accounts+npm@balena.io"},"repository":{"url":"git+https://github.com/balena-io-examples/gcp-iot-provision.git","type":"git"},"versionist":{"publishedAt":"2022-05-17T21:53:13.210Z"},"_npmVersion":"6.14.17","description":"Google Cloud function to provision a balena device to IoT Core","directories":{},"_nodeVersion":"14.17.1","dependencies":{"balena-sdk":"^16.11.2","@google-cloud/iot":"^2.5.0","@google-cloud/functions-framework":"^3.1.1"},"_hasShrinkwrap":false,"readmeFilename":"README.md","_npmOperationalInternal":{"tmp":"tmp/gcp-iot-provision_0.2.4-dependabot-npm-and-yarn-google-cloud-functions-framework-3-1-1-dfef560917c4cb151a248258f92139ac736490d8_1652824527401_0.098888033174924","host":"s3://npm-registry-packages"},"deprecated":"Deprecated: no longer maintained. The GitHub repository has been archived and no further releases will be published."},"0.2.5-dependabot-npm-and-yarn-google-cloud-functions-framework-3-1-1-58e990e8530b0be79dfa036fad30318197590f7e":{"name":"gcp-iot-provision","version":"0.2.5-dependabot-npm-and-yarn-google-cloud-functions-framework-3-1-1-58e990e8530b0be79dfa036fad30318197590f7e","keywords":["balena","balenaCloud","google","iotcore","iot","gcp"],"author":{"name":"Ken Bannister","email":"ken@balena.io"},"license":"Apache-2.0","_id":"gcp-iot-provision@0.2.5-dependabot-npm-and-yarn-google-cloud-functions-framework-3-1-1-58e990e8530b0be79dfa036fad30318197590f7e","maintainers":[{"name":"balena.io","email":"accounts+npm@balena.io"}],"homepage":"https://github.com/balena-io-examples/gcp-iot-provision","bugs":{"url":"https://github.com/balena-io-examples/gcp-iot-provision/issues"},"dist":{"shasum":"fa67cf6c57360dff41565b64e170d6aecdf7ee61","tarball":"https://registry.npmjs.org/gcp-iot-provision/-/gcp-iot-provision-0.2.5-dependabot-npm-and-yarn-google-cloud-functions-framework-3-1-1-58e990e8530b0be79dfa036fad30318197590f7e.tgz","fileCount":8,"integrity":"sha512-HvzTcP1tLItfQ2FHI40ifgxUnbkU138SxDtjH9TTxGixUCVPy5eKySrXH73DdPHEmpKbpzAwk5qhTImWL9ZkxA==","signatures":[{"sig":"MEUCIFZtm91HXh8Lylpm81+a0lbbR0iDmJo8zxwzqd6r1ux6AiEAggWrP1CoNbknkMicA8raavBoZVdONY2pnbthaQs5uaA=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":136528,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJii+QFACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmrfKQ/7B1mn8dLRJrTiLhkI+T/COzS35P9Uvufni69in0z6M6wYWLw0\r\nzVfJeGU1oW5ax3yfA0FoT2hfwU64FSs6vGx0EKMy/0cLb314SsVl0cWRvoIa\r\nk41UG2GL3zzZarwtnzqUcH57q3czGM97lkHloLIaXlwH9LqObuGgxn05XZNL\r\nWK5ykiMboH0FbAZq8/iphNqWRwAedWLOpSNE+oC3PembBkO7iVWhWSm8G61i\r\nbm9IoZSXnKDNvXmqCrLBHAbtMJhISsxPrOpglfldyfBkIS3BVyQiDpyYWevm\r\nh+o2hpJyQJD4ij9D9IARlfy6m1Rlw3eCxBd38r/XbrZu9pnX9+jPHykLvqkj\r\nMkmETbSbpzKdZn30WPTt3hvxn56tjiuqM7md79qCABgRtt1NEnH0NDNVVqxa\r\nTGP2Ms5cAemwLX7PLu3gHPNkv3b1oUlza3+Hl24NmjMbUxbnRoWsQ1kE5Cka\r\n5WE6ZAs6O6m6jGaaLe535bhPxM9FvFVJKMf+9USxQXCpf7SnBE3Kv91QDsrU\r\nWwC1RIvxB1YcOIRRYfIZYC2BDnuU5KkcsujM+O28C/IczJHlxZROgh13IKCS\r\nSJDvdPlpxC/jjFXdv5j5zt89Zw7R8aafcnqndICFMoeXjlPCDkSW0cia32S3\r\nFxLMVPNK1QgXvhNrtS9j/Z7OXKuWVRHfgXE=\r\n=psaS\r\n-----END PGP SIGNATURE-----\r\n"},"main":"index.js","type":"module","readme":"# Google Cloud Function for IoT Device Provisioning\n\nThis Cloud Function allows you to provision and synchronize a balena device with Google Cloud IoT Core in a secure and automated way via an HTTP endpoint. The Cloud Function may be called by a balena device, as seen in the [cloud-relay](https://github.com/balena-io-examples/cloud-relay) example.\n\n| Method | Action |\n|-------------|--------|\n| POST | Provisions a balena device with IoT Core. First the function verifies the device UUID with balenaCloud. Then it creates a public/private key pair and adds the device to the registry. Finally the function pushes the private key to a balena device environment variable. |\n| DELETE | Removes a balena device from the IoT Core registry and removes the balena device environment variable for the private key. Essentially reverses the actions from provisioning with HTTP POST. |\n\n## Setup and Testing\n### Google Cloud setup\nThe Cloud Function interacts with Google Cloud IoT Core via client code operating with service account credentials. You must setup a Google Cloud project with an IoT Core registry. The service account must have the *Cloud IoT Provisioner* role to manage device records in the IoT Core registry. See the IoT Core [documentation](https://cloud.google.com/iot/docs/how-tos) for more background.\n\n### Development setup\nClone this repo\n```\n$ git clone https://github.com/balena-io-examples/gcp-iot-provision\n```\n\nThe sections below show how to test the Cloud Function on a local test server and deploy to Cloud Functions. In either case you must provide the environment variables in the table below as instructed for the test/deployment.\n\n| Key         |    Value    |\n|-------------|-------------|\n| BALENA_API_KEY | for use of balena API; found in balenaCloud dashboard at: `account -> Preferences -> Access tokens` |\n| GCP_PROJECT_ID | Google Cloud project ID, like `my-project-000000`|\n| GCP_REGION | Google Cloud region for registry, like `us-central1` |\n| GCP_REGISTRY_ID | Google Cloud registry ID you provided to create the registry |\n| GCP_SERVICE_ACCOUNT |base64 encoding of the JSON formatted GCP service account credentials provided by Google when you created the service account. Example below, assuming the credentials JSON is contained in a file.<br><br>`cat <credentials.txt> \\| base64 -w 0` |\n\n### HTTP API\nThe HTTP endpoint expects a request containing a JSON body with the attributes below. Use POST to add a device to the cloud registry, DELETE to remove.\n\n| Attribute | Value |\n|-----------|-------|\n| uuid | UUID of device  |\n| balena_service | (optional) Name of service container on balena device that uses provisioned key and certificate, for example `cloud-relay`. If defined, creates service level variables; otherwise creates device level variables. Service level variables are more secure. |\n\n\n### Test locally\nThe Google Functions Framework is a convenient tool for local testing. \nFirst, start a local HTTP server ([docs reference](https://cloud.google.com/functions/docs/running/function-frameworks)) using a script like below.\n\n```\nexport BALENA_API_KEY=<...>\n... <other environment variables from table above>\nexport GCP_SERVICE_ACCOUNT=<...>\n\nnpx @google-cloud/functions-framework --target=provision\n```\n\nNext, use `curl` to send an HTTP request to the local server to provision a device. See the *HTTP API* section above for body contents.\n\n```\ncurl -X POST http://localhost:8080 -H \"Content-Type:application/json\" \\\n   -d '{ \"uuid\": \"<device-uuid>\", \"balena_service\": \"<service-name>\" }'\n```\n\nAfter a successful POST, you should see the device appear in your IoT Core registry and `GCP_CLIENT_PATH`, `GCP_DATA_TOPIC_ROOT`, `GCP_PRIVATE_KEY`, and `GCP_PROJECT_ID` variables appear in balenaCloud for the device. After a successful DELETE, those variables disappear.\n\n## Deploy\nTo deploy to Cloud Functions, use the command below. See the [command documentation](https://cloud.google.com/sdk/gcloud/reference/functions/deploy) for the format of `yaml-file`, which contains the variables from the table in the *Development setup* section above.\n\n```\ngcloud functions deploy provision --runtime=nodejs14 --trigger-http \\\n   --env-vars-file=<yaml-file> --allow-unauthenticated \\\n   --service-account=<name>@<xxxx>.iam.gserviceaccount.com\n```\n\nThe result is a Cloud Function like below. Notice the `TRIGGER` tab, which provides the URL for the function.\n\n![Alt text](docs/cloud-function.png)\n\n### Test the Cloud Function\nTo test the function, use a command like below, where the URL is from the `TRIGGER` tab in the console. See the *HTTP API* section above for body contents.\n\n```\ncurl -X POST https://<region>-<projectID>.cloudfunctions.net/provision \\\n   -H \"Content-Type:application/json\" \\\n   -d '{ \"uuid\": \"<device-uuid>\", \"balena_service\": \"<service-name>\" }'\n```\n\nAfter a successful POST, you should see the device appear in your IoT Core registry and `GCP_CLIENT_PATH`, `GCP_DATA_TOPIC_ROOT`, `GCP_PRIVATE_KEY`, and `GCP_PROJECT_ID` variables appear in balenaCloud for the device. After a successful DELETE, those variables disappear.\n","gitHead":"58e990e8530b0be79dfa036fad30318197590f7e","private":false,"scripts":{"test":"echo \"No tests yet\" && exit 0","start":"node index.js"},"_npmUser":{"name":"balena.io","email":"accounts+npm@balena.io"},"repository":{"url":"git+https://github.com/balena-io-examples/gcp-iot-provision.git","type":"git"},"versionist":{"publishedAt":"2022-05-23T19:41:57.798Z"},"_npmVersion":"6.14.17","description":"Google Cloud function to provision a balena device to IoT Core","directories":{},"_nodeVersion":"14.17.1","dependencies":{"balena-sdk":"^16.11.2","@google-cloud/iot":"^2.5.0","@google-cloud/functions-framework":"^3.1.1"},"_hasShrinkwrap":false,"readmeFilename":"README.md","_npmOperationalInternal":{"tmp":"tmp/gcp-iot-provision_0.2.5-dependabot-npm-and-yarn-google-cloud-functions-framework-3-1-1-58e990e8530b0be79dfa036fad30318197590f7e_1653335045112_0.0808813101669299","host":"s3://npm-registry-packages"},"deprecated":"Deprecated: no longer maintained. The GitHub repository has been archived and no further releases will be published."},"0.2.5-dependabot-npm-and-yarn-google-cloud-functions-framework-3-1-2-bc00a4e5900a2ca4dfd837ecb084b4e76c2b466b":{"name":"gcp-iot-provision","version":"0.2.5-dependabot-npm-and-yarn-google-cloud-functions-framework-3-1-2-bc00a4e5900a2ca4dfd837ecb084b4e76c2b466b","keywords":["balena","balenaCloud","google","iotcore","iot","gcp"],"author":{"name":"Ken Bannister","email":"ken@balena.io"},"license":"Apache-2.0","_id":"gcp-iot-provision@0.2.5-dependabot-npm-and-yarn-google-cloud-functions-framework-3-1-2-bc00a4e5900a2ca4dfd837ecb084b4e76c2b466b","maintainers":[{"name":"balena.io","email":"accounts+npm@balena.io"}],"homepage":"https://github.com/balena-io-examples/gcp-iot-provision","bugs":{"url":"https://github.com/balena-io-examples/gcp-iot-provision/issues"},"dist":{"shasum":"a4231fa1d99fb55b3596aa43eabaab3692d63b28","tarball":"https://registry.npmjs.org/gcp-iot-provision/-/gcp-iot-provision-0.2.5-dependabot-npm-and-yarn-google-cloud-functions-framework-3-1-2-bc00a4e5900a2ca4dfd837ecb084b4e76c2b466b.tgz","fileCount":8,"integrity":"sha512-vU3Y4LUC2CFER2hai6bTkzniYHStNwNYzAJdz6y94d0oqu/pSxidCdYNQSxNvVaqC+7fHdddvKQxl+SPgz6Pzw==","signatures":[{"sig":"MEQCIB7NJKZXwILaopDU1q0N2xt9/eebFgY5jysog98RpH5+AiBSEX5PUxpCeFcmWHjtU04nyP22DQsVCuagbBhPTh94KA==","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":136528,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJinllcACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmpkeQ//SKKQhwVFiHaTUGjxxSodGtO0jgypWxPfpVvo3UG+81hTa+Pg\r\n/FnGa0gmIcQB4U7lTaqR327qnfuuhS0T1asMFaUb8aaNojEENPS2Juh0YbUI\r\n8dv9ws1vXLdeYoncnfcWvXowufPHBmTqd3BanKHSjtBsLNNTXFS1tDaFbbkt\r\nB/m/U4iYVq0PbcEQ2x91B4AiYnUC3RNZIfW/rCdJf8DDAjvwrgB8nAk4HMIo\r\nBRf3WTqW37eYTrnyvd2n5388HzvQ//iBWn19E2NpBuJgqHZsMyJcuV0auh5T\r\n1NbjQYhCb42fOpszBbuT6KfTtPp6G42S0Bxx32X+kh8uaPvt49hFn+PwVzId\r\n1A7xUUURcQUOUK74+w3w+0chRmx2YIwprQaHfqpZaa1ctk+52p1QeNLE4cj3\r\nSnTIl4hbawgu+GQhJLmcX3m6jkKdsn2g+pxDnn8T26vDvM/l1hcGl4reBvL4\r\nhsNBqGnzTg5wQTl/XzSb7yGBBAfHE2kgoaP3AnnXJgrmN08D7W8VmwMzE/dE\r\na5QJRjnDlok+bwgL6ELpQukvwp/ElIzf4EYw4Qt2Th/sJKV5bwOIn1K0apDp\r\ng+Oyq0E9l6R1zVfKKzYUdoppb0QDWZkYgBxzLeSGoSjJwEE5oLwy3AVXtDcD\r\nYA7HYjqksMqzMCLxOeVccmlzVDpaNTGn1UE=\r\n=cxrc\r\n-----END PGP SIGNATURE-----\r\n"},"main":"index.js","type":"module","readme":"# Google Cloud Function for IoT Device Provisioning\n\nThis Cloud Function allows you to provision and synchronize a balena device with Google Cloud IoT Core in a secure and automated way via an HTTP endpoint. The Cloud Function may be called by a balena device, as seen in the [cloud-relay](https://github.com/balena-io-examples/cloud-relay) example.\n\n| Method | Action |\n|-------------|--------|\n| POST | Provisions a balena device with IoT Core. First the function verifies the device UUID with balenaCloud. Then it creates a public/private key pair and adds the device to the registry. Finally the function pushes the private key to a balena device environment variable. |\n| DELETE | Removes a balena device from the IoT Core registry and removes the balena device environment variable for the private key. Essentially reverses the actions from provisioning with HTTP POST. |\n\n## Setup and Testing\n### Google Cloud setup\nThe Cloud Function interacts with Google Cloud IoT Core via client code operating with service account credentials. You must setup a Google Cloud project with an IoT Core registry. The service account must have the *Cloud IoT Provisioner* role to manage device records in the IoT Core registry. See the IoT Core [documentation](https://cloud.google.com/iot/docs/how-tos) for more background.\n\n### Development setup\nClone this repo\n```\n$ git clone https://github.com/balena-io-examples/gcp-iot-provision\n```\n\nThe sections below show how to test the Cloud Function on a local test server and deploy to Cloud Functions. In either case you must provide the environment variables in the table below as instructed for the test/deployment.\n\n| Key         |    Value    |\n|-------------|-------------|\n| BALENA_API_KEY | for use of balena API; found in balenaCloud dashboard at: `account -> Preferences -> Access tokens` |\n| GCP_PROJECT_ID | Google Cloud project ID, like `my-project-000000`|\n| GCP_REGION | Google Cloud region for registry, like `us-central1` |\n| GCP_REGISTRY_ID | Google Cloud registry ID you provided to create the registry |\n| GCP_SERVICE_ACCOUNT |base64 encoding of the JSON formatted GCP service account credentials provided by Google when you created the service account. Example below, assuming the credentials JSON is contained in a file.<br><br>`cat <credentials.txt> \\| base64 -w 0` |\n\n### HTTP API\nThe HTTP endpoint expects a request containing a JSON body with the attributes below. Use POST to add a device to the cloud registry, DELETE to remove.\n\n| Attribute | Value |\n|-----------|-------|\n| uuid | UUID of device  |\n| balena_service | (optional) Name of service container on balena device that uses provisioned key and certificate, for example `cloud-relay`. If defined, creates service level variables; otherwise creates device level variables. Service level variables are more secure. |\n\n\n### Test locally\nThe Google Functions Framework is a convenient tool for local testing. \nFirst, start a local HTTP server ([docs reference](https://cloud.google.com/functions/docs/running/function-frameworks)) using a script like below.\n\n```\nexport BALENA_API_KEY=<...>\n... <other environment variables from table above>\nexport GCP_SERVICE_ACCOUNT=<...>\n\nnpx @google-cloud/functions-framework --target=provision\n```\n\nNext, use `curl` to send an HTTP request to the local server to provision a device. See the *HTTP API* section above for body contents.\n\n```\ncurl -X POST http://localhost:8080 -H \"Content-Type:application/json\" \\\n   -d '{ \"uuid\": \"<device-uuid>\", \"balena_service\": \"<service-name>\" }'\n```\n\nAfter a successful POST, you should see the device appear in your IoT Core registry and `GCP_CLIENT_PATH`, `GCP_DATA_TOPIC_ROOT`, `GCP_PRIVATE_KEY`, and `GCP_PROJECT_ID` variables appear in balenaCloud for the device. After a successful DELETE, those variables disappear.\n\n## Deploy\nTo deploy to Cloud Functions, use the command below. See the [command documentation](https://cloud.google.com/sdk/gcloud/reference/functions/deploy) for the format of `yaml-file`, which contains the variables from the table in the *Development setup* section above.\n\n```\ngcloud functions deploy provision --runtime=nodejs14 --trigger-http \\\n   --env-vars-file=<yaml-file> --allow-unauthenticated \\\n   --service-account=<name>@<xxxx>.iam.gserviceaccount.com\n```\n\nThe result is a Cloud Function like below. Notice the `TRIGGER` tab, which provides the URL for the function.\n\n![Alt text](docs/cloud-function.png)\n\n### Test the Cloud Function\nTo test the function, use a command like below, where the URL is from the `TRIGGER` tab in the console. See the *HTTP API* section above for body contents.\n\n```\ncurl -X POST https://<region>-<projectID>.cloudfunctions.net/provision \\\n   -H \"Content-Type:application/json\" \\\n   -d '{ \"uuid\": \"<device-uuid>\", \"balena_service\": \"<service-name>\" }'\n```\n\nAfter a successful POST, you should see the device appear in your IoT Core registry and `GCP_CLIENT_PATH`, `GCP_DATA_TOPIC_ROOT`, `GCP_PRIVATE_KEY`, and `GCP_PROJECT_ID` variables appear in balenaCloud for the device. After a successful DELETE, those variables disappear.\n","gitHead":"bc00a4e5900a2ca4dfd837ecb084b4e76c2b466b","private":false,"scripts":{"test":"echo \"No tests yet\" && exit 0","start":"node index.js"},"_npmUser":{"name":"balena.io","email":"accounts+npm@balena.io"},"repository":{"url":"git+https://github.com/balena-io-examples/gcp-iot-provision.git","type":"git"},"versionist":{"publishedAt":"2022-06-06T19:43:00.985Z"},"_npmVersion":"6.14.17","description":"Google Cloud function to provision a balena device to IoT Core","directories":{},"_nodeVersion":"14.19.3","dependencies":{"balena-sdk":"^16.11.2","@google-cloud/iot":"^2.5.0","@google-cloud/functions-framework":"^3.1.2"},"_hasShrinkwrap":false,"readmeFilename":"README.md","_npmOperationalInternal":{"tmp":"tmp/gcp-iot-provision_0.2.5-dependabot-npm-and-yarn-google-cloud-functions-framework-3-1-2-bc00a4e5900a2ca4dfd837ecb084b4e76c2b466b_1654544731981_0.14697052242282327","host":"s3://npm-registry-packages"},"deprecated":"Deprecated: no longer maintained. The GitHub repository has been archived and no further releases will be published."},"0.2.5-dependabot-npm-and-yarn-balena-sdk-16-22-0-14f427b32bf2be89722d613ff25928d178d92c0f":{"name":"gcp-iot-provision","version":"0.2.5-dependabot-npm-and-yarn-balena-sdk-16-22-0-14f427b32bf2be89722d613ff25928d178d92c0f","keywords":["balena","balenaCloud","google","iotcore","iot","gcp"],"author":{"name":"Ken Bannister","email":"ken@balena.io"},"license":"Apache-2.0","_id":"gcp-iot-provision@0.2.5-dependabot-npm-and-yarn-balena-sdk-16-22-0-14f427b32bf2be89722d613ff25928d178d92c0f","maintainers":[{"name":"balena.io","email":"accounts+npm@balena.io"}],"homepage":"https://github.com/balena-io-examples/gcp-iot-provision","bugs":{"url":"https://github.com/balena-io-examples/gcp-iot-provision/issues"},"dist":{"shasum":"809b4c6de28f8a82a766d7d62cd76c4599fdaece","tarball":"https://registry.npmjs.org/gcp-iot-provision/-/gcp-iot-provision-0.2.5-dependabot-npm-and-yarn-balena-sdk-16-22-0-14f427b32bf2be89722d613ff25928d178d92c0f.tgz","fileCount":8,"integrity":"sha512-0UjkQboeq+UkhT53hU6UY+Ky55JCI4qJwGQFW+pv+O3YhxlWvpXH0UA3deXplwtVNI/OcVr3bC44p9HwQH4Ihg==","signatures":[{"sig":"MEYCIQCV5kTKZS9jOGeO13sjjpDZmTbSANDKsbnylslYgr14NwIhAINqc1wc0oK+DwEkBPML2CvkYxxAEFjkhF2qzjQ2eqV3","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":136489,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJip5+UACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmozvA//cjkm1P2IL4aHF3nUVM/GvnF13OjU4gOPgmJtpcVy8nNA+WjT\r\nfNXTHXMjv530KJk572+1gmNHC/SgxJCl09LEqz5eFtGUrdcnfzJOznTGIf9E\r\n1W49kxvx38xlJn7nUpL2cFLodQv1djfgGJUVFTfbIKVLnosp1BKa+DOk45Eb\r\nCEZtlE54AfZAuC8GKzmnzUIVG49fXkfl40w+UaEYEVsDtwfZJXfrFgZvwza3\r\nE31FcUiAWuSZACMJfdqtuGLRedZVMQQIEHmmQ0yOul6vAjvUiHAzhpuFq0UU\r\nY0mVophxnSE8O4ZqfTgr5F0kyfPHkvL5uh2xgSubezuzMgg5nQd0qDUJDOP4\r\n9zfKsPosULYw7dCxlbTMiDdIq79B7MHtWq1HivDd0KhWqj2TQL6LjVx9saoR\r\ndxGvbM+obeRNTF0mMps5WaH/i8xaFw31e5SEoSuogkQCNHLBWJkhEWK7f736\r\nKr7hy24JrTOgZa/KO1WCxUiRziyYhTFhO3DsnCIDVqXvIUJggsJBD8szNth6\r\nHnbiNWBrWeuV16hkUbfyCRCbYRj+NGcI3U+fSAjtBxkzq044Jrhz8kI6iTKs\r\nx4Pi147HTDY938sUW9t5jrvG42nQkss7CYn/2wGr/Zfp/rn/eJcIcWLJ6cfM\r\njgUgJKl4dic2pltee6AxmxDbhGd2jf8TI9Y=\r\n=rU8t\r\n-----END PGP SIGNATURE-----\r\n"},"main":"index.js","type":"module","readme":"# Google Cloud Function for IoT Device Provisioning\n\nThis Cloud Function allows you to provision and synchronize a balena device with Google Cloud IoT Core in a secure and automated way via an HTTP endpoint. The Cloud Function may be called by a balena device, as seen in the [cloud-relay](https://github.com/balena-io-examples/cloud-relay) example.\n\n| Method | Action |\n|-------------|--------|\n| POST | Provisions a balena device with IoT Core. First the function verifies the device UUID with balenaCloud. Then it creates a public/private key pair and adds the device to the registry. Finally the function pushes the private key to a balena device environment variable. |\n| DELETE | Removes a balena device from the IoT Core registry and removes the balena device environment variable for the private key. Essentially reverses the actions from provisioning with HTTP POST. |\n\n## Setup and Testing\n### Google Cloud setup\nThe Cloud Function interacts with Google Cloud IoT Core via client code operating with service account credentials. You must setup a Google Cloud project with an IoT Core registry. The service account must have the *Cloud IoT Provisioner* role to manage device records in the IoT Core registry. See the IoT Core [documentation](https://cloud.google.com/iot/docs/how-tos) for more background.\n\n### Development setup\nClone this repo\n```\n$ git clone https://github.com/balena-io-examples/gcp-iot-provision\n```\n\nThe sections below show how to test the Cloud Function on a local test server and deploy to Cloud Functions. In either case you must provide the environment variables in the table below as instructed for the test/deployment.\n\n| Key         |    Value    |\n|-------------|-------------|\n| BALENA_API_KEY | for use of balena API; found in balenaCloud dashboard at: `account -> Preferences -> Access tokens` |\n| GCP_PROJECT_ID | Google Cloud project ID, like `my-project-000000`|\n| GCP_REGION | Google Cloud region for registry, like `us-central1` |\n| GCP_REGISTRY_ID | Google Cloud registry ID you provided to create the registry |\n| GCP_SERVICE_ACCOUNT |base64 encoding of the JSON formatted GCP service account credentials provided by Google when you created the service account. Example below, assuming the credentials JSON is contained in a file.<br><br>`cat <credentials.txt> \\| base64 -w 0` |\n\n### HTTP API\nThe HTTP endpoint expects a request containing a JSON body with the attributes below. Use POST to add a device to the cloud registry, DELETE to remove.\n\n| Attribute | Value |\n|-----------|-------|\n| uuid | UUID of device  |\n| balena_service | (optional) Name of service container on balena device that uses provisioned key and certificate, for example `cloud-relay`. If defined, creates service level variables; otherwise creates device level variables. Service level variables are more secure. |\n\n\n### Test locally\nThe Google Functions Framework is a convenient tool for local testing. \nFirst, start a local HTTP server ([docs reference](https://cloud.google.com/functions/docs/running/function-frameworks)) using a script like below.\n\n```\nexport BALENA_API_KEY=<...>\n... <other environment variables from table above>\nexport GCP_SERVICE_ACCOUNT=<...>\n\nnpx @google-cloud/functions-framework --target=provision\n```\n\nNext, use `curl` to send an HTTP request to the local server to provision a device. See the *HTTP API* section above for body contents.\n\n```\ncurl -X POST http://localhost:8080 -H \"Content-Type:application/json\" \\\n   -d '{ \"uuid\": \"<device-uuid>\", \"balena_service\": \"<service-name>\" }'\n```\n\nAfter a successful POST, you should see the device appear in your IoT Core registry and `GCP_CLIENT_PATH`, `GCP_DATA_TOPIC_ROOT`, `GCP_PRIVATE_KEY`, and `GCP_PROJECT_ID` variables appear in balenaCloud for the device. After a successful DELETE, those variables disappear.\n\n## Deploy\nTo deploy to Cloud Functions, use the command below. See the [command documentation](https://cloud.google.com/sdk/gcloud/reference/functions/deploy) for the format of `yaml-file`, which contains the variables from the table in the *Development setup* section above.\n\n```\ngcloud functions deploy provision --runtime=nodejs14 --trigger-http \\\n   --env-vars-file=<yaml-file> --allow-unauthenticated \\\n   --service-account=<name>@<xxxx>.iam.gserviceaccount.com\n```\n\nThe result is a Cloud Function like below. Notice the `TRIGGER` tab, which provides the URL for the function.\n\n![Alt text](docs/cloud-function.png)\n\n### Test the Cloud Function\nTo test the function, use a command like below, where the URL is from the `TRIGGER` tab in the console. See the *HTTP API* section above for body contents.\n\n```\ncurl -X POST https://<region>-<projectID>.cloudfunctions.net/provision \\\n   -H \"Content-Type:application/json\" \\\n   -d '{ \"uuid\": \"<device-uuid>\", \"balena_service\": \"<service-name>\" }'\n```\n\nAfter a successful POST, you should see the device appear in your IoT Core registry and `GCP_CLIENT_PATH`, `GCP_DATA_TOPIC_ROOT`, `GCP_PRIVATE_KEY`, and `GCP_PROJECT_ID` variables appear in balenaCloud for the device. After a successful DELETE, those variables disappear.\n","gitHead":"14f427b32bf2be89722d613ff25928d178d92c0f","private":false,"scripts":{"test":"echo \"No tests yet\" && exit 0","start":"node index.js"},"_npmUser":{"name":"balena.io","email":"accounts+npm@balena.io"},"repository":{"url":"git+https://github.com/balena-io-examples/gcp-iot-provision.git","type":"git"},"versionist":{"publishedAt":"2022-06-13T20:33:01.900Z"},"_npmVersion":"6.14.17","description":"Google Cloud function to provision a balena device to IoT Core","directories":{},"_nodeVersion":"14.19.3","dependencies":{"balena-sdk":"^16.11.2","@google-cloud/iot":"^2.5.0","@google-cloud/functions-framework":"^2.1.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","_npmOperationalInternal":{"tmp":"tmp/gcp-iot-provision_0.2.5-dependabot-npm-and-yarn-balena-sdk-16-22-0-14f427b32bf2be89722d613ff25928d178d92c0f_1655152531795_0.1610932821515647","host":"s3://npm-registry-packages"},"deprecated":"Deprecated: no longer maintained. The GitHub repository has been archived and no further releases will be published."},"0.2.5-doc-device-env-vars-fd750c9be0194b58d91e32531fb6768cfbbc623a":{"name":"gcp-iot-provision","version":"0.2.5-doc-device-env-vars-fd750c9be0194b58d91e32531fb6768cfbbc623a","keywords":["balena","balenaCloud","google","iotcore","iot","gcp"],"author":{"name":"Ken Bannister","email":"ken@balena.io"},"license":"Apache-2.0","_id":"gcp-iot-provision@0.2.5-doc-device-env-vars-fd750c9be0194b58d91e32531fb6768cfbbc623a","maintainers":[{"name":"balena.io","email":"accounts+npm@balena.io"}],"homepage":"https://github.com/balena-io-examples/gcp-iot-provision","bugs":{"url":"https://github.com/balena-io-examples/gcp-iot-provision/issues"},"dist":{"shasum":"cdda646ec48c04ba8a953bb0b832415fa59dfb5e","tarball":"https://registry.npmjs.org/gcp-iot-provision/-/gcp-iot-provision-0.2.5-doc-device-env-vars-fd750c9be0194b58d91e32531fb6768cfbbc623a.tgz","fileCount":8,"integrity":"sha512-+AURHEb5AMT5YurzDOXJUxnPovRYxb/FfQaJjI2/NruJJlrVCDcXgswC4jBQAHVPu5AqJotWegYHMEck7X5EUg==","signatures":[{"sig":"MEUCIQDmEFXBbCvp8BtHL+BiijJm6JhkmB1RcDotZbnDR/huRwIgEKpFYn9hKDWRKfXKfDS5MWDOKz+mHD7eFXUENgaRKtU=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":137233,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJitHDUACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2Vmo29Q/7BACmwd7DJin7iAp3fVawVvklgLQUi2lUUT0CY90PJ2n/swNr\r\niQeZXdvlVflpH3ukTtiHvPqsxNVkqK1ADtcV1On1GM2aTS2ITo6DGsYwG/ku\r\nO75ZouDivp7TRAB+2vwMXUfBPJW+vGX9f8ULN3kn1wX85FwWssQSOOVnjlgO\r\n4zqYBl0shkG/i5M0O/XMkBZoD+pSRianfc8gBsTD391R7JiRR1p3iKHJly0m\r\n+b9zIKPFqhvyFFtCe7jLSefA5RnHZcjhWfDlbmskTWbdsokat6MWR12zJSBq\r\n5QaI5VcgyxFH+uzzZ5XfJ72dLdVZSI6rHZK5d0S6WBDHXPhOEp2XuFci3783\r\n9/sBp2tf0q12FhgM4F0t6Cmjm9fpxQX+5LCgGMVybFaX0dW6yo24kgzWuoRG\r\nKhHlW9VaO9gKoQ/bYNd0vPC6FLgvEgsZfyqdI3mhJF0x5NT/W8ls2I/BI0D3\r\nkCm9lOps6Xag6JdqNhmmHRfbNHXQxJx07OaIH/Qy6f9s7znVQGxe7IObfIVC\r\nNMElEkQzYDtkswSVyGrtXjfpG272idSMqUPMyl52xm1jdSFoe5Q7UljUe8Jn\r\nthDR8DlszkruJGx+L1jJrwrORMzGTBTwyGne+GlQocjG2sWyAGP0MpVrUX9S\r\n9aFhmkd66xfCicwXhe1ElNNopfOXQZ0y3gE=\r\n=Qjqn\r\n-----END PGP SIGNATURE-----\r\n"},"main":"index.js","type":"module","readme":"# Google Cloud Function for IoT Device Provisioning\n\nThis Cloud Function allows you to provision and synchronize a balena device with Google Cloud IoT Core in a secure and automated way via an HTTP endpoint. The Cloud Function may be called by a balena device, as seen in the [cloud-relay](https://github.com/balena-io-examples/cloud-relay) example.\n\n| Method | Action |\n|-------------|--------|\n| POST | Provisions a balena device with IoT Core. First the function verifies the device UUID with balenaCloud. Then it creates a public/private key pair and adds the device to the registry. Finally the function sets balena device environment variables for these entities. |\n| DELETE | Removes a balena device from the IoT Core registry and removes the balena device environment variable for the private key. Essentially reverses the actions from provisioning with HTTP POST. |\n\n## Device Environment Variables\nOnce the Cloud function has provisioned the device with GCP, it sets balena device environment variables as described below, which allow the device to connect to IoT Core. Some aspects of the variable values are common across devices, and are collected from the cloud function deployment.\n\n| Variable | Value |\n|----------|-------|\n| GCP_CLIENT_PATH | `<registry-path>/devices/<device-id>`<br><br> `<registry-path>` is derived from the project ID, GCP region, and registry ID<br>`<device-id>` is derived from the balena UUID for the device |\n| GCP_DATA_TOPIC_ROOT | `/devices/<device-id>` |\n| GCP_PROJECT_ID | Google Cloud project ID |\n| GCP_PRIVATE_KEY | Private key in PEM format, base64 encoded to eliminate line wrapping |\n\n\n## Setup and Testing\n### Google Cloud setup\nThe Cloud Function interacts with Google Cloud IoT Core via client code operating with service account credentials. You must setup a Google Cloud project with an IoT Core registry. The service account must have the *Cloud IoT Provisioner* role to manage device records in the IoT Core registry. See the IoT Core [documentation](https://cloud.google.com/iot/docs/how-tos) for more background.\n\n### Development setup\nClone this repo\n```\n$ git clone https://github.com/balena-io-examples/gcp-iot-provision\n```\n\nThe sections below show how to test the Cloud Function on a local test server and deploy to Cloud Functions. In either case you must provide the environment variables in the table below as instructed for the test/deployment.\n\n| Key         |    Value    |\n|-------------|-------------|\n| BALENA_API_KEY | for use of balena API; found in balenaCloud dashboard at: `account -> Preferences -> Access tokens` |\n| GCP_PROJECT_ID | Google Cloud project ID, like `my-project-000000`|\n| GCP_REGION | Google Cloud region for registry, like `us-central1` |\n| GCP_REGISTRY_ID | Google Cloud registry ID you provided to create the registry |\n| GCP_SERVICE_ACCOUNT |base64 encoding of the JSON formatted GCP service account credentials provided by Google when you created the service account. Example below, assuming the credentials JSON is contained in a file.<br><br>`cat <credentials.txt> \\| base64 -w 0` |\n\n### HTTP API\nThe HTTP endpoint expects a request containing a JSON body with the attributes below. Use POST to add a device to the cloud registry, DELETE to remove.\n\n| Attribute | Value |\n|-----------|-------|\n| uuid | UUID of device  |\n| balena_service | (optional) Name of service container on balena device that uses provisioned key and certificate, for example `cloud-relay`. If defined, creates service level variables; otherwise creates device level variables. Service level variables are more secure. |\n\n\n### Test locally\nThe Google Functions Framework is a convenient tool for local testing. \nFirst, start a local HTTP server ([docs reference](https://cloud.google.com/functions/docs/running/function-frameworks)) using a script like below.\n\n```\nexport BALENA_API_KEY=<...>\n... <other environment variables from table above>\nexport GCP_SERVICE_ACCOUNT=<...>\n\nnpx @google-cloud/functions-framework --target=provision\n```\n\nNext, use `curl` to send an HTTP request to the local server to provision a device. See the *HTTP API* section above for body contents.\n\n```\ncurl -X POST http://localhost:8080 -H \"Content-Type:application/json\" \\\n   -d '{ \"uuid\": \"<device-uuid>\", \"balena_service\": \"<service-name>\" }'\n```\n\nAfter a successful POST, you should see the device appear in your IoT Core registry and `GCP_CLIENT_PATH`, `GCP_DATA_TOPIC_ROOT`, `GCP_PRIVATE_KEY`, and `GCP_PROJECT_ID` variables appear in balenaCloud for the device. After a successful DELETE, those variables disappear.\n\n## Deploy\nTo deploy to Cloud Functions, use the command below. See the [command documentation](https://cloud.google.com/sdk/gcloud/reference/functions/deploy) for the format of `yaml-file`, which contains the variables from the table in the *Development setup* section above.\n\n```\ngcloud functions deploy provision --runtime=nodejs14 --trigger-http \\\n   --env-vars-file=<yaml-file> --allow-unauthenticated \\\n   --service-account=<name>@<xxxx>.iam.gserviceaccount.com\n```\n\nThe result is a Cloud Function like below. Notice the `TRIGGER` tab, which provides the URL for the function.\n\n![Alt text](docs/cloud-function.png)\n\n### Test the Cloud Function\nTo test the function, use a command like below, where the URL is from the `TRIGGER` tab in the console. See the *HTTP API* section above for body contents.\n\n```\ncurl -X POST https://<region>-<projectID>.cloudfunctions.net/provision \\\n   -H \"Content-Type:application/json\" \\\n   -d '{ \"uuid\": \"<device-uuid>\", \"balena_service\": \"<service-name>\" }'\n```\n\nAfter a successful POST, you should see the device appear in your IoT Core registry and `GCP_CLIENT_PATH`, `GCP_DATA_TOPIC_ROOT`, `GCP_PRIVATE_KEY`, and `GCP_PROJECT_ID` variables appear in balenaCloud for the device. After a successful DELETE, those variables disappear.\n","gitHead":"fd750c9be0194b58d91e32531fb6768cfbbc623a","private":false,"scripts":{"test":"echo \"No tests yet\" && exit 0","start":"node index.js"},"_npmUser":{"name":"balena.io","email":"accounts+npm@balena.io"},"repository":{"url":"git+https://github.com/balena-io-examples/gcp-iot-provision.git","type":"git"},"versionist":{"publishedAt":"2022-06-23T13:53:23.218Z"},"_npmVersion":"6.14.17","description":"Google Cloud function to provision a balena device to IoT Core","directories":{},"_nodeVersion":"14.19.3","dependencies":{"balena-sdk":"^16.11.2","@google-cloud/iot":"^2.5.0","@google-cloud/functions-framework":"^2.1.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","_npmOperationalInternal":{"tmp":"tmp/gcp-iot-provision_0.2.5-doc-device-env-vars-fd750c9be0194b58d91e32531fb6768cfbbc623a_1655992532439_0.6302230760573504","host":"s3://npm-registry-packages"},"deprecated":"Deprecated: no longer maintained. The GitHub repository has been archived and no further releases will be published."},"0.2.5":{"name":"gcp-iot-provision","version":"0.2.5","keywords":["balena","balenaCloud","google","iotcore","iot","gcp"],"author":{"name":"Ken Bannister","email":"ken@balena.io"},"license":"Apache-2.0","_id":"gcp-iot-provision@0.2.5","maintainers":[{"name":"balena.io","email":"accounts+npm@balena.io"}],"homepage":"https://github.com/balena-io-examples/gcp-iot-provision","bugs":{"url":"https://github.com/balena-io-examples/gcp-iot-provision/issues"},"dist":{"shasum":"9de268750e7ca1bf7417db26c942aa40b071f055","tarball":"https://registry.npmjs.org/gcp-iot-provision/-/gcp-iot-provision-0.2.5.tgz","fileCount":8,"integrity":"sha512-xjU0HxVwMDfT+Hi/5S53liU3GVbu8E8EwqUzyhFna36TtMcbXSgX2U47+nuISq7MsAK+7Ha0kAhXTsyKMIlHgg==","signatures":[{"sig":"MEQCIAa7GFLFkB0007reRbvg0P72wtglsmMy1RuQ0ObCT81kAiBY9naUvvYOZ50hmfMDy2cY1mkWFKOwrhPtiAI3LZSrTg==","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":137172,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJitHf4ACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2Vmo9YA/9HhrZXu3DPbymvG5SodEuVS1fbSaYjd2W1B+Hdp+1P8w9w0Ge\r\nCwU2ar/ULze5ewaj003Iz27K2cH238gv7puzzvGXq8ceOiPWxkhUf7eEhUE/\r\novht+eWp9UpTjuL4T1BDYIyeSn+jda//A5OsB6tLM/ncD7RKHTpu14z6XRQ8\r\nvK1htcwb1G0sygvcWE/PC7uEuy7uXgEQbQc4ixiHPNozFNOJXfdzY1BwS5TI\r\nNTc5+JCI0ebCsnIX4F62Vw/xKM/ecQxuLFfgwlUg81kV3RvI8oTer9PfT7w2\r\nZ8Ua8tmmEmaYC34a9etM6pWCIUuL+ajHhuEM4DV+G/tyOSGz/gHjkNmbsx1d\r\n0xxsSeSSFiMAm6z9OHBTzqWWTLbhxNQPY3LbiO9XjBC4ayZd6onOKr7d3W01\r\n1nmJGzEBosBxOL/83Ck9fkJncKlREwztlVvKQbj3ytrL6cXeSr2TWhuxge/2\r\nF0o8xwBHDM8FDdUitNqvyOZtFygdXEQVGsqec6LsUMCf4ntTgYskevWhY8En\r\nn3N+5VLCu1RZlZ7EzZYePAtQ77kFa9jI/f1uSbA2u/bCz3L7abNyMFmmJt8U\r\niE9kft4X7EvoFH9KvZj/bxxrAGAJjGrxtZPzTx1Kiy9LCpdiOCA//3cIQQN4\r\nYNDaZL1ziZkBtW8OZWymrRnEM69AQb/4yQY=\r\n=8dCV\r\n-----END PGP SIGNATURE-----\r\n"},"main":"index.js","type":"module","gitHead":"9fbee56505f52fd69206fa96a5758a6da728ea44","private":false,"scripts":{"test":"echo \"No tests yet\" && exit 0","start":"node index.js"},"_npmUser":{"name":"balena.io","email":"accounts+npm@balena.io"},"repository":{"url":"git+https://github.com/balena-io-examples/gcp-iot-provision.git","type":"git"},"versionist":{"publishedAt":"2022-06-23T14:23:54.054Z"},"_npmVersion":"6.14.17","description":"Google Cloud function to provision a balena device to IoT Core","directories":{},"_nodeVersion":"14.19.3","dependencies":{"balena-sdk":"^16.11.2","@google-cloud/iot":"^2.5.0","@google-cloud/functions-framework":"^2.1.0"},"_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/gcp-iot-provision_0.2.5_1655994360458_0.16373296511978874","host":"s3://npm-registry-packages"},"deprecated":"Deprecated: no longer maintained. The GitHub repository has been archived and no further releases will be published."},"0.2.6-dependabot-npm-and-yarn-balena-sdk-16-22-0-0a2d6fd35c83a2cb526ba1dd48ba26640cb79e4b":{"name":"gcp-iot-provision","version":"0.2.6-dependabot-npm-and-yarn-balena-sdk-16-22-0-0a2d6fd35c83a2cb526ba1dd48ba26640cb79e4b","keywords":["balena","balenaCloud","google","iotcore","iot","gcp"],"author":{"name":"Ken Bannister","email":"ken@balena.io"},"license":"Apache-2.0","_id":"gcp-iot-provision@0.2.6-dependabot-npm-and-yarn-balena-sdk-16-22-0-0a2d6fd35c83a2cb526ba1dd48ba26640cb79e4b","maintainers":[{"name":"balena.io","email":"accounts+npm@balena.io"}],"homepage":"https://github.com/balena-io-examples/gcp-iot-provision","bugs":{"url":"https://github.com/balena-io-examples/gcp-iot-provision/issues"},"dist":{"shasum":"d1bd9e0d7aefbc84ec189b7b8d484bc7c0a68887","tarball":"https://registry.npmjs.org/gcp-iot-provision/-/gcp-iot-provision-0.2.6-dependabot-npm-and-yarn-balena-sdk-16-22-0-0a2d6fd35c83a2cb526ba1dd48ba26640cb79e4b.tgz","fileCount":8,"integrity":"sha512-LK1+HiFjbFQ6EfYN1BPqdsxw7iULKiGYpWMwLG2tXkQZ8rpMQa1po3ZXXjeBp5A0HSayLjomjm9fiPgRQOWUaw==","signatures":[{"sig":"MEQCIF3fFYD9+UfjI3B8eSFK1m8NkJibgWTSG5YcaasqjHGqAiAdUwqCb7bcMfAqdEI1KsyL08qVnmmI5iOFitVN8Tpqig==","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":137350,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJiuhbkACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmqEjQ/6A3cb/eXrHo4UxG5OdIG+yuj+y0N6ZvwkFyQTxQv80nNkBtY9\r\nKskrn8MRk2dGYVbkmL8+VV9HesT2m38LiOLEerS+n7drztdWQpz2KENgg7QG\r\nC3WX6sjnrxHK/Oz7z56UYZazOgriT6xVGYJo/UBNYn08fOvWbc131th6UboE\r\ncI3xMgZTArahlp7rL16c6uoBpF+lW1XSEd92RzsD1WZis5Go32CCTR+CE2cx\r\nEVtMjWDONtePWVd0VCSVoztgAZyXC+zqB4IyjAumw2iqYDmclj+jHeicguHt\r\neqDnvSlWlEO557pME05ETfVfZog00DRSDjV/jQDwSjy6Q7vSABsAgeRDp+nn\r\njKfhFGqEyR6Zpe9QVTECvbz4lU7Dkud7/ObmP4Gz23q55MHHYujqwzmP5jtU\r\nlMyWCni5nWTK4QfUJd+B/ZI8zi0uBX0NM/mvrPE7hDCfyKuoSQ7kPP26EJ4X\r\nVR/whiC6kNQ2zYPsvXRdsPFpTVvYuJD7FHiouuBrwPUOOJZBQSwhi5iaYjS/\r\nG9TN4hs50QSKDLSJBmF0FYC/WEO5tXQBntC4KU1mS9nfyNKx5G1MKUjhb4rK\r\ntUepd47oT+hy7KL/7hbGa6/DRmKkS84wT6+wyoCUAwgMbxKrUS2iKzCtw8jA\r\nV7xfA2GHt7ktzKzMTaPUIBOSu438Ecixczk=\r\n=Mg9P\r\n-----END PGP SIGNATURE-----\r\n"},"main":"index.js","type":"module","readme":"# Google Cloud Function for IoT Device Provisioning\n\nThis Cloud Function allows you to provision and synchronize a balena device with Google Cloud IoT Core in a secure and automated way via an HTTP endpoint. The Cloud Function may be called by a balena device, as seen in the [cloud-relay](https://github.com/balena-io-examples/cloud-relay) example.\n\n| Method | Action |\n|-------------|--------|\n| POST | Provisions a balena device with IoT Core. First the function verifies the device UUID with balenaCloud. Then it creates a public/private key pair and adds the device to the registry. Finally the function sets balena device environment variables for these entities. |\n| DELETE | Removes a balena device from the IoT Core registry and removes the balena device environment variable for the private key. Essentially reverses the actions from provisioning with HTTP POST. |\n\n## Device Environment Variables\nOnce the Cloud function has provisioned the device with GCP, it sets balena device environment variables as described below, which allow the device to connect to IoT Core. Some aspects of the variable values are common across devices, and are collected from the cloud function deployment.\n\n| Variable | Value |\n|----------|-------|\n| GCP_CLIENT_PATH | `<registry-path>/devices/<device-id>`<br><br> `<registry-path>` is derived from the project ID, GCP region, and registry ID<br>`<device-id>` is derived from the balena UUID for the device |\n| GCP_DATA_TOPIC_ROOT | `/devices/<device-id>` |\n| GCP_PROJECT_ID | Google Cloud project ID |\n| GCP_PRIVATE_KEY | Private key in PEM format, base64 encoded to eliminate line wrapping |\n\n\n## Setup and Testing\n### Google Cloud setup\nThe Cloud Function interacts with Google Cloud IoT Core via client code operating with service account credentials. You must setup a Google Cloud project with an IoT Core registry. The service account must have the *Cloud IoT Provisioner* role to manage device records in the IoT Core registry. See the IoT Core [documentation](https://cloud.google.com/iot/docs/how-tos) for more background.\n\n### Development setup\nClone this repo\n```\n$ git clone https://github.com/balena-io-examples/gcp-iot-provision\n```\n\nThe sections below show how to test the Cloud Function on a local test server and deploy to Cloud Functions. In either case you must provide the environment variables in the table below as instructed for the test/deployment.\n\n| Key         |    Value    |\n|-------------|-------------|\n| BALENA_API_KEY | for use of balena API; found in balenaCloud dashboard at: `account -> Preferences -> Access tokens` |\n| GCP_PROJECT_ID | Google Cloud project ID, like `my-project-000000`|\n| GCP_REGION | Google Cloud region for registry, like `us-central1` |\n| GCP_REGISTRY_ID | Google Cloud registry ID you provided to create the registry |\n| GCP_SERVICE_ACCOUNT |base64 encoding of the JSON formatted GCP service account credentials provided by Google when you created the service account. Example below, assuming the credentials JSON is contained in a file.<br><br>`cat <credentials.txt> \\| base64 -w 0` |\n\n### HTTP API\nThe HTTP endpoint expects a request containing a JSON body with the attributes below. Use POST to add a device to the cloud registry, DELETE to remove.\n\n| Attribute | Value |\n|-----------|-------|\n| uuid | UUID of device  |\n| balena_service | (optional) Name of service container on balena device that uses provisioned key and certificate, for example `cloud-relay`. If defined, creates service level variables; otherwise creates device level variables. Service level variables are more secure. |\n\n\n### Test locally\nThe Google Functions Framework is a convenient tool for local testing. \nFirst, start a local HTTP server ([docs reference](https://cloud.google.com/functions/docs/running/function-frameworks)) using a script like below.\n\n```\nexport BALENA_API_KEY=<...>\n... <other environment variables from table above>\nexport GCP_SERVICE_ACCOUNT=<...>\n\nnpx @google-cloud/functions-framework --target=provision\n```\n\nNext, use `curl` to send an HTTP request to the local server to provision a device. See the *HTTP API* section above for body contents.\n\n```\ncurl -X POST http://localhost:8080 -H \"Content-Type:application/json\" \\\n   -d '{ \"uuid\": \"<device-uuid>\", \"balena_service\": \"<service-name>\" }'\n```\n\nAfter a successful POST, you should see the device appear in your IoT Core registry and `GCP_CLIENT_PATH`, `GCP_DATA_TOPIC_ROOT`, `GCP_PRIVATE_KEY`, and `GCP_PROJECT_ID` variables appear in balenaCloud for the device. After a successful DELETE, those variables disappear.\n\n## Deploy\nTo deploy to Cloud Functions, use the command below. See the [command documentation](https://cloud.google.com/sdk/gcloud/reference/functions/deploy) for the format of `yaml-file`, which contains the variables from the table in the *Development setup* section above.\n\n```\ngcloud functions deploy provision --runtime=nodejs14 --trigger-http \\\n   --env-vars-file=<yaml-file> --allow-unauthenticated \\\n   --service-account=<name>@<xxxx>.iam.gserviceaccount.com\n```\n\nThe result is a Cloud Function like below. Notice the `TRIGGER` tab, which provides the URL for the function.\n\n![Alt text](docs/cloud-function.png)\n\n### Test the Cloud Function\nTo test the function, use a command like below, where the URL is from the `TRIGGER` tab in the console. See the *HTTP API* section above for body contents.\n\n```\ncurl -X POST https://<region>-<projectID>.cloudfunctions.net/provision \\\n   -H \"Content-Type:application/json\" \\\n   -d '{ \"uuid\": \"<device-uuid>\", \"balena_service\": \"<service-name>\" }'\n```\n\nAfter a successful POST, you should see the device appear in your IoT Core registry and `GCP_CLIENT_PATH`, `GCP_DATA_TOPIC_ROOT`, `GCP_PRIVATE_KEY`, and `GCP_PROJECT_ID` variables appear in balenaCloud for the device. After a successful DELETE, those variables disappear.\n","gitHead":"0a2d6fd35c83a2cb526ba1dd48ba26640cb79e4b","private":false,"scripts":{"test":"echo \"No tests yet\" && exit 0","start":"node index.js"},"_npmUser":{"name":"balena.io","email":"accounts+npm@balena.io"},"repository":{"url":"git+https://github.com/balena-io-examples/gcp-iot-provision.git","type":"git"},"versionist":{"publishedAt":"2022-06-27T20:43:26.314Z"},"_npmVersion":"6.14.17","description":"Google Cloud function to provision a balena device to IoT Core","directories":{},"_nodeVersion":"14.19.3","dependencies":{"balena-sdk":"^16.11.2","@google-cloud/iot":"^2.5.0","@google-cloud/functions-framework":"^2.1.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","_npmOperationalInternal":{"tmp":"tmp/gcp-iot-provision_0.2.6-dependabot-npm-and-yarn-balena-sdk-16-22-0-0a2d6fd35c83a2cb526ba1dd48ba26640cb79e4b_1656362724142_0.43632081698856995","host":"s3://npm-registry-packages"},"deprecated":"Deprecated: no longer maintained. The GitHub repository has been archived and no further releases will be published."},"0.2.6-uniform-readme-sections-5716c780868f8f33d9ba0275b116a9434b40526d":{"name":"gcp-iot-provision","version":"0.2.6-uniform-readme-sections-5716c780868f8f33d9ba0275b116a9434b40526d","keywords":["balena","balenaCloud","google","iotcore","iot","gcp"],"author":{"name":"Ken Bannister","email":"ken@balena.io"},"license":"Apache-2.0","_id":"gcp-iot-provision@0.2.6-uniform-readme-sections-5716c780868f8f33d9ba0275b116a9434b40526d","maintainers":[{"name":"balena.io","email":"accounts+npm@balena.io"}],"homepage":"https://github.com/balena-io-examples/gcp-iot-provision","bugs":{"url":"https://github.com/balena-io-examples/gcp-iot-provision/issues"},"dist":{"shasum":"7be7426a761ddc171ffb71cc31d857ae3e9d0dc7","tarball":"https://registry.npmjs.org/gcp-iot-provision/-/gcp-iot-provision-0.2.6-uniform-readme-sections-5716c780868f8f33d9ba0275b116a9434b40526d.tgz","fileCount":8,"integrity":"sha512-7OKOEzBbC0Ugt6ORjeY8/yxwVmRwpNHRFTcgqsXv/0sw34dwg2NNG6wTxIbTFQl9I24htUTmp4nIV+u3bWrGPw==","signatures":[{"sig":"MEUCIQCJfu41uqtwoemu3AHmy3Rkyuorvzulg1QyzBSQSZ04kQIgdQpCvCbMapD2vMpJoP5SZ+Vv+NfrV+wVXq5NDhkVITk=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":137324,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJiwFHBACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2Vmr0Sg/7BCUB4wYUGjVycI9fJFSEWj6UlRJ9cvezd2zSkhR5ULdX5yOm\r\nbM2POf3777brO+ZkzQVrzhU3ROK9v5GAqqokkiDcVs9IGS1aLABB+LY7BWP9\r\ndiQ4L8pq1jbuJVvm1d9DpcKUqBWO3CYLoaBFZoJEFPi93Z3skcfzo0JWbM8z\r\nfaCR13KJx5YnjU/O0QyptDAjbHPCen97RPzDHHIuekQ9678yKsJ52sPkombp\r\nRrOeQXi3lRhP+BQy7vxhhy+RW3335DcCQfSqjlPaE49lvXpO/M5BfHYeJgDV\r\no/mnHt/j8qJPFJ5Vho+//gKevA2p6BE+ofd/JwdmN9dRxe1Hm+XUqUjvFqlv\r\nJ42Rq3CzswDSfHsG1Cl4yHNCSxqk6mYxLB1sqfVvd/7pAPN9O5Pyteo0V6Lp\r\n3MMpiv3RucgtMECerw/G0b9DDP2bbf9uPYyPrPLWXHrmJNuBdcc7RV9sJNxB\r\n3CoGCC6ZeRuDRdJwpqM9ISGVXRbtOFhybSzTlRh4WHjCmM7d+7e3BQEmQd6R\r\nXCfX9wTQGcuyyHRV/LxOW2t8NOZvyja8ZOCMDCZA46Ax2y292gs1F+J0uqjH\r\n2MwviubC4v39G4egn7wGGzO61fyGzjJg/ImQNF0SmP9NU/hPWVPa2oAbS6pt\r\nmyJaO2O8IabgUOE0QNhAGAGZcP+Le7+FWG4=\r\n=r7Lb\r\n-----END PGP SIGNATURE-----\r\n"},"main":"index.js","type":"module","readme":"# Google Cloud Function for IoT Device Provisioning\n\nThis Cloud Function allows you to provision and synchronize a balena device with Google Cloud IoT Core in a secure and automated way via an HTTP endpoint. The Cloud Function may be called by a balena device, as seen in the [cloud-relay](https://github.com/balena-io-examples/cloud-relay) example.\n\n| Method | Action |\n|-------------|--------|\n| POST | Provisions a balena device with IoT Core. First the function verifies the device UUID with balenaCloud. Then it creates a public/private key pair and adds the device to the registry. Finally the function sets balena device environment variables for these entities. |\n| DELETE | Removes a balena device from the IoT Core registry and removes the balena device environment variable for the private key. Essentially reverses the actions from provisioning with HTTP POST. |\n\n## Device Environment Variables\nOnce the Cloud function has provisioned the device with GCP, it sets balena device environment variables as described below, which allow the device to connect to IoT Core. Some aspects of the variable values are common across devices, and are collected from the cloud function deployment.\n\n| Variable | Value |\n|----------|-------|\n| GCP_CLIENT_PATH | `<registry-path>/devices/<device-id>`<br><br> `<registry-path>` is derived from the project ID, GCP region, and registry ID<br>`<device-id>` is derived from the balena UUID for the device |\n| GCP_DATA_TOPIC_ROOT | `/devices/<device-id>` |\n| GCP_PROJECT_ID | Google Cloud project ID |\n| GCP_PRIVATE_KEY | Private key in PEM format, base64 encoded to eliminate line wrapping |\n\n\n## Setup and Testing\n### GCP setup\nThe Cloud Function interacts with Google Cloud IoT Core via client code operating with service account credentials. You must setup a Google Cloud project with an IoT Core registry. The service account must have the *Cloud IoT Provisioner* role to manage device records in the IoT Core registry. See the IoT Core [documentation](https://cloud.google.com/iot/docs/how-tos) for more background.\n\n### Workspace setup\nClone this repo\n```\n$ git clone https://github.com/balena-io-examples/gcp-iot-provision\n```\n\nThe sections below show how to test the Cloud Function on a local test server and deploy to Cloud Functions. In either case you must provide the environment variables in the table below as instructed for the test/deployment.\n\n| Key         |    Value    |\n|-------------|-------------|\n| BALENA_API_KEY | for use of balena API; found in balenaCloud dashboard at: `account -> Preferences -> Access tokens` |\n| GCP_PROJECT_ID | Google Cloud project ID, like `my-project-000000`|\n| GCP_REGION | Google Cloud region for registry, like `us-central1` |\n| GCP_REGISTRY_ID | Google Cloud registry ID you provided to create the registry |\n| GCP_SERVICE_ACCOUNT |base64 encoding of the JSON formatted GCP service account credentials provided by Google when you created the service account. Example below, assuming the credentials JSON is contained in a file.<br><br>`cat <credentials.txt> \\| base64 -w 0` |\n\n### HTTP API\nThe HTTP endpoint expects a request containing a JSON body with the attributes below. Use POST to add a device to the cloud registry, DELETE to remove.\n\n| Attribute | Value |\n|-----------|-------|\n| uuid | UUID of device  |\n| balena_service | (optional) Name of service container on balena device that uses provisioned key and certificate, for example `cloud-relay`. If defined, creates service level variables; otherwise creates device level variables. Service level variables are more secure. |\n\n\n### Test locally\nThe Google Functions Framework is a convenient tool for local testing. \nFirst, start a local HTTP server ([docs reference](https://cloud.google.com/functions/docs/running/function-frameworks)) using a script like below.\n\n```\nexport BALENA_API_KEY=<...>\n... <other environment variables from table above>\nexport GCP_SERVICE_ACCOUNT=<...>\n\nnpx @google-cloud/functions-framework --target=provision\n```\n\nNext, use `curl` to send an HTTP request to the local server to provision a device. See the *HTTP API* section above for body contents.\n\n```\ncurl -X POST http://localhost:8080 -H \"Content-Type:application/json\" \\\n   -d '{ \"uuid\": \"<device-uuid>\", \"balena_service\": \"<service-name>\" }'\n```\n\nAfter a successful POST, you should see the device appear in your IoT Core registry and `GCP_CLIENT_PATH`, `GCP_DATA_TOPIC_ROOT`, `GCP_PRIVATE_KEY`, and `GCP_PROJECT_ID` variables appear in balenaCloud for the device. After a successful DELETE, those variables disappear.\n\n## Deploy\nTo deploy to Cloud Functions, use the command below. See the [command documentation](https://cloud.google.com/sdk/gcloud/reference/functions/deploy) for the format of `yaml-file`, which contains the variables from the table in the *Development setup* section above.\n\n```\ngcloud functions deploy provision --runtime=nodejs14 --trigger-http \\\n   --env-vars-file=<yaml-file> --allow-unauthenticated \\\n   --service-account=<name>@<xxxx>.iam.gserviceaccount.com\n```\n\nThe result is a Cloud Function like below. Notice the `TRIGGER` tab, which provides the URL for the function.\n\n![Alt text](docs/cloud-function.png)\n\n### Test the Cloud Function\nTo test the function, use a command like below, where the URL is from the `TRIGGER` tab in the console. See the *HTTP API* section above for body contents.\n\n```\ncurl -X POST https://<region>-<projectID>.cloudfunctions.net/provision \\\n   -H \"Content-Type:application/json\" \\\n   -d '{ \"uuid\": \"<device-uuid>\", \"balena_service\": \"<service-name>\" }'\n```\n\nAfter a successful POST, you should see the device appear in your IoT Core registry and `GCP_CLIENT_PATH`, `GCP_DATA_TOPIC_ROOT`, `GCP_PRIVATE_KEY`, and `GCP_PROJECT_ID` variables appear in balenaCloud for the device. After a successful DELETE, those variables disappear.\n","gitHead":"5716c780868f8f33d9ba0275b116a9434b40526d","private":false,"scripts":{"test":"echo \"No tests yet\" && exit 0","start":"node index.js"},"_npmUser":{"name":"balena.io","email":"accounts+npm@balena.io"},"repository":{"url":"git+https://github.com/balena-io-examples/gcp-iot-provision.git","type":"git"},"versionist":{"publishedAt":"2022-07-02T14:07:46.794Z"},"_npmVersion":"6.14.17","description":"Google Cloud function to provision a balena device to IoT Core","directories":{},"_nodeVersion":"14.19.3","dependencies":{"balena-sdk":"^16.11.2","@google-cloud/iot":"^2.5.0","@google-cloud/functions-framework":"^2.1.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","_npmOperationalInternal":{"tmp":"tmp/gcp-iot-provision_0.2.6-uniform-readme-sections-5716c780868f8f33d9ba0275b116a9434b40526d_1656771008882_0.906706115618646","host":"s3://npm-registry-packages"},"deprecated":"Deprecated: no longer maintained. The GitHub repository has been archived and no further releases will be published."},"0.2.6":{"name":"gcp-iot-provision","version":"0.2.6","keywords":["balena","balenaCloud","google","iotcore","iot","gcp"],"author":{"name":"Ken Bannister","email":"ken@balena.io"},"license":"Apache-2.0","_id":"gcp-iot-provision@0.2.6","maintainers":[{"name":"balena.io","email":"accounts+npm@balena.io"}],"homepage":"https://github.com/balena-io-examples/gcp-iot-provision","bugs":{"url":"https://github.com/balena-io-examples/gcp-iot-provision/issues"},"dist":{"shasum":"b9e350dbfb2037044c618fd0749849b6cc0ff473","tarball":"https://registry.npmjs.org/gcp-iot-provision/-/gcp-iot-provision-0.2.6.tgz","fileCount":8,"integrity":"sha512-oBcxGUdsPk+185rDKEaa818312u6ZXLZv1FA4jVdQUXOHTy8Tj4drv3+DoW7ply5tj40wttjYvcDc2v3AcwRpg==","signatures":[{"sig":"MEUCIQD5xswqVsdXB5GXZmqgYeEplssCqsAJvHySs5QfudAADAIgfblh3JvVPAk+nKsNNoDaTziYPVo569Nf3TY32D5SaqA=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":137259,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJiwFLcACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2Vmoa5g//ez2Yw8YX64khfDyErBzvXJIofQ1niboPBRS/f6V2Rxqr3gmB\r\nLQOqhWqiGJ8JI7g5yAGKR79TCugMrycaaocx3kRO8brdFBczaJg+40pukkWi\r\n9HH9WUH5W5trc3qWJAjqtbJrhlxNPRa7iDVFJ3TAvR5ZYmWncVj4MTUsazsi\r\ndSIpWUHuL9buCJUJfwx5VmydwZYNkH8FjeqifJA5Wq62zXpe9MVwB20WfIwB\r\nYsRBjJm1IHLeTNBMvZX5E4Xc1WdtNCctLZKn3Z1q7dvUFkAoJDRIUOL6M7sG\r\nl8XQxq2n0zFlp1mCNixf4j74aoVcjBkg3S/24FBCI8XqUoKpd8gWC9aEHRm3\r\nPSvJ064OSDb2igzHVpmzSXVgzL9qYF3mDtrC3x+cza2U74DSkscxFV3nczbO\r\nPfSUzaE2DxvSBG5C4r8H5/X8yyZbIQmOwrRcbwegiTBEgq1N3jyK0SESqYsd\r\n1aGNostsqCAD2WOmOO/vFrXiR5NGfP7NlG18ccN2lzgAwA584abXeTzqGlUj\r\n12naGaeqx6U+cLGCFy676B+SFBoLJQB+7Bt+7vPVPy8MIWghsB3E1ix2MFq7\r\nqsYJwEEacziPxBeTQVrnJWGRm1bI+sNWZjztRmCMKXqd+jihCNcAfY/aLc8n\r\n3ISRsOpuVjXU4A3dpMjF7X0uH26vJEEcRJM=\r\n=vIpo\r\n-----END PGP SIGNATURE-----\r\n"},"main":"index.js","type":"module","gitHead":"3d0fcbce03db1488b681e3bcba12ecf7aae80c37","private":false,"scripts":{"test":"echo \"No tests yet\" && exit 0","start":"node index.js"},"_npmUser":{"name":"balena.io","email":"accounts+npm@balena.io"},"repository":{"url":"git+https://github.com/balena-io-examples/gcp-iot-provision.git","type":"git"},"versionist":{"publishedAt":"2022-07-02T14:13:00.069Z"},"_npmVersion":"6.14.17","description":"Google Cloud function to provision a balena device to IoT Core","directories":{},"_nodeVersion":"14.19.3","dependencies":{"balena-sdk":"^16.11.2","@google-cloud/iot":"^2.5.0","@google-cloud/functions-framework":"^2.1.0"},"_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/gcp-iot-provision_0.2.6_1656771292228_0.3303193606745034","host":"s3://npm-registry-packages"},"deprecated":"Deprecated: no longer maintained. The GitHub repository has been archived and no further releases will be published."},"0.2.7-dependabot-npm-and-yarn-balena-sdk-16-22-0-bad5e68351a454284dd7f5fc02bbb30702cb852c":{"name":"gcp-iot-provision","version":"0.2.7-dependabot-npm-and-yarn-balena-sdk-16-22-0-bad5e68351a454284dd7f5fc02bbb30702cb852c","keywords":["balena","balenaCloud","google","iotcore","iot","gcp"],"author":{"name":"Ken Bannister","email":"ken@balena.io"},"license":"Apache-2.0","_id":"gcp-iot-provision@0.2.7-dependabot-npm-and-yarn-balena-sdk-16-22-0-bad5e68351a454284dd7f5fc02bbb30702cb852c","maintainers":[{"name":"balena.io","email":"accounts+npm@balena.io"}],"homepage":"https://github.com/balena-io-examples/gcp-iot-provision","bugs":{"url":"https://github.com/balena-io-examples/gcp-iot-provision/issues"},"dist":{"shasum":"4b9b51df59b1f20c7a9ea2cb41ce4e7ba6e0e4af","tarball":"https://registry.npmjs.org/gcp-iot-provision/-/gcp-iot-provision-0.2.7-dependabot-npm-and-yarn-balena-sdk-16-22-0-bad5e68351a454284dd7f5fc02bbb30702cb852c.tgz","fileCount":8,"integrity":"sha512-i59j4sDHXe0UBkxWjt5Zs/SicFvcW7UZ88WAxTOegEE60cy086ILf5JK/aeVx2S53b2Te9cfq9yFMF2V1lzUgw==","signatures":[{"sig":"MEQCIGcEAX/5BMF9mzpijPYdrJVyecgf0oEwjqy/Nb3223O/AiA48PD40wSRHJgJTJCW6R4Pvz4RvmB+L9BCPyO4LBxyJA==","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":137437,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJiw0JlACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2Vmr02hAAjyXnAXSD1wcoSUX/zpwh143sZbd2dNLMUb/Hsf5KJPZNHRp/\r\n/puxv80CgxqTZWkzQNbdDq/jfF938D5tu0YHoseI9TQKn1XWUPaFpR0kOTbs\r\nNUUckIhsM3dJyKYpNpWr7F1/21tuY15OeZM4/kulKMnr0VXxXlPjUjd9+g/I\r\n7nGKEV4dfBAMLdwe2CvW6OSt7wUtNAowPZ8/mwFuTOS83GzgWuqsYQRs1GbN\r\ns3E9icEH0z0ZMfhjXhobDo6H8SzKA/Tcn3noO7Pxa7JRrS4lpi+ITZEa+jyJ\r\nV2fx36i58TPN85M5keqDkPtS9zdDhkGbnwI/7iW30yg7aHJ6DP+dedohHNCv\r\nALrsnd4AZ7py5MincK8ZtEr8Ow6FxdjcMYNOd8CraDC2VwJaySnPyCmkgbYZ\r\nW6XZY5AtMj0sZJ5/AuQkCz4dy7cdQx8WU9/c0qeUF8xv4Es/A3U5O8liCicG\r\ngfhedeyEqSP2880suVEC/Uk5aOTPh+u6D0SeB/zNYc2A8hhJEYNwsPk1kVAn\r\nXIQ3sJbRsNc050ibQp8thnriLQUceystX4RGjhBUZImrTbTOf4z13xvL5PFm\r\nTsieC2QFWOL0Sh2ufSfhXK9IlTDzJBqgvsAzbbjB2df/qLMhp46GN1K/9rBI\r\ni8rBVNn0zXRCu1toOMeWMZR2JRDcm4v7cOM=\r\n=Bn77\r\n-----END PGP SIGNATURE-----\r\n"},"main":"index.js","type":"module","readme":"# Google Cloud Function for IoT Device Provisioning\n\nThis Cloud Function allows you to provision and synchronize a balena device with Google Cloud IoT Core in a secure and automated way via an HTTP endpoint. The Cloud Function may be called by a balena device, as seen in the [cloud-relay](https://github.com/balena-io-examples/cloud-relay) example.\n\n| Method | Action |\n|-------------|--------|\n| POST | Provisions a balena device with IoT Core. First the function verifies the device UUID with balenaCloud. Then it creates a public/private key pair and adds the device to the registry. Finally the function sets balena device environment variables for these entities. |\n| DELETE | Removes a balena device from the IoT Core registry and removes the balena device environment variable for the private key. Essentially reverses the actions from provisioning with HTTP POST. |\n\n## Device Environment Variables\nOnce the Cloud function has provisioned the device with GCP, it sets balena device environment variables as described below, which allow the device to connect to IoT Core. Some aspects of the variable values are common across devices, and are collected from the cloud function deployment.\n\n| Variable | Value |\n|----------|-------|\n| GCP_CLIENT_PATH | `<registry-path>/devices/<device-id>`<br><br> `<registry-path>` is derived from the project ID, GCP region, and registry ID<br>`<device-id>` is derived from the balena UUID for the device |\n| GCP_DATA_TOPIC_ROOT | `/devices/<device-id>` |\n| GCP_PROJECT_ID | Google Cloud project ID |\n| GCP_PRIVATE_KEY | Private key in PEM format, base64 encoded to eliminate line wrapping |\n\n\n## Setup and Testing\n### GCP setup\nThe Cloud Function interacts with Google Cloud IoT Core via client code operating with service account credentials. You must setup a Google Cloud project with an IoT Core registry. The service account must have the *Cloud IoT Provisioner* role to manage device records in the IoT Core registry. See the IoT Core [documentation](https://cloud.google.com/iot/docs/how-tos) for more background.\n\n### Workspace setup\nClone this repo\n```\n$ git clone https://github.com/balena-io-examples/gcp-iot-provision\n```\n\nThe sections below show how to test the Cloud Function on a local test server and deploy to Cloud Functions. In either case you must provide the environment variables in the table below as instructed for the test/deployment.\n\n| Key         |    Value    |\n|-------------|-------------|\n| BALENA_API_KEY | for use of balena API; found in balenaCloud dashboard at: `account -> Preferences -> Access tokens` |\n| GCP_PROJECT_ID | Google Cloud project ID, like `my-project-000000`|\n| GCP_REGION | Google Cloud region for registry, like `us-central1` |\n| GCP_REGISTRY_ID | Google Cloud registry ID you provided to create the registry |\n| GCP_SERVICE_ACCOUNT |base64 encoding of the JSON formatted GCP service account credentials provided by Google when you created the service account. Example below, assuming the credentials JSON is contained in a file.<br><br>`cat <credentials.txt> \\| base64 -w 0` |\n\n### HTTP API\nThe HTTP endpoint expects a request containing a JSON body with the attributes below. Use POST to add a device to the cloud registry, DELETE to remove.\n\n| Attribute | Value |\n|-----------|-------|\n| uuid | UUID of device  |\n| balena_service | (optional) Name of service container on balena device that uses provisioned key and certificate, for example `cloud-relay`. If defined, creates service level variables; otherwise creates device level variables. Service level variables are more secure. |\n\n\n### Test locally\nThe Google Functions Framework is a convenient tool for local testing. \nFirst, start a local HTTP server ([docs reference](https://cloud.google.com/functions/docs/running/function-frameworks)) using a script like below.\n\n```\nexport BALENA_API_KEY=<...>\n... <other environment variables from table above>\nexport GCP_SERVICE_ACCOUNT=<...>\n\nnpx @google-cloud/functions-framework --target=provision\n```\n\nNext, use `curl` to send an HTTP request to the local server to provision a device. See the *HTTP API* section above for body contents.\n\n```\ncurl -X POST http://localhost:8080 -H \"Content-Type:application/json\" \\\n   -d '{ \"uuid\": \"<device-uuid>\", \"balena_service\": \"<service-name>\" }'\n```\n\nAfter a successful POST, you should see the device appear in your IoT Core registry and `GCP_CLIENT_PATH`, `GCP_DATA_TOPIC_ROOT`, `GCP_PRIVATE_KEY`, and `GCP_PROJECT_ID` variables appear in balenaCloud for the device. After a successful DELETE, those variables disappear.\n\n## Deploy\nTo deploy to Cloud Functions, use the command below. See the [command documentation](https://cloud.google.com/sdk/gcloud/reference/functions/deploy) for the format of `yaml-file`, which contains the variables from the table in the *Development setup* section above.\n\n```\ngcloud functions deploy provision --runtime=nodejs14 --trigger-http \\\n   --env-vars-file=<yaml-file> --allow-unauthenticated \\\n   --service-account=<name>@<xxxx>.iam.gserviceaccount.com\n```\n\nThe result is a Cloud Function like below. Notice the `TRIGGER` tab, which provides the URL for the function.\n\n![Alt text](docs/cloud-function.png)\n\n### Test the Cloud Function\nTo test the function, use a command like below, where the URL is from the `TRIGGER` tab in the console. See the *HTTP API* section above for body contents.\n\n```\ncurl -X POST https://<region>-<projectID>.cloudfunctions.net/provision \\\n   -H \"Content-Type:application/json\" \\\n   -d '{ \"uuid\": \"<device-uuid>\", \"balena_service\": \"<service-name>\" }'\n```\n\nAfter a successful POST, you should see the device appear in your IoT Core registry and `GCP_CLIENT_PATH`, `GCP_DATA_TOPIC_ROOT`, `GCP_PRIVATE_KEY`, and `GCP_PROJECT_ID` variables appear in balenaCloud for the device. After a successful DELETE, those variables disappear.\n","gitHead":"bad5e68351a454284dd7f5fc02bbb30702cb852c","private":false,"scripts":{"test":"echo \"No tests yet\" && exit 0","start":"node index.js"},"_npmUser":{"name":"balena.io","email":"accounts+npm@balena.io"},"repository":{"url":"git+https://github.com/balena-io-examples/gcp-iot-provision.git","type":"git"},"versionist":{"publishedAt":"2022-07-04T19:39:20.877Z"},"_npmVersion":"6.14.17","description":"Google Cloud function to provision a balena device to IoT Core","directories":{},"_nodeVersion":"14.19.3","dependencies":{"balena-sdk":"^16.11.2","@google-cloud/iot":"^2.5.0","@google-cloud/functions-framework":"^2.1.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","_npmOperationalInternal":{"tmp":"tmp/gcp-iot-provision_0.2.7-dependabot-npm-and-yarn-balena-sdk-16-22-0-bad5e68351a454284dd7f5fc02bbb30702cb852c_1656963685044_0.03961364307879567","host":"s3://npm-registry-packages"},"deprecated":"Deprecated: no longer maintained. The GitHub repository has been archived and no further releases will be published."},"0.2.7-dependabot-npm-and-yarn-balena-sdk-16-24-0-cee7aefb76ac8e6f577cb7f15a1c276bb190f803":{"name":"gcp-iot-provision","version":"0.2.7-dependabot-npm-and-yarn-balena-sdk-16-24-0-cee7aefb76ac8e6f577cb7f15a1c276bb190f803","keywords":["balena","balenaCloud","google","iotcore","iot","gcp"],"author":{"name":"Ken Bannister","email":"ken@balena.io"},"license":"Apache-2.0","_id":"gcp-iot-provision@0.2.7-dependabot-npm-and-yarn-balena-sdk-16-24-0-cee7aefb76ac8e6f577cb7f15a1c276bb190f803","maintainers":[{"name":"balena.io","email":"accounts+npm@balena.io"}],"homepage":"https://github.com/balena-io-examples/gcp-iot-provision","bugs":{"url":"https://github.com/balena-io-examples/gcp-iot-provision/issues"},"dist":{"shasum":"cd36a2b7937183bf987be066c9e9695e533ed739","tarball":"https://registry.npmjs.org/gcp-iot-provision/-/gcp-iot-provision-0.2.7-dependabot-npm-and-yarn-balena-sdk-16-24-0-cee7aefb76ac8e6f577cb7f15a1c276bb190f803.tgz","fileCount":8,"integrity":"sha512-sG6b98i/DXIOk98qqF4hFjFbNzKtZPoZ4GEBJXVIDcUxxzqWFLWdxmBonlKlGN8bx/5AYX+ygGNn7U7YV2YETQ==","signatures":[{"sig":"MEYCIQDHE3oseQ7hU3QGIjbG+Q6hMuuGsgL14RCWLJtCkU7nogIhAM09Tcj7LgrsDFGkf+uP7RNwQPLkai45ymQq8bQKERIk","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":137437,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJizJgmACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmoTFBAAgoEm/3hhFmu16k/PVVG23CRQ3q/kEIF5JzRs04mqBD7CQQO5\r\nMPaOHg+iWhtrqIKns8mq/sfIIe09rvEwFnIyrIaC3EkoN4VsDrckwS0K5Aug\r\nqa5zv3cmIuyTFyI7HK9UgOMxoPo0N2nFx/wqxuhjqFbCcAk0LRrNZwS/dL0H\r\n7Iwu9SOj948VRwd1VXrpUSbyKPl7ZerHdL1QX0FcLZPwD4fYTC9kgiph5xIk\r\nq9TJTcd5bpCAO5L8auNGN4S5WnvcEBziiiv7vJ8u5snH4FeDkEh31SLZvWWf\r\nj6hUQYcHgXFujzhrxzZUzURkkXvppb/CDMbV+Jdcztw8nBx9VtCZWEB0vrVs\r\n+sm0sPbO7ydF26ZxqkCRLsqxIsDxBQdfK7mqs8QqOyEiE7s3ec6HSPWiVI6F\r\n2Bqrzuc2q1Q06AzmwYXwBjCahWmRkxh5PnnkvBzbbbV0Hx7N2txuJQPM4tTl\r\nSYTX4b1blAopjy9h916duUHw+39qOwa14Vu9+u+SXyOjCwYg5wn33F19nYw2\r\nCV6QiDl/g5yp4OD86vqhqCV0Dj7Y6+wkUkzuJMomYXwzCTuOTPUn1Sez3nEE\r\n9BMm1J3ytdrtTNS2yivHP5EEPg7g1FrF21Ha/9VHGqQsCdDe26URYgc69D72\r\nuVSfS9eWdCT1sRqWJX/GZl5C/uiareNfcqw=\r\n=rZ3g\r\n-----END PGP SIGNATURE-----\r\n"},"main":"index.js","type":"module","readme":"# Google Cloud Function for IoT Device Provisioning\n\nThis Cloud Function allows you to provision and synchronize a balena device with Google Cloud IoT Core in a secure and automated way via an HTTP endpoint. The Cloud Function may be called by a balena device, as seen in the [cloud-relay](https://github.com/balena-io-examples/cloud-relay) example.\n\n| Method | Action |\n|-------------|--------|\n| POST | Provisions a balena device with IoT Core. First the function verifies the device UUID with balenaCloud. Then it creates a public/private key pair and adds the device to the registry. Finally the function sets balena device environment variables for these entities. |\n| DELETE | Removes a balena device from the IoT Core registry and removes the balena device environment variable for the private key. Essentially reverses the actions from provisioning with HTTP POST. |\n\n## Device Environment Variables\nOnce the Cloud function has provisioned the device with GCP, it sets balena device environment variables as described below, which allow the device to connect to IoT Core. Some aspects of the variable values are common across devices, and are collected from the cloud function deployment.\n\n| Variable | Value |\n|----------|-------|\n| GCP_CLIENT_PATH | `<registry-path>/devices/<device-id>`<br><br> `<registry-path>` is derived from the project ID, GCP region, and registry ID<br>`<device-id>` is derived from the balena UUID for the device |\n| GCP_DATA_TOPIC_ROOT | `/devices/<device-id>` |\n| GCP_PROJECT_ID | Google Cloud project ID |\n| GCP_PRIVATE_KEY | Private key in PEM format, base64 encoded to eliminate line wrapping |\n\n\n## Setup and Testing\n### GCP setup\nThe Cloud Function interacts with Google Cloud IoT Core via client code operating with service account credentials. You must setup a Google Cloud project with an IoT Core registry. The service account must have the *Cloud IoT Provisioner* role to manage device records in the IoT Core registry. See the IoT Core [documentation](https://cloud.google.com/iot/docs/how-tos) for more background.\n\n### Workspace setup\nClone this repo\n```\n$ git clone https://github.com/balena-io-examples/gcp-iot-provision\n```\n\nThe sections below show how to test the Cloud Function on a local test server and deploy to Cloud Functions. In either case you must provide the environment variables in the table below as instructed for the test/deployment.\n\n| Key         |    Value    |\n|-------------|-------------|\n| BALENA_API_KEY | for use of balena API; found in balenaCloud dashboard at: `account -> Preferences -> Access tokens` |\n| GCP_PROJECT_ID | Google Cloud project ID, like `my-project-000000`|\n| GCP_REGION | Google Cloud region for registry, like `us-central1` |\n| GCP_REGISTRY_ID | Google Cloud registry ID you provided to create the registry |\n| GCP_SERVICE_ACCOUNT |base64 encoding of the JSON formatted GCP service account credentials provided by Google when you created the service account. Example below, assuming the credentials JSON is contained in a file.<br><br>`cat <credentials.txt> \\| base64 -w 0` |\n\n### HTTP API\nThe HTTP endpoint expects a request containing a JSON body with the attributes below. Use POST to add a device to the cloud registry, DELETE to remove.\n\n| Attribute | Value |\n|-----------|-------|\n| uuid | UUID of device  |\n| balena_service | (optional) Name of service container on balena device that uses provisioned key and certificate, for example `cloud-relay`. If defined, creates service level variables; otherwise creates device level variables. Service level variables are more secure. |\n\n\n### Test locally\nThe Google Functions Framework is a convenient tool for local testing. \nFirst, start a local HTTP server ([docs reference](https://cloud.google.com/functions/docs/running/function-frameworks)) using a script like below.\n\n```\nexport BALENA_API_KEY=<...>\n... <other environment variables from table above>\nexport GCP_SERVICE_ACCOUNT=<...>\n\nnpx @google-cloud/functions-framework --target=provision\n```\n\nNext, use `curl` to send an HTTP request to the local server to provision a device. See the *HTTP API* section above for body contents.\n\n```\ncurl -X POST http://localhost:8080 -H \"Content-Type:application/json\" \\\n   -d '{ \"uuid\": \"<device-uuid>\", \"balena_service\": \"<service-name>\" }'\n```\n\nAfter a successful POST, you should see the device appear in your IoT Core registry and `GCP_CLIENT_PATH`, `GCP_DATA_TOPIC_ROOT`, `GCP_PRIVATE_KEY`, and `GCP_PROJECT_ID` variables appear in balenaCloud for the device. After a successful DELETE, those variables disappear.\n\n## Deploy\nTo deploy to Cloud Functions, use the command below. See the [command documentation](https://cloud.google.com/sdk/gcloud/reference/functions/deploy) for the format of `yaml-file`, which contains the variables from the table in the *Development setup* section above.\n\n```\ngcloud functions deploy provision --runtime=nodejs14 --trigger-http \\\n   --env-vars-file=<yaml-file> --allow-unauthenticated \\\n   --service-account=<name>@<xxxx>.iam.gserviceaccount.com\n```\n\nThe result is a Cloud Function like below. Notice the `TRIGGER` tab, which provides the URL for the function.\n\n![Alt text](docs/cloud-function.png)\n\n### Test the Cloud Function\nTo test the function, use a command like below, where the URL is from the `TRIGGER` tab in the console. See the *HTTP API* section above for body contents.\n\n```\ncurl -X POST https://<region>-<projectID>.cloudfunctions.net/provision \\\n   -H \"Content-Type:application/json\" \\\n   -d '{ \"uuid\": \"<device-uuid>\", \"balena_service\": \"<service-name>\" }'\n```\n\nAfter a successful POST, you should see the device appear in your IoT Core registry and `GCP_CLIENT_PATH`, `GCP_DATA_TOPIC_ROOT`, `GCP_PRIVATE_KEY`, and `GCP_PROJECT_ID` variables appear in balenaCloud for the device. After a successful DELETE, those variables disappear.\n","gitHead":"cee7aefb76ac8e6f577cb7f15a1c276bb190f803","private":false,"scripts":{"test":"echo \"No tests yet\" && exit 0","start":"node index.js"},"_npmUser":{"name":"balena.io","email":"accounts+npm@balena.io"},"repository":{"url":"git+https://github.com/balena-io-examples/gcp-iot-provision.git","type":"git"},"versionist":{"publishedAt":"2022-07-11T21:35:05.968Z"},"_npmVersion":"6.14.17","description":"Google Cloud function to provision a balena device to IoT Core","directories":{},"_nodeVersion":"14.19.3","dependencies":{"balena-sdk":"^16.11.2","@google-cloud/iot":"^2.5.0","@google-cloud/functions-framework":"^2.1.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","_npmOperationalInternal":{"tmp":"tmp/gcp-iot-provision_0.2.7-dependabot-npm-and-yarn-balena-sdk-16-24-0-cee7aefb76ac8e6f577cb7f15a1c276bb190f803_1657575462267_0.7078669222480258","host":"s3://npm-registry-packages"},"deprecated":"Deprecated: no longer maintained. The GitHub repository has been archived and no further releases will be published."},"0.2.7-add-repo-yml-0f09d42662b1a0426f0a64d4c53ea9fe36c12e43":{"name":"gcp-iot-provision","version":"0.2.7-add-repo-yml-0f09d42662b1a0426f0a64d4c53ea9fe36c12e43","keywords":["balena","balenaCloud","google","iotcore","iot","gcp"],"author":{"name":"Ken Bannister","email":"ken@balena.io"},"license":"Apache-2.0","_id":"gcp-iot-provision@0.2.7-add-repo-yml-0f09d42662b1a0426f0a64d4c53ea9fe36c12e43","maintainers":[{"name":"balena.io","email":"accounts+npm@balena.io"}],"homepage":"https://github.com/balena-io-examples/gcp-iot-provision","bugs":{"url":"https://github.com/balena-io-examples/gcp-iot-provision/issues"},"dist":{"shasum":"cb0519e805f2fd1f40a84697cf0046b092cc096e","tarball":"https://registry.npmjs.org/gcp-iot-provision/-/gcp-iot-provision-0.2.7-add-repo-yml-0f09d42662b1a0426f0a64d4c53ea9fe36c12e43.tgz","fileCount":9,"integrity":"sha512-c3bDu+NKNxebJc1M8YuI6+HVdODWnHWr+/iwiRERkwe9LsMZ3G62szpzRTMGwfeUrl5FY6lRyjn3gWbjiJVQSA==","signatures":[{"sig":"MEQCIAdG06NgtX6d4E3Ub6zTURzsOuMKD8tQCzLGKzVs0mo4AiA5rKfIvH9oQYiRhFvuQD0UWuNnOGDaJcmLm6I7rEnZDQ==","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":137405,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJi0J0DACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmpY+A/+O5kXZ6HRNttDLUU6so8Y3MEfUBOXk+8to2O4FQlO5RIyOuAh\r\n+x9Rvoq8nIBvs9H6SZjkle8DOwfZbCu/yv+m1OLZdDwdFDh3CHbW5wOEIjtx\r\nitMk1yLhRMWfj3VjkWxMjgQSyQErNtbWc4Say98yh+fOHD+tuSEI4L8WwAks\r\nwoic1bnk5XCPJySh1ZpRjwKdGezBso1yBRrtFBHlLDq+Iyq/bfSENQJLLeVN\r\n2GVCoEBej05BJCw6cv8It6JDxLHX9v3BoUCiqObEYnWRPfMEUaLZkLKL0zkR\r\n+wI8gyl91LJZtqB0V47AQztEDFJDsqYALWGkWj+fNUisULwP9Mba+M/3+HEN\r\nZvUie/GSLArCRKA2OCWJNYljvoT2bruOdN/EKf9LzU9N9G7TjLG8ufxaCRm4\r\n1CdLs3MIhcCRkoDS98rbJQoj5igne/ZJq0cwtr3ec4zxxw5E+0CS3w4j9g0R\r\nVo6wICf8xysPcuo+Cl4Cn9Au25dmFD/OF6vEGuZTUSrxScmDm/MnHiTurfFZ\r\nc/NX93U+5N/UIHvqa9UXoJ/cD09e8g/16Lbm+wNmz0exy9opA8pS20LJBjR/\r\nqmlC1bjzvHCh2P95lMeYLG94JHPm/FxhzDEyBdNmVZsnBjuz4HKMDFPiOTwK\r\nlLjrSa1p4P7wjxtZDb4BkGFMLPxlGnuIScI=\r\n=JC3g\r\n-----END PGP SIGNATURE-----\r\n"},"main":"index.js","type":"module","readme":"# Google Cloud Function for IoT Device Provisioning\n\nThis Cloud Function allows you to provision and synchronize a balena device with Google Cloud IoT Core in a secure and automated way via an HTTP endpoint. The Cloud Function may be called by a balena device, as seen in the [cloud-relay](https://github.com/balena-io-examples/cloud-relay) example.\n\n| Method | Action |\n|-------------|--------|\n| POST | Provisions a balena device with IoT Core. First the function verifies the device UUID with balenaCloud. Then it creates a public/private key pair and adds the device to the registry. Finally the function sets balena device environment variables for these entities. |\n| DELETE | Removes a balena device from the IoT Core registry and removes the balena device environment variable for the private key. Essentially reverses the actions from provisioning with HTTP POST. |\n\n## Device Environment Variables\nOnce the Cloud function has provisioned the device with GCP, it sets balena device environment variables as described below, which allow the device to connect to IoT Core. Some aspects of the variable values are common across devices, and are collected from the cloud function deployment.\n\n| Variable | Value |\n|----------|-------|\n| GCP_CLIENT_PATH | `<registry-path>/devices/<device-id>`<br><br> `<registry-path>` is derived from the project ID, GCP region, and registry ID<br>`<device-id>` is derived from the balena UUID for the device |\n| GCP_DATA_TOPIC_ROOT | `/devices/<device-id>` |\n| GCP_PROJECT_ID | Google Cloud project ID |\n| GCP_PRIVATE_KEY | Private key in PEM format, base64 encoded to eliminate line wrapping |\n\n\n## Setup and Testing\n### GCP setup\nThe Cloud Function interacts with Google Cloud IoT Core via client code operating with service account credentials. You must setup a Google Cloud project with an IoT Core registry. The service account must have the *Cloud IoT Provisioner* role to manage device records in the IoT Core registry. See the IoT Core [documentation](https://cloud.google.com/iot/docs/how-tos) for more background.\n\n### Workspace setup\nClone this repo\n```\n$ git clone https://github.com/balena-io-examples/gcp-iot-provision\n```\n\nThe sections below show how to test the Cloud Function on a local test server and deploy to Cloud Functions. In either case you must provide the environment variables in the table below as instructed for the test/deployment.\n\n| Key         |    Value    |\n|-------------|-------------|\n| BALENA_API_KEY | for use of balena API; found in balenaCloud dashboard at: `account -> Preferences -> Access tokens` |\n| GCP_PROJECT_ID | Google Cloud project ID, like `my-project-000000`|\n| GCP_REGION | Google Cloud region for registry, like `us-central1` |\n| GCP_REGISTRY_ID | Google Cloud registry ID you provided to create the registry |\n| GCP_SERVICE_ACCOUNT |base64 encoding of the JSON formatted GCP service account credentials provided by Google when you created the service account. Example below, assuming the credentials JSON is contained in a file.<br><br>`cat <credentials.txt> \\| base64 -w 0` |\n\n### HTTP API\nThe HTTP endpoint expects a request containing a JSON body with the attributes below. Use POST to add a device to the cloud registry, DELETE to remove.\n\n| Attribute | Value |\n|-----------|-------|\n| uuid | UUID of device  |\n| balena_service | (optional) Name of service container on balena device that uses provisioned key and certificate, for example `cloud-relay`. If defined, creates service level variables; otherwise creates device level variables. Service level variables are more secure. |\n\n\n### Test locally\nThe Google Functions Framework is a convenient tool for local testing. \nFirst, start a local HTTP server ([docs reference](https://cloud.google.com/functions/docs/running/function-frameworks)) using a script like below.\n\n```\nexport BALENA_API_KEY=<...>\n... <other environment variables from table above>\nexport GCP_SERVICE_ACCOUNT=<...>\n\nnpx @google-cloud/functions-framework --target=provision\n```\n\nNext, use `curl` to send an HTTP request to the local server to provision a device. See the *HTTP API* section above for body contents.\n\n```\ncurl -X POST http://localhost:8080 -H \"Content-Type:application/json\" \\\n   -d '{ \"uuid\": \"<device-uuid>\", \"balena_service\": \"<service-name>\" }'\n```\n\nAfter a successful POST, you should see the device appear in your IoT Core registry and `GCP_CLIENT_PATH`, `GCP_DATA_TOPIC_ROOT`, `GCP_PRIVATE_KEY`, and `GCP_PROJECT_ID` variables appear in balenaCloud for the device. After a successful DELETE, those variables disappear.\n\n## Deploy\nTo deploy to Cloud Functions, use the command below. See the [command documentation](https://cloud.google.com/sdk/gcloud/reference/functions/deploy) for the format of `yaml-file`, which contains the variables from the table in the *Development setup* section above.\n\n```\ngcloud functions deploy provision --runtime=nodejs14 --trigger-http \\\n   --env-vars-file=<yaml-file> --allow-unauthenticated \\\n   --service-account=<name>@<xxxx>.iam.gserviceaccount.com\n```\n\nThe result is a Cloud Function like below. Notice the `TRIGGER` tab, which provides the URL for the function.\n\n![Alt text](docs/cloud-function.png)\n\n### Test the Cloud Function\nTo test the function, use a command like below, where the URL is from the `TRIGGER` tab in the console. See the *HTTP API* section above for body contents.\n\n```\ncurl -X POST https://<region>-<projectID>.cloudfunctions.net/provision \\\n   -H \"Content-Type:application/json\" \\\n   -d '{ \"uuid\": \"<device-uuid>\", \"balena_service\": \"<service-name>\" }'\n```\n\nAfter a successful POST, you should see the device appear in your IoT Core registry and `GCP_CLIENT_PATH`, `GCP_DATA_TOPIC_ROOT`, `GCP_PRIVATE_KEY`, and `GCP_PROJECT_ID` variables appear in balenaCloud for the device. After a successful DELETE, those variables disappear.\n","gitHead":"0f09d42662b1a0426f0a64d4c53ea9fe36c12e43","private":false,"scripts":{"test":"echo \"No tests yet\" && exit 0","start":"node index.js"},"_npmUser":{"name":"balena.io","email":"accounts+npm@balena.io"},"repository":{"url":"git+https://github.com/balena-io-examples/gcp-iot-provision.git","type":"git"},"versionist":{"publishedAt":"2022-07-14T22:45:03.229Z"},"_npmVersion":"6.14.17","description":"Google Cloud function to provision a balena device to IoT Core","directories":{},"_nodeVersion":"14.19.3","dependencies":{"balena-sdk":"^16.11.2","@google-cloud/iot":"^2.5.0","@google-cloud/functions-framework":"^2.1.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","_npmOperationalInternal":{"tmp":"tmp/gcp-iot-provision_0.2.7-add-repo-yml-0f09d42662b1a0426f0a64d4c53ea9fe36c12e43_1657838851194_0.22177390022565957","host":"s3://npm-registry-packages"},"deprecated":"Deprecated: no longer maintained. The GitHub repository has been archived and no further releases will be published."},"0.2.7":{"name":"gcp-iot-provision","version":"0.2.7","keywords":["balena","balenaCloud","google","iotcore","iot","gcp"],"author":{"name":"Ken Bannister","email":"ken@balena.io"},"license":"Apache-2.0","_id":"gcp-iot-provision@0.2.7","maintainers":[{"name":"balena.io","email":"accounts+npm@balena.io"}],"homepage":"https://github.com/balena-io-examples/gcp-iot-provision","bugs":{"url":"https://github.com/balena-io-examples/gcp-iot-provision/issues"},"dist":{"shasum":"d6ba03e74da6e4691a5ea1e0615bf91039efc646","tarball":"https://registry.npmjs.org/gcp-iot-provision/-/gcp-iot-provision-0.2.7.tgz","fileCount":9,"integrity":"sha512-oA2u86EC8Kf9gj4bZCURZ4DiNLkZGzd2Zc0aGB5BZGrHOyTgd9fKfovEG/0T1VZmtFBSTVQYpjX2NCaPQQGzeA==","signatures":[{"sig":"MEUCIAmcV2korM8BvhD4/8sAdVa06GNR9sPM+11XD1dnal6VAiEA3Rws027JPVmsjL94sylGybF3KMwQ4o/1+aphPaLzMfo=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":137351,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJi0TrOACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmorNw/9FF6JOf71Qwyfj3S2f4zWZKOL/K1/dmE9DSBfiQrldI6oC/Fw\r\nf3dAlIL2fM8Td7BDZj2LNTLt82+dnl++qn4M5TqMKfk3zLgqDNb8GfRFJ+lX\r\nDfTTkeOKkHQ89gNXrBTaGMB6wpnofEsMsK1xB1b8jwAYEZB3fGd0j6ffSDh4\r\nr74IUxO+WWgpRGSPEFHwnwMDCFmbdg+Vk29heRJt/6Gtixdh70CA7ePcmZq2\r\n//RttYojWK87jrI7HWFI4gYUV680XDiJ0KYp9W+qTU9vd+PdMAXJSP9gdgbS\r\nf+o/KlACacdzXlH38DJjNGrHmqupX1OXYLA9cX8P1aovgmc8l+PGNMb7QSx4\r\nYvVVeFJFmKuXAs1buQEzP29M2Yppz9GgCh4HNTsabLorHJZqq0sB9VnbxlVz\r\n/9SG92ooDUiiTiG3/3wchsmyghdpw93XPrBz7QFsQia0LN2BFzXyuuDCUBRB\r\nQtuM9qs4Lybg1dk15d0jdGTZzOzLN584sfpO1FkrDAyTbPKmV54s9+X++4mp\r\n+C6kiF7vXX6/fwMH6Mv7MxcZ4TPygPu7hSKQ2xbSJhmt2odzqe1f1N0bavaj\r\nppoMWDBPiaRcDXEYP127SEHXWfH5eiEw56fVK8OM0QIXHIlCV/9pzhRaPQEe\r\nqv782w7s1PqOxaQcU6GbGa1c/mz1pTMV2dM=\r\n=1tFf\r\n-----END PGP SIGNATURE-----\r\n"},"main":"index.js","type":"module","gitHead":"677898586fa17c9912cc9bcf57916f0689c0c3cb","private":false,"scripts":{"test":"echo \"No tests yet\" && exit 0","start":"node index.js"},"_npmUser":{"name":"balena.io","email":"accounts+npm@balena.io"},"repository":{"url":"git+https://github.com/balena-io-examples/gcp-iot-provision.git","type":"git"},"versionist":{"publishedAt":"2022-07-15T09:58:51.223Z"},"_npmVersion":"6.14.17","description":"Google Cloud function to provision a balena device to IoT Core","directories":{},"_nodeVersion":"14.19.3","dependencies":{"balena-sdk":"^16.11.2","@google-cloud/iot":"^2.5.0","@google-cloud/functions-framework":"^2.1.0"},"_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/gcp-iot-provision_0.2.7_1657879246207_0.7368810128806436","host":"s3://npm-registry-packages"},"deprecated":"Deprecated: no longer maintained. The GitHub repository has been archived and no further releases will be published."},"0.2.8-dependabot-npm-and-yarn-moment-2-29-4-3c89a9bfdd6cd07673085dda5660f43122540b27":{"name":"gcp-iot-provision","version":"0.2.8-dependabot-npm-and-yarn-moment-2-29-4-3c89a9bfdd6cd07673085dda5660f43122540b27","keywords":["balena","balenaCloud","google","iotcore","iot","gcp"],"author":{"name":"Ken Bannister","email":"ken@balena.io"},"license":"Apache-2.0","_id":"gcp-iot-provision@0.2.8-dependabot-npm-and-yarn-moment-2-29-4-3c89a9bfdd6cd07673085dda5660f43122540b27","maintainers":[{"name":"balena.io","email":"accounts+npm@balena.io"}],"homepage":"https://github.com/balena-io-examples/gcp-iot-provision","bugs":{"url":"https://github.com/balena-io-examples/gcp-iot-provision/issues"},"dist":{"shasum":"5ce431224ddf627c3c51f997aae86846b60da351","tarball":"https://registry.npmjs.org/gcp-iot-provision/-/gcp-iot-provision-0.2.8-dependabot-npm-and-yarn-moment-2-29-4-3c89a9bfdd6cd07673085dda5660f43122540b27.tgz","fileCount":9,"integrity":"sha512-3KEWIZsuFO0mMAiI8ZDC3Gkn6LyLrRNEDE6eAvHP3Q9WqVs8fSmJN6NUSk1uO4WiataN0ASuJYRYuxjGEb/4vQ==","signatures":[{"sig":"MEQCID84DC5uvYLkhvrEBiZv48tfvwWLTKOlqQ40CLUT1JfRAiA8hGeEfwWJ4mlIjdBztL1ckrHInxNulyjrgeara+LVSA==","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":137515,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJi0Tv7ACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmqKtBAAoJgN4OkOEFd6ixVe0/5J4sN2RveSa4zAZs+TapXYDWj/axmz\r\nWJlDxZx6mOKbtJ5hNw7gzVv2voJOgdiLca4UDus2kEnXIfnldVpF9vLg4RtI\r\n955gFX0CjPLBPJl1PtVjo9CSExSsXDS0rjSqNM0J6dNWG3aZyAjHN+rbL5Cr\r\nsLr+jdH2ig1q0D/ojBoAay9RFZbHzLQi7CVafqqvMp7BuPPhbyzdGZJvYNdi\r\nvlpLPHEUbuj3uP16tNFdXU1+CNtXFCv3z1rSRJPHkQdejOAb5djXjrgRGzTw\r\ncJH3qh95OImdInDogWu7X+60guo+uJDtPp+HBG+iD0240i05GTkc1YfycmEE\r\nMbShfcvylGHSeMRf8K+YaNghRTsYfTNc33Aw3ap2qi1bxqqDpwx7MjycUnl6\r\nB34Y+0WT3By8XROc+vpEa+eiaV8z2r+T/KXfa9x9E2HYy3CPazSBMgWNYBm6\r\nMeSCBwKy8Mm4tZuOPo2bsMINzKCnYEfm5Vdgl01BufXN0Prn69uVm8HCPAR1\r\nJXOw0VrIrqUBD5au0fmZsirwLmeO2hYauEIrPxoKhn3Xu8GTGr2A+N+5NnMD\r\nzR89iXXCX1ZdL9P8FvpHvZspRmGpHJqNXVkvqFHylTkWklSRQDg+tucNhsLz\r\nkZ8elrnSj9P/SPYj/MesCxz58oYxLaVTDng=\r\n=uYwy\r\n-----END PGP SIGNATURE-----\r\n"},"main":"index.js","type":"module","readme":"# Google Cloud Function for IoT Device Provisioning\n\nThis Cloud Function allows you to provision and synchronize a balena device with Google Cloud IoT Core in a secure and automated way via an HTTP endpoint. The Cloud Function may be called by a balena device, as seen in the [cloud-relay](https://github.com/balena-io-examples/cloud-relay) example.\n\n| Method | Action |\n|-------------|--------|\n| POST | Provisions a balena device with IoT Core. First the function verifies the device UUID with balenaCloud. Then it creates a public/private key pair and adds the device to the registry. Finally the function sets balena device environment variables for these entities. |\n| DELETE | Removes a balena device from the IoT Core registry and removes the balena device environment variable for the private key. Essentially reverses the actions from provisioning with HTTP POST. |\n\n## Device Environment Variables\nOnce the Cloud function has provisioned the device with GCP, it sets balena device environment variables as described below, which allow the device to connect to IoT Core. Some aspects of the variable values are common across devices, and are collected from the cloud function deployment.\n\n| Variable | Value |\n|----------|-------|\n| GCP_CLIENT_PATH | `<registry-path>/devices/<device-id>`<br><br> `<registry-path>` is derived from the project ID, GCP region, and registry ID<br>`<device-id>` is derived from the balena UUID for the device |\n| GCP_DATA_TOPIC_ROOT | `/devices/<device-id>` |\n| GCP_PROJECT_ID | Google Cloud project ID |\n| GCP_PRIVATE_KEY | Private key in PEM format, base64 encoded to eliminate line wrapping |\n\n\n## Setup and Testing\n### GCP setup\nThe Cloud Function interacts with Google Cloud IoT Core via client code operating with service account credentials. You must setup a Google Cloud project with an IoT Core registry. The service account must have the *Cloud IoT Provisioner* role to manage device records in the IoT Core registry. See the IoT Core [documentation](https://cloud.google.com/iot/docs/how-tos) for more background.\n\n### Workspace setup\nClone this repo\n```\n$ git clone https://github.com/balena-io-examples/gcp-iot-provision\n```\n\nThe sections below show how to test the Cloud Function on a local test server and deploy to Cloud Functions. In either case you must provide the environment variables in the table below as instructed for the test/deployment.\n\n| Key         |    Value    |\n|-------------|-------------|\n| BALENA_API_KEY | for use of balena API; found in balenaCloud dashboard at: `account -> Preferences -> Access tokens` |\n| GCP_PROJECT_ID | Google Cloud project ID, like `my-project-000000`|\n| GCP_REGION | Google Cloud region for registry, like `us-central1` |\n| GCP_REGISTRY_ID | Google Cloud registry ID you provided to create the registry |\n| GCP_SERVICE_ACCOUNT |base64 encoding of the JSON formatted GCP service account credentials provided by Google when you created the service account. Example below, assuming the credentials JSON is contained in a file.<br><br>`cat <credentials.txt> \\| base64 -w 0` |\n\n### HTTP API\nThe HTTP endpoint expects a request containing a JSON body with the attributes below. Use POST to add a device to the cloud registry, DELETE to remove.\n\n| Attribute | Value |\n|-----------|-------|\n| uuid | UUID of device  |\n| balena_service | (optional) Name of service container on balena device that uses provisioned key and certificate, for example `cloud-relay`. If defined, creates service level variables; otherwise creates device level variables. Service level variables are more secure. |\n\n\n### Test locally\nThe Google Functions Framework is a convenient tool for local testing. \nFirst, start a local HTTP server ([docs reference](https://cloud.google.com/functions/docs/running/function-frameworks)) using a script like below.\n\n```\nexport BALENA_API_KEY=<...>\n... <other environment variables from table above>\nexport GCP_SERVICE_ACCOUNT=<...>\n\nnpx @google-cloud/functions-framework --target=provision\n```\n\nNext, use `curl` to send an HTTP request to the local server to provision a device. See the *HTTP API* section above for body contents.\n\n```\ncurl -X POST http://localhost:8080 -H \"Content-Type:application/json\" \\\n   -d '{ \"uuid\": \"<device-uuid>\", \"balena_service\": \"<service-name>\" }'\n```\n\nAfter a successful POST, you should see the device appear in your IoT Core registry and `GCP_CLIENT_PATH`, `GCP_DATA_TOPIC_ROOT`, `GCP_PRIVATE_KEY`, and `GCP_PROJECT_ID` variables appear in balenaCloud for the device. After a successful DELETE, those variables disappear.\n\n## Deploy\nTo deploy to Cloud Functions, use the command below. See the [command documentation](https://cloud.google.com/sdk/gcloud/reference/functions/deploy) for the format of `yaml-file`, which contains the variables from the table in the *Development setup* section above.\n\n```\ngcloud functions deploy provision --runtime=nodejs14 --trigger-http \\\n   --env-vars-file=<yaml-file> --allow-unauthenticated \\\n   --service-account=<name>@<xxxx>.iam.gserviceaccount.com\n```\n\nThe result is a Cloud Function like below. Notice the `TRIGGER` tab, which provides the URL for the function.\n\n![Alt text](docs/cloud-function.png)\n\n### Test the Cloud Function\nTo test the function, use a command like below, where the URL is from the `TRIGGER` tab in the console. See the *HTTP API* section above for body contents.\n\n```\ncurl -X POST https://<region>-<projectID>.cloudfunctions.net/provision \\\n   -H \"Content-Type:application/json\" \\\n   -d '{ \"uuid\": \"<device-uuid>\", \"balena_service\": \"<service-name>\" }'\n```\n\nAfter a successful POST, you should see the device appear in your IoT Core registry and `GCP_CLIENT_PATH`, `GCP_DATA_TOPIC_ROOT`, `GCP_PRIVATE_KEY`, and `GCP_PROJECT_ID` variables appear in balenaCloud for the device. After a successful DELETE, those variables disappear.\n","gitHead":"3c89a9bfdd6cd07673085dda5660f43122540b27","private":false,"scripts":{"test":"echo \"No tests yet\" && exit 0","start":"node index.js"},"_npmUser":{"name":"balena.io","email":"accounts+npm@balena.io"},"repository":{"url":"git+https://github.com/balena-io-examples/gcp-iot-provision.git","type":"git"},"versionist":{"publishedAt":"2022-07-15T10:02:25.950Z"},"_npmVersion":"6.14.17","description":"Google Cloud function to provision a balena device to IoT Core","directories":{},"_nodeVersion":"14.19.3","dependencies":{"balena-sdk":"^16.11.2","@google-cloud/iot":"^2.5.0","@google-cloud/functions-framework":"^2.1.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","_npmOperationalInternal":{"tmp":"tmp/gcp-iot-provision_0.2.8-dependabot-npm-and-yarn-moment-2-29-4-3c89a9bfdd6cd07673085dda5660f43122540b27_1657879547152_0.4041431979865391","host":"s3://npm-registry-packages"},"deprecated":"Deprecated: no longer maintained. The GitHub repository has been archived and no further releases will be published."},"0.2.8-dependabot-npm-and-yarn-balena-sdk-16-24-0-e479ec99c7493b1767876aace931060e2ba779d1":{"name":"gcp-iot-provision","version":"0.2.8-dependabot-npm-and-yarn-balena-sdk-16-24-0-e479ec99c7493b1767876aace931060e2ba779d1","keywords":["balena","balenaCloud","google","iotcore","iot","gcp"],"author":{"name":"Ken Bannister","email":"ken@balena.io"},"license":"Apache-2.0","_id":"gcp-iot-provision@0.2.8-dependabot-npm-and-yarn-balena-sdk-16-24-0-e479ec99c7493b1767876aace931060e2ba779d1","maintainers":[{"name":"balena.io","email":"accounts+npm@balena.io"}],"homepage":"https://github.com/balena-io-examples/gcp-iot-provision","bugs":{"url":"https://github.com/balena-io-examples/gcp-iot-provision/issues"},"dist":{"shasum":"ebe17d048fbb190f6682b7883d067bdee4b24c7c","tarball":"https://registry.npmjs.org/gcp-iot-provision/-/gcp-iot-provision-0.2.8-dependabot-npm-and-yarn-balena-sdk-16-24-0-e479ec99c7493b1767876aace931060e2ba779d1.tgz","fileCount":9,"integrity":"sha512-h3nzq1VaVsVt3VVjoxBvdSLYMa8csmNsWWzWNSwt3oI43RS2X9Y7zs+KTWCex7vGcDuMzAlGFczoNBxfSVvT6A==","signatures":[{"sig":"MEYCIQDFxgNivIE5HIKsnmyvAdpKsl2qgbj6qG9BBVkD2R1zogIhAIO1DcvGPiXg/YA5s5Jy3mfHTb2Ua3tPLlljzbeCfcGP","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":137526,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJi1dk/ACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2Vmq12A/9EQ33CIfZm/B/NqbgVyUGyJTv0j4J0wcDHGVVkcNLiZZtfbGb\r\nmI0pHfFlpJLQmXuwwJfKPZNwPycn7Ip+mCYwYzBykTg2P6F5QD1EGntrhEP5\r\nuvm3HqVEQGgVIOyCHkvMPyDSb5YGutAAPvEEakJd5KSQmEmkeYu4+J9Xj+J9\r\nGJPBF4TXl690g+t+jUtuDFAaTZH7cZsasT15Q2Y42EsI8eFGUitvPEffhs+Q\r\nIhXd3hZWiWhVkSBRH+fxWPFOTbwOvkEHGxztavWXYcpOohy39sK+9uZlOkrs\r\np+/ysUl174dp1yPCj0ndjlpSBwpT82Owf04Fy1JCR4681bRb1k+xn+gt/zZ9\r\nnHtwpM6CtFuOg0zmxa9VaOUO1C33PL/MKWkxGbEpHdeFA87lT4aAld3L2DYo\r\nH48vapWAdL66+dtJWv/iB2wKhpWmwgYlcQ4fk8xy3m0GTMeRLrsrbLG9pBwV\r\nVFTB45Skh0nRS5q0qJHw8bwS3SrqXDMnUOiPUyoOhq/HWx5GPk12VdTOSUu6\r\nJRzQQYru3nLcklOETJUT4DZraY5bDws10qox8kyPq3s3+7/GeXWOkrCnmk5S\r\n1SvrHqx+Vzi6X5Us/zbpkmXH/pzm2rP6bj/7ljntPY9QtdOrioOCKD3fTA8y\r\nxpuJgUlwR1abtS/g9QSqa5lKyvefi71WP9A=\r\n=yLX6\r\n-----END PGP SIGNATURE-----\r\n"},"main":"index.js","type":"module","readme":"# Google Cloud Function for IoT Device Provisioning\n\nThis Cloud Function allows you to provision and synchronize a balena device with Google Cloud IoT Core in a secure and automated way via an HTTP endpoint. The Cloud Function may be called by a balena device, as seen in the [cloud-relay](https://github.com/balena-io-examples/cloud-relay) example.\n\n| Method | Action |\n|-------------|--------|\n| POST | Provisions a balena device with IoT Core. First the function verifies the device UUID with balenaCloud. Then it creates a public/private key pair and adds the device to the registry. Finally the function sets balena device environment variables for these entities. |\n| DELETE | Removes a balena device from the IoT Core registry and removes the balena device environment variable for the private key. Essentially reverses the actions from provisioning with HTTP POST. |\n\n## Device Environment Variables\nOnce the Cloud function has provisioned the device with GCP, it sets balena device environment variables as described below, which allow the device to connect to IoT Core. Some aspects of the variable values are common across devices, and are collected from the cloud function deployment.\n\n| Variable | Value |\n|----------|-------|\n| GCP_CLIENT_PATH | `<registry-path>/devices/<device-id>`<br><br> `<registry-path>` is derived from the project ID, GCP region, and registry ID<br>`<device-id>` is derived from the balena UUID for the device |\n| GCP_DATA_TOPIC_ROOT | `/devices/<device-id>` |\n| GCP_PROJECT_ID | Google Cloud project ID |\n| GCP_PRIVATE_KEY | Private key in PEM format, base64 encoded to eliminate line wrapping |\n\n\n## Setup and Testing\n### GCP setup\nThe Cloud Function interacts with Google Cloud IoT Core via client code operating with service account credentials. You must setup a Google Cloud project with an IoT Core registry. The service account must have the *Cloud IoT Provisioner* role to manage device records in the IoT Core registry. See the IoT Core [documentation](https://cloud.google.com/iot/docs/how-tos) for more background.\n\n### Workspace setup\nClone this repo\n```\n$ git clone https://github.com/balena-io-examples/gcp-iot-provision\n```\n\nThe sections below show how to test the Cloud Function on a local test server and deploy to Cloud Functions. In either case you must provide the environment variables in the table below as instructed for the test/deployment.\n\n| Key         |    Value    |\n|-------------|-------------|\n| BALENA_API_KEY | for use of balena API; found in balenaCloud dashboard at: `account -> Preferences -> Access tokens` |\n| GCP_PROJECT_ID | Google Cloud project ID, like `my-project-000000`|\n| GCP_REGION | Google Cloud region for registry, like `us-central1` |\n| GCP_REGISTRY_ID | Google Cloud registry ID you provided to create the registry |\n| GCP_SERVICE_ACCOUNT |base64 encoding of the JSON formatted GCP service account credentials provided by Google when you created the service account. Example below, assuming the credentials JSON is contained in a file.<br><br>`cat <credentials.txt> \\| base64 -w 0` |\n\n### HTTP API\nThe HTTP endpoint expects a request containing a JSON body with the attributes below. Use POST to add a device to the cloud registry, DELETE to remove.\n\n| Attribute | Value |\n|-----------|-------|\n| uuid | UUID of device  |\n| balena_service | (optional) Name of service container on balena device that uses provisioned key and certificate, for example `cloud-relay`. If defined, creates service level variables; otherwise creates device level variables. Service level variables are more secure. |\n\n\n### Test locally\nThe Google Functions Framework is a convenient tool for local testing. \nFirst, start a local HTTP server ([docs reference](https://cloud.google.com/functions/docs/running/function-frameworks)) using a script like below.\n\n```\nexport BALENA_API_KEY=<...>\n... <other environment variables from table above>\nexport GCP_SERVICE_ACCOUNT=<...>\n\nnpx @google-cloud/functions-framework --target=provision\n```\n\nNext, use `curl` to send an HTTP request to the local server to provision a device. See the *HTTP API* section above for body contents.\n\n```\ncurl -X POST http://localhost:8080 -H \"Content-Type:application/json\" \\\n   -d '{ \"uuid\": \"<device-uuid>\", \"balena_service\": \"<service-name>\" }'\n```\n\nAfter a successful POST, you should see the device appear in your IoT Core registry and `GCP_CLIENT_PATH`, `GCP_DATA_TOPIC_ROOT`, `GCP_PRIVATE_KEY`, and `GCP_PROJECT_ID` variables appear in balenaCloud for the device. After a successful DELETE, those variables disappear.\n\n## Deploy\nTo deploy to Cloud Functions, use the command below. See the [command documentation](https://cloud.google.com/sdk/gcloud/reference/functions/deploy) for the format of `yaml-file`, which contains the variables from the table in the *Development setup* section above.\n\n```\ngcloud functions deploy provision --runtime=nodejs14 --trigger-http \\\n   --env-vars-file=<yaml-file> --allow-unauthenticated \\\n   --service-account=<name>@<xxxx>.iam.gserviceaccount.com\n```\n\nThe result is a Cloud Function like below. Notice the `TRIGGER` tab, which provides the URL for the function.\n\n![Alt text](docs/cloud-function.png)\n\n### Test the Cloud Function\nTo test the function, use a command like below, where the URL is from the `TRIGGER` tab in the console. See the *HTTP API* section above for body contents.\n\n```\ncurl -X POST https://<region>-<projectID>.cloudfunctions.net/provision \\\n   -H \"Content-Type:application/json\" \\\n   -d '{ \"uuid\": \"<device-uuid>\", \"balena_service\": \"<service-name>\" }'\n```\n\nAfter a successful POST, you should see the device appear in your IoT Core registry and `GCP_CLIENT_PATH`, `GCP_DATA_TOPIC_ROOT`, `GCP_PRIVATE_KEY`, and `GCP_PROJECT_ID` variables appear in balenaCloud for the device. After a successful DELETE, those variables disappear.\n","gitHead":"e479ec99c7493b1767876aace931060e2ba779d1","private":false,"scripts":{"test":"echo \"No tests yet\" && exit 0","start":"node index.js"},"_npmUser":{"name":"balena.io","email":"accounts+npm@balena.io"},"repository":{"url":"git+https://github.com/balena-io-examples/gcp-iot-provision.git","type":"git"},"versionist":{"publishedAt":"2022-07-18T22:03:35.116Z"},"_npmVersion":"6.14.17","description":"Google Cloud function to provision a balena device to IoT Core","directories":{},"_nodeVersion":"14.19.3","dependencies":{"balena-sdk":"^16.11.2","@google-cloud/iot":"^2.5.0","@google-cloud/functions-framework":"^2.1.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","_npmOperationalInternal":{"tmp":"tmp/gcp-iot-provision_0.2.8-dependabot-npm-and-yarn-balena-sdk-16-24-0-e479ec99c7493b1767876aace931060e2ba779d1_1658181951206_0.46635799407617107","host":"s3://npm-registry-packages"},"deprecated":"Deprecated: no longer maintained. The GitHub repository has been archived and no further releases will be published."},"0.2.8-dependabot-npm-and-yarn-balena-sdk-16-24-1-7c665096990208ee780836fc66c3f427b58842b3":{"name":"gcp-iot-provision","version":"0.2.8-dependabot-npm-and-yarn-balena-sdk-16-24-1-7c665096990208ee780836fc66c3f427b58842b3","keywords":["balena","balenaCloud","google","iotcore","iot","gcp"],"author":{"name":"Ken Bannister","email":"ken@balena.io"},"license":"Apache-2.0","_id":"gcp-iot-provision@0.2.8-dependabot-npm-and-yarn-balena-sdk-16-24-1-7c665096990208ee780836fc66c3f427b58842b3","maintainers":[{"name":"balena.io","email":"accounts+npm@balena.io"}],"homepage":"https://github.com/balena-io-examples/gcp-iot-provision","bugs":{"url":"https://github.com/balena-io-examples/gcp-iot-provision/issues"},"dist":{"shasum":"3af71442850b7ad06b78807cd6f636e4f2feef71","tarball":"https://registry.npmjs.org/gcp-iot-provision/-/gcp-iot-provision-0.2.8-dependabot-npm-and-yarn-balena-sdk-16-24-1-7c665096990208ee780836fc66c3f427b58842b3.tgz","fileCount":9,"integrity":"sha512-gF2PRx98SEqxfVPc0sOPlzI+mZiQmlbVyH1apefxTOxMiCc1LBOAESzspm9vla4NxBJYtA/ut0HJ7ONMl6pIlw==","signatures":[{"sig":"MEUCICIW2Q7hews5bTt3IO4bi+OxMGOnUiQ+k6fJAtm3M+tIAiEA6KzEnISuiG0Ga//1eRYdtazKZzIZXU53To7m0Kw5MLA=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":137526,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJi3vKiACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2Vmo3qA//aMXom3dmRF3q/DigX6efHnw9vwgc94UyDeWuaW6EXF05jxX+\r\nO+0cTahtyQ4k/GRbXUq/N6hPv97vwCeFZ6oXklTQDf4pTdc1dDWsc04XXW9x\r\n/0BgLzkPg7DDULEUHkVhg/w/KTFcyBgNz5D3DekMTUduqCp3p6gSS3CU7IIN\r\ndyyWsewmt3RdCvxBqZgg0dsn2fuAqIcZynzOqNXPsCaTUo49npeXxes0QSD4\r\ns+XD3ql9NITWBGYTBir6GJ0nnvwyJ8rhuap16ZPk2tvJH9ut2dL+esVwsXaC\r\noZBJqSkegKJh9Qh9tdR572FhI3xtVMUX+DvihGfslukjxRkpcHv4yvIQMZAM\r\ngOhDZ7IzQwXWeQxKPJpETFNJ5JwUNoZwr1XeKAp/Ky/W2kt9no8nJyj9XFZ2\r\n53vEgYcOM6pfZfGtjfG/WlFEgs9Og5acqP/XYK2l9KUe+HmKNzSlDqhDAlbu\r\nTyv9PqorZAJ4hBy2DLGcxv+DQ18lyjc1s7qk5/vRQ6EhnWzx2NBrJOwBKqbw\r\ngp3t9/Web8fNn1CR/t9J7Lr6tUQBWDsFRN95vwh8tHxA4nn1ptti+/fl9sCz\r\nLP7diurdeUcsOdgh84ycg/4YzH00K9xJmqLrCjvugm/Inbs3sk/2z/QvYHQ5\r\n/C1aLvsDrOKXK7czVgSiAx+DvxP3nSmcP3A=\r\n=AKdh\r\n-----END PGP SIGNATURE-----\r\n"},"main":"index.js","type":"module","readme":"# Google Cloud Function for IoT Device Provisioning\n\nThis Cloud Function allows you to provision and synchronize a balena device with Google Cloud IoT Core in a secure and automated way via an HTTP endpoint. The Cloud Function may be called by a balena device, as seen in the [cloud-relay](https://github.com/balena-io-examples/cloud-relay) example.\n\n| Method | Action |\n|-------------|--------|\n| POST | Provisions a balena device with IoT Core. First the function verifies the device UUID with balenaCloud. Then it creates a public/private key pair and adds the device to the registry. Finally the function sets balena device environment variables for these entities. |\n| DELETE | Removes a balena device from the IoT Core registry and removes the balena device environment variable for the private key. Essentially reverses the actions from provisioning with HTTP POST. |\n\n## Device Environment Variables\nOnce the Cloud function has provisioned the device with GCP, it sets balena device environment variables as described below, which allow the device to connect to IoT Core. Some aspects of the variable values are common across devices, and are collected from the cloud function deployment.\n\n| Variable | Value |\n|----------|-------|\n| GCP_CLIENT_PATH | `<registry-path>/devices/<device-id>`<br><br> `<registry-path>` is derived from the project ID, GCP region, and registry ID<br>`<device-id>` is derived from the balena UUID for the device |\n| GCP_DATA_TOPIC_ROOT | `/devices/<device-id>` |\n| GCP_PROJECT_ID | Google Cloud project ID |\n| GCP_PRIVATE_KEY | Private key in PEM format, base64 encoded to eliminate line wrapping |\n\n\n## Setup and Testing\n### GCP setup\nThe Cloud Function interacts with Google Cloud IoT Core via client code operating with service account credentials. You must setup a Google Cloud project with an IoT Core registry. The service account must have the *Cloud IoT Provisioner* role to manage device records in the IoT Core registry. See the IoT Core [documentation](https://cloud.google.com/iot/docs/how-tos) for more background.\n\n### Workspace setup\nClone this repo\n```\n$ git clone https://github.com/balena-io-examples/gcp-iot-provision\n```\n\nThe sections below show how to test the Cloud Function on a local test server and deploy to Cloud Functions. In either case you must provide the environment variables in the table below as instructed for the test/deployment.\n\n| Key         |    Value    |\n|-------------|-------------|\n| BALENA_API_KEY | for use of balena API; found in balenaCloud dashboard at: `account -> Preferences -> Access tokens` |\n| GCP_PROJECT_ID | Google Cloud project ID, like `my-project-000000`|\n| GCP_REGION | Google Cloud region for registry, like `us-central1` |\n| GCP_REGISTRY_ID | Google Cloud registry ID you provided to create the registry |\n| GCP_SERVICE_ACCOUNT |base64 encoding of the JSON formatted GCP service account credentials provided by Google when you created the service account. Example below, assuming the credentials JSON is contained in a file.<br><br>`cat <credentials.txt> \\| base64 -w 0` |\n\n### HTTP API\nThe HTTP endpoint expects a request containing a JSON body with the attributes below. Use POST to add a device to the cloud registry, DELETE to remove.\n\n| Attribute | Value |\n|-----------|-------|\n| uuid | UUID of device  |\n| balena_service | (optional) Name of service container on balena device that uses provisioned key and certificate, for example `cloud-relay`. If defined, creates service level variables; otherwise creates device level variables. Service level variables are more secure. |\n\n\n### Test locally\nThe Google Functions Framework is a convenient tool for local testing. \nFirst, start a local HTTP server ([docs reference](https://cloud.google.com/functions/docs/running/function-frameworks)) using a script like below.\n\n```\nexport BALENA_API_KEY=<...>\n... <other environment variables from table above>\nexport GCP_SERVICE_ACCOUNT=<...>\n\nnpx @google-cloud/functions-framework --target=provision\n```\n\nNext, use `curl` to send an HTTP request to the local server to provision a device. See the *HTTP API* section above for body contents.\n\n```\ncurl -X POST http://localhost:8080 -H \"Content-Type:application/json\" \\\n   -d '{ \"uuid\": \"<device-uuid>\", \"balena_service\": \"<service-name>\" }'\n```\n\nAfter a successful POST, you should see the device appear in your IoT Core registry and `GCP_CLIENT_PATH`, `GCP_DATA_TOPIC_ROOT`, `GCP_PRIVATE_KEY`, and `GCP_PROJECT_ID` variables appear in balenaCloud for the device. After a successful DELETE, those variables disappear.\n\n## Deploy\nTo deploy to Cloud Functions, use the command below. See the [command documentation](https://cloud.google.com/sdk/gcloud/reference/functions/deploy) for the format of `yaml-file`, which contains the variables from the table in the *Development setup* section above.\n\n```\ngcloud functions deploy provision --runtime=nodejs14 --trigger-http \\\n   --env-vars-file=<yaml-file> --allow-unauthenticated \\\n   --service-account=<name>@<xxxx>.iam.gserviceaccount.com\n```\n\nThe result is a Cloud Function like below. Notice the `TRIGGER` tab, which provides the URL for the function.\n\n![Alt text](docs/cloud-function.png)\n\n### Test the Cloud Function\nTo test the function, use a command like below, where the URL is from the `TRIGGER` tab in the console. See the *HTTP API* section above for body contents.\n\n```\ncurl -X POST https://<region>-<projectID>.cloudfunctions.net/provision \\\n   -H \"Content-Type:application/json\" \\\n   -d '{ \"uuid\": \"<device-uuid>\", \"balena_service\": \"<service-name>\" }'\n```\n\nAfter a successful POST, you should see the device appear in your IoT Core registry and `GCP_CLIENT_PATH`, `GCP_DATA_TOPIC_ROOT`, `GCP_PRIVATE_KEY`, and `GCP_PROJECT_ID` variables appear in balenaCloud for the device. After a successful DELETE, those variables disappear.\n","gitHead":"7c665096990208ee780836fc66c3f427b58842b3","private":false,"scripts":{"test":"echo \"No tests yet\" && exit 0","start":"node index.js"},"_npmUser":{"name":"balena.io","email":"accounts+npm@balena.io"},"repository":{"url":"git+https://github.com/balena-io-examples/gcp-iot-provision.git","type":"git"},"versionist":{"publishedAt":"2022-07-25T19:42:54.740Z"},"_npmVersion":"6.14.17","description":"Google Cloud function to provision a balena device to IoT Core","directories":{},"_nodeVersion":"14.19.3","dependencies":{"balena-sdk":"^16.11.2","@google-cloud/iot":"^2.5.0","@google-cloud/functions-framework":"^2.1.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","_npmOperationalInternal":{"tmp":"tmp/gcp-iot-provision_0.2.8-dependabot-npm-and-yarn-balena-sdk-16-24-1-7c665096990208ee780836fc66c3f427b58842b3_1658778273806_0.7194284953162045","host":"s3://npm-registry-packages"},"deprecated":"Deprecated: no longer maintained. The GitHub repository has been archived and no further releases will be published."},"0.2.8-dependabot-npm-and-yarn-balena-sdk-16-25-1-7b00e089f16c793d9a6f0c297bf551174dc5d257":{"name":"gcp-iot-provision","version":"0.2.8-dependabot-npm-and-yarn-balena-sdk-16-25-1-7b00e089f16c793d9a6f0c297bf551174dc5d257","keywords":["balena","balenaCloud","google","iotcore","iot","gcp"],"author":{"name":"Ken Bannister","email":"ken@balena.io"},"license":"Apache-2.0","_id":"gcp-iot-provision@0.2.8-dependabot-npm-and-yarn-balena-sdk-16-25-1-7b00e089f16c793d9a6f0c297bf551174dc5d257","maintainers":[{"name":"balena.io","email":"accounts+npm@balena.io"}],"homepage":"https://github.com/balena-io-examples/gcp-iot-provision","bugs":{"url":"https://github.com/balena-io-examples/gcp-iot-provision/issues"},"dist":{"shasum":"850b505e8566566f760dae2bf68e1996fa04f966","tarball":"https://registry.npmjs.org/gcp-iot-provision/-/gcp-iot-provision-0.2.8-dependabot-npm-and-yarn-balena-sdk-16-25-1-7b00e089f16c793d9a6f0c297bf551174dc5d257.tgz","fileCount":9,"integrity":"sha512-2Ne0XXWoaXw5Vr3oFSF48jBU1m7HIfjyhYCmI/eYWgdfnpx9wFhRRHIzEwi8p7CsStEQddbAHi55qAALOoKrTA==","signatures":[{"sig":"MEUCICPpa5PCWpoRW89QmNkj5J5qqUH4bZ+jvWCCOrQdl/v7AiEAwla24fUhDuWY8l46T1srM0fMSEm/oIfZO0wC5fPJaes=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":137526,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJi8WROACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2Vmq1uw//Tvv6EfoFHi6wVnfsXdWqRNaf5zHU6EVtUdTTusOrNj/210k9\r\nxObyEKhZT3lzsO1WoWIqdn25BbQoNKwd/7npLX6NsgE175LnhP9oBKG0c6Hh\r\n60YUQoeYzmcQ3d8oAFV/QahAJAwBAZcDejq0R0CI3huWw3LKr+97CneqBmpE\r\n7DeffumBM7ZbLqvkG8uGRYc22D/5OIXpQ9Bs2aokl1nkDc0Vp9PiU1CZwbjf\r\nhMG5BJvGzq9K2j2cZdhZKpxRsskyS3vgzZiAVmLwfVXGY3Sns2XaOoMUorKC\r\nPHa9SYansYI6ZkgHT/B84YMOUWEt7RajsvJxnSi7s0TVIf1PCBLztYSGyCAT\r\nxJfNN3EVkt0K0EnDOHcLDFU+c2hDVd9MSrS5YAVenULSW2WvNb8MCyMFHOlZ\r\nFfh2bsgDNLM982l40lReVDqFtc3DuA7l/ePZe8niw9aH9r//nTJ5GzCI6q5L\r\nzet4rdfHk+uktN4QC8DaJVEYVPYuDLdQXspGNM7UqXrb0BUB/JD0FW2t2hUQ\r\nDPYF6zkylMkj8DrR3qMMeOUCgEd+61+Hx4rYJNI3Nx0Sewf0LcRey7HgwqcD\r\nvlB5T+IwjCOJfBj4BdCEDci1Uh/1qPt1uK63qcXBMFj3FdV0k35Dg0sVh8gu\r\n3GkGRSqhG2Y7ER9uRonhh9aiJyuQHyRpUhQ=\r\n=E+cN\r\n-----END PGP SIGNATURE-----\r\n"},"main":"index.js","type":"module","readme":"# Google Cloud Function for IoT Device Provisioning\n\nThis Cloud Function allows you to provision and synchronize a balena device with Google Cloud IoT Core in a secure and automated way via an HTTP endpoint. The Cloud Function may be called by a balena device, as seen in the [cloud-relay](https://github.com/balena-io-examples/cloud-relay) example.\n\n| Method | Action |\n|-------------|--------|\n| POST | Provisions a balena device with IoT Core. First the function verifies the device UUID with balenaCloud. Then it creates a public/private key pair and adds the device to the registry. Finally the function sets balena device environment variables for these entities. |\n| DELETE | Removes a balena device from the IoT Core registry and removes the balena device environment variable for the private key. Essentially reverses the actions from provisioning with HTTP POST. |\n\n## Device Environment Variables\nOnce the Cloud function has provisioned the device with GCP, it sets balena device environment variables as described below, which allow the device to connect to IoT Core. Some aspects of the variable values are common across devices, and are collected from the cloud function deployment.\n\n| Variable | Value |\n|----------|-------|\n| GCP_CLIENT_PATH | `<registry-path>/devices/<device-id>`<br><br> `<registry-path>` is derived from the project ID, GCP region, and registry ID<br>`<device-id>` is derived from the balena UUID for the device |\n| GCP_DATA_TOPIC_ROOT | `/devices/<device-id>` |\n| GCP_PROJECT_ID | Google Cloud project ID |\n| GCP_PRIVATE_KEY | Private key in PEM format, base64 encoded to eliminate line wrapping |\n\n\n## Setup and Testing\n### GCP setup\nThe Cloud Function interacts with Google Cloud IoT Core via client code operating with service account credentials. You must setup a Google Cloud project with an IoT Core registry. The service account must have the *Cloud IoT Provisioner* role to manage device records in the IoT Core registry. See the IoT Core [documentation](https://cloud.google.com/iot/docs/how-tos) for more background.\n\n### Workspace setup\nClone this repo\n```\n$ git clone https://github.com/balena-io-examples/gcp-iot-provision\n```\n\nThe sections below show how to test the Cloud Function on a local test server and deploy to Cloud Functions. In either case you must provide the environment variables in the table below as instructed for the test/deployment.\n\n| Key         |    Value    |\n|-------------|-------------|\n| BALENA_API_KEY | for use of balena API; found in balenaCloud dashboard at: `account -> Preferences -> Access tokens` |\n| GCP_PROJECT_ID | Google Cloud project ID, like `my-project-000000`|\n| GCP_REGION | Google Cloud region for registry, like `us-central1` |\n| GCP_REGISTRY_ID | Google Cloud registry ID you provided to create the registry |\n| GCP_SERVICE_ACCOUNT |base64 encoding of the JSON formatted GCP service account credentials provided by Google when you created the service account. Example below, assuming the credentials JSON is contained in a file.<br><br>`cat <credentials.txt> \\| base64 -w 0` |\n\n### HTTP API\nThe HTTP endpoint expects a request containing a JSON body with the attributes below. Use POST to add a device to the cloud registry, DELETE to remove.\n\n| Attribute | Value |\n|-----------|-------|\n| uuid | UUID of device  |\n| balena_service | (optional) Name of service container on balena device that uses provisioned key and certificate, for example `cloud-relay`. If defined, creates service level variables; otherwise creates device level variables. Service level variables are more secure. |\n\n\n### Test locally\nThe Google Functions Framework is a convenient tool for local testing. \nFirst, start a local HTTP server ([docs reference](https://cloud.google.com/functions/docs/running/function-frameworks)) using a script like below.\n\n```\nexport BALENA_API_KEY=<...>\n... <other environment variables from table above>\nexport GCP_SERVICE_ACCOUNT=<...>\n\nnpx @google-cloud/functions-framework --target=provision\n```\n\nNext, use `curl` to send an HTTP request to the local server to provision a device. See the *HTTP API* section above for body contents.\n\n```\ncurl -X POST http://localhost:8080 -H \"Content-Type:application/json\" \\\n   -d '{ \"uuid\": \"<device-uuid>\", \"balena_service\": \"<service-name>\" }'\n```\n\nAfter a successful POST, you should see the device appear in your IoT Core registry and `GCP_CLIENT_PATH`, `GCP_DATA_TOPIC_ROOT`, `GCP_PRIVATE_KEY`, and `GCP_PROJECT_ID` variables appear in balenaCloud for the device. After a successful DELETE, those variables disappear.\n\n## Deploy\nTo deploy to Cloud Functions, use the command below. See the [command documentation](https://cloud.google.com/sdk/gcloud/reference/functions/deploy) for the format of `yaml-file`, which contains the variables from the table in the *Development setup* section above.\n\n```\ngcloud functions deploy provision --runtime=nodejs14 --trigger-http \\\n   --env-vars-file=<yaml-file> --allow-unauthenticated \\\n   --service-account=<name>@<xxxx>.iam.gserviceaccount.com\n```\n\nThe result is a Cloud Function like below. Notice the `TRIGGER` tab, which provides the URL for the function.\n\n![Alt text](docs/cloud-function.png)\n\n### Test the Cloud Function\nTo test the function, use a command like below, where the URL is from the `TRIGGER` tab in the console. See the *HTTP API* section above for body contents.\n\n```\ncurl -X POST https://<region>-<projectID>.cloudfunctions.net/provision \\\n   -H \"Content-Type:application/json\" \\\n   -d '{ \"uuid\": \"<device-uuid>\", \"balena_service\": \"<service-name>\" }'\n```\n\nAfter a successful POST, you should see the device appear in your IoT Core registry and `GCP_CLIENT_PATH`, `GCP_DATA_TOPIC_ROOT`, `GCP_PRIVATE_KEY`, and `GCP_PROJECT_ID` variables appear in balenaCloud for the device. After a successful DELETE, those variables disappear.\n","gitHead":"7b00e089f16c793d9a6f0c297bf551174dc5d257","private":false,"scripts":{"test":"echo \"No tests yet\" && exit 0","start":"node index.js"},"_npmUser":{"name":"balena.io","email":"accounts+npm@balena.io"},"repository":{"url":"git+https://github.com/balena-io-examples/gcp-iot-provision.git","type":"git"},"versionist":{"publishedAt":"2022-08-08T19:27:50.727Z"},"_npmVersion":"6.14.17","description":"Google Cloud function to provision a balena device to IoT Core","directories":{},"_nodeVersion":"14.19.3","dependencies":{"balena-sdk":"^16.11.2","@google-cloud/iot":"^2.5.0","@google-cloud/functions-framework":"^2.1.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","_npmOperationalInternal":{"tmp":"tmp/gcp-iot-provision_0.2.8-dependabot-npm-and-yarn-balena-sdk-16-25-1-7b00e089f16c793d9a6f0c297bf551174dc5d257_1659987022458_0.2108440385801431","host":"s3://npm-registry-packages"},"deprecated":"Deprecated: no longer maintained. The GitHub repository has been archived and no further releases will be published."},"0.2.8-dependabot-npm-and-yarn-balena-sdk-16-26-1-74dae0779fde7dd493a3edb773c03dac8363a525":{"name":"gcp-iot-provision","version":"0.2.8-dependabot-npm-and-yarn-balena-sdk-16-26-1-74dae0779fde7dd493a3edb773c03dac8363a525","keywords":["balena","balenaCloud","google","iotcore","iot","gcp"],"author":{"name":"Ken Bannister","email":"ken@balena.io"},"license":"Apache-2.0","_id":"gcp-iot-provision@0.2.8-dependabot-npm-and-yarn-balena-sdk-16-26-1-74dae0779fde7dd493a3edb773c03dac8363a525","maintainers":[{"name":"balena.io","email":"accounts+npm@balena.io"}],"homepage":"https://github.com/balena-io-examples/gcp-iot-provision","bugs":{"url":"https://github.com/balena-io-examples/gcp-iot-provision/issues"},"dist":{"shasum":"6cbfaa51a0bfda0c29c8d7c54a9821afefa0f8c7","tarball":"https://registry.npmjs.org/gcp-iot-provision/-/gcp-iot-provision-0.2.8-dependabot-npm-and-yarn-balena-sdk-16-26-1-74dae0779fde7dd493a3edb773c03dac8363a525.tgz","fileCount":9,"integrity":"sha512-2w8KSK3hBcbGzyuUy/UwP5Y+Tv8jqGqWZzjTzX1LzqLvora3bUi/rZCEGbSIc9qO0iaRw8btqWxDxJWgKwhqBA==","signatures":[{"sig":"MEUCIAIcw4TuU2KRhYhtdoNv6DdEVFs+daG3RY5f5yUCCDRZAiEA7AV/U6TYF/A0L9LNR7G+8f5EJbA153a6gdIU9mygvio=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":137526,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJjDRTXACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmoeEg/5AeOVZRcIywlQqSSSYm47IpYsUpmFh2LTE0r74cJJE9bK+RIe\r\nhzHYbWz0ePkNQYmhKCb9wG8ZIvP1whqno8pJqyLyg2Qh8Q3yDtqnySVNsdZr\r\nkn1yTEDuH9r+GioKK1OCIkvokO5/pAsoBPUqfR03Q+Bzn5vTOdaanJXKdiJp\r\nIQvbxXZnujwV425bf18Ip5l1vrURP93MfGk+OcN5bKbrq9BMhKi2TUkxHoNu\r\nVB7ZTRfblEBW1ZEa70lMyjHZtTXU/8X8SuqyDkyDK6e3xa219j3j01lk4sor\r\nspftOxTWECSBpoZ+3wNLVnTcCgTr/sMum7lsW2xe4UypU+b9Ty/xNwRzeeUl\r\nzPr1KMtnk7kIO3QtmqyM9Lh0C9k7hcG5cb7bfdZ6BBzw8R4Zpurbq9HNveSg\r\npzLB7WgLehY6Ts3hxsj7Ylk3FVJ98v9bQVUumpi3VADXG4YP9BvZ57xXsTRl\r\nbUYBsp969+wAVO0y/vNAxzJRX+2h+XfiEVYOK1JMscrbH1FkuwB9yBrUBnRt\r\nOEOmDMlVulXfp5yCppok8OBV6WsiqpyFXOH7L2kNRrqLop1V54sHo+ANjxSG\r\niU8PTRHPsdKw5+yzYmkFdhAwk06eo1mRMDerJEjzI+LX3Y0CiXrEiNTPB7RW\r\nSfrMRWa29EEbjT4Op4lWCMtIkO+5qZdO2J8=\r\n=VIqk\r\n-----END PGP SIGNATURE-----\r\n"},"main":"index.js","type":"module","readme":"# Google Cloud Function for IoT Device Provisioning\n\nThis Cloud Function allows you to provision and synchronize a balena device with Google Cloud IoT Core in a secure and automated way via an HTTP endpoint. The Cloud Function may be called by a balena device, as seen in the [cloud-relay](https://github.com/balena-io-examples/cloud-relay) example.\n\n| Method | Action |\n|-------------|--------|\n| POST | Provisions a balena device with IoT Core. First the function verifies the device UUID with balenaCloud. Then it creates a public/private key pair and adds the device to the registry. Finally the function sets balena device environment variables for these entities. |\n| DELETE | Removes a balena device from the IoT Core registry and removes the balena device environment variable for the private key. Essentially reverses the actions from provisioning with HTTP POST. |\n\n## Device Environment Variables\nOnce the Cloud function has provisioned the device with GCP, it sets balena device environment variables as described below, which allow the device to connect to IoT Core. Some aspects of the variable values are common across devices, and are collected from the cloud function deployment.\n\n| Variable | Value |\n|----------|-------|\n| GCP_CLIENT_PATH | `<registry-path>/devices/<device-id>`<br><br> `<registry-path>` is derived from the project ID, GCP region, and registry ID<br>`<device-id>` is derived from the balena UUID for the device |\n| GCP_DATA_TOPIC_ROOT | `/devices/<device-id>` |\n| GCP_PROJECT_ID | Google Cloud project ID |\n| GCP_PRIVATE_KEY | Private key in PEM format, base64 encoded to eliminate line wrapping |\n\n\n## Setup and Testing\n### GCP setup\nThe Cloud Function interacts with Google Cloud IoT Core via client code operating with service account credentials. You must setup a Google Cloud project with an IoT Core registry. The service account must have the *Cloud IoT Provisioner* role to manage device records in the IoT Core registry. See the IoT Core [documentation](https://cloud.google.com/iot/docs/how-tos) for more background.\n\n### Workspace setup\nClone this repo\n```\n$ git clone https://github.com/balena-io-examples/gcp-iot-provision\n```\n\nThe sections below show how to test the Cloud Function on a local test server and deploy to Cloud Functions. In either case you must provide the environment variables in the table below as instructed for the test/deployment.\n\n| Key         |    Value    |\n|-------------|-------------|\n| BALENA_API_KEY | for use of balena API; found in balenaCloud dashboard at: `account -> Preferences -> Access tokens` |\n| GCP_PROJECT_ID | Google Cloud project ID, like `my-project-000000`|\n| GCP_REGION | Google Cloud region for registry, like `us-central1` |\n| GCP_REGISTRY_ID | Google Cloud registry ID you provided to create the registry |\n| GCP_SERVICE_ACCOUNT |base64 encoding of the JSON formatted GCP service account credentials provided by Google when you created the service account. Example below, assuming the credentials JSON is contained in a file.<br><br>`cat <credentials.txt> \\| base64 -w 0` |\n\n### HTTP API\nThe HTTP endpoint expects a request containing a JSON body with the attributes below. Use POST to add a device to the cloud registry, DELETE to remove.\n\n| Attribute | Value |\n|-----------|-------|\n| uuid | UUID of device  |\n| balena_service | (optional) Name of service container on balena device that uses provisioned key and certificate, for example `cloud-relay`. If defined, creates service level variables; otherwise creates device level variables. Service level variables are more secure. |\n\n\n### Test locally\nThe Google Functions Framework is a convenient tool for local testing. \nFirst, start a local HTTP server ([docs reference](https://cloud.google.com/functions/docs/running/function-frameworks)) using a script like below.\n\n```\nexport BALENA_API_KEY=<...>\n... <other environment variables from table above>\nexport GCP_SERVICE_ACCOUNT=<...>\n\nnpx @google-cloud/functions-framework --target=provision\n```\n\nNext, use `curl` to send an HTTP request to the local server to provision a device. See the *HTTP API* section above for body contents.\n\n```\ncurl -X POST http://localhost:8080 -H \"Content-Type:application/json\" \\\n   -d '{ \"uuid\": \"<device-uuid>\", \"balena_service\": \"<service-name>\" }'\n```\n\nAfter a successful POST, you should see the device appear in your IoT Core registry and `GCP_CLIENT_PATH`, `GCP_DATA_TOPIC_ROOT`, `GCP_PRIVATE_KEY`, and `GCP_PROJECT_ID` variables appear in balenaCloud for the device. After a successful DELETE, those variables disappear.\n\n## Deploy\nTo deploy to Cloud Functions, use the command below. See the [command documentation](https://cloud.google.com/sdk/gcloud/reference/functions/deploy) for the format of `yaml-file`, which contains the variables from the table in the *Development setup* section above.\n\n```\ngcloud functions deploy provision --runtime=nodejs14 --trigger-http \\\n   --env-vars-file=<yaml-file> --allow-unauthenticated \\\n   --service-account=<name>@<xxxx>.iam.gserviceaccount.com\n```\n\nThe result is a Cloud Function like below. Notice the `TRIGGER` tab, which provides the URL for the function.\n\n![Alt text](docs/cloud-function.png)\n\n### Test the Cloud Function\nTo test the function, use a command like below, where the URL is from the `TRIGGER` tab in the console. See the *HTTP API* section above for body contents.\n\n```\ncurl -X POST https://<region>-<projectID>.cloudfunctions.net/provision \\\n   -H \"Content-Type:application/json\" \\\n   -d '{ \"uuid\": \"<device-uuid>\", \"balena_service\": \"<service-name>\" }'\n```\n\nAfter a successful POST, you should see the device appear in your IoT Core registry and `GCP_CLIENT_PATH`, `GCP_DATA_TOPIC_ROOT`, `GCP_PRIVATE_KEY`, and `GCP_PROJECT_ID` variables appear in balenaCloud for the device. After a successful DELETE, those variables disappear.\n","gitHead":"74dae0779fde7dd493a3edb773c03dac8363a525","private":false,"scripts":{"test":"echo \"No tests yet\" && exit 0","start":"node index.js"},"_npmUser":{"name":"balena.io","email":"accounts+npm@balena.io"},"repository":{"url":"git+https://github.com/balena-io-examples/gcp-iot-provision.git","type":"git"},"versionist":{"publishedAt":"2022-08-29T19:32:48.085Z"},"_npmVersion":"6.14.17","description":"Google Cloud function to provision a balena device to IoT Core","directories":{},"_nodeVersion":"14.19.3","dependencies":{"balena-sdk":"^16.11.2","@google-cloud/iot":"^2.5.0","@google-cloud/functions-framework":"^2.1.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","_npmOperationalInternal":{"tmp":"tmp/gcp-iot-provision_0.2.8-dependabot-npm-and-yarn-balena-sdk-16-26-1-74dae0779fde7dd493a3edb773c03dac8363a525_1661801686702_0.7880588368540222","host":"s3://npm-registry-packages"},"deprecated":"Deprecated: no longer maintained. The GitHub repository has been archived and no further releases will be published."},"0.2.8-dependabot-npm-and-yarn-balena-sdk-16-26-2-ed8fde2922e091a06e196673eb570786e6750e66":{"name":"gcp-iot-provision","version":"0.2.8-dependabot-npm-and-yarn-balena-sdk-16-26-2-ed8fde2922e091a06e196673eb570786e6750e66","keywords":["balena","balenaCloud","google","iotcore","iot","gcp"],"author":{"name":"Ken Bannister","email":"ken@balena.io"},"license":"Apache-2.0","_id":"gcp-iot-provision@0.2.8-dependabot-npm-and-yarn-balena-sdk-16-26-2-ed8fde2922e091a06e196673eb570786e6750e66","maintainers":[{"name":"balena.io","email":"accounts+npm@balena.io"}],"homepage":"https://github.com/balena-io-examples/gcp-iot-provision","bugs":{"url":"https://github.com/balena-io-examples/gcp-iot-provision/issues"},"dist":{"shasum":"3ad20cded21f77316b0e646425e7ec109790787c","tarball":"https://registry.npmjs.org/gcp-iot-provision/-/gcp-iot-provision-0.2.8-dependabot-npm-and-yarn-balena-sdk-16-26-2-ed8fde2922e091a06e196673eb570786e6750e66.tgz","fileCount":9,"integrity":"sha512-bY0mKs8VXf251GtLpix/z6cvSJKhfkoqagGW2sQOiFEOyOFYdjssPFmYyNH7hWfQcLKPjycr9B7eYhQNxGdvqQ==","signatures":[{"sig":"MEUCIQCXj/GpgBY/bpfs7v5vazfcqOEXzZGtYjcPSJDJle8NJAIgD07XrZo+hxQwz/j8Z2AXBD1tTR4HWu0I9BP9BTs+4KU=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":137526,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJjH4r8ACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2Vmr9EA//fRbVkovn7ysYKL6fAqWanei2peFsCli7ldcwu/dF8XsSPCvY\r\naP098GRL1yIQ8BuSKaTdXbzhRbouyIx4NNQX+mqai35L9I95KFS/Fs5edit/\r\nSwEX1sbu8rOahi75zEoRUbAATkH+iyr9PfP6IDyhY3TB8jwNo9FuTjB6fvL1\r\npZ72ho8TiMihg7mVAl9hD7SMCWlEBO1uRbQt6U/ovFw0NqqQZiXPYZHmqppb\r\n9gesOIMnOp5qT0Gb7lknCi6whXlom8D6GmBocw22qkVxjaE18IDEjGz4ZP8G\r\neZoIIKcNTauNf0E5ZLAP/9e3qj/fIVYtFaajmubbhakPzVbxRRqJWlkMj5hp\r\nHfVAtFV9tmfZLi7f3P456VRjVyfIjZHkmRWA2qPfiVyN2CDvU2hQe45a+8qA\r\nowjI+L59YH52O6mEwA1WJCWrL4SByeET2JCL6Z+/Er/RX10s7p/KLtoqbg8T\r\nxpQVBs1GIC1/fhO1mUoeR3b6tp+LJ8zItiH3w2rMQq+V0kLHpEhGJVdr2Dde\r\nIFY0+q0TSLDatP6q1wT08XeMHri6OEJyc7vo/cMh/R20UKT/SJQcJwz6gm+w\r\nWkfLU+pxMr9QlAxFYa8E7sRV0gx01y2t156Br3rz1lkbuFlu0MrixlBtuuf0\r\ndkO97XgJEirrmmbqAZvSpRiCdmSZygp7Ch8=\r\n=/ZAD\r\n-----END PGP SIGNATURE-----\r\n"},"main":"index.js","type":"module","readme":"# Google Cloud Function for IoT Device Provisioning\n\nThis Cloud Function allows you to provision and synchronize a balena device with Google Cloud IoT Core in a secure and automated way via an HTTP endpoint. The Cloud Function may be called by a balena device, as seen in the [cloud-relay](https://github.com/balena-io-examples/cloud-relay) example.\n\n| Method | Action |\n|-------------|--------|\n| POST | Provisions a balena device with IoT Core. First the function verifies the device UUID with balenaCloud. Then it creates a public/private key pair and adds the device to the registry. Finally the function sets balena device environment variables for these entities. |\n| DELETE | Removes a balena device from the IoT Core registry and removes the balena device environment variable for the private key. Essentially reverses the actions from provisioning with HTTP POST. |\n\n## Device Environment Variables\nOnce the Cloud function has provisioned the device with GCP, it sets balena device environment variables as described below, which allow the device to connect to IoT Core. Some aspects of the variable values are common across devices, and are collected from the cloud function deployment.\n\n| Variable | Value |\n|----------|-------|\n| GCP_CLIENT_PATH | `<registry-path>/devices/<device-id>`<br><br> `<registry-path>` is derived from the project ID, GCP region, and registry ID<br>`<device-id>` is derived from the balena UUID for the device |\n| GCP_DATA_TOPIC_ROOT | `/devices/<device-id>` |\n| GCP_PROJECT_ID | Google Cloud project ID |\n| GCP_PRIVATE_KEY | Private key in PEM format, base64 encoded to eliminate line wrapping |\n\n\n## Setup and Testing\n### GCP setup\nThe Cloud Function interacts with Google Cloud IoT Core via client code operating with service account credentials. You must setup a Google Cloud project with an IoT Core registry. The service account must have the *Cloud IoT Provisioner* role to manage device records in the IoT Core registry. See the IoT Core [documentation](https://cloud.google.com/iot/docs/how-tos) for more background.\n\n### Workspace setup\nClone this repo\n```\n$ git clone https://github.com/balena-io-examples/gcp-iot-provision\n```\n\nThe sections below show how to test the Cloud Function on a local test server and deploy to Cloud Functions. In either case you must provide the environment variables in the table below as instructed for the test/deployment.\n\n| Key         |    Value    |\n|-------------|-------------|\n| BALENA_API_KEY | for use of balena API; found in balenaCloud dashboard at: `account -> Preferences -> Access tokens` |\n| GCP_PROJECT_ID | Google Cloud project ID, like `my-project-000000`|\n| GCP_REGION | Google Cloud region for registry, like `us-central1` |\n| GCP_REGISTRY_ID | Google Cloud registry ID you provided to create the registry |\n| GCP_SERVICE_ACCOUNT |base64 encoding of the JSON formatted GCP service account credentials provided by Google when you created the service account. Example below, assuming the credentials JSON is contained in a file.<br><br>`cat <credentials.txt> \\| base64 -w 0` |\n\n### HTTP API\nThe HTTP endpoint expects a request containing a JSON body with the attributes below. Use POST to add a device to the cloud registry, DELETE to remove.\n\n| Attribute | Value |\n|-----------|-------|\n| uuid | UUID of device  |\n| balena_service | (optional) Name of service container on balena device that uses provisioned key and certificate, for example `cloud-relay`. If defined, creates service level variables; otherwise creates device level variables. Service level variables are more secure. |\n\n\n### Test locally\nThe Google Functions Framework is a convenient tool for local testing. \nFirst, start a local HTTP server ([docs reference](https://cloud.google.com/functions/docs/running/function-frameworks)) using a script like below.\n\n```\nexport BALENA_API_KEY=<...>\n... <other environment variables from table above>\nexport GCP_SERVICE_ACCOUNT=<...>\n\nnpx @google-cloud/functions-framework --target=provision\n```\n\nNext, use `curl` to send an HTTP request to the local server to provision a device. See the *HTTP API* section above for body contents.\n\n```\ncurl -X POST http://localhost:8080 -H \"Content-Type:application/json\" \\\n   -d '{ \"uuid\": \"<device-uuid>\", \"balena_service\": \"<service-name>\" }'\n```\n\nAfter a successful POST, you should see the device appear in your IoT Core registry and `GCP_CLIENT_PATH`, `GCP_DATA_TOPIC_ROOT`, `GCP_PRIVATE_KEY`, and `GCP_PROJECT_ID` variables appear in balenaCloud for the device. After a successful DELETE, those variables disappear.\n\n## Deploy\nTo deploy to Cloud Functions, use the command below. See the [command documentation](https://cloud.google.com/sdk/gcloud/reference/functions/deploy) for the format of `yaml-file`, which contains the variables from the table in the *Development setup* section above.\n\n```\ngcloud functions deploy provision --runtime=nodejs14 --trigger-http \\\n   --env-vars-file=<yaml-file> --allow-unauthenticated \\\n   --service-account=<name>@<xxxx>.iam.gserviceaccount.com\n```\n\nThe result is a Cloud Function like below. Notice the `TRIGGER` tab, which provides the URL for the function.\n\n![Alt text](docs/cloud-function.png)\n\n### Test the Cloud Function\nTo test the function, use a command like below, where the URL is from the `TRIGGER` tab in the console. See the *HTTP API* section above for body contents.\n\n```\ncurl -X POST https://<region>-<projectID>.cloudfunctions.net/provision \\\n   -H \"Content-Type:application/json\" \\\n   -d '{ \"uuid\": \"<device-uuid>\", \"balena_service\": \"<service-name>\" }'\n```\n\nAfter a successful POST, you should see the device appear in your IoT Core registry and `GCP_CLIENT_PATH`, `GCP_DATA_TOPIC_ROOT`, `GCP_PRIVATE_KEY`, and `GCP_PROJECT_ID` variables appear in balenaCloud for the device. After a successful DELETE, those variables disappear.\n","gitHead":"ed8fde2922e091a06e196673eb570786e6750e66","private":false,"scripts":{"test":"echo \"No tests yet\" && exit 0","start":"node index.js"},"_npmUser":{"name":"balena.io","email":"accounts+npm@balena.io"},"repository":{"url":"git+https://github.com/balena-io-examples/gcp-iot-provision.git","type":"git"},"versionist":{"publishedAt":"2022-09-12T19:37:26.587Z"},"_npmVersion":"6.14.17","description":"Google Cloud function to provision a balena device to IoT Core","directories":{},"_nodeVersion":"14.19.3","dependencies":{"balena-sdk":"^16.11.2","@google-cloud/iot":"^2.5.0","@google-cloud/functions-framework":"^2.1.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","_npmOperationalInternal":{"tmp":"tmp/gcp-iot-provision_0.2.8-dependabot-npm-and-yarn-balena-sdk-16-26-2-ed8fde2922e091a06e196673eb570786e6750e66_1663011580394_0.9334336910581607","host":"s3://npm-registry-packages"},"deprecated":"Deprecated: no longer maintained. The GitHub repository has been archived and no further releases will be published."},"0.2.8-dependabot-npm-and-yarn-balena-sdk-16-26-5-7bbc0e6ee003cee970259a7e257cc03566a8114d":{"name":"gcp-iot-provision","version":"0.2.8-dependabot-npm-and-yarn-balena-sdk-16-26-5-7bbc0e6ee003cee970259a7e257cc03566a8114d","keywords":["balena","balenaCloud","google","iotcore","iot","gcp"],"author":{"name":"Ken Bannister","email":"ken@balena.io"},"license":"Apache-2.0","_id":"gcp-iot-provision@0.2.8-dependabot-npm-and-yarn-balena-sdk-16-26-5-7bbc0e6ee003cee970259a7e257cc03566a8114d","maintainers":[{"name":"balena.io","email":"accounts+npm@balena.io"}],"homepage":"https://github.com/balena-io-examples/gcp-iot-provision","bugs":{"url":"https://github.com/balena-io-examples/gcp-iot-provision/issues"},"dist":{"shasum":"8b856059c06f0560a834b008159aa30f02983d3e","tarball":"https://registry.npmjs.org/gcp-iot-provision/-/gcp-iot-provision-0.2.8-dependabot-npm-and-yarn-balena-sdk-16-26-5-7bbc0e6ee003cee970259a7e257cc03566a8114d.tgz","fileCount":9,"integrity":"sha512-IErTUD5Wp1nJRM78KjQvdrVTKxBdpeEfkrIPlrJWVvZCMud2XupCYrDdJBYhNlJzxX11HmEIhy+YJIyhm0GfhA==","signatures":[{"sig":"MEYCIQD5eLiZyFAJ52CC2J4nCYq7a8O0WJwvM0Q7Ycgp/h+GpQIhAP31nR8TVF2PeKVQU3CiLVzKm04O3QoimSDMNeXjgUgc","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":137526,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJjMf6NACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmpotxAAlTLCw4DySWAqyJEWrz11ixie7tuo+RzcfkJFKm86JXnkgixr\r\nTenqIYgEzpoXmJLuG7E4hRDSBvQUqGZQdcsUJPLLpnWluvt/2I/s4ou9pXFG\r\n5nQCM6EVZHHAurcT0yKk6fz+nIBmLtONsz+oxkJW4rHUukvzDhiN9NYKIxjP\r\neypvzOPv7x11uld5XV3VffsU70HK+6MKmGenxJZ30tyGF3mHJ1ss0tGHll0k\r\nuDG7142DJdyhhXIE54OIyPQant00+FnJE0MlNwEDu4SFgUcqK8GWyKDRmCXi\r\nsQ9pYkmRWzxMQtX3fByI7NQFHWuk/zE5pZ3KJpUS8W8dM5+AkuY7z97/HiqD\r\n97uRl9XPXGS5EhqaaaZRTAbPmSHirEjJOncs3DZyvuFMTdLfSjpAaXbAHdyH\r\nFF912jZbHcvveKbdNDhDTzg5NUCny+Zf655Xkj47tw9SAh+0G/uJnAjMUE3C\r\nFQiwDt0A4R8Eglbiji64wDazUjo8gYMfWwNHElW5nqZLTvjp2ce9B7fN1QP3\r\nLkdo9OCEeYEue8+O97uQjPeYihdQnHT3ndRu+9wWWRmbI0TZ+KPoOH21xXfV\r\n/fV5wqwPQdiVy9EKY8yPawfh8Dn/FqZdh67rVD81AtZLXp0UpLjtNZ1bFpjg\r\n5GvD4UQci6w+Ij4j2uk5/zMfYCV0IJ3JGtc=\r\n=7eWp\r\n-----END PGP SIGNATURE-----\r\n"},"main":"index.js","type":"module","readme":"# Google Cloud Function for IoT Device Provisioning\n\nThis Cloud Function allows you to provision and synchronize a balena device with Google Cloud IoT Core in a secure and automated way via an HTTP endpoint. The Cloud Function may be called by a balena device, as seen in the [cloud-relay](https://github.com/balena-io-examples/cloud-relay) example.\n\n| Method | Action |\n|-------------|--------|\n| POST | Provisions a balena device with IoT Core. First the function verifies the device UUID with balenaCloud. Then it creates a public/private key pair and adds the device to the registry. Finally the function sets balena device environment variables for these entities. |\n| DELETE | Removes a balena device from the IoT Core registry and removes the balena device environment variable for the private key. Essentially reverses the actions from provisioning with HTTP POST. |\n\n## Device Environment Variables\nOnce the Cloud function has provisioned the device with GCP, it sets balena device environment variables as described below, which allow the device to connect to IoT Core. Some aspects of the variable values are common across devices, and are collected from the cloud function deployment.\n\n| Variable | Value |\n|----------|-------|\n| GCP_CLIENT_PATH | `<registry-path>/devices/<device-id>`<br><br> `<registry-path>` is derived from the project ID, GCP region, and registry ID<br>`<device-id>` is derived from the balena UUID for the device |\n| GCP_DATA_TOPIC_ROOT | `/devices/<device-id>` |\n| GCP_PROJECT_ID | Google Cloud project ID |\n| GCP_PRIVATE_KEY | Private key in PEM format, base64 encoded to eliminate line wrapping |\n\n\n## Setup and Testing\n### GCP setup\nThe Cloud Function interacts with Google Cloud IoT Core via client code operating with service account credentials. You must setup a Google Cloud project with an IoT Core registry. The service account must have the *Cloud IoT Provisioner* role to manage device records in the IoT Core registry. See the IoT Core [documentation](https://cloud.google.com/iot/docs/how-tos) for more background.\n\n### Workspace setup\nClone this repo\n```\n$ git clone https://github.com/balena-io-examples/gcp-iot-provision\n```\n\nThe sections below show how to test the Cloud Function on a local test server and deploy to Cloud Functions. In either case you must provide the environment variables in the table below as instructed for the test/deployment.\n\n| Key         |    Value    |\n|-------------|-------------|\n| BALENA_API_KEY | for use of balena API; found in balenaCloud dashboard at: `account -> Preferences -> Access tokens` |\n| GCP_PROJECT_ID | Google Cloud project ID, like `my-project-000000`|\n| GCP_REGION | Google Cloud region for registry, like `us-central1` |\n| GCP_REGISTRY_ID | Google Cloud registry ID you provided to create the registry |\n| GCP_SERVICE_ACCOUNT |base64 encoding of the JSON formatted GCP service account credentials provided by Google when you created the service account. Example below, assuming the credentials JSON is contained in a file.<br><br>`cat <credentials.txt> \\| base64 -w 0` |\n\n### HTTP API\nThe HTTP endpoint expects a request containing a JSON body with the attributes below. Use POST to add a device to the cloud registry, DELETE to remove.\n\n| Attribute | Value |\n|-----------|-------|\n| uuid | UUID of device  |\n| balena_service | (optional) Name of service container on balena device that uses provisioned key and certificate, for example `cloud-relay`. If defined, creates service level variables; otherwise creates device level variables. Service level variables are more secure. |\n\n\n### Test locally\nThe Google Functions Framework is a convenient tool for local testing. \nFirst, start a local HTTP server ([docs reference](https://cloud.google.com/functions/docs/running/function-frameworks)) using a script like below.\n\n```\nexport BALENA_API_KEY=<...>\n... <other environment variables from table above>\nexport GCP_SERVICE_ACCOUNT=<...>\n\nnpx @google-cloud/functions-framework --target=provision\n```\n\nNext, use `curl` to send an HTTP request to the local server to provision a device. See the *HTTP API* section above for body contents.\n\n```\ncurl -X POST http://localhost:8080 -H \"Content-Type:application/json\" \\\n   -d '{ \"uuid\": \"<device-uuid>\", \"balena_service\": \"<service-name>\" }'\n```\n\nAfter a successful POST, you should see the device appear in your IoT Core registry and `GCP_CLIENT_PATH`, `GCP_DATA_TOPIC_ROOT`, `GCP_PRIVATE_KEY`, and `GCP_PROJECT_ID` variables appear in balenaCloud for the device. After a successful DELETE, those variables disappear.\n\n## Deploy\nTo deploy to Cloud Functions, use the command below. See the [command documentation](https://cloud.google.com/sdk/gcloud/reference/functions/deploy) for the format of `yaml-file`, which contains the variables from the table in the *Development setup* section above.\n\n```\ngcloud functions deploy provision --runtime=nodejs14 --trigger-http \\\n   --env-vars-file=<yaml-file> --allow-unauthenticated \\\n   --service-account=<name>@<xxxx>.iam.gserviceaccount.com\n```\n\nThe result is a Cloud Function like below. Notice the `TRIGGER` tab, which provides the URL for the function.\n\n![Alt text](docs/cloud-function.png)\n\n### Test the Cloud Function\nTo test the function, use a command like below, where the URL is from the `TRIGGER` tab in the console. See the *HTTP API* section above for body contents.\n\n```\ncurl -X POST https://<region>-<projectID>.cloudfunctions.net/provision \\\n   -H \"Content-Type:application/json\" \\\n   -d '{ \"uuid\": \"<device-uuid>\", \"balena_service\": \"<service-name>\" }'\n```\n\nAfter a successful POST, you should see the device appear in your IoT Core registry and `GCP_CLIENT_PATH`, `GCP_DATA_TOPIC_ROOT`, `GCP_PRIVATE_KEY`, and `GCP_PROJECT_ID` variables appear in balenaCloud for the device. After a successful DELETE, those variables disappear.\n","gitHead":"7bbc0e6ee003cee970259a7e257cc03566a8114d","private":false,"scripts":{"test":"echo \"No tests yet\" && exit 0","start":"node index.js"},"_npmUser":{"name":"balena.io","email":"accounts+npm@balena.io"},"repository":{"url":"git+https://github.com/balena-io-examples/gcp-iot-provision.git","type":"git"},"versionist":{"publishedAt":"2022-09-26T19:30:23.720Z"},"_npmVersion":"6.14.17","description":"Google Cloud function to provision a balena device to IoT Core","directories":{},"_nodeVersion":"14.19.3","dependencies":{"balena-sdk":"^16.11.2","@google-cloud/iot":"^2.5.0","@google-cloud/functions-framework":"^2.1.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","_npmOperationalInternal":{"tmp":"tmp/gcp-iot-provision_0.2.8-dependabot-npm-and-yarn-balena-sdk-16-26-5-7bbc0e6ee003cee970259a7e257cc03566a8114d_1664220812972_0.541771038668506","host":"s3://npm-registry-packages"},"deprecated":"Deprecated: no longer maintained. The GitHub repository has been archived and no further releases will be published."},"0.2.8-dependabot-npm-and-yarn-balena-sdk-16-27-0-cb71ef781b6efb37aaefa3eb61a4c20341d06eb6":{"name":"gcp-iot-provision","version":"0.2.8-dependabot-npm-and-yarn-balena-sdk-16-27-0-cb71ef781b6efb37aaefa3eb61a4c20341d06eb6","keywords":["balena","balenaCloud","google","iotcore","iot","gcp"],"author":{"name":"Ken Bannister","email":"ken@balena.io"},"license":"Apache-2.0","_id":"gcp-iot-provision@0.2.8-dependabot-npm-and-yarn-balena-sdk-16-27-0-cb71ef781b6efb37aaefa3eb61a4c20341d06eb6","maintainers":[{"name":"balena.io","email":"accounts+npm@balena.io"}],"homepage":"https://github.com/balena-io-examples/gcp-iot-provision","bugs":{"url":"https://github.com/balena-io-examples/gcp-iot-provision/issues"},"dist":{"shasum":"5a73f19a985da0958bcfbed34d2aa066002fee77","tarball":"https://registry.npmjs.org/gcp-iot-provision/-/gcp-iot-provision-0.2.8-dependabot-npm-and-yarn-balena-sdk-16-27-0-cb71ef781b6efb37aaefa3eb61a4c20341d06eb6.tgz","fileCount":9,"integrity":"sha512-fihvDZKU7CsUCiNXcOWpg/WWp3UbqiWa+lprP4uCDkG1XlPL9xIpwk7vNVtXGGnEMyqGF5BsU12tAPxMzuabvA==","signatures":[{"sig":"MEUCIQDd1zAJT9TyKoLCCXuZJRknxoUo2TAJBwxv8QrXLqLdYAIgBVx8nYzlaoRJP4IjKuQokrAcWmetgU+4A/gMLi2iBzw=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":137526,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJjRHiPACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmrGhg//bUsy7N0MJhZ7d+qAo/Rczs72pLdc6cR8e3UKa7I/OON6PYCC\r\nqX1i92PGuVTJTblGNKmvyPJ3wO1IZX2q+Ttk94n2TS23KScoTv/9DO8GQWIg\r\nUrlVO64Mo4k9QZr2NDC3yn5ZPssAv5Yf6iCm9i75PMe0VXY8IbQIqnmH/CpM\r\n60FuLt8JpOJImlJxnw9ZuBaFqJA6hLEQnmKXjZ2JgTihceyMR8XjRHw/wQ1b\r\nvSI3kQK35VSBHpwHB6Hr5HWGGBvY1Qvx0NDFxvft9I8oPWkR9C1gC7xjUSX+\r\nn9khTnAtnyLaIF43KZuHh21AaoREqhHINzrU5OrWoEe19a6HxepQo0X2y60D\r\nnyfEHrkuJegC56sJom0NRb9t3NgxnTaGIQHXuTbDyut8jkUs9+ujU9h2TjsA\r\nIRlcCJanpUKw7/ffIsPdnnkNtE1UwfwnYxTjCmUJcAZUg+eZLIF0n3UMEVSa\r\nWm1X4nnLahhwEHgUtouHeII5LnLzR/5kBXBhHsPJb8Nx+g3SbnbaUrbaaIzW\r\n7g9cFI2MQa/MlYmdLtpxFeK0gLOgmBKdO9R5zzJVrjN9TNI82Z+Hq1wnX1uQ\r\nHSsKP+lq4utfOB95ZkYfHTff/2VKG6du7Zsh0H57UZWVKMXkaTfCmg7kWcIP\r\neUXXUtZxcchkeTf2w6xLicycIX2VQL3J7L0=\r\n=bHcQ\r\n-----END PGP SIGNATURE-----\r\n"},"main":"index.js","type":"module","readme":"# Google Cloud Function for IoT Device Provisioning\n\nThis Cloud Function allows you to provision and synchronize a balena device with Google Cloud IoT Core in a secure and automated way via an HTTP endpoint. The Cloud Function may be called by a balena device, as seen in the [cloud-relay](https://github.com/balena-io-examples/cloud-relay) example.\n\n| Method | Action |\n|-------------|--------|\n| POST | Provisions a balena device with IoT Core. First the function verifies the device UUID with balenaCloud. Then it creates a public/private key pair and adds the device to the registry. Finally the function sets balena device environment variables for these entities. |\n| DELETE | Removes a balena device from the IoT Core registry and removes the balena device environment variable for the private key. Essentially reverses the actions from provisioning with HTTP POST. |\n\n## Device Environment Variables\nOnce the Cloud function has provisioned the device with GCP, it sets balena device environment variables as described below, which allow the device to connect to IoT Core. Some aspects of the variable values are common across devices, and are collected from the cloud function deployment.\n\n| Variable | Value |\n|----------|-------|\n| GCP_CLIENT_PATH | `<registry-path>/devices/<device-id>`<br><br> `<registry-path>` is derived from the project ID, GCP region, and registry ID<br>`<device-id>` is derived from the balena UUID for the device |\n| GCP_DATA_TOPIC_ROOT | `/devices/<device-id>` |\n| GCP_PROJECT_ID | Google Cloud project ID |\n| GCP_PRIVATE_KEY | Private key in PEM format, base64 encoded to eliminate line wrapping |\n\n\n## Setup and Testing\n### GCP setup\nThe Cloud Function interacts with Google Cloud IoT Core via client code operating with service account credentials. You must setup a Google Cloud project with an IoT Core registry. The service account must have the *Cloud IoT Provisioner* role to manage device records in the IoT Core registry. See the IoT Core [documentation](https://cloud.google.com/iot/docs/how-tos) for more background.\n\n### Workspace setup\nClone this repo\n```\n$ git clone https://github.com/balena-io-examples/gcp-iot-provision\n```\n\nThe sections below show how to test the Cloud Function on a local test server and deploy to Cloud Functions. In either case you must provide the environment variables in the table below as instructed for the test/deployment.\n\n| Key         |    Value    |\n|-------------|-------------|\n| BALENA_API_KEY | for use of balena API; found in balenaCloud dashboard at: `account -> Preferences -> Access tokens` |\n| GCP_PROJECT_ID | Google Cloud project ID, like `my-project-000000`|\n| GCP_REGION | Google Cloud region for registry, like `us-central1` |\n| GCP_REGISTRY_ID | Google Cloud registry ID you provided to create the registry |\n| GCP_SERVICE_ACCOUNT |base64 encoding of the JSON formatted GCP service account credentials provided by Google when you created the service account. Example below, assuming the credentials JSON is contained in a file.<br><br>`cat <credentials.txt> \\| base64 -w 0` |\n\n### HTTP API\nThe HTTP endpoint expects a request containing a JSON body with the attributes below. Use POST to add a device to the cloud registry, DELETE to remove.\n\n| Attribute | Value |\n|-----------|-------|\n| uuid | UUID of device  |\n| balena_service | (optional) Name of service container on balena device that uses provisioned key and certificate, for example `cloud-relay`. If defined, creates service level variables; otherwise creates device level variables. Service level variables are more secure. |\n\n\n### Test locally\nThe Google Functions Framework is a convenient tool for local testing. \nFirst, start a local HTTP server ([docs reference](https://cloud.google.com/functions/docs/running/function-frameworks)) using a script like below.\n\n```\nexport BALENA_API_KEY=<...>\n... <other environment variables from table above>\nexport GCP_SERVICE_ACCOUNT=<...>\n\nnpx @google-cloud/functions-framework --target=provision\n```\n\nNext, use `curl` to send an HTTP request to the local server to provision a device. See the *HTTP API* section above for body contents.\n\n```\ncurl -X POST http://localhost:8080 -H \"Content-Type:application/json\" \\\n   -d '{ \"uuid\": \"<device-uuid>\", \"balena_service\": \"<service-name>\" }'\n```\n\nAfter a successful POST, you should see the device appear in your IoT Core registry and `GCP_CLIENT_PATH`, `GCP_DATA_TOPIC_ROOT`, `GCP_PRIVATE_KEY`, and `GCP_PROJECT_ID` variables appear in balenaCloud for the device. After a successful DELETE, those variables disappear.\n\n## Deploy\nTo deploy to Cloud Functions, use the command below. See the [command documentation](https://cloud.google.com/sdk/gcloud/reference/functions/deploy) for the format of `yaml-file`, which contains the variables from the table in the *Development setup* section above.\n\n```\ngcloud functions deploy provision --runtime=nodejs14 --trigger-http \\\n   --env-vars-file=<yaml-file> --allow-unauthenticated \\\n   --service-account=<name>@<xxxx>.iam.gserviceaccount.com\n```\n\nThe result is a Cloud Function like below. Notice the `TRIGGER` tab, which provides the URL for the function.\n\n![Alt text](docs/cloud-function.png)\n\n### Test the Cloud Function\nTo test the function, use a command like below, where the URL is from the `TRIGGER` tab in the console. See the *HTTP API* section above for body contents.\n\n```\ncurl -X POST https://<region>-<projectID>.cloudfunctions.net/provision \\\n   -H \"Content-Type:application/json\" \\\n   -d '{ \"uuid\": \"<device-uuid>\", \"balena_service\": \"<service-name>\" }'\n```\n\nAfter a successful POST, you should see the device appear in your IoT Core registry and `GCP_CLIENT_PATH`, `GCP_DATA_TOPIC_ROOT`, `GCP_PRIVATE_KEY`, and `GCP_PROJECT_ID` variables appear in balenaCloud for the device. After a successful DELETE, those variables disappear.\n","gitHead":"cb71ef781b6efb37aaefa3eb61a4c20341d06eb6","private":false,"scripts":{"test":"echo \"No tests yet\" && exit 0","start":"node index.js"},"_npmUser":{"name":"balena.io","email":"accounts+npm@balena.io"},"repository":{"url":"git+https://github.com/balena-io-examples/gcp-iot-provision.git","type":"git"},"versionist":{"publishedAt":"2022-10-10T19:47:09.813Z"},"_npmVersion":"6.14.17","description":"Google Cloud function to provision a balena device to IoT Core","directories":{},"_nodeVersion":"14.19.3","dependencies":{"balena-sdk":"^16.11.2","@google-cloud/iot":"^2.5.0","@google-cloud/functions-framework":"^2.1.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","_npmOperationalInternal":{"tmp":"tmp/gcp-iot-provision_0.2.8-dependabot-npm-and-yarn-balena-sdk-16-27-0-cb71ef781b6efb37aaefa3eb61a4c20341d06eb6_1665431695106_0.12328039211011865","host":"s3://npm-registry-packages"},"deprecated":"Deprecated: no longer maintained. The GitHub repository has been archived and no further releases will be published."},"0.2.8-dependabot-npm-and-yarn-balena-sdk-16-28-1-019ea09d1b26e78a3bdac40d7eb6aa83bfd0e5c3":{"name":"gcp-iot-provision","version":"0.2.8-dependabot-npm-and-yarn-balena-sdk-16-28-1-019ea09d1b26e78a3bdac40d7eb6aa83bfd0e5c3","keywords":["balena","balenaCloud","google","iotcore","iot","gcp"],"author":{"name":"Ken Bannister","email":"ken@balena.io"},"license":"Apache-2.0","_id":"gcp-iot-provision@0.2.8-dependabot-npm-and-yarn-balena-sdk-16-28-1-019ea09d1b26e78a3bdac40d7eb6aa83bfd0e5c3","maintainers":[{"name":"balena.io","email":"accounts+npm@balena.io"}],"homepage":"https://github.com/balena-io-examples/gcp-iot-provision","bugs":{"url":"https://github.com/balena-io-examples/gcp-iot-provision/issues"},"dist":{"shasum":"44854f699fc61794e2c3af492bfa5152bb49a3e2","tarball":"https://registry.npmjs.org/gcp-iot-provision/-/gcp-iot-provision-0.2.8-dependabot-npm-and-yarn-balena-sdk-16-28-1-019ea09d1b26e78a3bdac40d7eb6aa83bfd0e5c3.tgz","fileCount":9,"integrity":"sha512-uUBQ6lPtfEF3/EA0G5G0K+hWidhu4d2iCf2VNGtWEAUjG96JDyp0KJR1Plg/JT3VTA83HHMCSSXb4RuUfiFnEw==","signatures":[{"sig":"MEQCIAZeemuAsGUef46GdW9oI6SIiaFguIpB9Y9gEkMU9AKsAiBCznXVaDPZNBNxvlfMiJA5+PoxoZbIU7RX5oncinTOVg==","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":137526,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJjTa6ZACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmqnehAAi2CHzbN+Cbl1vNvVOELGYXQn+3SGncVMylNtgZugJ6OpN8vH\r\nVLIRKNghEmlU02rfCb2oN16ob0pkWjsFXcaraqCNONEOGAtz/kD9PU0z1qqg\r\nGbDKF0PAggzNStIV7eAP0h0vCUHS7kS5jspE1raya/nwWvWsq5fepuHKrOAF\r\nYY5AMV0ItQTwYaf7WxGFlxZxKfmdhwO6FCsF2SNoP4NoQiLIHiEW4N5IIwHU\r\nWC5z0TN3CA7iaV2k/vWpoQlfTAosGKinBj75w5089Gr6imMizBHfpYFRKS9J\r\njrpWkdW/8qhisKOcElPrqF+LgmGqs6aCEl/8hj0UGlZSHW0V2usegsm1qGtu\r\nSF9h5phMwBgNKP5rcR9JQu9UGN/nrzm3F4XUNq61SCNk9eCSu+Ur2jT/sDsL\r\nwJZwchRdOZB/VKutSTTpZlg81o/auZOcKdFPzt4l6x9CTCR5uQGUJfkoAcHX\r\n1dKLgZmKDupFnRhycOYF4ENMBgBVSUxusRHXd0xDytR9e1hFLZsIAsqEH4+t\r\n4IcsgnZ5CI1Pr6wY8VllH3570wjjJatVeNOMsFKLs5o2ZeFPxyAnnl+qp9ED\r\njplElbX0TgNVzbF+U4fwquiehfAaIu6tHo4NjIe1YN7hn/98LN725l2BjcWI\r\nTSdVi9dSP2SJU+LtAYk8hCYgcLbSPlzifOc=\r\n=Estv\r\n-----END PGP SIGNATURE-----\r\n"},"main":"index.js","type":"module","readme":"# Google Cloud Function for IoT Device Provisioning\n\nThis Cloud Function allows you to provision and synchronize a balena device with Google Cloud IoT Core in a secure and automated way via an HTTP endpoint. The Cloud Function may be called by a balena device, as seen in the [cloud-relay](https://github.com/balena-io-examples/cloud-relay) example.\n\n| Method | Action |\n|-------------|--------|\n| POST | Provisions a balena device with IoT Core. First the function verifies the device UUID with balenaCloud. Then it creates a public/private key pair and adds the device to the registry. Finally the function sets balena device environment variables for these entities. |\n| DELETE | Removes a balena device from the IoT Core registry and removes the balena device environment variable for the private key. Essentially reverses the actions from provisioning with HTTP POST. |\n\n## Device Environment Variables\nOnce the Cloud function has provisioned the device with GCP, it sets balena device environment variables as described below, which allow the device to connect to IoT Core. Some aspects of the variable values are common across devices, and are collected from the cloud function deployment.\n\n| Variable | Value |\n|----------|-------|\n| GCP_CLIENT_PATH | `<registry-path>/devices/<device-id>`<br><br> `<registry-path>` is derived from the project ID, GCP region, and registry ID<br>`<device-id>` is derived from the balena UUID for the device |\n| GCP_DATA_TOPIC_ROOT | `/devices/<device-id>` |\n| GCP_PROJECT_ID | Google Cloud project ID |\n| GCP_PRIVATE_KEY | Private key in PEM format, base64 encoded to eliminate line wrapping |\n\n\n## Setup and Testing\n### GCP setup\nThe Cloud Function interacts with Google Cloud IoT Core via client code operating with service account credentials. You must setup a Google Cloud project with an IoT Core registry. The service account must have the *Cloud IoT Provisioner* role to manage device records in the IoT Core registry. See the IoT Core [documentation](https://cloud.google.com/iot/docs/how-tos) for more background.\n\n### Workspace setup\nClone this repo\n```\n$ git clone https://github.com/balena-io-examples/gcp-iot-provision\n```\n\nThe sections below show how to test the Cloud Function on a local test server and deploy to Cloud Functions. In either case you must provide the environment variables in the table below as instructed for the test/deployment.\n\n| Key         |    Value    |\n|-------------|-------------|\n| BALENA_API_KEY | for use of balena API; found in balenaCloud dashboard at: `account -> Preferences -> Access tokens` |\n| GCP_PROJECT_ID | Google Cloud project ID, like `my-project-000000`|\n| GCP_REGION | Google Cloud region for registry, like `us-central1` |\n| GCP_REGISTRY_ID | Google Cloud registry ID you provided to create the registry |\n| GCP_SERVICE_ACCOUNT |base64 encoding of the JSON formatted GCP service account credentials provided by Google when you created the service account. Example below, assuming the credentials JSON is contained in a file.<br><br>`cat <credentials.txt> \\| base64 -w 0` |\n\n### HTTP API\nThe HTTP endpoint expects a request containing a JSON body with the attributes below. Use POST to add a device to the cloud registry, DELETE to remove.\n\n| Attribute | Value |\n|-----------|-------|\n| uuid | UUID of device  |\n| balena_service | (optional) Name of service container on balena device that uses provisioned key and certificate, for example `cloud-relay`. If defined, creates service level variables; otherwise creates device level variables. Service level variables are more secure. |\n\n\n### Test locally\nThe Google Functions Framework is a convenient tool for local testing. \nFirst, start a local HTTP server ([docs reference](https://cloud.google.com/functions/docs/running/function-frameworks)) using a script like below.\n\n```\nexport BALENA_API_KEY=<...>\n... <other environment variables from table above>\nexport GCP_SERVICE_ACCOUNT=<...>\n\nnpx @google-cloud/functions-framework --target=provision\n```\n\nNext, use `curl` to send an HTTP request to the local server to provision a device. See the *HTTP API* section above for body contents.\n\n```\ncurl -X POST http://localhost:8080 -H \"Content-Type:application/json\" \\\n   -d '{ \"uuid\": \"<device-uuid>\", \"balena_service\": \"<service-name>\" }'\n```\n\nAfter a successful POST, you should see the device appear in your IoT Core registry and `GCP_CLIENT_PATH`, `GCP_DATA_TOPIC_ROOT`, `GCP_PRIVATE_KEY`, and `GCP_PROJECT_ID` variables appear in balenaCloud for the device. After a successful DELETE, those variables disappear.\n\n## Deploy\nTo deploy to Cloud Functions, use the command below. See the [command documentation](https://cloud.google.com/sdk/gcloud/reference/functions/deploy) for the format of `yaml-file`, which contains the variables from the table in the *Development setup* section above.\n\n```\ngcloud functions deploy provision --runtime=nodejs14 --trigger-http \\\n   --env-vars-file=<yaml-file> --allow-unauthenticated \\\n   --service-account=<name>@<xxxx>.iam.gserviceaccount.com\n```\n\nThe result is a Cloud Function like below. Notice the `TRIGGER` tab, which provides the URL for the function.\n\n![Alt text](docs/cloud-function.png)\n\n### Test the Cloud Function\nTo test the function, use a command like below, where the URL is from the `TRIGGER` tab in the console. See the *HTTP API* section above for body contents.\n\n```\ncurl -X POST https://<region>-<projectID>.cloudfunctions.net/provision \\\n   -H \"Content-Type:application/json\" \\\n   -d '{ \"uuid\": \"<device-uuid>\", \"balena_service\": \"<service-name>\" }'\n```\n\nAfter a successful POST, you should see the device appear in your IoT Core registry and `GCP_CLIENT_PATH`, `GCP_DATA_TOPIC_ROOT`, `GCP_PRIVATE_KEY`, and `GCP_PROJECT_ID` variables appear in balenaCloud for the device. After a successful DELETE, those variables disappear.\n","gitHead":"019ea09d1b26e78a3bdac40d7eb6aa83bfd0e5c3","private":false,"scripts":{"test":"echo \"No tests yet\" && exit 0","start":"node index.js"},"_npmUser":{"name":"balena.io","email":"accounts+npm@balena.io"},"repository":{"url":"git+https://github.com/balena-io-examples/gcp-iot-provision.git","type":"git"},"versionist":{"publishedAt":"2022-10-17T19:28:16.634Z"},"_npmVersion":"6.14.17","description":"Google Cloud function to provision a balena device to IoT Core","directories":{},"_nodeVersion":"14.19.3","dependencies":{"balena-sdk":"^16.11.2","@google-cloud/iot":"^2.5.0","@google-cloud/functions-framework":"^2.1.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","_npmOperationalInternal":{"tmp":"tmp/gcp-iot-provision_0.2.8-dependabot-npm-and-yarn-balena-sdk-16-28-1-019ea09d1b26e78a3bdac40d7eb6aa83bfd0e5c3_1666035353209_0.031183362188881292","host":"s3://npm-registry-packages"},"deprecated":"Deprecated: no longer maintained. The GitHub repository has been archived and no further releases will be published."},"0.2.8-dependabot-npm-and-yarn-balena-sdk-16-28-2-d6a3b568c784f156bada381c3aa1fe5dfcb5e24e":{"name":"gcp-iot-provision","version":"0.2.8-dependabot-npm-and-yarn-balena-sdk-16-28-2-d6a3b568c784f156bada381c3aa1fe5dfcb5e24e","keywords":["balena","balenaCloud","google","iotcore","iot","gcp"],"author":{"name":"Ken Bannister","email":"ken@balena.io"},"license":"Apache-2.0","_id":"gcp-iot-provision@0.2.8-dependabot-npm-and-yarn-balena-sdk-16-28-2-d6a3b568c784f156bada381c3aa1fe5dfcb5e24e","maintainers":[{"name":"balena.io","email":"accounts+npm@balena.io"}],"homepage":"https://github.com/balena-io-examples/gcp-iot-provision","bugs":{"url":"https://github.com/balena-io-examples/gcp-iot-provision/issues"},"dist":{"shasum":"2eba176c94c41d7c36ff4704e31aa157274548c1","tarball":"https://registry.npmjs.org/gcp-iot-provision/-/gcp-iot-provision-0.2.8-dependabot-npm-and-yarn-balena-sdk-16-28-2-d6a3b568c784f156bada381c3aa1fe5dfcb5e24e.tgz","fileCount":9,"integrity":"sha512-Ik6qQAm1EN/2qTgpJIApuIyhJnQ8wo+0yVAmImigLussQ4GxA7NzjsAyqO9/gqXpPeKtfTHfZy6Z008Pa+W/9w==","signatures":[{"sig":"MEYCIQCPJs1BnISnbYkUr9rTKH6t+yi0WI0xK9jKSVRssLH1kAIhAOJsTuX+q17s9WtijOXQi29rVyCwhtS1pStX1GhgX+Ra","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":137526,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJjYCKNACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2Vmoz5A//eidsfKWyR2cK0P5k5uK8NnWNrTxiUgNLuFofuESWUiPmFMiB\r\nkfG5XF/sh+R1NJ4TPFLvSz6UZp74PP4lHtO7PAzJ5ehMaqHeJg2Dup9t0r2d\r\nkxouIIfq8IrYcUz+SFmWHs2ulzoAo8reRxAbywnlLkFZPbJc6wxY6EDsKDJc\r\nvpq3pzAonJeKBQoLOaKrIYCHWRJAuHiKeA/O5MEmF07h7djy13UDC582TJfi\r\nfBmkKjKcUYqnmDz6NEnTAJa2xdq7n4YAUi7Gn3DaJitMM5I1q4nyFHnX7UkH\r\n+QAtBJAmUf9OIuZyVqaWJNSi1GU7llYdfCmMhfV7htvOM+YGRJ58DNOoLh5G\r\nAH1G87DTPrxlrBiL96vdSo3CFs8yXVdiiiffGi1MeqQAXOgCDDKl4pWm2PlS\r\nOu58eWpOIXKIU+Z14p9A5nvoOmYac309cjeajHdp6K/0O2CgNDrb2KakBeGQ\r\nzx0+4+XopimKW/gLTqfGcGJjJI0pCNIzc+Ytq8FLnRqr8Mq1+XaJyR6STGfY\r\nG9FfaDIuFhvd70xDKl2cwTky4vNPswwrE7bGQZ05HsjNGM8URnOPqOYWks//\r\nXaB5atu2qk6nOPuxtW8/sucQ+FuRxriEe2LjgJvCvyIOBDJ9WQAcvBYndiJm\r\nYcESZWS0A/zAbXn1eJYNlBV+EguPd28jhEc=\r\n=wcQw\r\n-----END PGP SIGNATURE-----\r\n"},"main":"index.js","type":"module","readme":"# Google Cloud Function for IoT Device Provisioning\n\nThis Cloud Function allows you to provision and synchronize a balena device with Google Cloud IoT Core in a secure and automated way via an HTTP endpoint. The Cloud Function may be called by a balena device, as seen in the [cloud-relay](https://github.com/balena-io-examples/cloud-relay) example.\n\n| Method | Action |\n|-------------|--------|\n| POST | Provisions a balena device with IoT Core. First the function verifies the device UUID with balenaCloud. Then it creates a public/private key pair and adds the device to the registry. Finally the function sets balena device environment variables for these entities. |\n| DELETE | Removes a balena device from the IoT Core registry and removes the balena device environment variable for the private key. Essentially reverses the actions from provisioning with HTTP POST. |\n\n## Device Environment Variables\nOnce the Cloud function has provisioned the device with GCP, it sets balena device environment variables as described below, which allow the device to connect to IoT Core. Some aspects of the variable values are common across devices, and are collected from the cloud function deployment.\n\n| Variable | Value |\n|----------|-------|\n| GCP_CLIENT_PATH | `<registry-path>/devices/<device-id>`<br><br> `<registry-path>` is derived from the project ID, GCP region, and registry ID<br>`<device-id>` is derived from the balena UUID for the device |\n| GCP_DATA_TOPIC_ROOT | `/devices/<device-id>` |\n| GCP_PROJECT_ID | Google Cloud project ID |\n| GCP_PRIVATE_KEY | Private key in PEM format, base64 encoded to eliminate line wrapping |\n\n\n## Setup and Testing\n### GCP setup\nThe Cloud Function interacts with Google Cloud IoT Core via client code operating with service account credentials. You must setup a Google Cloud project with an IoT Core registry. The service account must have the *Cloud IoT Provisioner* role to manage device records in the IoT Core registry. See the IoT Core [documentation](https://cloud.google.com/iot/docs/how-tos) for more background.\n\n### Workspace setup\nClone this repo\n```\n$ git clone https://github.com/balena-io-examples/gcp-iot-provision\n```\n\nThe sections below show how to test the Cloud Function on a local test server and deploy to Cloud Functions. In either case you must provide the environment variables in the table below as instructed for the test/deployment.\n\n| Key         |    Value    |\n|-------------|-------------|\n| BALENA_API_KEY | for use of balena API; found in balenaCloud dashboard at: `account -> Preferences -> Access tokens` |\n| GCP_PROJECT_ID | Google Cloud project ID, like `my-project-000000`|\n| GCP_REGION | Google Cloud region for registry, like `us-central1` |\n| GCP_REGISTRY_ID | Google Cloud registry ID you provided to create the registry |\n| GCP_SERVICE_ACCOUNT |base64 encoding of the JSON formatted GCP service account credentials provided by Google when you created the service account. Example below, assuming the credentials JSON is contained in a file.<br><br>`cat <credentials.txt> \\| base64 -w 0` |\n\n### HTTP API\nThe HTTP endpoint expects a request containing a JSON body with the attributes below. Use POST to add a device to the cloud registry, DELETE to remove.\n\n| Attribute | Value |\n|-----------|-------|\n| uuid | UUID of device  |\n| balena_service | (optional) Name of service container on balena device that uses provisioned key and certificate, for example `cloud-relay`. If defined, creates service level variables; otherwise creates device level variables. Service level variables are more secure. |\n\n\n### Test locally\nThe Google Functions Framework is a convenient tool for local testing. \nFirst, start a local HTTP server ([docs reference](https://cloud.google.com/functions/docs/running/function-frameworks)) using a script like below.\n\n```\nexport BALENA_API_KEY=<...>\n... <other environment variables from table above>\nexport GCP_SERVICE_ACCOUNT=<...>\n\nnpx @google-cloud/functions-framework --target=provision\n```\n\nNext, use `curl` to send an HTTP request to the local server to provision a device. See the *HTTP API* section above for body contents.\n\n```\ncurl -X POST http://localhost:8080 -H \"Content-Type:application/json\" \\\n   -d '{ \"uuid\": \"<device-uuid>\", \"balena_service\": \"<service-name>\" }'\n```\n\nAfter a successful POST, you should see the device appear in your IoT Core registry and `GCP_CLIENT_PATH`, `GCP_DATA_TOPIC_ROOT`, `GCP_PRIVATE_KEY`, and `GCP_PROJECT_ID` variables appear in balenaCloud for the device. After a successful DELETE, those variables disappear.\n\n## Deploy\nTo deploy to Cloud Functions, use the command below. See the [command documentation](https://cloud.google.com/sdk/gcloud/reference/functions/deploy) for the format of `yaml-file`, which contains the variables from the table in the *Development setup* section above.\n\n```\ngcloud functions deploy provision --runtime=nodejs14 --trigger-http \\\n   --env-vars-file=<yaml-file> --allow-unauthenticated \\\n   --service-account=<name>@<xxxx>.iam.gserviceaccount.com\n```\n\nThe result is a Cloud Function like below. Notice the `TRIGGER` tab, which provides the URL for the function.\n\n![Alt text](docs/cloud-function.png)\n\n### Test the Cloud Function\nTo test the function, use a command like below, where the URL is from the `TRIGGER` tab in the console. See the *HTTP API* section above for body contents.\n\n```\ncurl -X POST https://<region>-<projectID>.cloudfunctions.net/provision \\\n   -H \"Content-Type:application/json\" \\\n   -d '{ \"uuid\": \"<device-uuid>\", \"balena_service\": \"<service-name>\" }'\n```\n\nAfter a successful POST, you should see the device appear in your IoT Core registry and `GCP_CLIENT_PATH`, `GCP_DATA_TOPIC_ROOT`, `GCP_PRIVATE_KEY`, and `GCP_PROJECT_ID` variables appear in balenaCloud for the device. After a successful DELETE, those variables disappear.\n","gitHead":"d6a3b568c784f156bada381c3aa1fe5dfcb5e24e","private":false,"scripts":{"test":"echo \"No tests yet\" && exit 0","start":"node index.js"},"_npmUser":{"name":"balena.io","email":"accounts+npm@balena.io"},"repository":{"url":"git+https://github.com/balena-io-examples/gcp-iot-provision.git","type":"git"},"versionist":{"publishedAt":"2022-10-31T19:26:51.036Z"},"_npmVersion":"6.14.17","description":"Google Cloud function to provision a balena device to IoT Core","directories":{},"_nodeVersion":"14.19.3","dependencies":{"balena-sdk":"^16.11.2","@google-cloud/iot":"^2.5.0","@google-cloud/functions-framework":"^2.1.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","_npmOperationalInternal":{"tmp":"tmp/gcp-iot-provision_0.2.8-dependabot-npm-and-yarn-balena-sdk-16-28-2-d6a3b568c784f156bada381c3aa1fe5dfcb5e24e_1667244685242_0.6517043170805195","host":"s3://npm-registry-packages"},"deprecated":"Deprecated: no longer maintained. The GitHub repository has been archived and no further releases will be published."},"0.2.8-dependabot-npm-and-yarn-balena-sdk-16-28-4-b597d1b00d9af56382041066e2a3057ec7d40d39":{"name":"gcp-iot-provision","version":"0.2.8-dependabot-npm-and-yarn-balena-sdk-16-28-4-b597d1b00d9af56382041066e2a3057ec7d40d39","keywords":["balena","balenaCloud","google","iotcore","iot","gcp"],"author":{"name":"Ken Bannister","email":"ken@balena.io"},"license":"Apache-2.0","_id":"gcp-iot-provision@0.2.8-dependabot-npm-and-yarn-balena-sdk-16-28-4-b597d1b00d9af56382041066e2a3057ec7d40d39","maintainers":[{"name":"balena.io","email":"accounts+npm@balena.io"}],"homepage":"https://github.com/balena-io-examples/gcp-iot-provision","bugs":{"url":"https://github.com/balena-io-examples/gcp-iot-provision/issues"},"dist":{"shasum":"1e01ac7913da39a4dd0fa9ca09c1b4cdfab121a2","tarball":"https://registry.npmjs.org/gcp-iot-provision/-/gcp-iot-provision-0.2.8-dependabot-npm-and-yarn-balena-sdk-16-28-4-b597d1b00d9af56382041066e2a3057ec7d40d39.tgz","fileCount":9,"integrity":"sha512-FMqiT0N0+5wSvktAM2jNsoSfmgHMlSrDNe06DZdQxwSheV954NQ50cwHzd1wJM9BB8XXmz7DFbtVb4WidkgzaQ==","signatures":[{"sig":"MEUCIQDHt/t1gqueYXT+S79VQMzDxmQVM4H6CGReuz2VFGoE4QIgcagDzZIUpSO3dyCRYOL8oM3dLfMegsNAo5OSPZgjG4M=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":137526,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJjaVmgACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2Vmr/TA//WXhKdkwm7AtvycVzwP0TIZ/1syVihftnCMqcs8itfo4EMM2k\r\nX2TjOV/xuJAZ/wqMz5sNGryMetL4ypcj01Y+eD7EDh5Zhk+vvdcKqjeZE8wr\r\nYhRTP0q1XQTs+V3e1tNaVWfRJ3dIVkRBiwChv96hAFktymYnkV2gChRNqpQ3\r\nzeXbZe4XWIcLs8yCchqIUZd9GDv7hdmIbWaSAICq5DvjMxHNa2r1UZ05GxFi\r\n7c2Q6ADGBI39PUiWmnI4RqTWpcU7lO7r3sBca2gu0rn3KvqAx/6bGSUC0ro6\r\n+YAw2tugA4AoZKBj6TXHIljreaprB9TYtqzKyRQ9g15jUiJ7mRSGBVAfZVsX\r\n5nMWHKqahcALWTgUBl4NiJTztU068TKRV+j04d/uimBYWsHjrSbGbOj5tUze\r\nn432N3oq4ARG0++tFhbXHdjEprxDSybj4n2ihAAWKxshxN8DOWmBn8cwOUiU\r\nTcn/2aYS6HuJjndSWrXZYEzV2cTmu3pmgKy0s4iUJIIu5eub5sExYs/w3dVX\r\nGgpj0luP+bEQg0zvAbdy4n239ghOZBXDf/xllrhwBOEChxOxEzwwVykj/g8D\r\nWW9hQq58QG66XLgeip18EWkLVfx6d9Tt5PY2TX+onM2verJYWEyuAMQ/5sdN\r\nF4MkXU2v4QZAWi6giFKOIak1FUw2QdA1cFk=\r\n=fbx+\r\n-----END PGP SIGNATURE-----\r\n"},"main":"index.js","type":"module","readme":"# Google Cloud Function for IoT Device Provisioning\n\nThis Cloud Function allows you to provision and synchronize a balena device with Google Cloud IoT Core in a secure and automated way via an HTTP endpoint. The Cloud Function may be called by a balena device, as seen in the [cloud-relay](https://github.com/balena-io-examples/cloud-relay) example.\n\n| Method | Action |\n|-------------|--------|\n| POST | Provisions a balena device with IoT Core. First the function verifies the device UUID with balenaCloud. Then it creates a public/private key pair and adds the device to the registry. Finally the function sets balena device environment variables for these entities. |\n| DELETE | Removes a balena device from the IoT Core registry and removes the balena device environment variable for the private key. Essentially reverses the actions from provisioning with HTTP POST. |\n\n## Device Environment Variables\nOnce the Cloud function has provisioned the device with GCP, it sets balena device environment variables as described below, which allow the device to connect to IoT Core. Some aspects of the variable values are common across devices, and are collected from the cloud function deployment.\n\n| Variable | Value |\n|----------|-------|\n| GCP_CLIENT_PATH | `<registry-path>/devices/<device-id>`<br><br> `<registry-path>` is derived from the project ID, GCP region, and registry ID<br>`<device-id>` is derived from the balena UUID for the device |\n| GCP_DATA_TOPIC_ROOT | `/devices/<device-id>` |\n| GCP_PROJECT_ID | Google Cloud project ID |\n| GCP_PRIVATE_KEY | Private key in PEM format, base64 encoded to eliminate line wrapping |\n\n\n## Setup and Testing\n### GCP setup\nThe Cloud Function interacts with Google Cloud IoT Core via client code operating with service account credentials. You must setup a Google Cloud project with an IoT Core registry. The service account must have the *Cloud IoT Provisioner* role to manage device records in the IoT Core registry. See the IoT Core [documentation](https://cloud.google.com/iot/docs/how-tos) for more background.\n\n### Workspace setup\nClone this repo\n```\n$ git clone https://github.com/balena-io-examples/gcp-iot-provision\n```\n\nThe sections below show how to test the Cloud Function on a local test server and deploy to Cloud Functions. In either case you must provide the environment variables in the table below as instructed for the test/deployment.\n\n| Key         |    Value    |\n|-------------|-------------|\n| BALENA_API_KEY | for use of balena API; found in balenaCloud dashboard at: `account -> Preferences -> Access tokens` |\n| GCP_PROJECT_ID | Google Cloud project ID, like `my-project-000000`|\n| GCP_REGION | Google Cloud region for registry, like `us-central1` |\n| GCP_REGISTRY_ID | Google Cloud registry ID you provided to create the registry |\n| GCP_SERVICE_ACCOUNT |base64 encoding of the JSON formatted GCP service account credentials provided by Google when you created the service account. Example below, assuming the credentials JSON is contained in a file.<br><br>`cat <credentials.txt> \\| base64 -w 0` |\n\n### HTTP API\nThe HTTP endpoint expects a request containing a JSON body with the attributes below. Use POST to add a device to the cloud registry, DELETE to remove.\n\n| Attribute | Value |\n|-----------|-------|\n| uuid | UUID of device  |\n| balena_service | (optional) Name of service container on balena device that uses provisioned key and certificate, for example `cloud-relay`. If defined, creates service level variables; otherwise creates device level variables. Service level variables are more secure. |\n\n\n### Test locally\nThe Google Functions Framework is a convenient tool for local testing. \nFirst, start a local HTTP server ([docs reference](https://cloud.google.com/functions/docs/running/function-frameworks)) using a script like below.\n\n```\nexport BALENA_API_KEY=<...>\n... <other environment variables from table above>\nexport GCP_SERVICE_ACCOUNT=<...>\n\nnpx @google-cloud/functions-framework --target=provision\n```\n\nNext, use `curl` to send an HTTP request to the local server to provision a device. See the *HTTP API* section above for body contents.\n\n```\ncurl -X POST http://localhost:8080 -H \"Content-Type:application/json\" \\\n   -d '{ \"uuid\": \"<device-uuid>\", \"balena_service\": \"<service-name>\" }'\n```\n\nAfter a successful POST, you should see the device appear in your IoT Core registry and `GCP_CLIENT_PATH`, `GCP_DATA_TOPIC_ROOT`, `GCP_PRIVATE_KEY`, and `GCP_PROJECT_ID` variables appear in balenaCloud for the device. After a successful DELETE, those variables disappear.\n\n## Deploy\nTo deploy to Cloud Functions, use the command below. See the [command documentation](https://cloud.google.com/sdk/gcloud/reference/functions/deploy) for the format of `yaml-file`, which contains the variables from the table in the *Development setup* section above.\n\n```\ngcloud functions deploy provision --runtime=nodejs14 --trigger-http \\\n   --env-vars-file=<yaml-file> --allow-unauthenticated \\\n   --service-account=<name>@<xxxx>.iam.gserviceaccount.com\n```\n\nThe result is a Cloud Function like below. Notice the `TRIGGER` tab, which provides the URL for the function.\n\n![Alt text](docs/cloud-function.png)\n\n### Test the Cloud Function\nTo test the function, use a command like below, where the URL is from the `TRIGGER` tab in the console. See the *HTTP API* section above for body contents.\n\n```\ncurl -X POST https://<region>-<projectID>.cloudfunctions.net/provision \\\n   -H \"Content-Type:application/json\" \\\n   -d '{ \"uuid\": \"<device-uuid>\", \"balena_service\": \"<service-name>\" }'\n```\n\nAfter a successful POST, you should see the device appear in your IoT Core registry and `GCP_CLIENT_PATH`, `GCP_DATA_TOPIC_ROOT`, `GCP_PRIVATE_KEY`, and `GCP_PROJECT_ID` variables appear in balenaCloud for the device. After a successful DELETE, those variables disappear.\n","gitHead":"b597d1b00d9af56382041066e2a3057ec7d40d39","private":false,"scripts":{"test":"echo \"No tests yet\" && exit 0","start":"node index.js"},"_npmUser":{"name":"balena.io","email":"accounts+npm@balena.io"},"repository":{"url":"git+https://github.com/balena-io-examples/gcp-iot-provision.git","type":"git"},"versionist":{"publishedAt":"2022-11-07T19:06:29.803Z"},"_npmVersion":"6.14.17","description":"Google Cloud function to provision a balena device to IoT Core","directories":{},"_nodeVersion":"14.19.3","dependencies":{"balena-sdk":"^16.11.2","@google-cloud/iot":"^2.5.0","@google-cloud/functions-framework":"^2.1.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","_npmOperationalInternal":{"tmp":"tmp/gcp-iot-provision_0.2.8-dependabot-npm-and-yarn-balena-sdk-16-28-4-b597d1b00d9af56382041066e2a3057ec7d40d39_1667848608327_0.12785178117231588","host":"s3://npm-registry-packages"},"deprecated":"Deprecated: no longer maintained. The GitHub repository has been archived and no further releases will be published."}},"time":{"created":"2022-05-17T02:03:44.251Z","modified":"2026-01-29T10:55:01.420Z","0.1.0-use-api-key-70d014cd051671eac1c011b18a253b19833cfcec":"2022-05-17T02:03:44.486Z","0.1.0-use-api-key-34f0049bb856d6d788486d4b02becdba46778294":"2022-05-17T02:11:06.972Z","0.2.0-dependabot-npm-and-yarn-minimist-1-2-6-6fcb6912765eed66678f8ffdba8110051bb65533":"2022-05-17T13:49:10.745Z","0.2.0-dependabot-npm-and-yarn-moment-2-29-3-7c3bbbe07a24ed25ea7bd0a512b3c8beefc0b42b":"2022-05-17T15:02:59.779Z","0.2.0-dependabot-npm-and-yarn-node-forge-1-3-1-34801fadbe6449712929c65e58bef087ddfdee49":"2022-05-17T15:03:24.611Z","0.2.0-dependabot-automation-bd10fbdcd31aed687926e3c7a678772e985af583":"2022-05-17T15:06:21.265Z","0.2.0":"2022-05-17T15:23:11.482Z","0.2.1-fix-dependabot-location-19e04aee08846ffec9536de7216601c0ffa9f4ee":"2022-05-17T16:36:37.900Z","0.2.1":"2022-05-17T16:42:30.959Z","0.2.2-dependabot-npm-and-yarn-minimist-1-2-6-3f850e85b59a5f8fe4b98e32af8d035b9f50feb3":"2022-05-17T20:27:13.207Z","0.2.2":"2022-05-17T20:37:01.638Z","0.2.3-dependabot-npm-and-yarn-moment-2-29-3-312b699e0064649a3f286f6e9d7cb837dff38aec":"2022-05-17T20:58:48.515Z","0.2.3":"2022-05-17T21:10:46.404Z","0.2.4-dependabot-npm-and-yarn-node-forge-1-3-1-fd3e783334351dec8d893cca0a52c4f4dfe7ac8d":"2022-05-17T21:21:31.205Z","0.2.4":"2022-05-17T21:41:04.212Z","0.2.4-dependabot-npm-and-yarn-google-cloud-functions-framework-3-1-1-dfef560917c4cb151a248258f92139ac736490d8":"2022-05-17T21:55:27.592Z","0.2.5-dependabot-npm-and-yarn-google-cloud-functions-framework-3-1-1-58e990e8530b0be79dfa036fad30318197590f7e":"2022-05-23T19:44:05.266Z","0.2.5-dependabot-npm-and-yarn-google-cloud-functions-framework-3-1-2-bc00a4e5900a2ca4dfd837ecb084b4e76c2b466b":"2022-06-06T19:45:32.146Z","0.2.5-dependabot-npm-and-yarn-balena-sdk-16-22-0-14f427b32bf2be89722d613ff25928d178d92c0f":"2022-06-13T20:35:31.976Z","0.2.5-doc-device-env-vars-fd750c9be0194b58d91e32531fb6768cfbbc623a":"2022-06-23T13:55:32.637Z","0.2.5":"2022-06-23T14:26:00.645Z","0.2.6-dependabot-npm-and-yarn-balena-sdk-16-22-0-0a2d6fd35c83a2cb526ba1dd48ba26640cb79e4b":"2022-06-27T20:45:24.423Z","0.2.6-uniform-readme-sections-5716c780868f8f33d9ba0275b116a9434b40526d":"2022-07-02T14:10:09.067Z","0.2.6":"2022-07-02T14:14:52.426Z","0.2.7-dependabot-npm-and-yarn-balena-sdk-16-22-0-bad5e68351a454284dd7f5fc02bbb30702cb852c":"2022-07-04T19:41:25.187Z","0.2.7-dependabot-npm-and-yarn-balena-sdk-16-24-0-cee7aefb76ac8e6f577cb7f15a1c276bb190f803":"2022-07-11T21:37:42.502Z","0.2.7-add-repo-yml-0f09d42662b1a0426f0a64d4c53ea9fe36c12e43":"2022-07-14T22:47:31.554Z","0.2.7":"2022-07-15T10:00:46.417Z","0.2.8-dependabot-npm-and-yarn-moment-2-29-4-3c89a9bfdd6cd07673085dda5660f43122540b27":"2022-07-15T10:05:47.376Z","0.2.8-dependabot-npm-and-yarn-balena-sdk-16-24-0-e479ec99c7493b1767876aace931060e2ba779d1":"2022-07-18T22:05:51.369Z","0.2.8-dependabot-npm-and-yarn-balena-sdk-16-24-1-7c665096990208ee780836fc66c3f427b58842b3":"2022-07-25T19:44:34.050Z","0.2.8-dependabot-npm-and-yarn-balena-sdk-16-25-1-7b00e089f16c793d9a6f0c297bf551174dc5d257":"2022-08-08T19:30:22.705Z","0.2.8-dependabot-npm-and-yarn-balena-sdk-16-26-1-74dae0779fde7dd493a3edb773c03dac8363a525":"2022-08-29T19:34:47.021Z","0.2.8-dependabot-npm-and-yarn-balena-sdk-16-26-2-ed8fde2922e091a06e196673eb570786e6750e66":"2022-09-12T19:39:40.567Z","0.2.8-dependabot-npm-and-yarn-balena-sdk-16-26-5-7bbc0e6ee003cee970259a7e257cc03566a8114d":"2022-09-26T19:33:33.220Z","0.2.8-dependabot-npm-and-yarn-balena-sdk-16-27-0-cb71ef781b6efb37aaefa3eb61a4c20341d06eb6":"2022-10-10T19:54:55.311Z","0.2.8-dependabot-npm-and-yarn-balena-sdk-16-28-1-019ea09d1b26e78a3bdac40d7eb6aa83bfd0e5c3":"2022-10-17T19:35:53.422Z","0.2.8-dependabot-npm-and-yarn-balena-sdk-16-28-2-d6a3b568c784f156bada381c3aa1fe5dfcb5e24e":"2022-10-31T19:31:25.393Z","0.2.8-dependabot-npm-and-yarn-balena-sdk-16-28-4-b597d1b00d9af56382041066e2a3057ec7d40d39":"2022-11-07T19:16:48.602Z"},"bugs":{"url":"https://github.com/balena-io-examples/gcp-iot-provision/issues"},"author":{"name":"Ken Bannister","email":"ken@balena.io"},"license":"Apache-2.0","homepage":"https://github.com/balena-io-examples/gcp-iot-provision","keywords":["balena","balenaCloud","google","iotcore","iot","gcp"],"repository":{"url":"git+https://github.com/balena-io-examples/gcp-iot-provision.git","type":"git"},"description":"Google Cloud function to provision a balena device to IoT Core","maintainers":[{"name":"balena.io","email":"accounts+npm@balena.io"}],"readme":"","readmeFilename":""}