Skip to content

Commit fd7b3b6

Browse files
authored
Update lookup plugins to support ENV vars (#2084)
By using the AzureRMAuth class we are consistent with how all modules create their credentials. Also fix inconsistencies with how client_id, secret and tenant are specified.
1 parent 7c85083 commit fd7b3b6

File tree

2 files changed

+66
-61
lines changed

2 files changed

+66
-61
lines changed

plugins/lookup/azure_keyvault_secret.py

Lines changed: 35 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,10 @@
3030
description: Client id of service principal that has access to the Azure Key Vault
3131
secret:
3232
description: Secret of the service principal.
33-
tenant_id:
33+
tenant:
3434
description: Tenant id of service principal.
35+
aliases:
36+
- tenant_id
3537
use_msi:
3638
description: MSI token autodiscover, default is true.
3739
use_cli:
@@ -44,7 +46,7 @@
4446
- For enabling MSI on Azure VM, please refer to this doc https://docs.microsoft.com/en-us/azure/active-directory/managed-service-identity/
4547
- 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.
4648
- If MSI is not enabled on ansible host, it's required to provide a valid service principal which has access to the key vault.
47-
- To authenticate via service principal, pass client_id, secret and tenant_id or set environment variables
49+
- To authenticate via service principal, pass client_id, secret and tenant or set environment variables
4850
AZURE_CLIENT_ID, AZURE_CLIENT_SECRET and AZURE_TENANT_ID.
4951
- Authentication via C(az login) is also supported.
5052
- To use a plugin from a collection, please reference the full namespace, collection name, and lookup plugin name that you want to use.
@@ -84,7 +86,7 @@
8486
vault_url=url,
8587
client_id=client_id,
8688
secret=secret,
87-
tenant_id=tenant,
89+
tenant=tenant,
8890
use_msi=false
8991
)
9092
}}"
@@ -122,14 +124,14 @@
122124
description: secret content string
123125
"""
124126

127+
from ansible_collections.azure.azcollection.plugins.module_utils.azure_rm_common import AzureRMAuth
125128
from ansible.errors import AnsibleError
126129
from ansible.plugins.lookup import LookupBase
127130
from ansible.utils.display import Display
128131
try:
129132
import logging
130133
import requests
131134
from azure.keyvault.secrets import SecretClient
132-
from azure.identity import DefaultAzureCredential, ClientSecretCredential, AzureCliCredential
133135
from azure.keyvault.secrets import SecretClient
134136

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

144146

145-
def lookup_secret_non_msi(terms, vault_url, kwargs):
146-
147-
client_id = kwargs['client_id'] if kwargs.get('client_id') else None
148-
secret = kwargs['secret'] if kwargs.get('secret') else None
149-
tenant_id = kwargs['tenant_id'] if kwargs.get('tenant_id') else None
150-
151-
if all(v is not None for v in [client_id, secret, tenant_id]):
152-
credential = ClientSecretCredential(
153-
tenant_id=tenant_id,
154-
client_id=client_id,
155-
client_secret=secret,
147+
class LookupModule(LookupBase):
148+
def lookup_secret_non_msi(self, terms, vault_url):
149+
150+
auth_source = 'auto'
151+
if self.get_option('use_cli'):
152+
auth_source = 'cli'
153+
auth_options = dict(
154+
auth_source=auth_source,
155+
client_id=self.get_option('client_id'),
156+
secret=self.get_option('secret'),
157+
tenant=self.get_option('tenant'),
158+
is_ad_resource=True
156159
)
157-
else:
158-
if kwargs.get('use_cli'):
159-
credential = AzureCliCredential()
160-
else:
161-
credential = DefaultAzureCredential()
162-
client = SecretClient(vault_url, credential)
163160

164-
ret = []
165-
for term in terms:
166-
try:
167-
secret_val = client.get_secret(term).value
168-
ret.append(secret_val)
169-
except Exception:
170-
raise AnsibleError('Failed to fetch secret ' + term + ' from ' + vault_url + '.')
171-
return ret
161+
azure_auth = AzureRMAuth(**auth_options)
172162

163+
client = SecretClient(vault_url, azure_auth.azure_credential_track2)
173164

174-
class LookupModule(LookupBase):
165+
ret = []
166+
for term in terms:
167+
try:
168+
secret_val = client.get_secret(term).value
169+
ret.append(secret_val)
170+
except Exception:
171+
raise AnsibleError('Failed to fetch secret ' + term + ' from ' + vault_url + '.')
172+
return ret
175173

176174
def run(self, terms, variables, **kwargs):
175+
176+
self.set_options(direct=kwargs)
177+
177178
ret = []
178-
vault_url = kwargs.pop('vault_url', None)
179-
use_msi = kwargs.pop('use_msi', True)
179+
vault_url = self.get_option('vault_url', None)
180+
use_msi = self.get_option('use_msi', True)
180181
TOKEN_ACQUIRED = False
181182
token = None
182183

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

188189
token_headers = {
@@ -221,4 +222,4 @@ def run(self, terms, variables, **kwargs):
221222
raise AnsibleError('Failed to fetch secret ' + term + ' from ' + vault_url + ' via MSI endpoint.')
222223
return ret
223224
else:
224-
return lookup_secret_non_msi(terms, vault_url, kwargs)
225+
return self.lookup_secret_non_msi(terms, vault_url)

plugins/lookup/azure_service_principal_attribute.py

Lines changed: 31 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -21,22 +21,35 @@
2121
description:
2222
- Describes object id of your Azure service principal account.
2323
options:
24-
azure_client_id:
24+
client_id:
2525
description: azure service principal client id.
26-
azure_secret:
26+
aliases:
27+
- azure_client_id
28+
secret:
2729
description: azure service principal secret
28-
azure_tenant:
30+
aliases:
31+
- azure_secret
32+
tenant:
2933
description: azure tenant
30-
azure_cloud_environment:
34+
aliases:
35+
- azure_tenant
36+
cloud_environment:
3137
description: azure cloud environment
38+
aliases:
39+
- azure_cloud_environment
40+
notes:
41+
- If MSI is not enabled on ansible host, it's required to provide a valid service principal which has access to the key vault.
42+
- To authenticate via service principal, pass client_id, secret and tenant or set environment variables
43+
AZURE_CLIENT_ID, AZURE_CLIENT_SECRET and AZURE_TENANT_ID.
44+
- Authentication via C(az login) is also supported.
3245
"""
3346

