How to pass Azure service principal details to Ansible via command-line? - azure

I am able to connect to Azure using Ansible by putting my service principle details into the credentials file stored in ~/.azure/credentials
That was OK for development, now (in production) I want to move away from using the text credentials file and pass the credentials to Ansible via the command-line via parameters.
How should this be done?
Any help is appreciated - thanks
I have tried:
ansible-playbook -i ./dev-env/epazure_rm.yml ./dev-env/site.yml -vvvv -u adminuser --extra-vars "AZURE_SUBSCRIPTION_ID=XXX AZURE_CLIENT_ID=XXX AZURE_SECRET=XXX AZURE_TENANT=XXX"
My Azure Dynamic Inventory plugin file looks like this
---
plugin: azure_rm
include_vm_resource_groups:
- rg-devdonal-eastus01
auth_source: auto
subscription_id: "{{ AZURE_SUBSCRIPTION_ID }}"
client_id: "{{ AZURE_CLIENT_ID }}"
secret: "{{ AZURE_SECRET }}"
tenant: "{{ AZURE_TENANT }}"
keyed_groups:
- prefix: tag
key: tags

You can use the environment variables for the credential and then read the variables from the environment, here is the example:
- debug: msg="{{ lookup('env','HOME') }} is an environment variable"
And there is also another issue shows the example.

Related

How to refer to AWX credentials in my ansible playbook

I'm new to ansible . I'm trying to use an existing playbook but deploy it to a different Azure account with seperate credentials but I'm running into some issues. I created a new credential via the AWX portal with my client_id, tenant_id, subscription_id and secret but I cant figure out how to get my playbook to pull this credential instead of the one its currently using.
My playbook authentication role authenticates like so
- name: 'Authenticating against Azure'
command: >
az login --service-principal
-u '{{ vault_azure_client_id }}'
-p '{{ vault_azure_client_secret }}'
-t '{{ vault_azure_tenant_id }}'
there is then a secrets folder with a vault file containing what looks like an encrypted string and starting with the below
$ANSIBLE_VAULT;1.1
My main file declares the variable like below
# Environment Variables
environment:
AZURE_CLIENT_ID: '{{ vault_azure_client_id }}'
AZURE_SECRET: '{{ vault_azure_client_secret }}'
AZURE_TENANT: '{{ vault_azure_tenant_id }}'
How do i edit the main file and role to point at my creds created through the console instead of the ones stored in ansible vault?
This is because by default your playbook file taking credential from vault file. Point to your main file to take credential rather than default file (Vault file).
Variables can come from different sources, such as the playbook file itself or external variable files that are imported in the playbook. Special precedence rules will apply when working with multiple variable sources that define a variable with the same name.
Suggestion 1 : If you are using variable in playbook file itself you pass use the variable like this.
vars:
- AZURE_CLIENT_ID: Client ID
- AZURE_SECRET: Client Secret Value
- AZURE_TENANT: Tenant ID
tasks:
- name: 'Authenticating against Azure'
command: >
az login --service-principal
-u '{{ AZURE_CLIENT_ID}}'
-p '{{ AZURE_SECRET }}'
-t '{{ AZURE_TENANT}}'
Reference : https://www.digitalocean.com/community/tutorials/how-to-use-variables-in-ansible-playbooks
Suggestion 2 : You can also pass the extra variables to an Ansible playbook using
--extra-vars or -e option while running the Ansible playbook, as seen below.
#ansible-playbook myplaybook.yaml --extra-vars "nodes=webgroup”
You can refer this Document to pass the variable from outside.
Assuming your unencrypted "vault file" in your "secrets folder" looks like this:
vault_azure_client_id: foo
vault_azure_client_secret: bar
vault_azure_tenant_id : baz
You have two options:
Stop using this file and configure these variables in AWX. You don't define these variables as credentials in AWX, you need to define them in the job template that calls the playbook.
Rewrite your "vault file" putting your secret variables inline. E.g:
vault_azure_client_id: !vault |
$ANSIBLE_VAULT;1.2;AES256;dev
30613...
vault_azure_client_secret: !vault |
$ANSIBLE_VAULT;1.2;AES256;dev
30613...
vault_azure_tenant_id : !vault |
$ANSIBLE_VAULT;1.2;AES256;dev
30613...
AWX has the limitation of not being able to decrypt variables in an encrypted file, but it could decrypt variables encrypted inline.

