Skip to content

Ingesting Web Application Click Logs into AWS (by HashiCorp)

Threat Model Architecture Representation

Let's use an Official example for Ingesting Web Application Click Logs:

This post provides an API based ingestion application system for websites & applications to push user interactions, click actions from their website into AWS. The ingestion process will be exposed using a web-based interaction with an API Gateway endpoint.

This example gives the source code for the following AWS architecture diagram:

ingesting-click-logs-from-web-application.png

The slp_tfplan processor can generate an accurate threat model by only following the steps below.

Generating my own Terraform files

1⃣ Clone and prepare the example reporitory:

These previous set-up commands are required because the example needs some lambda code to be compiled.

$ git clone https://github.com/aws-samples/aws-ingesting-click-logs-using-terraform.git
$ cd aws-ingesting-click-logs-using-terraform/source/clicklogger
$ mvn clean package
$ cd ../../terraform/templates

2⃣ Generate the tf-plan and tf-graph files:

$ terraform init
$ terraform plan -out=tf-plan
$ terraform show -json tf-plan > tf-plan.json
$ terraform graph -type=plan -plan=tf-plan > tf-graph.gv

Use the StartLeft CLI to generate the OTM file:

$ startleft parse \ 
  --iac-type TFPLAN \ 
  --default-mapping-file ir-mappings.yaml \ 
  --output-file output.otm \
  --project-id "my-project" \
  --project-name "My project" \ 
  tf-plan.json tf-graph.gv

After, we need to use the Terraform CLI to create the required files and execute StartLeft parse to generate the final OTM.

ingesting-click-logs-from-web-application-iriusrisk-diagram.png

trustzones:
  - type: b61d6911-338d-46a8-9f39-8dcd24abfe91
    name: Public Cloud
    risk:
      trust_rating: 10
    $default: true

  - type: f0ba7722-39b6-4c81-8290-a30a248bb8d9
    name: Internet
    risk:
      trust_rating: 1

