Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
69 changes: 35 additions & 34 deletions plugins/lookup/azure_keyvault_secret.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,10 @@
description: Client id of service principal that has access to the Azure Key Vault
secret:
description: Secret of the service principal.
tenant_id:
tenant:
description: Tenant id of service principal.
aliases:
- tenant_id
use_msi:
description: MSI token autodiscover, default is true.
use_cli:
Expand All @@ -44,7 +46,7 @@
- For enabling MSI on Azure VM, please refer to this doc https://docs.microsoft.com/en-us/azure/active-directory/managed-service-identity/
- After enabling MSI on Azure VM, remember to grant access of the Key Vault to the VM by adding a new Acess Policy in Azure Portal.
- If MSI is not enabled on ansible host, it's required to provide a valid service principal which has access to the key vault.
- To authenticate via service principal, pass client_id, secret and tenant_id or set environment variables
- To authenticate via service principal, pass client_id, secret and tenant or set environment variables
AZURE_CLIENT_ID, AZURE_CLIENT_SECRET and AZURE_TENANT_ID.
- Authentication via C(az login) is also supported.
- To use a plugin from a collection, please reference the full namespace, collection name, and lookup plugin name that you want to use.
Expand Down Expand Up @@ -84,7 +86,7 @@
vault_url=url,
client_id=client_id,
secret=secret,
tenant_id=tenant,
tenant=tenant,
use_msi=false
)
}}"
Expand Down Expand Up @@ -122,14 +124,14 @@
description: secret content string
"""

from ansible_collections.azure.azcollection.plugins.module_utils.azure_rm_common import AzureRMAuth
from ansible.errors import AnsibleError
from ansible.plugins.lookup import LookupBase
from ansible.utils.display import Display
try:
import logging
import requests
from azure.keyvault.secrets import SecretClient
from azure.identity import DefaultAzureCredential, ClientSecretCredential, AzureCliCredential
from azure.keyvault.secrets import SecretClient

except ImportError:
Expand All @@ -142,47 +144,46 @@
logger = logging.getLogger("azure.identity").setLevel(logging.ERROR)


def lookup_secret_non_msi(terms, vault_url, kwargs):

client_id = kwargs['client_id'] if kwargs.get('client_id') else None
secret = kwargs['secret'] if kwargs.get('secret') else None
tenant_id = kwargs['tenant_id'] if kwargs.get('tenant_id') else None

if all(v is not None for v in [client_id, secret, tenant_id]):
credential = ClientSecretCredential(
tenant_id=tenant_id,
client_id=client_id,
client_secret=secret,
class LookupModule(LookupBase):
def lookup_secret_non_msi(self, terms, vault_url):

auth_source = 'auto'
if self.get_option('use_cli'):
auth_source = 'cli'
auth_options = dict(
auth_source=auth_source,
client_id=self.get_option('client_id'),
secret=self.get_option('secret'),
tenant=self.get_option('tenant'),
is_ad_resource=True
)
else:
if kwargs.get('use_cli'):
credential = AzureCliCredential()
else:
credential = DefaultAzureCredential()
client = SecretClient(vault_url, credential)

ret = []
for term in terms:
try:
secret_val = client.get_secret(term).value
ret.append(secret_val)
except Exception:
raise AnsibleError('Failed to fetch secret ' + term + ' from ' + vault_url + '.')
return ret
azure_auth = AzureRMAuth(**auth_options)

client = SecretClient(vault_url, azure_auth.azure_credential_track2)

class LookupModule(LookupBase):
ret = []
for term in terms:
try:
secret_val = client.get_secret(term).value
ret.append(secret_val)
except Exception:
raise AnsibleError('Failed to fetch secret ' + term + ' from ' + vault_url + '.')
return ret

def run(self, terms, variables, **kwargs):

self.set_options(direct=kwargs)

ret = []
vault_url = kwargs.pop('vault_url', None)
use_msi = kwargs.pop('use_msi', True)
vault_url = self.get_option('vault_url', None)
use_msi = self.get_option('use_msi', True)
TOKEN_ACQUIRED = False
token = None

token_params = {
'api-version': '2018-02-01',
'resource': 'https://vault.{0}.net'.format(kwargs.get('cloud_type', 'azure'))
'resource': 'https://vault.{0}.net'.format(self.get_option('cloud_type', 'azure'))
}

token_headers = {
Expand Down Expand Up @@ -221,4 +222,4 @@ def run(self, terms, variables, **kwargs):
raise AnsibleError('Failed to fetch secret ' + term + ' from ' + vault_url + ' via MSI endpoint.')
return ret
else:
return lookup_secret_non_msi(terms, vault_url, kwargs)
return self.lookup_secret_non_msi(terms, vault_url)
58 changes: 31 additions & 27 deletions plugins/lookup/azure_service_principal_attribute.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,22 +21,35 @@
description:
- Describes object id of your Azure service principal account.
options:
azure_client_id:
client_id:
description: azure service principal client id.
azure_secret:
aliases:
- azure_client_id
secret:
description: azure service principal secret
azure_tenant:
aliases:
- azure_secret
tenant:
description: azure tenant
azure_cloud_environment:
aliases:
- azure_tenant
cloud_environment:
description: azure cloud environment
aliases:
- azure_cloud_environment
notes:
- If MSI is not enabled on ansible host, it's required to provide a valid service principal which has access to the key vault.
- To authenticate via service principal, pass client_id, secret and tenant or set environment variables
AZURE_CLIENT_ID, AZURE_CLIENT_SECRET and AZURE_TENANT_ID.
- Authentication via C(az login) is also supported.
"""

