I currently have SAML integration setup and working as expected between my authentication provider (auth0) and AWS/AWS API Gateway.
The complications arise however when defining an AWS Policy with the ${saml:sub} variable.
Here's an example of my configuration:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"execute-api:*"
],
"Resource": [
"arn:aws:execute-api:us-west-2:[removed]/*/GET/customers/${saml:sub}"
]
}
]
}
Basically I want to ensure that this endpoint is only accessible by the currently auth'd in user (based on their saml:sub). The currently auth'd user should not be able to access another customers record. Seems like this should be a potentially common use-case.
Auth0 automatically assigns saml:sub and the format of the id is something like this
auth0|429
I'm assuming the issue currently lies with the pipe character being there and it comparing it to an automatically escaped value when the request is made to the API Gateway URL via the browser. Because of this, i'm assuming access is denied to the resource because
auth0|429 != auth0%7C429.
Is there a way within an IAM policy to work around this?
Is there a potential workaround on the Auth0 side to assign a different value to ${saml:sub}?
Appreciate all the potential solutions above! Ultimately I ended up abandoning SAML integration between Auth0 and AWS and opting for a custom authorizer via a lambda function inside of API Gateway. This allowed for a little more flexible setup.
For anyone else facing a similar scenario, I came across this GitHub project that's been working great so far:
https://github.com/jghaines/lambda-auth0-authorizer
I modified the project for our own purposes a little bit, but essentially what we've done is mapped our internal user ID to the AWS principalId.
On the API Gateway side we've setup a /customers/me resource and then on the integration request modified the URL Path Parameters like so:
Integration Request Screenshot
Our policy in our lambda function is setup like so
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "324342",
"Effect": "Allow",
"Action": [
"execute-api:Invoke"
],
"Resource": [
"arn:aws:execute-api:us-west-2:[removed]/*/GET/customers/me"
]
}
]
}
This allows for dynamic access to the endpoint and only returns data specific to the logged in user.
In my opinion the issue you described should be solved/handled from within the AWS Policy configuration, but since I'm not knowledgeable on that I'll offer you a workaround from the perspective of avoiding potential troublesome characters.
You can configure and override the default SAML mappings that Auth0 uses to output user information and as such control the attributes used for each of the output claims and the SAML subject.
Check SAML attributes mapping for an overview on how to do this.
Additionally, check SAML configuration via rules for a detailed view of all the available options.
By default, Auth0 will check the following claims in order to decide the one to be used as the SAML subject:
http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier
http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress
http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name
The IAM Policy won't be able to recognize ${saml:sub} in the actual resource ARN. Beyond that, API GW won't automatically understand a SAML assertion.
Are you using a custom authorizer Lambda function to parse the SAML assertion? If so you would want to parse out the 'sub' field and insert it directly into the policy returned from the authorizer like so
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"execute-api:*"
],
"Resource": [
"arn:aws:execute-api:us-west-2:[removed]/*/GET/customers/auth0|429"
]
}
]
}
If you're already that far and it's still not working as expected, then you're right, it may be that the URI is not being normalized depending on the client/browser encoding. I'd have to test that. But as long as your backend treats /customers/auth0|429 == /customers/auth0%7C429, you could safely build a policy that allows both unencoded and encoded versions of the resource:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"execute-api:*"
],
"Resource": [
"arn:aws:execute-api:us-west-2:[removed]/*/GET/customers/auth0|429",
"arn:aws:execute-api:us-west-2:[removed]/*/GET/customers/auth0%7C429"
]
}
]
}
If you're not using custom authorizers, please elaborate on what your setup looks like. But either way, unfortunately the IAM policy won't ever be able to evaluate the ${var} syntax in the resource block.
Related
i am new at rest api azure and i dont know how to get correct body template of policy.
For example i used :
GET https://dev.azure.com/organization/project/_apis/policy/types?api-version=7.0
and the response are types of policies which i can use but how do i know the construction of the request body? Like this one:
{
"isEnabled": true,
"isBlocking": false,
"type": {
"id": "fa4e907d-c16b-4a4c-9dfa-4906e5d171dd"
},
"settings": {
"minimumApproverCount": 4,
"creatorVoteCounts": false,
"scope": [
{
"repositoryId": "a957e751-90e5-4857-949d-518cf5763394",
"refName": "refs/heads/master",
"matchKind": "exact"
}
]
}
}
Where should I find those request body templates? :(
Resources: https://learn.microsoft.com/en-us/rest/api/azure/devops/policy/configurations/create?view=azure-devops-rest-5.1&tabs=HTTP
Usually, when you could list or get the repo policy correctly, you could use the parameter configuration part of the returning result as the request body in creating the policy with post method.
rest api to list the branch policy.
GET https://dev.azure.com/{organization}/{project}/_apis/policy/configurations?api-version=5.1
with optional parameter
GET https://dev.azure.com/{organization}/{project}/_apis/policy/configurations?scope={scope}&policyType={policyType}&api-version=5.1
You could check the templates below for different configurations in Policy template examples.
Examples
Approval count policy
Build policy
Example policy
Git case enforcement policy
Git maximum blob size policy
Merge strategy policy
Work item policy
If you still don't know how to compose the request body, you could also share your scenario.
i finally made it, it was very hard and i dont understand why Microsoft has so bad documentation.... i had to made it by sending randoms request and look at the elements how the names are... so bad so much time spend...
I am trying to create an API that logs JSON request bodies in an SQS queue.
I have set up a basic queue in SQS in both the FIFO and non-FIFO layouts. I have the same problem each time. My policy for the SQS queue is as follows:
{
"Version": "2012-10-17",
"Id": "arn:aws:sqs:us-east-1:2222222222222:API-toSQS.fifo/SQSDefaultPolicy",
"Statement": [
{
"Sid": "Sid22222222222",
"Effect": "Allow",
"Principal": "*",
"Action": "SQS:*",
"Resource": "arn:aws:sqs:us-east-1:2222222222222:API-toSQS.fifo"
}
]
}
I have created a policy which i give all access to SQS for writing abilities. And I have created a role for API Gateway in which i assign the aforementioned policy to. Here is the policy i have assigned to this role:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "VisualEditor0",
"Effect": "Allow",
"Action": [
"sqs:DeleteMessage",
"sqs:ChangeMessageVisibility",
"sqs:DeleteMessageBatch",
"sqs:SendMessageBatch",
"sqs:PurgeQueue",
"sqs:DeleteQueue",
"sqs:SendMessage",
"sqs:CreateQueue",
"sqs:ChangeMessageVisibilityBatch",
"sqs:SetQueueAttributes"
],
"Resource": "*"
}
]
}
I have set up an API gateway. I have created a POST method. I've tried enabling the CORS option (which create an OPTIONS method) and i've done it without CORS enabled. My ARN for my security policy is correct, i have triple checked it. and i opt for the override path and have the full https URL of my SQS queue there, i have triple checked this as well. My endpoint is SQS of course.
For integration request i have a HTTP header for Content-Type and then a Mapped From as 'application/x-www-form-urlencoded'
in mapping templates i have passthrough set as never and have a Content-Type set to application/json is also have included the template Action=SendMessage&MessageBody=$input.body to translate from body to url as per a walkthrough i found.
i am getting the following error in the API Gateway test area
<AccessDeniedException>
<Message>Unable to determine service/operation name to be authorized</Message>
</AccessDeniedException>
Is there a AWS guru out there who can steer me in the right direction?
to clarify my issue is that it should be adding my test body
{"peanutbutter":"jelly"}
to the SQS queue, but no luck.
I can send url encoded messages to SQS all day from postman, but i want my business partners to be able to send a clean JSON object via http (postman, node, etc, whatever..)
thank you!
i opt for the override path and have the full https URL of my SQS queue there
In Path Override type only path part of SQS queue URL 2222222222222/API-toSQS.fifo.
Also, MessageGroupId is required for fifo queues and if ContentBasedDeduplication is not enabled MessageDeduplicationId is required too.
Example of mapping template:
Action=SendMessage&MessageGroupId=$input.params('MessageGroupId')&MessageDeduplicationId=$input.params('MessageDeduplicationId')&MessageBody=$input.body
in this case you need to define MessageGroupId and MessageDeduplicationId as required query string parameters in Method Request and obviously pass them on requests to the API endpoint.
For anyone having this same issue, removing all of the settings from the integration request in API Gateway and using Lambda as a "middleman" worked. Lambda is a great go-between for almost all of the AWS services. I would prefer to have a API Gateway -> SQS stack instead of using API Gateway -> Lambda -> SQS, but for whatever reason the way the lambda handles the HTTP request as opposed to trying to configure API Gateway to do the same, works without issue.
you will not need any external resources in Lambda, so no importing Zip files. Just import AWS and SQS. use the basic structure to accept the event, then take the body (as JSON in my case) and sqs.sendMessage to your queue.
hope this helps anyone with the same issue.
The JWT RFC does not seem to have any problem containing complex arrays such as:
{
"email": "test#test.com",
"businesses": [
{
"businessId": "1",
"businessName": "One",
"roles": [
"admin",
"accountant"
]
},
{
"businessId": "2",
"businessName": "Two",
"roles": [
"support"
]
}
]
}
And this seems a desirable scenario for our needs, since as part of the token we'd like to have a list of businesses a user has access to and what roles does he have for each business (it's part of its identity). The authorization policies at the API would later understand those groups and apply the required authorization logic.
I have seen that with IdentityServer4 the claims are added to the ProfileDataRequestContext's IEnumerable<Claim> IssuedClaims property.
Is there any recommended alternative to this complex claim structure? If not, is there any way to build that structure with IdentityServer4 (maybe some extension?) or the only way would be to manually serialize the JSON since the Claim seems to accept only a string?
PS: I have seen this question and this other where one of the authors of Identity Server talks about something similar being an antipattern. Not sure if the antipattern would be to have complex claims' structure or "authorization implementation details" in the claims.
Any advice on this would be great!
UPDATE:
After giving some thoughts I agree having a complex hierarchy of claims is not desirable and I could go around this problem with a dirty solution of prefixing roles for each businessId. Something like this:
{
"email": "test#test.com",
"roles": [
"1_admin",
"1_accountant",
"2_support"
],
"businesses": [
"1_One",
"2_Two"
]
}
that way I keep a simple structure and later on, at the client or API I can read the claims and find out that 1 is the id for the business with name One and it has the roles admin and account.
Would this be a better solution?
Claims are about identity information - and not complex permission "objects". You are far better off with a dedicated permission service that returns your permissions in any format you want based on the identity of the user.
I also hope your permission data doesn't change while the token is being used, otherwise you end up with stale data.
That said - claims are always strings in .NET - but you can serialize JSON objects into it by setting the ClaimValueType to IdentityServerConstants.ClaimValueTypes.Json.
What I'm trying to do (continuing off on a question I asked previously: How can I filter AWS Instances by IAM role in powershell and get the private ip address of that instance?) is get the private ip addresses of instances with a specific IAM Role. And I've got a code that works perfectly:
$filter = New-Object Amazon.EC2.Model.Filter -Property #{Name = "iam-instance-profile.arn"; Value = "arn:aws:iam::123456789012:instance-profile/TestRole"}
$ec2 = #(Get-EC2Instance -Filter $filter)
$ec2instances = $ec2.instances
$ipaddress = $ec2instances.privateipaddress
However, now instead of doing the filter in the code, I'd like to create an IAM Policy that restricts the user to only be able to get information on the instances that have a specific IAM Role. So if they try to get-ec2instance (for example), it should only return information on the relevant instances and not all instances in the account.
This is my IAM Policy that I have:
{
"Version": "2012-10-17",
"Statement": [
{
"Action": [
"ec2:DescribeInstances"
],
"Effect": "Allow",
"Resource": [
"*"
],
"Condition": {
"ArnEquals": {
"ec2:InstanceProfile": "arn:aws:iam::12356789102:instance-profile/TestRole"
}
}
}
]
}
However when I run get-ec2instance on Powershell, I am told that I'm not authorised to perform that action. I think that might be because get-ec2instance is only applicable to all instances but I'm not sure.
I would appreciate the help, thanks!
There is no option so far where in you can restrict an IAM user to see a specific EC2 instance.
There is only one API call exists ec2-describe-instances which shows one needs to have all the permission on all instances or none.
The reason for the issue is that get-ec2instance is trying to describe all of your instances including instances that doesn't have appropriate role assigned to it.
When talking about describing EC2 instances or listing S3 buckets, you should be able to list everything, otherwise you receive a 403 error.
I could suggest you to restrict your access with IAM for the security purpose only and continue filtering your instances using the code iteslf.
Please let me know if it works for you.
P. S. You may have went in a wrong way when decided to use IAM roles in order to organize your access.
AWS provide a feature called "Resource tagging". The direct purpose of it is to organize your resources and apply permissions based on the structure.
More information here:
http://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies_examples.html#iam-policy-example-ec2-tag-permissions
I'm attempting to run New-EC2Tag, getting the following error:
New-EC2Tag : You are not authorized to perform this operation.
The user policy is as follows:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": ["ec2:DescribeInstances","ec2:CreateTags"],
"Resource": "arn:aws:ec2:ap-southeast-2:<my_account_id>:instance/*",
"Condition": {
"StringEquals": {
"ec2:ResourceTag/OctopusTentacle": "yes"
}
}
}
]
}
It works fine in the Policy Simulator as above.
If I remove the condition and set Resource to * it works. Removing the condition or setting Resource to * alone do not work. I am running this as local Administrator on the instance.
What else is New-EC2Tag accessing/doing that I need to grant access to?
If New-EC2Tag works when clearing the Condition and wildcarding the Resource, then we should be inspecting both of those.
From some investigation, New-EC2Tag's related API action is CreateTags. According to Supported Resources and Conditions for Amazon EC2 API Actions, some API actions do not support ARNs. This seems to be the case with CreateTags, as it requests that you specify a resource ID instead. This is also corraborated by the "Supported Resources..." documentation I linked above, which does not list CreateTags as supporting arns.
In this case, the documentation recommends that you set the policy as such:
If the API action does not support ARNs, use the * wildcard to specify
that all resources can be affected by the action.
So that leaves the condition... the tag. The tag that you are using as a condition needs to already exist on the instance for the policy to be applied as you expect. An example from the policy simulator, where the tag already exists:
Another consideration is that the action may likewise not support conditions, but I haven't found anything to back that up.