Skip to content

Commit

Permalink
Use managed identity for end-to-end tests (#617)
Browse files Browse the repository at this point in the history
This change upgrades the scheduled and manual end-to-end test workflows and scripts to login to Azure CLI using a managed identity that has been installed on the customer runner VMs. It eliminates the need to generate a app secret and store it in the workflow.

To test, I ran the manual workflow with these changes and confirmed that it can still create Azure resources.
  • Loading branch information
damonbarry authored Jun 11, 2024
1 parent 40ba4e9 commit c1b3dda
Show file tree
Hide file tree
Showing 5 changed files with 10 additions and 72 deletions.
15 changes: 0 additions & 15 deletions .github/workflows/e2e-tests-manual.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,6 @@ jobs:
env:
BRANCH: "${{ github.event.inputs.branch }}"

AZURE_TENANT_ID: "${{ secrets.AZURE_TENANT_ID }}"
AZURE_USERNAME: "${{ secrets.AZURE_USERNAME }}"
AZURE_PASSWORD: "${{ secrets.AZURE_PASSWORD }}"
AZURE_RESOURCE_GROUP_NAME: "${{ secrets.AZURE_RESOURCE_GROUP_NAME }}"
AZURE_LOCATION: "${{ secrets.AZURE_LOCATION }}"

Expand Down Expand Up @@ -81,9 +78,6 @@ jobs:

OS: "${{ matrix.os }}"

AZURE_TENANT_ID: "${{ secrets.AZURE_TENANT_ID }}"
AZURE_USERNAME: "${{ secrets.AZURE_USERNAME }}"
AZURE_PASSWORD: "${{ secrets.AZURE_PASSWORD }}"
AZURE_RESOURCE_GROUP_NAME: "${{ secrets.AZURE_RESOURCE_GROUP_NAME }}"
AZURE_LOCATION: "${{ secrets.AZURE_LOCATION }}"

Expand All @@ -99,9 +93,6 @@ jobs:

OS: "${{ matrix.os }}"

AZURE_TENANT_ID: "${{ secrets.AZURE_TENANT_ID }}"
AZURE_USERNAME: "${{ secrets.AZURE_USERNAME }}"
AZURE_PASSWORD: "${{ secrets.AZURE_PASSWORD }}"
AZURE_RESOURCE_GROUP_NAME: "${{ secrets.AZURE_RESOURCE_GROUP_NAME }}"
AZURE_LOCATION: "${{ secrets.AZURE_LOCATION }}"

Expand All @@ -125,9 +116,6 @@ jobs:
env:
BRANCH: "${{ github.event.inputs.branch }}"

AZURE_TENANT_ID: "${{ secrets.AZURE_TENANT_ID }}"
AZURE_USERNAME: "${{ secrets.AZURE_USERNAME }}"
AZURE_PASSWORD: "${{ secrets.AZURE_PASSWORD }}"
AZURE_RESOURCE_GROUP_NAME: "${{ secrets.AZURE_RESOURCE_GROUP_NAME }}"
AZURE_LOCATION: "${{ secrets.AZURE_LOCATION }}"

Expand All @@ -152,8 +140,5 @@ jobs:
env:
BRANCH: "${{ github.event.inputs.branch }}"

AZURE_TENANT_ID: "${{ secrets.AZURE_TENANT_ID }}"
AZURE_USERNAME: "${{ secrets.AZURE_USERNAME }}"
AZURE_PASSWORD: "${{ secrets.AZURE_PASSWORD }}"
AZURE_RESOURCE_GROUP_NAME: "${{ secrets.AZURE_RESOURCE_GROUP_NAME }}"
AZURE_LOCATION: "${{ secrets.AZURE_LOCATION }}"
15 changes: 0 additions & 15 deletions .github/workflows/e2e-tests-scheduled.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,6 @@ jobs:
env:
BRANCH: "${{ matrix.branch }}"

AZURE_TENANT_ID: "${{ secrets.AZURE_TENANT_ID }}"
AZURE_USERNAME: "${{ secrets.AZURE_USERNAME }}"
AZURE_PASSWORD: "${{ secrets.AZURE_PASSWORD }}"
AZURE_RESOURCE_GROUP_NAME: "${{ secrets.AZURE_RESOURCE_GROUP_NAME }}"
AZURE_LOCATION: "${{ secrets.AZURE_LOCATION }}"

Expand Down Expand Up @@ -110,9 +107,6 @@ jobs:

OS: "${{ matrix.os }}"

AZURE_TENANT_ID: "${{ secrets.AZURE_TENANT_ID }}"
AZURE_USERNAME: "${{ secrets.AZURE_USERNAME }}"
AZURE_PASSWORD: "${{ secrets.AZURE_PASSWORD }}"
AZURE_RESOURCE_GROUP_NAME: "${{ secrets.AZURE_RESOURCE_GROUP_NAME }}"
AZURE_LOCATION: "${{ secrets.AZURE_LOCATION }}"

Expand All @@ -128,9 +122,6 @@ jobs:

OS: "${{ matrix.os }}"

AZURE_TENANT_ID: "${{ secrets.AZURE_TENANT_ID }}"
AZURE_USERNAME: "${{ secrets.AZURE_USERNAME }}"
AZURE_PASSWORD: "${{ secrets.AZURE_PASSWORD }}"
AZURE_RESOURCE_GROUP_NAME: "${{ secrets.AZURE_RESOURCE_GROUP_NAME }}"
AZURE_LOCATION: "${{ secrets.AZURE_LOCATION }}"

Expand Down Expand Up @@ -164,9 +155,6 @@ jobs:
env:
BRANCH: "${{ matrix.branch }}"

AZURE_TENANT_ID: "${{ secrets.AZURE_TENANT_ID }}"
AZURE_USERNAME: "${{ secrets.AZURE_USERNAME }}"
AZURE_PASSWORD: "${{ secrets.AZURE_PASSWORD }}"
AZURE_RESOURCE_GROUP_NAME: "${{ secrets.AZURE_RESOURCE_GROUP_NAME }}"
AZURE_LOCATION: "${{ secrets.AZURE_LOCATION }}"

Expand Down Expand Up @@ -201,8 +189,5 @@ jobs:
env:
BRANCH: "${{ matrix.branch }}"

AZURE_TENANT_ID: "${{ secrets.AZURE_TENANT_ID }}"
AZURE_USERNAME: "${{ secrets.AZURE_USERNAME }}"
AZURE_PASSWORD: "${{ secrets.AZURE_PASSWORD }}"
AZURE_RESOURCE_GROUP_NAME: "${{ secrets.AZURE_RESOURCE_GROUP_NAME }}"
AZURE_LOCATION: "${{ secrets.AZURE_LOCATION }}"
5 changes: 1 addition & 4 deletions ci/e2e-tests/az-login.sh
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,7 @@ echo 'Installed and updated azure-iot extension' >&2


echo 'Logging in to Azure...' >&2
>/dev/null az login --service-principal \
--tenant "$AZURE_TENANT_ID" \
--username "$AZURE_USERNAME" \
"--password=$AZURE_PASSWORD"
>/dev/null az login --identity
echo 'Logged in to Azure' >&2

if [ -n "${AZURE_LOCATION:-}" ]; then
Expand Down
15 changes: 0 additions & 15 deletions ci/e2e-tests/suite-common.sh
Original file line number Diff line number Diff line change
@@ -1,21 +1,6 @@
#!/bin/bash


# Test required variables early to avoid downloading the artifact unnecessarily.
if [ -z "${AZURE_TENANT_ID:-}" ]; then
echo 'AZURE_TENANT_ID not set' >&2
exit 1
fi
if [ -z "${AZURE_USERNAME:-}" ]; then
echo 'AZURE_USERNAME not set' >&2
exit 1
fi
if [ -z "${AZURE_PASSWORD:-}" ]; then
echo 'AZURE_PASSWORD not set' >&2
exit 1
fi


# Suite ID. Used as resource tag for all Azure resources created in this suite.
suite_id="${BRANCH:-unknown}:$GITHUB_RUN_ID:$GITHUB_RUN_NUMBER"
echo "suite_id: $suite_id" >&2
Expand Down
32 changes: 9 additions & 23 deletions docs-dev/e2e-tests.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,39 +15,34 @@ Put all together, there are three ways to run the script:

### `e2e-tests-scheduled.yaml` and `e2e-tests-manual.yaml`

The workflows use an Azure service principal and an Azure resource group that the principal must be able to create resources under.
The workflows use an Azure managed identity and an Azure resource group that the identity must be able to create resources under.

```sh
AZURE_ACCOUNT="$(az account show)"
AZURE_SUBSCRIPTION_ID="$(<<< "$AZURE_ACCOUNT" jq --raw-output '.id')"

AZURE_RESOURCE_GROUP_NAME='iot-identity-service-e2e-tests'
AZURE_SP_NAME="http://iot-identity-service-e2e-tests"
AZURE_SP_NAME='iot-identity-service-e2e-tests'

# The location of the resource group as well as resources created in the group.
AZURE_LOCATION='...'

az group create --name "$AZURE_RESOURCE_GROUP_NAME" --location "$AZURE_LOCATION"

AZURE_SP=$(az ad sp create-for-rbac --name "$AZURE_SP_NAME" --skip-assignment)

# Save the output of this command. It contains the password for the SP
# which cannot be obtained later.
echo "$AZURE_SP"

AZURE_SP_ID="$(<<< "$AZURE_SP" jq --raw-output '.appId')"
# The GitHub runner used in the workflows must be assigned the managed identity created in this step
AZURE_SP_ID=$(az identity create \
--name "$AZURE_SP_NAME" \
--resource-group "$AZURE_RESOURCE_GROUP_NAME" \
--location "$AZURE_LOCATION" | jq --raw-output '.principalId')

az role assignment create \
--assignee "$AZURE_SP_ID" \
--role 'Contributor' \
--scope "/subscriptions/$AZURE_SUBSCRIPTION_ID/resourceGroups/$AZURE_RESOURCE_GROUP_NAME"
```

Next, the identity of this SP and the name of this resource group must be set in GitHub secrets on the repo:
Next, the name of this resource group must be set in GitHub secrets on the repo:

- `AZURE_TENANT_ID`: The `tenant` property from the `az ad sp create-for-rbac` output.
- `AZURE_USERNAME`: The `appId` property from the `az ad sp create-for-rbac` output.
- `AZURE_PASSWORD`: The `password` property from the `az ad sp create-for-rbac` output.
- `AZURE_RESOURCE_GROUP_NAME`: The `AZURE_RESOURCE_GROUP_NAME` variable in the script.
- `AZURE_LOCATION`: The `AZURE_LOCATION` variable in the script. Note that this can be changed afterwards to start putting the resources in a different location instead of the resource group's location. (The location of a resource group is just a default for new resources.)

Expand All @@ -58,7 +53,7 @@ Note that the `e2e-tests-scheduled.yaml` workflow only runs in the main `Azure/i

### Running the script locally

This requires you to have your own Azure subscription. Follow the same steps as the section above to create a resource group and service principal, except for creating GitHub secrets.
This requires you to have your own Azure subscription and an Azure VM to run the tests from. Follow the same steps as the section above to create a resource group and managed identity, except for creating GitHub secrets. Assign the managed identity to the VM.

If you've never created an IoT Hub under your subscription, you'll need to register the `Microsoft.Devices` Resource Provider. (Make sure to do this while logged in as yourself, not when logged in as the SP, because the SP won't have permissions to do this.)

Expand All @@ -79,15 +74,6 @@ Set some more env vars for the parameters of the tests, then run the script.
```sh
cd ~/src/iot-identity-service

# The `tenant` property from the `az ad sp create-for-rbac` output.
export AZURE_TENANT_ID='...'

# The `appId` property from the `az ad sp create-for-rbac` output.
export AZURE_USERNAME='...'

# The `password` property from the `az ad sp create-for-rbac` output.
export AZURE_PASSWORD='...'

# Already defined in the setup script.
export AZURE_RESOURCE_GROUP_NAME

Expand Down

0 comments on commit c1b3dda

Please sign in to comment.