AWS API Gateway not invoking specified lambda - amazon-web-services

I recently deployed a new API endpoint and linked it to a specified lambda via cloud formation.
x-amazon-apigateway-integration:
uri: !Join
- ''
- - 'arn:aws:apigateway:'
- !Ref 'AWS::Region'
- ':lambda:path/2015-03-31/functions/arn:aws:lambda:'
- !Ref 'AWS::Region'
- ':'
- !Ref 'AWS::AccountId'
- ':function:'
- !Ref lbdBusinessPersonAccountsFunctionName
- '-'
- !Ref EnvName
- ':live'
- /invocations
When I check the API Gateway console, It seems like the lambda is correctly integrated to the API endpoint. But when I check the lambda console itself, no API GW trigger event was generated.
When I try manually link it to the gateway, it doesn't let me specify the resource I want to link it to, but instead creates a new resource under the lambda name.
Is there a manual linking step that I am missing?

On your cloudformation template, assuming you are using YAML; add the permissions mapping resource below. This gives apigateway the permission to add trigger/invoke your lambda (this is in addition to the appropriate IAM permissions).
FunctionInvokePermissions:
Type: "AWS::Lambda::Permission"
Properties:
Action: "lambda:InvokeFunction"
FunctionName: !GetAtt "Function.Arn"
Principal: "apigateway.amazonaws.com"
SourceArn: !Sub
- "arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${RestApiId}/${pathpart}/${method}"

Related

how to get Rolename from existing Lambda function on cloud via its friendly name or arn using cloudformation?

