Giter Club home page Giter Club logo

Comments (35)

rpgreen avatar rpgreen commented on June 23, 2024 14

Hi all,

I found the issue in the swagger definition.

Http method should be POST to invoke a lambda function, as per the Lambda API. See http://docs.aws.amazon.com/lambda/latest/dg/API_Invoke.html

Change the http method on your integration to POST and this should work.

from aws-apigateway-importer.

rpgreen avatar rpgreen commented on June 23, 2024 10

Hi folks,

First of all, I apologize for the sparse documentation - we are working on it!

These concepts are more specific to the API Gateway service and not particularly related to the Swagger importer - you would run into the same issues using our API. I realize this can be difficult to set up, but luckily this is usually a one-time setup per account. I'll try to clear a few things up.

There are currently 2 different ways to invoke a lambda function:

  1. Using credentials, whereby API Gateway assumes a role in your account, and then invokes the lambda function in your account. In Swagger or the API, this is achieved by referencing a role ARN in the credentials field. This role is typically not the lambda function "execution role" and its policy must at a minimum grant permission for API Gateway to assume it and to invoke lambda functions.

At a minimum, the role must have these actions allowed:

...
"lambda:InvokeFunction"
"iam:PassRole"
...

as well as a trust-relationship defined for API Gateway:

...
"Effect": "Allow",
"Principal": {
"Service": "apigateway.amazonaws.com"
},
"Action": "sts:AssumeRole"
...

See http://docs.aws.amazon.com/STS/latest/APIReference/API_AssumeRole.html

  1. Using "resource-based" permissions, whereby you set a policy on the lambda function itself, granting the API Gateway account permission to invoke it. In Swagger or the API, this is achieved by omitting the credentials field.

When you setup a method with a lambda function using the API Gateway management console, we automatically add a permission to the lambda function. However, the Swagger importer or the SDK does not add this permission - this is why you might see different results when using the console vs using the importer.

When using resource-based permissions, you must explicitly update the policy on the lambda function so that API Gateway can invoke it from the specified API/resource/method combination. To see an example policy, attach your lambda function using the API Gateway management console, then use the Lambda API or CLI to view the function policy (See http://docs.aws.amazon.com/lambda/latest/dg/API_GetPolicy.html). You can then replicate this policy for APIs managed by the Swagger importer. Note that wildcards can be used for API ID, resource, method, etc. in the function policy.

I hope this helps with the above questions.

Another point - if you get 403 "Missing authentication token" when calling your API, it may be related to an error in the URL (api id/stage/resource path) or http method, rather than an auth error. We send 403 in all cases when the resource cannot be located.

Please let me know if this helps!

Cheers,
Ryan

from aws-apigateway-importer.

Sam-Martin avatar Sam-Martin commented on June 23, 2024 7

I had a similar issue and it was because my uri read:
arn:aws:apigateway:eu-west-1:lambda:path/2015-03-31/functions/arn:aws:lambda:eu-west-1:<accountid>:function:ephemera-getsignedurl
instead of
arn:aws:apigateway:eu-west-1:lambda:path/2015-03-31/functions/arn:aws:lambda:eu-west-1:<accountid>:function:ephemera-getsignedurl/invocations
(i.e. it was missing the trailing /invocations)

from aws-apigateway-importer.

rpgreen avatar rpgreen commented on June 23, 2024 3

I just set up a simple example from scratch with a successful response from both the console test invoke and from curl.

Swagger:

...
                "x-amazon-apigateway-auth" : {
                    "type" : "none"
                },
                "x-amazon-apigateway-integration" : {
                    "type" : "aws",
                    "uri" : "arn:aws:apigateway:us-east-1:lambda:path/2015-03-31/functions/arn:aws:lambda:us-east-1:ACCT_ID:function:rg-no-permissions/invocations",
                    "httpMethod" : "POST",
                    "credentials" : "arn:aws:iam::ACCT_ID:role/apiGatewayLambdaInvokeRole",
                    "responses" : {
                        ".*error.*" : {
                            "statusCode" : "400"
                        },
                        "default" : {
                            "statusCode" : "200"
                        }
                    }
                }
       ...

with the following policy for apiGatewayLambdaInvokeRole:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "logs:*"
            ],
            "Resource": "arn:aws:logs:*:*:*"
        },
        {
            "Effect": "Allow",
            "Action": [
                "lambda:InvokeFunction"
            ],
            "Resource": [
                "*"
            ]
        }
    ]
}

and the following trust relationship:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "",
      "Effect": "Allow",
      "Principal": {
        "Service": "apigateway.amazonaws.com"
      },
      "Action": "sts:AssumeRole"
    }
  ]
}

Are you able to reproduce this with a new API and lambda function?

The error seems to be coming from lambda. Would you mind sending your lambda function execution role?

from aws-apigateway-importer.

Vilsepi avatar Vilsepi commented on June 23, 2024

I am having the same problem. I am trying to make the simplest possible API, which takes a GET request to /test, and forwards it to a Lambda function. I can make it just fine manually with the web interface, but not with Swagger.