3447
EXAMPLES = """
3548
set_fact:
3649
object_id: "{{ lookup('azure_service_principal_attribute',
37-
azure_client_id=azure_client_id,
38-
azure_secret=azure_secret,
39-
azure_tenant=azure_secret) }}"
50+
client_id=azure_client_id,
51+
secret=azure_secret,
52+
tenant=azure_secret) }}"
4053
"""
4154

4255
RETURN = """
@@ -45,13 +58,12 @@
4558
Returns object id of service principal.
4659
"""
4760

61+
from ansible_collections.azure.azcollection.plugins.module_utils.azure_rm_common import AzureRMAuth
4862
from ansible.errors import AnsibleError
4963
from ansible.plugins.lookup import LookupBase
5064
from ansible.module_utils._text import to_native
5165

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

6577
self.set_options(direct=kwargs)
6678

67-
credentials = {}
68-
credentials['azure_client_id'] = self.get_option('azure_client_id', None)
69-
credentials['azure_secret'] = self.get_option('azure_secret', None)
70-
credentials['azure_tenant'] = self.get_option('azure_tenant', 'common')
71-
72-
if credentials['azure_client_id'] is None or credentials['azure_secret'] is None:
73-
raise AnsibleError("Must specify azure_client_id and azure_secret")
74-
75-
_cloud_environment = azure_cloud.AZURE_PUBLIC_CLOUD
76-
if self.get_option('azure_cloud_environment', None) is not None:
77-
_cloud_environment = azure_cloud.get_cloud_from_metadata_endpoint(credentials['azure_cloud_environment'])
79+
auth_options = dict(
80+
client_id=self.get_option('client_id'),
81+
secret=self.get_option('secret'),
82+
tenant=self.get_option('tenant', 'common'),
83+
cloud_environment=self.get_options('cloud_environment'),
84+
is_ad_resource=True
85+
)
86+
azure_auth = AzureRMAuth(**auth_options)
7887

7988
try:
80-
azure_credential_track2 = ClientSecretCredential(client_id=credentials['azure_client_id'],
81-
client_secret=credentials['azure_secret'],
82-
tenant_id=credentials['azure_tenant'],
83-
authority=_cloud_environment.endpoints.active_directory)
84-
85-
client = GraphServiceClient(azure_credential_track2)
89+
client = GraphServiceClient(azure_auth.azure_credential_track2)
8690

87-
response = asyncio.get_event_loop().run_until_complete(self.get_service_principals(client, credentials['azure_client_id']))
91+
response = asyncio.get_event_loop().run_until_complete(self.get_service_principals(client, azure_auth.credentials['client_id']))
8892
if not response:
8993
return []
9094
return list(response.value)[0].id.split(',')

0 commit comments

Comments
 (0)