steep-motorcycle-5349
09/09/2025, 7:09 AMsteep-motorcycle-5349
09/09/2025, 3:26 PMpackage cloudfront
import (
"ddos-protection-pulumi/config"
"ddos-protection-pulumi/provider"
"fmt"
"<http://github.com/pulumi/pulumi-aws/sdk/v7/go/aws/cloudfront|github.com/pulumi/pulumi-aws/sdk/v7/go/aws/cloudfront>"
"<http://github.com/pulumi/pulumi-aws/sdk/v7/go/aws/cloudwatch|github.com/pulumi/pulumi-aws/sdk/v7/go/aws/cloudwatch>"
"<http://github.com/pulumi/pulumi-aws/sdk/v7/go/aws/iam|github.com/pulumi/pulumi-aws/sdk/v7/go/aws/iam>"
"<http://github.com/pulumi/pulumi-aws/sdk/v7/go/aws/kinesis|github.com/pulumi/pulumi-aws/sdk/v7/go/aws/kinesis>"
"<http://github.com/pulumi/pulumi/sdk/v3/go/pulumi|github.com/pulumi/pulumi/sdk/v3/go/pulumi>"
log "<http://github.com/sirupsen/logrus|github.com/sirupsen/logrus>"
)
func CreateFirehoseToVector(ctx *pulumi.Context) (*kinesis.FirehoseDeliveryStream, error) {
<http://log.Info|log.Info>("Creating Kinesis Data Firehose delivery stream to Vector HTTP endpoint")
// Reuse existing IAM role
//firehoseRoleARN := "arn:aws:iam::300926307005:role/firehose_delivery_role"
firehoseRole, err := CreateMinimalFirehoseRole(ctx)
if err != nil {
return nil, err
}
// S3 Backup bucket ARN
backupBucketArn := pulumi.String("arn:aws:s3:::<http://firehose-logs-backup.nanocosmos.de|firehose-logs-backup.nanocosmos.de>")
// Create Firehose Delivery Stream to HTTP endpoint (Vector)
firehoseStream, err := kinesis.NewFirehoseDeliveryStream(ctx, "nanoplayer1-firehose", &kinesis.FirehoseDeliveryStreamArgs{
Name: pulumi.String("nanoplayer1"),
Destination: pulumi.String("http_endpoint"),
// HTTP Endpoint Destination Configuration
HttpEndpointConfiguration: &kinesis.FirehoseDeliveryStreamHttpEndpointConfigurationArgs{
Url: pulumi.String("<https://vector-aws-kinesis-firehose.nanocosmos.cloud>"),
Name: pulumi.String("vector-http-endpoint"),
RetryDuration: <http://pulumi.Int|pulumi.Int>(300), // Max retry duration (5 min)
RoleArn: firehoseRole.Arn,
S3Configuration: &kinesis.FirehoseDeliveryStreamHttpEndpointConfigurationS3ConfigurationArgs{
BucketArn: backupBucketArn,
RoleArn: firehoseRole.Arn,
Prefix: pulumi.String("nanoplayer1/"),
BufferingSize: <http://pulumi.Int|pulumi.Int>(8), // In MB
BufferingInterval: <http://pulumi.Int|pulumi.Int>(300), // In seconds
CompressionFormat: pulumi.String("GZIP"),
},
ProcessingConfiguration: &kinesis.FirehoseDeliveryStreamHttpEndpointConfigurationProcessingConfigurationArgs{
Enabled: pulumi.Bool(false), // No Lambda processing
},
AccessKey: pulumi.String("TempPassword"), // Sensitive — consider using Secrets Manager in production
// Content encoding
CloudwatchLoggingOptions: &kinesis.FirehoseDeliveryStreamHttpEndpointConfigurationCloudwatchLoggingOptionsArgs{
Enabled: pulumi.Bool(true),
LogGroupName: pulumi.String("/aws/firehose/nanoplayer1"),
LogStreamName: pulumi.String("delivery-stream"),
},
},
}, pulumi.Provider(provider.GetUsEast1Provider(ctx)))
if err != nil {
log.Errorf("Failed to create Firehose delivery stream: %v", err)
return nil, fmt.Errorf("failed to create Firehose stream 'nanoplayer1': %w", err)
}
<http://log.Info|log.Info>("Successfully created Firehose delivery stream: nanoplayer1")
return firehoseStream, nil
}
func SetupLogForwarderToFirehose(ctx *pulumi.Context, cfVars config.CfVars, distr *cloudfront.Distribution, firehose *kinesis.FirehoseDeliveryStream) error {
log.Infof("Setting up CloudFront V2 log delivery to Firehose: nanoplayer1")
// Ensure all AWS resources for V2 logging are in us-east-1
usEast1Provider := provider.GetUsEast1Provider(ctx)
// Step 1: Create Log Delivery Source (CloudFront distribution)
logSource, err := cloudwatch.NewLogDeliverySource(ctx, "cf-log-source", &cloudwatch.LogDeliverySourceArgs{
Region: pulumi.String("us-east-1"),
Name: pulumi.String(cfVars.OriginId + "-log-source"),
LogType: pulumi.String("ACCESS_LOGS"),
ResourceArn: distr.Arn,
}, pulumi.Provider(usEast1Provider))
if err != nil {
log.Errorf("Failed to create log delivery source: %v", err)
return fmt.Errorf("failed to create log delivery source: %w", err)
}
// Step 2: Create Log Delivery Destination (Firehose) with proper role configuration
logDestination, err := cloudwatch.NewLogDeliveryDestination(ctx, "cf-firehose-destination", &cloudwatch.LogDeliveryDestinationArgs{
Region: pulumi.String("us-east-1"),
Name: pulumi.String("firehose-nanoplayer1-destination"),
OutputFormat: pulumi.String("json"), // Structured JSON logs
DeliveryDestinationConfiguration: &cloudwatch.LogDeliveryDestinationDeliveryDestinationConfigurationArgs{
DestinationResourceArn: firehose.Arn,
},
// Add tags if needed
Tags: pulumi.StringMap{
"Purpose": pulumi.String("CloudFront-Logs-to-Vector"),
},
}, pulumi.Provider(usEast1Provider))
if err != nil {
log.Errorf("Failed to create log delivery destination: %v", err)
return fmt.Errorf("failed to create log delivery destination: %w", err)
}
// Step 3: Enable Log Delivery (connect source → destination) with explicit role
_, err = cloudwatch.NewLogDelivery(ctx, "cf-to-firehose-delivery", &cloudwatch.LogDeliveryArgs{
Region: pulumi.String("us-east-1"),
DeliverySourceName: logSource.Name,
DeliveryDestinationArn: logDestination.Arn,
// Add tags if needed
Tags: pulumi.StringMap{
"Purpose": pulumi.String("CloudFront-to-Firehose-Delivery"),
},
}, pulumi.Provider(usEast1Provider), pulumi.DependsOn([]pulumi.Resource{logSource, logDestination}))
if err != nil {
log.Errorf("Failed to enable log delivery: %v", err)
return fmt.Errorf("failed to enable log delivery to firehose: %w", err)
}
log.Infof("Successfully enabled real-time log delivery from CloudFront to Firehose (nanoplayer)")
return nil
}
func CreateMinimalFirehoseRole(ctx *pulumi.Context) (*iam.Role, error) {
<http://log.Info|log.Info>("Creating minimal IAM role for Firehose delivery stream")
// Step 1: Create the IAM role that Firehose can assume
role, err := iam.NewRole(ctx, "firehose-nanoplayer-role", &iam.RoleArgs{
AssumeRolePolicy: pulumi.String(`{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": "<http://firehose.amazonaws.com|firehose.amazonaws.com>"
},
"Action": "sts:AssumeRole"
}
]
}`),
Description: pulumi.String("Minimal IAM role for Firehose to deliver CloudFront logs to Vector endpoint"),
}, pulumi.Provider(provider.GetUsEast1Provider(ctx)))
if err != nil {
return nil, fmt.Errorf("failed to create IAM role: %w", err)
}
// Step 2: Attach minimal required policies
// Inline policy: S3 + Firehose + CloudWatch Logs
policyDoc := pulumi.String(`{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "S3BackupPermissions",
"Effect": "Allow",
"Action": [
"s3:AbortMultipartUpload",
"s3:GetBucketLocation",
"s3:ListBucket",
"s3:ListBucketMultipartUploads",
"s3:PutObject"
],
"Resource": [
"arn:aws:s3:::<http://firehose-logs-backup.nanocosmos.de|firehose-logs-backup.nanocosmos.de>",
"arn:aws:s3:::<http://firehose-logs-backup.nanocosmos.de/*|firehose-logs-backup.nanocosmos.de/*>"
]
},
{
"Sid": "FirehoseDeliveryToHTTP",
"Effect": "Allow",
"Action": [
"firehose:PutRecord",
"firehose:PutRecordBatch"
],
"Resource": "*"
},
{
"Sid": "CloudWatchLogsDeliverySetup",
"Effect": "Allow",
"Action": [
"logs:CreateLogDelivery",
"logs:UpdateLogDelivery",
"logs:DeleteLogDelivery",
"logs:GetLogDelivery",
"logs:ListLogDeliveries",
"logs:PutResourcePolicy"
],
"Resource": "*"
},
{
"Sid": "CloudWatchLogging",
"Effect": "Allow",
"Action": [
"logs:PutLogEvents"
],
"Resource": "arn:aws:logs:us-east-1:*:*"
}
]
}`)
_, err = iam.NewRolePolicy(ctx, "firehose-nanoplayer-policy", &iam.RolePolicyArgs{
Role: role.Name,
Policy: policyDoc,
}, pulumi.Provider(provider.GetUsEast1Provider(ctx)))
if err != nil {
return nil, fmt.Errorf("failed to attach policy to IAM role: %w", err)
}
<http://log.Info|log.Info>("Successfully created minimal Firehose IAM role")
return role, nil
}
But I got an error:
aws:cloudwatch:LogDelivery (cf-to-firehose-delivery):
error: creating CloudWatch Logs Delivery: operation error CloudWatch Logs: CreateDelivery, https response error StatusCode: 400, RequestID: e656faef-aefe-445f-a36e-7d300d133e0c, AccessDeniedException: Access Denied for this Delivery Destination. Please make sure that you have correct permissions to access the Log Destination Resource.blue-jelly-20468
09/09/2025, 9:33 PMblue-jelly-20468
09/09/2025, 9:35 PM