How to enable access logging on API Gateway with SAM
Create a Log Group
To be able to read the access logs for your API, you must first create a dedicated log group on CloudWatch.
Navigate to the CloudWatch console and under Logs
, select Log Groups
.
Click on Create Log Group
on the top right of the page. This will prompt
you to create a new log group. Give it a name, choose a retention period and
click create.
Save the log group to SSM
Now that we have a new log group, the next step is going to be to save its arn
to the AWS Systems Manager Parameter Store. Navigate to the page from your console,
and click Parameter Store
(found under Application Management
) on the left sidebar.
There, you will have to click on Create New Parameter
. Much like the previous step,
give it a name, a type and an optional description. Under value, you want to paste the arn
of the log group. Click save and you should be good to go.
Update your API Gateway definition
Now that we have the parameter set up, it’s time to use it. We will create
a Parameter
resource in our template that will hold that variable. The syntax
looks a bit unfamiliar but it’s ok.
Parameters:
AccessLogsGroup:
Type: AWS::SSM::Parameter::Value<String>
Default: name-of-your-ssm-parameter
The reason we do it like this is so that we can keep our code DRY. This significantly decreases the risk of making errors when copy/pasting etc … and if we ever decide to use a different log group, we can just change the name once at the top of the file and all references will point to the correct resource.
Next we have to configure our API resource to use our newly created log group:
BarzLolAPI:
Type: AWS::Serverless::Api
Properties:
Name: "my_api"
StageName: my-stage
AccessLogSetting:
DestinationArn: !Ref AccessLogsGroup
Format: $context.extendedRequestId $context.identity.sourceIp $context.identity.caller $context.identity.user [$context.requestTime] "$context.httpMethod $context.resourcePath $context.protocol" $context.status $context.responseLength $context.requestId
For the format, I picked the default string I found in the docs but know that you can use json or even csv.
Don’t deploy your stack just yet, we have one more thing to do.
Roles and Policies
If you deploy the stack as is you will get an error about a missing role that’s required.
The reason is simple: for API Gateway to actually push logs to CloudWatch, it needs to have the correct permissions.
Thankfully, AWS provides us with a managed policy called AmazonAPIGatewayPushToCloudWatchLogs
.
To assign the correct permissions, we’ll need to do two things:
- Create the role with the proper trust policy
- Attach the managed policy to the role
This can be done easily with the CLI.
First, let’s create a trust policy for API Gateway to assume the role.
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "",
"Effect": "Allow",
"Principal": {
"Service": "apigateway.amazonaws.com"
},
"Action": "sts:AssumeRole"
}
]
}
With this, we can create the role by running this command:
aws iam create-role --role-name my-role --assume-role-policy-document file://trust.json
This command should output the arn
of the newly created role, keep it somewhere becaus we will need it shortly.
Now we can attach the managed policy to the role like so:
aws iam attach-role-policy --role-name my-role --policy-arn arn:aws:iam::aws:policy/service-role/AmazonAPIGatewayPushToCloudWatchLogs
Add the role to your API Gateway Settings
Navigate to your API Gateway, under settings (last link on the left sidebar), paste the arn of the role you just created
in the CloudWatch log role ARN
field.
Deploy Your Stack
You can now safely deploy your stack, make a few requests to your api and see the logs appear in your log group.