EXAMPLES = """
set_fact:
object_id: "{{ lookup('azure_service_principal_attribute',
azure_client_id=azure_client_id,
azure_secret=azure_secret,
azure_tenant=azure_secret) }}"
client_id=azure_client_id,
secret=azure_secret,
tenant=azure_secret) }}"
"""

RETURN = """
Expand All @@ -45,13 +58,12 @@
Returns object id of service principal.
"""

from ansible_collections.azure.azcollection.plugins.module_utils.azure_rm_common import AzureRMAuth
from ansible.errors import AnsibleError
from ansible.plugins.lookup import LookupBase
from ansible.module_utils._text import to_native

try:
from azure.cli.core import cloud as azure_cloud
from azure.identity._credentials.client_secret import ClientSecretCredential
import asyncio
from msgraph import GraphServiceClient
from msgraph.generated.service_principals.service_principals_request_builder import ServicePrincipalsRequestBuilder
Expand All @@ -64,27 +76,19 @@ def run(self, terms, variables, **kwargs):

self.set_options(direct=kwargs)

credentials = {}
credentials['azure_client_id'] = self.get_option('azure_client_id', None)
credentials['azure_secret'] = self.get_option('azure_secret', None)
credentials['azure_tenant'] = self.get_option('azure_tenant', 'common')

if credentials['azure_client_id'] is None or credentials['azure_secret'] is None:
raise AnsibleError("Must specify azure_client_id and azure_secret")

_cloud_environment = azure_cloud.AZURE_PUBLIC_CLOUD
if self.get_option('azure_cloud_environment', None) is not None:
_cloud_environment = azure_cloud.get_cloud_from_metadata_endpoint(credentials['azure_cloud_environment'])
auth_options = dict(
client_id=self.get_option('client_id'),
secret=self.get_option('secret'),
tenant=self.get_option('tenant', 'common'),
cloud_environment=self.get_options('cloud_environment'),
is_ad_resource=True
)
azure_auth = AzureRMAuth(**auth_options)

try:
azure_credential_track2 = ClientSecretCredential(client_id=credentials['azure_client_id'],
client_secret=credentials['azure_secret'],
tenant_id=credentials['azure_tenant'],
authority=_cloud_environment.endpoints.active_directory)

client = GraphServiceClient(azure_credential_track2)
client = GraphServiceClient(azure_auth.azure_credential_track2)

response = asyncio.get_event_loop().run_until_complete(self.get_service_principals(client, credentials['azure_client_id']))
response = asyncio.get_event_loop().run_until_complete(self.get_service_principals(client, azure_auth.credentials['client_id']))
if not response:
return []
return list(response.value)[0].id.split(',')
Expand Down