4

I am creating an Azure RM Storage Account with Ansible and I would like to fetch the value of the access keys for later usage in templates. These values are generated on the Azure side. I can get them, for example, with the PowerShell Get-AzureStorageKey cmdlet.

However, neither the return values of the azure_rm_storageaccount module nor the facts gathered with the azure_rm_storageaccount_facts module contain those keys.

I guess I could fetch them using a REST API call (per this answer), but I would have to create an OAuth2 token just for this task. With REST API there is likely no way to use the set of credentials defined for Ansible (i.e. environment variables AZURE_CLIENT_ID, AZURE_SECRET, AZURE_SUBSCRIPTION_ID, AZURE_TENANT).

Is there any way to fetch these keys (using the credentials already provided to Ansible)?


In fact, Ansible libraries seem to include the code for fetching these keys, but it also seems they are used only internally.


My playbook:

---
- hosts: localhost
  connection: local

  vars:
    resource_group_name: fetchtest01
    resource_group_location: southcentralus
    storage_account: fdsahf343u2s
    storage_account_type: Standard_LRS

  tasks:
    - name: Ensure resource group "{{ resource_group_name }}" exists
      azure_rm_resourcegroup:
        name: "{{ resource_group_name }}"
        location: "{{ resource_group_location }}"

    - name: Ensure storage account "{{ storage_account }}" exists in "{{ resource_group_name }}" resource group
      azure_rm_storageaccount:
        resource_group: "{{ resource_group_name }}"
        name: "{{ storage_account }}"
        account_type: "{{ storage_account_type }}"

   - name: Fetch storage account keys
     # fetch storage_account_keys

   - name: Use the storage_account_keys.primary in a template 
     template:
       # ...
Community
  • 1
  • 1
techraf
  • 64,883
  • 27
  • 193
  • 198

5 Answers5

3

Wrap Azure Cli within a task,

  tasks:
    - name: Retrieve storage access key
      shell: az storage account keys list --account-name {{ storage_account.name }} --resource-group {{ azure.resource_group }} --query "[0].value" --output tsv
      register: storage_access_key

Now, storage_access_key will contain desired result.

user3362908
  • 433
  • 5
  • 16
  • The important part is missing. You will need to use `storage_access_key.stdout` to get that key (at least with ansible 2.8). – pvasek Oct 03 '19 at 20:20
2

This week I struggled with exactly the same question. I wanted a way to retrieve these keys and I finally ended up using an Azure Service Principle and the Azure REST api. I stored on my laptop the credentials in ~/.azure/credentials as explained in the documentation https://docs.ansible.com/ansible/2.6/scenario_guides/guide_azure.html#storing-in-a-file

I also used an azure credentials profile having more then one service principale and I specify the AZURE_PROFILE environment variable at the command line like the following:

ansible-playbook -e AZURE_PROFILE="profile-dev" -i inventories/local playbooks/azure_sas_token.yml -vvv

the azure_sas_token.yml playbook

---
- name: get sas token and storage account keys
  hosts: 127.0.0.1
  become: no

  vars:
    az_subscription_id: "{{ lookup('ini',  'subscription_id section={{ AZURE_PROFILE }}  file={{ ansible_env.HOME }}/.azure/credentials') }}"
    az_client_id: "{{ lookup('ini',  'client_id section={{ AZURE_PROFILE }}  file={{ ansible_env.HOME }}/.azure/credentials') }}"
    az_tenant_id: "{{ lookup('ini',  'tenant section={{ AZURE_PROFILE }}  file={{ ansible_env.HOME }}/.azure/credentials') }}"
    az_secret: "{{ lookup('ini',  'secret section={{ AZURE_PROFILE }}  file={{ ansible_env.HOME }}/.azure/credentials') }}"

  tasks:
    - name: get sas token through oauth2
      uri:
        url: "https://login.windows.net/{{ az_tenant_id }}/oauth2/token"
        method: POST
        body: "resource=https://management.core.windows.net&client_id={{ az_client_id }}&grant_type=client_credentials&client_secret={{ az_secret }}"
        return_content: yes
      register: sas_token_info
      no_log: true

    - name: get the storage account keys
      uri:
        url: "https://management.azure.com/subscriptions/{{ az_subscription_id }}/resourceGroups/{{ resource_group }}/providers/Microsoft.Storage/storageAccounts/{{ storage_account }}/listKeys?api-version=2016-12-01"
        method: POST
        headers:
          Authorization: "Bearer {{ sas_token_info.json.access_token }}"
        return_content: yes
      register: storage_account_keys

    - debug:
        msg: "{{ storage_account_keys.json['keys'].0.value }}"

    - debug:
        msg: "{{ storage_account_keys.json['keys'].1.value }}"

