Fetch Azure Managed Identity from within Function - python

I am using Azure Managed Identity feature for my python Azure Functions App
and would like to be able to fetch currently assigned Client ID from within the Function App itself.
Search through documentation and azure-identity python sources did not give result I would expect.
Maybe I could:
Query Azure Instance Metadata Service myself to get this ID. (not really happy with this option)
Provision it as env variable during ARM deployment stage/ or by hands later on. (seems good and efficient, but not sure what is the best practice here)
UPDATE
Managed o get it working with ARM template and env variable
Deploys FunctionApp with System Identity
Provisions System Identity as env variable of this same FunctionApp
Idea is to use Microsoft.Resources/deployments subtemplate to update Function App configuration with:
{
"name": "AZURE_CLIENT_ID",
"value": "[reference(resourceId('Microsoft.Web/sites', variables('appName')), '2019-08-01', 'full').identity.principalId]"
},

The simplest option is to go to the identity tab for your Functions app, and turn on "System assigned managed identity".
You can then get the access token without having to provide the client_id, since the token request simply picks the system assigned identity if there is one for the Function app.
If you are using "user assigned managed identity", then you need to provide the client_id: either through env or directly in your code.
You may already be aware, but just an additional note: that you also need to make sure you have given access to your managed identity for the resource you are accessing, for example: going to the Azure resource your Function app needs to access and assigning an appropriate role for your managed identity.
your option 1 (query Azure Instance Metadata Service), is only available on VMs.
UPDATE
Since you need the client_id for other purposes, you may also consider reading it from the response to your request for the access token: client_id is one of the parameters in the JSON token returned to you along with the access token, and its value is the client_id of the managed identity you used (in your case, the system-assigned managed identity)
Here is a sample token response to illustrate this:
{
access_token: <...>,
resource: <...>,
token_type: 'Bearer',
client_id: <client_id of the managed identity used to get this token>
}

Related

Unit test app using local JSON for GCP authentication?

I want to Unit test a some FastAPI API endpoints which utilizes Google Cloud Platfrom, I want to write the test without using os.environ["GOOGLE_APPLICATION_CREDENTIALS"]='path_to_json_file.json' in the files to authenticate (as this service will be in the cloud soon). Is there a way to mock this?
It's slightly unclear from your question but it is unlikely that you would ever want to set GOOGLE_APPLICATION_CREDENTIALS from within your code, partly for this reason.
You should set the variable from the environment:
GOOGLE_APPLICATION_CREDENTIALS=/path/to/your/key.json
python3 your_code.py
Application Default Credentials (ADC) looks for credentials in 3 locations:
GOOGLE_APPLICATION_DEFAULT environment variable
gcloud application-default login
The compute service's identity
For this reason, setting the variable explicitly in code, overrides the possibility of #2 (less important) and #3 (more important).
If you set the variable outside of the code when you run the code for testing etc., the credentials will be found automatically and the code will be auth'd.
When you don't set the variable because the code is running on a compute service (e.g. Cloud Run, Compute Engine ...), the service's credentials will be used automatically by ADC and the code will be auth'd.

Pulumi inputs outpus and resource dependency Python GCP

I'm having some trouble in trying to understand how to pass an output of a resource as an input to another resource, so they have a dependency and the order at the creation time works properly.
Scenario:
Resource B has a dependency from Resource A.
I was trying to pass to resource B something like these
opts = ResourceOptions(depends_on=[ResourceA])
But for some reason, it acts as that parameter wasn't there and keeps creating Resource B before creating Resource A, therefore throwing an error.
If I execute pulumi up a second time, as Resource A exists, Resource B gets created.
I noticed that you could also pass an output as an input of another resource, and because of this, Pulumi understands that there is a relationship and makes it so automatically
https://www.pulumi.com/docs/intro/concepts/inputs-outputs/
But I can't get my head around it in how to pass that, so, any help regarding this would be appreciate it.
I also used the following explanation regarding how to use ResourceOptions, which I think that I'm using it correctly as the code above, but still no case
How to control resource creation order in Pulumi
Thanks in advance.
#mrthopson,
Let me try to explain using one of the public examples. I took it from this Pulumi example:
https://github.com/pulumi/examples/blob/master/aws-ts-eks/index.ts
// Create a VPC for our cluster.
const vpc = new awsx.ec2.Vpc("vpc", { numberOfAvailabilityZones: 2 });
// Create the EKS cluster itself and a deployment of the Kubernetes dashboard.
const cluster = new eks.Cluster("cluster", {
vpcId: vpc.id,
subnetIds: vpc.publicSubnetIds,
instanceType: "t2.medium",
desiredCapacity: 2,
minSize: 1,
maxSize: 2,
});
The example first creates a VPC in AWS. The VPC contains a number of different networks and the identifiers of these networks are exposed as outputs. When we create the EKS cluster, we pass the ids of the public subnets (output vpc.publicSubnetIds) as an input to the cluster (input: subnetIds).
That is the only thing you need to do to have a dependency from the EKS cluster on the VPC. When running Pulumi, the engine will find out it first needs to create the VPC and only after that it can create the EKS cluster.
Ringo

