I've been trying to get my python script to retrieve a secret from an Azure key vault. For the authentication I've been using the ServicePrincipal credential and the Azure-keyvault-secrets package which comes with a SecretClient class. But it's throwing an error which might be because of any updates in the python package.
Could anyone point out what's going wrong?
from azure.common.credentials import ServicePrincipalCredentials
from azure.keyvault.secrets import SecretClient
CLIENT_ID '...' #app_id
TENANT_ID = '...'
KEY = '...'
credentials = ServicePrincipalCredentials(
client_id=CLIENT_ID,
secret=KEY,
tenant=TENANT_ID
)
vault_url = '...'
secret_name = "..."
secret_version = '...'
client = SecretClient(vault_url=vault_url, credential=credentials)
secret = client.get_secret(secret_name)
It gives the following error :
Traceback (most recent call last):
File "key-vault.py", line 23, in <module>
secret = client.get_secret("cromaprivate128")
File "/Users/rishavputatunda/Library/Python/3.7/lib/python/site-packages/azure/core/tracing/decorator.py", line 71, in wrapper_use_tracer
return func(*args, **kwargs)
File "/Users/rishavputatunda/Library/Python/3.7/lib/python/site-packages/azure/keyvault/secrets/_client.py", line 71, in get_secret
**kwargs
File "/Users/rishavputatunda/Library/Python/3.7/lib/python/site-packages/azure/keyvault/secrets/_shared/_generated/v7_0/operations/_key_vault_client_operations.py", line 1621, in get_secret
pipeline_response = self._client._pipeline.run(request, stream=False, **kwargs)
File "/Users/rishavputatunda/Library/Python/3.7/lib/python/site-packages/azure/core/pipeline/_base.py", line 208, in run
return first_node.send(pipeline_request) # type: ignore
File "/Users/rishavputatunda/Library/Python/3.7/lib/python/site-packages/azure/core/pipeline/_base.py", line 80, in send
response = self.next.send(request)
File "/Users/rishavputatunda/Library/Python/3.7/lib/python/site-packages/azure/core/pipeline/_base.py", line 80, in send
response = self.next.send(request)
File "/Users/rishavputatunda/Library/Python/3.7/lib/python/site-packages/azure/core/pipeline/_base.py", line 80, in send
response = self.next.send(request)
File "/Users/rishavputatunda/Library/Python/3.7/lib/python/site-packages/azure/core/pipeline/policies/_redirect.py", line 157, in send
response = self.next.send(request)
File "/Users/rishavputatunda/Library/Python/3.7/lib/python/site-packages/azure/core/pipeline/policies/_retry.py", line 418, in send
response = self.next.send(request)
File "/Users/rishavputatunda/Library/Python/3.7/lib/python/site-packages/azure/keyvault/secrets/_shared/challenge_auth_policy.py", line 67, in send
self._handle_challenge(request, challenge)
File "/Users/rishavputatunda/Library/Python/3.7/lib/python/site-packages/azure/keyvault/secrets/_shared/challenge_auth_policy.py", line 91, in _handle_challenge
access_token = self._credential.get_token(scope)
AttributeError: 'ServicePrincipalCredentials' object has no attribute 'get_token'
We cannot use the ServicePrincipalCredentials to create a SecretClient. Because the ServicePrincipalCredentials cannot provide the access token. If you want to access key vault, please try to use the Credentials provided by sdk azure.identity.
For example
1. Create a service principal with Azure CLI
az login
az ad sp create-for-rbac -n "MyApp" --sdk-auth
Set access policy
az keyvault set-policy -n <your-unique-keyvault-name> --spn <clientId-of-your-service-principal> --secret-permissions delete get list set --key-permissions create decrypt delete encrypt get list unwrapKey wrapKe
code
from azure.identity import ClientSecretCredential
from azure.keyvault.secrets import SecretClient
tenant_id="<your sp tenant>"
client_id="<your sp client id>"
client_secret="<your sp client secret>"
credential = ClientSecretCredential(tenant_id, client_id, client_secret)
secret_client = SecretClient(vault_url="https://my-key-vault.vault.azure.net/", credential=credential)
secret = secret_client.get_secret("secret-name")
print(secret.name)
print(secret.value)
Related
I'd like to ask Azure for the details of the currently signed in user programmatically within a Python program. The program might run from the command line or within Azure batch.
Is there way to do the same thing as the azure cli does with az ad signed-in-user show, but through the Azure SDK for Python?
UPDATE:
Based on Gaurav's help and pointer to the Microsoft Graph Python Client Library, I tried the following:
from azure.identity import DefaultAzureCredential
from azure.storage.blob import BlobServiceClient, BlobClient, ContainerClient
from msgraphcore import GraphSession
credential = DefaultAzureCredential(
exclude_shared_token_cache_credential=True,
)
account_name = "mydatalake"
container_name = "test"
service = BlobServiceClient(
account_url=f"https://{account_name}.blob.core.windows.net/",
credential=credential
)
container_client = service.get_container_client(container_name)
blob_list = container_client.list_blobs()
for i, blob in enumerate(blob_list):
print("\t" + blob.name)
if i >= 9: break
scopes = ['user.read']
graph_session = GraphSession(credential, scopes)
result = graph_session.get('/me')
print(result.json())
I successfully get back blob names from a storage account. But it fails when it gets to the GraphAPI part with this stack trace:
Traceback (most recent call last):
File "py/src/azure_whoami.py", line 58, in <module>
result = graph_session.get('/me')
File "[...snip...]/site-packages/msgraphcore/middleware/options/middleware_control.py", line 24, in wrapper
return func(*args, **kwargs)
File "[...snip...]/site-packages/msgraphcore/graph_session.py", line 41, in get
return super().get(self._graph_url(url))
File "[...snip...]/site-packages/requests/sessions.py", line 555, in get
return self.request('GET', url, **kwargs)
File "[...snip...]/site-packages/requests/sessions.py", line 542, in request
resp = self.send(prep, **send_kwargs)
File "[...snip...]/site-packages/requests/sessions.py", line 655, in send
r = adapter.send(request, **kwargs)
File "[...snip...]/site-packages/msgraphcore/middleware/middleware.py", line 26,
in send
return self._middleware.send(request, **kwargs)
File "[...snip...]/site-packages/msgraphcore/middleware/authorization.py", line 16, in send
request.headers.update({'Authorization': 'Bearer {}'.format(self._get_access_token())})
File "[...snip...]/site-packages/msgraphcore/middleware/authorization.py", line 33, in _get_access_token
return self.credential.get_token(*self.scopes)[0]
File "[...snip...]/site-packages/azure/identity/_credentials/default.py", line 138, in get_token
token = self._successful_credential.get_token(*scopes, **kwargs)
File "[...snip...]/site-packages/azure/identity/_internal/decorators.py", line 27, in wrapper
token = fn(*args, **kwargs)
File "[...snip...]/site-packages/azure/identity/_credentials/azure_cli.py", line
58, in get_token
raise error
azure.identity._exceptions.CredentialUnavailableError: Please run 'az login' to set up an account
Based on the instructions provided here, you would first need to install the appropriate SDKs (msgraphcore and azure-identity).
After that your code would be something like (again taking from the same link)
# import modules
from azure.identity import UsernamePasswordCredential, DeviceCodeCredential
from msgraphcore import GraphSession
# Configuring credentials
# Added UsernamePassword for demo purposes only, please don't use this in production.
# ugly_credential = UsernamePasswordCredential('set-clientId', 'set-username', 'set-password')
device_credential = DeviceCodeCredential(
'set-clientId')
# There are many other options for getting an access token. See the following for more information.
# https://pypi.org/project/azure-identity/
# get data
scopes = ['user.read']
graph_session = GraphSession(device_credential, scopes)
result = graph_session.get('/me')
print(result.json())
I am using below python authentication script to connect to ADLS using service principal details but it keeps throwing exception:azure.core.exceptions.HttpResponseError: (AuthorizationPermissionMismatch) This request is not authorized to perform this operation using this permission.
The role assigned to me is "Storage blob data owner" and not sure what is missing?
Python Code:
from azure.storage.filedatalake import DataLakeServiceClient
from azure.identity import ClientSecretCredential
TENANT_ID = 'XXXXXXXXXX'
CLIENT_ID = 'XXXXXXXXXX'
CLIENT_SECRET = 'XXXXXXXXXX'
STORAGE_ACCOUNT_NAME = 'XXXXXXXXXX'
credential = ClientSecretCredential(TENANT_ID, CLIENT_ID, CLIENT_SECRET)
service_client = DataLakeServiceClient(account_url="{}://{}.dfs.core.windows.net".format(
"https", STORAGE_ACCOUNT_NAME), credential=credential)
print(service_client.primary_endpoint) # Can see the primary endpoint.
file_system_client = service_client.get_file_system_client("my-container")
file_system_client.create_directory("test-dir") #Throwing the (AuthorizationPermissionMismatch) error.
print("test directory created.")
Complete Trace:
Traceback (most recent call last):
File "/home//lib/python3.5/site-packages/azure/storage/filedatalake/_path_client.py", line 200, in _create
return self._client.path.create(**options)
File "/home/lib/python3.5/site-packages/azure/storage/filedatalake/_generated/operations/_path_operations.py", line 248, in create
raise HttpResponseError(response=response, model=error)
azure.core.exceptions.HttpResponseError: (AuthorizationPermissionMismatch) This request is not authorized to perform this operation using this permission.
RequestId:80605399-e01f-0038-2cd2-0a4210000000
Time:2021-02-24T17:25:49.0969802Z
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "adls_client.py", line 30, in <module>
file_system_client.create_directory("test-dir")
File "/home/lib/python3.5/site-packages/azure/storage/filedatalake/_file_system_client.py", line 540, in create_directory
directory_client.create_directory(metadata=metadata, **kwargs)
File "/home/lib/python3.5/site-packages/azure/storage/filedatalake/_data_lake_directory_client.py", line 160, in create_directory
return self._create('directory', metadata=metadata, **kwargs)
File "/home/lib/python3.5/site-packages/azure/storage/filedatalake/_path_client.py", line 202, in _create
process_storage_error(error)
File "/home/lib/python3.5/site-packages/azure/storage/filedatalake/_deserialize.py", line 150, in process_storage_error
raise error
azure.core.exceptions.HttpResponseError: (AuthorizationPermissionMismatch) This request is not authorized to perform this operation using this permission.
I can reproduce your error:
I am pretty sure your code is no problem, and, Storage blob data owner is the right RBAC role of your AD app. I think maybe the problem comes from the RBAC role does not take effect immediately, you need to wait a while. And then it should work.
I would like to use python kubernetes-client to connect to my AKS cluster api.
To do that I try to use the example give by kubernetes:
config.load_kube_config()
v1 = client.CoreV1Api()
print("Listing pods with their IPs:")
ret = v1.list_pod_for_all_namespaces(watch=False)
for i in ret.items:
print("%s\t%s\t%s" % (i.status.pod_ip, i.metadata.namespace, i.metadata.name))
It is supposed to load my local kubeconfig and get a pods list but I get the following error:
Traceback (most recent call last): File "test.py", line 4, in
config.load_kube_config() File "/Users//works/test-kube-api-python/env/lib/python2.7/site-packages/kubernetes/config/kube_config.py",
line 661, in load_kube_config
loader.load_and_set(config) File "/Users//works/test-kube-api-python/env/lib/python2.7/site-packages/kubernetes/config/kube_config.py",
line 469, in load_and_set
self._load_authentication() File "/Users//works/test-kube-api-python/env/lib/python2.7/site-packages/kubernetes/config/kube_config.py",
line 203, in _load_authentication
if self._load_auth_provider_token(): File "/Users//works/test-kube-api-python/env/lib/python2.7/site-packages/kubernetes/config/kube_config.py",
line 221, in _load_auth_provider_token
return self._load_azure_token(provider) File "/Users//works/test-kube-api-python/env/lib/python2.7/site-packages/kubernetes/config/kube_config.py",
line 233, in _load_azure_token
self._refresh_azure_token(provider['config']) File "/Users//works/test-kube-api-python/env/lib/python2.7/site-packages/kubernetes/config/kube_config.py",
line 253, in _refresh_azure_token
refresh_token, client_id, '00000002-0000-0000-c000-000000000000') File
"/Users//works/test-kube-api-python/env/lib/python2.7/site-packages/adal/authentication_context.py",
line 236, in acquire_token_with_refresh_token
return self._acquire_token(token_func) File "/Users//works/test-kube-api-python/env/lib/python2.7/site-packages/adal/authentication_context.py",
line 128, in _acquire_token
return token_func(self) File "/Users//works/test-kube-api-python/env/lib/python2.7/site-packages/adal/authentication_context.py",
line 234, in token_func
return token_request.get_token_with_refresh_token(refresh_token, client_secret) File
"/Users//works/test-kube-api-python/env/lib/python2.7/site-packages/adal/token_request.py",
line 343, in get_token_with_refresh_token
return self._get_token_with_refresh_token(refresh_token, None, client_secret) File
"/Users//works/test-kube-api-python/env/lib/python2.7/site-packages/adal/token_request.py",
line 340, in _get_token_with_refresh_token
return self._oauth_get_token(oauth_parameters) File "/Users//works/test-kube-api-python/env/lib/python2.7/site-packages/adal/token_request.py",
line 112, in _oauth_get_token
return client.get_token(oauth_parameters) File "/Users//works/test-kube-api-python/env/lib/python2.7/site-packages/adal/oauth2_client.py",
line 291, in get_token
raise AdalError(return_error_string, error_response) adal.adal_error.AdalError: Get Token request returned http error: 400
and server response:
{"error":"invalid_grant","error_description":"AADSTS65001: The user or
administrator has not consented to use the application with ID
'' named 'Kubernetes AD Client
'. Send an interactive authorization request for this user and
resource.\r\nTrace ID:
\r\nCorrelation ID:
\r\nTimestamp: 2019-10-14
12:32:35Z","error_codes":[65001],"timestamp":"2019-10-14
12:32:35Z","trace_id":"","correlation_id":"","suberror":"consent_required"}
I really don't understand why it doesn't work.
When I use kubectl, all work fine.
I read some docs but I'm not sure to understand the adal error.
Thanks for your help
Login as a tenant admin to https://portal.azure.com
Open the registration for your app in the
Go to Settings then Required Permissions
Press the Grant Permissions button
If you are not a tenant admin, you cannot give admin consent
From https://github.com/Azure-Samples/active-directory-angularjs-singlepageapp-dotnet-webapi/issues/19
This is good post where you can find snippet to authenticate to AKS:
from azure.identity import AzureCliCredential
from azure.mgmt.resource import ResourceManagementClient
from azure.mgmt.containerservice import ContainerServiceClient
from azure.mgmt.containerservice.models import (ManagedClusterAgentPoolProfile,
ManagedCluster)
credential = AzureCliCredential()
subscription_id = "XXXXX"
resource_group= 'MY-RG'
resouce_client=ResourceManagementClient(credential,subscription_id)
container_client=ContainerServiceClient(credential,subscription_id)
resouce_list=resouce_client.resources.list_by_resource_group(resource_group)
Note: You need to install respective Az Python SKD libraries.
I am trying to implement the Backend Application flow to get an access token from the Datahug API (Following instructions in https://api.datahug.com/#gettingstarted).
from oauthlib.oauth2 import BackendApplicationClient
from requests_oauthlib import OAuth2Session
def get_access_token():
token_url = 'https://apps.datahug.com/identity/connect/token'
client_id = CLIENT_ID
client_secret = CLIENT_SECRET
scope = 'datahug_api'
client = BackendApplicationClient(client_id=client_id)
client.prepare_request_body(scope=[scope])
oauth = OAuth2Session(client=client)
token = oauth.fetch_token(token_url=token_url,
client_id=client_id,
client_secret=client_secret)
return token
if __name__ == '__main__':
token = get_access_token()
print(token)
When running this code I'm getting an InvalidScopeError, namely
user:dh user$ python so_test.py
Traceback (most recent call last):
File "so_test.py", line 21, in <module>
token = get_access_token()
File "so_test.py", line 17, in get_access_token
client_secret=client_secret)
File "/Users/user/anaconda3/lib/python3.5/site-packages/requests_oauthlib/oauth2_session.py", line 244, in fetch_token
self._client.parse_request_body_response(r.text, scope=self.scope)
File "/Users/user/anaconda3/lib/python3.5/site-packages/oauthlib/oauth2/rfc6749/clients/base.py", line 409, in parse_request_body_response
self.token = parse_token_response(body, scope=scope)
File "/Users/user/anaconda3/lib/python3.5/site-packages/oauthlib/oauth2/rfc6749/parameters.py", line 376, in parse_token_response
validate_token_parameters(params)
File "/Users/user/anaconda3/lib/python3.5/site-packages/oauthlib/oauth2/rfc6749/parameters.py", line 383, in validate_token_parameters
raise_from_error(params.get('error'), params)
File "/Users/user/anaconda3/lib/python3.5/site-packages/oauthlib/oauth2/rfc6749/errors.py", line 325, in raise_from_error
raise cls(**kwargs)
oauthlib.oauth2.rfc6749.errors.InvalidScopeError: (invalid_scope)
It seems that the problem is in the value scope='datahug_api', but this is the value suggested in the datahug api. Any suggestions on how to solve this much appreciated.
You are missing scope in the oauth.fetch_token().
So, your variable token should be:
token = oauth.fetch_token(token_url=token_url,scope=scope,client_id=client_id,
client_secret=client_secret)
I had success adding the scope to the BackendApplicationClient as can be seen from the developer docs.
client = BackendApplicationClient(client_id=client_id, scope=scope)
oauth = OAuth2Session(client=client)
token = oauth.fetch_token(token_url=url, client_id=client_id, client_secret=client_secret)
I am using the requests_oauthlib module for OAuth authentication.
Unfortunately I cannot reproduce the OAuth1 workflow acoording to step one in this tutorial: http://requests-oauthlib.readthedocs.org/en/latest/oauth1_workflow.html
If I try to obtain a fetch response it throws me the followin error:
Traceback (most recent call last):
File "/home/neumannr/test.py", line 18, in <module>
fetch_response = oauth.fetch_request_token(request_token_url)
File "/usr/lib/python2.7/site-packages/requests_oauthlib/oauth1_session.py", line 195, in fetch_request_token
token = self._fetch_token(url)
File "/usr/lib/python2.7/site-packages/requests_oauthlib/oauth1_session.py", line 264, in _fetch_token
token = dict(urldecode(self.post(url).text))
File "/usr/lib/python2.7/site-packages/oauthlib/common.py", line 135, in urldecode
raise ValueError('Not a valid urlencoded string.')
ValueError: Not a valid urlencoded string.
My testing code looks as follows:
#! /usr/bin/env python
# Using OAuth1Session
from requests_oauthlib import OAuth1Session
# Using OAuth1 auth helper
import requests
from requests_oauthlib import OAuth1
client_key = 'a'
client_secret = 'b'
request_token_url = 'https://api.twitter.com/oauth/request_token'
# Using OAuth1Session
oauth = OAuth1Session(client_key, client_secret=client_secret)
fetch_response = oauth.fetch_request_token(request_token_url)
Since the URL is not being URL encoded within the tutorial either, I do not understand why this happens. If I try to URL encode the URL like this:
#! /usr/bin/env python
# Using OAuth1Session
import urllib
from requests_oauthlib import OAuth1Session
# Using OAuth1 auth helper
import requests
from requests_oauthlib import OAuth1
client_key = 'a'
client_secret = 'b'
request_token_url = urllib.quote('https://api.twitter.com/oauth/request_token')
# Using OAuth1Session
oauth = OAuth1Session(client_key, client_secret=client_secret)
fetch_response = oauth.fetch_request_token(request_token_url)
I get a missing schema error:
Traceback (most recent call last):
File "/home/neumannr/test.py", line 19, in <module>
fetch_response = oauth.fetch_request_token(request_token_url)
File "/usr/lib/python2.7/site-packages/requests_oauthlib/oauth1_session.py", line 195, in fetch_request_token
token = self._fetch_token(url)
File "/usr/lib/python2.7/site-packages/requests_oauthlib/oauth1_session.py", line 264, in _fetch_token
token = dict(urldecode(self.post(url).text))
File "/usr/lib/python2.7/site-packages/requests/sessions.py", line 377, in post
return self.request('POST', url, data=data, **kwargs)
File "/usr/lib/python2.7/site-packages/requests/sessions.py", line 324, in request
prep = req.prepare()
File "/usr/lib/python2.7/site-packages/requests/models.py", line 222, in prepare
p.prepare_url(self.url, self.params)
File "/usr/lib/python2.7/site-packages/requests/models.py", line 291, in prepare_url
raise MissingSchema("Invalid URL %r: No schema supplied" % url)
requests.exceptions.MissingSchema: Invalid URL u'https%3A//api.twitter.com/oauth/request_token': No schema supplied
How do I use oauthlib_requests anyway?
Thanks,
Richard
The error can be a result of a failed attempt to decode the response. For more details, please see OAuthlib issue 124.