# AWS Cloud Registration

This Terraform module enables registration and configuration of AWS accounts with CrowdStrike's Falcon Cloud Security.

## Key Features
- Asset Inventory
- Real-time Visibility and Detection
- Identity Protection (IDP)
- Sensor Management
- Agentless Scanning:
   - Data Security Posture Management (DSPM)
   - Vulnerability Scanning

:::note
For multi-region deployments, this module needs to be instantiated separately for each region where FCS components are required.
:::

## Pre-requisites
### Generate API Keys

CrowdStrike API keys are required to use this module. It is highly recommended that you create a dedicated API client with only the required scopes.

1. In the CrowdStrike console, navigate to **Support and resources** > **API Clients & Keys**. Click **Add new API Client**.
2. Add the required scopes for your deployment:

<table>
    <tr>
        <th>Option</th>
        <th>Scope Name</th>
        <th>Permission</th>
    </tr>
    <tr>
        <td rowspan="2">Automated account registration</td>
        <td>CSPM registration</td>
        <td><strong>Read</strong> and <strong>Write</strong></td>
    </tr>
    <tr>
        <td>Cloud security AWS registration</td>
        <td><strong>Read</strong> and <strong>Write</strong></td>
    </tr>
    <tr>
        <td rowspan="3">1-click sensor management</td>
        <td>CSPM sensor management</td>
        <td><strong>Read</strong> and <strong>Write</strong></td>
    </tr>
    <tr>
        <td>Installation tokens</td>
        <td><strong>Read</strong></td>
    </tr>
    <tr>
        <td>Sensor download</td>
        <td><strong>Read</strong></td>
    </tr>
    <tr>
        <td>DSPM</td>
        <td>DSPM Data scanner</td>
        <td><strong>Read</strong> and <strong>Write</strong></td>
    </tr>
</table>