How to pull values from TSI using session ID and tag name

I am trying to pull values from Time series insights using the session ID, environment name and tag name using python.
The steps that I have figured out is as follows.
I was able to get the session using the access token using which I am ale to reach the TSI environment which have the tag values I would want to pull.
to get the session using the access token
headers = {"Authorization": auth_token}
tsi_session = requests.Session()
tsi_session.params = params
tsi_session.headers.update(headers)
to use the session and access the TSI environment
tsi_environment = tsi_api_wrapper.get_tsi_environment(session=tsi_session, environment_name="some_name")
print(tsi_environment)
I was able to get the environment properties.
What would be the next step to get the values of a particular tag without using client ID and client secret but only the above mentioned inputs.
any help would be much appreciated.
to call Azure TSI's REST APIs you will always need to provide an Azure AD JWT token, and the identity retrieving the token will always first be required to authenticate. Thus, there will always need to be some sort of secret whether it's a user's password, client sec, certificate etc.
I see you got an auth token, nice. Is the object ID of the token the app's ID? I assume that you're looking for samples on how to have your web app facilitate an interactive user-login and that the app will call TSI as a downstream API? I believe you'll need to find the python equivalent of this sample. Note that your questions are more around obtaining auth tokens, rather than TSI-specific questions, thus you might consider tagging "azure-active-directory" instead.
Is this list of users fixed, or would it be dynamically changing? If it's dynamic then that may be problematic since the object ID within the token must have a role assignment for the TSI environment. In that case, you can instead have the users log into the app, but then app itself could turn around and call the TSI APIs as a service principal.
I found this post which seems applicable to your situation https://towardsdatascience.com/how-to-secure-python-flask-web-apis-with-azure-ad-14b46b8abf22

How to get account id and region dynamically while creating cloudwatch alarm via API

I am making AutoRecovery alarm via API and i want to make my code work in any system by just calling the python script. but as every one has unique AWS account id and region can also be different, so i want to fetch account id and region dynamically.
get-caller-identity is used for account id. but i ain't able to get how to use this function basically!
To identify these attributes of a particular EC2 instance from code running on the EC2 instance itself, use the Instance Identity Document.
Use any HTTP client utility to fetch this URL:
http://169.254.169.254/latest/dynamic/instance-identity/document
You can test this from the command line with curl.
This returns a JSON document containing -- among other things -- instanceId, accountId, and region for the instance.
The IP address 169.254.169.254 is always the same for every instance in every region. See also What's special about 169.254.169.254 IP address for AWS?
While STS GetCallerIdentity can be used to identify certain attributes of the credentials currently in use, it should not be necessary.

Access authorizer from an AWS lambda function with proxy integration - Python

[Derived from AWS ApiGateway Lambda Proxy access Authorizer ]
I´m using an Lambda Proxy and a Cognito User Pool Authorizer in my ApiGateway. With node.js Lambda functions, it's possible access to have access to the authorizer (basically, get the user id, email and stuff) in event.requestContext.authorizer.claims.
But in Python, there's no such object. Exploring the event object and the context object shows there's nothing like requestContext or authorizer, just an identity object that contains Cognito Federated Identities information : for me, it's just null.
I haven't seen any mention of the event.requestContext.authorizr.claims in Python AWS-Lambda functions, and it would be a pain to
use federated identities instead
in API Gateway, set Authorization to AWS_IAM and turn on Invoke with caller credential
drop the proxy integration for a custom integration or
write the lambdas with node.js instead of python
Have you any idea if I'm missing something, if it's not implemented by AWS, if there's an easy workaround, or anything else ?
Thanks a lot for your help !
Here's the context object in python aws-lambda function, in a dictionary-like form :
"aws_request_id":"99XXXXf5-6XXe-1XX8-bXXf-5dXXXXXXXX50",
"function_name":"test_DynamoDB",
"function_version":"$LATEST",
"invoked_function_arn":"arn:aws:lambda:eu-west-3:4XXXXXXXXXX0:function:test_DynamoDB",
"log":"<bound method LambdaContext.log of <__main__.LambdaContext object at 0x7f07bcb21da0>>",
"log_group_name":"/aws/lambda/test_DynamoDB",
"log_stream_name":"2018/06/13/[$LATEST]76XXXXXXXXXXXXXXXXXXXXXXXXXXXXf0",
"memory_limit_in_mb":"128",
"identity":{
"cognito_identity_id":null,
"cognito_identity_pool_id":null
},
"client_context": None
Update
From https://stackoverflow.com/a/44039371/9936457 , it seems the same issue was in C# lambda functions and there's a workaround for it, using System.IO.Streams. Would this solution work in Python, with the right syntax ?

Categories