Unable to encrypt Azure storage account using ansible

I am unable to set encryption for the storage account once the storage account created successfully. I am creating the below playbooks for the storage account and encryption.
- name: storage_account_creation | deploy storage account
azure_rm_storageaccount:
state: present
cloud_environment: "AzureCloud"
subscription_id: "XXXX-XXXX-XXXX-XXX"
resource_group_name: "XXXX-XXXX-XXXX-XXXX"
client_id: "XXXX-XXXX-XXXX-XXXX"
secret: "XXXX-XXXX-XXXX-XXXX"
tenant: "XXXX-XXXX-XXXX-XXX"
location: "{{ azloc['stdout_lines'][0] }}"
kind: BlobStorage
access_tier: "Hot"
name: "storageaccount_001"
account_type: "Standard_LRS"
network_acls:
bypass: AzureServices
default_action: deny
encrypt.yml
- name: encrypt | Get keyvault name from id
set_fact:
keyvaultname: "XXXXXXXXXX"
- name: encrypt | Get object id of storage account
shell: az storage account show --subscription "{{ subscription_id }}" -n "{{ Storageaccount_name }}" --query "identity.principalId" --output tsv
register: azsaobjectid
- debug:
var: azsaobjectid
- name: encrypt | Create key vault access policy for new storage account
shell: az keyvault set-policy --subscription "{{ subscription_id }}" -n {{ keyvaultname }}" --key-permissions get wrapKey unwrapKey --object-id "{{ azsaobjectid.stdout_lines[0] }}"
When I execute the scripts I get the below error
fatal: [localhost]: FAILED! =>
msg: |-
The task includes an option with an undefined variable. The error was: list object has no element 0
The error appears to be in 'encrypt.yml': line 10, column 4, but may
be elsewhere in the file depending on the exact syntax problem.
The offending line appears to be:
- name: encrypt | Create key vault access policy for new storage account
^ here
The error details suggest that you are using a variable that hasn't been defined. I suspect this is from your register block in get object id of storage account.
However...
Consider re-writing these tasks to use official azure modules.
Shelling out should be a last resort, and from the look of it, you can accomplish your goal by using the azure_rm_storageaccount_info_module module to gather facts, and azure_rm_keyvault module to set your policy.
Using official modules ensures your playbook is idempotent, easier to read, and your error details will likely become clearer as well.

Ansible Azure Dynamic Inventory and Sharing variables between hosts in a single playbook

