Skip to main content
Palo Alto Networks Cortex XCOR receives Amazon Web Services (AWS) logs through Amazon Data Firehose. In each AWS account and region, a Firehose stream sends logs to the AWS logs ingest endpoint in your Cortex XCOR tenant. CloudWatch Logs reach the stream through a subscription, and some AWS services send their logs to the stream directly.

What it collects

  • CloudWatch Logs: Logs that AWS services and your applications write to CloudWatch log groups. Use an account-level subscription policy to cover every log group in a region, including new ones, or add a subscription filter to each log group. Subscriptions cover only log groups in the Standard log class. CloudTrail can also send its events to a log group.
  • Logs sent straight to Firehose: Services such as Virtual Private Cloud (VPC) Flow Logs and Web Application Firewall (WAF) can deliver logs to a Firehose stream without a log group.
  • Not collected: Logs that AWS writes only to Amazon S3, such as Classic Load Balancer access logs.

How it works

The following diagram shows how AWS log sources reach Cortex XCOR and where Firehose stores eligible failed deliveries.

Before you begin

  • AWS permissions: The identity that runs the setup needs the permissions listed in Required permissions.
  • A Cortex XCOR API token: Create or use an API token for a restricted service account with write-only permission. For more information, see Create a restricted service account.
  • Your organization name: The <ORG_NAME> segment in https://<ORG_NAME>.chronosphere.io.
  • Existing subscriptions: Each account and region allows one account-level subscription policy, and each log group allows five subscription filters of its own, which the account-level policy doesn’t count against. If another tool already uses the account-level policy, subscribe log groups individually. To inspect the account policies, run:

Required permissions

To run the Terraform or CloudFormation setup in one account, the identity that runs it needs the following permissions. These permissions create and remove the setup resources. StackSets and the console need additional permissions.
  • Amazon Data Firehose
    • Actions: CreateDeliveryStream, DeleteDeliveryStream, DescribeDeliveryStream, UpdateDestination, ListTagsForDeliveryStream, TagDeliveryStream, UntagDeliveryStream
    • Resource: The stream
  • Amazon S3
    • Actions: CreateBucket, DeleteBucket, PutLifecycleConfiguration, PutBucketTagging, ListBucket, Get*, and DeleteObject to empty the bucket when you remove it
    • Resource: The failed-data bucket
  • CloudWatch Logs
    • Actions: CreateLogGroup, DeleteLogGroup, PutRetentionPolicy, CreateLogStream, DeleteLogStream, DescribeLogGroups, DescribeLogStreams, ListTagsForResource, TagResource, PutAccountPolicy, DeleteAccountPolicy, DescribeAccountPolicies, PutSubscriptionFilter, DeleteSubscriptionFilter, DescribeSubscriptionFilters
    • Resource: All resources, because account policies have no resource ARN
  • IAM
    • Actions: CreateRole, DeleteRole, GetRole, PutRolePolicy, GetRolePolicy, DeleteRolePolicy, ListRolePolicies, ListAttachedRolePolicies, ListInstanceProfilesForRole, PassRole
    • Resources: The two roles the setup creates
  • AWS Secrets Manager
    • Actions: CreateSecret, DeleteSecret, DescribeSecret, UpdateSecret, GetSecretValue, TagResource, UntagResource
    • Resource: The token secret
  • CloudFormation, for the CloudFormation tab only
    • Actions: CreateChangeSet, DescribeChangeSet, ExecuteChangeSet, DeleteChangeSet, DescribeStacks, DescribeStackEvents, DeleteStack, GetTemplateSummary
    • Resource: The stack
The setup creates two roles:
  • Firehose role: Trusted by Firehose in your account. It can write to the failed-data bucket, read the token secret, and write the stream’s error log.
  • Subscription role: Trusted by CloudWatch Logs in your account. It can put records into the stream.
The setup has no access to your existing buckets or other resources, and it doesn’t send logs written before it’s in place.

Firehose settings

