Skip to content

Commit 66fc5f2

Browse files
authored
Merge pull request #221356 from kgremban/dec9-dpsgitops
New tutorial for github actions
2 parents 3aa4915 + 1937b20 commit 66fc5f2

File tree

4 files changed

+343
-0
lines changed

4 files changed

+343
-0
lines changed
35.6 KB
Loading
12.9 KB
Loading

articles/iot-dps/toc.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,8 @@ items:
5050
href: tutorial-custom-allocation-policies.md
5151
- name: Provision for geolatency
5252
href: how-to-provision-multitenant.md
53+
- name: Automate provisioning with GitHub Actions
54+
href: tutorial-automation-github-actions.md
5355
- name: Concepts
5456
items:
5557
- name: DPS terminology
Lines changed: 341 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,341 @@
1+
---
2+
title: GitOps for Azure Device Provisioning Service
3+
description: Tutorial - Use GitHub Actions to automate the steps for creating and managing Azure Device Provisioning Service (DPS) resources
4+
author: kgremban
5+
ms.author: kgremban
6+
manager: lizross
7+
ms.date: 12/19/2022
8+
ms.topic: tutorial
9+
ms.service: iot-dps
10+
services: iot-dps
11+
ms.custom: mvc
12+
---
13+
14+
# Tutorial: Automate Azure Device Provisioning Service with GitHub Actions
15+
16+
Use automation tools like GitHub Actions to manage your IoT device lifecycle. This tutorial demonstrates a GitHub Actions workflow that connects a device to an IoT hub using Azure Device Provisioning Service (DPS).
17+
18+
In this tutorial, you learn how to:
19+
20+
> [!div class="checklist"]
21+
>
22+
> * Save authentication credentials as repository secrets.
23+
> * Create a workflow to provision IoT Hub and Device Provisioning Service resources.
24+
> * Run the workflow and monitor a simulated device as it connects to IoT Hub.
25+
26+
## Prerequisites
27+
28+
* An Azure subscription
29+
30+
If you don't have an Azure subscription, create a [free account](https://azure.microsoft.com/free/?ref=microsoft.com&utm_source=microsoft.com&utm_medium=docs&utm_campaign=visualstudio) before you begin.
31+
32+
* The Azure CLI
33+
34+
* Use the Bash environment in [Azure Cloud Shell](../cloud-shell/quickstart.md).
35+
[![Launch Cloud Shell in a new window](../../includes/media/cloud-shell-try-it/hdi-launch-cloud-shell.png)](https://shell.azure.com)
36+
* Or, If you prefer to run CLI reference commands locally, [install](/cli/azure/install-azure-cli) the Azure CLI. If you're running on Windows or macOS, consider [running Azure CLI in a Docker container](/cli/azure/run-azure-cli-docker).
37+
38+
* If you're using a local installation, sign in to the Azure CLI by using the [az login](/cli/azure/reference-index#az-login) command.
39+
40+
* Run [az version](/cli/azure/reference-index?#az-version) to find the version and dependent libraries that are installed. To upgrade to the latest version, run [az upgrade](/cli/azure/reference-index?#az-upgrade).
41+
42+
* A GitHub account with either a repository that you own or a repository where you have admin access. For more information, see [Get started with GitHub](https://docs.github.com/en/get-started).
43+
44+
## 1 - Create repository secrets
45+
46+
The workflow that you will define in the next section requires access to your Azure subscription to create and manage resources. You don't want to put that information in an unprotected file where it could be discovered, so instead we'll use repository secrets to store this information but still make it accessible as an environment variable in the workflow. For more information, see [Encrypted secrets](https://docs.github.com/actions/security-guides/encrypted-secrets).
47+
48+
Only repository owners and admins can manage repository secrets.
49+
50+
### Create a service principal
51+
52+
Rather than providing your personal access credentials, we'll create a service principal and then add those credentials as repository secrets. Use the Azure CLI to create a new service principal. For more information, see [Create an Azure service principal](/cli/azure/create-an-azure-service-principal-azure-cli).
53+
54+
The following command creates a service principal with *contributor* access to a specific resource group. Replace **<SUBSCRIPTION_ID>** and **<RESOURCE_GROUP_NAME>** with your own information.
55+
56+
This command requires owner or user access administrator roles in the subscription.
57+
58+
```azurecli
59+
az ad sp create-for-rbac --name github-actions-sp --role contributor --scopes /subscriptions/<SUBSCRIPTION_ID>/resourceGroups/<RESOURCE_GROUP_NAME>
60+
```
61+
62+
The output for this command includes a generated password for the service principal. Copy this password to use in the next section. You won't be able to access the password again.
63+
64+
### Save service principal credentials as secrets
65+
66+
1. On [GitHub.com](https://github.com), navigate to the **Settings** for your repository.
67+
68+
1. Select **Secrets** from the navigation menu, then select **Actions**.
69+
70+
1. Select **New repository secret**.
71+
72+
1. Create a secret for your service principal ID.
73+
74+
* **Name**: `APP_ID`
75+
* **Secret**: `github-actions-sp`, or the value you used for the service principal name if you used a different value.
76+
77+
1. Select **Add secret**, then select **New repository secret** to add a second secret.
78+
79+
1. Create a secret for your service principal password.
80+
81+
* **Name**: `SECRET`
82+
* **Secret**: Paste the password that you copied from the output of the service principal creation command.
83+
84+
1. Select **Add secret**, then select **New repository secret** to add the final secret.
85+
86+
1. Create a secret for your Azure tenant.
87+
88+
* **Name**: `TENANT`
89+
* **Secret**: Provide your Azure tenant. The value of this argument can either be an .onmicrosoft.com domain or the Azure object ID for the tenant.
90+
91+
1. Select **Add secret**.
92+
93+
## 2 - Create a workflow
94+
95+
A GitHub Actions *workflow* defines the tasks that will run once it's triggered by an *event*. A workflow contains one or more *jobs* which can run in parallel or sequentially. For more information, see [Understanding GitHub Actions](https://docs.github.com/en/actions/learn-github-actions/understanding-github-actions).
96+
97+
For this tutorial, we'll create one workflow that contains jobs for each of the following tasks:
98+
99+
* Provision an IoT Hub instance and a DPS instance.
100+
* Link the IoT Hub and DPS instances to each other.
101+
* Create an individual enrollment on the DPS instance, and register a device to the IoT hub via the DPS enrollment.
102+
* Simulate the device for five minutes and monitor the IoT hub events.
103+
104+
Workflows are YAML files that are located in the `.github/workflows/` directory of a repository.
105+
106+
1. In your GitHub repository, navigate to the **Actions** tab.
107+
1. In the **Actions** pane, select **New workflow**.
108+
1. On the **Choose a workflow page**, you can choose prebuilt templates to use. We're going to create out own workflow for this tutorial, so select **Set up a workflow yourself**.
109+
1. GitHub creates a new workflow file for you. Notice that it's in the `.github/workflows/` directory. Give the new file a meaningful name, like `dps-tutorial.yml`.
110+
1. Add the [name](https://docs.github.com/actions/using-workflows/workflow-syntax-for-github-actions#name) parameter to give your workflow a name.
111+
112+
```yml
113+
name: DPS Tutorial
114+
```
115+
116+
1. Add the [on.workflow_dispatch](https://docs.github.com/actions/using-workflows/workflow-syntax-for-github-actions#onworkflow_dispatchinputs) parameter. The `on` parameter defines when a workflow will run. The `workflow_dispatch` parameter indicates that we want to manually trigger the workflow. With this parameter, we could define `inputs` that would be passed to the workflow at each run, but we won't use those for this tutorial.
117+
118+
```yml
119+
on: workflow_dispatch
120+
```
121+
122+
1. Define the [environment variables](https://docs.github.com/actions/using-workflows/workflow-syntax-for-github-actions#env) for the resources you're creating in the workflow. These variables will be available to all the jobs in the workflow. You can also define environment variables for individual jobs, or for individual steps within jobs.
123+
124+
Replace the placeholder values with your own values. Make sure that you specify the same resource group that the service principal has access to.
125+
126+
```yml
127+
env:
128+
HUB_NAME: <Globally unique IoT hub name>
129+
DPS_NAME: <Desired Device Provisioning Service name>
130+
DEVICE_NAME: <Desired device name>
131+
RESOURCE_GROUP: <Solution resource group where resources will be created>
132+
```
133+
134+
1. Define environment variables for the secrets that you created in the previous section.
135+
136+
```yml
137+
SP_USER: ${{ secrets.APP_ID }}
138+
SP_SECRET: ${{ secrets.SECRET }}
139+
SP_TENANT: ${{ secrets.TENANT }}
140+
```
141+
142+
1. Add the [jobs](https://docs.github.com/actions/using-workflows/workflow-syntax-for-github-actions#jobs) parameter to the workflow file.
143+
144+
```yml
145+
jobs:
146+
```
147+
148+
1. Define the first job for our workflow, which we'll call the `provision` job. This job provisions the IoT Hub and DPS instances.
149+
150+
```yml
151+
provision:
152+
runs-on: ubuntu-latest
153+
steps:
154+
- name: Provision Infra
155+
run: |
156+
az --version
157+
az login --service-principal -u "$SP_USER" -p "$SP_SECRET" --tenant "$SP_TENANT"
158+
az iot hub create -n "$HUB_NAME" -g "$RESOURCE_GROUP"
159+
az iot dps create -n "$DPS_NAME" -g "$RESOURCE_GROUP"
160+
```
161+
162+
1. Define a job to `configure` the DPS and IoT Hub instances. Notice that this job uses the [needs](https://docs.github.com/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idneeds) parameter, which means that the `configure` job won't run until listed job completes its own run successfully.
163+
164+
```yml
165+
configure:
166+
runs-on: ubuntu-latest
167+
needs: provision
168+
steps:
169+
- name: Configure Infra
170+
run: |
171+
az login --service-principal -u "$SP_USER" -p "$SP_SECRET" --tenant "$SP_TENANT"
172+
az iot dps linked-hub create --dps-name "$DPS_NAME" --hub-name "$HUB_NAME"
173+
```
174+
175+
1. Define a job called `register` that will create an individual enrollment and then use that enrollment to register a device to IoT Hub.
176+
177+
```yml
178+
register:
179+
runs-on: ubuntu-latest
180+
needs: configure
181+
steps:
182+
- name: Create enrollment
183+
run: |
184+
az login --service-principal -u "$SP_USER" -p "$SP_SECRET" --tenant "$SP_TENANT"
185+
az extension add --name azure-iot
186+
az iot dps enrollment create -n "$DPS_NAME" --eid "$DEVICE_NAME" --attestation-type symmetrickey --auth-type login
187+
- name: Register device
188+
run: |
189+
az iot device registration create -n "$DPS_NAME" --rid "$DEVICE_NAME" --auth-type login
190+
```
191+
192+
1. Define a job to `simulate` an IoT device that will connect to the IoT hub and send sample telemetry messages.
193+
194+
```yml
195+
simulate:
196+
runs-on: ubuntu-latest
197+
needs: register
198+
steps:
199+
- name: Simulate device
200+
run: |
201+
az login --service-principal -u "$SP_USER" -p "$SP_SECRET" --tenant "$SP_TENANT"
202+
az extension add --name azure-iot
203+
az iot device simulate -n "$HUB_NAME" -d "$DEVICE_NAME"
204+
```
205+
206+
1. Define a job to `monitor` the IoT hub endpoint for events, and watch messages coming in from the simulated device. Notice that the **simulate** and **monitor** jobs both define the **register** job in their `needs` parameter. This configuration means that once the **register** job completes successfully, both these jobs will run in parallel.
207+
208+
```yml
209+
monitor:
210+
runs-on: ubuntu-latest
211+
needs: register
212+
steps:
213+
- name: Monitor d2c telemetry
214+
run: |
215+
az login --service-principal -u "$SP_USER" -p "$SP_SECRET" --tenant "$SP_TENANT"
216+
az extension add --name azure-iot
217+
az iot hub monitor-events -n "$HUB_NAME" -y
218+
```
219+
220+
1. The complete workflow file should look like this example, with your information replacing the placeholder values in the environment variables:
221+
222+
```yml
223+
name: DPS Tutorial
224+
225+
on: workflow_dispatch
226+
227+
env:
228+
HUB_NAME: <Globally unique IoT hub name>
229+
DPS_NAME: <Desired Device Provisioning Service name>
230+
DEVICE_NAME: <Desired device name>
231+
RESOURCE_GROUP: <Solution resource group where resources will be created>
232+
SP_USER: ${{ secrets.APP_ID }}
233+
SP_SECRET: ${{ secrets.SECRET }}
234+
SP_TENANT: ${{ secrets.TENANT }}
235+
236+
jobs:
237+
provision:
238+
runs-on: ubuntu-latest
239+
steps:
240+
- name: Provision Infra
241+
run: |
242+
az --version
243+
az login --service-principal -u "$SP_USER" -p "$SP_SECRET" --tenant "$SP_TENANT"
244+
az iot hub create -n "$HUB_NAME" -g "$RESOURCE_GROUP"
245+
az iot dps create -n "$DPS_NAME" -g "$RESOURCE_GROUP"
246+
configure:
247+
runs-on: ubuntu-latest
248+
needs: provision
249+
steps:
250+
- name: Configure Infra
251+
run: |
252+
az login --service-principal -u "$SP_USER" -p "$SP_SECRET" --tenant "$SP_TENANT"
253+
az iot dps linked-hub create --dps-name "$DPS_NAME" --hub-name "$HUB_NAME"
254+
register:
255+
runs-on: ubuntu-latest
256+
needs: configure
257+
steps:
258+
- name: Create enrollment
259+
run: |
260+
az login --service-principal -u "$SP_USER" -p "$SP_SECRET" --tenant "$SP_TENANT"
261+
az extension add --name azure-iot
262+
az iot dps enrollment create -n "$DPS_NAME" --eid "$DEVICE_NAME" --attestation-type symmetrickey --auth-type login
263+
- name: Register device
264+
run: |
265+
az iot device registration create -n "$DPS_NAME" --rid "$DEVICE_NAME" --auth-type login
266+
simulate:
267+
runs-on: ubuntu-latest
268+
needs: register
269+
steps:
270+
- name: Simulate device
271+
run: |
272+
az login --service-principal -u "$SP_USER" -p "$SP_SECRET" --tenant "$SP_TENANT"
273+
az extension add --name azure-iot
274+
az iot device simulate -n "$HUB_NAME" -d "$DEVICE_NAME"
275+
monitor:
276+
runs-on: ubuntu-latest
277+
needs: register
278+
steps:
279+
- name: Monitor d2c telemetry
280+
run: |
281+
az login --service-principal -u "$SP_USER" -p "$SP_SECRET" --tenant "$SP_TENANT"
282+
az extension add --name azure-iot
283+
az iot hub monitor-events -n "$HUB_NAME" -y
284+
```
285+
286+
1. Save, commit, and push this new file to your GitHub repository.
287+
288+
## 3 - Run the workflow
289+
290+
1. Navigate to the **Actions** tab of your GitHub repository.
291+
292+
1. In the **Actions** pane, select **DPS Tutorial**, which is the name that we defined in the workflow file, then select the **Run workflow** drop-down box.
293+
294+
:::image type="content" source="./media/tutorial-automation-github-actions/run-workflow.png" alt-text="Screenshot of the action tab where you can select a workflow and run it.":::
295+
296+
1. Change the branch if you created your workflow in a branch other than main, then select **Run workflow**.
297+
298+
1. A new workflow run appears in progress. Select the name to view details of the run.
299+
300+
1. In the workflow summary, you can watch as each job begins and completes. Select any job name to view its details. The simulated device job runs for five minutes and sends telemetry to IoT Hub. During this time, select the **simulate** job to watch messages being sent from the device, and the **monitor** job to watch those messages being received by IoT Hub.
301+
302+
1. When all the jobs have completed successfully, you should see green checkmarks by each one.
303+
304+
:::image type="content" source="./media/tutorial-automation-github-actions/workflow-successful.png" alt-text="Screenshot of a successfully completed workflow.":::
305+
306+
## Clean up resources
307+
308+
If you're not going to continue to use these resources created in this tutorial, delete
309+
them with the following steps.
310+
311+
Use the Azure CLI:
312+
313+
1. List the resources in your resource group.
314+
315+
```azurecli
316+
az resource list --resource-group <RESOURCE_GROUP_NAME>
317+
```
318+
319+
1. To delete individual resources, use the resource ID.
320+
321+
```azurecli
322+
az resource delete --resource-group <RESOURCE_GROUP_NAME> --ids <RESOURCE_ID>
323+
```
324+
325+
1. If you want to delete the whole resource group and all resources within it, run the following command:
326+
327+
```azurecli
328+
az group delete --resource-group <RESOURCE_GROUP_NAME>
329+
```
330+
331+
Use the Azure portal:
332+
333+
1. In the [Azure portal](https://portal.azure.com), navigate to the resource group where you created the new resources.
334+
1. You can either delete the entire resource group or select the individual resources that you want to remove, then select **Delete**.
335+
336+
## Next steps
337+
338+
Learn how to provision DPS instances with other automation tools.
339+
340+
> [!div class="nextstepaction"]
341+
> [Set up DPS with Bicep](tutorial-custom-allocation-policies.md)

0 commit comments

Comments
 (0)