Access authorizer from an AWS lambda function with proxy integration - Python - 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 ?

Related

AWS: Calling Cognito.sign_up from Lambda times out

I suspect this might be IAM/VPC issue but perhaps not? My Lambda function calls Cognito's sign_up to register. The lambda function is behind an API GET endpoint.
I am able to call the endpoint locally and it creates the Cognito user successfully. However, when I deploy it to a staging environment, it doesn't seem to be able to call Cognito anymore. I peeked at the Cloudwatch logs and there is no error reported.
Staging environment has a lambda function behind a VPC that also has a MySQL database as well. I am able to pull data from this database from this lambda function. From that same environment, I am now trying to call Cognito user pool.
I also checked that the permission IAM role for this lambda function has CognitoPowerUser permissions.
I am not sure what other IAM roles/permissions I am missing here, it seems to work fine when I call it locally but not from the said staging environment.
My assumption would also be that this is an issue with your Lambda function in the VPC being unable to reach the public internet due to your VPC set up.
I would encourage you to review this blog to ensure you are set up correctly from a network perspective.
https://aws.amazon.com/premiumsupport/knowledge-center/internet-access-lambda-function/

MWAA Webserver IPs on CDK

I'm creating an Amazon Managed Airflow (MWAA) using CDK with the setting of webserver_access_mode='PRIVATE_ONLY'. In this mode, AWS creates a VPC interface endpoint and binds an IP address, from the selected VPC private subnets, to them as explained here: https://docs.aws.amazon.com/mwaa/latest/userguide/configuring-networking.html
Now, I want to use those IPs to add a listener to an existing load balancer that I can then use to connect to a VPN, but this doesn't seem to be available as an output attribute/property of aws_cdk.aws_mwaa.CfnEnvironment: https://docs.aws.amazon.com/cdk/api/v1/python/aws_cdk.aws_mwaa/CfnEnvironment.html#aws_cdk.aws_mwaa.CfnEnvironment.NetworkConfigurationProperty
My question is, is there a way to obtain those IPs associated with the aws_cdk.aws_mwaa.CfnEnvironment? Right now I am looking up the results manually after the deployment with CDK and creating the listener but I would prefer to fully automate it in the same CDK construct.
I struggled with this same problem for some time. In the end I used a Custom Resource in my CFN template, passing it the URL of the MWAA webserver. In the Python code associated with the Custom Resource (Lambda) I do a socket.gethostbyname_ex() call, passing the URL as an argument. This call will return a tuple that that you'll have to parse to extract the endpoint addresses.
I made good use of the crhelper libraries (https://aws.amazon.com/blogs/infrastructure-and-automation/aws-cloudformation-custom-resource-creation-with-python-aws-lambda-and-crhelper/), which made things a lot easier.
In the end, I used a lambda function to resolve the webserver URL and register the IP addresses to the target group. The approach is described in the following AWS blog post: https://aws.amazon.com/blogs/networking-and-content-delivery/hostname-as-target-for-network-load-balancers/
The implementation of the lambda function is also available through the following AWS sample code: https://github.com/aws-samples/hostname-as-target-for-elastic-load-balancer

Fetch Azure Managed Identity from within Function

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>
}

How to host aws cdk custom construct library as an API

Few days back I asked a question to stack overflow community at about custom construct library Question
Although I didn't got the exact answer I was looking for. But somehow I managed to create a custom construct library. But now I have another query on how to host the CDK App as an API.
Below is the snapshot of custom construct library:
test_ec2 = ec2.Instance(self, "APIInstance",
vpc=my_vpc,
machine_image=ec2.AmazonLinuxImage(
generation=ec2.AmazonLinuxGeneration.AMAZON_LINUX
),
key_name="test-cdk",
instance_name=inst-name
)
If I want to host above AWS CDK Application as an API that will accept a string for the variable inst-name and will create a EC2 instance. I tried creating it as an lambda function but not sure how to manage "node dependencies and python dependencies" at same time.
Can it be done using an already created EC2 Instance(attaching an IAM Role with permission of cloudformation) and accepting HTTP requests (But don't know how?) Is this making sense?
Thank You in advance to all the devs.
There are many ways to do this. I think the simplest would be to syntesize your cloudformation templates and publish them to S3 ahead of time and use API gateway with a REST API and with AWS request type integration that would create the Cloudformation stack.
Here's a tutorial that explains how to build a REST API with AWS API integration: https://docs.aws.amazon.com/apigateway/latest/developerguide/getting-started-aws-proxy.html
Just this is for SNS:ListTopics action, but you would want cloudformation:CreateStack action instead.

Braintree + Python: Configure credential at transaction level rather than module

I am currently using Python to integrate with Braintree. At the module-level, we configure our API keys. From the doc:
import braintree
braintree.Configuration.configure(...)
def my_transaction():
braintree.Transaction.sale(...)
How can I configure braintree at the method level? That is, if I wanted to use a different credential for each transaction, how could I do so without updating a global config? Eg:
import braintree
def my_transaction():
braintree.Transaction.sale({
'configuration': {...},
'amount': ...
})
I would like to be able to use a different API key, depending on the source of the transaction. I would also like to be able to more easily toggle between Sandbox and Production credentials.
How would I accomplish this?
I work at Braintree. If you need more help, please get in touch with our support team.
Configuration objects can be instantiated:
config = braintree.Configuration(
environment=braintree.Environment.Sandbox,
merchant_id='my_merchant_id',
public_key='public_key',
private_key='private_key'
)
and passed to a Braintree gateway object:
gateway = braintree.BraintreeGateway(config)
which you can then use to run transactions:
result = gateway.transaction.create({'amount': ...})
So you can either instantiate a new gateway for each transaction with the appropriate credentials, or keep around a gateway with each set of credentials and use the appropriate one.

Categories