Use these settings regardless of how you create the stream: Firehose bills each CloudWatch Logs record at its compressed size, rounded up to 5 KB. Log groups that send few events per batch cost more per log. Firehose also bills data transfer for every delivery attempt, including retries. While deliveries fail, data transfer grows with each retry until the retry window ends.
  • Source: Direct PUT.
  • Destination: HTTP Endpoint.
  • HTTP endpoint URL: https://<ORG_NAME>.chronosphere.io/api/v1/data/logs/ingest/integrations/aws.
  • Authentication: An AWS Secrets Manager secret containing {"api_key":"<API_TOKEN>"}. Firehose picks up a rotated token within about 10 minutes. Using the API token as the endpoint access key also works, but stores it in the stream settings.
  • Content encoding: GZIP for smaller requests and lower data transfer costs.
  • Retry duration: 7200 seconds, the longest Firehose allows. Records that still fail go to the S3 bucket.
  • Buffer size: 1 MiB. Keep this value at 4 MiB or less. Firehose treats the size as a hint and encodes each record in a text representation larger than the source record. Cortex XCOR rejects requests over 16 MiB with a 413, and Firehose drops a batch that gets a 413 without retrying it or backing it up.
  • Buffer interval: 60 seconds.
  • Decompression and message extraction: Off. Cortex XCOR decodes CloudWatch Logs records. Message extraction removes the log group and log stream used to identify the service.
  • Source record backup in Amazon S3: Failed data only.
  • Backup bucket lifecycle: Expire objects after 14 days. Cortex XCOR drops retried logs more than 24 hours old.
  • Parameters: None. For the exception for VPC Flow Logs in a custom format, see Send logs straight to Firehose.

Set up log delivery

Set up delivery in each account and region you want logs from.
  1. Store your API token in AWS Secrets Manager in the region you’re setting up. Note the secret’s ARN. Read the token without echoing it, so it stays out of your shell history. Run the read command on its own:
    Then create the secret:
  2. The configuration was tested with version 6 of the aws provider. It also needs the time provider. Set the region on the aws provider:
  3. Set values for these variables, and apply the configuration in each account and region. It creates the Firehose stream, S3 bucket for failed data with a lifecycle rule, and IAM roles. Unless you turn it off, it also creates an account-level subscription policy that sends every log group in the region except the stream’s own error logs.
    Terraform example
  4. If you set create_account_policy = false, follow Subscribe individual log groups with the stream_arn and subscription_role_arn outputs.

Set up many accounts and regions

Set up one stream in each account and region you want logs from. Each stream reports its own deliveries, so a problem appears in the account and region it affects. To deploy to many accounts in an organization in AWS Organizations, run the CloudFormation template as a StackSet with service-managed permissions. Pass the API token as ApiToken instead of ApiTokenSecretArn. Each stack instance then creates its own secret, so accounts that automatic deployment adds later need no extra setup, unless they already have an account-level subscription policy. CloudFormation shows ApiToken as ****, but keeps it as a StackSet parameter. If the token should live only in Secrets Manager, set up each account with ApiTokenSecretArn instead. A StackSet exists only in the region where you create it. Choose one region to administer it from, and pass that region as --region <ADMIN_REGION> on every StackSet command, including later rotations and removal. With a delegated administrator, pick one of the regions AWS supports for delegated administrators. Before you start, from the organization’s management account, enable all features in AWS Organizations and activate trusted access for StackSets:
If an account and region the StackSet targets already has the single-account setup from this page, remove it first, as described in Remove log delivery. The StackSet’s stacks use the same stream and log group names, so their instances fail there. The management account isn’t targeted, so keep its setup. To administer the StackSet from a delegated administrator account instead, register that account from the management account:
From a delegated administrator, add --call-as DELEGATED_ADMIN to every StackSet command on this page: create-stack-set, create-stack-instances, update-stack-instances, update-stack-set, describe-stack-set-operation, list-stack-instances, delete-stack-instances, and delete-stack-set. The delegated administrator also needs organizations:ListDelegatedAdministrators. The commands below read the API token with read -rs, which works in bash and zsh and doesn’t show the token as you paste it. Run the read command on its own, before the commands that use the token.
  1. Read the API token:
  2. Write the parameters to a file only you can read, so the token stays out of your shell history:
  3. Create the StackSet from the template in the CloudFormation tab, saved as cortex-xcor-aws-logs.yaml, and then delete the parameters file:
    With automatic deployment, an account that joins a target organizational unit gets a stack, and an account that leaves has its stack deleted. The deleted stack’s failed-data bucket is kept.
  4. Deploy the StackSet to your organizational units and regions. <OU_ID> can be the organization’s root ID (r-...) to cover every account.
    These preferences deploy to every account and region at once and keep going past accounts that fail. Without them, CloudFormation deploys to one account at a time and stops at the first failure, which also skips every later region. The preferences don’t apply to automatic deployments.
  5. Wait for the operation to finish, and then list the stack instances that failed. With these preferences, the operation reports SUCCEEDED even when some instances failed.