---
swagger: '2.0'
info:
  version: 0.0.1
  title: First API app
  description: "It is alive!"
  schemes: 
    - "http"
  consumes:
    - "application/json"
  produces: 
    - "application/json"
paths:
  /test:
    get:
      summary: "Summary of get"
      description: "Description of get"
      responses:
        200:
          description: "A response"
          headers: 
            test-method-response-header:
              type: string
      x-amazon-apigateway-auth":
        type: none
      x-amazon-apigateway-integration:
        type: aws
        uri: arn:aws:apigateway:eu-west-1:lambda:path/2015-03-31/functions/arn:aws:lambda:eu-west-1:MY_ACCOUNT_ID:function:echoLambda/invocations
        credentials: "arn:aws:iam::MY_ACCOUNT_ID:role/lambda_basic_execution"
        httpMethod: "POST"
        requestTemplates:
          application/json: "json request template 2"
        responses:
          2//d{2}: 
            statusCode: "200"
            responseParameters: 
              method.response.header.test-method-response-header: "integration.response.header.integrationResponseHeaderParam1"
            responseTemplates: 
              application/json: "json 200 response template"
          default: 
            statusCode: "400"
            responseParameters: 
              method.response.header.test-method-response-header: "'static value'"
            responseTemplates: 
              application/json: "json 400 response template"

If I include the "credentials" parameter, I get:

API Gateway does not have permission to assume the provided role.

If I don't include it, I get:

Invalid permissions on Lambda function.

If I do include it, deploy the API and use the HTTP interface, I get a response:

{"message":"Missing Authentication Token"}

Even though x-amazon-apigateway-auth is set to none.

I do not understand what is the credential used for: is it a credential that the API gateway uses to call the Lambda function, or is it the credential that the Lambda function uses to execute? I don't think it's the latter, as isn't that already defined in the Lambda function configuration? If it is for the API gateway, I am guessing that using the web interface adds some magic credential.

I feel dumb. :(

from aws-apigateway-importer.

Vilsepi avatar Vilsepi commented on June 23, 2024

I noticed that there was an extra quote after the x-amazon-apigateway-auth which may or may not have cause some of the issues. In any case, if I use this Swagger file:

---
swagger: '2.0'
info:
  version: 0.0.1
  title: First Swagger API
  schemes:
    - "http"
  consumes:
    - "application/json"
  produces:
    - "application/json"
paths:
  /test:
    get:
      responses:
        200:
          description: "A response"
      x-amazon-apigateway-auth:
        type: none
      x-amazon-apigateway-integration:
        type: aws
        uri: arn:aws:apigateway:eu-west-1:lambda:path/2015-03-31/functions/arn:aws:lambda:eu-west-1:MY_ACCOUNT_ID:function:echoLambda/invocations
        credentials: null
        httpMethod: POST
        responses:
          default:
            statusCode: "200"
            responseTemplates:
              application/json: "json 200 response template"

The Test gives "Invalid permissions on Lambda function". The Integration seems fine in the API Gateway Console:

/test - GET - Integration Request
Integration type: Lambda Function
Lambda Region: eu-west-1
Lambda Function: echoLambda

But, when I go check the Lambda Console -> API endpoints, there are none specified. If I go back to the API Gateway Console -> Integration Request, click the Lambda Function field, do not change the name but just click Update, a dialog will appear:

You are about to give API Gateway permission to invoke your Lambda function:
arn:aws:lambda:eu-west-1:MY_ACCOUNT_ID:function:echoLambda

Once I click OK, the endpoint becomes visible in the Lambda Console, and while nothing has seemingly changed in the API Gateway Console, the Test now works. So how do I do think linkage with Swagger?

I have tried passing all kinds of roles in the credentials parameter, but they all return the same "API Gateway does not have permission to assume the provided role."

from aws-apigateway-importer.

rpgreen avatar rpgreen commented on June 23, 2024

This looks like a signature issue when calling lambda. I'll look into this and get back to you

from aws-apigateway-importer.

kmrgithub avatar kmrgithub commented on June 23, 2024

Hi rpgreen -

I attempted to use the CLI to add the permission after I ran my swagger file. I get the same error as shown above.

I ran the following command:
aws lambda add-permission --function-name BuyerFirstRS_Get --statement-id 123456789 --action
lambda:* --principal "apigateway.amazonaws.com"

Here is the policy entry after I ran get-policy.
{
"Action":"lambda:*",
"Resource":"arn:aws:lambda:us-east-1:ACCOUNT_ID:function:BuyerFirstRS_Get",
"Effect":"Allow",
"Principal":{"Service":"apigateway.amazonaws.com"},
"Sid":"123456789"
}

Thanks in advance.

from aws-apigateway-importer.

Vilsepi avatar Vilsepi commented on June 23, 2024

Thanks for the help, Ryan. I am just chiming in to let you know that I managed to get mine working. Indeed I was missing the trust relationship from the role, so API Gateway could not assume the role by itself. I have now gone back to reading the docs.

from aws-apigateway-importer.

johntitus avatar johntitus commented on June 23, 2024

Similar issue. My swagger file:

{
    "swagger": "2.0",
    "info": {
        "title": "fishstore"
    },
    "paths": {
        "/signup": {
            "get": {
                "responses": {
                    "200": {
                        "description": "ok"
                    }
                },
                "x-amazon-apigateway-auth": {
                    "type": "none"
                },
                "x-amazon-apigateway-integration": {
                    "type": "aws",
                    "uri": "arn:aws:apigateway:us-east-1:lambda:path/2015-03-31/functions/arn:aws:lambda:us-east-1:<my_account_id>:function:hocus_5f9s1xy8pd_controller_listFish/invocations",
                    "httpMethod": "GET",
                    "credentials": "arn:aws:iam::<my_account_id>:role/ExecLambdaRole",
                    "requestTemplates": {
                        "application/json": "Empty"
                    },
                    "responses": {
                        "default": {
                            "statusCode": "200"
                        }
                    }
                }
            }
        }
    }
}

That ExecLambdaRole has the following policy:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "logs:*"
      ],
      "Resource": "arn:aws:logs:*:*:*"
    },
    {
      "Effect": "Allow",
      "Action": [
        "lambda:InvokeFunction"
      ],
      "Resource": [
        "*"
      ]
    },
    {
      "Effect": "Allow",
      "Action": [
        "apigateway:*",
        "iam:PassRole"
      ],
      "Resource": [
        "*"
      ]
    }
  ]
}