I have created a CFN template for rotating secret of RDS. It consist of a AWS HostedLambda which calls for an autogenerated Role. I want to attach another policy to that role.
rRotationLambdaDecryptPolicy:
Type: AWS::IAM::ManagedPolicy
DependsOn: rSecretRotationScheduleHostedRotationLambda
Properties:
Description: "Providing access to HostedLambda for decrypting KMS"
ManagedPolicyName: CustomedHostedLambdaKmsUserRolePolicy
PolicyDocument:
Version: '2012-10-17'
Statement:
- Sid: AllowLambdaDecryptKMS
Effect: Allow
Action:
- kms:Decrypt
- kms:CreateGrant
Resource:
- !Sub arn:aws:kms:*:${AWS::AccountId}:key/*
Condition:
ForAnyValue:StringLike:
kms:ResourceAliases: alias/SecretsManager_KMSKey
Roles: <friendly rolename>
Problem is i know the Lambda friendly name and its Arn. Need to find the rolename linked to this lambda so that i can attach the above policy to it(Add its friendly name to Roles).
tried attaching this below
Roles:
Fn::Join:
- ""
- - '"'
- Fn::GetAtt:
- !Sub 'arn:aws:lambda::${AWS::AccountId}:function:SecretsManager-research-creds-rotation-lambda'
- Role
- '"'
P.S.- cant use importvalue here, because the nested stack has been created by AWS and its output doesn't consist of export.
Lambda used:-
rSecretRotationSchedule:
Type: AWS::SecretsManager::RotationSchedule
Properties:
SecretId:<SecretId>
HostedRotationLambda:
KmsKeyArn: <KmsKeyArn>
MasterSecretArn: <MasterSecretArn>
MasterSecretKmsKeyArn: <MasterSecretKmsKeyArn>
RotationType: PostgreSQLMultiUser
RotationLambdaName: SecretsManager-research-creds-rotation-lambda
VpcSecurityGroupIds: <VpcSecurityGroupIds>
VpcSubnetIds: <VpcSubnetIds>
RotationRules:
AutomaticallyAfterDays: 60
Below is the link from which i took reference for template:-
https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-secretsmanager-rotationschedule.html
Most likely you can't do this with plain CFN. You would have to develop a custom resource. This would be in the form of a new lambda function which would use AWS SDK to query attributes of your primary lambda function. Once the custom resource finds the role name it would return it to your stack for further use.

How to access cross region resources in Cloudformation

I have a static website stack that I deploy to us-east-1. I only need the s3 bucket to be deployed in the eu-west-1 region, so to achieve this I used Stack Sets like this;
StackSet:
Type: AWS::CloudFormation::StackSet
Properties:
Description: Multiple S3 buckets in multiple regions
PermissionModel: SELF_MANAGED
StackInstancesGroup:
- DeploymentTargets:
Accounts:
- !Ref "AWS::AccountId"
Regions:
- eu-west-1
StackSetName: !Sub "AppBucketStack"
TemplateBody: |
AWSTemplateFormatVersion: 2010-09-09
Description: Create a S3 bucket
Resources:
WebsiteBucket:
Type: AWS::S3::Bucket
DeletionPolicy: Retain
UpdateReplacePolicy: Retain
Properties:
BucketName: !Join
- ''
- - ameta-app-
- !Ref 'AWS::Region'
- '-'
- !Ref 'AWS::AccountId'
AccessControl: Private
CorsConfiguration:
CorsRules:
- AllowedHeaders:
- "*"
AllowedMethods:
- GET
- POST
- PUT
AllowedOrigins:
- "*"
MaxAge: 3600
WebsiteConfiguration:
IndexDocument: index.html
ErrorDocument: 404.html
Tags:
- Key: Company
WebsiteBucketPolicy:
Type: AWS::S3::BucketPolicy
Properties:
Bucket: !Ref 'WebsiteBucket'
PolicyDocument:
Version: '2012-10-17'
Statement:
- Action:
- s3:GetObject
Effect: Allow
Resource: !Join
- ''
- - 'arn:aws:s3:::'
- !Ref 'WebsiteBucket'
- /*
Principal:
CanonicalUser: !GetAtt OriginAccessIdentity.S3CanonicalUserId
However now I need to address the bucket's domain name(!GetAtt WebsiteBucket.DomainName) in cloudfront which is being deployed in us-east-1. It seems that I can't use the output of the StackSet since the resources are different regions.
Do you guys have any suggestions?
It seems that I can't use the output of the StackSet since the resources are different regions.
That's correct. You can't reference outputs across regions nor accounts. CloudFormation (CFN) is region-specific. The easiest way is to deploy your resources in us-east-1 and the pass their outputs as parameters to the second stack in different region. You can do it manually, or automatically using AWS CLI or SDK from your local workstation or ec2 instance.
But if want to keep everything within CFN, you would have to develop a custom resource for the second stack. The resource would be in the form of a lambda function which would use AWS SDK to get the outputs from us-east-1 and pass them to your stack in different region.

Create an SNS message from an existing buckets S3 create event using cloudformation/serverless

I have an existing s3 bucket not created by the serverless/cloudformation stack. I also have a serverless stack with a bunch of lambdas that are triggered off of s3 create events with different prefixes. I have a need to send some s3 create events over SNS so that it can be used in another system.
In my serverless.yaml I have a resources section where I can create an SNS Topic and Policy. This appears to work fine:
resources:
Resources:
# Create a topic for the created s3 documents to be published on.
MyS3ToSnsTopic:
Type: AWS::SNS::Topic
Properties:
DisplayName: 'Topic to notify new s3-to-sns s3 document was created'
TopicName: s3-to-sns
# Policy for Bucket to publish sns messages to `s3-to-sns` topic
MyS3ToSnsTopicPolicy:
Type: AWS::SNS::TopicPolicy
Properties:
PolicyDocument:
Id: MyS3ToSnsTopicPolicy
Version: '2012-10-17'
Statement:
- Sid: s3-to-sns-id
Effect: Allow
Principal:
AWS: "*"
Action: sns:Publish
Resource: !Join [':', ['arn:aws:sns:us-west-2', Ref: 'AWS::AccountId', 's3-to-sns']]
Condition:
ArnLike:
"aws:SourceArn": "arn:aws:s3:*:*:${self:custom.bucketName.${self:provider.stage}}"
Topics:
- !Ref MyS3ToSnsTopic
When I go to the bucket -> properties -> events I can manually add an event that listens to a prefix/suffix, and can publish to that topic. So the last piece is to create the event with cloudformation instead of manually doing it.
When I have serverless create a lambda trigger based on the create event it generates the following:
SomeFunctionNameCustomS31:
Type: Custom::S3
Version: 1
DependsOn:
- SomeFunctionNameLambdaFunction
- CustomDashresourceDashexistingDashs3LambdaFunction
Properties:
ServiceToken:
Fn::GetAtt:
- CustomDashresourceDashexistingDashs3LambdaFunction
- Arn
FunctionName: some-function-name
BucketName: some-bucket-name
BucketConfigs:
- Event: s3:ObjectCreated:*
Rules:
- Prefix: metrics/
- Suffix: ".json"
Is there a way to do something similar for SNS, but instead of using a FunctionName use something like TopicName? What other attributes would need to be added or changed? I've seen recommendations about NotificationConfiguration when you create the bucket with the stack, but my bucket wasn't created with my stack.
The framework allows you to customise resources it creates, and you can always configure any resources you manually create through the Resources block. Both allowing you to set NotificationConfiguration which allows for SNS subscription.
resources:
Resources:
MyBucket:
Type: AWS::S3::Bucket
Properties:
BucketName: ${self:custom.bucketName}
NotificationConfiguration:
TopicConfigurations:
- Event: s3:ObjectCreated:*
Topic:
Ref: MySnsTopic
The documentation also details how you would customize a framework created S3 bucket.

Restrict acces to API Gateway endpoint to VPC in cloudformation

I'm trying to limit access to my API Gateway endpoints to requests from my VPC. There are examples of API Gateway Resource Policies, and even a Policy property on the RestApi resource, but I can't figure out how to write a policy that needs the API's ID, when the API hasn't been created yet.
I have an example of my understanding how a stack should look like, based on the AWS documentation:
MyRestApi:
Type: 'AWS::ApiGateway::RestApi'
Properties:
Name: My Great API
Policy:
Version: 2012-10-17
Statement:
- Effect: Allow
Principal: '*'
Action: execute-api:Invoke
Resource:
Fn::Join:
- - ''
- 'arn:aws:execute-api:'
- Ref: region
- ':'
- Ref: accountId
- ':'
- Ref: MyRestApi
- Effect: Deny
Principal: '*'
Action: execute-api:Invoke
Resource:
Fn::Join:
- - ''
- 'arn:aws:execute-api:'
- Ref: Region
- ':'
- Ref: AccountId
- ':'
- Ref: MyRestApi
Condition:
StringNotEquals:
"aws:SourceVpc":
Ref: VpcId
The crux is that I can't reference MyRestApi in the policy when it's still being created. I'm sure I'm not the only one that wants to do this ... I'd rather think this is a common problem, so there is very likely an answer already I haven't found yet.
Thanks for any help,
Stefan
PS: The documentation I used was https://docs.aws.amazon.com/de_de/AWSCloudFormation/latest/UserGuide/aws-resource-apigateway-restapi.html#cfn-apigateway-restapi-policy and https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-resource-policies-examples.html
According to AWS documentation the policy supports a special syntax for Resource due to this problem.
"Resource": [
"execute-api:/stage/method/path"
]
In the comments, they call it:
// simplified format supported here because apiId is not known yet and partition/region/account can derived at import time

Serverless - Setting the authorization type to CUSTOM or COGNITO_USER_POOLS requires a valid authorizer

I have a problem when attaching custom authorizer on API gateway endpoint. Here is my scenario step :
Create custom authorizer (using lambda function).
Create new endpoint with integration type as HTTP.
Set AuthorizationType as CUSTOM
How I attach my custom authorizer on serverless yaml?
I try using AuthorizerId, got error “ProxyMethod - Invalid authorizer ID specified. Setting the authorization type to CUSTOM or COGNITO_USER_POOLS requires a valid authorizer.”
I didn’t find example code on serverless documentation for my scenario above
I try to follow AWS docs. It explains to use AuthorizerId, but not sure whether serverless support it or not.
Could someone assist me with this?
You should create the Authorizer first. The you will got an authorizer id which could be used in your config.
Resources:
authorizer:
Type: AWS::ApiGateway::Authorizer
Properties:
AuthorizerResultTtlInSeconds: 0
AuthorizerUri: !Join
- ''
- - 'arn:aws:apigateway:'
- '{region}'
- ':lambda:path/2015-03-31/functions/'
- 'arn:aws:lambda:{region}:'
- Ref: AWS::AccountId
- ':function:customAuthorizer'
- '/invocations'
Name: authorizer
RestApiId: {restApiId}
Outputs:
authorizerId:
Description: "API Gateway Auth Id"
Value: !Ref authorizer
Export:
Name: !Join
- '-'
- - !Ref AWS::StackName
- AuthorizerId