An instance fails in an account and region that already has an account-level subscription policy, because each account and region allows only one. For each of those, override CreateAccountPolicy to false, wait for the operation with the commands in step 5, and then subscribe log groups individually in that account with the DeliveryStreamArn and SubscriptionRoleArn outputs of its stack:
Target accounts rather than an organizational unit, because an override set on an organizational unit doesn’t apply to accounts that join it later. Fix failed instances promptly. Every later update to the StackSet tries to create them again, which makes the update much slower. A StackSet with service-managed permissions doesn’t deploy to the management account. To collect that account’s logs, set it up on its own as described earlier on this page. To rotate the token, read the new token on its own:
Then update the StackSet’s ApiToken parameter, keeping the other parameters:
Wait for the operation and list failed instances with the commands in step 5. If any instance is listed, fix its cause and run the update again, which retries the instances that didn’t update. If CloudFormation reports that another operation is in progress, such as an automatic deployment, wait for it to finish and run the update again. If the management account’s own setup uses the same token, update its secret in each region where you set it up. Read the new token again:
Then update each region:
Each Firehose stream starts using the new token within 10 minutes of its secret changing. Don’t revoke the old token until every stack and the management account’s secret have updated, and 10 more minutes have passed. This page doesn’t cover sending logs from many accounts to one stream.

Subscribe individual log groups

To send only some log groups, or when another tool holds the account-level policy, add a subscription filter to each log group:
Don’t include these log groups in the account-level policy, or their logs arrive twice.

Send logs straight to Firehose

Some services deliver logs to a Firehose stream without a log group. Give each service its own stream, created in the console with the same settings under a unique name. By default, the Terraform and CloudFormation configurations also create the account subscription policy, so don’t run them again for these streams. The account-level policy sends each additional stream’s error log group, /aws/kinesisfirehose/<STREAM_NAME>, to the stream targeted by the policy unless you add the error log group to the policy exclusion. Cortex XCOR recognizes these logs on its own:
  • AWS WAF: By the stream name, which AWS requires to start with aws-waf-logs-, and by the log format.
  • Amazon API Gateway: By a stream name that starts with amazon-apigateway-.
  • VPC Flow Logs: By the default log format. For a custom format, add the stream parameter xcor_integration with the value aws_vpc.
For other logs sent straight to Firehose, set the xcor_integration parameter to a recognized AWS integration ID, such as aws_cloudtrail, aws_eks, aws_lambda, or aws_rds. Cortex XCOR ignores unknown values. Logs it can’t otherwise recognize are stored with the label aws_other.

Validate log ingestion

After setup, wait for logs to arrive before validating ingestion.
  1. In the Amazon Data Firehose console, open the stream. HTTP endpoint delivery success should report 100%, and Records delivered to HTTP endpoint should be non-zero.
  2. In Cortex XCOR, go to Explorers > Logs Explorer and run:
    Each AWS service sending logs appears as a row.

Log labels and fields

Every log gets two labels:
  • xcor.integration.name: always aws, the integration’s catalog ID.
  • xcor_integration: the AWS service that wrote the log, such as aws_lambda, aws_rds, aws_eks, aws_vpc, or aws_cloudtrail. Cortex XCOR determines the service from the log group name, log stream name, log format, or a stream parameter. Logs it can’t attribute to an AWS service get aws_other and are stored like any other log.
