Skip to content

Commit a4fa400

Browse files
authored
Merge pull request #185998 from juliakm/users/jukullam/adding-oidc-gha
Adding GitHub authentication to static blog article
2 parents 68a4c56 + ef03e43 commit a4fa400

File tree

1 file changed

+196
-4
lines changed

1 file changed

+196
-4
lines changed

articles/storage/blobs/storage-blobs-static-site-github-actions.md

Lines changed: 196 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ ms.service: storage
66
ms.topic: how-to
77
ms.author: jukullam
88
ms.reviewer: dineshm
9-
ms.date: 11/19/2021
9+
ms.date: 01/24/2022
1010
ms.subservice: blobs
1111
ms.custom: devx-track-javascript, github-actions-azure, devx-track-azurecli
1212

@@ -25,14 +25,17 @@ Get started with [GitHub Actions](https://docs.github.com/en/actions) by using a
2525
An Azure subscription and GitHub account.
2626

2727
- An Azure account with an active subscription. [Create an account for free](https://azure.microsoft.com/free/?WT.mc_id=A261C142F).
28-
- A GitHub repository with your static website code. If you don't have a GitHub account, [sign up for free](https://github.com/join).
28+
- A GitHub repository with your static website code. If you do not have a GitHub account, [sign up for free](https://github.com/join).
2929
- A working static website hosted in Azure Storage. Learn how to [host a static website in Azure Storage](storage-blob-static-website-how-to.md). To follow this example, you should also deploy [Azure CDN](static-website-content-delivery-network.md).
3030

3131
> [!NOTE]
3232
> It's common to use a content delivery network (CDN) to reduce latency to your users around the globe and to reduce the number of transactions to your storage account. Deploying static content to a cloud-based storage service can reduce the need for potentially expensive compute instance. For more information, see [Static Content Hosting pattern](/azure/architecture/patterns/static-content-hosting).
3333
3434
## Generate deployment credentials
3535

36+
37+
# [Service principal](#tab/userlevel)
38+
3639
You can create a [service principal](../../active-directory/develop/app-objects-and-service-principals.md#service-principal-object) with the [az ad sp create-for-rbac](/cli/azure/ad/sp#az_ad_sp_create_for_rbac) command in the [Azure CLI](/cli/azure/). Run this command with [Azure Cloud Shell](https://shell.azure.com/) in the Azure portal or by selecting the **Try it** button.
3740

3841
Replace the placeholder `myStaticSite` with the name of your site hosted in Azure Storage.
@@ -41,7 +44,7 @@ Replace the placeholder `myStaticSite` with the name of your site hosted in Azur
4144
az ad sp create-for-rbac --name {myStaticSite} --role contributor --scopes /subscriptions/{subscription-id}/resourceGroups/{resource-group} --sdk-auth
4245
```
4346

44-
In the example above, replace the placeholders with your subscription ID and resource group name. The output is a JSON object with the role assignment credentials that provide access to your storage account similar to below. Copy this JSON object for later.
47+
In the example, replace the placeholders with your subscription ID and resource group name. The output is a JSON object with the role assignment credentials that provide access to your storage account. Copy this JSON object for later.
4548

4649
```output
4750
{
@@ -56,8 +59,57 @@ In the example above, replace the placeholders with your subscription ID and res
5659
> [!IMPORTANT]
5760
> It is always a good practice to grant minimum access. The scope in the previous example is limited to the specific App Service app and not the entire resource group.
5861
62+
# [OpenID Connect](#tab/openid)
63+
64+
OpenID Connect is an authentication method that uses short-lived tokens. Setting up [OpenID Connect with GitHub Actions](https://docs.github.com/en/actions/deployment/security-hardening-your-deployments/about-security-hardening-with-openid-connect) is more complex process that offers hardened security.
65+
66+
1. If you do not have an existing application, register a [new Active Directory application and service principal that can access resources](../../active-directory/develop/howto-create-service-principal-portal.md). Create the Active Directory application.
67+
68+
```azurecli-interactive
69+
az ad app create --display-name myApp
70+
```
71+
72+
This command will output JSON with an `appId` that is your `client-id`. Save the value to use as the `AZURE_CLIENT_ID` GitHub secret later.
73+
74+
You will use the `objectId` value when creating federated credentials with Graph API and reference it as the `APPLICATION-OBJECT-ID`.
75+
76+
1. Create a service principal. Replace the `$appID` with the appId from your JSON output.
77+
78+
This command generates JSON output with a different `objectId` and will be used in the next step. The new `objectId` is the `assignee-object-id`.
79+
80+
Copy the `appOwnerTenantId` to use as a GitHub secret for `AZURE_TENANT_ID` later.
81+
82+
```azurecli-interactive
83+
az ad sp create --id $appId
84+
```
85+
86+
1. Create a new role assignment by subscription and object. By default, the role assignment will be tied to your default subscription. Replace `$subscriptionId` with your subscription ID and `$assigneeObjectId` with the generated `assignee-object-id`. Learn [how to manage Azure subscriptions with the Azure CLI](/cli/azure/manage-azure-subscriptions-azure-cli).
87+
88+
```azurecli-interactive
89+
az role assignment create --role contributor --subscription $subscriptionId --assignee-object-id $assigneeObjectId --assignee-principal-type ServicePrincipal
90+
```
91+
92+
1. Run the following command to [create a new federated identity credential](/graph/api/application-post-federatedidentitycredentials?view=graph-rest-beta&preserve-view=true) for your active directory application.
93+
94+
* Replace `APPLICATION-OBJECT-ID` with the **objectId (generated while creating app)** for your Active Directory application.
95+
* Set a value for `CREDENTIAL-NAME` to reference later.
96+
* Set the `subject`. The value of this is defined by GitHub depending on your workflow:
97+
* Jobs in your GitHub Actions environment: `repo:< Organization/Repository >:environment:< Name >`
98+
* For Jobs not tied to an environment, include the ref path for branch/tag based on the ref path used for triggering the workflow: `repo:< Organization/Repository >:ref:< ref path>`. For example, `repo:n-username/ node_express:ref:refs/heads/my-branch` or `repo:n-username/ node_express:ref:refs/tags/my-tag`.
99+
* For workflows triggered by a pull request event: `repo:< Organization/Repository >:pull_request`.
100+
101+
```azurecli
102+
az rest --method POST --uri 'https://graph.microsoft.com/beta/applications/<APPLICATION-OBJECT-ID>/federatedIdentityCredentials' --body '{"name":"<CREDENTIAL-NAME>","issuer":"https://token.actions.githubusercontent.com","subject":"repo:organization/repository:ref:refs/heads/main","description":"Testing","audiences":["api://AzureADTokenExchange"]}'
103+
```
104+
105+
To learn how to create a Create an active directory application, service principal, and federated credentials in Azure portal, see [Connect GitHub and Azure](/azure/developer/github/connect-from-azure#use-the-azure-login-action-with-openid-connect).
106+
107+
---
108+
59109
## Configure the GitHub secret
60110
111+
# [Service principal](#tab/userlevel)
112+
61113
1. In [GitHub](https://github.com/), browse your repository.
62114
63115
1. Select **Settings > Secrets > New secret**.
@@ -72,8 +124,32 @@ In the example above, replace the placeholders with your subscription ID and res
72124
creds: ${{ secrets.AZURE_CREDENTIALS }}
73125
```
74126
127+
# [OpenID Connect](#tab/openid)
128+
129+
You need to provide your application's **Client ID**, **Tenant ID**, and **Subscription ID** to the login action. These values can either be provided directly in the workflow or can be stored in GitHub secrets and referenced in your workflow. Saving the values as GitHub secrets is the more secure option.
130+
131+
1. Open your GitHub repository and go to **Settings**.
132+
133+
1. Select **Settings > Secrets > New secret**.
134+
135+
1. Create secrets for `AZURE_CLIENT_ID`, `AZURE_TENANT_ID`, and `AZURE_SUBSCRIPTION_ID`. Use these values from your Active Directory application for your GitHub secrets:
136+
137+
|GitHub Secret | Active Directory Application |
138+
|---------|---------|
139+
|AZURE_CLIENT_ID | Application (client) ID |
140+
|AZURE_TENANT_ID | Directory (tenant) ID |
141+
|AZURE_SUBSCRIPTION_ID | Subscription ID |
142+
143+
1. Save each secret by selecting **Add secret**.
144+
145+
---
146+
147+
75148
## Add your workflow
76149
150+
# [Service principal](#tab/userlevel)
151+
152+
77153
1. Go to **Actions** for your GitHub repository.
78154
79155
:::image type="content" source="media/storage-blob-static-website/storage-blob-github-actions-header.png" alt-text="GitHub actions menu item":::
@@ -90,7 +166,7 @@ In the example above, replace the placeholders with your subscription ID and res
90166
branches: [ main ]
91167
```
92168
93-
1. Rename your workflow `Blob storage website CI` and add the checkout and login actions. These actions will checkout your site code and authenticate with Azure using the `AZURE_CREDENTIALS` GitHub secret you created earlier.
169+
1. Rename your workflow `Blob storage website CI` and add the checkout and login actions. These actions will check out your site code and authenticate with Azure using the `AZURE_CREDENTIALS` GitHub secret you created earlier.
94170
95171
```yaml
96172
name: Blob storage website CI
@@ -160,6 +236,122 @@ In the example above, replace the placeholders with your subscription ID and res
160236
if: always()
161237
```
162238
239+
# [OpenID Connect](#tab/openid)
240+
241+
1. Go to **Actions** for your GitHub repository.
242+
243+
:::image type="content" source="media/storage-blob-static-website/storage-blob-github-actions-header.png" alt-text="GitHub actions menu item":::
244+
245+
1. Select **Set up your workflow yourself**.
246+
247+
1. Delete everything after the `on:` section of your workflow file. For example, your remaining workflow may look like this.
248+
249+
```yaml
250+
name: CI with OpenID Connect
251+
252+
on:
253+
push:
254+
branches: [ main ]
255+
```
256+
257+
1. Add a permissions section.
258+
259+
260+
```yaml
261+
name: CI with OpenID Connect
262+
263+
on:
264+
push:
265+
branches: [ main ]
266+
267+
permissions:
268+
id-token: write
269+
contents: read
270+
```
271+
272+
1. Add checkout and login actions. These actions will check out your site code and authenticate with Azure using the GitHub secrets you created earlier.
273+
274+
```yaml
275+
name: CI with OpenID Connect
276+
277+
on:
278+
push:
279+
branches: [ main ]
280+
281+
permissions:
282+
id-token: write
283+
contents: read
284+
285+
jobs:
286+
build:
287+
runs-on: ubuntu-latest
288+
steps:
289+
- uses: actions/checkout@v2
290+
- uses: azure/login@v1
291+
with:
292+
client-id: ${{ secrets.AZURE_CLIENT_ID }}
293+
tenant-id: ${{ secrets.AZURE_TENANT_ID }}
294+
subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
295+
```
296+
297+
1. Use the Azure CLI action to upload your code to blob storage and to purge your CDN endpoint. For `az storage blob upload-batch`, replace the placeholder with your storage account name. The script will upload to the `$web` container. For `az cdn endpoint purge`, replace the placeholders with your CDN profile name, CDN endpoint name, and resource group. To speed up your CDN purge, you can add the `--no-wait` option to `az cdn endpoint purge`. To enhance security, you can also add the `--account-key` option with your [storage account key](../common/storage-account-keys-manage.md).
298+
299+
```yaml
300+
- name: Upload to blob storage
301+
uses: azure/CLI@v1
302+
with:
303+
inlineScript: |
304+
az storage blob upload-batch --account-name <STORAGE_ACCOUNT_NAME> --auth-mode key -d '$web' -s .
305+
- name: Purge CDN endpoint
306+
uses: azure/CLI@v1
307+
with:
308+
inlineScript: |
309+
az cdn endpoint purge --content-paths "/*" --profile-name "CDN_PROFILE_NAME" --name "CDN_ENDPOINT" --resource-group "RESOURCE_GROUP"
310+
```
311+
312+
1. Complete your workflow by adding an action to logout of Azure. Here is the completed workflow. The file will appear in the `.github/workflows` folder of your repository.
313+
314+
```yaml
315+
name: CI with OpenID Connect
316+
317+
on:
318+
push:
319+
branches: [ main ]
320+
321+
permissions:
322+
id-token: write
323+
contents: read
324+
325+
jobs:
326+
build:
327+
runs-on: ubuntu-latest
328+
steps:
329+
- uses: actions/checkout@v2
330+
- uses: azure/login@v1
331+
with:
332+
client-id: ${{ secrets.AZURE_CLIENT_ID }}
333+
tenant-id: ${{ secrets.AZURE_TENANT_ID }}
334+
subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
335+
336+
- name: Upload to blob storage
337+
uses: azure/CLI@v1
338+
with:
339+
inlineScript: |
340+
az storage blob upload-batch --account-name <STORAGE_ACCOUNT_NAME> --auth-mode key -d '$web' -s .
341+
- name: Purge CDN endpoint
342+
uses: azure/CLI@v1
343+
with:
344+
inlineScript: |
345+
az cdn endpoint purge --content-paths "/*" --profile-name "CDN_PROFILE_NAME" --name "CDN_ENDPOINT" --resource-group "RESOURCE_GROUP"
346+
347+
# Azure logout
348+
- name: logout
349+
run: |
350+
az logout
351+
if: always()
352+
```
353+
---
354+
163355
## Review your deployment
164356
165357
1. Go to **Actions** for your GitHub repository.

0 commit comments

Comments
 (0)