That role also has the following Trust Relationship:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "",
      "Effect": "Allow",
      "Principal": {
        "Service": [
          "lambda.amazonaws.com",
          "apigateway.amazonaws.com"
        ]
      },
      "Action": "sts:AssumeRole"
    }
  ]
}

I run the following command:
./aws-api-import.sh --create /tmp/swagger.json

The resulting API in the console looks ok:
image

But the Test response results in:

<AccessDeniedException>
  <Message>Unable to determine service/operation name to be authorized</Message>
</AccessDeniedException>

And the logs are:

                    Execution log for request test-request
Thu Aug 06 18:20:04 UTC 2015 : Starting execution for request: test-invoke-request
Thu Aug 06 18:20:04 UTC 2015 : API Key: test-invoke-api-key
Thu Aug 06 18:20:04 UTC 2015 : Method request path: {}
Thu Aug 06 18:20:04 UTC 2015 : Method request query string: {}
Thu Aug 06 18:20:04 UTC 2015 : Method request headers: {}
Thu Aug 06 18:20:04 UTC 2015 : Method request body before transformations: null
Thu Aug 06 18:20:04 UTC 2015 : Endpoint request URI: https://lambda.us-east-1.amazonaws.com/2015-03-31/functions/arn:aws:lambda:us-east-1:<my_account_id>:function:hocus_5f9s1xy8pd_controller_listFish/invocations
Thu Aug 06 18:20:04 UTC 2015 : Endpoint request headers: {Authorization=AWS4-HMAC-SHA256 Credential=ASIAJYO22ALFEROHAWOQ/20150806/us-east-1/lambda/aws4_request, SignedHeaders=accept;content-type;host;user-agent;x-amz-content-sha256;x-amz-date, Signature=2f7d34a6f6eefedf8585e97c622bfd0dd11f32546e8d42b33b9da28d519d0c72, X-Amz-Date=20150806T182004Z, Accept=application/json, User-Agent=AmazonAPIGateway_0ss8j7bbod, X-Amz-Security-Token=AQoDYXdzEDMaoALpewKb93Zai1Pem3Oc1Ezvq43wSjO8+P1giS21vzu3o9HC6Hv4A0J1NMvLEhvLjA+n0HSMwBdpdT5fqFypWni8y+HlXxtBBZIOw6xsqs0hVJ4dFgc6nqCzBDqaz/r7mkhDxTp44XWPLCtBNdT+W471/PCcW8HEGfbhEskHx0L4kFaC3dWhdMcfuQAbk5JAcJYWovmnZHg11sOMKOwYCc1/iZChGxDJ1byw+BOfeEkKD8+hY8Vm1zHXC1fTh9ygB240DGZxEYyFwmad+PFKTJiznrvlCHAWH+sCwGJzglzwUFx6Xl4qEcT28VcQNr/AjKLAFD4Ez+rWhseEXJ3t6u3Vj4unUc2/VZF7i1LuTuIt48A+yxZFR2XPMpFJtExF1GEg1MqOrgU=, Host=lambda.us-east-1.amazonaws.com, X-Amz-Content-Sha256=c6c094bc0054f9cbe34102ff49f86b3928b5ac09f3d2ac87e170d0500675921f, Content-Type=application/json}
Thu Aug 06 18:20:04 UTC 2015 : Endpoint request body after transformations: Empty
Thu Aug 06 18:20:04 UTC 2015 : Endpoint response body before transformations: <AccessDeniedException>
  <Message>Unable to determine service/operation name to be authorized</Message>
</AccessDeniedException>

Thu Aug 06 18:20:04 UTC 2015 : Endpoint response headers: {x-amzn-RequestId=c27c931d-3c67-11e5-98a0-5de465424063, Connection=keep-alive, Content-Length=130, Date=Thu, 06 Aug 2015 18:20:04 GMT}
Thu Aug 06 18:20:04 UTC 2015 : Method response body after transformations: <AccessDeniedException>
  <Message>Unable to determine service/operation name to be authorized</Message>
</AccessDeniedException>

Thu Aug 06 18:20:04 UTC 2015 : Method response headers: {Content-Type=application/json}
Thu Aug 06 18:20:04 UTC 2015 : Successfully completed execution

from aws-apigateway-importer.

rpgreen avatar rpgreen commented on June 23, 2024

We are actively looking into this. Can you confirm that you get the same
response message when deploying this API and invoking it through an http
client?

On Thursday, August 6, 2015, John [email protected] wrote:

Similar issue. My swagger file:

{
"swagger": "2.0",
"info": {
"title": "fishstore"
},
"paths": {
"/signup": {
"get": {
"responses": {
"200": {
"description": "ok"
}
},
"x-amazon-apigateway-auth": {
"type": "none"
},
"x-amazon-apigateway-integration": {
"type": "aws",
"uri": "arn:aws:apigateway:us-east-1:lambda:path/2015-03-31/functions/arn:aws:lambda:us-east-1:<my_account_id>:function:hocus_5f9s1xy8pd_controller_listFish/invocations",
"httpMethod": "GET",
"credentials": "arn:aws:iam::<my_account_id>:role/ExecLambdaRole",
"requestTemplates": {
"application/json": "Empty"
},
"responses": {
"default": {
"statusCode": "200"
}
}
}
}
}
}
}

That ExecLambdaRole has the following policy:

{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"logs:"
],
"Resource": "arn:aws:logs:
::"
},
{
"Effect": "Allow",
"Action": [
"lambda:InvokeFunction"
],
"Resource": [
""
]
},
{
"Effect": "Allow",
"Action": [
"apigateway:
",
"iam:PassRole"
],
"Resource": [
"*"
]
}
]
}

That role also has the following Trust Relationship:

{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "",
"Effect": "Allow",
"Principal": {
"Service": [
"lambda.amazonaws.com",
"apigateway.amazonaws.com"
]
},
"Action": "sts:AssumeRole"
}
]
}

I run the following command:
./aws-api-import.sh --create /tmp/swagger.json

The resulting API in the console looks ok:
[image: image]
https://cloud.githubusercontent.com/assets/590334/9119719/2fd7b426-3c46-11e5-9ebb-7681e121472a.png

But the Test response results in:

Unable to determine service/operation name to be authorized

And the logs are:

                Execution log for request test-request

Thu Aug 06 18:20:04 UTC 2015 : Starting execution for request: test-invoke-request
Thu Aug 06 18:20:04 UTC 2015 : API Key: test-invoke-api-key
Thu Aug 06 18:20:04 UTC 2015 : Method request path: {}
Thu Aug 06 18:20:04 UTC 2015 : Method request query string: {}
Thu Aug 06 18:20:04 UTC 2015 : Method request headers: {}
Thu Aug 06 18:20:04 UTC 2015 : Method request body before transformations: null
Thu Aug 06 18:20:04 UTC 2015 : Endpoint request URI: https://lambda.us-east-1.amazonaws.com/2015-03-31/functions/arn:aws:lambda:us-east-1:<my_account_id>:function:hocus_5f9s1xy8pd_controller_listFish/invocations
Thu Aug 06 18:20:04 UTC 2015 : Endpoint request headers: {Authorization=AWS4-HMAC-SHA256 Credential=ASIAJYO22ALFEROHAWOQ/20150806/us-east-1/lambda/aws4_request, SignedHeaders=accept;content-type;host;user-agent;x-amz-content-sha256;x-amz-date, Signature=2f7d34a6f6eefedf8585e97c622bfd0dd11f32546e8d42b33b9da28d519d0c72, X-Amz-Date=20150806T182004Z, Accept=application/json, User-Agent=AmazonAPIGateway_0ss8j7bbod, X-Amz-Security-Token=AQoDYXdzEDMaoALpewKb93Zai1Pem3Oc1Ezvq43wSjO8+P1giS21vzu3o9HC6Hv4A0J1NMvLEhvLjA+n0HSMwBdpdT5fqFypWni8y+HlXxtBBZIOw6xsqs0hVJ4dFgc6nqCzBDqaz/r7mkhDxTp44XWPLCtBNdT+W471/PCcW8HEGfbhEskHx0L4kFaC3dWhdMcfuQAbk5JAcJYWovmnZHg11sOMKOwYCc1/iZChGxDJ1byw+BOfeEkKD8+hY8Vm1zHXC1fTh9ygB240DGZxEYyFwmad+PFKTJiznrvlCHAWH+sCwGJzglzwUFx6Xl4qEcT28VcQNr/AjKLAFD4Ez+rWhseEXJ3t6u3Vj4unUc2/VZF7i1LuTuIt48A+yxZFR2XPMpFJtExF1GEg1MqOrgU=, Host=lambda.us-east-1.amazonaws.com, X-Amz-Content-Sha256=c6c094bc0054f9cbe34102ff49f86b3928b5ac09f3d2ac87e170d0500675921f, Content-Type=application/json
}
Thu Aug 06 18:20:04 UTC 2015 : Endpoint request body after transformations: Empty
Thu Aug 06 18:20:04 UTC 2015 : Endpoint response body before transformations:
Unable to determine service/operation name to be authorized