Keep the default AWS log group names. The exception is Amazon ECS: Cortex XCOR recognizes ECS logs only in log groups under /aws/ecs/ or /aws/vendedlogs/ecs/, so the /ecs/<task definition family> group that the ECS console creates gets aws_other. Cortex XCOR can still recognize some services from custom log group names by using the log stream name or format. Other logs get aws_other. Every log also carries these fields, set from the delivery rather than the log message: Logs delivered through a CloudWatch Logs subscription also carry these fields: For an organization trail, aws.account_id is the management account. CloudTrail’s recipientAccountId field identifies the account for each event, and its awsRegion field identifies the event’s region. Cortex XCOR parses a JSON log message into fields and stores any other message in message. Fields set by the log take precedence over the following fields that Cortex XCOR sets:
  • Time: The log’s timestamp field, then CloudTrail’s eventTime, then the time CloudWatch Logs stored the event. A log sent straight to Firehose without a time gets the time Cortex XCOR receives it.
  • Service: The service field is the xcor_integration value without aws_, such as cloudtrail, eks, or rds. Lambda logs get the function name. Logs labeled aws_other get the log group, or aws_other when there’s no log group.
  • Message: For CloudTrail, message is the event name, such as AssumeRole.
  • Severity: CloudTrail events with an errorCode get ERROR. Other CloudTrail events get INFO, and other logs without a severity get your organization’s default.

Troubleshooting

Firehose records delivery errors in the log group /aws/kinesisfirehose/<STREAM_NAME>.
  • 401 errors, or a content-type: application/json error whose raw response starts with 401: The token isn’t an API token for a restricted service account with write-only permission in this organization. After a token change, Firehose can keep using the old token for up to 10 minutes.
  • Secrets Manager errors: The secret must be JSON with the key api_key, and the stream role needs secretsmanager:GetSecretValue on the secret.
  • 404 errors, or a content-type: application/json error whose raw response starts with 404: The endpoint URL is incorrect. It must end in /api/v1/data/logs/ingest/integrations/aws.
  • Logs labeled aws_other: The log group has a custom name or is the ECS console’s /ecs/ group, or the logs came straight from a service that Cortex XCOR couldn’t identify from the stream name or log format. Set the stream parameter xcor_integration to a recognized AWS integration ID. For example, use aws_vpc for VPC Flow Logs in a custom format.
  • Delivery succeeds but some logs are missing: Cortex XCOR drops logs more than 24 hours old or more than 24 hours in the future. CloudWatch Logs can deliver older events, such as after a long outage.
  • Duplicate logs: After an error, Firehose sends the entire batch again, so some records can arrive twice.
Records that still fail after the retry window go to the S3 bucket. Cortex XCOR doesn’t read the bucket, so those records aren’t ingested unless they’re sent again within 24 hours of their timestamps.

Remove log delivery

Until you remove it, the account-level policy keeps sending every log group in the region to the stream, and Firehose continues billing for it.
  • For Terraform, run terraform destroy.
  • For CloudFormation, note the failed-data bucket’s name, and then delete the stack:
    From template 1.1.0, deleting the stack keeps the failed-data bucket, so leftover records can’t make the delete fail. Its records still expire, and you can delete it with aws s3 rb s3://<BUCKET> --force when you no longer need them, where <BUCKET> is the name the first command printed. If you passed ApiToken, deleting the stack also deletes its secret immediately, without a recovery window.
  • For a StackSet, delete the stack instances from the organizational units and regions you deployed to:
    Wait for the operation with the commands in step 5 of Set up many accounts and regions, and then delete the StackSet. Each account keeps its failed-data bucket.
  • In the console, delete the account-level policy, then the Firehose stream, subscription role, failed-data bucket, and the stream’s error log group, which the console creates:
  • For individual subscriptions, remove each subscription with:
If you use Terraform, delete resources by hand, or delete a stack from a template before 1.1.0, empty the failed-data bucket first, or its deletion fails. If you created the token secret yourself and passed ApiTokenSecretArn, delete it too, because the setup doesn’t own it. By default, Secrets Manager schedules deletion with a 30-day recovery window. During that window, another setup attempt with the same secret name fails. The --force-delete-without-recovery option skips the recovery window. Deletion is asynchronous, so wait and retry if the name remains unavailable: