Compare commits

..

58 Commits

Author SHA1 Message Date
Balaga Gayatri
0d0ee46f76 Update README.md 2021-06-21 11:08:59 +05:30
Balaga Gayatri
114a8ef99d Update README.md 2021-06-21 10:19:29 +05:30
Balaga Gayatri
a78820d812 Update README.md 2021-06-21 10:12:12 +05:30
Balaga Gayatri
1a2f091d94 Update README.md 2021-06-17 13:43:45 +05:30
Balaga Gayatri
c590679de3 Merge pull request #116 from Azure/users/balaga-gayatri/defaultlabels
Update defaultLabels.yml
2021-06-03 18:23:36 +05:30
Balaga Gayatri
b6d623b57e Update defaultLabels.yml 2021-06-03 18:20:15 +05:30
Balaga Gayatri
bbbe7da52a Update defaultLabels.yml 2021-06-03 17:18:30 +05:30
Balaga Gayatri
799fd51bc6 Merge pull request #114 from Azure/users/balaga-gayatri/defaultlabels
Create defaultLabels.yml
2021-06-02 12:15:31 +05:30
Balaga Gayatri
a9a1dcd2f7 Create defaultLabels.yml 2021-05-28 16:50:38 +05:30
Kanchan Verma
e7b36a5753 Merge pull request #99 from Azure/users/balaga-gayatri/developer-guidelines
Updated contribution section with the developer guidelines for actions
2021-03-31 10:17:12 +05:30
Balaga Gayatri
7f6ed87d4a Added dev guidance link to the contribution section in readme 2021-03-24 13:00:48 +05:30
Balaga Gayatri
c6b99d2720 Updated contribution section with the developer guidelines for azure actions. 2021-03-22 17:36:23 +05:30
reilem
5de298368f Improved SP creation docs (#96)
* Improved SP creation docs

* Update README.md

Co-authored-by: aksm-ms <58936966+aksm-ms@users.noreply.github.com>
2021-01-22 12:05:08 +05:30
garvitarai
1ab2192eba updating login action reference on ASH sample workflow (#97)
* updating login action reference on ASH sample workflow

* added links to the official microsoft docs tutorial
2021-01-22 10:51:13 +05:30
Arjun Gupta
80970a8c03 Merge pull request #93 from Azure/azuresovereigncloud
GitHub Actions Beta Preview for deploying to Azure Stack Hub
2020-12-31 11:16:51 +05:30
Arjun Gupta
2e97c69135 update readme 2020-12-30 23:11:51 +05:30
Arjun Gupta
a614f3cbd0 add description for all supported clouds 2020-12-30 22:40:50 +05:30
Arjun Gupta
3e306521aa add main.js 2020-12-30 22:14:08 +05:30
Arjun Gupta
56641ce573 remove az login else block. bad merge. + tidy up some code 2020-12-30 22:12:01 +05:30
Arjun Gupta
0d0c4a32af Merge branch 'master' of https://github.com/Azure/login into azuresovereigncloud 2020-12-30 18:30:26 +05:30
garvitarai
14b73ca9b5 Updating instructions to include Azure Stack Hub (#89)
* Updating instructions to include Azure Stack Hub

Added sample work flow for ASH and service principle instructions

* Updating based on PR feedback

- Added a description to environment parameter
- Updated instructions to say "required only for ash" for service principle instructions

Co-authored-by: Amruta Kawade <65217380+AmrutaKawade@users.noreply.github.com>
2020-12-29 14:36:06 +05:30
Arjun Gupta
2e72d699b0 Merge branch 'master' of https://github.com/Azure/login into azuresovereigncloud 2020-12-28 16:44:13 +05:30
Arjun Gupta
ff610a161c add js build files 2020-12-28 16:36:51 +05:30
Arjun Gupta
c72b9ad43b add node_modules to gitignore 2020-12-28 16:36:32 +05:30
Arjun Gupta
9584e50c92 resolve merge conflict attempt #1. 2020-12-28 16:29:52 +05:30
Zainudeen V K
d773655321 Updating azlogin readme (#91)
* Update README.md

* Update README.md

Co-authored-by: Amruta Kawade <65217380+AmrutaKawade@users.noreply.github.com>
2020-12-28 16:21:55 +05:30
Arjun Gupta
de36370b39 remove node modules 2020-12-28 16:08:43 +05:30
Arjun Gupta
bb5ee3d98d comment node_modules from gitignore 2020-12-28 16:07:59 +05:30
Amruta Kawade
aa362ff93f Delete custom.md 2020-12-28 14:51:43 +05:30
Amruta Kawade
80b45a252f Update issue templates 2020-12-28 14:50:50 +05:30
Amruta Kawade
14ff6a1af1 Update issue templates (#92) 2020-12-28 14:44:16 +05:30
Zainudeen V K
4440d80620 PR to include support for Sovereign cloud in azlogin action (#85)
* added support for Azure Gov cloud

* changes to Azure cloud

* az gov cloud changes

* changes as per PR comment

* chnages to include enum and valdiation

* changes to include validation

* changes

* deleted Enums.js

* changes to constant file

* added library of Consts.js

* changes from arary to set

* changes to environment input
2020-12-10 19:13:33 +05:30
aksm-ms
e7b230d17a adding params to escape symbols in az cli (#80)
* adding params to escape symbols in az cli

* addressed review comments
2020-11-06 15:37:06 +05:30
Ganeshrockz
21f0955fe4 Updated readme for allow-no-subscriptions input support (#79)
* Updated readme for no-subscriptions support

* Minor changes

* Updated readme
2020-11-05 12:15:27 +05:30
aksm-ms
45f2ccef11 adding az cli version debug logs (#76) 2020-11-03 17:12:56 +05:30
aksm-ms
3ca410cd24 adding lib 2020-11-03 14:14:40 +05:30
Ganeshrockz
481142a71d Added no subscription support (#73)
* Added no subscription support

* Added L0s

* added no subcriptions login support

* test changes

Co-authored-by: Ganesh S <ganeshs@CBREV-KESTUR.redmond.corp.microsoft.com>
Co-authored-by: aksm-ms <58936966+aksm-ms@users.noreply.github.com>
2020-11-03 13:49:13 +05:30
Noel
fa833a8f44 fix typo (#75) 2020-10-29 10:29:51 +05:30
Usha N
f86425d665 Updating telemetry to remove Hashing of repo name (#66)
* Updating telemetry to remove Hashing of repo name

We have CELA sign off to log user name in telemetry instead of a Hash.. It will also help us map repo names with Azure subscriptions directly.

* Update main.ts

* adding lib/main.js

* adding main.ts

Co-authored-by: Ashish Ranjan <asranja@github.com>
Co-authored-by: aksm-ms <58936966+aksm-ms@users.noreply.github.com>
2020-10-21 10:25:56 +05:30
aksm-ms
8158dc4846 Update README.md (#72) 2020-10-21 09:49:38 +05:30
dependabot[bot]
9eb3db5a71 Bump @actions/core from 1.1.3 to 1.2.6 (#60)
Bumps [@actions/core](https://github.com/actions/toolkit/tree/HEAD/packages/core) from 1.1.3 to 1.2.6.
- [Release notes](https://github.com/actions/toolkit/releases)
- [Changelog](https://github.com/actions/toolkit/blob/main/packages/core/RELEASES.md)
- [Commits](https://github.com/actions/toolkit/commits/HEAD/packages/core)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Amruta Kawade <65217380+AmrutaKawade@users.noreply.github.com>
2020-10-12 14:01:59 +05:30
aksm-ms
498ec10cdf Bump lodash from 4.17.15 to 4.17.19 (#52)
Bumps [lodash](https://github.com/lodash/lodash) from 4.17.15 to 4.17.19.
- [Release notes](https://github.com/lodash/lodash/releases)
- [Commits](https://github.com/lodash/lodash/compare/4.17.15...4.17.19)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Amruta Kawade <65217380+AmrutaKawade@users.noreply.github.com>
2020-10-12 13:59:03 +05:30
Amruta Kawade
c494a29b96 Merge pull request #63 from Azure/AmrutaKawade-patch-1
Create issue-label-bot.yaml
2020-10-06 13:48:27 +05:30
Amruta Kawade
756a6f0316 Create issue-label-bot.yaml 2020-10-06 10:30:41 +05:30
Kraig Brockschmidt
6fc8a38800 Add explanation of az ad sp create-for-rbac (#57)
* Add explanation of az ad sp create-for-rbac
Fulfills an internal Microsoft request to explain what the command is doing.

Also cleans up the readmd a little and add a note about forking a sample repository when applicable.

* Add note on managing service principals

* Update secrets link
2020-09-30 09:25:49 +05:30
Max Held
5dbba71255 fix typo (#58) 2020-09-29 17:47:06 +05:30
Rakesh Kumar
807bb60301 Update build files and add node_modules (#54)
* update build files

* add node_modules
2020-09-23 12:15:33 +05:30
Usha N
8ea3fa2ba0 Merge pull request #53 from garvitarai/AzureStackSupport-Beta
Update README.md
2020-09-23 10:18:31 +05:30
garvitarai
0bf4fdc1f9 Update README.md 2020-09-22 21:32:53 -07:00
Justin Hutchings
7e173d1a14 Add CodeQL security scanning (#35) 2020-09-22 13:33:27 +05:30
garvitarai
ee83f1dbb6 Update README.md 2020-09-21 15:39:12 -07:00
Rakesh Kumar
513cdfa020 login action for azurestack (#41)
* login action for azurestack

* test update for azurestack

* review changes

* review changes v2

* review changes v3
2020-08-28 09:18:43 +05:30
Usha N
604f0eb80b Update README.md 2020-08-26 13:41:07 +05:30
Usha N
e9a9c1efa4 Merge pull request #48 from johnlokerse/patch-1
Updated 'secrets' url in the README
2020-08-25 16:09:32 +05:30
John
45e5e991bf Updated 'secrets' url in the README
Updated the URL regarding the 'secret' docs. The issue was opened here: https://github.com/Azure/login/issues/47.
2020-08-23 16:53:51 +02:00
aksm-ms
91da0d4635 Update ci.yml 2020-07-21 15:17:27 +05:30
aksm-ms
ed39f6a8e2 Update package.json 2020-06-29 10:55:58 +05:30
aksm-ms
b25b548bf8 escaping single quotes (#38) 2020-06-15 14:31:32 +05:30
17 changed files with 718 additions and 277 deletions

View File

@@ -0,0 +1,10 @@
---
name: Bug Report / Feature Request
about: Create a report to help us improve
title: ''
labels: need-to-triage
assignees: ''
---

4
.github/issue-label-bot.yaml vendored Normal file
View File

@@ -0,0 +1,4 @@
label-alias:
bug: 'bug'
feature_request: 'enhancement'
question: 'question'

View File

@@ -12,7 +12,7 @@ jobs:
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
strategy: strategy:
matrix: matrix:
os: [windows-latest, ubuntu-latest, macos-latest] os: [windows-latest, ubuntu-latest]
steps: steps:
- name: 'Checking out repo code' - name: 'Checking out repo code'
@@ -25,4 +25,4 @@ jobs:
- name: 'Run L0 tests' - name: 'Run L0 tests'
run: | run: |
npm run test npm run test

52
.github/workflows/codeql.yml vendored Normal file
View File

@@ -0,0 +1,52 @@
name: "Code scanning - action"
on:
push:
pull_request:
schedule:
- cron: '0 19 * * 0'
jobs:
CodeQL-Build:
# CodeQL runs on ubuntu-latest and windows-latest
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v2
with:
# We must fetch at least the immediate parents so that if this is
# a pull request then we can checkout the head.
fetch-depth: 2
# If this run was triggered by a pull request event, then checkout
# the head of the pull request instead of the merge commit.
- run: git checkout HEAD^2
if: ${{ github.event_name == 'pull_request' }}
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v1
# Override language selection by uncommenting this and choosing your languages
# with:
# languages: go, javascript, csharp, python, cpp, java
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild
uses: github/codeql-action/autobuild@v1
# Command-line programs to run using the OS shell.
# 📚 https://git.io/JvXDl
# ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
# and modify them (or add more) to build your code if your project
# uses a compiled language
#- run: |
# make bootstrap
# make release
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v1

36
.github/workflows/defaultLabels.yml vendored Normal file
View File

@@ -0,0 +1,36 @@
name: setting-default-labels
# Controls when the action will run.
on:
schedule:
- cron: "0 0/3 * * *"
# A workflow run is made up of one or more jobs that can run sequentially or in parallel
jobs:
build:
# The type of runner that the job will run on
runs-on: ubuntu-latest
# Steps represent a sequence of tasks that will be executed as part of the job
steps:
- uses: actions/stale@v3
name: Setting issue as idle
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
stale-issue-message: 'This issue is idle because it has been open for 14 days with no activity.'
stale-issue-label: 'idle'
days-before-stale: 14
days-before-close: -1
operations-per-run: 100
exempt-issue-labels: 'backlog'
- uses: actions/stale@v3
name: Setting PR as idle
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
stale-pr-message: 'This PR is idle because it has been open for 14 days with no activity.'
stale-pr-label: 'idle'
days-before-stale: 14
days-before-close: -1
operations-per-run: 100

400
README.md
View File

@@ -1,150 +1,250 @@
# GitHub Actions for deploying to Azure # GitHub Actions for deploying to Azure
## Automate your GitHub workflows using Azure Actions ## Automate your GitHub workflows using Azure Actions
[GitHub Actions](https://help.github.com/en/articles/about-github-actions) gives you the flexibility to build an automated software development lifecycle workflow. [GitHub Actions](https://help.github.com/en/articles/about-github-actions) gives you the flexibility to build an automated software development lifecycle workflow.
With [GitHub Actions for Azure](https://github.com/Azure/actions/) you can create workflows that you can set up in your repository to build, test, package, release and **deploy** to Azure. With [GitHub Actions for Azure](https://github.com/Azure/actions/) you can create workflows that you can set up in your repository to build, test, package, release and **deploy** to Azure.
# GitHub Action for Azure Login NOTE: you must have write permissions to the repository in question. If you're using a sample repository from Microsoft, be sure to first fork the repository to your own GitHub account.
With the Azure login Action, you can automate your workflow to do an Azure login using [Azure service principal](https://docs.microsoft.com/en-us/azure/active-directory/develop/app-objects-and-service-principals) and run Az CLI and Azure PowerShell scripts.
Get started today with a [free Azure account](https://azure.com/free/open-source).
By default, only az cli login will be done. In addition to az cli, you can login using Az module to run Azure PowerShell scripts by setting enable-AzPSSession to true.
# GitHub Action for Azure Login
Get started today with a [free Azure account](https://azure.com/free/open-source)!
With the Azure login Action, you can automate your workflow to do an Azure login using [Azure service principal](https://docs.microsoft.com/azure/active-directory/develop/app-objects-and-service-principals) and run Azure CLI and Azure PowerShell scripts. You can leverage this action for the public or soverign clouds including Azure Government and Azure Stack Hub (using the `environment` parameter).
This repository contains GitHub Action for [Azure Login](https://github.com/Azure/login/blob/master/action.yml).
By default, the action only logs in with the Azure CLI (using the `az login` command). To log in with the Az PowerShell module, set `enable-AzPSSession` to true. To login to Azure tenants without any subscriptions, set the optional parameter `allow-no-subscriptions` to true.
## Sample workflow that uses Azure login action to run az cli
To login into one of the Azure Government clouds, set the optional parameter environment with supported cloud names AzureUSGovernment or AzureChinaCloud. If this parameter is not specified, it takes the default value AzureCloud and connect to the Azure Public Cloud. Additionally the parameter creds takes the Azure service principal created in the particular cloud to connect (Refer to Configure deployment credentials section below for details).
```yaml
This repository contains GitHub Action for [Azure Login](https://github.com/Azure/login/blob/master/action.yml).
# File: .github/workflows/workflow.yml
## Sample workflow that uses Azure login action to run az cli
on: [push]
```yaml
name: AzureLoginSample # File: .github/workflows/workflow.yml
jobs: on: [push]
build-and-deploy: name: AzureLoginSample
runs-on: ubuntu-latest
steps: jobs:
- uses: azure/login@v1.1 build-and-deploy:
with: runs-on: ubuntu-latest
creds: ${{ secrets.AZURE_CREDENTIALS }} steps:
- run: | - uses: azure/login@v1
az webapp list --query "[?state=='Running']" with:
creds: ${{ secrets.AZURE_CREDENTIALS }}
```
- run: |
## Sample workflow that uses Azure login action to run Azure PowerShell az webapp list --query "[?state=='Running']"
```
```yaml
## Sample workflow that uses Azure login action to run Azure PowerShell
# File: .github/workflows/workflow.yml
```yaml
on: [push] # File: .github/workflows/workflow.yml
name: AzurePowerShellSample on: [push]
jobs: name: AzurePowerShellSample
build-and-deploy: jobs:
runs-on: ubuntu-latest
steps: build-and-deploy:
runs-on: ubuntu-latest
- name: Login via Az module steps:
uses: azure/login@v1.1
with: - name: Login via Az module
creds: ${{secrets.AZURE_CREDENTIALS}} uses: azure/login@v1
enable-AzPSSession: true with:
creds: ${{secrets.AZURE_CREDENTIALS}}
- name: Run Az CLI script enable-AzPSSession: true
run: |
az webapp list --query "[?state=='Running']" - name: Run Az CLI script
run: |
- name: Run Azure PowerShell script az webapp list --query "[?state=='Running']"
uses: azure/powershell@v1
with: - name: Run Azure PowerShell script
azPSVersion: '3.1.0' uses: azure/powershell@v1
inlineScript: | with:
Get-AzVM -ResourceGroupName "ActionsDemo" azPSVersion: '3.1.0'
inlineScript: |
Get-AzVM -ResourceGroupName "ActionsDemo"
```
```
## Sample to connect to Azure US Government cloud
Refer [Azure PowerShell](https://github.com/azure/powershell) Github action to run your Azure PowerShell scripts.
```
## Configure deployment credentials: - name: Login to Azure US Gov Cloud with CLI
uses: azure/login@v1
For any credentials like Azure Service Principal, Publish Profile etc add them as [secrets](https://help.github.com/en/articles/virtual-environments-for-github-actions#creating-and-using-secrets-encrypted-variables) in the GitHub repository and then use them in the workflow. with:
creds: ${{ secrets.AZURE_US_GOV_CREDENTIALS }}
The above example uses user-level credentials i.e., Azure Service Principal for deployment. environment: 'AzureUSGovernment'
enable-AzPSSession: false
Follow the steps to configure the secret: - name: Login to Azure US Gov Cloud with Az Powershell
* Define a new secret under your repository settings, Add secret menu uses: azure/login@v1
* Store the output of the below [az cli](https://docs.microsoft.com/en-us/cli/azure/?view=azure-cli-latest) command as the value of secret variable, for example 'AZURE_CREDENTIALS' with:
```bash creds: ${{ secrets.AZURE_US_GOV_CREDENTIALS }}
environment: 'AzureUSGovernment'
az ad sp create-for-rbac --name "myApp" --role contributor \ enable-AzPSSession: true
--scopes /subscriptions/{subscription-id}/resourceGroups/{resource-group} \ ```
--sdk-auth
Refer to the [Azure PowerShell](https://github.com/azure/powershell) Github action to run your Azure PowerShell scripts.
# Replace {subscription-id}, {resource-group} with the subscription, resource group details
## Sample Azure Login workflow that to run az cli on Azure Stack Hub
# The command should output a JSON object similar to this:
```yaml
{
"clientId": "<GUID>", # File: .github/workflows/workflow.yml
"clientSecret": "<GUID>",
"subscriptionId": "<GUID>", on: [push]
"tenantId": "<GUID>",
(...) name: AzureLoginSample
}
jobs:
```
* Now in the workflow file in your branch: `.github/workflows/workflow.yml` replace the secret in Azure login action with your secret (Refer to the example above) build-and-deploy:
runs-on: ubuntu-latest
steps:
# Azure Login metadata file - uses: azure/login@v1
with:
```yaml creds: ${{ secrets.AZURE_CREDENTIALS }}
environment: 'AzureStack'
# action.yml
- run: |
# Login to Azure subscription az webapp list --query "[?state=='Running']"
name: 'Azure Login'
description: 'AuthenticatetoAzureandrunyourAzCLIorAzPowerShellbasedActionsorscripts.github.com/Azure/Actions' ```
inputs: Refer to the [Azure Stack Hub Login Action Tutorial](https://docs.microsoft.com/en-us/azure-stack/user/ci-cd-github-action-login-cli?view=azs-2008) for more detailed instructions.
creds:
description: 'Paste output of `az ad sp create-for-rbac` as value of secret variable: AZURE_CREDENTIALS' ## Configure deployment credentials:
required: true
enable-AzPSSession: The previous sample workflows depend on a [secrets](https://docs.github.com/en/free-pro-team@latest/actions/reference/encrypted-secrets) named `AZURE_CREDENTIALS` in your repository. The value of this secret is expected to be a JSON object that represents a service principal (an identifer for an application or process) that authenticates the workflow with Azure.
description: 'SetthisvaluetotruetoenableAzurePowerShellLogininadditiontoAzCLIlogin'
required: false To function correctly, this service principal must be assigned the [Contributor]((https://docs.microsoft.com/azure/role-based-access-control/built-in-roles#contributor)) role for the web app or the resource group that contains the web app.
default: false
branding: The following steps describe how to create the service principal, assign the role, and create a secret in your repository with the resulting credentials.
icon: 'login.svg'
color: 'blue' 1. Open the Azure Cloud Shell at [https://shell.azure.com](https://shell.azure.com). You can alternately use the [Azure CLI](https://docs.microsoft.com/cli/azure/install-azure-cli?view=azure-cli-latest) if you've installed it locally. (For more information on Cloud Shell, see the [Cloud Shell Overview](https://docs.microsoft.com/azure/cloud-shell/overview).)
runs:
using: 'node12' 1.1 **(Required ONLY when environment is Azure Stack Hub)** Run the following command to set the SQL Management endpoint to 'not supported'
main: 'lib/main.js' ```bash
```
az cloud update -n {environmentName} --endpoint-sql-management https://notsupported
# Contributing
```
This project welcomes contributions and suggestions. Most contributions require you to agree to a
Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us 2. Use the [az ad sp create-for-rbac](https://docs.microsoft.com/cli/azure/ad/sp?view=azure-cli-latest#az_ad_sp_create_for_rbac) command to create a service principal and assign a Contributor role:
the rights to use your contribution. For details, visit https://cla.opensource.microsoft.com.
For web apps (also more secure)
When you submit a pull request, a CLA bot will automatically determine whether you need to provide
a CLA and decorate the PR appropriately (e.g., status check, comment). Simply follow the instructions ```azurecli
provided by the bot. You will only need to do this once across all repos using our CLA. az ad sp create-for-rbac --name "{sp-name}" --sdk-auth --role contributor \
--scopes /subscriptions/{subscription-id}/resourceGroups/{resource-group}/providers/Microsoft.Web/sites/{app-name}
This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). ```
For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or
contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments. For usage with other Azure services (Storage Accounts, Active Directory, etc.)
```azurecli
az ad sp create-for-rbac --name "{sp-name}" --sdk-auth --role contributor \
--scopes /subscriptions/{subscription-id}/resourceGroups/{resource-group}
```
Replace the following:
* `{sp-name}` with a suitable name for your service principal, such as the name of the app itself. The name must be unique within your organization.
* `{subscription-id}` with the subscription ID you want to use (found in Subscriptions in portal)
* `{resource-group}` the resource group containing the web app.
* [optional] `{app-name}` if you wish to have a tighter & more secure scope, use the first option and replace this with the name of the web app.
More info can be found [here](https://docs.microsoft.com/en-us/cli/azure/ad/sp?view=azure-cli-latest#az_ad_sp_create_for_rbac).
This command invokes Azure Active Directory (via the `ad` part of the command) to create a service principal (via `sp`) specifically for [Role-Based Access Control (RBAC)](https://docs.microsoft.com/azure/role-based-access-control/overview) (via `create-for-rbac`).
The `--role` argument specifies the permissions to grant to the service principal at the specified `--scope`. In this case, you grant the built-in [Contributor](https://docs.microsoft.com/azure/role-based-access-control/built-in-roles#contributor) role at the scope of the web app in the specified resource group in the specified subscription. If desired, you can omit the part of the scope starting with `/providers/...` to grant the service principal the Contributor role for the entire resource group. For security purposes, however, it's always preferable to grant permissions at the most restrictive scope possible.
3. When complete, the `az ad sp create-for-rbac` command displays JSON output in the following form (which is specified by the `--sdk-auth` argument):
```json
{
"clientId": "<GUID>",
"clientSecret": "<GUID>",
"subscriptionId": "<GUID>",
"tenantId": "<GUID>",
(...)
}
```
4. In your repository, use **Add secret** to create a new secret named `AZURE_CREDENTIALS` (as shown in the example workflow), or using whatever name is in your workflow file.
NOTE: While adding secret `AZURE_CREDENTIALS` make sure to add like this
{"clientId": "<GUID>",
"clientSecret": "<GUID>",
"subscriptionId": "<GUID>",
"tenantId": "<GUID>",
(...)}
instead of
{
"clientId": "<GUID>",
"clientSecret": "<GUID>",
"subscriptionId": "<GUID>",
"tenantId": "<GUID>",
(...)
}
to prevent unnecessary masking of `{ } ` in your logs which are in dictionary form.
5. Paste the entire JSON object produced by the `az ad sp create-for-rbac` command as the secret value and save the secret.
NOTE: to manage service principals created with `az ad sp create-for-rbac`, visit the [Azure portal](https://portal.azure.com), navigate to your Azure Active Directory, then select **Manage** > **App registrations** on the left-hand menu. Your service principal should appear in the list. Select a principal to navigate to its properties. You can also manage role assignments using the [az role assignment](https://docs.microsoft.com/cli/azure/role/assignment?view=azure-cli-latest) command.
## Support for using `allow-no-subscriptions` flag with az login
Capability has been added to support access to tenants without subscriptions. This can be useful to run tenant level commands, such as `az ad`. The action accepts an optional parameter `allow-no-subscriptions` which is `false` by default.
```yaml
# File: .github/workflows/workflow.yml
on: [push]
name: AzureLoginWithNoSubscriptions
jobs:
build-and-deploy:
runs-on: ubuntu-latest
steps:
- uses: azure/login@v1
with:
creds: ${{ secrets.AZURE_CREDENTIALS }}
allow-no-subscriptions: true
```
## Az logout and security hardening
This action doesn't implement ```az logout``` by default at the end of execution. However there is no way of tampering the credentials or account information because the github hosted runner is on a VM that will get reimaged for every customer run which gets everything deleted. But if the runner is self-hosted which is not github provided it is recommended to manually logout at the end of the workflow as shown below. More details on security of the runners can be found [here](https://docs.github.com/en/actions/learn-github-actions/security-hardening-for-github-actions#hardening-for-self-hosted-runners).
```
- name: Azure CLI script
uses: azure/CLI@v1
with:
azcliversion: 2.0.72
inlineScript: |
az logout
az cache purge
az account clear
```
# Contributing
This project welcomes contributions and suggestions. Most contributions require you to agree to a Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us the rights to use your contribution. For details, visit https://cla.opensource.microsoft.com.
For detailed developer guidelines, visit [developer guidelines for azure actions](https://github.com/Azure/actions/blob/main/docs/developer-guildelines.md).
When you submit a pull request, a CLA bot will automatically determine whether you need to provide a CLA and decorate the PR appropriately (e.g., status check, comment). Simply follow the instructions provided by the bot. You will only need to do this once across all repos using our CLA.
This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments.

View File

@@ -5,7 +5,7 @@ jest.mock('../../src/PowerShell/Utilities/PowerShellToolRunner');
let spnlogin: ServicePrincipalLogin; let spnlogin: ServicePrincipalLogin;
beforeAll(() => { beforeAll(() => {
spnlogin = new ServicePrincipalLogin("servicePrincipalID", "servicePrinicipalkey", "tenantId", "subscriptionId"); spnlogin = new ServicePrincipalLogin("servicePrincipalID", "servicePrinicipalkey", "tenantId", "subscriptionId", false, null, null);
}); });
afterEach(() => { afterEach(() => {

View File

@@ -0,0 +1,25 @@
import ScriptBuilder from "../../../src/PowerShell/Utilities/ScriptBuilder";
import Constants from "../../../src/PowerShell/Constants";
describe("Getting AzLogin PS script" , () => {
const scheme = Constants.ServicePrincipal;
let args: any = {
servicePrincipalId: "service-principal-id",
servicePrincipalKey: "service-principal-key",
environment: "environment",
scopeLevel: Constants.Subscription,
subscriptionId: "subId",
allowNoSubscriptionsLogin: true
}
test("PS script should not set context while passing allowNoSubscriptionsLogin as true", () => {
const loginScript = new ScriptBuilder().getAzPSLoginScript(scheme, "tenant-id", args);
expect(loginScript.includes("Set-AzContext -SubscriptionId")).toBeFalsy();
});
test("PS script should set context while passing allowNoSubscriptionsLogin as false", () => {
args["allowNoSubscriptionsLogin"] = false;
const loginScript = new ScriptBuilder().getAzPSLoginScript(scheme, "tenant-id", args);
expect(loginScript.includes("Set-AzContext -SubscriptionId")).toBeTruthy();
});
});

View File

@@ -9,6 +9,14 @@ inputs:
description: 'SetthisvaluetotruetoenableAzurePowerShellLogininadditiontoAzCLIlogin' description: 'SetthisvaluetotruetoenableAzurePowerShellLogininadditiontoAzCLIlogin'
required: false required: false
default: false default: false
environment:
description: 'Name of the environment. Supported values are azurecloud, azurestack, azureusgovernment, azurechinacloud, azuregermancloud. Default being azurecloud'
required: false
default: AzureCloud
allow-no-subscriptions:
description: 'Setthisvaluetotrueto enable support for accessing tenants without subscriptions'
required: false
default: false
branding: branding:
icon: 'login.svg' icon: 'login.svg'
color: 'blue' color: 'blue'

View File

@@ -25,11 +25,14 @@ const PowerShellToolRunner_1 = __importDefault(require("./Utilities/PowerShellTo
const ScriptBuilder_1 = __importDefault(require("./Utilities/ScriptBuilder")); const ScriptBuilder_1 = __importDefault(require("./Utilities/ScriptBuilder"));
const Constants_1 = __importDefault(require("./Constants")); const Constants_1 = __importDefault(require("./Constants"));
class ServicePrincipalLogin { class ServicePrincipalLogin {
constructor(servicePrincipalId, servicePrincipalKey, tenantId, subscriptionId) { constructor(servicePrincipalId, servicePrincipalKey, tenantId, subscriptionId, allowNoSubscriptionsLogin, environment, resourceManagerEndpointUrl) {
this.servicePrincipalId = servicePrincipalId; this.servicePrincipalId = servicePrincipalId;
this.servicePrincipalKey = servicePrincipalKey; this.servicePrincipalKey = servicePrincipalKey;
this.tenantId = tenantId; this.tenantId = tenantId;
this.subscriptionId = subscriptionId; this.subscriptionId = subscriptionId;
this.environment = environment;
this.resourceManagerEndpointUrl = resourceManagerEndpointUrl;
this.allowNoSubscriptionsLogin = allowNoSubscriptionsLogin;
} }
initialize() { initialize() {
return __awaiter(this, void 0, void 0, function* () { return __awaiter(this, void 0, void 0, function* () {
@@ -53,8 +56,10 @@ class ServicePrincipalLogin {
servicePrincipalId: this.servicePrincipalId, servicePrincipalId: this.servicePrincipalId,
servicePrincipalKey: this.servicePrincipalKey, servicePrincipalKey: this.servicePrincipalKey,
subscriptionId: this.subscriptionId, subscriptionId: this.subscriptionId,
environment: ServicePrincipalLogin.environment, environment: this.environment,
scopeLevel: ServicePrincipalLogin.scopeLevel scopeLevel: ServicePrincipalLogin.scopeLevel,
allowNoSubscriptionsLogin: this.allowNoSubscriptionsLogin,
resourceManagerEndpointUrl: this.resourceManagerEndpointUrl
}; };
const script = new ScriptBuilder_1.default().getAzPSLoginScript(ServicePrincipalLogin.scheme, this.tenantId, args); const script = new ScriptBuilder_1.default().getAzPSLoginScript(ServicePrincipalLogin.scheme, this.tenantId, args);
yield PowerShellToolRunner_1.default.init(); yield PowerShellToolRunner_1.default.init();
@@ -68,6 +73,5 @@ class ServicePrincipalLogin {
} }
} }
exports.ServicePrincipalLogin = ServicePrincipalLogin; exports.ServicePrincipalLogin = ServicePrincipalLogin;
ServicePrincipalLogin.environment = Constants_1.default.AzureCloud;
ServicePrincipalLogin.scopeLevel = Constants_1.default.Subscription; ServicePrincipalLogin.scopeLevel = Constants_1.default.Subscription;
ServicePrincipalLogin.scheme = Constants_1.default.ServicePrincipal; ServicePrincipalLogin.scheme = Constants_1.default.ServicePrincipal;

View File

@@ -20,10 +20,13 @@ class ScriptBuilder {
let command = `Clear-AzContext -Scope Process; let command = `Clear-AzContext -Scope Process;
Clear-AzContext -Scope CurrentUser -Force -ErrorAction SilentlyContinue;`; Clear-AzContext -Scope CurrentUser -Force -ErrorAction SilentlyContinue;`;
if (scheme === Constants_1.default.ServicePrincipal) { if (scheme === Constants_1.default.ServicePrincipal) {
if (args.environment.toLowerCase() == "azurestack") {
command += `Add-AzEnvironment -Name ${args.environment} -ARMEndpoint ${args.resourceManagerEndpointUrl} | out-null;`;
}
command += `Connect-AzAccount -ServicePrincipal -Tenant '${tenantId}' -Credential \ command += `Connect-AzAccount -ServicePrincipal -Tenant '${tenantId}' -Credential \
(New-Object System.Management.Automation.PSCredential('${args.servicePrincipalId}',(ConvertTo-SecureString '${args.servicePrincipalKey.replace("'", "''")}' -AsPlainText -Force))) \ (New-Object System.Management.Automation.PSCredential('${args.servicePrincipalId}',(ConvertTo-SecureString '${args.servicePrincipalKey.replace("'", "''")}' -AsPlainText -Force))) \
-Environment '${args.environment}' | out-null;`; -Environment '${args.environment}' | out-null;`;
if (args.scopeLevel === Constants_1.default.Subscription) { if (args.scopeLevel === Constants_1.default.Subscription && !args.allowNoSubscriptionsLogin) {
command += `Set-AzContext -SubscriptionId '${args.subscriptionId}' -TenantId '${tenantId}' | out-null;`; command += `Set-AzContext -SubscriptionId '${args.subscriptionId}' -TenantId '${tenantId}' | out-null;`;
} }
} }

View File

@@ -1,90 +1,168 @@
"use strict"; "use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) { return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next()); step((generator = generator.apply(thisArg, _arguments || [])).next());
}); });
}; };
var __importStar = (this && this.__importStar) || function (mod) { var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod; if (mod && mod.__esModule) return mod;
var result = {}; var result = {};
if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k]; if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k];
result["default"] = mod; result["default"] = mod;
return result; return result;
}; };
Object.defineProperty(exports, "__esModule", { value: true }); Object.defineProperty(exports, "__esModule", { value: true });
const core = __importStar(require("@actions/core")); const core = __importStar(require("@actions/core"));
const crypto = __importStar(require("crypto")); const exec = __importStar(require("@actions/exec"));
const exec = __importStar(require("@actions/exec")); const io = __importStar(require("@actions/io"));
const io = __importStar(require("@actions/io")); const actions_secret_parser_1 = require("actions-secret-parser");
const actions_secret_parser_1 = require("actions-secret-parser"); const ServicePrincipalLogin_1 = require("./PowerShell/ServicePrincipalLogin");
const ServicePrincipalLogin_1 = require("./PowerShell/ServicePrincipalLogin"); var azPath;
var azPath; var prefix = !!process.env.AZURE_HTTP_USER_AGENT ? `${process.env.AZURE_HTTP_USER_AGENT}` : "";
var prefix = !!process.env.AZURE_HTTP_USER_AGENT ? `${process.env.AZURE_HTTP_USER_AGENT}` : ""; var azPSHostEnv = !!process.env.AZUREPS_HOST_ENVIRONMENT ? `${process.env.AZUREPS_HOST_ENVIRONMENT}` : "";
var azPSHostEnv = !!process.env.AZUREPS_HOST_ENVIRONMENT ? `${process.env.AZUREPS_HOST_ENVIRONMENT}` : ""; function main() {
function main() { return __awaiter(this, void 0, void 0, function* () {
return __awaiter(this, void 0, void 0, function* () { try {
try { // Set user agent variable
// Set user agent variable var isAzCLISuccess = false;
var isAzCLISuccess = false; let usrAgentRepo = `${process.env.GITHUB_REPOSITORY}`;
let usrAgentRepo = crypto.createHash('sha256').update(`${process.env.GITHUB_REPOSITORY}`).digest('hex'); let actionName = 'AzureLogin';
let actionName = 'AzureLogin'; let userAgentString = (!!prefix ? `${prefix}+` : '') + `GITHUBACTIONS/${actionName}@v1_${usrAgentRepo}`;
let userAgentString = (!!prefix ? `${prefix}+` : '') + `GITHUBACTIONS/${actionName}@v1_${usrAgentRepo}`; let azurePSHostEnv = (!!azPSHostEnv ? `${azPSHostEnv}+` : '') + `GITHUBACTIONS/${actionName}@v1_${usrAgentRepo}`;
let azurePSHostEnv = (!!azPSHostEnv ? `${azPSHostEnv}+` : '') + `GITHUBACTIONS/${actionName}@v1_${usrAgentRepo}`; core.exportVariable('AZURE_HTTP_USER_AGENT', userAgentString);
core.exportVariable('AZURE_HTTP_USER_AGENT', userAgentString); core.exportVariable('AZUREPS_HOST_ENVIRONMENT', azurePSHostEnv);
core.exportVariable('AZUREPS_HOST_ENVIRONMENT', azurePSHostEnv); azPath = yield io.which("az", true);
azPath = yield io.which("az", true); let azureSupportedCloudName = new Set([
yield executeAzCliCommand("--version"); "azureusgovernment",
let creds = core.getInput('creds', { required: true }); "azurechinacloud",
let secrets = new actions_secret_parser_1.SecretParser(creds, actions_secret_parser_1.FormatType.JSON); "azuregermancloud",
let servicePrincipalId = secrets.getSecret("$.clientId", false); "azurecloud",
let servicePrincipalKey = secrets.getSecret("$.clientSecret", true); "azurestack"
let tenantId = secrets.getSecret("$.tenantId", false); ]);
let subscriptionId = secrets.getSecret("$.subscriptionId", false); let output = "";
const enableAzPSSession = core.getInput('enable-AzPSSession').toLowerCase() === "true"; const execOptions = {
if (!servicePrincipalId || !servicePrincipalKey || !tenantId || !subscriptionId) { listeners: {
throw new Error("Not all values are present in the creds object. Ensure clientId, clientSecret, tenantId and subscriptionId are supplied."); stdout: (data) => {
} output += data.toString();
// Attempting Az cli login }
yield executeAzCliCommand(`login --service-principal -u "${servicePrincipalId}" -p "${servicePrincipalKey}" --tenant "${tenantId}"`, true); }
yield executeAzCliCommand(`account set --subscription "${subscriptionId}"`, true); };
isAzCLISuccess = true; yield executeAzCliCommand("--version", true, execOptions);
if (enableAzPSSession) { core.debug(`az cli version used:\n${output}`);
// Attempting Az PS login let creds = core.getInput('creds', { required: true });
console.log(`Running Azure PS Login`); let secrets = new actions_secret_parser_1.SecretParser(creds, actions_secret_parser_1.FormatType.JSON);
const spnlogin = new ServicePrincipalLogin_1.ServicePrincipalLogin(servicePrincipalId, servicePrincipalKey, tenantId, subscriptionId); let servicePrincipalId = secrets.getSecret("$.clientId", false);
yield spnlogin.initialize(); let servicePrincipalKey = secrets.getSecret("$.clientSecret", true);
yield spnlogin.login(); let tenantId = secrets.getSecret("$.tenantId", false);
} let subscriptionId = secrets.getSecret("$.subscriptionId", false);
console.log("Login successful."); let resourceManagerEndpointUrl = secrets.getSecret("$.resourceManagerEndpointUrl", false);
} let environment = core.getInput("environment").toLowerCase();
catch (error) { const enableAzPSSession = core.getInput('enable-AzPSSession').toLowerCase() === "true";
if (!isAzCLISuccess) { const allowNoSubscriptionsLogin = core.getInput('allow-no-subscriptions').toLowerCase() === "true";
core.error("Az CLI Login failed. Please check the credentials. For more information refer https://aka.ms/create-secrets-for-GitHub-workflows"); if (!servicePrincipalId || !servicePrincipalKey || !tenantId) {
} throw new Error("Not all values are present in the creds object. Ensure clientId, clientSecret and tenantId are supplied.");
else { }
core.error(`Azure PowerShell Login failed. Please check the credentials. For more information refer https://aka.ms/create-secrets-for-GitHub-workflows"`); if (!subscriptionId && !allowNoSubscriptionsLogin) {
} throw new Error("Not all values are present in the creds object. Ensure subscriptionId is supplied.");
core.setFailed(error); }
} if (!azureSupportedCloudName.has(environment)) {
finally { throw new Error("Unsupported value for environment is passed.The list of supported values for environment are azureusgovernment', azurechinacloud, azuregermancloud, azurecloud or azurestack");
// Reset AZURE_HTTP_USER_AGENT }
core.exportVariable('AZURE_HTTP_USER_AGENT', prefix); // Attempting Az cli login
core.exportVariable('AZUREPS_HOST_ENVIRONMENT', azPSHostEnv); if (environment == "azurestack") {
} if (!resourceManagerEndpointUrl) {
}); throw new Error("resourceManagerEndpointUrl is a required parameter when environment is defined.");
} }
function executeAzCliCommand(command, silent) { console.log(`Unregistering cloud: "${environment}" first if it exists`);
return __awaiter(this, void 0, void 0, function* () { try {
try { yield executeAzCliCommand(`cloud set -n AzureCloud`, true);
yield exec.exec(`"${azPath}" ${command}`, [], { silent: !!silent }); yield executeAzCliCommand(`cloud unregister -n "${environment}"`, false);
} }
catch (error) { catch (error) {
throw new Error(error); console.log(`Ignore cloud not registered error: "${error}"`);
} }
}); console.log(`Registering cloud: "${environment}" with ARM endpoint: "${resourceManagerEndpointUrl}"`);
} try {
main(); let baseUri = resourceManagerEndpointUrl;
if (baseUri.endsWith('/')) {
baseUri = baseUri.substring(0, baseUri.length - 1); // need to remove trailing / from resourceManagerEndpointUrl to correctly derive suffixes below
}
let suffixKeyvault = ".vault" + baseUri.substring(baseUri.indexOf('.')); // keyvault suffix starts with .
let suffixStorage = baseUri.substring(baseUri.indexOf('.') + 1); // storage suffix starts without .
let profileVersion = "2019-03-01-hybrid";
yield executeAzCliCommand(`cloud register -n "${environment}" --endpoint-resource-manager "${resourceManagerEndpointUrl}" --suffix-keyvault-dns "${suffixKeyvault}" --suffix-storage-endpoint "${suffixStorage}" --profile "${profileVersion}"`, false);
}
catch (error) {
core.error(`Error while trying to register cloud "${environment}": "${error}"`);
}
console.log(`Done registering cloud: "${environment}"`);
}
yield executeAzCliCommand(`cloud set -n "${environment}"`, false);
console.log(`Done setting cloud: "${environment}"`);
// Attempting Az cli login
if (allowNoSubscriptionsLogin) {
let args = [
"--allow-no-subscriptions",
"--service-principal",
"-u", servicePrincipalId,
"-p", servicePrincipalKey,
"--tenant", tenantId
];
yield executeAzCliCommand(`login`, true, {}, args);
}
else {
let args = [
"--service-principal",
"-u", servicePrincipalId,
"-p", servicePrincipalKey,
"--tenant", tenantId
];
yield executeAzCliCommand(`login`, true, {}, args);
args = [
"--subscription",
subscriptionId
];
yield executeAzCliCommand(`account set`, true, {}, args);
}
isAzCLISuccess = true;
if (enableAzPSSession) {
// Attempting Az PS login
console.log(`Running Azure PS Login`);
const spnlogin = new ServicePrincipalLogin_1.ServicePrincipalLogin(servicePrincipalId, servicePrincipalKey, tenantId, subscriptionId, allowNoSubscriptionsLogin, environment, resourceManagerEndpointUrl);
yield spnlogin.initialize();
yield spnlogin.login();
}
console.log("Login successful.");
}
catch (error) {
if (!isAzCLISuccess) {
core.error("Az CLI Login failed. Please check the credentials. For more information refer https://aka.ms/create-secrets-for-GitHub-workflows");
}
else {
core.error(`Azure PowerShell Login failed. Please check the credentials. For more information refer https://aka.ms/create-secrets-for-GitHub-workflows"`);
}
core.setFailed(error);
}
finally {
// Reset AZURE_HTTP_USER_AGENT
core.exportVariable('AZURE_HTTP_USER_AGENT', prefix);
core.exportVariable('AZUREPS_HOST_ENVIRONMENT', azPSHostEnv);
}
});
}
function executeAzCliCommand(command, silent, execOptions = {}, args = []) {
return __awaiter(this, void 0, void 0, function* () {
execOptions.silent = !!silent;
try {
yield exec.exec(`"${azPath}" ${command}`, args, execOptions);
}
catch (error) {
throw new Error(error);
}
});
}
main();

14
package-lock.json generated
View File

@@ -1,13 +1,13 @@
{ {
"name": "login", "name": "login",
"version": "1.0.0", "version": "1.1.0",
"lockfileVersion": 1, "lockfileVersion": 1,
"requires": true, "requires": true,
"dependencies": { "dependencies": {
"@actions/core": { "@actions/core": {
"version": "1.1.3", "version": "1.2.6",
"resolved": "https://registry.npmjs.org/@actions/core/-/core-1.1.3.tgz", "resolved": "https://registry.npmjs.org/@actions/core/-/core-1.2.6.tgz",
"integrity": "sha512-2BIib53Jh4Cfm+1XNuZYYGTeRo8yiWEAUMoliMh1qQGMaqTF4VUlhhcsBylTu4qWmUx45DrY0y0XskimAHSqhw==" "integrity": "sha512-ZQYitnqiyBc3D+k7LsgSBmMDVkOVidaagDG7j3fOym77jNunWRuYx7VSHa9GNfFZh+zh61xsCjRj4JxMZlDqTA=="
}, },
"@actions/exec": { "@actions/exec": {
"version": "1.0.1", "version": "1.0.1",
@@ -3331,9 +3331,9 @@
} }
}, },
"lodash": { "lodash": {
"version": "4.17.15", "version": "4.17.19",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.19.tgz",
"integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==", "integrity": "sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ==",
"dev": true "dev": true
}, },
"lodash.memoize": { "lodash.memoize": {

View File

@@ -1,6 +1,6 @@
{ {
"name": "login", "name": "login",
"version": "1.0.0", "version": "1.1.0",
"description": "Login Azure wraps the az login, allowing for Azure actions to log into Azure", "description": "Login Azure wraps the az login, allowing for Azure actions to log into Azure",
"main": "lib/main.js", "main": "lib/main.js",
"scripts": { "scripts": {
@@ -18,7 +18,7 @@
"typescript": "^3.6.3" "typescript": "^3.6.3"
}, },
"dependencies": { "dependencies": {
"@actions/core": "^1.1.3", "@actions/core": "^1.2.6",
"@actions/exec": "^1.0.1", "@actions/exec": "^1.0.1",
"@actions/io": "^1.0.1", "@actions/io": "^1.0.1",
"actions-secret-parser": "^1.0.2" "actions-secret-parser": "^1.0.2"

View File

@@ -6,19 +6,31 @@ import ScriptBuilder from './Utilities/ScriptBuilder';
import Constants from './Constants'; import Constants from './Constants';
export class ServicePrincipalLogin implements IAzurePowerShellSession { export class ServicePrincipalLogin implements IAzurePowerShellSession {
static readonly environment: string = Constants.AzureCloud;
static readonly scopeLevel: string = Constants.Subscription; static readonly scopeLevel: string = Constants.Subscription;
static readonly scheme: string = Constants.ServicePrincipal; static readonly scheme: string = Constants.ServicePrincipal;
environment: string;
servicePrincipalId: string; servicePrincipalId: string;
servicePrincipalKey: string; servicePrincipalKey: string;
tenantId: string; tenantId: string;
subscriptionId: string; subscriptionId: string;
resourceManagerEndpointUrl: string;
allowNoSubscriptionsLogin: boolean;
constructor(servicePrincipalId: string, servicePrincipalKey: string, tenantId: string, subscriptionId: string) { constructor(servicePrincipalId: string,
servicePrincipalKey: string,
tenantId: string,
subscriptionId: string,
allowNoSubscriptionsLogin: boolean,
environment: string,
resourceManagerEndpointUrl: string) {
this.servicePrincipalId = servicePrincipalId; this.servicePrincipalId = servicePrincipalId;
this.servicePrincipalKey = servicePrincipalKey; this.servicePrincipalKey = servicePrincipalKey;
this.tenantId = tenantId; this.tenantId = tenantId;
this.subscriptionId = subscriptionId; this.subscriptionId = subscriptionId;
this.environment = environment;
this.resourceManagerEndpointUrl = resourceManagerEndpointUrl;
this.allowNoSubscriptionsLogin = allowNoSubscriptionsLogin;
} }
async initialize() { async initialize() {
@@ -41,8 +53,10 @@ export class ServicePrincipalLogin implements IAzurePowerShellSession {
servicePrincipalId: this.servicePrincipalId, servicePrincipalId: this.servicePrincipalId,
servicePrincipalKey: this.servicePrincipalKey, servicePrincipalKey: this.servicePrincipalKey,
subscriptionId: this.subscriptionId, subscriptionId: this.subscriptionId,
environment: ServicePrincipalLogin.environment, environment: this.environment,
scopeLevel: ServicePrincipalLogin.scopeLevel scopeLevel: ServicePrincipalLogin.scopeLevel,
allowNoSubscriptionsLogin: this.allowNoSubscriptionsLogin,
resourceManagerEndpointUrl: this.resourceManagerEndpointUrl
} }
const script: string = new ScriptBuilder().getAzPSLoginScript(ServicePrincipalLogin.scheme, this.tenantId, args); const script: string = new ScriptBuilder().getAzPSLoginScript(ServicePrincipalLogin.scheme, this.tenantId, args);
await PowerShellToolRunner.init(); await PowerShellToolRunner.init();

View File

@@ -9,10 +9,13 @@ export default class ScriptBuilder {
let command = `Clear-AzContext -Scope Process; let command = `Clear-AzContext -Scope Process;
Clear-AzContext -Scope CurrentUser -Force -ErrorAction SilentlyContinue;`; Clear-AzContext -Scope CurrentUser -Force -ErrorAction SilentlyContinue;`;
if (scheme === Constants.ServicePrincipal) { if (scheme === Constants.ServicePrincipal) {
if (args.environment.toLowerCase() == "azurestack") {
command += `Add-AzEnvironment -Name ${args.environment} -ARMEndpoint ${args.resourceManagerEndpointUrl} | out-null;`;
}
command += `Connect-AzAccount -ServicePrincipal -Tenant '${tenantId}' -Credential \ command += `Connect-AzAccount -ServicePrincipal -Tenant '${tenantId}' -Credential \
(New-Object System.Management.Automation.PSCredential('${args.servicePrincipalId}',(ConvertTo-SecureString '${args.servicePrincipalKey.replace("'", "''")}' -AsPlainText -Force))) \ (New-Object System.Management.Automation.PSCredential('${args.servicePrincipalId}',(ConvertTo-SecureString '${args.servicePrincipalKey.replace("'", "''")}' -AsPlainText -Force))) \
-Environment '${args.environment}' | out-null;`; -Environment '${args.environment}' | out-null;`;
if (args.scopeLevel === Constants.Subscription) { if (args.scopeLevel === Constants.Subscription && !args.allowNoSubscriptionsLogin) {
command += `Set-AzContext -SubscriptionId '${args.subscriptionId}' -TenantId '${tenantId}' | out-null;`; command += `Set-AzContext -SubscriptionId '${args.subscriptionId}' -TenantId '${tenantId}' | out-null;`;
} }
} }

View File

@@ -1,8 +1,6 @@
import * as core from '@actions/core'; import * as core from '@actions/core';
import * as crypto from "crypto";
import * as exec from '@actions/exec'; import * as exec from '@actions/exec';
import * as io from '@actions/io'; import * as io from '@actions/io';
import { FormatType, SecretParser } from 'actions-secret-parser'; import { FormatType, SecretParser } from 'actions-secret-parser';
import { ServicePrincipalLogin } from './PowerShell/ServicePrincipalLogin'; import { ServicePrincipalLogin } from './PowerShell/ServicePrincipalLogin';
@@ -14,7 +12,7 @@ async function main() {
try { try {
// Set user agent variable // Set user agent variable
var isAzCLISuccess = false; var isAzCLISuccess = false;
let usrAgentRepo = crypto.createHash('sha256').update(`${process.env.GITHUB_REPOSITORY}`).digest('hex'); let usrAgentRepo = `${process.env.GITHUB_REPOSITORY}`;
let actionName = 'AzureLogin'; let actionName = 'AzureLogin';
let userAgentString = (!!prefix ? `${prefix}+` : '') + `GITHUBACTIONS/${actionName}@v1_${usrAgentRepo}`; let userAgentString = (!!prefix ? `${prefix}+` : '') + `GITHUBACTIONS/${actionName}@v1_${usrAgentRepo}`;
let azurePSHostEnv = (!!azPSHostEnv ? `${azPSHostEnv}+` : '') + `GITHUBACTIONS/${actionName}@v1_${usrAgentRepo}`; let azurePSHostEnv = (!!azPSHostEnv ? `${azPSHostEnv}+` : '') + `GITHUBACTIONS/${actionName}@v1_${usrAgentRepo}`;
@@ -22,49 +20,155 @@ async function main() {
core.exportVariable('AZUREPS_HOST_ENVIRONMENT', azurePSHostEnv); core.exportVariable('AZUREPS_HOST_ENVIRONMENT', azurePSHostEnv);
azPath = await io.which("az", true); azPath = await io.which("az", true);
await executeAzCliCommand("--version");
let azureSupportedCloudName = new Set([
"azureusgovernment",
"azurechinacloud",
"azuregermancloud",
"azurecloud",
"azurestack"]);
let output: string = "";
const execOptions: any = {
listeners: {
stdout: (data: Buffer) => {
output += data.toString();
}
}
};
await executeAzCliCommand("--version", true, execOptions);
core.debug(`az cli version used:\n${output}`);
let creds = core.getInput('creds', { required: true }); let creds = core.getInput('creds', { required: true });
let secrets = new SecretParser(creds, FormatType.JSON); let secrets = new SecretParser(creds, FormatType.JSON);
let servicePrincipalId = secrets.getSecret("$.clientId", false); let servicePrincipalId = secrets.getSecret("$.clientId", false);
let servicePrincipalKey = secrets.getSecret("$.clientSecret", true); let servicePrincipalKey = secrets.getSecret("$.clientSecret", true);
let tenantId = secrets.getSecret("$.tenantId", false); let tenantId = secrets.getSecret("$.tenantId", false);
let subscriptionId = secrets.getSecret("$.subscriptionId", false); let subscriptionId = secrets.getSecret("$.subscriptionId", false);
let resourceManagerEndpointUrl = secrets.getSecret("$.resourceManagerEndpointUrl", false);
let environment = core.getInput("environment").toLowerCase();
const enableAzPSSession = core.getInput('enable-AzPSSession').toLowerCase() === "true"; const enableAzPSSession = core.getInput('enable-AzPSSession').toLowerCase() === "true";
if (!servicePrincipalId || !servicePrincipalKey || !tenantId || !subscriptionId) { const allowNoSubscriptionsLogin = core.getInput('allow-no-subscriptions').toLowerCase() === "true";
throw new Error("Not all values are present in the creds object. Ensure clientId, clientSecret, tenantId and subscriptionId are supplied.");
if (!servicePrincipalId || !servicePrincipalKey || !tenantId) {
throw new Error("Not all values are present in the creds object. Ensure clientId, clientSecret and tenantId are supplied.");
} }
if (!subscriptionId && !allowNoSubscriptionsLogin) {
throw new Error("Not all values are present in the creds object. Ensure subscriptionId is supplied.");
}
if (!azureSupportedCloudName.has(environment)){
throw new Error("Unsupported value for environment is passed.The list of supported values for environment are azureusgovernment', azurechinacloud, azuregermancloud, azurecloud or azurestack");
}
// Attempting Az cli login // Attempting Az cli login
await executeAzCliCommand(`login --service-principal -u "${servicePrincipalId}" -p "${servicePrincipalKey}" --tenant "${tenantId}"`, true); if (environment == "azurestack") {
await executeAzCliCommand(`account set --subscription "${subscriptionId}"`, true); if (!resourceManagerEndpointUrl) {
throw new Error("resourceManagerEndpointUrl is a required parameter when environment is defined.");
}
console.log(`Unregistering cloud: "${environment}" first if it exists`);
try {
await executeAzCliCommand(`cloud set -n AzureCloud`, true);
await executeAzCliCommand(`cloud unregister -n "${environment}"`, false);
}
catch (error) {
console.log(`Ignore cloud not registered error: "${error}"`);
}
console.log(`Registering cloud: "${environment}" with ARM endpoint: "${resourceManagerEndpointUrl}"`);
try {
let baseUri = resourceManagerEndpointUrl;
if (baseUri.endsWith('/')) {
baseUri = baseUri.substring(0, baseUri.length-1); // need to remove trailing / from resourceManagerEndpointUrl to correctly derive suffixes below
}
let suffixKeyvault = ".vault" + baseUri.substring(baseUri.indexOf('.')); // keyvault suffix starts with .
let suffixStorage = baseUri.substring(baseUri.indexOf('.')+1); // storage suffix starts without .
let profileVersion = "2019-03-01-hybrid";
await executeAzCliCommand(`cloud register -n "${environment}" --endpoint-resource-manager "${resourceManagerEndpointUrl}" --suffix-keyvault-dns "${suffixKeyvault}" --suffix-storage-endpoint "${suffixStorage}" --profile "${profileVersion}"`, false);
}
catch (error) {
core.error(`Error while trying to register cloud "${environment}": "${error}"`);
}
console.log(`Done registering cloud: "${environment}"`)
}
await executeAzCliCommand(`cloud set -n "${environment}"`, false);
console.log(`Done setting cloud: "${environment}"`);
// Attempting Az cli login
if (allowNoSubscriptionsLogin) {
let args = [
"--allow-no-subscriptions",
"--service-principal",
"-u", servicePrincipalId,
"-p", servicePrincipalKey,
"--tenant", tenantId
];
await executeAzCliCommand(`login`, true, {}, args);
}
else {
let args = [
"--service-principal",
"-u", servicePrincipalId,
"-p", servicePrincipalKey,
"--tenant", tenantId
];
await executeAzCliCommand(`login`, true, {}, args);
args = [
"--subscription",
subscriptionId
];
await executeAzCliCommand(`account set`, true, {}, args);
}
isAzCLISuccess = true; isAzCLISuccess = true;
if (enableAzPSSession) { if (enableAzPSSession) {
// Attempting Az PS login // Attempting Az PS login
console.log(`Running Azure PS Login`); console.log(`Running Azure PS Login`);
const spnlogin: ServicePrincipalLogin = new ServicePrincipalLogin(servicePrincipalId, servicePrincipalKey, tenantId, subscriptionId); const spnlogin: ServicePrincipalLogin = new ServicePrincipalLogin(
servicePrincipalId,
servicePrincipalKey,
tenantId,
subscriptionId,
allowNoSubscriptionsLogin,
environment,
resourceManagerEndpointUrl);
await spnlogin.initialize(); await spnlogin.initialize();
await spnlogin.login(); await spnlogin.login();
} }
console.log("Login successful."); console.log("Login successful.");
} catch (error) { }
catch (error) {
if (!isAzCLISuccess) { if (!isAzCLISuccess) {
core.error("Az CLI Login failed. Please check the credentials. For more information refer https://aka.ms/create-secrets-for-GitHub-workflows"); core.error("Az CLI Login failed. Please check the credentials. For more information refer https://aka.ms/create-secrets-for-GitHub-workflows");
} else { }
else {
core.error(`Azure PowerShell Login failed. Please check the credentials. For more information refer https://aka.ms/create-secrets-for-GitHub-workflows"`); core.error(`Azure PowerShell Login failed. Please check the credentials. For more information refer https://aka.ms/create-secrets-for-GitHub-workflows"`);
} }
core.setFailed(error); core.setFailed(error);
} finally { }
finally {
// Reset AZURE_HTTP_USER_AGENT // Reset AZURE_HTTP_USER_AGENT
core.exportVariable('AZURE_HTTP_USER_AGENT', prefix); core.exportVariable('AZURE_HTTP_USER_AGENT', prefix);
core.exportVariable('AZUREPS_HOST_ENVIRONMENT', azPSHostEnv); core.exportVariable('AZUREPS_HOST_ENVIRONMENT', azPSHostEnv);
} }
} }
async function executeAzCliCommand(command: string, silent?: boolean) { async function executeAzCliCommand(
command: string,
silent?: boolean,
execOptions: any = {},
args: any = []) {
execOptions.silent = !!silent;
try { try {
await exec.exec(`"${azPath}" ${command}`, [], {silent: !!silent}); await exec.exec(`"${azPath}" ${command}`, args, execOptions);
} }
catch(error) { catch (error) {
throw new Error(error); throw new Error(error);
} }
} }