Using these 2 tasks I was able to get the keys of my storage account and then I was able to automate my file share creation and mount my cifs drive.

Hope it can help someone.

DoRivard
  • 792
  • 3
  • 16
  • 27
1

Not really an answer to your question directly as I have not worked with Ansible so I am going to provide an explanation on why you were not able to get the storage account keys using azure_rm_storageaccount_facts module.

Essentially in Azure Resource Manager, you would need certain kinds of permissions to perform an operation. Because you could potentially update the data in a storage account, the team has split the operation of getting storage account properties and keys in two separate operations. To get the properties, you would perform Get Properties operation which doesn't return keys. To get the keys, you would need to perform List Keys.

I believe azure_rm_storageaccount_facts only performs the 1st operation (i.e. Get Properties) and this is why you're not getting the keys. I looked at all Azure related operations here and I could not find an operation to return the keys.


If using PowerShell is an option, the Cmdlet you would want to use is Get-AzureRmStorageAccountKey and not Get-AzureStorageKey as this is for Classic storage accounts.

techraf
  • 64,883
  • 27
  • 193
  • 198
Gaurav Mantri
  • 128,066
  • 12
  • 206
  • 241
  • :). `Do you happen to know, if the keys are at all accessible using any method utilising the AZURE_CLIENT_ID, AZURE_SECRET, AZURE_SUBSCRIPTION_ID, AZURE_TENANT credentials?` - Yes. This is essentially a `Service Principal`. You just have to ensure that this Service Principal has permission to perform List Keys operation. You can put this Service Principal in a `Storage Account Contributor` role. However it will also use OAuth2. – Gaurav Mantri Mar 26 '17 at 12:45
  • 1
    Yes, at first I thought there was some deeper separation, but these are just two different calls. In fact there is code for [fetching these keys in Ansible](https://github.com/ansible/ansible/blob/devel/lib/ansible/module_utils/azure_rm_common.py#L0455). Tracing how to use it... – techraf Mar 27 '17 at 00:45
1

Here is a bash snippet that will give you a KEY. The command returns 2 keys, this will give you one of them. Assumes you have jq and the azure cli installed.

KEY=$(az storage account keys list --resource-group ${RG_NAME} --account-name ${STORAGE_NAME} | jq -r '.[].value' | head -1)

Matt
  • 281
  • 4
  • 9
  • I liked your using `jq` and wanted to add that you might use index 0 to get the first key: `KEY=$(az storage account keys list --resource-group ${RG_NAME} --account-name ${STORAGE_NAME} | jq -r '.[0].value')` – Jaap van der Herberg Sep 27 '22 at 12:36
1

now the azure_rm_storageaccount_facts module has supported showing the access keys for the account. Actually, it could show the connection string by setting the show_connection_string: true before. For a convenient usage, now, by setting show_connection_string: true, it will also contain a field named key which contains the access keys.

Example can be like the following one

- name: Get facts for one account
  azure_rm_storageaccount_facts:
    resource_group: myResourceGroup
    name: clh0002
    show_connection_string: true

and the returned dict would contain the key

primary_endpoints:
{
blob:
table:
queue:
key:
}