3. Click **Add** to create the API client. The next screen will display the API **CLIENT ID**, **SECRET**, and **BASE URL**. You will need all three for the next step.

    <details><summary>picture</summary>
    <p>

    ![api-client-keys](https://github.com/CrowdStrike/aws-ssm-distributor/blob/main/official-package/assets/api-client-keys.png)

    </p>
    </details>

:::note
This page is only shown once. Make sure you copy **CLIENT ID**, **SECRET**, and **BASE URL** to a secure location.
:::

## Usage

```hcl
terraform {
  required_version = ">= 1.5.0"
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = ">= 5.0.0"
    }
    crowdstrike = {
      source  = "CrowdStrike/crowdstrike"
      version = ">= 0.0.58"
    }
  }
}

variable "falcon_client_id" {
  type        = string
  sensitive   = true
  description = "Falcon API Client ID"
}

variable "falcon_client_secret" {
  type        = string
  sensitive   = true
  description = "Falcon API Client Secret"
}

variable "account_id" {
  type        = string
  default     = ""
  description = "The AWS 12 digit account ID"
  validation {
    condition     = length(var.account_id) == 0 || can(regex("^[0-9]{12}$", var.account_id))
    error_message = "account_id must be either empty or the 12-digit AWS account ID"
  }
}

locals {
  enable_realtime_visibility    = true
  primary_region                = "us-east-1"
  enable_idp                    = true
  enable_sensor_management      = true
  enable_dspm                   = true
  enable_vulnerability_scanning = true
  agentless_scanning_regions    = ["us-east-1", "us-east-2"]
  use_existing_cloudtrail       = true
  log_ingestion_method          = "eventbridge"
}

provider "crowdstrike" {
  client_id     = var.falcon_client_id
  client_secret = var.falcon_client_secret
}
provider "aws" {
  region = "us-east-1"
  alias  = "us-east-1"
}
provider "aws" {
  region = "us-east-2"
  alias  = "us-east-2"
}

# Provision AWS account in Falcon.
resource "crowdstrike_cloud_aws_account" "this" {
  account_id = local.account_id

  asset_inventory = {
    enabled = true
  }

  realtime_visibility = {
    enabled                 = local.enable_realtime_visibility
    cloudtrail_region       = local.primary_region
    use_existing_cloudtrail = local.use_existing_cloudtrail
    log_ingestion_method    = local.log_ingestion_method
  }

  idp = {
    enabled = local.enable_idp
  }

  sensor_management = {
    enabled = local.enable_sensor_management
  }

  dspm = {
    enabled = local.enable_dspm
  }

  vulnerability_scanning = {
    enabled = local.enable_vulnerability_scanning
  }
}

module "fcs_account_onboarding" {
  source                        = "CrowdStrike/cloud-registration/aws"
  falcon_client_id              = var.falcon_client_id
  falcon_client_secret          = var.falcon_client_secret
  account_id                    = var.account_id
  primary_region                = local.primary_region
  enable_sensor_management      = local.enable_sensor_management
  enable_realtime_visibility    = local.enable_realtime_visibility
  enable_idp                    = local.enable_idp
  use_existing_cloudtrail       = local.use_existing_cloudtrail
  enable_dspm                   = local.enable_dspm && contains(local.agentless_scanning_regions, "us-east-1")
  enable_vulnerability_scanning = local.enable_vulnerability_scanning && contains(local.agentless_scanning_regions, "us-east-1")
  agentless_scanning_regions    = local.agentless_scanning_regions
  log_ingestion_method            = local.log_ingestion_method

  iam_role_name                = crowdstrike_cloud_aws_account.this.iam_role_name
  external_id                  = crowdstrike_cloud_aws_account.this.external_id
  intermediate_role_arn        = crowdstrike_cloud_aws_account.this.intermediate_role_arn
  eventbus_arn                 = crowdstrike_cloud_aws_account.this.eventbus_arn
  agentless_scanning_role_name = crowdstrike_cloud_aws_account.this.agentless_scanning_role_name
  cloudtrail_bucket_name       = crowdstrike_cloud_aws_account.this.cloudtrail_bucket_name

  providers = {
    aws         = aws.us-east-1
    crowdstrike = crowdstrike
  }
}

# for each region where you want to onboard DSPM features or Vulnerability Scanning features
# - duplicate this module
# - update the provider with region specific one
# If you want to onboard Real-time Visibility with 'eventbridge' as the log_ingestion_method, for each region you want to onboard Real-Time Visibility features
# - duplicate this module
# - update the provider with region specific one
# If you want to onboard Real-time Visibility with 's3' as the log_ingestion_method, for the region that the SNS topic is in
# - duplicate this module
# - update the provider with region specific one
module "fcs_account_us_east_2" {
  source                        = "CrowdStrike/cloud-registration/aws"
  falcon_client_id              = var.falcon_client_id
  falcon_client_secret          = var.falcon_client_secret
  account_id                    = var.account_id
  primary_region                = local.primary_region
  enable_sensor_management      = local.enable_sensor_management
  enable_realtime_visibility    = local.enable_realtime_visibility
  enable_idp                    = local.enable_idp
  use_existing_cloudtrail       = local.use_existing_cloudtrail
  enable_dspm                   = local.enable_dspm && contains(local.agentless_scanning_regions, "us-east-2")
  enable_vulnerability_scanning = local.enable_vulnerability_scanning && contains(local.agentless_scanning_regions, "us-east-2")
  agentless_scanning_regions    = local.agentless_scanning_regions
  log_ingestion_method            = local.log_ingestion_method

  iam_role_name                                 = crowdstrike_cloud_aws_account.this.iam_role_name
  external_id                                   = crowdstrike_cloud_aws_account.this.external_id
  intermediate_role_arn                         = crowdstrike_cloud_aws_account.this.intermediate_role_arn
  eventbus_arn                                  = crowdstrike_cloud_aws_account.this.eventbus_arn
  agentless_scanning_role_name                  = crowdstrike_cloud_aws_account.this.agentless_scanning_role_name
  cloudtrail_bucket_name                        = crowdstrike_cloud_aws_account.this.cloudtrail_bucket_name
  agentless_scanning_integration_role_unique_id = module.fcs_account_onboarding.integration_role_unique_id
  agentless_scanning_scanner_role_unique_id     = module.fcs_account_onboarding.scanner_role_unique_id

  providers = {
    aws         = aws.us-east-2
    crowdstrike = crowdstrike
  }
}
```

## Providers

| Name | Version |
|------|---------|
|  [aws](#provider\_aws) | >= 5.0.0 |
|  [crowdstrike](#provider\_crowdstrike) | >= 0.0.58 |
## Resources

| Name | Type |
|------|------|
| [aws_caller_identity.current](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/caller_identity) | data source |
| [aws_region.current](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/region) | data source |
| [crowdstrike_cloud_aws_account.target](https://registry.terraform.io/providers/CrowdStrike/crowdstrike/latest/docs/data-sources/cloud_aws_account) | data source |
## Inputs

| Name | Description | Type | Default | Required |
|------|-------------|------|---------|:--------:|
|  [account\_id](#input\_account\_id) | The AWS 12 digit account ID | `string` | `""` | no |
|  [account\_type](#input\_account\_type) | Account type can be either 'commercial' or 'gov' | `string` | `"commercial"` | no |
|  [agentless\_scanning\_create\_nat\_gateway](#input\_agentless\_scanning\_create\_nat\_gateway) | Set to true to create a NAT Gateway for agentless scanning environments | `bool` | `true` | no |
|  [agentless\_scanning\_custom\_vpc\_resources\_map](#input\_agentless\_scanning\_custom\_vpc\_resources\_map) | Map of regions to custom VPC resources for Agentless Scanning deployment.<br/>Each region can specify existing VPC resources to use instead of creating new ones.<br/><br/>Example:<br/>{<br/>  "us-east-1" = {<br/>    vpc            = "vpc-0123456789abcdef0"<br/>    scanner\_subnet = "subnet-0123456789abcdef0"<br/>    scanner\_sg     = "sg-0123456789abcdef0"<br/>    db\_subnet\_a    = "subnet-1123456789abcdef0"<br/>    db\_subnet\_b    = "subnet-2123456789abcdef0"<br/>    db\_sg          = "sg-1123456789abcdef0"<br/>  }<br/>}<br/><br/>All resource IDs must exist in the specified region. | <pre>map(object({<br/>    vpc            = string<br/>    scanner_subnet = string<br/>    scanner_sg     = string<br/>    db_subnet_a    = string<br/>    db_subnet_b    = string<br/>    db_sg          = string<br/>  }))</pre> | `{}` | no |
|  [agentless\_scanning\_host\_account\_id](#input\_agentless\_scanning\_host\_account\_id) | The AWS account ID where agentless scanning host resources are deployed | `string` | `""` | no |
|  [agentless\_scanning\_host\_role\_name](#input\_agentless\_scanning\_host\_role\_name) | Name of agentless scanning integration role in host account | `string` | `"CrowdStrikeAgentlessScanningIntegrationRole"` | no |
|  [agentless\_scanning\_host\_scanner\_role\_name](#input\_agentless\_scanning\_host\_scanner\_role\_name) | Name of agentless scanning scanner role in host account | `string` | `"CrowdStrikeAgentlessScanningScannerRole"` | no |
|  [agentless\_scanning\_integration\_role\_unique\_id](#input\_agentless\_scanning\_integration\_role\_unique\_id) | The unique ID of the Agentless scanning integration role | `string` | `""` | no |
|  [agentless\_scanning\_regions](#input\_agentless\_scanning\_regions) | List of regions where agentless scanning will be deployed | `list(string)` | <pre>[<br/>  "us-east-1"<br/>]</pre> | no |
|  [agentless\_scanning\_role\_name](#input\_agentless\_scanning\_role\_name) | The unique name of the IAM role that Agentless scanning will be assuming | `string` | `"CrowdStrikeAgentlessScanningIntegrationRole"` | no |
|  [agentless\_scanning\_scanner\_role\_name](#input\_agentless\_scanning\_scanner\_role\_name) | The unique name of the IAM role that Agentless scanning scanner will be assuming | `string` | `"CrowdStrikeAgentlessScanningScannerRole"` | no |
|  [agentless\_scanning\_scanner\_role\_unique\_id](#input\_agentless\_scanning\_scanner\_role\_unique\_id) | The unique ID of the Agentless scanning scanner role | `string` | `""` | no |
|  [agentless\_scanning\_use\_custom\_vpc](#input\_agentless\_scanning\_use\_custom\_vpc) | Use existing custom VPC resources for ALL deployment regions (requires agentless\_scanning\_custom\_vpc\_resources\_map with all regions) | `bool` | `false` | no |
|  [cloudtrail\_bucket\_name](#input\_cloudtrail\_bucket\_name) | DEPRECATED: This variable is no longer used. CrowdStrike no longer provisions or references a CloudTrail S3 bucket. | `string` | `""` | no |
|  [create\_rtvd\_rules](#input\_create\_rtvd\_rules) | Set to false if you don't want to enable monitoring in this region | `bool` | `true` | no |
|  [cs\_address](#input\_cs\_address) | CrowdStrike Falcon address for sensor management Lambda (e.g. az.laggar.gcw.crowdstrike.com:443). Required when is\_gov = true. | `string` | `""` | no |
|  [current\_account\_id](#input\_current\_account\_id) | The AWS 12 digit account ID this module instance is deploying into. Distinct from 'account\_id', which selects the Falcon registration to look up and is intentionally empty for organization registrations. Set this when the module is called with depends\_on, or in any topology where Terraform defers data source reads to apply time - otherwise the count expressions gated on the account ID cannot be resolved at plan time. When null, falls back to 'account\_id' and then to data.aws\_caller\_identity.current. | `string` | `null` | no |
|  [dspm\_create\_nat\_gateway](#input\_dspm\_create\_nat\_gateway) | DEPRECATED: Use agentless\_scanning\_create\_nat\_gateway instead. Set to true to create a NAT Gateway for DSPM scanning environments | `bool` | `true` | no |
|  [dspm\_dynamodb\_access](#input\_dspm\_dynamodb\_access) | Apply permissions for DSPM DynamoDB table scanning | `bool` | `true` | no |
|  [dspm\_ebs\_access](#input\_dspm\_ebs\_access) | Apply permissions for DSPM VM scanning | `bool` | `true` | no |
|  [dspm\_integration\_role\_unique\_id](#input\_dspm\_integration\_role\_unique\_id) | DEPRECATED: Use agentless\_scanning\_integration\_role\_unique\_id instead. The unique ID of the DSPM integration role | `string` | `""` | no |
|  [dspm\_rds\_access](#input\_dspm\_rds\_access) | Apply permissions for DSPM RDS instance scanning | `bool` | `true` | no |
|  [dspm\_redshift\_access](#input\_dspm\_redshift\_access) | Apply permissions for DSPM Redshift cluster scanning | `bool` | `true` | no |
|  [dspm\_regions](#input\_dspm\_regions) | DEPRECATED: Use agentless\_scanning\_regions instead. List of regions where DSPM scanning will be deployed | `list(string)` | `[]` | no |
|  [dspm\_role\_name](#input\_dspm\_role\_name) | DEPRECATED: Use agentless\_scanning\_role\_name instead. The unique name of the IAM role that DSPM will be assuming | `string` | `""` | no |
|  [dspm\_s3\_access](#input\_dspm\_s3\_access) | Apply permissions for DSPM S3 bucket scanning | `bool` | `true` | no |
|  [dspm\_scanner\_role\_name](#input\_dspm\_scanner\_role\_name) | DEPRECATED: Use agentless\_scanning\_scanner\_role\_name instead. The unique name of the IAM role that CrowdStrike Scanner will be assuming | `string` | `""` | no |
|  [dspm\_scanner\_role\_unique\_id](#input\_dspm\_scanner\_role\_unique\_id) | DEPRECATED: Use agentless\_scanning\_scanner\_role\_unique\_id instead. The unique ID of the DSPM scanner role | `string` | `""` | no |
|  [enable\_dspm](#input\_enable\_dspm) | Set to true to enable Data Security Posture Managment | `bool` | `false` | no |
|  [enable\_idp](#input\_enable\_idp) | Set to true to install Identity Protection resources | `bool` | `false` | no |
|  [enable\_realtime\_visibility](#input\_enable\_realtime\_visibility) | Set to true to install realtime visibility resources | `bool` | `false` | no |
|  [enable\_sensor\_management](#input\_enable\_sensor\_management) | Set to true to install 1Click Sensor Management resources | `bool` | n/a | yes |
|  [enable\_vulnerability\_scanning](#input\_enable\_vulnerability\_scanning) | Set to true to enable Vulnerability Scanning | `bool` | `false` | no |
|  [eventbridge\_role\_name](#input\_eventbridge\_role\_name) | The eventbridge role name | `string` | `"CrowdStrikeCSPMEventBridge"` | no |
|  [eventbus\_arn](#input\_eventbus\_arn) | Eventbus ARN to send events to | `string` | `""` | no |
|  [external\_id](#input\_external\_id) | The external ID used to assume the AWS reader role | `string` | `""` | no |
|  [falcon\_client\_id](#input\_falcon\_client\_id) | Falcon API Client ID | `string` | n/a | yes |
|  [falcon\_client\_secret](#input\_falcon\_client\_secret) | Falcon API Client Secret | `string` | n/a | yes |
|  [iam\_role\_name](#input\_iam\_role\_name) | The name of the reader role | `string` | `""` | no |
|  [intermediate\_role\_arn](#input\_intermediate\_role\_arn) | The intermediate role that is allowed to assume the reader role | `string` | `""` | no |
|  [is\_gov](#input\_is\_gov) | Set to true if you are deploying in gov Falcon | `bool` | `false` | no |
|  [is\_primary\_region](#input\_is\_primary\_region) | Explicit override for primary-region detection. Prefer setting 'region' instead, which lets the module derive this. Provided for callers that want to gate global resources directly. When null, derived by comparing the region against primary\_region. | `bool` | `null` | no |
|  [log\_ingestion\_kms\_key\_arn](#input\_log\_ingestion\_kms\_key\_arn) | Optional KMS key ARN for decrypting S3 objects (when log\_ingestion\_method=s3) | `string` | `""` | no |
|  [log\_ingestion\_method](#input\_log\_ingestion\_method) | Choose the method for ingesting CloudTrail logs - eventbridge (default) or s3. If s3 is selected, be sure to deploy to the region associated with the SNS topic connected to your CloudTrail instance. | `string` | `"eventbridge"` | no |
|  [log\_ingestion\_s3\_bucket\_name](#input\_log\_ingestion\_s3\_bucket\_name) | S3 bucket name containing CloudTrail logs (required when log\_ingestion\_method=s3) | `string` | `""` | no |
|  [log\_ingestion\_s3\_bucket\_prefix](#input\_log\_ingestion\_s3\_bucket\_prefix) | Optional S3 bucket prefix/path for CloudTrail logs (when log\_ingestion\_method=s3) | `string` | `""` | no |
|  [log\_ingestion\_sns\_topic\_arn](#input\_log\_ingestion\_sns\_topic\_arn) | SNS topic ARN that publishes S3 object creation events (required when log\_ingestion\_method=s3) | `string` | `""` | no |
|  [organization\_id](#input\_organization\_id) | The AWS Organization ID. Leave blank if when onboarding single account | `string` | `""` | no |
|  [permissions\_boundary](#input\_permissions\_boundary) | The name of the policy used to set the permissions boundary for IAM roles | `string` | `""` | no |
|  [primary\_region](#input\_primary\_region) | Region for deploying global AWS resources (IAM roles, policies, etc.) that are account-wide and only need to be created once. Distinct from agentless\_scanning\_regions which controls region-specific resource deployment. | `string` | n/a | yes |
|  [region](#input\_region) | The region this module instance deploys into. Set this explicitly when the module is called with depends\_on, or in any topology where Terraform defers data source reads to apply time - otherwise the count expressions gated on region cannot be resolved at plan time. When null, the region is read from data.aws\_region.current. | `string` | `null` | no |
|  [resource\_prefix](#input\_resource\_prefix) | The prefix to be added to all resource names | `string` | `"CrowdStrike"` | no |
|  [resource\_suffix](#input\_resource\_suffix) | The suffix to be added to all resource names | `string` | `""` | no |
|  [tags](#input\_tags) | A map of tags to add to all resources that support tagging | `map(string)` | `{}` | no |
|  [use\_existing\_cloudtrail](#input\_use\_existing\_cloudtrail) | DEPRECATED: This variable is no longer used. CrowdStrike no longer provisions CloudTrail resources. All deployments now behave as if use\_existing\_cloudtrail=true. | `bool` | `true` | no |
|  [use\_existing\_iam\_reader\_role](#input\_use\_existing\_iam\_reader\_role) | Set to true if you want to use an existing IAM role for asset inventory | `bool` | `false` | no |
|  [vpc\_cidr\_block](#input\_vpc\_cidr\_block) | VPC CIDR block | `string` | `"10.0.0.0/16"` | no |
## Outputs

| Name | Description |
|------|-------------|
|  [integration\_role\_unique\_id](#output\_integration\_role\_unique\_id) | The unique ID of the DSPM integration role |
|  [scanner\_role\_unique\_id](#output\_scanner\_role\_unique\_id) | The unique ID of the DSPM scanner role |