github.com/StackPointCloud/packer@v0.10.2-0.20180716202532-b28098e0f79b/website/source/docs/builders/azure-setup.html.md (about) 1 --- 2 description: | 3 In order to build VMs in Azure, Packer needs various configuration options. 4 These options and how to obtain them are documented on this page. 5 layout: docs 6 page_title: 'Setup - Azure - Builders' 7 sidebar_current: 'docs-builders-azure-setup' 8 --- 9 10 # Authorizing Packer Builds in Azure 11 12 In order to build VMs in Azure Packer needs 6 configuration options to be specified: 13 14 - `subscription_id` - UUID identifying your Azure subscription (where billing is handled) 15 16 - `client_id` - UUID identifying the Active Directory service principal that will run your Packer builds 17 18 - `client_secret` - service principal secret / password 19 20 - `resource_group_name` - name of the resource group where your VHD(s) will be stored 21 22 - `storage_account` - name of the storage account where your VHD(s) will be stored 23 24 -> Behind the scenes Packer uses the OAuth protocol to authenticate against Azure Active Directory and authorize requests to the Azure Service Management API. These topics are unnecessarily complicated so we will try to ignore them for the rest of this document.<br /><br />You do not need to understand how OAuth works in order to use Packer with Azure, though the Active Directory terms "service principal" and "role" will be useful for understanding Azure's access policies. 25 26 In order to get all of the items above, you will need a username and password for your Azure account. 27 28 ## Device Login 29 30 Device login is an alternative way to authorize in Azure Packer. Device login only requires you to know your 31 Subscription ID. (Device login is only supported for Linux based VMs.) Device login is intended for those who are first 32 time users, and just want to ''kick the tires.'' We recommend the SPN approach if you intend to automate Packer. 33 34 > Device login is for **interactive** builds, and SPN is **automated** builds. 35 36 There are three pieces of information you must provide to enable device login mode. 37 38 1. SubscriptionID 39 2. Resource Group - parent resource group that Packer uses to build an image. 40 3. Storage Account - storage account where the image will be placed. 41 42 > Device login mode is enabled by not setting client\_id and client\_secret. 43 44 > Device login mode is for the Public and US Gov clouds only. 45 46 The device login flow asks that you open a web browser, navigate to <http://aka.ms/devicelogin>, and input the supplied 47 code. This authorizes the Packer for Azure application to act on your behalf. An OAuth token will be created, and stored 48 in the user's home directory (~/.azure/packer/oauth-TenantID.json). This token is used if the token file exists, and it 49 is refreshed as necessary. The token file prevents the need to continually execute the device login flow. Packer will ask 50 for two device login auth, one for service management endpoint and another for accessing temp keyvault secrets that it creates. 51 52 ## Install the Azure CLI 53 54 To get the credentials above, we will need to install the Azure CLI. Please refer to Microsoft's official [installation guide](https://azure.microsoft.com/en-us/documentation/articles/xplat-cli-install/). 55 56 -> The guides below also use a tool called [`jq`](https://stedolan.github.io/jq/) to simplify the output from the Azure CLI, though this is optional. If you use homebrew you can simply `brew install node jq`. 57 58 If you already have node.js installed you can use `npm` to install `azure-cli`: 59 60 ``` shell 61 $ npm install -g azure-cli --no-progress 62 ``` 63 64 You can also use the Python-based Azure CLI in Docker. It also comes with `jq` pre-installed: 65 66 ```shell 67 $ docker run -it azuresdk/azure-cli-python 68 ``` 69 70 As there are differences between the node.js client and the Python client, we've included commands for the Python client underneath each node.js command. 71 72 ## Guided Setup 73 74 The Packer project includes a [setup script](https://github.com/hashicorp/packer/blob/master/contrib/azure-setup.sh) that can help you setup your account. It uses an interactive bash script to log you into Azure, name your resources, and export your Packer configuration. 75 76 ## Manual Setup 77 78 If you want more control or the script does not work for you, you can also use the manual instructions below to setup your Azure account. You will need to manually keep track of the various account identifiers, resource names, and your service principal password. 79 80 ### Identify Your Tenant and Subscription IDs 81 82 Login using the Azure CLI 83 84 ``` shell 85 $ azure config mode arm 86 $ azure login -u USERNAME 87 ``` 88 89 If you're using the Python client: 90 91 ```shell 92 $ az login 93 # To sign in, use a web browser to open the page https://aka.ms/devicelogin and enter the code CODE_PROVIDED to authenticate 94 ``` 95 96 Once you've completed logging in, you should get a JSON array like the one below: 97 98 ```shell 99 [ 100 { 101 "cloudName": "AzureCloud", 102 "id": "$uuid", 103 "isDefault": false, 104 "name": "Pay-As-You-Go", 105 "state": "Enabled", 106 "tenantId": "$tenant_uuid", 107 "user": { 108 "name": "my_email@anywhere.com", 109 "type": "user" 110 } 111 } 112 ] 113 114 ``` 115 Get your account information 116 117 ``` shell 118 $ azure account list --json | jq -r '.[].name' 119 $ azure account set ACCOUNTNAME 120 $ azure account show --json | jq -r ".[] | .id" 121 ``` 122 123 Python: 124 ``` shell 125 $ az account set "$(az account list | jq -r '.[].name')" 126 ``` 127 128 -> Throughout this document when you see a command pipe to `jq` you may instead omit `--json` and everything after it, but the output will be more verbose. For example you can simply run `azure account list` instead. 129 130 This will print out one line that look like this: 131 132 4f562e88-8caf-421a-b4da-e3f6786c52ec 133 134 This is your `subscription_id`. Note it for later. 135 136 ### Create a Resource Group 137 138 A [resource group](https://azure.microsoft.com/en-us/documentation/articles/resource-group-overview/#resource-groups) is used to organize related resources. Resource groups and storage accounts are tied to a location. To see available locations, run: 139 140 ``` shell 141 $ azure location list 142 # ... 143 144 $ azure group create -n GROUPNAME -l LOCATION 145 ``` 146 147 Python: 148 149 ```shell 150 $ az group create -n GROUPNAME -l LOCATION 151 ``` 152 153 Your storage account (below) will need to use the same `GROUPNAME` and `LOCATION`. 154 155 ### Create a Storage Account 156 157 We will need to create a storage account where your Packer artifacts will be stored. We will create a `LRS` storage account which is the least expensive price/GB at the time of writing. 158 159 ``` shell 160 $ azure storage account create \ 161 -g GROUPNAME \ 162 -l LOCATION \ 163 --sku-name LRS \ 164 --kind storage STORAGENAME 165 ``` 166 167 Python: 168 169 ```shell 170 $ az storage account create -n STORAGENAME -g GROUPNAME -l LOCATION --sku Standard_LRS 171 ``` 172 173 -> `LRS` and `Standard_LRS` are meant as literal "LRS" or "Standard_LRS" and not as variables. 174 175 Make sure that `GROUPNAME` and `LOCATION` are the same as above. Also, ensure that `GROUPNAME` is less than 24 characters long and contains only lowercase letters and numbers. 176 177 ### Create an Application 178 179 An application represents a way to authorize access to the Azure API. Note that you will need to specify a URL for your application (this is intended to be used for OAuth callbacks) but these do not actually need to be valid URLs. 180 181 ``` shell 182 $ azure ad app create \ 183 -n APPNAME \ 184 -i APPURL \ 185 --home-page APPURL \ 186 -p PASSWORD 187 ``` 188 189 Python: 190 191 ```shell 192 az ad app create --display-name APPNAME --identifier-uris APPURL --homepage APPURL --password PASSWORD 193 ``` 194 195 Password is your `client_secret` and can be anything you like. I recommend using `openssl rand -base64 24`. 196 197 ### Create a Service Principal 198 199 You cannot directly grant permissions to an application. Instead, you create a service principal associated with the application and assign permissions to the service principal. 200 201 First, get the `APPID` for the application we just created. 202 203 ``` shell 204 $ azure ad app list --json \ 205 | jq '.[] | select(.displayName | contains("APPNAME")) | .appId' 206 # ... 207 208 $ azure ad sp create --applicationId APPID 209 ``` 210 211 Python: 212 213 ```shell 214 $ id=$(az ad app list | jq -r '.[] | select(.displayName == "Packer") | .appId') 215 $ az ad sp create --id "$id" 216 ``` 217 218 ### Grant Permissions to Your Application 219 220 Finally, we will associate the proper permissions with our application's service principal. We're going to assign the `Owner` role to our Packer application and change the scope to manage our whole subscription. (The `Owner` role can be scoped to a specific resource group to further reduce the scope of the account.) This allows Packer to create temporary resource groups for each build. 221 222 ``` shell 223 $ azure role assignment create \ 224 --spn APPURL \ 225 -o "Owner" \ 226 -c /subscriptions/SUBSCRIPTIONID 227 ``` 228 229 Python: 230 231 ```shell 232 # NOTE: Trying to assign the role to the service principal by name directly yields a HTTP 400 error. See: https://github.com/Azure/azure-cli/issues/4911 233 $ az role assignment create --assignee "$(az ad sp list | jq -r '.[] | select(.displayName == "APPNAME") | .objectId')" --role Owner 234 ``` 235 236 There are a lot of pre-defined roles and you can define your own with more granular permissions, though this is out of scope. You can see a list of pre-configured roles via: 237 238 ``` shell 239 $ azure role list --json \ 240 | jq ".[] | {name:.Name, description:.Description}" 241 ``` 242 243 ### Configuring Packer 244 245 Now (finally) everything has been setup in Azure. Let's get our configuration keys together: 246 247 Python: 248 249 ```shell 250 $ cat <<EOF 251 > { 252 > "subscription_id": $(az account show | jq '.id'), 253 > "client_id": $(az ad app list | jq '.[] | select(.displayName == "Packer") | .appId'), 254 > "client_secret": "$password", 255 > "location": "$location", 256 > "tenant_id": $(az account show | jq '.tenantId') 257 > "object_id": $(az ad app list | jq '.[] | select(.displayName == "Packer") | .objectId') 258 > } 259 > EOF 260 ``` 261 262 node.js: 263 264 Get `subscription_id`: 265 266 ``` shell 267 $ azure account show --json \ 268 | jq ".[] | .id" 269 ``` 270 271 Get `client_id` 272 273 ``` shell 274 $ azure ad app list --json \ 275 | jq '.[] | select(.displayName | contains("APPNAME")) | .appId' 276 ``` 277 278 279 Get `client_secret` 280 281 This cannot be retrieved. If you forgot this, you will have to delete and re-create your service principal and the associated permissions. 282 283 Get `object_id` (OSTYpe=Windows only) 284 285 ``` shell 286 azure ad sp show -n CLIENT_ID 287 ``` 288 289 Get `resource_group_name` 290 291 ``` shell 292 $ azure group list 293 ``` 294 295 Get `storage_account` 296 297 ``` shell 298 $ azure storage account list 299 ```