Thu Aug 06 18:20:04 UTC 2015 : Endpoint response headers: {x-amzn-RequestId=c27c931d-3c67-11e5-98a0-5de465424063, Connection=keep-alive, Content-Length=130, Date=Thu, 06 Aug 2015 18:20:04 GMT}
Thu Aug 06 18:20:04 UTC 2015 : Method response body after transformations:
Unable to determine service/operation name to be authorized

Thu Aug 06 18:20:04 UTC 2015 : Method response headers: {Content-Type=application/json}
Thu Aug 06 18:20:04 UTC 2015 : Successfully completed execution


Reply to this email directly or view it on GitHub
#9 (comment)
.

from aws-apigateway-importer.

johntitus avatar johntitus commented on June 23, 2024

Yes

john@john-VirtualBox ~/aws-apigateway-swagger-importer $ curl https://<my_api_id>.execute-api.us-east-1.amazonaws.com/test/signup
<AccessDeniedException>
  <Message>Unable to determine service/operation name to be authorized</Message>
</AccessDeniedException>

from aws-apigateway-importer.

rpgreen avatar rpgreen commented on June 23, 2024

If you can recreate this, please send the x-amzn-RequestId response header so I can investigate further

from aws-apigateway-importer.

johntitus avatar johntitus commented on June 23, 2024

I think I see what you mean - that while the API Gateway method is GET, internally it needs to send a POST to the lambda? I had been under the impression that the two methods had to match.

I don't have a built swagger importer here at home, but I'll test first thing in the morning. Thank you for looking into this - it's been driving me crazy.

from aws-apigateway-importer.

Garyguo2011 avatar Garyguo2011 commented on June 23, 2024

That works perfectly. Awesome!!!!

from aws-apigateway-importer.

johntitus avatar johntitus commented on June 23, 2024

Thank you, works just as you said!

from aws-apigateway-importer.

jontg avatar jontg commented on June 23, 2024

I just reproduced this by copying an existing API into a new API and deleting the old one (which was instantiated via cloudformation).

from aws-apigateway-importer.

jackie-scholl avatar jackie-scholl commented on June 23, 2024

If lambda always needs POST requests, then would it make sense for httpMethod be hardcoded and not required in every x-amazon-apigateway-integration definition?

from aws-apigateway-importer.

jackrk avatar jackrk commented on June 23, 2024

The integration definition applies to Lambda, HTTP backends, and also other AWS services. Yes Lambda does require POST requests, but I don't believe it makes sense to go with that assumption behind the scenes.

As to the previous comment on the URI missing '/invocations', I agree the format is complex and easy to mess up. We are working on improving documentation across the board.

from aws-apigateway-importer.

cosbor11 avatar cosbor11 commented on June 23, 2024

@rpgreen

Im trying to make a declarative and repeatable way to deploy my entire AWS env and am struggling to wire the api gateway to the lambdas.
Im finding that I need to programmatically give API Gateway permission to invoke my lambda function using the second methodology ("resource-based" permission settings) that you mentioned...

When I do the following awscli command:

aws lambda get-policy --function-name MyLambda

I get a response like this:

{
   "Version":"2012-10-17",
   "Statement":[
      {
         "Condition":{
            "ArnLike":{
               "AWS:SourceArn":"arn:aws:execute-api:us-west-2:{account-id}:d6v9eiz6we/*/POST/{path}"
            }
         },
         "Action":"lambda:InvokeFunction",
         "Resource":"arn:aws:lambda:us-west-2:394393457149:function:MyLambda",
         "Effect":"Allow",
         "Principal":{
            "Service":"apigateway.amazonaws.com"
         },
         "Sid":"5d320ee4ee34cesdq43564......"
      }
   ],
   "Id":"default"
}

The Sid, I'm assuming is the Service ID. Is that needed to create this Policy?

Also, How can I create this policy and apply it to the service before the service is created?
I guess Im just confused about whether to put the chicken before the egg and why the aws-apigateway-importer doesn't do this automatically.

Here is the general process Im thinking I need to do to get my api wired to the lambdas?

  1. Create the Roles and Policies for the Lambda using aws cloudformation create-stack
  2. Upload a jar with all my lambdas to an S3 bucket
  3. Update or create the lambda configuration to use the latest jar/handler.
    aws lambda create-function or aws lambda update-function-code.
  4. Use the aws-apigateway-importer to generate the API
  5. Get the Sid of the gateway I just created
  6. Create a policy similar to the one above? How would I do that? aws lambda add-permission --function-name MyFunction ... or is there a better way to do this?

from aws-apigateway-importer.

rpgreen avatar rpgreen commented on June 23, 2024

Yeah that's pretty much it. Few notes below:

Source ARN identifies an API Gateway method and should be structured like this:

arn:aws:execute-api:[REGION]:[ACCOUNT_ID]:[API_ID]/[STAGE]/[HTTP_METHOD]/[FULL_RESOURCE_PATH]

(Note wildcard (*) can be used for the value of STAGE)

You may need to modify the importer code in order to dynamically build a list of the resource paths/methods and lambda functions to add the permissions. Or you could simply hardcode them into your add permission script, but that would need to be maintained when you change the API definition.

Sid is the "statement ID" and must be unique - it's not related to the API.

Keep in mind that there is a limit to the overall size of the function policy, so if you keep adding permissions to the same function you will eventually hit the limit.

from aws-apigateway-importer.

rpgreen avatar rpgreen commented on June 23, 2024

Related to #111

from aws-apigateway-importer.

cosbor11 avatar cosbor11 commented on June 23, 2024

Thanks. I think I will write a bash script that pulls the path from the swagger file using jq (a bash json parsing tool) and do this for each path.

Im wondering tho, which of those ARN sections can I add a wild card to? and which can I not?

Can I create a policy like this:

arn:aws:execute-api:*:[ACCOUNT_ID]:[API_ID]/*/*/*

Thus granting all methods to each lambda associated with the API. Does this present any real security concern (when a restful endpoint has invocation access to a lambda it's not linked to)?

from aws-apigateway-importer.

rpgreen avatar rpgreen commented on June 23, 2024

Does this present any real security concern (when a restful endpoint has invocation access to a lambda it's not linked to)?

Yes, absolutely. I believe wildcards are accepted in any element, but I would strongly suggest to be as specific as possible when building the source ARN. At a bare minimum you should explicitly set the account ID and the API ID.

Hope this helps. If you think your script could be re-used a PR would be much appreciated

from aws-apigateway-importer.

cosbor11 avatar cosbor11 commented on June 23, 2024

Ok, thanks Ryan. I'll consider adding a PR to importer. I have a local snapshot and I'll see If that might be a better solution with my timeframe

from aws-apigateway-importer.

cosbor11 avatar cosbor11 commented on June 23, 2024

The version of AWS SDK (1.9.6), that the aws-apigateway-importer is using does not support creating a policy via the awsIdentityManagementClient or awsLambdaClient. Support is there for the latest (v1.10.53) version. Any plans on upgrading the SDK version? I can upgrade the pom.xml if you're okay with that.

from aws-apigateway-importer.

rpgreen avatar rpgreen commented on June 23, 2024

Yeah that should be straightforward, go for it.

Alternatively, if you wanted to use the CLI you could have any arbitrary version running in your environment.

from aws-apigateway-importer.

cosbor11 avatar cosbor11 commented on June 23, 2024

I wired in a awsLambdaClient, when I invoke the AddPermission, I get and InternalFailure and cant figure out why.

Upgrading the sdk version worked fine:

<properties>
    <aws-sdk.version>1.10.53</aws-sdk.version>
</properties>
...
<dependency>
    <groupId>com.amazonaws</groupId>
    <artifactId>aws-java-sdk-core</artifactId>
    <version>${aws-sdk.version}</version>
</dependency>

<dependency>
    <groupId>com.amazonaws</groupId>
    <artifactId>aws-java-sdk</artifactId>
    <version>${aws-sdk.version}</version>
</dependency>

Here is the ApiGatewaySdkSwaggerApiImporter code that I added (it looks at integration extenstion in swagger for a resourcePolicyConfig):

private void createResourcePolicy(RestApi api, Resource resource, Operation op, Method method, Map<String, String> resourcePolicyConfig){
    LOG.info("Creating policy for " + method.getHttpMethod() + " /" + resource.getPathPart() + "...");

    AddPermissionRequest permissionRequest = new AddPermissionRequest();
    permissionRequest.setAction("lambda:InvokeFunction");
    permissionRequest.setPrincipal("apigateway.amazonaws.com");
    permissionRequest.setStatementId(UUID.randomUUID().toString());

    String functionName = resourcePolicyConfig.get("functionName");
    if(functionName == null || functionName.isEmpty()){
        throw new IllegalArgumentException("resourcePolicyConfig must have functionName defined.");
    }
    permissionRequest.setFunctionName(functionName);

    String accountId = resourcePolicyConfig.get("accountId");
    if(accountId == null || accountId.isEmpty()){
        throw new IllegalArgumentException("resourcePolicyConfig must have accountId defined.");
    }
    permissionRequest.setSourceAccount(accountId);

    final String apiId = api.getId();
    String sourceArn = MessageFormat.format("arn:aws:execute-api:us-west-2:{0}:{1}/*/{2}/{3}", accountId, apiId, method.getHttpMethod(), resource.getPathPart());
    //LOG.info("SourceArn = " + sourceArn);
    permissionRequest.setSourceArn(sourceArn);

    try {
        AddPermissionResult result = awsLambda.addPermission(permissionRequest);
        LOG.info(result.toString());
    } catch(AmazonServiceException e) {
        LOG.error(e);
    }
}

And here is the Provider configuration:

@Provides
protected AWSLambda provideAWSLambda(AWSCredentialsProvider credsProvider,
                                             RetryPolicy.BackoffStrategy backoffStrategy,
                                             @Named("region") String region) {

    final RetryPolicy retrypolicy = new RetryPolicy(PredefinedRetryPolicies.DEFAULT_RETRY_CONDITION, backoffStrategy, 5, true);

    final ClientConfiguration clientConfig = new ClientConfiguration().withUserAgent(USER_AGENT).withRetryPolicy(retrypolicy);
    clientConfig.setProtocol(Protocol.HTTPS);

    AWSLambdaClient awsLambdaClient = new AWSLambdaClient(credsProvider.getCredentials(), clientConfig);

    awsLambdaClient.setEndpoint(getEndpoint(region));

    return awsLambdaClient;
}

But I keep getting this error when invoking addPermission:

com.amazonaws.AmazonClientException: Unable to unmarshall error response (Unable to parse error response: '<InternalFailure/>'). Response Code: 500, Response Text: Internal Server Error
    at com.amazonaws.http.AmazonHttpClient.handleErrorResponse(AmazonHttpClient.java:1363)
    at com.amazonaws.http.AmazonHttpClient.executeOneRequest(AmazonHttpClient.java:913)
    at com.amazonaws.http.AmazonHttpClient.executeHelper(AmazonHttpClient.java:631)
    at com.amazonaws.http.AmazonHttpClient.doExecute(AmazonHttpClient.java:400)
    at com.amazonaws.http.AmazonHttpClient.executeWithTimer(AmazonHttpClient.java:362)
    at com.amazonaws.http.AmazonHttpClient.execute(AmazonHttpClient.java:311)
    at com.amazonaws.services.lambda.AWSLambdaClient.invoke(AWSLambdaClient.java:2031)
    at com.amazonaws.services.lambda.AWSLambdaClient.addPermission(AWSLambdaClient.java:450)
    at com.amazonaws.service.apigateway.importer.impl.sdk.ApiGatewaySdkSwaggerApiImporter.createResourcePolicy(ApiGatewaySdkSwaggerApiImporter.java:349)
    at com.amazonaws.service.apigateway.importer.impl.sdk.ApiGatewaySdkSwaggerApiImporter.createMethod(ApiGatewaySdkSwaggerApiImporter.java:285)
    at com.amazonaws.service.apigateway.importer.impl.sdk.ApiGatewaySdkSwaggerApiImporter.lambda$createMethods$3(ApiGatewaySdkSwaggerApiImporter.java:208)
    at com.amazonaws.service.apigateway.importer.impl.sdk.ApiGatewaySdkSwaggerApiImporter$$Lambda$4/1576277927.accept(Unknown Source)
    at java.util.HashMap$EntrySet.forEach(HashMap.java:1035)
    at com.amazonaws.service.apigateway.importer.impl.sdk.ApiGatewaySdkSwaggerApiImporter.createMethods(ApiGatewaySdkSwaggerApiImporter.java:206)
    at com.amazonaws.service.apigateway.importer.impl.sdk.ApiGatewaySdkSwaggerApiImporter.createResources(ApiGatewaySdkSwaggerApiImporter.java:197)
    at com.amazonaws.service.apigateway.importer.impl.sdk.ApiGatewaySdkSwaggerApiImporter.createApi(ApiGatewaySdkSwaggerApiImporter.java:76)
    at com.amazonaws.service.apigateway.importer.impl.ApiGatewaySwaggerFileImporter.importApi(ApiGatewaySwaggerFileImporter.java:48)
    at com.amazonaws.service.apigateway.importer.ApiImporterMain.importSwagger(ApiImporterMain.java:155)
    at com.amazonaws.service.apigateway.importer.ApiImporterMain.execute(ApiImporterMain.java:145)
    at com.amazonaws.service.apigateway.importer.ApiImporterMain.main(ApiImporterMain.java:83)
Caused by: com.amazonaws.AmazonClientException: Unable to parse error response: '<InternalFailure/>'
    at com.amazonaws.http.JsonErrorResponseHandler.handle(JsonErrorResponseHandler.java:55)
    at com.amazonaws.http.JsonErrorResponseHandler.handle(JsonErrorResponseHandler.java:29)
    at com.amazonaws.http.AmazonHttpClient.handleErrorResponse(AmazonHttpClient.java:1338)
    ... 19 more
Caused by: com.amazonaws.util.json.JSONException: A JSONObject text must begin with '{' at 1 [character 2 line 1]
    at com.amazonaws.util.json.JSONTokener.syntaxError(JSONTokener.java:422)
    at com.amazonaws.util.json.JSONObject.<init>(JSONObject.java:196)
    at com.amazonaws.util.json.JSONObject.<init>(JSONObject.java:323)
    at com.amazonaws.http.JsonErrorResponseHandler.handle(JsonErrorResponseHandler.java:53)
    ... 21 more

This is using the following integration config in swagger:

"x-amazon-apigateway-integration": {
    "responses": {
        "default": {
            "statusCode": "200",
            "responseParameters": {
                "method.response.header.Access-Control-Allow-Origin": "'*'"
            },
            "responseTemplates": {
                "application/json": "__passthrough__"
            }
        }
    },
    "uri": "arn:aws:apigateway:us-west-2:lambda:path/2015-03-31/functions/arn:aws:lambda:us-west-2:{account}:function:MyLambda/invocations",
    "httpMethod": "POST",
    "type": "aws",
    "resourcePolicyConfig": {
        "accountId" : "{account}",
        "functionName" : "MyLambda"
    }
}

Any idea why I would be getting an Internal Error? My code matches up with the documentation; Example 2: Grant Amazon API Gateway Permissions to Invoke Your Lambda Function

I'll see what happens when I try with awscli.

from aws-apigateway-importer.

rpgreen avatar rpgreen commented on June 23, 2024

That looks like a fault on the Lambda service side. Are you able to get it working with simple test input for source arn, etc?

Your code looks good except that the source ARN should include the full resource path, not just the path part.

Are you sure that the credentials used have IAM policy to allow them to add permission?

This looks like a Lambda bug to me - I would suggest to follow up with the Lambda team with your stack trace: https://forums.aws.amazon.com/forum.jspa?forumID=186

from aws-apigateway-importer.

cosbor11 avatar cosbor11 commented on June 23, 2024

I am able to get it working using awscli with the following command:

 aws lambda add-permission --region us-west-2 --function-name  MyLambda --statement-id 3C64D50A-7FEA-4AC6-8331-99751E22DFDA --principal apigateway.amazonaws.com --action lambda:InvokeFunction --source-arn arn:aws:execute-api:us-west-2:{accountId}:7gshcby1c6/*/POST/my-resource

The response looks like this:

{
     "Statement": "{\"Condition\":{\"ArnLike\":{\"AWS:SourceArn\":\"arn:aws:execute-api:us-west-   2:394393457149:7gshcby1c6/*/POST/my-resource\"}},\"Action\":    [\"lambda:InvokeFunction\"],\"Resource\":\"arn:aws:lambda:us-west-2:{accoutId}:function:MyLambda\",\"Effect\":\"Allow\",\"Principal\":{\"Service\":\"apigateway.amazonaws.com\"},\"Sid\":\"3C64D50A-7FEA-4AC6-8331-99751E22DFDA\"}"
}

It looks like the bug is with the java sdk.

from aws-apigateway-importer.

lony avatar lony commented on June 23, 2024

+1

from aws-apigateway-importer.

shubhpatel108 avatar shubhpatel108 commented on June 23, 2024

If you are using boto3 for adding an integration of lambda function to APIGatway, make sure httpMethod and integrationHttpMethod both are set to 'POST'.

from aws-apigateway-importer.

BerndWessels avatar BerndWessels commented on June 23, 2024

Has this been resolved? I cannot find a way to make it work using terraform. See here for details.

from aws-apigateway-importer.

4lex-gs avatar 4lex-gs commented on June 23, 2024

I had a similar issue.
My wrong setting on "Integration Request" caused it.

I had to set "Use path override" but I chose another one.
I resolved the problem when I change setting.

Wed Nov 23 15:14:16 UTC 2016 : Endpoint response body before transformations: <AccessDeniedException>
  <Message>Unable to determine service/operation name to be authorized</Message>
</AccessDeniedException>

Wed Nov 23 15:14:16 UTC 2016 : Endpoint response headers: {x-amzn-RequestId=************* Connection=keep-alive, Content-Length=130, Date=Wed, 23 Nov 2016 15:14:15 GMT}
Wed Nov 23 15:14:16 UTC 2016 : Method response body after transformations: <AccessDeniedException>
  <Message>Unable to determine service/operation name to be authorized</Message>
</AccessDeniedException>

Wed Nov 23 15:14:16 UTC 2016 : Method response headers: {X-Amzn-Trace-Id=Root=1-*************************, Content-Type=application/json}
Wed Nov 23 15:14:16 UTC 2016 : Successfully completed execution
Wed Nov 23 15:14:16 UTC 2016 : Method completed with status: 200

from aws-apigateway-importer.

calebickler avatar calebickler commented on June 23, 2024

I was finally able to get my API Gateway custom authorizer to work because of this issue, so thanks!

But I wish this was simpler and in the AWS docs, would of saved tons of time, AWS needs to improve their API Gateway docs/experience, its quite frustrating.

from aws-apigateway-importer.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.