components:

  - label: aws_acm_certificate
    type: CD-ACM
    $singleton: true

  - label: aws_cloudwatch_metric_alarm
    type: cloudwatch
    $singleton: true

  - label: aws_dynamodb_table
    type: dynamodb

  - label: aws_vpc
    type: vpc

  - label: aws_instance
    type: ec2

  - label: aws_subnet
    type: empty-component

  - label: aws_vpc_endpoint
    type: empty-component

  - label: aws_internet_gateway
    type: empty-component

  - label: aws_ecs_service
    type: elastic-container-service

  - label: aws_ecs_task_definition
    type: docker-container

  - label: ["aws_lb", "aws_elb", "aws_alb"]
    type: load-balancer

  - label: aws_kms_key
    type: kms
    $singleton: true

  - label: aws_lambda_function
    type: aws-lambda-function

  - label: aws_cloudwatch_log_group
    type: cloudwatch
    $singleton: true

  - label: ["aws_db_instance", "aws_rds_cluster"]
    type: rds

  - label: aws_route53_zone
    type: route-53

  - label: aws_autoscaling_group
    type: CD-EC2-AUTO-SCALING

  - label: cloudflare_record
    type: empty-component

  - label: [aws_s3_bucket, aws_s3_bucket_object]
    type: s3

  - label: aws_secretsmanager_secret
    type: CD-SECRETS-MANAGER
    $singleton: true

  - label: aws_sqs_queue
    type: sqs-simple-queue-service

  - label: {$regex: ^aws_ssm_\w*$}
    type: CD-SYSTEMS-MANAGER
    $singleton: true

  - label: aws_synthetics_canary
    type: empty-component

  - label: {$regex: ^aws_api_gateway_\w*$}
    type: api-gateway
    $singleton: true

  - label: {$regex: ^aws_athena_\w*$}
    type: athena
    $singleton: true

  - label: {$regex: ^aws_mq_\w*$}
    type: CD-MQ
    $singleton: true

  - label: {$regex: ^aws_cloudfront_\w*$}
    type: cf-cloudfront
    $singleton: true

  - label: aws_cloudtrail
    type: cloudtrail

  - label: ["aws_cognito_user_pool", "aws_cognito_identity_pool"]
    type: cognito

  - label: {$regex: ^aws_config_\w*$}
    type: CD-CONFIG
    $singleton: true

  - label: {$regex: ^aws_ecr_\w*$}
    type: elastic-container-registry
    $singleton: true

  - label: aws_eks_cluster
    type: elastic-container-kubernetes

  - label: {$regex: ^aws_elasticache_\w*$}
    type: elasticache
    $singleton: true

  - label: {$regex: ^aws_guardduty_\w*$}
    type: CD-GUARDDUTY
    $singleton: true

  - label: {$regex: ^aws_inspector_\w*$}
    type: CD-INSPECTOR
    $singleton: true

  - label: {$regex: ^aws_macie2_\w*$}
    type: CD-MACIE
    $singleton: true

  - label: aws_networkfirewall_firewall
    type: CD-AWS-NETWORK-FIREWALL

  - label: aws_redshift_cluster
    type: redshift

  - label: {$regex: ^aws_ses_\w*$}
    type: CD-SES
    $singleton: true

  - label: {$regex: ^aws_sns_\w*$}
    type: sns
    $singleton: true

  - label: {$regex: ^aws_sfn_\w*$}
    type: step-functions

  - label: {$regex: ^aws_waf(.*)_\w*$}
    type: CD-WAF
    $singleton: true

  - label: {$regex: ^aws_kinesis_analytics_\w*$}
    type: kinesis-data-analytics
    $singleton: true

  - label: {$regex: ^aws_kinesis_stream\w*$}
    type: kinesis-data-analytics
    $singleton: true

  - label: {$regex: ^aws_kinesis_firehose_\w*$}
    type: kinesis-data-firehose
    $singleton: true

  - label: {$regex: ^aws_iam_\w*$}
    type: CD-AWS-IAM
    $singleton: true

  - label: {$regex: ^aws_cloudwatch_event_\w*$}
    type: eventbridge
    $singleton: true

  - label: {$regex: ^aws_codebuild_\w*$}
    type: CD-CODEBUILD
    $singleton: true

  - label: {$regex: ^aws_codepipeline\w*$}
    type: CD-CODEPIPELINE
    $singleton: true

  - label: aws_ebs_volume
    type: elastic-block-store

  - label: {$regex: ^aws_shield_\w*$}
    type: CD-SHIELD
    $singleton: true

  - label: {$regex: ^aws_cloudformation_\w*$}
    type: CD-CLOUDFORMATION
    $singleton: true

  - label: aws_glue_job
    type: CD-GLUE

  - label: aws_glue_registry
    type: CD-GLUE-SCHEMA-REGISTRY

  - label: aws_efs_file_system
    type: elastic-file-system

  - label: aws_transfer_server
    type: CD-TRANSFER-FML

  - label: aws_codecommit_repository
    type: CD-CODECOMMIT

  - label: aws_globalaccelerator_accelerator
    type: CD-GLOBAL-ACC

  - label: {$regex: ^aws_dms_\w*$}
    type: CD-DMS
    $singleton: true

  - label: {$regex: ^aws_iot_\w*$}
    type: CD-IOT-CORE
    $singleton: true

  - label: {$regex: ^aws_medialive_\w*$}
    type: CD-MEDIALIVE
    $singleton: true

  - label: {$regex: ^aws_gamelift_\w*$}
    type: CD-GAMELIFT
    $singleton: true

  - label: {$regex: ^aws_directory_service_\w*$}
    type: CD-DIR-SERVICE
    $singleton: true

  - label: {$regex: ^aws_appsync_\w*$}
    type: CD-APPSYNC
    $singleton: true

  - label: {$regex: ^aws_fms_\w*$}
    type: firewall-manager
    $singleton: true

  - label: aws_neptune_cluster
    type: CD-NEPTUNE

  - label: aws_ec2_transit_gateway
    type: CD-AWS-TRANSIT-GW

  - label: {$regex: ^aws_batch_\w*$}
    type: CD-BATCH
    $singleton: true

  - label: aws_elastic_beanstalk_application
    type: CD-ELASTIC-BEANSTALK

  - label: {$regex: ^aws_dx_\w*$}
    type: direct-connect
    $singleton: true

  - label: aws_emr_cluster
    type: CD-EMR

  - label: aws_msk_cluster
    type: CD-MSK

  - label: aws_elastictranscoder_pipeline
    type: CD-ELASTIC-TRANSCODER

  - label: aws_sagemaker_app
    type: CD-SAGEMAKER

  # AZURE
  - label: [ "azurerm_data_share", "azurerm_data_share_account" ]
    type: CD-MICROSOFT-AZURE-DATA-SHARE

  - label: azurerm_elastic_cloud_elasticsearch
    type: CD-MICROSOFT-AZURE-ELASTICSEARCH

  - label: [ "azurerm_media_services_account", "azurerm_media_services_account_filter" ]
    type: CD-MICROSOFT-AZURE-MEDIA-SERVICES

configuration:
  attack_surface:
    client: generic-client
    trustzone: f0ba7722-39b6-4c81-8290-a30a248bb8d9

#  skip:
#    - aws_security_group
#    - aws_db_subnet_group
#  catch_all: empty-component
otmVersion: 0.1.0
project:
  name: name
  id: id
representations:
  - name: Terraform
    id: Terraform
    type: code
trustZones:
  - id: b61d6911-338d-46a8-9f39-8dcd24abfe91
    name: Public Cloud
    risk:
      trustRating: 10
components:
  - id: aws_dynamodb_table.click-logger-table
    name: click-logger-table
    type: dynamodb
    parent:
      trustZone: b61d6911-338d-46a8-9f39-8dcd24abfe91
    tags:
      - aws_dynamodb_table
  - id: aws_kinesis_firehose_delivery_stream.click_logger_firehose_delivery_stream
    name: click_logger_firehose_delivery_stream
    type: kinesis-data-firehose
    parent:
      trustZone: b61d6911-338d-46a8-9f39-8dcd24abfe91
    tags:
      - aws_kinesis_firehose_delivery_stream
  - id: aws_lambda_function.lambda_clicklogger
    name: lambda_clicklogger
    type: aws-lambda-function
    parent:
      trustZone: b61d6911-338d-46a8-9f39-8dcd24abfe91
    tags:
      - aws_lambda_function
  - id: aws_lambda_function.lambda_clicklogger_authorizer
    name: lambda_clicklogger_authorizer
    type: aws-lambda-function
    parent:
      trustZone: b61d6911-338d-46a8-9f39-8dcd24abfe91
    tags:
      - aws_lambda_function
  - id: aws_lambda_function.lambda_clicklogger_stream_consumer
    name: lambda_clicklogger_stream_consumer
    type: aws-lambda-function
    parent:
      trustZone: b61d6911-338d-46a8-9f39-8dcd24abfe91
    tags:
      - aws_lambda_function
  - id: aws_s3_bucket.click_logger_firehose_delivery_s3_bucket
    name: click_logger_firehose_delivery_s3_bucket
    type: s3
    parent:
      trustZone: b61d6911-338d-46a8-9f39-8dcd24abfe91
    tags:
      - aws_s3_bucket
  - id: aws_api_gateway_account.click_logger_api_gateway_account
    name: api-gateway (grouped)
    type: api-gateway
    parent:
      trustZone: b61d6911-338d-46a8-9f39-8dcd24abfe91
    tags:
      - aws_api_gateway_method_response
      - aws_api_gateway_method_settings
      - aws_api_gateway_integration_response
      - aws_api_gateway_method
      - aws_api_gateway_model
      - aws_api_gateway_request_validator
      - aws_api_gateway_integration
      - aws_api_gateway_account
      - aws_api_gateway_resource
      - aws_api_gateway_rest_api
      - aws_api_gateway_authorizer
      - aws_api_gateway_deployment
  - id: aws_cloudwatch_log_group.click_logger_firehose_delivery_stream_log_group
    name: cloudwatch (grouped)
    type: cloudwatch
    parent:
      trustZone: b61d6911-338d-46a8-9f39-8dcd24abfe91
    tags:
      - aws_cloudwatch_log_group
dataflows:
  - id: cb8953f8-1436-47a6-8939-ffcd07902614
    name: clicklogger-authorizer to lambda_clicklogger_authorizer
    source: aws_api_gateway_account.click_logger_api_gateway_account
    destination: aws_lambda_function.lambda_clicklogger_authorizer
    bidirectional: false
  - id: 4f25e0b3-0b8a-4e84-90db-f0a8de34467e
    name: integration to lambda_clicklogger
    source: aws_api_gateway_account.click_logger_api_gateway_account
    destination: aws_lambda_function.lambda_clicklogger
    bidirectional: false
  - id: 66cecdff-ba09-42b1-a75f-8e98fdae2dc4
    name: lambda_click_logger_authorizer_log_group to lambda_clicklogger_authorizer
    source: aws_cloudwatch_log_group.click_logger_firehose_delivery_stream_log_group
    destination: aws_lambda_function.lambda_clicklogger_authorizer
    bidirectional: false
  - id: e01769b2-d461-4c4d-b7aa-cc028f4533ab
    name: lambda_click_logger_log_group to lambda_clicklogger
    source: aws_cloudwatch_log_group.click_logger_firehose_delivery_stream_log_group
    destination: aws_lambda_function.lambda_clicklogger
    bidirectional: false
  - id: 9618b94c-b899-45d0-ba70-61d141e2ad54
    name: click_logger_firehose_delivery_stream to lambda_clicklogger_stream_consumer
    source: aws_kinesis_firehose_delivery_stream.click_logger_firehose_delivery_stream
    destination: aws_lambda_function.lambda_clicklogger_stream_consumer
    bidirectional: false
  - id: e4431bbb-a8d5-413e-be2b-8c5b0cc06d81
    name: click_logger_firehose_delivery_stream to
      click_logger_firehose_delivery_s3_bucket
    source: aws_kinesis_firehose_delivery_stream.click_logger_firehose_delivery_stream
    destination: aws_s3_bucket.click_logger_firehose_delivery_s3_bucket
    bidirectional: false
  - id: 3c58eb54-f1eb-4762-9f2b-dd88793032e3
    name: lambda_clicklogger to click_logger_firehose_delivery_stream
    source: aws_lambda_function.lambda_clicklogger
    destination: aws_kinesis_firehose_delivery_stream.click_logger_firehose_delivery_stream
    bidirectional: false
  - id: 50058e60-209a-4a2f-99b3-066bb633e2eb
    name: lambda_clicklogger_stream_consumer to click-logger-table
    source: aws_lambda_function.lambda_clicklogger_stream_consumer
    destination: aws_dynamodb_table.click-logger-table
    bidirectional: false

As we can see in the previous example, StartLeft can automatically reproduce an almost exact architecture diagram than the one present in the example website.

Full Architecture Representation

This approach enables StartLeft not only to create threat models but also to explore all the components and the dataflows among them, by configuring this behavior in the mapping file. In that way, you can get this diagram from the example above:

ingesting-click-logs-from-web-application-iriusrisk-diagram-full.png

The following configuration needs to be added in the mapping file to enable this feature.

configuration:
  skip:
    - aws_security_group
    - aws_internet_gateway
    - aws_db_subnet_group
  catch_all: empty-component