Problem: referencing a fact about a host ( in this case, the private ip ) from another host in a playbook using a wildcard only seems to work in the "Host" part of a playbook, not inside a task. vm_ubuntu* cannot be used in a task.
In a single playbook, I have a couple of hosts, and because the inventory is dynamic, I don't have the hostname ahead of time as Azure appends an identifier after it has been created.
I am using TF to create.
And using the Azure dynamic inventory method.
I am calling my playbook like this, where myazure_rm.yml is a bog standard azure dynamic inventory method, as of the time of this writing.
ansible-playbook -i ./myazure_rm.yml ./bwaf-playbook.yaml --key-file ~/.ssh/id_rsa --u azureuser
My playbook looks like this ( abbreviated ).
- hosts: vm_ubuntu*
tasks:
- name: housekeeping
set_fact:
vm_ubuntu_private_ip="{{ hostvars[inventory_hostname]['ansible_default_ipv4']['address'] }}"
#"
- debug: var=vm_ubuntu_private_ip
- hosts: vm_bwaf*
connection: local
vars:
vm_bwaf_private_ip: "{{private_ipv4_addresses | join }}"
vm_bwaf_public_ip: "{{ public_ipv4_addresses | join }}"
vm_ubuntu_private_ip: "{{ hostvars['vm_ubuntu*']['ip'] }}"
api_url: "http://{{ vm_bwaf_public_ip }}:8000/restapi/{{ api_version }}"
#"
I am answering my own question to get rep, and to to help others of course.
I also want to thank the person ( https://stackoverflow.com/users/4281353/mon ) who came up with this first, which appears in here: How do I set register a variable to persist between plays in ansible?
- name: "Save private ip to dummy host"
add_host:
name: "dummy_host"
ip: "{{ vm_ubuntu_private_ip }}"
And then this can be referenced in the other host in the playbook like this:
- hosts: vm_bwaf*
connection: local
vars:
vm_bwaf_private_ip: "{{private_ipv4_addresses | join }}"
vm_bwaf_public_ip: "{{ public_ipv4_addresses | join }}"
vm_ubuntu_private_ip: "{{ hostvars['dummy_host']['ip'] }}"

How do we use encoded value in playbook and decode it whenever needed in ansible playbook?

I am trying to use ansible-pull method for running a playbooks with extra vars on run time of playbooks.
Here is how i needed to run my playbook with vars looks like.
ansible-playbook decode.yml --extra-vars "host_name=xxxxxxx bind_password=xxxxxxxxx swap_disk=xxxxx"
The bind_password will have encoded value of admin password.
and i have tried writing below playbook for it.
I am able to debug every value and getting it correctly but after decoding password not getting exact value or not sure whether i am doing it correct or not?
---
- name: Install and configure AD authentication
hosts: test
become: yes
become_user: root
vars:
hostname: "{{ host_name }}"
diskname: "{{ swap_disk }}"
password: "{{ bind_password }}"
tasks:
- name: Ansible prompt example.
debug:
msg: "{{ bind_password }}"
- name: Ansible prompt example.
debug:
msg: "{{ host_name }}"
- name: Ansible prompt example.
debug:
msg: "{{ swap_disk }}"
- name: Setup the hostname
command: hostnamectl set-hostname --static "{{ host_name }}"
- name: decode passwd
command: export passwd=$(echo "{{ bind_password }}" | base64 --decode)
- name: print decoded password
shell: echo "$passwd"
register: mypasswd
- name: debug decode value
debug:
msg: "{{ mypasswd }}"
but while we can decode base64 value with command:
echo "encodedvalue" | base64 --decode
How can i run this playbook with ansible-pull as well.
later i want to convert this playbook into roles (role1) and then needs to run it as below:
How can we run role based playbook using ansible-pull?
The problem is not b64decoding your value. Your command should not cause any problems and probably gives the expected result if you type it manually in your terminal.
But ansible is creating an ssh connection for each task, therefore each shell/command task starts on a new session. So exporting an env var in one command task and using that env var in the next shell task will never work.
Moreover, why do you want to handle all this with so many command/shell tasks when you have all the needed tools directly in ansible ? Here is a possible rewrite of your last 3 tasks that fits into a single one.
- name: debug decoded value of bind_password
debug:
msg: "{{ bind_password | b64decode }}"

Calling Terraform from Ansible

When i am using terraform modules directly being called from shell scripts it works fine.
But when i am wrapping same shell script which is called from an ansible task it fails. validated all the environment variables for ARM credentials which are being passed. All are fine, but somehow not getting any success to run terraform as an ansible task.
Below is the error I get
Error refreshing state: 1 error(s) occurred:\n\n* module.oracle_server.provider.azurerm: Unable to list provider registration status, it is possible that this is due to invalid credentials or the service principal does not have permission to use the Resource Manager API, Azure error: azure.BearerAuthorizer#WithAuthorization: Failed to refresh the Token for request to https://management.azure.com/subscriptions/****/providers?api-version=2016-02-01: StatusCode=0 -- Original Error: adal:
UPDATEd by the editor
Please update your ansible codes here, more than in comment, lost all format.
- name: Terraform Module
terraform:
project_path: "{{ terraform_module_path }}"
state: "{{ item.infra_state }}"
variables:
platform: "{{ platform }}"
application_name: "{{ application_name }}"
environment: "{{ env }}"
From the error message, it can't properly set the azure credentials, so please check if you include the provider codes or not.
# Configure the Azure Provider
provider "azurerm" {
# whilst the `version` attribute is optional, we recommend pinning to a given version of the Provider
version = "=1.21.0"
}
Reference: https://www.terraform.io/docs/providers/azurerm/

Resources