Bare minimum to arrange for building and deploying to Azure with GitLab


Azure Infrastructure-as-code GitLab


Table of contents:

In this short post you’ll find how to prepare your GitLab to deploy to Azure.

Service principal #

Generate Service Principal (aka App Registration) using azure CLI (either builtin shell or local terminal, you must be logged in with Owner role credentials since we need to assign role to the scope):

1
2az ad sp create-for-rbac --name GitLabServicePrincipalName --role Owner --scopes /
3
4{
5  "appId": "<REDACTED>",
6  "displayName": "GitLabServicePrincipalName",
7  "password": "<REDACTED>",
8  "tenant": "<REDACTED>"
9}

Feel free to change scopes and role (i.e. custom role or subscription scope instead). Learn more how to generate SPN here.

Secrets in GitLab #

Safe appId, password, tenant and subscription ID in GitLab => Settings => CI/CD => Variables (make sure to enable checkbox Mask variable for each secret so the values won’t end up in the logs of the job).

GitLab CI example #

Example of .gitlab-ci.yml:

 1# You can override the included template(s) by including variable overrides
 2# SAST customization: https://docs.gitlab.com/ee/user/application_security/sast/#customizing-the-sast-settings
 3# Secret Detection customization: https://docs.gitlab.com/ee/user/application_security/secret_detection/#customizing-settings
 4# Dependency Scanning customization: https://docs.gitlab.com/ee/user/application_security/dependency_scanning/#customizing-the-dependency-scanning-settings
 5# Container Scanning customization: https://docs.gitlab.com/ee/user/application_security/container_scanning/#customizing-the-container-scanning-settings
 6# Note that environment variables can be set in several places
 7# See https://docs.gitlab.com/ee/ci/variables/#cicd-variable-precedence
 8include:
 9- template: Security/SAST.gitlab-ci.yml
10image: mcr.microsoft.com/azure-cli
11variables:
12  appId: "$appId"
13  password: "$password"
14  tenant: "$tenant"
15  subId: "$subId"
16stages:
17- build
18- test
19- deploy
20build-job:
21  stage: build
22  script:
23  - echo "Building Bicep artifact ... "
24  - az login --service-principal -u $appId -p $password -t $tenant
25  - az account set -s $subId
26  - az group create -g rg-group -l westeurope
27  - az deployment group what-if -g rg-group -f ./bicep/main.bicep
28  - az deployment group validate -g rg-group -f ./bicep/main.bicep
29  artifacts:
30    paths:
31    - bicep
32    expire_in: 1 week
33  only:
34  - dev
35unit-test-job:
36  stage: test
37  script:
38  - echo "Running unit tests... This will take about 60 seconds."
39  - sleep 60
40  - echo "Code coverage is 90%"
41  only:
42  - main
43lint-test-job:
44  stage: test
45  script:
46  - echo "Linting code... This will take about 10 seconds."
47  - sleep 10
48  - echo "No lint issues found."
49  only:
50  - main
51deploy-job:
52  stage: deploy
53  script:
54  - az login --service-principal -u $appId -p $password -t $tenant
55  - az account set -s $subId
56  - az group list
57  - az deployment group create -g rg-group -f ./bicep/main.bicep
58  only:
59  - dev
60sast:
61  stage: test

Few remarks:

Feel free to explore this public repo to see the entire example. Structure of the repo is quite simple:

1
2tree 
3.
4├── .gitlab-ci.yml <== example of pipeline
5├── README.md 
6└── bicep
7    └── main.bicep <== example of template to execute by the pipeline

Until next post! 👋

comments powered by Disqus